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