]> git.sur5r.net Git - glabels/blob - glabels2/src/label-object.c
- Added mygal, a modified version of the gal library, to provide a sophisticated...
[glabels] / glabels2 / src / label-object.c
1 /*
2  *  (GLABELS) Label and Business Card Creation program for GNOME
3  *
4  *  label_object.c:  GLabels label object base class
5  *
6  *  Copyright (C) 2001-2002  Jim Evins <evins@snaught.com>.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21  */
22 #include <config.h>
23
24 #include <glib.h>
25 #include <libart_lgpl/libart.h>
26
27 #include "label-object.h"
28 #include "marshal.h"
29
30 #include "debug.h"
31
32 /*========================================================*/
33 /* Private types.                                         */
34 /*========================================================*/
35
36 struct _glLabelObjectPrivate {
37         gchar             *name;
38         gdouble            x, y;
39         gdouble            w, h;
40         gdouble            affine[6];
41 };
42
43 enum {
44         CHANGED,
45         MOVED,
46         FLIP_ROTATE,
47         TOP,
48         BOTTOM,
49         LAST_SIGNAL
50 };
51
52 /*========================================================*/
53 /* Private globals.                                       */
54 /*========================================================*/
55
56 static GObjectClass *parent_class = NULL;
57
58 static guint signals[LAST_SIGNAL] = {0};
59
60 static guint instance = 0;
61
62 /*========================================================*/
63 /* Private function prototypes.                           */
64 /*========================================================*/
65
66 static void gl_label_object_class_init    (glLabelObjectClass *klass);
67 static void gl_label_object_instance_init (glLabelObject      *object);
68 static void gl_label_object_finalize      (GObject            *object);
69
70 static void merge_changed_cb              (glLabel            *label,
71                                            glLabelObject      *object);
72
73 static void set_size                      (glLabelObject      *object,
74                                            gdouble             w,
75                                            gdouble             h);
76
77 static void get_size                      (glLabelObject      *object,
78                                            gdouble            *w,
79                                            gdouble            *h);
80
81 \f
82 /*****************************************************************************/
83 /* Boilerplate object stuff.                                                 */
84 /*****************************************************************************/
85 GType
86 gl_label_object_get_type (void)
87 {
88         static GType type = 0;
89
90         if (!type) {
91                 GTypeInfo info = {
92                         sizeof (glLabelObjectClass),
93                         NULL,
94                         NULL,
95                         (GClassInitFunc) gl_label_object_class_init,
96                         NULL,
97                         NULL,
98                         sizeof (glLabelObject),
99                         0,
100                         (GInstanceInitFunc) gl_label_object_instance_init,
101                 };
102
103                 type = g_type_register_static (G_TYPE_OBJECT,
104                                                "glLabelObject", &info, 0);
105         }
106
107         return type;
108 }
109
110 static void
111 gl_label_object_class_init (glLabelObjectClass *klass)
112 {
113         GObjectClass       *gobject_class = (GObjectClass *) klass;
114         glLabelObjectClass *object_class  = (glLabelObjectClass *) klass;
115
116         gl_debug (DEBUG_LABEL, "START");
117
118         parent_class = g_type_class_peek_parent (klass);
119
120         gobject_class->finalize = gl_label_object_finalize;
121
122         object_class->set_size = set_size;
123         object_class->get_size = get_size;
124
125         signals[CHANGED] =
126                 g_signal_new ("changed",
127                               G_OBJECT_CLASS_TYPE (gobject_class),
128                               G_SIGNAL_RUN_LAST,
129                               G_STRUCT_OFFSET (glLabelObjectClass, changed),
130                               NULL, NULL,
131                               gl_marshal_VOID__VOID,
132                               G_TYPE_NONE,
133                               0);
134
135         signals[MOVED] =
136                 g_signal_new ("moved",
137                               G_OBJECT_CLASS_TYPE (gobject_class),
138                               G_SIGNAL_RUN_LAST,
139                               G_STRUCT_OFFSET (glLabelObjectClass, moved),
140                               NULL, NULL,
141                               gl_marshal_VOID__DOUBLE_DOUBLE,
142                               G_TYPE_NONE,
143                               2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
144         signals[FLIP_ROTATE] =
145                 g_signal_new ("flip_rotate",
146                               G_OBJECT_CLASS_TYPE (gobject_class),
147                               G_SIGNAL_RUN_LAST,
148                               G_STRUCT_OFFSET (glLabelObjectClass, flip_rotate),
149                               NULL, NULL,
150                               gl_marshal_VOID__VOID,
151                               G_TYPE_NONE,
152                               0);
153         signals[TOP] =
154                 g_signal_new ("top",
155                               G_OBJECT_CLASS_TYPE (gobject_class),
156                               G_SIGNAL_RUN_LAST,
157                               G_STRUCT_OFFSET (glLabelObjectClass, top),
158                               NULL, NULL,
159                               gl_marshal_VOID__VOID,
160                               G_TYPE_NONE,
161                               0);
162
163         signals[BOTTOM] =
164                 g_signal_new ("bottom",
165                               G_OBJECT_CLASS_TYPE (gobject_class),
166                               G_SIGNAL_RUN_LAST,
167                               G_STRUCT_OFFSET (glLabelObjectClass, bottom),
168                               NULL, NULL,
169                               gl_marshal_VOID__VOID,
170                               G_TYPE_NONE,
171                               0);
172
173         gl_debug (DEBUG_LABEL, "END");
174 }
175
176 static void
177 gl_label_object_instance_init (glLabelObject *object)
178 {
179         gl_debug (DEBUG_LABEL, "START");
180
181         object->private = g_new0 (glLabelObjectPrivate, 1);
182
183         object->private->name = g_strdup_printf ("object%d", instance++);
184
185         art_affine_identity (object->private->affine);
186
187         gl_debug (DEBUG_LABEL, "END");
188 }
189
190 static void
191 gl_label_object_finalize (GObject *object)
192 {
193         glLabel       *parent;
194
195         gl_debug (DEBUG_LABEL, "START");
196
197         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
198
199         parent = GL_LABEL_OBJECT(object)->parent;
200         gl_label_remove_object (parent, GL_LABEL_OBJECT(object));
201
202         g_free (GL_LABEL_OBJECT(object)->private->name);
203         g_free (GL_LABEL_OBJECT(object)->private);
204
205         G_OBJECT_CLASS (parent_class)->finalize (object);
206
207         gl_debug (DEBUG_LABEL, "END");
208 }
209
210 /*****************************************************************************/
211 /* New label object.                                                         */
212 /*****************************************************************************/
213 GObject *
214 gl_label_object_new (glLabel *label)
215 {
216         glLabelObject *object;
217
218         gl_debug (DEBUG_LABEL, "START");
219
220         object = g_object_new (gl_label_object_get_type(), NULL);
221
222         gl_label_object_set_parent (object, label);
223
224         gl_debug (DEBUG_LABEL, "END");
225
226         return G_OBJECT (object);
227 }
228
229 /*****************************************************************************/
230 /* Duplicate object.                                                         */
231 /*****************************************************************************/
232 glLabelObject *
233 gl_label_object_dup (glLabelObject *src_object,
234                      glLabel       *label)
235 {
236         glLabelObject    *dst_object;
237         gdouble           x, y, w, h;
238         gdouble           affine[6];
239
240         gl_debug (DEBUG_LABEL, "START");
241
242         g_return_if_fail (src_object && GL_IS_LABEL_OBJECT (src_object));
243
244         dst_object = g_object_new (G_OBJECT_TYPE(src_object), NULL);
245
246         gl_label_object_set_parent (dst_object, label);
247
248         gl_label_object_get_position (src_object, &x, &y);
249         gl_label_object_get_size     (src_object, &w, &h);
250         gl_label_object_get_affine   (src_object, affine);
251
252         gl_label_object_set_position (dst_object, x, y);
253         gl_label_object_set_size     (dst_object, w, h);
254         gl_label_object_set_affine   (dst_object, affine);
255
256         if ( GL_LABEL_OBJECT_GET_CLASS(src_object)->copy != NULL ) {
257
258                 /* We have an object specific method, use it */
259                 GL_LABEL_OBJECT_GET_CLASS(src_object)->copy (dst_object, src_object);
260
261         }
262
263         gl_debug (DEBUG_LABEL, "END");
264
265         return dst_object;
266 }
267
268 /*****************************************************************************/
269 /* Emit "changed" signal (for derived objects).                              */
270 /*****************************************************************************/
271 void
272 gl_label_object_emit_changed (glLabelObject *object)
273 {
274         gl_debug (DEBUG_LABEL, "START");
275
276         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
277
278         g_signal_emit (G_OBJECT(object), signals[CHANGED], 0);
279
280         gl_debug (DEBUG_LABEL, "END");
281 }
282
283 /*****************************************************************************/
284 /* Set parent label of object.                                               */
285 /*****************************************************************************/
286 void
287 gl_label_object_set_parent (glLabelObject *object,
288                             glLabel       *label)
289 {
290         glLabel *old_parent;
291
292         gl_debug (DEBUG_LABEL, "START");
293
294         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
295         g_return_if_fail (label && GL_IS_LABEL (label));
296
297         old_parent = object->parent;
298         if ( old_parent != NULL ) {
299                 g_signal_handlers_disconnect_by_func (old_parent,
300                                                       G_CALLBACK(merge_changed_cb),
301                                                       object);
302                 gl_label_remove_object( old_parent, object );
303         }
304         gl_label_add_object( label, object );
305
306         g_signal_connect (G_OBJECT(label), "merge_changed",
307                           G_CALLBACK(merge_changed_cb), object);
308
309         g_signal_emit (G_OBJECT(object), signals[CHANGED], 0);
310
311         gl_debug (DEBUG_LABEL, "END");
312 }
313
314 /*****************************************************************************/
315 /* Get parent label of object.                                               */
316 /*****************************************************************************/
317 glLabel *
318 gl_label_object_get_parent (glLabelObject *object)
319 {
320         gl_debug (DEBUG_LABEL, "START");
321
322         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
323
324         gl_debug (DEBUG_LABEL, "END");
325
326         return object->parent;
327 }
328
329 /*****************************************************************************/
330 /* Set name of object.                                                       */
331 /*****************************************************************************/
332 void
333 gl_label_object_set_name (glLabelObject *object,
334                           gchar         *name)
335 {
336         gl_debug (DEBUG_LABEL, "START");
337
338         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
339
340         g_free(object->private->name);
341         object->private->name = name;
342
343         g_signal_emit (G_OBJECT(object), signals[CHANGED], 0);
344
345         gl_debug (DEBUG_LABEL, "END");
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_if_fail (object && GL_IS_LABEL_OBJECT (object));
357
358         gl_debug (DEBUG_LABEL, "END");
359
360         return g_strdup(object->private->name);
361 }
362
363 /*****************************************************************************/
364 /* Set position of object.                                                   */
365 /*****************************************************************************/
366 void
367 gl_label_object_set_position (glLabelObject *object,
368                               gdouble        x,
369                               gdouble        y)
370 {
371         gdouble dx, dy;
372
373         gl_debug (DEBUG_LABEL, "START");
374
375         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
376
377         dx = x - object->private->x;
378         dy = y - object->private->y;
379
380         object->private->x = x;
381         object->private->y = y;
382
383         g_signal_emit (G_OBJECT(object), signals[MOVED], 0, dx, dy);
384
385         gl_debug (DEBUG_LABEL, "END");
386 }
387
388 /*****************************************************************************/
389 /* Set position of object relative to old position.                          */
390 /*****************************************************************************/
391 void
392 gl_label_object_set_position_relative (glLabelObject *object,
393                                        gdouble        dx,
394                                        gdouble        dy)
395 {
396         gl_debug (DEBUG_LABEL, "START");
397
398         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
399
400         object->private->x += dx;
401         object->private->y += dy;
402
403         gl_debug (DEBUG_LABEL, "       x = %f, y= %f",
404                   object->private->x,
405                   object->private->y);
406
407         g_signal_emit (G_OBJECT(object), signals[MOVED], 0, dx, dy);
408
409         gl_debug (DEBUG_LABEL, "END");
410 }
411
412 /*****************************************************************************/
413 /* Get position of object.                                                   */
414 /*****************************************************************************/
415 void
416 gl_label_object_get_position (glLabelObject *object,
417                               gdouble       *x,
418                               gdouble       *y)
419 {
420         gl_debug (DEBUG_LABEL, "START");
421
422         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
423
424         *x = object->private->x;
425         *y = object->private->y;
426
427         gl_debug (DEBUG_LABEL, "END");
428 }
429
430 /*---------------------------------------------------------------------------*/
431 /* PRIVATE.  Default set size method.                                        */
432 /*---------------------------------------------------------------------------*/
433 static void
434 set_size (glLabelObject *object,
435           gdouble        w,
436           gdouble        h)
437 {
438         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
439
440         object->private->w = w;
441         object->private->h = h;
442 }
443
444 /*****************************************************************************/
445 /* Set size of object.                                                       */
446 /*****************************************************************************/
447 void
448 gl_label_object_set_size (glLabelObject *object,
449                           gdouble        w,
450                           gdouble        h)
451 {
452         gl_debug (DEBUG_LABEL, "START");
453
454         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
455
456         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_size != NULL ) {
457
458                 /* We have an object specific method, use it */
459                 GL_LABEL_OBJECT_GET_CLASS(object)->set_size (object, w, h);
460
461         } else {
462
463                 set_size (object, w, h);
464
465         }
466
467         g_signal_emit (G_OBJECT(object), signals[CHANGED], 0);
468
469         gl_debug (DEBUG_LABEL, "END");
470 }
471
472 /*---------------------------------------------------------------------------*/
473 /* PRIVATE.  Default get size method.                                        */
474 /*---------------------------------------------------------------------------*/
475 static void
476 get_size (glLabelObject *object,
477           gdouble       *w,
478           gdouble       *h)
479 {
480         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
481
482         *w = object->private->w;
483         *h = object->private->h;
484 }
485
486 /*****************************************************************************/
487 /* Get size of object.                                                       */
488 /*****************************************************************************/
489 void
490 gl_label_object_get_size (glLabelObject *object,
491                           gdouble       *w,
492                           gdouble       *h)
493 {
494         gl_debug (DEBUG_LABEL, "START");
495
496         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
497
498         if ( GL_LABEL_OBJECT_GET_CLASS(object)->get_size != NULL ) {
499
500                 /* We have an object specific method, use it */
501                 GL_LABEL_OBJECT_GET_CLASS(object)->get_size (object, w, h);
502
503         } else {
504
505                 get_size (object, w, h);
506
507         }
508
509         gl_debug (DEBUG_LABEL, "END");
510 }
511
512 /*****************************************************************************/
513 /* Get extent of object.                                                     */
514 /*****************************************************************************/
515 void
516 gl_label_object_get_extent (glLabelObject *object,
517                             gdouble       *x1,
518                             gdouble       *y1,
519                             gdouble       *x2,
520                             gdouble       *y2)
521 {
522         gdouble  w, h;
523         ArtPoint a1, a2, a3, a4, b1, b2, b3, b4;
524         gdouble  affine[6];
525
526         gl_debug (DEBUG_LABEL, "START");
527
528         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
529
530         gl_label_object_get_size (object, &w, &h);
531
532         /* setup untransformed corners of bounding box */
533         a1.x = 0.0;
534         a1.y = 0.0;
535         a2.x = w;
536         a2.y = 0.0;
537         a3.x = w;
538         a3.y = h;
539         a4.x = 0.0;
540         a4.y = h;
541
542         /* transform these points */
543         gl_label_object_get_affine (object, affine);
544         art_affine_point (&b1, &a1, affine);
545         art_affine_point (&b2, &a2, affine);
546         art_affine_point (&b3, &a3, affine);
547         art_affine_point (&b4, &a4, affine);
548
549         /* now find the maximum extent of these points in x and y */
550         *x1 = MIN (b1.x, MIN (b2.x, MIN (b3.x, b4.x))) + object->private->x;
551         *y1 = MIN (b1.y, MIN (b2.y, MIN (b3.y, b4.y))) + object->private->y;
552         *x2 = MAX (b1.x, MAX (b2.x, MAX (b3.x, b4.x))) + object->private->x;
553         *y2 = MAX (b1.y, MAX (b2.y, MAX (b3.y, b4.y))) + object->private->y;
554         
555         gl_debug (DEBUG_LABEL, "END");
556 }
557
558 /*****************************************************************************/
559 /* Can text properties be set for this object?                               */
560 /*****************************************************************************/
561 gboolean
562 gl_label_object_can_text (glLabelObject     *object)
563 {
564         gl_debug (DEBUG_LABEL, "");
565
566         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
567
568         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_font_family != NULL ) {
569
570                 return TRUE;
571
572         } else {
573
574                 return FALSE;
575
576         }
577
578 }
579
580 /*****************************************************************************/
581 /* Set font family for all text contained in object.                         */
582 /*****************************************************************************/
583 void
584 gl_label_object_set_font_family (glLabelObject     *object,
585                                  const gchar       *font_family)
586 {
587         gl_debug (DEBUG_LABEL, "START");
588
589         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
590
591         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_font_family != NULL ) {
592
593                 /* We have an object specific method, use it */
594                 GL_LABEL_OBJECT_GET_CLASS(object)->set_font_family (object, font_family);
595
596         }
597
598         gl_debug (DEBUG_LABEL, "END");
599 }
600
601 /****************************************************************************/
602 /* Set font size for all text contained in object.                          */
603 /****************************************************************************/
604 void
605 gl_label_object_set_font_size (glLabelObject     *object,
606                                gdouble            font_size)
607 {
608         gl_debug (DEBUG_LABEL, "START");
609
610         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
611
612         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_font_size != NULL ) {
613
614                 /* We have an object specific method, use it */
615                 GL_LABEL_OBJECT_GET_CLASS(object)->set_font_size (object, font_size);
616
617         }
618
619         gl_debug (DEBUG_LABEL, "END");
620 }
621
622 /****************************************************************************/
623 /* Set font weight for all text contained in object.                        */
624 /****************************************************************************/
625 void
626 gl_label_object_set_font_weight (glLabelObject     *object,
627                                  GnomeFontWeight    font_weight)
628 {
629         gl_debug (DEBUG_LABEL, "START");
630
631         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
632
633         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_font_weight != NULL ) {
634
635                 /* We have an object specific method, use it */
636                 GL_LABEL_OBJECT_GET_CLASS(object)->set_font_weight (object, font_weight);
637
638         }
639
640         gl_debug (DEBUG_LABEL, "END");
641 }
642
643 /****************************************************************************/
644 /* Set font italic flag for all text contained in object.                   */
645 /****************************************************************************/
646 void
647 gl_label_object_set_font_italic_flag (glLabelObject     *object,
648                                       GnomeFontWeight    font_italic_flag)
649 {
650         gl_debug (DEBUG_LABEL, "START");
651
652         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
653
654         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_font_italic_flag != NULL ) {
655
656                 /* We have an object specific method, use it */
657                 GL_LABEL_OBJECT_GET_CLASS(object)->set_font_italic_flag (object,
658                                                                          font_italic_flag);
659
660         }
661
662         gl_debug (DEBUG_LABEL, "END");
663 }
664
665 /****************************************************************************/
666 /* Set text alignment for all text contained in object.                     */
667 /****************************************************************************/
668 void
669 gl_label_object_set_text_alignment (glLabelObject     *object,
670                                     GtkJustification   text_alignment)
671 {
672         gl_debug (DEBUG_LABEL, "START");
673
674         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
675
676         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_text_alignment != NULL ) {
677
678                 /* We have an object specific method, use it */
679                 GL_LABEL_OBJECT_GET_CLASS(object)->set_text_alignment (object,
680                                                                        text_alignment);
681
682         }
683
684         gl_debug (DEBUG_LABEL, "END");
685 }
686
687 /****************************************************************************/
688 /* Set text color for all text contained in object.                         */
689 /****************************************************************************/
690 void
691 gl_label_object_set_text_color (glLabelObject     *object,
692                                 guint              text_color)
693 {
694         gl_debug (DEBUG_LABEL, "START");
695
696         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
697
698         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_text_color != NULL ) {
699
700                 /* We have an object specific method, use it */
701                 GL_LABEL_OBJECT_GET_CLASS(object)->set_text_color (object, text_color);
702
703         }
704
705         gl_debug (DEBUG_LABEL, "END");
706 }
707
708 /*****************************************************************************/
709 /* Can fill properties be set for this object?                               */
710 /*****************************************************************************/
711 gboolean
712 gl_label_object_can_fill (glLabelObject     *object)
713 {
714         gl_debug (DEBUG_LABEL, "");
715
716         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
717
718         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_fill_color != NULL ) {
719
720                 return TRUE;
721
722         } else {
723
724                 return FALSE;
725
726         }
727
728 }
729
730 /****************************************************************************/
731 /* Set fill color for object.                                               */
732 /****************************************************************************/
733 void
734 gl_label_object_set_fill_color (glLabelObject     *object,
735                                 guint              fill_color)
736 {
737         gl_debug (DEBUG_LABEL, "START");
738
739         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
740
741         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_fill_color != NULL ) {
742
743                 /* We have an object specific method, use it */
744                 GL_LABEL_OBJECT_GET_CLASS(object)->set_fill_color (object, fill_color);
745
746         }
747
748         gl_debug (DEBUG_LABEL, "END");
749 }
750
751 /*****************************************************************************/
752 /* Can line color property be set for this object?                           */
753 /*****************************************************************************/
754 gboolean
755 gl_label_object_can_line_color (glLabelObject     *object)
756 {
757         gl_debug (DEBUG_LABEL, "");
758
759         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
760
761         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_line_color != NULL ) {
762
763                 return TRUE;
764
765         } else {
766
767                 return FALSE;
768
769         }
770
771 }
772
773 /****************************************************************************/
774 /* Set line color for object.                                               */
775 /****************************************************************************/
776 void
777 gl_label_object_set_line_color (glLabelObject     *object,
778                                 guint              line_color)
779 {
780         gl_debug (DEBUG_LABEL, "START");
781
782         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
783
784         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_line_color != NULL ) {
785
786                 /* We have an object specific method, use it */
787                 GL_LABEL_OBJECT_GET_CLASS(object)->set_line_color (object, line_color);
788
789         }
790
791         gl_debug (DEBUG_LABEL, "END");
792 }
793
794 /*****************************************************************************/
795 /* Can line width property be set for this object?                           */
796 /*****************************************************************************/
797 gboolean
798 gl_label_object_can_line_width (glLabelObject     *object)
799 {
800         gl_debug (DEBUG_LABEL, "");
801
802         g_return_val_if_fail (object && GL_IS_LABEL_OBJECT (object), FALSE);
803
804         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_line_width != NULL ) {
805
806                 return TRUE;
807
808         } else {
809
810                 return FALSE;
811
812         }
813
814 }
815
816 /****************************************************************************/
817 /* Set line width for object.                                               */
818 /****************************************************************************/
819 void
820 gl_label_object_set_line_width (glLabelObject     *object,
821                                 gdouble            line_width)
822 {
823         gl_debug (DEBUG_LABEL, "START");
824
825         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
826
827         if ( GL_LABEL_OBJECT_GET_CLASS(object)->set_line_width != NULL ) {
828
829                 /* We have an object specific method, use it */
830                 GL_LABEL_OBJECT_GET_CLASS(object)->set_line_width (object, line_width);
831
832         }
833
834         gl_debug (DEBUG_LABEL, "END");
835 }
836
837 /****************************************************************************/
838 /* Flip object horizontally.                                                */
839 /****************************************************************************/
840 void
841 gl_label_object_flip_horiz (glLabelObject *object)
842 {
843         gdouble flip_affine[6];
844
845         gl_debug (DEBUG_LABEL, "START");
846
847         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
848
849         art_affine_scale (flip_affine, -1.0, 1.0);
850         art_affine_multiply (object->private->affine, object->private->affine, flip_affine);
851
852         g_signal_emit (G_OBJECT(object), signals[FLIP_ROTATE], 0);
853
854         gl_debug (DEBUG_LABEL, "END");
855 }
856
857 /****************************************************************************/
858 /* Flip object vertically.                                                  */
859 /****************************************************************************/
860 void
861 gl_label_object_flip_vert (glLabelObject *object)
862 {
863         gdouble flip_affine[6];
864
865         gl_debug (DEBUG_LABEL, "START");
866
867         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
868
869         art_affine_scale (flip_affine, 1.0, -1.0);
870         art_affine_multiply (object->private->affine, object->private->affine, flip_affine);
871
872         g_signal_emit (G_OBJECT(object), signals[FLIP_ROTATE], 0);
873
874         gl_debug (DEBUG_LABEL, "END");
875 }
876
877 /****************************************************************************/
878 /* Rotate object.                                                           */
879 /****************************************************************************/
880 void
881 gl_label_object_rotate (glLabelObject *object,
882                         gdouble        theta_degs)
883 {
884         gdouble rotate_affine[6];
885
886         gl_debug (DEBUG_LABEL, "START");
887
888         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
889
890         art_affine_rotate (rotate_affine, theta_degs);
891         art_affine_multiply (object->private->affine, object->private->affine, rotate_affine);
892
893         g_signal_emit (G_OBJECT(object), signals[FLIP_ROTATE], 0);
894
895         gl_debug (DEBUG_LABEL, "END");
896 }
897
898 /****************************************************************************/
899 /* Set raw affine                                                           */
900 /****************************************************************************/
901 void
902 gl_label_object_set_affine (glLabelObject *object,
903                             gdouble        affine[6])
904 {
905         gl_debug (DEBUG_LABEL, "");
906
907         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
908
909         object->private->affine[0] = affine[0];
910         object->private->affine[1] = affine[1];
911         object->private->affine[2] = affine[2];
912         object->private->affine[3] = affine[3];
913         object->private->affine[4] = affine[4];
914         object->private->affine[5] = affine[5];
915 }
916
917 /****************************************************************************/
918 /* Get raw affine                                                           */
919 /****************************************************************************/
920 void
921 gl_label_object_get_affine (glLabelObject *object,
922                             gdouble        affine[6])
923 {
924         gl_debug (DEBUG_LABEL, "");
925
926         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
927
928         affine[0] = object->private->affine[0];
929         affine[1] = object->private->affine[1];
930         affine[2] = object->private->affine[2];
931         affine[3] = object->private->affine[3];
932         affine[4] = object->private->affine[4];
933         affine[5] = object->private->affine[5];
934 }
935
936 /****************************************************************************/
937 /* Get i2w affine, i.e. applied affine + translation.                       */
938 /****************************************************************************/
939 void
940 gl_label_object_get_i2w_affine (glLabelObject *object,
941                                 gdouble        affine[6])
942 {
943         gdouble x, y;
944         gdouble translation[6];
945
946         gl_debug (DEBUG_LABEL, "");
947
948         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
949
950         gl_label_object_get_affine (object, affine);
951         gl_label_object_get_position (object, &x, &y);
952
953         art_affine_translate (translation, x, y);
954         art_affine_multiply (affine, affine, translation);
955 }
956
957 /****************************************************************************/
958 /* Get w2i affine, i.e. inverse of applied affine + translation.            */
959 /****************************************************************************/
960 void
961 gl_label_object_get_w2i_affine (glLabelObject *object,
962                                 gdouble        affine[6])
963 {
964         gdouble i2w[6];
965         gl_debug (DEBUG_LABEL, "");
966
967         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
968
969         gl_label_object_get_i2w_affine (object, i2w);
970         art_affine_invert (affine, i2w);
971 }
972
973 /****************************************************************************/
974 /* Bring label object to front/top.                                         */
975 /****************************************************************************/
976 void
977 gl_label_object_raise_to_top (glLabelObject *object)
978 {
979         glLabel *label;
980
981         gl_debug (DEBUG_LABEL, "START");
982
983         label = object->parent;
984
985         gl_label_raise_object_to_top (label, object);
986
987         g_signal_emit (G_OBJECT(object), signals[TOP], 0);
988
989         gl_debug (DEBUG_LABEL, "END");
990 }
991
992 /****************************************************************************/
993 /* Send label object to rear/bottom.                                        */
994 /****************************************************************************/
995 void
996 gl_label_object_lower_to_bottom (glLabelObject *object)
997 {
998         glLabel *label;
999
1000         gl_debug (DEBUG_LABEL, "START");
1001
1002         label = object->parent;
1003
1004         gl_label_lower_object_to_bottom (label, object);
1005
1006         g_signal_emit (G_OBJECT(object), signals[BOTTOM], 0);
1007
1008         gl_debug (DEBUG_LABEL, "END");
1009 }
1010
1011 /*--------------------------------------------------------------------------*/
1012 /* PRIVATE.  Label's merge data changed callback.                           */
1013 /*--------------------------------------------------------------------------*/
1014 static void
1015 merge_changed_cb (glLabel       *label,
1016                   glLabelObject *object)
1017 {
1018         gl_label_object_emit_changed (object);
1019 }
1020