]> git.sur5r.net Git - glabels/blob - src/label.c
Imported Upstream version 3.2.0
[glabels] / src / label.c
1 /*
2  *  label.c
3  *  Copyright (C) 2001-2009  Jim Evins <evins@snaught.com>.
4  *
5  *  This file is part of gLabels.
6  *
7  *  gLabels is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  gLabels is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with gLabels.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #include "label.h"
24
25 #include <glib/gi18n.h>
26 #include <math.h>
27
28 #include "template-history.h"
29 #include "file-util.h"
30 #include "xml-label.h"
31 #include "prefs.h"
32 #include "label-text.h"
33 #include "label-image.h"
34 #include "marshal.h"
35
36 #include "debug.h"
37
38
39 /*========================================================*/
40 /* Private macros and constants.                          */
41 /*========================================================*/
42
43
44 /*========================================================*/
45 /* Private types.                                         */
46 /*========================================================*/
47
48 struct _glLabelPrivate {
49
50         gchar       *filename;
51         gint         compression;
52         gint         untitled_instance;
53
54         gboolean     modified_flag;
55         GTimeVal     time_stamp;
56
57         lglTemplate *template;
58         gboolean     rotate_flag;
59
60         GList       *object_list;
61
62         glMerge     *merge;
63
64         GHashTable  *pixbuf_cache;
65         GHashTable  *svg_cache;
66
67         /* Delay changed signals while operating on selections of multiple objects. */
68         gboolean     selection_op_flag;
69         gboolean     delayed_change_flag;
70
71         /* Default object text properties */
72         gchar             *default_font_family;
73         gdouble            default_font_size;
74         PangoWeight        default_font_weight;
75         gboolean           default_font_italic_flag;
76         guint              default_text_color;
77         PangoAlignment     default_text_alignment;
78         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         g_signal_emit (G_OBJECT(label), signals[SELECTION_CHANGED], 0);
1234
1235         gl_debug (DEBUG_LABEL, "END");
1236 }
1237
1238
1239 /****************************************************************************/
1240 /* Bring selection object to front/top.                                     */
1241 /****************************************************************************/
1242 void
1243 gl_label_raise_selection_to_top (glLabel       *label)
1244 {
1245         GList         *selection_list;
1246         GList         *p;
1247         glLabelObject *object;
1248
1249         gl_debug (DEBUG_LABEL, "START");
1250
1251         gl_label_checkpoint (label, _("Bring to front"));
1252
1253         begin_selection_op (label);
1254
1255         selection_list = gl_label_get_selection_list (label);
1256
1257         for ( p = selection_list; p != NULL; p = p->next )
1258         {
1259                 object = GL_LABEL_OBJECT (p->data);
1260
1261                 label->priv->object_list = g_list_remove (label->priv->object_list, object);
1262         }
1263
1264         /* Move to end of list, representing front most object */
1265         label->priv->object_list = g_list_concat (label->priv->object_list, selection_list);
1266
1267         do_modify (label);
1268
1269         end_selection_op (label);
1270
1271         gl_debug (DEBUG_LABEL, "END");
1272 }
1273
1274
1275 /****************************************************************************/
1276 /* Send selection to rear/bottom.                                           */
1277 /****************************************************************************/
1278 void
1279 gl_label_lower_selection_to_bottom (glLabel       *label)
1280 {
1281         GList         *selection_list;
1282         GList         *p;
1283         glLabelObject *object;
1284
1285         gl_debug (DEBUG_LABEL, "START");
1286
1287         gl_label_checkpoint (label, _("Send to back"));
1288
1289         begin_selection_op (label);
1290
1291         selection_list = gl_label_get_selection_list (label);
1292
1293         for ( p = selection_list; p != NULL; p = p->next )
1294         {
1295                 object = GL_LABEL_OBJECT (p->data);
1296
1297                 label->priv->object_list = g_list_remove (label->priv->object_list, object);
1298         }
1299
1300         /* Move to front of list, representing rear most object */
1301         label->priv->object_list = g_list_concat (selection_list, label->priv->object_list);
1302
1303         do_modify (label);
1304
1305         end_selection_op (label);
1306
1307         gl_debug (DEBUG_LABEL, "END");
1308 }
1309
1310
1311 /*****************************************************************************/
1312 /* Rotate selected objects by given angle.                                   */
1313 /*****************************************************************************/
1314 void
1315 gl_label_rotate_selection (glLabel *label,
1316                            gdouble  theta_degs)
1317 {
1318         GList         *selection_list;
1319         GList         *p;
1320         glLabelObject *object;
1321
1322         gl_debug (DEBUG_LABEL, "START");
1323
1324         g_return_if_fail (label && GL_IS_LABEL (label));
1325
1326         begin_selection_op (label);
1327
1328         gl_label_checkpoint (label, _("Rotate"));
1329
1330         selection_list = gl_label_get_selection_list (label);
1331
1332         for ( p = selection_list; p != NULL; p = p->next )
1333         {
1334                 object = GL_LABEL_OBJECT (p->data);
1335
1336                 gl_label_object_rotate (object, theta_degs);
1337         }
1338
1339         g_list_free (selection_list);
1340
1341         end_selection_op (label);
1342
1343         gl_debug (DEBUG_LABEL, "END");
1344 }
1345
1346
1347 /*****************************************************************************/
1348 /* Rotate selected objects 90 degrees left.                                  */
1349 /*****************************************************************************/
1350 void
1351 gl_label_rotate_selection_left (glLabel *label)
1352 {
1353         GList         *selection_list;
1354         GList         *p;
1355         glLabelObject *object;
1356
1357         gl_debug (DEBUG_LABEL, "START");
1358
1359         g_return_if_fail (label && GL_IS_LABEL (label));
1360
1361         begin_selection_op (label);
1362
1363         gl_label_checkpoint (label, _("Rotate left"));
1364
1365         selection_list = gl_label_get_selection_list (label);
1366
1367         for ( p = selection_list; p != NULL; p = p->next )
1368         {
1369                 object = GL_LABEL_OBJECT (p->data);
1370
1371                 gl_label_object_rotate (object, -90.0);
1372         }
1373
1374         g_list_free (selection_list);
1375
1376         end_selection_op (label);
1377
1378         gl_debug (DEBUG_LABEL, "END");
1379 }
1380
1381
1382 /*****************************************************************************/
1383 /* Rotate selected objects 90 degrees right.                                 */
1384 /*****************************************************************************/
1385 void
1386 gl_label_rotate_selection_right (glLabel *label)
1387 {
1388         GList         *selection_list;
1389         GList         *p;
1390         glLabelObject *object;
1391
1392         gl_debug (DEBUG_LABEL, "START");
1393
1394         g_return_if_fail (label && GL_IS_LABEL (label));
1395
1396         gl_label_checkpoint (label, _("Rotate right"));
1397
1398         begin_selection_op (label);
1399
1400         selection_list = gl_label_get_selection_list (label);
1401
1402         for ( p = selection_list; p != NULL; p = p->next )
1403         {
1404                 object = GL_LABEL_OBJECT (p->data);
1405
1406                 gl_label_object_rotate (object, 90.0);
1407         }
1408
1409         g_list_free (selection_list);
1410
1411         end_selection_op (label);
1412
1413         gl_debug (DEBUG_LABEL, "END");
1414 }
1415
1416
1417 /*****************************************************************************/
1418 /* Flip selected objects horizontally.                                       */
1419 /*****************************************************************************/
1420 void
1421 gl_label_flip_selection_horiz (glLabel *label)
1422 {
1423         GList         *selection_list;
1424         GList         *p;
1425         glLabelObject *object;
1426
1427         gl_debug (DEBUG_LABEL, "START");
1428
1429         g_return_if_fail (label && GL_IS_LABEL (label));
1430
1431         gl_label_checkpoint (label, _("Flip horizontally"));
1432
1433         begin_selection_op (label);
1434
1435         selection_list = gl_label_get_selection_list (label);
1436
1437         for ( p = selection_list; p != NULL; p = p->next )
1438         {
1439                 object = GL_LABEL_OBJECT (p->data);
1440
1441                 gl_label_object_flip_horiz (object);
1442         }
1443
1444         g_list_free (selection_list);
1445
1446         end_selection_op (label);
1447
1448         gl_debug (DEBUG_LABEL, "END");
1449 }
1450
1451
1452 /*****************************************************************************/
1453 /* Flip selected objects vertically.                                         */
1454 /*****************************************************************************/
1455 void
1456 gl_label_flip_selection_vert (glLabel *label)
1457 {
1458         GList         *selection_list;
1459         GList         *p;
1460         glLabelObject *object;
1461
1462         gl_debug (DEBUG_LABEL, "START");
1463
1464         g_return_if_fail (label && GL_IS_LABEL (label));
1465
1466         gl_label_checkpoint (label, _("Flip vertically"));
1467
1468         begin_selection_op (label);
1469
1470         selection_list = gl_label_get_selection_list (label);
1471
1472         for ( p = selection_list; p != NULL; p = p->next )
1473         {
1474                 object = GL_LABEL_OBJECT (p->data);
1475
1476                 gl_label_object_flip_vert (object);
1477         }
1478
1479         g_list_free (selection_list);
1480
1481         end_selection_op (label);
1482
1483         gl_debug (DEBUG_LABEL, "END");
1484 }
1485
1486
1487 /*****************************************************************************/
1488 /* Align selected objects to left most edge.                                 */
1489 /*****************************************************************************/
1490 void
1491 gl_label_align_selection_left (glLabel *label)
1492 {
1493         GList         *selection_list;
1494         GList         *p;
1495         glLabelObject *object;
1496         gdouble        dx, x1_min;
1497         glLabelRegion  obj_extent;
1498
1499         gl_debug (DEBUG_LABEL, "START");
1500
1501         g_return_if_fail (label && GL_IS_LABEL (label));
1502
1503         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1504                           !gl_label_is_selection_atomic (label));
1505
1506         gl_label_checkpoint (label, _("Align left"));
1507
1508         begin_selection_op (label);
1509
1510         selection_list = gl_label_get_selection_list (label);
1511
1512         /* find left most edge */
1513         p = selection_list;
1514         object = GL_LABEL_OBJECT (p->data);
1515
1516         gl_label_object_get_extent (object, &obj_extent);
1517         x1_min = obj_extent.x1;
1518         for (p = p->next; p != NULL; p = p->next)
1519         {
1520                 object = GL_LABEL_OBJECT (p->data);
1521
1522                 gl_label_object_get_extent (object, &obj_extent);
1523                 if ( obj_extent.x1 < x1_min ) x1_min = obj_extent.x1;
1524         }
1525
1526         /* now adjust the object positions to line up the left edges */
1527         for (p = selection_list; p != NULL; p = p->next)
1528         {
1529                 object = GL_LABEL_OBJECT (p->data);
1530
1531                 gl_label_object_get_extent (object, &obj_extent);
1532                 dx = x1_min - obj_extent.x1;
1533                 gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
1534         }
1535
1536         g_list_free (selection_list);
1537
1538         end_selection_op (label);
1539
1540         gl_debug (DEBUG_LABEL, "END");
1541 }
1542
1543
1544 /*****************************************************************************/
1545 /* Align selected objects to right most edge.                                */
1546 /*****************************************************************************/
1547 void
1548 gl_label_align_selection_right (glLabel *label)
1549 {
1550         GList         *selection_list;
1551         GList         *p;
1552         glLabelObject *object;
1553         gdouble        dx, x2_max;
1554         glLabelRegion  obj_extent;
1555
1556         gl_debug (DEBUG_LABEL, "START");
1557
1558         g_return_if_fail (label && GL_IS_LABEL (label));
1559
1560         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1561                           !gl_label_is_selection_atomic (label));
1562
1563         gl_label_checkpoint (label, _("Align right"));
1564
1565         begin_selection_op (label);
1566
1567         selection_list = gl_label_get_selection_list (label);
1568
1569         /* find left most edge */
1570         p = selection_list;
1571         object = GL_LABEL_OBJECT (p->data);
1572
1573         gl_label_object_get_extent (object, &obj_extent);
1574         x2_max = obj_extent.x2;
1575         for (p = p->next; p != NULL; p = p->next)
1576         {
1577                 object = GL_LABEL_OBJECT (p->data);
1578
1579                 gl_label_object_get_extent (object, &obj_extent);
1580                 if ( obj_extent.x2 > x2_max ) x2_max = obj_extent.x2;
1581         }
1582
1583         /* now adjust the object positions to line up the left edges */
1584         for (p = selection_list; p != NULL; p = p->next)
1585         {
1586                 object = GL_LABEL_OBJECT (p->data);
1587
1588                 gl_label_object_get_extent (object, &obj_extent);
1589                 dx = x2_max - obj_extent.x2;
1590                 gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
1591         }
1592
1593         g_list_free (selection_list);
1594
1595         end_selection_op (label);
1596
1597         gl_debug (DEBUG_LABEL, "END");
1598 }
1599
1600
1601 /*****************************************************************************/
1602 /* Align selected objects to horizontal center of objects.                   */
1603 /*****************************************************************************/
1604 void
1605 gl_label_align_selection_hcenter (glLabel *label)
1606 {
1607         GList         *selection_list;
1608         GList         *p;
1609         glLabelObject *object;
1610         gdouble        dx;
1611         gdouble        dxmin;
1612         gdouble        xsum, xavg;
1613         glLabelRegion  obj_extent;
1614         gdouble        xcenter;
1615         gint           n;
1616
1617         gl_debug (DEBUG_LABEL, "START");
1618
1619         g_return_if_fail (label && GL_IS_LABEL (label));
1620
1621         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1622                           !gl_label_is_selection_atomic (label));
1623
1624         gl_label_checkpoint (label, _("Align horizontal center"));
1625
1626         begin_selection_op (label);
1627
1628         selection_list = gl_label_get_selection_list (label);
1629
1630         /* find average center of objects */
1631         xsum = 0.0;
1632         n = 0;
1633         for (p = selection_list; p != NULL; p = p->next)
1634         {
1635                 object = GL_LABEL_OBJECT (p->data);
1636
1637                 gl_label_object_get_extent (object, &obj_extent);
1638                 xsum += (obj_extent.x1 + obj_extent.x2) / 2.0;
1639                 n++;
1640         }
1641         xavg = xsum / n;
1642
1643         /* find center of object closest to average center */
1644         p = selection_list;
1645         object = GL_LABEL_OBJECT (p->data);
1646
1647         gl_label_object_get_extent (object, &obj_extent);
1648         dxmin = fabs (xavg - (obj_extent.x1 + obj_extent.x2)/2.0);
1649         xcenter = (obj_extent.x1 + obj_extent.x2)/2.0;
1650         for (p = p->next; p != NULL; p = p->next)
1651         {
1652                 object = GL_LABEL_OBJECT (p->data);
1653
1654                 gl_label_object_get_extent (object, &obj_extent);
1655                 dx = fabs (xavg - (obj_extent.x1 + obj_extent.x2)/2.0);
1656                 if ( dx < dxmin )
1657                 {
1658                         dxmin = dx;
1659                         xcenter = (obj_extent.x1 + obj_extent.x2)/2.0;
1660                 }
1661         }
1662
1663         /* now adjust the object positions to line up this center */
1664         for (p = selection_list; p != NULL; p = p->next)
1665         {
1666                 object = GL_LABEL_OBJECT (p->data);
1667
1668                 gl_label_object_get_extent (object, &obj_extent);
1669                 dx = xcenter - (obj_extent.x1 + obj_extent.x2)/2.0;
1670                 gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
1671         }
1672
1673         g_list_free (selection_list);
1674
1675         end_selection_op (label);
1676
1677         gl_debug (DEBUG_LABEL, "END");
1678 }
1679
1680
1681 /*****************************************************************************/
1682 /* Align selected objects to top most edge.                                  */
1683 /*****************************************************************************/
1684 void
1685 gl_label_align_selection_top (glLabel *label)
1686 {
1687         GList         *selection_list;
1688         GList         *p;
1689         glLabelObject *object;
1690         gdouble        dy, y1_min;
1691         glLabelRegion  obj_extent;
1692
1693         gl_debug (DEBUG_LABEL, "START");
1694
1695         g_return_if_fail (label && GL_IS_LABEL (label));
1696
1697         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1698                           !gl_label_is_selection_atomic (label));
1699
1700         gl_label_checkpoint (label, _("Align tops"));
1701
1702         begin_selection_op (label);
1703
1704         selection_list = gl_label_get_selection_list (label);
1705
1706         /* find top most edge */
1707         p = selection_list;
1708         object = GL_LABEL_OBJECT (p->data);
1709
1710         gl_label_object_get_extent (object, &obj_extent);
1711         y1_min = obj_extent.y1;
1712         for (p = p->next; p != NULL; p = p->next)
1713         {
1714                 object = GL_LABEL_OBJECT (p->data);
1715
1716                 gl_label_object_get_extent (object, &obj_extent);
1717                 if ( obj_extent.y1 < y1_min ) y1_min = obj_extent.y1;
1718         }
1719
1720         /* now adjust the object positions to line up the top edges */
1721         for (p = selection_list; p != NULL; p = p->next)
1722         {
1723                 object = GL_LABEL_OBJECT (p->data);
1724
1725                 gl_label_object_get_extent (object, &obj_extent);
1726                 dy = y1_min - obj_extent.y1;
1727                 gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
1728         }
1729
1730         g_list_free (selection_list);
1731
1732         end_selection_op (label);
1733
1734         gl_debug (DEBUG_LABEL, "END");
1735 }
1736
1737
1738 /*****************************************************************************/
1739 /* Align selected objects to bottom most edge.                               */
1740 /*****************************************************************************/
1741 void
1742 gl_label_align_selection_bottom (glLabel *label)
1743 {
1744         GList         *selection_list;
1745         GList         *p;
1746         glLabelObject *object;
1747         gdouble        dy, y2_max;
1748         glLabelRegion  obj_extent;
1749
1750         gl_debug (DEBUG_LABEL, "START");
1751
1752         g_return_if_fail (label && GL_IS_LABEL (label));
1753
1754         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1755                           !gl_label_is_selection_atomic (label));
1756
1757         gl_label_checkpoint (label, _("Align bottoms"));
1758
1759         begin_selection_op (label);
1760
1761         selection_list = gl_label_get_selection_list (label);
1762
1763         /* find bottom most edge */
1764         p = selection_list;
1765         object = GL_LABEL_OBJECT (p->data);
1766
1767         gl_label_object_get_extent (object, &obj_extent);
1768         y2_max = obj_extent.y2;
1769         for (p = p->next; p != NULL; p = p->next)
1770         {
1771                 object = GL_LABEL_OBJECT (p->data);
1772
1773                 gl_label_object_get_extent (object, &obj_extent);
1774                 if ( obj_extent.y2 > y2_max ) y2_max = obj_extent.y2;
1775         }
1776
1777         /* now adjust the object positions to line up the bottom edges */
1778         for (p = selection_list; p != NULL; p = p->next)
1779         {
1780                 object = GL_LABEL_OBJECT (p->data);
1781
1782                 gl_label_object_get_extent (object, &obj_extent);
1783                 dy = y2_max - obj_extent.y2;
1784                 gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
1785         }
1786
1787         g_list_free (selection_list);
1788
1789         end_selection_op (label);
1790
1791         gl_debug (DEBUG_LABEL, "END");
1792 }
1793
1794
1795 /*****************************************************************************/
1796 /* Align selected objects to viertical center of objects.                    */
1797 /*****************************************************************************/
1798 void
1799 gl_label_align_selection_vcenter (glLabel *label)
1800 {
1801         GList         *selection_list;
1802         GList         *p;
1803         glLabelObject *object;
1804         gdouble        dy;
1805         gdouble        dymin;
1806         gdouble        ysum, yavg;
1807         glLabelRegion  obj_extent;
1808         gdouble        ycenter;
1809         gint           n;
1810
1811         gl_debug (DEBUG_LABEL, "START");
1812
1813         g_return_if_fail (label && GL_IS_LABEL (label));
1814
1815         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1816                           !gl_label_is_selection_atomic (label));
1817
1818         gl_label_checkpoint (label, _("Align vertical center"));
1819
1820         begin_selection_op (label);
1821
1822         selection_list = gl_label_get_selection_list (label);
1823
1824         /* find average center of objects */
1825         ysum = 0.0;
1826         n = 0;
1827         for (p = selection_list; p != NULL; p = p->next)
1828         {
1829                 object = GL_LABEL_OBJECT (p->data);
1830
1831                 gl_label_object_get_extent (object, &obj_extent);
1832                 ysum += (obj_extent.y1 + obj_extent.y2) / 2.0;
1833                 n++;
1834         }
1835         yavg = ysum / n;
1836
1837         /* find center of object closest to average center */
1838         p = selection_list;
1839         object = GL_LABEL_OBJECT (p->data);
1840
1841         gl_label_object_get_extent (object, &obj_extent);
1842         dymin = fabs (yavg - (obj_extent.y1 + obj_extent.y2)/2.0);
1843         ycenter = (obj_extent.y1 + obj_extent.y2)/2.0;
1844         for (p = p->next; p != NULL; p = p->next)
1845         {
1846                 object = GL_LABEL_OBJECT (p->data);
1847
1848                 gl_label_object_get_extent (object, &obj_extent);
1849                 dy = fabs (yavg - (obj_extent.y1 + obj_extent.y2)/2.0);
1850                 if ( dy < dymin )
1851                 {
1852                         dymin = dy;
1853                         ycenter = (obj_extent.y1 + obj_extent.y2)/2.0;
1854                 }
1855         }
1856
1857         /* now adjust the object positions to line up this center */
1858         for (p = selection_list; p != NULL; p = p->next)
1859         {
1860                 object = GL_LABEL_OBJECT (p->data);
1861
1862                 gl_label_object_get_extent (object, &obj_extent);
1863                 dy = ycenter - (obj_extent.y1 + obj_extent.y2)/2.0;
1864                 gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
1865         }
1866
1867         g_list_free (selection_list);
1868
1869         end_selection_op (label);
1870
1871         gl_debug (DEBUG_LABEL, "END");
1872 }
1873
1874
1875 /*****************************************************************************/
1876 /* Center selected objects to in center of label.                            */
1877 /*****************************************************************************/
1878 void
1879 gl_label_center_selection_horiz (glLabel *label)
1880 {
1881         GList         *selection_list;
1882         GList         *p;
1883         glLabelObject *object;
1884         gdouble        dx;
1885         gdouble        x_label_center;
1886         gdouble        x_obj_center;
1887         glLabelRegion  obj_extent;
1888         gdouble        w, h;
1889
1890         gl_debug (DEBUG_LABEL, "START");
1891
1892         g_return_if_fail (label && GL_IS_LABEL (label));
1893
1894         g_return_if_fail (!gl_label_is_selection_empty (label));
1895
1896         gl_label_checkpoint (label, _("Center horizontally"));
1897
1898         begin_selection_op (label);
1899
1900         gl_label_get_size (label, &w, &h);
1901         x_label_center = w / 2.0;
1902
1903         /* adjust the object positions */
1904         selection_list = gl_label_get_selection_list (label);
1905         for (p = selection_list; p != NULL; p = p->next)
1906         {
1907                 object = GL_LABEL_OBJECT (p->data);
1908
1909                 gl_label_object_get_extent (object, &obj_extent);
1910                 x_obj_center = (obj_extent.x1 + obj_extent.x2) / 2.0;
1911                 dx = x_label_center - x_obj_center;
1912                 gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
1913         }
1914         g_list_free (selection_list);
1915
1916         end_selection_op (label);
1917
1918         gl_debug (DEBUG_LABEL, "END");
1919 }
1920
1921
1922 /*****************************************************************************/
1923 /* Center selected objects to in center of label.                            */
1924 /*****************************************************************************/
1925 void
1926 gl_label_center_selection_vert (glLabel *label)
1927 {
1928         GList         *selection_list;
1929         GList         *p;
1930         glLabelObject *object;
1931         gdouble        dy;
1932         gdouble        y_label_center;
1933         gdouble        y_obj_center;
1934         glLabelRegion  obj_extent;
1935         gdouble        w, h;
1936
1937         gl_debug (DEBUG_LABEL, "START");
1938
1939         g_return_if_fail (label && GL_IS_LABEL (label));
1940
1941         g_return_if_fail (!gl_label_is_selection_empty (label));
1942
1943         gl_label_checkpoint (label, _("Center vertically"));
1944
1945         begin_selection_op (label);
1946
1947         gl_label_get_size (label, &w, &h);
1948         y_label_center = h / 2.0;
1949
1950         /* adjust the object positions */
1951         selection_list = gl_label_get_selection_list (label);
1952         for (p = selection_list; p != NULL; p = p->next)
1953         {
1954                 object = GL_LABEL_OBJECT (p->data);
1955
1956                 gl_label_object_get_extent (object, &obj_extent);
1957                 y_obj_center = (obj_extent.y1 + obj_extent.y2) / 2.0;
1958                 dy = y_label_center - y_obj_center;
1959                 gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
1960         }
1961         g_list_free (selection_list);
1962
1963         end_selection_op (label);
1964
1965         gl_debug (DEBUG_LABEL, "END");
1966 }
1967
1968
1969 /*****************************************************************************/
1970 /* Move selected objects                                                     */
1971 /*****************************************************************************/
1972 void
1973 gl_label_move_selection (glLabel  *label,
1974                          gdouble   dx,
1975                          gdouble   dy)
1976 {
1977         GList         *selection_list;
1978         GList         *p;
1979         glLabelObject *object;
1980
1981         gl_debug (DEBUG_LABEL, "START");
1982
1983         g_return_if_fail (label && GL_IS_LABEL (label));
1984
1985         begin_selection_op (label);
1986
1987         selection_list = gl_label_get_selection_list (label);
1988
1989         for (p = selection_list; p != NULL; p = p->next)
1990         {
1991                 object = GL_LABEL_OBJECT (p->data);
1992
1993                 gl_label_object_set_position_relative (object, dx, dy, TRUE);
1994         }
1995
1996         g_list_free (selection_list);
1997
1998         end_selection_op (label);
1999
2000         gl_debug (DEBUG_LABEL, "END");
2001 }
2002
2003
2004 /*****************************************************************************/
2005 /* Set font family for all text contained in selected objects.               */
2006 /*****************************************************************************/
2007 void
2008 gl_label_set_selection_font_family (glLabel      *label,
2009                                     const gchar  *font_family)
2010 {
2011         GList         *selection_list;
2012         GList         *p;
2013         glLabelObject *object;
2014
2015         gl_debug (DEBUG_LABEL, "START");
2016
2017         g_return_if_fail (label && GL_IS_LABEL (label));
2018
2019         begin_selection_op (label);
2020
2021         selection_list = gl_label_get_selection_list (label);
2022
2023         for (p = selection_list; p != NULL; p = p->next)
2024         {
2025                 object = GL_LABEL_OBJECT (p->data);
2026                 gl_label_object_set_font_family (object, font_family, TRUE);
2027         }
2028
2029         g_list_free (selection_list);
2030
2031         end_selection_op (label);
2032
2033         gl_debug (DEBUG_LABEL, "END");
2034 }
2035
2036
2037 /*****************************************************************************/
2038 /* Set font size for all text contained in selected objects.                 */
2039 /*****************************************************************************/
2040 void
2041 gl_label_set_selection_font_size (glLabel  *label,
2042                                   gdouble   font_size)
2043 {
2044         GList         *selection_list;
2045         GList         *p;
2046         glLabelObject *object;
2047
2048         gl_debug (DEBUG_LABEL, "START");
2049
2050         g_return_if_fail (label && GL_IS_LABEL (label));
2051
2052         begin_selection_op (label);
2053
2054         selection_list = gl_label_get_selection_list (label);
2055
2056         for (p = selection_list; p != NULL; p = p->next)
2057         {
2058                 object = GL_LABEL_OBJECT (p->data);
2059                 gl_label_object_set_font_size (object, font_size, TRUE);
2060         }
2061
2062         g_list_free (selection_list);
2063
2064         end_selection_op (label);
2065
2066         gl_debug (DEBUG_LABEL, "END");
2067 }
2068
2069
2070 /*****************************************************************************/
2071 /* Set font weight for all text contained in selected objects.               */
2072 /*****************************************************************************/
2073 void
2074 gl_label_set_selection_font_weight (glLabel      *label,
2075                                     PangoWeight   font_weight)
2076 {
2077         GList         *selection_list;
2078         GList         *p;
2079         glLabelObject *object;
2080
2081         gl_debug (DEBUG_LABEL, "START");
2082
2083         g_return_if_fail (label && GL_IS_LABEL (label));
2084
2085         begin_selection_op (label);
2086
2087         selection_list = gl_label_get_selection_list (label);
2088
2089         for (p = selection_list; p != NULL; p = p->next)
2090         {
2091                 object = GL_LABEL_OBJECT (p->data);
2092                 gl_label_object_set_font_weight (object, font_weight, TRUE);
2093         }
2094
2095         g_list_free (selection_list);
2096
2097         end_selection_op (label);
2098
2099         gl_debug (DEBUG_LABEL, "END");
2100 }
2101
2102
2103 /*****************************************************************************/
2104 /* Set font italic flag for all text contained in selected objects.          */
2105 /*****************************************************************************/
2106 void
2107 gl_label_set_selection_font_italic_flag (glLabel   *label,
2108                                          gboolean   font_italic_flag)
2109 {
2110         GList         *selection_list;
2111         GList         *p;
2112         glLabelObject *object;
2113
2114         gl_debug (DEBUG_LABEL, "START");
2115
2116         g_return_if_fail (label && GL_IS_LABEL (label));
2117
2118         begin_selection_op (label);
2119
2120         selection_list = gl_label_get_selection_list (label);
2121
2122         for (p = selection_list; p != NULL; p = p->next)
2123         {
2124                 object = GL_LABEL_OBJECT (p->data);
2125                 gl_label_object_set_font_italic_flag (object, font_italic_flag, TRUE);
2126         }
2127
2128         g_list_free (selection_list);
2129
2130         end_selection_op (label);
2131
2132         gl_debug (DEBUG_LABEL, "END");
2133 }
2134
2135
2136 /*****************************************************************************/
2137 /* Set text alignment for all text contained in selected objects.            */
2138 /*****************************************************************************/
2139 void
2140 gl_label_set_selection_text_alignment (glLabel        *label,
2141                                        PangoAlignment  text_alignment)
2142 {
2143         GList         *selection_list;
2144         GList         *p;
2145         glLabelObject *object;
2146
2147         gl_debug (DEBUG_LABEL, "START");
2148
2149         g_return_if_fail (label && GL_IS_LABEL (label));
2150
2151         begin_selection_op (label);
2152
2153         selection_list = gl_label_get_selection_list (label);
2154
2155         for (p = selection_list; p != NULL; p = p->next)
2156         {
2157                 object = GL_LABEL_OBJECT (p->data);
2158                 gl_label_object_set_text_alignment (object, text_alignment, TRUE);
2159         }
2160
2161         g_list_free (selection_list);
2162
2163         end_selection_op (label);
2164
2165         gl_debug (DEBUG_LABEL, "END");
2166 }
2167
2168
2169 /*****************************************************************************/
2170 /* Set vertical text alignment for all text contained in selected objects.   */
2171 /*****************************************************************************/
2172 void
2173 gl_label_set_selection_text_valignment (glLabel        *label,
2174                                         glValignment    text_valignment)
2175 {
2176         GList         *selection_list;
2177         GList         *p;
2178         glLabelObject *object;
2179
2180         gl_debug (DEBUG_LABEL, "START");
2181
2182         g_return_if_fail (label && GL_IS_LABEL (label));
2183
2184         begin_selection_op (label);
2185
2186         selection_list = gl_label_get_selection_list (label);
2187
2188         for (p = selection_list; p != NULL; p = p->next)
2189         {
2190                 object = GL_LABEL_OBJECT (p->data);
2191                 gl_label_object_set_text_valignment (object, text_valignment, TRUE);
2192         }
2193
2194         g_list_free (selection_list);
2195
2196         end_selection_op (label);
2197
2198         gl_debug (DEBUG_LABEL, "END");
2199 }
2200
2201
2202 /*****************************************************************************/
2203 /* Set text line spacing for all text contained in selected objects.         */
2204 /*****************************************************************************/
2205 void
2206 gl_label_set_selection_text_line_spacing (glLabel  *label,
2207                                           gdouble   text_line_spacing)
2208 {
2209         GList         *selection_list;
2210         GList         *p;
2211         glLabelObject *object;
2212
2213         gl_debug (DEBUG_LABEL, "START");
2214
2215         g_return_if_fail (label && GL_IS_LABEL (label));
2216
2217         begin_selection_op (label);
2218
2219         selection_list = gl_label_get_selection_list (label);
2220
2221         for (p = selection_list; p != NULL; p = p->next)
2222         {
2223                 object = GL_LABEL_OBJECT (p->data);
2224                 gl_label_object_set_text_line_spacing (object, text_line_spacing, TRUE);
2225         }
2226
2227         g_list_free (selection_list);
2228
2229         end_selection_op (label);
2230
2231         gl_debug (DEBUG_LABEL, "END");
2232 }
2233
2234
2235 /*****************************************************************************/
2236 /* Set text color for all text contained in selected objects.                */
2237 /*****************************************************************************/
2238 void
2239 gl_label_set_selection_text_color (glLabel      *label,
2240                                    glColorNode  *text_color_node)
2241 {
2242         GList         *selection_list;
2243         GList         *p;
2244         glLabelObject *object;
2245
2246         gl_debug (DEBUG_LABEL, "START");
2247
2248         g_return_if_fail (label && GL_IS_LABEL (label));
2249
2250         begin_selection_op (label);
2251
2252         selection_list = gl_label_get_selection_list (label);
2253
2254         for (p = selection_list; p != NULL; p = p->next)
2255         {
2256                 object = GL_LABEL_OBJECT (p->data);
2257                 gl_label_object_set_text_color (object, text_color_node, TRUE);
2258         }
2259
2260         g_list_free (selection_list);
2261
2262         end_selection_op (label);
2263
2264         gl_debug (DEBUG_LABEL, "END");
2265 }
2266
2267
2268 /*****************************************************************************/
2269 /* Set fill color for all selected objects.                                  */
2270 /*****************************************************************************/
2271 void
2272 gl_label_set_selection_fill_color (glLabel      *label,
2273                                    glColorNode  *fill_color_node)
2274 {
2275         GList         *selection_list;
2276         GList         *p;
2277         glLabelObject *object;
2278
2279         gl_debug (DEBUG_LABEL, "START");
2280
2281         g_return_if_fail (label && GL_IS_LABEL (label));
2282
2283         begin_selection_op (label);
2284
2285         selection_list = gl_label_get_selection_list (label);
2286
2287         for (p = selection_list; p != NULL; p = p->next)
2288         {
2289                 object = GL_LABEL_OBJECT (p->data);
2290                 gl_label_object_set_fill_color (object, fill_color_node, TRUE);
2291         }
2292
2293         g_list_free (selection_list);
2294
2295         end_selection_op (label);
2296
2297         gl_debug (DEBUG_LABEL, "END");
2298 }
2299
2300
2301 /*****************************************************************************/
2302 /* Set line color for all selected objects.                                  */
2303 /*****************************************************************************/
2304 void
2305 gl_label_set_selection_line_color (glLabel      *label,
2306                                    glColorNode  *line_color_node)
2307 {
2308         GList         *selection_list;
2309         GList         *p;
2310         glLabelObject *object;
2311
2312         gl_debug (DEBUG_LABEL, "START");
2313
2314         g_return_if_fail (label && GL_IS_LABEL (label));
2315
2316         begin_selection_op (label);
2317
2318         selection_list = gl_label_get_selection_list (label);
2319
2320         for (p = selection_list; p != NULL; p = p->next)
2321         {
2322                 object = GL_LABEL_OBJECT (p->data);
2323                 gl_label_object_set_line_color (object, line_color_node, TRUE);
2324         }
2325
2326         g_list_free (selection_list);
2327
2328         end_selection_op (label);
2329
2330         gl_debug (DEBUG_LABEL, "END");
2331 }
2332
2333
2334 /*****************************************************************************/
2335 /* Set line width for all selected objects.                                  */
2336 /*****************************************************************************/
2337 void
2338 gl_label_set_selection_line_width (glLabel  *label,
2339                                   gdouble  line_width)
2340 {
2341         GList         *selection_list;
2342         GList         *p;
2343         glLabelObject *object;
2344
2345         gl_debug (DEBUG_LABEL, "START");
2346
2347         g_return_if_fail (label && GL_IS_LABEL (label));
2348
2349         begin_selection_op (label);
2350
2351         selection_list = gl_label_get_selection_list (label);
2352
2353         for (p = selection_list; p != NULL; p = p->next)
2354         {
2355                 object = GL_LABEL_OBJECT (p->data);
2356                 gl_label_object_set_line_width (object, line_width, TRUE);
2357         }
2358
2359         g_list_free (selection_list);
2360
2361         end_selection_op (label);
2362
2363         gl_debug (DEBUG_LABEL, "END");
2364 }
2365
2366
2367 /*****************************************************************************/
2368 /* "Cut" selected items and place on clipboard.                              */
2369 /*****************************************************************************/
2370 void
2371 gl_label_cut_selection (glLabel       *label)
2372 {
2373         gl_debug (DEBUG_LABEL, "START");
2374
2375         g_return_if_fail (label && GL_IS_LABEL (label));
2376
2377         gl_label_copy_selection (label);
2378         gl_label_delete_selection (label);
2379
2380         gl_debug (DEBUG_LABEL, "END");
2381 }
2382
2383
2384 /*****************************************************************************/
2385 /* "Copy" selected items to clipboard.                                       */
2386 /*****************************************************************************/
2387 void
2388 gl_label_copy_selection (glLabel       *label)
2389 {
2390         GtkClipboard      *clipboard;
2391         GList             *selection_list;
2392         glLabel           *label_copy;
2393         GList             *p;
2394         glLabelObject     *object;
2395         glXMLLabelStatus   status;
2396
2397         ClipboardData     *data;
2398
2399         static GtkTargetEntry glabels_targets[] = { { "application/glabels", 0, 0 },
2400                                                     { "text/xml",            0, 0 },
2401         };
2402
2403         GtkTargetList  *target_list;
2404         GtkTargetEntry *target_table;
2405         gint            n_targets;
2406
2407         gl_debug (DEBUG_LABEL, "START");
2408
2409         g_return_if_fail (label && GL_IS_LABEL (label));
2410
2411         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2412
2413         selection_list = gl_label_get_selection_list (label);
2414
2415         if (selection_list)
2416         {
2417
2418                 data = g_new0 (ClipboardData, 1);
2419
2420                 target_list = gtk_target_list_new (glabels_targets, G_N_ELEMENTS(glabels_targets));
2421
2422                 /*
2423                  * Serialize selection by encoding as an XML label document.
2424                  */
2425                 label_copy = GL_LABEL(gl_label_new ());
2426
2427                 gl_label_set_template (label_copy, label->priv->template, FALSE);
2428                 gl_label_set_rotate_flag (label_copy, label->priv->rotate_flag, FALSE);
2429
2430                 for (p = selection_list; p != NULL; p = p->next)
2431                 {
2432                         object = GL_LABEL_OBJECT (p->data);
2433
2434                         gl_label_add_object (label_copy, gl_label_object_dup (object, label_copy));
2435                 }
2436
2437                 data->xml_buffer = gl_xml_label_save_buffer (label_copy, &status);
2438
2439                 g_object_unref (G_OBJECT (label_copy));
2440
2441
2442                 /*
2443                  * Is it an atomic text selection?  If so, also make available as text.
2444                  */
2445                 if ( gl_label_is_selection_atomic (label) &&
2446                      GL_IS_LABEL_TEXT (selection_list->data) )
2447                 {
2448                         glLabelText *text_object = GL_LABEL_TEXT (selection_list->data);
2449
2450                         gtk_target_list_add_text_targets (target_list, 1);
2451
2452                         data->text = gl_label_text_get_text (text_object);
2453                 }
2454
2455
2456                 /*
2457                  * Is it an atomic image selection?  If so, also make available as pixbuf.
2458                  */
2459                 if ( gl_label_is_selection_atomic (label) &&
2460                      GL_IS_LABEL_IMAGE (selection_list->data) )
2461                 {
2462                         glLabelImage  *image_object = GL_LABEL_IMAGE (selection_list->data);
2463                         GdkPixbuf     *pixbuf = gl_label_image_get_pixbuf (image_object, NULL);
2464
2465                         if (pixbuf)
2466                         {
2467                                 gtk_target_list_add_image_targets (target_list, 2, TRUE);
2468                                 data->pixbuf = pixbuf;
2469                         }
2470                 }
2471
2472
2473                 target_table = gtk_target_table_new_from_list (target_list, &n_targets);
2474
2475                 gtk_clipboard_set_with_data (clipboard,
2476                                              target_table, n_targets,
2477                                              (GtkClipboardGetFunc)clipboard_get_cb,
2478                                              (GtkClipboardClearFunc)clipboard_clear_cb,
2479                                              data);
2480
2481                 gtk_target_table_free (target_table, n_targets);
2482                 gtk_target_list_unref (target_list);
2483         }
2484
2485
2486         g_list_free (selection_list);
2487
2488         gl_debug (DEBUG_LABEL, "END");
2489 }
2490
2491
2492 /*****************************************************************************/
2493 /* "Paste" from clipboard.                                                   */
2494 /*****************************************************************************/
2495 void
2496 gl_label_paste (glLabel       *label)
2497 {
2498         GtkClipboard  *clipboard;
2499
2500         gl_debug (DEBUG_LABEL, "START");
2501
2502         g_return_if_fail (label && GL_IS_LABEL (label));
2503
2504         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2505
2506         gtk_clipboard_request_targets (clipboard,
2507                                        (GtkClipboardTargetsReceivedFunc)receive_targets_cb,
2508                                        label);
2509
2510         gl_debug (DEBUG_LABEL, "END");
2511 }
2512
2513
2514 /*****************************************************************************/
2515 /* Is there anything that can be pasted?                                     */
2516 /*****************************************************************************/
2517 gboolean
2518 gl_label_can_paste (glLabel       *label)
2519 {
2520         GtkClipboard *clipboard;
2521         gboolean      can_flag;
2522
2523         gl_debug (DEBUG_LABEL, "START");
2524
2525         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2526
2527         can_flag = gtk_clipboard_wait_is_target_available (clipboard,
2528                                                            gdk_atom_intern("application/glabels", TRUE))
2529                 || gtk_clipboard_wait_is_text_available (clipboard)
2530                 || gtk_clipboard_wait_is_image_available (clipboard);
2531
2532         gl_debug (DEBUG_LABEL, "END");
2533         return can_flag;
2534 }
2535
2536
2537 /****************************************************************************/
2538 /* Clipboard "Get" function.                                                */
2539 /****************************************************************************/
2540 static void
2541 clipboard_get_cb (GtkClipboard     *clipboard,
2542                   GtkSelectionData *selection_data,
2543                   guint             info,
2544                   ClipboardData    *data)
2545 {
2546         gl_debug (DEBUG_LABEL, "START");
2547
2548         switch (info)
2549         {
2550
2551         case 0:
2552                 gtk_selection_data_set (selection_data,
2553                                         gtk_selection_data_get_target (selection_data),
2554                                         8,
2555                                         (guchar *)data->xml_buffer, strlen (data->xml_buffer));
2556                 break;
2557
2558         case 1:
2559                 gtk_selection_data_set_text (selection_data, data->text, -1);
2560                 break;
2561
2562         case 2:
2563                 gtk_selection_data_set_pixbuf (selection_data, data->pixbuf);
2564                 break;
2565
2566         default:
2567                 g_assert_not_reached ();
2568                 break;
2569
2570         }
2571
2572         gl_debug (DEBUG_LABEL, "END");
2573 }
2574
2575
2576 /****************************************************************************/
2577 /* Clipboard "Clear" function.                                              */
2578 /****************************************************************************/
2579 static void
2580 clipboard_clear_cb (GtkClipboard     *clipboard,
2581                     ClipboardData    *data)
2582 {
2583         gl_debug (DEBUG_LABEL, "START");
2584
2585         g_free (data->xml_buffer);
2586         g_free (data->text);
2587         if (data->pixbuf)
2588         {
2589                 g_object_unref (data->pixbuf);
2590         }
2591
2592         g_free (data);
2593
2594         gl_debug (DEBUG_LABEL, "END");
2595 }
2596
2597
2598 /****************************************************************************/
2599 /* Deal with clipboard data.                                                */
2600 /****************************************************************************/
2601 static void
2602 receive_targets_cb (GtkClipboard *clipboard,
2603                     GdkAtom      *targets,
2604                     gint          n_targets,
2605                     glLabel      *label)
2606 {
2607         gint i;
2608
2609         /*
2610          * Application/glabels
2611          */
2612         for ( i = 0; i < n_targets; i++ )
2613         {
2614                 if ( strcmp(gdk_atom_name(targets[i]), "application/glabels") == 0 )
2615                 {
2616                         gtk_clipboard_request_contents (clipboard,
2617                                                         gdk_atom_intern("application/glabels", TRUE),
2618                                                         (GtkClipboardReceivedFunc)paste_xml_received_cb,
2619                                                         label);
2620                         return;
2621                 }
2622         }
2623
2624         /*
2625          * Text
2626          */
2627         if ( gtk_targets_include_text (targets, n_targets) )
2628         {
2629                 gtk_clipboard_request_text (clipboard,
2630                                             (GtkClipboardTextReceivedFunc)paste_text_received_cb,
2631                                             label);
2632                 return;
2633         }
2634
2635         /*
2636          * Image
2637          */
2638         if ( gtk_targets_include_image (targets, n_targets, TRUE) )
2639         {
2640                 gtk_clipboard_request_image (clipboard,
2641                                              (GtkClipboardImageReceivedFunc)paste_image_received_cb,
2642                                              label);
2643                 return;
2644         }
2645 }
2646
2647
2648 /****************************************************************************/
2649 /* Paste received glabels XML callback.                                     */
2650 /****************************************************************************/
2651 static void
2652 paste_xml_received_cb (GtkClipboard     *clipboard,
2653                        GtkSelectionData *selection_data,
2654                        glLabel          *label)
2655 {
2656         gchar            *xml_buffer;
2657         glLabel          *label_copy;
2658         glXMLLabelStatus  status;
2659         GList            *p;
2660         glLabelObject    *object, *newobject;
2661
2662         gl_debug (DEBUG_LABEL, "START");
2663
2664         gl_label_checkpoint (label, _("Paste"));
2665
2666         xml_buffer = (gchar *)gtk_selection_data_get_data (selection_data);
2667
2668         /*
2669          * Deserialize XML label document and extract objects.
2670          */
2671         label_copy = gl_xml_label_open_buffer (xml_buffer, &status);
2672         if ( label_copy )
2673         {
2674                 gl_label_unselect_all (label);
2675
2676                 for (p = label_copy->priv->object_list; p != NULL; p = p->next)
2677                 {
2678                         object = (glLabelObject *) p->data;
2679                         newobject = gl_label_object_dup (object, label);
2680                         gl_label_add_object( label, newobject );
2681
2682                         gl_label_select_object (label, newobject);
2683
2684                         gl_debug (DEBUG_LABEL, "object pasted");
2685                 }
2686
2687                 g_object_unref (G_OBJECT (label_copy));
2688         }
2689
2690         gl_debug (DEBUG_LABEL, "END");
2691 }
2692
2693
2694 /****************************************************************************/
2695 /* Paste received text callback.                                            */
2696 /****************************************************************************/
2697 static void
2698 paste_text_received_cb (GtkClipboard     *clipboard,
2699                         const gchar      *text,
2700                         glLabel          *label)
2701 {
2702         glLabelObject    *object;
2703
2704         gl_debug (DEBUG_LABEL, "START");
2705
2706         gl_label_checkpoint (label, _("Paste"));
2707
2708         gl_label_unselect_all (label);
2709
2710         object = GL_LABEL_OBJECT (gl_label_text_new (label, FALSE));
2711         gl_label_text_set_text (GL_LABEL_TEXT (object), text, FALSE);
2712         gl_label_object_set_position (object, 18, 18, FALSE);
2713
2714         gl_label_select_object (label, object);
2715
2716         gl_debug (DEBUG_LABEL, "END");
2717 }
2718
2719
2720 /****************************************************************************/
2721 /* Paste received image callback.                                           */
2722 /****************************************************************************/
2723 static void
2724 paste_image_received_cb (GtkClipboard     *clipboard,
2725                          GdkPixbuf        *pixbuf,
2726                          glLabel          *label)
2727 {
2728         glLabelObject    *object;
2729
2730         gl_debug (DEBUG_LABEL, "START");
2731
2732         gl_label_checkpoint (label, _("Paste"));
2733
2734         gl_label_unselect_all (label);
2735
2736         object = GL_LABEL_OBJECT (gl_label_image_new (label, FALSE));
2737         gl_label_image_set_pixbuf (GL_LABEL_IMAGE (object), pixbuf, FALSE);
2738         gl_label_object_set_position (object, 18, 18, FALSE);
2739
2740         gl_label_select_object (label, object);
2741
2742         gl_debug (DEBUG_LABEL, "END");
2743 }
2744
2745
2746 /****************************************************************************/
2747 /* Set default font family.                                                 */
2748 /****************************************************************************/
2749 void
2750 gl_label_set_default_font_family (glLabel     *label,
2751                                   const gchar *font_family)
2752 {
2753         gl_debug (DEBUG_LABEL, "START");
2754
2755         g_return_if_fail (label && GL_IS_LABEL (label));
2756
2757         g_free (label->priv->default_font_family);
2758         label->priv->default_font_family = g_strdup (font_family);
2759
2760         gl_debug (DEBUG_LABEL, "END");
2761 }
2762
2763
2764 /****************************************************************************/
2765 /* Set default font size.                                                   */
2766 /****************************************************************************/
2767 void
2768 gl_label_set_default_font_size (glLabel *label,
2769                                 gdouble  font_size)
2770 {
2771         gl_debug (DEBUG_LABEL, "START");
2772
2773         g_return_if_fail (label && GL_IS_LABEL (label));
2774
2775         label->priv->default_font_size = font_size;
2776
2777         gl_debug (DEBUG_LABEL, "END");
2778 }
2779
2780
2781 /****************************************************************************/
2782 /* Set default font weight.                                                 */
2783 /****************************************************************************/
2784 void
2785 gl_label_set_default_font_weight (glLabel     *label,
2786                                   PangoWeight  font_weight)
2787 {
2788         gl_debug (DEBUG_LABEL, "START");
2789
2790         g_return_if_fail (label && GL_IS_LABEL (label));
2791
2792         label->priv->default_font_weight = font_weight;
2793
2794         gl_debug (DEBUG_LABEL, "END");
2795 }
2796
2797
2798 /****************************************************************************/
2799 /* Set default font italic flag.                                            */
2800 /****************************************************************************/
2801 void
2802 gl_label_set_default_font_italic_flag (glLabel  *label,
2803                                        gboolean  font_italic_flag)
2804 {
2805         gl_debug (DEBUG_LABEL, "START");
2806
2807         g_return_if_fail (label && GL_IS_LABEL (label));
2808
2809         label->priv->default_font_italic_flag = font_italic_flag;
2810
2811         gl_debug (DEBUG_LABEL, "END");
2812 }
2813
2814
2815 /****************************************************************************/
2816 /* Set default text color.                                                  */
2817 /****************************************************************************/
2818 void
2819 gl_label_set_default_text_color (glLabel *label,
2820                                  guint    text_color)
2821 {
2822         gl_debug (DEBUG_LABEL, "START");
2823
2824         g_return_if_fail (label && GL_IS_LABEL (label));
2825
2826         label->priv->default_text_color = text_color;
2827
2828         gl_debug (DEBUG_LABEL, "END");
2829 }
2830
2831
2832 /****************************************************************************/
2833 /* Set default text alignment.                                              */
2834 /****************************************************************************/
2835 void
2836 gl_label_set_default_text_alignment (glLabel        *label,
2837                                      PangoAlignment  text_alignment)
2838 {
2839         gl_debug (DEBUG_LABEL, "START");
2840
2841         g_return_if_fail (label && GL_IS_LABEL (label));
2842
2843         label->priv->default_text_alignment = text_alignment;
2844         gl_debug (DEBUG_LABEL, "END");
2845 }
2846
2847
2848 /****************************************************************************/
2849 /* Set default vertical text alignment.                                     */
2850 /****************************************************************************/
2851 void
2852 gl_label_set_default_text_valignment (glLabel        *label,
2853                                       glValignment    text_valignment)
2854 {
2855         gl_debug (DEBUG_LABEL, "START");
2856
2857         g_return_if_fail (label && GL_IS_LABEL (label));
2858
2859         label->priv->default_text_valignment = text_valignment;
2860         gl_debug (DEBUG_LABEL, "END");
2861 }
2862
2863
2864 /****************************************************************************/
2865 /* Set default text line spacing.                                           */
2866 /****************************************************************************/
2867 void
2868 gl_label_set_default_text_line_spacing (glLabel *label,
2869                                         gdouble  text_line_spacing)
2870 {
2871         gl_debug (DEBUG_LABEL, "START");
2872
2873         g_return_if_fail (label && GL_IS_LABEL (label));
2874
2875         label->priv->default_text_line_spacing = text_line_spacing;
2876
2877         gl_debug (DEBUG_LABEL, "END");
2878 }
2879
2880
2881 /****************************************************************************/
2882 /* Set default line width.                                                  */
2883 /****************************************************************************/
2884 void
2885 gl_label_set_default_line_width (glLabel *label,
2886                                  gdouble  line_width)
2887 {
2888         gl_debug (DEBUG_LABEL, "START");
2889
2890         g_return_if_fail (label && GL_IS_LABEL (label));
2891
2892         label->priv->default_line_width = line_width;
2893
2894         gl_debug (DEBUG_LABEL, "END");
2895 }
2896
2897
2898 /****************************************************************************/
2899 /* Set default line color.                                                  */
2900 /****************************************************************************/
2901 void
2902 gl_label_set_default_line_color (glLabel *label,
2903                                  guint    line_color)
2904 {
2905         gl_debug (DEBUG_LABEL, "START");
2906
2907         g_return_if_fail (label && GL_IS_LABEL (label));
2908
2909         label->priv->default_line_color = line_color;
2910
2911         gl_debug (DEBUG_LABEL, "END");
2912 }
2913
2914
2915 /****************************************************************************/
2916 /* Set default fill color.                                                  */
2917 /****************************************************************************/
2918 void
2919 gl_label_set_default_fill_color (glLabel *label,
2920                                  guint    fill_color)
2921 {
2922         gl_debug (DEBUG_LABEL, "START");
2923
2924         g_return_if_fail (label && GL_IS_LABEL (label));
2925
2926         label->priv->default_fill_color = fill_color;
2927
2928         gl_debug (DEBUG_LABEL, "END");
2929 }
2930
2931
2932 /****************************************************************************/
2933 /* Get default font family.                                                 */
2934 /****************************************************************************/
2935 gchar *
2936 gl_label_get_default_font_family (glLabel *label)
2937 {
2938         gl_debug (DEBUG_LABEL, "START");
2939
2940         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
2941
2942         gl_debug (DEBUG_LABEL, "END");
2943
2944         return g_strdup (label->priv->default_font_family);
2945 }
2946
2947
2948 /****************************************************************************/
2949 /* Get default font size.                                                   */
2950 /****************************************************************************/
2951 gdouble
2952 gl_label_get_default_font_size (glLabel *label)
2953 {
2954         gl_debug (DEBUG_LABEL, "START");
2955
2956         g_return_val_if_fail (label && GL_IS_LABEL (label), 12.0);
2957
2958         gl_debug (DEBUG_LABEL, "END");
2959
2960         return label->priv->default_font_size;
2961 }
2962
2963
2964 /****************************************************************************/
2965 /* Get default font weight.                                                 */
2966 /****************************************************************************/
2967 PangoWeight
2968 gl_label_get_default_font_weight (glLabel *label)
2969 {
2970         gl_debug (DEBUG_LABEL, "START");
2971
2972         g_return_val_if_fail (label && GL_IS_LABEL (label), PANGO_WEIGHT_NORMAL);
2973
2974         gl_debug (DEBUG_LABEL, "END");
2975
2976         return label->priv->default_font_weight;
2977 }
2978
2979
2980 /****************************************************************************/
2981 /* Get default font italic flag.                                            */
2982 /****************************************************************************/
2983 gboolean
2984 gl_label_get_default_font_italic_flag (glLabel *label)
2985 {
2986         gl_debug (DEBUG_LABEL, "START");
2987
2988         g_return_val_if_fail (label && GL_IS_LABEL (label), FALSE);
2989
2990         gl_debug (DEBUG_LABEL, "END");
2991
2992         return label->priv->default_font_italic_flag;
2993 }
2994
2995
2996 /****************************************************************************/
2997 /* Get default text color.                                                  */
2998 /****************************************************************************/
2999 guint
3000 gl_label_get_default_text_color (glLabel *label)
3001 {
3002         gl_debug (DEBUG_LABEL, "START");
3003
3004         g_return_val_if_fail (label && GL_IS_LABEL (label), 0);
3005
3006         gl_debug (DEBUG_LABEL, "END");
3007
3008         return label->priv->default_text_color;
3009 }
3010
3011
3012 /****************************************************************************/
3013 /* Get default text alignment.                                              */
3014 /****************************************************************************/
3015 PangoAlignment
3016 gl_label_get_default_text_alignment (glLabel *label)
3017 {
3018         gl_debug (DEBUG_LABEL, "START");
3019
3020         g_return_val_if_fail (label && GL_IS_LABEL (label), PANGO_ALIGN_LEFT);
3021
3022         gl_debug (DEBUG_LABEL, "END");
3023
3024         return label->priv->default_text_alignment;
3025 }
3026
3027
3028 /****************************************************************************/
3029 /* Get default vertical text alignment.                                     */
3030 /****************************************************************************/
3031 glValignment
3032 gl_label_get_default_text_valignment (glLabel *label)
3033 {
3034         gl_debug (DEBUG_LABEL, "START");
3035
3036         g_return_val_if_fail (label && GL_IS_LABEL (label), GL_VALIGN_TOP);
3037
3038         gl_debug (DEBUG_LABEL, "END");
3039
3040         return label->priv->default_text_valignment;
3041 }
3042
3043
3044 /****************************************************************************/
3045 /* Get default text line spacing.                                           */
3046 /****************************************************************************/
3047 gdouble
3048 gl_label_get_default_text_line_spacing (glLabel *label)
3049 {
3050         gl_debug (DEBUG_LABEL, "START");
3051
3052         g_return_val_if_fail (label && GL_IS_LABEL (label), 1.0);
3053
3054         gl_debug (DEBUG_LABEL, "END");
3055
3056         return label->priv->default_text_line_spacing;
3057 }
3058
3059
3060 /****************************************************************************/
3061 /* Get default line width.                                                  */
3062 /****************************************************************************/
3063 gdouble
3064 gl_label_get_default_line_width (glLabel *label)
3065 {
3066         gl_debug (DEBUG_LABEL, "START");
3067
3068         g_return_val_if_fail (label && GL_IS_LABEL (label), 1.0);
3069
3070         gl_debug (DEBUG_LABEL, "END");
3071
3072         return label->priv->default_line_width;
3073 }
3074
3075
3076 /****************************************************************************/
3077 /* Get default line color.                                                  */
3078 /****************************************************************************/
3079 guint
3080 gl_label_get_default_line_color (glLabel *label)
3081 {
3082         gl_debug (DEBUG_LABEL, "START");
3083
3084         g_return_val_if_fail (label && GL_IS_LABEL (label), 0);
3085
3086         gl_debug (DEBUG_LABEL, "END");
3087
3088         return label->priv->default_line_color;
3089 }
3090
3091
3092 /****************************************************************************/
3093 /* Get default fill color.                                                  */
3094 /****************************************************************************/
3095 guint
3096 gl_label_get_default_fill_color (glLabel *label)
3097 {
3098         gl_debug (DEBUG_LABEL, "START");
3099
3100         g_return_val_if_fail (label && GL_IS_LABEL (label), 0);
3101
3102         gl_debug (DEBUG_LABEL, "END");
3103
3104         return label->priv->default_fill_color;
3105 }
3106
3107
3108 /****************************************************************************/
3109 /* Draw label.                                                              */
3110 /****************************************************************************/
3111 void
3112 gl_label_draw (glLabel       *label,
3113                cairo_t       *cr,
3114                gboolean       screen_flag,
3115                glMergeRecord *record)
3116 {
3117         GList            *p_obj;
3118         glLabelObject    *object;
3119
3120         g_return_if_fail (label && GL_IS_LABEL (label));
3121
3122         for (p_obj = label->priv->object_list; p_obj != NULL; p_obj = p_obj->next)
3123         {
3124                 object = GL_LABEL_OBJECT (p_obj->data);
3125
3126                 gl_label_object_draw (object, cr, screen_flag, record);
3127         }
3128 }
3129
3130
3131 /****************************************************************************/
3132 /* Get object located at coordinates.                                       */
3133 /****************************************************************************/
3134 glLabelObject *gl_label_object_at              (glLabel       *label,
3135                                                 cairo_t       *cr,
3136                                                 gdouble        x_pixels,
3137                                                 gdouble        y_pixels)
3138 {
3139         GList            *p_obj;
3140         glLabelObject    *object;
3141
3142         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
3143
3144         for (p_obj = g_list_last (label->priv->object_list); p_obj != NULL; p_obj = p_obj->prev)
3145         {
3146                 object = GL_LABEL_OBJECT (p_obj->data);
3147
3148                 if (gl_label_object_is_located_at (object, cr, x_pixels, y_pixels))
3149                 {
3150                         return object;
3151                 }
3152
3153         }
3154
3155         return NULL;
3156 }
3157
3158
3159 /****************************************************************************/
3160 /* Return handle and associated object at coordinates.                      */
3161 /****************************************************************************/
3162 glLabelObject *
3163 gl_label_get_handle_at (glLabel             *label,
3164                         cairo_t             *cr,
3165                         gdouble              x_pixels,
3166                         gdouble              y_pixels,
3167                         glLabelObjectHandle *handle)
3168 {
3169         GList            *selection_list;
3170         GList            *p_obj;
3171         glLabelObject    *object;
3172
3173         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
3174
3175         selection_list = gl_label_get_selection_list (label);
3176
3177         for (p_obj = g_list_last (selection_list); p_obj != NULL; p_obj = p_obj->prev)
3178         {
3179
3180                 object = GL_LABEL_OBJECT (p_obj->data);
3181
3182                 if ((*handle = gl_label_object_handle_at (object, cr, x_pixels, y_pixels)))
3183                 {
3184                         g_list_free (selection_list);
3185                         return object;
3186                 }
3187
3188         }
3189
3190         g_list_free (selection_list);
3191
3192         *handle = GL_LABEL_OBJECT_HANDLE_NONE;
3193         return NULL;
3194 }
3195
3196
3197 /****************************************************************************/
3198 /* Checkpoint state.                                                        */
3199 /****************************************************************************/
3200 void
3201 gl_label_checkpoint (glLabel       *this,
3202                      const gchar   *description)
3203 {
3204         State *state;
3205
3206         gl_debug (DEBUG_LABEL, "START");
3207
3208         /*
3209          * Do not perform consecutive checkpoints that are identical.
3210          * E.g. moving an object by dragging, would produce a large number
3211          * of incremental checkpoints -- what we really want is a single
3212          * checkpoint so that we can undo the entire dragging effort with
3213          * one "undo"
3214          */
3215         if ( this->priv->cp_cleared_flag
3216              || (this->priv->cp_desc == NULL)
3217              || (strcmp (description, this->priv->cp_desc) != 0) )
3218         {
3219
3220                 /* Sever old redo "thread" */
3221                 stack_clear (this->priv->redo_stack);
3222
3223                 /* Save state onto undo stack. */
3224                 state = state_new (this, description);
3225                 stack_push_state (this->priv->undo_stack, state);
3226
3227                 /* Track consecutive checkpoints. */
3228                 this->priv->cp_cleared_flag = FALSE;
3229                 this->priv->cp_desc         = g_strdup (description);
3230         }
3231
3232         gl_debug (DEBUG_LABEL, "END");
3233 }
3234
3235
3236 /****************************************************************************/
3237 /* Undo.                                                                    */
3238 /****************************************************************************/
3239 void
3240 gl_label_undo (glLabel       *this)
3241 {
3242         State *state_old;
3243         State *state_now;
3244
3245         gl_debug (DEBUG_LABEL, "START");
3246
3247         state_old = stack_pop_state (this->priv->undo_stack);
3248         state_now = state_new (this, state_old->description);
3249
3250         stack_push_state (this->priv->redo_stack, state_now);
3251
3252         state_restore (state_old, this);
3253         state_free (state_old);
3254
3255         this->priv->cp_cleared_flag = TRUE;
3256
3257         gl_debug (DEBUG_LABEL, "END");
3258 }
3259
3260
3261 /****************************************************************************/
3262 /* Redo.                                                                    */
3263 /****************************************************************************/
3264 void
3265 gl_label_redo (glLabel       *this)
3266 {
3267         State *state_old;
3268         State *state_now;
3269
3270         gl_debug (DEBUG_LABEL, "START");
3271
3272         state_old = stack_pop_state (this->priv->redo_stack);
3273         state_now = state_new (this, state_old->description);
3274
3275         stack_push_state (this->priv->undo_stack, state_now);
3276
3277         state_restore (state_old, this);
3278         state_free (state_old);
3279
3280         this->priv->cp_cleared_flag = TRUE;
3281
3282         gl_debug (DEBUG_LABEL, "END");
3283 }
3284
3285
3286 /****************************************************************************/
3287 /* Can undo?                                                                */
3288 /****************************************************************************/
3289 gboolean
3290 gl_label_can_undo (glLabel *this)
3291 {
3292         return (!g_queue_is_empty (this->priv->undo_stack));
3293 }
3294
3295
3296 /****************************************************************************/
3297 /* Can redo?                                                                */
3298 /****************************************************************************/
3299 gboolean
3300 gl_label_can_redo (glLabel *this)
3301 {
3302         return (!g_queue_is_empty (this->priv->redo_stack));
3303 }
3304
3305
3306 /****************************************************************************/
3307 /* Get undo description string.                                             */
3308 /****************************************************************************/
3309 gchar *
3310 gl_label_get_undo_description (glLabel *this)
3311 {
3312         State *state;
3313         gchar *description;
3314
3315         state = g_queue_peek_head (this->priv->undo_stack);
3316         if ( state )
3317         {
3318                 description = g_strdup (state->description);
3319         }
3320         else
3321         {
3322                 description = g_strdup ("");
3323         }
3324
3325         return description;
3326 }
3327
3328
3329 /****************************************************************************/
3330 /* Get redo description string.                                             */
3331 /****************************************************************************/
3332 gchar *
3333 gl_label_get_redo_description (glLabel *this)
3334 {
3335         State *state;
3336         gchar *description;
3337
3338         state = g_queue_peek_head (this->priv->redo_stack);
3339         if ( state )
3340         {
3341                 description = g_strdup (state->description);
3342         }
3343         else
3344         {
3345                 description = g_strdup ("");
3346         }
3347
3348         return description;
3349 }
3350
3351
3352 /****************************************************************************/
3353 /* Clear undo or redo stack.                                                */
3354 /****************************************************************************/
3355 static void
3356 stack_clear (GQueue *stack)
3357 {
3358         State *state;
3359
3360         gl_debug (DEBUG_LABEL, "START");
3361
3362         while ( (state = g_queue_pop_head (stack)) != NULL )
3363         {
3364                 state_free (state);
3365         }
3366
3367         gl_debug (DEBUG_LABEL, "END");
3368 }
3369
3370
3371 /****************************************************************************/
3372 /* Push state onto stack.                                                   */
3373 /****************************************************************************/
3374 static void
3375 stack_push_state (GQueue *stack,
3376                   State  *state)
3377 {
3378         gl_debug (DEBUG_LABEL, "START");
3379
3380         g_queue_push_head( stack, state );
3381
3382         gl_debug (DEBUG_LABEL, "END");
3383 }
3384
3385
3386 /****************************************************************************/
3387 /* Pop state from stack.                                                    */
3388 /****************************************************************************/
3389 static State *
3390 stack_pop_state (GQueue *stack)
3391 {
3392         State *state;
3393
3394         gl_debug (DEBUG_LABEL, "START");
3395
3396         state = g_queue_pop_head (stack);
3397
3398         gl_debug (DEBUG_LABEL, "END");
3399         return state;
3400 }
3401
3402
3403 /****************************************************************************/
3404 /* New state from label.                                                    */
3405 /****************************************************************************/
3406 static State *
3407 state_new (glLabel       *this,
3408            const gchar   *description)
3409 {
3410         State          *state;
3411         GList          *p_obj;
3412         glLabelObject  *object;
3413
3414         gl_debug (DEBUG_LABEL, "START");
3415
3416         state = g_new0 (State, 1);
3417
3418         state->description = g_strdup (description);
3419
3420         state->template    = lgl_template_dup (this->priv->template);
3421         state->rotate_flag = this->priv->rotate_flag;
3422
3423         for ( p_obj = this->priv->object_list; p_obj != NULL; p_obj = p_obj->next )
3424         {
3425                 object = GL_LABEL_OBJECT (p_obj->data);
3426
3427                 state->object_list = g_list_append (state->object_list,
3428                                                     gl_label_object_dup (object, this));
3429         }
3430
3431         state->merge = gl_merge_dup (this->priv->merge);
3432
3433         state->modified_flag = this->priv->modified_flag;
3434         state->time_stamp    = this->priv->time_stamp;
3435
3436
3437         gl_debug (DEBUG_LABEL, "END");
3438         return state;
3439 }
3440
3441
3442 /****************************************************************************/
3443 /* Restore label from saved state.                                          */
3444 /****************************************************************************/
3445 static void
3446 state_free (State   *state)
3447 {
3448         GList          *p_obj;
3449
3450         gl_debug (DEBUG_LABEL, "START");
3451
3452         g_free (state->description);
3453
3454         lgl_template_free (state->template);
3455         if ( state->merge )
3456         {
3457                 g_object_unref (G_OBJECT (state->merge));
3458         }
3459
3460         for ( p_obj = state->object_list; p_obj != NULL; p_obj = p_obj->next )
3461         {
3462                 g_object_unref (G_OBJECT (p_obj->data));
3463         }
3464         g_list_free (state->object_list);
3465
3466         g_free (state);
3467
3468         gl_debug (DEBUG_LABEL, "END");
3469 }
3470
3471
3472 /****************************************************************************/
3473 /* Restore label from saved state.                                          */
3474 /****************************************************************************/
3475 static void
3476 state_restore (State   *state,
3477                glLabel *this)
3478                
3479 {
3480         GList          *p_obj, *p_next;
3481         glLabelObject  *object;
3482
3483         gl_debug (DEBUG_LABEL, "START");
3484
3485         gl_label_set_rotate_flag (this, state->rotate_flag, FALSE);
3486         gl_label_set_template (this, state->template, FALSE);
3487
3488         for ( p_obj = this->priv->object_list; p_obj != NULL; p_obj = p_next )
3489         {
3490                 p_next = p_obj->next; /* Hold on to next; delete is destructive */
3491                 object = GL_LABEL_OBJECT (p_obj->data);
3492
3493                 gl_label_delete_object (this, object);
3494         }
3495
3496         for ( p_obj = state->object_list; p_obj != NULL; p_obj = p_obj->next )
3497         {
3498                 object = GL_LABEL_OBJECT (p_obj->data);
3499
3500                 gl_label_add_object (this, gl_label_object_dup (object, this));
3501         }
3502         g_signal_emit (G_OBJECT(this), signals[SELECTION_CHANGED], 0);
3503
3504         gl_label_set_merge (this, state->merge, FALSE);
3505         
3506
3507         if ( !state->modified_flag &&
3508              (state->time_stamp.tv_sec  == this->priv->time_stamp.tv_sec) &&
3509              (state->time_stamp.tv_usec == this->priv->time_stamp.tv_usec) )
3510         {
3511                 gl_label_clear_modified (this);
3512         }
3513
3514         gl_debug (DEBUG_LABEL, "END");
3515 }
3516
3517
3518
3519
3520 /*
3521  * Local Variables:       -- emacs
3522  * mode: C                -- emacs
3523  * c-basic-offset: 8      -- emacs
3524  * tab-width: 8           -- emacs
3525  * indent-tabs-mode: nil  -- emacs
3526  * End:                   -- emacs
3527  */