]> git.sur5r.net Git - glabels/blob - src/label.c
Imported Upstream version 3.4.0
[glabels] / src / label.c
1 /*
2  *  label.c
3  *  Copyright (C) 2001-2009  Jim Evins <evins@snaught.com>.
4  *
5  *  This file is part of gLabels.
6  *
7  *  gLabels is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  gLabels is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with gLabels.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #include "label.h"
24
25 #include <glib/gi18n.h>
26 #include <math.h>
27
28 #include "template-history.h"
29 #include "file-util.h"
30 #include "xml-label.h"
31 #include "prefs.h"
32 #include "label-text.h"
33 #include "label-image.h"
34 #include "marshal.h"
35
36 #include "debug.h"
37
38
39 /*========================================================*/
40 /* Private macros and constants.                          */
41 /*========================================================*/
42
43
44 /*========================================================*/
45 /* Private types.                                         */
46 /*========================================================*/
47
48 struct _glLabelPrivate {
49
50         gchar       *filename;
51         gint         compression;
52         gint         untitled_instance;
53
54         gboolean     modified_flag;
55         GTimeVal     time_stamp;
56
57         lglTemplate *template;
58         gboolean     rotate_flag;
59
60         GList       *object_list;
61
62         glMerge     *merge;
63
64         GHashTable  *pixbuf_cache;
65         GHashTable  *svg_cache;
66
67         /* Delay changed signals while operating on selections of multiple objects. */
68         gboolean     selection_op_flag;
69         gboolean     delayed_change_flag;
70
71         /* Default object text properties */
72         gchar             *default_font_family;
73         gdouble            default_font_size;
74         PangoWeight        default_font_weight;
75         gboolean           default_font_italic_flag;
76         guint              default_text_color;
77         PangoAlignment     default_text_alignment;
78         glValignment       default_text_valignment;
79         gdouble            default_text_line_spacing;
80
81         /* Default object line properties */
82         gdouble            default_line_width;
83         guint              default_line_color;
84         
85         /* Default object fill properties */
86         guint              default_fill_color;
87
88         /* Undo/Redo state */
89         GQueue      *undo_stack;
90         GQueue      *redo_stack;
91         gboolean     cp_cleared_flag;
92         gchar       *cp_desc;
93 };
94
95 typedef struct {
96         gchar             *xml_buffer;
97         gchar             *text;
98         GdkPixbuf         *pixbuf;
99 } ClipboardData;
100
101 enum {
102         SELECTION_CHANGED,
103         CHANGED,
104         NAME_CHANGED,
105         MODIFIED_CHANGED,
106         MERGE_CHANGED,
107         SIZE_CHANGED,
108         LAST_SIGNAL
109 };
110
111 typedef struct {
112         gchar       *description;
113
114         gboolean     modified_flag;
115         GTimeVal     time_stamp;
116
117         lglTemplate *template;
118         gboolean     rotate_flag;
119
120         GList       *object_list;
121
122         glMerge     *merge;
123
124 } State;
125
126
127 /*========================================================*/
128 /* Private globals.                                       */
129 /*========================================================*/
130
131 static guint signals[LAST_SIGNAL] = {0};
132
133 static guint untitled = 0;
134
135
136 /*========================================================*/
137 /* Private function prototypes.                           */
138 /*========================================================*/
139
140 static void gl_label_finalize      (GObject *object);
141
142 static void object_changed_cb      (glLabelObject *object,
143                                     glLabel       *label);
144
145 static void object_moved_cb        (glLabelObject *object,
146                                     glLabel       *label);
147
148 static void do_modify              (glLabel       *label);
149
150 static void begin_selection_op     (glLabel       *label);
151 static void end_selection_op       (glLabel       *label);
152
153 static void clipboard_get_cb       (GtkClipboard     *clipboard,
154                                     GtkSelectionData *selection_data,
155                                     guint             info,
156                                     ClipboardData    *data);
157
158 static void clipboard_clear_cb     (GtkClipboard     *clipboard,
159                                     ClipboardData    *data);
160
161 static void receive_targets_cb     (GtkClipboard     *clipboard,
162                                     GdkAtom          *targets,
163                                     gint              n_targets,
164                                     glLabel          *label);
165
166 static void paste_xml_received_cb  (GtkClipboard     *clipboard,
167                                     GtkSelectionData *selection_data,
168                                     glLabel          *label);
169
170 static void paste_text_received_cb (GtkClipboard     *clipboard,
171                                     const gchar      *text,
172                                     glLabel          *label);
173
174 static void paste_image_received_cb(GtkClipboard     *clipboard,
175                                     GdkPixbuf        *pixbuf,
176                                     glLabel          *label);
177
178 static void   stack_clear          (GQueue           *stack);
179 static void   stack_push_state     (GQueue           *stack,
180                                     State            *state);
181 static State *stack_pop_state      (GQueue           *stack);
182
183 static State *state_new            (glLabel          *this,
184                                     const gchar      *description);
185 static void   state_free           (State            *state);
186 static void   state_restore        (State            *state,
187                                     glLabel          *this);
188
189
190 /*****************************************************************************/
191 /* Boilerplate object stuff.                                                 */
192 /*****************************************************************************/
193 G_DEFINE_TYPE (glLabel, gl_label, G_TYPE_OBJECT)
194
195
196 static void
197 gl_label_class_init (glLabelClass *class)
198 {
199         GObjectClass *object_class = G_OBJECT_CLASS (class);
200
201         gl_debug (DEBUG_LABEL, "START");
202
203         gl_label_parent_class = g_type_class_peek_parent (class);
204
205         object_class->finalize = gl_label_finalize;
206
207         signals[SELECTION_CHANGED] =
208                 g_signal_new ("selection_changed",
209                               G_OBJECT_CLASS_TYPE (object_class),
210                               G_SIGNAL_RUN_LAST,
211                               G_STRUCT_OFFSET (glLabelClass, selection_changed),
212                               NULL, NULL,
213                               gl_marshal_VOID__VOID,
214                               G_TYPE_NONE,
215                               0);
216         signals[CHANGED] =
217                 g_signal_new ("changed",
218                               G_OBJECT_CLASS_TYPE (object_class),
219                               G_SIGNAL_RUN_LAST,
220                               G_STRUCT_OFFSET (glLabelClass, changed),
221                               NULL, NULL,
222                               gl_marshal_VOID__VOID,
223                               G_TYPE_NONE,
224                               0);
225         signals[NAME_CHANGED] =
226                 g_signal_new ("name_changed",
227                               G_OBJECT_CLASS_TYPE (object_class),
228                               G_SIGNAL_RUN_LAST,
229                               G_STRUCT_OFFSET (glLabelClass, name_changed),
230                               NULL, NULL,
231                               gl_marshal_VOID__VOID,
232                               G_TYPE_NONE,
233                               0);
234         signals[MODIFIED_CHANGED] =
235                 g_signal_new ("modified_changed",
236                               G_OBJECT_CLASS_TYPE (object_class),
237                               G_SIGNAL_RUN_LAST,
238                               G_STRUCT_OFFSET (glLabelClass, modified_changed),
239                               NULL, NULL,
240                               gl_marshal_VOID__VOID,
241                               G_TYPE_NONE,
242                               0);
243         signals[MERGE_CHANGED] =
244                 g_signal_new ("merge_changed",
245                               G_OBJECT_CLASS_TYPE (object_class),
246                               G_SIGNAL_RUN_LAST,
247                               G_STRUCT_OFFSET (glLabelClass, merge_changed),
248                               NULL, NULL,
249                               gl_marshal_VOID__VOID,
250                               G_TYPE_NONE,
251                               0);
252         signals[SIZE_CHANGED] =
253                 g_signal_new ("size_changed",
254                               G_OBJECT_CLASS_TYPE (object_class),
255                               G_SIGNAL_RUN_LAST,
256                               G_STRUCT_OFFSET (glLabelClass, size_changed),
257                               NULL, NULL,
258                               gl_marshal_VOID__VOID,
259                               G_TYPE_NONE,
260                               0);
261
262         gl_debug (DEBUG_LABEL, "END");
263 }
264
265
266 static void
267 gl_label_init (glLabel *label)
268 {
269         gl_debug (DEBUG_LABEL, "START");
270
271         label->priv = g_new0 (glLabelPrivate, 1);
272
273         label->priv->template      = NULL;
274         label->priv->rotate_flag   = FALSE;
275         label->priv->object_list   = NULL;
276
277         label->priv->filename      = NULL;
278         label->priv->modified_flag = FALSE;
279         label->priv->compression   = 9;
280
281         label->priv->merge         = NULL;
282         label->priv->pixbuf_cache  = gl_pixbuf_cache_new ();
283         label->priv->svg_cache     = gl_svg_cache_new ();
284
285         label->priv->undo_stack    = g_queue_new ();
286         label->priv->redo_stack    = g_queue_new ();
287
288         /*
289          * Defaults from preferences
290          */
291         label->priv->default_font_family       = gl_prefs_model_get_default_font_family (gl_prefs);
292         label->priv->default_font_size         = gl_prefs_model_get_default_font_size (gl_prefs);
293         label->priv->default_font_weight       = gl_prefs_model_get_default_font_weight (gl_prefs);
294         label->priv->default_font_italic_flag  = gl_prefs_model_get_default_font_italic_flag (gl_prefs);
295         label->priv->default_text_color        = gl_prefs_model_get_default_text_color (gl_prefs);
296         label->priv->default_text_alignment    = gl_prefs_model_get_default_text_alignment (gl_prefs);
297         label->priv->default_text_line_spacing = gl_prefs_model_get_default_text_line_spacing (gl_prefs);
298         label->priv->default_line_width        = gl_prefs_model_get_default_line_width (gl_prefs);
299         label->priv->default_line_color        = gl_prefs_model_get_default_line_color (gl_prefs);
300         label->priv->default_fill_color        = gl_prefs_model_get_default_fill_color (gl_prefs);
301
302         gl_debug (DEBUG_LABEL, "END");
303 }
304
305
306 static void
307 gl_label_finalize (GObject *object)
308 {
309         glLabel *label = GL_LABEL (object);
310         GList   *p;
311
312         gl_debug (DEBUG_LABEL, "START");
313
314         g_return_if_fail (object && GL_IS_LABEL (object));
315
316         for (p = label->priv->object_list; p != NULL; p = p->next)
317         {
318                 g_object_unref (G_OBJECT(p->data));
319         }
320         g_list_free (label->priv->object_list);
321
322         lgl_template_free (label->priv->template);
323         g_free (label->priv->filename);
324         if (label->priv->merge != NULL)
325         {
326                 g_object_unref (G_OBJECT(label->priv->merge));
327         }
328         g_free (label->priv->default_font_family);
329
330         stack_clear (label->priv->undo_stack);
331         stack_clear (label->priv->redo_stack);
332
333         g_queue_free (label->priv->undo_stack);
334         g_queue_free (label->priv->redo_stack);
335
336         gl_pixbuf_cache_free (label->priv->pixbuf_cache);
337         gl_svg_cache_free (label->priv->svg_cache);
338
339         g_free (label->priv);
340
341         G_OBJECT_CLASS (gl_label_parent_class)->finalize (object);
342
343         gl_debug (DEBUG_LABEL, "END");
344 }
345
346
347 /*****************************************************************************/
348 /* New label.                                                                */
349 /*****************************************************************************/
350 GObject *
351 gl_label_new (void)
352 {
353         glLabel *label;
354
355         gl_debug (DEBUG_LABEL, "START");
356
357         label = g_object_new (gl_label_get_type(), NULL);
358
359         gl_debug (DEBUG_LABEL, "END");
360
361         return G_OBJECT (label);
362 }
363
364
365 /****************************************************************************/
366 /* Set filename.                                                            */
367 /****************************************************************************/
368 void
369 gl_label_set_filename (glLabel     *label,
370                        const gchar *filename)
371 {
372         label->priv->filename = g_strdup (filename);
373
374         g_signal_emit (G_OBJECT(label), signals[NAME_CHANGED], 0);
375 }
376
377
378 /****************************************************************************/
379 /* return filename.                                                         */
380 /****************************************************************************/
381 gchar *
382 gl_label_get_filename (glLabel *label)
383 {
384         gl_debug (DEBUG_LABEL, "");
385
386         return g_strdup ( label->priv->filename );
387 }
388
389
390 /****************************************************************************/
391 /* return short filename.                                                   */
392 /****************************************************************************/
393 gchar *
394 gl_label_get_short_name (glLabel *label)
395 {
396         gl_debug (DEBUG_LABEL, "");
397
398         if ( label->priv->filename == NULL )
399         {
400
401                 if ( label->priv->untitled_instance == 0 )
402                 {
403                         label->priv->untitled_instance = ++untitled;
404                 }
405
406                 return g_strdup_printf ( "%s %d", _("Untitled"),
407                                          label->priv->untitled_instance );
408
409         }
410         else
411         {
412                 gchar *temp_name, *short_name;
413
414                 temp_name = g_path_get_basename ( label->priv->filename );
415                 short_name = gl_file_util_remove_extension (temp_name);
416                 g_free (temp_name);
417
418                 return short_name;
419         }
420 }
421
422
423 /****************************************************************************/
424 /* Is label untitled?                                                       */
425 /****************************************************************************/
426 gboolean
427 gl_label_is_untitled (glLabel *label)
428 {
429         gl_debug (DEBUG_LABEL, "return %d",(label->priv->filename == NULL));
430         return (label->priv->filename == NULL);
431 }
432
433
434 /****************************************************************************/
435 /* Set compression level.                                                   */
436 /****************************************************************************/
437 void
438 gl_label_set_compression (glLabel  *label,
439                           gint      compression)
440 {
441         gl_debug (DEBUG_LABEL, "set %d", compression);
442
443         /* Older versions of libxml2 always return a -1 for documents "read in," so
444          * default to 9.  Also, default to 9 for anything else out of range. */
445         if ((compression < 0) || (compression >9))
446         {
447                 compression = 9;
448         }
449
450         gl_debug (DEBUG_LABEL, "actual set %d", compression);
451         label->priv->compression = compression;
452 }
453
454
455 /****************************************************************************/
456 /* Get compression level.                                                   */
457 /****************************************************************************/
458 gint
459 gl_label_get_compression (glLabel *label)
460 {
461         gl_debug (DEBUG_LABEL, "return %d", label->priv->compression);
462         return label->priv->compression;
463 }
464
465
466 /****************************************************************************/
467 /* Set modified flag.                                                       */
468 /****************************************************************************/
469 void
470 gl_label_set_modified (glLabel *label)
471 {
472
473         if ( !label->priv->modified_flag )
474         {
475
476                 label->priv->modified_flag = TRUE;
477
478                 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
479         }
480
481 }
482
483
484 /****************************************************************************/
485 /* Clear modified flag.                                                     */
486 /****************************************************************************/
487 void
488 gl_label_clear_modified (glLabel *label)
489 {
490
491         if ( label->priv->modified_flag )
492         {
493
494                 g_get_current_time (&label->priv->time_stamp);
495                 label->priv->modified_flag = FALSE;
496
497                 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
498         }
499
500 }
501
502
503 /****************************************************************************/
504 /* Is label modified?                                                       */
505 /****************************************************************************/
506 gboolean
507 gl_label_is_modified (glLabel *label)
508 {
509         gl_debug (DEBUG_LABEL, "return %d", label->priv->modified_flag);
510         return label->priv->modified_flag;
511 }
512
513
514 /****************************************************************************/
515 /* Object "changed" callback.                                               */
516 /****************************************************************************/
517 static void
518 object_changed_cb (glLabelObject *object,
519                    glLabel       *label)
520 {
521         do_modify (label);
522 }
523
524
525 /****************************************************************************/
526 /* Object "moved" callback.                                                 */
527 /****************************************************************************/
528 static void
529 object_moved_cb (glLabelObject *object,
530                  glLabel       *label)
531 {
532         do_modify (label);
533 }
534
535
536 /****************************************************************************/
537 /* Do modify.                                                               */
538 /****************************************************************************/
539 static void
540 do_modify (glLabel  *label)
541 {
542         if ( label->priv->selection_op_flag )
543         {
544                 label->priv->delayed_change_flag = TRUE;
545         }
546         else
547         {
548                 label->priv->modified_flag = TRUE;
549
550                 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
551                 g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
552         }
553 }
554
555
556 /****************************************************************************/
557 /* Begin selection operation.                                               */
558 /****************************************************************************/
559 static void
560 begin_selection_op (glLabel  *label)
561 {
562         label->priv->selection_op_flag = TRUE;
563 }
564
565
566 /****************************************************************************/
567 /* End selection operation.                                                 */
568 /****************************************************************************/
569 static void
570 end_selection_op (glLabel  *label)
571 {
572         label->priv->selection_op_flag = FALSE;
573         if ( label->priv->delayed_change_flag )
574         {
575                 label->priv->delayed_change_flag = FALSE;
576                 do_modify (label);
577         }
578 }
579
580
581 /****************************************************************************/
582 /* set template.                                                            */
583 /****************************************************************************/
584 void
585 gl_label_set_template (glLabel           *label,
586                        const lglTemplate *template,
587                        gboolean           checkpoint)
588 {
589         gchar *name;
590
591         gl_debug (DEBUG_LABEL, "START");
592
593         g_return_if_fail (label && GL_IS_LABEL (label));
594         g_return_if_fail (template);
595
596         if ((label->priv->template == NULL) ||
597             !lgl_template_do_templates_match (template, label->priv->template))
598         {
599
600                 if ( checkpoint )
601                 {
602                         gl_label_checkpoint (label, _("Label properties"));
603                 }
604
605                 lgl_template_free (label->priv->template);
606                 label->priv->template = lgl_template_dup (template);
607
608                 do_modify (label);
609                 g_signal_emit (G_OBJECT(label), signals[SIZE_CHANGED], 0);
610
611                 name = lgl_template_get_name (template);
612                 gl_template_history_model_add_name (gl_template_history, name);
613                 g_free (name);
614         }
615
616         gl_debug (DEBUG_LABEL, "END");
617 }
618
619
620 /****************************************************************************/
621 /* get template.                                                            */
622 /****************************************************************************/
623 const lglTemplate *
624 gl_label_get_template (glLabel            *label)
625 {
626         return label->priv->template;
627 }
628
629
630 /****************************************************************************/
631 /* set rotate flag.                                                         */
632 /****************************************************************************/
633 void
634 gl_label_set_rotate_flag (glLabel *label,
635                           gboolean rotate_flag,
636                           gboolean checkpoint)
637 {
638         gl_debug (DEBUG_LABEL, "START");
639
640         g_return_if_fail (label && GL_IS_LABEL (label));
641
642         if (rotate_flag != label->priv->rotate_flag)
643         {
644                 if ( checkpoint )
645                 {
646                         gl_label_checkpoint (label, _("Label properties"));
647                 }
648
649                 label->priv->rotate_flag = rotate_flag;
650
651                 do_modify (label);
652                 g_signal_emit (G_OBJECT(label), signals[SIZE_CHANGED], 0);
653         }
654
655         gl_debug (DEBUG_LABEL, "END");
656 }
657
658
659 /****************************************************************************/
660 /* Get rotate flag.                                                         */
661 /****************************************************************************/
662 gboolean
663 gl_label_get_rotate_flag (glLabel       *label)
664 {
665         return label->priv->rotate_flag;
666 }
667
668
669 /****************************************************************************/
670 /* Get label size.                                                          */
671 /****************************************************************************/
672 void
673 gl_label_get_size (glLabel *label,
674                    gdouble *w,
675                    gdouble *h)
676 {
677         lglTemplate            *template;
678         const lglTemplateFrame *frame;
679
680         gl_debug (DEBUG_LABEL, "START");
681
682         g_return_if_fail (label && GL_IS_LABEL (label));
683
684         template = label->priv->template;
685         if ( !template )
686         {
687                 gl_debug (DEBUG_LABEL, "END -- template NULL");
688                 *w = *h = 0;
689                 return;
690         }
691         frame = (lglTemplateFrame *)template->frames->data;
692
693         if (!label->priv->rotate_flag)
694         {
695                 lgl_template_frame_get_size (frame, w, h);
696         }
697         else
698         {
699                 lgl_template_frame_get_size (frame, h, w);
700         }
701
702         gl_debug (DEBUG_LABEL, "END");
703 }
704
705
706 /****************************************************************************/
707 /* 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 second 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         do_modify (label);
1457
1458         end_selection_op (label);
1459
1460         gl_debug (DEBUG_LABEL, "END");
1461 }
1462
1463
1464 /*****************************************************************************/
1465 /* Rotate selected objects 90 degrees left.                                  */
1466 /*****************************************************************************/
1467 void
1468 gl_label_rotate_selection_left (glLabel *label)
1469 {
1470         GList         *selection_list;
1471         GList         *p;
1472         glLabelObject *object;
1473
1474         gl_debug (DEBUG_LABEL, "START");
1475
1476         g_return_if_fail (label && GL_IS_LABEL (label));
1477
1478         begin_selection_op (label);
1479
1480         gl_label_checkpoint (label, _("Rotate left"));
1481
1482         selection_list = gl_label_get_selection_list (label);
1483
1484         for ( p = selection_list; p != NULL; p = p->next )
1485         {
1486                 object = GL_LABEL_OBJECT (p->data);
1487
1488                 gl_label_object_rotate (object, -90.0);
1489         }
1490
1491         g_list_free (selection_list);
1492
1493         do_modify (label);
1494
1495         end_selection_op (label);
1496
1497         gl_debug (DEBUG_LABEL, "END");
1498 }
1499
1500
1501 /*****************************************************************************/
1502 /* Rotate selected objects 90 degrees right.                                 */
1503 /*****************************************************************************/
1504 void
1505 gl_label_rotate_selection_right (glLabel *label)
1506 {
1507         GList         *selection_list;
1508         GList         *p;
1509         glLabelObject *object;
1510
1511         gl_debug (DEBUG_LABEL, "START");
1512
1513         g_return_if_fail (label && GL_IS_LABEL (label));
1514
1515         gl_label_checkpoint (label, _("Rotate right"));
1516
1517         begin_selection_op (label);
1518
1519         selection_list = gl_label_get_selection_list (label);
1520
1521         for ( p = selection_list; p != NULL; p = p->next )
1522         {
1523                 object = GL_LABEL_OBJECT (p->data);
1524
1525                 gl_label_object_rotate (object, 90.0);
1526         }
1527
1528         g_list_free (selection_list);
1529
1530         do_modify (label);
1531
1532         end_selection_op (label);
1533
1534         gl_debug (DEBUG_LABEL, "END");
1535 }
1536
1537
1538 /*****************************************************************************/
1539 /* Flip selected objects horizontally.                                       */
1540 /*****************************************************************************/
1541 void
1542 gl_label_flip_selection_horiz (glLabel *label)
1543 {
1544         GList         *selection_list;
1545         GList         *p;
1546         glLabelObject *object;
1547
1548         gl_debug (DEBUG_LABEL, "START");
1549
1550         g_return_if_fail (label && GL_IS_LABEL (label));
1551
1552         gl_label_checkpoint (label, _("Flip horizontally"));
1553
1554         begin_selection_op (label);
1555
1556         selection_list = gl_label_get_selection_list (label);
1557
1558         for ( p = selection_list; p != NULL; p = p->next )
1559         {
1560                 object = GL_LABEL_OBJECT (p->data);
1561
1562                 gl_label_object_flip_horiz (object);
1563         }
1564
1565         g_list_free (selection_list);
1566
1567         do_modify (label);
1568
1569         end_selection_op (label);
1570
1571         gl_debug (DEBUG_LABEL, "END");
1572 }
1573
1574
1575 /*****************************************************************************/
1576 /* Flip selected objects vertically.                                         */
1577 /*****************************************************************************/
1578 void
1579 gl_label_flip_selection_vert (glLabel *label)
1580 {
1581         GList         *selection_list;
1582         GList         *p;
1583         glLabelObject *object;
1584
1585         gl_debug (DEBUG_LABEL, "START");
1586
1587         g_return_if_fail (label && GL_IS_LABEL (label));
1588
1589         gl_label_checkpoint (label, _("Flip vertically"));
1590
1591         begin_selection_op (label);
1592
1593         selection_list = gl_label_get_selection_list (label);
1594
1595         for ( p = selection_list; p != NULL; p = p->next )
1596         {
1597                 object = GL_LABEL_OBJECT (p->data);
1598
1599                 gl_label_object_flip_vert (object);
1600         }
1601
1602         g_list_free (selection_list);
1603
1604         do_modify (label);
1605
1606         end_selection_op (label);
1607
1608         gl_debug (DEBUG_LABEL, "END");
1609 }
1610
1611
1612 /*****************************************************************************/
1613 /* Align selected objects to left most edge.                                 */
1614 /*****************************************************************************/
1615 void
1616 gl_label_align_selection_left (glLabel *label)
1617 {
1618         GList         *selection_list;
1619         GList         *p;
1620         glLabelObject *object;
1621         gdouble        dx, x1_min;
1622         glLabelRegion  obj_extent;
1623
1624         gl_debug (DEBUG_LABEL, "START");
1625
1626         g_return_if_fail (label && GL_IS_LABEL (label));
1627
1628         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1629                           !gl_label_is_selection_atomic (label));
1630
1631         gl_label_checkpoint (label, _("Align left"));
1632
1633         begin_selection_op (label);
1634
1635         selection_list = gl_label_get_selection_list (label);
1636
1637         /* find left most edge */
1638         p = selection_list;
1639         object = GL_LABEL_OBJECT (p->data);
1640
1641         gl_label_object_get_extent (object, &obj_extent);
1642         x1_min = obj_extent.x1;
1643         for (p = p->next; p != NULL; p = p->next)
1644         {
1645                 object = GL_LABEL_OBJECT (p->data);
1646
1647                 gl_label_object_get_extent (object, &obj_extent);
1648                 if ( obj_extent.x1 < x1_min ) x1_min = obj_extent.x1;
1649         }
1650
1651         /* now adjust the object positions to line up the left edges */
1652         for (p = selection_list; p != NULL; p = p->next)
1653         {
1654                 object = GL_LABEL_OBJECT (p->data);
1655
1656                 gl_label_object_get_extent (object, &obj_extent);
1657                 dx = x1_min - obj_extent.x1;
1658                 gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
1659         }
1660
1661         g_list_free (selection_list);
1662
1663         end_selection_op (label);
1664
1665         gl_debug (DEBUG_LABEL, "END");
1666 }
1667
1668
1669 /*****************************************************************************/
1670 /* Align selected objects to right most edge.                                */
1671 /*****************************************************************************/
1672 void
1673 gl_label_align_selection_right (glLabel *label)
1674 {
1675         GList         *selection_list;
1676         GList         *p;
1677         glLabelObject *object;
1678         gdouble        dx, x2_max;
1679         glLabelRegion  obj_extent;
1680
1681         gl_debug (DEBUG_LABEL, "START");
1682
1683         g_return_if_fail (label && GL_IS_LABEL (label));
1684
1685         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1686                           !gl_label_is_selection_atomic (label));
1687
1688         gl_label_checkpoint (label, _("Align right"));
1689
1690         begin_selection_op (label);
1691
1692         selection_list = gl_label_get_selection_list (label);
1693
1694         /* find left most edge */
1695         p = selection_list;
1696         object = GL_LABEL_OBJECT (p->data);
1697
1698         gl_label_object_get_extent (object, &obj_extent);
1699         x2_max = obj_extent.x2;
1700         for (p = p->next; p != NULL; p = p->next)
1701         {
1702                 object = GL_LABEL_OBJECT (p->data);
1703
1704                 gl_label_object_get_extent (object, &obj_extent);
1705                 if ( obj_extent.x2 > x2_max ) x2_max = obj_extent.x2;
1706         }
1707
1708         /* now adjust the object positions to line up the left edges */
1709         for (p = selection_list; p != NULL; p = p->next)
1710         {
1711                 object = GL_LABEL_OBJECT (p->data);
1712
1713                 gl_label_object_get_extent (object, &obj_extent);
1714                 dx = x2_max - obj_extent.x2;
1715                 gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
1716         }
1717
1718         g_list_free (selection_list);
1719
1720         end_selection_op (label);
1721
1722         gl_debug (DEBUG_LABEL, "END");
1723 }
1724
1725
1726 /*****************************************************************************/
1727 /* Align selected objects to horizontal center of objects.                   */
1728 /*****************************************************************************/
1729 void
1730 gl_label_align_selection_hcenter (glLabel *label)
1731 {
1732         GList         *selection_list;
1733         GList         *p;
1734         glLabelObject *object;
1735         gdouble        dx;
1736         gdouble        dxmin;
1737         gdouble        xsum, xavg;
1738         glLabelRegion  obj_extent;
1739         gdouble        xcenter;
1740         gint           n;
1741
1742         gl_debug (DEBUG_LABEL, "START");
1743
1744         g_return_if_fail (label && GL_IS_LABEL (label));
1745
1746         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1747                           !gl_label_is_selection_atomic (label));
1748
1749         gl_label_checkpoint (label, _("Align horizontal center"));
1750
1751         begin_selection_op (label);
1752
1753         selection_list = gl_label_get_selection_list (label);
1754
1755         /* find average center of objects */
1756         xsum = 0.0;
1757         n = 0;
1758         for (p = selection_list; p != NULL; p = p->next)
1759         {
1760                 object = GL_LABEL_OBJECT (p->data);
1761
1762                 gl_label_object_get_extent (object, &obj_extent);
1763                 xsum += (obj_extent.x1 + obj_extent.x2) / 2.0;
1764                 n++;
1765         }
1766         xavg = xsum / n;
1767
1768         /* find center of object closest to average center */
1769         p = selection_list;
1770         object = GL_LABEL_OBJECT (p->data);
1771
1772         gl_label_object_get_extent (object, &obj_extent);
1773         dxmin = fabs (xavg - (obj_extent.x1 + obj_extent.x2)/2.0);
1774         xcenter = (obj_extent.x1 + obj_extent.x2)/2.0;
1775         for (p = p->next; p != NULL; p = p->next)
1776         {
1777                 object = GL_LABEL_OBJECT (p->data);
1778
1779                 gl_label_object_get_extent (object, &obj_extent);
1780                 dx = fabs (xavg - (obj_extent.x1 + obj_extent.x2)/2.0);
1781                 if ( dx < dxmin )
1782                 {
1783                         dxmin = dx;
1784                         xcenter = (obj_extent.x1 + obj_extent.x2)/2.0;
1785                 }
1786         }
1787
1788         /* now adjust the object positions to line up this center */
1789         for (p = selection_list; p != NULL; p = p->next)
1790         {
1791                 object = GL_LABEL_OBJECT (p->data);
1792
1793                 gl_label_object_get_extent (object, &obj_extent);
1794                 dx = xcenter - (obj_extent.x1 + obj_extent.x2)/2.0;
1795                 gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
1796         }
1797
1798         g_list_free (selection_list);
1799
1800         end_selection_op (label);
1801
1802         gl_debug (DEBUG_LABEL, "END");
1803 }
1804
1805
1806 /*****************************************************************************/
1807 /* Align selected objects to top most edge.                                  */
1808 /*****************************************************************************/
1809 void
1810 gl_label_align_selection_top (glLabel *label)
1811 {
1812         GList         *selection_list;
1813         GList         *p;
1814         glLabelObject *object;
1815         gdouble        dy, y1_min;
1816         glLabelRegion  obj_extent;
1817
1818         gl_debug (DEBUG_LABEL, "START");
1819
1820         g_return_if_fail (label && GL_IS_LABEL (label));
1821
1822         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1823                           !gl_label_is_selection_atomic (label));
1824
1825         gl_label_checkpoint (label, _("Align tops"));
1826
1827         begin_selection_op (label);
1828
1829         selection_list = gl_label_get_selection_list (label);
1830
1831         /* find top most edge */
1832         p = selection_list;
1833         object = GL_LABEL_OBJECT (p->data);
1834
1835         gl_label_object_get_extent (object, &obj_extent);
1836         y1_min = obj_extent.y1;
1837         for (p = p->next; p != NULL; p = p->next)
1838         {
1839                 object = GL_LABEL_OBJECT (p->data);
1840
1841                 gl_label_object_get_extent (object, &obj_extent);
1842                 if ( obj_extent.y1 < y1_min ) y1_min = obj_extent.y1;
1843         }
1844
1845         /* now adjust the object positions to line up the top edges */
1846         for (p = selection_list; p != NULL; p = p->next)
1847         {
1848                 object = GL_LABEL_OBJECT (p->data);
1849
1850                 gl_label_object_get_extent (object, &obj_extent);
1851                 dy = y1_min - obj_extent.y1;
1852                 gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
1853         }
1854
1855         g_list_free (selection_list);
1856
1857         end_selection_op (label);
1858
1859         gl_debug (DEBUG_LABEL, "END");
1860 }
1861
1862
1863 /*****************************************************************************/
1864 /* Align selected objects to bottom most edge.                               */
1865 /*****************************************************************************/
1866 void
1867 gl_label_align_selection_bottom (glLabel *label)
1868 {
1869         GList         *selection_list;
1870         GList         *p;
1871         glLabelObject *object;
1872         gdouble        dy, y2_max;
1873         glLabelRegion  obj_extent;
1874
1875         gl_debug (DEBUG_LABEL, "START");
1876
1877         g_return_if_fail (label && GL_IS_LABEL (label));
1878
1879         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1880                           !gl_label_is_selection_atomic (label));
1881
1882         gl_label_checkpoint (label, _("Align bottoms"));
1883
1884         begin_selection_op (label);
1885
1886         selection_list = gl_label_get_selection_list (label);
1887
1888         /* find bottom most edge */
1889         p = selection_list;
1890         object = GL_LABEL_OBJECT (p->data);
1891
1892         gl_label_object_get_extent (object, &obj_extent);
1893         y2_max = obj_extent.y2;
1894         for (p = p->next; p != NULL; p = p->next)
1895         {
1896                 object = GL_LABEL_OBJECT (p->data);
1897
1898                 gl_label_object_get_extent (object, &obj_extent);
1899                 if ( obj_extent.y2 > y2_max ) y2_max = obj_extent.y2;
1900         }
1901
1902         /* now adjust the object positions to line up the bottom edges */
1903         for (p = selection_list; p != NULL; p = p->next)
1904         {
1905                 object = GL_LABEL_OBJECT (p->data);
1906
1907                 gl_label_object_get_extent (object, &obj_extent);
1908                 dy = y2_max - obj_extent.y2;
1909                 gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
1910         }
1911
1912         g_list_free (selection_list);
1913
1914         end_selection_op (label);
1915
1916         gl_debug (DEBUG_LABEL, "END");
1917 }
1918
1919
1920 /*****************************************************************************/
1921 /* Align selected objects to viertical center of objects.                    */
1922 /*****************************************************************************/
1923 void
1924 gl_label_align_selection_vcenter (glLabel *label)
1925 {
1926         GList         *selection_list;
1927         GList         *p;
1928         glLabelObject *object;
1929         gdouble        dy;
1930         gdouble        dymin;
1931         gdouble        ysum, yavg;
1932         glLabelRegion  obj_extent;
1933         gdouble        ycenter;
1934         gint           n;
1935
1936         gl_debug (DEBUG_LABEL, "START");
1937
1938         g_return_if_fail (label && GL_IS_LABEL (label));
1939
1940         g_return_if_fail (!gl_label_is_selection_empty (label) &&
1941                           !gl_label_is_selection_atomic (label));
1942
1943         gl_label_checkpoint (label, _("Align vertical center"));
1944
1945         begin_selection_op (label);
1946
1947         selection_list = gl_label_get_selection_list (label);
1948
1949         /* find average center of objects */
1950         ysum = 0.0;
1951         n = 0;
1952         for (p = selection_list; p != NULL; p = p->next)
1953         {
1954                 object = GL_LABEL_OBJECT (p->data);
1955
1956                 gl_label_object_get_extent (object, &obj_extent);
1957                 ysum += (obj_extent.y1 + obj_extent.y2) / 2.0;
1958                 n++;
1959         }
1960         yavg = ysum / n;
1961
1962         /* find center of object closest to average center */
1963         p = selection_list;
1964         object = GL_LABEL_OBJECT (p->data);
1965
1966         gl_label_object_get_extent (object, &obj_extent);
1967         dymin = fabs (yavg - (obj_extent.y1 + obj_extent.y2)/2.0);
1968         ycenter = (obj_extent.y1 + obj_extent.y2)/2.0;
1969         for (p = p->next; p != NULL; p = p->next)
1970         {
1971                 object = GL_LABEL_OBJECT (p->data);
1972
1973                 gl_label_object_get_extent (object, &obj_extent);
1974                 dy = fabs (yavg - (obj_extent.y1 + obj_extent.y2)/2.0);
1975                 if ( dy < dymin )
1976                 {
1977                         dymin = dy;
1978                         ycenter = (obj_extent.y1 + obj_extent.y2)/2.0;
1979                 }
1980         }
1981
1982         /* now adjust the object positions to line up this center */
1983         for (p = selection_list; p != NULL; p = p->next)
1984         {
1985                 object = GL_LABEL_OBJECT (p->data);
1986
1987                 gl_label_object_get_extent (object, &obj_extent);
1988                 dy = ycenter - (obj_extent.y1 + obj_extent.y2)/2.0;
1989                 gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
1990         }
1991
1992         g_list_free (selection_list);
1993
1994         end_selection_op (label);
1995
1996         gl_debug (DEBUG_LABEL, "END");
1997 }
1998
1999
2000 /*****************************************************************************/
2001 /* Center selected objects to in center of label.                            */
2002 /*****************************************************************************/
2003 void
2004 gl_label_center_selection_horiz (glLabel *label)
2005 {
2006         GList         *selection_list;
2007         GList         *p;
2008         glLabelObject *object;
2009         gdouble        dx;
2010         gdouble        x_label_center;
2011         gdouble        x_obj_center;
2012         glLabelRegion  obj_extent;
2013         gdouble        w, h;
2014
2015         gl_debug (DEBUG_LABEL, "START");
2016
2017         g_return_if_fail (label && GL_IS_LABEL (label));
2018
2019         g_return_if_fail (!gl_label_is_selection_empty (label));
2020
2021         gl_label_checkpoint (label, _("Center horizontally"));
2022
2023         begin_selection_op (label);
2024
2025         gl_label_get_size (label, &w, &h);
2026         x_label_center = w / 2.0;
2027
2028         /* adjust the object positions */
2029         selection_list = gl_label_get_selection_list (label);
2030         for (p = selection_list; p != NULL; p = p->next)
2031         {
2032                 object = GL_LABEL_OBJECT (p->data);
2033
2034                 gl_label_object_get_extent (object, &obj_extent);
2035                 x_obj_center = (obj_extent.x1 + obj_extent.x2) / 2.0;
2036                 dx = x_label_center - x_obj_center;
2037                 gl_label_object_set_position_relative (object, dx, 0.0, FALSE);
2038         }
2039         g_list_free (selection_list);
2040
2041         end_selection_op (label);
2042
2043         gl_debug (DEBUG_LABEL, "END");
2044 }
2045
2046
2047 /*****************************************************************************/
2048 /* Center selected objects to in center of label.                            */
2049 /*****************************************************************************/
2050 void
2051 gl_label_center_selection_vert (glLabel *label)
2052 {
2053         GList         *selection_list;
2054         GList         *p;
2055         glLabelObject *object;
2056         gdouble        dy;
2057         gdouble        y_label_center;
2058         gdouble        y_obj_center;
2059         glLabelRegion  obj_extent;
2060         gdouble        w, h;
2061
2062         gl_debug (DEBUG_LABEL, "START");
2063
2064         g_return_if_fail (label && GL_IS_LABEL (label));
2065
2066         g_return_if_fail (!gl_label_is_selection_empty (label));
2067
2068         gl_label_checkpoint (label, _("Center vertically"));
2069
2070         begin_selection_op (label);
2071
2072         gl_label_get_size (label, &w, &h);
2073         y_label_center = h / 2.0;
2074
2075         /* adjust the object positions */
2076         selection_list = gl_label_get_selection_list (label);
2077         for (p = selection_list; p != NULL; p = p->next)
2078         {
2079                 object = GL_LABEL_OBJECT (p->data);
2080
2081                 gl_label_object_get_extent (object, &obj_extent);
2082                 y_obj_center = (obj_extent.y1 + obj_extent.y2) / 2.0;
2083                 dy = y_label_center - y_obj_center;
2084                 gl_label_object_set_position_relative (object, 0.0, dy, FALSE);
2085         }
2086         g_list_free (selection_list);
2087
2088         end_selection_op (label);
2089
2090         gl_debug (DEBUG_LABEL, "END");
2091 }
2092
2093
2094 /*****************************************************************************/
2095 /* Move selected objects                                                     */
2096 /*****************************************************************************/
2097 void
2098 gl_label_move_selection (glLabel  *label,
2099                          gdouble   dx,
2100                          gdouble   dy)
2101 {
2102         GList         *selection_list;
2103         GList         *p;
2104         glLabelObject *object;
2105
2106         gl_debug (DEBUG_LABEL, "START");
2107
2108         g_return_if_fail (label && GL_IS_LABEL (label));
2109
2110         begin_selection_op (label);
2111
2112         selection_list = gl_label_get_selection_list (label);
2113
2114         for (p = selection_list; p != NULL; p = p->next)
2115         {
2116                 object = GL_LABEL_OBJECT (p->data);
2117
2118                 gl_label_object_set_position_relative (object, dx, dy, TRUE);
2119         }
2120
2121         g_list_free (selection_list);
2122
2123         end_selection_op (label);
2124
2125         gl_debug (DEBUG_LABEL, "END");
2126 }
2127
2128
2129 /*****************************************************************************/
2130 /* Set font family for all text contained in selected objects.               */
2131 /*****************************************************************************/
2132 void
2133 gl_label_set_selection_font_family (glLabel      *label,
2134                                     const gchar  *font_family)
2135 {
2136         GList         *selection_list;
2137         GList         *p;
2138         glLabelObject *object;
2139
2140         gl_debug (DEBUG_LABEL, "START");
2141
2142         g_return_if_fail (label && GL_IS_LABEL (label));
2143
2144         begin_selection_op (label);
2145
2146         selection_list = gl_label_get_selection_list (label);
2147
2148         for (p = selection_list; p != NULL; p = p->next)
2149         {
2150                 object = GL_LABEL_OBJECT (p->data);
2151                 gl_label_object_set_font_family (object, font_family, TRUE);
2152         }
2153
2154         g_list_free (selection_list);
2155
2156         end_selection_op (label);
2157
2158         gl_debug (DEBUG_LABEL, "END");
2159 }
2160
2161
2162 /*****************************************************************************/
2163 /* Set font size for all text contained in selected objects.                 */
2164 /*****************************************************************************/
2165 void
2166 gl_label_set_selection_font_size (glLabel  *label,
2167                                   gdouble   font_size)
2168 {
2169         GList         *selection_list;
2170         GList         *p;
2171         glLabelObject *object;
2172
2173         gl_debug (DEBUG_LABEL, "START");
2174
2175         g_return_if_fail (label && GL_IS_LABEL (label));
2176
2177         begin_selection_op (label);
2178
2179         selection_list = gl_label_get_selection_list (label);
2180
2181         for (p = selection_list; p != NULL; p = p->next)
2182         {
2183                 object = GL_LABEL_OBJECT (p->data);
2184                 gl_label_object_set_font_size (object, font_size, TRUE);
2185         }
2186
2187         g_list_free (selection_list);
2188
2189         end_selection_op (label);
2190
2191         gl_debug (DEBUG_LABEL, "END");
2192 }
2193
2194
2195 /*****************************************************************************/
2196 /* Set font weight for all text contained in selected objects.               */
2197 /*****************************************************************************/
2198 void
2199 gl_label_set_selection_font_weight (glLabel      *label,
2200                                     PangoWeight   font_weight)
2201 {
2202         GList         *selection_list;
2203         GList         *p;
2204         glLabelObject *object;
2205
2206         gl_debug (DEBUG_LABEL, "START");
2207
2208         g_return_if_fail (label && GL_IS_LABEL (label));
2209
2210         begin_selection_op (label);
2211
2212         selection_list = gl_label_get_selection_list (label);
2213
2214         for (p = selection_list; p != NULL; p = p->next)
2215         {
2216                 object = GL_LABEL_OBJECT (p->data);
2217                 gl_label_object_set_font_weight (object, font_weight, TRUE);
2218         }
2219
2220         g_list_free (selection_list);
2221
2222         end_selection_op (label);
2223
2224         gl_debug (DEBUG_LABEL, "END");
2225 }
2226
2227
2228 /*****************************************************************************/
2229 /* Set font italic flag for all text contained in selected objects.          */
2230 /*****************************************************************************/
2231 void
2232 gl_label_set_selection_font_italic_flag (glLabel   *label,
2233                                          gboolean   font_italic_flag)
2234 {
2235         GList         *selection_list;
2236         GList         *p;
2237         glLabelObject *object;
2238
2239         gl_debug (DEBUG_LABEL, "START");
2240
2241         g_return_if_fail (label && GL_IS_LABEL (label));
2242
2243         begin_selection_op (label);
2244
2245         selection_list = gl_label_get_selection_list (label);
2246
2247         for (p = selection_list; p != NULL; p = p->next)
2248         {
2249                 object = GL_LABEL_OBJECT (p->data);
2250                 gl_label_object_set_font_italic_flag (object, font_italic_flag, TRUE);
2251         }
2252
2253         g_list_free (selection_list);
2254
2255         end_selection_op (label);
2256
2257         gl_debug (DEBUG_LABEL, "END");
2258 }
2259
2260
2261 /*****************************************************************************/
2262 /* Set text alignment for all text contained in selected objects.            */
2263 /*****************************************************************************/
2264 void
2265 gl_label_set_selection_text_alignment (glLabel        *label,
2266                                        PangoAlignment  text_alignment)
2267 {
2268         GList         *selection_list;
2269         GList         *p;
2270         glLabelObject *object;
2271
2272         gl_debug (DEBUG_LABEL, "START");
2273
2274         g_return_if_fail (label && GL_IS_LABEL (label));
2275
2276         begin_selection_op (label);
2277
2278         selection_list = gl_label_get_selection_list (label);
2279
2280         for (p = selection_list; p != NULL; p = p->next)
2281         {
2282                 object = GL_LABEL_OBJECT (p->data);
2283                 gl_label_object_set_text_alignment (object, text_alignment, TRUE);
2284         }
2285
2286         g_list_free (selection_list);
2287
2288         end_selection_op (label);
2289
2290         gl_debug (DEBUG_LABEL, "END");
2291 }
2292
2293
2294 /*****************************************************************************/
2295 /* Set vertical text alignment for all text contained in selected objects.   */
2296 /*****************************************************************************/
2297 void
2298 gl_label_set_selection_text_valignment (glLabel        *label,
2299                                         glValignment    text_valignment)
2300 {
2301         GList         *selection_list;
2302         GList         *p;
2303         glLabelObject *object;
2304
2305         gl_debug (DEBUG_LABEL, "START");
2306
2307         g_return_if_fail (label && GL_IS_LABEL (label));
2308
2309         begin_selection_op (label);
2310
2311         selection_list = gl_label_get_selection_list (label);
2312
2313         for (p = selection_list; p != NULL; p = p->next)
2314         {
2315                 object = GL_LABEL_OBJECT (p->data);
2316                 gl_label_object_set_text_valignment (object, text_valignment, TRUE);
2317         }
2318
2319         g_list_free (selection_list);
2320
2321         end_selection_op (label);
2322
2323         gl_debug (DEBUG_LABEL, "END");
2324 }
2325
2326
2327 /*****************************************************************************/
2328 /* Set text line spacing for all text contained in selected objects.         */
2329 /*****************************************************************************/
2330 void
2331 gl_label_set_selection_text_line_spacing (glLabel  *label,
2332                                           gdouble   text_line_spacing)
2333 {
2334         GList         *selection_list;
2335         GList         *p;
2336         glLabelObject *object;
2337
2338         gl_debug (DEBUG_LABEL, "START");
2339
2340         g_return_if_fail (label && GL_IS_LABEL (label));
2341
2342         begin_selection_op (label);
2343
2344         selection_list = gl_label_get_selection_list (label);
2345
2346         for (p = selection_list; p != NULL; p = p->next)
2347         {
2348                 object = GL_LABEL_OBJECT (p->data);
2349                 gl_label_object_set_text_line_spacing (object, text_line_spacing, TRUE);
2350         }
2351
2352         g_list_free (selection_list);
2353
2354         end_selection_op (label);
2355
2356         gl_debug (DEBUG_LABEL, "END");
2357 }
2358
2359
2360 /*****************************************************************************/
2361 /* Set text color for all text contained in selected objects.                */
2362 /*****************************************************************************/
2363 void
2364 gl_label_set_selection_text_color (glLabel      *label,
2365                                    glColorNode  *text_color_node)
2366 {
2367         GList         *selection_list;
2368         GList         *p;
2369         glLabelObject *object;
2370
2371         gl_debug (DEBUG_LABEL, "START");
2372
2373         g_return_if_fail (label && GL_IS_LABEL (label));
2374
2375         begin_selection_op (label);
2376
2377         selection_list = gl_label_get_selection_list (label);
2378
2379         for (p = selection_list; p != NULL; p = p->next)
2380         {
2381                 object = GL_LABEL_OBJECT (p->data);
2382                 gl_label_object_set_text_color (object, text_color_node, TRUE);
2383         }
2384
2385         g_list_free (selection_list);
2386
2387         end_selection_op (label);
2388
2389         gl_debug (DEBUG_LABEL, "END");
2390 }
2391
2392
2393 /*****************************************************************************/
2394 /* Set fill color for all selected objects.                                  */
2395 /*****************************************************************************/
2396 void
2397 gl_label_set_selection_fill_color (glLabel      *label,
2398                                    glColorNode  *fill_color_node)
2399 {
2400         GList         *selection_list;
2401         GList         *p;
2402         glLabelObject *object;
2403
2404         gl_debug (DEBUG_LABEL, "START");
2405
2406         g_return_if_fail (label && GL_IS_LABEL (label));
2407
2408         begin_selection_op (label);
2409
2410         selection_list = gl_label_get_selection_list (label);
2411
2412         for (p = selection_list; p != NULL; p = p->next)
2413         {
2414                 object = GL_LABEL_OBJECT (p->data);
2415                 gl_label_object_set_fill_color (object, fill_color_node, TRUE);
2416         }
2417
2418         g_list_free (selection_list);
2419
2420         end_selection_op (label);
2421
2422         gl_debug (DEBUG_LABEL, "END");
2423 }
2424
2425
2426 /*****************************************************************************/
2427 /* Set line color for all selected objects.                                  */
2428 /*****************************************************************************/
2429 void
2430 gl_label_set_selection_line_color (glLabel      *label,
2431                                    glColorNode  *line_color_node)
2432 {
2433         GList         *selection_list;
2434         GList         *p;
2435         glLabelObject *object;
2436
2437         gl_debug (DEBUG_LABEL, "START");
2438
2439         g_return_if_fail (label && GL_IS_LABEL (label));
2440
2441         begin_selection_op (label);
2442
2443         selection_list = gl_label_get_selection_list (label);
2444
2445         for (p = selection_list; p != NULL; p = p->next)
2446         {
2447                 object = GL_LABEL_OBJECT (p->data);
2448                 gl_label_object_set_line_color (object, line_color_node, TRUE);
2449         }
2450
2451         g_list_free (selection_list);
2452
2453         end_selection_op (label);
2454
2455         gl_debug (DEBUG_LABEL, "END");
2456 }
2457
2458
2459 /*****************************************************************************/
2460 /* Set line width for all selected objects.                                  */
2461 /*****************************************************************************/
2462 void
2463 gl_label_set_selection_line_width (glLabel  *label,
2464                                   gdouble  line_width)
2465 {
2466         GList         *selection_list;
2467         GList         *p;
2468         glLabelObject *object;
2469
2470         gl_debug (DEBUG_LABEL, "START");
2471
2472         g_return_if_fail (label && GL_IS_LABEL (label));
2473
2474         begin_selection_op (label);
2475
2476         selection_list = gl_label_get_selection_list (label);
2477
2478         for (p = selection_list; p != NULL; p = p->next)
2479         {
2480                 object = GL_LABEL_OBJECT (p->data);
2481                 gl_label_object_set_line_width (object, line_width, TRUE);
2482         }
2483
2484         g_list_free (selection_list);
2485
2486         end_selection_op (label);
2487
2488         gl_debug (DEBUG_LABEL, "END");
2489 }
2490
2491
2492 /*****************************************************************************/
2493 /* "Cut" selected items and place on clipboard.                              */
2494 /*****************************************************************************/
2495 void
2496 gl_label_cut_selection (glLabel       *label)
2497 {
2498         gl_debug (DEBUG_LABEL, "START");
2499
2500         g_return_if_fail (label && GL_IS_LABEL (label));
2501
2502         gl_label_copy_selection (label);
2503         gl_label_delete_selection (label);
2504
2505         gl_debug (DEBUG_LABEL, "END");
2506 }
2507
2508
2509 /*****************************************************************************/
2510 /* "Copy" selected items to clipboard.                                       */
2511 /*****************************************************************************/
2512 void
2513 gl_label_copy_selection (glLabel       *label)
2514 {
2515         GtkClipboard      *clipboard;
2516         GList             *selection_list;
2517         glLabel           *label_copy;
2518         GList             *p;
2519         glLabelObject     *object;
2520         glXMLLabelStatus   status;
2521
2522         ClipboardData     *data;
2523
2524         static GtkTargetEntry glabels_targets[] = { { "application/glabels", 0, 0 },
2525                                                     { "text/xml",            0, 0 },
2526         };
2527
2528         GtkTargetList  *target_list;
2529         GtkTargetEntry *target_table;
2530         gint            n_targets;
2531
2532         gl_debug (DEBUG_LABEL, "START");
2533
2534         g_return_if_fail (label && GL_IS_LABEL (label));
2535
2536         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2537
2538         selection_list = gl_label_get_selection_list (label);
2539
2540         if (selection_list)
2541         {
2542
2543                 data = g_new0 (ClipboardData, 1);
2544
2545                 target_list = gtk_target_list_new (glabels_targets, G_N_ELEMENTS(glabels_targets));
2546
2547                 /*
2548                  * Serialize selection by encoding as an XML label document.
2549                  */
2550                 label_copy = GL_LABEL(gl_label_new ());
2551
2552                 gl_label_set_template (label_copy, label->priv->template, FALSE);
2553                 gl_label_set_rotate_flag (label_copy, label->priv->rotate_flag, FALSE);
2554
2555                 for (p = selection_list; p != NULL; p = p->next)
2556                 {
2557                         object = GL_LABEL_OBJECT (p->data);
2558
2559                         gl_label_add_object (label_copy, gl_label_object_dup (object, label_copy));
2560                 }
2561
2562                 data->xml_buffer = gl_xml_label_save_buffer (label_copy, &status);
2563
2564                 g_object_unref (G_OBJECT (label_copy));
2565
2566
2567                 /*
2568                  * Is it an atomic text selection?  If so, also make available as text.
2569                  */
2570                 if ( gl_label_is_selection_atomic (label) &&
2571                      GL_IS_LABEL_TEXT (selection_list->data) )
2572                 {
2573                         glLabelText *text_object = GL_LABEL_TEXT (selection_list->data);
2574
2575                         gtk_target_list_add_text_targets (target_list, 1);
2576
2577                         data->text = gl_label_text_get_text (text_object);
2578                 }
2579
2580
2581                 /*
2582                  * Is it an atomic image selection?  If so, also make available as pixbuf.
2583                  */
2584                 if ( gl_label_is_selection_atomic (label) &&
2585                      GL_IS_LABEL_IMAGE (selection_list->data) )
2586                 {
2587                         glLabelImage  *image_object = GL_LABEL_IMAGE (selection_list->data);
2588                         GdkPixbuf     *pixbuf = gl_label_image_get_pixbuf (image_object, NULL);
2589
2590                         if (pixbuf)
2591                         {
2592                                 gtk_target_list_add_image_targets (target_list, 2, TRUE);
2593                                 data->pixbuf = pixbuf;
2594                         }
2595                 }
2596
2597
2598                 target_table = gtk_target_table_new_from_list (target_list, &n_targets);
2599
2600                 gtk_clipboard_set_with_data (clipboard,
2601                                              target_table, n_targets,
2602                                              (GtkClipboardGetFunc)clipboard_get_cb,
2603                                              (GtkClipboardClearFunc)clipboard_clear_cb,
2604                                              data);
2605
2606                 gtk_target_table_free (target_table, n_targets);
2607                 gtk_target_list_unref (target_list);
2608         }
2609
2610
2611         g_list_free (selection_list);
2612
2613         gl_debug (DEBUG_LABEL, "END");
2614 }
2615
2616
2617 /*****************************************************************************/
2618 /* "Paste" from clipboard.                                                   */
2619 /*****************************************************************************/
2620 void
2621 gl_label_paste (glLabel       *label)
2622 {
2623         GtkClipboard  *clipboard;
2624
2625         gl_debug (DEBUG_LABEL, "START");
2626
2627         g_return_if_fail (label && GL_IS_LABEL (label));
2628
2629         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2630
2631         gtk_clipboard_request_targets (clipboard,
2632                                        (GtkClipboardTargetsReceivedFunc)receive_targets_cb,
2633                                        label);
2634
2635         gl_debug (DEBUG_LABEL, "END");
2636 }
2637
2638
2639 /*****************************************************************************/
2640 /* Is there anything that can be pasted?                                     */
2641 /*****************************************************************************/
2642 gboolean
2643 gl_label_can_paste (glLabel       *label)
2644 {
2645         GtkClipboard *clipboard;
2646         gboolean      can_flag;
2647
2648         gl_debug (DEBUG_LABEL, "START");
2649
2650         clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2651
2652         can_flag = gtk_clipboard_wait_is_target_available (clipboard,
2653                                                            gdk_atom_intern("application/glabels", TRUE))
2654                 || gtk_clipboard_wait_is_text_available (clipboard)
2655                 || gtk_clipboard_wait_is_image_available (clipboard);
2656
2657         gl_debug (DEBUG_LABEL, "END");
2658         return can_flag;
2659 }
2660
2661
2662 /****************************************************************************/
2663 /* Clipboard "Get" function.                                                */
2664 /****************************************************************************/
2665 static void
2666 clipboard_get_cb (GtkClipboard     *clipboard,
2667                   GtkSelectionData *selection_data,
2668                   guint             info,
2669                   ClipboardData    *data)
2670 {
2671         gl_debug (DEBUG_LABEL, "START");
2672
2673         switch (info)
2674         {
2675
2676         case 0:
2677                 gtk_selection_data_set (selection_data,
2678                                         gtk_selection_data_get_target (selection_data),
2679                                         8,
2680                                         (guchar *)data->xml_buffer, strlen (data->xml_buffer));
2681                 break;
2682
2683         case 1:
2684                 gtk_selection_data_set_text (selection_data, data->text, -1);
2685                 break;
2686
2687         case 2:
2688                 gtk_selection_data_set_pixbuf (selection_data, data->pixbuf);
2689                 break;
2690
2691         default:
2692                 g_assert_not_reached ();
2693                 break;
2694
2695         }
2696
2697         gl_debug (DEBUG_LABEL, "END");
2698 }
2699
2700
2701 /****************************************************************************/
2702 /* Clipboard "Clear" function.                                              */
2703 /****************************************************************************/
2704 static void
2705 clipboard_clear_cb (GtkClipboard     *clipboard,
2706                     ClipboardData    *data)
2707 {
2708         gl_debug (DEBUG_LABEL, "START");
2709
2710         g_free (data->xml_buffer);
2711         g_free (data->text);
2712         if (data->pixbuf)
2713         {
2714                 g_object_unref (data->pixbuf);
2715         }
2716
2717         g_free (data);
2718
2719         gl_debug (DEBUG_LABEL, "END");
2720 }
2721
2722
2723 /****************************************************************************/
2724 /* Deal with clipboard data.                                                */
2725 /****************************************************************************/
2726 static void
2727 receive_targets_cb (GtkClipboard *clipboard,
2728                     GdkAtom      *targets,
2729                     gint          n_targets,
2730                     glLabel      *label)
2731 {
2732         gint i;
2733
2734         /*
2735          * Application/glabels
2736          */
2737         for ( i = 0; i < n_targets; i++ )
2738         {
2739                 if ( strcmp(gdk_atom_name(targets[i]), "application/glabels") == 0 )
2740                 {
2741                         gtk_clipboard_request_contents (clipboard,
2742                                                         gdk_atom_intern("application/glabels", TRUE),
2743                                                         (GtkClipboardReceivedFunc)paste_xml_received_cb,
2744                                                         label);
2745                         return;
2746                 }
2747         }
2748
2749         /*
2750          * Text
2751          */
2752         if ( gtk_targets_include_text (targets, n_targets) )
2753         {
2754                 gtk_clipboard_request_text (clipboard,
2755                                             (GtkClipboardTextReceivedFunc)paste_text_received_cb,
2756                                             label);
2757                 return;
2758         }
2759
2760         /*
2761          * Image
2762          */
2763         if ( gtk_targets_include_image (targets, n_targets, TRUE) )
2764         {
2765                 gtk_clipboard_request_image (clipboard,
2766                                              (GtkClipboardImageReceivedFunc)paste_image_received_cb,
2767                                              label);
2768                 return;
2769         }
2770 }
2771
2772
2773 /****************************************************************************/
2774 /* Paste received glabels XML callback.                                     */
2775 /****************************************************************************/
2776 static void
2777 paste_xml_received_cb (GtkClipboard     *clipboard,
2778                        GtkSelectionData *selection_data,
2779                        glLabel          *label)
2780 {
2781         gchar            *xml_buffer;
2782         glLabel          *label_copy;
2783         glXMLLabelStatus  status;
2784         GList            *p;
2785         glLabelObject    *object, *newobject;
2786
2787         gl_debug (DEBUG_LABEL, "START");
2788
2789         gl_label_checkpoint (label, _("Paste"));
2790
2791         xml_buffer = (gchar *)gtk_selection_data_get_data (selection_data);
2792
2793         /*
2794          * Deserialize XML label document and extract objects.
2795          */
2796         label_copy = gl_xml_label_open_buffer (xml_buffer, &status);
2797         if ( label_copy )
2798         {
2799                 gl_label_unselect_all (label);
2800
2801                 for (p = label_copy->priv->object_list; p != NULL; p = p->next)
2802                 {
2803                         object = (glLabelObject *) p->data;
2804                         newobject = gl_label_object_dup (object, label);
2805                         gl_label_add_object( label, newobject );
2806
2807                         gl_label_select_object (label, newobject);
2808
2809                         gl_debug (DEBUG_LABEL, "object pasted");
2810                 }
2811
2812                 g_object_unref (G_OBJECT (label_copy));
2813         }
2814
2815         gl_debug (DEBUG_LABEL, "END");
2816 }
2817
2818
2819 /****************************************************************************/
2820 /* Paste received text callback.                                            */
2821 /****************************************************************************/
2822 static void
2823 paste_text_received_cb (GtkClipboard     *clipboard,
2824                         const gchar      *text,
2825                         glLabel          *label)
2826 {
2827         glLabelObject    *object;
2828
2829         gl_debug (DEBUG_LABEL, "START");
2830
2831         gl_label_checkpoint (label, _("Paste"));
2832
2833         gl_label_unselect_all (label);
2834
2835         object = GL_LABEL_OBJECT (gl_label_text_new (label, FALSE));
2836         gl_label_text_set_text (GL_LABEL_TEXT (object), text, FALSE);
2837         gl_label_object_set_position (object, 18, 18, FALSE);
2838
2839         gl_label_select_object (label, object);
2840
2841         gl_debug (DEBUG_LABEL, "END");
2842 }
2843
2844
2845 /****************************************************************************/
2846 /* Paste received image callback.                                           */
2847 /****************************************************************************/
2848 static void
2849 paste_image_received_cb (GtkClipboard     *clipboard,
2850                          GdkPixbuf        *pixbuf,
2851                          glLabel          *label)
2852 {
2853         glLabelObject    *object;
2854
2855         gl_debug (DEBUG_LABEL, "START");
2856
2857         gl_label_checkpoint (label, _("Paste"));
2858
2859         gl_label_unselect_all (label);
2860
2861         object = GL_LABEL_OBJECT (gl_label_image_new (label, FALSE));
2862         gl_label_image_set_pixbuf (GL_LABEL_IMAGE (object), pixbuf, FALSE);
2863         gl_label_object_set_position (object, 18, 18, FALSE);
2864
2865         gl_label_select_object (label, object);
2866
2867         gl_debug (DEBUG_LABEL, "END");
2868 }
2869
2870
2871 /****************************************************************************/
2872 /* Set default font family.                                                 */
2873 /****************************************************************************/
2874 void
2875 gl_label_set_default_font_family (glLabel     *label,
2876                                   const gchar *font_family)
2877 {
2878         gl_debug (DEBUG_LABEL, "START");
2879
2880         g_return_if_fail (label && GL_IS_LABEL (label));
2881
2882         g_free (label->priv->default_font_family);
2883         label->priv->default_font_family = g_strdup (font_family);
2884
2885         gl_debug (DEBUG_LABEL, "END");
2886 }
2887
2888
2889 /****************************************************************************/
2890 /* Set default font size.                                                   */
2891 /****************************************************************************/
2892 void
2893 gl_label_set_default_font_size (glLabel *label,
2894                                 gdouble  font_size)
2895 {
2896         gl_debug (DEBUG_LABEL, "START");
2897
2898         g_return_if_fail (label && GL_IS_LABEL (label));
2899
2900         label->priv->default_font_size = font_size;
2901
2902         gl_debug (DEBUG_LABEL, "END");
2903 }
2904
2905
2906 /****************************************************************************/
2907 /* Set default font weight.                                                 */
2908 /****************************************************************************/
2909 void
2910 gl_label_set_default_font_weight (glLabel     *label,
2911                                   PangoWeight  font_weight)
2912 {
2913         gl_debug (DEBUG_LABEL, "START");
2914
2915         g_return_if_fail (label && GL_IS_LABEL (label));
2916
2917         label->priv->default_font_weight = font_weight;
2918
2919         gl_debug (DEBUG_LABEL, "END");
2920 }
2921
2922
2923 /****************************************************************************/
2924 /* Set default font italic flag.                                            */
2925 /****************************************************************************/
2926 void
2927 gl_label_set_default_font_italic_flag (glLabel  *label,
2928                                        gboolean  font_italic_flag)
2929 {
2930         gl_debug (DEBUG_LABEL, "START");
2931
2932         g_return_if_fail (label && GL_IS_LABEL (label));
2933
2934         label->priv->default_font_italic_flag = font_italic_flag;
2935
2936         gl_debug (DEBUG_LABEL, "END");
2937 }
2938
2939
2940 /****************************************************************************/
2941 /* Set default text color.                                                  */
2942 /****************************************************************************/
2943 void
2944 gl_label_set_default_text_color (glLabel *label,
2945                                  guint    text_color)
2946 {
2947         gl_debug (DEBUG_LABEL, "START");
2948
2949         g_return_if_fail (label && GL_IS_LABEL (label));
2950
2951         label->priv->default_text_color = text_color;
2952
2953         gl_debug (DEBUG_LABEL, "END");
2954 }
2955
2956
2957 /****************************************************************************/
2958 /* Set default text alignment.                                              */
2959 /****************************************************************************/
2960 void
2961 gl_label_set_default_text_alignment (glLabel        *label,
2962                                      PangoAlignment  text_alignment)
2963 {
2964         gl_debug (DEBUG_LABEL, "START");
2965
2966         g_return_if_fail (label && GL_IS_LABEL (label));
2967
2968         label->priv->default_text_alignment = text_alignment;
2969         gl_debug (DEBUG_LABEL, "END");
2970 }
2971
2972
2973 /****************************************************************************/
2974 /* Set default vertical text alignment.                                     */
2975 /****************************************************************************/
2976 void
2977 gl_label_set_default_text_valignment (glLabel        *label,
2978                                       glValignment    text_valignment)
2979 {
2980         gl_debug (DEBUG_LABEL, "START");
2981
2982         g_return_if_fail (label && GL_IS_LABEL (label));
2983
2984         label->priv->default_text_valignment = text_valignment;
2985         gl_debug (DEBUG_LABEL, "END");
2986 }
2987
2988
2989 /****************************************************************************/
2990 /* Set default text line spacing.                                           */
2991 /****************************************************************************/
2992 void
2993 gl_label_set_default_text_line_spacing (glLabel *label,
2994                                         gdouble  text_line_spacing)
2995 {
2996         gl_debug (DEBUG_LABEL, "START");
2997
2998         g_return_if_fail (label && GL_IS_LABEL (label));
2999
3000         label->priv->default_text_line_spacing = text_line_spacing;
3001
3002         gl_debug (DEBUG_LABEL, "END");
3003 }
3004
3005
3006 /****************************************************************************/
3007 /* Set default line width.                                                  */
3008 /****************************************************************************/
3009 void
3010 gl_label_set_default_line_width (glLabel *label,
3011                                  gdouble  line_width)
3012 {
3013         gl_debug (DEBUG_LABEL, "START");
3014
3015         g_return_if_fail (label && GL_IS_LABEL (label));
3016
3017         label->priv->default_line_width = line_width;
3018
3019         gl_debug (DEBUG_LABEL, "END");
3020 }
3021
3022
3023 /****************************************************************************/
3024 /* Set default line color.                                                  */
3025 /****************************************************************************/
3026 void
3027 gl_label_set_default_line_color (glLabel *label,
3028                                  guint    line_color)
3029 {
3030         gl_debug (DEBUG_LABEL, "START");
3031
3032         g_return_if_fail (label && GL_IS_LABEL (label));
3033
3034         label->priv->default_line_color = line_color;
3035
3036         gl_debug (DEBUG_LABEL, "END");
3037 }
3038
3039
3040 /****************************************************************************/
3041 /* Set default fill color.                                                  */
3042 /****************************************************************************/
3043 void
3044 gl_label_set_default_fill_color (glLabel *label,
3045                                  guint    fill_color)
3046 {
3047         gl_debug (DEBUG_LABEL, "START");
3048
3049         g_return_if_fail (label && GL_IS_LABEL (label));
3050
3051         label->priv->default_fill_color = fill_color;
3052
3053         gl_debug (DEBUG_LABEL, "END");
3054 }
3055
3056
3057 /****************************************************************************/
3058 /* Get default font family.                                                 */
3059 /****************************************************************************/
3060 gchar *
3061 gl_label_get_default_font_family (glLabel *label)
3062 {
3063         gl_debug (DEBUG_LABEL, "START");
3064
3065         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
3066
3067         gl_debug (DEBUG_LABEL, "END");
3068
3069         return g_strdup (label->priv->default_font_family);
3070 }
3071
3072
3073 /****************************************************************************/
3074 /* Get default font size.                                                   */
3075 /****************************************************************************/
3076 gdouble
3077 gl_label_get_default_font_size (glLabel *label)
3078 {
3079         gl_debug (DEBUG_LABEL, "START");
3080
3081         g_return_val_if_fail (label && GL_IS_LABEL (label), 12.0);
3082
3083         gl_debug (DEBUG_LABEL, "END");
3084
3085         return label->priv->default_font_size;
3086 }
3087
3088
3089 /****************************************************************************/
3090 /* Get default font weight.                                                 */
3091 /****************************************************************************/
3092 PangoWeight
3093 gl_label_get_default_font_weight (glLabel *label)
3094 {
3095         gl_debug (DEBUG_LABEL, "START");
3096
3097         g_return_val_if_fail (label && GL_IS_LABEL (label), PANGO_WEIGHT_NORMAL);
3098
3099         gl_debug (DEBUG_LABEL, "END");
3100
3101         return label->priv->default_font_weight;
3102 }
3103
3104
3105 /****************************************************************************/
3106 /* Get default font italic flag.                                            */
3107 /****************************************************************************/
3108 gboolean
3109 gl_label_get_default_font_italic_flag (glLabel *label)
3110 {
3111         gl_debug (DEBUG_LABEL, "START");
3112
3113         g_return_val_if_fail (label && GL_IS_LABEL (label), FALSE);
3114
3115         gl_debug (DEBUG_LABEL, "END");
3116
3117         return label->priv->default_font_italic_flag;
3118 }
3119
3120
3121 /****************************************************************************/
3122 /* Get default text color.                                                  */
3123 /****************************************************************************/
3124 guint
3125 gl_label_get_default_text_color (glLabel *label)
3126 {
3127         gl_debug (DEBUG_LABEL, "START");
3128
3129         g_return_val_if_fail (label && GL_IS_LABEL (label), 0);
3130
3131         gl_debug (DEBUG_LABEL, "END");
3132
3133         return label->priv->default_text_color;
3134 }
3135
3136
3137 /****************************************************************************/
3138 /* Get default text alignment.                                              */
3139 /****************************************************************************/
3140 PangoAlignment
3141 gl_label_get_default_text_alignment (glLabel *label)
3142 {
3143         gl_debug (DEBUG_LABEL, "START");
3144
3145         g_return_val_if_fail (label && GL_IS_LABEL (label), PANGO_ALIGN_LEFT);
3146
3147         gl_debug (DEBUG_LABEL, "END");
3148
3149         return label->priv->default_text_alignment;
3150 }
3151
3152
3153 /****************************************************************************/
3154 /* Get default vertical text alignment.                                     */
3155 /****************************************************************************/
3156 glValignment
3157 gl_label_get_default_text_valignment (glLabel *label)
3158 {
3159         gl_debug (DEBUG_LABEL, "START");
3160
3161         g_return_val_if_fail (label && GL_IS_LABEL (label), GL_VALIGN_TOP);
3162
3163         gl_debug (DEBUG_LABEL, "END");
3164
3165         return label->priv->default_text_valignment;
3166 }
3167
3168
3169 /****************************************************************************/
3170 /* Get default text line spacing.                                           */
3171 /****************************************************************************/
3172 gdouble
3173 gl_label_get_default_text_line_spacing (glLabel *label)
3174 {
3175         gl_debug (DEBUG_LABEL, "START");
3176
3177         g_return_val_if_fail (label && GL_IS_LABEL (label), 1.0);
3178
3179         gl_debug (DEBUG_LABEL, "END");
3180
3181         return label->priv->default_text_line_spacing;
3182 }
3183
3184
3185 /****************************************************************************/
3186 /* Get default line width.                                                  */
3187 /****************************************************************************/
3188 gdouble
3189 gl_label_get_default_line_width (glLabel *label)
3190 {
3191         gl_debug (DEBUG_LABEL, "START");
3192
3193         g_return_val_if_fail (label && GL_IS_LABEL (label), 1.0);
3194
3195         gl_debug (DEBUG_LABEL, "END");
3196
3197         return label->priv->default_line_width;
3198 }
3199
3200
3201 /****************************************************************************/
3202 /* Get default line color.                                                  */
3203 /****************************************************************************/
3204 guint
3205 gl_label_get_default_line_color (glLabel *label)
3206 {
3207         gl_debug (DEBUG_LABEL, "START");
3208
3209         g_return_val_if_fail (label && GL_IS_LABEL (label), 0);
3210
3211         gl_debug (DEBUG_LABEL, "END");
3212
3213         return label->priv->default_line_color;
3214 }
3215
3216
3217 /****************************************************************************/
3218 /* Get default fill color.                                                  */
3219 /****************************************************************************/
3220 guint
3221 gl_label_get_default_fill_color (glLabel *label)
3222 {
3223         gl_debug (DEBUG_LABEL, "START");
3224
3225         g_return_val_if_fail (label && GL_IS_LABEL (label), 0);
3226
3227         gl_debug (DEBUG_LABEL, "END");
3228
3229         return label->priv->default_fill_color;
3230 }
3231
3232
3233 /****************************************************************************/
3234 /* Draw label.                                                              */
3235 /****************************************************************************/
3236 void
3237 gl_label_draw (glLabel       *label,
3238                cairo_t       *cr,
3239                gboolean       screen_flag,
3240                glMergeRecord *record)
3241 {
3242         GList            *p_obj;
3243         glLabelObject    *object;
3244
3245         g_return_if_fail (label && GL_IS_LABEL (label));
3246
3247         for (p_obj = label->priv->object_list; p_obj != NULL; p_obj = p_obj->next)
3248         {
3249                 object = GL_LABEL_OBJECT (p_obj->data);
3250
3251                 gl_label_object_draw (object, cr, screen_flag, record);
3252         }
3253 }
3254
3255
3256 /****************************************************************************/
3257 /* Get object located at coordinates.                                       */
3258 /****************************************************************************/
3259 glLabelObject *gl_label_object_at              (glLabel       *label,
3260                                                 cairo_t       *cr,
3261                                                 gdouble        x_pixels,
3262                                                 gdouble        y_pixels)
3263 {
3264         GList            *p_obj;
3265         glLabelObject    *object;
3266
3267         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
3268
3269         for (p_obj = g_list_last (label->priv->object_list); p_obj != NULL; p_obj = p_obj->prev)
3270         {
3271                 object = GL_LABEL_OBJECT (p_obj->data);
3272
3273                 if (gl_label_object_is_located_at (object, cr, x_pixels, y_pixels))
3274                 {
3275                         return object;
3276                 }
3277
3278         }
3279
3280         return NULL;
3281 }
3282
3283
3284 /****************************************************************************/
3285 /* Return handle and associated object at coordinates.                      */
3286 /****************************************************************************/
3287 glLabelObject *
3288 gl_label_get_handle_at (glLabel             *label,
3289                         cairo_t             *cr,
3290                         gdouble              x_pixels,
3291                         gdouble              y_pixels,
3292                         glLabelObjectHandle *handle)
3293 {
3294         GList            *selection_list;
3295         GList            *p_obj;
3296         glLabelObject    *object;
3297
3298         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
3299
3300         selection_list = gl_label_get_selection_list (label);
3301
3302         for (p_obj = g_list_last (selection_list); p_obj != NULL; p_obj = p_obj->prev)
3303         {
3304
3305                 object = GL_LABEL_OBJECT (p_obj->data);
3306
3307                 if ((*handle = gl_label_object_handle_at (object, cr, x_pixels, y_pixels)))
3308                 {
3309                         g_list_free (selection_list);
3310                         return object;
3311                 }
3312
3313         }
3314
3315         g_list_free (selection_list);
3316
3317         *handle = GL_LABEL_OBJECT_HANDLE_NONE;
3318         return NULL;
3319 }
3320
3321
3322 /****************************************************************************/
3323 /* Checkpoint state.                                                        */
3324 /****************************************************************************/
3325 void
3326 gl_label_checkpoint (glLabel       *this,
3327                      const gchar   *description)
3328 {
3329         State *state;
3330
3331         gl_debug (DEBUG_LABEL, "START");
3332
3333         /*
3334          * Do not perform consecutive checkpoints that are identical.
3335          * E.g. moving an object by dragging, would produce a large number
3336          * of incremental checkpoints -- what we really want is a single
3337          * checkpoint so that we can undo the entire dragging effort with
3338          * one "undo"
3339          */
3340         if ( this->priv->cp_cleared_flag
3341              || (this->priv->cp_desc == NULL)
3342              || (strcmp (description, this->priv->cp_desc) != 0) )
3343         {
3344
3345                 /* Sever old redo "thread" */
3346                 stack_clear (this->priv->redo_stack);
3347
3348                 /* Save state onto undo stack. */
3349                 state = state_new (this, description);
3350                 stack_push_state (this->priv->undo_stack, state);
3351
3352                 /* Track consecutive checkpoints. */
3353                 this->priv->cp_cleared_flag = FALSE;
3354                 this->priv->cp_desc         = g_strdup (description);
3355         }
3356
3357         gl_debug (DEBUG_LABEL, "END");
3358 }
3359
3360
3361 /****************************************************************************/
3362 /* Undo.                                                                    */
3363 /****************************************************************************/
3364 void
3365 gl_label_undo (glLabel       *this)
3366 {
3367         State *state_old;
3368         State *state_now;
3369
3370         gl_debug (DEBUG_LABEL, "START");
3371
3372         state_old = stack_pop_state (this->priv->undo_stack);
3373         state_now = state_new (this, state_old->description);
3374
3375         stack_push_state (this->priv->redo_stack, state_now);
3376
3377         state_restore (state_old, this);
3378         state_free (state_old);
3379
3380         this->priv->cp_cleared_flag = TRUE;
3381
3382         gl_debug (DEBUG_LABEL, "END");
3383 }
3384
3385
3386 /****************************************************************************/
3387 /* Redo.                                                                    */
3388 /****************************************************************************/
3389 void
3390 gl_label_redo (glLabel       *this)
3391 {
3392         State *state_old;
3393         State *state_now;
3394
3395         gl_debug (DEBUG_LABEL, "START");
3396
3397         state_old = stack_pop_state (this->priv->redo_stack);
3398         state_now = state_new (this, state_old->description);
3399
3400         stack_push_state (this->priv->undo_stack, state_now);
3401
3402         state_restore (state_old, this);
3403         state_free (state_old);
3404
3405         this->priv->cp_cleared_flag = TRUE;
3406
3407         gl_debug (DEBUG_LABEL, "END");
3408 }
3409
3410
3411 /****************************************************************************/
3412 /* Can undo?                                                                */
3413 /****************************************************************************/
3414 gboolean
3415 gl_label_can_undo (glLabel *this)
3416 {
3417         return (!g_queue_is_empty (this->priv->undo_stack));
3418 }
3419
3420
3421 /****************************************************************************/
3422 /* Can redo?                                                                */
3423 /****************************************************************************/
3424 gboolean
3425 gl_label_can_redo (glLabel *this)
3426 {
3427         return (!g_queue_is_empty (this->priv->redo_stack));
3428 }
3429
3430
3431 /****************************************************************************/
3432 /* Get undo description string.                                             */
3433 /****************************************************************************/
3434 gchar *
3435 gl_label_get_undo_description (glLabel *this)
3436 {
3437         State *state;
3438         gchar *description;
3439
3440         state = g_queue_peek_head (this->priv->undo_stack);
3441         if ( state )
3442         {
3443                 description = g_strdup (state->description);
3444         }
3445         else
3446         {
3447                 description = g_strdup ("");
3448         }
3449
3450         return description;
3451 }
3452
3453
3454 /****************************************************************************/
3455 /* Get redo description string.                                             */
3456 /****************************************************************************/
3457 gchar *
3458 gl_label_get_redo_description (glLabel *this)
3459 {
3460         State *state;
3461         gchar *description;
3462
3463         state = g_queue_peek_head (this->priv->redo_stack);
3464         if ( state )
3465         {
3466                 description = g_strdup (state->description);
3467         }
3468         else
3469         {
3470                 description = g_strdup ("");
3471         }
3472
3473         return description;
3474 }
3475
3476
3477 /****************************************************************************/
3478 /* Clear undo or redo stack.                                                */
3479 /****************************************************************************/
3480 static void
3481 stack_clear (GQueue *stack)
3482 {
3483         State *state;
3484
3485         gl_debug (DEBUG_LABEL, "START");
3486
3487         while ( (state = g_queue_pop_head (stack)) != NULL )
3488         {
3489                 state_free (state);
3490         }
3491
3492         gl_debug (DEBUG_LABEL, "END");
3493 }
3494
3495
3496 /****************************************************************************/
3497 /* Push state onto stack.                                                   */
3498 /****************************************************************************/
3499 static void
3500 stack_push_state (GQueue *stack,
3501                   State  *state)
3502 {
3503         gl_debug (DEBUG_LABEL, "START");
3504
3505         g_queue_push_head( stack, state );
3506
3507         gl_debug (DEBUG_LABEL, "END");
3508 }
3509
3510
3511 /****************************************************************************/
3512 /* Pop state from stack.                                                    */
3513 /****************************************************************************/
3514 static State *
3515 stack_pop_state (GQueue *stack)
3516 {
3517         State *state;
3518
3519         gl_debug (DEBUG_LABEL, "START");
3520
3521         state = g_queue_pop_head (stack);
3522
3523         gl_debug (DEBUG_LABEL, "END");
3524         return state;
3525 }
3526
3527
3528 /****************************************************************************/
3529 /* New state from label.                                                    */
3530 /****************************************************************************/
3531 static State *
3532 state_new (glLabel       *this,
3533            const gchar   *description)
3534 {
3535         State          *state;
3536         GList          *p_obj;
3537         glLabelObject  *object;
3538
3539         gl_debug (DEBUG_LABEL, "START");
3540
3541         state = g_new0 (State, 1);
3542
3543         state->description = g_strdup (description);
3544
3545         state->template    = lgl_template_dup (this->priv->template);
3546         state->rotate_flag = this->priv->rotate_flag;
3547
3548         for ( p_obj = this->priv->object_list; p_obj != NULL; p_obj = p_obj->next )
3549         {
3550                 object = GL_LABEL_OBJECT (p_obj->data);
3551
3552                 state->object_list = g_list_append (state->object_list,
3553                                                     gl_label_object_dup (object, this));
3554         }
3555
3556         state->merge = gl_merge_dup (this->priv->merge);
3557
3558         state->modified_flag = this->priv->modified_flag;
3559         state->time_stamp    = this->priv->time_stamp;
3560
3561
3562         gl_debug (DEBUG_LABEL, "END");
3563         return state;
3564 }
3565
3566
3567 /****************************************************************************/
3568 /* Restore label from saved state.                                          */
3569 /****************************************************************************/
3570 static void
3571 state_free (State   *state)
3572 {
3573         GList          *p_obj;
3574
3575         gl_debug (DEBUG_LABEL, "START");
3576
3577         g_free (state->description);
3578
3579         lgl_template_free (state->template);
3580         if ( state->merge )
3581         {
3582                 g_object_unref (G_OBJECT (state->merge));
3583         }
3584
3585         for ( p_obj = state->object_list; p_obj != NULL; p_obj = p_obj->next )
3586         {
3587                 g_object_unref (G_OBJECT (p_obj->data));
3588         }
3589         g_list_free (state->object_list);
3590
3591         g_free (state);
3592
3593         gl_debug (DEBUG_LABEL, "END");
3594 }
3595
3596
3597 /****************************************************************************/
3598 /* Restore label from saved state.                                          */
3599 /****************************************************************************/
3600 static void
3601 state_restore (State   *state,
3602                glLabel *this)
3603                
3604 {
3605         GList          *p_obj, *p_next;
3606         glLabelObject  *object;
3607
3608         gl_debug (DEBUG_LABEL, "START");
3609
3610         gl_label_set_rotate_flag (this, state->rotate_flag, FALSE);
3611         gl_label_set_template (this, state->template, FALSE);
3612
3613         for ( p_obj = this->priv->object_list; p_obj != NULL; p_obj = p_next )
3614         {
3615                 p_next = p_obj->next; /* Hold on to next; delete is destructive */
3616                 object = GL_LABEL_OBJECT (p_obj->data);
3617
3618                 gl_label_delete_object (this, object);
3619         }
3620
3621         for ( p_obj = state->object_list; p_obj != NULL; p_obj = p_obj->next )
3622         {
3623                 object = GL_LABEL_OBJECT (p_obj->data);
3624
3625                 gl_label_add_object (this, gl_label_object_dup (object, this));
3626         }
3627         g_signal_emit (G_OBJECT(this), signals[SELECTION_CHANGED], 0);
3628
3629         gl_label_set_merge (this, state->merge, FALSE);
3630         
3631
3632         if ( !state->modified_flag &&
3633              (state->time_stamp.tv_sec  == this->priv->time_stamp.tv_sec) &&
3634              (state->time_stamp.tv_usec == this->priv->time_stamp.tv_usec) )
3635         {
3636                 gl_label_clear_modified (this);
3637         }
3638
3639         gl_debug (DEBUG_LABEL, "END");
3640 }
3641
3642
3643
3644
3645 /*
3646  * Local Variables:       -- emacs
3647  * mode: C                -- emacs
3648  * c-basic-offset: 8      -- emacs
3649  * tab-width: 8           -- emacs
3650  * indent-tabs-mode: nil  -- emacs
3651  * End:                   -- emacs
3652  */