1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
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 2 of the License, or
7 * (at your option) any later version.
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.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 * Modified for viking by Quy Tonthat <qtonthat@gmail.com>
24 #include "print-preview.h"
27 #define DRAWING_AREA_SIZE 200
37 static void vik_print_preview_finalize (GObject *object);
39 static void vik_print_preview_size_allocate (GtkWidget *widget,
40 GtkAllocation *allocation,
41 VikPrintPreview *preview);
42 static void vik_print_preview_realize (GtkWidget *widget);
43 static gboolean vik_print_preview_event (GtkWidget *widget,
45 VikPrintPreview *preview);
47 static gboolean vik_print_preview_expose_event (GtkWidget *widget,
48 GdkEventExpose *eevent,
49 VikPrintPreview *preview);
51 static gdouble vik_print_preview_get_scale (VikPrintPreview *preview);
53 static void vik_print_preview_get_page_margins (VikPrintPreview *preview,
55 gdouble *right_margin,
57 gdouble *bottom_margin);
59 static void print_preview_queue_draw (VikPrintPreview *preview);
62 G_DEFINE_TYPE (VikPrintPreview, vik_print_preview, GTK_TYPE_ASPECT_FRAME)
64 #define parent_class vik_print_preview_parent_class
66 static guint vik_print_preview_signals[LAST_SIGNAL] = { 0 };
69 #define g_marshal_value_peek_double(v) (v)->data[0].v_double
72 marshal_VOID__DOUBLE_DOUBLE (GClosure *closure,
75 const GValue *param_values,
76 gpointer invocation_hint,
77 gpointer marshal_data)
79 typedef void (*GMarshalFunc_VOID__DOUBLE_DOUBLE) (gpointer data1,
83 register GMarshalFunc_VOID__DOUBLE_DOUBLE callback;
84 register GCClosure *cc = (GCClosure*) closure;
85 register gpointer data1, data2;
87 g_return_if_fail (n_param_values == 3);
89 if (G_CCLOSURE_SWAP_DATA (closure))
91 data1 = closure->data;
92 data2 = g_value_peek_pointer (param_values + 0);
96 data1 = g_value_peek_pointer (param_values + 0);
97 data2 = closure->data;
100 callback = (GMarshalFunc_VOID__DOUBLE_DOUBLE) (marshal_data ?
101 marshal_data : cc->callback);
104 g_marshal_value_peek_double (param_values + 1),
105 g_marshal_value_peek_double (param_values + 2),
110 vik_print_preview_class_init (VikPrintPreviewClass *klass)
112 GObjectClass *object_class = G_OBJECT_CLASS (klass);
114 vik_print_preview_signals[OFFSETS_CHANGED] =
115 g_signal_new ("offsets-changed",
116 G_TYPE_FROM_CLASS (klass),
118 G_STRUCT_OFFSET (VikPrintPreviewClass, offsets_changed),
120 marshal_VOID__DOUBLE_DOUBLE,
125 object_class->finalize = vik_print_preview_finalize;
127 klass->offsets_changed = NULL;
131 vik_print_preview_init (VikPrintPreview *preview)
133 preview->page = NULL;
134 preview->pixbuf = NULL;
135 preview->dragging = FALSE;
136 preview->image_offset_x = 0.0;
137 preview->image_offset_y = 0.0;
138 preview->image_offset_x_max = 0.0;
139 preview->image_offset_y_max = 0.0;
140 preview->image_xres = 230.0; // 1.0
141 preview->image_yres = 230.0;
142 preview->use_full_page = FALSE;
144 preview->area = gtk_drawing_area_new();
145 gtk_container_add (GTK_CONTAINER (preview), preview->area);
146 gtk_widget_show (preview->area);
148 gtk_widget_add_events (GTK_WIDGET (preview->area), GDK_BUTTON_PRESS_MASK);
150 g_signal_connect (preview->area, "size-allocate",
151 G_CALLBACK (vik_print_preview_size_allocate),
153 g_signal_connect (preview->area, "realize",
154 G_CALLBACK (vik_print_preview_realize),
156 g_signal_connect (preview->area, "event",
157 G_CALLBACK (vik_print_preview_event),
159 g_signal_connect (preview->area, "expose-event",
160 G_CALLBACK (vik_print_preview_expose_event),
166 vik_print_preview_finalize (GObject *object)
168 VikPrintPreview *preview = VIK_PRINT_PREVIEW (object);
170 if (preview->drawable)
172 preview->drawable = NULL;
177 g_object_unref (preview->pixbuf);
178 preview->pixbuf = NULL;
183 g_object_unref (preview->page);
184 preview->page = NULL;
187 G_OBJECT_CLASS (vik_print_preview_parent_class)->finalize (object);
191 * vik_print_preview_new:
193 * @drawable_id: the drawable to print
195 * Creates a new #VikPrintPreview widget.
197 * Return value: the new #VikPrintPreview widget.
200 vik_print_preview_new (GtkPageSetup *page,
201 GdkDrawable *drawable)
203 VikPrintPreview *preview;
206 preview = g_object_new (VIK_TYPE_PRINT_PREVIEW, NULL);
208 preview->drawable = drawable;
211 preview->page = gtk_page_setup_copy (page);
213 preview->page = gtk_page_setup_new ();
215 ratio = (gtk_page_setup_get_paper_width (preview->page, GTK_UNIT_POINTS) /
216 gtk_page_setup_get_paper_height (preview->page, GTK_UNIT_POINTS));
218 gtk_aspect_frame_set (GTK_ASPECT_FRAME (preview), 0.5, 0.5, ratio, FALSE);
220 gtk_widget_set_size_request (preview->area,
221 DRAWING_AREA_SIZE, DRAWING_AREA_SIZE);
223 return GTK_WIDGET (preview);
227 * vik_print_preview_set_image_dpi:
228 * @preview: a #VikPrintPreview.
229 * @xres: the X resolution
230 * @yres: the Y resolution
232 * Sets the resolution of the image/drawable displayed by the
236 vik_print_preview_set_image_dpi (VikPrintPreview *preview,
240 g_return_if_fail (VIK_IS_PRINT_PREVIEW (preview));
242 if (preview->image_xres != xres || preview->image_yres != yres)
244 preview->image_xres = xres;
245 preview->image_yres = yres;
247 print_preview_queue_draw (preview);
252 * vik_print_preview_set_page_setup:
253 * @preview: a #VikPrintPreview.
254 * @page: the page setup to use
256 * Sets the page setup to use by the #VikPrintPreview.
259 vik_print_preview_set_page_setup (VikPrintPreview *preview,
265 g_object_unref (preview->page);
267 preview->page = gtk_page_setup_copy (page);
269 ratio = (gtk_page_setup_get_paper_width (page, GTK_UNIT_POINTS) /
270 gtk_page_setup_get_paper_height (page, GTK_UNIT_POINTS));
272 gtk_aspect_frame_set (GTK_ASPECT_FRAME (preview), 0.5, 0.5, ratio, FALSE);
274 print_preview_queue_draw (preview);
278 * vik_print_preview_set_image_offsets:
279 * @preview: a #VikPrintPreview.
280 * @offset_x: the X offset
281 * @offset_y: the Y offset
283 * Sets the offsets of the image/drawable displayed by the #VikPrintPreview.
284 * It does not emit the "offsets-changed" signal.
287 vik_print_preview_set_image_offsets (VikPrintPreview *preview,
291 g_return_if_fail (VIK_IS_PRINT_PREVIEW (preview));
293 preview->image_offset_x = offset_x;
294 preview->image_offset_y = offset_y;
296 print_preview_queue_draw (preview);
300 * vik_print_preview_set_image_offsets_max:
301 * @preview: a #VikPrintPreview.
302 * @offset_x_max: the maximum X offset allowed
303 * @offset_y_max: the maximum Y offset allowed
305 * Sets the maximum offsets of the image/drawable displayed by the
306 * #VikPrintPreview. It does not emit the "offsets-changed" signal.
309 vik_print_preview_set_image_offsets_max (VikPrintPreview *preview,
310 gdouble offset_x_max,
311 gdouble offset_y_max)
313 g_return_if_fail (VIK_IS_PRINT_PREVIEW (preview));
315 preview->image_offset_x_max = offset_x_max;
316 preview->image_offset_y_max = offset_y_max;
318 print_preview_queue_draw (preview);
322 * vik_print_preview_set_use_full_page:
323 * @preview: a #VikPrintPreview.
324 * @full_page: TRUE to ignore the page margins
326 * If @full_page is TRUE, the page margins are ignored and the full page
327 * can be used to setup printing.
330 vik_print_preview_set_use_full_page (VikPrintPreview *preview,
333 g_return_if_fail (VIK_IS_PRINT_PREVIEW (preview));
335 preview->use_full_page = full_page;
337 print_preview_queue_draw (preview);
341 vik_print_preview_realize (GtkWidget *widget)
345 cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
347 gdk_window_set_cursor (gtk_widget_get_window(widget), cursor);
348 gdk_cursor_unref (cursor);
352 vik_print_preview_event (GtkWidget *widget,
354 VikPrintPreview *preview)
356 static gdouble orig_offset_x = 0.0;
357 static gdouble orig_offset_y = 0.0;
358 static gint start_x = 0;
359 static gint start_y = 0;
367 case GDK_BUTTON_PRESS:
368 gdk_pointer_grab (gtk_widget_get_window(widget), FALSE,
369 (GDK_BUTTON1_MOTION_MASK |
370 GDK_BUTTON_RELEASE_MASK),
371 NULL, NULL, event->button.time);
373 orig_offset_x = preview->image_offset_x;
374 orig_offset_y = preview->image_offset_y;
376 start_x = event->button.x;
377 start_y = event->button.y;
379 preview->dragging = TRUE;
382 case GDK_MOTION_NOTIFY:
383 scale = vik_print_preview_get_scale (preview);
385 offset_x = (orig_offset_x + (event->motion.x - start_x) / scale);
386 offset_y = (orig_offset_y + (event->motion.y - start_y) / scale);
388 offset_x = CLAMP (offset_x, 0, preview->image_offset_x_max);
389 offset_y = CLAMP (offset_y, 0, preview->image_offset_y_max);
391 if (preview->image_offset_x != offset_x ||
392 preview->image_offset_y != offset_y)
394 vik_print_preview_set_image_offsets (preview, offset_x, offset_y);
396 g_signal_emit (preview,
397 vik_print_preview_signals[OFFSETS_CHANGED], 0,
398 preview->image_offset_x, preview->image_offset_y);
402 case GDK_BUTTON_RELEASE:
403 gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
405 start_x = start_y = 0;
406 preview->dragging = FALSE;
408 print_preview_queue_draw (preview);
418 static GdkPixbuf *get_thumbnail(GdkDrawable *drawable, gint thumb_width, gint thumb_height)
422 GdkPixbuf *thumbnail;
424 gdk_drawable_get_size(drawable, &width, &height);
425 pixbuf = gdk_pixbuf_get_from_drawable(NULL, drawable,
426 NULL, 0, 0, 0, 0, width, height);
427 thumbnail = gdk_pixbuf_scale_simple(pixbuf, thumb_width, thumb_height,
428 GDK_INTERP_BILINEAR);
429 g_object_unref(pixbuf);
434 vik_print_preview_expose_event (GtkWidget *widget,
435 GdkEventExpose *eevent,
436 VikPrintPreview *preview)
439 gdouble paper_height;
441 gdouble right_margin;
443 gdouble bottom_margin;
447 paper_width = gtk_page_setup_get_paper_width (preview->page,
449 paper_height = gtk_page_setup_get_paper_height (preview->page,
451 vik_print_preview_get_page_margins (preview,
457 cr = gdk_cairo_create (gtk_widget_get_window(widget));
459 scale = vik_print_preview_get_scale (preview);
461 /* draw background */
462 cairo_scale (cr, scale, scale);
463 gdk_cairo_set_source_color (cr, >k_widget_get_style(widget)->white);
464 cairo_rectangle (cr, 0, 0, paper_width, paper_height);
467 /* draw page_margins */
468 gdk_cairo_set_source_color (cr, >k_widget_get_style(widget)->black);
472 paper_width - left_margin - right_margin,
473 paper_height - top_margin - bottom_margin);
476 if (preview->dragging)
479 gdk_drawable_get_size(preview->drawable, &width, &height);
481 left_margin + preview->image_offset_x,
482 top_margin + preview->image_offset_y,
483 (gdouble) width * 72.0 / preview->image_xres,
484 (gdouble) height * 72.0 / preview->image_yres);
489 GdkDrawable *drawable = preview->drawable;
493 left_margin + preview->image_offset_x,
494 top_margin + preview->image_offset_y);
496 if (preview->pixbuf == NULL)
498 GtkAllocation allocation;
499 gtk_widget_get_allocation ( widget, &allocation );
500 gint width = MIN (allocation.width, 1024);
501 gint height = MIN (allocation.height, 1024);
503 preview->pixbuf = get_thumbnail(drawable, width, height);
506 if (preview->pixbuf != NULL)
509 gdk_drawable_get_size(drawable, &width, &height);
511 gdouble scale_x = ((gdouble) width /
512 gdk_pixbuf_get_width (preview->pixbuf));
513 gdouble scale_y = ((gdouble) height /
514 gdk_pixbuf_get_height (preview->pixbuf));
516 scale_x = scale_x * 72.0 / preview->image_xres;
517 scale_y = scale_y * 72.0 / preview->image_yres;
519 cairo_scale (cr, scale_x, scale_y);
521 gdk_cairo_set_source_pixbuf (cr, preview->pixbuf, 0, 0);
533 vik_print_preview_get_scale (VikPrintPreview* preview)
538 scale_x = ((gdouble) preview->area->allocation.width /
539 gtk_page_setup_get_paper_width (preview->page, GTK_UNIT_POINTS));
541 scale_y = ((gdouble) preview->area->allocation.height /
542 gtk_page_setup_get_paper_height (preview->page, GTK_UNIT_POINTS));
544 return MIN (scale_x, scale_y);
548 vik_print_preview_size_allocate (GtkWidget *widget,
549 GtkAllocation *allocation,
550 VikPrintPreview *preview)
552 if (preview->pixbuf != NULL)
554 g_object_unref (preview->pixbuf);
555 preview->pixbuf = NULL;
560 vik_print_preview_get_page_margins (VikPrintPreview *preview,
561 gdouble *left_margin,
562 gdouble *right_margin,
564 gdouble *bottom_margin)
566 if (preview->use_full_page)
571 *bottom_margin = 0.0;
575 *left_margin = gtk_page_setup_get_left_margin (preview->page,
577 *right_margin = gtk_page_setup_get_right_margin (preview->page,
579 *top_margin = gtk_page_setup_get_top_margin (preview->page,
581 *bottom_margin = gtk_page_setup_get_bottom_margin (preview->page,
587 print_preview_queue_draw (VikPrintPreview *preview)
589 gtk_widget_queue_draw (GTK_WIDGET (preview->area));