]> git.sur5r.net Git - glabels/blob - glabels2/src/wdgt-mini-preview.c
2007-02-04 Jim Evins <evins@snaught.com>
[glabels] / glabels2 / src / wdgt-mini-preview.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2
3 /*
4  *  (GLABELS) Label and Business Card Creation program for GNOME
5  *
6  *  wdgt_mini_preview.c:  mini preview widget module
7  *
8  *  Copyright (C) 2001-2007  Jim Evins <evins@snaught.com>.
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
23  */
24
25 #include <config.h>
26
27 #include "wdgt-mini-preview.h"
28
29 #include <math.h>
30
31 #include "marshal.h"
32 #include "color.h"
33
34 #include "debug.h"
35
36 #define SHADOW_X_OFFSET 5
37 #define SHADOW_Y_OFFSET 5
38
39 /*===========================================*/
40 /* Private types                             */
41 /*===========================================*/
42
43 enum {
44         CLICKED,
45         PRESSED,
46         LAST_SIGNAL
47 };
48
49 typedef struct {
50         gdouble x;
51         gdouble y;
52 } LabelCenter;
53
54 struct _glWdgtMiniPreviewPrivate {
55
56         gint            height;
57         gint            width;
58
59         glTemplate     *template;
60         gdouble         scale;
61         gdouble         offset_x;
62         gdouble         offset_y;
63         gint            labels_per_sheet;
64         LabelCenter    *centers;
65
66         gint            highlight_first;
67         gint            highlight_last;
68
69         gboolean        dragging;
70         gint            first_i;
71         gint            last_i;
72         gint            prev_i;
73 };
74
75 /*===========================================*/
76 /* Private globals                           */
77 /*===========================================*/
78
79 static GtkDrawingAreaClass *parent_class;
80
81 static gint wdgt_mini_preview_signals[LAST_SIGNAL] = { 0 };
82
83 /*===========================================*/
84 /* Local function prototypes                 */
85 /*===========================================*/
86
87 static void gl_wdgt_mini_preview_class_init    (glWdgtMiniPreviewClass *class);
88 static void gl_wdgt_mini_preview_instance_init (glWdgtMiniPreview      *preview);
89 static void gl_wdgt_mini_preview_finalize      (GObject                *object);
90
91 static void gl_wdgt_mini_preview_construct     (glWdgtMiniPreview      *preview,
92                                                 gint                    height,
93                                                 gint                    width);
94
95 static gboolean expose_event_cb                (GtkWidget              *widget,
96                                                 GdkEventExpose         *event);
97 static void style_set_cb                       (GtkWidget              *widget,
98                                                 GtkStyle               *previous_style);
99 static gboolean button_press_event_cb          (GtkWidget              *widget,
100                                                 GdkEventButton         *event);
101 static gboolean motion_notify_event_cb         (GtkWidget              *widget,
102                                                 GdkEventMotion         *event);
103 static gboolean button_release_event_cb        (GtkWidget              *widget,
104                                                 GdkEventButton         *event);
105
106
107 static void redraw                             (GtkWidget              *widget);
108 static void draw                               (glWdgtMiniPreview      *preview,
109                                                 cairo_t                *cr);
110
111 static void draw_shadow                        (glWdgtMiniPreview      *preview,
112                                                 cairo_t                *cr,
113                                                 gdouble                      x,
114                                                 gdouble                 y,
115                                                 gdouble                 width,
116                                                 gdouble                 height);
117 static void draw_paper                         (glWdgtMiniPreview      *preview,
118                                                 cairo_t                *cr,
119                                                 gdouble                 width,
120                                                 gdouble                 height,
121                                                 gdouble                 line_width);
122 static void draw_labels                        (glWdgtMiniPreview      *preview,
123                                                 cairo_t                *cr,
124                                                 const glTemplate       *template,
125                                                 gdouble                 line_width);
126 static void create_label_path                  (cairo_t                *cr,
127                                                 const glTemplate       *template,
128                                                 gdouble                 x0,
129                                                 gdouble                 y0);
130 static void create_rect_label_path             (cairo_t                *cr,
131                                                 const glTemplate       *template,
132                                                 gdouble                 x0,
133                                                 gdouble                 y0);
134 static void create_round_label_path            (cairo_t                *cr,
135                                                 const glTemplate       *template,
136                                                 gdouble                 x0,
137                                                 gdouble                 y0);
138 static void create_cd_label_path               (cairo_t                *cr,
139                                                 const glTemplate       *template,
140                                                 gdouble                 x0,
141                                                 gdouble                 y0);
142
143 static gint find_closest_label                 (glWdgtMiniPreview      *preview,
144                                                 gdouble                 x,
145                                                 gdouble                 y);
146
147
148 \f
149 /****************************************************************************/
150 /* Boilerplate Object stuff.                                                */
151 /****************************************************************************/
152 GType
153 gl_wdgt_mini_preview_get_type (void)
154 {
155         static GType type = 0;
156
157         if (!type) {
158                 static const GTypeInfo info = {
159                         sizeof (glWdgtMiniPreviewClass),
160                         NULL,
161                         NULL,
162                         (GClassInitFunc) gl_wdgt_mini_preview_class_init,
163                         NULL,
164                         NULL,
165                         sizeof (glWdgtMiniPreview),
166                         0,
167                         (GInstanceInitFunc) gl_wdgt_mini_preview_instance_init,
168                         NULL
169                 };
170
171                 type = g_type_register_static (GTK_TYPE_DRAWING_AREA,
172                                                "glWdgtMiniPreview", &info, 0);
173         }
174
175         return type;
176 }
177
178 static void
179 gl_wdgt_mini_preview_class_init (glWdgtMiniPreviewClass *class)
180 {
181         GObjectClass   *object_class = G_OBJECT_CLASS (class);
182         GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
183
184         gl_debug (DEBUG_MINI_PREVIEW, "START");
185
186         parent_class = gtk_type_class (gtk_hbox_get_type ());
187
188         object_class->finalize = gl_wdgt_mini_preview_finalize;
189
190         widget_class->expose_event         = expose_event_cb;
191         widget_class->style_set            = style_set_cb;
192         widget_class->button_press_event   = button_press_event_cb;
193         widget_class->motion_notify_event  = motion_notify_event_cb;
194         widget_class->button_release_event = button_release_event_cb;
195
196         wdgt_mini_preview_signals[CLICKED] =
197             g_signal_new ("clicked",
198                           G_OBJECT_CLASS_TYPE(object_class),
199                           G_SIGNAL_RUN_LAST,
200                           G_STRUCT_OFFSET (glWdgtMiniPreviewClass, clicked),
201                           NULL, NULL,
202                           gl_marshal_VOID__INT,
203                           G_TYPE_NONE, 1, G_TYPE_INT);
204
205         wdgt_mini_preview_signals[PRESSED] =
206             g_signal_new ("pressed",
207                           G_OBJECT_CLASS_TYPE(object_class),
208                           G_SIGNAL_RUN_LAST,
209                           G_STRUCT_OFFSET (glWdgtMiniPreviewClass, pressed),
210                           NULL, NULL,
211                           gl_marshal_VOID__INT_INT,
212                           G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
213
214         gl_debug (DEBUG_MINI_PREVIEW, "END");
215 }
216
217 static void
218 gl_wdgt_mini_preview_instance_init (glWdgtMiniPreview *preview)
219 {
220         gl_debug (DEBUG_MINI_PREVIEW, "START");
221
222         preview->priv = g_new0 (glWdgtMiniPreviewPrivate, 1);
223
224         gtk_widget_add_events (GTK_WIDGET (preview),
225                                GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
226                                GDK_POINTER_MOTION_MASK);
227
228         gl_debug (DEBUG_MINI_PREVIEW, "END");
229 }
230
231 static void
232 gl_wdgt_mini_preview_finalize (GObject *object)
233 {
234         glWdgtMiniPreview *preview;
235         glWdgtMiniPreviewClass *class;
236
237         gl_debug (DEBUG_MINI_PREVIEW, "START");
238
239         g_return_if_fail (object != NULL);
240         g_return_if_fail (GL_IS_WDGT_MINI_PREVIEW (object));
241
242         preview = GL_WDGT_MINI_PREVIEW (object);
243
244         gl_template_free (preview->priv->template);
245         g_free (preview->priv->centers);
246         g_free (preview->priv);
247
248         G_OBJECT_CLASS (parent_class)->finalize (object);
249
250         gl_debug (DEBUG_MINI_PREVIEW, "END");
251 }
252
253 GtkWidget *
254 gl_wdgt_mini_preview_new (gint height,
255                           gint width)
256 {
257         glWdgtMiniPreview *preview;
258
259         gl_debug (DEBUG_MINI_PREVIEW, "START");
260
261         preview = g_object_new (gl_wdgt_mini_preview_get_type (), NULL);
262
263         gl_wdgt_mini_preview_construct (preview, height, width);
264
265         gl_debug (DEBUG_MINI_PREVIEW, "END");
266
267         return GTK_WIDGET (preview);
268 }
269
270 /*--------------------------------------------------------------------------*/
271 /* Construct composite widget.                                              */
272 /*--------------------------------------------------------------------------*/
273 static void
274 gl_wdgt_mini_preview_construct (glWdgtMiniPreview *preview,
275                                 gint               height,
276                                 gint               width)
277 {
278         GnomeCanvasGroup *group;
279         GtkStyle         *style;
280         guint             shadow_color;
281
282         gl_debug (DEBUG_MINI_PREVIEW, "START");
283
284         preview->priv->height = height;
285         preview->priv->width  = width;
286
287         gtk_widget_set_size_request (GTK_WIDGET (preview), width, height);
288
289         gl_debug (DEBUG_MINI_PREVIEW, "END");
290 }
291
292 /****************************************************************************/
293 /* Set label for mini-preview to determine geometry.                        */
294 /****************************************************************************/
295 void gl_wdgt_mini_preview_set_label_by_name (glWdgtMiniPreview *preview,
296                                              const gchar       *name)
297 {
298         glTemplate *template;
299
300         gl_debug (DEBUG_MINI_PREVIEW, "START");
301
302         /* Fetch template */
303         template = gl_template_from_name (name);
304
305         gl_wdgt_mini_preview_set_template (preview, template);
306
307         gl_template_free (template);
308
309         gl_debug (DEBUG_MINI_PREVIEW, "END");
310 }
311
312 /****************************************************************************/
313 /* Set label for mini-preview to determine geometry.                        */
314 /****************************************************************************/
315 void gl_wdgt_mini_preview_set_template (glWdgtMiniPreview *preview,
316                                         const glTemplate  *template)
317 {
318         const glTemplateLabelType *label_type;
319         glTemplateOrigin          *origins;
320         gdouble                    w, h;
321         gint                       i;
322
323         gl_debug (DEBUG_MINI_PREVIEW, "START");
324
325         label_type = gl_template_get_first_label_type (template);
326
327         /*
328          * Set template
329          */
330         gl_template_free (preview->priv->template);
331         preview->priv->template = gl_template_dup (template);
332
333         /*
334          * Set scale and offsets
335          */
336         w = preview->priv->width - 4 - 2*SHADOW_X_OFFSET;
337         h = preview->priv->height - 4 - 2*SHADOW_Y_OFFSET;
338         if ( (w/template->page_width) > (h/template->page_height) ) {
339                 preview->priv->scale = h / template->page_height;
340         } else {
341                 preview->priv->scale = w / template->page_width;
342         }
343         preview->priv->offset_x = (preview->priv->width/preview->priv->scale - template->page_width) / 2.0;
344         preview->priv->offset_y = (preview->priv->height/preview->priv->scale - template->page_height) / 2.0;
345
346         /*
347          * Set labels per sheet
348          */
349         preview->priv->labels_per_sheet = gl_template_get_n_labels (label_type);
350
351         /*
352          * Initialize centers
353          */
354         g_free (preview->priv->centers);
355         preview->priv->centers = g_new0 (LabelCenter, preview->priv->labels_per_sheet);
356         origins = gl_template_get_origins (label_type);
357         gl_template_get_label_size (label_type, &w, &h);
358         for ( i=0; i<preview->priv->labels_per_sheet; i++ )
359         {
360                 preview->priv->centers[i].x = origins[i].x + w/2.0;
361                 preview->priv->centers[i].y = origins[i].y + h/2.0;
362         }
363         g_free (origins);
364
365         /*
366          * Redraw modified preview
367          */
368         redraw( GTK_WIDGET (preview));
369
370         gl_debug (DEBUG_MINI_PREVIEW, "END");
371 }
372
373 /****************************************************************************/
374 /* Highlight given label outlines.                                          */
375 /****************************************************************************/
376 void
377 gl_wdgt_mini_preview_highlight_range (glWdgtMiniPreview *preview,
378                                       gint               first_label,
379                                       gint               last_label)
380 {
381         gl_debug (DEBUG_MINI_PREVIEW, "START");
382
383         preview->priv->highlight_first = first_label;
384         preview->priv->highlight_last =  last_label;
385
386         redraw( GTK_WIDGET (preview));
387
388         gl_debug (DEBUG_MINI_PREVIEW, "END");
389 }
390
391
392 /*--------------------------------------------------------------------------*/
393 /* Expose event handler.                                                    */
394 /*--------------------------------------------------------------------------*/
395 static gboolean
396 expose_event_cb (GtkWidget       *widget,
397                  GdkEventExpose  *event)
398 {
399         cairo_t *cr;
400
401         gl_debug (DEBUG_MINI_PREVIEW, "START");
402
403         cr = gdk_cairo_create (widget->window);
404
405         cairo_rectangle (cr,
406                         event->area.x, event->area.y,
407                         event->area.width, event->area.height);
408         cairo_clip (cr);
409         
410         draw (GL_WDGT_MINI_PREVIEW (widget), cr);
411
412         cairo_destroy (cr);
413
414         gl_debug (DEBUG_MINI_PREVIEW, "END");
415         return FALSE;
416 }
417
418 /*--------------------------------------------------------------------------*/
419 /* Button press event handler                                               */
420 /*--------------------------------------------------------------------------*/
421 static gboolean
422 button_press_event_cb (GtkWidget      *widget,
423                        GdkEventButton *event)
424 {
425         glWdgtMiniPreview *preview = GL_WDGT_MINI_PREVIEW (widget);
426         cairo_t           *cr;
427         gdouble            x, y;
428         gint               i;
429
430         gl_debug (DEBUG_MINI_PREVIEW, "START");
431
432         if ( event->button == 1 )
433         {
434                 cr = gdk_cairo_create (widget->window);
435
436                 /* Set transformation. */
437                 cairo_identity_matrix (cr);
438                 cairo_scale (cr, preview->priv->scale, preview->priv->scale);
439                 cairo_translate (cr, preview->priv->offset_x, preview->priv->offset_y);
440
441                 x = event->x;
442                 y = event->y;
443                 cairo_device_to_user (cr, &x, &y);
444
445                 i = find_closest_label (preview, x, y);
446
447                 g_signal_emit (G_OBJECT(preview),
448                                wdgt_mini_preview_signals[CLICKED],
449                                0, i);
450
451                 preview->priv->first_i = i;
452                 preview->priv->last_i  = i;
453                 g_signal_emit (G_OBJECT(preview),
454                                wdgt_mini_preview_signals[PRESSED],
455                                0, preview->priv->first_i, preview->priv->last_i);
456
457                 preview->priv->dragging = TRUE;
458                 preview->priv->prev_i   = i;
459
460                 cairo_destroy (cr);
461         }
462
463         gl_debug (DEBUG_MINI_PREVIEW, "END");
464         return FALSE;
465 }
466
467 /*--------------------------------------------------------------------------*/
468 /* Motion notify event handler                                              */
469 /*--------------------------------------------------------------------------*/
470 static gboolean
471 motion_notify_event_cb (GtkWidget      *widget,
472                         GdkEventMotion *event)
473 {
474         glWdgtMiniPreview *preview = GL_WDGT_MINI_PREVIEW (widget);
475         cairo_t           *cr;
476         gdouble            x, y;
477         gint               i;
478
479         gl_debug (DEBUG_MINI_PREVIEW, "START");
480
481         if (preview->priv->dragging)
482         {
483                 cr = gdk_cairo_create (widget->window);
484
485                 /* Set transformation. */
486                 cairo_identity_matrix (cr);
487                 cairo_scale (cr, preview->priv->scale, preview->priv->scale);
488                 cairo_translate (cr, preview->priv->offset_x, preview->priv->offset_y);
489
490                 x = event->x;
491                 y = event->y;
492                 cairo_device_to_user (cr, &x, &y);
493
494                 i = find_closest_label (preview, x, y);
495
496                 if ( i != preview->priv->prev_i )
497                 {
498                         preview->priv->last_i = i;
499
500                         g_signal_emit (G_OBJECT(preview),
501                                        wdgt_mini_preview_signals[PRESSED],
502                                        0,
503                                        MIN (preview->priv->first_i, preview->priv->last_i),
504                                        MAX (preview->priv->first_i, preview->priv->last_i));
505
506                         preview->priv->prev_i = i;
507                 }
508                 cairo_destroy (cr);
509         }
510
511         gl_debug (DEBUG_MINI_PREVIEW, "END");
512         return FALSE;
513 }
514
515 /*--------------------------------------------------------------------------*/
516 /* Button release event handler                                             */
517 /*--------------------------------------------------------------------------*/
518 static gboolean
519 button_release_event_cb (GtkWidget      *widget,
520                          GdkEventButton *event)
521 {
522         glWdgtMiniPreview *preview = GL_WDGT_MINI_PREVIEW (widget);
523         
524         gl_debug (DEBUG_MINI_PREVIEW, "START");
525
526         if ( event->button == 1 )
527         {
528                 preview->priv->dragging = FALSE;
529
530         }
531
532         gl_debug (DEBUG_MINI_PREVIEW, "END");
533         return FALSE;
534 }
535
536 /*--------------------------------------------------------------------------*/
537 /* Style set handler (updates colors when style/theme changes).             */
538 /*--------------------------------------------------------------------------*/
539 static void
540 style_set_cb (GtkWidget        *widget,
541               GtkStyle         *previous_style)
542 {
543         gl_debug (DEBUG_MINI_PREVIEW, "START");
544
545         redraw( widget );
546
547         gl_debug (DEBUG_MINI_PREVIEW, "END");
548 }
549
550 /*--------------------------------------------------------------------------*/
551 /* Redraw.                                                                  */
552 /*--------------------------------------------------------------------------*/
553 static void
554 redraw (GtkWidget *widget)
555 {
556         GdkRegion *region;
557         
558         gl_debug (DEBUG_MINI_PREVIEW, "START");
559
560         if (widget->window)
561         {
562
563                 region = gdk_drawable_get_clip_region (widget->window);
564
565                 gdk_window_invalidate_region (widget->window, region, TRUE);
566                 gdk_window_process_updates (widget->window, TRUE);
567
568                 gdk_region_destroy (region);
569         }
570
571         gl_debug (DEBUG_MINI_PREVIEW, "END");
572 }
573
574 /*--------------------------------------------------------------------------*/
575 /* Find index+1 of label closest to given coordinates.                      */
576 /*--------------------------------------------------------------------------*/
577 static gint
578 find_closest_label (glWdgtMiniPreview      *preview,
579                     gdouble                 x,
580                     gdouble                 y)
581 {
582         gint    i;
583         gint    min_i;
584         gdouble dx, dy, d2, min_d2;
585
586         dx = x - preview->priv->centers[0].x;
587         dy = y - preview->priv->centers[0].y;
588         min_d2 = dx*dx + dy*dy;
589         min_i = 0;
590
591         for ( i=1; i<preview->priv->labels_per_sheet; i++ )
592         {
593                 dx = x - preview->priv->centers[i].x;
594                 dy = y - preview->priv->centers[i].y;
595                 d2 = dx*dx + dy*dy;
596
597                 if ( d2 < min_d2 )
598                 {
599                         min_d2 = d2;
600                         min_i  = i;
601                 }
602         }
603
604         return min_i + 1;
605 }
606
607 /*--------------------------------------------------------------------------*/
608 /* Draw mini preview.                                                       */
609 /*--------------------------------------------------------------------------*/
610 static void
611 draw (glWdgtMiniPreview  *preview,
612       cairo_t            *cr)
613 {
614         glTemplate *template = preview->priv->template;
615         gdouble     shadow_x, shadow_y;
616
617         gl_debug (DEBUG_MINI_PREVIEW, "START");
618
619         if (template)
620         {
621
622                 /* Set transformation. */
623                 cairo_identity_matrix (cr);
624                 cairo_scale (cr, preview->priv->scale, preview->priv->scale);
625                 cairo_translate (cr, preview->priv->offset_x, preview->priv->offset_y);
626
627
628                 /* update shadow */
629                 shadow_x = SHADOW_X_OFFSET/preview->priv->scale;
630                 shadow_y = SHADOW_Y_OFFSET/preview->priv->scale;
631
632                 draw_shadow (preview, cr,
633                              shadow_x, shadow_y,
634                              template->page_width, template->page_height);
635
636                 draw_paper (preview, cr,
637                             template->page_width, template->page_height,
638                             1.0/preview->priv->scale);
639
640                 draw_labels (preview, cr, template, 1.0/preview->priv->scale);
641                              
642         }
643
644         gl_debug (DEBUG_MINI_PREVIEW, "END");
645
646 }
647
648
649 /*--------------------------------------------------------------------------*/
650 /* Draw page shadow                                                         */
651 /*--------------------------------------------------------------------------*/
652 static void
653 draw_shadow (glWdgtMiniPreview      *preview,
654              cairo_t                *cr,
655              gdouble                 x,
656              gdouble                 y,
657              gdouble                 width,
658              gdouble                 height)
659 {
660         GtkStyle *style;
661         guint     shadow_color;
662
663         gl_debug (DEBUG_MINI_PREVIEW, "START");
664
665         cairo_save (cr);
666
667         cairo_rectangle (cr, x, y, width, height);
668
669         style = gtk_widget_get_style (GTK_WIDGET(preview));
670         shadow_color = gl_color_from_gdk_color (&style->bg[GTK_STATE_ACTIVE]);
671         cairo_set_source_rgb (cr,
672                               GL_COLOR_F_RED   (shadow_color),
673                               GL_COLOR_F_GREEN (shadow_color),
674                               GL_COLOR_F_BLUE  (shadow_color));
675
676         cairo_fill (cr);
677
678         cairo_restore (cr);
679
680         gl_debug (DEBUG_MINI_PREVIEW, "END");
681 }
682
683 /*--------------------------------------------------------------------------*/
684 /* Draw page                                                                */
685 /*--------------------------------------------------------------------------*/
686 static void
687 draw_paper (glWdgtMiniPreview      *preview,
688             cairo_t                *cr,
689             gdouble                 width,
690             gdouble                 height,
691             gdouble                 line_width)
692 {
693         cairo_save (cr);
694
695         gl_debug (DEBUG_MINI_PREVIEW, "START");
696
697         cairo_rectangle (cr, 0.0, 0.0, width, height);
698
699         cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
700         cairo_fill_preserve (cr);
701
702         cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
703         cairo_set_line_width (cr, line_width);
704         cairo_stroke (cr);
705
706         cairo_restore (cr);
707
708         gl_debug (DEBUG_MINI_PREVIEW, "END");
709 }
710
711 /*--------------------------------------------------------------------------*/
712 /* Draw labels                                                              */
713 /*--------------------------------------------------------------------------*/
714 static void
715 draw_labels (glWdgtMiniPreview *preview,
716              cairo_t           *cr,
717              const glTemplate  *template,
718              gdouble            line_width)
719 {
720         const glTemplateLabelType *label_type;
721         gint                       i, n_labels;
722         glTemplateOrigin          *origins;
723         GtkStyle                  *style;
724         guint                      highlight_color;
725
726         gl_debug (DEBUG_MINI_PREVIEW, "START");
727
728         label_type = gl_template_get_first_label_type (template);
729
730         n_labels = gl_template_get_n_labels (label_type);
731         origins  = gl_template_get_origins (label_type);
732
733         style = gtk_widget_get_style (GTK_WIDGET(preview));
734         highlight_color = gl_color_from_gdk_color (&style->base[GTK_STATE_SELECTED]);
735
736         for ( i=0; i < n_labels; i++ ) {
737
738                 cairo_save (cr);
739
740                 create_label_path (cr, template, origins[i].x, origins[i].y);
741
742                 if ( ((i+1) >= preview->priv->highlight_first) &&
743                      ((i+1) <= preview->priv->highlight_last) )
744                 {
745                         cairo_set_source_rgb (cr,
746                                               GL_COLOR_F_RED   (highlight_color),
747                                               GL_COLOR_F_GREEN (highlight_color),
748                                               GL_COLOR_F_BLUE  (highlight_color));
749                 }
750                 else
751                 {
752                         cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
753                 }
754                 cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
755                 cairo_fill_preserve (cr);
756
757                 cairo_set_line_width (cr, line_width);
758                 cairo_set_source_rgb (cr, 0.5, 0.5, 0.5);
759                 cairo_stroke (cr);
760
761                 cairo_restore (cr);
762
763         }
764
765         g_free (origins);
766
767         gl_debug (DEBUG_MINI_PREVIEW, "END");
768 }
769
770 /*--------------------------------------------------------------------------*/
771 /* Create label path                                                        */
772 /*--------------------------------------------------------------------------*/
773 static void
774 create_label_path (cairo_t           *cr,
775                    const glTemplate  *template,
776                    gdouble            x0,
777                    gdouble            y0)
778 {
779         const glTemplateLabelType *label_type;
780
781         gl_debug (DEBUG_MINI_PREVIEW, "START");
782
783         label_type = gl_template_get_first_label_type (template);
784
785         switch (label_type->shape) {
786
787         case GL_TEMPLATE_SHAPE_RECT:
788                 create_rect_label_path (cr, template, x0, y0);
789                 break;
790
791         case GL_TEMPLATE_SHAPE_ROUND:
792                 create_round_label_path (cr, template, x0, y0);
793                 break;
794
795         case GL_TEMPLATE_SHAPE_CD:
796                 create_cd_label_path (cr, template, x0, y0);
797                 break;
798
799         default:
800                 g_message ("Unknown label style");
801                 break;
802         }
803
804         gl_debug (DEBUG_MINI_PREVIEW, "END");
805 }
806
807 /*--------------------------------------------------------------------------*/
808 /* Create rectangular label path                                            */
809 /*--------------------------------------------------------------------------*/
810 static void
811 create_rect_label_path (cairo_t           *cr,
812                         const glTemplate  *template,
813                         gdouble            x0,
814                         gdouble            y0)
815 {
816         const glTemplateLabelType *label_type;
817         gdouble                    w, h;
818
819         gl_debug (DEBUG_MINI_PREVIEW, "START");
820
821         label_type = gl_template_get_first_label_type (template);
822         gl_template_get_label_size (label_type, &w, &h);
823
824         cairo_rectangle (cr, x0, y0, w, h);
825
826         gl_debug (DEBUG_MINI_PREVIEW, "END");
827 }
828
829 /*--------------------------------------------------------------------------*/
830 /* Create round label path                                                  */
831 /*--------------------------------------------------------------------------*/
832 static void
833 create_round_label_path (cairo_t           *cr,
834                          const glTemplate  *template,
835                          gdouble            x0,
836                          gdouble            y0)
837 {
838         const glTemplateLabelType *label_type;
839         gdouble                    w, h;
840
841         gl_debug (DEBUG_MINI_PREVIEW, "START");
842
843         label_type = gl_template_get_first_label_type (template);
844         gl_template_get_label_size (label_type, &w, &h);
845
846         cairo_arc (cr, x0+w/2, y0+h/2, w/2, 0.0, 2*M_PI);
847         cairo_close_path (cr);
848
849         gl_debug (DEBUG_MINI_PREVIEW, "END");
850 }
851
852 /*--------------------------------------------------------------------------*/
853 /* Create cd label path                                                     */
854 /*--------------------------------------------------------------------------*/
855 static void
856 create_cd_label_path (cairo_t           *cr,
857                       const glTemplate  *template,
858                       gdouble            x0,
859                       gdouble            y0)
860 {
861         const glTemplateLabelType *label_type;
862         gdouble                    w, h;
863         gdouble                    xc, yc;
864         gdouble                    r1, r2;
865         gdouble                    theta1, theta2;
866
867         gl_debug (DEBUG_MINI_PREVIEW, "START");
868
869         label_type = gl_template_get_first_label_type (template);
870         gl_template_get_label_size (label_type, &w, &h);
871
872         xc = x0 + w/2.0;
873         yc = y0 + h/2.0;
874
875         r1 = label_type->size.cd.r1;
876         r2 = label_type->size.cd.r2;
877
878         /*
879          * Outer path (may be clipped)
880          */
881         theta1 = acos (w / (2.0*r1));
882         theta2 = asin (h / (2.0*r1));
883
884         cairo_new_path (cr);
885         cairo_arc (cr, xc, yc, r1, theta1, theta2);
886         cairo_arc (cr, xc, yc, r1, M_PI-theta2, M_PI-theta1);
887         cairo_arc (cr, xc, yc, r1, M_PI+theta1, M_PI+theta2);
888         cairo_arc (cr, xc, yc, r1, 2*M_PI-theta2, 2*M_PI-theta1);
889         cairo_close_path (cr);
890
891
892         /* Inner path (hole) */
893         cairo_new_sub_path (cr);
894         cairo_arc (cr, xc, yc, r2, 0.0, 2*M_PI);
895         cairo_close_path (cr);
896
897         gl_debug (DEBUG_MINI_PREVIEW, "END");
898 }
899