]> git.sur5r.net Git - glabels/blob - glabels2/src/label-object.c
Added initial object rotation code.
[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 \f
74 /*****************************************************************************/
75 /* Boilerplate object stuff.                                                 */
76 /*****************************************************************************/
77 GType
78 gl_label_object_get_type (void)
79 {
80         static GType type = 0;
81
82         if (!type) {
83                 GTypeInfo info = {
84                         sizeof (glLabelObjectClass),
85                         NULL,
86                         NULL,
87                         (GClassInitFunc) gl_label_object_class_init,
88                         NULL,
89                         NULL,
90                         sizeof (glLabelObject),
91                         0,
92                         (GInstanceInitFunc) gl_label_object_instance_init,
93                 };
94
95                 type = g_type_register_static (G_TYPE_OBJECT,
96                                                "glLabelObject", &info, 0);
97         }
98
99         return type;
100 }
101
102 static void
103 gl_label_object_class_init (glLabelObjectClass *klass)
104 {
105         GObjectClass *object_class = (GObjectClass *) klass;
106
107         gl_debug (DEBUG_LABEL, "START");
108
109         parent_class = g_type_class_peek_parent (klass);
110
111         object_class->finalize = gl_label_object_finalize;
112
113         signals[CHANGED] =
114                 g_signal_new ("changed",
115                               G_OBJECT_CLASS_TYPE (object_class),
116                               G_SIGNAL_RUN_LAST,
117                               G_STRUCT_OFFSET (glLabelObjectClass, changed),
118                               NULL, NULL,
119                               gl_marshal_VOID__VOID,
120                               G_TYPE_NONE,
121                               0);
122
123         signals[MOVED] =
124                 g_signal_new ("moved",
125                               G_OBJECT_CLASS_TYPE (object_class),
126                               G_SIGNAL_RUN_LAST,
127                               G_STRUCT_OFFSET (glLabelObjectClass, moved),
128                               NULL, NULL,
129                               gl_marshal_VOID__DOUBLE_DOUBLE,
130                               G_TYPE_NONE,
131                               2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
132         signals[FLIP_ROTATE] =
133                 g_signal_new ("flip_rotate",
134                               G_OBJECT_CLASS_TYPE (object_class),
135                               G_SIGNAL_RUN_LAST,
136                               G_STRUCT_OFFSET (glLabelObjectClass, flip_rotate),
137                               NULL, NULL,
138                               gl_marshal_VOID__VOID,
139                               G_TYPE_NONE,
140                               0);
141         signals[TOP] =
142                 g_signal_new ("top",
143                               G_OBJECT_CLASS_TYPE (object_class),
144                               G_SIGNAL_RUN_LAST,
145                               G_STRUCT_OFFSET (glLabelObjectClass, top),
146                               NULL, NULL,
147                               gl_marshal_VOID__VOID,
148                               G_TYPE_NONE,
149                               0);
150
151         signals[BOTTOM] =
152                 g_signal_new ("bottom",
153                               G_OBJECT_CLASS_TYPE (object_class),
154                               G_SIGNAL_RUN_LAST,
155                               G_STRUCT_OFFSET (glLabelObjectClass, bottom),
156                               NULL, NULL,
157                               gl_marshal_VOID__VOID,
158                               G_TYPE_NONE,
159                               0);
160
161         gl_debug (DEBUG_LABEL, "END");
162 }
163
164 static void
165 gl_label_object_instance_init (glLabelObject *object)
166 {
167         gl_debug (DEBUG_LABEL, "START");
168
169         object->private = g_new0 (glLabelObjectPrivate, 1);
170
171         object->private->name = g_strdup_printf ("object%d", instance++);
172
173         art_affine_identity (object->private->affine);
174
175         gl_debug (DEBUG_LABEL, "END");
176 }
177
178 static void
179 gl_label_object_finalize (GObject *object)
180 {
181         glLabel       *parent;
182
183         gl_debug (DEBUG_LABEL, "START");
184
185         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
186
187         parent = GL_LABEL_OBJECT(object)->parent;
188         gl_label_remove_object (parent, GL_LABEL_OBJECT(object));
189
190         g_free (GL_LABEL_OBJECT(object)->private);
191
192         G_OBJECT_CLASS (parent_class)->finalize (object);
193
194         gl_debug (DEBUG_LABEL, "END");
195 }
196
197 /*****************************************************************************/
198 /* New label object.                                                         */
199 /*****************************************************************************/
200 GObject *
201 gl_label_object_new (glLabel *label)
202 {
203         glLabelObject *object;
204
205         gl_debug (DEBUG_LABEL, "START");
206
207         object = g_object_new (gl_label_object_get_type(), NULL);
208
209         gl_label_object_set_parent (object, label);
210
211         gl_debug (DEBUG_LABEL, "END");
212
213         return G_OBJECT (object);
214 }
215
216 /*****************************************************************************/
217 /* Copy properties of one label object to another.                           */
218 /*****************************************************************************/
219 void
220 gl_label_object_copy_props (glLabelObject *dst_object,
221                             glLabelObject *src_object)
222 {
223         gdouble           x, y, w, h;
224         gdouble           affine[6];
225
226         g_return_if_fail (src_object && GL_IS_LABEL_OBJECT (src_object));
227         g_return_if_fail (dst_object && GL_IS_LABEL_OBJECT (dst_object));
228
229         gl_label_object_get_position (src_object, &x, &y);
230         gl_label_object_get_size     (src_object, &w, &h);
231         gl_label_object_get_affine   (src_object, affine);
232
233         gl_label_object_set_position (dst_object, x, y);
234         gl_label_object_set_size     (dst_object, w, h);
235         gl_label_object_set_affine   (dst_object, affine);
236 }
237
238 /*****************************************************************************/
239 /* Emit "changed" signal (for derived objects).                              */
240 /*****************************************************************************/
241 void
242 gl_label_object_emit_changed (glLabelObject *object)
243 {
244         gl_debug (DEBUG_LABEL, "START");
245
246         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
247
248         g_signal_emit (G_OBJECT(object), signals[CHANGED], 0);
249
250         gl_debug (DEBUG_LABEL, "END");
251 }
252
253 /*****************************************************************************/
254 /* Set parent label of object.                                               */
255 /*****************************************************************************/
256 void
257 gl_label_object_set_parent (glLabelObject *object,
258                             glLabel       *label)
259 {
260         glLabel *old_parent;
261
262         gl_debug (DEBUG_LABEL, "START");
263
264         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
265         g_return_if_fail (label && GL_IS_LABEL (label));
266
267         old_parent = object->parent;
268         if ( old_parent != NULL ) {
269                 g_signal_handlers_disconnect_by_func (old_parent,
270                                                       G_CALLBACK(merge_changed_cb),
271                                                       object);
272                 gl_label_remove_object( old_parent, object );
273         }
274         gl_label_add_object( label, object );
275
276         g_signal_connect (G_OBJECT(label), "merge_changed",
277                           G_CALLBACK(merge_changed_cb), object);
278
279         g_signal_emit (G_OBJECT(object), signals[CHANGED], 0);
280
281         gl_debug (DEBUG_LABEL, "END");
282 }
283
284 /*****************************************************************************/
285 /* Get parent label of object.                                               */
286 /*****************************************************************************/
287 glLabel *
288 gl_label_object_get_parent (glLabelObject *object)
289 {
290         gl_debug (DEBUG_LABEL, "START");
291
292         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
293
294         gl_debug (DEBUG_LABEL, "END");
295
296         return object->parent;
297 }
298
299 /*****************************************************************************/
300 /* Set name of object.                                                       */
301 /*****************************************************************************/
302 void
303 gl_label_object_set_name (glLabelObject *object,
304                           gchar         *name)
305 {
306         gl_debug (DEBUG_LABEL, "START");
307
308         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
309
310         g_free(object->private->name);
311         object->private->name = name;
312
313         g_signal_emit (G_OBJECT(object), signals[CHANGED], 0);
314
315         gl_debug (DEBUG_LABEL, "END");
316 }
317
318 /*****************************************************************************/
319 /* Get name of object.                                                       */
320 /*****************************************************************************/
321 gchar *
322 gl_label_object_get_name (glLabelObject *object)
323 {
324         gl_debug (DEBUG_LABEL, "START");
325
326         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
327
328         gl_debug (DEBUG_LABEL, "END");
329
330         return g_strdup(object->private->name);
331 }
332
333 /*****************************************************************************/
334 /* Set position of object.                                                   */
335 /*****************************************************************************/
336 void
337 gl_label_object_set_position (glLabelObject *object,
338                               gdouble        x,
339                               gdouble        y)
340 {
341         gdouble dx, dy;
342
343         gl_debug (DEBUG_LABEL, "START");
344
345         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
346
347         dx = x - object->private->x;
348         dy = y - object->private->y;
349
350         object->private->x = x;
351         object->private->y = y;
352
353         g_signal_emit (G_OBJECT(object), signals[MOVED], 0, dx, dy);
354
355         gl_debug (DEBUG_LABEL, "END");
356 }
357
358 /*****************************************************************************/
359 /* Set position of object relative to old position.                          */
360 /*****************************************************************************/
361 void
362 gl_label_object_set_position_relative (glLabelObject *object,
363                                        gdouble        dx,
364                                        gdouble        dy)
365 {
366         gl_debug (DEBUG_LABEL, "START");
367
368         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
369
370         object->private->x += dx;
371         object->private->y += dy;
372
373         gl_debug (DEBUG_LABEL, "       x = %f, y= %f",
374                   object->private->x,
375                   object->private->y);
376
377         g_signal_emit (G_OBJECT(object), signals[MOVED], 0, dx, dy);
378
379         gl_debug (DEBUG_LABEL, "END");
380 }
381
382 /*****************************************************************************/
383 /* Get position of object.                                                   */
384 /*****************************************************************************/
385 void
386 gl_label_object_get_position (glLabelObject *object,
387                               gdouble       *x,
388                               gdouble       *y)
389 {
390         gl_debug (DEBUG_LABEL, "START");
391
392         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
393
394         *x = object->private->x;
395         *y = object->private->y;
396
397         gl_debug (DEBUG_LABEL, "END");
398 }
399
400 /*****************************************************************************/
401 /* Set size of object.                                                       */
402 /*****************************************************************************/
403 void
404 gl_label_object_set_size (glLabelObject *object,
405                           gdouble        w,
406                           gdouble        h)
407 {
408         gl_debug (DEBUG_LABEL, "START");
409
410         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
411
412         object->private->w = w;
413         object->private->h = h;
414
415         g_signal_emit (G_OBJECT(object), signals[CHANGED], 0);
416
417         gl_debug (DEBUG_LABEL, "END");
418 }
419
420 /*****************************************************************************/
421 /* Get size of object.                                                       */
422 /*****************************************************************************/
423 void
424 gl_label_object_get_size (glLabelObject *object,
425                           gdouble       *w,
426                           gdouble       *h)
427 {
428         gl_debug (DEBUG_LABEL, "START");
429
430         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
431
432         *w = object->private->w;
433         *h = object->private->h;
434
435         gl_debug (DEBUG_LABEL, "END");
436 }
437
438 /*****************************************************************************/
439 /* Get extent of object.                                                     */
440 /*****************************************************************************/
441 void
442 gl_label_object_get_extent (glLabelObject *object,
443                             gdouble       *x1,
444                             gdouble       *y1,
445                             gdouble       *x2,
446                             gdouble       *y2)
447 {
448         ArtPoint a1, a2, a3, a4, b1, b2, b3, b4;
449         gdouble  affine[6];
450
451         gl_debug (DEBUG_LABEL, "START");
452
453         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
454
455         /* setup untransformed corners of bounding box */
456         a1.x = 0.0;
457         a1.y = 0.0;
458         a2.x = object->private->w;
459         a2.y = 0.0;
460         a3.x = object->private->w;
461         a3.y = object->private->h;
462         a4.x = 0.0;
463         a4.y = object->private->h;
464
465         /* transform these points */
466         gl_label_object_get_applied_affine (object, affine);
467         art_affine_point (&b1, &a1, affine);
468         art_affine_point (&b2, &a2, affine);
469         art_affine_point (&b3, &a3, affine);
470         art_affine_point (&b4, &a4, affine);
471
472         /* now find the maximum extent of these points in x and y */
473         *x1 = MIN (b1.x, MIN (b2.x, MIN (b3.x, b4.x))) + object->private->x;
474         *y1 = MIN (b1.y, MIN (b2.y, MIN (b3.y, b4.y))) + object->private->y;
475         *x2 = MAX (b1.x, MAX (b2.x, MAX (b3.x, b4.x))) + object->private->x;
476         *y2 = MAX (b1.y, MAX (b2.y, MAX (b3.y, b4.y))) + object->private->y;
477         
478         gl_debug (DEBUG_LABEL, "END");
479 }
480
481 /****************************************************************************/
482 /* Flip object horizontally.                                                */
483 /****************************************************************************/
484 void
485 gl_label_object_flip_horiz (glLabelObject *object)
486 {
487         gl_debug (DEBUG_LABEL, "START");
488
489         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
490
491         art_affine_flip (object->private->affine, object->private->affine, TRUE, FALSE);
492
493         g_signal_emit (G_OBJECT(object), signals[FLIP_ROTATE], 0);
494
495         gl_debug (DEBUG_LABEL, "END");
496 }
497
498 /****************************************************************************/
499 /* Flip object vertically.                                                  */
500 /****************************************************************************/
501 void
502 gl_label_object_flip_vert (glLabelObject *object)
503 {
504         gl_debug (DEBUG_LABEL, "START");
505
506         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
507
508         art_affine_flip (object->private->affine, object->private->affine, FALSE, TRUE);
509
510         g_signal_emit (G_OBJECT(object), signals[FLIP_ROTATE], 0);
511
512         gl_debug (DEBUG_LABEL, "END");
513 }
514
515 /****************************************************************************/
516 /* Rotate object.                                                           */
517 /****************************************************************************/
518 void
519 gl_label_object_rotate (glLabelObject *object,
520                         gdouble        theta_degs)
521 {
522         gdouble rotate_affine[6];
523
524         gl_debug (DEBUG_LABEL, "START");
525
526         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
527
528         art_affine_rotate (rotate_affine, theta_degs);
529         art_affine_multiply (object->private->affine, object->private->affine, rotate_affine);
530
531         g_signal_emit (G_OBJECT(object), signals[FLIP_ROTATE], 0);
532
533         gl_debug (DEBUG_LABEL, "END");
534 }
535
536 /****************************************************************************/
537 /* Set raw affine                                                           */
538 /****************************************************************************/
539 void
540 gl_label_object_set_affine (glLabelObject *object,
541                             gdouble        affine[6])
542 {
543         gl_debug (DEBUG_LABEL, "");
544
545         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
546
547         object->private->affine[0] = affine[0];
548         object->private->affine[1] = affine[1];
549         object->private->affine[2] = affine[2];
550         object->private->affine[3] = affine[3];
551         object->private->affine[4] = affine[4];
552         object->private->affine[5] = affine[5];
553 }
554
555 /****************************************************************************/
556 /* Get raw affine                                                           */
557 /****************************************************************************/
558 void
559 gl_label_object_get_affine (glLabelObject *object,
560                             gdouble        affine[6])
561 {
562         gl_debug (DEBUG_LABEL, "");
563
564         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
565
566         affine[0] = object->private->affine[0];
567         affine[1] = object->private->affine[1];
568         affine[2] = object->private->affine[2];
569         affine[3] = object->private->affine[3];
570         affine[4] = object->private->affine[4];
571         affine[5] = object->private->affine[5];
572 }
573
574 /****************************************************************************/
575 /* Get applied affine, i.e. translated to center of object and back         */
576 /****************************************************************************/
577 void
578 gl_label_object_get_applied_affine (glLabelObject *object,
579                                     gdouble        affine[6])
580 {
581         gdouble to_center[6], to_origin[6];
582
583         gl_debug (DEBUG_LABEL, "");
584
585         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
586
587         /* setup transformation affine */
588         art_affine_translate (to_center, -object->private->w/2.0, -object->private->h/2.0);
589         art_affine_multiply (affine, to_center, object->private->affine);
590         art_affine_translate (to_origin, object->private->w/2.0, object->private->h/2.0);
591         art_affine_multiply (affine, affine, to_origin);
592 }
593
594 /****************************************************************************/
595 /* Bring label object to front/top.                                         */
596 /****************************************************************************/
597 void
598 gl_label_object_raise_to_top (glLabelObject *object)
599 {
600         glLabel *label;
601
602         gl_debug (DEBUG_LABEL, "START");
603
604         label = object->parent;
605
606         gl_label_raise_object_to_top (label, object);
607
608         g_signal_emit (G_OBJECT(object), signals[TOP], 0);
609
610         gl_debug (DEBUG_LABEL, "END");
611 }
612
613 /****************************************************************************/
614 /* Send label object to rear/bottom.                                        */
615 /****************************************************************************/
616 void
617 gl_label_object_lower_to_bottom (glLabelObject *object)
618 {
619         glLabel *label;
620
621         gl_debug (DEBUG_LABEL, "START");
622
623         label = object->parent;
624
625         gl_label_lower_object_to_bottom (label, object);
626
627         g_signal_emit (G_OBJECT(object), signals[BOTTOM], 0);
628
629         gl_debug (DEBUG_LABEL, "END");
630 }
631
632 /*--------------------------------------------------------------------------*/
633 /* PRIVATE.  Label's merge data changed callback.                           */
634 /*--------------------------------------------------------------------------*/
635 static void
636 merge_changed_cb (glLabel       *label,
637                   glLabelObject *object)
638 {
639         gl_label_object_emit_changed (object);
640 }
641