Portability: remove dirname needs with g_mkdir_with_parents
[viking.git] / src / print-preview.c
blobb7c8b710d05c7f017bc3d1bbc463dd633ccd7da5
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>
22 #include <gtk/gtk.h>
24 #if GTK_CHECK_VERSION(2,10,0)
26 #include "print-preview.h"
29 #define DRAWING_AREA_SIZE 200
32 enum
34 OFFSETS_CHANGED,
35 LAST_SIGNAL
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,
46 GdkEvent *event,
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,
56 gdouble *left_margin,
57 gdouble *right_margin,
58 gdouble *top_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
73 static void
74 marshal_VOID__DOUBLE_DOUBLE (GClosure *closure,
75 GValue *return_value,
76 guint n_param_values,
77 const GValue *param_values,
78 gpointer invocation_hint,
79 gpointer marshal_data)
81 typedef void (*GMarshalFunc_VOID__DOUBLE_DOUBLE) (gpointer data1,
82 gdouble arg_1,
83 gdouble arg_2,
84 gpointer data2);
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);
96 else
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);
105 callback (data1,
106 g_marshal_value_peek_double (param_values + 1),
107 g_marshal_value_peek_double (param_values + 2),
108 data2);
111 static void
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),
119 G_SIGNAL_RUN_FIRST,
120 G_STRUCT_OFFSET (VikPrintPreviewClass, offsets_changed),
121 NULL, NULL,
122 marshal_VOID__DOUBLE_DOUBLE,
123 G_TYPE_NONE, 2,
124 G_TYPE_DOUBLE,
125 G_TYPE_DOUBLE);
127 object_class->finalize = vik_print_preview_finalize;
129 klass->offsets_changed = NULL;
132 static void
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),
154 preview);
155 g_signal_connect (preview->area, "realize",
156 G_CALLBACK (vik_print_preview_realize),
157 NULL);
158 g_signal_connect (preview->area, "event",
159 G_CALLBACK (vik_print_preview_event),
160 preview);
161 g_signal_connect (preview->area, "expose-event",
162 G_CALLBACK (vik_print_preview_expose_event),
163 preview);
167 static void
168 vik_print_preview_finalize (GObject *object)
170 VikPrintPreview *preview = VIK_PRINT_PREVIEW (object);
172 if (preview->drawable)
174 preview->drawable = NULL;
177 if (preview->pixbuf)
179 g_object_unref (preview->pixbuf);
180 preview->pixbuf = NULL;
183 if (preview->page)
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:
194 * @page: page setup
195 * @drawable_id: the drawable to print
197 * Creates a new #VikPrintPreview widget.
199 * Return value: the new #VikPrintPreview widget.
201 GtkWidget *
202 vik_print_preview_new (GtkPageSetup *page,
203 GdkDrawable *drawable)
205 VikPrintPreview *preview;
206 gfloat ratio;
208 preview = g_object_new (VIK_TYPE_PRINT_PREVIEW, NULL);
210 preview->drawable = drawable;
212 if (page != NULL)
213 preview->page = gtk_page_setup_copy (page);
214 else
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
235 * #VikPrintPreview.
237 void
238 vik_print_preview_set_image_dpi (VikPrintPreview *preview,
239 gdouble xres,
240 gdouble yres)
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.
260 void
261 vik_print_preview_set_page_setup (VikPrintPreview *preview,
262 GtkPageSetup *page)
264 gfloat ratio;
266 if (preview->page)
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.
288 void
289 vik_print_preview_set_image_offsets (VikPrintPreview *preview,
290 gdouble offset_x,
291 gdouble offset_y)
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.
310 void
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.
331 void
332 vik_print_preview_set_use_full_page (VikPrintPreview *preview,
333 gboolean full_page)
335 g_return_if_fail (VIK_IS_PRINT_PREVIEW (preview));
337 preview->use_full_page = full_page;
339 print_preview_queue_draw (preview);
342 static void
343 vik_print_preview_realize (GtkWidget *widget)
345 GdkCursor *cursor;
347 cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
348 GDK_FLEUR);
349 gdk_window_set_cursor (widget->window, cursor);
350 gdk_cursor_unref (cursor);
353 static gboolean
354 vik_print_preview_event (GtkWidget *widget,
355 GdkEvent *event,
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;
363 gdouble offset_x;
364 gdouble offset_y;
365 gdouble scale;
367 switch (event->type)
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;
382 break;
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);
402 break;
404 case GDK_BUTTON_RELEASE:
405 gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
406 event->button.time);
407 start_x = start_y = 0;
408 preview->dragging = FALSE;
410 print_preview_queue_draw (preview);
411 break;
413 default:
414 break;
417 return FALSE;
420 static GdkPixbuf *get_thumbnail(GdkDrawable *drawable, gint thumb_width, gint thumb_height)
422 gint width, height;
423 GdkPixbuf *pixbuf;
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);
432 return thumbnail;
435 static gboolean
436 vik_print_preview_expose_event (GtkWidget *widget,
437 GdkEventExpose *eevent,
438 VikPrintPreview *preview)
440 gdouble paper_width;
441 gdouble paper_height;
442 gdouble left_margin;
443 gdouble right_margin;
444 gdouble top_margin;
445 gdouble bottom_margin;
446 gdouble scale;
447 cairo_t *cr;
449 paper_width = gtk_page_setup_get_paper_width (preview->page,
450 GTK_UNIT_POINTS);
451 paper_height = gtk_page_setup_get_paper_height (preview->page,
452 GTK_UNIT_POINTS);
453 vik_print_preview_get_page_margins (preview,
454 &left_margin,
455 &right_margin,
456 &top_margin,
457 &bottom_margin);
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);
467 cairo_fill (cr);
469 /* draw page_margins */
470 gdk_cairo_set_source_color (cr, &widget->style->black);
471 cairo_rectangle (cr,
472 left_margin,
473 top_margin,
474 paper_width - left_margin - right_margin,
475 paper_height - top_margin - bottom_margin);
476 cairo_stroke (cr);
478 if (preview->dragging)
480 gint width, height;
481 gdk_drawable_get_size(preview->drawable, &width, &height);
482 cairo_rectangle (cr,
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);
487 cairo_stroke (cr);
489 else
491 GdkDrawable *drawable = preview->drawable;
493 /* draw image */
494 cairo_translate (cr,
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)
508 gint width, height;
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);
523 cairo_paint (cr);
527 cairo_destroy (cr);
529 return FALSE;
532 static gdouble
533 vik_print_preview_get_scale (VikPrintPreview* preview)
535 gdouble scale_x;
536 gdouble scale_y;
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);
547 static void
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;
559 static void
560 vik_print_preview_get_page_margins (VikPrintPreview *preview,
561 gdouble *left_margin,
562 gdouble *right_margin,
563 gdouble *top_margin,
564 gdouble *bottom_margin)
566 if (preview->use_full_page)
568 *left_margin = 0.0;
569 *right_margin = 0.0;
570 *top_margin = 0.0;
571 *bottom_margin = 0.0;
573 else
575 *left_margin = gtk_page_setup_get_left_margin (preview->page,
576 GTK_UNIT_POINTS);
577 *right_margin = gtk_page_setup_get_right_margin (preview->page,
578 GTK_UNIT_POINTS);
579 *top_margin = gtk_page_setup_get_top_margin (preview->page,
580 GTK_UNIT_POINTS);
581 *bottom_margin = gtk_page_setup_get_bottom_margin (preview->page,
582 GTK_UNIT_POINTS);
586 static void
587 print_preview_queue_draw (VikPrintPreview *preview)
589 gtk_widget_queue_draw (GTK_WIDGET (preview->area));
592 #endif