]> git.sur5r.net Git - glabels/blob - src/label.c
d1cc309a8013512034e4dabd6d2b8646edd3ecbf
[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 /* get string with info about dimensions                                    */
708 /****************************************************************************/
709 gchar *
710 gl_label_get_dimensions_string (glLabel *label)
711 {
712         gchar                  *dims;
713         lglTemplate            *template;
714         const lglTemplateFrame *frame;
715         lglUnits                units;
716         gdouble                 units_per_point;
717         gchar                  *s1 = NULL;
718         gchar                  *s2 = NULL;
719         gchar                  *s3 = NULL;
720
721         gl_debug (DEBUG_LABEL, "START");
722
723         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
724
725         template = label->priv->template;
726         if (!template)
727                 return g_strdup("");
728         frame = (lglTemplateFrame *)template->frames->data;
729         units = gl_prefs_model_get_units (gl_prefs);
730         units_per_point = lgl_units_get_units_per_point (units);
731
732         switch (frame->shape)
733         {
734         case LGL_TEMPLATE_FRAME_SHAPE_RECT:
735                 if (units == LGL_UNITS_INCH)
736                 {
737                         s1 = lgl_str_format_fraction (frame->rect.w*units_per_point);
738                         s2 = lgl_str_format_fraction (frame->rect.h*units_per_point);
739                         s3 = lgl_str_format_fraction (frame->rect.r*units_per_point);
740                 }
741                 else
742                 {
743                         s1 = g_strdup_printf ("%.5g", frame->rect.w*units_per_point);
744                         s2 = g_strdup_printf ("%.5g", frame->rect.h*units_per_point);
745                         s3 = g_strdup_printf ("%.5g", frame->rect.r*units_per_point);
746                 }
747                 if (frame->rect.r == 0)
748                         /*Translators: A rectangular label dimensions. first param is numeric value*/
749                         /* of width, second is numeric value of height and third is unit. Example:*/
750                         /*"60 Ã— 22.5 mm (width / height)"*/
751                         dims = g_strdup_printf (_("%s × %s %s (width × height)"),
752                                                 s1, s2, lgl_units_get_name (units));
753                 else
754                         /*Translators: A rounded rectangular label dimensions. first param is numeric*/
755                         /*value of width, second is numeric value of height, third is numeric value*/
756                         /*of round and fourth is unit. Example:*/
757                         /*"50 Ã— 30 / 1.5 mm (width Ã— height / round)"*/
758                         dims = g_strdup_printf (_("%s × %s / %s %s (width × height / round)"),
759                                                 s1, s2, s3, lgl_units_get_name (units));
760                 break;
761
762         case LGL_TEMPLATE_FRAME_SHAPE_ELLIPSE:
763                 if (units == LGL_UNITS_INCH)
764                 {
765                         s1 = lgl_str_format_fraction (frame->ellipse.w*units_per_point);
766                         s2 = lgl_str_format_fraction (frame->ellipse.h*units_per_point);
767                 }
768                 else
769                 {
770                         s1 = g_strdup_printf ("%.5g", frame->ellipse.w*units_per_point);
771                         s2 = g_strdup_printf ("%.5g", frame->ellipse.h*units_per_point);
772                 }
773                 /*Translators: A elliptical label dimensions. first param is numeric value of*/
774                 /*width, second is numeric value of height and third is unit. Example:*/
775                 /*"60 Ã— 22.5 mm (width / height)"*/
776                 dims = g_strdup_printf (_("%s × %s %s (width × height)"),
777                                         s1, s2, lgl_units_get_name (units));
778                 break;
779
780         case LGL_TEMPLATE_FRAME_SHAPE_ROUND:
781                 if (units == LGL_UNITS_INCH)
782                         s1 = lgl_str_format_fraction (2*frame->round.r*units_per_point);
783                 else
784                         s1 = g_strdup_printf ("%.5g", 2*frame->round.r*units_per_point);
785                 /*Translators: A round label dimensions. first param is numeric value of*/
786                 /*diameter and secons is unit. Example:*/
787                 /*"120.5 mm (diameter)"*/
788                 dims = g_strdup_printf (_("%s %s (diameter)"),
789                                         s1, lgl_units_get_name (units));
790                 break;
791
792         case LGL_TEMPLATE_FRAME_SHAPE_CD:
793                 if (units == LGL_UNITS_INCH)
794                 {
795                         s1 = lgl_str_format_fraction (2*frame->cd.r1*units_per_point);
796                         s2 = lgl_str_format_fraction (2*frame->cd.r2*units_per_point);
797                 }
798                 else
799                 {
800                         s1 = g_strdup_printf ("%.5g", 2*frame->cd.r1*units_per_point);
801                         s2 = g_strdup_printf ("%.5g", 2*frame->cd.r2*units_per_point);
802                 }
803                 /*Translators: A CD/DVD label dimensions. first param is numeric value of*/
804                 /*diameter, second is numeric value of hole and third is unit. Example:*/
805                 /*"120.5 / 30 mm (diameter / hole)"*/
806                 dims = g_strdup_printf (_("%s / %s %s (diameter / hole)"),
807                                         s1, s2, lgl_units_get_name (units));
808                 break;
809         }
810
811         g_free (s1);
812         g_free (s2);
813         g_free (s3);
814
815         gl_debug (DEBUG_LABEL, "END");
816
817         return dims;
818 }
819
820
821 /****************************************************************************/
822 /* set merge information structure.                                         */
823 /****************************************************************************/
824 void
825 gl_label_set_merge (glLabel *label,
826                     glMerge *merge,
827                     gboolean checkpoint)
828 {
829         gl_debug (DEBUG_LABEL, "START");
830
831         g_return_if_fail (label && GL_IS_LABEL (label));
832
833         if ( checkpoint )
834         {
835                 gl_label_checkpoint (label, _("Merge properties"));
836         }
837
838         if ( label->priv->merge != NULL )
839         {
840                 g_object_unref (G_OBJECT(label->priv->merge));
841         }
842         label->priv->merge = gl_merge_dup (merge);
843
844         do_modify (label);
845         g_signal_emit (G_OBJECT(label), signals[MERGE_CHANGED], 0);
846
847         gl_debug (DEBUG_LABEL, "END");
848 }
849
850
851 /****************************************************************************/
852 /* Get merge information structure.                                         */
853 /****************************************************************************/
854 glMerge *
855 gl_label_get_merge (glLabel *label)
856 {
857         gl_debug (DEBUG_LABEL, "START");
858
859         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
860
861         gl_debug (DEBUG_LABEL, "END");
862
863         return gl_merge_dup (label->priv->merge);
864 }
865
866
867 /****************************************************************************/
868 /* Get pixbuf cache.                                                        */
869 /****************************************************************************/
870 GHashTable *
871 gl_label_get_pixbuf_cache (glLabel       *label)
872 {
873         return label->priv->pixbuf_cache;
874 }
875
876
877 /****************************************************************************/
878 /* Get svg cache.                                                           */
879 /****************************************************************************/
880 GHashTable *
881 gl_label_get_svg_cache (glLabel       *label)
882 {
883         return label->priv->svg_cache;
884 }
885
886
887 /*****************************************************************************/
888 /* Add object to label.                                                      */
889 /*****************************************************************************/
890 void
891 gl_label_add_object (glLabel       *label,
892                      glLabelObject *object)
893 {
894         gl_debug (DEBUG_LABEL, "START");
895
896         g_return_if_fail (label && GL_IS_LABEL (label));
897         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
898
899         gl_label_object_set_parent (object, label);
900         label->priv->object_list = g_list_append (label->priv->object_list, object);
901
902         g_signal_connect (G_OBJECT (object), "changed",
903                           G_CALLBACK (object_changed_cb), label);
904         g_signal_connect (G_OBJECT (object), "moved",
905                           G_CALLBACK (object_moved_cb), label);
906
907         do_modify (label);
908
909         gl_debug (DEBUG_LABEL, "END");
910 }
911
912
913 /*****************************************************************************/
914 /* Delete object from label.                                                 */
915 /*****************************************************************************/
916 void
917 gl_label_delete_object (glLabel       *label,
918                         glLabelObject *object)
919 {
920         gl_debug (DEBUG_LABEL, "START");
921
922         g_return_if_fail (label && GL_IS_LABEL (label));
923         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
924
925         label->priv->object_list = g_list_remove (label->priv->object_list, object);
926
927         g_signal_handlers_disconnect_by_func (G_OBJECT (object),
928                                               G_CALLBACK (object_changed_cb), label);
929         g_signal_handlers_disconnect_by_func (G_OBJECT (object),
930                                               G_CALLBACK (object_moved_cb), label);
931         g_object_unref (object);
932
933         do_modify (label);
934
935         gl_debug (DEBUG_LABEL, "END");
936 }
937
938
939 /*****************************************************************************/
940 /* Get object list.                                                          */
941 /*****************************************************************************/
942 const GList *
943 gl_label_get_object_list (glLabel       *label)
944 {
945         return label->priv->object_list;
946 }
947
948
949 /*****************************************************************************/
950 /* Select object.                                                            */
951 /*****************************************************************************/
952 void
953 gl_label_select_object (glLabel       *label,
954                         glLabelObject *object)
955 {
956         gl_debug (DEBUG_LABEL, "START");
957
958         g_return_if_fail (label && GL_IS_LABEL (label));
959         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
960
961         gl_label_object_select (object);
962
963         label->priv->cp_cleared_flag = TRUE;
964         g_signal_emit (G_OBJECT(label), signals[SELECTION_CHANGED], 0);
965
966         gl_debug (DEBUG_LABEL, "END");
967 }
968
969
970 /*****************************************************************************/
971 /* Unselect object.                                                          */
972 /*****************************************************************************/
973 void
974 gl_label_unselect_object (glLabel       *label,
975                           glLabelObject *object)
976 {
977         gl_debug (DEBUG_LABEL, "START");
978
979         g_return_if_fail (label && GL_IS_LABEL (label));
980         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
981
982         gl_label_object_unselect (object);
983
984         label->priv->cp_cleared_flag = TRUE;
985         g_signal_emit (G_OBJECT(label), signals[SELECTION_CHANGED], 0);
986
987         gl_debug (DEBUG_LABEL, "END");
988 }
989
990
991 /*****************************************************************************/
992 /* Select all objects.                                                       */
993 /*****************************************************************************/
994 void
995 gl_label_select_all (glLabel       *label)
996 {
997         GList         *p;
998         glLabelObject *object;
999
1000         gl_debug (DEBUG_LABEL, "START");
1001
1002         g_return_if_fail (label && GL_IS_LABEL (label));
1003
1004         for ( p = label->priv->object_list; p != NULL; p = p->next )
1005         {
1006                 object = GL_LABEL_OBJECT (p->data);
1007
1008                 gl_label_object_select (object);
1009         }
1010
1011         label->priv->cp_cleared_flag = TRUE;
1012         g_signal_emit (G_OBJECT(label), signals[SELECTION_CHANGED], 0);
1013
1014         gl_debug (DEBUG_LABEL, "END");
1015 }
1016
1017
1018 /*****************************************************************************/
1019 /* Unselect all objects.                                                     */
1020 /*****************************************************************************/
1021 void
1022 gl_label_unselect_all (glLabel       *label)
1023 {
1024         GList         *p;
1025         glLabelObject *object;
1026
1027         gl_debug (DEBUG_LABEL, "START");
1028
1029         g_return_if_fail (label && GL_IS_LABEL (label));
1030
1031         for ( p = label->priv->object_list; p != NULL; p = p->next )
1032         {
1033                 object = GL_LABEL_OBJECT (p->data);
1034
1035                 gl_label_object_unselect (object);
1036         }
1037
1038         label->priv->cp_cleared_flag = TRUE;
1039         g_signal_emit (G_OBJECT(label), signals[SELECTION_CHANGED], 0);
1040
1041         gl_debug (DEBUG_LABEL, "END");
1042 }
1043
1044
1045 /*****************************************************************************/
1046 /* Select all objects contained in region.                                   */
1047 /*****************************************************************************/
1048 void
1049 gl_label_select_region (glLabel       *label,
1050                         glLabelRegion *region)
1051 {
1052         GList         *p;
1053         glLabelObject *object;
1054         gdouble        r_x1, r_y1;
1055         gdouble        r_x2, r_y2;
1056         glLabelRegion  obj_extent;
1057
1058         gl_debug (DEBUG_LABEL, "START");
1059
1060         g_return_if_fail (label && GL_IS_LABEL (label));
1061
1062         r_x1 = MIN (region->x1, region->x2);
1063         r_y1 = MIN (region->y1, region->y2);
1064         r_x2 = MAX (region->x1, region->x2);
1065         r_y2 = MAX (region->y1, region->y2);
1066
1067         for (p = label->priv->object_list; p != NULL; p = p->next)
1068         {
1069                 object = GL_LABEL_OBJECT(p->data);
1070
1071                 gl_label_object_get_extent (object, &obj_extent);
1072                 if ((obj_extent.x1 >= r_x1) &&
1073                     (obj_extent.x2 <= r_x2) &&
1074                     (obj_extent.y1 >= r_y1) &&
1075                     (obj_extent.y2 <= r_y2))
1076                 {
1077                         gl_label_object_select (object);
1078                 }
1079         }
1080
1081         label->priv->cp_cleared_flag = TRUE;
1082         g_signal_emit (G_OBJECT(label), signals[SELECTION_CHANGED], 0);
1083
1084         gl_debug (DEBUG_LABEL, "END");
1085 }
1086
1087
1088 /*****************************************************************************/
1089 /* Is selection empty?                                                       */
1090 /*****************************************************************************/
1091 gboolean
1092 gl_label_is_selection_empty (glLabel       *label)
1093 {
1094         GList         *p;
1095         glLabelObject *object;
1096
1097         for ( p = label->priv->object_list; p != NULL; p = p->next )
1098         {
1099                 object = GL_LABEL_OBJECT (p->data);
1100
1101                 if ( gl_label_object_is_selected (object) )
1102                 {
1103                         return FALSE;
1104                 }
1105         }
1106
1107         return TRUE;
1108 }
1109
1110
1111 /*****************************************************************************/
1112 /* Is selection atomic?                                                      */
1113 /*****************************************************************************/
1114 gboolean
1115 gl_label_is_selection_atomic (glLabel       *label)
1116 {
1117         GList         *p;
1118         glLabelObject *object;
1119         gint           n_selected = 0;
1120
1121         for ( p = label->priv->object_list; p != NULL; p = p->next )
1122         {
1123                 object = GL_LABEL_OBJECT (p->data);
1124
1125                 if ( gl_label_object_is_selected (object) )
1126                 {
1127                         n_selected++;
1128
1129                         if (n_selected > 1)
1130                         {
1131                                 return FALSE;
1132                         }
1133                 }
1134         }
1135
1136         return (n_selected == 1);
1137 }
1138
1139
1140 /*****************************************************************************/
1141 /* Get first selected object.                                                */
1142 /*****************************************************************************/
1143 glLabelObject *
1144 gl_label_get_1st_selected_object (glLabel  *label)
1145 {
1146         GList         *p;
1147         glLabelObject *object;
1148
1149         for ( p = label->priv->object_list; p != NULL; p = p->next )
1150         {
1151                 object = GL_LABEL_OBJECT (p->data);
1152
1153                 if ( gl_label_object_is_selected (object) )
1154                 {
1155                         return object;
1156                 }
1157         }
1158
1159         return NULL;
1160 }
1161
1162
1163 /*****************************************************************************/
1164 /* Get list of selected objects.                                             */
1165 /*****************************************************************************/
1166 GList *
1167 gl_label_get_selection_list (glLabel *label)
1168 {
1169         GList         *selection_list = NULL;
1170         GList         *p;
1171         glLabelObject *object;
1172
1173         for ( p = label->priv->object_list; p != NULL; p = p->next )
1174         {
1175                 object = GL_LABEL_OBJECT (p->data);
1176
1177                 if ( gl_label_object_is_selected (object) )
1178                 {
1179                         selection_list = g_list_append (selection_list, object);
1180                 }
1181         }
1182
1183         return (selection_list);
1184 }
1185
1186
1187 /*****************************************************************************/
1188 /* Can text properties be set for selection?                                 */
1189 /*****************************************************************************/
1190 gboolean
1191 gl_label_can_selection_text (glLabel *label)
1192 {
1193         GList         *selection_list;
1194         GList         *p;
1195         glLabelObject *object;
1196
1197         gl_debug (DEBUG_LABEL, "");
1198
1199         g_return_val_if_fail (label && GL_IS_LABEL (label), FALSE);
1200
1201         selection_list = gl_label_get_selection_list (label);
1202
1203         for (p = selection_list; p != NULL; p = p->next)
1204         {
1205                 object = GL_LABEL_OBJECT (p->data);
1206
1207                 if (gl_label_object_can_text (object))
1208                 {
1209                         g_list_free (selection_list);
1210                         return TRUE;
1211                 }
1212         }
1213
1214         g_list_free (selection_list);
1215         return FALSE;
1216 }
1217
1218
1219 /*****************************************************************************/
1220 /* Can fill properties be set for selection?                                 */
1221 /*****************************************************************************/
1222 gboolean
1223 gl_label_can_selection_fill (glLabel *label)
1224 {
1225         GList         *selection_list;
1226         GList         *p;
1227         glLabelObject *object;
1228
1229         gl_debug (DEBUG_LABEL, "");
1230
1231         g_return_val_if_fail (label && GL_IS_LABEL (label), FALSE);
1232
1233         selection_list = gl_label_get_selection_list (label);
1234
1235         for (p = selection_list; p != NULL; p = p->next)
1236         {
1237                 object = GL_LABEL_OBJECT (p->data);
1238
1239                 if (gl_label_object_can_fill (object))
1240                 {
1241                         g_list_free (selection_list);
1242                         return TRUE;
1243                 }
1244
1245         }
1246
1247         g_list_free (selection_list);
1248         return FALSE;
1249 }
1250
1251
1252 /*****************************************************************************/
1253 /* Can line color properties be set for selection?                           */
1254 /*****************************************************************************/
1255 gboolean
1256 gl_label_can_selection_line_color (glLabel *label)
1257 {
1258         GList         *selection_list;
1259         GList         *p;
1260         glLabelObject *object;
1261
1262         gl_debug (DEBUG_LABEL, "");
1263
1264         g_return_val_if_fail (label && GL_IS_LABEL (label), FALSE);
1265
1266         selection_list = gl_label_get_selection_list (label);
1267
1268         for (p = selection_list; p != NULL; p = p->next)
1269         {
1270                 object = GL_LABEL_OBJECT (p->data);
1271
1272                 if (gl_label_object_can_line_color (object))
1273                 {
1274                         g_list_free (selection_list);
1275                         return TRUE;
1276                 }
1277         }
1278
1279         g_list_free (selection_list);
1280         return FALSE;
1281 }
1282
1283
1284 /*****************************************************************************/
1285 /* Can line width properties be set for selection?                           */
1286 /*****************************************************************************/
1287 gboolean
1288 gl_label_can_selection_line_width (glLabel *label)
1289 {
1290         GList         *selection_list;
1291         GList         *p;
1292         glLabelObject *object;
1293
1294         gl_debug (DEBUG_LABEL, "");
1295
1296         g_return_val_if_fail (label && GL_IS_LABEL (label), FALSE);
1297
1298         selection_list = gl_label_get_selection_list (label);
1299
1300         for (p = selection_list; p != NULL; p = p->next)
1301         {
1302                 object = GL_LABEL_OBJECT (p->data);
1303
1304                 if (gl_label_object_can_line_width (object))
1305                 {
1306                         g_list_free (selection_list);
1307                         return TRUE;
1308                 }
1309
1310         }
1311
1312         g_list_free (selection_list);
1313         return FALSE;
1314 }
1315
1316
1317 /*****************************************************************************/
1318 /* Delete selection from label.                                              */
1319 /*****************************************************************************/
1320 void
1321 gl_label_delete_selection (glLabel       *label)
1322 {
1323         GList         *selection_list;
1324         GList         *p;
1325         glLabelObject *object;
1326
1327         gl_debug (DEBUG_LABEL, "START");
1328
1329         g_return_if_fail (label && GL_IS_LABEL (label));
1330
1331         gl_label_checkpoint (label, _("Delete"));
1332
1333         begin_selection_op (label);
1334
1335         selection_list = gl_label_get_selection_list (label);
1336
1337         for ( p = selection_list; p != NULL; p = p->next )
1338         {
1339                 object = GL_LABEL_OBJECT (p->data);
1340
1341                 gl_label_delete_object (label, object);
1342         }
1343
1344         g_list_free (selection_list);
1345
1346         end_selection_op (label);
1347
1348         g_signal_emit (G_OBJECT(label), signals[SELECTION_CHANGED], 0);
1349
1350         gl_debug (DEBUG_LABEL, "END");
1351 }
1352
1353
1354 /****************************************************************************/
1355 /* Bring selection object to front/top.                                     */
1356 /****************************************************************************/
1357 void
1358 gl_label_raise_selection_to_top (glLabel       *label)
1359 {
1360         GList         *selection_list;
1361         GList         *p;
1362         glLabelObject *object;
1363
1364         gl_debug (DEBUG_LABEL, "START");
1365
1366         gl_label_checkpoint (label, _("Bring to front"));
1367
1368         begin_selection_op (label);
1369
1370         selection_list = gl_label_get_selection_list (label);
1371
1372         for ( p = selection_list; p != NULL; p = p->next )
1373         {
1374                 object = GL_LABEL_OBJECT (p->data);
1375
1376                 label->priv->object_list = g_list_remove (label->priv->object_list, object);
1377         }
1378
1379         /* Move to end of list, representing front most object */
1380         label->priv->object_list = g_list_concat (label->priv->object_list, selection_list);
1381
1382         do_modify (label);
1383
1384         end_selection_op (label);
1385
1386         gl_debug (DEBUG_LABEL, "END");
1387 }
1388
1389
1390 /****************************************************************************/
1391 /* Send selection to rear/bottom.                                           */
1392 /****************************************************************************/
1393 void
1394 gl_label_lower_selection_to_bottom (glLabel       *label)
1395 {
1396         GList         *selection_list;
1397         GList         *p;
1398         glLabelObject *object;
1399
1400         gl_debug (DEBUG_LABEL, "START");
1401
1402         gl_label_checkpoint (label, _("Send to back"));
1403
1404         begin_selection_op (label);
1405
1406         selection_list = gl_label_get_selection_list (label);
1407
1408         for ( p = selection_list; p != NULL; p = p->next )
1409         {
1410                 object = GL_LABEL_OBJECT (p->data);
1411
1412                 label->priv->object_list = g_list_remove (label->priv->object_list, object);
1413         }
1414
1415         /* Move to front of list, representing rear most object */
1416         label->priv->object_list = g_list_concat (selection_list, label->priv->object_list);
1417
1418         do_modify (label);
1419
1420         end_selection_op (label);
1421
1422         gl_debug (DEBUG_LABEL, "END");
1423 }
1424
1425
1426 /*****************************************************************************/
1427 /* Rotate selected objects by given angle.                                   */
1428 /*****************************************************************************/
1429 void
1430 gl_label_rotate_selection (glLabel *label,
1431                            gdouble  theta_degs)
1432 {
1433         GList         *selection_list;
1434         GList         *p;
1435         glLabelObject *object;
1436
1437         gl_debug (DEBUG_LABEL, "START");
1438
1439         g_return_if_fail (label && GL_IS_LABEL (label));
1440
1441         begin_selection_op (label);
1442
1443         gl_label_checkpoint (label, _("Rotate"));
1444
1445         selection_list = gl_label_get_selection_list (label);
1446
1447         for ( p = selection_list; p != NULL; p = p->next )
1448         {
1449                 object = GL_LABEL_OBJECT (p->data);
1450
1451                 gl_label_object_rotate (object, theta_degs);
1452         }
1453
1454         g_list_free (selection_list);
1455
1456         end_selection_op (label);
1457
1458         gl_debug (DEBUG_LABEL, "END");
1459 }
1460
1461
1462 /*****************************************************************************/
1463 /* Rotate selected objects 90 degrees left.                                  */
1464 /*****************************************************************************/
1465 void
1466 gl_label_rotate_selection_left (glLabel *label)
1467 {
1468         GList         *selection_list;
1469         GList         *p;
1470         glLabelObject *object;
1471
1472         gl_debug (DEBUG_LABEL, "START");
1473
1474         g_return_if_fail (label && GL_IS_LABEL (label));
1475
1476         begin_selection_op (label);
1477
1478         gl_label_checkpoint (label, _("Rotate left"));
1479
1480         selection_list = gl_label_get_selection_list (label);
1481
1482         for ( p = selection_list; p != NULL; p = p->next )
1483         {
1484                 object = GL_LABEL_OBJECT (p->data);
1485
1486                 gl_label_object_rotate (object, -90.0);
1487         }
1488
1489         g_list_free (selection_list);
1490
1491         end_selection_op (label);
1492
1493         gl_debug (DEBUG_LABEL, "END");
1494 }
1495
1496
1497 /*****************************************************************************/
1498 /* Rotate selected objects 90 degrees right.                                 */
1499 /*****************************************************************************/
1500 void
1501 gl_label_rotate_selection_right (glLabel *label)
1502 {
1503         GList         *selection_list;
1504         GList         *p;
1505         glLabelObject *object;
1506
1507         gl_debug (DEBUG_LABEL, "START");
1508
1509         g_return_if_fail (label && GL_IS_LABEL (label));
1510
1511         gl_label_checkpoint (label, _("Rotate right"));
1512
1513         begin_selection_op (label);
1514
1515         selection_list = gl_label_get_selection_list (label);
1516
1517         for ( p = selection_list; p != NULL; p = p->next )
1518         {
1519                 object = GL_LABEL_OBJECT (p->data);
1520
1521                 gl_label_object_rotate (object, 90.0);
1522         }
1523
1524         g_list_free (selection_list);
1525
1526         end_selection_op (label);
1527
1528         gl_debug (DEBUG_LABEL, "END");
1529 }
1530
1531
1532 /*****************************************************************************/
1533 /* Flip selected objects horizontally.                                       */
1534 /*****************************************************************************/
1535 void
1536 gl_label_flip_selection_horiz (glLabel *label)
1537 {
1538         GList         *selection_list;
1539         GList         *p;
1540         glLabelObject *object;
1541
1542         gl_debug (DEBUG_LABEL, "START");
1543
1544         g_return_if_fail (label && GL_IS_LABEL (label));
1545
1546         gl_label_checkpoint (label, _("Flip horizontally"));
1547
1548         begin_selection_op (label);
1549
1550         selection_list = gl_label_get_selection_list (label);
1551
1552         for ( p = selection_list; p != NULL; p = p->next )
1553         {
1554                 object = GL_LABEL_OBJECT (p->data);
1555
1556                 gl_label_object_flip_horiz (object);
1557         }
1558
1559         g_list_free (selection_list);
1560
1561         end_selection_op (label);
1562
1563         gl_debug (DEBUG_LABEL, "END");
1564 }
1565
1566
1567 /*****************************************************************************/
1568 /* Flip selected objects vertically.                                         */
1569 /*****************************************************************************/
1570 void
1571 gl_label_flip_selection_vert (glLabel *label)
1572 {
1573         GList         *selection_list;
1574         GList         *p;
1575         glLabelObject *object;
1576
1577         gl_debug (DEBUG_LABEL, "START");
1578
1579         g_return_if_fail (label && GL_IS_LABEL (label));
1580
1581         gl_label_checkpoint (label, _("Flip vertically"));
1582
1583         begin_selection_op (label);
1584
1585         selection_list = gl_label_get_selection_list (label);
1586
1587         for ( p = selection_list; p != NULL; p = p->next )
1588         {
1589                 object = GL_LABEL_OBJECT (p->data);
1590
1591                 gl_label_object_flip_vert (object);
1592         }
1593
1594         g_list_free (selection_list);
1595
1596         end_selection_op (label);
1597
1598         gl_debug (DEBUG_LABEL, "END");
1599 }
1600
1601
1602 /*****************************************************************************/
1603 /* Align selected objects to left most edge.                                 */
1604 /*****************************************************************************/
1605 void
1606 gl_label_align_selection_left (glLabel *label)
1607 {
1608         GList         *selection_list;
1609         GList         *p;
1610         glLabelObject *object;
1611         gdouble        dx, x1_min;
1612         glLabelRegion  obj_extent;
1613
1614         gl_debug (DEBUG_LABEL, "START");
1615
1616         g_return_if_fail (label && GL_IS_LABEL (label));
1617
1618         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1619                           !gl_label_is_selection_atomic (label));
1620
1621         gl_label_checkpoint (label, _("Align left"));
1622
1623         begin_selection_op (label);
1624
1625         selection_list = gl_label_get_selection_list (label);
1626
1627         /* find left most edge */
1628         p = selection_list;
1629         object = GL_LABEL_OBJECT (p->data);
1630
1631         gl_label_object_get_extent (object, &obj_extent);
1632         x1_min = obj_extent.x1;
1633         for (p = p->next; p != NULL; p = p->next)
1634         {
1635                 object = GL_LABEL_OBJECT (p->data);
1636
1637                 gl_label_object_get_extent (object, &obj_extent);
1638                 if ( obj_extent.x1 < x1_min ) x1_min = obj_extent.x1;
1639         }
1640
1641         /* now adjust the object positions to line up the left edges */
1642         for (p = selection_list; p != NULL; p = p->next)
1643         {
1644                 object = GL_LABEL_OBJECT (p->data);
1645
1646                 gl_label_object_get_extent (object, &obj_extent);
1647                 dx = x1_min - obj_extent.x1;
1648                 gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
1649         }
1650
1651         g_list_free (selection_list);
1652
1653         end_selection_op (label);
1654
1655         gl_debug (DEBUG_LABEL, "END");
1656 }
1657
1658
1659 /*****************************************************************************/
1660 /* Align selected objects to right most edge.                                */
1661 /*****************************************************************************/
1662 void
1663 gl_label_align_selection_right (glLabel *label)
1664 {
1665         GList         *selection_list;
1666         GList         *p;
1667         glLabelObject *object;
1668         gdouble        dx, x2_max;
1669         glLabelRegion  obj_extent;
1670
1671         gl_debug (DEBUG_LABEL, "START");
1672
1673         g_return_if_fail (label && GL_IS_LABEL (label));
1674
1675         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1676                           !gl_label_is_selection_atomic (label));
1677
1678         gl_label_checkpoint (label, _("Align right"));
1679
1680         begin_selection_op (label);
1681
1682         selection_list = gl_label_get_selection_list (label);
1683
1684         /* find left most edge */
1685         p = selection_list;
1686         object = GL_LABEL_OBJECT (p->data);
1687
1688         gl_label_object_get_extent (object, &obj_extent);
1689         x2_max = obj_extent.x2;
1690         for (p = p->next; p != NULL; p = p->next)
1691         {
1692                 object = GL_LABEL_OBJECT (p->data);
1693
1694                 gl_label_object_get_extent (object, &obj_extent);
1695                 if ( obj_extent.x2 > x2_max ) x2_max = obj_extent.x2;
1696         }
1697
1698         /* now adjust the object positions to line up the left edges */
1699         for (p = selection_list; p != NULL; p = p->next)
1700         {
1701                 object = GL_LABEL_OBJECT (p->data);
1702
1703                 gl_label_object_get_extent (object, &obj_extent);
1704                 dx = x2_max - obj_extent.x2;
1705                 gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
1706         }
1707
1708         g_list_free (selection_list);
1709
1710         end_selection_op (label);
1711
1712         gl_debug (DEBUG_LABEL, "END");
1713 }
1714
1715
1716 /*****************************************************************************/
1717 /* Align selected objects to horizontal center of objects.                   */
1718 /*****************************************************************************/
1719 void
1720 gl_label_align_selection_hcenter (glLabel *label)
1721 {
1722         GList         *selection_list;
1723         GList         *p;
1724         glLabelObject *object;
1725         gdouble        dx;
1726         gdouble        dxmin;
1727         gdouble        xsum, xavg;
1728         glLabelRegion  obj_extent;
1729         gdouble        xcenter;
1730         gint           n;
1731
1732         gl_debug (DEBUG_LABEL, "START");
1733
1734         g_return_if_fail (label && GL_IS_LABEL (label));
1735
1736         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1737                           !gl_label_is_selection_atomic (label));
1738
1739         gl_label_checkpoint (label, _("Align horizontal center"));
1740
1741         begin_selection_op (label);
1742
1743         selection_list = gl_label_get_selection_list (label);
1744
1745         /* find average center of objects */
1746         xsum = 0.0;
1747         n = 0;
1748         for (p = selection_list; p != NULL; p = p->next)
1749         {
1750                 object = GL_LABEL_OBJECT (p->data);
1751
1752                 gl_label_object_get_extent (object, &obj_extent);
1753                 xsum += (obj_extent.x1 + obj_extent.x2) / 2.0;
1754                 n++;
1755         }
1756         xavg = xsum / n;
1757
1758         /* find center of object closest to average center */
1759         p = selection_list;
1760         object = GL_LABEL_OBJECT (p->data);
1761
1762         gl_label_object_get_extent (object, &obj_extent);
1763         dxmin = fabs (xavg - (obj_extent.x1 + obj_extent.x2)/2.0);
1764         xcenter = (obj_extent.x1 + obj_extent.x2)/2.0;
1765         for (p = p->next; p != NULL; p = p->next)
1766         {
1767                 object = GL_LABEL_OBJECT (p->data);
1768
1769                 gl_label_object_get_extent (object, &obj_extent);
1770                 dx = fabs (xavg - (obj_extent.x1 + obj_extent.x2)/2.0);
1771                 if ( dx < dxmin )
1772                 {
1773                         dxmin = dx;
1774                         xcenter = (obj_extent.x1 + obj_extent.x2)/2.0;
1775                 }
1776         }
1777
1778         /* now adjust the object positions to line up this center */
1779         for (p = selection_list; p != NULL; p = p->next)
1780         {
1781                 object = GL_LABEL_OBJECT (p->data);
1782
1783                 gl_label_object_get_extent (object, &obj_extent);
1784                 dx = xcenter - (obj_extent.x1 + obj_extent.x2)/2.0;
1785                 gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
1786         }
1787
1788         g_list_free (selection_list);
1789
1790         end_selection_op (label);
1791
1792         gl_debug (DEBUG_LABEL, "END");
1793 }
1794
1795
1796 /*****************************************************************************/
1797 /* Align selected objects to top most edge.                                  */
1798 /*****************************************************************************/
1799 void
1800 gl_label_align_selection_top (glLabel *label)
1801 {
1802         GList         *selection_list;
1803         GList         *p;
1804         glLabelObject *object;
1805         gdouble        dy, y1_min;
1806         glLabelRegion  obj_extent;
1807
1808         gl_debug (DEBUG_LABEL, "START");
1809
1810         g_return_if_fail (label && GL_IS_LABEL (label));
1811
1812         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1813                           !gl_label_is_selection_atomic (label));
1814
1815         gl_label_checkpoint (label, _("Align tops"));
1816
1817         begin_selection_op (label);
1818
1819         selection_list = gl_label_get_selection_list (label);
1820
1821         /* find top most edge */
1822         p = selection_list;
1823         object = GL_LABEL_OBJECT (p->data);
1824
1825         gl_label_object_get_extent (object, &obj_extent);
1826         y1_min = obj_extent.y1;
1827         for (p = p->next; p != NULL; p = p->next)
1828         {
1829                 object = GL_LABEL_OBJECT (p->data);
1830
1831                 gl_label_object_get_extent (object, &obj_extent);
1832                 if ( obj_extent.y1 < y1_min ) y1_min = obj_extent.y1;
1833         }
1834
1835         /* now adjust the object positions to line up the top edges */
1836         for (p = selection_list; p != NULL; p = p->next)
1837         {
1838                 object = GL_LABEL_OBJECT (p->data);
1839
1840                 gl_label_object_get_extent (object, &obj_extent);
1841                 dy = y1_min - obj_extent.y1;
1842                 gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
1843         }
1844
1845         g_list_free (selection_list);
1846
1847         end_selection_op (label);
1848
1849         gl_debug (DEBUG_LABEL, "END");
1850 }
1851
1852
1853 /*****************************************************************************/
1854 /* Align selected objects to bottom most edge.                               */
1855 /*****************************************************************************/
1856 void
1857 gl_label_align_selection_bottom (glLabel *label)
1858 {
1859         GList         *selection_list;
1860         GList         *p;
1861         glLabelObject *object;
1862         gdouble        dy, y2_max;
1863         glLabelRegion  obj_extent;
1864
1865         gl_debug (DEBUG_LABEL, "START");
1866
1867         g_return_if_fail (label && GL_IS_LABEL (label));
1868
1869         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1870                           !gl_label_is_selection_atomic (label));
1871
1872         gl_label_checkpoint (label, _("Align bottoms"));
1873
1874         begin_selection_op (label);
1875
1876         selection_list = gl_label_get_selection_list (label);
1877
1878         /* find bottom most edge */
1879         p = selection_list;
1880         object = GL_LABEL_OBJECT (p->data);
1881
1882         gl_label_object_get_extent (object, &obj_extent);
1883         y2_max = obj_extent.y2;
1884         for (p = p->next; p != NULL; p = p->next)
1885         {
1886                 object = GL_LABEL_OBJECT (p->data);
1887
1888                 gl_label_object_get_extent (object, &obj_extent);
1889                 if ( obj_extent.y2 > y2_max ) y2_max = obj_extent.y2;
1890         }
1891
1892         /* now adjust the object positions to line up the bottom edges */
1893         for (p = selection_list; p != NULL; p = p->next)
1894         {
1895                 object = GL_LABEL_OBJECT (p->data);
1896
1897                 gl_label_object_get_extent (object, &obj_extent);
1898                 dy = y2_max - obj_extent.y2;
1899                 gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
1900         }
1901
1902         g_list_free (selection_list);
1903
1904         end_selection_op (label);
1905
1906         gl_debug (DEBUG_LABEL, "END");
1907 }
1908
1909
1910 /*****************************************************************************/
1911 /* Align selected objects to viertical center of objects.                    */
1912 /*****************************************************************************/
1913 void
1914 gl_label_align_selection_vcenter (glLabel *label)
1915 {
1916         GList         *selection_list;
1917         GList         *p;
1918         glLabelObject *object;
1919         gdouble        dy;
1920         gdouble        dymin;
1921         gdouble        ysum, yavg;
1922         glLabelRegion  obj_extent;
1923         gdouble        ycenter;
1924         gint           n;
1925
1926         gl_debug (DEBUG_LABEL, "START");
1927
1928         g_return_if_fail (label && GL_IS_LABEL (label));
1929
1930         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1931                           !gl_label_is_selection_atomic (label));
1932
1933         gl_label_checkpoint (label, _("Align vertical center"));
1934
1935         begin_selection_op (label);
1936
1937         selection_list = gl_label_get_selection_list (label);
1938
1939         /* find average center of objects */
1940         ysum = 0.0;
1941         n = 0;
1942         for (p = selection_list; p != NULL; p = p->next)
1943         {
1944                 object = GL_LABEL_OBJECT (p->data);
1945
1946                 gl_label_object_get_extent (object, &obj_extent);
1947                 ysum += (obj_extent.y1 + obj_extent.y2) / 2.0;
1948                 n++;
1949         }
1950         yavg = ysum / n;
1951
1952         /* find center of object closest to average center */
1953         p = selection_list;
1954         object = GL_LABEL_OBJECT (p->data);
1955
1956         gl_label_object_get_extent (object, &obj_extent);
1957         dymin = fabs (yavg - (obj_extent.y1 + obj_extent.y2)/2.0);
1958         ycenter = (obj_extent.y1 + obj_extent.y2)/2.0;
1959         for (p = p->next; p != NULL; p = p->next)
1960         {
1961                 object = GL_LABEL_OBJECT (p->data);
1962
1963                 gl_label_object_get_extent (object, &obj_extent);
1964                 dy = fabs (yavg - (obj_extent.y1 + obj_extent.y2)/2.0);
1965                 if ( dy < dymin )
1966                 {
1967                         dymin = dy;
1968                         ycenter = (obj_extent.y1 + obj_extent.y2)/2.0;
1969                 }
1970         }
1971
1972         /* now adjust the object positions to line up this center */
1973         for (p = selection_list; p != NULL; p = p->next)
1974         {
1975                 object = GL_LABEL_OBJECT (p->data);
1976
1977                 gl_label_object_get_extent (object, &obj_extent);
1978                 dy = ycenter - (obj_extent.y1 + obj_extent.y2)/2.0;
1979                 gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
1980         }
1981
1982         g_list_free (selection_list);
1983
1984         end_selection_op (label);
1985
1986         gl_debug (DEBUG_LABEL, "END");
1987 }
1988
1989
1990 /*****************************************************************************/
1991 /* Center selected objects to in center of label.                            */
1992 /*****************************************************************************/
1993 void
1994 gl_label_center_selection_horiz (glLabel *label)
1995 {
1996         GList         *selection_list;
1997         GList         *p;
1998         glLabelObject *object;
1999         gdouble        dx;
2000         gdouble        x_label_center;
2001         gdouble        x_obj_center;
2002         glLabelRegion  obj_extent;
2003         gdouble        w, h;
2004
2005         gl_debug (DEBUG_LABEL, "START");
2006
2007         g_return_if_fail (label && GL_IS_LABEL (label));
2008
2009         g_return_if_fail (!gl_label_is_selection_empty (label));
2010
2011         gl_label_checkpoint (label, _("Center horizontally"));
2012
2013         begin_selection_op (label);
2014
2015         gl_label_get_size (label, &w, &h);
2016         x_label_center = w / 2.0;
2017
2018         /* adjust the object positions */
2019         selection_list = gl_label_get_selection_list (label);
2020         for (p = selection_list; p != NULL; p = p->next)
2021         {
2022                 object = GL_LABEL_OBJECT (p->data);
2023
2024                 gl_label_object_get_extent (object, &obj_extent);
2025                 x_obj_center = (obj_extent.x1 + obj_extent.x2) / 2.0;
2026                 dx = x_label_center - x_obj_center;
2027                 gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
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 /* Center selected objects to in center of label.                            */
2039 /*****************************************************************************/
2040 void
2041 gl_label_center_selection_vert (glLabel *label)
2042 {
2043         GList         *selection_list;
2044         GList         *p;
2045         glLabelObject *object;
2046         gdouble        dy;
2047         gdouble        y_label_center;
2048         gdouble        y_obj_center;
2049         glLabelRegion  obj_extent;
2050         gdouble        w, h;
2051
2052         gl_debug (DEBUG_LABEL, "START");
2053
2054         g_return_if_fail (label && GL_IS_LABEL (label));
2055
2056         g_return_if_fail (!gl_label_is_selection_empty (label));
2057
2058         gl_label_checkpoint (label, _("Center vertically"));
2059
2060         begin_selection_op (label);
2061
2062         gl_label_get_size (label, &w, &h);
2063         y_label_center = h / 2.0;
2064
2065         /* adjust the object positions */
2066         selection_list = gl_label_get_selection_list (label);
2067         for (p = selection_list; p != NULL; p = p->next)
2068         {
2069                 object = GL_LABEL_OBJECT (p->data);
2070
2071                 gl_label_object_get_extent (object, &obj_extent);
2072                 y_obj_center = (obj_extent.y1 + obj_extent.y2) / 2.0;
2073                 dy = y_label_center - y_obj_center;
2074                 gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
2075         }
2076         g_list_free (selection_list);
2077
2078         end_selection_op (label);
2079
2080         gl_debug (DEBUG_LABEL, "END");
2081 }
2082
2083
2084 /*****************************************************************************/
2085 /* Move selected objects                                                     */
2086 /*****************************************************************************/
2087 void
2088 gl_label_move_selection (glLabel  *label,
2089                          gdouble   dx,
2090                          gdouble   dy)
2091 {
2092         GList         *selection_list;
2093         GList         *p;
2094         glLabelObject *object;
2095
2096         gl_debug (DEBUG_LABEL, "START");
2097
2098         g_return_if_fail (label && GL_IS_LABEL (label));
2099
2100         begin_selection_op (label);
2101
2102         selection_list = gl_label_get_selection_list (label);
2103
2104         for (p = selection_list; p != NULL; p = p->next)
2105         {
2106                 object = GL_LABEL_OBJECT (p->data);
2107
2108                 gl_label_object_set_position_relative (object, dx, dy, TRUE);
2109         }
2110
2111         g_list_free (selection_list);
2112
2113         end_selection_op (label);
2114
2115         gl_debug (DEBUG_LABEL, "END");
2116 }
2117
2118
2119 /*****************************************************************************/
2120 /* Set font family for all text contained in selected objects.               */
2121 /*****************************************************************************/
2122 void
2123 gl_label_set_selection_font_family (glLabel      *label,
2124                                     const gchar  *font_family)
2125 {
2126         GList         *selection_list;
2127         GList         *p;
2128         glLabelObject *object;
2129
2130         gl_debug (DEBUG_LABEL, "START");
2131
2132         g_return_if_fail (label && GL_IS_LABEL (label));
2133
2134         begin_selection_op (label);
2135
2136         selection_list = gl_label_get_selection_list (label);
2137
2138         for (p = selection_list; p != NULL; p = p->next)
2139         {
2140                 object = GL_LABEL_OBJECT (p->data);
2141                 gl_label_object_set_font_family (object, font_family, TRUE);
2142         }
2143
2144         g_list_free (selection_list);
2145
2146         end_selection_op (label);
2147
2148         gl_debug (DEBUG_LABEL, "END");
2149 }
2150
2151
2152 /*****************************************************************************/
2153 /* Set font size for all text contained in selected objects.                 */
2154 /*****************************************************************************/
2155 void
2156 gl_label_set_selection_font_size (glLabel  *label,
2157                                   gdouble   font_size)
2158 {
2159         GList         *selection_list;
2160         GList         *p;
2161         glLabelObject *object;
2162
2163         gl_debug (DEBUG_LABEL, "START");
2164
2165         g_return_if_fail (label && GL_IS_LABEL (label));
2166
2167         begin_selection_op (label);
2168
2169         selection_list = gl_label_get_selection_list (label);
2170
2171         for (p = selection_list; p != NULL; p = p->next)
2172         {
2173                 object = GL_LABEL_OBJECT (p->data);
2174                 gl_label_object_set_font_size (object, font_size, TRUE);
2175         }
2176
2177         g_list_free (selection_list);
2178
2179         end_selection_op (label);
2180
2181         gl_debug (DEBUG_LABEL, "END");
2182 }
2183
2184
2185 /*****************************************************************************/
2186 /* Set font weight for all text contained in selected objects.               */
2187 /*****************************************************************************/
2188 void
2189 gl_label_set_selection_font_weight (glLabel      *label,
2190                                     PangoWeight   font_weight)
2191 {
2192         GList         *selection_list;
2193         GList         *p;
2194         glLabelObject *object;
2195
2196         gl_debug (DEBUG_LABEL, "START");
2197
2198         g_return_if_fail (label && GL_IS_LABEL (label));
2199
2200         begin_selection_op (label);
2201
2202         selection_list = gl_label_get_selection_list (label);
2203
2204         for (p = selection_list; p != NULL; p = p->next)
2205         {
2206                 object = GL_LABEL_OBJECT (p->data);
2207                 gl_label_object_set_font_weight (object, font_weight, TRUE);
2208         }
2209
2210         g_list_free (selection_list);
2211
2212         end_selection_op (label);
2213
2214         gl_debug (DEBUG_LABEL, "END");
2215 }
2216
2217
2218 /*****************************************************************************/
2219 /* Set font italic flag for all text contained in selected objects.          */
2220 /*****************************************************************************/
2221 void
2222 gl_label_set_selection_font_italic_flag (glLabel   *label,
2223                                          gboolean   font_italic_flag)
2224 {
2225         GList         *selection_list;
2226         GList         *p;
2227         glLabelObject *object;
2228
2229         gl_debug (DEBUG_LABEL, "START");
2230
2231         g_return_if_fail (label && GL_IS_LABEL (label));
2232
2233         begin_selection_op (label);
2234
2235         selection_list = gl_label_get_selection_list (label);
2236
2237         for (p = selection_list; p != NULL; p = p->next)
2238         {
2239                 object = GL_LABEL_OBJECT (p->data);
2240                 gl_label_object_set_font_italic_flag (object, font_italic_flag, TRUE);
2241         }
2242
2243         g_list_free (selection_list);
2244
2245         end_selection_op (label);
2246
2247         gl_debug (DEBUG_LABEL, "END");
2248 }
2249
2250
2251 /*****************************************************************************/
2252 /* Set text alignment for all text contained in selected objects.            */
2253 /*****************************************************************************/
2254 void
2255 gl_label_set_selection_text_alignment (glLabel        *label,
2256                                        PangoAlignment  text_alignment)
2257 {
2258         GList         *selection_list;
2259         GList         *p;
2260         glLabelObject *object;
2261
2262         gl_debug (DEBUG_LABEL, "START");
2263
2264         g_return_if_fail (label && GL_IS_LABEL (label));
2265
2266         begin_selection_op (label);
2267
2268         selection_list = gl_label_get_selection_list (label);
2269
2270         for (p = selection_list; p != NULL; p = p->next)
2271         {
2272                 object = GL_LABEL_OBJECT (p->data);
2273                 gl_label_object_set_text_alignment (object, text_alignment, TRUE);
2274         }
2275
2276         g_list_free (selection_list);
2277
2278         end_selection_op (label);
2279
2280         gl_debug (DEBUG_LABEL, "END");
2281 }
2282
2283
2284 /*****************************************************************************/
2285 /* Set vertical text alignment for all text contained in selected objects.   */
2286 /*****************************************************************************/
2287 void
2288 gl_label_set_selection_text_valignment (glLabel        *label,
2289                                         glValignment    text_valignment)
2290 {
2291         GList         *selection_list;
2292         GList         *p;
2293         glLabelObject *object;
2294
2295         gl_debug (DEBUG_LABEL, "START");
2296
2297         g_return_if_fail (label && GL_IS_LABEL (label));
2298
2299         begin_selection_op (label);
2300
2301         selection_list = gl_label_get_selection_list (label);
2302
2303         for (p = selection_list; p != NULL; p = p->next)
2304         {
2305                 object = GL_LABEL_OBJECT (p->data);
2306                 gl_label_object_set_text_valignment (object, text_valignment, TRUE);
2307         }
2308
2309         g_list_free (selection_list);
2310
2311         end_selection_op (label);
2312
2313         gl_debug (DEBUG_LABEL, "END");
2314 }
2315
2316
2317 /*****************************************************************************/
2318 /* Set text line spacing for all text contained in selected objects.         */
2319 /*****************************************************************************/
2320 void
2321 gl_label_set_selection_text_line_spacing (glLabel  *label,
2322                                           gdouble   text_line_spacing)
2323 {
2324         GList         *selection_list;
2325         GList         *p;
2326         glLabelObject *object;
2327
2328         gl_debug (DEBUG_LABEL, "START");
2329
2330         g_return_if_fail (label && GL_IS_LABEL (label));
2331
2332         begin_selection_op (label);
2333
2334         selection_list = gl_label_get_selection_list (label);
2335
2336         for (p = selection_list; p != NULL; p = p->next)
2337         {
2338                 object = GL_LABEL_OBJECT (p->data);
2339                 gl_label_object_set_text_line_spacing (object, text_line_spacing, TRUE);
2340         }
2341
2342         g_list_free (selection_list);
2343
2344         end_selection_op (label);
2345
2346         gl_debug (DEBUG_LABEL, "END");
2347 }
2348
2349
2350 /*****************************************************************************/
2351 /* Set text color for all text contained in selected objects.                */
2352 /*****************************************************************************/
2353 void
2354 gl_label_set_selection_text_color (glLabel      *label,
2355                                    glColorNode  *text_color_node)
2356 {
2357         GList         *selection_list;
2358         GList         *p;
2359         glLabelObject *object;
2360
2361         gl_debug (DEBUG_LABEL, "START");
2362
2363         g_return_if_fail (label && GL_IS_LABEL (label));
2364
2365         begin_selection_op (label);
2366
2367         selection_list = gl_label_get_selection_list (label);
2368
2369         for (p = selection_list; p != NULL; p = p->next)
2370         {
2371                 object = GL_LABEL_OBJECT (p->data);
2372                 gl_label_object_set_text_color (object, text_color_node, TRUE);
2373         }
2374
2375         g_list_free (selection_list);
2376
2377         end_selection_op (label);
2378
2379         gl_debug (DEBUG_LABEL, "END");
2380 }
2381
2382
2383 /*****************************************************************************/
2384 /* Set fill color for all selected objects.                                  */
2385 /*****************************************************************************/
2386 void
2387 gl_label_set_selection_fill_color (glLabel      *label,
2388                                    glColorNode  *fill_color_node)
2389 {
2390         GList         *selection_list;
2391         GList         *p;
2392         glLabelObject *object;
2393
2394         gl_debug (DEBUG_LABEL, "START");
2395
2396         g_return_if_fail (label && GL_IS_LABEL (label));
2397
2398         begin_selection_op (label);
2399
2400         selection_list = gl_label_get_selection_list (label);
2401
2402         for (p = selection_list; p != NULL; p = p->next)
2403         {
2404                 object = GL_LABEL_OBJECT (p->data);
2405                 gl_label_object_set_fill_color (object, fill_color_node, TRUE);
2406         }
2407
2408         g_list_free (selection_list);
2409
2410         end_selection_op (label);
2411
2412         gl_debug (DEBUG_LABEL, "END");
2413 }
2414
2415
2416 /*****************************************************************************/
2417 /* Set line color for all selected objects.                                  */
2418 /*****************************************************************************/
2419 void
2420 gl_label_set_selection_line_color (glLabel      *label,
2421                                    glColorNode  *line_color_node)
2422 {
2423         GList         *selection_list;
2424         GList         *p;
2425         glLabelObject *object;
2426
2427         gl_debug (DEBUG_LABEL, "START");
2428
2429         g_return_if_fail (label && GL_IS_LABEL (label));
2430
2431         begin_selection_op (label);
2432
2433         selection_list = gl_label_get_selection_list (label);
2434
2435         for (p = selection_list; p != NULL; p = p->next)
2436         {
2437                 object = GL_LABEL_OBJECT (p->data);
2438                 gl_label_object_set_line_color (object, line_color_node, TRUE);
2439         }
2440
2441         g_list_free (selection_list);
2442
2443         end_selection_op (label);
2444
2445         gl_debug (DEBUG_LABEL, "END");
2446 }
2447
2448
2449 /*****************************************************************************/
2450 /* Set line width for all selected objects.                                  */
2451 /*****************************************************************************/
2452 void
2453 gl_label_set_selection_line_width (glLabel  *label,
2454                                   gdouble  line_width)
2455 {
2456         GList         *selection_list;
2457         GList         *p;
2458         glLabelObject *object;
2459
2460         gl_debug (DEBUG_LABEL, "START");
2461
2462         g_return_if_fail (label && GL_IS_LABEL (label));
2463
2464         begin_selection_op (label);
2465
2466         selection_list = gl_label_get_selection_list (label);
2467
2468         for (p = selection_list; p != NULL; p = p->next)
2469         {
2470                 object = GL_LABEL_OBJECT (p->data);
2471                 gl_label_object_set_line_width (object, line_width, TRUE);
2472         }
2473
2474         g_list_free (selection_list);
2475
2476         end_selection_op (label);
2477
2478         gl_debug (DEBUG_LABEL, "END");
2479 }
2480
2481
2482 /*****************************************************************************/
2483 /* "Cut" selected items and place on clipboard.                              */
2484 /*****************************************************************************/
2485 void
2486 gl_label_cut_selection (glLabel       *label)
2487 {
2488         gl_debug (DEBUG_LABEL, "START");
2489
2490         g_return_if_fail (label && GL_IS_LABEL (label));
2491
2492         gl_label_copy_selection (label);
2493         gl_label_delete_selection (label);
2494
2495         gl_debug (DEBUG_LABEL, "END");
2496 }
2497
2498
2499 /*****************************************************************************/
2500 /* "Copy" selected items to clipboard.                                       */
2501 /*****************************************************************************/
2502 void
2503 gl_label_copy_selection (glLabel       *label)
2504 {
2505         GtkClipboard      *clipboard;
2506         GList             *selection_list;
2507         glLabel           *label_copy;
2508         GList             *p;
2509         glLabelObject     *object;
2510         glXMLLabelStatus   status;
2511
2512         ClipboardData     *data;
2513
2514         static GtkTargetEntry glabels_targets[] = { { "application/glabels", 0, 0 },
2515                                                     { "text/xml",            0, 0 },
2516         };
2517
2518         GtkTargetList  *target_list;
2519         GtkTargetEntry *target_table;
2520         gint            n_targets;
2521
2522         gl_debug (DEBUG_LABEL, "START");
2523
2524         g_return_if_fail (label && GL_IS_LABEL (label));
2525
2526         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2527
2528         selection_list = gl_label_get_selection_list (label);
2529
2530         if (selection_list)
2531         {
2532
2533                 data = g_new0 (ClipboardData, 1);
2534
2535                 target_list = gtk_target_list_new (glabels_targets, G_N_ELEMENTS(glabels_targets));
2536
2537                 /*
2538                  * Serialize selection by encoding as an XML label document.
2539                  */
2540                 label_copy = GL_LABEL(gl_label_new ());
2541
2542                 gl_label_set_template (label_copy, label->priv->template, FALSE);
2543                 gl_label_set_rotate_flag (label_copy, label->priv->rotate_flag, FALSE);
2544
2545                 for (p = selection_list; p != NULL; p = p->next)
2546                 {
2547                         object = GL_LABEL_OBJECT (p->data);
2548
2549                         gl_label_add_object (label_copy, gl_label_object_dup (object, label_copy));
2550                 }
2551
2552                 data->xml_buffer = gl_xml_label_save_buffer (label_copy, &status);
2553
2554                 g_object_unref (G_OBJECT (label_copy));
2555
2556
2557                 /*
2558                  * Is it an atomic text selection?  If so, also make available as text.
2559                  */
2560                 if ( gl_label_is_selection_atomic (label) &&
2561                      GL_IS_LABEL_TEXT (selection_list->data) )
2562                 {
2563                         glLabelText *text_object = GL_LABEL_TEXT (selection_list->data);
2564
2565                         gtk_target_list_add_text_targets (target_list, 1);
2566
2567                         data->text = gl_label_text_get_text (text_object);
2568                 }
2569
2570
2571                 /*
2572                  * Is it an atomic image selection?  If so, also make available as pixbuf.
2573                  */
2574                 if ( gl_label_is_selection_atomic (label) &&
2575                      GL_IS_LABEL_IMAGE (selection_list->data) )
2576                 {
2577                         glLabelImage  *image_object = GL_LABEL_IMAGE (selection_list->data);
2578                         GdkPixbuf     *pixbuf = gl_label_image_get_pixbuf (image_object, NULL);
2579
2580                         if (pixbuf)
2581                         {
2582                                 gtk_target_list_add_image_targets (target_list, 2, TRUE);
2583                                 data->pixbuf = pixbuf;
2584                         }
2585                 }
2586
2587
2588                 target_table = gtk_target_table_new_from_list (target_list, &n_targets);
2589
2590                 gtk_clipboard_set_with_data (clipboard,
2591                                              target_table, n_targets,
2592                                              (GtkClipboardGetFunc)clipboard_get_cb,
2593                                              (GtkClipboardClearFunc)clipboard_clear_cb,
2594                                              data);
2595
2596                 gtk_target_table_free (target_table, n_targets);
2597                 gtk_target_list_unref (target_list);
2598         }
2599
2600
2601         g_list_free (selection_list);
2602
2603         gl_debug (DEBUG_LABEL, "END");
2604 }
2605
2606
2607 /*****************************************************************************/
2608 /* "Paste" from clipboard.                                                   */
2609 /*****************************************************************************/
2610 void
2611 gl_label_paste (glLabel       *label)
2612 {
2613         GtkClipboard  *clipboard;
2614
2615         gl_debug (DEBUG_LABEL, "START");
2616
2617         g_return_if_fail (label && GL_IS_LABEL (label));
2618
2619         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2620
2621         gtk_clipboard_request_targets (clipboard,
2622                                        (GtkClipboardTargetsReceivedFunc)receive_targets_cb,
2623                                        label);
2624
2625         gl_debug (DEBUG_LABEL, "END");
2626 }
2627
2628
2629 /*****************************************************************************/
2630 /* Is there anything that can be pasted?                                     */
2631 /*****************************************************************************/
2632 gboolean
2633 gl_label_can_paste (glLabel       *label)
2634 {
2635         GtkClipboard *clipboard;
2636         gboolean      can_flag;
2637
2638         gl_debug (DEBUG_LABEL, "START");
2639
2640         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2641
2642         can_flag = gtk_clipboard_wait_is_target_available (clipboard,
2643                                                            gdk_atom_intern("application/glabels", TRUE))
2644                 || gtk_clipboard_wait_is_text_available (clipboard)
2645                 || gtk_clipboard_wait_is_image_available (clipboard);
2646
2647         gl_debug (DEBUG_LABEL, "END");
2648         return can_flag;
2649 }
2650
2651
2652 /****************************************************************************/
2653 /* Clipboard "Get" function.                                                */
2654 /****************************************************************************/
2655 static void
2656 clipboard_get_cb (GtkClipboard     *clipboard,
2657                   GtkSelectionData *selection_data,
2658                   guint             info,
2659                   ClipboardData    *data)
2660 {
2661         gl_debug (DEBUG_LABEL, "START");
2662
2663         switch (info)
2664         {
2665
2666         case 0:
2667                 gtk_selection_data_set (selection_data,
2668                                         gtk_selection_data_get_target (selection_data),
2669                                         8,
2670                                         (guchar *)data->xml_buffer, strlen (data->xml_buffer));
2671                 break;
2672
2673         case 1:
2674                 gtk_selection_data_set_text (selection_data, data->text, -1);
2675                 break;
2676
2677         case 2:
2678                 gtk_selection_data_set_pixbuf (selection_data, data->pixbuf);
2679                 break;
2680
2681         default:
2682                 g_assert_not_reached ();
2683                 break;
2684
2685         }
2686
2687         gl_debug (DEBUG_LABEL, "END");
2688 }
2689
2690
2691 /****************************************************************************/
2692 /* Clipboard "Clear" function.                                              */
2693 /****************************************************************************/
2694 static void
2695 clipboard_clear_cb (GtkClipboard     *clipboard,
2696                     ClipboardData    *data)
2697 {
2698         gl_debug (DEBUG_LABEL, "START");
2699
2700         g_free (data->xml_buffer);
2701         g_free (data->text);
2702         if (data->pixbuf)
2703         {
2704                 g_object_unref (data->pixbuf);
2705         }
2706
2707         g_free (data);
2708
2709         gl_debug (DEBUG_LABEL, "END");
2710 }
2711
2712
2713 /****************************************************************************/
2714 /* Deal with clipboard data.                                                */
2715 /****************************************************************************/
2716 static void
2717 receive_targets_cb (GtkClipboard *clipboard,
2718                     GdkAtom      *targets,
2719                     gint          n_targets,
2720                     glLabel      *label)
2721 {
2722         gint i;
2723
2724         /*
2725          * Application/glabels
2726          */
2727         for ( i = 0; i < n_targets; i++ )
2728         {
2729                 if ( strcmp(gdk_atom_name(targets[i]), "application/glabels") == 0 )
2730                 {
2731                         gtk_clipboard_request_contents (clipboard,
2732                                                         gdk_atom_intern("application/glabels", TRUE),
2733                                                         (GtkClipboardReceivedFunc)paste_xml_received_cb,
2734                                                         label);
2735                         return;
2736                 }
2737         }
2738
2739         /*
2740          * Text
2741          */
2742         if ( gtk_targets_include_text (targets, n_targets) )
2743         {
2744                 gtk_clipboard_request_text (clipboard,
2745                                             (GtkClipboardTextReceivedFunc)paste_text_received_cb,
2746                                             label);
2747                 return;
2748         }
2749
2750         /*
2751          * Image
2752          */
2753         if ( gtk_targets_include_image (targets, n_targets, TRUE) )
2754         {
2755                 gtk_clipboard_request_image (clipboard,
2756                                              (GtkClipboardImageReceivedFunc)paste_image_received_cb,
2757                                              label);
2758                 return;
2759         }
2760 }
2761
2762
2763 /****************************************************************************/
2764 /* Paste received glabels XML callback.                                     */
2765 /****************************************************************************/
2766 static void
2767 paste_xml_received_cb (GtkClipboard     *clipboard,
2768                        GtkSelectionData *selection_data,
2769                        glLabel          *label)
2770 {
2771         gchar            *xml_buffer;
2772         glLabel          *label_copy;
2773         glXMLLabelStatus  status;
2774         GList            *p;
2775         glLabelObject    *object, *newobject;
2776
2777         gl_debug (DEBUG_LABEL, "START");
2778
2779         gl_label_checkpoint (label, _("Paste"));
2780
2781         xml_buffer = (gchar *)gtk_selection_data_get_data (selection_data);
2782
2783         /*
2784          * Deserialize XML label document and extract objects.
2785          */
2786         label_copy = gl_xml_label_open_buffer (xml_buffer, &status);
2787         if ( label_copy )
2788         {
2789                 gl_label_unselect_all (label);
2790
2791                 for (p = label_copy->priv->object_list; p != NULL; p = p->next)
2792                 {
2793                         object = (glLabelObject *) p->data;
2794                         newobject = gl_label_object_dup (object, label);
2795                         gl_label_add_object( label, newobject );
2796
2797                         gl_label_select_object (label, newobject);
2798
2799                         gl_debug (DEBUG_LABEL, "object pasted");
2800                 }
2801
2802                 g_object_unref (G_OBJECT (label_copy));
2803         }
2804
2805         gl_debug (DEBUG_LABEL, "END");
2806 }
2807
2808
2809 /****************************************************************************/
2810 /* Paste received text callback.                                            */
2811 /****************************************************************************/
2812 static void
2813 paste_text_received_cb (GtkClipboard     *clipboard,
2814                         const gchar      *text,
2815                         glLabel          *label)
2816 {
2817         glLabelObject    *object;
2818
2819         gl_debug (DEBUG_LABEL, "START");
2820
2821         gl_label_checkpoint (label, _("Paste"));
2822
2823         gl_label_unselect_all (label);
2824
2825         object = GL_LABEL_OBJECT (gl_label_text_new (label, FALSE));
2826         gl_label_text_set_text (GL_LABEL_TEXT (object), text, FALSE);
2827         gl_label_object_set_position (object, 18, 18, FALSE);
2828
2829         gl_label_select_object (label, object);
2830
2831         gl_debug (DEBUG_LABEL, "END");
2832 }
2833
2834
2835 /****************************************************************************/
2836 /* Paste received image callback.                                           */
2837 /****************************************************************************/
2838 static void
2839 paste_image_received_cb (GtkClipboard     *clipboard,
2840                          GdkPixbuf        *pixbuf,
2841                          glLabel          *label)
2842 {
2843         glLabelObject    *object;
2844
2845         gl_debug (DEBUG_LABEL, "START");
2846
2847         gl_label_checkpoint (label, _("Paste"));
2848
2849         gl_label_unselect_all (label);
2850
2851         object = GL_LABEL_OBJECT (gl_label_image_new (label, FALSE));
2852         gl_label_image_set_pixbuf (GL_LABEL_IMAGE (object), pixbuf, FALSE);
2853         gl_label_object_set_position (object, 18, 18, FALSE);
2854
2855         gl_label_select_object (label, object);
2856
2857         gl_debug (DEBUG_LABEL, "END");
2858 }
2859
2860
2861 /****************************************************************************/
2862 /* Set default font family.                                                 */
2863 /****************************************************************************/
2864 void
2865 gl_label_set_default_font_family (glLabel     *label,
2866                                   const gchar *font_family)
2867 {
2868         gl_debug (DEBUG_LABEL, "START");
2869
2870         g_return_if_fail (label && GL_IS_LABEL (label));
2871
2872         g_free (label->priv->default_font_family);
2873         label->priv->default_font_family = g_strdup (font_family);
2874
2875         gl_debug (DEBUG_LABEL, "END");
2876 }
2877
2878
2879 /****************************************************************************/
2880 /* Set default font size.                                                   */
2881 /****************************************************************************/
2882 void
2883 gl_label_set_default_font_size (glLabel *label,
2884                                 gdouble  font_size)
2885 {
2886         gl_debug (DEBUG_LABEL, "START");
2887
2888         g_return_if_fail (label && GL_IS_LABEL (label));
2889
2890         label->priv->default_font_size = font_size;
2891
2892         gl_debug (DEBUG_LABEL, "END");
2893 }
2894
2895
2896 /****************************************************************************/
2897 /* Set default font weight.                                                 */
2898 /****************************************************************************/
2899 void
2900 gl_label_set_default_font_weight (glLabel     *label,
2901                                   PangoWeight  font_weight)
2902 {
2903         gl_debug (DEBUG_LABEL, "START");
2904
2905         g_return_if_fail (label && GL_IS_LABEL (label));
2906
2907         label->priv->default_font_weight = font_weight;
2908
2909         gl_debug (DEBUG_LABEL, "END");
2910 }
2911
2912
2913 /****************************************************************************/
2914 /* Set default font italic flag.                                            */
2915 /****************************************************************************/
2916 void
2917 gl_label_set_default_font_italic_flag (glLabel  *label,
2918                                        gboolean  font_italic_flag)
2919 {
2920         gl_debug (DEBUG_LABEL, "START");
2921
2922         g_return_if_fail (label && GL_IS_LABEL (label));
2923
2924         label->priv->default_font_italic_flag = font_italic_flag;
2925
2926         gl_debug (DEBUG_LABEL, "END");
2927 }
2928
2929
2930 /****************************************************************************/
2931 /* Set default text color.                                                  */
2932 /****************************************************************************/
2933 void
2934 gl_label_set_default_text_color (glLabel *label,
2935                                  guint    text_color)
2936 {
2937         gl_debug (DEBUG_LABEL, "START");
2938
2939         g_return_if_fail (label && GL_IS_LABEL (label));
2940
2941         label->priv->default_text_color = text_color;
2942
2943         gl_debug (DEBUG_LABEL, "END");
2944 }
2945
2946
2947 /****************************************************************************/
2948 /* Set default text alignment.                                              */
2949 /****************************************************************************/
2950 void
2951 gl_label_set_default_text_alignment (glLabel        *label,
2952                                      PangoAlignment  text_alignment)
2953 {
2954         gl_debug (DEBUG_LABEL, "START");
2955
2956         g_return_if_fail (label && GL_IS_LABEL (label));
2957
2958         label->priv->default_text_alignment = text_alignment;
2959         gl_debug (DEBUG_LABEL, "END");
2960 }
2961
2962
2963 /****************************************************************************/
2964 /* Set default vertical text alignment.                                     */
2965 /****************************************************************************/
2966 void
2967 gl_label_set_default_text_valignment (glLabel        *label,
2968                                       glValignment    text_valignment)
2969 {
2970         gl_debug (DEBUG_LABEL, "START");
2971
2972         g_return_if_fail (label && GL_IS_LABEL (label));
2973
2974         label->priv->default_text_valignment = text_valignment;
2975         gl_debug (DEBUG_LABEL, "END");
2976 }
2977
2978
2979 /****************************************************************************/
2980 /* Set default text line spacing.                                           */
2981 /****************************************************************************/
2982 void
2983 gl_label_set_default_text_line_spacing (glLabel *label,
2984                                         gdouble  text_line_spacing)
2985 {
2986         gl_debug (DEBUG_LABEL, "START");
2987
2988         g_return_if_fail (label && GL_IS_LABEL (label));
2989
2990         label->priv->default_text_line_spacing = text_line_spacing;
2991
2992         gl_debug (DEBUG_LABEL, "END");
2993 }
2994
2995
2996 /****************************************************************************/
2997 /* Set default line width.                                                  */
2998 /****************************************************************************/
2999 void
3000 gl_label_set_default_line_width (glLabel *label,
3001                                  gdouble  line_width)
3002 {
3003         gl_debug (DEBUG_LABEL, "START");
3004
3005         g_return_if_fail (label && GL_IS_LABEL (label));
3006
3007         label->priv->default_line_width = line_width;
3008
3009         gl_debug (DEBUG_LABEL, "END");
3010 }
3011
3012
3013 /****************************************************************************/
3014 /* Set default line color.                                                  */
3015 /****************************************************************************/
3016 void
3017 gl_label_set_default_line_color (glLabel *label,
3018                                  guint    line_color)
3019 {
3020         gl_debug (DEBUG_LABEL, "START");
3021
3022         g_return_if_fail (label && GL_IS_LABEL (label));
3023
3024         label->priv->default_line_color = line_color;
3025
3026         gl_debug (DEBUG_LABEL, "END");
3027 }
3028
3029
3030 /****************************************************************************/
3031 /* Set default fill color.                                                  */
3032 /****************************************************************************/
3033 void
3034 gl_label_set_default_fill_color (glLabel *label,
3035                                  guint    fill_color)
3036 {
3037         gl_debug (DEBUG_LABEL, "START");
3038
3039         g_return_if_fail (label && GL_IS_LABEL (label));
3040
3041         label->priv->default_fill_color = fill_color;
3042
3043         gl_debug (DEBUG_LABEL, "END");
3044 }
3045
3046
3047 /****************************************************************************/
3048 /* Get default font family.                                                 */
3049 /****************************************************************************/
3050 gchar *
3051 gl_label_get_default_font_family (glLabel *label)
3052 {
3053         gl_debug (DEBUG_LABEL, "START");
3054
3055         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
3056
3057         gl_debug (DEBUG_LABEL, "END");
3058
3059         return g_strdup (label->priv->default_font_family);
3060 }
3061
3062
3063 /****************************************************************************/
3064 /* Get default font size.                                                   */
3065 /****************************************************************************/
3066 gdouble
3067 gl_label_get_default_font_size (glLabel *label)
3068 {
3069         gl_debug (DEBUG_LABEL, "START");
3070
3071         g_return_val_if_fail (label && GL_IS_LABEL (label), 12.0);
3072
3073         gl_debug (DEBUG_LABEL, "END");
3074
3075         return label->priv->default_font_size;
3076 }
3077
3078
3079 /****************************************************************************/
3080 /* Get default font weight.                                                 */
3081 /****************************************************************************/
3082 PangoWeight
3083 gl_label_get_default_font_weight (glLabel *label)
3084 {
3085         gl_debug (DEBUG_LABEL, "START");
3086
3087         g_return_val_if_fail (label && GL_IS_LABEL (label), PANGO_WEIGHT_NORMAL);
3088
3089         gl_debug (DEBUG_LABEL, "END");
3090
3091         return label->priv->default_font_weight;
3092 }
3093
3094
3095 /****************************************************************************/
3096 /* Get default font italic flag.                                            */
3097 /****************************************************************************/
3098 gboolean
3099 gl_label_get_default_font_italic_flag (glLabel *label)
3100 {
3101         gl_debug (DEBUG_LABEL, "START");
3102
3103         g_return_val_if_fail (label && GL_IS_LABEL (label), FALSE);
3104
3105         gl_debug (DEBUG_LABEL, "END");
3106
3107         return label->priv->default_font_italic_flag;
3108 }
3109
3110
3111 /****************************************************************************/
3112 /* Get default text color.                                                  */
3113 /****************************************************************************/
3114 guint
3115 gl_label_get_default_text_color (glLabel *label)
3116 {
3117         gl_debug (DEBUG_LABEL, "START");
3118
3119         g_return_val_if_fail (label && GL_IS_LABEL (label), 0);
3120
3121         gl_debug (DEBUG_LABEL, "END");
3122
3123         return label->priv->default_text_color;
3124 }
3125
3126
3127 /****************************************************************************/
3128 /* Get default text alignment.                                              */
3129 /****************************************************************************/
3130 PangoAlignment
3131 gl_label_get_default_text_alignment (glLabel *label)
3132 {
3133         gl_debug (DEBUG_LABEL, "START");
3134
3135         g_return_val_if_fail (label && GL_IS_LABEL (label), PANGO_ALIGN_LEFT);
3136
3137         gl_debug (DEBUG_LABEL, "END");
3138
3139         return label->priv->default_text_alignment;
3140 }
3141
3142
3143 /****************************************************************************/
3144 /* Get default vertical text alignment.                                     */
3145 /****************************************************************************/
3146 glValignment
3147 gl_label_get_default_text_valignment (glLabel *label)
3148 {
3149         gl_debug (DEBUG_LABEL, "START");
3150
3151         g_return_val_if_fail (label && GL_IS_LABEL (label), GL_VALIGN_TOP);
3152
3153         gl_debug (DEBUG_LABEL, "END");
3154
3155         return label->priv->default_text_valignment;
3156 }
3157
3158
3159 /****************************************************************************/
3160 /* Get default text line spacing.                                           */
3161 /****************************************************************************/
3162 gdouble
3163 gl_label_get_default_text_line_spacing (glLabel *label)
3164 {
3165         gl_debug (DEBUG_LABEL, "START");
3166
3167         g_return_val_if_fail (label && GL_IS_LABEL (label), 1.0);
3168
3169         gl_debug (DEBUG_LABEL, "END");
3170
3171         return label->priv->default_text_line_spacing;
3172 }
3173
3174
3175 /****************************************************************************/
3176 /* Get default line width.                                                  */
3177 /****************************************************************************/
3178 gdouble
3179 gl_label_get_default_line_width (glLabel *label)
3180 {
3181         gl_debug (DEBUG_LABEL, "START");
3182
3183         g_return_val_if_fail (label && GL_IS_LABEL (label), 1.0);
3184
3185         gl_debug (DEBUG_LABEL, "END");
3186
3187         return label->priv->default_line_width;
3188 }
3189
3190
3191 /****************************************************************************/
3192 /* Get default line color.                                                  */
3193 /****************************************************************************/
3194 guint
3195 gl_label_get_default_line_color (glLabel *label)
3196 {
3197         gl_debug (DEBUG_LABEL, "START");
3198
3199         g_return_val_if_fail (label && GL_IS_LABEL (label), 0);
3200
3201         gl_debug (DEBUG_LABEL, "END");
3202
3203         return label->priv->default_line_color;
3204 }
3205
3206
3207 /****************************************************************************/
3208 /* Get default fill color.                                                  */
3209 /****************************************************************************/
3210 guint
3211 gl_label_get_default_fill_color (glLabel *label)
3212 {
3213         gl_debug (DEBUG_LABEL, "START");
3214
3215         g_return_val_if_fail (label && GL_IS_LABEL (label), 0);
3216
3217         gl_debug (DEBUG_LABEL, "END");
3218
3219         return label->priv->default_fill_color;
3220 }
3221
3222
3223 /****************************************************************************/
3224 /* Draw label.                                                              */
3225 /****************************************************************************/
3226 void
3227 gl_label_draw (glLabel       *label,
3228                cairo_t       *cr,
3229                gboolean       screen_flag,
3230                glMergeRecord *record)
3231 {
3232         GList            *p_obj;
3233         glLabelObject    *object;
3234
3235         g_return_if_fail (label && GL_IS_LABEL (label));
3236
3237         for (p_obj = label->priv->object_list; p_obj != NULL; p_obj = p_obj->next)
3238         {
3239                 object = GL_LABEL_OBJECT (p_obj->data);
3240
3241                 gl_label_object_draw (object, cr, screen_flag, record);
3242         }
3243 }
3244
3245
3246 /****************************************************************************/
3247 /* Get object located at coordinates.                                       */
3248 /****************************************************************************/
3249 glLabelObject *gl_label_object_at              (glLabel       *label,
3250                                                 cairo_t       *cr,
3251                                                 gdouble        x_pixels,
3252                                                 gdouble        y_pixels)
3253 {
3254         GList            *p_obj;
3255         glLabelObject    *object;
3256
3257         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
3258
3259         for (p_obj = g_list_last (label->priv->object_list); p_obj != NULL; p_obj = p_obj->prev)
3260         {
3261                 object = GL_LABEL_OBJECT (p_obj->data);
3262
3263                 if (gl_label_object_is_located_at (object, cr, x_pixels, y_pixels))
3264                 {
3265                         return object;
3266                 }
3267
3268         }
3269
3270         return NULL;
3271 }
3272
3273
3274 /****************************************************************************/
3275 /* Return handle and associated object at coordinates.                      */
3276 /****************************************************************************/
3277 glLabelObject *
3278 gl_label_get_handle_at (glLabel             *label,
3279                         cairo_t             *cr,
3280                         gdouble              x_pixels,
3281                         gdouble              y_pixels,
3282                         glLabelObjectHandle *handle)
3283 {
3284         GList            *selection_list;
3285         GList            *p_obj;
3286         glLabelObject    *object;
3287
3288         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
3289
3290         selection_list = gl_label_get_selection_list (label);
3291
3292         for (p_obj = g_list_last (selection_list); p_obj != NULL; p_obj = p_obj->prev)
3293         {
3294
3295                 object = GL_LABEL_OBJECT (p_obj->data);
3296
3297                 if ((*handle = gl_label_object_handle_at (object, cr, x_pixels, y_pixels)))
3298                 {
3299                         g_list_free (selection_list);
3300                         return object;
3301                 }
3302
3303         }
3304
3305         g_list_free (selection_list);
3306
3307         *handle = GL_LABEL_OBJECT_HANDLE_NONE;
3308         return NULL;
3309 }
3310
3311
3312 /****************************************************************************/
3313 /* Checkpoint state.                                                        */
3314 /****************************************************************************/
3315 void
3316 gl_label_checkpoint (glLabel       *this,
3317                      const gchar   *description)
3318 {
3319         State *state;
3320
3321         gl_debug (DEBUG_LABEL, "START");
3322
3323         /*
3324          * Do not perform consecutive checkpoints that are identical.
3325          * E.g. moving an object by dragging, would produce a large number
3326          * of incremental checkpoints -- what we really want is a single
3327          * checkpoint so that we can undo the entire dragging effort with
3328          * one "undo"
3329          */
3330         if ( this->priv->cp_cleared_flag
3331              || (this->priv->cp_desc == NULL)
3332              || (strcmp (description, this->priv->cp_desc) != 0) )
3333         {
3334
3335                 /* Sever old redo "thread" */
3336                 stack_clear (this->priv->redo_stack);
3337
3338                 /* Save state onto undo stack. */
3339                 state = state_new (this, description);
3340                 stack_push_state (this->priv->undo_stack, state);
3341
3342                 /* Track consecutive checkpoints. */
3343                 this->priv->cp_cleared_flag = FALSE;
3344                 this->priv->cp_desc         = g_strdup (description);
3345         }
3346
3347         gl_debug (DEBUG_LABEL, "END");
3348 }
3349
3350
3351 /****************************************************************************/
3352 /* Undo.                                                                    */
3353 /****************************************************************************/
3354 void
3355 gl_label_undo (glLabel       *this)
3356 {
3357         State *state_old;
3358         State *state_now;
3359
3360         gl_debug (DEBUG_LABEL, "START");
3361
3362         state_old = stack_pop_state (this->priv->undo_stack);
3363         state_now = state_new (this, state_old->description);
3364
3365         stack_push_state (this->priv->redo_stack, state_now);
3366
3367         state_restore (state_old, this);
3368         state_free (state_old);
3369
3370         this->priv->cp_cleared_flag = TRUE;
3371
3372         gl_debug (DEBUG_LABEL, "END");
3373 }
3374
3375
3376 /****************************************************************************/
3377 /* Redo.                                                                    */
3378 /****************************************************************************/
3379 void
3380 gl_label_redo (glLabel       *this)
3381 {
3382         State *state_old;
3383         State *state_now;
3384
3385         gl_debug (DEBUG_LABEL, "START");
3386
3387         state_old = stack_pop_state (this->priv->redo_stack);
3388         state_now = state_new (this, state_old->description);
3389
3390         stack_push_state (this->priv->undo_stack, state_now);
3391
3392         state_restore (state_old, this);
3393         state_free (state_old);
3394
3395         this->priv->cp_cleared_flag = TRUE;
3396
3397         gl_debug (DEBUG_LABEL, "END");
3398 }
3399
3400
3401 /****************************************************************************/
3402 /* Can undo?                                                                */
3403 /****************************************************************************/
3404 gboolean
3405 gl_label_can_undo (glLabel *this)
3406 {
3407         return (!g_queue_is_empty (this->priv->undo_stack));
3408 }
3409
3410
3411 /****************************************************************************/
3412 /* Can redo?                                                                */
3413 /****************************************************************************/
3414 gboolean
3415 gl_label_can_redo (glLabel *this)
3416 {
3417         return (!g_queue_is_empty (this->priv->redo_stack));
3418 }
3419
3420
3421 /****************************************************************************/
3422 /* Get undo description string.                                             */
3423 /****************************************************************************/
3424 gchar *
3425 gl_label_get_undo_description (glLabel *this)
3426 {
3427         State *state;
3428         gchar *description;
3429
3430         state = g_queue_peek_head (this->priv->undo_stack);
3431         if ( state )
3432         {
3433                 description = g_strdup (state->description);
3434         }
3435         else
3436         {
3437                 description = g_strdup ("");
3438         }
3439
3440         return description;
3441 }
3442
3443
3444 /****************************************************************************/
3445 /* Get redo description string.                                             */
3446 /****************************************************************************/
3447 gchar *
3448 gl_label_get_redo_description (glLabel *this)
3449 {
3450         State *state;
3451         gchar *description;
3452
3453         state = g_queue_peek_head (this->priv->redo_stack);
3454         if ( state )
3455         {
3456                 description = g_strdup (state->description);
3457         }
3458         else
3459         {
3460                 description = g_strdup ("");
3461         }
3462
3463         return description;
3464 }
3465
3466
3467 /****************************************************************************/
3468 /* Clear undo or redo stack.                                                */
3469 /****************************************************************************/
3470 static void
3471 stack_clear (GQueue *stack)
3472 {
3473         State *state;
3474
3475         gl_debug (DEBUG_LABEL, "START");
3476
3477         while ( (state = g_queue_pop_head (stack)) != NULL )
3478         {
3479                 state_free (state);
3480         }
3481
3482         gl_debug (DEBUG_LABEL, "END");
3483 }
3484
3485
3486 /****************************************************************************/
3487 /* Push state onto stack.                                                   */
3488 /****************************************************************************/
3489 static void
3490 stack_push_state (GQueue *stack,
3491                   State  *state)
3492 {
3493         gl_debug (DEBUG_LABEL, "START");
3494
3495         g_queue_push_head( stack, state );
3496
3497         gl_debug (DEBUG_LABEL, "END");
3498 }
3499
3500
3501 /****************************************************************************/
3502 /* Pop state from stack.                                                    */
3503 /****************************************************************************/
3504 static State *
3505 stack_pop_state (GQueue *stack)
3506 {
3507         State *state;
3508
3509         gl_debug (DEBUG_LABEL, "START");
3510
3511         state = g_queue_pop_head (stack);
3512
3513         gl_debug (DEBUG_LABEL, "END");
3514         return state;
3515 }
3516
3517
3518 /****************************************************************************/
3519 /* New state from label.                                                    */
3520 /****************************************************************************/
3521 static State *
3522 state_new (glLabel       *this,
3523            const gchar   *description)
3524 {
3525         State          *state;
3526         GList          *p_obj;
3527         glLabelObject  *object;
3528
3529         gl_debug (DEBUG_LABEL, "START");
3530
3531         state = g_new0 (State, 1);
3532
3533         state->description = g_strdup (description);
3534
3535         state->template    = lgl_template_dup (this->priv->template);
3536         state->rotate_flag = this->priv->rotate_flag;
3537
3538         for ( p_obj = this->priv->object_list; p_obj != NULL; p_obj = p_obj->next )
3539         {
3540                 object = GL_LABEL_OBJECT (p_obj->data);
3541
3542                 state->object_list = g_list_append (state->object_list,
3543                                                     gl_label_object_dup (object, this));
3544         }
3545
3546         state->merge = gl_merge_dup (this->priv->merge);
3547
3548         state->modified_flag = this->priv->modified_flag;
3549         state->time_stamp    = this->priv->time_stamp;
3550
3551
3552         gl_debug (DEBUG_LABEL, "END");
3553         return state;
3554 }
3555
3556
3557 /****************************************************************************/
3558 /* Restore label from saved state.                                          */
3559 /****************************************************************************/
3560 static void
3561 state_free (State   *state)
3562 {
3563         GList          *p_obj;
3564
3565         gl_debug (DEBUG_LABEL, "START");
3566
3567         g_free (state->description);
3568
3569         lgl_template_free (state->template);
3570         if ( state->merge )
3571         {
3572                 g_object_unref (G_OBJECT (state->merge));
3573         }
3574
3575         for ( p_obj = state->object_list; p_obj != NULL; p_obj = p_obj->next )
3576         {
3577                 g_object_unref (G_OBJECT (p_obj->data));
3578         }
3579         g_list_free (state->object_list);
3580
3581         g_free (state);
3582
3583         gl_debug (DEBUG_LABEL, "END");
3584 }
3585
3586
3587 /****************************************************************************/
3588 /* Restore label from saved state.                                          */
3589 /****************************************************************************/
3590 static void
3591 state_restore (State   *state,
3592                glLabel *this)
3593                
3594 {
3595         GList          *p_obj, *p_next;
3596         glLabelObject  *object;
3597
3598         gl_debug (DEBUG_LABEL, "START");
3599
3600         gl_label_set_rotate_flag (this, state->rotate_flag, FALSE);
3601         gl_label_set_template (this, state->template, FALSE);
3602
3603         for ( p_obj = this->priv->object_list; p_obj != NULL; p_obj = p_next )
3604         {
3605                 p_next = p_obj->next; /* Hold on to next; delete is destructive */
3606                 object = GL_LABEL_OBJECT (p_obj->data);
3607
3608                 gl_label_delete_object (this, object);
3609         }
3610
3611         for ( p_obj = state->object_list; p_obj != NULL; p_obj = p_obj->next )
3612         {
3613                 object = GL_LABEL_OBJECT (p_obj->data);
3614
3615                 gl_label_add_object (this, gl_label_object_dup (object, this));
3616         }
3617         g_signal_emit (G_OBJECT(this), signals[SELECTION_CHANGED], 0);
3618
3619         gl_label_set_merge (this, state->merge, FALSE);
3620         
3621
3622         if ( !state->modified_flag &&
3623              (state->time_stamp.tv_sec  == this->priv->time_stamp.tv_sec) &&
3624              (state->time_stamp.tv_usec == this->priv->time_stamp.tv_usec) )
3625         {
3626                 gl_label_clear_modified (this);
3627         }
3628
3629         gl_debug (DEBUG_LABEL, "END");
3630 }
3631
3632
3633
3634
3635 /*
3636  * Local Variables:       -- emacs
3637  * mode: C                -- emacs
3638  * c-basic-offset: 8      -- emacs
3639  * tab-width: 8           -- emacs
3640  * indent-tabs-mode: nil  -- emacs
3641  * End:                   -- emacs
3642  */