]> git.sur5r.net Git - glabels/blob - src/label-object.c
Cleanup of build system.
[glabels] / src / label-object.c
1 /*
2  *  label-object.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 "label-object.h"
24
25 #include <glib/gi18n.h>
26 #include <glib.h>
27 #include <math.h>
28
29 #include "marshal.h"
30
31 #include "debug.h"
32
33
34 /*========================================================*/
35 /* Private defines.                                       */
36 /*========================================================*/
37
38 #define DEFAULT_SHADOW_X_OFFSET (3.6)
39 #define DEFAULT_SHADOW_Y_OFFSET (3.6)
40 #define DEFAULT_SHADOW_COLOR    GL_COLOR_BLACK
41 #define DEFAULT_SHADOW_OPACITY  (0.5)
42
43 #define HANDLE_FILL_RGBA_ARGS      0.0,   0.75,  0.0,   0.4
44 #define HANDLE_OUTLINE_RGBA_ARGS   0.0,   0.0,   0.0,   0.8
45
46 #define HANDLE_OUTLINE_WIDTH_PIXELS   1.0
47 #define HANDLE_PIXELS 7
48
49
50 /*========================================================*/
51 /* Private types.                                         */
52 /*========================================================*/
53
54 struct _glLabelObjectPrivate {
55
56         gchar             *name;
57
58         gboolean           selected_flag;
59         glLabel           *parent;
60
61         gdouble            x, y;
62         gdouble            w, h;
63         cairo_matrix_t     matrix;
64
65         gdouble            aspect_ratio;
66
67         gboolean           shadow_state;
68         gdouble            shadow_x;
69         gdouble            shadow_y;
70         glColorNode       *shadow_color_node;
71         gdouble            shadow_opacity;
72 };
73
74 enum {
75         CHANGED,
76         LAST_SIGNAL
77 };
78
79
80 /*========================================================*/
81 /* Private globals.                                       */
82 /*========================================================*/
83
84 static guint instance = 0;
85
86 static guint signals[LAST_SIGNAL] = {0};
87
88
89 /*========================================================*/
90 /* Private function prototypes.                           */
91 /*========================================================*/
92
93 static void     gl_label_object_finalize  (GObject            *object);
94
95 static void     set_size                  (glLabelObject      *object,
96                                            gdouble             w,
97                                            gdouble             h,
98                                            gboolean            checkpoint);
99
100
101 /*****************************************************************************/
102 /* Boilerplate object stuff.                                                 */
103 /*****************************************************************************/
104 G_DEFINE_TYPE (glLabelObject, gl_label_object, G_TYPE_OBJECT);
105
106
107 static void
108 gl_label_object_class_init (glLabelObjectClass *class)
109 {
110         GObjectClass       *object_class = G_OBJECT_CLASS (class);
111
112         gl_debug (DEBUG_LABEL, "START");
113
114         gl_label_object_parent_class = g_type_class_peek_parent (class);
115
116         object_class->finalize = gl_label_object_finalize;
117
118         class->set_size     = set_size;
119         class->draw_handles = gl_label_object_draw_handles_box; /* Default style */
120         class->handle_at    = gl_label_object_box_handle_at;    /* Default style */
121
122         signals[CHANGED] =
123                 g_signal_new ("changed",
124                               G_OBJECT_CLASS_TYPE (object_class),
125                               G_SIGNAL_RUN_LAST,
126                               G_STRUCT_OFFSET (glLabelObjectClass, changed),
127                               NULL, NULL,
128                               gl_marshal_VOID__VOID,
129                               G_TYPE_NONE,
130                               0);
131
132         gl_debug (DEBUG_LABEL, "END");
133 }
134
135
136 static void
137 gl_label_object_init (glLabelObject *object)
138 {
139         gl_debug (DEBUG_LABEL, "START");
140
141         object->priv = g_new0 (glLabelObjectPrivate, 1);
142
143         object->priv->name = g_strdup_printf ("object%d", instance++);
144
145         cairo_matrix_init_identity (&object->priv->matrix);
146
147         object->priv->shadow_state = FALSE;
148         object->priv->shadow_x = DEFAULT_SHADOW_X_OFFSET;
149         object->priv->shadow_y = DEFAULT_SHADOW_Y_OFFSET;
150         object->priv->shadow_color_node = gl_color_node_new_default ();
151         object->priv->shadow_color_node->color = DEFAULT_SHADOW_COLOR;
152         object->priv->shadow_opacity = DEFAULT_SHADOW_OPACITY;
153
154         gl_debug (DEBUG_LABEL, "END");
155 }
156
157
158 static void
159 gl_label_object_finalize (GObject *object)
160 {
161         glLabelObject *label_object = GL_LABEL_OBJECT (object);
162
163         gl_debug (DEBUG_LABEL, "START");
164
165         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
166
167         g_free (label_object->priv->name);
168         g_free (label_object->priv);
169
170         G_OBJECT_CLASS (gl_label_object_parent_class)->finalize (object);
171
172         gl_debug (DEBUG_LABEL, "END");
173 }
174
175
176 /*****************************************************************************/
177 /* New label object.                                                         */
178 /*****************************************************************************/
179 GObject *
180 gl_label_object_new (glLabel *label)
181 {
182         glLabelObject *object;
183
184         gl_debug (DEBUG_LABEL, "START");
185
186         object = g_object_new (gl_label_object_get_type(), NULL);
187
188         gl_label_object_set_parent (object, label);
189
190         gl_debug (DEBUG_LABEL, "END");
191
192         return G_OBJECT (object);
193 }
194
195
196 /*****************************************************************************/
197 /* Duplicate object.                                                         */
198 /*****************************************************************************/
199 glLabelObject *
200 gl_label_object_dup (glLabelObject *src_object,
201                      glLabel       *label)
202 {
203         glLabelObject    *dst_object;
204         gdouble           x, y, w, h;
205         cairo_matrix_t    matrix;
206         gboolean          shadow_state;
207         gdouble           shadow_x, shadow_y;
208         glColorNode      *shadow_color_node;
209         gdouble           shadow_opacity;
210
211         gl_debug (DEBUG_LABEL, "START");
212
213         g_return_val_if_fail (src_object && GL_IS_LABEL_OBJECT (src_object), NULL);
214
215         dst_object = g_object_new (G_OBJECT_TYPE(src_object), NULL);
216
217         gl_label_object_set_parent (dst_object, label);
218         dst_object->priv->selected_flag = src_object->priv->selected_flag;
219
220         gl_label_object_get_position      (src_object, &x, &y);
221         gl_label_object_get_raw_size      (src_object, &w, &h);
222         gl_label_object_get_matrix        (src_object, &matrix);
223         gl_label_object_get_shadow_offset (src_object, &shadow_x, &shadow_y);
224         shadow_color_node = gl_label_object_get_shadow_color   (src_object);
225         shadow_opacity    = gl_label_object_get_shadow_opacity (src_object);
226         shadow_state      = gl_label_object_get_shadow_state   (src_object);
227
228         gl_label_object_set_position (dst_object, x, y, FALSE);
229         gl_label_object_set_size     (dst_object, w, h, FALSE);
230         gl_label_object_set_matrix   (dst_object, &matrix);
231         gl_label_object_set_shadow_offset  (dst_object, shadow_x, shadow_y, FALSE);
232         gl_label_object_set_shadow_color   (dst_object, shadow_color_node, FALSE);
233         gl_label_object_set_shadow_opacity (dst_object, shadow_opacity, FALSE);
234         gl_label_object_set_shadow_state   (dst_object, shadow_state, FALSE);
235
236         gl_color_node_free (&shadow_color_node);
237
238         if ( GL_LABEL_OBJECT_GET_CLASS(src_object)->copy != NULL )
239         {
240                 /* We have an object specific method, use it */
241                 GL_LABEL_OBJECT_GET_CLASS(src_object)->copy (dst_object, src_object);
242         }
243
244         gl_debug (DEBUG_LABEL, "END");
245
246         return dst_object;
247 }
248
249
250 /*****************************************************************************/
251 /* Emit "changed" signal (for derived objects).                              */
252 /*****************************************************************************/
253 void
254 gl_label_object_emit_changed (glLabelObject *object)
255 {
256         gl_debug (DEBUG_LABEL, "START");
257
258         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
259
260         g_signal_emit (G_OBJECT(object), signals[CHANGED], 0);
261
262         gl_debug (DEBUG_LABEL, "END");
263 }
264
265
266 /*****************************************************************************/
267 /* Set parent label of object.                                               */
268 /*****************************************************************************/
269 void
270 gl_label_object_set_parent (glLabelObject *object,
271                             glLabel       *label)
272 {
273         gl_debug (DEBUG_LABEL, "START");
274
275         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
276         g_return_if_fail (label && GL_IS_LABEL (label));
277
278         object->priv->parent = label;
279 }
280
281
282 /*****************************************************************************/
283 /* Get parent label of object.                                               */
284 /*****************************************************************************/
285 glLabel *
286 gl_label_object_get_parent (glLabelObject *object)
287 {
288         gl_debug (DEBUG_LABEL, "START");
289
290         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), NULL);
291
292         gl_debug (DEBUG_LABEL, "END");
293
294         return object->priv->parent;
295 }
296
297
298 /*****************************************************************************/
299 /* Select object.                                                            */
300 /*****************************************************************************/
301 void
302 gl_label_object_select (glLabelObject     *object)
303 {
304         object->priv->selected_flag = TRUE;
305 }
306
307
308 /*****************************************************************************/
309 /* Unselect object.                                                          */
310 /*****************************************************************************/
311 void
312 gl_label_object_unselect (glLabelObject     *object)
313 {
314         object->priv->selected_flag = FALSE;
315 }
316
317
318 /*****************************************************************************/
319 /* Is object selected?                                                       */
320 /*****************************************************************************/
321 gboolean
322 gl_label_object_is_selected (glLabelObject     *object)
323 {
324         return object->priv->selected_flag;
325 }
326
327
328 /*****************************************************************************/
329 /* Set name of object.                                                       */
330 /*****************************************************************************/
331 void    
332 gl_label_object_set_name (glLabelObject *object,
333                           gchar         *name)
334 {
335         gl_debug (DEBUG_LABEL, "START");
336
337         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
338
339         g_free(object->priv->name);
340         object->priv->name = name;
341
342         gl_label_object_emit_changed (object);
343
344         gl_debug (DEBUG_LABEL, "END");
345 }
346
347
348 /*****************************************************************************/
349 /* Get name of object.                                                       */
350 /*****************************************************************************/
351 gchar *
352 gl_label_object_get_name (glLabelObject *object)
353 {
354         gl_debug (DEBUG_LABEL, "START");
355
356         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), NULL);
357
358         gl_debug (DEBUG_LABEL, "END");
359
360         return g_strdup(object->priv->name);
361 }
362
363
364 /*****************************************************************************/
365 /* Set position of object.                                                   */
366 /*****************************************************************************/
367 void    
368 gl_label_object_set_position (glLabelObject *object,
369                               gdouble        x,
370                               gdouble        y,
371                               gboolean       checkpoint)
372 {
373         gdouble  dx, dy;
374
375         gl_debug (DEBUG_LABEL, "START");
376
377         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
378
379         if ( (x != object->priv->x) || (y != object->priv->y) )
380         {
381                 if ( checkpoint )
382                 {
383                         gl_label_checkpoint (object->priv->parent, _("Move"));
384                 }
385
386                 dx = x - object->priv->x;
387                 dy = y - object->priv->y;
388
389                 object->priv->x = x;
390                 object->priv->y = y;
391         }
392
393         gl_label_object_emit_changed (object);
394
395         gl_debug (DEBUG_LABEL, "END");
396 }
397
398
399 /*****************************************************************************/
400 /* Set position of object relative to old position.                          */
401 /*****************************************************************************/
402 void    
403 gl_label_object_set_position_relative (glLabelObject *object,
404                                        gdouble        dx,
405                                        gdouble        dy,
406                                        gboolean       checkpoint)
407 {
408         gl_debug (DEBUG_LABEL, "START");
409
410         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
411
412         if ( (dx != 0.0) || (dy != 0.0) )
413         {
414                 if ( checkpoint )
415                 {
416                         gl_label_checkpoint (object->priv->parent, _("Move"));
417                 }
418
419                 object->priv->x += dx;
420                 object->priv->y += dy;
421
422                 gl_debug (DEBUG_LABEL, "       x = %f, y= %f",
423                           object->priv->x,
424                           object->priv->y);
425         }
426
427         gl_label_object_emit_changed (object);
428
429         gl_debug (DEBUG_LABEL, "END");
430 }
431
432
433 /*****************************************************************************/
434 /* Get position of object.                                                   */
435 /*****************************************************************************/
436 void
437 gl_label_object_get_position (glLabelObject *object,
438                               gdouble       *x,
439                               gdouble       *y)
440 {
441         gl_debug (DEBUG_LABEL, "START");
442
443         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
444
445         *x = object->priv->x;
446         *y = object->priv->y;
447
448         gl_debug (DEBUG_LABEL, "END");
449 }
450
451
452 /*---------------------------------------------------------------------------*/
453 /* PRIVATE.  Default set size method.                                        */
454 /*---------------------------------------------------------------------------*/
455 static void
456 set_size (glLabelObject *object,
457           gdouble        w,
458           gdouble        h,
459           gboolean       checkpoint)
460 {
461         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
462
463         if ( (object->priv->w != w) || (object->priv->h != h) )
464         {
465                 if ( checkpoint )
466                 {
467                         gl_label_checkpoint (object->priv->parent, _("Resize"));
468                 }
469
470                 object->priv->w = w;
471                 object->priv->h = h;
472
473                 gl_label_object_emit_changed (object);
474         }
475 }
476
477
478 /*****************************************************************************/
479 /* Set size of object.                                                       */
480 /*****************************************************************************/
481 void    
482 gl_label_object_set_size (glLabelObject *object,
483                           gdouble        w,
484                           gdouble        h,
485                           gboolean       checkpoint)
486 {
487         gl_debug (DEBUG_LABEL, "START");
488
489         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
490
491         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_size != NULL )
492         {
493                 /* We have an object specific method, use it */
494                 GL_LABEL_OBJECT_GET_CLASS(object)->set_size (object, w, h, checkpoint);
495
496                 object->priv->aspect_ratio = h / w;
497         }
498
499         gl_debug (DEBUG_LABEL, "END");
500 }
501
502
503 /*****************************************************************************/
504 /* Set size of object honoring current aspect ratio.                         */
505 /*****************************************************************************/
506 void    
507 gl_label_object_set_size_honor_aspect (glLabelObject *object,
508                                        gdouble        w,
509                                        gdouble        h,
510                                        gboolean       checkpoint)
511 {
512         gl_debug (DEBUG_LABEL, "START");
513
514         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
515
516         if ( h > w*object->priv->aspect_ratio )
517         {
518                 h = w * object->priv->aspect_ratio;
519         }
520         else
521         {
522                 w = h / object->priv->aspect_ratio;
523         }
524
525         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_size != NULL )
526         {
527                 /* We have an object specific method, use it */
528                 GL_LABEL_OBJECT_GET_CLASS(object)->set_size (object, w, h, checkpoint);
529         }
530
531         gl_debug (DEBUG_LABEL, "END");
532 }
533
534
535 /*****************************************************************************/
536 /* Get raw size method (don't let object content adjust size).               */
537 /*****************************************************************************/
538 void
539 gl_label_object_get_raw_size (glLabelObject *object,
540                               gdouble       *w,
541                               gdouble       *h)
542 {
543         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
544
545         *w = object->priv->w;
546         *h = object->priv->h;
547 }
548
549
550 /*****************************************************************************/
551 /* Get size of object.                                                       */
552 /*****************************************************************************/
553 void
554 gl_label_object_get_size (glLabelObject *object,
555                           gdouble       *w,
556                           gdouble       *h)
557 {
558         gl_debug (DEBUG_LABEL, "START");
559
560         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
561
562         if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_size != NULL )
563         {
564                 /* We have an object specific method, use it */
565                 GL_LABEL_OBJECT_GET_CLASS(object)->get_size (object, w, h);
566         }
567         else
568         {
569                 gl_label_object_get_raw_size (object, w, h);
570         }
571
572         gl_debug (DEBUG_LABEL, "END");
573 }
574
575
576 /*****************************************************************************/
577 /* Get extent of object.                                                     */
578 /*****************************************************************************/
579 void
580 gl_label_object_get_extent (glLabelObject *object,
581                             glLabelRegion *region)
582 {
583         gdouble        w, h;
584         gdouble        line_w;
585         gdouble        xa1, ya1, xa2, ya2, xa3, ya3, xa4, ya4;
586         cairo_matrix_t matrix;
587
588         gl_debug (DEBUG_LABEL, "START");
589
590         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
591
592         gl_label_object_get_size (object, &w, &h);
593         line_w = gl_label_object_get_line_width (object);
594
595         /* setup untransformed corners of bounding box, account for line width */
596         xa1 =   - line_w/2;
597         ya1 =   - line_w/2;
598         xa2 = w + line_w/2;
599         ya2 =   - line_w/2;
600         xa3 = w + line_w/2;
601         ya3 = h + line_w/2;
602         xa4 =   - line_w/2;
603         ya4 = h + line_w/2;
604
605         /* transform these points */
606         gl_label_object_get_matrix (object, &matrix);
607         cairo_matrix_transform_point (&matrix, &xa1, &ya1);
608         cairo_matrix_transform_point (&matrix, &xa2, &ya2);
609         cairo_matrix_transform_point (&matrix, &xa3, &ya3);
610         cairo_matrix_transform_point (&matrix, &xa4, &ya4);
611
612         /* now find the maximum extent of these points in x and y */
613         region->x1 = MIN (xa1, MIN (xa2, MIN (xa3, xa4))) + object->priv->x;
614         region->y1 = MIN (ya1, MIN (ya2, MIN (ya3, ya4))) + object->priv->y;
615         region->x2 = MAX (xa1, MAX (xa2, MAX (xa3, xa4))) + object->priv->x;
616         region->y2 = MAX (ya1, MAX (ya2, MAX (ya3, ya4))) + object->priv->y;
617
618         gl_debug (DEBUG_LABEL, "END");
619 }
620
621
622 /*****************************************************************************/
623 /* Can text properties be set for this object?                               */
624 /*****************************************************************************/
625 gboolean
626 gl_label_object_can_text (glLabelObject     *object)
627 {
628         gl_debug (DEBUG_LABEL, "");
629
630         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
631
632         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_font_family != NULL )
633         {
634                 return TRUE;
635         }
636         else
637         {
638                 return FALSE;
639         }
640 }
641
642
643 /*****************************************************************************/
644 /* Set font family for all text contained in object.                         */
645 /*****************************************************************************/
646 void    
647 gl_label_object_set_font_family (glLabelObject     *object,
648                                  const gchar       *font_family,
649                                  gboolean           checkpoint)
650 {
651         gl_debug (DEBUG_LABEL, "START");
652
653         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
654
655         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_font_family != NULL )
656         {
657                 /* We have an object specific method, use it */
658                 GL_LABEL_OBJECT_GET_CLASS(object)->set_font_family (object, font_family, checkpoint);
659         }
660
661         gl_debug (DEBUG_LABEL, "END");
662 }
663
664
665 /****************************************************************************/
666 /* Set font size for all text contained in object.                          */
667 /****************************************************************************/
668 void    
669 gl_label_object_set_font_size (glLabelObject     *object,
670                                gdouble            font_size,
671                                gboolean           checkpoint)
672 {
673         gl_debug (DEBUG_LABEL, "START");
674
675         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
676
677         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_font_size != NULL )
678         {
679                 /* We have an object specific method, use it */
680                 GL_LABEL_OBJECT_GET_CLASS(object)->set_font_size (object, font_size, checkpoint);
681         }
682
683         gl_debug (DEBUG_LABEL, "END");
684 }
685
686
687 /****************************************************************************/
688 /* Set font weight for all text contained in object.                        */
689 /****************************************************************************/
690 void    
691 gl_label_object_set_font_weight (glLabelObject     *object,
692                                  PangoWeight        font_weight,
693                                  gboolean           checkpoint)
694 {
695         gl_debug (DEBUG_LABEL, "START");
696
697         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
698
699         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_font_weight != NULL )
700         {
701                 /* We have an object specific method, use it */
702                 GL_LABEL_OBJECT_GET_CLASS(object)->set_font_weight (object, font_weight, checkpoint);
703         }
704
705         gl_debug (DEBUG_LABEL, "END");
706 }
707
708
709 /****************************************************************************/
710 /* Set font italic flag for all text contained in object.                   */
711 /****************************************************************************/
712 void    
713 gl_label_object_set_font_italic_flag (glLabelObject     *object,
714                                       gboolean           font_italic_flag,
715                                       gboolean           checkpoint)
716 {
717         gl_debug (DEBUG_LABEL, "START");
718
719         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
720
721         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_font_italic_flag != NULL )
722         {
723                 /* We have an object specific method, use it */
724                 GL_LABEL_OBJECT_GET_CLASS(object)->set_font_italic_flag (object, font_italic_flag, checkpoint);
725         }
726
727         gl_debug (DEBUG_LABEL, "END");
728 }
729
730
731 /****************************************************************************/
732 /* Set text alignment for all text contained in object.                     */
733 /****************************************************************************/
734 void    
735 gl_label_object_set_text_alignment (glLabelObject     *object,
736                                     PangoAlignment     text_alignment,
737                                     gboolean           checkpoint)
738 {
739         gl_debug (DEBUG_LABEL, "START");
740
741         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
742
743         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_text_alignment != NULL )
744         {
745                 /* We have an object specific method, use it */
746                 GL_LABEL_OBJECT_GET_CLASS(object)->set_text_alignment (object, text_alignment, checkpoint);
747         }
748
749         gl_debug (DEBUG_LABEL, "END");
750 }
751
752
753 /****************************************************************************/
754 /* Set text line spacing for all text contained in object.                  */
755 /****************************************************************************/
756 void    
757 gl_label_object_set_text_line_spacing (glLabelObject     *object,
758                                        gdouble            text_line_spacing,
759                                        gboolean           checkpoint)
760 {
761         gl_debug (DEBUG_LABEL, "START");
762
763         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
764
765         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_text_line_spacing != NULL )
766         {
767                 /* We have an object specific method, use it */
768                 GL_LABEL_OBJECT_GET_CLASS(object)->set_text_line_spacing (object, text_line_spacing, checkpoint);
769         }
770
771         gl_debug (DEBUG_LABEL, "END");
772 }
773
774
775 /****************************************************************************/
776 /* Set text color for all text contained in object.                         */
777 /****************************************************************************/
778 void    
779 gl_label_object_set_text_color (glLabelObject     *object,
780                                 glColorNode       *text_color_node,
781                                 gboolean           checkpoint)
782 {
783         gl_debug (DEBUG_LABEL, "START");
784
785         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
786
787         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_text_color != NULL )
788         {
789                 /* We have an object specific method, use it */
790                 GL_LABEL_OBJECT_GET_CLASS(object)->set_text_color (object, text_color_node, checkpoint);
791         }
792
793         gl_debug (DEBUG_LABEL, "END");
794 }
795
796
797 /*****************************************************************************/
798 /* Get font family for all text contained in object.                         */
799 /*****************************************************************************/
800 gchar *
801 gl_label_object_get_font_family (glLabelObject     *object)
802 {
803         gchar *ret = NULL;
804
805         gl_debug (DEBUG_LABEL, "START");
806
807         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), NULL);
808
809         if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_font_family != NULL )
810         {
811                 /* We have an object specific method, use it */
812                 ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_font_family (object);
813         }
814
815         gl_debug (DEBUG_LABEL, "END");
816
817         return ret;
818 }
819
820
821 /****************************************************************************/
822 /* Get font size for all text contained in object.                          */
823 /****************************************************************************/
824 gdouble
825 gl_label_object_get_font_size (glLabelObject     *object)
826 {
827         gdouble ret = 0.0;
828
829         gl_debug (DEBUG_LABEL, "START");
830
831         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), 0.0);
832
833         if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_font_size != NULL )
834         {
835                 /* We have an object specific method, use it */
836                 ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_font_size (object);
837         }
838
839         gl_debug (DEBUG_LABEL, "END");
840
841         return ret;
842 }
843
844
845 /****************************************************************************/
846 /* Get font weight for all text contained in object.                        */
847 /****************************************************************************/
848 PangoWeight    
849 gl_label_object_get_font_weight (glLabelObject     *object)
850 {
851         PangoWeight     ret = PANGO_WEIGHT_NORMAL;
852
853         gl_debug (DEBUG_LABEL, "START");
854
855         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), PANGO_WEIGHT_NORMAL);
856
857         if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_font_weight != NULL )
858         {
859                 /* We have an object specific method, use it */
860                 ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_font_weight (object);
861         }
862
863         gl_debug (DEBUG_LABEL, "END");
864
865         return ret;
866 }
867
868
869 /****************************************************************************/
870 /* Get font italic flag for all text contained in object.                   */
871 /****************************************************************************/
872 gboolean
873 gl_label_object_get_font_italic_flag (glLabelObject     *object)
874 {
875         gboolean ret = FALSE;
876
877         gl_debug (DEBUG_LABEL, "START");
878
879         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
880
881         if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_font_italic_flag != NULL )
882         {
883                 /* We have an object specific method, use it */
884                 ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_font_italic_flag (object);
885         }
886
887         gl_debug (DEBUG_LABEL, "END");
888
889         return ret;
890 }
891
892
893 /****************************************************************************/
894 /* Get text alignment for all text contained in object.                     */
895 /****************************************************************************/
896 PangoAlignment
897 gl_label_object_get_text_alignment (glLabelObject     *object)
898 {
899         PangoAlignment ret = PANGO_ALIGN_LEFT;
900
901         gl_debug (DEBUG_LABEL, "START");
902
903         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), PANGO_ALIGN_LEFT);
904
905         if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_text_alignment != NULL )
906         {
907                 /* We have an object specific method, use it */
908                 ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_text_alignment (object);
909         }
910
911         gl_debug (DEBUG_LABEL, "END");
912
913         return ret;
914 }
915
916
917 /****************************************************************************/
918 /* Get text line spacing for all text contained in object.                  */
919 /****************************************************************************/
920 gdouble
921 gl_label_object_get_text_line_spacing (glLabelObject     *object)
922 {
923         gdouble ret = 0.0;
924
925         gl_debug (DEBUG_LABEL, "START");
926
927         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), 0.0);
928
929         if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_text_line_spacing != NULL )
930         {
931                 /* We have an object specific method, use it */
932                 ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_text_line_spacing (object);
933         }
934
935         gl_debug (DEBUG_LABEL, "END");
936
937         return ret;
938 }
939
940
941 /****************************************************************************/
942 /* Get text color for all text contained in object.                         */
943 /****************************************************************************/
944 glColorNode*
945 gl_label_object_get_text_color (glLabelObject     *object)
946 {
947         glColorNode *ret = NULL;
948
949         gl_debug (DEBUG_LABEL, "START");
950
951         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), 0);
952
953         if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_text_color != NULL )
954         {
955                 /* We have an object specific method, use it */
956                 ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_text_color (object);
957         }
958
959         gl_debug (DEBUG_LABEL, "END");
960
961         return ret;
962 }
963
964
965 /*****************************************************************************/
966 /* Can fill properties be set for this object?                               */
967 /*****************************************************************************/
968 gboolean
969 gl_label_object_can_fill (glLabelObject     *object)
970 {
971         gl_debug (DEBUG_LABEL, "");
972
973         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
974
975         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_fill_color != NULL )
976         {
977                 return TRUE;
978         }
979         else
980         {
981                 return FALSE;
982         }
983
984 }
985
986
987 /****************************************************************************/
988 /* Set fill color for object.                                               */
989 /****************************************************************************/
990 void    
991 gl_label_object_set_fill_color (glLabelObject     *object,
992                                 glColorNode       *fill_color_node,
993                                 gboolean           checkpoint)
994 {
995         gl_debug (DEBUG_LABEL, "START");
996
997         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
998
999         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_fill_color != NULL )
1000         {
1001                 /* We have an object specific method, use it */
1002                 GL_LABEL_OBJECT_GET_CLASS(object)->set_fill_color (object, fill_color_node, checkpoint);
1003         }
1004
1005         gl_debug (DEBUG_LABEL, "END");
1006 }
1007
1008
1009 /****************************************************************************/
1010 /* Get fill color for object.                                               */
1011 /****************************************************************************/
1012 glColorNode*
1013 gl_label_object_get_fill_color (glLabelObject     *object)
1014 {
1015         glColorNode *ret = NULL;
1016
1017         gl_debug (DEBUG_LABEL, "START");
1018
1019         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), 0);
1020
1021         if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_fill_color != NULL )
1022         {
1023                 /* We have an object specific method, use it */
1024                 ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_fill_color (object);
1025         }
1026
1027         gl_debug (DEBUG_LABEL, "END");
1028
1029         return ret;
1030 }
1031
1032
1033 /*****************************************************************************/
1034 /* Can line color property be set for this object?                           */
1035 /*****************************************************************************/
1036 gboolean
1037 gl_label_object_can_line_color (glLabelObject     *object)
1038 {
1039         gl_debug (DEBUG_LABEL, "");
1040
1041         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
1042
1043         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_line_color != NULL )
1044         {
1045                 return TRUE;
1046         }
1047         else
1048         {
1049                 return FALSE;
1050         }
1051
1052 }
1053
1054
1055 /****************************************************************************/
1056 /* Set line color for object.                                               */
1057 /****************************************************************************/
1058 void    
1059 gl_label_object_set_line_color (glLabelObject     *object,
1060                                 glColorNode       *line_color_node,
1061                                 gboolean           checkpoint)
1062 {
1063         gl_debug (DEBUG_LABEL, "START");
1064
1065         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
1066
1067         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_line_color != NULL )
1068         {
1069                 /* We have an object specific method, use it */
1070                 GL_LABEL_OBJECT_GET_CLASS(object)->set_line_color (object, line_color_node, checkpoint);
1071         }
1072
1073         gl_debug (DEBUG_LABEL, "END");
1074 }
1075
1076
1077 /****************************************************************************/
1078 /* Get line color for object.                                               */
1079 /****************************************************************************/
1080 glColorNode*
1081 gl_label_object_get_line_color (glLabelObject     *object)
1082 {
1083         glColorNode *ret = NULL;
1084
1085         gl_debug (DEBUG_LABEL, "START");
1086
1087         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), 0);
1088
1089         if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_line_color != NULL )
1090         {
1091                 /* We have an object specific method, use it */
1092                 ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_line_color (object);
1093         }
1094
1095         gl_debug (DEBUG_LABEL, "END");
1096
1097         return ret;
1098 }
1099
1100
1101 /*****************************************************************************/
1102 /* Can line width property be set for this object?                           */
1103 /*****************************************************************************/
1104 gboolean
1105 gl_label_object_can_line_width (glLabelObject     *object)
1106 {
1107         gl_debug (DEBUG_LABEL, "");
1108
1109         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
1110
1111         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_line_width != NULL )
1112         {
1113                 return TRUE;
1114         }
1115         else
1116         {
1117                 return FALSE;
1118         }
1119
1120 }
1121
1122
1123 /****************************************************************************/
1124 /* Set line width for object.                                               */
1125 /****************************************************************************/
1126 void    
1127 gl_label_object_set_line_width (glLabelObject     *object,
1128                                 gdouble            line_width,
1129                                 gboolean           checkpoint)
1130 {
1131         gl_debug (DEBUG_LABEL, "START");
1132
1133         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
1134
1135         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_line_width != NULL )
1136         {
1137                 /* We have an object specific method, use it */
1138                 GL_LABEL_OBJECT_GET_CLASS(object)->set_line_width (object, line_width, checkpoint);
1139         }
1140
1141         gl_debug (DEBUG_LABEL, "END");
1142 }
1143
1144
1145 /****************************************************************************/
1146 /* Get line width for object.                                               */
1147 /****************************************************************************/
1148 gdouble
1149 gl_label_object_get_line_width (glLabelObject     *object)
1150 {
1151         gdouble ret = 0.0;
1152
1153         gl_debug (DEBUG_LABEL, "START");
1154
1155         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), 0.0);
1156
1157         if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_line_width != NULL )
1158         {
1159                 /* We have an object specific method, use it */
1160                 ret = GL_LABEL_OBJECT_GET_CLASS(object)->get_line_width (object);
1161         }
1162
1163         gl_debug (DEBUG_LABEL, "END");
1164
1165         return ret;
1166 }
1167
1168
1169 /****************************************************************************/
1170 /* Set shadow state of object.                                              */
1171 /****************************************************************************/
1172 void    
1173 gl_label_object_set_shadow_state (glLabelObject     *object,
1174                                   gboolean           state,
1175                                   gboolean           checkpoint)
1176 {
1177         gl_debug (DEBUG_LABEL, "START");
1178
1179         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
1180
1181         if (object->priv->shadow_state != state)
1182         {
1183                 if ( checkpoint )
1184                 {
1185                         gl_label_checkpoint (object->priv->parent, _("Shadow state"));
1186                 }
1187
1188                 object->priv->shadow_state = state;
1189
1190                 gl_label_object_emit_changed (object);
1191         }
1192
1193         gl_debug (DEBUG_LABEL, "END");
1194 }
1195
1196
1197 /****************************************************************************/
1198 /* Get shadow state of object.                                              */
1199 /****************************************************************************/
1200 gboolean
1201 gl_label_object_get_shadow_state (glLabelObject     *object)
1202 {
1203         gl_debug (DEBUG_LABEL, "");
1204
1205         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
1206
1207         return object->priv->shadow_state;
1208 }
1209
1210
1211 /****************************************************************************/
1212 /* Set offset of object's shadow.                                           */
1213 /****************************************************************************/
1214 void    
1215 gl_label_object_set_shadow_offset (glLabelObject     *object,
1216                                    gdouble            x,
1217                                    gdouble            y,
1218                                    gboolean           checkpoint)
1219 {
1220         gl_debug (DEBUG_LABEL, "START");
1221
1222         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
1223
1224         if ( (x != object->priv->shadow_x) || (y != object->priv->shadow_y) )
1225         {
1226                 if ( checkpoint )
1227                 {
1228                         gl_label_checkpoint (object->priv->parent, _("Shadow offset"));
1229                 }
1230
1231                 object->priv->shadow_x = x;
1232                 object->priv->shadow_y = y;
1233
1234                 gl_label_object_emit_changed (object);
1235         }
1236
1237         gl_debug (DEBUG_LABEL, "END");
1238 }
1239
1240
1241 /****************************************************************************/
1242 /* Get offset of object's shadow.                                           */
1243 /****************************************************************************/
1244 void
1245 gl_label_object_get_shadow_offset (glLabelObject     *object,
1246                                    gdouble           *x,
1247                                    gdouble           *y)
1248 {
1249         gl_debug (DEBUG_LABEL, "START");
1250
1251         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
1252
1253         *x = object->priv->shadow_x;
1254         *y = object->priv->shadow_y;
1255
1256         gl_debug (DEBUG_LABEL, "END");
1257 }
1258
1259
1260 /****************************************************************************/
1261 /* Set color of object's shadow.                                            */
1262 /****************************************************************************/
1263 void    
1264 gl_label_object_set_shadow_color (glLabelObject     *object,
1265                                   glColorNode       *color_node,
1266                                   gboolean           checkpoint)
1267 {
1268         gl_debug (DEBUG_LABEL, "START");
1269
1270         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
1271
1272         if ( !gl_color_node_equal (object->priv->shadow_color_node, color_node ))
1273         {
1274                 if ( checkpoint )
1275                 {
1276                         gl_label_checkpoint (object->priv->parent, _("Shadow color"));
1277                 }
1278
1279                 gl_color_node_free (&(object->priv->shadow_color_node));
1280                 object->priv->shadow_color_node = gl_color_node_dup (color_node);
1281
1282                 gl_label_object_emit_changed (object);
1283         }
1284
1285         gl_debug (DEBUG_LABEL, "END");
1286 }
1287
1288
1289 /****************************************************************************/
1290 /* Get color of object's shadow.                                            */
1291 /****************************************************************************/
1292 glColorNode*
1293 gl_label_object_get_shadow_color (glLabelObject     *object)
1294 {
1295         gl_debug (DEBUG_LABEL, "");
1296
1297         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), NULL);
1298
1299         return gl_color_node_dup (object->priv->shadow_color_node);
1300 }
1301
1302
1303 /****************************************************************************/
1304 /* Set opacity of object's shadow.                                          */
1305 /****************************************************************************/
1306 void    
1307 gl_label_object_set_shadow_opacity (glLabelObject     *object,
1308                                     gdouble            alpha,
1309                                     gboolean           checkpoint)
1310 {
1311         gl_debug (DEBUG_LABEL, "START");
1312
1313         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
1314
1315         if (object->priv->shadow_opacity != alpha)
1316         {
1317                 if ( checkpoint )
1318                 {
1319                         gl_label_checkpoint (object->priv->parent, _("Shadow opacity"));
1320                 }
1321
1322                 object->priv->shadow_opacity = alpha;
1323
1324                 gl_label_object_emit_changed (object);
1325         }
1326
1327         gl_debug (DEBUG_LABEL, "END");
1328 }
1329
1330
1331 /****************************************************************************/
1332 /* Get opacity of object's shadow.                                          */
1333 /****************************************************************************/
1334 gdouble
1335 gl_label_object_get_shadow_opacity (glLabelObject     *object)
1336 {
1337         gl_debug (DEBUG_LABEL, "");
1338
1339         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
1340
1341         return object->priv->shadow_opacity;
1342 }
1343
1344
1345 /****************************************************************************/
1346 /* Flip object horizontally.                                                */
1347 /****************************************************************************/
1348 void
1349 gl_label_object_flip_horiz (glLabelObject *object)
1350 {
1351         cairo_matrix_t flip_matrix;
1352
1353         gl_debug (DEBUG_LABEL, "START");
1354
1355         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
1356
1357         cairo_matrix_init_scale (&flip_matrix, -1.0, 1.0);
1358         cairo_matrix_multiply (&object->priv->matrix, &object->priv->matrix, &flip_matrix);
1359
1360         gl_debug (DEBUG_LABEL, "END");
1361 }
1362
1363
1364 /****************************************************************************/
1365 /* Flip object vertically.                                                  */
1366 /****************************************************************************/
1367 void
1368 gl_label_object_flip_vert (glLabelObject *object)
1369 {
1370         cairo_matrix_t flip_matrix;
1371
1372         gl_debug (DEBUG_LABEL, "START");
1373
1374         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
1375
1376         cairo_matrix_init_scale (&flip_matrix, 1.0, -1.0);
1377         cairo_matrix_multiply (&object->priv->matrix, &object->priv->matrix, &flip_matrix);
1378
1379         gl_debug (DEBUG_LABEL, "END");
1380 }
1381
1382
1383 /****************************************************************************/
1384 /* Rotate object.                                                           */
1385 /****************************************************************************/
1386 void
1387 gl_label_object_rotate (glLabelObject *object,
1388                         gdouble        theta_degs)
1389 {
1390         cairo_matrix_t rotate_matrix;
1391
1392         gl_debug (DEBUG_LABEL, "START");
1393
1394         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
1395
1396         cairo_matrix_init_rotate (&rotate_matrix, theta_degs*(G_PI/180.));
1397         cairo_matrix_multiply (&object->priv->matrix, &object->priv->matrix, &rotate_matrix);
1398
1399         gl_debug (DEBUG_LABEL, "END");
1400 }
1401
1402
1403 /****************************************************************************/
1404 /* Set raw affine                                                           */
1405 /****************************************************************************/
1406 void
1407 gl_label_object_set_matrix (glLabelObject  *object,
1408                             cairo_matrix_t *matrix)
1409 {
1410         gl_debug (DEBUG_LABEL, "");
1411
1412         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
1413
1414         object->priv->matrix = *matrix;
1415 }
1416
1417
1418 /****************************************************************************/
1419 /* Get raw affine                                                           */
1420 /****************************************************************************/
1421 void
1422 gl_label_object_get_matrix (glLabelObject  *object,
1423                             cairo_matrix_t *matrix)
1424 {
1425         gl_debug (DEBUG_LABEL, "");
1426
1427         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
1428
1429         *matrix = object->priv->matrix;
1430 }
1431
1432
1433 /*****************************************************************************/
1434 /* Draw object                                                               */
1435 /*****************************************************************************/
1436 void
1437 gl_label_object_draw (glLabelObject *object,
1438                       cairo_t       *cr,
1439                       gboolean       screen_flag,
1440                       glMergeRecord *record)
1441
1442 {
1443         gdouble        x0, y0;
1444         cairo_matrix_t matrix;
1445         gboolean       shadow_state;
1446         gdouble        shadow_x, shadow_y;
1447
1448         gl_debug (DEBUG_LABEL, "START");
1449
1450         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
1451
1452         gl_label_object_get_position (object, &x0, &y0);
1453         gl_label_object_get_matrix (object, &matrix);
1454
1455         cairo_save (cr);
1456         cairo_translate (cr, x0, y0);
1457
1458         if ( GL_LABEL_OBJECT_GET_CLASS(object)->draw_shadow != NULL )
1459         {
1460                 shadow_state = gl_label_object_get_shadow_state (object);
1461
1462                 if ( shadow_state )
1463                 {
1464                         gl_label_object_get_shadow_offset (object, &shadow_x, &shadow_y);
1465
1466                         cairo_save (cr);
1467                         cairo_translate (cr, shadow_x, shadow_y);
1468                         cairo_transform (cr, &matrix);
1469
1470                         GL_LABEL_OBJECT_GET_CLASS(object)->draw_shadow (object,
1471                                                                         cr,
1472                                                                         screen_flag,
1473                                                                         record);
1474
1475                         cairo_restore (cr);
1476                 }
1477         }
1478
1479         if ( GL_LABEL_OBJECT_GET_CLASS(object)->draw_object != NULL )
1480         {
1481                 cairo_save (cr);
1482                 cairo_transform (cr, &matrix);
1483
1484                 GL_LABEL_OBJECT_GET_CLASS(object)->draw_object (object,
1485                                                                 cr,
1486                                                                 screen_flag,
1487                                                                 record);
1488
1489                 cairo_restore (cr);
1490         }
1491
1492         cairo_restore (cr);
1493
1494         gl_debug (DEBUG_LABEL, "END");
1495 }
1496
1497
1498 /*****************************************************************************/
1499 /* Is object located at coordinates.                                         */
1500 /*****************************************************************************/
1501 gboolean
1502 gl_label_object_is_located_at (glLabelObject     *object,
1503                                cairo_t           *cr,
1504                                gdouble            x_pixels,
1505                                gdouble            y_pixels)
1506 {
1507         gboolean            ret_val = FALSE;
1508         gdouble             x0, y0;
1509         cairo_matrix_t      matrix;
1510         gdouble             x, y;
1511
1512         gl_debug (DEBUG_LABEL, "START");
1513
1514         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
1515
1516         if ( GL_LABEL_OBJECT_GET_CLASS(object)->draw_object != NULL )
1517         {
1518
1519                 gl_label_object_get_position (object, &x0, &y0);
1520                 gl_label_object_get_matrix (object, &matrix);
1521
1522                 cairo_save (cr);
1523
1524                 cairo_translate (cr, x0, y0);
1525                 cairo_transform (cr, &matrix);
1526
1527                 x = x_pixels;
1528                 y = y_pixels;
1529                 cairo_device_to_user (cr, &x, &y);
1530
1531                 ret_val = GL_LABEL_OBJECT_GET_CLASS(object)->object_at (object, cr, x, y);
1532
1533                 cairo_restore (cr);
1534         }
1535
1536         gl_debug (DEBUG_LABEL, "END");
1537
1538         return ret_val;
1539 }
1540
1541
1542 /*****************************************************************************/
1543 /* Draw object handles                                                       */
1544 /*****************************************************************************/
1545 void
1546 gl_label_object_draw_handles (glLabelObject     *object,
1547                               cairo_t           *cr)
1548 {
1549         gdouble        x0, y0;
1550         cairo_matrix_t matrix;
1551
1552         gl_debug (DEBUG_LABEL, "START");
1553
1554         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
1555
1556         if ( GL_LABEL_OBJECT_GET_CLASS(object)->draw_object != NULL )
1557         {
1558
1559                 gl_label_object_get_position (object, &x0, &y0);
1560                 gl_label_object_get_matrix (object, &matrix);
1561
1562                 cairo_save (cr);
1563
1564                 cairo_translate (cr, x0, y0);
1565                 cairo_transform (cr, &matrix);
1566
1567                 GL_LABEL_OBJECT_GET_CLASS(object)->draw_handles (object, cr);
1568
1569                 cairo_restore (cr);
1570         }
1571
1572         gl_debug (DEBUG_LABEL, "END");
1573 }
1574
1575
1576 /*--------------------------------------------------------------------------*/
1577 /* Draw individual handle                                                   */
1578 /*--------------------------------------------------------------------------*/
1579 static void
1580 draw_handle (cairo_t                *cr,
1581              glLabelObject          *object,
1582              gdouble                 x_handle,
1583              gdouble                 y_handle)
1584 {
1585         gdouble scale_x, scale_y;
1586
1587
1588         gl_debug (DEBUG_VIEW, "START");
1589
1590         cairo_save (cr);
1591
1592         cairo_translate (cr, x_handle, y_handle);
1593
1594         scale_x = 1.0;
1595         scale_y = 1.0;
1596         cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1597         cairo_scale (cr, scale_x, scale_y);
1598
1599         cairo_rectangle (cr,
1600                          -HANDLE_PIXELS/2.0, -HANDLE_PIXELS/2.0,
1601                          HANDLE_PIXELS, HANDLE_PIXELS);
1602
1603         cairo_set_source_rgba (cr, HANDLE_FILL_RGBA_ARGS);
1604         cairo_fill_preserve (cr);
1605                                
1606         cairo_set_line_width (cr, HANDLE_OUTLINE_WIDTH_PIXELS);
1607         cairo_set_source_rgba (cr, HANDLE_OUTLINE_RGBA_ARGS);
1608         cairo_stroke (cr);
1609
1610         cairo_restore (cr);
1611
1612         gl_debug (DEBUG_VIEW, "END");
1613 }
1614
1615
1616 /*--------------------------------------------------------------------------*/
1617 /* Create handle path                                                       */
1618 /*--------------------------------------------------------------------------*/
1619 static void
1620 create_handle_path (cairo_t                *cr,
1621                     glLabelObject          *object,
1622                     gdouble                 x_handle,
1623                     gdouble                 y_handle)
1624 {
1625         gdouble scale_x, scale_y;
1626
1627
1628         gl_debug (DEBUG_VIEW, "START");
1629
1630         cairo_save (cr);
1631
1632         cairo_translate (cr, x_handle, y_handle);
1633
1634         scale_x = 1.0;
1635         scale_y = 1.0;
1636         cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1637         cairo_scale (cr, scale_x, scale_y);
1638
1639         cairo_rectangle (cr,
1640                          -HANDLE_PIXELS/2.0, -HANDLE_PIXELS/2.0,
1641                          HANDLE_PIXELS, HANDLE_PIXELS);
1642
1643         cairo_restore (cr);
1644
1645         gl_debug (DEBUG_VIEW, "END");
1646 }
1647
1648
1649 /*****************************************************************************/
1650 /* Draw box style handles.                                                   */
1651 /*****************************************************************************/
1652 void
1653 gl_label_object_draw_handles_box (glLabelObject     *object,
1654                                   cairo_t           *cr)
1655 {
1656         gdouble w, h;
1657
1658         gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
1659
1660         /* North */
1661         draw_handle (cr, object, w/2, 0);
1662
1663         /* North East */
1664         draw_handle (cr, object, w, 0);
1665
1666         /* East */
1667         draw_handle (cr, object, w, h/2);
1668
1669         /* South East */
1670         draw_handle (cr, object, w, h);
1671
1672         /* South */
1673         draw_handle (cr, object, w/2, h);
1674
1675         /* South West */
1676         draw_handle (cr, object, 0, h);
1677
1678         /* West */
1679         draw_handle (cr, object, 0, h/2);
1680
1681         /* North West */
1682         draw_handle (cr, object, 0, 0);
1683 }
1684
1685
1686 /*****************************************************************************/
1687 /* Draw line style handles.                                                  */
1688 /*****************************************************************************/
1689 void
1690 gl_label_object_draw_handles_line (glLabelObject     *object,
1691                                    cairo_t           *cr)
1692 {
1693         gdouble w, h;
1694
1695         gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
1696
1697         /* P2 */
1698         draw_handle (cr, object, w, h);
1699
1700         /* P1 */
1701         draw_handle (cr, object, 0, 0);
1702 }
1703
1704
1705 /*****************************************************************************/
1706 /* Get handle at given coordinates, if any.                                  */
1707 /*****************************************************************************/
1708 glLabelObjectHandle
1709 gl_label_object_handle_at (glLabelObject     *object,
1710                            cairo_t           *cr,
1711                            gdouble            x_pixels,
1712                            gdouble            y_pixels)
1713 {
1714         glLabelObjectHandle handle = GL_LABEL_OBJECT_HANDLE_NONE;
1715         gdouble             x0, y0;
1716         cairo_matrix_t      matrix;
1717         gdouble             x, y;
1718
1719         gl_debug (DEBUG_LABEL, "START");
1720
1721         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), handle);
1722
1723         if ( GL_LABEL_OBJECT_GET_CLASS(object)->draw_object != NULL )
1724         {
1725
1726                 gl_label_object_get_position (object, &x0, &y0);
1727                 gl_label_object_get_matrix (object, &matrix);
1728
1729                 cairo_save (cr);
1730
1731                 cairo_translate (cr, x0, y0);
1732                 cairo_transform (cr, &matrix);
1733
1734                 x = x_pixels;
1735                 y = y_pixels;
1736                 cairo_device_to_user (cr, &x, &y);
1737
1738                 handle = GL_LABEL_OBJECT_GET_CLASS(object)->handle_at (object, cr, x, y);
1739
1740                 cairo_restore (cr);
1741         }
1742
1743         gl_debug (DEBUG_LABEL, "END");
1744
1745         return handle;
1746 }
1747
1748
1749 /*****************************************************************************/
1750 /* Get handle at given coordinates for box style handles, if any.            */
1751 /*****************************************************************************/
1752 glLabelObjectHandle
1753 gl_label_object_box_handle_at (glLabelObject     *object,
1754                                cairo_t           *cr,
1755                                gdouble            x,
1756                                gdouble            y)
1757 {
1758         gdouble w, h;
1759
1760         gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
1761
1762         /* South East */
1763         create_handle_path (cr, object, w, h);
1764         if (cairo_in_fill (cr, x, y))
1765         {
1766                 return GL_LABEL_OBJECT_HANDLE_SE;
1767         }
1768         
1769         /* South West */
1770         create_handle_path (cr, object, 0, h);
1771         if (cairo_in_fill (cr, x, y))
1772         {
1773                 return GL_LABEL_OBJECT_HANDLE_SW;
1774         }
1775
1776         /* North East */
1777         create_handle_path (cr, object, w, 0);
1778         if (cairo_in_fill (cr, x, y))
1779         {
1780                 return GL_LABEL_OBJECT_HANDLE_NE;
1781         }
1782
1783         /* North West */
1784         create_handle_path (cr, object, 0, 0);
1785         if (cairo_in_fill (cr, x, y))
1786         {
1787                 return GL_LABEL_OBJECT_HANDLE_NW;
1788         }
1789
1790         /* East */
1791         create_handle_path (cr, object, w, h/2);
1792         if (cairo_in_fill (cr, x, y))
1793         {
1794                 return GL_LABEL_OBJECT_HANDLE_E;
1795         }
1796
1797         /* South */
1798         create_handle_path (cr, object, w/2, h);
1799         if (cairo_in_fill (cr, x, y))
1800         {
1801                 return GL_LABEL_OBJECT_HANDLE_S;
1802         }
1803
1804         /* West */
1805         create_handle_path (cr, object, 0, h/2);
1806         if (cairo_in_fill (cr, x, y))
1807         {
1808                 return GL_LABEL_OBJECT_HANDLE_W;
1809         }
1810
1811         /* North */
1812         create_handle_path (cr, object, w/2, 0);
1813         if (cairo_in_fill (cr, x, y))
1814         {
1815                 return GL_LABEL_OBJECT_HANDLE_N;
1816         }
1817
1818         return GL_LABEL_OBJECT_HANDLE_NONE;
1819 }
1820
1821
1822 /*****************************************************************************/
1823 /* Get handle at given coordinates for line style handles, if any.           */
1824 /*****************************************************************************/
1825 glLabelObjectHandle
1826 gl_label_object_line_handle_at (glLabelObject     *object,
1827                                 cairo_t           *cr,
1828                                 gdouble            x,
1829                                 gdouble            y)
1830 {
1831         gdouble w, h;
1832
1833         gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
1834
1835         /* P2 */
1836         create_handle_path (cr, object, w, h);
1837         if (cairo_in_fill (cr, x, y))
1838         {
1839                 return GL_LABEL_OBJECT_HANDLE_P2;
1840         }
1841         
1842         /* P1 */
1843         create_handle_path (cr, object, 0, h);
1844         if (cairo_in_fill (cr, x, y))
1845         {
1846                 return GL_LABEL_OBJECT_HANDLE_P1;
1847         }
1848
1849         return GL_LABEL_OBJECT_HANDLE_NONE;
1850 }
1851
1852
1853
1854
1855 /*
1856  * Local Variables:       -- emacs
1857  * mode: C                -- emacs
1858  * c-basic-offset: 8      -- emacs
1859  * tab-width: 8           -- emacs
1860  * indent-tabs-mode: nil  -- emacs
1861  * End:                   -- emacs
1862  */