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