]> git.sur5r.net Git - glabels/blob - glabels2/src/label-object.c
Added text box support.
[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 /* Flip object horizontally.                                                */
560 /****************************************************************************/
561 void
562 gl_label_object_flip_horiz (glLabelObject *object)
563 {
564         gdouble flip_affine[6];
565
566         gl_debug (DEBUG_LABEL, "START");
567
568         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
569
570         art_affine_scale (flip_affine, -1.0, 1.0);
571         art_affine_multiply (object->private->affine, object->private->affine, flip_affine);
572
573         g_signal_emit (G_OBJECT(object), signals[FLIP_ROTATE], 0);
574
575         gl_debug (DEBUG_LABEL, "END");
576 }
577
578 /****************************************************************************/
579 /* Flip object vertically.                                                  */
580 /****************************************************************************/
581 void
582 gl_label_object_flip_vert (glLabelObject *object)
583 {
584         gdouble flip_affine[6];
585
586         gl_debug (DEBUG_LABEL, "START");
587
588         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
589
590         art_affine_scale (flip_affine, 1.0, -1.0);
591         art_affine_multiply (object->private->affine, object->private->affine, flip_affine);
592
593         g_signal_emit (G_OBJECT(object), signals[FLIP_ROTATE], 0);
594
595         gl_debug (DEBUG_LABEL, "END");
596 }
597
598 /****************************************************************************/
599 /* Rotate object.                                                           */
600 /****************************************************************************/
601 void
602 gl_label_object_rotate (glLabelObject *object,
603                         gdouble        theta_degs)
604 {
605         gdouble rotate_affine[6];
606
607         gl_debug (DEBUG_LABEL, "START");
608
609         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
610
611         art_affine_rotate (rotate_affine, theta_degs);
612         art_affine_multiply (object->private->affine, object->private->affine, rotate_affine);
613
614         g_signal_emit (G_OBJECT(object), signals[FLIP_ROTATE], 0);
615
616         gl_debug (DEBUG_LABEL, "END");
617 }
618
619 /****************************************************************************/
620 /* Set raw affine                                                           */
621 /****************************************************************************/
622 void
623 gl_label_object_set_affine (glLabelObject *object,
624                             gdouble        affine[6])
625 {
626         gl_debug (DEBUG_LABEL, "");
627
628         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
629
630         object->private->affine[0] = affine[0];
631         object->private->affine[1] = affine[1];
632         object->private->affine[2] = affine[2];
633         object->private->affine[3] = affine[3];
634         object->private->affine[4] = affine[4];
635         object->private->affine[5] = affine[5];
636 }
637
638 /****************************************************************************/
639 /* Get raw affine                                                           */
640 /****************************************************************************/
641 void
642 gl_label_object_get_affine (glLabelObject *object,
643                             gdouble        affine[6])
644 {
645         gl_debug (DEBUG_LABEL, "");
646
647         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
648
649         affine[0] = object->private->affine[0];
650         affine[1] = object->private->affine[1];
651         affine[2] = object->private->affine[2];
652         affine[3] = object->private->affine[3];
653         affine[4] = object->private->affine[4];
654         affine[5] = object->private->affine[5];
655 }
656
657 /****************************************************************************/
658 /* Get i2w affine, i.e. applied affine + translation.                       */
659 /****************************************************************************/
660 void
661 gl_label_object_get_i2w_affine (glLabelObject *object,
662                                 gdouble        affine[6])
663 {
664         gdouble x, y;
665         gdouble translation[6];
666
667         gl_debug (DEBUG_LABEL, "");
668
669         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
670
671         gl_label_object_get_affine (object, affine);
672         gl_label_object_get_position (object, &x, &y);
673
674         art_affine_translate (translation, x, y);
675         art_affine_multiply (affine, affine, translation);
676 }
677
678 /****************************************************************************/
679 /* Get w2i affine, i.e. inverse of applied affine + translation.            */
680 /****************************************************************************/
681 void
682 gl_label_object_get_w2i_affine (glLabelObject *object,
683                                 gdouble        affine[6])
684 {
685         gdouble i2w[6];
686         gl_debug (DEBUG_LABEL, "");
687
688         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
689
690         gl_label_object_get_i2w_affine (object, i2w);
691         art_affine_invert (affine, i2w);
692 }
693
694 /****************************************************************************/
695 /* Bring label object to front/top.                                         */
696 /****************************************************************************/
697 void
698 gl_label_object_raise_to_top (glLabelObject *object)
699 {
700         glLabel *label;
701
702         gl_debug (DEBUG_LABEL, "START");
703
704         label = object->parent;
705
706         gl_label_raise_object_to_top (label, object);
707
708         g_signal_emit (G_OBJECT(object), signals[TOP], 0);
709
710         gl_debug (DEBUG_LABEL, "END");
711 }
712
713 /****************************************************************************/
714 /* Send label object to rear/bottom.                                        */
715 /****************************************************************************/
716 void
717 gl_label_object_lower_to_bottom (glLabelObject *object)
718 {
719         glLabel *label;
720
721         gl_debug (DEBUG_LABEL, "START");
722
723         label = object->parent;
724
725         gl_label_lower_object_to_bottom (label, object);
726
727         g_signal_emit (G_OBJECT(object), signals[BOTTOM], 0);
728
729         gl_debug (DEBUG_LABEL, "END");
730 }
731
732 /*--------------------------------------------------------------------------*/
733 /* PRIVATE.  Label's merge data changed callback.                           */
734 /*--------------------------------------------------------------------------*/
735 static void
736 merge_changed_cb (glLabel       *label,
737                   glLabelObject *object)
738 {
739         gl_label_object_emit_changed (object);
740 }
741