Compilation: don't compile dialogs separately.
[gnumeric.git] / src / dialogs / dialog-printer-setup.c
blobf6a264491456ecaf524c541fb8265b0f81a1f320
1 /*
2 * dialog-printer-setup.c: Printer setup dialog box
4 * Authors:
5 * Wayne Schuller (k_wayne@linuxpower.org)
6 * Miguel de Icaza (miguel@gnu.org)
7 * Andreas J. Guelzow (aguelzow@pyrshep.ca)
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, see <https://www.gnu.org/licenses/>.
22 #include <gnumeric-config.h>
23 #include <glib/gi18n-lib.h>
24 #include <gnumeric.h>
25 #include <gtk/gtk.h>
26 #include "dialogs.h"
27 #include "help.h"
29 #include <gui-util.h>
30 #include <commands.h>
31 #include <print-info.h>
32 #include <print.h>
33 #include <ranges.h>
34 #include <sheet.h>
35 #include <sheet-object-graph.h>
36 #include <workbook.h>
37 #include <wbc-gtk.h>
38 #include <style.h>
39 #include <gnumeric-conf.h>
41 #include <gdk/gdkkeysyms.h>
42 #include <goffice/goffice.h>
43 #include <string.h>
45 #define PREVIEW_MARGIN_X 20
46 #define PREVIEW_MARGIN_Y 20
48 #define MARGIN_COLOR_DEFAULT 0xa9a9a9ff /* dark gray */
49 #define MARGIN_COLOR_ACTIVE GO_COLOR_RED
51 /* FIXME: do not hardcode pixel counts. */
52 #define HF_PREVIEW_X 350
53 #define HF_PREVIEW_Y 75
54 #define HF_PREVIEW_SHADOW 2
55 #define HF_PREVIEW_PADDING 5
56 #define HF_PREVIEW_MARGIN 10
58 #define PRINTER_SETUP_KEY "printer-setup-dialog"
60 #define PAPER_PAGE 0
61 #define SCALE_PAGE 1
62 #define HF_PAGE 2
64 #define HF_TAG_NAME "field_tag"
66 typedef struct {
67 /* The Canvas object */
68 GtkWidget *canvas;
70 /* Objects in the Preview Canvas */
71 GocItem *group;
73 /* Values for the scaling of the nice preview */
74 int width, height;
75 int offset_x, offset_y; /* For centering the small page preview */
76 double scale;
77 } MarginPreviewInfo;
79 typedef struct {
80 /* The available width and height for the nice preview page */
81 guint height, width;
82 } MarginPreviewPageAvailableSize;
84 typedef struct {
85 /* The Canvas object for the header/footer sample preview */
86 GtkWidget *canvas;
88 /* Objects in the Preview Canvas */
89 GocItem *left;
90 GocItem *middle;
91 GocItem *right;
93 } HFPreviewInfo;
96 typedef struct _PrinterSetupState PrinterSetupState;
97 typedef struct {
98 double value;
99 GtkSpinButton *spin;
100 GocItem *line;
101 double bound_x1, bound_y1, bound_x2, bound_y2;
102 MarginPreviewInfo *pi;
103 PrinterSetupState *state;
104 } UnitInfo;
106 struct _PrinterSetupState {
107 WBCGtk *wbcg;
108 Sheet *sheet;
109 GtkBuilder *gui;
110 GnmPrintInformation *pi;
111 GtkWidget *dialog;
112 GtkWidget *sheet_selector;
114 GtkWidget *scale_percent_radio;
115 GtkWidget *scale_fit_to_radio;
116 GtkWidget *scale_no_radio;
118 GtkWidget *portrait_radio;
119 GtkWidget *landscape_radio;
120 GtkWidget *rev_portrait_radio;
121 GtkWidget *rev_landscape_radio;
123 GtkWidget *unit_selector;
124 GtkTreeModel *unit_model;
125 GtkUnit display_unit;
127 struct {
128 UnitInfo top, bottom, left, right;
129 UnitInfo header, footer;
130 } margins;
132 MarginPreviewInfo preview;
134 double height, width;
136 GtkWidget * check_center_v;
137 GtkWidget * check_center_h;
139 GtkWidget *icon_rd;
140 GtkWidget *icon_dr;
141 GnmExprEntry *area_entry;
142 GnmExprEntry *top_entry;
143 GnmExprEntry *left_entry;
145 /* The header and footer data. */
146 GnmPrintHF *header;
147 GnmPrintHF *footer;
149 /* The header and footer customize dialogs. */
150 GtkWidget *customize_header;
151 GtkWidget *customize_footer;
153 /* The header and footer preview widgets. */
154 HFPreviewInfo *pi_header;
155 HFPreviewInfo *pi_footer;
157 /* Error Display */
158 struct {
159 GtkListStore *store;
160 GtkWidget *combo;
161 } error_display;
163 /* Comment Display */
164 struct {
165 GtkListStore *store;
166 GtkWidget *combo;
167 } comment_display;
170 typedef struct _HFCustomizeState HFCustomizeState;
172 typedef struct _HFDTFormatState HFDTFormatState;
173 struct _HFDTFormatState {
174 GtkWidget *dialog;
175 GtkBuilder *gui;
176 HFCustomizeState *hf_state;
177 char *format_string;
178 GtkWidget *format_sel;
181 struct _HFCustomizeState {
182 GtkWidget *dialog;
183 GtkBuilder *gui;
184 PrinterSetupState *printer_setup_state;
185 GnmPrintHF **hf;
186 gboolean is_header;
187 GtkTextBuffer *left_buffer;
188 GtkTextBuffer *middle_buffer;
189 GtkTextBuffer *right_buffer;
190 GList *marks;
193 typedef enum {
194 HF_FIELD_UNKNOWN,
195 HF_FIELD_FILE,
196 HF_FIELD_PATH,
197 HF_FIELD_DATE,
198 HF_FIELD_TIME,
199 HF_FIELD_PAGE,
200 HF_FIELD_PAGES,
201 HF_FIELD_SHEET,
202 HF_FIELD_CELL
203 } HFFieldType;
205 typedef struct _HFMarkInfo HFMarkInfo;
206 struct _HFMarkInfo {
207 GtkTextMark *mark;
208 HFFieldType type;
209 char *options;
212 static void dialog_gtk_printer_setup_cb (PrinterSetupState *state);
213 static void fetch_settings (PrinterSetupState *state);
214 static void do_update_page (PrinterSetupState *state);
215 static void do_fetch_margins (PrinterSetupState *state);
216 static void do_hf_customize (gboolean header, PrinterSetupState *state);
217 static char *do_hf_dt_format_customize (gboolean date, HFCustomizeState *hf_state);
220 static double
221 get_conversion_factor (GtkUnit unit)
223 switch (unit) {
224 case GTK_UNIT_MM:
225 return (72./25.4);
226 case GTK_UNIT_INCH:
227 return 72.;
228 case GTK_UNIT_PIXEL:
229 case GTK_UNIT_POINTS:
230 default:
231 return 1.0;
235 static void
236 margin_preview_page_destroy (PrinterSetupState *state)
238 if (state->preview.group) {
239 g_object_unref (state->preview.group);
240 state->preview.group = NULL;
244 static void
245 move_line (GocItem *item,
246 double x1, double y1,
247 double x2, double y2)
249 if (item != NULL)
250 goc_item_set (item,
251 "x0", floor (x1) + .5,
252 "y0", floor (y1) + .5,
253 "x1", floor (x2) + .5,
254 "y1", floor (y2) + .5,
255 NULL);
258 static GocItem *
259 make_line (GocGroup *g, double x1, double y1, double x2, double y2)
262 GocItem *item;
263 GOStyle *style;
265 item = goc_item_new (
266 g, goc_line_get_type (),
267 "x0", floor (x1) + .5,
268 "y0", floor (y1) + .5,
269 "x1", floor (x2) + .5,
270 "y1", floor (y2) + .5,
271 NULL);
272 style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
273 style->line.width = 1.;
274 style->line.color = MARGIN_COLOR_DEFAULT;
276 return item;
279 static void
280 draw_margin_top (UnitInfo *uinfo)
282 double x1, x2, y1;
284 x1 = uinfo->bound_x1;
285 x2 = uinfo->bound_x2;
286 y1 = uinfo->bound_y1;
288 y1 += uinfo->pi->scale * uinfo->value;
289 move_line (uinfo->line, x1, y1, x2, y1);
292 static void
293 draw_margin_bottom (UnitInfo *uinfo)
295 double x1, x2, y2;
297 x1 = uinfo->bound_x1;
298 x2 = uinfo->bound_x2;
299 y2 = uinfo->bound_y2;
301 y2 -= uinfo->pi->scale * uinfo->value;
302 move_line (uinfo->line, x1, y2, x2, y2);
305 static void
306 draw_margin_left (UnitInfo *uinfo)
308 double x1, y1, y2;
310 x1 = uinfo->bound_x1;
311 y1 = uinfo->bound_y1;
312 y2 = uinfo->bound_y2;
314 x1 += uinfo->pi->scale * uinfo->value;
315 move_line (uinfo->line, x1, y1, x1, y2);
318 static void
319 draw_margin_right (UnitInfo *uinfo)
321 double y1, x2, y2;
323 y1 = uinfo->bound_y1;
324 x2 = uinfo->bound_x2;
325 y2 = uinfo->bound_y2;
327 x2 -= uinfo->pi->scale * uinfo->value;
328 move_line (uinfo->line, x2, y1, x2, y2);
331 static void
332 draw_margin_header (UnitInfo *uinfo)
334 double x1, y1, x2;
335 double outside = uinfo->pi->scale *
336 uinfo->state->margins.top.value;
337 double inside = uinfo->pi->scale * uinfo->value;
339 x1 = uinfo->bound_x1;
340 y1 = uinfo->bound_y1;
341 x2 = uinfo->bound_x2;
343 if (inside < 1.0)
344 inside = 1.0;
345 y1 += outside + inside ;
347 move_line (uinfo->line, x1, y1, x2, y1);
350 static void
351 draw_margin_footer (UnitInfo *uinfo)
353 double x1, x2, y2;
354 double outside = uinfo->pi->scale *
355 uinfo->state->margins.bottom.value;
356 double inside = uinfo->pi->scale * uinfo->value;
358 x1 = uinfo->bound_x1;
359 x2 = uinfo->bound_x2;
360 y2 = uinfo->bound_y2;
362 if (inside < 1.0)
363 inside = 1.0;
364 y2 -= outside + inside ;
365 move_line (uinfo->line, x1, y2, x2, y2);
368 static void
369 create_margin (UnitInfo *uinfo,
370 double x1, double y1,
371 double x2, double y2)
373 GocGroup *g = GOC_GROUP (uinfo->state->preview.group);
375 uinfo->line = make_line (g, x1 + 8, y1, x1 + 8, y2);
376 uinfo->bound_x1 = x1;
377 uinfo->bound_y1 = y1;
378 uinfo->bound_x2 = x2;
379 uinfo->bound_y2 = y2;
382 static void
383 draw_margins (PrinterSetupState *state, double x1, double y1, double x2, double y2)
385 /* Margins */
386 create_margin (&state->margins.left, x1, y1, x2, y2);
387 create_margin (&state->margins.right, x1, y1, x2, y2);
388 create_margin (&state->margins.top, x1, y1, x2, y2);
389 create_margin (&state->margins.bottom, x1, y1, x2, y2);
391 /* Headers & footers */
392 create_margin (&state->margins.header, x1, y1, x2, y2);
393 create_margin (&state->margins.footer, x1, y1, x2, y2);
395 /* Margins */
396 draw_margin_left (&state->margins.left);
397 draw_margin_right (&state->margins.right);
398 draw_margin_top (&state->margins.top);
399 draw_margin_bottom (&state->margins.bottom);
401 /* Headers & footers */
402 draw_margin_header (&state->margins.header);
403 draw_margin_footer (&state->margins.footer);
406 static void
407 margin_preview_page_available_size (PrinterSetupState *state,
408 MarginPreviewPageAvailableSize *available_size)
410 GList *children, *l;
411 GtkWidget *grid;
412 unsigned *widths, *heights;
413 GtkRequisition requisition;
414 unsigned top, left, width, height, i;
415 unsigned nrows, ncols, first_col, first_row;
417 /* Reset available size to zero*/
418 available_size->width = 0;
419 available_size->height = 0;
421 grid = go_gtk_builder_get_widget (state->gui, "paper-selector-grid");
422 gtk_container_child_get (GTK_CONTAINER (grid),
423 go_gtk_builder_get_widget (state->gui, "container-paper-sample"),
424 "top-attach", &first_row,
425 "left-attach", &first_col,
426 "width", &ncols,
427 "height", &nrows,
428 NULL);
429 widths = g_new0 (guint, ncols);
430 heights = g_new0 (guint, nrows);
432 /* Iterate through all child widgets in the grid */
433 children = gtk_container_get_children (GTK_CONTAINER (grid));
434 for (l = children; l; l = l->next) {
435 GtkWidget *child_widget = l->data;
437 /* Determine which cells the align widget spans across */
438 gtk_container_child_get (GTK_CONTAINER (grid), GTK_WIDGET (child_widget),
439 "top-attach", &top,
440 "left-attach", &left,
441 "width", &width,
442 "height", &height,
443 NULL);
445 /* Determine the requisition size for the widget */
446 gtk_widget_get_preferred_size (GTK_WIDGET(child_widget), &requisition, NULL);
448 /* Find largest widget in each table column */
449 /* Exclude widgets that expand across more than one grid cells
450 * or are not in a relevant column */
451 if (left >= first_col && width == 1 && left < first_col + ncols) {
452 if ((guint) requisition.width > widths[left - first_col]) {
453 widths[left - first_col] = (guint) requisition.width;
457 /* Find largest widget in each table row */
458 /* Exclude widgets that expand across more than one grid cells
459 * or are not in a relevant column */
460 if (top >= first_row && height == 1 && top < first_row + nrows) {
461 if ((guint) requisition.height > heights[top - first_row]) {
462 heights[top - first_row] = (guint) requisition.height;
466 g_list_free (children);
468 /* Calculate width of container widget using maximum */
469 /* widget widths from above */
470 for (i = 0; i < ncols; i++){
471 available_size->width = available_size->width + widths[i];
474 /* Calculate height of container widget using maximum */
475 /* widget heights from above */
476 for (i = 0; i < nrows; i++){
477 available_size->height = available_size->height + heights[i];
480 g_free(widths);
481 g_free(heights);
483 /* Account for the spacing between table cells */
484 available_size->width = available_size->width +
485 gtk_grid_get_column_spacing (GTK_GRID (grid)) * (ncols - 1);
486 available_size->height = available_size->height +
487 gtk_grid_get_row_spacing (GTK_GRID (grid)) * (nrows - 1);
490 static void
491 margin_preview_page_create (PrinterSetupState *state)
493 double x1, y1, x2, y2;
494 double width, height;
495 MarginPreviewInfo *pi = &state->preview;
496 GOStyle *style;
497 MarginPreviewPageAvailableSize margin_available_size;
499 margin_preview_page_available_size (state, &margin_available_size);
500 gtk_widget_set_size_request (state->preview.canvas, margin_available_size.width, margin_available_size.height);
502 width = state->width;
503 height = state->height;
504 x1 = (margin_available_size.width - PREVIEW_MARGIN_X) / width;
505 x2 = (margin_available_size.height - PREVIEW_MARGIN_Y) / height;
506 pi->scale = MIN (x1, x2);
508 pi->offset_x = (margin_available_size.width - (width * pi->scale)) / 2;
509 pi->offset_y = (margin_available_size.height - (height * pi->scale)) / 2;
510 x1 = pi->offset_x;
511 y1 = pi->offset_y;
512 x2 = pi->offset_x + width * pi->scale;
513 y2 = pi->offset_y + height * pi->scale;
515 pi->group = goc_item_new (
516 goc_canvas_get_root (GOC_CANVAS (pi->canvas)),
517 goc_group_get_type (),
518 "x", 0.0,
519 "y", 0.0,
520 NULL);
522 style = go_styled_object_get_style (
523 GO_STYLED_OBJECT (goc_item_new (GOC_GROUP (pi->group),
524 GOC_TYPE_RECTANGLE,
525 "x", (double) x1+2,
526 "y", (double) y1+2,
527 "width", (double) x2-x1,
528 "height", (double) y2-y1,
529 NULL)));
530 style->fill.pattern.back = GO_COLOR_BLACK;
531 style->line.color = GO_COLOR_BLACK;
532 style->line.width = 1.;
534 style = go_styled_object_get_style (
535 GO_STYLED_OBJECT (goc_item_new (GOC_GROUP (pi->group),
536 GOC_TYPE_RECTANGLE,
537 "x", (double) x1,
538 "y", (double) y1,
539 "width", (double) x2-x1,
540 "height", (double) y2-y1,
541 NULL)));
542 style->fill.pattern.back = GO_COLOR_WHITE;
543 style->line.color = GO_COLOR_BLACK;
544 style->line.width = 1.;
546 goc_item_invalidate (pi->group);
548 draw_margins (state, x1, y1, x2, y2);
551 static void
552 canvas_update (PrinterSetupState *state)
554 margin_preview_page_destroy (state);
555 margin_preview_page_create (state);
559 static gboolean
560 cb_spin_activated (UnitInfo *target)
562 GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (target->line));
563 style->fill.pattern.back = MARGIN_COLOR_ACTIVE,
564 goc_item_invalidate (target->line);
565 return FALSE;
568 static gboolean
569 cb_spin_deactivated (UnitInfo *target)
571 GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (target->line));
572 style->fill.pattern.back = MARGIN_COLOR_DEFAULT,
573 goc_item_invalidate (target->line);
574 return FALSE;
575 return FALSE;
578 static void
579 configure_bounds_header (PrinterSetupState *state)
581 double max = state->height - state->margins.top.value
582 - state->margins.footer.value - state->margins.bottom.value;
583 gtk_spin_button_set_range (state->margins.header.spin, 0., max);
586 static void
587 configure_bounds_footer (PrinterSetupState *state)
589 double max = state->height - state->margins.header.value
590 - state->margins.top.value - state->margins.bottom.value;
591 gtk_spin_button_set_range (state->margins.footer.spin, 0., max);
594 static void
595 configure_bounds_bottom (PrinterSetupState *state)
597 double max = state->height - state->margins.header.value
598 - state->margins.footer.value - state->margins.top.value;
599 gtk_spin_button_set_range (state->margins.bottom.spin, 0., max);
602 static void
603 configure_bounds_top (PrinterSetupState *state)
605 double max = state->height - state->margins.header.value
606 - state->margins.footer.value - state->margins.bottom.value;
607 gtk_spin_button_set_range (state->margins.top.spin, 0., max);
610 static void
611 configure_bounds_left (PrinterSetupState *state)
613 double max = state->width - state->margins.right.value;
614 gtk_spin_button_set_range (state->margins.left.spin, 0., max);
617 static void
618 configure_bounds_right (PrinterSetupState *state)
620 double max = state->width - state->margins.left.value;
621 gtk_spin_button_set_range (state->margins.right.spin, 0., max);
624 static void
625 value_changed_header_cb (gpointer user_data)
627 UnitInfo *target = user_data;
629 target->value = gtk_spin_button_get_value (target->spin);
631 configure_bounds_top (target->state);
632 configure_bounds_bottom (target->state);
633 configure_bounds_footer (target->state);
635 draw_margin_header (target);
638 static void
639 value_changed_footer_cb (gpointer user_data)
641 UnitInfo *target = user_data;
643 target->value = gtk_spin_button_get_value (target->spin);
645 configure_bounds_top (target->state);
646 configure_bounds_bottom (target->state);
647 configure_bounds_header (target->state);
649 draw_margin_footer (target);
652 static void
653 value_changed_top_cb (gpointer user_data)
655 UnitInfo *target = user_data;
657 target->value = gtk_spin_button_get_value (target->spin);
659 configure_bounds_header (target->state);
660 configure_bounds_bottom (target->state);
661 configure_bounds_footer (target->state);
663 draw_margin_top (target);
664 draw_margin_header (&target->state->margins.header);
668 static void
669 value_changed_bottom_cb (gpointer user_data)
671 UnitInfo *target = user_data;
673 target->value = gtk_spin_button_get_value (target->spin);
675 configure_bounds_header (target->state);
676 configure_bounds_top (target->state);
677 configure_bounds_footer (target->state);
679 draw_margin_bottom (target);
680 draw_margin_footer (&target->state->margins.footer);
683 static void
684 value_changed_left_cb (gpointer user_data)
686 UnitInfo *target = user_data;
688 target->value = gtk_spin_button_get_value (target->spin);
690 configure_bounds_right (target->state);
692 draw_margin_left (target);
695 static void
696 value_changed_right_cb (gpointer user_data)
698 UnitInfo *target = user_data;
700 target->value = gtk_spin_button_get_value (target->spin);
702 configure_bounds_left (target->state);
704 draw_margin_right (target);
707 static void
708 margin_spin_configure (UnitInfo *target, PrinterSetupState *state,
709 const char *spin_name,
710 void (*value_changed_cb) (gpointer user_data))
712 target->value = 0.;
713 target->pi = &state->preview;
714 target->spin = GTK_SPIN_BUTTON (go_gtk_builder_get_widget (state->gui, spin_name));
715 target->state = state;
716 gtk_spin_button_set_update_policy (target->spin, GTK_UPDATE_IF_VALID);
717 g_signal_connect_swapped (G_OBJECT (target->spin),
718 "value_changed",
719 G_CALLBACK (value_changed_cb), target);
720 g_signal_connect_swapped (G_OBJECT (target->spin),
721 "focus_in_event",
722 G_CALLBACK (cb_spin_activated), target);
723 g_signal_connect_swapped (G_OBJECT (target->spin),
724 "focus_out_event",
725 G_CALLBACK (cb_spin_deactivated), target);
728 static void
729 cb_unit_selector_changed (G_GNUC_UNUSED GtkComboBox *widget,
730 PrinterSetupState *state)
732 GtkTreeIter iter;
733 GtkUnit unit;
735 g_return_if_fail (state != NULL);
737 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (state->unit_selector), &iter)) {
738 gtk_tree_model_get (state->unit_model, &iter, 1, &unit, -1);
740 do_fetch_margins (state);
741 state->display_unit = unit;
742 do_update_page (state);
746 static gint
747 unit_sort_func (GtkTreeModel *model,
748 GtkTreeIter *a, GtkTreeIter *b,
749 G_GNUC_UNUSED gpointer user_data)
751 char *str_a;
752 char *str_b;
753 gint result;
755 gtk_tree_model_get (model, a, 0, &str_a, -1);
756 gtk_tree_model_get (model, b, 0, &str_b, -1);
758 result = g_utf8_collate (str_a, str_b);
760 g_free (str_a);
761 g_free (str_b);
762 return result;
767 * Header and footer are stored with Excel semantics, but displayed with
768 * more natural semantics. In Excel, both top margin and header are measured
769 * from top of sheet. The Gnumeric user interface presents header as the
770 * band between top margin and the print area. Bottom margin and footer are
771 * handled likewise. See illustration at top of src/print.c
773 static void
774 do_setup_margin (PrinterSetupState *state)
776 GtkWidget *grid, *container;
777 MarginPreviewPageAvailableSize margin_available_size;
780 GtkListStore *list_store;
781 GtkTreeIter iter;
782 GtkTreeIter current;
783 GtkCellRenderer *text_renderer;
785 list_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
787 gtk_list_store_append (list_store, &iter);
788 gtk_list_store_set (list_store, &iter, 0, (_("points")), 1, GTK_UNIT_POINTS, -1);
789 if (GTK_UNIT_POINTS == state->display_unit)
790 current = iter;
791 gtk_list_store_append (list_store, &iter);
792 gtk_list_store_set (list_store, &iter, 0, (_("inches")), 1, GTK_UNIT_INCH, -1);
793 if (GTK_UNIT_INCH == state->display_unit)
794 current = iter;
795 gtk_list_store_append (list_store, &iter);
796 gtk_list_store_set (list_store, &iter, 0, (_("mm")), 1, GTK_UNIT_MM, -1);
797 if (GTK_UNIT_MM == state->display_unit)
798 current = iter;
800 gtk_tree_sortable_set_default_sort_func
801 (GTK_TREE_SORTABLE (list_store),
802 unit_sort_func, NULL, NULL);
803 gtk_tree_sortable_set_sort_column_id
804 (GTK_TREE_SORTABLE (list_store),
805 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
806 GTK_SORT_ASCENDING);
808 state->unit_selector = gtk_combo_box_new_with_model (GTK_TREE_MODEL (list_store));
809 state->unit_model = GTK_TREE_MODEL (list_store);
810 text_renderer = gtk_cell_renderer_text_new ();
811 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(state->unit_selector),
812 text_renderer, TRUE);
813 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT(state->unit_selector),
814 text_renderer, "text", 0);
816 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (state->unit_selector), &current);
818 grid = go_gtk_builder_get_widget (state->gui, "paper-selector-grid");
819 gtk_widget_set_hexpand (state->unit_selector, TRUE);
820 gtk_grid_attach (GTK_GRID (grid), state->unit_selector, 3, 8, 1, 1);
822 g_signal_connect (G_OBJECT (state->unit_selector), "changed",
823 G_CALLBACK (cb_unit_selector_changed), state);
824 gtk_widget_show (state->unit_selector);
826 margin_preview_page_available_size (state, &margin_available_size);
828 g_return_if_fail (state && state->pi);
830 state->preview.canvas = GTK_WIDGET (g_object_new (GOC_TYPE_CANVAS, NULL));
831 gtk_widget_set_size_request (state->preview.canvas, margin_available_size.width, margin_available_size.height);
832 gtk_widget_show (state->preview.canvas);
834 margin_spin_configure (&state->margins.header, state, "spin-header",
835 value_changed_header_cb);
836 margin_spin_configure (&state->margins.footer, state, "spin-footer",
837 value_changed_footer_cb);
838 margin_spin_configure (&state->margins.top, state, "spin-top",
839 value_changed_top_cb);
840 margin_spin_configure (&state->margins.bottom, state, "spin-bottom",
841 value_changed_bottom_cb);
842 margin_spin_configure (&state->margins.left, state, "spin-left",
843 value_changed_left_cb);
844 margin_spin_configure (&state->margins.right, state, "spin-right",
845 value_changed_right_cb);
847 state->check_center_h = go_gtk_builder_get_widget (state->gui,
848 "check_center_h");
849 state->check_center_v = go_gtk_builder_get_widget (state->gui,
850 "check_center_v");
851 gtk_toggle_button_set_active (
852 GTK_TOGGLE_BUTTON (state->check_center_v),
853 state->pi->center_vertically == 1);
854 gtk_toggle_button_set_active (
855 GTK_TOGGLE_BUTTON (state->check_center_h),
856 state->pi->center_horizontally == 1);
858 container = go_gtk_builder_get_widget (state->gui,
859 "container-paper-sample");
860 gtk_container_add (GTK_CONTAINER (container), state->preview.canvas);
864 /* Display the header or footer preview in the print setup dialog.
865 * Use the canvas widget in the HFPreviewInfo struct.
868 static void
869 display_hf_preview (PrinterSetupState *state, gboolean header)
871 gchar *text = NULL;
872 GnmPrintHF *sample = NULL;
873 GnmPrintHFRenderInfo *hfi;
874 HFPreviewInfo *pi;
876 g_return_if_fail (state != NULL);
878 hfi = gnm_print_hf_render_info_new ();
880 hfi->page = 1;
881 hfi->pages = 99;
882 hfi->sheet = state->sheet;
884 if (header) {
885 pi = state->pi_header;
886 sample = state->header;
887 } else {
888 pi = state->pi_footer;
889 sample = state->footer;
892 text = gnm_print_hf_format_render (sample->left_format, hfi, HF_RENDER_PRINT);
893 goc_item_set (pi->left, "text", text ? text : "", NULL);
894 g_free (text);
896 text = gnm_print_hf_format_render (sample->middle_format, hfi, HF_RENDER_PRINT);
897 goc_item_set (pi->middle, "text", text ? text : "", NULL);
898 g_free (text);
900 text = gnm_print_hf_format_render (sample->right_format, hfi, HF_RENDER_PRINT);
901 goc_item_set (pi->right, "text", text ? text : "", NULL);
902 g_free (text);
904 gnm_print_hf_render_info_destroy (hfi);
907 static void
908 do_header_customize (PrinterSetupState *state)
910 do_hf_customize (TRUE, state);
913 static void
914 do_footer_customize (PrinterSetupState *state)
916 do_hf_customize (FALSE, state);
919 static void
920 header_changed (GtkComboBox *menu, PrinterSetupState *state)
922 GList *selection = g_list_nth (gnm_print_hf_formats,
923 gtk_combo_box_get_active (menu));
924 GnmPrintHF *format = (selection)? selection->data: NULL;
926 if (format == NULL) {
927 do_header_customize (state);
928 } else {
929 gnm_print_hf_free (state->header);
930 state->header = gnm_print_hf_copy (format);
933 display_hf_preview (state, TRUE);
936 static void
937 footer_changed (GtkComboBox *menu, PrinterSetupState *state)
939 GList *selection = g_list_nth (gnm_print_hf_formats,
940 gtk_combo_box_get_active (menu));
941 GnmPrintHF *format = (selection)? selection->data: NULL;
943 if (format == NULL) {
944 do_footer_customize (state);
945 } else {
946 gnm_print_hf_free (state->footer);
947 state->footer = gnm_print_hf_copy (format);
950 display_hf_preview (state, FALSE);
953 static char *
954 create_hf_name (char const *left, char const *middle, char const *right)
956 char *this, *res;
958 res = g_strdup_printf ("%s%s%s%s%s",
959 left," \xe2\x90\xa3 ", middle, " \xe2\x90\xa3 ", right);
961 this = res;
962 while (*this) {
963 if (*this == '\n') {
964 char *newstring;
965 *this = 0;
966 newstring = g_strconcat (res, "\xe2\x90\xa4", this + 1, NULL);
967 this = newstring + (this - res);
968 g_free (res);
969 res = newstring;
970 } else
971 this = g_utf8_find_next_char (this, NULL);
974 return res;
977 static void
978 append_hf_item (GtkListStore *store, GnmPrintHF *format, GnmPrintHFRenderInfo *hfi)
980 GtkTreeIter iter;
981 char *left, *middle, *right;
982 char *res;
984 left = gnm_print_hf_format_render (format->left_format, hfi, HF_RENDER_PRINT);
985 middle = gnm_print_hf_format_render (format->middle_format, hfi, HF_RENDER_PRINT);
986 right = gnm_print_hf_format_render (format->right_format, hfi, HF_RENDER_PRINT);
988 res = create_hf_name (left, middle, right);
990 gtk_list_store_append (store, &iter);
991 gtk_list_store_set (store, &iter,
992 0, res,
993 -1);
995 g_free (res);
996 g_free (left);
997 g_free (middle);
998 g_free (right);
1003 * Fills one of the GtkCombos for headers or footers with the list
1004 * of existing header/footer formats
1006 static void
1007 fill_hf (PrinterSetupState *state, GtkComboBox *om, GCallback callback, gboolean header)
1009 GList *l;
1010 GnmPrintHFRenderInfo *hfi;
1011 GtkListStore *store;
1012 GnmPrintHF *select = header ? state->header : state->footer;
1013 int i, idx = -1;
1015 hfi = gnm_print_hf_render_info_new ();
1016 hfi->page = 1;
1017 hfi->pages = 99;
1019 store = gtk_list_store_new (1, G_TYPE_STRING);
1020 gtk_combo_box_set_model (om, GTK_TREE_MODEL (store));
1021 g_object_unref (store);
1023 for (i = 0, l = gnm_print_hf_formats; l; l = l->next, i++) {
1024 GnmPrintHF *format = l->data;
1026 if (gnm_print_hf_same (format, select))
1027 idx = i;
1029 append_hf_item (store, format, hfi);
1032 if (idx < 0)
1033 g_critical ("Current format is not registered!");
1035 gtk_combo_box_set_active (om, idx);
1036 g_signal_connect (G_OBJECT (om), "changed", callback, state);
1038 gnm_print_hf_render_info_destroy (hfi);
1041 static void
1042 do_setup_hf_menus (PrinterSetupState *state)
1044 GtkComboBox *header;
1045 GtkComboBox *footer;
1047 g_return_if_fail (state != NULL);
1049 header = GTK_COMBO_BOX (go_gtk_builder_get_widget (state->gui, "option-menu-header"));
1050 footer = GTK_COMBO_BOX (go_gtk_builder_get_widget (state->gui, "option-menu-footer"));
1052 if (state->header)
1053 gnm_print_hf_register (state->header);
1054 if (state->footer)
1055 gnm_print_hf_register (state->footer);
1057 if (state->header)
1058 fill_hf (state, header, G_CALLBACK (header_changed), TRUE);
1059 if (state->footer)
1060 fill_hf (state, footer, G_CALLBACK (footer_changed), FALSE);
1063 /************* Header Footer Customization *********** Start *************/
1065 static void
1066 hf_delete_tag_cb (HFCustomizeState *hf_state)
1068 GtkWidget* focus;
1070 focus = gtk_window_get_focus (GTK_WINDOW (hf_state->dialog));
1072 if (GTK_IS_TEXT_VIEW (focus)) {
1073 GtkTextBuffer *textbuffer;
1074 GtkTextTag *tag;
1075 GtkTextIter start;
1076 GtkTextIter end;
1078 textbuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (focus));
1079 tag = gtk_text_tag_table_lookup (gtk_text_buffer_get_tag_table (textbuffer),
1080 HF_TAG_NAME);
1081 gtk_text_buffer_get_selection_bounds (textbuffer, &start, &end);
1083 if (gtk_text_iter_has_tag (&start, tag) && !gtk_text_iter_begins_tag (&start, tag))
1084 gtk_text_iter_backward_to_tag_toggle (&start, tag);
1085 if (gtk_text_iter_has_tag (&end, tag) && !gtk_text_iter_toggles_tag (&end, tag))
1086 gtk_text_iter_forward_to_tag_toggle (&end, tag);
1089 gtk_text_buffer_delete (textbuffer, &start, &end);
1094 static void
1095 hf_insert_hf_stock_tag (HFCustomizeState *hf_state, GtkTextBuffer *buffer,
1096 HFFieldType type, const char *options)
1098 GtkTextIter iter;
1099 gchar const *icon_name;
1100 GdkPixbuf* pix;
1101 GtkTextMark *new_mark;
1102 HFMarkInfo *mark_info;
1104 switch (type) {
1105 case HF_FIELD_FILE:
1106 icon_name = GTK_STOCK_FILE;
1107 break;
1108 case HF_FIELD_PATH:
1109 icon_name = "folder";
1110 break;
1111 case HF_FIELD_PAGE:
1112 icon_name = "gnumeric-pagesetup-hf-page";
1113 break;
1114 case HF_FIELD_PAGES:
1115 icon_name = "gnumeric-pagesetup-hf-pages";
1116 break;
1117 case HF_FIELD_DATE:
1118 icon_name = "gnumeric-pagesetup-hf-date";
1119 break;
1120 case HF_FIELD_TIME:
1121 icon_name = "gnumeric-pagesetup-hf-time";
1122 break;
1123 case HF_FIELD_SHEET:
1124 icon_name = "gnumeric-pagesetup-hf-sheet";
1125 break;
1126 case HF_FIELD_CELL:
1127 icon_name = "gnumeric-pagesetup-hf-cell";
1128 break;
1129 default:
1130 return;
1133 hf_delete_tag_cb (hf_state);
1135 if (gtk_text_buffer_insert_interactive_at_cursor
1136 (buffer, "", -1, TRUE)) {
1137 GtkWidget *w = GTK_WIDGET (wbcg_toplevel (hf_state->printer_setup_state->wbcg));
1139 gtk_text_buffer_get_iter_at_mark
1140 (buffer, &iter, gtk_text_buffer_get_insert (buffer));
1142 pix = go_gtk_widget_render_icon_pixbuf (w, icon_name, GTK_ICON_SIZE_BUTTON);
1143 gtk_text_buffer_insert_pixbuf (buffer, &iter, pix);
1144 g_object_unref (pix);
1145 gtk_text_iter_backward_char (&iter);
1146 new_mark = gtk_text_buffer_create_mark (buffer, NULL,
1147 &iter, FALSE);
1148 g_object_ref (new_mark);
1150 mark_info = g_new0 (HFMarkInfo, 1);
1151 mark_info->mark = new_mark;
1152 mark_info->type = type;
1153 mark_info->options = g_strdup (options);
1154 hf_state->marks = g_list_append (hf_state->marks, mark_info);
1158 static void
1159 hf_insert_hf_tag (HFCustomizeState *hf_state, HFFieldType type,
1160 const char *options)
1162 GtkWidget* focus;
1164 focus = gtk_window_get_focus (GTK_WINDOW (hf_state->dialog));
1166 if (GTK_IS_TEXT_VIEW (focus)) {
1167 GtkTextBuffer *buffer =
1168 gtk_text_view_get_buffer (GTK_TEXT_VIEW (focus));
1169 hf_insert_hf_stock_tag (hf_state, buffer, type, options);
1175 static void
1176 hf_insert_date_cb (GtkWidget *widget, HFCustomizeState *hf_state)
1179 hf_insert_hf_tag (hf_state, HF_FIELD_DATE,
1180 g_object_get_data (G_OBJECT (widget), "options"));
1183 static void
1184 hf_insert_custom_date_cb (G_GNUC_UNUSED GtkWidget *widget,
1185 HFCustomizeState *hf_state)
1187 char *format;
1189 format = do_hf_dt_format_customize (TRUE, hf_state);
1190 if (format != NULL) {
1191 hf_insert_hf_tag (hf_state, HF_FIELD_DATE, format);
1192 g_free (format);
1196 static void
1197 hf_insert_time_cb (GtkWidget *widget, HFCustomizeState *hf_state)
1199 hf_insert_hf_tag (hf_state, HF_FIELD_TIME,
1200 g_object_get_data (G_OBJECT (widget), "options"));
1203 static void
1204 hf_insert_custom_time_cb (G_GNUC_UNUSED GtkWidget *widget,
1205 HFCustomizeState *hf_state)
1207 char *format;
1209 format = do_hf_dt_format_customize (FALSE, hf_state);
1210 if (format != NULL) {
1211 hf_insert_hf_tag (hf_state, HF_FIELD_TIME, format);
1212 g_free (format);
1216 static void
1217 hf_insert_cell_cb (GtkWidget *widget, HFCustomizeState *hf_state)
1219 const char *options;
1220 options = g_object_get_data (G_OBJECT (widget), "options");
1221 if (options == NULL)
1222 options = "A1";
1223 hf_insert_hf_tag (hf_state, HF_FIELD_CELL, options);
1226 static void
1227 hf_insert_page_cb (HFCustomizeState *hf_state)
1229 hf_insert_hf_tag (hf_state, HF_FIELD_PAGE, NULL);
1232 static void
1233 hf_insert_pages_cb (HFCustomizeState *hf_state)
1235 hf_insert_hf_tag (hf_state, HF_FIELD_PAGES, NULL);
1238 static void
1239 hf_insert_sheet_cb (HFCustomizeState *hf_state)
1241 hf_insert_hf_tag (hf_state, HF_FIELD_SHEET, NULL);
1244 static void
1245 hf_insert_file_cb (HFCustomizeState *hf_state)
1247 hf_insert_hf_tag (hf_state, HF_FIELD_FILE, NULL);
1250 static void
1251 hf_insert_path_cb (HFCustomizeState *hf_state)
1253 hf_insert_hf_tag (hf_state, HF_FIELD_PATH, NULL);
1256 static void
1257 buffer_delete_range_cb (GtkTextBuffer *textbuffer,
1258 GtkTextIter *start,
1259 GtkTextIter *end,
1260 HFCustomizeState *hf_state)
1262 GtkTextTag *tag;
1263 GtkTextIter iter;
1264 GList *l = hf_state->marks;
1266 tag = gtk_text_tag_table_lookup (gtk_text_buffer_get_tag_table (textbuffer),
1267 HF_TAG_NAME);
1268 gtk_text_iter_order (start, end);
1270 if (gtk_text_iter_has_tag (start, tag) && !gtk_text_iter_begins_tag (start, tag))
1271 gtk_text_iter_backward_to_tag_toggle (start, tag);
1272 if (gtk_text_iter_has_tag (end, tag) && !gtk_text_iter_toggles_tag (end, tag))
1273 gtk_text_iter_forward_to_tag_toggle (end, tag);
1275 /* Deleting all of our marks from this range */
1276 while (l) {
1277 HFMarkInfo *info = l->data;
1279 if (gtk_text_mark_get_buffer (info->mark) == textbuffer) {
1280 gtk_text_buffer_get_iter_at_mark (textbuffer, &iter, info->mark);
1281 if (gtk_text_iter_in_range (&iter, start, end))
1282 gtk_text_buffer_delete_mark (textbuffer, info->mark);
1284 l = l->next;
1288 static int
1289 mark_info_compare (HFMarkInfo *a, HFMarkInfo *b)
1291 GtkTextIter iter_a, iter_b;
1292 GtkTextBuffer *buffer;
1294 buffer = gtk_text_mark_get_buffer (a->mark);
1295 gtk_text_buffer_get_iter_at_mark (buffer, &iter_a, a->mark);
1296 gtk_text_buffer_get_iter_at_mark (buffer, &iter_b, b->mark);
1298 return gtk_text_iter_compare (&iter_a, &iter_b);
1301 static void
1302 append_tag_descriptor (GString* string, HFFieldType type, char const *options)
1304 char const *code;
1306 switch (type) {
1307 case HF_FIELD_FILE:
1308 code = "&[FILE";
1309 break;
1310 case HF_FIELD_PATH:
1311 code = "&[PATH";
1312 break;
1313 case HF_FIELD_DATE:
1314 code = "&[DATE";
1315 break;
1316 case HF_FIELD_TIME:
1317 code = "&[TIME";
1318 break;
1319 case HF_FIELD_PAGE:
1320 code = "&[PAGE";
1321 break;
1322 case HF_FIELD_PAGES:
1323 code = "&[PAGES";
1324 break;
1325 case HF_FIELD_SHEET:
1326 code = "&[TAB";
1327 break;
1328 case HF_FIELD_CELL:
1329 code = "&[CELL";
1330 break;
1331 default:
1332 return;
1335 g_string_append (string, code);
1336 if (options) {
1337 g_string_append_c (string, ':');
1338 g_string_append (string, options);
1340 g_string_append_c (string, ']');
1343 static char *
1344 text_get (HFCustomizeState *hf_state, GtkTextBuffer *buffer)
1346 GtkTextIter start;
1347 GtkTextIter end;
1348 GList *l, *sorted_marks = NULL;
1349 gchar *text;
1350 GString* string;
1352 string = g_string_new ("");
1354 l = hf_state->marks;
1355 while (l) {
1356 HFMarkInfo *m = l->data;
1357 if (gtk_text_mark_get_buffer (m->mark) == buffer)
1358 sorted_marks = g_list_insert_sorted
1359 (sorted_marks, m, (GCompareFunc) mark_info_compare);
1360 l = l->next;
1363 gtk_text_buffer_get_bounds (buffer, &start, &end);
1365 l = sorted_marks;
1366 while (l) {
1367 HFMarkInfo *m = l->data;
1368 GtkTextIter mark_position;
1370 gtk_text_buffer_get_iter_at_mark (buffer, &mark_position, m->mark);
1371 text = gtk_text_buffer_get_text (buffer, &start, &mark_position, FALSE);
1372 g_string_append (string, text);
1373 g_free (text);
1374 append_tag_descriptor (string, m->type, m->options);
1375 start = mark_position;
1376 l = l->next;
1378 g_list_free (sorted_marks);
1379 text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
1380 g_string_append (string, text);
1381 g_free (text);
1383 return g_string_free (string, FALSE);
1386 static void
1387 hf_customize_apply (HFCustomizeState *hf_state)
1389 char *left_format, *right_format, *middle_format;
1391 g_return_if_fail (hf_state != NULL);
1393 left_format = text_get (hf_state, hf_state->left_buffer);
1394 middle_format = text_get (hf_state, hf_state->middle_buffer);
1395 right_format = text_get (hf_state, hf_state->right_buffer);
1397 gnm_print_hf_free (*(hf_state->hf));
1398 *(hf_state->hf) = gnm_print_hf_new (left_format, middle_format, right_format);
1400 g_free (left_format);
1401 g_free (middle_format);
1402 g_free (right_format);
1404 gnm_print_hf_register (*(hf_state->hf));
1405 do_setup_hf_menus (hf_state->printer_setup_state);
1406 display_hf_preview (hf_state->printer_setup_state, hf_state->is_header);
1408 gtk_text_buffer_set_modified (hf_state->left_buffer, FALSE);
1409 gtk_text_buffer_set_modified (hf_state->middle_buffer, FALSE);
1410 gtk_text_buffer_set_modified (hf_state->right_buffer, FALSE);
1412 gtk_widget_set_sensitive (go_gtk_builder_get_widget (hf_state->gui, "apply_button"), FALSE);
1413 gtk_widget_set_sensitive (go_gtk_builder_get_widget (hf_state->gui, "ok_button"), FALSE);
1417 static void
1418 hf_customize_ok (HFCustomizeState *hf_state)
1420 hf_customize_apply (hf_state);
1421 gtk_widget_destroy (hf_state->dialog);
1424 static gboolean
1425 cb_hf_changed (GtkBuilder *gui)
1427 gtk_widget_set_sensitive (go_gtk_builder_get_widget (gui, "apply_button"), TRUE);
1428 gtk_widget_set_sensitive (go_gtk_builder_get_widget (gui, "ok_button"), TRUE);
1429 return FALSE;
1433 static void
1434 add_named_tags (GtkTextBuffer *buffer)
1436 GtkTextTag *tag;
1438 tag = gtk_text_tag_new (HF_TAG_NAME);
1439 g_object_set(tag,
1440 "editable", FALSE,
1441 "underline", TRUE,
1442 "underline-set", TRUE,
1443 "weight", PANGO_WEIGHT_BOLD,
1444 "weight-set", TRUE,
1445 "stretch", PANGO_STRETCH_CONDENSED,
1446 "stretch-set", TRUE,
1447 NULL);
1449 gtk_text_tag_table_add (gtk_text_buffer_get_tag_table (buffer), tag);
1452 static gboolean
1453 check_hf_tag (char const *unknown_tag, char const *known_tag, gchar **options, gint length)
1455 int len;
1456 char const *closing = unknown_tag + length;
1458 if (0 != g_ascii_strncasecmp (unknown_tag, "&[", 2))
1459 return FALSE;
1460 unknown_tag += 2;
1461 len = strlen (known_tag);
1462 if (0 != g_ascii_strncasecmp (unknown_tag, known_tag, len))
1463 return FALSE;
1464 unknown_tag += len;
1465 if (*unknown_tag == ']')
1466 return TRUE;
1467 if (*unknown_tag != ':')
1468 return FALSE;
1469 unknown_tag++;
1470 len = closing - unknown_tag - 1;
1471 if ((len > 0) && (options != NULL)) {
1472 *options = g_strndup (unknown_tag, len);
1474 return TRUE;
1477 static gboolean
1478 is_known_tag (HFCustomizeState* hf_state, GtkTextBuffer *buffer, char const *tag, gint length)
1480 gchar *options = NULL;
1482 if (check_hf_tag (tag, "FILE", &options, length))
1483 hf_insert_hf_stock_tag (hf_state, buffer, HF_FIELD_FILE, options);
1484 else if (check_hf_tag (tag, "PATH", &options, length))
1485 hf_insert_hf_stock_tag (hf_state, buffer, HF_FIELD_PATH, options);
1486 else if (check_hf_tag (tag, "PAGES", &options, length))
1487 hf_insert_hf_stock_tag (hf_state, buffer, HF_FIELD_PAGES, options);
1488 else if (check_hf_tag (tag, "PAGE", &options, length))
1489 hf_insert_hf_stock_tag (hf_state, buffer, HF_FIELD_PAGE, options);
1490 else if (check_hf_tag (tag, "TAB", &options, length))
1491 hf_insert_hf_stock_tag (hf_state, buffer, HF_FIELD_SHEET, options);
1492 else if (check_hf_tag (tag, "DATE", &options, length))
1493 hf_insert_hf_stock_tag (hf_state, buffer, HF_FIELD_DATE, options);
1494 else if (check_hf_tag (tag, "TIME", &options, length))
1495 hf_insert_hf_stock_tag (hf_state, buffer, HF_FIELD_TIME, options);
1496 else if (check_hf_tag (tag, "CELL", &options, length))
1497 hf_insert_hf_stock_tag (hf_state, buffer, HF_FIELD_CELL, options);
1498 else
1499 return FALSE;
1501 g_free (options);
1503 return TRUE;
1506 static void
1507 add_text_to_buffer (HFCustomizeState* hf_state, GtkTextBuffer *buffer, char const *text)
1509 gchar const *here = text, *end;
1510 gunichar closing = g_utf8_get_char ("]");
1511 gunichar ambersand = g_utf8_get_char ("&");
1512 GtkTextIter iter;
1514 g_return_if_fail (here != NULL);
1516 while (*here) {
1517 if (here[0] == '&' && here[1] == '[') {
1518 end = g_utf8_strchr (here, -1, closing);
1519 if (end == NULL) {
1520 gtk_text_buffer_insert (buffer, &iter, here, -1);
1521 break;
1522 } else {
1523 if (!is_known_tag ( hf_state, buffer, here, end - here + 1)) {
1524 gtk_text_buffer_get_end_iter (buffer, &iter);
1525 gtk_text_buffer_insert_with_tags_by_name
1526 (buffer, &iter, here, end - here + 1,
1527 HF_TAG_NAME, NULL);
1529 here = end + 1;
1531 } else {
1532 end = g_utf8_strchr (g_utf8_find_next_char (here, NULL),
1533 -1, ambersand);
1534 gtk_text_buffer_get_end_iter (buffer, &iter);
1535 if (end == NULL) {
1536 gtk_text_buffer_insert (buffer, &iter, here, -1);
1537 break;
1538 } else {
1539 gtk_text_buffer_insert (buffer, &iter, here, end - here);
1540 here = end;
1545 gtk_text_buffer_set_modified (buffer, FALSE);
1548 static void
1549 free_hf_mark_info (HFMarkInfo *info)
1551 if (info->mark)
1552 g_object_unref (info->mark);
1553 g_free (info->options);
1554 g_free (info);
1557 static void
1558 free_hf_state (HFCustomizeState *hf_state)
1560 g_return_if_fail (hf_state != NULL);
1562 g_list_free_full (hf_state->marks, (GDestroyNotify) free_hf_mark_info);
1563 g_free (hf_state);
1566 static void
1567 hf_attach_insert_date_menu (GtkMenuToolButton *button, HFCustomizeState* hf_state)
1569 GtkWidget *menu = NULL;
1570 GtkWidget *item = NULL;
1572 g_signal_connect
1573 (G_OBJECT (button),
1574 "clicked", G_CALLBACK (hf_insert_date_cb), hf_state);
1576 menu = gtk_menu_new ();
1578 item = gtk_menu_item_new_with_label (_("Default date format"));
1579 g_signal_connect
1580 (G_OBJECT (item),
1581 "activate", G_CALLBACK (hf_insert_date_cb), hf_state);
1582 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1584 item = gtk_menu_item_new_with_label (_("Custom date format"));
1585 g_signal_connect
1586 (G_OBJECT (item),
1587 "activate", G_CALLBACK (hf_insert_custom_date_cb), hf_state);
1588 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1590 item = gtk_separator_menu_item_new ();
1591 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1593 item = gtk_menu_item_new_with_label (("YYYY/MM/DD"));
1594 g_signal_connect
1595 (G_OBJECT (item),
1596 "activate", G_CALLBACK (hf_insert_date_cb), hf_state);
1597 g_object_set_data_full (G_OBJECT (item), "options", g_strdup("YYYY/MM/DD"), g_free);
1598 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1600 gtk_menu_tool_button_set_menu (button, menu);
1601 gtk_widget_show_all (menu);
1604 static void
1605 hf_attach_insert_time_menu (GtkMenuToolButton *button, HFCustomizeState* hf_state)
1607 GtkWidget *menu = NULL;
1608 GtkWidget *item = NULL;
1610 g_signal_connect
1611 (G_OBJECT (button),
1612 "clicked", G_CALLBACK (hf_insert_time_cb), hf_state);
1614 menu = gtk_menu_new ();
1616 item = gtk_menu_item_new_with_label (_("Default time format"));
1617 g_signal_connect
1618 (G_OBJECT (item),
1619 "activate", G_CALLBACK (hf_insert_time_cb), hf_state);
1620 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1622 item = gtk_menu_item_new_with_label (_("Custom time format"));
1623 g_signal_connect
1624 (G_OBJECT (item),
1625 "activate", G_CALLBACK (hf_insert_custom_time_cb), hf_state);
1626 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1628 item = gtk_separator_menu_item_new ();
1629 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1631 item = gtk_menu_item_new_with_label (("HH:MM:SS"));
1632 g_signal_connect
1633 (G_OBJECT (item),
1634 "activate", G_CALLBACK (hf_insert_time_cb), hf_state);
1635 g_object_set_data_full (G_OBJECT (item), "options", g_strdup("HH:MM:SS"), g_free);
1636 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1638 gtk_menu_tool_button_set_menu (button, menu);
1639 gtk_widget_show_all (menu);
1642 static void
1643 hf_attach_insert_cell_menu (GtkMenuToolButton *button, HFCustomizeState* hf_state)
1645 GtkWidget *menu = NULL;
1646 GtkWidget *item = NULL;
1648 g_signal_connect
1649 (G_OBJECT (button),
1650 "clicked", G_CALLBACK (hf_insert_cell_cb), hf_state);
1652 menu = gtk_menu_new ();
1654 item = gtk_menu_item_new_with_label (_("A1 (first cell of the page area)"));
1655 g_signal_connect
1656 (G_OBJECT (item),
1657 "activate", G_CALLBACK (hf_insert_cell_cb), hf_state);
1658 g_object_set_data_full (G_OBJECT (item), "options", g_strdup("A1"), g_free);
1659 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1661 item = gtk_menu_item_new_with_label (_("$A$1 (first cell of this worksheet)"));
1662 g_signal_connect
1663 (G_OBJECT (item),
1664 "activate", G_CALLBACK (hf_insert_cell_cb), hf_state);
1665 g_object_set_data_full (G_OBJECT (item), "options", g_strdup("$A$1"), g_free);
1666 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1668 item = gtk_menu_item_new_with_label (_("First Printed Cell Of The Page"));
1669 g_signal_connect
1670 (G_OBJECT (item),
1671 "activate", G_CALLBACK (hf_insert_cell_cb), hf_state);
1672 g_object_set_data_full (G_OBJECT (item), "options", g_strdup("rep|A1"), g_free);
1673 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1675 gtk_menu_tool_button_set_menu (button, menu);
1676 gtk_widget_show_all (menu);
1679 static void
1680 cb_hf_destroyed (GObject *obj) {
1681 g_object_set_data (obj, "gui", NULL);
1685 * Open up a DIALOG to allow the user to customize the header
1686 * or the footer.
1688 static void
1689 do_hf_customize (gboolean header, PrinterSetupState *state)
1691 GtkBuilder *gui;
1692 GtkTextView *left, *middle, *right;
1693 GtkTextBuffer *left_buffer, *middle_buffer, *right_buffer;
1695 GtkWidget *dialog;
1696 HFCustomizeState* hf_state;
1697 GtkToolButton *button;
1699 /* Check if this dialog isn't already created. */
1700 if (header)
1701 dialog = state->customize_header;
1702 else
1703 dialog = state->customize_footer;
1705 if (dialog != NULL) {
1706 gdk_window_show (gtk_widget_get_window (dialog));
1707 gdk_window_raise (gtk_widget_get_window (dialog));
1708 return;
1711 gui = gnm_gtk_builder_load ("res:ui/hf-config.ui", NULL, GO_CMD_CONTEXT (state->wbcg));
1712 if (gui == NULL)
1713 return;
1715 hf_state = g_new0 (HFCustomizeState, 1);
1716 hf_state->gui = gui;
1717 hf_state->printer_setup_state = state;
1718 hf_state->is_header = header;
1720 left = GTK_TEXT_VIEW (go_gtk_builder_get_widget (gui, "left-format"));
1721 middle = GTK_TEXT_VIEW (go_gtk_builder_get_widget (gui, "middle-format"));
1722 right = GTK_TEXT_VIEW (go_gtk_builder_get_widget (gui, "right-format"));
1724 dialog = go_gtk_builder_get_widget (gui, "hf-config");
1725 hf_state->dialog = dialog;
1727 if (header) {
1728 hf_state->hf = &state->header;
1729 state->customize_header = dialog;
1730 gtk_window_set_title (GTK_WINDOW (dialog), _("Custom header configuration"));
1732 } else {
1733 hf_state->hf = &state->footer;
1734 state->customize_footer = dialog;
1735 gtk_window_set_title (GTK_WINDOW (dialog), _("Custom footer configuration"));
1738 hf_state->left_buffer = left_buffer = gtk_text_view_get_buffer (left);
1739 hf_state->middle_buffer = middle_buffer = gtk_text_view_get_buffer (middle);
1740 hf_state->right_buffer = right_buffer = gtk_text_view_get_buffer (right);
1742 add_named_tags (left_buffer);
1743 add_named_tags (middle_buffer);
1744 add_named_tags (right_buffer);
1746 add_text_to_buffer (hf_state, left_buffer, (*(hf_state->hf))->left_format);
1747 add_text_to_buffer (hf_state, middle_buffer, (*(hf_state->hf))->middle_format);
1748 add_text_to_buffer (hf_state, right_buffer, (*(hf_state->hf))->right_format);
1750 g_signal_connect (G_OBJECT (left_buffer), "delete-range",
1751 G_CALLBACK (buffer_delete_range_cb), hf_state);
1752 g_signal_connect (G_OBJECT (middle_buffer), "delete-range",
1753 G_CALLBACK (buffer_delete_range_cb), hf_state);
1754 g_signal_connect (G_OBJECT (right_buffer), "delete-range",
1755 G_CALLBACK (buffer_delete_range_cb), hf_state);
1757 g_signal_connect_swapped (G_OBJECT (go_gtk_builder_get_widget (gui, "apply_button")),
1758 "clicked", G_CALLBACK (hf_customize_apply), hf_state);
1759 g_signal_connect_swapped (G_OBJECT (go_gtk_builder_get_widget (gui, "ok_button")),
1760 "clicked", G_CALLBACK (hf_customize_ok), hf_state);
1761 g_signal_connect_swapped
1762 (G_OBJECT (go_gtk_builder_get_widget (gui, "cancel_button")),
1763 "clicked", G_CALLBACK (gtk_widget_destroy), dialog);
1764 gtk_widget_set_sensitive (go_gtk_builder_get_widget (gui, "apply_button"), FALSE);
1765 gtk_widget_set_sensitive (go_gtk_builder_get_widget (gui, "ok_button"), FALSE);
1767 if (header)
1768 g_signal_connect (G_OBJECT (dialog), "destroy",
1769 G_CALLBACK (gtk_widget_destroyed),
1770 &state->customize_header);
1771 else
1772 g_signal_connect (G_OBJECT (dialog), "destroy",
1773 G_CALLBACK (gtk_widget_destroyed),
1774 &state->customize_footer);
1777 g_object_set_data_full (G_OBJECT (dialog),
1778 "hfstate", hf_state, (GDestroyNotify) free_hf_state);
1780 /* Setup bindings to mark when the entries are modified. */
1781 g_signal_connect_swapped (G_OBJECT (left_buffer),
1782 "modified-changed", G_CALLBACK (cb_hf_changed), gui);
1783 g_signal_connect_swapped (G_OBJECT (middle_buffer),
1784 "modified-changed", G_CALLBACK (cb_hf_changed), gui);
1785 g_signal_connect_swapped (G_OBJECT (right_buffer),
1786 "modified-changed", G_CALLBACK (cb_hf_changed), gui);
1788 gnm_init_help_button (go_gtk_builder_get_widget (gui, "help_button"),
1789 header ? GNUMERIC_HELP_LINK_PRINTER_SETUP_HEADER_CUSTOMIZATION
1790 : GNUMERIC_HELP_LINK_PRINTER_SETUP_FOOTER_CUSTOMIZATION);
1792 g_signal_connect_swapped
1793 (G_OBJECT (go_gtk_builder_get_widget (gui, "delete-button")),
1794 "clicked", G_CALLBACK (hf_delete_tag_cb), hf_state);
1796 button = GTK_TOOL_BUTTON (go_gtk_builder_get_widget (gui, "insert-date-button"));
1797 gtk_tool_button_set_icon_name (button, "gnumeric-pagesetup-hf-date");
1798 hf_attach_insert_date_menu (GTK_MENU_TOOL_BUTTON (button), hf_state);
1800 button = GTK_TOOL_BUTTON (go_gtk_builder_get_widget (gui, "insert-page-button"));
1801 gtk_tool_button_set_icon_name (button, "gnumeric-pagesetup-hf-page");
1802 g_signal_connect_swapped
1803 (G_OBJECT (button),
1804 "clicked", G_CALLBACK (hf_insert_page_cb), hf_state);
1806 button = GTK_TOOL_BUTTON (go_gtk_builder_get_widget (gui, "insert-pages-button"));
1807 gtk_tool_button_set_icon_name (button, "gnumeric-pagesetup-hf-pages");
1808 g_signal_connect_swapped
1809 (G_OBJECT (button),
1810 "clicked", G_CALLBACK (hf_insert_pages_cb), hf_state);
1812 button = GTK_TOOL_BUTTON (go_gtk_builder_get_widget (gui, "insert-sheet-button"));
1813 gtk_tool_button_set_icon_name (button, "gnumeric-pagesetup-hf-sheet");
1814 g_signal_connect_swapped
1815 (G_OBJECT (button),
1816 "clicked", G_CALLBACK (hf_insert_sheet_cb), hf_state);
1818 button = GTK_TOOL_BUTTON (go_gtk_builder_get_widget (gui, "insert-time-button"));
1819 gtk_tool_button_set_icon_name (button, "gnumeric-pagesetup-hf-time");
1820 hf_attach_insert_time_menu (GTK_MENU_TOOL_BUTTON (button), hf_state);
1822 g_signal_connect_swapped
1823 (G_OBJECT (go_gtk_builder_get_widget (gui, "insert-file-button")),
1824 "clicked", G_CALLBACK (hf_insert_file_cb), hf_state);
1826 g_signal_connect_swapped
1827 (G_OBJECT (go_gtk_builder_get_widget (gui, "insert-path-button")),
1828 "clicked", G_CALLBACK (hf_insert_path_cb), hf_state);
1830 button = GTK_TOOL_BUTTON (go_gtk_builder_get_widget (gui, "insert-cell-button"));
1831 gtk_tool_button_set_icon_name (button, "gnumeric-pagesetup-hf-cell");
1832 hf_attach_insert_cell_menu (GTK_MENU_TOOL_BUTTON (button), hf_state);
1835 /* Let them begin typing into the first entry widget. */
1836 gtk_widget_grab_focus (GTK_WIDGET (left));
1838 gtk_window_set_transient_for (GTK_WINDOW (dialog),
1839 GTK_WINDOW (state->dialog));
1841 /* The following would cause the dialog to be below the page setup dialog: */
1842 /* go_gtk_window_set_transient (GTK_WINDOW (dialog), GTK_WINDOW (state->dialog)); */
1844 g_object_set_data_full (G_OBJECT (dialog), "gui", gui, g_object_unref);
1845 g_signal_connect (G_OBJECT (dialog), "destroy", G_CALLBACK (cb_hf_destroyed), NULL);
1847 gtk_widget_show_all (dialog);
1850 /************* Header Footer Customization *********** End *************/
1852 /************* Date/Time Format Customization ******** Start ***********/
1854 static void
1855 hf_dt_customize_ok (HFDTFormatState *hf_dt_state)
1857 GOFormat const *format =
1858 go_format_sel_get_fmt (GO_FORMAT_SEL (hf_dt_state->format_sel));
1859 hf_dt_state->format_string = g_strdup (go_format_as_XL (format));
1862 static char *
1863 do_hf_dt_format_customize (gboolean date, HFCustomizeState *hf_state)
1865 GtkBuilder *gui;
1867 GtkWidget *dialog, *format_sel, *grid;
1868 HFDTFormatState* hf_dt_state;
1869 gint result;
1870 char *result_string = NULL;
1872 gui = gnm_gtk_builder_load ("res:ui/hf-dt-format.ui", NULL,
1873 GO_CMD_CONTEXT (hf_state->printer_setup_state->wbcg));
1874 if (gui == NULL)
1875 return NULL;
1877 hf_dt_state = g_new0 (HFDTFormatState, 1);
1878 hf_dt_state->gui = gui;
1879 hf_dt_state->hf_state = hf_state;
1880 hf_dt_state->format_string = NULL;
1882 dialog = go_gtk_builder_get_widget (gui, "hf-dt-format");
1883 hf_dt_state->dialog = dialog;
1885 if (date) {
1886 gtk_window_set_title (GTK_WINDOW (dialog), _("Date format selection"));
1887 } else {
1888 gtk_window_set_title (GTK_WINDOW (dialog), _("Time format selection"));
1891 g_signal_connect_swapped (G_OBJECT (go_gtk_builder_get_widget (gui, "ok_button")),
1892 "clicked", G_CALLBACK (hf_dt_customize_ok), hf_dt_state);
1894 g_object_set_data_full (G_OBJECT (dialog),
1895 "hfdtstate", hf_dt_state, (GDestroyNotify) g_free);
1897 gnm_init_help_button (go_gtk_builder_get_widget (gui, "help_button"),
1898 GNUMERIC_HELP_LINK_PRINTER_SETUP_GENERAL);
1900 grid = go_gtk_builder_get_widget (gui, "layout-grid");
1901 if (grid == NULL) { /* how can this happen? */
1902 gtk_widget_destroy (dialog);
1903 return NULL;
1905 hf_dt_state->format_sel = format_sel = go_format_sel_new_full (TRUE);
1906 go_format_sel_set_style_format
1907 (GO_FORMAT_SEL (format_sel),
1908 date ? go_format_default_date () : go_format_default_time ());
1910 gtk_widget_show_all (dialog);
1911 gtk_grid_attach (GTK_GRID (grid), format_sel, 0, 1, 2, 1);
1912 gtk_widget_show (format_sel);
1914 result = gtk_dialog_run (GTK_DIALOG (dialog));
1915 switch (result)
1917 case GTK_RESPONSE_OK:
1918 result_string = hf_dt_state->format_string;
1919 break;
1920 default:
1921 gtk_widget_destroy (dialog);
1922 return NULL;
1924 gtk_widget_destroy (dialog);
1925 g_object_unref (hf_dt_state->gui);
1926 hf_dt_state->gui = NULL;
1927 return result_string;
1932 /************* Date/Time Format Customization ******** End *************/
1934 /* header/footer_preview_event
1935 * If the user double clicks on a header/footer preview canvas, we will
1936 * open up the dialog to modify the header or footer.
1937 * They can also do this from the option menu.
1939 static gboolean
1940 header_preview_event (G_GNUC_UNUSED GocCanvas *canvas,
1941 GdkEvent *event, PrinterSetupState *state)
1943 if (event == NULL ||
1944 event->type != GDK_2BUTTON_PRESS ||
1945 event->button.button != 1)
1946 return FALSE;
1947 do_hf_customize (TRUE, state);
1948 return TRUE;
1951 static gboolean
1952 footer_preview_event (G_GNUC_UNUSED GocCanvas *canvas,
1953 GdkEvent *event, PrinterSetupState *state)
1955 if (event == NULL ||
1956 event->type != GDK_2BUTTON_PRESS ||
1957 event->button.button != 1)
1958 return FALSE;
1959 do_hf_customize (FALSE, state);
1960 return TRUE;
1963 /* create_hf_preview_canvas
1964 * Creates the canvas to do a header or footer preview in the print setup.
1967 static void
1968 create_hf_preview_canvas (PrinterSetupState *state, gboolean header)
1970 GtkWidget *wid;
1971 HFPreviewInfo *pi;
1972 PangoFontDescription *font_desc;
1973 GnmStyle *style;
1974 gdouble width = HF_PREVIEW_X;
1975 gdouble height = HF_PREVIEW_Y;
1976 gdouble shadow = HF_PREVIEW_SHADOW;
1977 gdouble padding = HF_PREVIEW_PADDING;
1978 gdouble margin = HF_PREVIEW_MARGIN;
1979 gdouble bottom_margin = height - margin;
1980 GOStyle *gostyle;
1982 pi = g_new (HFPreviewInfo, 1);
1984 if (header)
1985 state->pi_header = pi;
1986 else
1987 state->pi_footer = pi;
1989 pi->canvas = GTK_WIDGET (g_object_new (GOC_TYPE_CANVAS, NULL));
1991 gostyle = go_styled_object_get_style (
1992 GO_STYLED_OBJECT (goc_item_new (goc_canvas_get_root (GOC_CANVAS (pi->canvas)),
1993 GOC_TYPE_RECTANGLE,
1994 "x", 1. + shadow,
1995 "y", (header ? shadow : 0.),
1996 "width", width,
1997 "height", height + (header ? -shadow: shadow),
1998 NULL)));
1999 gostyle->fill.pattern.back = GO_COLOR_BLACK;
2000 gostyle->line.width = 0.;
2001 gostyle->line.color = 0;
2003 gostyle = go_styled_object_get_style (
2004 GO_STYLED_OBJECT (goc_item_new (goc_canvas_get_root (GOC_CANVAS (pi->canvas)),
2005 GOC_TYPE_RECTANGLE,
2006 "x", 1.0,
2007 "y", (header? 1.0: 0.),
2008 "width", width,
2009 "height", height,
2010 NULL)));
2011 gostyle->fill.pattern.back = GO_COLOR_WHITE;
2012 gostyle->line.width = 0.;
2013 gostyle->line.color = 0;
2015 style = gnm_conf_get_printer_decoration_font ();
2016 font_desc = pango_font_description_new ();
2017 pango_font_description_set_family (font_desc, gnm_style_get_font_name (style));
2018 pango_font_description_set_style
2019 (font_desc, gnm_style_get_font_italic (style) ?
2020 PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
2021 pango_font_description_set_variant (font_desc, PANGO_VARIANT_NORMAL);
2022 pango_font_description_set_weight (font_desc, PANGO_WEIGHT_NORMAL);
2023 pango_font_description_set_size (font_desc, 8 * PANGO_SCALE);
2024 gnm_style_unref (style);
2026 pi->left = goc_item_new (
2027 goc_canvas_get_root (GOC_CANVAS (pi->canvas)),
2028 goc_text_get_type (),
2029 "x", padding,
2030 "y", header ? margin : bottom_margin,
2031 "anchor", header ? GO_ANCHOR_NORTH_WEST : GO_ANCHOR_SOUTH_WEST,
2032 "text", "Left",
2033 NULL);
2034 gostyle = go_styled_object_get_style (GO_STYLED_OBJECT (pi->left));
2035 go_style_set_font_desc (gostyle, pango_font_description_copy (font_desc));
2037 pi->middle = goc_item_new (
2038 goc_canvas_get_root (GOC_CANVAS (pi->canvas)),
2039 goc_text_get_type (),
2040 "x", width / 2,
2041 "y", header ? margin : bottom_margin,
2042 "anchor", header ? GO_ANCHOR_NORTH : GO_ANCHOR_SOUTH,
2043 "text", "Center",
2044 NULL);
2045 gostyle = go_styled_object_get_style (GO_STYLED_OBJECT (pi->left));
2046 go_style_set_font_desc (gostyle, pango_font_description_copy (font_desc));
2048 pi->right = goc_item_new (
2049 goc_canvas_get_root (GOC_CANVAS (pi->canvas)),
2050 goc_text_get_type (),
2051 "x", width - padding,
2052 "y", header ? margin : bottom_margin,
2053 "anchor", header ? GO_ANCHOR_NORTH_EAST : GO_ANCHOR_SOUTH_EAST,
2054 "text", "Right",
2055 NULL);
2056 gostyle = go_styled_object_get_style (GO_STYLED_OBJECT (pi->left));
2057 go_style_set_font_desc (gostyle, pango_font_description_copy (font_desc));
2059 pango_font_description_free (font_desc);
2061 gtk_widget_show_all (pi->canvas);
2063 if (header) {
2064 g_signal_connect (G_OBJECT (pi->canvas),
2065 "event",
2066 G_CALLBACK (header_preview_event), state);
2067 wid = go_gtk_builder_get_widget (state->gui, "container-header-sample");
2068 } else {
2069 g_signal_connect (G_OBJECT (pi->canvas),
2070 "event",
2071 G_CALLBACK (footer_preview_event), state);
2072 wid = go_gtk_builder_get_widget (state->gui, "container-footer-sample");
2074 gtk_widget_set_size_request (pi->canvas, width + shadow + 1, height + (header ? 1: shadow));
2076 gtk_container_add (GTK_CONTAINER (wid), GTK_WIDGET (pi->canvas));
2080 * Setup the widgets for the header and footer tab.
2082 * Creates the two preview canvas's for the header and footer.
2084 static void
2085 do_setup_hf (PrinterSetupState *state)
2087 GtkComboBox *header;
2088 GtkComboBox *footer;
2089 GtkCellRenderer *renderer;
2090 GtkWidget *w;
2092 g_return_if_fail (state != NULL);
2094 header = GTK_COMBO_BOX (go_gtk_builder_get_widget (state->gui, "option-menu-header"));
2095 renderer = (GtkCellRenderer*) gtk_cell_renderer_text_new();
2096 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (header), renderer, TRUE);
2097 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (header), renderer,
2098 "text", 0,
2099 NULL);
2100 footer = GTK_COMBO_BOX (go_gtk_builder_get_widget (state->gui, "option-menu-footer"));
2101 renderer = (GtkCellRenderer*) gtk_cell_renderer_text_new();
2102 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (footer), renderer, TRUE);
2103 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (footer), renderer,
2104 "text", 0,
2105 NULL);
2107 state->header = gnm_print_hf_copy (state->pi->header ? state->pi->header :
2108 gnm_print_hf_formats->data);
2109 state->footer = gnm_print_hf_copy (state->pi->footer ? state->pi->footer :
2110 gnm_print_hf_formats->data);
2112 do_setup_hf_menus (state);
2114 w = go_gtk_builder_get_widget (state->gui, "configure-header-button");
2115 g_signal_connect_swapped (G_OBJECT (w),
2116 "clicked",
2117 G_CALLBACK (do_header_customize), state);
2118 w = go_gtk_builder_get_widget (state->gui, "configure-footer-button");
2119 g_signal_connect_swapped (G_OBJECT (w),
2120 "clicked",
2121 G_CALLBACK (do_footer_customize), state);
2124 create_hf_preview_canvas (state, TRUE);
2125 create_hf_preview_canvas (state, FALSE);
2127 display_hf_preview (state, TRUE);
2128 display_hf_preview (state, FALSE);
2132 static void
2133 display_order_icon (GtkToggleButton *toggle, PrinterSetupState *state)
2135 GtkWidget *show, *hide;
2137 if (gtk_toggle_button_get_active (toggle)){
2138 show = state->icon_rd;
2139 hide = state->icon_dr;
2140 } else {
2141 hide = state->icon_rd;
2142 show = state->icon_dr;
2145 gtk_widget_show (show);
2146 gtk_widget_hide (hide);
2149 static void
2150 load_print_area (PrinterSetupState *state)
2152 GnmRange *print_area;
2154 print_area = sheet_get_nominal_printarea
2155 (wb_control_cur_sheet
2156 (GNM_WBC (state->wbcg)));
2157 if (print_area != NULL)
2158 gnm_expr_entry_load_from_range
2159 (state->area_entry,
2160 wb_control_cur_sheet (GNM_WBC (state->wbcg)),
2161 print_area);
2162 else
2163 gnm_expr_entry_load_from_text
2164 (state->area_entry, "");
2165 g_free (print_area);
2168 static void
2169 do_setup_error_display (PrinterSetupState *state)
2171 static struct {
2172 char const *label;
2173 guint type;
2174 } display_types[] = {
2175 {N_("Print as displayed"), GNM_PRINT_ERRORS_AS_DISPLAYED},
2176 {N_("Print as spaces"), GNM_PRINT_ERRORS_AS_BLANK},
2177 {N_("Print as dashes"), GNM_PRINT_ERRORS_AS_DASHES},
2178 {N_("Print as #N/A"), GNM_PRINT_ERRORS_AS_NA}
2181 gint i;
2182 GtkCellRenderer *cell;
2183 gint item = GNM_PRINT_ERRORS_AS_DISPLAYED;
2184 GtkTreeIter iter;
2186 for (i = 0; i < (int)G_N_ELEMENTS (display_types); i++) {
2187 gtk_list_store_insert_with_values (state->error_display.store,
2188 NULL, G_MAXINT,
2189 0, _(display_types[i].label),
2190 1, display_types[i].type,
2191 -1);
2192 if (display_types[i].type == state->pi->error_display)
2193 item = i;
2195 cell = gtk_cell_renderer_text_new();
2196 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(state->error_display.combo), cell, TRUE);
2197 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(state->error_display.combo),
2198 cell, "text", 0, NULL);
2199 if (gtk_tree_model_iter_nth_child
2200 (GTK_TREE_MODEL (state->error_display.store), &iter, NULL, item))
2201 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (state->error_display.combo), &iter);
2204 static void
2205 do_setup_comment_display (PrinterSetupState *state)
2207 static struct {
2208 char const *label;
2209 guint type;
2210 } display_types[] = {
2211 {N_("Do not print"), GNM_PRINT_COMMENTS_NONE},
2212 {N_("Print in place"), GNM_PRINT_COMMENTS_IN_PLACE},
2213 {N_("Print at end"), GNM_PRINT_COMMENTS_AT_END}
2216 gint i;
2217 GtkCellRenderer *cell;
2218 gint item = GNM_PRINT_COMMENTS_NONE;
2219 GtkTreeIter iter;
2221 for (i = 0; i < (int)G_N_ELEMENTS (display_types); i++) {
2222 gtk_list_store_insert_with_values (state->comment_display.store,
2223 NULL, G_MAXINT,
2224 0, _(display_types[i].label),
2225 1, display_types[i].type,
2226 -1);
2227 if (display_types[i].type == state->pi->comment_placement)
2228 item = i;
2230 cell = gtk_cell_renderer_text_new();
2231 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(state->comment_display.combo), cell, TRUE);
2232 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(state->comment_display.combo), cell, "text", 0, NULL);
2233 if (gtk_tree_model_iter_nth_child
2234 (GTK_TREE_MODEL (state->comment_display.store), &iter, NULL, item))
2235 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (state->comment_display.combo), &iter);
2237 gtk_widget_set_sensitive (state->comment_display.combo, FALSE);
2240 static void
2241 do_setup_page_area (PrinterSetupState *state)
2243 GtkWidget *pa_grid = go_gtk_builder_get_widget (state->gui,
2244 "print-area-grid");
2245 GtkWidget *repeat_grid = go_gtk_builder_get_widget (state->gui,
2246 "area-grid");
2248 state->area_entry = gnm_expr_entry_new (state->wbcg, FALSE);
2249 gnm_expr_entry_set_flags (state->area_entry,
2250 GNM_EE_SHEET_OPTIONAL,
2251 GNM_EE_SHEET_OPTIONAL);
2252 gtk_container_add (GTK_CONTAINER (pa_grid),
2253 GTK_WIDGET (state->area_entry));
2254 gtk_widget_set_hexpand (GTK_WIDGET (state->area_entry), TRUE);
2255 gtk_widget_show (GTK_WIDGET (state->area_entry));
2257 state->top_entry = gnm_expr_entry_new (state->wbcg, TRUE);
2258 gnm_expr_entry_set_flags (state->top_entry,
2259 GNM_EE_SINGLE_RANGE | GNM_EE_FULL_ROW | GNM_EE_SHEET_OPTIONAL,
2260 GNM_EE_MASK);
2261 gtk_widget_set_hexpand (GTK_WIDGET (state->top_entry), TRUE);
2262 gtk_grid_attach (GTK_GRID (repeat_grid),
2263 GTK_WIDGET (state->top_entry), 1, 2, 1, 1);
2264 gtk_widget_show (GTK_WIDGET (state->top_entry));
2266 state->left_entry = gnm_expr_entry_new (state->wbcg, TRUE);
2267 gnm_expr_entry_set_flags (state->left_entry,
2268 GNM_EE_SINGLE_RANGE | GNM_EE_FULL_COL | GNM_EE_SHEET_OPTIONAL,
2269 GNM_EE_MASK);
2270 gtk_widget_set_hexpand (GTK_WIDGET (state->left_entry), TRUE);
2271 gtk_grid_attach (GTK_GRID (repeat_grid),
2272 GTK_WIDGET (state->left_entry), 1, 3, 1, 1);
2273 gtk_widget_show (GTK_WIDGET (state->left_entry));
2276 gnm_editable_enters (GTK_WINDOW (state->dialog),
2277 GTK_WIDGET (gnm_expr_entry_get_entry (state->area_entry)));
2278 gnm_editable_enters (GTK_WINDOW (state->dialog),
2279 GTK_WIDGET (gnm_expr_entry_get_entry (state->top_entry)));
2280 gnm_editable_enters (GTK_WINDOW (state->dialog),
2281 GTK_WIDGET (gnm_expr_entry_get_entry (state->left_entry)));
2283 gnm_expr_entry_load_from_text (state->top_entry,
2284 state->pi->repeat_top);
2285 gnm_expr_entry_load_from_text (state->left_entry,
2286 state->pi->repeat_left);
2288 load_print_area (state);
2291 static void
2292 do_setup_page_info (PrinterSetupState *state)
2294 GtkWidget *gridlines = go_gtk_builder_get_widget (state->gui, "check-grid-lines");
2295 GtkWidget *onlystyles= go_gtk_builder_get_widget (state->gui, "check-only-styles");
2296 GtkWidget *bw = go_gtk_builder_get_widget (state->gui, "check-black-white");
2297 GtkWidget *titles = go_gtk_builder_get_widget (state->gui, "check-print-titles");
2298 GtkWidget *do_not_print = go_gtk_builder_get_widget (state->gui, "check-do-not-print");
2299 GtkWidget *order_rd = go_gtk_builder_get_widget (state->gui, "radio-order-right");
2300 GtkWidget *order_dr = go_gtk_builder_get_widget (state->gui, "radio-order-down");
2301 GtkWidget *order_grid = go_gtk_builder_get_widget (state->gui, "page-order-grid");
2302 GtkWidget *order;
2304 state->error_display.combo = go_gtk_builder_get_widget (state->gui, "error-box");
2305 state->error_display.store = GTK_LIST_STORE (gtk_combo_box_get_model
2306 (GTK_COMBO_BOX (state->error_display.combo)));
2307 do_setup_error_display (state);
2309 state->comment_display.combo = go_gtk_builder_get_widget (state->gui, "comments-box");
2310 state->comment_display.store = GTK_LIST_STORE (gtk_combo_box_get_model
2311 (GTK_COMBO_BOX (state->comment_display.combo)));
2312 do_setup_comment_display (state);
2314 state->icon_rd = gtk_image_new_from_resource ("/org/gnumeric/gnumeric/images/right-down.png");
2315 state->icon_dr = gtk_image_new_from_resource ("/org/gnumeric/gnumeric/images/down-right.png");
2317 gtk_widget_hide (state->icon_dr);
2318 gtk_widget_hide (state->icon_rd);
2320 gtk_grid_attach (GTK_GRID (order_grid), state->icon_rd, 1, 0, 1, 2);
2321 gtk_grid_attach (GTK_GRID (order_grid), state->icon_dr, 1, 0, 1, 2);
2323 g_signal_connect (G_OBJECT (order_rd), "toggled", G_CALLBACK (display_order_icon), state);
2325 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gridlines),
2326 state->pi->print_grid_lines);
2327 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (onlystyles),
2328 state->pi->print_even_if_only_styles);
2329 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bw),
2330 state->pi->print_black_and_white);
2331 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (titles),
2332 state->pi->print_titles);
2333 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (do_not_print),
2334 state->pi->do_not_print);
2336 order = state->pi->print_across_then_down ? order_rd : order_dr;
2337 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (order), TRUE);
2338 display_order_icon (GTK_TOGGLE_BUTTON (order_rd), state);
2342 static void
2343 do_update_margin (UnitInfo *margin, double value, GtkUnit unit)
2345 margin->value = value;
2346 gtk_spin_button_set_range (margin->spin, 0. , 2. * value);
2347 gtk_spin_button_set_value (margin->spin, value);
2348 switch (unit) {
2349 case GTK_UNIT_MM:
2350 gtk_spin_button_set_digits (margin->spin, 1);
2351 gtk_spin_button_set_increments (margin->spin, 1., 0.);
2352 break;
2353 case GTK_UNIT_INCH:
2354 gtk_spin_button_set_digits (margin->spin, 3);
2355 gtk_spin_button_set_increments (margin->spin, 0.125, 0.);
2356 break;
2357 case GTK_UNIT_POINTS:
2358 gtk_spin_button_set_digits (margin->spin, 1);
2359 gtk_spin_button_set_increments (margin->spin, 1., 0.);
2360 break;
2361 case GTK_UNIT_PIXEL:
2362 break;
2366 static void
2367 do_update_page (PrinterSetupState *state)
2369 GnmPrintInformation *pi = state->pi;
2370 GtkBuilder *gui;
2371 double top, bottom;
2372 double left, right;
2373 double edge_to_below_header, edge_to_above_footer;
2374 char *text;
2375 char const *format;
2376 double scale;
2378 gui = state->gui;
2380 gtk_label_set_text (GTK_LABEL (go_gtk_builder_get_widget (gui,
2381 "paper-type-label")),
2382 print_info_get_paper_display_name (pi));
2383 state->height = print_info_get_paper_height (pi,state->display_unit);
2384 state->width = print_info_get_paper_width (pi,state->display_unit);
2385 switch (state->display_unit) {
2386 case GTK_UNIT_PIXEL:
2387 format = _("%.0f pixels wide by %.0f pixels tall");
2388 break;
2389 case GTK_UNIT_POINTS:
2390 format = _("%.0f points wide by %.0f points tall");
2391 break;
2392 case GTK_UNIT_INCH:
2393 format = _("%.1f in wide by %.1f in tall");
2394 break;
2395 case GTK_UNIT_MM:
2396 format = _("%.0f mm wide by %.0f mm tall");
2397 break;
2398 default:
2399 format = _("%.1f wide by %.1f tall");
2400 break;
2402 text = g_strdup_printf (format, state->width, state->height);
2403 gtk_label_set_text (GTK_LABEL (go_gtk_builder_get_widget (gui,
2404 "paper-size-label")),
2405 text);
2406 g_free (text);
2408 print_info_get_margins (state->pi,
2409 &top, &bottom,
2410 &left, &right,
2411 &edge_to_below_header,
2412 &edge_to_above_footer);
2413 scale = get_conversion_factor (state->display_unit);
2414 do_update_margin (&state->margins.header,
2415 (edge_to_below_header - top) / scale,
2416 state->display_unit);
2417 do_update_margin (&state->margins.footer,
2418 (edge_to_above_footer - bottom) / scale,
2419 state->display_unit);
2420 do_update_margin (&state->margins.top, top / scale,
2421 state->display_unit);
2422 do_update_margin (&state->margins.bottom, bottom / scale,
2423 state->display_unit);
2424 do_update_margin (&state->margins.left, left / scale,
2425 state->display_unit);
2426 do_update_margin (&state->margins.right, right / scale,
2427 state->display_unit);
2428 configure_bounds_top (state);
2429 configure_bounds_header (state);
2430 configure_bounds_left (state);
2431 configure_bounds_right (state);
2432 configure_bounds_footer (state);
2433 configure_bounds_bottom (state);
2435 canvas_update (state);
2437 switch (print_info_get_paper_orientation (state->pi)) {
2438 case GTK_PAGE_ORIENTATION_PORTRAIT:
2439 gtk_toggle_button_set_active
2440 (GTK_TOGGLE_BUTTON (state->portrait_radio), TRUE);
2441 break;
2442 case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
2443 gtk_toggle_button_set_active
2444 (GTK_TOGGLE_BUTTON (state->rev_portrait_radio), TRUE);
2445 break;
2446 case GTK_PAGE_ORIENTATION_LANDSCAPE:
2447 gtk_toggle_button_set_active
2448 (GTK_TOGGLE_BUTTON (state->landscape_radio), TRUE);
2449 break;
2450 default:
2451 gtk_toggle_button_set_active
2452 (GTK_TOGGLE_BUTTON (state->rev_landscape_radio), TRUE);
2453 break;
2458 static void
2459 orientation_changed_cb (PrinterSetupState *state)
2461 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->portrait_radio)))
2462 print_info_set_paper_orientation (state->pi, GTK_PAGE_ORIENTATION_PORTRAIT);
2463 else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->rev_portrait_radio)))
2464 print_info_set_paper_orientation (state->pi, GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT);
2465 else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->landscape_radio)))
2466 print_info_set_paper_orientation (state->pi, GTK_PAGE_ORIENTATION_LANDSCAPE);
2467 else
2468 print_info_set_paper_orientation (state->pi, GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE);
2469 do_update_page (state);
2472 static void
2473 do_setup_page (PrinterSetupState *state)
2475 GtkBuilder *gui;
2477 gui = state->gui;
2479 g_signal_connect_swapped (G_OBJECT (go_gtk_builder_get_widget (gui, "paper-button")),
2480 "clicked",
2481 G_CALLBACK (dialog_gtk_printer_setup_cb), state);
2483 state->portrait_radio = go_gtk_builder_get_widget (gui, "portrait-button");
2484 state->landscape_radio = go_gtk_builder_get_widget (gui, "landscape-button");
2485 state->rev_portrait_radio = go_gtk_builder_get_widget (gui, "r-portrait-button");
2486 state->rev_landscape_radio = go_gtk_builder_get_widget (gui, "r-landscape-button");
2488 g_signal_connect_swapped (G_OBJECT (state->portrait_radio), "toggled",
2489 G_CALLBACK (orientation_changed_cb), state);
2490 g_signal_connect_swapped (G_OBJECT (state->rev_portrait_radio), "toggled",
2491 G_CALLBACK (orientation_changed_cb), state);
2492 g_signal_connect_swapped (G_OBJECT (state->landscape_radio), "toggled",
2493 G_CALLBACK (orientation_changed_cb), state);
2495 do_setup_margin (state);
2497 do_update_page (state);
2502 static void
2503 scaling_percent_changed (GtkToggleButton *toggle, PrinterSetupState *state)
2505 gboolean scale_percent = gtk_toggle_button_get_active (toggle);
2507 gtk_widget_set_sensitive (GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "scale-percent-spin")), scale_percent);
2508 gtk_widget_set_sensitive (GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "scale-percent-label")), scale_percent);
2511 static void
2512 scaling_fit_to_h_changed (GtkToggleButton *toggle, PrinterSetupState *state)
2514 gboolean scale_fit_to_h = gtk_toggle_button_get_active (toggle);
2515 gtk_widget_set_sensitive
2516 (GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "scale-h-spin")),
2517 scale_fit_to_h);
2518 gtk_widget_set_sensitive
2519 (GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "fit-h-check-label")),
2520 scale_fit_to_h);
2523 static void
2524 scaling_fit_to_v_changed (GtkToggleButton *toggle, PrinterSetupState *state)
2526 gboolean scale_fit_to_v = gtk_toggle_button_get_active (toggle);
2527 gtk_widget_set_sensitive
2528 (GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "scale-v-spin")),
2529 scale_fit_to_v);
2530 gtk_widget_set_sensitive
2531 (GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "fit-v-check-label")),
2532 scale_fit_to_v);
2535 static void
2536 scaling_fit_to_changed (GtkToggleButton *toggle, PrinterSetupState *state)
2538 gboolean scale_fit_to = gtk_toggle_button_get_active (toggle);
2540 if (scale_fit_to) {
2541 scaling_fit_to_h_changed (GTK_TOGGLE_BUTTON
2542 (go_gtk_builder_get_widget (state->gui, "fit-h-check")), state);
2543 scaling_fit_to_v_changed (GTK_TOGGLE_BUTTON
2544 (go_gtk_builder_get_widget (state->gui, "fit-v-check")), state);
2545 } else {
2546 gtk_widget_set_sensitive
2547 (GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "scale-v-spin")), FALSE);
2548 gtk_widget_set_sensitive
2549 (GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "fit-v-check-label")), FALSE);
2550 gtk_widget_set_sensitive
2551 (GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "scale-h-spin")), FALSE);
2552 gtk_widget_set_sensitive
2553 (GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "fit-h-check-label")), FALSE);
2555 gtk_widget_set_sensitive
2556 (GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "fit-h-check")), scale_fit_to);
2557 gtk_widget_set_sensitive
2558 (GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "fit-v-check")), scale_fit_to);
2561 static void
2562 do_setup_scale (PrinterSetupState *state)
2564 GnmPrintInformation *pi = state->pi;
2565 GtkWidget *scale_percent_spin, *scale_width_spin, *scale_height_spin;
2566 GtkBuilder *gui;
2568 gui = state->gui;
2570 state->scale_percent_radio = go_gtk_builder_get_widget (gui, "scale-percent-radio");
2571 state->scale_fit_to_radio = go_gtk_builder_get_widget (gui, "scale-fit-to-radio");
2572 state->scale_no_radio = go_gtk_builder_get_widget (gui, "scale-no-radio");
2574 g_signal_connect (G_OBJECT (state->scale_percent_radio), "toggled",
2575 G_CALLBACK (scaling_percent_changed), state);
2576 g_signal_connect (G_OBJECT (state->scale_fit_to_radio), "toggled",
2577 G_CALLBACK (scaling_fit_to_changed), state);
2578 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (state->gui, "fit-h-check")),
2579 "toggled", G_CALLBACK (scaling_fit_to_h_changed), state);
2580 g_signal_connect (G_OBJECT (go_gtk_builder_get_widget (state->gui, "fit-v-check")),
2581 "toggled", G_CALLBACK (scaling_fit_to_v_changed), state);
2583 scaling_percent_changed (GTK_TOGGLE_BUTTON (state->scale_percent_radio), state);
2584 scaling_fit_to_changed (GTK_TOGGLE_BUTTON (state->scale_fit_to_radio), state);
2587 if (pi->scaling.type == PRINT_SCALE_PERCENTAGE) {
2588 if (pi->scaling.percentage.x == 100.)
2589 gtk_toggle_button_set_active
2590 (GTK_TOGGLE_BUTTON (state->scale_no_radio), TRUE);
2591 else
2592 gtk_toggle_button_set_active
2593 (GTK_TOGGLE_BUTTON (state->scale_percent_radio), TRUE);
2594 } else {
2595 gtk_toggle_button_set_active
2596 (GTK_TOGGLE_BUTTON (state->scale_fit_to_radio), TRUE);
2599 scale_percent_spin = go_gtk_builder_get_widget (gui, "scale-percent-spin");
2600 gtk_spin_button_set_value (
2601 GTK_SPIN_BUTTON (scale_percent_spin), pi->scaling.percentage.x);
2602 gnm_editable_enters (GTK_WINDOW (state->dialog),
2603 GTK_WIDGET (scale_percent_spin));
2605 scale_width_spin = go_gtk_builder_get_widget (gui, "scale-h-spin");
2606 gtk_spin_button_set_value (
2607 GTK_SPIN_BUTTON (scale_width_spin), pi->scaling.dim.cols);
2608 gtk_toggle_button_set_active
2609 (GTK_TOGGLE_BUTTON (go_gtk_builder_get_widget (state->gui, "fit-h-check")),
2610 pi->scaling.dim.cols > 0);
2611 gnm_editable_enters (GTK_WINDOW (state->dialog),
2612 GTK_WIDGET (scale_width_spin));
2614 scale_height_spin = go_gtk_builder_get_widget (gui, "scale-v-spin");
2615 gtk_spin_button_set_value (
2616 GTK_SPIN_BUTTON (scale_height_spin), pi->scaling.dim.rows);
2617 gtk_toggle_button_set_active
2618 (GTK_TOGGLE_BUTTON (go_gtk_builder_get_widget (state->gui, "fit-v-check")),
2619 pi->scaling.dim.rows > 0);
2620 gnm_editable_enters (GTK_WINDOW (state->dialog),
2621 GTK_WIDGET (scale_height_spin));
2625 static Sheet *
2626 print_setup_get_sheet (PrinterSetupState *state)
2628 GtkWidget *w = go_gtk_builder_get_widget (state->gui, "apply-to-all");
2629 gboolean apply_all_sheets = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
2631 gnm_conf_set_printsetup_all_sheets (apply_all_sheets);
2633 if (apply_all_sheets)
2634 return NULL;
2635 return workbook_sheet_by_index (state->sheet->workbook,
2636 gtk_combo_box_get_active (GTK_COMBO_BOX
2637 (state->sheet_selector)));
2640 static void
2641 cb_do_print_preview (PrinterSetupState *state)
2643 GnmPrintInformation *old_pi;
2644 double width, height;
2645 GogGraph *graph = NULL;
2647 fetch_settings (state);
2648 old_pi = state->sheet->print_info;
2649 state->sheet->print_info = state->pi;
2650 if (state->sheet->sheet_type == GNM_SHEET_OBJECT) {
2651 graph = GOG_GRAPH (sheet_object_graph_get_gog (GNM_SO (state->sheet->sheet_objects->data)));
2652 if (graph) {
2653 double top, bottom, left, right, edge_to_below_header, edge_to_above_footer, w, h;
2654 gog_graph_get_size (graph, &width, &height);
2655 w = print_info_get_paper_width (state->pi, GTK_UNIT_POINTS);
2656 h = print_info_get_paper_height (state->pi, GTK_UNIT_POINTS);
2657 print_info_get_margins (state->pi, &top, &bottom, &left, &right, &edge_to_below_header, &edge_to_above_footer);
2658 w -= left + right;
2659 h -= top + bottom + edge_to_above_footer + edge_to_below_header;
2660 gog_graph_set_size (graph, w, h);
2663 gnm_print_sheet (GNM_WBC (state->wbcg),
2664 state->sheet, TRUE, GNM_PRINT_ACTIVE_SHEET, NULL);
2665 if (graph)
2666 gog_graph_set_size (graph, width, height);
2667 state->sheet->print_info = old_pi;
2670 static void
2671 cb_do_print_cancel (PrinterSetupState *state)
2673 gtk_widget_destroy (state->dialog);
2676 static void
2677 cb_do_print_ok (PrinterSetupState *state)
2679 fetch_settings (state);
2680 if (gtk_toggle_button_get_active (
2681 GTK_TOGGLE_BUTTON (
2682 go_gtk_builder_get_widget (state->gui,
2683 "is_default_check")))) {
2684 gnm_print_info_save (state->pi);
2686 cmd_print_setup (GNM_WBC (state->wbcg),
2687 print_setup_get_sheet (state), state->pi);
2688 gtk_widget_destroy (state->dialog);
2691 static void
2692 cb_do_print (PrinterSetupState *state)
2694 Sheet *sheet = state->sheet;
2695 WorkbookControl *wbc = GNM_WBC (state->wbcg);
2697 cb_do_print_ok (state);
2698 gnm_print_sheet (wbc, sheet, FALSE, GNM_PRINT_SAVED_INFO, NULL);
2701 static void
2702 cb_do_print_destroy (PrinterSetupState *state)
2704 if (state->customize_header)
2705 gtk_widget_destroy (state->customize_header);
2707 if (state->customize_footer)
2708 gtk_widget_destroy (state->customize_footer);
2710 g_object_unref (state->gui);
2712 gnm_print_hf_free (state->header);
2713 gnm_print_hf_free (state->footer);
2714 gnm_print_info_free (state->pi);
2715 g_free (state->pi_header);
2716 g_free (state->pi_footer);
2717 g_object_unref (state->unit_model);
2718 g_free (state);
2721 static void
2722 cb_do_sheet_selector_toggled (GtkToggleButton *togglebutton,
2723 PrinterSetupState *state)
2725 gboolean all_sheets = gtk_toggle_button_get_active (togglebutton);
2727 gtk_widget_set_sensitive (state->sheet_selector, !all_sheets);
2730 static void
2731 do_setup_sheet_selector (PrinterSetupState *state)
2733 GtkWidget *grid, *w;
2734 int i, n, n_this = 0;
2736 g_return_if_fail (state != NULL);
2737 g_return_if_fail (state->sheet != NULL);
2739 grid = go_gtk_builder_get_widget (state->gui, "sheet-grid");
2740 state->sheet_selector = gtk_combo_box_text_new ();
2741 n = workbook_sheet_count (state->sheet->workbook);
2742 for (i = 0 ; i < n ; i++) {
2743 Sheet * a_sheet = workbook_sheet_by_index (state->sheet->workbook, i);
2744 if (a_sheet == state->sheet)
2745 n_this = i;
2746 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (state->sheet_selector),
2747 a_sheet->name_unquoted);
2749 gtk_combo_box_set_active (GTK_COMBO_BOX (state->sheet_selector), n_this);
2750 gtk_widget_set_hexpand (state->sheet_selector, TRUE);
2751 gtk_grid_attach (GTK_GRID (grid), state->sheet_selector, 1, 1, 1, 1);
2752 w = go_gtk_builder_get_widget (state->gui, "apply-to-all");
2753 g_signal_connect (G_OBJECT (w),
2754 "toggled",
2755 G_CALLBACK (cb_do_sheet_selector_toggled), state);
2756 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w),
2757 gnm_conf_get_printsetup_all_sheets ());
2758 cb_do_sheet_selector_toggled (GTK_TOGGLE_BUTTON (w), state);
2759 w = go_gtk_builder_get_widget (state->gui, "apply-to-selected");
2760 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w),
2761 !gnm_conf_get_printsetup_all_sheets ());
2762 gtk_widget_show_all (grid);
2765 static void
2766 do_setup_main_dialog (PrinterSetupState *state)
2768 GtkWidget *w;
2770 g_return_if_fail (state != NULL);
2771 g_return_if_fail (state->sheet != NULL);
2772 g_return_if_fail (state->wbcg != NULL);
2774 state->dialog = go_gtk_builder_get_widget (state->gui, "print-setup");
2776 w = go_gtk_builder_get_widget (state->gui, "ok");
2777 g_signal_connect_swapped (G_OBJECT (w),
2778 "clicked",
2779 G_CALLBACK (cb_do_print_ok), state);
2780 w = go_gtk_builder_get_widget (state->gui, "print");
2781 g_signal_connect_swapped (G_OBJECT (w),
2782 "clicked",
2783 G_CALLBACK (cb_do_print), state);
2784 w = go_gtk_builder_get_widget (state->gui, "preview");
2785 g_signal_connect_swapped (G_OBJECT (w),
2786 "clicked",
2787 G_CALLBACK (cb_do_print_preview), state);
2788 w = go_gtk_builder_get_widget (state->gui, "cancel");
2789 g_signal_connect_swapped (G_OBJECT (w),
2790 "clicked",
2791 G_CALLBACK (cb_do_print_cancel), state);
2793 w = go_gtk_builder_get_widget (state->gui, "print-setup-notebook");
2794 gtk_notebook_set_current_page (GTK_NOTEBOOK (w), 0);
2796 g_object_set_data_full (G_OBJECT (state->dialog),
2797 "state", state, (GDestroyNotify) cb_do_print_destroy);
2798 wbc_gtk_attach_guru (state->wbcg, state->dialog);
2801 static PrinterSetupState *
2802 printer_setup_state_new (WBCGtk *wbcg, Sheet *sheet)
2804 PrinterSetupState *state;
2805 GtkBuilder *gui;
2807 gui = gnm_gtk_builder_load ("res:ui/print.ui", NULL, GO_CMD_CONTEXT (wbcg));
2808 if (gui == NULL)
2809 return NULL;
2811 state = g_new0 (PrinterSetupState, 1);
2812 state->wbcg = wbcg;
2813 state->sheet = sheet;
2814 state->gui = gui;
2815 state->pi = gnm_print_info_dup (sheet->print_info);
2816 state->display_unit = state->pi->desired_display.top;
2817 state->customize_header = NULL;
2818 state->customize_footer = NULL;
2820 do_setup_main_dialog (state);
2821 do_setup_sheet_selector (state);
2822 do_setup_hf (state);
2823 do_setup_page_area (state);
2824 do_setup_page_info (state);
2825 do_setup_page (state);
2826 do_setup_scale (state);
2828 return state;
2831 static void
2832 do_fetch_page (PrinterSetupState *state)
2834 state->pi->center_horizontally = gtk_toggle_button_get_active
2835 (GTK_TOGGLE_BUTTON (state->check_center_h));
2836 state->pi->center_vertically = gtk_toggle_button_get_active
2837 (GTK_TOGGLE_BUTTON (state->check_center_v));
2840 static void
2841 do_fetch_unit (PrinterSetupState *state)
2843 if (state->display_unit != state->pi->desired_display.top) {
2844 state->pi->desired_display.top = state->display_unit;
2845 state->pi->desired_display.bottom = state->display_unit;
2846 state->pi->desired_display.header = state->display_unit;
2847 state->pi->desired_display.footer = state->display_unit;
2848 state->pi->desired_display.left = state->display_unit;
2849 state->pi->desired_display.right = state->display_unit;
2853 static void
2854 do_fetch_scale (PrinterSetupState *state)
2856 GtkWidget *w;
2857 GtkBuilder *gui = state->gui;
2859 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->scale_no_radio))) {
2860 state->pi->scaling.percentage.x = state->pi->scaling.percentage.y = 100.;
2861 state->pi->scaling.type = PRINT_SCALE_PERCENTAGE;
2862 } else {
2863 w = go_gtk_builder_get_widget (gui, "scale-percent-spin");
2864 state->pi->scaling.percentage.x = state->pi->scaling.percentage.y
2865 = gtk_spin_button_get_value (GTK_SPIN_BUTTON (w));
2866 state->pi->scaling.type =
2867 ((gtk_toggle_button_get_active
2868 (GTK_TOGGLE_BUTTON (state->scale_percent_radio))) ?
2869 PRINT_SCALE_PERCENTAGE : PRINT_SCALE_FIT_PAGES);
2871 w = go_gtk_builder_get_widget (gui, "fit-h-check");
2872 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)))
2873 state->pi->scaling.dim.cols = 0;
2874 else {
2875 w = go_gtk_builder_get_widget (gui, "scale-h-spin");
2876 state->pi->scaling.dim.cols =
2877 gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (w));
2880 w = go_gtk_builder_get_widget (gui, "fit-v-check");
2881 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)))
2882 state->pi->scaling.dim.rows = 0;
2883 else {
2884 w = go_gtk_builder_get_widget (gui, "scale-v-spin");
2885 state->pi->scaling.dim.rows =
2886 gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (w));
2891 * Header and footer are stored with Excel semantics, but displayed with
2892 * more natural semantics. In Excel, both top margin and header are measured
2893 * from top of sheet. See illustration at start of src/print.c. The Gnumeric
2894 * user interface presents header as the band between top margin and the
2895 * print area. Bottom margin and footer are handled likewise.
2897 static void
2898 do_fetch_margins (PrinterSetupState *state)
2900 double header, footer, top, bottom, left, right;
2901 GtkPageSetup *ps = gnm_print_info_get_page_setup (state->pi);
2902 double factor = get_conversion_factor (state->display_unit);
2904 header = state->margins.header.value;
2905 footer = state->margins.footer.value;
2906 top = state->margins.top.value;
2907 bottom = state->margins.bottom.value;
2908 left = state->margins.left.value;
2909 right = state->margins.right.value;
2911 gtk_page_setup_set_top_margin (ps, top, state->display_unit);
2912 gtk_page_setup_set_bottom_margin (ps, bottom, state->display_unit);
2913 gtk_page_setup_set_left_margin (ps, left, state->display_unit);
2914 gtk_page_setup_set_right_margin (ps, right, state->display_unit);
2916 header += top;
2917 footer += bottom;
2919 print_info_set_edge_to_above_footer (state->pi, footer * factor);
2920 print_info_set_edge_to_below_header (state->pi, header * factor);
2923 static void
2924 do_fetch_hf (PrinterSetupState *state)
2926 gnm_print_hf_free (state->pi->header);
2927 gnm_print_hf_free (state->pi->footer);
2929 state->pi->header = gnm_print_hf_copy (state->header);
2930 state->pi->footer = gnm_print_hf_copy (state->footer);
2933 static void
2934 do_fetch_page_info (PrinterSetupState *state)
2936 GnmPrintInformation *pi = state->pi;
2937 GtkTreeIter iter;
2939 pi->print_grid_lines = gtk_toggle_button_get_active
2940 (GTK_TOGGLE_BUTTON (go_gtk_builder_get_widget (state->gui, "check-grid-lines")));
2941 pi->print_even_if_only_styles = gtk_toggle_button_get_active
2942 (GTK_TOGGLE_BUTTON (go_gtk_builder_get_widget (state->gui, "check-only-styles")));
2943 pi->print_black_and_white = gtk_toggle_button_get_active
2944 (GTK_TOGGLE_BUTTON (go_gtk_builder_get_widget (state->gui, "check-black-white")));
2945 pi->print_titles = gtk_toggle_button_get_active
2946 (GTK_TOGGLE_BUTTON (go_gtk_builder_get_widget (state->gui, "check-print-titles")));
2947 pi->print_across_then_down = gtk_toggle_button_get_active
2948 (GTK_TOGGLE_BUTTON (go_gtk_builder_get_widget (state->gui, "radio-order-right")));
2949 pi->do_not_print = gtk_toggle_button_get_active
2950 (GTK_TOGGLE_BUTTON (go_gtk_builder_get_widget (state->gui, "check-do-not-print")));
2952 g_free (pi->repeat_top);
2953 pi->repeat_top = g_strdup (gnm_expr_entry_get_text (state->top_entry));
2955 g_free (pi->repeat_left);
2956 pi->repeat_left = g_strdup (gnm_expr_entry_get_text (state->left_entry));
2958 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (state->error_display.combo), &iter))
2959 gtk_tree_model_get (GTK_TREE_MODEL (state->error_display.store), &iter,
2960 1, &(pi->error_display),
2961 -1);
2962 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (state->comment_display.combo), &iter))
2963 gtk_tree_model_get (GTK_TREE_MODEL (state->comment_display.store), &iter,
2964 1, &(pi->comment_placement),
2965 -1);
2968 static void
2969 fetch_settings (PrinterSetupState *state)
2971 do_fetch_page (state);
2972 do_fetch_scale (state);
2973 do_fetch_margins (state);
2974 do_fetch_unit (state);
2975 do_fetch_hf (state);
2976 do_fetch_page_info (state);
2980 static void
2981 dialog_printer_setup_done_cb (GtkPageSetup *page_setup,
2982 gpointer data)
2984 if (page_setup) {
2985 PrinterSetupState *state = data;
2986 gnm_print_info_set_page_setup (state->pi,
2987 gtk_page_setup_copy (page_setup));
2988 do_update_page (state);
2992 static void
2993 dialog_gtk_printer_setup_cb (PrinterSetupState *state)
2995 GtkPageSetup *page_setup = gnm_print_info_get_page_setup (state->pi);
2997 gtk_print_run_page_setup_dialog_async
2998 (GTK_WINDOW (state->dialog),
2999 page_setup,
3000 NULL,
3001 dialog_printer_setup_done_cb,
3002 state);
3007 void
3008 dialog_printer_setup (WBCGtk *wbcg, Sheet *sheet)
3010 PrinterSetupState *state;
3012 /* Only one guru per workbook. */
3013 if (wbc_gtk_get_guru (wbcg))
3014 return;
3016 /* Only pop up one copy per workbook */
3017 if (gnm_dialog_raise_if_exists (wbcg, PRINTER_SETUP_KEY))
3018 return;
3020 state = printer_setup_state_new (wbcg, sheet);
3021 if (!state)
3022 return;
3024 gnm_dialog_setup_destroy_handlers (GTK_DIALOG (state->dialog),
3025 state->wbcg,
3026 GNM_DIALOG_DESTROY_CURRENT_SHEET_REMOVED);
3028 gnm_init_help_button (
3029 go_gtk_builder_get_widget (state->gui, "help_button"),
3030 GNUMERIC_HELP_LINK_PRINTER_SETUP_GENERAL);
3031 gnm_keyed_dialog (
3032 wbcg, GTK_WINDOW (state->dialog), PRINTER_SETUP_KEY);
3033 gtk_widget_show (state->dialog);