]> git.sur5r.net Git - glabels/blob - glabels2/src/mini-preview.c
9bcedbff5671865cb1277eb9b781dd82475b6197
[glabels] / glabels2 / src / mini-preview.c
1 /*
2  *  mini-preview.c
3  *  Copyright (C) 2001-2009  Jim Evins <evins@snaught.com>.
4  *
5  *  This file is part of gLabels.
6  *
7  *  gLabels is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  gLabels is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with gLabels.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #include "mini-preview.h"
24
25 #include <math.h>
26
27 #include "libglabels/db.h"
28 #include "cairo-label-path.h"
29 #include "marshal.h"
30 #include "color.h"
31 #include "print.h"
32
33 #include "debug.h"
34
35
36 /*===========================================*/
37 /* Private macros and constants.             */
38 /*===========================================*/
39
40 #define MARGIN 2
41 #define SHADOW_OFFSET 3
42
43
44 /*===========================================*/
45 /* Private types                             */
46 /*===========================================*/
47
48 enum {
49         CLICKED,
50         PRESSED,
51         RELEASED,
52         LAST_SIGNAL
53 };
54
55 typedef struct {
56         gdouble x;
57         gdouble y;
58 } LabelCenter;
59
60 struct _glMiniPreviewPrivate {
61
62         GtkWidget      *canvas;
63
64         lglTemplate    *template;
65         gint            labels_per_sheet;
66         LabelCenter    *centers;
67
68         gint            highlight_first;
69         gint            highlight_last;
70
71         gboolean        dragging;
72         gint            first_i;
73         gint            last_i;
74         gint            prev_i;
75
76         gboolean        update_scheduled_flag;
77
78         glLabel        *label;
79         gint            page;
80         gint            n_sheets;
81         gint            n_copies;
82         gint            first;
83         gint            last;
84         gboolean        collate_flag;
85         gboolean        outline_flag;
86         gboolean        reverse_flag;
87         gboolean        crop_marks_flag;
88 };
89
90
91 /*===========================================*/
92 /* Private globals                           */
93 /*===========================================*/
94
95 static gint mini_preview_signals[LAST_SIGNAL] = { 0 };
96
97
98 /*===========================================*/
99 /* Local function prototypes                 */
100 /*===========================================*/
101
102 static void     gl_mini_preview_finalize       (GObject                *object);
103
104 static void     gl_mini_preview_construct      (glMiniPreview          *this,
105                                                 gint                    height,
106                                                 gint                    width);
107
108 static gboolean button_press_event_cb          (GtkWidget              *widget,
109                                                 GdkEventButton         *event);
110 static gboolean motion_notify_event_cb         (GtkWidget              *widget,
111                                                 GdkEventMotion         *event);
112 static gboolean button_release_event_cb        (GtkWidget              *widget,
113                                                 GdkEventButton         *event);
114
115
116 static gboolean expose_event_cb                (GtkWidget              *widget,
117                                                 GdkEventExpose         *event,
118                                                 glMiniPreview          *this);
119 static void     style_set_cb                   (GtkWidget              *widget,
120                                                 GtkStyle               *previous_style,
121                                                 glMiniPreview          *this);
122
123 static void     redraw                         (glMiniPreview          *this);
124 static void     draw                           (glMiniPreview          *this,
125                                                 cairo_t                *cr);
126
127 static void     draw_shadow                    (glMiniPreview          *this,
128                                                 cairo_t                *cr,
129                                                 gdouble                 x,
130                                                 gdouble                 y,
131                                                 gdouble                 width,
132                                                 gdouble                 height);
133 static void     draw_paper                     (glMiniPreview          *this,
134                                                 cairo_t                *cr,
135                                                 gdouble                 width,
136                                                 gdouble                 height,
137                                                 gdouble                 line_width);
138 static void     draw_labels                    (glMiniPreview          *this,
139                                                 cairo_t                *cr,
140                                                 lglTemplate            *template,
141                                                 gdouble                 line_width);
142 static void     draw_rich_preview              (glMiniPreview          *this,
143                                                 cairo_t                *cr);
144
145
146 static gint     find_closest_label             (glMiniPreview          *this,
147                                                 gdouble                 x,
148                                                 gdouble                 y);
149
150 static gdouble  set_transform_and_get_scale    (glMiniPreview          *this,
151                                                 cairo_t                *cr);
152
153
154 /****************************************************************************/
155 /* Object infrastructure.                                                   */
156 /****************************************************************************/
157 G_DEFINE_TYPE (glMiniPreview, gl_mini_preview, GTK_TYPE_EVENT_BOX);
158
159
160 /*****************************************************************************/
161 /* Class Init Function.                                                      */
162 /*****************************************************************************/
163 static void
164 gl_mini_preview_class_init (glMiniPreviewClass *class)
165 {
166         GObjectClass   *object_class = G_OBJECT_CLASS (class);
167         GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
168
169         gl_debug (DEBUG_MINI_PREVIEW, "START");
170
171         gl_mini_preview_parent_class = g_type_class_peek_parent (class);
172
173         object_class->finalize = gl_mini_preview_finalize;
174
175         widget_class->button_press_event   = button_press_event_cb;
176         widget_class->motion_notify_event  = motion_notify_event_cb;
177         widget_class->button_release_event = button_release_event_cb;
178
179         mini_preview_signals[CLICKED] =
180             g_signal_new ("clicked",
181                           G_OBJECT_CLASS_TYPE(object_class),
182                           G_SIGNAL_RUN_LAST,
183                           G_STRUCT_OFFSET (glMiniPreviewClass, clicked),
184                           NULL, NULL,
185                           gl_marshal_VOID__INT,
186                           G_TYPE_NONE, 1, G_TYPE_INT);
187
188         mini_preview_signals[PRESSED] =
189             g_signal_new ("pressed",
190                           G_OBJECT_CLASS_TYPE(object_class),
191                           G_SIGNAL_RUN_LAST,
192                           G_STRUCT_OFFSET (glMiniPreviewClass, pressed),
193                           NULL, NULL,
194                           gl_marshal_VOID__INT_INT,
195                           G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
196
197         mini_preview_signals[RELEASED] =
198             g_signal_new ("released",
199                           G_OBJECT_CLASS_TYPE(object_class),
200                           G_SIGNAL_RUN_LAST,
201                           G_STRUCT_OFFSET (glMiniPreviewClass, released),
202                           NULL, NULL,
203                           gl_marshal_VOID__INT_INT,
204                           G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
205
206         gl_debug (DEBUG_MINI_PREVIEW, "END");
207 }
208
209
210 /*****************************************************************************/
211 /* Object Instance Init Function.                                            */
212 /*****************************************************************************/
213 static void
214 gl_mini_preview_init (glMiniPreview *this)
215 {
216         gl_debug (DEBUG_MINI_PREVIEW, "START");
217
218         this->priv = g_new0 (glMiniPreviewPrivate, 1);
219
220         gtk_widget_add_events (GTK_WIDGET (this),
221                                GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
222                                GDK_POINTER_MOTION_MASK);
223
224         gtk_event_box_set_visible_window (GTK_EVENT_BOX (this), FALSE);
225
226         this->priv->canvas = gtk_drawing_area_new ();
227         GTK_WIDGET_SET_FLAGS (this->priv->canvas, GTK_NO_WINDOW);
228         gtk_container_add (GTK_CONTAINER (this), this->priv->canvas);
229
230         g_signal_connect (G_OBJECT (this->priv->canvas), "expose-event",
231                           G_CALLBACK (expose_event_cb), this);
232         g_signal_connect (G_OBJECT (this->priv->canvas), "style-set",
233                           G_CALLBACK (style_set_cb), this);
234
235         gl_debug (DEBUG_MINI_PREVIEW, "END");
236 }
237
238
239 /*****************************************************************************/
240 /* Finalize Method.                                                          */
241 /*****************************************************************************/
242 static void
243 gl_mini_preview_finalize (GObject *object)
244 {
245         glMiniPreview *this = GL_MINI_PREVIEW (object);
246
247         gl_debug (DEBUG_MINI_PREVIEW, "START");
248
249         g_return_if_fail (object != NULL);
250         g_return_if_fail (GL_IS_MINI_PREVIEW (object));
251
252         if (this->priv->label)
253         {
254                 g_object_unref (this->priv->label);
255         }
256         lgl_template_free (this->priv->template);
257         g_free (this->priv->centers);
258         g_free (this->priv);
259
260         G_OBJECT_CLASS (gl_mini_preview_parent_class)->finalize (object);
261
262         gl_debug (DEBUG_MINI_PREVIEW, "END");
263 }
264
265
266 /*****************************************************************************/
267 /** New Object Generator.                                                    */
268 /*****************************************************************************/
269 GtkWidget *
270 gl_mini_preview_new (gint height,
271                      gint width)
272 {
273         glMiniPreview *this;
274
275         gl_debug (DEBUG_MINI_PREVIEW, "START");
276
277         this = g_object_new (gl_mini_preview_get_type (), NULL);
278
279         gl_mini_preview_construct (this, height, width);
280
281         gl_debug (DEBUG_MINI_PREVIEW, "END");
282
283         return GTK_WIDGET (this);
284 }
285
286
287 /*--------------------------------------------------------------------------*/
288 /* Construct composite widget.                                              */
289 /*--------------------------------------------------------------------------*/
290 static void
291 gl_mini_preview_construct (glMiniPreview *this,
292                            gint           height,
293                            gint           width)
294 {
295         gl_debug (DEBUG_MINI_PREVIEW, "START");
296
297         gtk_widget_set_size_request (GTK_WIDGET (this->priv->canvas), width, height);
298
299         gl_debug (DEBUG_MINI_PREVIEW, "END");
300 }
301
302
303 /****************************************************************************/
304 /* Set template for mini-preview to determine geometry.                     */
305 /****************************************************************************/
306 void
307 gl_mini_preview_set_by_name (glMiniPreview *this,
308                              const gchar   *name)
309 {
310         lglTemplate *template;
311
312         gl_debug (DEBUG_MINI_PREVIEW, "START");
313
314         /* Fetch template */
315         template = lgl_db_lookup_template_from_name (name);
316
317         gl_mini_preview_set_template (this, template);
318
319         lgl_template_free (template);
320
321         gl_debug (DEBUG_MINI_PREVIEW, "END");
322 }
323
324
325 /****************************************************************************/
326 /* Set template for mini-preview to determine geometry.                     */
327 /****************************************************************************/
328 void
329 gl_mini_preview_set_template (glMiniPreview     *this,
330                               const lglTemplate *template)
331 {
332         const lglTemplateFrame    *frame;
333         lglTemplateOrigin         *origins;
334         gdouble                    w, h;
335         gint                       i;
336
337         gl_debug (DEBUG_MINI_PREVIEW, "START");
338
339         frame = (lglTemplateFrame *)template->frames->data;
340
341         /*
342          * Set template
343          */
344         lgl_template_free (this->priv->template);
345         this->priv->template = lgl_template_dup (template);
346
347         /*
348          * Set labels per sheet
349          */
350         this->priv->labels_per_sheet = lgl_template_frame_get_n_labels (frame);
351
352         /*
353          * Initialize centers
354          */
355         g_free (this->priv->centers);
356         this->priv->centers = g_new0 (LabelCenter, this->priv->labels_per_sheet);
357         origins = lgl_template_frame_get_origins (frame);
358         lgl_template_frame_get_size (frame, &w, &h);
359         for ( i=0; i<this->priv->labels_per_sheet; i++ )
360         {
361                 this->priv->centers[i].x = origins[i].x + w/2.0;
362                 this->priv->centers[i].y = origins[i].y + h/2.0;
363         }
364         g_free (origins);
365
366         /*
367          * Redraw modified preview
368          */
369         redraw (this);
370
371         gl_debug (DEBUG_MINI_PREVIEW, "END");
372 }
373
374
375 /****************************************************************************/
376 /* Highlight given label outlines.                                          */
377 /****************************************************************************/
378 void
379 gl_mini_preview_highlight_range (glMiniPreview *this,
380                                  gint           first_label,
381                                  gint           last_label)
382 {
383         gl_debug (DEBUG_MINI_PREVIEW, "START");
384
385         if ( (first_label != this->priv->highlight_first) ||
386              (last_label  != this->priv->highlight_last) )
387         {
388
389                 this->priv->highlight_first = first_label;
390                 this->priv->highlight_last =  last_label;
391
392                 redraw (this);
393
394         }
395
396         gl_debug (DEBUG_MINI_PREVIEW, "END");
397 }
398
399
400 /****************************************************************************/
401 /* Set label.                                                               */
402 /****************************************************************************/
403 void
404 gl_mini_preview_set_label (glMiniPreview     *this,
405                            glLabel           *label)
406 {
407         if ( this->priv->label )
408         {
409                 g_object_unref (this->priv->label);
410         }
411         this->priv->label = g_object_ref (label);
412         redraw (this);
413 }
414
415
416 /****************************************************************************/
417 /* Set page number.                                                         */
418 /****************************************************************************/
419 void
420 gl_mini_preview_set_page (glMiniPreview     *this,
421                           gint               page)
422 {
423         if ( page != this->priv->page )
424         {
425                 this->priv->page = page;
426                 redraw (this);
427         }
428 }
429
430
431 /****************************************************************************/
432 /* Set number of sheets.                                                    */
433 /****************************************************************************/
434 void
435 gl_mini_preview_set_n_sheets (glMiniPreview     *this,
436                               gint               n_sheets)
437 {
438         if ( n_sheets != this->priv->n_sheets )
439         {
440                 this->priv->n_sheets = n_sheets;
441                 redraw (this);
442         }
443 }
444
445
446 /****************************************************************************/
447 /* Set number of copies (merge only).                                       */
448 /****************************************************************************/
449 void
450 gl_mini_preview_set_n_copies (glMiniPreview     *this,
451                               gint               n_copies)
452 {
453         if ( n_copies != this->priv->n_copies )
454         {
455                 this->priv->n_copies = n_copies;
456                 redraw (this);
457         }
458 }
459
460
461 /****************************************************************************/
462 /* Set first label number on first sheet.                                   */
463 /****************************************************************************/
464 void
465 gl_mini_preview_set_first (glMiniPreview     *this,
466                            gint               first)
467 {
468         if ( first != this->priv->first )
469         {
470                 this->priv->first = first;
471                 redraw (this);
472         }
473 }
474
475
476 /****************************************************************************/
477 /* Set last label number on first sheet (non-merge only).                   */
478 /****************************************************************************/
479 void
480 gl_mini_preview_set_last (glMiniPreview     *this,
481                           gint               last)
482 {
483         if ( last != this->priv->last )
484         {
485                 this->priv->last = last;
486                 redraw (this);
487         }
488 }
489
490
491 /****************************************************************************/
492 /* Set collate flag (merge only).                                           */
493 /****************************************************************************/
494 void
495 gl_mini_preview_set_collate_flag (glMiniPreview     *this,
496                                   gboolean           collate_flag)
497 {
498         if ( collate_flag != this->priv->collate_flag )
499         {
500                 this->priv->collate_flag = collate_flag;
501                 redraw (this);
502         }
503 }
504
505
506 /****************************************************************************/
507 /* Set outline flag.                                                        */
508 /****************************************************************************/
509 void
510 gl_mini_preview_set_outline_flag (glMiniPreview     *this,
511                                   gboolean           outline_flag)
512 {
513         if ( outline_flag != this->priv->outline_flag )
514         {
515                 this->priv->outline_flag = outline_flag;
516                 redraw (this);
517         }
518 }
519
520
521 /****************************************************************************/
522 /* Set reverse flag.                                                        */
523 /****************************************************************************/
524 void
525 gl_mini_preview_set_reverse_flag (glMiniPreview     *this,
526                                   gboolean           reverse_flag)
527 {
528         if ( reverse_flag != this->priv->reverse_flag )
529         {
530                 this->priv->reverse_flag = reverse_flag;
531                 redraw (this);
532         }
533 }
534
535
536 /****************************************************************************/
537 /* Set crop marks flag.                                                     */
538 /****************************************************************************/
539 void
540 gl_mini_preview_set_crop_marks_flag (glMiniPreview     *this,
541                                      gboolean           crop_marks_flag)
542 {
543         if ( crop_marks_flag != this->priv->crop_marks_flag )
544         {
545                 this->priv->crop_marks_flag = crop_marks_flag;
546                 redraw (this);
547         }
548 }
549
550
551 /*--------------------------------------------------------------------------*/
552 /* Set transformation and return scale.                                     */
553 /*--------------------------------------------------------------------------*/
554 static gdouble
555 set_transform_and_get_scale (glMiniPreview *this,
556                              cairo_t       *cr)
557 {
558         lglTemplate *template = this->priv->template;
559         gdouble      w, h;
560         gdouble      scale;
561         gdouble      offset_x, offset_y;
562
563         /* Establish scale and origin. */
564         w = GTK_WIDGET (this)->allocation.width;
565         h = GTK_WIDGET (this)->allocation.height;
566
567         /* establish scale. */
568         scale = MIN( (w - 2*MARGIN - 2*SHADOW_OFFSET)/template->page_width,
569                      (h - 2*MARGIN - 2*SHADOW_OFFSET)/template->page_height );
570
571         /* Find offset to center preview. */
572         offset_x = (w/scale - template->page_width) / 2.0;
573         offset_y = (h/scale - template->page_height) / 2.0;
574
575         /* Set transformation. */
576         cairo_scale (cr, scale, scale);
577         cairo_translate (cr, offset_x, offset_y);
578
579         return scale;
580 }
581
582
583 /*--------------------------------------------------------------------------*/
584 /* Button press event handler                                               */
585 /*--------------------------------------------------------------------------*/
586 static gboolean
587 button_press_event_cb (GtkWidget      *widget,
588                        GdkEventButton *event)
589 {
590         glMiniPreview     *this = GL_MINI_PREVIEW (widget);
591         cairo_t           *cr;
592         gdouble            scale;
593         gdouble            x, y;
594         gint               i;
595
596         gl_debug (DEBUG_MINI_PREVIEW, "START");
597
598         if ( event->button == 1 )
599         {
600                 cr = gdk_cairo_create (GTK_WIDGET (this->priv->canvas)->window);
601
602                 scale = set_transform_and_get_scale (this, cr);
603
604                 x = event->x;
605                 y = event->y;
606                 cairo_device_to_user (cr, &x, &y);
607
608                 i = find_closest_label (this, x, y);
609
610                 g_signal_emit (G_OBJECT(this),
611                                mini_preview_signals[CLICKED],
612                                0, i);
613
614                 this->priv->first_i = i;
615                 this->priv->last_i  = i;
616                 g_signal_emit (G_OBJECT(this),
617                                mini_preview_signals[PRESSED],
618                                0, this->priv->first_i, this->priv->last_i);
619
620                 this->priv->dragging = TRUE;
621                 this->priv->prev_i   = i;
622
623                 cairo_destroy (cr);
624         }
625
626         gl_debug (DEBUG_MINI_PREVIEW, "END");
627         return FALSE;
628 }
629
630
631 /*--------------------------------------------------------------------------*/
632 /* Motion notify event handler                                              */
633 /*--------------------------------------------------------------------------*/
634 static gboolean
635 motion_notify_event_cb (GtkWidget      *widget,
636                         GdkEventMotion *event)
637 {
638         glMiniPreview *this = GL_MINI_PREVIEW (widget);
639         cairo_t           *cr;
640         gdouble            scale;
641         gdouble            x, y;
642         gint               i;
643
644         gl_debug (DEBUG_MINI_PREVIEW, "START");
645
646         if (this->priv->dragging)
647         {
648                 cr = gdk_cairo_create (GTK_WIDGET (this->priv->canvas)->window);
649
650                 scale = set_transform_and_get_scale (this, cr);
651
652                 x = event->x;
653                 y = event->y;
654                 cairo_device_to_user (cr, &x, &y);
655
656                 i = find_closest_label (this, x, y);
657
658                 if ( i != this->priv->prev_i )
659                 {
660                         this->priv->last_i = i;
661
662                         g_signal_emit (G_OBJECT(this),
663                                        mini_preview_signals[PRESSED],
664                                        0,
665                                        MIN (this->priv->first_i, this->priv->last_i),
666                                        MAX (this->priv->first_i, this->priv->last_i));
667
668                         this->priv->prev_i = i;
669                 }
670                 cairo_destroy (cr);
671         }
672
673         gl_debug (DEBUG_MINI_PREVIEW, "END");
674         return FALSE;
675 }
676
677
678 /*--------------------------------------------------------------------------*/
679 /* Button release event handler                                             */
680 /*--------------------------------------------------------------------------*/
681 static gboolean
682 button_release_event_cb (GtkWidget      *widget,
683                          GdkEventButton *event)
684 {
685         glMiniPreview *this = GL_MINI_PREVIEW (widget);
686         
687         gl_debug (DEBUG_MINI_PREVIEW, "START");
688
689         if ( event->button == 1 )
690         {
691                 this->priv->dragging = FALSE;
692
693         }
694
695         g_signal_emit (G_OBJECT(this),
696                        mini_preview_signals[RELEASED],
697                        0, this->priv->first_i, this->priv->last_i);
698
699         gl_debug (DEBUG_MINI_PREVIEW, "END");
700         return FALSE;
701 }
702
703
704 /*--------------------------------------------------------------------------*/
705 /* Find index+1 of label closest to given coordinates.                      */
706 /*--------------------------------------------------------------------------*/
707 static gint
708 find_closest_label (glMiniPreview      *this,
709                     gdouble             x,
710                     gdouble             y)
711 {
712         gint    i;
713         gint    min_i;
714         gdouble dx, dy, d2, min_d2;
715
716         dx = x - this->priv->centers[0].x;
717         dy = y - this->priv->centers[0].y;
718         min_d2 = dx*dx + dy*dy;
719         min_i = 0;
720
721         for ( i=1; i<this->priv->labels_per_sheet; i++ )
722         {
723                 dx = x - this->priv->centers[i].x;
724                 dy = y - this->priv->centers[i].y;
725                 d2 = dx*dx + dy*dy;
726
727                 if ( d2 < min_d2 )
728                 {
729                         min_d2 = d2;
730                         min_i  = i;
731                 }
732         }
733
734         return min_i + 1;
735 }
736
737
738 /*--------------------------------------------------------------------------*/
739 /* Expose event handler.                                                    */
740 /*--------------------------------------------------------------------------*/
741 static gboolean
742 expose_event_cb (GtkWidget       *widget,
743                  GdkEventExpose  *event,
744                  glMiniPreview   *this)
745 {
746         cairo_t       *cr;
747
748         gl_debug (DEBUG_MINI_PREVIEW, "START");
749
750         this->priv->update_scheduled_flag = FALSE;
751
752         cr = gdk_cairo_create (widget->window);
753
754         cairo_rectangle (cr,
755                         event->area.x, event->area.y,
756                         event->area.width, event->area.height);
757         cairo_clip (cr);
758         cairo_translate (cr, widget->allocation.x, widget->allocation.y);
759         
760         draw (this, cr);
761
762         cairo_destroy (cr);
763
764         gl_debug (DEBUG_MINI_PREVIEW, "END");
765         return FALSE;
766 }
767
768
769 /*--------------------------------------------------------------------------*/
770 /* Style set handler (updates colors when style/theme changes).             */
771 /*--------------------------------------------------------------------------*/
772 static void
773 style_set_cb (GtkWidget        *widget,
774               GtkStyle         *previous_style,
775               glMiniPreview    *this)
776 {
777         gl_debug (DEBUG_MINI_PREVIEW, "START");
778
779         redraw (this);
780
781         gl_debug (DEBUG_MINI_PREVIEW, "END");
782 }
783
784
785 /*--------------------------------------------------------------------------*/
786 /* Redraw.                                                                  */
787 /*--------------------------------------------------------------------------*/
788 static void
789 redraw (glMiniPreview      *this)
790 {
791         GdkRegion *region;
792         
793         gl_debug (DEBUG_MINI_PREVIEW, "START");
794
795         if (GTK_WIDGET (this->priv->canvas)->window)
796         {
797
798                 if ( !this->priv->update_scheduled_flag )
799                 {
800                         this->priv->update_scheduled_flag = TRUE;
801
802                         region = gdk_drawable_get_clip_region (GTK_WIDGET (this->priv->canvas)->window);
803                         gdk_window_invalidate_region (GTK_WIDGET (this->priv->canvas)->window, region, TRUE);
804                         gdk_region_destroy (region);
805                 }
806         }
807
808         gl_debug (DEBUG_MINI_PREVIEW, "END");
809 }
810
811
812 /*--------------------------------------------------------------------------*/
813 /* Draw mini preview.                                                       */
814 /*--------------------------------------------------------------------------*/
815 static void
816 draw (glMiniPreview  *this,
817       cairo_t        *cr)
818 {
819         lglTemplate *template = this->priv->template;
820         gdouble      scale;
821         gdouble      shadow_x, shadow_y;
822
823
824         gl_debug (DEBUG_MINI_PREVIEW, "START");
825
826         if (template)
827         {
828
829                 scale = set_transform_and_get_scale (this, cr);
830
831                 /* update shadow */
832                 shadow_x = SHADOW_OFFSET/scale;
833                 shadow_y = SHADOW_OFFSET/scale;
834
835                 draw_shadow (this, cr,
836                              shadow_x, shadow_y,
837                              template->page_width, template->page_height);
838
839                 draw_paper (this, cr,
840                             template->page_width, template->page_height,
841                             1.0/scale);
842
843                 draw_labels (this, cr, template, 1.0/scale);
844
845                 if (this->priv->label)
846                 {
847                         draw_rich_preview (this, cr);
848                 }
849                              
850         }
851
852         gl_debug (DEBUG_MINI_PREVIEW, "END");
853
854 }
855
856
857 /*--------------------------------------------------------------------------*/
858 /* Draw page shadow                                                         */
859 /*--------------------------------------------------------------------------*/
860 static void
861 draw_shadow (glMiniPreview      *this,
862              cairo_t            *cr,
863              gdouble             x,
864              gdouble             y,
865              gdouble             width,
866              gdouble             height)
867 {
868         GtkStyle *style;
869         guint     shadow_color;
870
871         gl_debug (DEBUG_MINI_PREVIEW, "START");
872
873         cairo_save (cr);
874
875         cairo_rectangle (cr, x, y, width, height);
876
877         style = gtk_widget_get_style (GTK_WIDGET(this));
878         shadow_color = gl_color_from_gdk_color (&style->dark[GTK_STATE_NORMAL]);
879         cairo_set_source_rgb (cr, GL_COLOR_RGB_ARGS (shadow_color));
880
881         cairo_fill (cr);
882
883         cairo_restore (cr);
884
885         gl_debug (DEBUG_MINI_PREVIEW, "END");
886 }
887
888
889 /*--------------------------------------------------------------------------*/
890 /* Draw page                                                                */
891 /*--------------------------------------------------------------------------*/
892 static void
893 draw_paper (glMiniPreview      *this,
894             cairo_t            *cr,
895             gdouble             width,
896             gdouble             height,
897             gdouble             line_width)
898 {
899         GtkStyle                  *style;
900         guint                      paper_color, outline_color;
901
902         gl_debug (DEBUG_MINI_PREVIEW, "START");
903
904         cairo_save (cr);
905
906         style = gtk_widget_get_style (GTK_WIDGET(this));
907         paper_color   = gl_color_from_gdk_color (&style->light[GTK_STATE_NORMAL]);
908         outline_color = gl_color_from_gdk_color (&style->fg[GTK_STATE_NORMAL]);
909
910         cairo_rectangle (cr, 0.0, 0.0, width, height);
911
912         cairo_set_source_rgb (cr, GL_COLOR_RGB_ARGS (paper_color));
913         cairo_fill_preserve (cr);
914
915         cairo_set_source_rgb (cr, GL_COLOR_RGB_ARGS (outline_color));
916         cairo_set_line_width (cr, line_width);
917         cairo_stroke (cr);
918
919         cairo_restore (cr);
920
921         gl_debug (DEBUG_MINI_PREVIEW, "END");
922 }
923
924
925 /*--------------------------------------------------------------------------*/
926 /* Draw labels                                                              */
927 /*--------------------------------------------------------------------------*/
928 static void
929 draw_labels (glMiniPreview *this,
930              cairo_t       *cr,
931              lglTemplate   *template,
932              gdouble        line_width)
933 {
934         const lglTemplateFrame    *frame;
935         gint                       i, n_labels;
936         lglTemplateOrigin         *origins;
937         GtkStyle                  *style;
938         guint                      base_color;
939         guint                      highlight_color, paper_color, outline_color;
940
941         gl_debug (DEBUG_MINI_PREVIEW, "START");
942
943         frame = (lglTemplateFrame *)template->frames->data;
944
945         n_labels = lgl_template_frame_get_n_labels (frame);
946         origins  = lgl_template_frame_get_origins (frame);
947
948         style = gtk_widget_get_style (GTK_WIDGET(this));
949         base_color      = gl_color_from_gdk_color (&style->base[GTK_STATE_SELECTED]);
950
951         paper_color     = gl_color_from_gdk_color (&style->light[GTK_STATE_NORMAL]);
952         highlight_color = gl_color_set_opacity (base_color, 0.10);
953         if (this->priv->label)
954         {
955                 /* Outlines are more subtle when doing a rich preview. */
956                 outline_color   = gl_color_set_opacity (base_color, 0.05);
957         }
958         else
959         {
960                 outline_color   = gl_color_set_opacity (base_color, 1.00);
961         }
962
963         for ( i=0; i < n_labels; i++ ) {
964
965                 cairo_save (cr);
966
967                 cairo_translate (cr, origins[i].x, origins[i].y);
968                 gl_cairo_label_path (cr, template, FALSE, FALSE);
969
970                 if ( ((i+1) >= this->priv->highlight_first) &&
971                      ((i+1) <= this->priv->highlight_last) )
972                 {
973                         cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (highlight_color));
974                         cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
975                         cairo_fill_preserve (cr);
976                 }
977
978                 cairo_set_line_width (cr, line_width);
979                 cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (outline_color));
980                 cairo_stroke (cr);
981
982                 cairo_restore (cr);
983
984         }
985
986         g_free (origins);
987
988         gl_debug (DEBUG_MINI_PREVIEW, "END");
989 }
990
991
992 /*--------------------------------------------------------------------------*/
993 /* Draw rich preview using print renderers.                                 */
994 /*--------------------------------------------------------------------------*/
995 static void
996 draw_rich_preview (glMiniPreview          *this,
997                    cairo_t                *cr)
998 {
999         glMerge      *merge;
1000         glPrintState  state;
1001
1002         merge = gl_label_get_merge (this->priv->label);
1003
1004         if (!merge)
1005         {
1006                 gl_print_simple_sheet (this->priv->label,
1007                                        cr,
1008                                        this->priv->page,
1009                                        this->priv->n_sheets,
1010                                        this->priv->first,
1011                                        this->priv->last,
1012                                        this->priv->outline_flag,
1013                                        this->priv->reverse_flag,
1014                                        this->priv->crop_marks_flag);
1015         }
1016         else
1017         {
1018                 /* FIXME: maybe the renderers should be more self contained.
1019                  *        This will only work for the first page, since
1020                  *        previous pages must be rendered to establish
1021                  *        state.
1022                  */
1023                 state.i_copy = 0;
1024                 state.p_record = (GList *)gl_merge_get_record_list (merge);
1025
1026                 if (this->priv->collate_flag)
1027                 {
1028                         gl_print_collated_merge_sheet (this->priv->label,
1029                                                        cr,
1030                                                        this->priv->page,
1031                                                        this->priv->n_copies,
1032                                                        this->priv->first,
1033                                                        this->priv->outline_flag,
1034                                                        this->priv->reverse_flag,
1035                                                        this->priv->crop_marks_flag,
1036                                                        &state);
1037                 }
1038                 else
1039                 {
1040                         gl_print_uncollated_merge_sheet (this->priv->label,
1041                                                          cr,
1042                                                          this->priv->page,
1043                                                          this->priv->n_copies,
1044                                                          this->priv->first,
1045                                                          this->priv->outline_flag,
1046                                                          this->priv->reverse_flag,
1047                                                          this->priv->crop_marks_flag,
1048                                                          &state);
1049                 }
1050         }
1051 }
1052
1053
1054
1055 /*
1056  * Local Variables:       -- emacs
1057  * mode: C                -- emacs
1058  * c-basic-offset: 8      -- emacs
1059  * tab-width: 8           -- emacs
1060  * indent-tabs-mode: nil  -- emacs
1061  * End:                   -- emacs
1062  */