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 #if GTK_CHECK_VERSION(2,10,0)
26 #include "print-preview.h"
29 #define DRAWING_AREA_SIZE 200
39 static void vik_print_preview_finalize (GObject
*object
);
41 static void vik_print_preview_size_allocate (GtkWidget
*widget
,
42 GtkAllocation
*allocation
,
43 VikPrintPreview
*preview
);
44 static void vik_print_preview_realize (GtkWidget
*widget
);
45 static gboolean
vik_print_preview_event (GtkWidget
*widget
,
47 VikPrintPreview
*preview
);
49 static gboolean
vik_print_preview_expose_event (GtkWidget
*widget
,
50 GdkEventExpose
*eevent
,
51 VikPrintPreview
*preview
);
53 static gdouble
vik_print_preview_get_scale (VikPrintPreview
*preview
);
55 static void vik_print_preview_get_page_margins (VikPrintPreview
*preview
,
57 gdouble
*right_margin
,
59 gdouble
*bottom_margin
);
61 static void print_preview_queue_draw (VikPrintPreview
*preview
);
64 G_DEFINE_TYPE (VikPrintPreview
, vik_print_preview
, GTK_TYPE_ASPECT_FRAME
)
66 #define parent_class vik_print_preview_parent_class
68 static guint vik_print_preview_signals
[LAST_SIGNAL
] = { 0 };
71 #define g_marshal_value_peek_double(v) (v)->data[0].v_double
74 marshal_VOID__DOUBLE_DOUBLE (GClosure
*closure
,
77 const GValue
*param_values
,
78 gpointer invocation_hint
,
79 gpointer marshal_data
)
81 typedef void (*GMarshalFunc_VOID__DOUBLE_DOUBLE
) (gpointer data1
,
85 register GMarshalFunc_VOID__DOUBLE_DOUBLE callback
;
86 register GCClosure
*cc
= (GCClosure
*) closure
;
87 register gpointer data1
, data2
;
89 g_return_if_fail (n_param_values
== 3);
91 if (G_CCLOSURE_SWAP_DATA (closure
))
93 data1
= closure
->data
;
94 data2
= g_value_peek_pointer (param_values
+ 0);
98 data1
= g_value_peek_pointer (param_values
+ 0);
99 data2
= closure
->data
;
102 callback
= (GMarshalFunc_VOID__DOUBLE_DOUBLE
) (marshal_data
?
103 marshal_data
: cc
->callback
);
106 g_marshal_value_peek_double (param_values
+ 1),
107 g_marshal_value_peek_double (param_values
+ 2),
112 vik_print_preview_class_init (VikPrintPreviewClass
*klass
)
114 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
116 vik_print_preview_signals
[OFFSETS_CHANGED
] =
117 g_signal_new ("offsets-changed",
118 G_TYPE_FROM_CLASS (klass
),
120 G_STRUCT_OFFSET (VikPrintPreviewClass
, offsets_changed
),
122 marshal_VOID__DOUBLE_DOUBLE
,
127 object_class
->finalize
= vik_print_preview_finalize
;
129 klass
->offsets_changed
= NULL
;
133 vik_print_preview_init (VikPrintPreview
*preview
)
135 preview
->page
= NULL
;
136 preview
->pixbuf
= NULL
;
137 preview
->dragging
= FALSE
;
138 preview
->image_offset_x
= 0.0;
139 preview
->image_offset_y
= 0.0;
140 preview
->image_offset_x_max
= 0.0;
141 preview
->image_offset_y_max
= 0.0;
142 preview
->image_xres
= 230.0; // 1.0
143 preview
->image_yres
= 230.0;
144 preview
->use_full_page
= FALSE
;
146 preview
->area
= gtk_drawing_area_new();
147 gtk_container_add (GTK_CONTAINER (preview
), preview
->area
);
148 gtk_widget_show (preview
->area
);
150 gtk_widget_add_events (GTK_WIDGET (preview
->area
), GDK_BUTTON_PRESS_MASK
);
152 g_signal_connect (preview
->area
, "size-allocate",
153 G_CALLBACK (vik_print_preview_size_allocate
),
155 g_signal_connect (preview
->area
, "realize",
156 G_CALLBACK (vik_print_preview_realize
),
158 g_signal_connect (preview
->area
, "event",
159 G_CALLBACK (vik_print_preview_event
),
161 g_signal_connect (preview
->area
, "expose-event",
162 G_CALLBACK (vik_print_preview_expose_event
),
168 vik_print_preview_finalize (GObject
*object
)
170 VikPrintPreview
*preview
= VIK_PRINT_PREVIEW (object
);
172 if (preview
->drawable
)
174 preview
->drawable
= NULL
;
179 g_object_unref (preview
->pixbuf
);
180 preview
->pixbuf
= NULL
;
185 g_object_unref (preview
->page
);
186 preview
->page
= NULL
;
189 G_OBJECT_CLASS (vik_print_preview_parent_class
)->finalize (object
);
193 * vik_print_preview_new:
195 * @drawable_id: the drawable to print
197 * Creates a new #VikPrintPreview widget.
199 * Return value: the new #VikPrintPreview widget.
202 vik_print_preview_new (GtkPageSetup
*page
,
203 GdkDrawable
*drawable
)
205 VikPrintPreview
*preview
;
208 preview
= g_object_new (VIK_TYPE_PRINT_PREVIEW
, NULL
);
210 preview
->drawable
= drawable
;
213 preview
->page
= gtk_page_setup_copy (page
);
215 preview
->page
= gtk_page_setup_new ();
217 ratio
= (gtk_page_setup_get_paper_width (preview
->page
, GTK_UNIT_POINTS
) /
218 gtk_page_setup_get_paper_height (preview
->page
, GTK_UNIT_POINTS
));
220 gtk_aspect_frame_set (GTK_ASPECT_FRAME (preview
), 0.5, 0.5, ratio
, FALSE
);
222 gtk_widget_set_size_request (preview
->area
,
223 DRAWING_AREA_SIZE
, DRAWING_AREA_SIZE
);
225 return GTK_WIDGET (preview
);
229 * vik_print_preview_set_image_dpi:
230 * @preview: a #VikPrintPreview.
231 * @xres: the X resolution
232 * @yres: the Y resolution
234 * Sets the resolution of the image/drawable displayed by the
238 vik_print_preview_set_image_dpi (VikPrintPreview
*preview
,
242 g_return_if_fail (VIK_IS_PRINT_PREVIEW (preview
));
244 if (preview
->image_xres
!= xres
|| preview
->image_yres
!= yres
)
246 preview
->image_xres
= xres
;
247 preview
->image_yres
= yres
;
249 print_preview_queue_draw (preview
);
254 * vik_print_preview_set_page_setup:
255 * @preview: a #VikPrintPreview.
256 * @page: the page setup to use
258 * Sets the page setup to use by the #VikPrintPreview.
261 vik_print_preview_set_page_setup (VikPrintPreview
*preview
,
267 g_object_unref (preview
->page
);
269 preview
->page
= gtk_page_setup_copy (page
);
271 ratio
= (gtk_page_setup_get_paper_width (page
, GTK_UNIT_POINTS
) /
272 gtk_page_setup_get_paper_height (page
, GTK_UNIT_POINTS
));
274 gtk_aspect_frame_set (GTK_ASPECT_FRAME (preview
), 0.5, 0.5, ratio
, FALSE
);
276 print_preview_queue_draw (preview
);
280 * vik_print_preview_set_image_offsets:
281 * @preview: a #VikPrintPreview.
282 * @offset_x: the X offset
283 * @offset_y: the Y offset
285 * Sets the offsets of the image/drawable displayed by the #VikPrintPreview.
286 * It does not emit the "offsets-changed" signal.
289 vik_print_preview_set_image_offsets (VikPrintPreview
*preview
,
293 g_return_if_fail (VIK_IS_PRINT_PREVIEW (preview
));
295 preview
->image_offset_x
= offset_x
;
296 preview
->image_offset_y
= offset_y
;
298 print_preview_queue_draw (preview
);
302 * vik_print_preview_set_image_offsets_max:
303 * @preview: a #VikPrintPreview.
304 * @offset_x_max: the maximum X offset allowed
305 * @offset_y_max: the maximum Y offset allowed
307 * Sets the maximum offsets of the image/drawable displayed by the
308 * #VikPrintPreview. It does not emit the "offsets-changed" signal.
311 vik_print_preview_set_image_offsets_max (VikPrintPreview
*preview
,
312 gdouble offset_x_max
,
313 gdouble offset_y_max
)
315 g_return_if_fail (VIK_IS_PRINT_PREVIEW (preview
));
317 preview
->image_offset_x_max
= offset_x_max
;
318 preview
->image_offset_y_max
= offset_y_max
;
320 print_preview_queue_draw (preview
);
324 * vik_print_preview_set_use_full_page:
325 * @preview: a #VikPrintPreview.
326 * @full_page: TRUE to ignore the page margins
328 * If @full_page is TRUE, the page margins are ignored and the full page
329 * can be used to setup printing.
332 vik_print_preview_set_use_full_page (VikPrintPreview
*preview
,
335 g_return_if_fail (VIK_IS_PRINT_PREVIEW (preview
));
337 preview
->use_full_page
= full_page
;
339 print_preview_queue_draw (preview
);
343 vik_print_preview_realize (GtkWidget
*widget
)
347 cursor
= gdk_cursor_new_for_display (gtk_widget_get_display (widget
),
349 gdk_window_set_cursor (widget
->window
, cursor
);
350 gdk_cursor_unref (cursor
);
354 vik_print_preview_event (GtkWidget
*widget
,
356 VikPrintPreview
*preview
)
358 static gdouble orig_offset_x
= 0.0;
359 static gdouble orig_offset_y
= 0.0;
360 static gint start_x
= 0;
361 static gint start_y
= 0;
369 case GDK_BUTTON_PRESS
:
370 gdk_pointer_grab (widget
->window
, FALSE
,
371 (GDK_BUTTON1_MOTION_MASK
|
372 GDK_BUTTON_RELEASE_MASK
),
373 NULL
, NULL
, event
->button
.time
);
375 orig_offset_x
= preview
->image_offset_x
;
376 orig_offset_y
= preview
->image_offset_y
;
378 start_x
= event
->button
.x
;
379 start_y
= event
->button
.y
;
381 preview
->dragging
= TRUE
;
384 case GDK_MOTION_NOTIFY
:
385 scale
= vik_print_preview_get_scale (preview
);
387 offset_x
= (orig_offset_x
+ (event
->motion
.x
- start_x
) / scale
);
388 offset_y
= (orig_offset_y
+ (event
->motion
.y
- start_y
) / scale
);
390 offset_x
= CLAMP (offset_x
, 0, preview
->image_offset_x_max
);
391 offset_y
= CLAMP (offset_y
, 0, preview
->image_offset_y_max
);
393 if (preview
->image_offset_x
!= offset_x
||
394 preview
->image_offset_y
!= offset_y
)
396 vik_print_preview_set_image_offsets (preview
, offset_x
, offset_y
);
398 g_signal_emit (preview
,
399 vik_print_preview_signals
[OFFSETS_CHANGED
], 0,
400 preview
->image_offset_x
, preview
->image_offset_y
);
404 case GDK_BUTTON_RELEASE
:
405 gdk_display_pointer_ungrab (gtk_widget_get_display (widget
),
407 start_x
= start_y
= 0;
408 preview
->dragging
= FALSE
;
410 print_preview_queue_draw (preview
);
420 static GdkPixbuf
*get_thumbnail(GdkDrawable
*drawable
, gint thumb_width
, gint thumb_height
)
424 GdkPixbuf
*thumbnail
;
426 gdk_drawable_get_size(drawable
, &width
, &height
);
427 pixbuf
= gdk_pixbuf_get_from_drawable(NULL
, drawable
,
428 NULL
, 0, 0, 0, 0, width
, height
);
429 thumbnail
= gdk_pixbuf_scale_simple(pixbuf
, thumb_width
, thumb_height
,
430 GDK_INTERP_BILINEAR
);
431 g_object_unref(pixbuf
);
436 vik_print_preview_expose_event (GtkWidget
*widget
,
437 GdkEventExpose
*eevent
,
438 VikPrintPreview
*preview
)
441 gdouble paper_height
;
443 gdouble right_margin
;
445 gdouble bottom_margin
;
449 paper_width
= gtk_page_setup_get_paper_width (preview
->page
,
451 paper_height
= gtk_page_setup_get_paper_height (preview
->page
,
453 vik_print_preview_get_page_margins (preview
,
459 cr
= gdk_cairo_create (widget
->window
);
461 scale
= vik_print_preview_get_scale (preview
);
463 /* draw background */
464 cairo_scale (cr
, scale
, scale
);
465 gdk_cairo_set_source_color (cr
, &widget
->style
->white
);
466 cairo_rectangle (cr
, 0, 0, paper_width
, paper_height
);
469 /* draw page_margins */
470 gdk_cairo_set_source_color (cr
, &widget
->style
->black
);
474 paper_width
- left_margin
- right_margin
,
475 paper_height
- top_margin
- bottom_margin
);
478 if (preview
->dragging
)
481 gdk_drawable_get_size(preview
->drawable
, &width
, &height
);
483 left_margin
+ preview
->image_offset_x
,
484 top_margin
+ preview
->image_offset_y
,
485 (gdouble
) width
* 72.0 / preview
->image_xres
,
486 (gdouble
) height
* 72.0 / preview
->image_yres
);
491 GdkDrawable
*drawable
= preview
->drawable
;
495 left_margin
+ preview
->image_offset_x
,
496 top_margin
+ preview
->image_offset_y
);
498 if (preview
->pixbuf
== NULL
)
500 gint width
= MIN (widget
->allocation
.width
, 1024);
501 gint height
= MIN (widget
->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
));