]> git.street.me.uk Git - andy/viking.git/blame - src/print-preview.c
Finish to remove Google
[andy/viking.git] / src / print-preview.c
CommitLineData
42f34743
QT
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 2 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, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18/*
19 * Modified for viking by Quy Tonthat <qtonthat@gmail.com>
20 */
21
22#include <gtk/gtk.h>
23
9a995996
EB
24#if GTK_CHECK_VERSION(2,10,0)
25
42f34743
QT
26#include "print-preview.h"
27
28
29#define DRAWING_AREA_SIZE 200
30
31
32enum
33{
34 OFFSETS_CHANGED,
35 LAST_SIGNAL
36};
37
38
39static void vik_print_preview_finalize (GObject *object);
40
41static void vik_print_preview_size_allocate (GtkWidget *widget,
42 GtkAllocation *allocation,
43 VikPrintPreview *preview);
44static void vik_print_preview_realize (GtkWidget *widget);
45static gboolean vik_print_preview_event (GtkWidget *widget,
46 GdkEvent *event,
47 VikPrintPreview *preview);
48
49static gboolean vik_print_preview_expose_event (GtkWidget *widget,
50 GdkEventExpose *eevent,
51 VikPrintPreview *preview);
52
53static gdouble vik_print_preview_get_scale (VikPrintPreview *preview);
54
55static 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);
60
61static void print_preview_queue_draw (VikPrintPreview *preview);
62
63
64G_DEFINE_TYPE (VikPrintPreview, vik_print_preview, GTK_TYPE_ASPECT_FRAME)
65
66#define parent_class vik_print_preview_parent_class
67
68static guint vik_print_preview_signals[LAST_SIGNAL] = { 0 };
69
70
71#define g_marshal_value_peek_double(v) (v)->data[0].v_double
72
73static void
74marshal_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)
80{
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;
88
89 g_return_if_fail (n_param_values == 3);
90
91 if (G_CCLOSURE_SWAP_DATA (closure))
92 {
93 data1 = closure->data;
94 data2 = g_value_peek_pointer (param_values + 0);
95 }
96 else
97 {
98 data1 = g_value_peek_pointer (param_values + 0);
99 data2 = closure->data;
100 }
101
102 callback = (GMarshalFunc_VOID__DOUBLE_DOUBLE) (marshal_data ?
103 marshal_data : cc->callback);
104
105 callback (data1,
106 g_marshal_value_peek_double (param_values + 1),
107 g_marshal_value_peek_double (param_values + 2),
108 data2);
109}
110
111static void
112vik_print_preview_class_init (VikPrintPreviewClass *klass)
113{
114 GObjectClass *object_class = G_OBJECT_CLASS (klass);
115
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);
126
127 object_class->finalize = vik_print_preview_finalize;
128
129 klass->offsets_changed = NULL;
130}
131
132static void
133vik_print_preview_init (VikPrintPreview *preview)
134{
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;
145
146 preview->area = gtk_drawing_area_new();
147 gtk_container_add (GTK_CONTAINER (preview), preview->area);
148 gtk_widget_show (preview->area);
149
150 gtk_widget_add_events (GTK_WIDGET (preview->area), GDK_BUTTON_PRESS_MASK);
151
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);
164}
165
166
167static void
168vik_print_preview_finalize (GObject *object)
169{
170 VikPrintPreview *preview = VIK_PRINT_PREVIEW (object);
171
172 if (preview->drawable)
173 {
174 preview->drawable = NULL;
175 }
176
177 if (preview->pixbuf)
178 {
179 g_object_unref (preview->pixbuf);
180 preview->pixbuf = NULL;
181 }
182
183 if (preview->page)
184 {
185 g_object_unref (preview->page);
186 preview->page = NULL;
187 }
188
189 G_OBJECT_CLASS (vik_print_preview_parent_class)->finalize (object);
190}
191
192/**
193 * vik_print_preview_new:
194 * @page: page setup
195 * @drawable_id: the drawable to print
196 *
197 * Creates a new #VikPrintPreview widget.
198 *
199 * Return value: the new #VikPrintPreview widget.
200 **/
201GtkWidget *
202vik_print_preview_new (GtkPageSetup *page,
203 GdkDrawable *drawable)
204{
205 VikPrintPreview *preview;
206 gfloat ratio;
207
208 preview = g_object_new (VIK_TYPE_PRINT_PREVIEW, NULL);
209
210 preview->drawable = drawable;
211
212 if (page != NULL)
213 preview->page = gtk_page_setup_copy (page);
214 else
215 preview->page = gtk_page_setup_new ();
216
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));
219
220 gtk_aspect_frame_set (GTK_ASPECT_FRAME (preview), 0.5, 0.5, ratio, FALSE);
221
222 gtk_widget_set_size_request (preview->area,
223 DRAWING_AREA_SIZE, DRAWING_AREA_SIZE);
224
225 return GTK_WIDGET (preview);
226}
227
228/**
229 * vik_print_preview_set_image_dpi:
230 * @preview: a #VikPrintPreview.
231 * @xres: the X resolution
232 * @yres: the Y resolution
233 *
234 * Sets the resolution of the image/drawable displayed by the
235 * #VikPrintPreview.
236 **/
237void
238vik_print_preview_set_image_dpi (VikPrintPreview *preview,
239 gdouble xres,
240 gdouble yres)
241{
242 g_return_if_fail (VIK_IS_PRINT_PREVIEW (preview));
243
244 if (preview->image_xres != xres || preview->image_yres != yres)
245 {
246 preview->image_xres = xres;
247 preview->image_yres = yres;
248
249 print_preview_queue_draw (preview);
250 }
251}
252
253/**
254 * vik_print_preview_set_page_setup:
255 * @preview: a #VikPrintPreview.
256 * @page: the page setup to use
257 *
258 * Sets the page setup to use by the #VikPrintPreview.
259 **/
260void
261vik_print_preview_set_page_setup (VikPrintPreview *preview,
262 GtkPageSetup *page)
263{
264 gfloat ratio;
265
266 if (preview->page)
267 g_object_unref (preview->page);
268
269 preview->page = gtk_page_setup_copy (page);
270
271 ratio = (gtk_page_setup_get_paper_width (page, GTK_UNIT_POINTS) /
272 gtk_page_setup_get_paper_height (page, GTK_UNIT_POINTS));
273
274 gtk_aspect_frame_set (GTK_ASPECT_FRAME (preview), 0.5, 0.5, ratio, FALSE);
275
276 print_preview_queue_draw (preview);
277}
278
279/**
280 * vik_print_preview_set_image_offsets:
281 * @preview: a #VikPrintPreview.
282 * @offset_x: the X offset
283 * @offset_y: the Y offset
284 *
285 * Sets the offsets of the image/drawable displayed by the #VikPrintPreview.
286 * It does not emit the "offsets-changed" signal.
287 **/
288void
289vik_print_preview_set_image_offsets (VikPrintPreview *preview,
290 gdouble offset_x,
291 gdouble offset_y)
292{
293 g_return_if_fail (VIK_IS_PRINT_PREVIEW (preview));
294
295 preview->image_offset_x = offset_x;
296 preview->image_offset_y = offset_y;
297
298 print_preview_queue_draw (preview);
299}
300
301/**
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
306 *
307 * Sets the maximum offsets of the image/drawable displayed by the
308 * #VikPrintPreview. It does not emit the "offsets-changed" signal.
309 **/
310void
311vik_print_preview_set_image_offsets_max (VikPrintPreview *preview,
312 gdouble offset_x_max,
313 gdouble offset_y_max)
314{
315 g_return_if_fail (VIK_IS_PRINT_PREVIEW (preview));
316
317 preview->image_offset_x_max = offset_x_max;
318 preview->image_offset_y_max = offset_y_max;
319
320 print_preview_queue_draw (preview);
321}
322
323/**
324 * vik_print_preview_set_use_full_page:
325 * @preview: a #VikPrintPreview.
326 * @full_page: TRUE to ignore the page margins
327 *
328 * If @full_page is TRUE, the page margins are ignored and the full page
329 * can be used to setup printing.
330 **/
331void
332vik_print_preview_set_use_full_page (VikPrintPreview *preview,
333 gboolean full_page)
334{
335 g_return_if_fail (VIK_IS_PRINT_PREVIEW (preview));
336
337 preview->use_full_page = full_page;
338
339 print_preview_queue_draw (preview);
340}
341
342static void
343vik_print_preview_realize (GtkWidget *widget)
344{
345 GdkCursor *cursor;
346
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);
351}
352
353static gboolean
354vik_print_preview_event (GtkWidget *widget,
355 GdkEvent *event,
356 VikPrintPreview *preview)
357{
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;
362
363 gdouble offset_x;
364 gdouble offset_y;
365 gdouble scale;
366
367 switch (event->type)
368 {
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);
374
375 orig_offset_x = preview->image_offset_x;
376 orig_offset_y = preview->image_offset_y;
377
378 start_x = event->button.x;
379 start_y = event->button.y;
380
381 preview->dragging = TRUE;
382 break;
383
384 case GDK_MOTION_NOTIFY:
385 scale = vik_print_preview_get_scale (preview);
386
387 offset_x = (orig_offset_x + (event->motion.x - start_x) / scale);
388 offset_y = (orig_offset_y + (event->motion.y - start_y) / scale);
389
390 offset_x = CLAMP (offset_x, 0, preview->image_offset_x_max);
391 offset_y = CLAMP (offset_y, 0, preview->image_offset_y_max);
392
393 if (preview->image_offset_x != offset_x ||
394 preview->image_offset_y != offset_y)
395 {
396 vik_print_preview_set_image_offsets (preview, offset_x, offset_y);
397
398 g_signal_emit (preview,
399 vik_print_preview_signals[OFFSETS_CHANGED], 0,
400 preview->image_offset_x, preview->image_offset_y);
401 }
402 break;
403
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;
409
410 print_preview_queue_draw (preview);
411 break;
412
413 default:
414 break;
415 }
416
417 return FALSE;
418}
419
420static GdkPixbuf *get_thumbnail(GdkDrawable *drawable, gint thumb_width, gint thumb_height)
421{
422 gint width, height;
423 GdkPixbuf *pixbuf;
424 GdkPixbuf *thumbnail;
425
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;
433}
434
435static gboolean
436vik_print_preview_expose_event (GtkWidget *widget,
437 GdkEventExpose *eevent,
438 VikPrintPreview *preview)
439{
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;
448
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);
458
459 cr = gdk_cairo_create (widget->window);
460
461 scale = vik_print_preview_get_scale (preview);
462
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);
468
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);
477
478 if (preview->dragging)
479 {
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);
488 }
489 else
490 {
491 GdkDrawable *drawable = preview->drawable;
492
493 /* draw image */
494 cairo_translate (cr,
495 left_margin + preview->image_offset_x,
496 top_margin + preview->image_offset_y);
497
498 if (preview->pixbuf == NULL)
499 {
500 gint width = MIN (widget->allocation.width, 1024);
501 gint height = MIN (widget->allocation.height, 1024);
502
503 preview->pixbuf = get_thumbnail(drawable, width, height);
504 }
505
506 if (preview->pixbuf != NULL)
507 {
508 gint width, height;
509 gdk_drawable_get_size(drawable, &width, &height);
510
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));
515
516 scale_x = scale_x * 72.0 / preview->image_xres;
517 scale_y = scale_y * 72.0 / preview->image_yres;
518
519 cairo_scale (cr, scale_x, scale_y);
520
521 gdk_cairo_set_source_pixbuf (cr, preview->pixbuf, 0, 0);
522
523 cairo_paint (cr);
524 }
525 }
526
527 cairo_destroy (cr);
528
529 return FALSE;
530}
531
532static gdouble
533vik_print_preview_get_scale (VikPrintPreview* preview)
534{
535 gdouble scale_x;
536 gdouble scale_y;
537
538 scale_x = ((gdouble) preview->area->allocation.width /
539 gtk_page_setup_get_paper_width (preview->page, GTK_UNIT_POINTS));
540
541 scale_y = ((gdouble) preview->area->allocation.height /
542 gtk_page_setup_get_paper_height (preview->page, GTK_UNIT_POINTS));
543
544 return MIN (scale_x, scale_y);
545}
546
547static void
548vik_print_preview_size_allocate (GtkWidget *widget,
549 GtkAllocation *allocation,
550 VikPrintPreview *preview)
551{
552 if (preview->pixbuf != NULL)
553 {
554 g_object_unref (preview->pixbuf);
555 preview->pixbuf = NULL;
556 }
557}
558
559static void
560vik_print_preview_get_page_margins (VikPrintPreview *preview,
561 gdouble *left_margin,
562 gdouble *right_margin,
563 gdouble *top_margin,
564 gdouble *bottom_margin)
565{
566 if (preview->use_full_page)
567 {
568 *left_margin = 0.0;
569 *right_margin = 0.0;
570 *top_margin = 0.0;
571 *bottom_margin = 0.0;
572 }
573 else
574 {
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);
583 }
584}
585
586static void
587print_preview_queue_draw (VikPrintPreview *preview)
588{
589 gtk_widget_queue_draw (GTK_WIDGET (preview->area));
590}
9a995996
EB
591
592#endif