1 /*
2 * Photos - access, organize and share your photos on GNOME
3 * Copyright © 2006 – 2007 The Free Software Foundation
4 * Copyright © 2013 – 2019 Red Hat, Inc.
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /* Based on code from:
21 * + Eye of GNOME
22 */
23
24
25 #include "config.h"
26
27 #ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
28 #include <langinfo.h>
29 #endif
30
31 #include <glib/gi18n.h>
32 #include <glib/gprintf.h>
33 #include <gtk/gtkunixprint.h>
34
35 #include "photos-gegl.h"
36 #include "photos-print-setup.h"
37 #include "photos-print-preview.h"
38
39
40 struct _PhotosPrintSetup
41 {
42 GtkGrid parent_instance;
43 GeglNode *node;
44 GtkPageSetup *page_setup;
45 GtkWidget *left;
46 GtkWidget *right;
47 GtkWidget *top;
48 GtkWidget *bottom;
49 GtkWidget *center;
50 GtkWidget *width;
51 GtkWidget *height;
52 GtkWidget *scaling;
53 GtkWidget *preview;
54 GtkWidget *unit;
55 GtkUnit current_unit;
56 };
57
58 enum
59 {
60 PROP_0,
61 PROP_NODE,
62 PROP_PAGE_SETUP
63 };
64
65
66 G_DEFINE_TYPE (PhotosPrintSetup, photos_print_setup, GTK_TYPE_GRID);
67
68
69 enum
70 {
71 CENTER_NONE,
72 CENTER_HORIZONTAL,
73 CENTER_VERTICAL,
74 CENTER_BOTH
75 };
76
77 enum
78 {
79 CHANGE_HORIZ,
80 CHANGE_VERT
81 };
82
83 enum
84 {
85 UNIT_INCH,
86 UNIT_MM
87 };
88
89 #define FACTOR_INCH_TO_MM 25.4
90 #define FACTOR_INCH_TO_PIXEL 72.
91 #define FACTOR_MM_TO_INCH 0.03937007874015748
92 #define FACTOR_MM_TO_PIXEL 2.834645669
93
94 static void photos_print_setup_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
95
96 static void on_left_value_changed (GtkSpinButton *spinbutton, gpointer user_data);
97 static void on_right_value_changed (GtkSpinButton *spinbutton, gpointer user_data);
98 static void on_top_value_changed (GtkSpinButton *spinbutton, gpointer user_data);
99 static void on_bottom_value_changed (GtkSpinButton *spinbutton, gpointer user_data);
100
101 static void on_width_value_changed (GtkSpinButton *spinbutton, gpointer user_data);
102 static void on_height_value_changed (GtkSpinButton *spinbutton, gpointer user_data);
103
104
105 static void
photos_print_setup_block_handlers(PhotosPrintSetup * self)106 photos_print_setup_block_handlers (PhotosPrintSetup *self)
107 {
108 g_signal_handlers_block_by_func (self->left, on_left_value_changed, self);
109 g_signal_handlers_block_by_func (self->right, on_right_value_changed, self);
110 g_signal_handlers_block_by_func (self->width, on_width_value_changed, self);
111 g_signal_handlers_block_by_func (self->top, on_top_value_changed, self);
112 g_signal_handlers_block_by_func (self->bottom, on_bottom_value_changed, self);
113 g_signal_handlers_block_by_func (self->height, on_height_value_changed, self);
114 }
115
116
117 static void
photos_print_setup_unblock_handlers(PhotosPrintSetup * self)118 photos_print_setup_unblock_handlers (PhotosPrintSetup *self)
119 {
120 g_signal_handlers_unblock_by_func (self->left, on_left_value_changed, self);
121 g_signal_handlers_unblock_by_func (self->right, on_right_value_changed, self);
122 g_signal_handlers_unblock_by_func (self->width, on_width_value_changed, self);
123 g_signal_handlers_unblock_by_func (self->top, on_top_value_changed, self);
124 g_signal_handlers_unblock_by_func (self->bottom, on_bottom_value_changed, self);
125 g_signal_handlers_unblock_by_func (self->height, on_height_value_changed, self);
126 }
127
128
129 static gdouble
get_scale_to_px_factor(PhotosPrintSetup * self)130 get_scale_to_px_factor (PhotosPrintSetup *self)
131 {
132 gdouble factor = 0.;
133
134 switch (self->current_unit)
135 {
136 case GTK_UNIT_MM:
137 factor = FACTOR_MM_TO_PIXEL;
138 break;
139
140 case GTK_UNIT_INCH:
141 factor = FACTOR_INCH_TO_PIXEL;
142 break;
143
144 case GTK_UNIT_NONE:
145 case GTK_UNIT_POINTS:
146 default:
147 g_assert_not_reached ();
148 }
149
150 return factor;
151 }
152
153
154 static gdouble
photos_print_setup_get_max_percentage(PhotosPrintSetup * self)155 photos_print_setup_get_max_percentage (PhotosPrintSetup *self)
156 {
157 GeglRectangle bbox;
158 gdouble height;
159 gdouble page_height;
160 gdouble page_width;
161 gdouble width;
162 gdouble perc;
163
164 page_width = gtk_page_setup_get_page_width (self->page_setup, GTK_UNIT_INCH);
165 page_height = gtk_page_setup_get_page_height (self->page_setup, GTK_UNIT_INCH);
166 bbox = gegl_node_get_bounding_box (self->node);
167
168 width = (gdouble) bbox.width / FACTOR_INCH_TO_PIXEL;
169 height = (gdouble) bbox.height / FACTOR_INCH_TO_PIXEL;
170
171 if (page_width > width && page_height > height)
172 perc = 1.0;
173 else
174 perc = MIN (page_width / width, page_height / height);
175
176 return perc;
177 }
178
179
180 static void
photos_print_setup_center(gdouble page_width,gdouble width,GtkSpinButton * s_left,GtkSpinButton * s_right)181 photos_print_setup_center (gdouble page_width, gdouble width, GtkSpinButton *s_left, GtkSpinButton *s_right)
182 {
183 gdouble left;
184 gdouble right;
185
186 left = (page_width - width) / 2;
187 right = page_width - left - width;
188 gtk_spin_button_set_value (s_left, left);
189 gtk_spin_button_set_value (s_right, right);
190 }
191
192
193 static void
photos_print_setup_center_changed(GtkComboBox * combobox,gpointer user_data)194 photos_print_setup_center_changed (GtkComboBox *combobox, gpointer user_data)
195 {
196 PhotosPrintSetup *self = PHOTOS_PRINT_SETUP (user_data);
197 gint active;
198
199 active = gtk_combo_box_get_active (combobox);
200
201 switch (active)
202 {
203 case CENTER_HORIZONTAL:
204 photos_print_setup_center (gtk_page_setup_get_page_width (self->page_setup, self->current_unit),
205 gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->width)),
206 GTK_SPIN_BUTTON (self->left),
207 GTK_SPIN_BUTTON (self->right));
208 break;
209
210 case CENTER_VERTICAL:
211 photos_print_setup_center (gtk_page_setup_get_page_height (self->page_setup, self->current_unit),
212 gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->height)),
213 GTK_SPIN_BUTTON (self->top),
214 GTK_SPIN_BUTTON (self->bottom));
215 break;
216
217 case CENTER_BOTH:
218 photos_print_setup_center (gtk_page_setup_get_page_width (self->page_setup, self->current_unit),
219 gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->width)),
220 GTK_SPIN_BUTTON (self->left),
221 GTK_SPIN_BUTTON (self->right));
222 photos_print_setup_center (gtk_page_setup_get_page_height (self->page_setup, self->current_unit),
223 gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->height)),
224 GTK_SPIN_BUTTON (self->top),
225 GTK_SPIN_BUTTON (self->bottom));
226 break;
227
228 case CENTER_NONE:
229 default:
230 break;
231 }
232
233 gtk_combo_box_set_active (combobox, active);
234 }
235
236
237 static void
update_image_pos_ranges(PhotosPrintSetup * self,gdouble page_width,gdouble page_height,gdouble width,gdouble height)238 update_image_pos_ranges (PhotosPrintSetup *self,
239 gdouble page_width,
240 gdouble page_height,
241 gdouble width,
242 gdouble height)
243 {
244 gtk_spin_button_set_range (GTK_SPIN_BUTTON (self->left), 0, page_width - width);
245 gtk_spin_button_set_range (GTK_SPIN_BUTTON (self->right), 0, page_width - width);
246 gtk_spin_button_set_range (GTK_SPIN_BUTTON (self->top), 0, page_height - height);
247 gtk_spin_button_set_range (GTK_SPIN_BUTTON (self->bottom), 0, page_height - height);
248 }
249
250
251 static void
on_scale_changed(GtkRange * range,gpointer user_data)252 on_scale_changed (GtkRange *range, gpointer user_data)
253 {
254 PhotosPrintSetup *self = PHOTOS_PRINT_SETUP (user_data);
255 GeglRectangle bbox;
256 gdouble height;
257 gdouble scale;
258 gdouble width;
259 gdouble left, right, top, bottom;
260 gdouble page_width, page_height;
261 gdouble factor;
262
263 gtk_combo_box_set_active (GTK_COMBO_BOX (self->center), CENTER_NONE);
264
265 bbox = gegl_node_get_bounding_box (self->node);
266 factor = get_scale_to_px_factor (self);
267
268 width = (gdouble) bbox.width / factor;
269 height = (gdouble) bbox.height / factor;
270
271 left = gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->left));
272 top = gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->top));
273
274 scale = CLAMP (0.01 * gtk_range_get_value (range), 0, photos_print_setup_get_max_percentage (self));
275
276 photos_print_preview_set_scale (PHOTOS_PRINT_PREVIEW (self->preview), scale);
277
278 width *= scale;
279 height *= scale;
280
281 page_width = gtk_page_setup_get_page_width (self->page_setup, self->current_unit);
282 page_height = gtk_page_setup_get_page_height (self->page_setup, self->current_unit);
283
284 update_image_pos_ranges (self, page_width, page_height, width, height);
285
286 right = page_width - left - width;
287 bottom = page_height - top - height;
288
289 gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->width), width);
290 gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->height), height);
291 gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->right), right);
292 gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->bottom), bottom);
293 }
294
295
296 static gchar *
on_scale_format_value(GtkScale * scale,gdouble value)297 on_scale_format_value (GtkScale *scale, gdouble value)
298 {
299 return g_strdup_printf ("%i%%", (gint) value);
300 }
301
302
303 static void
photos_print_setup_position_values_changed(PhotosPrintSetup * self,GtkWidget * w_changed,GtkWidget * w_to_update,GtkWidget * w_size,gdouble total_size,gint change)304 photos_print_setup_position_values_changed (PhotosPrintSetup *self,
305 GtkWidget *w_changed,
306 GtkWidget *w_to_update,
307 GtkWidget *w_size,
308 gdouble total_size,
309 gint change)
310 {
311 gdouble changed, to_update, size;
312 gdouble pos;
313
314 size = gtk_spin_button_get_value (GTK_SPIN_BUTTON (w_size));
315 changed = gtk_spin_button_get_value (GTK_SPIN_BUTTON (w_changed));
316
317 to_update = total_size - changed - size;
318 gtk_spin_button_set_value (GTK_SPIN_BUTTON (w_to_update), to_update);
319 gtk_combo_box_set_active (GTK_COMBO_BOX (self->center), CENTER_NONE);
320
321 switch (change)
322 {
323 case CHANGE_HORIZ:
324 pos = gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->left));
325 if (self->current_unit == GTK_UNIT_MM)
326 pos *= FACTOR_MM_TO_INCH;
327 photos_print_preview_set_image_position (PHOTOS_PRINT_PREVIEW (self->preview), pos, -1);
328 break;
329
330 case CHANGE_VERT:
331 pos = gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->top));
332 if (self->current_unit == GTK_UNIT_MM)
333 pos *= FACTOR_MM_TO_INCH;
334 photos_print_preview_set_image_position (PHOTOS_PRINT_PREVIEW (self->preview), -1, pos);
335 break;
336
337 default:
338 g_assert_not_reached ();
339 break;
340 }
341 }
342
343
344 static void
on_left_value_changed(GtkSpinButton * spinbutton,gpointer user_data)345 on_left_value_changed (GtkSpinButton *spinbutton, gpointer user_data)
346 {
347 PhotosPrintSetup *self = PHOTOS_PRINT_SETUP (user_data);
348
349 photos_print_setup_position_values_changed (self,
350 self->left,
351 self->right,
352 self->width,
353 gtk_page_setup_get_page_width (self->page_setup,
354 self->current_unit),
355 CHANGE_HORIZ);
356 }
357
358
359 static void
on_right_value_changed(GtkSpinButton * spinbutton,gpointer user_data)360 on_right_value_changed (GtkSpinButton *spinbutton, gpointer user_data)
361 {
362 PhotosPrintSetup *self = PHOTOS_PRINT_SETUP (user_data);
363
364 photos_print_setup_position_values_changed (self,
365 self->right,
366 self->left,
367 self->width,
368 gtk_page_setup_get_page_width (self->page_setup,
369 self->current_unit),
370 CHANGE_HORIZ);
371 }
372
373
374 static void
on_top_value_changed(GtkSpinButton * spinbutton,gpointer user_data)375 on_top_value_changed (GtkSpinButton *spinbutton,
376 gpointer user_data)
377 {
378 PhotosPrintSetup *self = PHOTOS_PRINT_SETUP (user_data);
379
380 photos_print_setup_position_values_changed (self,
381 self->top,
382 self->bottom,
383 self->height,
384 gtk_page_setup_get_page_height (self->page_setup,
385 self->current_unit),
386 CHANGE_VERT);
387 }
388
389
390 static void
on_bottom_value_changed(GtkSpinButton * spinbutton,gpointer user_data)391 on_bottom_value_changed (GtkSpinButton *spinbutton, gpointer user_data)
392 {
393 PhotosPrintSetup *self = PHOTOS_PRINT_SETUP (user_data);
394
395 photos_print_setup_position_values_changed (self,
396 self->bottom,
397 self->top,
398 self->height,
399 gtk_page_setup_get_page_height (self->page_setup,
400 self->current_unit),
401 CHANGE_VERT);
402 }
403
404
405 static void
photos_print_setup_size_changed(PhotosPrintSetup * self,GtkWidget * w_size_x,GtkWidget * w_size_y,GtkWidget * w_margin_x_1,GtkWidget * w_margin_x_2,GtkWidget * w_margin_y_1,GtkWidget * w_margin_y_2,gdouble page_size_x,gdouble page_size_y,gint change)406 photos_print_setup_size_changed (PhotosPrintSetup *self,
407 GtkWidget *w_size_x,
408 GtkWidget *w_size_y,
409 GtkWidget *w_margin_x_1,
410 GtkWidget *w_margin_x_2,
411 GtkWidget *w_margin_y_1,
412 GtkWidget *w_margin_y_2,
413 gdouble page_size_x,
414 gdouble page_size_y,
415 gint change)
416 {
417 GeglRectangle bbox;
418 gdouble margin_x_1, margin_x_2;
419 gdouble margin_y_1, margin_y_2;
420 gdouble orig_size_x = -1, orig_size_y = -1, scale;
421 gdouble size_x, size_y;
422 gdouble factor;
423
424 size_x = gtk_spin_button_get_value (GTK_SPIN_BUTTON (w_size_x));
425 margin_x_1 = gtk_spin_button_get_value (GTK_SPIN_BUTTON (w_margin_x_1));
426 margin_y_1 = gtk_spin_button_get_value (GTK_SPIN_BUTTON (w_margin_y_1));
427
428 bbox = gegl_node_get_bounding_box (self->node);
429 factor = get_scale_to_px_factor (self);
430
431 switch (change)
432 {
433 case CHANGE_HORIZ:
434 orig_size_x = (gdouble) bbox.width / factor;
435 orig_size_y = (gdouble) bbox.height / factor;
436 break;
437
438 case CHANGE_VERT:
439 orig_size_y = (gdouble) bbox.width / factor;
440 orig_size_x = (gdouble) bbox.height / factor;
441 break;
442
443 default:
444 g_assert_not_reached ();
445 break;
446 }
447
448 scale = CLAMP (size_x / orig_size_x, 0, 1);
449
450 size_y = scale * orig_size_y;
451
452 margin_x_2 = page_size_x - margin_x_1 - size_x;
453 margin_y_2 = page_size_y - margin_y_1 - size_y;
454
455 photos_print_preview_set_scale (PHOTOS_PRINT_PREVIEW (self->preview), scale);
456
457 switch (change)
458 {
459 case CHANGE_HORIZ:
460 update_image_pos_ranges (self, page_size_x, page_size_y, size_x, size_y);
461 break;
462
463 case CHANGE_VERT:
464 update_image_pos_ranges (self, page_size_y, page_size_x, size_y, size_x);
465 break;
466
467 default:
468 g_assert_not_reached ();
469 break;
470 }
471
472 gtk_range_set_value (GTK_RANGE (self->scaling), 100*scale);
473
474 gtk_spin_button_set_value (GTK_SPIN_BUTTON (w_margin_x_2), margin_x_2);
475 gtk_spin_button_set_value (GTK_SPIN_BUTTON (w_size_y), size_y);
476 gtk_spin_button_set_value (GTK_SPIN_BUTTON (w_margin_y_2), margin_y_2);
477
478 gtk_combo_box_set_active (GTK_COMBO_BOX (self->center), CENTER_NONE);
479 }
480
481 static void
on_width_value_changed(GtkSpinButton * spinbutton,gpointer user_data)482 on_width_value_changed (GtkSpinButton *spinbutton, gpointer user_data)
483 {
484 PhotosPrintSetup *self = PHOTOS_PRINT_SETUP (user_data);
485
486 photos_print_setup_size_changed (self,
487 self->width,
488 self->height,
489 self->left,
490 self->right,
491 self->top,
492 self->bottom,
493 gtk_page_setup_get_page_width (self->page_setup, self->current_unit),
494 gtk_page_setup_get_page_height (self->page_setup, self->current_unit),
495 CHANGE_HORIZ);
496 }
497
498
499 static void
on_height_value_changed(GtkSpinButton * spinbutton,gpointer user_data)500 on_height_value_changed (GtkSpinButton *spinbutton, gpointer user_data)
501 {
502 PhotosPrintSetup *self = PHOTOS_PRINT_SETUP (user_data);
503
504 photos_print_setup_size_changed (self,
505 self->height,
506 self->width,
507 self->top,
508 self->bottom,
509 self->left,
510 self->right,
511 gtk_page_setup_get_page_height (self->page_setup, self->current_unit),
512 gtk_page_setup_get_page_width (self->page_setup, self->current_unit),
513 CHANGE_VERT);
514 }
515
516
517 static void
change_unit(GtkSpinButton * spinbutton,gdouble factor,gint digits,gdouble step,gdouble page)518 change_unit (GtkSpinButton *spinbutton, gdouble factor, gint digits, gdouble step, gdouble page)
519 {
520 gdouble value;
521 gdouble range;
522
523 gtk_spin_button_get_range (spinbutton, NULL, &range);
524 range *= factor;
525
526 value = gtk_spin_button_get_value (spinbutton);
527 value *= factor;
528
529 gtk_spin_button_set_range (spinbutton, 0, range);
530 gtk_spin_button_set_value (spinbutton, value);
531 gtk_spin_button_set_digits (spinbutton, digits);
532 gtk_spin_button_set_increments (spinbutton, step, page);
533 }
534
535
536 static void
photos_print_setup_set_scale_unit(PhotosPrintSetup * self,GtkUnit unit)537 photos_print_setup_set_scale_unit (PhotosPrintSetup *self, GtkUnit unit)
538 {
539 gdouble factor;
540 gdouble step, page;
541 gint digits;
542
543 if (G_UNLIKELY (self->current_unit == unit))
544 return;
545
546 switch (unit)
547 {
548 case GTK_UNIT_MM:
549 factor = FACTOR_INCH_TO_MM;
550 digits = 0;
551 step = 1;
552 page = 10;
553 break;
554
555 case GTK_UNIT_INCH:
556 factor = FACTOR_MM_TO_INCH;
557 digits = 2;
558 step = 0.01;
559 page = 0.1;
560 break;
561
562 case GTK_UNIT_NONE:
563 case GTK_UNIT_POINTS:
564 default:
565 g_assert_not_reached ();
566 }
567
568 photos_print_setup_block_handlers (self);
569
570 change_unit (GTK_SPIN_BUTTON (self->width), factor, digits, step, page);
571 change_unit (GTK_SPIN_BUTTON (self->height), factor, digits, step, page);
572 change_unit (GTK_SPIN_BUTTON (self->left), factor, digits, step, page);
573 change_unit (GTK_SPIN_BUTTON (self->right), factor, digits, step, page);
574 change_unit (GTK_SPIN_BUTTON (self->top), factor, digits, step, page);
575 change_unit (GTK_SPIN_BUTTON (self->bottom), factor, digits, step, page);
576
577 photos_print_setup_unblock_handlers (self);
578
579 self->current_unit = unit;
580 }
581
582
583 static void
on_unit_changed(GtkComboBox * combobox,gpointer user_data)584 on_unit_changed (GtkComboBox *combobox, gpointer user_data)
585 {
586 GtkUnit unit = GTK_UNIT_INCH;
587
588 switch (gtk_combo_box_get_active (combobox))
589 {
590 case UNIT_INCH:
591 unit = GTK_UNIT_INCH;
592 break;
593
594 case UNIT_MM:
595 unit = GTK_UNIT_MM;
596 break;
597
598 default:
599 g_assert_not_reached ();
600 }
601
602 photos_print_setup_set_scale_unit (PHOTOS_PRINT_SETUP (user_data), unit);
603 }
604
605
606 static void
on_preview_pixbuf_moved(PhotosPrintPreview * preview,gpointer user_data)607 on_preview_pixbuf_moved (PhotosPrintPreview *preview, gpointer user_data)
608 {
609 PhotosPrintSetup *self = PHOTOS_PRINT_SETUP (user_data);
610 gdouble x;
611 gdouble y;
612
613 photos_print_preview_get_image_position (preview, &x, &y);
614
615 if (self->current_unit == GTK_UNIT_MM)
616 {
617 x *= FACTOR_INCH_TO_MM;
618 y *= FACTOR_INCH_TO_MM;
619 }
620
621 gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->left), x);
622 gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->top), y);
623 }
624
625
626 static gboolean
on_preview_image_scrolled(GtkWidget * widget,GdkEventScroll * event,gpointer user_data)627 on_preview_image_scrolled (GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
628 {
629 PhotosPrintSetup *self = PHOTOS_PRINT_SETUP (user_data);
630 PhotosPrintPreview *preview = PHOTOS_PRINT_PREVIEW (widget);
631 gfloat scale;
632
633 scale = photos_print_preview_get_scale (preview);
634
635 if (!photos_print_preview_point_in_image_area (preview, event->x, event->y))
636 return FALSE;
637
638 switch (event->direction)
639 {
640 case GDK_SCROLL_UP:
641 /* scale up */
642 scale *= 1.1;
643 break;
644
645 case GDK_SCROLL_DOWN:
646 /* scale down */
647 scale *= 0.9;
648 break;
649
650 case GDK_SCROLL_LEFT:
651 case GDK_SCROLL_RIGHT:
652 case GDK_SCROLL_SMOOTH:
653 default:
654 return FALSE;
655 break;
656 }
657
658 gtk_range_set_value (GTK_RANGE (self->scaling), 100*scale);
659
660 return TRUE;
661 }
662
663
664 static gboolean
on_preview_image_key_pressed(GtkWidget * widget,GdkEventKey * event,gpointer user_data)665 on_preview_image_key_pressed (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
666 {
667 PhotosPrintSetup *self = PHOTOS_PRINT_SETUP (user_data);
668 PhotosPrintPreview *preview = PHOTOS_PRINT_PREVIEW (widget);
669 gfloat scale;
670
671 scale = photos_print_preview_get_scale (preview);
672
673 switch (event->keyval)
674 {
675 case GDK_KEY_KP_Add:
676 case GDK_KEY_plus:
677 /* scale up */
678 scale *= 1.1;
679 break;
680
681 case GDK_KEY_KP_Subtract:
682 case GDK_KEY_minus:
683 /* scale down */
684 scale *= 0.9;
685 break;
686
687 default:
688 return FALSE;
689 break;
690 }
691
692 gtk_range_set_value (GTK_RANGE (self->scaling), 100 * scale);
693
694 return TRUE;
695 }
696
697
698 /* Function taken from gtkprintunixdialog.c */
699 static GtkWidget *
photos_print_setup_wrap_in_frame(const gchar * label,GtkWidget * child)700 photos_print_setup_wrap_in_frame (const gchar *label, GtkWidget *child)
701 {
702 GtkWidget *frame;
703 GtkWidget *label_widget;
704 gchar *bold_text;
705
706 label_widget = gtk_label_new ("");
707 gtk_label_set_xalign (GTK_LABEL (label_widget), 0.0);
708 gtk_widget_show (label_widget);
709
710 bold_text = g_markup_printf_escaped ("<b>%s</b>", label);
711 gtk_label_set_markup (GTK_LABEL (label_widget), bold_text);
712 g_free (bold_text);
713
714 frame = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
715 gtk_box_pack_start (GTK_BOX (frame), label_widget, FALSE, FALSE, 0);
716
717 gtk_widget_set_margin_start (child, 12);
718 gtk_widget_set_halign (child, GTK_ALIGN_FILL);
719 gtk_widget_set_valign (child, GTK_ALIGN_FILL);
720
721 gtk_box_pack_start (GTK_BOX (frame), child, FALSE, FALSE, 0);
722
723 gtk_widget_show (frame);
724
725 return frame;
726 }
727
728
729 static GtkWidget *
grid_attach_spin_button_with_label(GtkWidget * grid,const gchar * text_label,gint left,gint top)730 grid_attach_spin_button_with_label (GtkWidget *grid, const gchar* text_label, gint left, gint top)
731 {
732 GtkWidget *label;
733 GtkWidget *spin_button;
734
735 label = gtk_label_new_with_mnemonic (text_label);
736 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
737 spin_button = gtk_spin_button_new_with_range (0, 100, 0.01);
738 gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spin_button), 2);
739 gtk_entry_set_width_chars (GTK_ENTRY (spin_button), 6);
740 gtk_grid_attach (GTK_GRID (grid), label, left, top, 1, 1);
741 gtk_grid_attach_next_to (GTK_GRID (grid), spin_button, label, GTK_POS_RIGHT, 1, 1);
742 gtk_label_set_mnemonic_widget (GTK_LABEL (label), spin_button);
743
744 return spin_button;
745 }
746
747
748 static void
photos_print_setup_set_initial_values(PhotosPrintSetup * self)749 photos_print_setup_set_initial_values (PhotosPrintSetup *self)
750 {
751 GeglRectangle bbox;
752 gdouble page_height;
753 gdouble page_width;
754 gdouble factor;
755 gdouble height;
756 gdouble max_perc;
757 gdouble width;
758
759 factor = get_scale_to_px_factor (self);
760
761 bbox = gegl_node_get_bounding_box (self->node);
762 width = (gdouble) bbox.width/factor;
763 height = (gdouble) bbox.height/factor;
764
765 max_perc = photos_print_setup_get_max_percentage (self);
766
767 width *= max_perc;
768 height *= max_perc;
769
770 gtk_range_set_range (GTK_RANGE (self->scaling), 1, 100 * max_perc);
771 gtk_range_set_increments (GTK_RANGE (self->scaling), max_perc, 10 * max_perc);
772 gtk_range_set_value (GTK_RANGE (self->scaling), 100 * max_perc);
773
774 photos_print_preview_set_scale (PHOTOS_PRINT_PREVIEW (self->preview), max_perc);
775 gtk_spin_button_set_range (GTK_SPIN_BUTTON (self->width), 0, width);
776 gtk_spin_button_set_range (GTK_SPIN_BUTTON (self->height), 0, height);
777 gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->width), width);
778 gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->height), height);
779
780 gtk_combo_box_set_active (GTK_COMBO_BOX (self->center), CENTER_BOTH);
781
782 photos_print_setup_center (gtk_page_setup_get_page_width (self->page_setup, self->current_unit),
783 gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->width)),
784 GTK_SPIN_BUTTON (self->left), GTK_SPIN_BUTTON (self->right));
785 photos_print_setup_center (gtk_page_setup_get_page_height (self->page_setup, self->current_unit),
786 gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->height)),
787 GTK_SPIN_BUTTON (self->top), GTK_SPIN_BUTTON (self->bottom));
788
789 page_width = gtk_page_setup_get_page_width (self->page_setup, self->current_unit);
790 page_height = gtk_page_setup_get_page_height (self->page_setup, self->current_unit);
791
792 update_image_pos_ranges (self, page_width, page_height, width, height);
793 }
794
795
796 static void
photos_print_setup_constructed(GObject * object)797 photos_print_setup_constructed (GObject *object)
798 {
799 PhotosPrintSetup *self = PHOTOS_PRINT_SETUP (object);
800
801 G_OBJECT_CLASS (photos_print_setup_parent_class)->constructed (object);
802
803 photos_print_setup_set_initial_values (self);
804 photos_print_preview_set_from_page_setup (PHOTOS_PRINT_PREVIEW (self->preview), self->page_setup);
805
806 g_signal_connect (self->left, "value-changed", G_CALLBACK (on_left_value_changed), self);
807 g_signal_connect (self->right, "value-changed", G_CALLBACK (on_right_value_changed), self);
808 g_signal_connect (self->top, "value-changed", G_CALLBACK (on_top_value_changed), self);
809 g_signal_connect (self->bottom, "value-changed", G_CALLBACK (on_bottom_value_changed), self);
810 g_signal_connect (self->width, "value-changed", G_CALLBACK (on_width_value_changed), self);
811 g_signal_connect (self->height, "value-changed", G_CALLBACK (on_height_value_changed), self);
812 g_signal_connect (self->scaling, "value-changed", G_CALLBACK (on_scale_changed), self);
813 g_signal_connect (self->scaling, "format-value", G_CALLBACK (on_scale_format_value), NULL);
814 g_signal_connect (self->preview, "pixbuf-moved", G_CALLBACK (on_preview_pixbuf_moved), self);
815 g_signal_connect (self->preview, "scroll-event", G_CALLBACK (on_preview_image_scrolled), self);
816 g_signal_connect (self->preview, "key-press-event", G_CALLBACK (on_preview_image_key_pressed), self);
817 }
818
819
820 static void
photos_print_setup_dispose(GObject * object)821 photos_print_setup_dispose (GObject *object)
822 {
823 PhotosPrintSetup *self = PHOTOS_PRINT_SETUP (object);
824
825 g_clear_object (&self->node);
826 g_clear_object (&self->page_setup);
827
828 G_OBJECT_CLASS (photos_print_setup_parent_class)->dispose (object);
829 }
830
831
832 static void
photos_print_setup_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)833 photos_print_setup_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
834 {
835 PhotosPrintSetup *self = PHOTOS_PRINT_SETUP (object);
836
837 switch (prop_id)
838 {
839 case PROP_NODE:
840 {
841 GdkPixbuf *pixbuf;
842
843 self->node = GEGL_NODE (g_value_dup_object (value));
844 pixbuf = photos_gegl_create_pixbuf_from_node (self->node);
845 if (pixbuf != NULL)
846 {
847 g_object_set (self->preview, "pixbuf", pixbuf, NULL);
848 g_object_unref (pixbuf);
849 }
850 }
851 break;
852
853 case PROP_PAGE_SETUP:
854 self->page_setup = GTK_PAGE_SETUP (g_value_dup_object (value));
855 break;
856
857 default:
858 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
859 }
860 }
861
862
863 static void
photos_print_setup_init(PhotosPrintSetup * self)864 photos_print_setup_init (PhotosPrintSetup *self)
865 {
866 GtkWidget *frame;
867 GtkWidget *grid;
868 GtkWidget *label;
869 GtkWidget *hscale;
870 GtkWidget *combobox;
871
872 #ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
873 gchar *locale_scale = NULL;
874 #endif
875
876 gtk_container_set_border_width (GTK_CONTAINER (self), 12);
877 gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_VERTICAL);
878 gtk_grid_set_column_spacing (GTK_GRID (self), 18);
879 gtk_grid_set_row_spacing (GTK_GRID (self), 18);
880
881 grid = gtk_grid_new ();
882 gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
883 gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
884 frame = photos_print_setup_wrap_in_frame (_("Position"), grid);
885 gtk_grid_attach (GTK_GRID (self), frame, 0, 0, 1, 1);
886
887 self->left = grid_attach_spin_button_with_label (grid, _("_Left:"), 0, 0);
888 self->right = grid_attach_spin_button_with_label (grid,_("_Right:"), 0, 1);
889 self->top = grid_attach_spin_button_with_label (grid, _("_Top:"), 2, 0);
890 self->bottom = grid_attach_spin_button_with_label (grid, _("_Bottom:"), 2, 1);
891
892 label = gtk_label_new_with_mnemonic (_("C_enter:"));
893 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
894
895 combobox = gtk_combo_box_text_new ();
896 gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combobox), CENTER_NONE, _("None"));
897 gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combobox), CENTER_HORIZONTAL, _("Horizontal"));
898 gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combobox), CENTER_VERTICAL, _("Vertical"));
899 gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combobox), CENTER_BOTH, _("Both"));
900 gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), CENTER_NONE);
901 /* Attach combobox below right margin spinbutton and span until end */
902 gtk_grid_attach_next_to (GTK_GRID (grid), combobox, self->right, GTK_POS_BOTTOM, 3, 1);
903 /* Attach the label to the left of the combobox */
904 gtk_grid_attach_next_to (GTK_GRID (grid), label, combobox, GTK_POS_LEFT, 1, 1);
905 gtk_label_set_mnemonic_widget (GTK_LABEL (label), combobox);
906 self->center = combobox;
907 g_signal_connect (G_OBJECT (combobox), "changed", G_CALLBACK (photos_print_setup_center_changed), self);
908
909 grid = gtk_grid_new ();
910 gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
911 gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
912 frame = photos_print_setup_wrap_in_frame (_("Size"), grid);
913 gtk_grid_attach (GTK_GRID (self), frame, 0, 1, 1, 1);
914
915 self->width = grid_attach_spin_button_with_label (grid, _("_Width:"), 0, 0);
916 self->height = grid_attach_spin_button_with_label (grid, _("_Height:"), 2, 0);
917
918 label = gtk_label_new_with_mnemonic (_("_Scaling:"));
919 hscale = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 1, 100, 1);
920 gtk_scale_set_value_pos (GTK_SCALE (hscale), GTK_POS_RIGHT);
921 gtk_range_set_value (GTK_RANGE (hscale), 100);
922 gtk_grid_attach_next_to (GTK_GRID (grid), hscale, self->width, GTK_POS_BOTTOM, 3, 1);
923 gtk_grid_attach_next_to (GTK_GRID (grid), label, hscale, GTK_POS_LEFT, 1, 1);
924 gtk_label_set_mnemonic_widget (GTK_LABEL (label), hscale);
925 self->scaling = hscale;
926
927 label = gtk_label_new_with_mnemonic (_("_Unit:"));
928 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
929
930 combobox = gtk_combo_box_text_new ();
931 gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combobox), UNIT_MM, _("Millimeters"));
932 gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combobox), UNIT_INCH, _("Inches"));
933
934 #ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
935 locale_scale = nl_langinfo (_NL_MEASUREMENT_MEASUREMENT);
936 if (locale_scale && locale_scale[0] == 2)
937 {
938 gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), UNIT_INCH);
939 photos_print_setup_set_scale_unit (self, GTK_UNIT_INCH);
940 }
941 else
942 #endif
943 {
944 gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), UNIT_MM);
945 photos_print_setup_set_scale_unit (self, GTK_UNIT_MM);
946 }
947
948 gtk_grid_attach_next_to (GTK_GRID (grid), combobox, hscale, GTK_POS_BOTTOM, 3, 1);
949 gtk_grid_attach_next_to (GTK_GRID (grid), label, combobox, GTK_POS_LEFT, 1, 1);
950
951 gtk_label_set_mnemonic_widget (GTK_LABEL (label), combobox);
952 self->unit = combobox;
953 g_signal_connect (G_OBJECT (combobox), "changed", G_CALLBACK (on_unit_changed), self);
954
955 self->preview = photos_print_preview_new ();
956
957 /* FIXME: This shouldn't be set by hand */
958 gtk_widget_set_size_request (self->preview, 250, 250);
959
960 frame = photos_print_setup_wrap_in_frame (_("Preview"), self->preview);
961 /* The preview widget needs to span the whole grid height */
962 gtk_grid_attach (GTK_GRID (self), frame, 1, 0, 1, 2);
963
964 gtk_widget_show_all (GTK_WIDGET (self));
965 }
966
967
968 static void
photos_print_setup_class_init(PhotosPrintSetupClass * class)969 photos_print_setup_class_init (PhotosPrintSetupClass *class)
970 {
971 GObjectClass *object_class = G_OBJECT_CLASS (class);
972
973 object_class->constructed = photos_print_setup_constructed;
974 object_class->dispose = photos_print_setup_dispose;
975 object_class->set_property = photos_print_setup_set_property;
976
977 g_object_class_install_property (object_class,
978 PROP_NODE,
979 g_param_spec_object ("node",
980 "GeglNode object",
981 "The node corresponding to the item whose printing "
982 "properties will be set up",
983 GEGL_TYPE_NODE,
984 G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
985
986 g_object_class_install_property (object_class,
987 PROP_PAGE_SETUP,
988 g_param_spec_object ("page-setup",
989 "GtkPageSetup object",
990 "The information for the page where the item will be "
991 "printed",
992 GTK_TYPE_PAGE_SETUP,
993 G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
994 }
995
996
997 GtkWidget *
photos_print_setup_new(GeglNode * node,GtkPageSetup * page_setup)998 photos_print_setup_new (GeglNode *node, GtkPageSetup *page_setup)
999 {
1000 return g_object_new (PHOTOS_TYPE_PRINT_SETUP, "node", node, "page-setup", page_setup, NULL);
1001 }
1002
1003
1004 void
photos_print_setup_get_options(PhotosPrintSetup * self,gdouble * left,gdouble * top,gdouble * scale,GtkUnit * unit)1005 photos_print_setup_get_options (PhotosPrintSetup *self,
1006 gdouble *left,
1007 gdouble *top,
1008 gdouble *scale,
1009 GtkUnit *unit)
1010 {
1011 *left = gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->left));
1012 *top = gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->top));
1013 *scale = gtk_range_get_value (GTK_RANGE (self->scaling));
1014 *unit = self->current_unit;
1015 }
1016
1017
1018 void
photos_print_setup_update(PhotosPrintSetup * self,GtkPageSetup * page_setup)1019 photos_print_setup_update (PhotosPrintSetup *self, GtkPageSetup *page_setup)
1020 {
1021 gdouble pos_x;
1022 gdouble pos_y;
1023
1024 self->page_setup = gtk_page_setup_copy (page_setup);
1025
1026 photos_print_setup_set_initial_values (PHOTOS_PRINT_SETUP (self));
1027
1028 photos_print_preview_set_from_page_setup (PHOTOS_PRINT_PREVIEW (self->preview), self->page_setup);
1029
1030 pos_x = gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->left));
1031 pos_y = gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->top));
1032 if (self->current_unit == GTK_UNIT_MM)
1033 {
1034 pos_x *= FACTOR_MM_TO_INCH;
1035 pos_y *= FACTOR_MM_TO_INCH;
1036 }
1037 photos_print_preview_set_image_position (PHOTOS_PRINT_PREVIEW (self->preview), pos_x, pos_y);
1038 }
1039