]> git.sur5r.net Git - glabels/blob - src/mini-preview.c
Make libglabels parallel installable with other versions
[glabels] / 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.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_has_window(this->priv->canvas, FALSE);
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         GtkAllocation  allocation;
560         gdouble        w, h;
561         gdouble        scale;
562         gdouble        offset_x, offset_y;
563
564         /* Establish scale and origin. */
565         gtk_widget_get_allocation (GTK_WIDGET (this), &allocation);
566         w = allocation.width;
567         h = allocation.height;
568
569         /* establish scale. */
570         scale = MIN( (w - 2*MARGIN - 2*SHADOW_OFFSET)/template->page_width,
571                      (h - 2*MARGIN - 2*SHADOW_OFFSET)/template->page_height );
572
573         /* Find offset to center preview. */
574         offset_x = (w/scale - template->page_width) / 2.0;
575         offset_y = (h/scale - template->page_height) / 2.0;
576
577         /* Set transformation. */
578         cairo_scale (cr, scale, scale);
579         cairo_translate (cr, offset_x, offset_y);
580
581         return scale;
582 }
583
584
585 /*--------------------------------------------------------------------------*/
586 /* Button press event handler                                               */
587 /*--------------------------------------------------------------------------*/
588 static gboolean
589 button_press_event_cb (GtkWidget      *widget,
590                        GdkEventButton *event)
591 {
592         glMiniPreview     *this = GL_MINI_PREVIEW (widget);
593         GdkWindow         *window;
594         cairo_t           *cr;
595         gdouble            scale;
596         gdouble            x, y;
597         gint               i;
598
599         gl_debug (DEBUG_MINI_PREVIEW, "START");
600
601         if ( event->button == 1 )
602         {
603
604                 window = gtk_widget_get_window (this->priv->canvas);
605
606                 cr = gdk_cairo_create (window);
607
608                 scale = set_transform_and_get_scale (this, cr);
609
610                 x = event->x;
611                 y = event->y;
612                 cairo_device_to_user (cr, &x, &y);
613
614                 i = find_closest_label (this, x, y);
615
616                 g_signal_emit (G_OBJECT(this),
617                                mini_preview_signals[CLICKED],
618                                0, i);
619
620                 this->priv->first_i = i;
621                 this->priv->last_i  = i;
622                 g_signal_emit (G_OBJECT(this),
623                                mini_preview_signals[PRESSED],
624                                0, this->priv->first_i, this->priv->last_i);
625
626                 this->priv->dragging = TRUE;
627                 this->priv->prev_i   = i;
628
629                 cairo_destroy (cr);
630         }
631
632         gl_debug (DEBUG_MINI_PREVIEW, "END");
633         return FALSE;
634 }
635
636
637 /*--------------------------------------------------------------------------*/
638 /* Motion notify event handler                                              */
639 /*--------------------------------------------------------------------------*/
640 static gboolean
641 motion_notify_event_cb (GtkWidget      *widget,
642                         GdkEventMotion *event)
643 {
644         glMiniPreview *this = GL_MINI_PREVIEW (widget);
645         GdkWindow     *window;
646         cairo_t       *cr;
647         gdouble        scale;
648         gdouble        x, y;
649         gint           i;
650
651         gl_debug (DEBUG_MINI_PREVIEW, "START");
652
653         if (this->priv->dragging)
654         {
655                 window = gtk_widget_get_window (this->priv->canvas);
656
657                 cr = gdk_cairo_create (window);
658
659                 scale = set_transform_and_get_scale (this, cr);
660
661                 x = event->x;
662                 y = event->y;
663                 cairo_device_to_user (cr, &x, &y);
664
665                 i = find_closest_label (this, x, y);
666
667                 if ( i != this->priv->prev_i )
668                 {
669                         this->priv->last_i = i;
670
671                         g_signal_emit (G_OBJECT(this),
672                                        mini_preview_signals[PRESSED],
673                                        0,
674                                        MIN (this->priv->first_i, this->priv->last_i),
675                                        MAX (this->priv->first_i, this->priv->last_i));
676
677                         this->priv->prev_i = i;
678                 }
679                 cairo_destroy (cr);
680         }
681
682         gl_debug (DEBUG_MINI_PREVIEW, "END");
683         return FALSE;
684 }
685
686
687 /*--------------------------------------------------------------------------*/
688 /* Button release event handler                                             */
689 /*--------------------------------------------------------------------------*/
690 static gboolean
691 button_release_event_cb (GtkWidget      *widget,
692                          GdkEventButton *event)
693 {
694         glMiniPreview *this = GL_MINI_PREVIEW (widget);
695         
696         gl_debug (DEBUG_MINI_PREVIEW, "START");
697
698         if ( event->button == 1 )
699         {
700                 this->priv->dragging = FALSE;
701
702         }
703
704         g_signal_emit (G_OBJECT(this),
705                        mini_preview_signals[RELEASED],
706                        0, this->priv->first_i, this->priv->last_i);
707
708         gl_debug (DEBUG_MINI_PREVIEW, "END");
709         return FALSE;
710 }
711
712
713 /*--------------------------------------------------------------------------*/
714 /* Find index+1 of label closest to given coordinates.                      */
715 /*--------------------------------------------------------------------------*/
716 static gint
717 find_closest_label (glMiniPreview      *this,
718                     gdouble             x,
719                     gdouble             y)
720 {
721         gint    i;
722         gint    min_i;
723         gdouble dx, dy, d2, min_d2;
724
725         dx = x - this->priv->centers[0].x;
726         dy = y - this->priv->centers[0].y;
727         min_d2 = dx*dx + dy*dy;
728         min_i = 0;
729
730         for ( i=1; i<this->priv->labels_per_sheet; i++ )
731         {
732                 dx = x - this->priv->centers[i].x;
733                 dy = y - this->priv->centers[i].y;
734                 d2 = dx*dx + dy*dy;
735
736                 if ( d2 < min_d2 )
737                 {
738                         min_d2 = d2;
739                         min_i  = i;
740                 }
741         }
742
743         return min_i + 1;
744 }
745
746
747 /*--------------------------------------------------------------------------*/
748 /* Expose event handler.                                                    */
749 /*--------------------------------------------------------------------------*/
750 static gboolean
751 expose_event_cb (GtkWidget       *widget,
752                  GdkEventExpose  *event,
753                  glMiniPreview   *this)
754 {
755         GdkWindow     *window;
756         cairo_t       *cr;
757         GtkAllocation  allocation;
758
759         gl_debug (DEBUG_MINI_PREVIEW, "START");
760
761         this->priv->update_scheduled_flag = FALSE;
762
763         window = gtk_widget_get_window (widget);
764
765         cr = gdk_cairo_create (window);
766
767         cairo_rectangle (cr,
768                         event->area.x, event->area.y,
769                         event->area.width, event->area.height);
770         cairo_clip (cr);
771
772         gtk_widget_get_allocation (widget, &allocation);
773         cairo_translate (cr, allocation.x, allocation.y);
774         
775         draw (this, cr);
776
777         cairo_destroy (cr);
778
779         gl_debug (DEBUG_MINI_PREVIEW, "END");
780         return FALSE;
781 }
782
783
784 /*--------------------------------------------------------------------------*/
785 /* Style set handler (updates colors when style/theme changes).             */
786 /*--------------------------------------------------------------------------*/
787 static void
788 style_set_cb (GtkWidget        *widget,
789               GtkStyle         *previous_style,
790               glMiniPreview    *this)
791 {
792         gl_debug (DEBUG_MINI_PREVIEW, "START");
793
794         redraw (this);
795
796         gl_debug (DEBUG_MINI_PREVIEW, "END");
797 }
798
799
800 /*--------------------------------------------------------------------------*/
801 /* Redraw.                                                                  */
802 /*--------------------------------------------------------------------------*/
803 static void
804 redraw (glMiniPreview      *this)
805 {
806         GdkWindow *window;
807         GdkRegion *region;
808         
809         gl_debug (DEBUG_MINI_PREVIEW, "START");
810
811         window = gtk_widget_get_window (this->priv->canvas);
812
813         if (window)
814         {
815
816                 if ( !this->priv->update_scheduled_flag )
817                 {
818                         this->priv->update_scheduled_flag = TRUE;
819
820                         region = gdk_drawable_get_clip_region (window);
821                         gdk_window_invalidate_region (window, region, TRUE);
822                         gdk_region_destroy (region);
823                 }
824         }
825
826         gl_debug (DEBUG_MINI_PREVIEW, "END");
827 }
828
829
830 /*--------------------------------------------------------------------------*/
831 /* Draw mini preview.                                                       */
832 /*--------------------------------------------------------------------------*/
833 static void
834 draw (glMiniPreview  *this,
835       cairo_t        *cr)
836 {
837         lglTemplate *template = this->priv->template;
838         gdouble      scale;
839         gdouble      shadow_x, shadow_y;
840
841
842         gl_debug (DEBUG_MINI_PREVIEW, "START");
843
844         if (template)
845         {
846
847                 scale = set_transform_and_get_scale (this, cr);
848
849                 /* update shadow */
850                 shadow_x = SHADOW_OFFSET/scale;
851                 shadow_y = SHADOW_OFFSET/scale;
852
853                 draw_shadow (this, cr,
854                              shadow_x, shadow_y,
855                              template->page_width, template->page_height);
856
857                 draw_paper (this, cr,
858                             template->page_width, template->page_height,
859                             1.0/scale);
860
861                 draw_labels (this, cr, template, 1.0/scale);
862
863                 if (this->priv->label)
864                 {
865                         draw_rich_preview (this, cr);
866                 }
867                              
868         }
869
870         gl_debug (DEBUG_MINI_PREVIEW, "END");
871
872 }
873
874
875 /*--------------------------------------------------------------------------*/
876 /* Draw page shadow                                                         */
877 /*--------------------------------------------------------------------------*/
878 static void
879 draw_shadow (glMiniPreview      *this,
880              cairo_t            *cr,
881              gdouble             x,
882              gdouble             y,
883              gdouble             width,
884              gdouble             height)
885 {
886         GtkStyle *style;
887         guint     shadow_color;
888
889         gl_debug (DEBUG_MINI_PREVIEW, "START");
890
891         cairo_save (cr);
892
893         cairo_rectangle (cr, x, y, width, height);
894
895         style = gtk_widget_get_style (GTK_WIDGET(this));
896         shadow_color = gl_color_from_gdk_color (&style->dark[GTK_STATE_NORMAL]);
897         cairo_set_source_rgb (cr, GL_COLOR_RGB_ARGS (shadow_color));
898
899         cairo_fill (cr);
900
901         cairo_restore (cr);
902
903         gl_debug (DEBUG_MINI_PREVIEW, "END");
904 }
905
906
907 /*--------------------------------------------------------------------------*/
908 /* Draw page                                                                */
909 /*--------------------------------------------------------------------------*/
910 static void
911 draw_paper (glMiniPreview      *this,
912             cairo_t            *cr,
913             gdouble             width,
914             gdouble             height,
915             gdouble             line_width)
916 {
917         GtkStyle                  *style;
918         guint                      paper_color, outline_color;
919
920         gl_debug (DEBUG_MINI_PREVIEW, "START");
921
922         cairo_save (cr);
923
924         style = gtk_widget_get_style (GTK_WIDGET(this));
925         paper_color   = gl_color_from_gdk_color (&style->light[GTK_STATE_NORMAL]);
926         outline_color = gl_color_from_gdk_color (&style->fg[GTK_STATE_NORMAL]);
927
928         cairo_rectangle (cr, 0.0, 0.0, width, height);
929
930         cairo_set_source_rgb (cr, GL_COLOR_RGB_ARGS (paper_color));
931         cairo_fill_preserve (cr);
932
933         cairo_set_source_rgb (cr, GL_COLOR_RGB_ARGS (outline_color));
934         cairo_set_line_width (cr, line_width);
935         cairo_stroke (cr);
936
937         cairo_restore (cr);
938
939         gl_debug (DEBUG_MINI_PREVIEW, "END");
940 }
941
942
943 /*--------------------------------------------------------------------------*/
944 /* Draw labels                                                              */
945 /*--------------------------------------------------------------------------*/
946 static void
947 draw_labels (glMiniPreview *this,
948              cairo_t       *cr,
949              lglTemplate   *template,
950              gdouble        line_width)
951 {
952         const lglTemplateFrame    *frame;
953         gint                       i, n_labels;
954         lglTemplateOrigin         *origins;
955         GtkStyle                  *style;
956         guint                      base_color;
957         guint                      highlight_color, paper_color, outline_color;
958
959         gl_debug (DEBUG_MINI_PREVIEW, "START");
960
961         frame = (lglTemplateFrame *)template->frames->data;
962
963         n_labels = lgl_template_frame_get_n_labels (frame);
964         origins  = lgl_template_frame_get_origins (frame);
965
966         style = gtk_widget_get_style (GTK_WIDGET(this));
967         base_color      = gl_color_from_gdk_color (&style->base[GTK_STATE_SELECTED]);
968
969         paper_color     = gl_color_from_gdk_color (&style->light[GTK_STATE_NORMAL]);
970         highlight_color = gl_color_set_opacity (base_color, 0.10);
971         if (this->priv->label)
972         {
973                 /* Outlines are more subtle when doing a rich preview. */
974                 outline_color   = gl_color_set_opacity (base_color, 0.05);
975         }
976         else
977         {
978                 outline_color   = gl_color_set_opacity (base_color, 1.00);
979         }
980
981         for ( i=0; i < n_labels; i++ ) {
982
983                 cairo_save (cr);
984
985                 cairo_translate (cr, origins[i].x, origins[i].y);
986                 gl_cairo_label_path (cr, template, FALSE, FALSE);
987
988                 if ( ((i+1) >= this->priv->highlight_first) &&
989                      ((i+1) <= this->priv->highlight_last) )
990                 {
991                         cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (highlight_color));
992                         cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
993                         cairo_fill_preserve (cr);
994                 }
995
996                 cairo_set_line_width (cr, line_width);
997                 cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (outline_color));
998                 cairo_stroke (cr);
999
1000                 cairo_restore (cr);
1001
1002         }
1003
1004         g_free (origins);
1005
1006         gl_debug (DEBUG_MINI_PREVIEW, "END");
1007 }
1008
1009
1010 /*--------------------------------------------------------------------------*/
1011 /* Draw rich preview using print renderers.                                 */
1012 /*--------------------------------------------------------------------------*/
1013 static void
1014 draw_rich_preview (glMiniPreview          *this,
1015                    cairo_t                *cr)
1016 {
1017         glMerge      *merge;
1018         glPrintState  state;
1019
1020         merge = gl_label_get_merge (this->priv->label);
1021
1022         if (!merge)
1023         {
1024                 gl_print_simple_sheet (this->priv->label,
1025                                        cr,
1026                                        this->priv->page,
1027                                        this->priv->n_sheets,
1028                                        this->priv->first,
1029                                        this->priv->last,
1030                                        this->priv->outline_flag,
1031                                        this->priv->reverse_flag,
1032                                        this->priv->crop_marks_flag);
1033         }
1034         else
1035         {
1036                 /* FIXME: maybe the renderers should be more self contained.
1037                  *        This will only work for the first page, since
1038                  *        previous pages must be rendered to establish
1039                  *        state.
1040                  */
1041                 state.i_copy = 0;
1042                 state.p_record = (GList *)gl_merge_get_record_list (merge);
1043
1044                 if (this->priv->collate_flag)
1045                 {
1046                         gl_print_collated_merge_sheet (this->priv->label,
1047                                                        cr,
1048                                                        this->priv->page,
1049                                                        this->priv->n_copies,
1050                                                        this->priv->first,
1051                                                        this->priv->outline_flag,
1052                                                        this->priv->reverse_flag,
1053                                                        this->priv->crop_marks_flag,
1054                                                        &state);
1055                 }
1056                 else
1057                 {
1058                         gl_print_uncollated_merge_sheet (this->priv->label,
1059                                                          cr,
1060                                                          this->priv->page,
1061                                                          this->priv->n_copies,
1062                                                          this->priv->first,
1063                                                          this->priv->outline_flag,
1064                                                          this->priv->reverse_flag,
1065                                                          this->priv->crop_marks_flag,
1066                                                          &state);
1067                 }
1068         }
1069 }
1070
1071
1072
1073 /*
1074  * Local Variables:       -- emacs
1075  * mode: C                -- emacs
1076  * c-basic-offset: 8      -- emacs
1077  * tab-width: 8           -- emacs
1078  * indent-tabs-mode: nil  -- emacs
1079  * End:                   -- emacs
1080  */