]> git.street.me.uk Git - andy/viking.git/blob - src/print.c
Add Terraserver
[andy/viking.git] / src / print.c
1 /*
2  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3  *
4  * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5  *
6  * print.c
7  * Copyright (C) 2007, Quy Tonthat <qtonthat@gmail.com>
8  *
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.
13  *
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.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <string.h>
29 #include <glib/gprintf.h>
30 #include <glib/gi18n.h>
31 #include <gtk/gtk.h>
32
33 #if GTK_CHECK_VERSION(2,10,0)
34
35 #include "viking.h"
36 #include "print.h"
37 #include "print-preview.h"
38
39 typedef enum
40 {
41   VIK_PRINT_CENTER_NONE         = 0,
42   VIK_PRINT_CENTER_HORIZONTALLY,
43   VIK_PRINT_CENTER_VERTICALLY,
44   VIK_PRINT_CENTER_BOTH,
45 } PrintCenterMode;
46
47 typedef struct {
48   gchar *name;
49   PrintCenterMode mode;
50 } PrintCenterName;
51
52 static const PrintCenterName center_modes[] = {
53   {N_("None"),          VIK_PRINT_CENTER_NONE},
54   {N_("Horizontally"),  VIK_PRINT_CENTER_HORIZONTALLY},
55   {N_("Vertically"),    VIK_PRINT_CENTER_VERTICALLY},
56   {N_("Both"),          VIK_PRINT_CENTER_BOTH},
57   {NULL,            -1}
58 };
59
60 typedef struct {
61   gint                num_pages;
62   gboolean            show_info_header;
63   VikWindow           *vw;
64   VikViewport         *vvp;
65   gdouble             xmpp, ympp;  /* zoom level (meters/pixel) */
66   gdouble             xres;
67   gdouble             yres;
68   gint                width;
69   gint                height;
70   gdouble             offset_x;
71   gdouble             offset_y;
72   PrintCenterMode     center;
73   gboolean            use_full_page;
74   GtkPrintOperation  *operation;
75 } PrintData;
76
77 static GtkWidget *create_custom_widget_cb(GtkPrintOperation *operation, PrintData *data);
78 static void begin_print(GtkPrintOperation *operation, GtkPrintContext *context, PrintData *data);
79 static void draw_page(GtkPrintOperation *print, GtkPrintContext *context, gint page_nr, PrintData *data);
80 static void end_print(GtkPrintOperation *operation, GtkPrintContext *context,  PrintData *data);
81
82 void a_print(VikWindow *vw, VikViewport *vvp)
83 {
84   /* TODO: make print_settings non-static when saving_settings_to_file is
85    * implemented. Keep it static for now to retain settings for each
86    * viking session
87    */
88   static GtkPrintSettings *print_settings = NULL;
89
90   GtkPrintOperation *print_oper;
91   GtkPrintOperationResult res;
92   PrintData data;
93
94   print_oper = gtk_print_operation_new ();
95
96   data.num_pages     = 1;
97   data.vw            = vw;
98   data.vvp           = vvp;
99   data.offset_x      = 0;
100   data.offset_y      = 0;
101   data.center        = VIK_PRINT_CENTER_BOTH;
102   data.use_full_page = FALSE;
103   data.operation     = print_oper;
104
105   data.xmpp          = vik_viewport_get_xmpp(vvp);
106   data.ympp          = vik_viewport_get_ympp(vvp);
107   data.width         = vik_viewport_get_width(vvp);
108   data.height        = vik_viewport_get_height(vvp);
109
110   data.xres = data.yres = 230;   /* FIXME */
111
112   if (print_settings != NULL) 
113     gtk_print_operation_set_print_settings (print_oper, print_settings);
114
115   g_signal_connect (print_oper, "begin_print", G_CALLBACK (begin_print), &data);
116   g_signal_connect (print_oper, "draw_page", G_CALLBACK (draw_page), &data);
117   g_signal_connect (print_oper, "end-print", G_CALLBACK (end_print), &data);
118   g_signal_connect (print_oper, "create-custom-widget", G_CALLBACK (create_custom_widget_cb), &data);
119
120   gtk_print_operation_set_custom_tab_label (print_oper, _("Image Settings"));
121
122   res = gtk_print_operation_run (print_oper,
123                                  GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
124                                  GTK_WINDOW (vw), NULL);
125
126   if (res == GTK_PRINT_OPERATION_RESULT_APPLY) {
127     if (print_settings != NULL)
128       g_object_unref (print_settings);
129     print_settings = g_object_ref (gtk_print_operation_get_print_settings (print_oper));
130   }
131
132   g_object_unref (print_oper);
133 }
134
135 static void begin_print(GtkPrintOperation *operation,
136                         GtkPrintContext   *context,
137                         PrintData         *data)
138 {
139   // fputs("DEBUG: begin_print() called\n", stderr);
140   gtk_print_operation_set_n_pages (operation, data->num_pages);
141   gtk_print_operation_set_use_full_page (operation, data->use_full_page);
142
143 }
144
145 static void end_print(GtkPrintOperation *operation,
146                       GtkPrintContext   *context,
147                       PrintData *data)
148 {
149   // fputs("DEBUG: end_print() called\n", stderr);
150
151 }
152
153 static void copy_row_from_rgb(guchar *surface_pixels, guchar *pixbuf_pixels, gint width)
154 {
155   guint32 *cairo_data = (guint32 *) surface_pixels;
156   guchar  *p;
157   gint     i;
158
159   for (i = 0, p = pixbuf_pixels; i < width; i++) {
160     guint32 r = *p++;
161     guint32 g = *p++;
162     guint32 b = *p++;
163     cairo_data[i] = 0xFF000000 | (r << 16) | (g << 8) | b;
164   }
165 }
166
167 #define INT_MULT(a,b,t)  ((t) = (a) * (b) + 0x80, ((((t) >> 8) + (t)) >> 8))
168 #define INT_BLEND(a,b,alpha,tmp)  (INT_MULT((a) - (b), alpha, tmp) + (b))
169 static void copy_row_from_rgba(guchar *surface_pixels, guchar *pixbuf_pixels, gint width)
170 {
171   guint32 *cairo_data = (guint32 *) surface_pixels;
172   guchar  *p;
173   gint     i;
174
175   for (i = 0, p = pixbuf_pixels; i < width; i++) {
176     guint32 r = *p++;
177     guint32 g = *p++;
178     guint32 b = *p++;
179     guint32 a = *p++;
180
181     if (a != 255) {
182       guint32 tmp;
183       /* composite on a white background */
184       r = INT_BLEND (r, 255, a, tmp);
185       g = INT_BLEND (g, 255, a, tmp);
186       b = INT_BLEND (b, 255, a, tmp);
187     }
188     cairo_data[i] = 0xFF000000 | (r << 16) | (g << 8) | b;
189   }
190 }
191
192 static void draw_page_cairo(GtkPrintContext *context, PrintData *data)
193 {
194   cairo_t         *cr;
195   GdkPixbuf       *pixbuf_to_draw; 
196   cairo_surface_t *surface;
197   guchar          *surface_pixels;
198   guchar          *pixbuf_pixels;
199   gint             stride;
200   gint             pixbuf_stride;
201   gint             pixbuf_n_channels;
202   gdouble          cr_width;
203   gdouble          cr_height;
204   gdouble          cr_dpi_x;
205   gdouble          cr_dpi_y;
206   gdouble          scale_x;
207   gdouble          scale_y;
208   gint             y;
209
210   cr = gtk_print_context_get_cairo_context(context);
211   pixbuf_to_draw = gdk_pixbuf_get_from_drawable(NULL,
212                                GDK_DRAWABLE(vik_viewport_get_pixmap(data->vvp)),
213                                NULL, 0, 0, 0, 0, data->width, data->height);
214   surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
215                                        data->width, data->height);
216   
217   cr_width  = gtk_print_context_get_width  (context);
218   cr_height = gtk_print_context_get_height (context);
219   cr_dpi_x  = gtk_print_context_get_dpi_x  (context);
220   cr_dpi_y  = gtk_print_context_get_dpi_y  (context);
221
222   scale_x = cr_dpi_x / data->xres;
223   scale_y = cr_dpi_y / data->yres;
224
225   cairo_translate (cr,
226                    data->offset_x / cr_dpi_x * 72.0,
227                    data->offset_y / cr_dpi_y * 72.0);
228   cairo_scale (cr, scale_x, scale_y);
229
230   surface_pixels = cairo_image_surface_get_data (surface);
231   stride = cairo_image_surface_get_stride (surface);
232   pixbuf_pixels = gdk_pixbuf_get_pixels (pixbuf_to_draw);
233   pixbuf_stride = gdk_pixbuf_get_rowstride(pixbuf_to_draw);
234   pixbuf_n_channels = gdk_pixbuf_get_n_channels(pixbuf_to_draw);
235
236   // fprintf(stderr, "DEBUG: %s() surface_pixels=%p pixbuf_pixels=%p size=%d surface_width=%d surface_height=%d stride=%d data_height=%d pixmap_stride=%d pixmap_nchannels=%d pixmap_bit_per_Sample=%d\n", __PRETTY_FUNCTION__, surface_pixels, pixbuf_pixels, stride * data->height, cairo_image_surface_get_width(surface), cairo_image_surface_get_height(surface), stride, data->height, gdk_pixbuf_get_rowstride(pixbuf_to_draw), gdk_pixbuf_get_n_channels(pixbuf_to_draw), gdk_pixbuf_get_bits_per_sample(pixbuf_to_draw));
237
238   /* Assume the pixbuf has 8 bits per channel */
239   for (y = 0; y < data->height; y++, surface_pixels += stride, pixbuf_pixels += pixbuf_stride) {
240     switch (pixbuf_n_channels) {
241       case 3:
242         copy_row_from_rgb (surface_pixels, pixbuf_pixels, data->width);
243         break;
244       case 4:
245         copy_row_from_rgba (surface_pixels, pixbuf_pixels, data->width);
246         break;
247     }
248   }
249
250   g_object_unref(G_OBJECT(pixbuf_to_draw));
251
252   cairo_set_source_surface(cr, surface, 0, 0);
253   cairo_rectangle(cr, 0, 0, data->width, data->height);
254   cairo_fill(cr);
255   cairo_surface_destroy(surface);
256 }
257
258 static void draw_page(GtkPrintOperation *print,
259                       GtkPrintContext   *context,
260                       gint               page_nr,
261                       PrintData         *data)
262 {
263   // fprintf(stderr, "DEBUG: draw_page() page_nr=%d\n", page_nr);
264   draw_page_cairo(context, data);
265
266 }
267
268 /*********************** page layout gui *********************/
269 typedef struct
270 {
271   PrintData       *data;
272   GtkWidget       *center_combo;
273   GtkWidget       *scale;
274   GtkWidget       *scale_label;
275   GtkWidget       *preview;
276 } CustomWidgetInfo;
277
278 enum
279 {
280   BOTTOM,
281   TOP,
282   RIGHT,
283   LEFT,
284   WIDTH,
285   HEIGHT
286 };
287
288 static gboolean scale_change_value_cb(GtkRange *range, GtkScrollType scroll, gdouble value, CustomWidgetInfo *pinfo);
289 static void get_page_dimensions (CustomWidgetInfo *info, gdouble *page_width, gdouble *page_height, GtkUnit unit);
290 static void center_changed_cb (GtkWidget *combo, CustomWidgetInfo *info);
291 static void get_max_offsets (CustomWidgetInfo *info, gdouble *offset_x_max, gdouble *offset_y_max);
292 static void update_offsets (CustomWidgetInfo *info);
293
294 static void set_scale_label(CustomWidgetInfo *pinfo, gdouble scale_val)
295 {
296   static const gdouble inch_to_mm = 25.4;
297   gchar label_text[64];
298
299   g_snprintf(label_text, sizeof(label_text), "<i>%.0fx%0.f mm (%.0f%%)</i>",
300       inch_to_mm * pinfo->data->width / pinfo->data->xres,
301       inch_to_mm * pinfo->data->height / pinfo->data->yres,
302       scale_val);
303   gtk_label_set_markup (GTK_LABEL (pinfo->scale_label), label_text);
304 }
305
306 static void set_scale_value(CustomWidgetInfo *pinfo)
307 {
308   gdouble width;
309   gdouble height;
310   gdouble ratio, ratio_w, ratio_h;
311
312
313   get_page_dimensions (pinfo, &width, &height, GTK_UNIT_INCH);
314   ratio_w = 100 * pinfo->data->width / pinfo->data->xres / width;
315   ratio_h = 100 * pinfo->data->height / pinfo->data->yres / height;
316
317   ratio = MAX(ratio_w, ratio_h);
318   g_signal_handlers_block_by_func(GTK_RANGE(pinfo->scale), scale_change_value_cb, pinfo);
319   gtk_range_set_value(GTK_RANGE(pinfo->scale), ratio);
320   g_signal_handlers_unblock_by_func(GTK_RANGE(pinfo->scale), scale_change_value_cb, pinfo);
321   set_scale_label(pinfo, ratio);
322 }
323
324 static void update_page_setup (CustomWidgetInfo *pinfo)
325 {
326   gdouble paper_width;
327   gdouble paper_height;
328   gdouble offset_x_max, offset_y_max;
329   PrintData    *data = pinfo->data;
330
331   get_page_dimensions (pinfo, &paper_width, &paper_height, GTK_UNIT_INCH);
332   if ((paper_width < (pinfo->data->width / data->xres)) ||
333       (paper_height < (pinfo->data->height / data->yres))) {
334     gdouble xres, yres;
335     xres = (gdouble) pinfo->data->width / paper_width;
336     yres = (gdouble) pinfo->data->height / paper_height;
337     data->xres = data->yres = MAX(xres, yres);
338     vik_print_preview_set_image_dpi (VIK_PRINT_PREVIEW (pinfo->preview),
339                                   data->xres, data->yres);
340   }
341   get_max_offsets (pinfo, &offset_x_max, &offset_y_max);
342   vik_print_preview_set_image_offsets_max (VIK_PRINT_PREVIEW (pinfo->preview),
343                                             offset_x_max, offset_y_max);
344   update_offsets (pinfo);
345   set_scale_value(pinfo);
346   if (pinfo->preview)
347     vik_print_preview_set_image_offsets (VIK_PRINT_PREVIEW (pinfo->preview),
348                                      pinfo->data->offset_x, pinfo->data->offset_y);
349
350 }
351
352 static void page_setup_cb (GtkWidget *widget, CustomWidgetInfo *info)
353 {
354   PrintData *data = info->data;
355   GtkPrintOperation *operation = data->operation;
356   GtkPrintSettings  *settings;
357   GtkPageSetup      *page_setup;
358   GtkWidget         *toplevel;
359
360   toplevel = gtk_widget_get_toplevel (widget);
361   if (! GTK_WIDGET_TOPLEVEL (toplevel))
362     toplevel = NULL;
363
364   settings = gtk_print_operation_get_print_settings (operation);
365   if (! settings)
366     settings = gtk_print_settings_new ();
367
368   page_setup = gtk_print_operation_get_default_page_setup (operation);
369
370   page_setup = gtk_print_run_page_setup_dialog (GTK_WINDOW (toplevel),
371                                                 page_setup, settings);
372
373   gtk_print_operation_set_default_page_setup (operation, page_setup);
374
375   vik_print_preview_set_page_setup (VIK_PRINT_PREVIEW (info->preview),
376                                      page_setup);
377
378   update_page_setup (info);
379
380 }
381
382 static void full_page_toggled_cb (GtkWidget *widget, CustomWidgetInfo *pinfo)
383 {
384   gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
385
386   pinfo->data->use_full_page = active;
387   update_page_setup (pinfo);
388   vik_print_preview_set_use_full_page (VIK_PRINT_PREVIEW(pinfo->preview),
389                                         active);
390 }
391
392 static void set_center_none (CustomWidgetInfo *info)
393 {
394   info->data->center = VIK_PRINT_CENTER_NONE;
395
396   if (info->center_combo) {
397     g_signal_handlers_block_by_func (info->center_combo,
398                                        center_changed_cb, info);
399
400     info->data->center = VIK_PRINT_CENTER_NONE;
401     gtk_combo_box_set_active(GTK_COMBO_BOX(info->center_combo), info->data->center);
402     g_signal_handlers_unblock_by_func (info->center_combo,
403                                          center_changed_cb, info);
404   }
405 }
406
407 static void preview_offsets_changed_cb (GtkWidget *widget,
408                                         gdouble    offset_x, gdouble    offset_y,
409                                         CustomWidgetInfo *info)
410 {
411   set_center_none (info);
412
413   info->data->offset_x = offset_x;
414   info->data->offset_y = offset_y;
415
416   update_offsets (info);
417
418 }
419
420 static void get_page_dimensions (CustomWidgetInfo *info,
421                                      gdouble       *page_width,
422                                      gdouble       *page_height,
423                                      GtkUnit        unit)
424 {
425   GtkPageSetup *setup;
426
427   setup = gtk_print_operation_get_default_page_setup (info->data->operation);
428
429   *page_width = gtk_page_setup_get_paper_width (setup, unit);
430   *page_height = gtk_page_setup_get_paper_height (setup, unit);
431
432   if (!info->data->use_full_page) {
433     gdouble left_margin = gtk_page_setup_get_left_margin (setup, unit);
434     gdouble right_margin = gtk_page_setup_get_right_margin (setup, unit);
435     gdouble top_margin = gtk_page_setup_get_top_margin (setup, unit);
436     gdouble bottom_margin = gtk_page_setup_get_bottom_margin (setup, unit);
437
438     *page_width -= left_margin + right_margin;
439     *page_height -= top_margin + bottom_margin;
440   }
441
442 }
443
444 static void get_max_offsets (CustomWidgetInfo *info,
445                                        gdouble *offset_x_max,
446                                        gdouble *offset_y_max)
447 {
448   gdouble width;
449   gdouble height;
450
451   get_page_dimensions (info, &width, &height, GTK_UNIT_POINTS);
452
453   *offset_x_max = width - 72.0 * info->data->width / info->data->xres;
454   *offset_x_max = MAX (0, *offset_x_max);
455
456   *offset_y_max = height - 72.0 * info->data->height / info->data->yres;
457   *offset_y_max = MAX (0, *offset_y_max);
458 }
459
460 static void update_offsets (CustomWidgetInfo *info)
461 {
462   PrintData *data = info->data;
463   gdouble    offset_x_max;
464   gdouble    offset_y_max;
465
466   get_max_offsets (info, &offset_x_max, &offset_y_max);
467
468   switch (data->center) {
469     case VIK_PRINT_CENTER_NONE:
470       if (data->offset_x > offset_x_max)
471         data->offset_x = offset_x_max;
472       if (data->offset_y > offset_y_max)
473         data->offset_y = offset_y_max;
474       break;
475
476     case VIK_PRINT_CENTER_HORIZONTALLY:
477       data->offset_x = offset_x_max / 2.0;
478       break;
479
480     case VIK_PRINT_CENTER_VERTICALLY:
481       data->offset_y = offset_y_max / 2.0;
482       break;
483
484     case VIK_PRINT_CENTER_BOTH:
485       data->offset_x = offset_x_max / 2.0;
486       data->offset_y = offset_y_max / 2.0;
487       break;
488     }
489 }
490
491 static void center_changed_cb (GtkWidget *combo, CustomWidgetInfo *info)
492 {
493   info->data->center = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
494   update_offsets (info);
495
496   if (info->preview)
497     vik_print_preview_set_image_offsets (VIK_PRINT_PREVIEW (info->preview),
498                                      info->data->offset_x, info->data->offset_y);
499 }
500
501 static gboolean scale_change_value_cb(GtkRange     *range,
502                                  GtkScrollType scroll,
503                                  gdouble       value,
504                                  CustomWidgetInfo  *pinfo)
505 {
506   gdouble paper_width;
507   gdouble paper_height;
508   gdouble xres, yres, res;
509   gdouble offset_x_max, offset_y_max;
510   gdouble scale = CLAMP(value, 1, 100);
511
512   get_page_dimensions (pinfo, &paper_width, &paper_height, GTK_UNIT_INCH);
513   xres = pinfo->data->width * 100 / paper_width / scale;
514   yres = pinfo->data->height * 100 / paper_height / scale;
515   res = MAX(xres, yres);
516   pinfo->data->xres = pinfo->data->yres = res;
517   get_max_offsets (pinfo, &offset_x_max, &offset_y_max);
518   update_offsets (pinfo);
519   if (pinfo->preview) {
520     vik_print_preview_set_image_dpi (VIK_PRINT_PREVIEW (pinfo->preview),
521                                   pinfo->data->xres, pinfo->data->yres);
522     vik_print_preview_set_image_offsets (VIK_PRINT_PREVIEW (pinfo->preview),
523                                   pinfo->data->offset_x, pinfo->data->offset_y);
524     vik_print_preview_set_image_offsets_max (VIK_PRINT_PREVIEW (pinfo->preview),
525                                             offset_x_max, offset_y_max);
526   }
527
528   set_scale_label(pinfo, scale);
529
530   return FALSE;
531 }
532
533 static void custom_widgets_cleanup(CustomWidgetInfo *info)
534 {
535   g_free(info);
536 }
537
538 static GtkWidget *create_custom_widget_cb(GtkPrintOperation *operation, PrintData *data)
539 {
540   GtkWidget    *layout;
541   GtkWidget    *main_hbox;
542   GtkWidget    *main_vbox;
543   GtkWidget    *hbox;
544   GtkWidget    *vbox;
545   GtkWidget    *button;
546   GtkWidget    *label;
547   GtkPageSetup *setup;
548
549   CustomWidgetInfo  *info = g_malloc0(sizeof(CustomWidgetInfo));
550   g_signal_connect_swapped (data->operation, _("done"), G_CALLBACK (custom_widgets_cleanup), info);
551
552
553   info->data = data;
554
555   setup = gtk_print_operation_get_default_page_setup (data->operation);
556   if (! setup) {
557     setup = gtk_page_setup_new ();
558     gtk_print_operation_set_default_page_setup (data->operation, setup);
559   }
560
561   layout = gtk_vbox_new (FALSE, 6);
562   gtk_container_set_border_width (GTK_CONTAINER (layout), 12);
563
564   /*  main hbox  */
565   main_hbox = gtk_hbox_new (FALSE, 12);
566   gtk_box_pack_start (GTK_BOX (layout), main_hbox, TRUE, TRUE, 0);
567   gtk_widget_show (main_hbox);
568
569   /*  main vbox  */
570   main_vbox = gtk_vbox_new (FALSE, 12);
571   gtk_box_pack_start (GTK_BOX (main_hbox), main_vbox, FALSE, FALSE, 0);
572   gtk_widget_show (main_vbox);
573
574   vbox = gtk_vbox_new (FALSE, 6);
575   gtk_box_pack_start (GTK_BOX (main_vbox), vbox, FALSE, FALSE, 0);
576   gtk_widget_show (vbox);
577
578   /* Page Size */
579   button = gtk_button_new_with_mnemonic (_("_Adjust Page Size "
580                                            "and Orientation"));
581   gtk_box_pack_start (GTK_BOX (main_vbox), button, FALSE, FALSE, 0);
582   g_signal_connect (G_OBJECT (button), "clicked",
583                     G_CALLBACK (page_setup_cb),
584                     info);
585   gtk_widget_show (button);
586
587   /* Center */
588   GtkWidget *combo;
589   const PrintCenterName *center;
590
591   hbox = gtk_hbox_new (FALSE, 6);
592   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
593   gtk_widget_show (hbox);
594
595   label = gtk_label_new_with_mnemonic (_("C_enter:"));
596   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
597   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
598   gtk_widget_show (label);
599
600   combo = gtk_combo_box_new_text ();
601   for (center = center_modes; center->name; center++) {
602     gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _(center->name));
603   }
604   gtk_combo_box_set_active(GTK_COMBO_BOX(combo), VIK_PRINT_CENTER_BOTH);
605   gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
606   gtk_widget_show (combo);
607   gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
608   g_signal_connect(combo, "changed",
609                    G_CALLBACK(center_changed_cb), info);
610   info->center_combo = combo;
611
612   /* ignore page margins */
613   button = gtk_check_button_new_with_mnemonic (_("Ignore Page _Margins"));
614
615   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
616                                 data->use_full_page);
617   gtk_box_pack_start (GTK_BOX (main_vbox), button, FALSE, FALSE, 0);
618   g_signal_connect (button, "toggled",
619                     G_CALLBACK (full_page_toggled_cb),
620                     info);
621   gtk_widget_show (button);
622
623   /* scale */
624   vbox = gtk_vbox_new (FALSE, 1);
625   gtk_box_pack_start (GTK_BOX (main_vbox), vbox, FALSE, FALSE, 0);
626   gtk_widget_show (vbox);
627
628   hbox = gtk_hbox_new (FALSE, 6);
629   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
630   gtk_widget_show (hbox);
631
632   label = gtk_label_new_with_mnemonic (_("Image S_ize:"));
633   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
634   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
635   gtk_widget_show (label);
636
637   label = gtk_label_new (NULL);
638   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
639   info->scale_label = label;
640   gtk_box_pack_start (GTK_BOX (hbox), info->scale_label, TRUE, TRUE, 0);
641   gtk_widget_show (info->scale_label);
642
643   info->scale = gtk_hscale_new_with_range(1, 100, 1);
644   gtk_box_pack_start (GTK_BOX (vbox), info->scale, TRUE, TRUE, 0);
645   gtk_scale_set_draw_value(GTK_SCALE(info->scale), FALSE);
646   gtk_widget_show (info->scale);
647   gtk_label_set_mnemonic_widget (GTK_LABEL (label), info->scale);
648
649   g_signal_connect(info->scale, "change_value",
650                    G_CALLBACK(scale_change_value_cb), info);
651
652
653   info->preview = vik_print_preview_new (setup, GDK_DRAWABLE(vik_viewport_get_pixmap(data->vvp)));
654   vik_print_preview_set_use_full_page (VIK_PRINT_PREVIEW(info->preview),
655                                         data->use_full_page);
656   gtk_box_pack_start (GTK_BOX (main_hbox), info->preview, TRUE, TRUE, 0);
657   gtk_widget_show (info->preview);
658
659   g_signal_connect (info->preview, "offsets-changed",
660                     G_CALLBACK (preview_offsets_changed_cb),
661                     info);
662
663   update_page_setup (info);
664
665   gdouble offset_x_max, offset_y_max;
666   get_max_offsets (info, &offset_x_max, &offset_y_max);
667   vik_print_preview_set_image_offsets_max (VIK_PRINT_PREVIEW (info->preview),
668                                             offset_x_max, offset_y_max);
669
670   set_scale_value(info);
671   
672   return layout;
673 }
674
675 #endif