1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19
20 #include <libgimp/gimp.h>
21 #include <libgimp/gimpui.h>
22
23 #include "print-preview.h"
24
25
26 enum
27 {
28 OFFSETS_CHANGED,
29 LAST_SIGNAL
30 };
31
32
33 #define SIZE_REQUEST 200
34
35
36 struct _PrintPreview
37 {
38 GtkEventBox parent_instance;
39
40 GdkCursor *cursor;
41
42 GtkPageSetup *page;
43 cairo_surface_t *thumbnail;
44 gboolean dragging;
45 gboolean inside;
46
47 gint32 drawable_id;
48
49 gdouble image_offset_x;
50 gdouble image_offset_y;
51 gdouble image_offset_x_max;
52 gdouble image_offset_y_max;
53 gdouble image_width;
54 gdouble image_height;
55
56 gboolean use_full_page;
57
58 /* for mouse drags */
59 gdouble orig_offset_x;
60 gdouble orig_offset_y;
61 gint start_x;
62 gint start_y;
63 };
64
65 struct _PrintPreviewClass
66 {
67 GtkEventBoxClass parent_class;
68
69 void (* offsets_changed) (PrintPreview *print_preview,
70 gint offset_x,
71 gint offset_y);
72 };
73
74
75 static void print_preview_finalize (GObject *object);
76
77 static void print_preview_realize (GtkWidget *widget);
78 static void print_preview_unrealize (GtkWidget *widget);
79 static void print_preview_size_request (GtkWidget *widget,
80 GtkRequisition *requisition);
81 static void print_preview_size_allocate (GtkWidget *widget,
82 GtkAllocation *allocation);
83 static gboolean print_preview_expose_event (GtkWidget *widget,
84 GdkEventExpose *event);
85 static gboolean print_preview_button_press_event (GtkWidget *widget,
86 GdkEventButton *event);
87 static gboolean print_preview_button_release_event (GtkWidget *widget,
88 GdkEventButton *event);
89 static gboolean print_preview_motion_notify_event (GtkWidget *widget,
90 GdkEventMotion *event);
91 static gboolean print_preview_leave_notify_event (GtkWidget *widget,
92 GdkEventCrossing *event);
93
94 static gboolean print_preview_is_inside (PrintPreview *preview,
95 gdouble x,
96 gdouble y);
97 static void print_preview_set_inside (PrintPreview *preview,
98 gboolean inside);
99
100 static gdouble print_preview_get_scale (PrintPreview *preview);
101
102 static void print_preview_get_page_size (PrintPreview *preview,
103 gdouble *paper_width,
104 gdouble *paper_height);
105 static void print_preview_get_page_margins (PrintPreview *preview,
106 gdouble *left_margin,
107 gdouble *right_margin,
108 gdouble *top_margin,
109 gdouble *bottom_margin);
110 static cairo_surface_t * print_preview_get_thumbnail (gint32 drawable_id,
111 gint width,
112 gint height);
113
114
115 G_DEFINE_TYPE (PrintPreview, print_preview, GTK_TYPE_EVENT_BOX)
116
117 #define parent_class print_preview_parent_class
118
119 static guint print_preview_signals[LAST_SIGNAL] = { 0 };
120
121
122 #define g_marshal_value_peek_double(v) (v)->data[0].v_double
123
124 static void
marshal_VOID__DOUBLE_DOUBLE(GClosure * closure,GValue * return_value,guint n_param_values,const GValue * param_values,gpointer invocation_hint,gpointer marshal_data)125 marshal_VOID__DOUBLE_DOUBLE (GClosure *closure,
126 GValue *return_value,
127 guint n_param_values,
128 const GValue *param_values,
129 gpointer invocation_hint,
130 gpointer marshal_data)
131 {
132 typedef void (*GMarshalFunc_VOID__DOUBLE_DOUBLE) (gpointer data1,
133 gdouble arg_1,
134 gdouble arg_2,
135 gpointer data2);
136 register GMarshalFunc_VOID__DOUBLE_DOUBLE callback;
137 register GCClosure *cc = (GCClosure*) closure;
138 register gpointer data1, data2;
139
140 g_return_if_fail (n_param_values == 3);
141
142 if (G_CCLOSURE_SWAP_DATA (closure))
143 {
144 data1 = closure->data;
145 data2 = g_value_peek_pointer (param_values + 0);
146 }
147 else
148 {
149 data1 = g_value_peek_pointer (param_values + 0);
150 data2 = closure->data;
151 }
152
153 callback = (GMarshalFunc_VOID__DOUBLE_DOUBLE) (marshal_data ?
154 marshal_data : cc->callback);
155
156 callback (data1,
157 g_marshal_value_peek_double (param_values + 1),
158 g_marshal_value_peek_double (param_values + 2),
159 data2);
160 }
161
162 static void
print_preview_class_init(PrintPreviewClass * klass)163 print_preview_class_init (PrintPreviewClass *klass)
164 {
165 GObjectClass *object_class = G_OBJECT_CLASS (klass);
166 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
167
168 print_preview_signals[OFFSETS_CHANGED] =
169 g_signal_new ("offsets-changed",
170 G_TYPE_FROM_CLASS (klass),
171 G_SIGNAL_RUN_FIRST,
172 G_STRUCT_OFFSET (PrintPreviewClass, offsets_changed),
173 NULL, NULL,
174 marshal_VOID__DOUBLE_DOUBLE,
175 G_TYPE_NONE, 2,
176 G_TYPE_DOUBLE,
177 G_TYPE_DOUBLE);
178
179 object_class->finalize = print_preview_finalize;
180
181 widget_class->realize = print_preview_realize;
182 widget_class->unrealize = print_preview_unrealize;
183 widget_class->size_request = print_preview_size_request;
184 widget_class->size_allocate = print_preview_size_allocate;
185 widget_class->expose_event = print_preview_expose_event;
186 widget_class->button_press_event = print_preview_button_press_event;
187 widget_class->button_release_event = print_preview_button_release_event;
188 widget_class->motion_notify_event = print_preview_motion_notify_event;
189 widget_class->leave_notify_event = print_preview_leave_notify_event;
190
191 klass->offsets_changed = NULL;
192 }
193
194 static void
print_preview_init(PrintPreview * preview)195 print_preview_init (PrintPreview *preview)
196 {
197 gtk_event_box_set_visible_window (GTK_EVENT_BOX (preview), FALSE);
198
199 gtk_widget_add_events (GTK_WIDGET (preview),
200 GDK_BUTTON_PRESS_MASK |
201 GDK_BUTTON_RELEASE_MASK |
202 GDK_POINTER_MOTION_MASK);
203 }
204
205
206 static void
print_preview_finalize(GObject * object)207 print_preview_finalize (GObject *object)
208 {
209 PrintPreview *preview = PRINT_PREVIEW (object);
210
211 if (preview->thumbnail)
212 {
213 cairo_surface_destroy (preview->thumbnail);
214 preview->thumbnail = NULL;
215 }
216
217 if (preview->page)
218 {
219 g_object_unref (preview->page);
220 preview->page = NULL;
221 }
222
223 G_OBJECT_CLASS (print_preview_parent_class)->finalize (object);
224 }
225
226 static void
print_preview_realize(GtkWidget * widget)227 print_preview_realize (GtkWidget *widget)
228 {
229 PrintPreview *preview = PRINT_PREVIEW (widget);
230
231 GTK_WIDGET_CLASS (print_preview_parent_class)->realize (widget);
232
233 preview->cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
234 GDK_HAND1);
235 }
236
237 static void
print_preview_unrealize(GtkWidget * widget)238 print_preview_unrealize (GtkWidget *widget)
239 {
240 PrintPreview *preview = PRINT_PREVIEW (widget);
241
242 if (preview->cursor)
243 gdk_cursor_unref (preview->cursor);
244
245 GTK_WIDGET_CLASS (print_preview_parent_class)->unrealize (widget);
246 }
247
248 static void
print_preview_size_request(GtkWidget * widget,GtkRequisition * requisition)249 print_preview_size_request (GtkWidget *widget,
250 GtkRequisition *requisition)
251 {
252 PrintPreview *preview = PRINT_PREVIEW (widget);
253 gdouble paper_width;
254 gdouble paper_height;
255 gint border;
256
257 border = gtk_container_get_border_width (GTK_CONTAINER (widget)) + 1;
258
259 print_preview_get_page_size (preview, &paper_width, &paper_height);
260
261 if (paper_width > paper_height)
262 {
263 requisition->height = SIZE_REQUEST;
264 requisition->width = paper_width * SIZE_REQUEST / paper_height;
265 requisition->width = MIN (requisition->width, 2 * SIZE_REQUEST);
266 }
267 else
268 {
269 requisition->width = SIZE_REQUEST;
270 requisition->height = paper_height * SIZE_REQUEST / paper_width;
271 requisition->height = MIN (requisition->height, 2 * SIZE_REQUEST);
272 }
273
274 requisition->width += 2 * border;
275 requisition->height += 2 * border;
276 }
277
278 static void
print_preview_size_allocate(GtkWidget * widget,GtkAllocation * allocation)279 print_preview_size_allocate (GtkWidget *widget,
280 GtkAllocation *allocation)
281 {
282 PrintPreview *preview = PRINT_PREVIEW (widget);
283
284 GTK_WIDGET_CLASS (print_preview_parent_class)->size_allocate (widget,
285 allocation);
286
287 if (preview->thumbnail)
288 {
289 cairo_surface_destroy (preview->thumbnail);
290 preview->thumbnail = NULL;
291 }
292 }
293
294 static gboolean
print_preview_button_press_event(GtkWidget * widget,GdkEventButton * event)295 print_preview_button_press_event (GtkWidget *widget,
296 GdkEventButton *event)
297 {
298 PrintPreview *preview = PRINT_PREVIEW (widget);
299
300 if (event->type == GDK_BUTTON_PRESS && event->button == 1 && preview->inside)
301 {
302 GdkCursor *cursor;
303
304 cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
305 GDK_FLEUR);
306
307 if (gdk_pointer_grab (event->window, FALSE,
308 (GDK_BUTTON1_MOTION_MASK |
309 GDK_BUTTON_RELEASE_MASK),
310 NULL, cursor, event->time) == GDK_GRAB_SUCCESS)
311 {
312 preview->orig_offset_x = preview->image_offset_x;
313 preview->orig_offset_y = preview->image_offset_y;
314
315 preview->start_x = event->x;
316 preview->start_y = event->y;
317
318 preview->dragging = TRUE;
319 }
320
321 gdk_cursor_unref (cursor);
322 }
323
324 return FALSE;
325 }
326
327 static gboolean
print_preview_button_release_event(GtkWidget * widget,GdkEventButton * event)328 print_preview_button_release_event (GtkWidget *widget,
329 GdkEventButton *event)
330 {
331 PrintPreview *preview = PRINT_PREVIEW (widget);
332
333 if (preview->dragging)
334 {
335 gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
336 event->time);
337 preview->dragging = FALSE;
338
339 print_preview_set_inside (preview,
340 print_preview_is_inside (preview,
341 event->x, event->y));
342 }
343
344 return FALSE;
345 }
346
347 static gboolean
print_preview_motion_notify_event(GtkWidget * widget,GdkEventMotion * event)348 print_preview_motion_notify_event (GtkWidget *widget,
349 GdkEventMotion *event)
350 {
351 PrintPreview *preview = PRINT_PREVIEW (widget);
352
353 if (preview->dragging)
354 {
355 gdouble scale = print_preview_get_scale (preview);
356 gdouble offset_x;
357 gdouble offset_y;
358
359 offset_x = (preview->orig_offset_x +
360 (event->x - preview->start_x) / scale);
361 offset_y = (preview->orig_offset_y +
362 (event->y - preview->start_y) / scale);
363
364 offset_x = CLAMP (offset_x, 0, preview->image_offset_x_max);
365 offset_y = CLAMP (offset_y, 0, preview->image_offset_y_max);
366
367 if (preview->image_offset_x != offset_x ||
368 preview->image_offset_y != offset_y)
369 {
370 print_preview_set_image_offsets (preview, offset_x, offset_y);
371
372 g_signal_emit (preview,
373 print_preview_signals[OFFSETS_CHANGED], 0,
374 preview->image_offset_x,
375 preview->image_offset_y);
376 }
377 }
378 else
379 {
380 print_preview_set_inside (preview,
381 print_preview_is_inside (preview,
382 event->x, event->y));
383 }
384
385 return FALSE;
386 }
387
388 static gboolean
print_preview_leave_notify_event(GtkWidget * widget,GdkEventCrossing * event)389 print_preview_leave_notify_event (GtkWidget *widget,
390 GdkEventCrossing *event)
391 {
392 PrintPreview *preview = PRINT_PREVIEW (widget);
393
394 if (event->mode == GDK_CROSSING_NORMAL)
395 print_preview_set_inside (preview, FALSE);
396
397 return FALSE;
398 }
399
400 static gboolean
print_preview_expose_event(GtkWidget * widget,GdkEventExpose * event)401 print_preview_expose_event (GtkWidget *widget,
402 GdkEventExpose *event)
403 {
404 PrintPreview *preview = PRINT_PREVIEW (widget);
405 GtkStyle *style = gtk_widget_get_style (widget);
406 GtkAllocation allocation;
407 cairo_t *cr;
408 gdouble paper_width;
409 gdouble paper_height;
410 gdouble left_margin;
411 gdouble right_margin;
412 gdouble top_margin;
413 gdouble bottom_margin;
414 gdouble scale;
415 gint border;
416
417 gtk_widget_get_allocation (widget, &allocation);
418
419 border = gtk_container_get_border_width (GTK_CONTAINER (widget)) + 1;
420
421 print_preview_get_page_size (preview, &paper_width, &paper_height);
422 print_preview_get_page_margins (preview,
423 &left_margin, &right_margin,
424 &top_margin, &bottom_margin);
425
426 scale = print_preview_get_scale (preview);
427
428 cr = gdk_cairo_create (gtk_widget_get_window (widget));
429
430 cairo_translate (cr,
431 allocation.x + border,
432 allocation.y + border);
433
434 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
435 {
436 gint width = allocation.width - 2 * border;
437
438 cairo_translate (cr, width - scale * paper_width, 0);
439 }
440
441 cairo_set_line_width (cr, 1.0);
442
443 /* draw page background */
444 cairo_rectangle (cr, 0, 0, scale * paper_width, scale * paper_height);
445
446 gdk_cairo_set_source_color (cr, &style->black);
447 cairo_stroke_preserve (cr);
448
449 gdk_cairo_set_source_color (cr, &style->white);
450 cairo_fill (cr);
451
452 /* draw page_margins */
453 cairo_rectangle (cr,
454 scale * left_margin,
455 scale * top_margin,
456 scale * (paper_width - left_margin - right_margin),
457 scale * (paper_height - top_margin - bottom_margin));
458
459 gdk_cairo_set_source_color (cr, &style->mid[gtk_widget_get_state (widget)]);
460 cairo_stroke (cr);
461
462 cairo_translate (cr,
463 scale * (left_margin + preview->image_offset_x),
464 scale * (top_margin + preview->image_offset_y));
465
466 if (preview->dragging || preview->inside)
467 {
468 cairo_rectangle (cr,
469 0, 0,
470 scale * preview->image_width,
471 scale * preview->image_height);
472
473 gdk_cairo_set_source_color (cr, &style->black);
474 cairo_stroke (cr);
475 }
476
477 if (preview->thumbnail == NULL &&
478 gimp_item_is_valid (preview->drawable_id))
479 {
480 preview->thumbnail =
481 print_preview_get_thumbnail (preview->drawable_id,
482 MIN (allocation.width, 1024),
483 MIN (allocation.height, 1024));
484 }
485
486 if (preview->thumbnail != NULL)
487 {
488 gdouble scale_x;
489 gdouble scale_y;
490
491 scale_x = (preview->image_width /
492 cairo_image_surface_get_width (preview->thumbnail));
493 scale_y = (preview->image_height /
494 cairo_image_surface_get_height (preview->thumbnail));
495
496 cairo_rectangle (cr, 0, 0, preview->image_width, preview->image_height);
497
498 cairo_scale (cr, scale_x * scale, scale_y * scale);
499
500 cairo_set_source_surface (cr, preview->thumbnail, 0, 0);
501 cairo_fill (cr);
502 }
503
504 cairo_destroy (cr);
505
506 return FALSE;
507 }
508
509 /**
510 * print_preview_new:
511 * @page: page setup
512 * @drawable_id: the drawable to print
513 *
514 * Creates a new #PrintPreview widget.
515 *
516 * Return value: the new #PrintPreview widget.
517 **/
518 GtkWidget *
print_preview_new(GtkPageSetup * page,gint32 drawable_id)519 print_preview_new (GtkPageSetup *page,
520 gint32 drawable_id)
521 {
522 PrintPreview *preview;
523
524 g_return_val_if_fail (GTK_IS_PAGE_SETUP (page), NULL);
525
526 preview = g_object_new (PRINT_TYPE_PREVIEW, NULL);
527
528 preview->drawable_id = drawable_id;
529
530 print_preview_set_page_setup (preview, page);
531
532 return GTK_WIDGET (preview);
533 }
534
535 /**
536 * print_preview_set_image_dpi:
537 * @preview: a #PrintPreview.
538 * @xres: the X resolution
539 * @yres: the Y resolution
540 *
541 * Sets the resolution of the image/drawable displayed by the
542 * #PrintPreview.
543 **/
544 void
print_preview_set_image_dpi(PrintPreview * preview,gdouble xres,gdouble yres)545 print_preview_set_image_dpi (PrintPreview *preview,
546 gdouble xres,
547 gdouble yres)
548 {
549 gdouble width;
550 gdouble height;
551
552 g_return_if_fail (PRINT_IS_PREVIEW (preview));
553 g_return_if_fail (xres > 0.0 && yres > 0.0);
554
555 width = gimp_drawable_width (preview->drawable_id) * 72.0 / xres;
556 height = gimp_drawable_height (preview->drawable_id) * 72.0 / yres;
557
558 if (width != preview->image_width || height != preview->image_height)
559 {
560 preview->image_width = width;
561 preview->image_height = height;
562
563 gtk_widget_queue_draw (GTK_WIDGET (preview));
564 }
565 }
566
567 /**
568 * print_preview_set_page_setup:
569 * @preview: a #PrintPreview.
570 * @page: the page setup to use
571 *
572 * Sets the page setup to use by the #PrintPreview.
573 **/
574 void
print_preview_set_page_setup(PrintPreview * preview,GtkPageSetup * page)575 print_preview_set_page_setup (PrintPreview *preview,
576 GtkPageSetup *page)
577 {
578 g_return_if_fail (PRINT_IS_PREVIEW (preview));
579 g_return_if_fail (GTK_IS_PAGE_SETUP (page));
580
581 if (preview->page)
582 g_object_unref (preview->page);
583
584 preview->page = gtk_page_setup_copy (page);
585
586 gtk_widget_queue_resize (GTK_WIDGET (preview));
587 }
588
589 /**
590 * print_preview_set_image_offsets:
591 * @preview: a #PrintPreview.
592 * @offset_x: the X offset
593 * @offset_y: the Y offset
594 *
595 * Sets the offsets of the image/drawable displayed by the #PrintPreview.
596 * It does not emit the "offsets-changed" signal.
597 **/
598 void
print_preview_set_image_offsets(PrintPreview * preview,gdouble offset_x,gdouble offset_y)599 print_preview_set_image_offsets (PrintPreview *preview,
600 gdouble offset_x,
601 gdouble offset_y)
602 {
603 g_return_if_fail (PRINT_IS_PREVIEW (preview));
604
605 preview->image_offset_x = offset_x;
606 preview->image_offset_y = offset_y;
607
608 gtk_widget_queue_draw (GTK_WIDGET (preview));
609 }
610
611 /**
612 * print_preview_set_image_offsets_max:
613 * @preview: a #PrintPreview.
614 * @offset_x_max: the maximum X offset allowed
615 * @offset_y_max: the maximum Y offset allowed
616 *
617 * Sets the maximum offsets of the image/drawable displayed by the
618 * #PrintPreview. It does not emit the "offsets-changed" signal.
619 **/
620 void
print_preview_set_image_offsets_max(PrintPreview * preview,gdouble offset_x_max,gdouble offset_y_max)621 print_preview_set_image_offsets_max (PrintPreview *preview,
622 gdouble offset_x_max,
623 gdouble offset_y_max)
624 {
625 g_return_if_fail (PRINT_IS_PREVIEW (preview));
626
627 preview->image_offset_x_max = offset_x_max;
628 preview->image_offset_y_max = offset_y_max;
629
630 gtk_widget_queue_draw (GTK_WIDGET (preview));
631 }
632
633 /**
634 * print_preview_set_use_full_page:
635 * @preview: a #PrintPreview.
636 * @full_page: TRUE to ignore the page margins
637 *
638 * If @full_page is TRUE, the page margins are ignored and the full page
639 * can be used to setup printing.
640 **/
641 void
print_preview_set_use_full_page(PrintPreview * preview,gboolean full_page)642 print_preview_set_use_full_page (PrintPreview *preview,
643 gboolean full_page)
644 {
645 g_return_if_fail (PRINT_IS_PREVIEW (preview));
646
647 preview->use_full_page = full_page;
648
649 gtk_widget_queue_draw (GTK_WIDGET (preview));
650 }
651
652 static gboolean
print_preview_is_inside(PrintPreview * preview,gdouble x,gdouble y)653 print_preview_is_inside (PrintPreview *preview,
654 gdouble x,
655 gdouble y)
656 {
657 GtkWidget *widget = GTK_WIDGET (preview);
658 GtkAllocation allocation;
659 gdouble left_margin;
660 gdouble right_margin;
661 gdouble top_margin;
662 gdouble bottom_margin;
663 gdouble scale;
664 gint border;
665
666 gtk_widget_get_allocation (widget, &allocation);
667
668 border = gtk_container_get_border_width (GTK_CONTAINER (widget)) + 1;
669
670 x -= border;
671
672 scale = print_preview_get_scale (preview);
673
674 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
675 {
676 gdouble paper_width;
677 gdouble paper_height;
678 gint width = allocation.width - 2 * border;
679
680 print_preview_get_page_size (preview, &paper_width, &paper_height);
681
682 x -= width - scale * paper_width;
683 }
684
685 print_preview_get_page_margins (preview,
686 &left_margin, &right_margin,
687 &top_margin, &bottom_margin);
688
689 x = x / scale - left_margin;
690 y = y / scale - top_margin;
691
692 return (x > preview->image_offset_x &&
693 x < preview->image_offset_x + preview->image_width &&
694 y > preview->image_offset_y &&
695 y < preview->image_offset_y + preview->image_height);
696 }
697
698 static void
print_preview_set_inside(PrintPreview * preview,gboolean inside)699 print_preview_set_inside (PrintPreview *preview,
700 gboolean inside)
701 {
702 if (inside != preview->inside)
703 {
704 GtkWidget *widget = GTK_WIDGET (preview);
705
706 preview->inside = inside;
707
708 if (gtk_widget_is_drawable (widget))
709 gdk_window_set_cursor (gtk_widget_get_window (widget),
710 inside ? preview->cursor : NULL);
711
712 gtk_widget_queue_draw (widget);
713 }
714 }
715
716 static gdouble
print_preview_get_scale(PrintPreview * preview)717 print_preview_get_scale (PrintPreview *preview)
718 {
719 GtkWidget *widget = GTK_WIDGET (preview);
720 GtkAllocation allocation;
721 gdouble paper_width;
722 gdouble paper_height;
723 gdouble scale_x;
724 gdouble scale_y;
725 gint border;
726
727 gtk_widget_get_allocation (widget, &allocation);
728
729 border = gtk_container_get_border_width (GTK_CONTAINER (widget)) + 1;
730
731 print_preview_get_page_size (preview, &paper_width, &paper_height);
732
733 scale_x = (gdouble) (allocation.width - 2 * border) / paper_width;
734 scale_y = (gdouble) (allocation.height - 2 * border) / paper_height;
735
736 return MIN (scale_x, scale_y);
737 }
738
739 static void
print_preview_get_page_size(PrintPreview * preview,gdouble * paper_width,gdouble * paper_height)740 print_preview_get_page_size (PrintPreview *preview,
741 gdouble *paper_width,
742 gdouble *paper_height)
743 {
744 *paper_width = gtk_page_setup_get_paper_width (preview->page,
745 GTK_UNIT_POINTS);
746 *paper_height = gtk_page_setup_get_paper_height (preview->page,
747 GTK_UNIT_POINTS);
748 }
749
750 static void
print_preview_get_page_margins(PrintPreview * preview,gdouble * left_margin,gdouble * right_margin,gdouble * top_margin,gdouble * bottom_margin)751 print_preview_get_page_margins (PrintPreview *preview,
752 gdouble *left_margin,
753 gdouble *right_margin,
754 gdouble *top_margin,
755 gdouble *bottom_margin)
756 {
757 if (preview->use_full_page)
758 {
759 *left_margin = 0.0;
760 *right_margin = 0.0;
761 *top_margin = 0.0;
762 *bottom_margin = 0.0;
763 }
764 else
765 {
766 *left_margin = gtk_page_setup_get_left_margin (preview->page,
767 GTK_UNIT_POINTS);
768 *right_margin = gtk_page_setup_get_right_margin (preview->page,
769 GTK_UNIT_POINTS);
770 *top_margin = gtk_page_setup_get_top_margin (preview->page,
771 GTK_UNIT_POINTS);
772 *bottom_margin = gtk_page_setup_get_bottom_margin (preview->page,
773 GTK_UNIT_POINTS);
774 }
775 }
776
777
778 /* This thumbnail code should eventually end up in libgimpui. */
779
780 static cairo_surface_t *
print_preview_get_thumbnail(gint32 drawable_id,gint width,gint height)781 print_preview_get_thumbnail (gint32 drawable_id,
782 gint width,
783 gint height)
784 {
785 cairo_surface_t *surface;
786 cairo_format_t format;
787 guchar *data;
788 guchar *dest;
789 const guchar *src;
790 gint src_stride;
791 gint dest_stride;
792 gint y;
793 gint bpp;
794
795 g_return_val_if_fail (width > 0 && width <= 1024, NULL);
796 g_return_val_if_fail (height > 0 && height <= 1024, NULL);
797
798 data = gimp_drawable_get_thumbnail_data (drawable_id,
799 &width, &height, &bpp);
800
801 switch (bpp)
802 {
803 case 1:
804 case 3:
805 format = CAIRO_FORMAT_RGB24;
806 break;
807
808 case 2:
809 case 4:
810 format = CAIRO_FORMAT_ARGB32;
811 break;
812
813 default:
814 g_assert_not_reached ();
815 break;
816 }
817
818 surface = cairo_image_surface_create (format, width, height);
819
820 src = data;
821 src_stride = width * bpp;
822
823 dest = cairo_image_surface_get_data (surface);
824 dest_stride = cairo_image_surface_get_stride (surface);
825
826 for (y = 0; y < height; y++)
827 {
828 const guchar *s = src;
829 guchar *d = dest;
830 gint w = width;
831
832 switch (bpp)
833 {
834 case 1:
835 while (w--)
836 {
837 GIMP_CAIRO_RGB24_SET_PIXEL (d, s[0], s[0], s[0]);
838 s += 1;
839 d += 4;
840 }
841 break;
842
843 case 2:
844 while (w--)
845 {
846 GIMP_CAIRO_ARGB32_SET_PIXEL (d, s[0], s[0], s[0], s[1]);
847 s += 2;
848 d += 4;
849 }
850 break;
851
852 case 3:
853 while (w--)
854 {
855 GIMP_CAIRO_RGB24_SET_PIXEL (d, s[0], s[1], s[2]);
856 s += 3;
857 d += 4;
858 }
859 break;
860
861 case 4:
862 while (w--)
863 {
864 GIMP_CAIRO_ARGB32_SET_PIXEL (d, s[0], s[1], s[2], s[3]);
865 s += 4;
866 d += 4;
867 }
868 break;
869 }
870
871 src += src_stride;
872 dest += dest_stride;
873 }
874
875 g_free (data);
876
877 cairo_surface_mark_dirty (surface);
878
879 return surface;
880 }
881