]> git.sur5r.net Git - glabels/blob - glabels2/src/label.c
4a6d9f3c36d7f291de544951cb2ed3c625cd0792
[glabels] / glabels2 / src / label.c
1 /*
2  *  label.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.h"
24
25 #include <glib/gi18n.h>
26
27 #include "prefs.h"
28 #include "util.h"
29 #include "marshal.h"
30
31 #include "debug.h"
32
33
34 /*========================================================*/
35 /* Private macros and constants.                          */
36 /*========================================================*/
37
38
39 /*========================================================*/
40 /* Private types.                                         */
41 /*========================================================*/
42
43 struct _glLabelPrivate {
44
45         gchar       *filename;
46         gint         compression;
47         gboolean     modified_flag;
48         gint         untitled_instance;
49
50         glMerge     *merge;
51
52         GHashTable  *pixbuf_cache;
53 };
54
55 enum {
56         CHANGED,
57         NAME_CHANGED,
58         MODIFIED_CHANGED,
59         MERGE_CHANGED,
60         SIZE_CHANGED,
61         OBJECT_ADDED,
62         LAST_SIGNAL
63 };
64
65
66 /*========================================================*/
67 /* Private globals.                                       */
68 /*========================================================*/
69
70 static guint signals[LAST_SIGNAL] = {0};
71
72 static guint untitled = 0;
73
74
75 /*========================================================*/
76 /* Private function prototypes.                           */
77 /*========================================================*/
78
79 static void gl_label_finalize      (GObject *object);
80
81 static void object_changed_cb      (glLabelObject *object,
82                                     glLabel       *label);
83
84 static void object_moved_cb        (glLabelObject *object,
85                                     gdouble        x,
86                                     gdouble        y,
87                                     glLabel       *label);
88
89
90 /*****************************************************************************/
91 /* Boilerplate object stuff.                                                 */
92 /*****************************************************************************/
93 G_DEFINE_TYPE (glLabel, gl_label, G_TYPE_OBJECT);
94
95
96 static void
97 gl_label_class_init (glLabelClass *class)
98 {
99         GObjectClass *object_class = G_OBJECT_CLASS (class);
100
101         gl_debug (DEBUG_LABEL, "START");
102
103         gl_label_parent_class = g_type_class_peek_parent (class);
104
105         object_class->finalize = gl_label_finalize;
106
107         signals[CHANGED] =
108                 g_signal_new ("changed",
109                               G_OBJECT_CLASS_TYPE (object_class),
110                               G_SIGNAL_RUN_LAST,
111                               G_STRUCT_OFFSET (glLabelClass, changed),
112                               NULL, NULL,
113                               gl_marshal_VOID__VOID,
114                               G_TYPE_NONE,
115                               0);
116         signals[NAME_CHANGED] =
117                 g_signal_new ("name_changed",
118                               G_OBJECT_CLASS_TYPE (object_class),
119                               G_SIGNAL_RUN_LAST,
120                               G_STRUCT_OFFSET (glLabelClass, name_changed),
121                               NULL, NULL,
122                               gl_marshal_VOID__VOID,
123                               G_TYPE_NONE,
124                               0);
125         signals[MODIFIED_CHANGED] =
126                 g_signal_new ("modified_changed",
127                               G_OBJECT_CLASS_TYPE (object_class),
128                               G_SIGNAL_RUN_LAST,
129                               G_STRUCT_OFFSET (glLabelClass, modified_changed),
130                               NULL, NULL,
131                               gl_marshal_VOID__VOID,
132                               G_TYPE_NONE,
133                               0);
134         signals[MERGE_CHANGED] =
135                 g_signal_new ("merge_changed",
136                               G_OBJECT_CLASS_TYPE (object_class),
137                               G_SIGNAL_RUN_LAST,
138                               G_STRUCT_OFFSET (glLabelClass, merge_changed),
139                               NULL, NULL,
140                               gl_marshal_VOID__VOID,
141                               G_TYPE_NONE,
142                               0);
143         signals[SIZE_CHANGED] =
144                 g_signal_new ("size_changed",
145                               G_OBJECT_CLASS_TYPE (object_class),
146                               G_SIGNAL_RUN_LAST,
147                               G_STRUCT_OFFSET (glLabelClass, size_changed),
148                               NULL, NULL,
149                               gl_marshal_VOID__VOID,
150                               G_TYPE_NONE,
151                               0);
152         signals[OBJECT_ADDED] =
153                 g_signal_new ("object_added",
154                               G_OBJECT_CLASS_TYPE (object_class),
155                               G_SIGNAL_RUN_LAST,
156                               G_STRUCT_OFFSET (glLabelClass, object_added),
157                               NULL, NULL,
158                               gl_marshal_VOID__OBJECT,
159                               G_TYPE_NONE,
160                               1, G_TYPE_OBJECT);
161
162         gl_debug (DEBUG_LABEL, "END");
163 }
164
165
166 static void
167 gl_label_init (glLabel *label)
168 {
169         gl_debug (DEBUG_LABEL, "START");
170
171         label->template     = NULL;
172         label->rotate_flag  = FALSE;
173         label->objects      = NULL;
174
175         label->priv = g_new0 (glLabelPrivate, 1);
176
177         label->priv->filename     = NULL;
178         label->priv->merge        = NULL;
179         label->priv->pixbuf_cache = gl_pixbuf_cache_new ();
180
181         gl_debug (DEBUG_LABEL, "END");
182 }
183
184
185 static void
186 gl_label_finalize (GObject *object)
187 {
188         glLabel *label = GL_LABEL (object);
189         GList   *p, *p_next;
190
191         gl_debug (DEBUG_LABEL, "START");
192
193         g_return_if_fail (object && GL_IS_LABEL (object));
194
195         for (p = label->objects; p != NULL; p = p_next) {
196                 p_next = p->next;       /* NOTE: p will be left dangling */
197                 g_object_unref (G_OBJECT(p->data));
198         }
199
200         lgl_template_free (label->template);
201         g_free (label->priv->filename);
202         if (label->priv->merge != NULL) {
203                 g_object_unref (G_OBJECT(label->priv->merge));
204         }
205         gl_pixbuf_cache_free (label->priv->pixbuf_cache);
206
207         g_free (label->priv);
208
209         G_OBJECT_CLASS (gl_label_parent_class)->finalize (object);
210
211         gl_debug (DEBUG_LABEL, "END");
212 }
213
214
215 GObject *
216 gl_label_new (void)
217 {
218         glLabel *label;
219
220         gl_debug (DEBUG_LABEL, "START");
221
222         label = g_object_new (gl_label_get_type(), NULL);
223
224         label->priv->compression = 9;
225
226         label->priv->modified_flag = FALSE;
227
228         gl_debug (DEBUG_LABEL, "END");
229
230         return G_OBJECT (label);
231 }
232
233
234 /*****************************************************************************/
235 /* Add object to label.                                                      */
236 /*****************************************************************************/
237 void
238 gl_label_add_object (glLabel       *label,
239                      glLabelObject *object)
240 {
241         gl_debug (DEBUG_LABEL, "START");
242
243         g_return_if_fail (label && GL_IS_LABEL (label));
244         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
245
246         object->parent = label;
247         label->objects = g_list_append (label->objects, g_object_ref (object));
248
249         label->priv->modified_flag = TRUE;
250
251         g_signal_emit (G_OBJECT(label), signals[OBJECT_ADDED], 0, object);
252         g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
253         g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
254
255         g_signal_connect (G_OBJECT(object), "changed",
256                           G_CALLBACK(object_changed_cb), label);
257
258         g_signal_connect (G_OBJECT(object), "moved",
259                           G_CALLBACK(object_moved_cb), label);
260
261         gl_debug (DEBUG_LABEL, "END");
262 }
263
264
265 /*****************************************************************************/
266 /* Remove object from label.                                                 */
267 /*****************************************************************************/
268 void
269 gl_label_remove_object (glLabel       *label,
270                         glLabelObject *object)
271 {
272         gl_debug (DEBUG_LABEL, "START");
273
274         g_return_if_fail (label && GL_IS_LABEL (label));
275         g_return_if_fail (GL_IS_LABEL_OBJECT (object));
276
277         object->parent = NULL;
278         label->objects = g_list_remove (label->objects, object);
279
280         if ( G_OBJECT(label)->ref_count /* not finalized */ ) {
281
282                 g_signal_handlers_disconnect_by_func (object,
283                                                       G_CALLBACK(object_changed_cb),
284                                                       label);
285                 g_signal_handlers_disconnect_by_func (object,
286                                                       G_CALLBACK(object_moved_cb),
287                                                       label);
288
289                 label->priv->modified_flag = TRUE;
290
291                 g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
292                 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
293
294         }
295
296         gl_debug (DEBUG_LABEL, "END");
297 }
298
299
300 /*---------------------------------------------------------------------------*/
301 /* PRIVATE.  Object changed callback.                                        */
302 /*---------------------------------------------------------------------------*/
303 static void
304 object_changed_cb (glLabelObject *object,
305                    glLabel       *label)
306 {
307
308         if ( !label->priv->modified_flag ) {
309
310                 label->priv->modified_flag = TRUE;
311
312                 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
313         }
314
315         g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
316 }
317
318
319 /*---------------------------------------------------------------------------*/
320 /* PRIVATE.  Object moved callback.                                          */
321 /*---------------------------------------------------------------------------*/
322 static void
323 object_moved_cb (glLabelObject *object,
324                  gdouble        x,
325                  gdouble        y,
326                  glLabel       *label)
327 {
328
329         if ( !label->priv->modified_flag ) {
330
331                 label->priv->modified_flag = TRUE;
332
333                 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
334         }
335
336         g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
337 }
338
339
340 /****************************************************************************/
341 /* Bring label object to front/top.                                         */
342 /****************************************************************************/
343 void
344 gl_label_raise_object_to_top (glLabel       *label,
345                               glLabelObject *object)
346 {
347         gl_debug (DEBUG_LABEL, "START");
348
349         /* Move to end of list, representing front most object */
350         label->objects = g_list_remove (label->objects, object);
351         label->objects = g_list_append (label->objects, object);
352
353         label->priv->modified_flag = TRUE;
354
355         g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
356         g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
357
358         gl_debug (DEBUG_LABEL, "END");
359 }
360
361
362 /****************************************************************************/
363 /* Send label object to rear/bottom.                                        */
364 /****************************************************************************/
365 void
366 gl_label_lower_object_to_bottom (glLabel       *label,
367                                  glLabelObject *object)
368 {
369         gl_debug (DEBUG_LABEL, "START");
370
371         /* Move to front of list, representing rear most object */
372         label->objects = g_list_remove (label->objects, object);
373         label->objects = g_list_prepend (label->objects, object);
374
375         label->priv->modified_flag = TRUE;
376
377         g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
378         g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
379
380         gl_debug (DEBUG_LABEL, "END");
381 }
382
383
384 /****************************************************************************/
385 /* set template.                                                            */
386 /****************************************************************************/
387 extern void
388 gl_label_set_template (glLabel     *label,
389                        lglTemplate *template)
390 {
391         gchar *name;
392
393         gl_debug (DEBUG_LABEL, "START");
394
395         g_return_if_fail (label && GL_IS_LABEL (label));
396         g_return_if_fail (template);
397
398         if ((label->template == NULL) ||
399             !lgl_template_do_templates_match (template, label->template)) {
400
401                 lgl_template_free (label->template);
402                 label->template = lgl_template_dup (template);
403
404                 label->priv->modified_flag = TRUE;
405
406                 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
407                 g_signal_emit (G_OBJECT(label), signals[SIZE_CHANGED], 0);
408                 g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
409
410                 name = lgl_template_get_name (template);
411                 gl_prefs_add_recent_template (name);
412                 g_free (name);
413         }
414
415         gl_debug (DEBUG_LABEL, "END");
416 }
417
418
419 /****************************************************************************/
420 /* set rotate flag.                                                         */
421 /****************************************************************************/
422 extern void
423 gl_label_set_rotate_flag (glLabel *label,
424                           gboolean rotate_flag)
425 {
426         gl_debug (DEBUG_LABEL, "START");
427
428         g_return_if_fail (label && GL_IS_LABEL (label));
429
430         if (rotate_flag != label->rotate_flag) {
431
432                 label->rotate_flag = rotate_flag;
433
434                 label->priv->modified_flag = TRUE;
435
436                 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
437                 g_signal_emit (G_OBJECT(label), signals[SIZE_CHANGED], 0);
438                 g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
439
440         }
441
442         gl_debug (DEBUG_LABEL, "END");
443 }
444
445
446 /****************************************************************************/
447 /* Get label size.                                                          */
448 /****************************************************************************/
449 void
450 gl_label_get_size (glLabel *label,
451                    gdouble *w,
452                    gdouble *h)
453 {
454         lglTemplate            *template;
455         const lglTemplateFrame *frame;
456
457         gl_debug (DEBUG_LABEL, "START");
458
459         g_return_if_fail (label && GL_IS_LABEL (label));
460
461         template = label->template;
462         if ( !template ) {
463                 gl_debug (DEBUG_LABEL, "END -- template NULL");
464                 *w = *h = 0;
465                 return;
466         }
467         frame = (lglTemplateFrame *)template->frames->data;
468
469         if (!label->rotate_flag) {
470                 lgl_template_frame_get_size (frame, w, h);
471         } else {
472                 lgl_template_frame_get_size (frame, h, w);
473         }
474
475         gl_debug (DEBUG_LABEL, "END");
476 }
477
478
479 /****************************************************************************/
480 /* set merge information structure.                                         */
481 /****************************************************************************/
482 extern void
483 gl_label_set_merge (glLabel *label,
484                     glMerge *merge)
485 {
486         gl_debug (DEBUG_LABEL, "START");
487
488         g_return_if_fail (label && GL_IS_LABEL (label));
489
490         if ( label->priv->merge != NULL ) {
491                 g_object_unref (G_OBJECT(label->priv->merge));
492         }
493         label->priv->merge = gl_merge_dup (merge);
494
495         label->priv->modified_flag = TRUE;
496
497         g_signal_emit (G_OBJECT(label), signals[MERGE_CHANGED], 0);
498         g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
499         g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
500
501         gl_debug (DEBUG_LABEL, "END");
502 }
503
504
505 /****************************************************************************/
506 /* Get merge information structure.                                         */
507 /****************************************************************************/
508 glMerge *
509 gl_label_get_merge (glLabel *label)
510 {
511         gl_debug (DEBUG_LABEL, "START");
512
513         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
514
515         gl_debug (DEBUG_LABEL, "END");
516
517         return gl_merge_dup (label->priv->merge);
518 }
519
520
521 /****************************************************************************/
522 /* return filename.                                                         */
523 /****************************************************************************/
524 gchar *
525 gl_label_get_filename (glLabel *label)
526 {
527         gl_debug (DEBUG_LABEL, "");
528
529         return g_strdup ( label->priv->filename );
530 }
531
532
533 /****************************************************************************/
534 /* return short filename.                                                   */
535 /****************************************************************************/
536 gchar *
537 gl_label_get_short_name (glLabel *label)
538 {
539         gl_debug (DEBUG_LABEL, "");
540
541         if ( label->priv->filename == NULL ) {
542
543                 if ( label->priv->untitled_instance == 0 ) {
544                         label->priv->untitled_instance = ++untitled;
545                 }
546
547                 return g_strdup_printf ( "%s %d", _("Untitled"),
548                                          label->priv->untitled_instance );
549
550         } else {
551                 gchar *temp_name, *short_name;
552
553                 temp_name = g_path_get_basename ( label->priv->filename );
554                 short_name = gl_util_remove_extension (temp_name);
555                 g_free (temp_name);
556
557                 return short_name;
558         }
559 }
560
561
562 /****************************************************************************/
563 /* Get pixbuf cache.                                                        */
564 /****************************************************************************/
565 GHashTable *
566 gl_label_get_pixbuf_cache (glLabel       *label)
567 {
568         return label->priv->pixbuf_cache;
569 }
570
571
572 /****************************************************************************/
573 /* Is label modified?                                                       */
574 /****************************************************************************/
575 gboolean
576 gl_label_is_modified (glLabel *label)
577 {
578         gl_debug (DEBUG_LABEL, "return %d", label->priv->modified_flag);
579         return label->priv->modified_flag;
580 }
581
582
583 /****************************************************************************/
584 /* Is label untitled?                                                       */
585 /****************************************************************************/
586 gboolean
587 gl_label_is_untitled (glLabel *label)
588 {
589         gl_debug (DEBUG_LABEL, "return %d",(label->priv->filename == NULL));
590         return (label->priv->filename == NULL);
591 }
592
593
594 /****************************************************************************/
595 /* Can undo?                                                                */
596 /****************************************************************************/
597 gboolean
598 gl_label_can_undo (glLabel *label)
599 {
600         return FALSE;
601 }
602
603
604 /****************************************************************************/
605 /* Can redo?                                                                */
606 /****************************************************************************/
607 gboolean
608 gl_label_can_redo (glLabel *label)
609 {
610         return FALSE;
611 }
612
613
614 /****************************************************************************/
615 /* Set filename.                                                            */
616 /****************************************************************************/
617 void
618 gl_label_set_filename (glLabel     *label,
619                        const gchar *filename)
620 {
621         label->priv->filename = g_strdup (filename);
622
623         g_signal_emit (G_OBJECT(label), signals[NAME_CHANGED], 0);
624 }
625
626
627 /****************************************************************************/
628 /* Clear modified flag.                                                     */
629 /****************************************************************************/
630 void
631 gl_label_clear_modified (glLabel *label)
632 {
633
634         if ( label->priv->modified_flag ) {
635
636                 label->priv->modified_flag = FALSE;
637
638                 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
639         }
640
641 }
642
643
644 /****************************************************************************/
645 /* Set compression level.                                                   */
646 /****************************************************************************/
647 void
648 gl_label_set_compression (glLabel  *label,
649                           gint      compression)
650 {
651         gl_debug (DEBUG_LABEL, "set %d", compression);
652
653         /* Older versions of libxml2 always return a -1 for documents "read in," so
654          * default to 9.  Also, default to 9 for anything else out of range. */
655         if ((compression < 0) || (compression >9)) {
656                 compression = 9;
657         }
658
659         gl_debug (DEBUG_LABEL, "actual set %d", compression);
660         label->priv->compression = compression;
661 }
662
663
664 /****************************************************************************/
665 /* Get compression level.                                                   */
666 /****************************************************************************/
667 gint
668 gl_label_get_compression (glLabel *label)
669 {
670         gl_debug (DEBUG_LABEL, "return %d", label->priv->compression);
671         return label->priv->compression;
672 }
673
674
675 /****************************************************************************/
676 /* Draw label.                                                              */
677 /****************************************************************************/
678 void
679 gl_label_draw (glLabel       *label,
680                cairo_t       *cr,
681                gboolean       screen_flag,
682                glMergeRecord *record)
683 {
684         GList            *p_obj;
685         glLabelObject    *object;
686
687         g_return_if_fail (label && GL_IS_LABEL (label));
688
689         for (p_obj = label->objects; p_obj != NULL; p_obj = p_obj->next)
690         {
691                 object = GL_LABEL_OBJECT (p_obj->data);
692
693                 gl_label_object_draw (object, cr, screen_flag, record);
694         }
695 }
696
697
698
699
700 /*
701  * Local Variables:       -- emacs
702  * mode: C                -- emacs
703  * c-basic-offset: 8      -- emacs
704  * tab-width: 8           -- emacs
705  * indent-tabs-mode: nil  -- emacs
706  * End:                   -- emacs
707  */