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