]> git.sur5r.net Git - glabels/blob - src/label.c
Encapsulate barcode style in single struct.
[glabels] / 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 #include <math.h>
27
28 #include "template-history.h"
29 #include "file-util.h"
30 #include "xml-label.h"
31 #include "prefs.h"
32 #include "label-text.h"
33 #include "label-image.h"
34 #include "marshal.h"
35
36 #include "debug.h"
37
38
39 /*========================================================*/
40 /* Private macros and constants.                          */
41 /*========================================================*/
42
43
44 /*========================================================*/
45 /* Private types.                                         */
46 /*========================================================*/
47
48 struct _glLabelPrivate {
49
50         gchar       *filename;
51         gint         compression;
52         gint         untitled_instance;
53
54         gboolean     modified_flag;
55         GTimeVal     time_stamp;
56
57         lglTemplate *template;
58         gboolean     rotate_flag;
59
60         GList       *object_list;
61
62         glMerge     *merge;
63
64         GHashTable  *pixbuf_cache;
65         GHashTable  *svg_cache;
66
67         /* Delay changed signals while operating on selections of multiple objects. */
68         gboolean     selection_op_flag;
69         gboolean     delayed_change_flag;
70
71         /* Default object text properties */
72         gchar             *default_font_family;
73         gdouble            default_font_size;
74         PangoWeight        default_font_weight;
75         gboolean           default_font_italic_flag;
76         guint              default_text_color;
77         PangoAlignment     default_text_alignment;
78         gdouble            default_text_line_spacing;
79
80         /* Default object line properties */
81         gdouble            default_line_width;
82         guint              default_line_color;
83         
84         /* Default object fill properties */
85         guint              default_fill_color;
86
87         /* Undo/Redo state */
88         GQueue      *undo_stack;
89         GQueue      *redo_stack;
90         gboolean     cp_cleared_flag;
91         gchar       *cp_desc;
92 };
93
94 typedef struct {
95         gchar             *xml_buffer;
96         gchar             *text;
97         GdkPixbuf         *pixbuf;
98 } ClipboardData;
99
100 enum {
101         SELECTION_CHANGED,
102         CHANGED,
103         NAME_CHANGED,
104         MODIFIED_CHANGED,
105         MERGE_CHANGED,
106         SIZE_CHANGED,
107         LAST_SIGNAL
108 };
109
110 typedef struct {
111         gchar       *description;
112
113         gboolean     modified_flag;
114         GTimeVal     time_stamp;
115
116         lglTemplate *template;
117         gboolean     rotate_flag;
118
119         GList       *object_list;
120
121         glMerge     *merge;
122
123 } State;
124
125
126 /*========================================================*/
127 /* Private globals.                                       */
128 /*========================================================*/
129
130 static guint signals[LAST_SIGNAL] = {0};
131
132 static guint untitled = 0;
133
134
135 /*========================================================*/
136 /* Private function prototypes.                           */
137 /*========================================================*/
138
139 static void gl_label_finalize      (GObject *object);
140
141 static void object_changed_cb      (glLabelObject *object,
142                                     glLabel       *label);
143
144 static void do_modify              (glLabel       *label);
145
146 static void begin_selection_op     (glLabel       *label);
147 static void end_selection_op       (glLabel       *label);
148
149 static void clipboard_get_cb       (GtkClipboard     *clipboard,
150                                     GtkSelectionData *selection_data,
151                                     guint             info,
152                                     ClipboardData    *data);
153
154 static void clipboard_clear_cb     (GtkClipboard     *clipboard,
155                                     ClipboardData    *data);
156
157 static void receive_targets_cb     (GtkClipboard     *clipboard,
158                                     GdkAtom          *targets,
159                                     gint              n_targets,
160                                     glLabel          *label);
161
162 static void paste_xml_received_cb  (GtkClipboard     *clipboard,
163                                     GtkSelectionData *selection_data,
164                                     glLabel          *label);
165
166 static void paste_text_received_cb (GtkClipboard     *clipboard,
167                                     const gchar      *text,
168                                     glLabel          *label);
169
170 static void paste_image_received_cb(GtkClipboard     *clipboard,
171                                     GdkPixbuf        *pixbuf,
172                                     glLabel          *label);
173
174 static void   stack_clear          (GQueue           *stack);
175 static void   stack_push_state     (GQueue           *stack,
176                                     State            *state);
177 static State *stack_pop_state      (GQueue           *stack);
178
179 static State *state_new            (glLabel          *this,
180                                     const gchar      *description);
181 static void   state_free           (State            *state);
182 static void   state_restore        (State            *state,
183                                     glLabel          *this);
184
185
186 /*****************************************************************************/
187 /* Boilerplate object stuff.                                                 */
188 /*****************************************************************************/
189 G_DEFINE_TYPE (glLabel, gl_label, G_TYPE_OBJECT);
190
191
192 static void
193 gl_label_class_init (glLabelClass *class)
194 {
195         GObjectClass *object_class = G_OBJECT_CLASS (class);
196
197         gl_debug (DEBUG_LABEL, "START");
198
199         gl_label_parent_class = g_type_class_peek_parent (class);
200
201         object_class->finalize = gl_label_finalize;
202
203         signals[SELECTION_CHANGED] =
204                 g_signal_new ("selection_changed",
205                               G_OBJECT_CLASS_TYPE (object_class),
206                               G_SIGNAL_RUN_LAST,
207                               G_STRUCT_OFFSET (glLabelClass, selection_changed),
208                               NULL, NULL,
209                               gl_marshal_VOID__VOID,
210                               G_TYPE_NONE,
211                               0);
212         signals[CHANGED] =
213                 g_signal_new ("changed",
214                               G_OBJECT_CLASS_TYPE (object_class),
215                               G_SIGNAL_RUN_LAST,
216                               G_STRUCT_OFFSET (glLabelClass, changed),
217                               NULL, NULL,
218                               gl_marshal_VOID__VOID,
219                               G_TYPE_NONE,
220                               0);
221         signals[NAME_CHANGED] =
222                 g_signal_new ("name_changed",
223                               G_OBJECT_CLASS_TYPE (object_class),
224                               G_SIGNAL_RUN_LAST,
225                               G_STRUCT_OFFSET (glLabelClass, name_changed),
226                               NULL, NULL,
227                               gl_marshal_VOID__VOID,
228                               G_TYPE_NONE,
229                               0);
230         signals[MODIFIED_CHANGED] =
231                 g_signal_new ("modified_changed",
232                               G_OBJECT_CLASS_TYPE (object_class),
233                               G_SIGNAL_RUN_LAST,
234                               G_STRUCT_OFFSET (glLabelClass, modified_changed),
235                               NULL, NULL,
236                               gl_marshal_VOID__VOID,
237                               G_TYPE_NONE,
238                               0);
239         signals[MERGE_CHANGED] =
240                 g_signal_new ("merge_changed",
241                               G_OBJECT_CLASS_TYPE (object_class),
242                               G_SIGNAL_RUN_LAST,
243                               G_STRUCT_OFFSET (glLabelClass, merge_changed),
244                               NULL, NULL,
245                               gl_marshal_VOID__VOID,
246                               G_TYPE_NONE,
247                               0);
248         signals[SIZE_CHANGED] =
249                 g_signal_new ("size_changed",
250                               G_OBJECT_CLASS_TYPE (object_class),
251                               G_SIGNAL_RUN_LAST,
252                               G_STRUCT_OFFSET (glLabelClass, size_changed),
253                               NULL, NULL,
254                               gl_marshal_VOID__VOID,
255                               G_TYPE_NONE,
256                               0);
257
258         gl_debug (DEBUG_LABEL, "END");
259 }
260
261
262 static void
263 gl_label_init (glLabel *label)
264 {
265         gl_debug (DEBUG_LABEL, "START");
266
267         label->priv = g_new0 (glLabelPrivate, 1);
268
269         label->priv->template      = NULL;
270         label->priv->rotate_flag   = FALSE;
271         label->priv->object_list   = NULL;
272
273         label->priv->filename      = NULL;
274         label->priv->modified_flag = FALSE;
275         label->priv->compression   = 9;
276
277         label->priv->merge         = NULL;
278         label->priv->pixbuf_cache  = gl_pixbuf_cache_new ();
279         label->priv->svg_cache     = gl_svg_cache_new ();
280
281         label->priv->undo_stack    = g_queue_new ();
282         label->priv->redo_stack    = g_queue_new ();
283
284         /*
285          * Defaults from preferences
286          */
287         label->priv->default_font_family       = gl_prefs_model_get_default_font_family (gl_prefs);
288         label->priv->default_font_size         = gl_prefs_model_get_default_font_size (gl_prefs);
289         label->priv->default_font_weight       = gl_prefs_model_get_default_font_weight (gl_prefs);
290         label->priv->default_font_italic_flag  = gl_prefs_model_get_default_font_italic_flag (gl_prefs);
291         label->priv->default_text_color        = gl_prefs_model_get_default_text_color (gl_prefs);
292         label->priv->default_text_alignment    = gl_prefs_model_get_default_text_alignment (gl_prefs);
293         label->priv->default_text_line_spacing = gl_prefs_model_get_default_text_line_spacing (gl_prefs);
294         label->priv->default_line_width        = gl_prefs_model_get_default_line_width (gl_prefs);
295         label->priv->default_line_color        = gl_prefs_model_get_default_line_color (gl_prefs);
296         label->priv->default_fill_color        = gl_prefs_model_get_default_fill_color (gl_prefs);
297
298         gl_debug (DEBUG_LABEL, "END");
299 }
300
301
302 static void
303 gl_label_finalize (GObject *object)
304 {
305         glLabel *label = GL_LABEL (object);
306         GList   *p;
307
308         gl_debug (DEBUG_LABEL, "START");
309
310         g_return_if_fail (object && GL_IS_LABEL (object));
311
312         for (p = label->priv->object_list; p != NULL; p = p->next)
313         {
314                 g_object_unref (G_OBJECT(p->data));
315         }
316         g_list_free (label->priv->object_list);
317
318         lgl_template_free (label->priv->template);
319         g_free (label->priv->filename);
320         if (label->priv->merge != NULL)
321         {
322                 g_object_unref (G_OBJECT(label->priv->merge));
323         }
324         g_free (label->priv->default_font_family);
325
326         stack_clear (label->priv->undo_stack);
327         stack_clear (label->priv->redo_stack);
328
329         g_queue_free (label->priv->undo_stack);
330         g_queue_free (label->priv->redo_stack);
331
332         gl_pixbuf_cache_free (label->priv->pixbuf_cache);
333         gl_svg_cache_free (label->priv->svg_cache);
334
335         g_free (label->priv);
336
337         G_OBJECT_CLASS (gl_label_parent_class)->finalize (object);
338
339         gl_debug (DEBUG_LABEL, "END");
340 }
341
342
343 /*****************************************************************************/
344 /* New label.                                                                */
345 /*****************************************************************************/
346 GObject *
347 gl_label_new (void)
348 {
349         glLabel *label;
350
351         gl_debug (DEBUG_LABEL, "START");
352
353         label = g_object_new (gl_label_get_type(), NULL);
354
355         gl_debug (DEBUG_LABEL, "END");
356
357         return G_OBJECT (label);
358 }
359
360
361 /****************************************************************************/
362 /* Set filename.                                                            */
363 /****************************************************************************/
364 void
365 gl_label_set_filename (glLabel     *label,
366                        const gchar *filename)
367 {
368         label->priv->filename = g_strdup (filename);
369
370         g_signal_emit (G_OBJECT(label), signals[NAME_CHANGED], 0);
371 }
372
373
374 /****************************************************************************/
375 /* return filename.                                                         */
376 /****************************************************************************/
377 gchar *
378 gl_label_get_filename (glLabel *label)
379 {
380         gl_debug (DEBUG_LABEL, "");
381
382         return g_strdup ( label->priv->filename );
383 }
384
385
386 /****************************************************************************/
387 /* return short filename.                                                   */
388 /****************************************************************************/
389 gchar *
390 gl_label_get_short_name (glLabel *label)
391 {
392         gl_debug (DEBUG_LABEL, "");
393
394         if ( label->priv->filename == NULL )
395         {
396
397                 if ( label->priv->untitled_instance == 0 )
398                 {
399                         label->priv->untitled_instance = ++untitled;
400                 }
401
402                 return g_strdup_printf ( "%s %d", _("Untitled"),
403                                          label->priv->untitled_instance );
404
405         }
406         else
407         {
408                 gchar *temp_name, *short_name;
409
410                 temp_name = g_path_get_basename ( label->priv->filename );
411                 short_name = gl_file_util_remove_extension (temp_name);
412                 g_free (temp_name);
413
414                 return short_name;
415         }
416 }
417
418
419 /****************************************************************************/
420 /* Is label untitled?                                                       */
421 /****************************************************************************/
422 gboolean
423 gl_label_is_untitled (glLabel *label)
424 {
425         gl_debug (DEBUG_LABEL, "return %d",(label->priv->filename == NULL));
426         return (label->priv->filename == NULL);
427 }
428
429
430 /****************************************************************************/
431 /* Set compression level.                                                   */
432 /****************************************************************************/
433 void
434 gl_label_set_compression (glLabel  *label,
435                           gint      compression)
436 {
437         gl_debug (DEBUG_LABEL, "set %d", compression);
438
439         /* Older versions of libxml2 always return a -1 for documents "read in," so
440          * default to 9.  Also, default to 9 for anything else out of range. */
441         if ((compression < 0) || (compression >9))
442         {
443                 compression = 9;
444         }
445
446         gl_debug (DEBUG_LABEL, "actual set %d", compression);
447         label->priv->compression = compression;
448 }
449
450
451 /****************************************************************************/
452 /* Get compression level.                                                   */
453 /****************************************************************************/
454 gint
455 gl_label_get_compression (glLabel *label)
456 {
457         gl_debug (DEBUG_LABEL, "return %d", label->priv->compression);
458         return label->priv->compression;
459 }
460
461
462 /****************************************************************************/
463 /* Set modified flag.                                                       */
464 /****************************************************************************/
465 void
466 gl_label_set_modified (glLabel *label)
467 {
468
469         if ( !label->priv->modified_flag )
470         {
471
472                 label->priv->modified_flag = TRUE;
473
474                 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
475         }
476
477 }
478
479
480 /****************************************************************************/
481 /* Clear modified flag.                                                     */
482 /****************************************************************************/
483 void
484 gl_label_clear_modified (glLabel *label)
485 {
486
487         if ( label->priv->modified_flag )
488         {
489
490                 g_get_current_time (&label->priv->time_stamp);
491                 label->priv->modified_flag = FALSE;
492
493                 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
494         }
495
496 }
497
498
499 /****************************************************************************/
500 /* Is label modified?                                                       */
501 /****************************************************************************/
502 gboolean
503 gl_label_is_modified (glLabel *label)
504 {
505         gl_debug (DEBUG_LABEL, "return %d", label->priv->modified_flag);
506         return label->priv->modified_flag;
507 }
508
509
510 /****************************************************************************/
511 /* Object "changed" callback.                                               */
512 /****************************************************************************/
513 static void
514 object_changed_cb (glLabelObject *object,
515                    glLabel       *label)
516 {
517         do_modify (label);
518 }
519
520
521 /****************************************************************************/
522 /* Do modify.                                                               */
523 /****************************************************************************/
524 static void
525 do_modify (glLabel  *label)
526 {
527         if ( label->priv->selection_op_flag )
528         {
529                 label->priv->delayed_change_flag = TRUE;
530         }
531         else
532         {
533                 label->priv->modified_flag = TRUE;
534
535                 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
536                 g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
537         }
538 }
539
540
541 /****************************************************************************/
542 /* Begin selection operation.                                               */
543 /****************************************************************************/
544 static void
545 begin_selection_op (glLabel  *label)
546 {
547         label->priv->selection_op_flag = TRUE;
548 }
549
550
551 /****************************************************************************/
552 /* End selection operation.                                                 */
553 /****************************************************************************/
554 static void
555 end_selection_op (glLabel  *label)
556 {
557         label->priv->selection_op_flag = FALSE;
558         if ( label->priv->delayed_change_flag )
559         {
560                 label->priv->delayed_change_flag = FALSE;
561                 do_modify (label);
562         }
563 }
564
565
566 /****************************************************************************/
567 /* set template.                                                            */
568 /****************************************************************************/
569 void
570 gl_label_set_template (glLabel           *label,
571                        const lglTemplate *template,
572                        gboolean           checkpoint)
573 {
574         gchar *name;
575
576         gl_debug (DEBUG_LABEL, "START");
577
578         g_return_if_fail (label && GL_IS_LABEL (label));
579         g_return_if_fail (template);
580
581         if ((label->priv->template == NULL) ||
582             !lgl_template_do_templates_match (template, label->priv->template))
583         {
584
585                 if ( checkpoint )
586                 {
587                         gl_label_checkpoint (label, _("Label properties"));
588                 }
589
590                 lgl_template_free (label->priv->template);
591                 label->priv->template = lgl_template_dup (template);
592
593                 do_modify (label);
594                 g_signal_emit (G_OBJECT(label), signals[SIZE_CHANGED], 0);
595
596                 name = lgl_template_get_name (template);
597                 gl_template_history_model_add_name (gl_template_history, name);
598                 g_free (name);
599         }
600
601         gl_debug (DEBUG_LABEL, "END");
602 }
603
604
605 /****************************************************************************/
606 /* get template.                                                            */
607 /****************************************************************************/
608 const lglTemplate *
609 gl_label_get_template (glLabel            *label)
610 {
611         return label->priv->template;
612 }
613
614
615 /****************************************************************************/
616 /* set rotate flag.                                                         */
617 /****************************************************************************/
618 void
619 gl_label_set_rotate_flag (glLabel *label,
620                           gboolean rotate_flag,
621                           gboolean checkpoint)
622 {
623         gl_debug (DEBUG_LABEL, "START");
624
625         g_return_if_fail (label && GL_IS_LABEL (label));
626
627         if (rotate_flag != label->priv->rotate_flag)
628         {
629                 if ( checkpoint )
630                 {
631                         gl_label_checkpoint (label, _("Label properties"));
632                 }
633
634                 label->priv->rotate_flag = rotate_flag;
635
636                 do_modify (label);
637                 g_signal_emit (G_OBJECT(label), signals[SIZE_CHANGED], 0);
638         }
639
640         gl_debug (DEBUG_LABEL, "END");
641 }
642
643
644 /****************************************************************************/
645 /* Get rotate flag.                                                         */
646 /****************************************************************************/
647 gboolean
648 gl_label_get_rotate_flag (glLabel       *label)
649 {
650         return label->priv->rotate_flag;
651 }
652
653
654 /****************************************************************************/
655 /* Get label size.                                                          */
656 /****************************************************************************/
657 void
658 gl_label_get_size (glLabel *label,
659                    gdouble *w,
660                    gdouble *h)
661 {
662         lglTemplate            *template;
663         const lglTemplateFrame *frame;
664
665         gl_debug (DEBUG_LABEL, "START");
666
667         g_return_if_fail (label && GL_IS_LABEL (label));
668
669         template = label->priv->template;
670         if ( !template )
671         {
672                 gl_debug (DEBUG_LABEL, "END -- template NULL");
673                 *w = *h = 0;
674                 return;
675         }
676         frame = (lglTemplateFrame *)template->frames->data;
677
678         if (!label->priv->rotate_flag)
679         {
680                 lgl_template_frame_get_size (frame, w, h);
681         }
682         else
683         {
684                 lgl_template_frame_get_size (frame, h, w);
685         }
686
687         gl_debug (DEBUG_LABEL, "END");
688 }
689
690
691 /****************************************************************************/
692 /* set merge information structure.                                         */
693 /****************************************************************************/
694 void
695 gl_label_set_merge (glLabel *label,
696                     glMerge *merge,
697                     gboolean checkpoint)
698 {
699         gl_debug (DEBUG_LABEL, "START");
700
701         g_return_if_fail (label && GL_IS_LABEL (label));
702
703         if ( checkpoint )
704         {
705                 gl_label_checkpoint (label, _("Merge properties"));
706         }
707
708         if ( label->priv->merge != NULL )
709         {
710                 g_object_unref (G_OBJECT(label->priv->merge));
711         }
712         label->priv->merge = gl_merge_dup (merge);
713
714         do_modify (label);
715         g_signal_emit (G_OBJECT(label), signals[MERGE_CHANGED], 0);
716
717         gl_debug (DEBUG_LABEL, "END");
718 }
719
720
721 /****************************************************************************/
722 /* Get merge information structure.                                         */
723 /****************************************************************************/
724 glMerge *
725 gl_label_get_merge (glLabel *label)
726 {
727         gl_debug (DEBUG_LABEL, "START");
728
729         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
730
731         gl_debug (DEBUG_LABEL, "END");
732
733         return gl_merge_dup (label->priv->merge);
734 }
735
736
737 /****************************************************************************/
738 /* Get pixbuf cache.                                                        */
739 /****************************************************************************/
740 GHashTable *
741 gl_label_get_pixbuf_cache (glLabel       *label)
742 {
743         return label->priv->pixbuf_cache;
744 }
745
746
747 /****************************************************************************/
748 /* Get svg cache.                                                           */
749 /****************************************************************************/
750 GHashTable *
751 gl_label_get_svg_cache (glLabel       *label)
752 {
753         return label->priv->svg_cache;
754 }
755
756
757 /*****************************************************************************/
758 /* Add object to label.                                                      */
759 /*****************************************************************************/
760 void
761 gl_label_add_object (glLabel       *label,
762                      glLabelObject *object)
763 {
764         gl_debug (DEBUG_LABEL, "START");
765
766         g_return_if_fail (label && GL_IS_LABEL (label));
767         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
768
769         gl_label_object_set_parent (object, label);
770         label->priv->object_list = g_list_append (label->priv->object_list, object);
771
772         g_signal_connect (G_OBJECT (object), "changed",
773                           G_CALLBACK (object_changed_cb), label);
774
775         do_modify (label);
776
777         gl_debug (DEBUG_LABEL, "END");
778 }
779
780
781 /*****************************************************************************/
782 /* Delete object from label.                                                 */
783 /*****************************************************************************/
784 void
785 gl_label_delete_object (glLabel       *label,
786                         glLabelObject *object)
787 {
788         gl_debug (DEBUG_LABEL, "START");
789
790         g_return_if_fail (label && GL_IS_LABEL (label));
791         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
792
793         label->priv->object_list = g_list_remove (label->priv->object_list, object);
794
795         g_signal_handlers_disconnect_by_func (G_OBJECT (object),
796                                               G_CALLBACK (object_changed_cb), label);
797         g_object_unref (object);
798
799         do_modify (label);
800
801         gl_debug (DEBUG_LABEL, "END");
802 }
803
804
805 /*****************************************************************************/
806 /* Get object list.                                                          */
807 /*****************************************************************************/
808 const GList *
809 gl_label_get_object_list (glLabel       *label)
810 {
811         return label->priv->object_list;
812 }
813
814
815 /*****************************************************************************/
816 /* Select object.                                                            */
817 /*****************************************************************************/
818 void
819 gl_label_select_object (glLabel       *label,
820                         glLabelObject *object)
821 {
822         gl_debug (DEBUG_LABEL, "START");
823
824         g_return_if_fail (label && GL_IS_LABEL (label));
825         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
826
827         gl_label_object_select (object);
828
829         label->priv->cp_cleared_flag = TRUE;
830         g_signal_emit (G_OBJECT(label), signals[SELECTION_CHANGED], 0);
831
832         gl_debug (DEBUG_LABEL, "END");
833 }
834
835
836 /*****************************************************************************/
837 /* Unselect object.                                                          */
838 /*****************************************************************************/
839 void
840 gl_label_unselect_object (glLabel       *label,
841                           glLabelObject *object)
842 {
843         gl_debug (DEBUG_LABEL, "START");
844
845         g_return_if_fail (label && GL_IS_LABEL (label));
846         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
847
848         gl_label_object_unselect (object);
849
850         label->priv->cp_cleared_flag = TRUE;
851         g_signal_emit (G_OBJECT(label), signals[SELECTION_CHANGED], 0);
852
853         gl_debug (DEBUG_LABEL, "END");
854 }
855
856
857 /*****************************************************************************/
858 /* Select all objects.                                                       */
859 /*****************************************************************************/
860 void
861 gl_label_select_all (glLabel       *label)
862 {
863         GList         *p;
864         glLabelObject *object;
865
866         gl_debug (DEBUG_LABEL, "START");
867
868         g_return_if_fail (label && GL_IS_LABEL (label));
869
870         for ( p = label->priv->object_list; p != NULL; p = p->next )
871         {
872                 object = GL_LABEL_OBJECT (p->data);
873
874                 gl_label_object_select (object);
875         }
876
877         label->priv->cp_cleared_flag = TRUE;
878         g_signal_emit (G_OBJECT(label), signals[SELECTION_CHANGED], 0);
879
880         gl_debug (DEBUG_LABEL, "END");
881 }
882
883
884 /*****************************************************************************/
885 /* Unselect all objects.                                                     */
886 /*****************************************************************************/
887 void
888 gl_label_unselect_all (glLabel       *label)
889 {
890         GList         *p;
891         glLabelObject *object;
892
893         gl_debug (DEBUG_LABEL, "START");
894
895         g_return_if_fail (label && GL_IS_LABEL (label));
896
897         for ( p = label->priv->object_list; p != NULL; p = p->next )
898         {
899                 object = GL_LABEL_OBJECT (p->data);
900
901                 gl_label_object_unselect (object);
902         }
903
904         label->priv->cp_cleared_flag = TRUE;
905         g_signal_emit (G_OBJECT(label), signals[SELECTION_CHANGED], 0);
906
907         gl_debug (DEBUG_LABEL, "END");
908 }
909
910
911 /*****************************************************************************/
912 /* Select all objects contained in region.                                   */
913 /*****************************************************************************/
914 void
915 gl_label_select_region (glLabel       *label,
916                         glLabelRegion *region)
917 {
918         GList         *p;
919         glLabelObject *object;
920         gdouble        r_x1, r_y1;
921         gdouble        r_x2, r_y2;
922         glLabelRegion  obj_extent;
923
924         gl_debug (DEBUG_LABEL, "START");
925
926         g_return_if_fail (label && GL_IS_LABEL (label));
927
928         r_x1 = MIN (region->x1, region->x2);
929         r_y1 = MIN (region->y1, region->y2);
930         r_x2 = MAX (region->x1, region->x2);
931         r_y2 = MAX (region->y1, region->y2);
932
933         for (p = label->priv->object_list; p != NULL; p = p->next)
934         {
935                 object = GL_LABEL_OBJECT(p->data);
936
937                 gl_label_object_get_extent (object, &obj_extent);
938                 if ((obj_extent.x1 >= r_x1) &&
939                     (obj_extent.x2 <= r_x2) &&
940                     (obj_extent.y1 >= r_y1) &&
941                     (obj_extent.y2 <= r_y2))
942                 {
943                         gl_label_object_select (object);
944                 }
945         }
946
947         label->priv->cp_cleared_flag = TRUE;
948         g_signal_emit (G_OBJECT(label), signals[SELECTION_CHANGED], 0);
949
950         gl_debug (DEBUG_LABEL, "END");
951 }
952
953
954 /*****************************************************************************/
955 /* Is selection empty?                                                       */
956 /*****************************************************************************/
957 gboolean
958 gl_label_is_selection_empty (glLabel       *label)
959 {
960         GList         *p;
961         glLabelObject *object;
962
963         for ( p = label->priv->object_list; p != NULL; p = p->next )
964         {
965                 object = GL_LABEL_OBJECT (p->data);
966
967                 if ( gl_label_object_is_selected (object) )
968                 {
969                         return FALSE;
970                 }
971         }
972
973         return TRUE;
974 }
975
976
977 /*****************************************************************************/
978 /* Is selection atomic?                                                      */
979 /*****************************************************************************/
980 gboolean
981 gl_label_is_selection_atomic (glLabel       *label)
982 {
983         GList         *p;
984         glLabelObject *object;
985         gint           n_selected = 0;
986
987         for ( p = label->priv->object_list; p != NULL; p = p->next )
988         {
989                 object = GL_LABEL_OBJECT (p->data);
990
991                 if ( gl_label_object_is_selected (object) )
992                 {
993                         n_selected++;
994
995                         if (n_selected > 1)
996                         {
997                                 return FALSE;
998                         }
999                 }
1000         }
1001
1002         return (n_selected == 1);
1003 }
1004
1005
1006 /*****************************************************************************/
1007 /* Get first selected object.                                                */
1008 /*****************************************************************************/
1009 glLabelObject *
1010 gl_label_get_1st_selected_object (glLabel  *label)
1011 {
1012         GList         *p;
1013         glLabelObject *object;
1014
1015         for ( p = label->priv->object_list; p != NULL; p = p->next )
1016         {
1017                 object = GL_LABEL_OBJECT (p->data);
1018
1019                 if ( gl_label_object_is_selected (object) )
1020                 {
1021                         return object;
1022                 }
1023         }
1024
1025         return NULL;
1026 }
1027
1028
1029 /*****************************************************************************/
1030 /* Get list of selected objects.                                             */
1031 /*****************************************************************************/
1032 GList *
1033 gl_label_get_selection_list (glLabel *label)
1034 {
1035         GList         *selection_list = NULL;
1036         GList         *p;
1037         glLabelObject *object;
1038
1039         for ( p = label->priv->object_list; p != NULL; p = p->next )
1040         {
1041                 object = GL_LABEL_OBJECT (p->data);
1042
1043                 if ( gl_label_object_is_selected (object) )
1044                 {
1045                         selection_list = g_list_append (selection_list, object);
1046                 }
1047         }
1048
1049         return (selection_list);
1050 }
1051
1052
1053 /*****************************************************************************/
1054 /* Can text properties be set for selection?                                 */
1055 /*****************************************************************************/
1056 gboolean
1057 gl_label_can_selection_text (glLabel *label)
1058 {
1059         GList         *selection_list;
1060         GList         *p;
1061         glLabelObject *object;
1062
1063         gl_debug (DEBUG_LABEL, "");
1064
1065         g_return_val_if_fail (label && GL_IS_LABEL (label), FALSE);
1066
1067         selection_list = gl_label_get_selection_list (label);
1068
1069         for (p = selection_list; p != NULL; p = p->next)
1070         {
1071                 object = GL_LABEL_OBJECT (p->data);
1072
1073                 if (gl_label_object_can_text (object))
1074                 {
1075                         g_list_free (selection_list);
1076                         return TRUE;
1077                 }
1078         }
1079
1080         g_list_free (selection_list);
1081         return FALSE;
1082 }
1083
1084
1085 /*****************************************************************************/
1086 /* Can fill properties be set for selection?                                 */
1087 /*****************************************************************************/
1088 gboolean
1089 gl_label_can_selection_fill (glLabel *label)
1090 {
1091         GList         *selection_list;
1092         GList         *p;
1093         glLabelObject *object;
1094
1095         gl_debug (DEBUG_LABEL, "");
1096
1097         g_return_val_if_fail (label && GL_IS_LABEL (label), FALSE);
1098
1099         selection_list = gl_label_get_selection_list (label);
1100
1101         for (p = selection_list; p != NULL; p = p->next)
1102         {
1103                 object = GL_LABEL_OBJECT (p->data);
1104
1105                 if (gl_label_object_can_fill (object))
1106                 {
1107                         g_list_free (selection_list);
1108                         return TRUE;
1109                 }
1110
1111         }
1112
1113         g_list_free (selection_list);
1114         return FALSE;
1115 }
1116
1117
1118 /*****************************************************************************/
1119 /* Can line color properties be set for selection?                           */
1120 /*****************************************************************************/
1121 gboolean
1122 gl_label_can_selection_line_color (glLabel *label)
1123 {
1124         GList         *selection_list;
1125         GList         *p;
1126         glLabelObject *object;
1127
1128         gl_debug (DEBUG_LABEL, "");
1129
1130         g_return_val_if_fail (label && GL_IS_LABEL (label), FALSE);
1131
1132         selection_list = gl_label_get_selection_list (label);
1133
1134         for (p = selection_list; p != NULL; p = p->next)
1135         {
1136                 object = GL_LABEL_OBJECT (p->data);
1137
1138                 if (gl_label_object_can_line_color (object))
1139                 {
1140                         g_list_free (selection_list);
1141                         return TRUE;
1142                 }
1143         }
1144
1145         g_list_free (selection_list);
1146         return FALSE;
1147 }
1148
1149
1150 /*****************************************************************************/
1151 /* Can line width properties be set for selection?                           */
1152 /*****************************************************************************/
1153 gboolean
1154 gl_label_can_selection_line_width (glLabel *label)
1155 {
1156         GList         *selection_list;
1157         GList         *p;
1158         glLabelObject *object;
1159
1160         gl_debug (DEBUG_LABEL, "");
1161
1162         g_return_val_if_fail (label && GL_IS_LABEL (label), FALSE);
1163
1164         selection_list = gl_label_get_selection_list (label);
1165
1166         for (p = selection_list; p != NULL; p = p->next)
1167         {
1168                 object = GL_LABEL_OBJECT (p->data);
1169
1170                 if (gl_label_object_can_line_width (object))
1171                 {
1172                         g_list_free (selection_list);
1173                         return TRUE;
1174                 }
1175
1176         }
1177
1178         g_list_free (selection_list);
1179         return FALSE;
1180 }
1181
1182
1183 /*****************************************************************************/
1184 /* Delete selection from label.                                              */
1185 /*****************************************************************************/
1186 void
1187 gl_label_delete_selection (glLabel       *label)
1188 {
1189         GList         *selection_list;
1190         GList         *p;
1191         glLabelObject *object;
1192
1193         gl_debug (DEBUG_LABEL, "START");
1194
1195         g_return_if_fail (label && GL_IS_LABEL (label));
1196
1197         gl_label_checkpoint (label, _("Delete"));
1198
1199         begin_selection_op (label);
1200
1201         selection_list = gl_label_get_selection_list (label);
1202
1203         for ( p = selection_list; p != NULL; p = p->next )
1204         {
1205                 object = GL_LABEL_OBJECT (p->data);
1206
1207                 gl_label_delete_object (label, object);
1208         }
1209
1210         g_list_free (selection_list);
1211
1212         end_selection_op (label);
1213
1214         gl_debug (DEBUG_LABEL, "END");
1215 }
1216
1217
1218 /****************************************************************************/
1219 /* Bring selection object to front/top.                                     */
1220 /****************************************************************************/
1221 void
1222 gl_label_raise_selection_to_top (glLabel       *label)
1223 {
1224         GList         *selection_list;
1225         GList         *p;
1226         glLabelObject *object;
1227
1228         gl_debug (DEBUG_LABEL, "START");
1229
1230         gl_label_checkpoint (label, _("Bring to front"));
1231
1232         begin_selection_op (label);
1233
1234         selection_list = gl_label_get_selection_list (label);
1235
1236         for ( p = selection_list; p != NULL; p = p->next )
1237         {
1238                 object = GL_LABEL_OBJECT (p->data);
1239
1240                 label->priv->object_list = g_list_remove (label->priv->object_list, object);
1241         }
1242
1243         /* Move to end of list, representing front most object */
1244         label->priv->object_list = g_list_concat (label->priv->object_list, selection_list);
1245
1246         do_modify (label);
1247
1248         end_selection_op (label);
1249
1250         gl_debug (DEBUG_LABEL, "END");
1251 }
1252
1253
1254 /****************************************************************************/
1255 /* Send selection to rear/bottom.                                           */
1256 /****************************************************************************/
1257 void
1258 gl_label_lower_selection_to_bottom (glLabel       *label)
1259 {
1260         GList         *selection_list;
1261         GList         *p;
1262         glLabelObject *object;
1263
1264         gl_debug (DEBUG_LABEL, "START");
1265
1266         gl_label_checkpoint (label, _("Send to back"));
1267
1268         begin_selection_op (label);
1269
1270         selection_list = gl_label_get_selection_list (label);
1271
1272         for ( p = selection_list; p != NULL; p = p->next )
1273         {
1274                 object = GL_LABEL_OBJECT (p->data);
1275
1276                 label->priv->object_list = g_list_remove (label->priv->object_list, object);
1277         }
1278
1279         /* Move to front of list, representing rear most object */
1280         label->priv->object_list = g_list_concat (selection_list, label->priv->object_list);
1281
1282         do_modify (label);
1283
1284         end_selection_op (label);
1285
1286         gl_debug (DEBUG_LABEL, "END");
1287 }
1288
1289
1290 /*****************************************************************************/
1291 /* Rotate selected objects by given angle.                                   */
1292 /*****************************************************************************/
1293 void
1294 gl_label_rotate_selection (glLabel *label,
1295                            gdouble  theta_degs)
1296 {
1297         GList         *selection_list;
1298         GList         *p;
1299         glLabelObject *object;
1300
1301         gl_debug (DEBUG_LABEL, "START");
1302
1303         g_return_if_fail (label && GL_IS_LABEL (label));
1304
1305         begin_selection_op (label);
1306
1307         gl_label_checkpoint (label, _("Rotate"));
1308
1309         selection_list = gl_label_get_selection_list (label);
1310
1311         for ( p = selection_list; p != NULL; p = p->next )
1312         {
1313                 object = GL_LABEL_OBJECT (p->data);
1314
1315                 gl_label_object_rotate (object, theta_degs);
1316         }
1317
1318         g_list_free (selection_list);
1319
1320         end_selection_op (label);
1321
1322         gl_debug (DEBUG_LABEL, "END");
1323 }
1324
1325
1326 /*****************************************************************************/
1327 /* Rotate selected objects 90 degrees left.                                  */
1328 /*****************************************************************************/
1329 void
1330 gl_label_rotate_selection_left (glLabel *label)
1331 {
1332         GList         *selection_list;
1333         GList         *p;
1334         glLabelObject *object;
1335
1336         gl_debug (DEBUG_LABEL, "START");
1337
1338         g_return_if_fail (label && GL_IS_LABEL (label));
1339
1340         begin_selection_op (label);
1341
1342         gl_label_checkpoint (label, _("Rotate left"));
1343
1344         selection_list = gl_label_get_selection_list (label);
1345
1346         for ( p = selection_list; p != NULL; p = p->next )
1347         {
1348                 object = GL_LABEL_OBJECT (p->data);
1349
1350                 gl_label_object_rotate (object, -90.0);
1351         }
1352
1353         g_list_free (selection_list);
1354
1355         end_selection_op (label);
1356
1357         gl_debug (DEBUG_LABEL, "END");
1358 }
1359
1360
1361 /*****************************************************************************/
1362 /* Rotate selected objects 90 degrees right.                                 */
1363 /*****************************************************************************/
1364 void
1365 gl_label_rotate_selection_right (glLabel *label)
1366 {
1367         GList         *selection_list;
1368         GList         *p;
1369         glLabelObject *object;
1370
1371         gl_debug (DEBUG_LABEL, "START");
1372
1373         g_return_if_fail (label && GL_IS_LABEL (label));
1374
1375         gl_label_checkpoint (label, _("Rotate right"));
1376
1377         begin_selection_op (label);
1378
1379         selection_list = gl_label_get_selection_list (label);
1380
1381         for ( p = selection_list; p != NULL; p = p->next )
1382         {
1383                 object = GL_LABEL_OBJECT (p->data);
1384
1385                 gl_label_object_rotate (object, 90.0);
1386         }
1387
1388         g_list_free (selection_list);
1389
1390         end_selection_op (label);
1391
1392         gl_debug (DEBUG_LABEL, "END");
1393 }
1394
1395
1396 /*****************************************************************************/
1397 /* Flip selected objects horizontally.                                       */
1398 /*****************************************************************************/
1399 void
1400 gl_label_flip_selection_horiz (glLabel *label)
1401 {
1402         GList         *selection_list;
1403         GList         *p;
1404         glLabelObject *object;
1405
1406         gl_debug (DEBUG_LABEL, "START");
1407
1408         g_return_if_fail (label && GL_IS_LABEL (label));
1409
1410         gl_label_checkpoint (label, _("Flip horizontally"));
1411
1412         begin_selection_op (label);
1413
1414         selection_list = gl_label_get_selection_list (label);
1415
1416         for ( p = selection_list; p != NULL; p = p->next )
1417         {
1418                 object = GL_LABEL_OBJECT (p->data);
1419
1420                 gl_label_object_flip_horiz (object);
1421         }
1422
1423         g_list_free (selection_list);
1424
1425         end_selection_op (label);
1426
1427         gl_debug (DEBUG_LABEL, "END");
1428 }
1429
1430
1431 /*****************************************************************************/
1432 /* Flip selected objects vertically.                                         */
1433 /*****************************************************************************/
1434 void
1435 gl_label_flip_selection_vert (glLabel *label)
1436 {
1437         GList         *selection_list;
1438         GList         *p;
1439         glLabelObject *object;
1440
1441         gl_debug (DEBUG_LABEL, "START");
1442
1443         g_return_if_fail (label && GL_IS_LABEL (label));
1444
1445         gl_label_checkpoint (label, _("Flip vertically"));
1446
1447         begin_selection_op (label);
1448
1449         selection_list = gl_label_get_selection_list (label);
1450
1451         for ( p = selection_list; p != NULL; p = p->next )
1452         {
1453                 object = GL_LABEL_OBJECT (p->data);
1454
1455                 gl_label_object_flip_vert (object);
1456         }
1457
1458         g_list_free (selection_list);
1459
1460         end_selection_op (label);
1461
1462         gl_debug (DEBUG_LABEL, "END");
1463 }
1464
1465
1466 /*****************************************************************************/
1467 /* Align selected objects to left most edge.                                 */
1468 /*****************************************************************************/
1469 void
1470 gl_label_align_selection_left (glLabel *label)
1471 {
1472         GList         *selection_list;
1473         GList         *p;
1474         glLabelObject *object;
1475         gdouble        dx, x1_min;
1476         glLabelRegion  obj_extent;
1477
1478         gl_debug (DEBUG_LABEL, "START");
1479
1480         g_return_if_fail (label && GL_IS_LABEL (label));
1481
1482         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1483                           !gl_label_is_selection_atomic (label));
1484
1485         gl_label_checkpoint (label, _("Align left"));
1486
1487         begin_selection_op (label);
1488
1489         selection_list = gl_label_get_selection_list (label);
1490
1491         /* find left most edge */
1492         p = selection_list;
1493         object = GL_LABEL_OBJECT (p->data);
1494
1495         gl_label_object_get_extent (object, &obj_extent);
1496         x1_min = obj_extent.x1;
1497         for (p = p->next; p != NULL; p = p->next)
1498         {
1499                 object = GL_LABEL_OBJECT (p->data);
1500
1501                 gl_label_object_get_extent (object, &obj_extent);
1502                 if ( obj_extent.x1 < x1_min ) x1_min = obj_extent.x1;
1503         }
1504
1505         /* now adjust the object positions to line up the left edges */
1506         for (p = selection_list; p != NULL; p = p->next)
1507         {
1508                 object = GL_LABEL_OBJECT (p->data);
1509
1510                 gl_label_object_get_extent (object, &obj_extent);
1511                 dx = x1_min - obj_extent.x1;
1512                 gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
1513         }
1514
1515         g_list_free (selection_list);
1516
1517         end_selection_op (label);
1518
1519         gl_debug (DEBUG_LABEL, "END");
1520 }
1521
1522
1523 /*****************************************************************************/
1524 /* Align selected objects to right most edge.                                */
1525 /*****************************************************************************/
1526 void
1527 gl_label_align_selection_right (glLabel *label)
1528 {
1529         GList         *selection_list;
1530         GList         *p;
1531         glLabelObject *object;
1532         gdouble        dx, x2_max;
1533         glLabelRegion  obj_extent;
1534
1535         gl_debug (DEBUG_LABEL, "START");
1536
1537         g_return_if_fail (label && GL_IS_LABEL (label));
1538
1539         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1540                           !gl_label_is_selection_atomic (label));
1541
1542         gl_label_checkpoint (label, _("Align right"));
1543
1544         begin_selection_op (label);
1545
1546         selection_list = gl_label_get_selection_list (label);
1547
1548         /* find left most edge */
1549         p = selection_list;
1550         object = GL_LABEL_OBJECT (p->data);
1551
1552         gl_label_object_get_extent (object, &obj_extent);
1553         x2_max = obj_extent.x2;
1554         for (p = p->next; p != NULL; p = p->next)
1555         {
1556                 object = GL_LABEL_OBJECT (p->data);
1557
1558                 gl_label_object_get_extent (object, &obj_extent);
1559                 if ( obj_extent.x2 > x2_max ) x2_max = obj_extent.x2;
1560         }
1561
1562         /* now adjust the object positions to line up the left edges */
1563         for (p = selection_list; p != NULL; p = p->next)
1564         {
1565                 object = GL_LABEL_OBJECT (p->data);
1566
1567                 gl_label_object_get_extent (object, &obj_extent);
1568                 dx = x2_max - obj_extent.x2;
1569                 gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
1570         }
1571
1572         g_list_free (selection_list);
1573
1574         end_selection_op (label);
1575
1576         gl_debug (DEBUG_LABEL, "END");
1577 }
1578
1579
1580 /*****************************************************************************/
1581 /* Align selected objects to horizontal center of objects.                   */
1582 /*****************************************************************************/
1583 void
1584 gl_label_align_selection_hcenter (glLabel *label)
1585 {
1586         GList         *selection_list;
1587         GList         *p;
1588         glLabelObject *object;
1589         gdouble        dx;
1590         gdouble        dxmin;
1591         gdouble        xsum, xavg;
1592         glLabelRegion  obj_extent;
1593         gdouble        xcenter;
1594         gint           n;
1595
1596         gl_debug (DEBUG_LABEL, "START");
1597
1598         g_return_if_fail (label && GL_IS_LABEL (label));
1599
1600         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1601                           !gl_label_is_selection_atomic (label));
1602
1603         gl_label_checkpoint (label, _("Align horizontal center"));
1604
1605         begin_selection_op (label);
1606
1607         selection_list = gl_label_get_selection_list (label);
1608
1609         /* find average center of objects */
1610         xsum = 0.0;
1611         n = 0;
1612         for (p = selection_list; p != NULL; p = p->next)
1613         {
1614                 object = GL_LABEL_OBJECT (p->data);
1615
1616                 gl_label_object_get_extent (object, &obj_extent);
1617                 xsum += (obj_extent.x1 + obj_extent.x2) / 2.0;
1618                 n++;
1619         }
1620         xavg = xsum / n;
1621
1622         /* find center of object closest to average center */
1623         p = selection_list;
1624         object = GL_LABEL_OBJECT (p->data);
1625
1626         gl_label_object_get_extent (object, &obj_extent);
1627         dxmin = fabs (xavg - (obj_extent.x1 + obj_extent.x2)/2.0);
1628         xcenter = (obj_extent.x1 + obj_extent.x2)/2.0;
1629         for (p = p->next; p != NULL; p = p->next)
1630         {
1631                 object = GL_LABEL_OBJECT (p->data);
1632
1633                 gl_label_object_get_extent (object, &obj_extent);
1634                 dx = fabs (xavg - (obj_extent.x1 + obj_extent.x2)/2.0);
1635                 if ( dx < dxmin )
1636                 {
1637                         dxmin = dx;
1638                         xcenter = (obj_extent.x1 + obj_extent.x2)/2.0;
1639                 }
1640         }
1641
1642         /* now adjust the object positions to line up this center */
1643         for (p = selection_list; p != NULL; p = p->next)
1644         {
1645                 object = GL_LABEL_OBJECT (p->data);
1646
1647                 gl_label_object_get_extent (object, &obj_extent);
1648                 dx = xcenter - (obj_extent.x1 + obj_extent.x2)/2.0;
1649                 gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
1650         }
1651
1652         g_list_free (selection_list);
1653
1654         end_selection_op (label);
1655
1656         gl_debug (DEBUG_LABEL, "END");
1657 }
1658
1659
1660 /*****************************************************************************/
1661 /* Align selected objects to top most edge.                                  */
1662 /*****************************************************************************/
1663 void
1664 gl_label_align_selection_top (glLabel *label)
1665 {
1666         GList         *selection_list;
1667         GList         *p;
1668         glLabelObject *object;
1669         gdouble        dy, y1_min;
1670         glLabelRegion  obj_extent;
1671
1672         gl_debug (DEBUG_LABEL, "START");
1673
1674         g_return_if_fail (label && GL_IS_LABEL (label));
1675
1676         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1677                           !gl_label_is_selection_atomic (label));
1678
1679         gl_label_checkpoint (label, _("Align tops"));
1680
1681         begin_selection_op (label);
1682
1683         selection_list = gl_label_get_selection_list (label);
1684
1685         /* find top most edge */
1686         p = selection_list;
1687         object = GL_LABEL_OBJECT (p->data);
1688
1689         gl_label_object_get_extent (object, &obj_extent);
1690         y1_min = obj_extent.y1;
1691         for (p = p->next; p != NULL; p = p->next)
1692         {
1693                 object = GL_LABEL_OBJECT (p->data);
1694
1695                 gl_label_object_get_extent (object, &obj_extent);
1696                 if ( obj_extent.y1 < y1_min ) y1_min = obj_extent.y1;
1697         }
1698
1699         /* now adjust the object positions to line up the top edges */
1700         for (p = selection_list; p != NULL; p = p->next)
1701         {
1702                 object = GL_LABEL_OBJECT (p->data);
1703
1704                 gl_label_object_get_extent (object, &obj_extent);
1705                 dy = y1_min - obj_extent.y1;
1706                 gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
1707         }
1708
1709         g_list_free (selection_list);
1710
1711         end_selection_op (label);
1712
1713         gl_debug (DEBUG_LABEL, "END");
1714 }
1715
1716
1717 /*****************************************************************************/
1718 /* Align selected objects to bottom most edge.                               */
1719 /*****************************************************************************/
1720 void
1721 gl_label_align_selection_bottom (glLabel *label)
1722 {
1723         GList         *selection_list;
1724         GList         *p;
1725         glLabelObject *object;
1726         gdouble        dy, y2_max;
1727         glLabelRegion  obj_extent;
1728
1729         gl_debug (DEBUG_LABEL, "START");
1730
1731         g_return_if_fail (label && GL_IS_LABEL (label));
1732
1733         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1734                           !gl_label_is_selection_atomic (label));
1735
1736         gl_label_checkpoint (label, _("Align bottoms"));
1737
1738         begin_selection_op (label);
1739
1740         selection_list = gl_label_get_selection_list (label);
1741
1742         /* find bottom most edge */
1743         p = selection_list;
1744         object = GL_LABEL_OBJECT (p->data);
1745
1746         gl_label_object_get_extent (object, &obj_extent);
1747         y2_max = obj_extent.y2;
1748         for (p = p->next; p != NULL; p = p->next)
1749         {
1750                 object = GL_LABEL_OBJECT (p->data);
1751
1752                 gl_label_object_get_extent (object, &obj_extent);
1753                 if ( obj_extent.y2 > y2_max ) y2_max = obj_extent.y2;
1754         }
1755
1756         /* now adjust the object positions to line up the bottom edges */
1757         for (p = selection_list; p != NULL; p = p->next)
1758         {
1759                 object = GL_LABEL_OBJECT (p->data);
1760
1761                 gl_label_object_get_extent (object, &obj_extent);
1762                 dy = y2_max - obj_extent.y2;
1763                 gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
1764         }
1765
1766         g_list_free (selection_list);
1767
1768         end_selection_op (label);
1769
1770         gl_debug (DEBUG_LABEL, "END");
1771 }
1772
1773
1774 /*****************************************************************************/
1775 /* Align selected objects to viertical center of objects.                    */
1776 /*****************************************************************************/
1777 void
1778 gl_label_align_selection_vcenter (glLabel *label)
1779 {
1780         GList         *selection_list;
1781         GList         *p;
1782         glLabelObject *object;
1783         gdouble        dy;
1784         gdouble        dymin;
1785         gdouble        ysum, yavg;
1786         glLabelRegion  obj_extent;
1787         gdouble        ycenter;
1788         gint           n;
1789
1790         gl_debug (DEBUG_LABEL, "START");
1791
1792         g_return_if_fail (label && GL_IS_LABEL (label));
1793
1794         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1795                           !gl_label_is_selection_atomic (label));
1796
1797         gl_label_checkpoint (label, _("Align vertical center"));
1798
1799         begin_selection_op (label);
1800
1801         selection_list = gl_label_get_selection_list (label);
1802
1803         /* find average center of objects */
1804         ysum = 0.0;
1805         n = 0;
1806         for (p = selection_list; p != NULL; p = p->next)
1807         {
1808                 object = GL_LABEL_OBJECT (p->data);
1809
1810                 gl_label_object_get_extent (object, &obj_extent);
1811                 ysum += (obj_extent.y1 + obj_extent.y2) / 2.0;
1812                 n++;
1813         }
1814         yavg = ysum / n;
1815
1816         /* find center of object closest to average center */
1817         p = selection_list;
1818         object = GL_LABEL_OBJECT (p->data);
1819
1820         gl_label_object_get_extent (object, &obj_extent);
1821         dymin = fabs (yavg - (obj_extent.y1 + obj_extent.y2)/2.0);
1822         ycenter = (obj_extent.y1 + obj_extent.y2)/2.0;
1823         for (p = p->next; p != NULL; p = p->next)
1824         {
1825                 object = GL_LABEL_OBJECT (p->data);
1826
1827                 gl_label_object_get_extent (object, &obj_extent);
1828                 dy = fabs (yavg - (obj_extent.y1 + obj_extent.y2)/2.0);
1829                 if ( dy < dymin )
1830                 {
1831                         dymin = dy;
1832                         ycenter = (obj_extent.y1 + obj_extent.y2)/2.0;
1833                 }
1834         }
1835
1836         /* now adjust the object positions to line up this center */
1837         for (p = selection_list; p != NULL; p = p->next)
1838         {
1839                 object = GL_LABEL_OBJECT (p->data);
1840
1841                 gl_label_object_get_extent (object, &obj_extent);
1842                 dy = ycenter - (obj_extent.y1 + obj_extent.y2)/2.0;
1843                 gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
1844         }
1845
1846         g_list_free (selection_list);
1847
1848         end_selection_op (label);
1849
1850         gl_debug (DEBUG_LABEL, "END");
1851 }
1852
1853
1854 /*****************************************************************************/
1855 /* Center selected objects to in center of label.                            */
1856 /*****************************************************************************/
1857 void
1858 gl_label_center_selection_horiz (glLabel *label)
1859 {
1860         GList         *selection_list;
1861         GList         *p;
1862         glLabelObject *object;
1863         gdouble        dx;
1864         gdouble        x_label_center;
1865         gdouble        x_obj_center;
1866         glLabelRegion  obj_extent;
1867         gdouble        w, h;
1868
1869         gl_debug (DEBUG_LABEL, "START");
1870
1871         g_return_if_fail (label && GL_IS_LABEL (label));
1872
1873         g_return_if_fail (!gl_label_is_selection_empty (label));
1874
1875         gl_label_checkpoint (label, _("Center horizontally"));
1876
1877         begin_selection_op (label);
1878
1879         gl_label_get_size (label, &w, &h);
1880         x_label_center = w / 2.0;
1881
1882         /* adjust the object positions */
1883         selection_list = gl_label_get_selection_list (label);
1884         for (p = selection_list; p != NULL; p = p->next)
1885         {
1886                 object = GL_LABEL_OBJECT (p->data);
1887
1888                 gl_label_object_get_extent (object, &obj_extent);
1889                 x_obj_center = (obj_extent.x1 + obj_extent.x2) / 2.0;
1890                 dx = x_label_center - x_obj_center;
1891                 gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
1892         }
1893         g_list_free (selection_list);
1894
1895         end_selection_op (label);
1896
1897         gl_debug (DEBUG_LABEL, "END");
1898 }
1899
1900
1901 /*****************************************************************************/
1902 /* Center selected objects to in center of label.                            */
1903 /*****************************************************************************/
1904 void
1905 gl_label_center_selection_vert (glLabel *label)
1906 {
1907         GList         *selection_list;
1908         GList         *p;
1909         glLabelObject *object;
1910         gdouble        dy;
1911         gdouble        y_label_center;
1912         gdouble        y_obj_center;
1913         glLabelRegion  obj_extent;
1914         gdouble        w, h;
1915
1916         gl_debug (DEBUG_LABEL, "START");
1917
1918         g_return_if_fail (label && GL_IS_LABEL (label));
1919
1920         g_return_if_fail (!gl_label_is_selection_empty (label));
1921
1922         gl_label_checkpoint (label, _("Center vertically"));
1923
1924         begin_selection_op (label);
1925
1926         gl_label_get_size (label, &w, &h);
1927         y_label_center = h / 2.0;
1928
1929         /* adjust the object positions */
1930         selection_list = gl_label_get_selection_list (label);
1931         for (p = selection_list; p != NULL; p = p->next)
1932         {
1933                 object = GL_LABEL_OBJECT (p->data);
1934
1935                 gl_label_object_get_extent (object, &obj_extent);
1936                 y_obj_center = (obj_extent.y1 + obj_extent.y2) / 2.0;
1937                 dy = y_label_center - y_obj_center;
1938                 gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
1939         }
1940         g_list_free (selection_list);
1941
1942         end_selection_op (label);
1943
1944         gl_debug (DEBUG_LABEL, "END");
1945 }
1946
1947
1948 /*****************************************************************************/
1949 /* Move selected objects                                                     */
1950 /*****************************************************************************/
1951 void
1952 gl_label_move_selection (glLabel  *label,
1953                          gdouble   dx,
1954                          gdouble   dy)
1955 {
1956         GList         *selection_list;
1957         GList         *p;
1958         glLabelObject *object;
1959
1960         gl_debug (DEBUG_LABEL, "START");
1961
1962         g_return_if_fail (label && GL_IS_LABEL (label));
1963
1964         begin_selection_op (label);
1965
1966         selection_list = gl_label_get_selection_list (label);
1967
1968         for (p = selection_list; p != NULL; p = p->next)
1969         {
1970                 object = GL_LABEL_OBJECT (p->data);
1971
1972                 gl_label_object_set_position_relative (object, dx, dy, TRUE);
1973         }
1974
1975         g_list_free (selection_list);
1976
1977         end_selection_op (label);
1978
1979         gl_debug (DEBUG_LABEL, "END");
1980 }
1981
1982
1983 /*****************************************************************************/
1984 /* Set font family for all text contained in selected objects.               */
1985 /*****************************************************************************/
1986 void
1987 gl_label_set_selection_font_family (glLabel      *label,
1988                                     const gchar  *font_family)
1989 {
1990         GList         *selection_list;
1991         GList         *p;
1992         glLabelObject *object;
1993
1994         gl_debug (DEBUG_LABEL, "START");
1995
1996         g_return_if_fail (label && GL_IS_LABEL (label));
1997
1998         begin_selection_op (label);
1999
2000         selection_list = gl_label_get_selection_list (label);
2001
2002         for (p = selection_list; p != NULL; p = p->next)
2003         {
2004                 object = GL_LABEL_OBJECT (p->data);
2005                 gl_label_object_set_font_family (object, font_family, TRUE);
2006         }
2007
2008         g_list_free (selection_list);
2009
2010         end_selection_op (label);
2011
2012         gl_debug (DEBUG_LABEL, "END");
2013 }
2014
2015
2016 /*****************************************************************************/
2017 /* Set font size for all text contained in selected objects.                 */
2018 /*****************************************************************************/
2019 void
2020 gl_label_set_selection_font_size (glLabel  *label,
2021                                   gdouble   font_size)
2022 {
2023         GList         *selection_list;
2024         GList         *p;
2025         glLabelObject *object;
2026
2027         gl_debug (DEBUG_LABEL, "START");
2028
2029         g_return_if_fail (label && GL_IS_LABEL (label));
2030
2031         begin_selection_op (label);
2032
2033         selection_list = gl_label_get_selection_list (label);
2034
2035         for (p = selection_list; p != NULL; p = p->next)
2036         {
2037                 object = GL_LABEL_OBJECT (p->data);
2038                 gl_label_object_set_font_size (object, font_size, TRUE);
2039         }
2040
2041         g_list_free (selection_list);
2042
2043         end_selection_op (label);
2044
2045         gl_debug (DEBUG_LABEL, "END");
2046 }
2047
2048
2049 /*****************************************************************************/
2050 /* Set font weight for all text contained in selected objects.               */
2051 /*****************************************************************************/
2052 void
2053 gl_label_set_selection_font_weight (glLabel      *label,
2054                                     PangoWeight   font_weight)
2055 {
2056         GList         *selection_list;
2057         GList         *p;
2058         glLabelObject *object;
2059
2060         gl_debug (DEBUG_LABEL, "START");
2061
2062         g_return_if_fail (label && GL_IS_LABEL (label));
2063
2064         begin_selection_op (label);
2065
2066         selection_list = gl_label_get_selection_list (label);
2067
2068         for (p = selection_list; p != NULL; p = p->next)
2069         {
2070                 object = GL_LABEL_OBJECT (p->data);
2071                 gl_label_object_set_font_weight (object, font_weight, TRUE);
2072         }
2073
2074         g_list_free (selection_list);
2075
2076         end_selection_op (label);
2077
2078         gl_debug (DEBUG_LABEL, "END");
2079 }
2080
2081
2082 /*****************************************************************************/
2083 /* Set font italic flag for all text contained in selected objects.          */
2084 /*****************************************************************************/
2085 void
2086 gl_label_set_selection_font_italic_flag (glLabel   *label,
2087                                          gboolean   font_italic_flag)
2088 {
2089         GList         *selection_list;
2090         GList         *p;
2091         glLabelObject *object;
2092
2093         gl_debug (DEBUG_LABEL, "START");
2094
2095         g_return_if_fail (label && GL_IS_LABEL (label));
2096
2097         begin_selection_op (label);
2098
2099         selection_list = gl_label_get_selection_list (label);
2100
2101         for (p = selection_list; p != NULL; p = p->next)
2102         {
2103                 object = GL_LABEL_OBJECT (p->data);
2104                 gl_label_object_set_font_italic_flag (object, font_italic_flag, TRUE);
2105         }
2106
2107         g_list_free (selection_list);
2108
2109         end_selection_op (label);
2110
2111         gl_debug (DEBUG_LABEL, "END");
2112 }
2113
2114
2115 /*****************************************************************************/
2116 /* Set text alignment for all text contained in selected objects.            */
2117 /*****************************************************************************/
2118 void
2119 gl_label_set_selection_text_alignment (glLabel        *label,
2120                                        PangoAlignment  text_alignment)
2121 {
2122         GList         *selection_list;
2123         GList         *p;
2124         glLabelObject *object;
2125
2126         gl_debug (DEBUG_LABEL, "START");
2127
2128         g_return_if_fail (label && GL_IS_LABEL (label));
2129
2130         begin_selection_op (label);
2131
2132         selection_list = gl_label_get_selection_list (label);
2133
2134         for (p = selection_list; p != NULL; p = p->next)
2135         {
2136                 object = GL_LABEL_OBJECT (p->data);
2137                 gl_label_object_set_text_alignment (object, text_alignment, TRUE);
2138         }
2139
2140         g_list_free (selection_list);
2141
2142         end_selection_op (label);
2143
2144         gl_debug (DEBUG_LABEL, "END");
2145 }
2146
2147
2148 /*****************************************************************************/
2149 /* Set text line spacing for all text contained in selected objects.         */
2150 /*****************************************************************************/
2151 void
2152 gl_label_set_selection_text_line_spacing (glLabel  *label,
2153                                           gdouble   text_line_spacing)
2154 {
2155         GList         *selection_list;
2156         GList         *p;
2157         glLabelObject *object;
2158
2159         gl_debug (DEBUG_LABEL, "START");
2160
2161         g_return_if_fail (label && GL_IS_LABEL (label));
2162
2163         begin_selection_op (label);
2164
2165         selection_list = gl_label_get_selection_list (label);
2166
2167         for (p = selection_list; p != NULL; p = p->next)
2168         {
2169                 object = GL_LABEL_OBJECT (p->data);
2170                 gl_label_object_set_text_line_spacing (object, text_line_spacing, TRUE);
2171         }
2172
2173         g_list_free (selection_list);
2174
2175         end_selection_op (label);
2176
2177         gl_debug (DEBUG_LABEL, "END");
2178 }
2179
2180
2181 /*****************************************************************************/
2182 /* Set text color for all text contained in selected objects.                */
2183 /*****************************************************************************/
2184 void
2185 gl_label_set_selection_text_color (glLabel      *label,
2186                                    glColorNode  *text_color_node)
2187 {
2188         GList         *selection_list;
2189         GList         *p;
2190         glLabelObject *object;
2191
2192         gl_debug (DEBUG_LABEL, "START");
2193
2194         g_return_if_fail (label && GL_IS_LABEL (label));
2195
2196         begin_selection_op (label);
2197
2198         selection_list = gl_label_get_selection_list (label);
2199
2200         for (p = selection_list; p != NULL; p = p->next)
2201         {
2202                 object = GL_LABEL_OBJECT (p->data);
2203                 gl_label_object_set_text_color (object, text_color_node, TRUE);
2204         }
2205
2206         g_list_free (selection_list);
2207
2208         end_selection_op (label);
2209
2210         gl_debug (DEBUG_LABEL, "END");
2211 }
2212
2213
2214 /*****************************************************************************/
2215 /* Set fill color for all selected objects.                                  */
2216 /*****************************************************************************/
2217 void
2218 gl_label_set_selection_fill_color (glLabel      *label,
2219                                    glColorNode  *fill_color_node)
2220 {
2221         GList         *selection_list;
2222         GList         *p;
2223         glLabelObject *object;
2224
2225         gl_debug (DEBUG_LABEL, "START");
2226
2227         g_return_if_fail (label && GL_IS_LABEL (label));
2228
2229         begin_selection_op (label);
2230
2231         selection_list = gl_label_get_selection_list (label);
2232
2233         for (p = selection_list; p != NULL; p = p->next)
2234         {
2235                 object = GL_LABEL_OBJECT (p->data);
2236                 gl_label_object_set_fill_color (object, fill_color_node, TRUE);
2237         }
2238
2239         g_list_free (selection_list);
2240
2241         end_selection_op (label);
2242
2243         gl_debug (DEBUG_LABEL, "END");
2244 }
2245
2246
2247 /*****************************************************************************/
2248 /* Set line color for all selected objects.                                  */
2249 /*****************************************************************************/
2250 void
2251 gl_label_set_selection_line_color (glLabel      *label,
2252                                    glColorNode  *line_color_node)
2253 {
2254         GList         *selection_list;
2255         GList         *p;
2256         glLabelObject *object;
2257
2258         gl_debug (DEBUG_LABEL, "START");
2259
2260         g_return_if_fail (label && GL_IS_LABEL (label));
2261
2262         begin_selection_op (label);
2263
2264         selection_list = gl_label_get_selection_list (label);
2265
2266         for (p = selection_list; p != NULL; p = p->next)
2267         {
2268                 object = GL_LABEL_OBJECT (p->data);
2269                 gl_label_object_set_line_color (object, line_color_node, TRUE);
2270         }
2271
2272         g_list_free (selection_list);
2273
2274         end_selection_op (label);
2275
2276         gl_debug (DEBUG_LABEL, "END");
2277 }
2278
2279
2280 /*****************************************************************************/
2281 /* Set line width for all selected objects.                                  */
2282 /*****************************************************************************/
2283 void
2284 gl_label_set_selection_line_width (glLabel  *label,
2285                                   gdouble  line_width)
2286 {
2287         GList         *selection_list;
2288         GList         *p;
2289         glLabelObject *object;
2290
2291         gl_debug (DEBUG_LABEL, "START");
2292
2293         g_return_if_fail (label && GL_IS_LABEL (label));
2294
2295         begin_selection_op (label);
2296
2297         selection_list = gl_label_get_selection_list (label);
2298
2299         for (p = selection_list; p != NULL; p = p->next)
2300         {
2301                 object = GL_LABEL_OBJECT (p->data);
2302                 gl_label_object_set_line_width (object, line_width, TRUE);
2303         }
2304
2305         g_list_free (selection_list);
2306
2307         end_selection_op (label);
2308
2309         gl_debug (DEBUG_LABEL, "END");
2310 }
2311
2312
2313 /*****************************************************************************/
2314 /* "Cut" selected items and place on clipboard.                              */
2315 /*****************************************************************************/
2316 void
2317 gl_label_cut_selection (glLabel       *label)
2318 {
2319         gl_debug (DEBUG_LABEL, "START");
2320
2321         g_return_if_fail (label && GL_IS_LABEL (label));
2322
2323         gl_label_copy_selection (label);
2324         gl_label_delete_selection (label);
2325
2326         gl_debug (DEBUG_LABEL, "END");
2327 }
2328
2329
2330 /*****************************************************************************/
2331 /* "Copy" selected items to clipboard.                                       */
2332 /*****************************************************************************/
2333 void
2334 gl_label_copy_selection (glLabel       *label)
2335 {
2336         GtkClipboard      *clipboard;
2337         GList             *selection_list;
2338         glLabel           *label_copy;
2339         GList             *p;
2340         glLabelObject     *object;
2341         glXMLLabelStatus   status;
2342
2343         ClipboardData     *data;
2344
2345         static GtkTargetEntry glabels_targets[] = { { "application/glabels", 0, 0 },
2346                                                     { "text/xml",            0, 0 },
2347         };
2348
2349         GtkTargetList  *target_list;
2350         GtkTargetEntry *target_table;
2351         gint            n_targets;
2352
2353         gl_debug (DEBUG_LABEL, "START");
2354
2355         g_return_if_fail (label && GL_IS_LABEL (label));
2356
2357         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2358
2359         selection_list = gl_label_get_selection_list (label);
2360
2361         if (selection_list)
2362         {
2363
2364                 data = g_new0 (ClipboardData, 1);
2365
2366                 target_list = gtk_target_list_new (glabels_targets, G_N_ELEMENTS(glabels_targets));
2367
2368                 /*
2369                  * Serialize selection by encoding as an XML label document.
2370                  */
2371                 label_copy = GL_LABEL(gl_label_new ());
2372
2373                 gl_label_set_template (label_copy, label->priv->template, FALSE);
2374                 gl_label_set_rotate_flag (label_copy, label->priv->rotate_flag, FALSE);
2375
2376                 for (p = selection_list; p != NULL; p = p->next)
2377                 {
2378                         object = GL_LABEL_OBJECT (p->data);
2379
2380                         gl_label_add_object (label_copy, gl_label_object_dup (object, label_copy));
2381                 }
2382
2383                 data->xml_buffer = gl_xml_label_save_buffer (label_copy, &status);
2384
2385                 g_object_unref (G_OBJECT (label_copy));
2386
2387
2388                 /*
2389                  * Is it an atomic text selection?  If so, also make available as text.
2390                  */
2391                 if ( gl_label_is_selection_atomic (label) &&
2392                      GL_IS_LABEL_TEXT (selection_list->data) )
2393                 {
2394                         glLabelText *text_object = GL_LABEL_TEXT (selection_list->data);
2395
2396                         gtk_target_list_add_text_targets (target_list, 1);
2397
2398                         data->text = gl_label_text_get_text (text_object);
2399                 }
2400
2401
2402                 /*
2403                  * Is it an atomic image selection?  If so, also make available as pixbuf.
2404                  */
2405                 if ( gl_label_is_selection_atomic (label) &&
2406                      GL_IS_LABEL_IMAGE (selection_list->data) )
2407                 {
2408                         glLabelImage  *image_object = GL_LABEL_IMAGE (selection_list->data);
2409                         GdkPixbuf     *pixbuf = gl_label_image_get_pixbuf (image_object, NULL);
2410
2411                         if (pixbuf)
2412                         {
2413                                 gtk_target_list_add_image_targets (target_list, 2, TRUE);
2414                                 data->pixbuf = pixbuf;
2415                         }
2416                 }
2417
2418
2419                 target_table = gtk_target_table_new_from_list (target_list, &n_targets);
2420
2421                 gtk_clipboard_set_with_data (clipboard,
2422                                              target_table, n_targets,
2423                                              (GtkClipboardGetFunc)clipboard_get_cb,
2424                                              (GtkClipboardClearFunc)clipboard_clear_cb,
2425                                              data);
2426
2427                 gtk_target_table_free (target_table, n_targets);
2428                 gtk_target_list_unref (target_list);
2429         }
2430
2431
2432         g_list_free (selection_list);
2433
2434         gl_debug (DEBUG_LABEL, "END");
2435 }
2436
2437
2438 /*****************************************************************************/
2439 /* "Paste" from clipboard.                                                   */
2440 /*****************************************************************************/
2441 void
2442 gl_label_paste (glLabel       *label)
2443 {
2444         GtkClipboard  *clipboard;
2445
2446         gl_debug (DEBUG_LABEL, "START");
2447
2448         g_return_if_fail (label && GL_IS_LABEL (label));
2449
2450         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2451
2452         gtk_clipboard_request_targets (clipboard,
2453                                        (GtkClipboardTargetsReceivedFunc)receive_targets_cb,
2454                                        label);
2455
2456         gl_debug (DEBUG_LABEL, "END");
2457 }
2458
2459
2460 /*****************************************************************************/
2461 /* Is there anything that can be pasted?                                     */
2462 /*****************************************************************************/
2463 gboolean
2464 gl_label_can_paste (glLabel       *label)
2465 {
2466         GtkClipboard *clipboard;
2467         gboolean      can_flag;
2468
2469         gl_debug (DEBUG_LABEL, "START");
2470
2471         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2472
2473         can_flag = gtk_clipboard_wait_is_target_available (clipboard,
2474                                                            gdk_atom_intern("application/glabels", TRUE))
2475                 || gtk_clipboard_wait_is_text_available (clipboard)
2476                 || gtk_clipboard_wait_is_image_available (clipboard);
2477
2478         gl_debug (DEBUG_LABEL, "END");
2479         return can_flag;
2480 }
2481
2482
2483 /****************************************************************************/
2484 /* Clipboard "Get" function.                                                */
2485 /****************************************************************************/
2486 static void
2487 clipboard_get_cb (GtkClipboard     *clipboard,
2488                   GtkSelectionData *selection_data,
2489                   guint             info,
2490                   ClipboardData    *data)
2491 {
2492         gl_debug (DEBUG_LABEL, "START");
2493
2494         switch (info)
2495         {
2496
2497         case 0:
2498                 gtk_selection_data_set (selection_data,
2499                                         gtk_selection_data_get_target (selection_data),
2500                                         8,
2501                                         (guchar *)data->xml_buffer, strlen (data->xml_buffer));
2502                 break;
2503
2504         case 1:
2505                 gtk_selection_data_set_text (selection_data, data->text, -1);
2506                 break;
2507
2508         case 2:
2509                 gtk_selection_data_set_pixbuf (selection_data, data->pixbuf);
2510                 break;
2511
2512         default:
2513                 g_assert_not_reached ();
2514                 break;
2515
2516         }
2517
2518         gl_debug (DEBUG_LABEL, "END");
2519 }
2520
2521
2522 /****************************************************************************/
2523 /* Clipboard "Clear" function.                                              */
2524 /****************************************************************************/
2525 static void
2526 clipboard_clear_cb (GtkClipboard     *clipboard,
2527                     ClipboardData    *data)
2528 {
2529         gl_debug (DEBUG_LABEL, "START");
2530
2531         g_free (data->xml_buffer);
2532         g_free (data->text);
2533         if (data->pixbuf)
2534         {
2535                 g_object_unref (data->pixbuf);
2536         }
2537
2538         g_free (data);
2539
2540         gl_debug (DEBUG_LABEL, "END");
2541 }
2542
2543
2544 /****************************************************************************/
2545 /* Deal with clipboard data.                                                */
2546 /****************************************************************************/
2547 static void
2548 receive_targets_cb (GtkClipboard *clipboard,
2549                     GdkAtom      *targets,
2550                     gint          n_targets,
2551                     glLabel      *label)
2552 {
2553         gint i;
2554
2555         /*
2556          * Application/glabels
2557          */
2558         for ( i = 0; i < n_targets; i++ )
2559         {
2560                 if ( strcmp(gdk_atom_name(targets[i]), "application/glabels") == 0 )
2561                 {
2562                         gtk_clipboard_request_contents (clipboard,
2563                                                         gdk_atom_intern("application/glabels", TRUE),
2564                                                         (GtkClipboardReceivedFunc)paste_xml_received_cb,
2565                                                         label);
2566                         return;
2567                 }
2568         }
2569
2570         /*
2571          * Text
2572          */
2573         if ( gtk_targets_include_text (targets, n_targets) )
2574         {
2575                 gtk_clipboard_request_text (clipboard,
2576                                             (GtkClipboardTextReceivedFunc)paste_text_received_cb,
2577                                             label);
2578                 return;
2579         }
2580
2581         /*
2582          * Image
2583          */
2584         if ( gtk_targets_include_image (targets, n_targets, TRUE) )
2585         {
2586                 gtk_clipboard_request_image (clipboard,
2587                                              (GtkClipboardImageReceivedFunc)paste_image_received_cb,
2588                                              label);
2589                 return;
2590         }
2591 }
2592
2593
2594 /****************************************************************************/
2595 /* Paste received glabels XML callback.                                     */
2596 /****************************************************************************/
2597 static void
2598 paste_xml_received_cb (GtkClipboard     *clipboard,
2599                        GtkSelectionData *selection_data,
2600                        glLabel          *label)
2601 {
2602         gchar            *xml_buffer;
2603         glLabel          *label_copy;
2604         glXMLLabelStatus  status;
2605         GList            *p;
2606         glLabelObject    *object, *newobject;
2607
2608         gl_debug (DEBUG_LABEL, "START");
2609
2610         gl_label_checkpoint (label, _("Paste"));
2611
2612         xml_buffer = (gchar *)gtk_selection_data_get_data (selection_data);
2613
2614         /*
2615          * Deserialize XML label document and extract objects.
2616          */
2617         label_copy = gl_xml_label_open_buffer (xml_buffer, &status);
2618         if ( label_copy )
2619         {
2620                 gl_label_unselect_all (label);
2621
2622                 for (p = label_copy->priv->object_list; p != NULL; p = p->next)
2623                 {
2624                         object = (glLabelObject *) p->data;
2625                         newobject = gl_label_object_dup (object, label);
2626                         gl_label_add_object( label, newobject );
2627
2628                         gl_label_select_object (label, newobject);
2629
2630                         gl_debug (DEBUG_LABEL, "object pasted");
2631                 }
2632
2633                 g_object_unref (G_OBJECT (label_copy));
2634         }
2635
2636         gl_debug (DEBUG_LABEL, "END");
2637 }
2638
2639
2640 /****************************************************************************/
2641 /* Paste received text callback.                                            */
2642 /****************************************************************************/
2643 static void
2644 paste_text_received_cb (GtkClipboard     *clipboard,
2645                         const gchar      *text,
2646                         glLabel          *label)
2647 {
2648         glLabelObject    *object;
2649
2650         gl_debug (DEBUG_LABEL, "START");
2651
2652         gl_label_checkpoint (label, _("Paste"));
2653
2654         gl_label_unselect_all (label);
2655
2656         object = GL_LABEL_OBJECT (gl_label_text_new (label, FALSE));
2657         gl_label_text_set_text (GL_LABEL_TEXT (object), text, FALSE);
2658         gl_label_object_set_position (object, 18, 18, FALSE);
2659
2660         gl_label_select_object (label, object);
2661
2662         gl_debug (DEBUG_LABEL, "END");
2663 }
2664
2665
2666 /****************************************************************************/
2667 /* Paste received image callback.                                           */
2668 /****************************************************************************/
2669 static void
2670 paste_image_received_cb (GtkClipboard     *clipboard,
2671                          GdkPixbuf        *pixbuf,
2672                          glLabel          *label)
2673 {
2674         glLabelObject    *object;
2675
2676         gl_debug (DEBUG_LABEL, "START");
2677
2678         gl_label_checkpoint (label, _("Paste"));
2679
2680         gl_label_unselect_all (label);
2681
2682         object = GL_LABEL_OBJECT (gl_label_image_new (label, FALSE));
2683         gl_label_image_set_pixbuf (GL_LABEL_IMAGE (object), pixbuf, FALSE);
2684         gl_label_object_set_position (object, 18, 18, FALSE);
2685
2686         gl_label_select_object (label, object);
2687
2688         gl_debug (DEBUG_LABEL, "END");
2689 }
2690
2691
2692 /****************************************************************************/
2693 /* Set default font family.                                                 */
2694 /****************************************************************************/
2695 void
2696 gl_label_set_default_font_family (glLabel     *label,
2697                                   const gchar *font_family)
2698 {
2699         gl_debug (DEBUG_LABEL, "START");
2700
2701         g_return_if_fail (label && GL_IS_LABEL (label));
2702
2703         g_free (label->priv->default_font_family);
2704         label->priv->default_font_family = g_strdup (font_family);
2705
2706         gl_debug (DEBUG_LABEL, "END");
2707 }
2708
2709
2710 /****************************************************************************/
2711 /* Set default font size.                                                   */
2712 /****************************************************************************/
2713 void
2714 gl_label_set_default_font_size (glLabel *label,
2715                                 gdouble  font_size)
2716 {
2717         gl_debug (DEBUG_LABEL, "START");
2718
2719         g_return_if_fail (label && GL_IS_LABEL (label));
2720
2721         label->priv->default_font_size = font_size;
2722
2723         gl_debug (DEBUG_LABEL, "END");
2724 }
2725
2726
2727 /****************************************************************************/
2728 /* Set default font weight.                                                 */
2729 /****************************************************************************/
2730 void
2731 gl_label_set_default_font_weight (glLabel     *label,
2732                                   PangoWeight  font_weight)
2733 {
2734         gl_debug (DEBUG_LABEL, "START");
2735
2736         g_return_if_fail (label && GL_IS_LABEL (label));
2737
2738         label->priv->default_font_weight = font_weight;
2739
2740         gl_debug (DEBUG_LABEL, "END");
2741 }
2742
2743
2744 /****************************************************************************/
2745 /* Set default font italic flag.                                            */
2746 /****************************************************************************/
2747 void
2748 gl_label_set_default_font_italic_flag (glLabel  *label,
2749                                        gboolean  font_italic_flag)
2750 {
2751         gl_debug (DEBUG_LABEL, "START");
2752
2753         g_return_if_fail (label && GL_IS_LABEL (label));
2754
2755         label->priv->default_font_italic_flag = font_italic_flag;
2756
2757         gl_debug (DEBUG_LABEL, "END");
2758 }
2759
2760
2761 /****************************************************************************/
2762 /* Set default text color.                                                  */
2763 /****************************************************************************/
2764 void
2765 gl_label_set_default_text_color (glLabel *label,
2766                                  guint    text_color)
2767 {
2768         gl_debug (DEBUG_LABEL, "START");
2769
2770         g_return_if_fail (label && GL_IS_LABEL (label));
2771
2772         label->priv->default_text_color = text_color;
2773
2774         gl_debug (DEBUG_LABEL, "END");
2775 }
2776
2777
2778 /****************************************************************************/
2779 /* Set default text alignment.                                              */
2780 /****************************************************************************/
2781 void
2782 gl_label_set_default_text_alignment (glLabel        *label,
2783                                      PangoAlignment  text_alignment)
2784 {
2785         gl_debug (DEBUG_LABEL, "START");
2786
2787         g_return_if_fail (label && GL_IS_LABEL (label));
2788
2789         label->priv->default_text_alignment = text_alignment;
2790         gl_debug (DEBUG_LABEL, "END");
2791 }
2792
2793
2794 /****************************************************************************/
2795 /* Set default text line spacing.                                           */
2796 /****************************************************************************/
2797 void
2798 gl_label_set_default_text_line_spacing (glLabel *label,
2799                                         gdouble  text_line_spacing)
2800 {
2801         gl_debug (DEBUG_LABEL, "START");
2802
2803         g_return_if_fail (label && GL_IS_LABEL (label));
2804
2805         label->priv->default_text_line_spacing = text_line_spacing;
2806
2807         gl_debug (DEBUG_LABEL, "END");
2808 }
2809
2810
2811 /****************************************************************************/
2812 /* Set default line width.                                                  */
2813 /****************************************************************************/
2814 void
2815 gl_label_set_default_line_width (glLabel *label,
2816                                  gdouble  line_width)
2817 {
2818         gl_debug (DEBUG_LABEL, "START");
2819
2820         g_return_if_fail (label && GL_IS_LABEL (label));
2821
2822         label->priv->default_line_width = line_width;
2823
2824         gl_debug (DEBUG_LABEL, "END");
2825 }
2826
2827
2828 /****************************************************************************/
2829 /* Set default line color.                                                  */
2830 /****************************************************************************/
2831 void
2832 gl_label_set_default_line_color (glLabel *label,
2833                                  guint    line_color)
2834 {
2835         gl_debug (DEBUG_LABEL, "START");
2836
2837         g_return_if_fail (label && GL_IS_LABEL (label));
2838
2839         label->priv->default_line_color = line_color;
2840
2841         gl_debug (DEBUG_LABEL, "END");
2842 }
2843
2844
2845 /****************************************************************************/
2846 /* Set default fill color.                                                  */
2847 /****************************************************************************/
2848 void
2849 gl_label_set_default_fill_color (glLabel *label,
2850                                  guint    fill_color)
2851 {
2852         gl_debug (DEBUG_LABEL, "START");
2853
2854         g_return_if_fail (label && GL_IS_LABEL (label));
2855
2856         label->priv->default_fill_color = fill_color;
2857
2858         gl_debug (DEBUG_LABEL, "END");
2859 }
2860
2861
2862 /****************************************************************************/
2863 /* Get default font family.                                                 */
2864 /****************************************************************************/
2865 gchar *
2866 gl_label_get_default_font_family (glLabel *label)
2867 {
2868         gl_debug (DEBUG_LABEL, "START");
2869
2870         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
2871
2872         gl_debug (DEBUG_LABEL, "END");
2873
2874         return g_strdup (label->priv->default_font_family);
2875 }
2876
2877
2878 /****************************************************************************/
2879 /* Get default font size.                                                   */
2880 /****************************************************************************/
2881 gdouble
2882 gl_label_get_default_font_size (glLabel *label)
2883 {
2884         gl_debug (DEBUG_LABEL, "START");
2885
2886         g_return_val_if_fail (label && GL_IS_LABEL (label), 12.0);
2887
2888         gl_debug (DEBUG_LABEL, "END");
2889
2890         return label->priv->default_font_size;
2891 }
2892
2893
2894 /****************************************************************************/
2895 /* Get default font weight.                                                 */
2896 /****************************************************************************/
2897 PangoWeight
2898 gl_label_get_default_font_weight (glLabel *label)
2899 {
2900         gl_debug (DEBUG_LABEL, "START");
2901
2902         g_return_val_if_fail (label && GL_IS_LABEL (label), PANGO_WEIGHT_NORMAL);
2903
2904         gl_debug (DEBUG_LABEL, "END");
2905
2906         return label->priv->default_font_weight;
2907 }
2908
2909
2910 /****************************************************************************/
2911 /* Get default font italic flag.                                            */
2912 /****************************************************************************/
2913 gboolean
2914 gl_label_get_default_font_italic_flag (glLabel *label)
2915 {
2916         gl_debug (DEBUG_LABEL, "START");
2917
2918         g_return_val_if_fail (label && GL_IS_LABEL (label), FALSE);
2919
2920         gl_debug (DEBUG_LABEL, "END");
2921
2922         return label->priv->default_font_italic_flag;
2923 }
2924
2925
2926 /****************************************************************************/
2927 /* Get default text color.                                                  */
2928 /****************************************************************************/
2929 guint
2930 gl_label_get_default_text_color (glLabel *label)
2931 {
2932         gl_debug (DEBUG_LABEL, "START");
2933
2934         g_return_val_if_fail (label && GL_IS_LABEL (label), 0);
2935
2936         gl_debug (DEBUG_LABEL, "END");
2937
2938         return label->priv->default_text_color;
2939 }
2940
2941
2942 /****************************************************************************/
2943 /* Get default text alignment.                                              */
2944 /****************************************************************************/
2945 PangoAlignment
2946 gl_label_get_default_text_alignment (glLabel *label)
2947 {
2948         gl_debug (DEBUG_LABEL, "START");
2949
2950         g_return_val_if_fail (label && GL_IS_LABEL (label), PANGO_ALIGN_LEFT);
2951
2952         gl_debug (DEBUG_LABEL, "END");
2953
2954         return label->priv->default_text_alignment;
2955 }
2956
2957
2958 /****************************************************************************/
2959 /* Get default text line spacing.                                           */
2960 /****************************************************************************/
2961 gdouble
2962 gl_label_get_default_text_line_spacing (glLabel *label)
2963 {
2964         gl_debug (DEBUG_LABEL, "START");
2965
2966         g_return_val_if_fail (label && GL_IS_LABEL (label), 1.0);
2967
2968         gl_debug (DEBUG_LABEL, "END");
2969
2970         return label->priv->default_text_line_spacing;
2971 }
2972
2973
2974 /****************************************************************************/
2975 /* Get default line width.                                                  */
2976 /****************************************************************************/
2977 gdouble
2978 gl_label_get_default_line_width (glLabel *label)
2979 {
2980         gl_debug (DEBUG_LABEL, "START");
2981
2982         g_return_val_if_fail (label && GL_IS_LABEL (label), 1.0);
2983
2984         gl_debug (DEBUG_LABEL, "END");
2985
2986         return label->priv->default_line_width;
2987 }
2988
2989
2990 /****************************************************************************/
2991 /* Get default line color.                                                  */
2992 /****************************************************************************/
2993 guint
2994 gl_label_get_default_line_color (glLabel *label)
2995 {
2996         gl_debug (DEBUG_LABEL, "START");
2997
2998         g_return_val_if_fail (label && GL_IS_LABEL (label), 0);
2999
3000         gl_debug (DEBUG_LABEL, "END");
3001
3002         return label->priv->default_line_color;
3003 }
3004
3005
3006 /****************************************************************************/
3007 /* Get default fill color.                                                  */
3008 /****************************************************************************/
3009 guint
3010 gl_label_get_default_fill_color (glLabel *label)
3011 {
3012         gl_debug (DEBUG_LABEL, "START");
3013
3014         g_return_val_if_fail (label && GL_IS_LABEL (label), 0);
3015
3016         gl_debug (DEBUG_LABEL, "END");
3017
3018         return label->priv->default_fill_color;
3019 }
3020
3021
3022 /****************************************************************************/
3023 /* Draw label.                                                              */
3024 /****************************************************************************/
3025 void
3026 gl_label_draw (glLabel       *label,
3027                cairo_t       *cr,
3028                gboolean       screen_flag,
3029                glMergeRecord *record)
3030 {
3031         GList            *p_obj;
3032         glLabelObject    *object;
3033
3034         g_return_if_fail (label && GL_IS_LABEL (label));
3035
3036         for (p_obj = label->priv->object_list; p_obj != NULL; p_obj = p_obj->next)
3037         {
3038                 object = GL_LABEL_OBJECT (p_obj->data);
3039
3040                 gl_label_object_draw (object, cr, screen_flag, record);
3041         }
3042 }
3043
3044
3045 /****************************************************************************/
3046 /* Get object located at coordinates.                                       */
3047 /****************************************************************************/
3048 glLabelObject *gl_label_object_at              (glLabel       *label,
3049                                                 cairo_t       *cr,
3050                                                 gdouble        x_pixels,
3051                                                 gdouble        y_pixels)
3052 {
3053         GList            *p_obj;
3054         glLabelObject    *object;
3055
3056         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
3057
3058         for (p_obj = g_list_last (label->priv->object_list); p_obj != NULL; p_obj = p_obj->prev)
3059         {
3060                 object = GL_LABEL_OBJECT (p_obj->data);
3061
3062                 if (gl_label_object_is_located_at (object, cr, x_pixels, y_pixels))
3063                 {
3064                         return object;
3065                 }
3066
3067         }
3068
3069         return NULL;
3070 }
3071
3072
3073 /****************************************************************************/
3074 /* Return handle and associated object at coordinates.                      */
3075 /****************************************************************************/
3076 glLabelObject *
3077 gl_label_get_handle_at (glLabel             *label,
3078                         cairo_t             *cr,
3079                         gdouble              x_pixels,
3080                         gdouble              y_pixels,
3081                         glLabelObjectHandle *handle)
3082 {
3083         GList            *selection_list;
3084         GList            *p_obj;
3085         glLabelObject    *object;
3086
3087         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
3088
3089         selection_list = gl_label_get_selection_list (label);
3090
3091         for (p_obj = g_list_last (selection_list); p_obj != NULL; p_obj = p_obj->prev)
3092         {
3093
3094                 object = GL_LABEL_OBJECT (p_obj->data);
3095
3096                 if ((*handle = gl_label_object_handle_at (object, cr, x_pixels, y_pixels)))
3097                 {
3098                         g_list_free (selection_list);
3099                         return object;
3100                 }
3101
3102         }
3103
3104         g_list_free (selection_list);
3105
3106         *handle = GL_LABEL_OBJECT_HANDLE_NONE;
3107         return NULL;
3108 }
3109
3110
3111 /****************************************************************************/
3112 /* Checkpoint state.                                                        */
3113 /****************************************************************************/
3114 void
3115 gl_label_checkpoint (glLabel       *this,
3116                      const gchar   *description)
3117 {
3118         State *state;
3119
3120         gl_debug (DEBUG_LABEL, "START");
3121
3122         /*
3123          * Do not perform consecutive checkpoints that are identical.
3124          * E.g. moving an object by dragging, would produce a large number
3125          * of incremental checkpoints -- what we really want is a single
3126          * checkpoint so that we can undo the entire dragging effort with
3127          * one "undo"
3128          */
3129         if ( this->priv->cp_cleared_flag
3130              || (this->priv->cp_desc == NULL)
3131              || (strcmp (description, this->priv->cp_desc) != 0) )
3132         {
3133
3134                 /* Sever old redo "thread" */
3135                 stack_clear (this->priv->redo_stack);
3136
3137                 /* Save state onto undo stack. */
3138                 state = state_new (this, description);
3139                 stack_push_state (this->priv->undo_stack, state);
3140
3141                 /* Track consecutive checkpoints. */
3142                 this->priv->cp_cleared_flag = FALSE;
3143                 this->priv->cp_desc         = g_strdup (description);
3144         }
3145
3146         gl_debug (DEBUG_LABEL, "END");
3147 }
3148
3149
3150 /****************************************************************************/
3151 /* Undo.                                                                    */
3152 /****************************************************************************/
3153 void
3154 gl_label_undo (glLabel       *this)
3155 {
3156         State *state_old;
3157         State *state_now;
3158
3159         gl_debug (DEBUG_LABEL, "START");
3160
3161         state_old = stack_pop_state (this->priv->undo_stack);
3162         state_now = state_new (this, state_old->description);
3163
3164         stack_push_state (this->priv->redo_stack, state_now);
3165
3166         state_restore (state_old, this);
3167         state_free (state_old);
3168
3169         this->priv->cp_cleared_flag = TRUE;
3170
3171         gl_debug (DEBUG_LABEL, "END");
3172 }
3173
3174
3175 /****************************************************************************/
3176 /* Redo.                                                                    */
3177 /****************************************************************************/
3178 void
3179 gl_label_redo (glLabel       *this)
3180 {
3181         State *state_old;
3182         State *state_now;
3183
3184         gl_debug (DEBUG_LABEL, "START");
3185
3186         state_old = stack_pop_state (this->priv->redo_stack);
3187         state_now = state_new (this, state_old->description);
3188
3189         stack_push_state (this->priv->undo_stack, state_now);
3190
3191         state_restore (state_old, this);
3192         state_free (state_old);
3193
3194         this->priv->cp_cleared_flag = TRUE;
3195
3196         gl_debug (DEBUG_LABEL, "END");
3197 }
3198
3199
3200 /****************************************************************************/
3201 /* Can undo?                                                                */
3202 /****************************************************************************/
3203 gboolean
3204 gl_label_can_undo (glLabel *this)
3205 {
3206         return (!g_queue_is_empty (this->priv->undo_stack));
3207 }
3208
3209
3210 /****************************************************************************/
3211 /* Can redo?                                                                */
3212 /****************************************************************************/
3213 gboolean
3214 gl_label_can_redo (glLabel *this)
3215 {
3216         return (!g_queue_is_empty (this->priv->redo_stack));
3217 }
3218
3219
3220 /****************************************************************************/
3221 /* Get undo description string.                                             */
3222 /****************************************************************************/
3223 gchar *
3224 gl_label_get_undo_description (glLabel *this)
3225 {
3226         State *state;
3227         gchar *description;
3228
3229         state = g_queue_peek_head (this->priv->undo_stack);
3230         if ( state )
3231         {
3232                 description = g_strdup (state->description);
3233         }
3234         else
3235         {
3236                 description = g_strdup ("");
3237         }
3238
3239         return description;
3240 }
3241
3242
3243 /****************************************************************************/
3244 /* Get redo description string.                                             */
3245 /****************************************************************************/
3246 gchar *
3247 gl_label_get_redo_description (glLabel *this)
3248 {
3249         State *state;
3250         gchar *description;
3251
3252         state = g_queue_peek_head (this->priv->redo_stack);
3253         if ( state )
3254         {
3255                 description = g_strdup (state->description);
3256         }
3257         else
3258         {
3259                 description = g_strdup ("");
3260         }
3261
3262         return description;
3263 }
3264
3265
3266 /****************************************************************************/
3267 /* Clear undo or redo stack.                                                */
3268 /****************************************************************************/
3269 static void
3270 stack_clear (GQueue *stack)
3271 {
3272         State *state;
3273
3274         gl_debug (DEBUG_LABEL, "START");
3275
3276         while ( (state = g_queue_pop_head (stack)) != NULL )
3277         {
3278                 state_free (state);
3279         }
3280
3281         gl_debug (DEBUG_LABEL, "END");
3282 }
3283
3284
3285 /****************************************************************************/
3286 /* Push state onto stack.                                                   */
3287 /****************************************************************************/
3288 static void
3289 stack_push_state (GQueue *stack,
3290                   State  *state)
3291 {
3292         gl_debug (DEBUG_LABEL, "START");
3293
3294         g_queue_push_head( stack, state );
3295
3296         gl_debug (DEBUG_LABEL, "END");
3297 }
3298
3299
3300 /****************************************************************************/
3301 /* Pop state from stack.                                                    */
3302 /****************************************************************************/
3303 static State *
3304 stack_pop_state (GQueue *stack)
3305 {
3306         State *state;
3307
3308         gl_debug (DEBUG_LABEL, "START");
3309
3310         state = g_queue_pop_head (stack);
3311
3312         gl_debug (DEBUG_LABEL, "END");
3313         return state;
3314 }
3315
3316
3317 /****************************************************************************/
3318 /* New state from label.                                                    */
3319 /****************************************************************************/
3320 static State *
3321 state_new (glLabel       *this,
3322            const gchar   *description)
3323 {
3324         State          *state;
3325         GList          *p_obj;
3326         glLabelObject  *object;
3327
3328         gl_debug (DEBUG_LABEL, "START");
3329
3330         state = g_new0 (State, 1);
3331
3332         state->description = g_strdup (description);
3333
3334         state->template    = lgl_template_dup (this->priv->template);
3335         state->rotate_flag = this->priv->rotate_flag;
3336
3337         for ( p_obj = this->priv->object_list; p_obj != NULL; p_obj = p_obj->next )
3338         {
3339                 object = GL_LABEL_OBJECT (p_obj->data);
3340
3341                 state->object_list = g_list_append (state->object_list,
3342                                                     gl_label_object_dup (object, this));
3343         }
3344
3345         state->merge = gl_merge_dup (this->priv->merge);
3346
3347         state->modified_flag = this->priv->modified_flag;
3348         state->time_stamp    = this->priv->time_stamp;
3349
3350
3351         gl_debug (DEBUG_LABEL, "END");
3352         return state;
3353 }
3354
3355
3356 /****************************************************************************/
3357 /* Restore label from saved state.                                          */
3358 /****************************************************************************/
3359 static void
3360 state_free (State   *state)
3361 {
3362         GList          *p_obj;
3363
3364         gl_debug (DEBUG_LABEL, "START");
3365
3366         g_free (state->description);
3367
3368         lgl_template_free (state->template);
3369         if ( state->merge )
3370         {
3371                 g_object_unref (G_OBJECT (state->merge));
3372         }
3373
3374         for ( p_obj = state->object_list; p_obj != NULL; p_obj = p_obj->next )
3375         {
3376                 g_object_unref (G_OBJECT (p_obj->data));
3377         }
3378         g_list_free (state->object_list);
3379
3380         g_free (state);
3381
3382         gl_debug (DEBUG_LABEL, "END");
3383 }
3384
3385
3386 /****************************************************************************/
3387 /* Restore label from saved state.                                          */
3388 /****************************************************************************/
3389 static void
3390 state_restore (State   *state,
3391                glLabel *this)
3392                
3393 {
3394         GList          *p_obj, *p_next;
3395         glLabelObject  *object;
3396
3397         gl_debug (DEBUG_LABEL, "START");
3398
3399         gl_label_set_rotate_flag (this, state->rotate_flag, FALSE);
3400         gl_label_set_template (this, state->template, FALSE);
3401
3402         for ( p_obj = this->priv->object_list; p_obj != NULL; p_obj = p_next )
3403         {
3404                 p_next = p_obj->next; /* Hold on to next; delete is destructive */
3405                 object = GL_LABEL_OBJECT (p_obj->data);
3406
3407                 gl_label_delete_object (this, object);
3408         }
3409
3410         for ( p_obj = state->object_list; p_obj != NULL; p_obj = p_obj->next )
3411         {
3412                 object = GL_LABEL_OBJECT (p_obj->data);
3413
3414                 gl_label_add_object (this, gl_label_object_dup (object, this));
3415         }
3416         g_signal_emit (G_OBJECT(this), signals[SELECTION_CHANGED], 0);
3417
3418         gl_label_set_merge (this, state->merge, FALSE);
3419         
3420
3421         if ( !state->modified_flag &&
3422              (state->time_stamp.tv_sec  == this->priv->time_stamp.tv_sec) &&
3423              (state->time_stamp.tv_usec == this->priv->time_stamp.tv_usec) )
3424         {
3425                 gl_label_clear_modified (this);
3426         }
3427
3428         gl_debug (DEBUG_LABEL, "END");
3429 }
3430
3431
3432
3433
3434 /*
3435  * Local Variables:       -- emacs
3436  * mode: C                -- emacs
3437  * c-basic-offset: 8      -- emacs
3438  * tab-width: 8           -- emacs
3439  * indent-tabs-mode: nil  -- emacs
3440  * End:                   -- emacs
3441  */