]> git.sur5r.net Git - glabels/blob - glabels2/src/view.c
Moved item event handler to view-object.c.
[glabels] / glabels2 / src / view.c
1 /*
2  *  (GLABELS) Label and Business Card Creation program for GNOME
3  *
4  *  view.c:  GLabels View module
5  *
6  *  Copyright (C) 2001-2002  Jim Evins <evins@snaught.com>.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21  */
22
23 #include <config.h>
24
25 #include <gtk/gtk.h>
26 #include <gtk/gtkinvisible.h>
27
28 #include <string.h>
29 #include <math.h>
30
31 #include "view.h"
32 #include "view-object.h"
33 #include "view-box.h"
34 #include "view-ellipse.h"
35 #include "view-line.h"
36 #include "view-image.h"
37 #include "view-text.h"
38 #include "view-barcode.h"
39 #include "xml-label.h"
40 #include "color.h"
41 #include "stock.h"
42 #include "merge-properties-dialog.h"
43 #include "marshal.h"
44
45 #include "debug.h"
46
47 /*==========================================================================*/
48 /* Private macros and constants.                                            */
49 /*==========================================================================*/
50
51 #define BG_COLOR        GL_COLOR (192, 192, 192)
52 #define OUTLINE_COLOR   GL_COLOR (173, 216, 230)
53 #define PAPER_COLOR     GL_COLOR (255, 255, 255)
54 #define GRID_COLOR      BG_COLOR
55 #define MARKUP_COLOR    GL_COLOR (240, 100, 100)
56
57 #define SEL_LINE_COLOR  GL_COLOR_A (0, 0, 255, 128)
58 #define SEL_FILL_COLOR  GL_COLOR_A (192, 192, 255, 128)
59
60 /*==========================================================================*/
61 /* Private types.                                                           */
62 /*==========================================================================*/
63
64 enum {
65         SELECTION_CHANGED,
66         ZOOM_CHANGED,
67         POINTER_MOVED,
68         POINTER_EXIT,
69         MODE_CHANGED,
70         LAST_SIGNAL
71 };
72
73
74 /*==========================================================================*/
75 /* Private globals                                                          */
76 /*==========================================================================*/
77
78 static GtkContainerClass *parent_class;
79
80 static guint signals[LAST_SIGNAL] = {0};
81
82 /* "CLIPBOARD" selection */
83 static GdkAtom clipboard_atom = GDK_NONE;
84
85 static gdouble scales[] = {
86         8.0, 6.0, 4.0, 3.0,
87         2.0,
88         1.5, 1.0, 0.5, 0.25,
89 };
90 #define N_SCALES G_N_ELEMENTS(scales)
91 #define HOME_SCALE 2.0
92
93 /*==========================================================================*/
94 /* Local function prototypes                                                */
95 /*==========================================================================*/
96
97 static void       gl_view_class_init              (glViewClass *class);
98 static void       gl_view_init                    (glView *view);
99 static void       gl_view_finalize                (GObject *object);
100
101 static void       gl_view_construct               (glView *view);
102 static GtkWidget *gl_view_construct_canvas        (glView *view);
103 static void       gl_view_construct_selection     (glView *view);
104
105 static gdouble    get_apropriate_scale            (gdouble w, gdouble h);
106
107 static void       draw_layers                     (glView *view);
108
109 static void       draw_label_layer                (glView *view);
110
111 static void       draw_highlight_layer            (glView *view);
112
113 static void       draw_bg_fg_layers               (glView *view);
114 static void       draw_bg_fg_rect                 (glView *view);
115 static void       draw_bg_fg_rounded_rect         (glView *view);
116 static void       draw_bg_fg_round                (glView *view);
117 static void       draw_bg_fg_cd                   (glView *view);
118
119 static void       draw_grid_layer                 (glView *view);
120
121 static void       draw_markup_layer               (glView *view);
122
123 static void       draw_markup_margin              (glView *view,
124                                                    glTemplateMarkupMargin *margin);
125 static void       draw_markup_margin_rect         (glView *view,
126                                                    glTemplateMarkupMargin *margin);
127 static void       draw_markup_margin_rounded_rect (glView *view,
128                                                    glTemplateMarkupMargin *margin);
129 static void       draw_markup_margin_round        (glView *view,
130                                                    glTemplateMarkupMargin *margin);
131 static void       draw_markup_margin_cd           (glView *view,
132                                                    glTemplateMarkupMargin *margin);
133
134 static void       draw_markup_line                (glView *view,
135                                                    glTemplateMarkupLine   *line);
136
137
138 static void       select_object_real              (glView *view,
139                                                    glViewObject *view_object);
140 static void       unselect_object_real            (glView *view,
141                                                    glViewObject *view_object);
142
143 static gboolean   object_at                       (glView *view,
144                                                    gdouble x, gdouble y);
145
146 static gboolean   is_item_member_of_group         (glView          *view,
147                                                    GnomeCanvasItem *item,
148                                                    GnomeCanvasItem *group);
149
150 static int        canvas_event                    (GnomeCanvas *canvas,
151                                                    GdkEvent    *event,
152                                                    glView      *view);
153 static int        canvas_event_arrow_mode         (GnomeCanvas *canvas,
154                                                    GdkEvent    *event,
155                                                    glView      *view);
156
157 static void       construct_selection_menu       (glView *view);
158
159 static void       construct_empty_selection_menu (glView *view);
160
161 static void       selection_clear_cb             (GtkWidget         *widget,
162                                                   GdkEventSelection *event,
163                                                   gpointer          data);
164
165 static void       selection_get_cb               (GtkWidget         *widget,
166                                                   GtkSelectionData  *selection_data,
167                                                   guint             info,
168                                                   guint             time,
169                                                   gpointer          data);
170
171 static void       selection_received_cb          (GtkWidget         *widget,
172                                                   GtkSelectionData  *selection_data,
173                                                   guint             time,
174                                                   gpointer          data);
175 \f
176 /****************************************************************************/
177 /* Boilerplate Object stuff.                                                */
178 /****************************************************************************/
179 guint
180 gl_view_get_type (void)
181 {
182         static guint view_type = 0;
183
184         if (!view_type) {
185                 GTypeInfo view_info = {
186                         sizeof (glViewClass),
187                         NULL,
188                         NULL,
189                         (GClassInitFunc) gl_view_class_init,
190                         NULL,
191                         NULL,
192                         sizeof (glView),
193                         0,
194                         (GInstanceInitFunc) gl_view_init,
195                 };
196
197                 view_type =
198                     g_type_register_static (gtk_vbox_get_type (),
199                                             "glView", &view_info, 0);
200         }
201
202         return view_type;
203 }
204
205 static void
206 gl_view_class_init (glViewClass *class)
207 {
208         GObjectClass *object_class = (GObjectClass *) class;
209
210         gl_debug (DEBUG_VIEW, "START");
211
212         parent_class = g_type_class_peek_parent (class);
213
214         object_class->finalize = gl_view_finalize;
215
216         signals[SELECTION_CHANGED] =
217                 g_signal_new ("selection_changed",
218                               G_OBJECT_CLASS_TYPE (object_class),
219                               G_SIGNAL_RUN_LAST,
220                               G_STRUCT_OFFSET (glViewClass, selection_changed),
221                               NULL, NULL,
222                               gl_marshal_VOID__VOID,
223                               G_TYPE_NONE,
224                               0);
225
226         signals[ZOOM_CHANGED] =
227                 g_signal_new ("zoom_changed",
228                               G_OBJECT_CLASS_TYPE (object_class),
229                               G_SIGNAL_RUN_LAST,
230                               G_STRUCT_OFFSET (glViewClass, zoom_changed),
231                               NULL, NULL,
232                               gl_marshal_VOID__DOUBLE,
233                               G_TYPE_NONE,
234                               1, G_TYPE_DOUBLE);
235
236         signals[POINTER_MOVED] =
237                 g_signal_new ("pointer_moved",
238                               G_OBJECT_CLASS_TYPE (object_class),
239                               G_SIGNAL_RUN_LAST,
240                               G_STRUCT_OFFSET (glViewClass, pointer_moved),
241                               NULL, NULL,
242                               gl_marshal_VOID__DOUBLE_DOUBLE,
243                               G_TYPE_NONE,
244                               2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
245
246         signals[POINTER_EXIT] =
247                 g_signal_new ("pointer_exit",
248                               G_OBJECT_CLASS_TYPE (object_class),
249                               G_SIGNAL_RUN_LAST,
250                               G_STRUCT_OFFSET (glViewClass, pointer_exit),
251                               NULL, NULL,
252                               gl_marshal_VOID__VOID,
253                               G_TYPE_NONE,
254                               0);
255
256         signals[MODE_CHANGED] =
257                 g_signal_new ("mode_changed",
258                               G_OBJECT_CLASS_TYPE (object_class),
259                               G_SIGNAL_RUN_LAST,
260                               G_STRUCT_OFFSET (glViewClass, mode_changed),
261                               NULL, NULL,
262                               gl_marshal_VOID__VOID,
263                               G_TYPE_NONE,
264                               0);
265
266         gl_debug (DEBUG_VIEW, "END");
267 }
268
269 static void
270 gl_view_init (glView *view)
271 {
272         gl_debug (DEBUG_VIEW, "START");
273
274         view->label = NULL;
275
276         view->grid_spacing = 9;
277
278         gl_debug (DEBUG_VIEW, "END");
279 }
280
281 static void
282 gl_view_finalize (GObject *object)
283 {
284         glView *view;
285
286         gl_debug (DEBUG_VIEW, "START");
287
288         g_return_if_fail (object != NULL);
289         g_return_if_fail (GL_IS_VIEW (object));
290
291         view = GL_VIEW (object);
292
293         G_OBJECT_CLASS (parent_class)->finalize (object);
294
295         gl_debug (DEBUG_VIEW, "END");
296 }
297
298 /****************************************************************************/
299 /* NEW view object.                                                         */
300 /****************************************************************************/
301 GtkWidget *
302 gl_view_new (glLabel *label)
303 {
304         glView *view = g_object_new (gl_view_get_type (), NULL);
305
306         gl_debug (DEBUG_VIEW, "START");
307
308         view->label = label;
309
310         gl_view_construct (view);
311
312         gl_debug (DEBUG_VIEW, "END");
313
314         return GTK_WIDGET (view);
315 }
316
317 /*---------------------------------------------------------------------------*/
318 /* PRIVATE.  Construct composite widget.                                     */
319 /*---------------------------------------------------------------------------*/
320 static void
321 gl_view_construct (glView *view)
322 {
323         GtkWidget *wvbox, *wscroll;
324
325         gl_debug (DEBUG_VIEW, "START");
326
327         g_return_if_fail (GL_IS_VIEW (view));
328
329         wvbox = GTK_WIDGET (view);
330
331         view->state = GL_VIEW_STATE_ARROW;
332         view->object_list = NULL;
333
334         gl_view_construct_canvas (view);
335         wscroll = gtk_scrolled_window_new (NULL, NULL);
336         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (wscroll),
337                                         GTK_POLICY_AUTOMATIC,
338                                         GTK_POLICY_AUTOMATIC);
339         gtk_box_pack_start (GTK_BOX (wvbox), wscroll, TRUE, TRUE, 0);
340         gtk_container_add (GTK_CONTAINER (wscroll), view->canvas);
341
342         gl_view_construct_selection (view);
343
344         construct_selection_menu (view);
345         construct_empty_selection_menu (view);
346
347         gl_debug (DEBUG_VIEW, "END");
348 }
349
350 /*---------------------------------------------------------------------------*/
351 /* PRIVATE.  Create canvas w/ a background in the shape of the label/card.   */
352 /*---------------------------------------------------------------------------*/
353 static GtkWidget *
354 gl_view_construct_canvas (glView *view)
355 {
356         gdouble   scale;
357         glLabel  *label = view->label;
358         gdouble   label_width, label_height;
359         GdkColor *bg_color;
360
361         gl_debug (DEBUG_VIEW, "START");
362
363         g_return_val_if_fail (GL_IS_VIEW (view), NULL);
364         g_return_val_if_fail (label != NULL, NULL);
365
366         gtk_widget_push_colormap (gdk_rgb_get_colormap ());
367         view->canvas = gnome_canvas_new_aa ();
368         gtk_widget_pop_colormap ();
369
370         bg_color = gl_color_to_gdk_color (BG_COLOR);
371         gtk_widget_modify_bg (GTK_WIDGET(view->canvas), GTK_STATE_NORMAL, bg_color);
372         g_free (bg_color);
373
374         gl_label_get_size (label, &label_width, &label_height);
375         gl_debug (DEBUG_VIEW, "Label size: w=%lf, h=%lf",
376                   label_width, label_height);
377
378         scale = get_apropriate_scale (label_width, label_height);
379         gl_debug (DEBUG_VIEW, "scale =%lf", scale);
380
381         gl_debug (DEBUG_VIEW, "Canvas size: w=%lf, h=%lf",
382                               scale * label_width + 40,
383                               scale * label_height + 40);
384         gtk_widget_set_size_request (GTK_WIDGET(view->canvas),
385                                      scale * label_width + 40,
386                                      scale * label_height + 40);
387         gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (view->canvas),
388                                           scale);
389         view->scale = scale;
390
391         gnome_canvas_set_scroll_region (GNOME_CANVAS (view->canvas),
392                                         0.0, 0.0, label_width, label_height);
393
394         draw_layers (view);
395
396         g_signal_connect (G_OBJECT (view->canvas), "event",
397                           G_CALLBACK (canvas_event), view);
398
399         gl_debug (DEBUG_VIEW, "END");
400
401         return view->canvas;
402 }
403
404 /*---------------------------------------------------------------------------*/
405 /* PRIVATE.  Create clipboard selection targets.                             */
406 /*---------------------------------------------------------------------------*/
407 static void
408 gl_view_construct_selection (glView *view)
409 {
410         gl_debug (DEBUG_VIEW, "START");
411
412         g_return_if_fail (GL_IS_VIEW (view));
413
414         view->have_selection = FALSE;
415         view->selection_data = NULL;
416         view->invisible = gtk_invisible_new ();
417
418         view->selected_object_list = NULL;
419
420         if (!clipboard_atom) {
421                 clipboard_atom = gdk_atom_intern ("GLABELS_CLIPBOARD", FALSE);
422         }
423
424         gtk_selection_add_target (view->invisible,
425                                   clipboard_atom, GDK_SELECTION_TYPE_STRING, 1);
426
427         g_signal_connect (G_OBJECT (view->invisible),
428                           "selection_clear_event",
429                           G_CALLBACK (selection_clear_cb), view);
430
431         g_signal_connect (G_OBJECT (view->invisible), "selection_get",
432                           G_CALLBACK (selection_get_cb), view);
433
434         g_signal_connect (G_OBJECT (view->invisible),
435                           "selection_received",
436                           G_CALLBACK (selection_received_cb), view);
437
438         gl_debug (DEBUG_VIEW, "END");
439 }
440
441 /*---------------------------------------------------------------------------*/
442 /* PRIVATE.  Determine an apropriate scale for given label & screen size     */
443 /*---------------------------------------------------------------------------*/
444 static gdouble
445 get_apropriate_scale (gdouble w, gdouble h)
446 {
447         gdouble w_screen, h_screen;
448         gint i;
449         gdouble k;
450
451         gl_debug (DEBUG_VIEW, "");
452
453         w_screen = (gdouble) gdk_screen_width ();
454         h_screen = (gdouble) gdk_screen_height ();
455
456         for (i = 0; i < N_SCALES; i++) {
457                 k = scales[i];
458                 if (k <= HOME_SCALE) {
459                         if ((k * w < (w_screen - 256))
460                             && (k * h < (h_screen - 256)))
461                                 return k;
462                 }
463         }
464
465         return 0.25;
466 }
467
468 /*---------------------------------------------------------------------------*/
469 /* PRIVATE.  Create, draw and order layers.                                  */
470 /*---------------------------------------------------------------------------*/
471 static void
472 draw_layers (glView *view)
473 {
474         draw_bg_fg_layers (view);
475         draw_grid_layer (view);
476         draw_markup_layer (view);
477         draw_highlight_layer (view); /* Must be done before label layer */
478         draw_label_layer (view);
479
480         gnome_canvas_item_raise_to_top (GNOME_CANVAS_ITEM(view->fg_group));
481         gnome_canvas_item_raise_to_top (GNOME_CANVAS_ITEM(view->highlight_group));
482 }
483
484 /*---------------------------------------------------------------------------*/
485 /* PRIVATE.  Draw label layer.                                               */
486 /*---------------------------------------------------------------------------*/
487 static void
488 draw_label_layer (glView *view)
489 {
490         GnomeCanvasGroup *group;
491         glLabel          *label;
492         GList            *p_obj;
493         glLabelObject    *object;
494         glViewObject     *view_object;
495
496         group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
497         view->label_group = GNOME_CANVAS_GROUP(
498                 gnome_canvas_item_new (group,
499                                        gnome_canvas_group_get_type (),
500                                        "x", 0.0,
501                                        "y", 0.0,
502                                        NULL));
503
504         label = view->label;
505
506         for (p_obj = label->objects; p_obj != NULL; p_obj = p_obj->next) {
507                 object = (glLabelObject *) p_obj->data;
508
509                 if (GL_IS_LABEL_BOX (object)) {
510                         view_object = gl_view_box_new (GL_LABEL_BOX(object),
511                                                        view);
512                 } else if (GL_IS_LABEL_ELLIPSE (object)) {
513                         view_object = gl_view_ellipse_new (GL_LABEL_ELLIPSE(object),
514                                                            view);
515                 } else if (GL_IS_LABEL_LINE (object)) {
516                         view_object = gl_view_line_new (GL_LABEL_LINE(object),
517                                                         view);
518                 } else if (GL_IS_LABEL_IMAGE (object)) {
519                         view_object = gl_view_image_new (GL_LABEL_IMAGE(object),
520                                                          view);
521                 } else if (GL_IS_LABEL_TEXT (object)) {
522                         view_object = gl_view_text_new (GL_LABEL_TEXT(object),
523                                                         view);
524                 } else if (GL_IS_LABEL_BARCODE (object)) {
525                         view_object = gl_view_barcode_new (GL_LABEL_BARCODE(object),
526                                                            view);
527                 } else {
528                         /* Should not happen! */
529                         view_object = NULL;
530                         g_warning ("Invalid label object type.");
531                 }
532         }
533 }
534
535 /*---------------------------------------------------------------------------*/
536 /* PRIVATE.  Create highlight layer.                                         */
537 /*---------------------------------------------------------------------------*/
538 static void
539 draw_highlight_layer (glView *view)
540 {
541         GnomeCanvasGroup *group;
542
543         group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
544         view->highlight_group = GNOME_CANVAS_GROUP(
545                 gnome_canvas_item_new (group,
546                                        gnome_canvas_group_get_type (),
547                                        "x", 0.0,
548                                        "y", 0.0,
549                                        NULL));
550 }
551
552 /*---------------------------------------------------------------------------*/
553 /* PRIVATE.  Draw background and foreground outlines.                        */
554 /*---------------------------------------------------------------------------*/
555 static void
556 draw_bg_fg_layers (glView *view)
557 {
558         glLabel          *label;
559         glTemplate       *template;
560         GnomeCanvasGroup *group;
561
562         group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
563         view->bg_group = GNOME_CANVAS_GROUP(
564                 gnome_canvas_item_new (group,
565                                        gnome_canvas_group_get_type (),
566                                        "x", 0.0,
567                                        "y", 0.0,
568                                        NULL));
569         view->fg_group = GNOME_CANVAS_GROUP(
570                 gnome_canvas_item_new (group,
571                                        gnome_canvas_group_get_type (),
572                                        "x", 0.0,
573                                        "y", 0.0,
574                                        NULL));
575
576         label = view->label;
577         template = gl_label_get_template (label);
578
579         switch (template->label.style) {
580
581         case GL_TEMPLATE_STYLE_RECT:
582                 if (template->label.rect.r == 0.0) {
583                         /* Square corners. */
584                         draw_bg_fg_rect (view);
585                 } else {
586                         /* Rounded corners. */
587                         draw_bg_fg_rounded_rect (view);
588                 }
589                 break;
590
591         case GL_TEMPLATE_STYLE_ROUND:
592                 draw_bg_fg_round (view);
593                 break;
594
595         case GL_TEMPLATE_STYLE_CD:
596                 draw_bg_fg_cd (view);
597                 break;
598
599         default:
600                 g_warning ("Unknown template label style");
601                 break;
602         }
603 }
604
605 /*---------------------------------------------------------------------------*/
606 /* PRIVATE.  Draw simple recangular background.                              */
607 /*---------------------------------------------------------------------------*/
608 static void
609 draw_bg_fg_rect (glView *view)
610 {
611         glLabel          *label = view->label;
612         glTemplate       *template;
613         gdouble           w, h;
614         GnomeCanvasItem  *item;
615
616         gl_debug (DEBUG_VIEW, "START");
617
618         g_return_if_fail (GL_IS_VIEW (view));
619         g_return_if_fail (label != NULL);
620
621         gl_label_get_size (label, &w, &h);
622         template = gl_label_get_template (label);
623
624         /* Background */
625         item = gnome_canvas_item_new (view->bg_group,
626                                       gnome_canvas_rect_get_type (),
627                                       "x1", 0.0,
628                                       "y1", 0.0,
629                                       "x2", w,
630                                       "y2", h,
631                                       "fill_color_rgba", PAPER_COLOR,
632                                       NULL);
633
634         /* Foreground */
635         item = gnome_canvas_item_new (view->fg_group,
636                                       gnome_canvas_rect_get_type (),
637                                       "x1", 0.0,
638                                       "y1", 0.0,
639                                       "x2", w,
640                                       "y2", h,
641                                       "width_pixels", 2,
642                                       "outline_color_rgba", OUTLINE_COLOR,
643                                       NULL);
644
645         gl_debug (DEBUG_VIEW, "END");
646 }
647
648 /*---------------------------------------------------------------------------*/
649 /* PRIVATE.  Draw rounded recangular background.                             */
650 /*---------------------------------------------------------------------------*/
651 static void
652 draw_bg_fg_rounded_rect (glView *view)
653 {
654         glLabel           *label = view->label;
655         GnomeCanvasPoints *points;
656         gint               i_coords, i_theta;
657         glTemplate        *template;
658         gdouble            r, w, h;
659         GnomeCanvasItem   *item;
660
661         gl_debug (DEBUG_VIEW, "START");
662
663         g_return_if_fail (GL_IS_VIEW (view));
664         g_return_if_fail (label != NULL);
665
666         gl_label_get_size (label, &w, &h);
667         template = gl_label_get_template (label);
668         r = template->label.rect.r;
669
670         points = gnome_canvas_points_new (4 * (1 + 90 / 5));
671         i_coords = 0;
672         for (i_theta = 0; i_theta <= 90; i_theta += 5) {
673                 points->coords[i_coords++] =
674                     r - r * sin (i_theta * G_PI / 180.0);
675                 points->coords[i_coords++] =
676                     r - r * cos (i_theta * G_PI / 180.0);
677         }
678         for (i_theta = 0; i_theta <= 90; i_theta += 5) {
679                 points->coords[i_coords++] =
680                     r - r * cos (i_theta * G_PI / 180.0);
681                 points->coords[i_coords++] =
682                     (h - r) + r * sin (i_theta * G_PI / 180.0);
683         }
684         for (i_theta = 0; i_theta <= 90; i_theta += 5) {
685                 points->coords[i_coords++] =
686                     (w - r) + r * sin (i_theta * G_PI / 180.0);
687                 points->coords[i_coords++] =
688                     (h - r) + r * cos (i_theta * G_PI / 180.0);
689         }
690         for (i_theta = 0; i_theta <= 90; i_theta += 5) {
691                 points->coords[i_coords++] =
692                     (w - r) + r * cos (i_theta * G_PI / 180.0);
693                 points->coords[i_coords++] =
694                     r - r * sin (i_theta * G_PI / 180.0);
695         }
696
697         /* Background */
698         item = gnome_canvas_item_new (view->bg_group,
699                                       gnome_canvas_polygon_get_type (),
700                                       "points", points,
701                                       "fill_color_rgba", PAPER_COLOR,
702                                       NULL);
703
704         /* Foreground */
705         item = gnome_canvas_item_new (view->fg_group,
706                                       gnome_canvas_polygon_get_type (),
707                                       "points", points,
708                                       "width_pixels", 2,
709                                       "outline_color_rgba", OUTLINE_COLOR,
710                                       NULL);
711
712         gnome_canvas_points_free (points);
713
714         gl_debug (DEBUG_VIEW, "END");
715 }
716
717 /*---------------------------------------------------------------------------*/
718 /* PRIVATE.  Draw round background.                                          */
719 /*---------------------------------------------------------------------------*/
720 static void
721 draw_bg_fg_round (glView *view)
722 {
723         glLabel          *label = view->label;
724         glTemplate       *template;
725         gdouble           r;
726         GnomeCanvasItem  *item;
727
728         gl_debug (DEBUG_VIEW, "START");
729
730         g_return_if_fail (GL_IS_VIEW (view));
731         g_return_if_fail (label != NULL);
732
733         template = gl_label_get_template (label);
734
735         r = template->label.round.r;
736
737         /* Background */
738         item = gnome_canvas_item_new (view->bg_group,
739                                       gnome_canvas_ellipse_get_type (),
740                                       "x1", 0.0,
741                                       "y1", 0.0,
742                                       "x2", 2.0*r,
743                                       "y2", 2.0*r,
744                                       "fill_color_rgba", PAPER_COLOR,
745                                       NULL);
746
747         /* Foreground */
748         item = gnome_canvas_item_new (view->fg_group,
749                                       gnome_canvas_ellipse_get_type (),
750                                       "x1", 0.0,
751                                       "y1", 0.0,
752                                       "x2", 2.0*r,
753                                       "y2", 2.0*r,
754                                       "width_pixels", 2,
755                                       "outline_color_rgba", OUTLINE_COLOR,
756                                       NULL);
757
758         gl_debug (DEBUG_VIEW, "END");
759 }
760
761 /*---------------------------------------------------------------------------*/
762 /* PRIVATE.  Draw CD style background, circular w/ concentric hole.          */
763 /*---------------------------------------------------------------------------*/
764 static void
765 draw_bg_fg_cd (glView *view)
766 {
767         glLabel          *label = view->label;
768         glTemplate       *template;
769         gdouble           r1, r2;
770         GnomeCanvasItem  *item;
771
772         gl_debug (DEBUG_VIEW, "START");
773
774         g_return_if_fail (GL_IS_VIEW (view));
775         g_return_if_fail (label != NULL);
776
777         template = gl_label_get_template (label);
778
779         r1 = template->label.cd.r1;
780         r2 = template->label.cd.r2;
781
782         /* Background */
783         /* outer circle */
784         item = gnome_canvas_item_new (view->bg_group,
785                                       gnome_canvas_ellipse_get_type (),
786                                       "x1", 0.0,
787                                       "y1", 0.0,
788                                       "x2", 2.0*r1,
789                                       "y2", 2.0*r1,
790                                       "fill_color_rgba", PAPER_COLOR,
791                                       NULL);
792         /* hole */
793         item = gnome_canvas_item_new (view->bg_group,
794                                       gnome_canvas_ellipse_get_type (),
795                                       "x1", r1 - r2,
796                                       "y1", r1 - r2,
797                                       "x2", r1 + r2,
798                                       "y2", r1 + r2,
799                                       "fill_color_rgba", GRID_COLOR,
800                                       NULL);
801
802         /* Foreground */
803         /* outer circle */
804         item = gnome_canvas_item_new (view->fg_group,
805                                       gnome_canvas_ellipse_get_type (),
806                                       "x1", 0.0,
807                                       "y1", 0.0,
808                                       "x2", 2.0*r1,
809                                       "y2", 2.0*r1,
810                                       "width_pixels", 2,
811                                       "outline_color_rgba", OUTLINE_COLOR,
812                                       NULL);
813         /* hole */
814         item = gnome_canvas_item_new (view->fg_group,
815                                       gnome_canvas_ellipse_get_type (),
816                                       "x1", r1 - r2,
817                                       "y1", r1 - r2,
818                                       "x2", r1 + r2,
819                                       "y2", r1 + r2,
820                                       "width_pixels", 2,
821                                       "outline_color_rgba", OUTLINE_COLOR,
822                                       NULL);
823
824         gl_debug (DEBUG_VIEW, "END");
825 }
826
827 /*---------------------------------------------------------------------------*/
828 /* PRIVATE.  Draw grid lines.                                                */
829 /*---------------------------------------------------------------------------*/
830 static void
831 draw_grid_layer (glView *view)
832 {
833         gdouble            w, h, x, y;
834         GnomeCanvasPoints *points;
835         GnomeCanvasItem  *item;
836         GnomeCanvasGroup *group;
837
838         gl_debug (DEBUG_VIEW, "START");
839
840         g_return_if_fail (view && GL_IS_VIEW (view));
841         g_return_if_fail (view->label && GL_IS_LABEL(view->label));
842
843         gl_label_get_size (view->label, &w, &h);
844
845         group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
846         view->grid_group = GNOME_CANVAS_GROUP(
847                 gnome_canvas_item_new (group,
848                                        gnome_canvas_group_get_type (),
849                                        "x", 0.0,
850                                        "y", 0.0,
851                                        NULL));
852         points = gnome_canvas_points_new (2);
853
854         points->coords[1] = 0.0;
855         points->coords[3] = h;
856         for ( x=0.0; x < w; x += view->grid_spacing ) {
857                 points->coords[0] = points->coords[2] = x;
858                 item = gnome_canvas_item_new (view->grid_group,
859                                               gnome_canvas_line_get_type (),
860                                               "points", points,
861                                               "width_pixels", 1,
862                                               "fill_color_rgba", GRID_COLOR,
863                                               NULL);
864         }
865         points->coords[0] = points->coords[2] = w;
866         item = gnome_canvas_item_new (view->grid_group,
867                                       gnome_canvas_line_get_type (),
868                                       "points", points,
869                                       "width_pixels", 1,
870                                       "fill_color_rgba", GRID_COLOR,
871                                       NULL);
872
873         points->coords[0] = 0.0;
874         points->coords[2] = w;
875         for ( y=0.0; y < h; y += view->grid_spacing ) {
876                 points->coords[1] = points->coords[3] = y;
877                 item = gnome_canvas_item_new (view->grid_group,
878                                               gnome_canvas_line_get_type (),
879                                               "points", points,
880                                               "width_pixels", 1,
881                                               "fill_color_rgba", GRID_COLOR,
882                                               NULL);
883         }
884         points->coords[1] = points->coords[3] = h;
885         item = gnome_canvas_item_new (view->grid_group,
886                                       gnome_canvas_line_get_type (),
887                                       "points", points,
888                                       "width_pixels", 1,
889                                       "fill_color_rgba", GRID_COLOR,
890                                       NULL);
891
892         gnome_canvas_points_free (points);
893
894         gl_debug (DEBUG_VIEW, "END");
895 }
896
897 /*---------------------------------------------------------------------------*/
898 /* PRIVATE.  Draw markup lines.                                              */
899 /*---------------------------------------------------------------------------*/
900 static void
901 draw_markup_layer (glView *view)
902 {
903         GnomeCanvasGroup *group;
904         glLabel          *label;
905         glTemplate       *template;
906         GList            *p;
907         glTemplateMarkup *markup;
908
909         group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
910         view->markup_group = GNOME_CANVAS_GROUP(
911                 gnome_canvas_item_new (group,
912                                        gnome_canvas_group_get_type (),
913                                        "x", 0.0,
914                                        "y", 0.0,
915                                        NULL));
916         label = view->label;
917         template = gl_label_get_template (label);
918
919         for ( p=template->label.any.markups; p != NULL; p=p->next ) {
920                 markup = (glTemplateMarkup *)p->data;
921
922                 switch (markup->type) {
923                 case GL_TEMPLATE_MARKUP_MARGIN:
924                         draw_markup_margin (view,
925                                             (glTemplateMarkupMargin *)markup);
926                         break;
927                 case GL_TEMPLATE_MARKUP_LINE:
928                         draw_markup_line (view,
929                                           (glTemplateMarkupLine *)markup);
930                         break;
931                 default:
932                         g_warning ("Unknown template markup type");
933                         break;
934                 }
935         }
936 }
937
938 /*---------------------------------------------------------------------------*/
939 /* PRIVATE.  Draw margin markup.                                             */
940 /*---------------------------------------------------------------------------*/
941 static void
942 draw_markup_margin (glView                 *view,
943                     glTemplateMarkupMargin *margin)
944 {
945         glLabel    *label;
946         glTemplate *template;
947
948         label = view->label;
949         template = gl_label_get_template (label);
950
951         switch (template->label.style) {
952
953         case GL_TEMPLATE_STYLE_RECT:
954                 if (template->label.rect.r == 0.0) {
955                         /* Square corners. */
956                         draw_markup_margin_rect (view, margin);
957                 } else {
958                         if ( margin->size < template->label.rect.r) {
959                                 /* Rounded corners. */
960                                 draw_markup_margin_rounded_rect (view, margin);
961                         } else {
962                                 /* Square corners. */
963                                 draw_markup_margin_rect (view, margin);
964                         }
965                 }
966                 break;
967
968         case GL_TEMPLATE_STYLE_ROUND:
969                 draw_markup_margin_round (view, margin);
970                 break;
971
972         case GL_TEMPLATE_STYLE_CD:
973                 draw_markup_margin_cd (view, margin);
974                 break;
975
976         default:
977                 g_warning ("Unknown template label style");
978                 break;
979         }
980 }
981
982 /*---------------------------------------------------------------------------*/
983 /* PRIVATE.  Draw simple recangular margin.                                  */
984 /*---------------------------------------------------------------------------*/
985 static void
986 draw_markup_margin_rect (glView                 *view,
987                          glTemplateMarkupMargin *margin)
988 {
989         glLabel          *label = view->label;
990         glTemplate       *template;
991         gdouble           w, h, m;
992         GnomeCanvasItem  *item;
993
994         gl_debug (DEBUG_VIEW, "START");
995
996         g_return_if_fail (GL_IS_VIEW (view));
997         g_return_if_fail (label != NULL);
998
999         gl_label_get_size (label, &w, &h);
1000         template = gl_label_get_template (label);
1001         m = margin->size;
1002
1003         /* Bounding box @ margin */
1004         gnome_canvas_item_new (view->markup_group,
1005                                gnome_canvas_rect_get_type (),
1006                                "x1", m,
1007                                "y1", m,
1008                                "x2", w - m,
1009                                "y2", h - m,
1010                                "width_pixels", 1,
1011                                "outline_color_rgba", MARKUP_COLOR,
1012                                NULL);
1013
1014         gl_debug (DEBUG_VIEW, "END");
1015 }
1016
1017 /*---------------------------------------------------------------------------*/
1018 /* PRIVATE.  Draw rounded recangular markup.                                 */
1019 /*---------------------------------------------------------------------------*/
1020 static void
1021 draw_markup_margin_rounded_rect (glView                 *view,
1022                                  glTemplateMarkupMargin *margin)
1023 {
1024         glLabel           *label = view->label;
1025         GnomeCanvasPoints *points;
1026         gint               i_coords, i_theta;
1027         glTemplate        *template;
1028         gdouble            r, w, h, m;
1029         GnomeCanvasItem   *item;
1030
1031         gl_debug (DEBUG_VIEW, "START");
1032
1033         g_return_if_fail (GL_IS_VIEW (view));
1034         g_return_if_fail (label != NULL);
1035
1036         gl_label_get_size (label, &w, &h);
1037         template = gl_label_get_template (label);
1038         r = template->label.rect.r;
1039         m = margin->size;
1040
1041         r = r - m;
1042         w = w - 2 * m;
1043         h = h - 2 * m;
1044
1045         /* rectangle with rounded corners */
1046         points = gnome_canvas_points_new (4 * (1 + 90 / 5));
1047         i_coords = 0;
1048         for (i_theta = 0; i_theta <= 90; i_theta += 5) {
1049                 points->coords[i_coords++] =
1050                         m + r - r * sin (i_theta * G_PI / 180.0);
1051                 points->coords[i_coords++] =
1052                         m + r - r * cos (i_theta * G_PI / 180.0);
1053         }
1054         for (i_theta = 0; i_theta <= 90; i_theta += 5) {
1055                 points->coords[i_coords++] =
1056                         m + r - r * cos (i_theta * G_PI / 180.0);
1057                 points->coords[i_coords++] =
1058                         m + (h - r) + r * sin (i_theta * G_PI / 180.0);
1059         }
1060         for (i_theta = 0; i_theta <= 90; i_theta += 5) {
1061                 points->coords[i_coords++] =
1062                         m + (w - r) + r * sin (i_theta * G_PI / 180.0);
1063                 points->coords[i_coords++] =
1064                         m + (h - r) + r * cos (i_theta * G_PI / 180.0);
1065         }
1066         for (i_theta = 0; i_theta <= 90; i_theta += 5) {
1067                 points->coords[i_coords++] =
1068                         m + (w - r) + r * cos (i_theta * G_PI / 180.0);
1069                 points->coords[i_coords++] =
1070                         m + r - r * sin (i_theta * G_PI / 180.0);
1071         }
1072         item = gnome_canvas_item_new (view->markup_group,
1073                                       gnome_canvas_polygon_get_type (),
1074                                       "points", points,
1075                                       "width_pixels", 1,
1076                                       "outline_color_rgba", MARKUP_COLOR,
1077                                       NULL);
1078         gnome_canvas_points_free (points);
1079
1080         gl_debug (DEBUG_VIEW, "END");
1081 }
1082
1083 /*---------------------------------------------------------------------------*/
1084 /* PRIVATE.  Draw round margin.                                              */
1085 /*---------------------------------------------------------------------------*/
1086 static void
1087 draw_markup_margin_round (glView                 *view,
1088                           glTemplateMarkupMargin *margin)
1089 {
1090         glLabel          *label = view->label;
1091         glTemplate       *template;
1092         gdouble           r, m;
1093         GnomeCanvasItem  *item;
1094
1095         gl_debug (DEBUG_VIEW, "START");
1096
1097         g_return_if_fail (GL_IS_VIEW (view));
1098         g_return_if_fail (label != NULL);
1099
1100         template = gl_label_get_template (label);
1101
1102         r = template->label.round.r;
1103         m = margin->size;
1104
1105         /* Margin outline */
1106         item = gnome_canvas_item_new (view->markup_group,
1107                                       gnome_canvas_ellipse_get_type (),
1108                                       "x1", m,
1109                                       "y1", m,
1110                                       "x2", 2.0*r - m,
1111                                       "y2", 2.0*r - m,
1112                                       "width_pixels", 1,
1113                                       "outline_color_rgba", MARKUP_COLOR,
1114                                       NULL);
1115
1116         gl_debug (DEBUG_VIEW, "END");
1117 }
1118
1119 /*---------------------------------------------------------------------------*/
1120 /* PRIVATE.  Draw CD margins.                                                */
1121 /*---------------------------------------------------------------------------*/
1122 static void
1123 draw_markup_margin_cd (glView                 *view,
1124                        glTemplateMarkupMargin *margin)
1125 {
1126         glLabel          *label = view->label;
1127         glTemplate       *template;
1128         gdouble           m, r1, r2;
1129         GnomeCanvasItem  *item;
1130
1131         gl_debug (DEBUG_VIEW, "START");
1132
1133         g_return_if_fail (GL_IS_VIEW (view));
1134         g_return_if_fail (label != NULL);
1135
1136         template = gl_label_get_template (label);
1137
1138         r1 = template->label.cd.r1;
1139         r2 = template->label.cd.r2;
1140         m  = margin->size;
1141
1142         /* outer margin */
1143         item = gnome_canvas_item_new (view->markup_group,
1144                                       gnome_canvas_ellipse_get_type (),
1145                                       "x1", m,
1146                                       "y1", m,
1147                                       "x2", 2.0*r1 - m,
1148                                       "y2", 2.0*r1 - m,
1149                                       "width_pixels", 1,
1150                                       "outline_color_rgba", MARKUP_COLOR,
1151                                       NULL);
1152         /* inner margin */
1153         item = gnome_canvas_item_new (view->markup_group,
1154                                       gnome_canvas_ellipse_get_type (),
1155                                       "x1", r1 - r2 - m,
1156                                       "y1", r1 - r2 - m,
1157                                       "x2", r1 + r2 + m,
1158                                       "y2", r1 + r2 + m,
1159                                       "width_pixels", 1,
1160                                       "outline_color_rgba", MARKUP_COLOR,
1161                                       NULL);
1162
1163         gl_debug (DEBUG_VIEW, "END");
1164 }
1165
1166 /*---------------------------------------------------------------------------*/
1167 /* PRIVATE.  Draw line markup.                                               */
1168 /*---------------------------------------------------------------------------*/
1169 static void
1170 draw_markup_line (glView               *view,
1171                   glTemplateMarkupLine *line)
1172 {
1173         GnomeCanvasPoints *points;
1174
1175         gl_debug (DEBUG_VIEW, "START");
1176
1177         g_return_if_fail (GL_IS_VIEW (view));
1178
1179         points = gnome_canvas_points_new (2);
1180         points->coords[0] = line->x1;
1181         points->coords[1] = line->y1;
1182         points->coords[2] = line->x2;
1183         points->coords[3] = line->y2;
1184
1185         /* Bounding box @ margin */
1186         gnome_canvas_item_new (view->markup_group,
1187                                gnome_canvas_line_get_type (),
1188                                "points", points,
1189                                "width_pixels", 1,
1190                                "fill_color_rgba", MARKUP_COLOR,
1191                                NULL);
1192
1193         gnome_canvas_points_free (points);
1194
1195         gl_debug (DEBUG_VIEW, "END");
1196 }
1197
1198 /*****************************************************************************/
1199 /* Show grid.                                                                */
1200 /*****************************************************************************/
1201 void       gl_view_show_grid               (glView            *view)
1202 {
1203         gnome_canvas_item_show (GNOME_CANVAS_ITEM(view->grid_group));
1204 }
1205
1206 /*****************************************************************************/
1207 /* Hide grid.                                                                */
1208 /*****************************************************************************/
1209 void       gl_view_hide_grid               (glView            *view)
1210 {
1211         gnome_canvas_item_hide (GNOME_CANVAS_ITEM(view->grid_group));
1212 }
1213
1214 /*****************************************************************************/
1215 /* Set grid spacing.                                                         */
1216 /*****************************************************************************/
1217 void       gl_view_set_grid_spacing        (glView            *view,
1218                                             gdouble            spacing)
1219 {
1220         view->grid_spacing = spacing;
1221
1222         gtk_object_destroy (GTK_OBJECT(view->grid_group));
1223         draw_grid_layer (view);
1224 }
1225
1226 /*****************************************************************************/
1227 /* Show markup.                                                              */
1228 /*****************************************************************************/
1229 void       gl_view_show_markup             (glView            *view)
1230 {
1231         gnome_canvas_item_show (GNOME_CANVAS_ITEM(view->markup_group));
1232 }
1233
1234 /*****************************************************************************/
1235 /* Hide markup.                                                              */
1236 /*****************************************************************************/
1237 void       gl_view_hide_markup             (glView            *view)
1238 {
1239         gnome_canvas_item_hide (GNOME_CANVAS_ITEM(view->markup_group));
1240 }
1241
1242 /*****************************************************************************/
1243 /* Set arrow mode.                                                           */
1244 /*****************************************************************************/
1245 void
1246 gl_view_arrow_mode (glView *view)
1247 {
1248         static GdkCursor *cursor = NULL;
1249
1250         gl_debug (DEBUG_VIEW, "START");
1251
1252         g_return_if_fail (GL_IS_VIEW (view));
1253
1254         if (!cursor) {
1255                 cursor = gdk_cursor_new (GDK_LEFT_PTR);
1256         }
1257
1258         gdk_window_set_cursor (view->canvas->window, cursor);
1259
1260         view->state = GL_VIEW_STATE_ARROW;
1261
1262         gl_debug (DEBUG_VIEW, "END");
1263 }
1264
1265 /*****************************************************************************/
1266 /* Set create text object mode.                                              */
1267 /*****************************************************************************/
1268 void
1269 gl_view_object_create_mode (glView            *view,
1270                             glLabelObjectType type)
1271 {
1272         GdkCursor *cursor;
1273
1274         gl_debug (DEBUG_VIEW, "START");
1275
1276         g_return_if_fail (GL_IS_VIEW (view));
1277
1278         switch (type) {
1279         case GL_LABEL_OBJECT_BOX:
1280                 cursor = gl_view_box_get_create_cursor ();
1281                 break;
1282         case GL_LABEL_OBJECT_ELLIPSE:
1283                 cursor = gl_view_ellipse_get_create_cursor ();
1284                 break;
1285         case GL_LABEL_OBJECT_LINE:
1286                 cursor = gl_view_line_get_create_cursor ();
1287                 break;
1288         case GL_LABEL_OBJECT_IMAGE:
1289                 cursor = gl_view_image_get_create_cursor ();
1290                 break;
1291         case GL_LABEL_OBJECT_TEXT:
1292                 cursor = gl_view_text_get_create_cursor ();
1293                 break;
1294         case GL_LABEL_OBJECT_BARCODE:
1295                 cursor = gl_view_barcode_get_create_cursor ();
1296                 break;
1297         default:
1298                 g_warning ("Invalid label object type.");/*Should not happen!*/
1299                 break;
1300         }
1301
1302         gdk_window_set_cursor (view->canvas->window, cursor);
1303
1304         view->state = GL_VIEW_STATE_OBJECT_CREATE;
1305         view->create_type = type;
1306
1307         gl_debug (DEBUG_VIEW, "END");
1308 }
1309
1310 /*****************************************************************************/
1311 /* Select given object (adding to current selection).                        */
1312 /*****************************************************************************/
1313 void
1314 gl_view_select_object (glView       *view,
1315                        glViewObject *view_object)
1316 {
1317         gl_debug (DEBUG_VIEW, "START");
1318
1319         select_object_real (view, view_object);
1320
1321         g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
1322
1323         gl_debug (DEBUG_VIEW, "END");
1324 }
1325
1326 /*****************************************************************************/
1327 /* Unselect given object (removing from current selection).                  */
1328 /*****************************************************************************/
1329 void
1330 gl_view_unselect_object (glView       *view,
1331                          glViewObject *view_object)
1332 {
1333         gl_debug (DEBUG_VIEW, "START");
1334
1335         unselect_object_real (view, view_object);
1336
1337         g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
1338
1339         gl_debug (DEBUG_VIEW, "END");
1340 }
1341
1342 /*****************************************************************************/
1343 /* Select all items.                                                         */
1344 /*****************************************************************************/
1345 void
1346 gl_view_select_all (glView *view)
1347 {
1348         GList *p, *p_next;
1349
1350         gl_debug (DEBUG_VIEW, "START");
1351
1352         g_return_if_fail (GL_IS_VIEW (view));
1353
1354         /* 1st unselect anything already selected. */
1355         for (p = view->selected_object_list; p != NULL; p = p_next) {
1356                 p_next = p->next;
1357                 unselect_object_real (view, GL_VIEW_OBJECT (p->data));
1358         }
1359
1360         /* Finally select all objects. */
1361         for (p = view->object_list; p != NULL; p = p->next) {
1362                 select_object_real (view, GL_VIEW_OBJECT (p->data));
1363         }
1364
1365         g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
1366
1367         gl_debug (DEBUG_VIEW, "END");
1368 }
1369
1370 /*****************************************************************************/
1371 /* Remove all selections                                                     */
1372 /*****************************************************************************/
1373 void
1374 gl_view_unselect_all (glView *view)
1375 {
1376         GList *p, *p_next;
1377
1378         gl_debug (DEBUG_VIEW, "START");
1379
1380         g_return_if_fail (GL_IS_VIEW (view));
1381
1382         for (p = view->selected_object_list; p != NULL; p = p_next) {
1383                 p_next = p->next;
1384                 unselect_object_real (view, GL_VIEW_OBJECT (p->data));
1385         }
1386
1387         g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
1388
1389         gl_debug (DEBUG_VIEW, "END");
1390 }
1391
1392 /*****************************************************************************/
1393 /* Select all objects within given rectangular region (adding to selection). */
1394 /*****************************************************************************/
1395 void
1396 gl_view_select_region (glView  *view,
1397                        gdouble  x1,
1398                        gdouble  y1,
1399                        gdouble  x2,
1400                        gdouble  y2)
1401 {
1402         GList *p;
1403         glViewObject *view_object;
1404         glLabelObject *object;
1405         gdouble i_x1, i_y1, i_x2, i_y2;
1406
1407         gl_debug (DEBUG_VIEW, "START");
1408
1409         g_return_if_fail (GL_IS_VIEW (view));
1410         g_return_if_fail ((x1 <= x2) && (y1 <= y2));
1411
1412         for (p = view->object_list; p != NULL; p = p->next) {
1413                 view_object = GL_VIEW_OBJECT(p->data);
1414                 if (!gl_view_is_object_selected (view, view_object)) {
1415
1416                         object = gl_view_object_get_object (view_object);
1417
1418                         gl_label_object_get_extent (object, &i_x1, &i_y1, &i_x2, &i_y2);
1419                         if ((i_x1 >= x1) && (i_x2 <= x2) && (i_y1 >= y1)
1420                             && (i_y2 <= y2)) {
1421                                 select_object_real (view, view_object);
1422                         }
1423
1424                 }
1425         }
1426
1427         g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
1428
1429         gl_debug (DEBUG_VIEW, "END");
1430 }
1431
1432 /*---------------------------------------------------------------------------*/
1433 /* PRIVATE. Select an object.                                                */
1434 /*---------------------------------------------------------------------------*/
1435 static void
1436 select_object_real (glView       *view,
1437                     glViewObject *view_object)
1438 {
1439         gl_debug (DEBUG_VIEW, "START");
1440
1441         g_return_if_fail (GL_IS_VIEW (view));
1442         g_return_if_fail (GL_IS_VIEW_OBJECT (view_object));
1443
1444         if (!gl_view_is_object_selected (view, view_object)) {
1445                 view->selected_object_list =
1446                     g_list_prepend (view->selected_object_list, view_object);
1447         }
1448         gl_view_object_show_highlight (view_object);
1449         gtk_widget_grab_focus (GTK_WIDGET (view->canvas));
1450
1451         gl_debug (DEBUG_VIEW, "END");
1452 }
1453
1454 /*---------------------------------------------------------------------------*/
1455 /* PRIVATE.  Un-select object.                                               */
1456 /*---------------------------------------------------------------------------*/
1457 static void
1458 unselect_object_real (glView       *view,
1459                       glViewObject *view_object)
1460 {
1461         gl_debug (DEBUG_VIEW, "START");
1462
1463         g_return_if_fail (GL_IS_VIEW (view));
1464         g_return_if_fail (GL_IS_VIEW_OBJECT (view_object));
1465
1466         gl_view_object_hide_highlight (view_object);
1467
1468         view->selected_object_list =
1469             g_list_remove (view->selected_object_list, view_object);
1470
1471         gl_debug (DEBUG_VIEW, "END");
1472 }
1473
1474 /*---------------------------------------------------------------------------*/
1475 /* PRIVATE. Return object at (x,y).                                          */
1476 /*---------------------------------------------------------------------------*/
1477 static gboolean
1478 object_at (glView  *view,
1479            gdouble  x,
1480            gdouble  y)
1481 {
1482         GnomeCanvasItem *item, *p_item;
1483         GList *p;
1484
1485         gl_debug (DEBUG_VIEW, "");
1486
1487         g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
1488
1489         item = gnome_canvas_get_item_at (GNOME_CANVAS (view->canvas), x, y);
1490
1491         /* No item is at x, y */
1492         if (item == NULL)
1493                 return FALSE;
1494
1495         /* ignore items not in label or highlight layers, e.g. background items */
1496         if (!is_item_member_of_group(view, item, GNOME_CANVAS_ITEM(view->label_group)) &&
1497             !is_item_member_of_group(view, item, GNOME_CANVAS_ITEM(view->highlight_group)))
1498                 return FALSE;
1499
1500         return TRUE;
1501 }
1502
1503 /*---------------------------------------------------------------------------*/
1504 /* PRIVATE.  Is the item a child (or grandchild, etc.) of group.             */
1505 /*---------------------------------------------------------------------------*/
1506 static gboolean
1507 is_item_member_of_group (glView          *view,
1508                          GnomeCanvasItem *item,
1509                          GnomeCanvasItem *group)
1510 {
1511         GnomeCanvasItem *parent;
1512         GnomeCanvasItem *root_group;
1513
1514         root_group = GNOME_CANVAS_ITEM(gnome_canvas_root (GNOME_CANVAS (view->canvas)));
1515
1516         for ( parent=item->parent; parent && (parent!=root_group); parent=parent->parent) {
1517                 if (parent == group) return TRUE;
1518         }
1519         return FALSE;
1520 }
1521
1522 /*****************************************************************************/
1523 /* Is the object in our current selection?                                   */
1524 /*****************************************************************************/
1525 gboolean
1526 gl_view_is_object_selected (glView       *view,
1527                     glViewObject *view_object)
1528 {
1529         gl_debug (DEBUG_VIEW, "");
1530
1531         g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
1532         g_return_val_if_fail (GL_IS_VIEW_OBJECT (view_object), FALSE);
1533
1534         if (g_list_find (view->selected_object_list, view_object) == NULL) {
1535                 return FALSE;
1536         }
1537         return TRUE;
1538 }
1539
1540 /*****************************************************************************/
1541 /* Is our current selection empty?                                           */
1542 /*****************************************************************************/
1543 gboolean
1544 gl_view_is_selection_empty (glView *view)
1545 {
1546         gl_debug (DEBUG_VIEW, "");
1547
1548         g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
1549
1550         if (view->selected_object_list == NULL) {
1551                 return TRUE;
1552         } else {
1553                 return FALSE;
1554         }
1555 }
1556
1557 /*****************************************************************************/
1558 /* Is our current selection atomic?  I.e. only one item selected.            */
1559 /*****************************************************************************/
1560 gboolean
1561 gl_view_is_selection_atomic (glView *view)
1562 {
1563         gl_debug (DEBUG_VIEW, "");
1564
1565         g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
1566
1567         if (view->selected_object_list == NULL)
1568                 return FALSE;
1569         if (view->selected_object_list->next == NULL)
1570                 return TRUE;
1571         return FALSE;
1572 }
1573
1574 /*****************************************************************************/
1575 /* Delete selected objects. (Bypass clipboard)                               */
1576 /*****************************************************************************/
1577 void
1578 gl_view_delete_selection (glView *view)
1579 {
1580         GList *p, *p_next;
1581
1582         gl_debug (DEBUG_VIEW, "START");
1583
1584         g_return_if_fail (GL_IS_VIEW (view));
1585
1586         for (p = view->selected_object_list; p != NULL; p = p_next) {
1587                 p_next = p->next;
1588                 g_object_unref (G_OBJECT (p->data));
1589         }
1590
1591         g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
1592
1593         gl_debug (DEBUG_VIEW, "END");
1594 }
1595
1596 /*****************************************************************************/
1597 /* Edit properties of selected object.                                       */
1598 /*****************************************************************************/
1599 void
1600 gl_view_edit_object_props (glView *view)
1601 {
1602         glViewObject *view_object;
1603
1604         gl_debug (DEBUG_VIEW, "START");
1605
1606         g_return_if_fail (GL_IS_VIEW (view));
1607
1608         if (gl_view_is_selection_atomic (view)) {
1609
1610                 view_object = GL_VIEW_OBJECT(view->selected_object_list->data);
1611                 gl_view_object_show_dialog (view_object);
1612
1613         }
1614
1615         gl_debug (DEBUG_VIEW, "END");
1616 }
1617
1618 /*****************************************************************************/
1619 /* Raise selected items to top.                                              */
1620 /*****************************************************************************/
1621 void
1622 gl_view_raise_selection (glView *view)
1623 {
1624         GList         *p;
1625         glViewObject  *view_object;
1626         glLabelObject *object;
1627
1628         gl_debug (DEBUG_VIEW, "START");
1629
1630         g_return_if_fail (GL_IS_VIEW (view));
1631
1632         for (p = view->selected_object_list; p != NULL; p = p->next) {
1633                 view_object = GL_VIEW_OBJECT (p->data);
1634                 object = gl_view_object_get_object (view_object);
1635                 gl_label_object_raise_to_top (object);
1636         }
1637
1638         gl_debug (DEBUG_VIEW, "END");
1639 }
1640
1641 /*****************************************************************************/
1642 /* Lower selected items to bottom.                                           */
1643 /*****************************************************************************/
1644 void
1645 gl_view_lower_selection (glView *view)
1646 {
1647         GList         *p;
1648         glViewObject  *view_object;
1649         glLabelObject *object;
1650
1651         gl_debug (DEBUG_VIEW, "START");
1652
1653         g_return_if_fail (GL_IS_VIEW (view));
1654
1655         for (p = view->selected_object_list; p != NULL; p = p->next) {
1656                 view_object = GL_VIEW_OBJECT (p->data);
1657                 object = gl_view_object_get_object (view_object);
1658                 gl_label_object_lower_to_bottom (object);
1659         }
1660
1661         gl_debug (DEBUG_VIEW, "END");
1662 }
1663
1664 /*****************************************************************************/
1665 /* Rotate selected objects by given angle.                                   */
1666 /*****************************************************************************/
1667 void
1668 gl_view_rotate_selection (glView *view,
1669                           gdouble theta_degs)
1670 {
1671         GList         *p;
1672         glViewObject  *view_object;
1673         glLabelObject *object;
1674
1675         gl_debug (DEBUG_VIEW, "START");
1676
1677         g_return_if_fail (GL_IS_VIEW (view));
1678
1679         for (p = view->selected_object_list; p != NULL; p = p->next) {
1680                 view_object = GL_VIEW_OBJECT (p->data);
1681                 object = gl_view_object_get_object (view_object);
1682                 gl_label_object_rotate (object, theta_degs);
1683         }
1684
1685         gl_debug (DEBUG_VIEW, "END");
1686 }
1687
1688 /*****************************************************************************/
1689 /* Rotate selected objects 90 degrees left.                                  */
1690 /*****************************************************************************/
1691 void
1692 gl_view_rotate_selection_left (glView *view)
1693 {
1694         GList         *p;
1695         glViewObject  *view_object;
1696         glLabelObject *object;
1697
1698         gl_debug (DEBUG_VIEW, "START");
1699
1700         g_return_if_fail (GL_IS_VIEW (view));
1701
1702         for (p = view->selected_object_list; p != NULL; p = p->next) {
1703                 view_object = GL_VIEW_OBJECT (p->data);
1704                 object = gl_view_object_get_object (view_object);
1705                 gl_label_object_rotate (object, -90.0);
1706         }
1707
1708         gl_debug (DEBUG_VIEW, "END");
1709 }
1710
1711 /*****************************************************************************/
1712 /* Rotate selected objects 90 degrees right.                                 */
1713 /*****************************************************************************/
1714 void
1715 gl_view_rotate_selection_right (glView *view)
1716 {
1717         GList         *p;
1718         glViewObject  *view_object;
1719         glLabelObject *object;
1720
1721         gl_debug (DEBUG_VIEW, "START");
1722
1723         g_return_if_fail (GL_IS_VIEW (view));
1724
1725         for (p = view->selected_object_list; p != NULL; p = p->next) {
1726                 view_object = GL_VIEW_OBJECT (p->data);
1727                 object = gl_view_object_get_object (view_object);
1728                 gl_label_object_rotate (object, 90.0);
1729         }
1730
1731         gl_debug (DEBUG_VIEW, "END");
1732 }
1733
1734 /*****************************************************************************/
1735 /* Flip selected objects horizontally.                                       */
1736 /*****************************************************************************/
1737 void
1738 gl_view_flip_selection_horiz (glView *view)
1739 {
1740         GList         *p;
1741         glViewObject  *view_object;
1742         glLabelObject *object;
1743
1744         gl_debug (DEBUG_VIEW, "START");
1745
1746         g_return_if_fail (GL_IS_VIEW (view));
1747
1748         for (p = view->selected_object_list; p != NULL; p = p->next) {
1749                 view_object = GL_VIEW_OBJECT (p->data);
1750                 object = gl_view_object_get_object (view_object);
1751                 gl_label_object_flip_horiz (object);
1752         }
1753
1754         gl_debug (DEBUG_VIEW, "END");
1755 }
1756
1757 /*****************************************************************************/
1758 /* Flip selected objects vertically.                                         */
1759 /*****************************************************************************/
1760 void
1761 gl_view_flip_selection_vert (glView *view)
1762 {
1763         GList         *p;
1764         glViewObject  *view_object;
1765         glLabelObject *object;
1766
1767         gl_debug (DEBUG_VIEW, "START");
1768
1769         g_return_if_fail (GL_IS_VIEW (view));
1770
1771         for (p = view->selected_object_list; p != NULL; p = p->next) {
1772                 view_object = GL_VIEW_OBJECT (p->data);
1773                 object = gl_view_object_get_object (view_object);
1774                 gl_label_object_flip_vert (object);
1775         }
1776
1777         gl_debug (DEBUG_VIEW, "END");
1778 }
1779
1780 /*****************************************************************************/
1781 /* Align selected objects to left most edge.                                 */
1782 /*****************************************************************************/
1783 void
1784 gl_view_align_selection_left (glView *view)
1785 {
1786         GList         *p;
1787         glViewObject  *view_object;
1788         glLabelObject *object;
1789         gdouble        dx, x1min, x1, y1, x2, y2;
1790
1791         gl_debug (DEBUG_VIEW, "START");
1792
1793         g_return_if_fail (GL_IS_VIEW (view));
1794
1795         g_return_if_fail (!gl_view_is_selection_empty (view) &&
1796                           !gl_view_is_selection_atomic (view));
1797
1798         /* find left most edge */
1799         p = view->selected_object_list;
1800         view_object = GL_VIEW_OBJECT (p->data);
1801         object = gl_view_object_get_object (view_object);
1802         gl_label_object_get_extent (object, &x1min, &y1, &x2, &y2);
1803         for (p = p->next; p != NULL; p = p->next) {
1804                 view_object = GL_VIEW_OBJECT (p->data);
1805                 object = gl_view_object_get_object (view_object);
1806                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
1807                 if ( x1 < x1min ) x1min = x1;
1808         }
1809
1810         /* now adjust the object positions to line up the left edges */
1811         for (p = view->selected_object_list; p != NULL; p = p->next) {
1812                 view_object = GL_VIEW_OBJECT (p->data);
1813                 object = gl_view_object_get_object (view_object);
1814                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
1815                 dx = x1min - x1;
1816                 gl_label_object_set_position_relative (object, dx, 0.0);
1817         }
1818
1819         gl_debug (DEBUG_VIEW, "END");
1820 }
1821
1822
1823 /*****************************************************************************/
1824 /* Align selected objects to right most edge.                                */
1825 /*****************************************************************************/
1826 void
1827 gl_view_align_selection_right (glView *view)
1828 {
1829         GList         *p;
1830         glViewObject  *view_object;
1831         glLabelObject *object;
1832         gdouble        dx, x2max, x1, y1, x2, y2;
1833
1834         gl_debug (DEBUG_VIEW, "START");
1835
1836         g_return_if_fail (GL_IS_VIEW (view));
1837
1838         g_return_if_fail (!gl_view_is_selection_empty (view) &&
1839                           !gl_view_is_selection_atomic (view));
1840
1841         /* find right most edge */
1842         p = view->selected_object_list;
1843         view_object = GL_VIEW_OBJECT (p->data);
1844         object = gl_view_object_get_object (view_object);
1845         gl_label_object_get_extent (object, &x1, &y1, &x2max, &y2);
1846         for (p = p->next; p != NULL; p = p->next) {
1847                 view_object = GL_VIEW_OBJECT (p->data);
1848                 object = gl_view_object_get_object (view_object);
1849                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
1850                 if ( x2 > x2max ) x2max = x2;
1851         }
1852
1853         /* now adjust the object positions to line up the right edges */
1854         for (p = view->selected_object_list; p != NULL; p = p->next) {
1855                 view_object = GL_VIEW_OBJECT (p->data);
1856                 object = gl_view_object_get_object (view_object);
1857                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
1858                 dx = x2max - x2;
1859                 gl_label_object_set_position_relative (object, dx, 0.0);
1860         }
1861
1862         gl_debug (DEBUG_VIEW, "END");
1863 }
1864
1865 /*****************************************************************************/
1866 /* Align selected objects to horizontal center of objects.                   */
1867 /*****************************************************************************/
1868 void
1869 gl_view_align_selection_hcenter (glView *view)
1870 {
1871         GList         *p;
1872         glViewObject  *view_object;
1873         glLabelObject *object;
1874         gdouble        dx, dxmin, xsum, xavg, xcenter, x1, y1, x2, y2;
1875         gint           n;
1876
1877         gl_debug (DEBUG_VIEW, "START");
1878
1879         g_return_if_fail (GL_IS_VIEW (view));
1880
1881         g_return_if_fail (!gl_view_is_selection_empty (view) &&
1882                           !gl_view_is_selection_atomic (view));
1883
1884         /* find average center of objects */
1885         xsum = 0.0;
1886         n = 0;
1887         for (p = view->selected_object_list; p != NULL; p = p->next) {
1888                 view_object = GL_VIEW_OBJECT (p->data);
1889                 object = gl_view_object_get_object (view_object);
1890                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
1891                 xsum += (x1 + x2) / 2.0;
1892                 n++;
1893         }
1894         xavg = xsum / n;
1895
1896         /* find center of object closest to average center */
1897         p = view->selected_object_list;
1898         view_object = GL_VIEW_OBJECT (p->data);
1899         object = gl_view_object_get_object (view_object);
1900         gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
1901         dxmin = fabs (xavg - (x1 + x2)/2.0);
1902         xcenter = (x1 + x2)/2.0;
1903         for (p = p->next; p != NULL; p = p->next) {
1904                 view_object = GL_VIEW_OBJECT (p->data);
1905                 object = gl_view_object_get_object (view_object);
1906                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
1907                 dx = fabs (xavg - (x1 + x2)/2.0);
1908                 if ( dx < dxmin ) {
1909                         dxmin = dx;
1910                         xcenter = (x1 + x2)/2.0;
1911                 }
1912         }
1913
1914         /* now adjust the object positions to line up this center */
1915         for (p = view->selected_object_list; p != NULL; p = p->next) {
1916                 view_object = GL_VIEW_OBJECT (p->data);
1917                 object = gl_view_object_get_object (view_object);
1918                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
1919                 dx = xcenter - (x1 + x2)/2.0;
1920                 gl_label_object_set_position_relative (object, dx, 0.0);
1921         }
1922
1923         gl_debug (DEBUG_VIEW, "END");
1924 }
1925
1926 /*****************************************************************************/
1927 /* Align selected objects to top most edge.                                  */
1928 /*****************************************************************************/
1929 void
1930 gl_view_align_selection_top (glView *view)
1931 {
1932         GList         *p;
1933         glViewObject  *view_object;
1934         glLabelObject *object;
1935         gdouble        dy, y1min, x1, y1, x2, y2;
1936
1937         gl_debug (DEBUG_VIEW, "START");
1938
1939         g_return_if_fail (GL_IS_VIEW (view));
1940
1941         g_return_if_fail (!gl_view_is_selection_empty (view) &&
1942                           !gl_view_is_selection_atomic (view));
1943
1944         /* find top most edge */
1945         p = view->selected_object_list;
1946         view_object = GL_VIEW_OBJECT (p->data);
1947         object = gl_view_object_get_object (view_object);
1948         gl_label_object_get_extent (object, &x1, &y1min, &x2, &y2);
1949         for (p = p->next; p != NULL; p = p->next) {
1950                 view_object = GL_VIEW_OBJECT (p->data);
1951                 object = gl_view_object_get_object (view_object);
1952                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
1953                 if ( y1 < y1min ) y1min = y1;
1954         }
1955
1956         /* now adjust the object positions to line up the top edges */
1957         for (p = view->selected_object_list; p != NULL; p = p->next) {
1958                 view_object = GL_VIEW_OBJECT (p->data);
1959                 object = gl_view_object_get_object (view_object);
1960                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
1961                 dy = y1min - y1;
1962                 gl_label_object_set_position_relative (object, 0.0, dy);
1963         }
1964
1965         gl_debug (DEBUG_VIEW, "END");
1966 }
1967
1968 /*****************************************************************************/
1969 /* Align selected objects to bottom most edge.                               */
1970 /*****************************************************************************/
1971 void
1972 gl_view_align_selection_bottom (glView *view)
1973 {
1974         GList         *p;
1975         glViewObject  *view_object;
1976         glLabelObject *object;
1977         gdouble        dy, y2max, x1, y1, x2, y2;
1978
1979         gl_debug (DEBUG_VIEW, "START");
1980
1981         g_return_if_fail (GL_IS_VIEW (view));
1982
1983         g_return_if_fail (!gl_view_is_selection_empty (view) &&
1984                           !gl_view_is_selection_atomic (view));
1985
1986         /* find bottom most edge */
1987         p = view->selected_object_list;
1988         view_object = GL_VIEW_OBJECT (p->data);
1989         object = gl_view_object_get_object (view_object);
1990         gl_label_object_get_extent (object, &x1, &y1, &x2, &y2max);
1991         for (p = p->next; p != NULL; p = p->next) {
1992                 view_object = GL_VIEW_OBJECT (p->data);
1993                 object = gl_view_object_get_object (view_object);
1994                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
1995                 if ( y2 > y2max ) y2max = y2;
1996         }
1997
1998         /* now adjust the object positions to line up the bottom edges */
1999         for (p = view->selected_object_list; p != NULL; p = p->next) {
2000                 view_object = GL_VIEW_OBJECT (p->data);
2001                 object = gl_view_object_get_object (view_object);
2002                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2003                 dy = y2max - y2;
2004                 gl_label_object_set_position_relative (object, 0.0, dy);
2005         }
2006
2007         gl_debug (DEBUG_VIEW, "END");
2008 }
2009
2010 /*****************************************************************************/
2011 /* Align selected objects to viertical center of objects.                    */
2012 /*****************************************************************************/
2013 void
2014 gl_view_align_selection_vcenter (glView *view)
2015 {
2016         GList         *p;
2017         glViewObject  *view_object;
2018         glLabelObject *object;
2019         gdouble        dy, dymin, ysum, yavg, ycenter, x1, y1, x2, y2;
2020         gint           n;
2021
2022         gl_debug (DEBUG_VIEW, "START");
2023
2024         g_return_if_fail (GL_IS_VIEW (view));
2025
2026         g_return_if_fail (!gl_view_is_selection_empty (view) &&
2027                           !gl_view_is_selection_atomic (view));
2028
2029         /* find average center of objects */
2030         ysum = 0.0;
2031         n = 0;
2032         for (p = view->selected_object_list; p != NULL; p = p->next) {
2033                 view_object = GL_VIEW_OBJECT (p->data);
2034                 object = gl_view_object_get_object (view_object);
2035                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2036                 ysum += (y1 + y2) / 2.0;
2037                 n++;
2038         }
2039         yavg = ysum / n;
2040
2041         /* find center of object closest to average center */
2042         p = view->selected_object_list;
2043         view_object = GL_VIEW_OBJECT (p->data);
2044         object = gl_view_object_get_object (view_object);
2045         gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2046         dymin = fabs (yavg - (y1 + y2)/2.0);
2047         ycenter = (y1 + y2)/2.0;
2048         for (p = p->next; p != NULL; p = p->next) {
2049                 view_object = GL_VIEW_OBJECT (p->data);
2050                 object = gl_view_object_get_object (view_object);
2051                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2052                 dy = fabs (yavg - (y1 + y2)/2.0);
2053                 if ( dy < dymin ) {
2054                         dymin = dy;
2055                         ycenter = (y1 + y2)/2.0;
2056                 }
2057         }
2058
2059         /* now adjust the object positions to line up this center */
2060         for (p = view->selected_object_list; p != NULL; p = p->next) {
2061                 view_object = GL_VIEW_OBJECT (p->data);
2062                 object = gl_view_object_get_object (view_object);
2063                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2064                 dy = ycenter - (y1 + y2)/2.0;
2065                 gl_label_object_set_position_relative (object, 0.0, dy);
2066         }
2067
2068         gl_debug (DEBUG_VIEW, "END");
2069 }
2070
2071 /*****************************************************************************/
2072 /* Center selected objects to in center of label.                            */
2073 /*****************************************************************************/
2074 void
2075 gl_view_center_selection_horiz (glView *view)
2076 {
2077         GList         *p;
2078         glViewObject  *view_object;
2079         glLabelObject *object;
2080         gdouble        dx, x_label_center, x_obj_center, x1, y1, x2, y2, w, h;
2081
2082         gl_debug (DEBUG_VIEW, "START");
2083
2084         g_return_if_fail (GL_IS_VIEW (view));
2085
2086         g_return_if_fail (!gl_view_is_selection_empty (view));
2087
2088         gl_label_get_size (view->label, &w, &h);
2089         x_label_center = w / 2.0;
2090
2091         /* adjust the object positions */
2092         for (p = view->selected_object_list; p != NULL; p = p->next) {
2093                 view_object = GL_VIEW_OBJECT (p->data);
2094                 object = gl_view_object_get_object (view_object);
2095                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2096                 x_obj_center = (x1 + x2) / 2.0;
2097                 dx = x_label_center - x_obj_center;
2098                 gl_label_object_set_position_relative (object, dx, 0.0);
2099         }
2100
2101         gl_debug (DEBUG_VIEW, "END");
2102 }
2103
2104
2105 /*****************************************************************************/
2106 /* Center selected objects to in center of label.                            */
2107 /*****************************************************************************/
2108 void
2109 gl_view_center_selection_vert (glView *view)
2110 {
2111         GList         *p;
2112         glViewObject  *view_object;
2113         glLabelObject *object;
2114         gdouble        dy, y_label_center, y_obj_center, x1, y1, x2, y2, w, h;
2115
2116         gl_debug (DEBUG_VIEW, "START");
2117
2118         g_return_if_fail (GL_IS_VIEW (view));
2119
2120         g_return_if_fail (!gl_view_is_selection_empty (view));
2121
2122         gl_label_get_size (view->label, &w, &h);
2123         y_label_center = h / 2.0;
2124
2125         /* adjust the object positions */
2126         for (p = view->selected_object_list; p != NULL; p = p->next) {
2127                 view_object = GL_VIEW_OBJECT (p->data);
2128                 object = gl_view_object_get_object (view_object);
2129                 gl_label_object_get_extent (object, &x1, &y1, &x2, &y2);
2130                 y_obj_center = (y1 + y2) / 2.0;
2131                 dy = y_label_center - y_obj_center;
2132                 gl_label_object_set_position_relative (object, 0.0, dy);
2133         }
2134
2135         gl_debug (DEBUG_VIEW, "END");
2136 }
2137
2138
2139 /*****************************************************************************/
2140 /* Move selected objects                                                     */
2141 /*****************************************************************************/
2142 void
2143 gl_view_move_selection (glView  *view,
2144                 gdouble  dx,
2145                 gdouble  dy)
2146 {
2147         GList *p;
2148         glLabelObject *object;
2149
2150         gl_debug (DEBUG_VIEW, "START");
2151
2152         g_return_if_fail (view && GL_IS_VIEW (view));
2153
2154         for (p = view->selected_object_list; p != NULL; p = p->next) {
2155
2156                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2157                 gl_label_object_set_position_relative (object, dx, dy);
2158
2159         }
2160
2161         gl_debug (DEBUG_VIEW, "END");
2162 }
2163
2164 /*****************************************************************************/
2165 /* "Cut" selected items and place in clipboard selections.                   */
2166 /*****************************************************************************/
2167 void
2168 gl_view_cut (glView *view)
2169 {
2170         gl_debug (DEBUG_VIEW, "START");
2171
2172         g_return_if_fail (GL_IS_VIEW (view));
2173
2174         gl_view_copy (view);
2175         gl_view_delete_selection (view);
2176
2177         gl_debug (DEBUG_VIEW, "END");
2178 }
2179
2180 /*****************************************************************************/
2181 /* "Copy" selected items to clipboard selections.                            */
2182 /*****************************************************************************/
2183 void
2184 gl_view_copy (glView *view)
2185 {
2186         GList *p;
2187         glViewObject *view_object;
2188         glLabelObject *object;
2189         glTemplate *template;
2190         gboolean rotate_flag;
2191
2192         gl_debug (DEBUG_VIEW, "START");
2193
2194         g_return_if_fail (GL_IS_VIEW (view));
2195
2196         if (view->selected_object_list) {
2197
2198                 if ( view->selection_data ) {
2199                         g_object_unref (view->selection_data);
2200                 }
2201                 template = gl_label_get_template (view->label);
2202                 rotate_flag = gl_label_get_rotate_flag (view->label);
2203                 view->selection_data = GL_LABEL(gl_label_new ());
2204                 gl_label_set_template (view->selection_data, template);
2205                 gl_label_set_rotate_flag (view->selection_data, rotate_flag);
2206                 gl_template_free (&template);
2207
2208                 for (p = view->selected_object_list; p != NULL; p = p->next) {
2209
2210                         view_object = GL_VIEW_OBJECT (p->data);
2211                         object = gl_view_object_get_object (view_object);
2212
2213                         gl_label_object_dup (object, view->selection_data);
2214
2215                 }
2216
2217                 gtk_selection_owner_set (view->invisible,
2218                                          clipboard_atom, GDK_CURRENT_TIME);
2219                 view->have_selection = TRUE;
2220
2221         }
2222
2223         gl_debug (DEBUG_VIEW, "END");
2224 }
2225
2226 /*****************************************************************************/
2227 /* "Paste" from private clipboard selection.                                 */
2228 /*****************************************************************************/
2229 void
2230 gl_view_paste (glView *view)
2231 {
2232         gl_debug (DEBUG_VIEW, "START");
2233
2234         g_return_if_fail (GL_IS_VIEW (view));
2235
2236         gtk_selection_convert (GTK_WIDGET (view->invisible),
2237                                clipboard_atom, GDK_SELECTION_TYPE_STRING,
2238                                GDK_CURRENT_TIME);
2239
2240         gl_debug (DEBUG_VIEW, "END");
2241 }
2242
2243 /*****************************************************************************/
2244 /* Zoom in one "notch"                                                       */
2245 /*****************************************************************************/
2246 void
2247 gl_view_zoom_in (glView *view)
2248 {
2249         gint i, i_min;
2250         gdouble dist, dist_min;
2251
2252         gl_debug (DEBUG_VIEW, "START");
2253
2254         g_return_if_fail (GL_IS_VIEW (view));
2255
2256         /* Find index of current scale (or best match) */
2257         i_min = 1;              /* start with 2nd largest scale */
2258         dist_min = fabs (scales[1] - view->scale);
2259         for (i = 2; i < N_SCALES; i++) {
2260                 dist = fabs (scales[i] - view->scale);
2261                 if (dist < dist_min) {
2262                         i_min = i;
2263                         dist_min = dist;
2264                 }
2265         }
2266
2267         /* zoom in one "notch" */
2268         i = MAX (0, i_min - 1);
2269         gl_view_set_zoom (view, scales[i] / HOME_SCALE);
2270
2271         gl_debug (DEBUG_VIEW, "END");
2272 }
2273
2274 /*****************************************************************************/
2275 /* Zoom out one "notch"                                                      */
2276 /*****************************************************************************/
2277 void
2278 gl_view_zoom_out (glView *view)
2279 {
2280         gint i, i_min;
2281         gdouble dist, dist_min;
2282
2283         gl_debug (DEBUG_VIEW, "START");
2284
2285         g_return_if_fail (GL_IS_VIEW (view));
2286
2287         /* Find index of current scale (or best match) */
2288         i_min = 0;              /* start with largest scale */
2289         dist_min = fabs (scales[0] - view->scale);
2290         for (i = 1; i < N_SCALES; i++) {
2291                 dist = fabs (scales[i] - view->scale);
2292                 if (dist < dist_min) {
2293                         i_min = i;
2294                         dist_min = dist;
2295                 }
2296         }
2297
2298         /* zoom out one "notch" */
2299         if (i_min >= N_SCALES)
2300                 return;
2301         i = i_min + 1;
2302         if (i >= N_SCALES)
2303                 return;
2304         gl_view_set_zoom (view, scales[i] / HOME_SCALE);
2305
2306         gl_debug (DEBUG_VIEW, "END");
2307 }
2308
2309 /*****************************************************************************/
2310 /* Set current zoom factor to explicit value.                                */
2311 /*****************************************************************************/
2312 void
2313 gl_view_set_zoom (glView  *view,
2314                   gdouble scale)
2315 {
2316         gl_debug (DEBUG_VIEW, "START");
2317
2318         g_return_if_fail (GL_IS_VIEW (view));
2319         g_return_if_fail (scale > 0.0);
2320
2321         view->scale = scale * HOME_SCALE;
2322         gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (view->canvas),
2323                                           scale * HOME_SCALE);
2324
2325         g_signal_emit (G_OBJECT(view), signals[ZOOM_CHANGED], 0, scale);
2326
2327         gl_debug (DEBUG_VIEW, "END");
2328 }
2329
2330 /*****************************************************************************/
2331 /* Get current zoom factor.                                                  */
2332 /*****************************************************************************/
2333 gdouble
2334 gl_view_get_zoom (glView *view)
2335 {
2336         gl_debug (DEBUG_VIEW, "");
2337
2338         g_return_val_if_fail (GL_IS_VIEW (view), 1.0);
2339
2340         return view->scale / HOME_SCALE;
2341 }
2342
2343 /*****************************************************************************/
2344 /* Is this the maximum zoom level.                                           */
2345 /*****************************************************************************/
2346 gboolean
2347 gl_view_is_zoom_max (glView *view)
2348 {
2349         gl_debug (DEBUG_VIEW, "");
2350
2351         g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
2352
2353         return view->scale >= scales[0];
2354 }
2355
2356 /*****************************************************************************/
2357 /* Is this the minimum zoom level.                                           */
2358 /*****************************************************************************/
2359 gboolean
2360 gl_view_is_zoom_min (glView *view)
2361 {
2362         gl_debug (DEBUG_VIEW, "");
2363
2364         g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
2365
2366         return view->scale <= scales[N_SCALES-1];
2367 }
2368
2369 /*****************************************************************************/
2370 /* Launch merge properties dialog.                                           */
2371 /*****************************************************************************/
2372 void
2373 gl_view_edit_merge_props (glView *view)
2374 {
2375         gl_debug (DEBUG_VIEW, "");
2376
2377         g_return_if_fail (GL_IS_VIEW (view));
2378
2379         if (view->merge_props_dialog != NULL) {
2380                 gtk_widget_show_all (view->merge_props_dialog);
2381                 gtk_window_present (GTK_WINDOW(view->merge_props_dialog));
2382                 return;
2383         }
2384
2385         view->merge_props_dialog = gl_merge_properties_dialog_new (view);
2386         gtk_widget_show_all (view->merge_props_dialog);
2387
2388         g_signal_connect (G_OBJECT(view->merge_props_dialog), "destroy",
2389                           G_CALLBACK (gtk_widget_destroyed),
2390                           &view->merge_props_dialog);
2391 }
2392
2393 /*---------------------------------------------------------------------------*/
2394 /* PRIVATE.  Canvas event handler.                                           */
2395 /*---------------------------------------------------------------------------*/
2396 static int
2397 canvas_event (GnomeCanvas *canvas,
2398               GdkEvent    *event,
2399               glView      *view)
2400 {
2401         gdouble x, y;
2402
2403         gl_debug (DEBUG_VIEW, "");
2404
2405         /* emit pointer signals regardless of state */
2406         switch (event->type) {
2407         case GDK_MOTION_NOTIFY:
2408                 gl_debug (DEBUG_VIEW, "MOTION_NOTIFY");
2409                 gnome_canvas_window_to_world (canvas,
2410                                               event->motion.x,
2411                                               event->motion.y, &x, &y);
2412                 g_signal_emit (G_OBJECT(view), signals[POINTER_MOVED], 0, x, y);
2413                 break; /* fall through */
2414
2415         case GDK_LEAVE_NOTIFY:
2416                 gl_debug (DEBUG_VIEW, "LEAVEW_NOTIFY");
2417                 g_signal_emit (G_OBJECT(view), signals[POINTER_EXIT], 0);
2418                 break; /* fall through */
2419
2420         default:
2421                 break; /* fall through */
2422         }
2423
2424
2425         switch (view->state) {
2426
2427         case GL_VIEW_STATE_ARROW:
2428                 return canvas_event_arrow_mode (canvas, event, view);
2429
2430         case GL_VIEW_STATE_OBJECT_CREATE:
2431                 switch (view->create_type) {
2432                 case GL_LABEL_OBJECT_BOX:
2433                         return gl_view_box_create_event_handler (canvas,
2434                                                                  event,
2435                                                                  view);
2436                         break;
2437                 case GL_LABEL_OBJECT_ELLIPSE:
2438                         return gl_view_ellipse_create_event_handler (canvas,
2439                                                                      event,
2440                                                                      view);
2441                         break;
2442                 case GL_LABEL_OBJECT_LINE:
2443                         return gl_view_line_create_event_handler (canvas,
2444                                                                   event,
2445                                                                   view);
2446                         break;
2447                 case GL_LABEL_OBJECT_IMAGE:
2448                         return gl_view_image_create_event_handler (canvas,
2449                                                                    event,
2450                                                                    view);
2451                         break;
2452                 case GL_LABEL_OBJECT_TEXT:
2453                         return gl_view_text_create_event_handler (canvas,
2454                                                                   event,
2455                                                                   view);
2456                         break;
2457                 case GL_LABEL_OBJECT_BARCODE:
2458                         return gl_view_barcode_create_event_handler (canvas,
2459                                                                      event,
2460                                                                      view);
2461                         break;
2462                 default:
2463                         /*Should not happen!*/
2464                         g_warning ("Invalid label object type.");
2465                         return FALSE;
2466         }
2467
2468         default:
2469                 g_warning ("Invalid view state.");      /*Should not happen!*/
2470                 return FALSE;
2471
2472         }
2473 }
2474
2475 /*---------------------------------------------------------------------------*/
2476 /* PRIVATE.  Canvas event handler (arrow mode)                               */
2477 /*---------------------------------------------------------------------------*/
2478 static int
2479 canvas_event_arrow_mode (GnomeCanvas *canvas,
2480                          GdkEvent    *event,
2481                          glView      *view)
2482 {
2483         static gdouble x0, y0;
2484         static gboolean dragging = FALSE;
2485         static GnomeCanvasItem *item;
2486         gdouble x, y, x1, y1, x2, y2;
2487         GnomeCanvasGroup *group;
2488         GdkCursor *cursor;
2489
2490         gl_debug (DEBUG_VIEW, "");
2491
2492         switch (event->type) {
2493
2494         case GDK_BUTTON_PRESS:
2495                 gl_debug (DEBUG_VIEW, "BUTTON_PRESS");
2496                 switch (event->button.button) {
2497                 case 1:
2498                         gnome_canvas_window_to_world (canvas,
2499                                                       event->button.x,
2500                                                       event->button.y, &x, &y);
2501
2502                         if (!object_at (view, x, y)) {
2503                                 if (!(event->button.state & GDK_CONTROL_MASK)) {
2504                                         gl_view_unselect_all (view);
2505                                 }
2506
2507                                 dragging = TRUE;
2508                                 gnome_canvas_item_grab (canvas->root,
2509                                                         GDK_POINTER_MOTION_MASK |
2510                                                         GDK_BUTTON_RELEASE_MASK |
2511                                                         GDK_BUTTON_PRESS_MASK,
2512                                                         NULL, event->button.time);
2513                                 group =
2514                                     gnome_canvas_root (GNOME_CANVAS
2515                                                        (view->canvas));
2516                                 item =
2517                                     gnome_canvas_item_new (group,
2518                                                            gnome_canvas_rect_get_type (),
2519                                                            "x1", x, "y1", y,
2520                                                            "x2", x, "y2", y,
2521                                                            "width_pixels", 2,
2522                                                            "outline_color_rgba",
2523                                                            SEL_LINE_COLOR,
2524                                                            "fill_color_rgba",
2525                                                            SEL_FILL_COLOR,
2526                                                            NULL);
2527                                 x0 = x;
2528                                 y0 = y;
2529
2530                         }
2531                         return FALSE;
2532                 case 3:
2533                         gnome_canvas_window_to_world (canvas,
2534                                                       event->button.x,
2535                                                       event->button.y, &x, &y);
2536
2537                         if (!object_at (view, x, y)) {
2538                                 /* bring up apropriate menu for selection. */
2539                                 gl_view_popup_menu (view, event);
2540                         }
2541                         return FALSE;
2542                 default:
2543                         return FALSE;
2544                 }
2545
2546         case GDK_BUTTON_RELEASE:
2547                 gl_debug (DEBUG_VIEW, "BUTTON_RELEASE");
2548                 switch (event->button.button) {
2549                 case 1:
2550                         if (dragging) {
2551                                 dragging = FALSE;
2552                                 gnome_canvas_item_ungrab (canvas->root,
2553                                                           event->button.time);
2554                                 gnome_canvas_window_to_world (canvas,
2555                                                               event->button.x,
2556                                                               event->button.y,
2557                                                               &x, &y);
2558                                 x1 = MIN (x, x0);
2559                                 y1 = MIN (y, y0);
2560                                 x2 = MAX (x, x0);
2561                                 y2 = MAX (y, y0);
2562                                 gl_view_select_region (view, x1, y1, x2, y2);
2563                                 gtk_object_destroy (GTK_OBJECT (item));
2564                                 return TRUE;
2565                         }
2566                         return FALSE;
2567
2568                 default:
2569                         return FALSE;
2570                 }
2571
2572         case GDK_MOTION_NOTIFY:
2573                 gl_debug (DEBUG_VIEW, "MOTION_NOTIFY");
2574                 gnome_canvas_window_to_world (canvas,
2575                                               event->motion.x,
2576                                               event->motion.y, &x, &y);
2577                 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
2578                         gnome_canvas_item_set (item,
2579                                                "x1", MIN (x, x0),
2580                                                "y1", MIN (y, y0),
2581                                                "x2", MAX (x, x0),
2582                                                "y2", MAX (y, y0), NULL);
2583                         return TRUE;
2584                 } else {
2585                         return FALSE;
2586                 }
2587
2588         case GDK_KEY_PRESS:
2589                 gl_debug (DEBUG_VIEW, "KEY_PRESS");
2590                 if (!dragging) {
2591                         switch (event->key.keyval) {
2592                         case GDK_Left:
2593                         case GDK_KP_Left:
2594                                 gl_view_move_selection (view,
2595                                                         -1.0 / (view->scale), 0.0);
2596                                 break;
2597                         case GDK_Up:
2598                         case GDK_KP_Up:
2599                                 gl_view_move_selection (view,
2600                                                         0.0, -1.0 / (view->scale));
2601                                 break;
2602                         case GDK_Right:
2603                         case GDK_KP_Right:
2604                                 gl_view_move_selection (view,
2605                                                         1.0 / (view->scale), 0.0);
2606                                 break;
2607                         case GDK_Down:
2608                         case GDK_KP_Down:
2609                                 gl_view_move_selection (view,
2610                                                         0.0, 1.0 / (view->scale));
2611                                 break;
2612                         case GDK_Delete:
2613                         case GDK_KP_Delete:
2614                                 gl_view_delete_selection (view);
2615                                 cursor = gdk_cursor_new (GDK_LEFT_PTR);
2616                                 gdk_window_set_cursor (view->canvas->window,
2617                                                        cursor);
2618                                 gdk_cursor_unref (cursor);
2619                                 break;
2620                         default:
2621                                 return FALSE;
2622                         }
2623                 }
2624                 return TRUE;    /* We handled this or we were dragging. */
2625
2626         default:
2627                 gl_debug (DEBUG_VIEW, "default");
2628                 return FALSE;
2629         }
2630
2631 }
2632
2633 /*---------------------------------------------------------------------------*/
2634 /* PRIVATE.  create menu for selections.                                     */
2635 /*---------------------------------------------------------------------------*/
2636 void
2637 construct_selection_menu (glView *view)
2638 {
2639         GtkWidget *menu, *menuitem, *submenu;
2640
2641         gl_debug (DEBUG_VIEW, "START");
2642
2643         g_return_if_fail (GL_IS_VIEW (view));
2644
2645         menu = gtk_menu_new ();
2646
2647         menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_PROPERTIES, NULL);
2648         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
2649         gtk_widget_show (menuitem);
2650         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2651                                   G_CALLBACK (gl_view_edit_object_props), view);
2652         view->atomic_selection_items =
2653                 g_list_prepend (view->atomic_selection_items, menuitem);
2654
2655         /*
2656          * Separator -------------------------
2657          */
2658         menuitem = gtk_menu_item_new ();
2659         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
2660         gtk_widget_show (menuitem);
2661
2662         /*
2663          * Submenu: Order
2664          */
2665         menuitem = gtk_menu_item_new_with_mnemonic (_("_Order"));
2666         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
2667         gtk_widget_show (menuitem);
2668         submenu = gtk_menu_new ();
2669         gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
2670
2671         menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ORDER_TOP, NULL);
2672         gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
2673         gtk_widget_show (menuitem);
2674         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2675                                   G_CALLBACK (gl_view_raise_selection), view);
2676
2677         menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ORDER_BOTTOM, NULL);
2678         gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
2679         gtk_widget_show (menuitem);
2680         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2681                                   G_CALLBACK (gl_view_lower_selection), view);
2682
2683         /*
2684          * Submenu: Rotate/Flip
2685          */
2686         menuitem = gtk_menu_item_new_with_mnemonic (_("_Rotate/Flip"));
2687         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
2688         gtk_widget_show (menuitem);
2689         submenu = gtk_menu_new ();
2690         gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
2691
2692         menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ROTATE_LEFT, NULL);
2693         gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
2694         gtk_widget_show (menuitem);
2695         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2696                                   G_CALLBACK (gl_view_rotate_selection_left), view);
2697
2698         menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ROTATE_RIGHT, NULL);
2699         gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
2700         gtk_widget_show (menuitem);
2701         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2702                                   G_CALLBACK (gl_view_rotate_selection_right), view);
2703
2704         menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_FLIP_HORIZ, NULL);
2705         gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
2706         gtk_widget_show (menuitem);
2707         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2708                                   G_CALLBACK (gl_view_flip_selection_horiz), view);
2709
2710         menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_FLIP_VERT, NULL);
2711         gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
2712         gtk_widget_show (menuitem);
2713         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2714                                   G_CALLBACK (gl_view_flip_selection_vert), view);
2715
2716         /*
2717          * Submenu: Align Horizontally
2718          */
2719         menuitem = gtk_menu_item_new_with_mnemonic (_("Align _Horizontally"));
2720         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
2721         gtk_widget_show (menuitem);
2722         submenu = gtk_menu_new ();
2723         gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
2724
2725         menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ALIGN_LEFT, NULL);
2726         gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
2727         gtk_widget_show (menuitem);
2728         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2729                                   G_CALLBACK (gl_view_align_selection_left), view);
2730         view->multi_selection_items =
2731                 g_list_prepend (view->multi_selection_items, menuitem);
2732
2733         menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ALIGN_HCENTER, NULL);
2734         gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
2735         gtk_widget_show (menuitem);
2736         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2737                                   G_CALLBACK (gl_view_align_selection_hcenter), view);
2738         view->multi_selection_items =
2739                 g_list_prepend (view->multi_selection_items, menuitem);
2740
2741         menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ALIGN_RIGHT, NULL);
2742         gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
2743         gtk_widget_show (menuitem);
2744         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2745                                   G_CALLBACK (gl_view_align_selection_right), view);
2746         view->multi_selection_items =
2747                 g_list_prepend (view->multi_selection_items, menuitem);
2748
2749         menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_CENTER_HORIZ, NULL);
2750         gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
2751         gtk_widget_show (menuitem);
2752         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2753                                   G_CALLBACK (gl_view_center_selection_horiz), view);
2754
2755         /*
2756          * Submenu: Align Vertically
2757          */
2758         menuitem = gtk_menu_item_new_with_mnemonic (_("Align _Vertically"));
2759         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
2760         gtk_widget_show (menuitem);
2761         submenu = gtk_menu_new ();
2762         gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
2763
2764         menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ALIGN_TOP, NULL);
2765         gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
2766         gtk_widget_show (menuitem);
2767         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2768                                   G_CALLBACK (gl_view_align_selection_top), view);
2769         view->multi_selection_items =
2770                 g_list_prepend (view->multi_selection_items, menuitem);
2771
2772         menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ALIGN_VCENTER, NULL);
2773         gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
2774         gtk_widget_show (menuitem);
2775         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2776                                   G_CALLBACK (gl_view_align_selection_vcenter), view);
2777         view->multi_selection_items =
2778                 g_list_prepend (view->multi_selection_items, menuitem);
2779
2780         menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_ALIGN_BOTTOM, NULL);
2781         gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
2782         gtk_widget_show (menuitem);
2783         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2784                                   G_CALLBACK (gl_view_align_selection_bottom), view);
2785         view->multi_selection_items =
2786                 g_list_prepend (view->multi_selection_items, menuitem);
2787
2788         menuitem = gtk_image_menu_item_new_from_stock (GL_STOCK_CENTER_VERT, NULL);
2789         gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
2790         gtk_widget_show (menuitem);
2791         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2792                                   G_CALLBACK (gl_view_center_selection_vert), view);
2793
2794         /*
2795          * Separator -------------------------
2796          */
2797         menuitem = gtk_menu_item_new ();
2798         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
2799         gtk_widget_show (menuitem);
2800
2801         menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_CUT, NULL);
2802         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
2803         gtk_widget_show (menuitem);
2804         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2805                                   G_CALLBACK (gl_view_cut), view);
2806
2807         menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_COPY, NULL);
2808         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
2809         gtk_widget_show (menuitem);
2810         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2811                                   G_CALLBACK (gl_view_copy), view);
2812
2813         menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_PASTE, NULL);
2814         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
2815         gtk_widget_show (menuitem);
2816         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2817                                   G_CALLBACK (gl_view_paste), view);
2818
2819         menuitem = gtk_menu_item_new_with_mnemonic (_("_Delete"));
2820         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
2821         gtk_widget_show (menuitem);
2822         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2823                                   G_CALLBACK (gl_view_delete_selection), view);
2824
2825
2826         view->selection_menu = menu;
2827
2828         gl_debug (DEBUG_VIEW, "END");
2829 }
2830
2831 /*---------------------------------------------------------------------------*/
2832 /* PRIVATE.  create menu for empty selections.                               */
2833 /*---------------------------------------------------------------------------*/
2834 void
2835 construct_empty_selection_menu (glView *view)
2836 {
2837         GtkWidget *menu, *menuitem, *submenu;
2838
2839         gl_debug (DEBUG_VIEW, "START");
2840
2841         g_return_if_fail (GL_IS_VIEW (view));
2842
2843         menu = gtk_menu_new ();
2844
2845         menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_PASTE, NULL);
2846         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
2847         gtk_widget_show (menuitem);
2848         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
2849                                   G_CALLBACK (gl_view_paste), view);
2850
2851
2852         view->empty_selection_menu = menu;
2853
2854         gl_debug (DEBUG_VIEW, "END");
2855 }
2856
2857 /****************************************************************************/
2858 /* popup menu.                                                              */
2859 /****************************************************************************/
2860 void
2861 gl_view_popup_menu (glView       *view,
2862                     GdkEvent     *event)
2863 {
2864         GtkMenu *menu;
2865         GList   *p;
2866
2867         gl_debug (DEBUG_VIEW, "START");
2868
2869         g_return_if_fail (GL_IS_VIEW (view));
2870
2871         if (gl_view_is_selection_empty (view)) {
2872
2873                 if (view->empty_selection_menu != NULL) {
2874                         gtk_menu_popup (GTK_MENU (view->empty_selection_menu),
2875                                         NULL, NULL, NULL, NULL,
2876                                         event->button.button,
2877                                         event->button.time);
2878                 }
2879
2880         } else {
2881
2882                 for (p=view->atomic_selection_items; p!=NULL; p=p->next) {
2883                         gtk_widget_set_sensitive (GTK_WIDGET(p->data),
2884                                                   gl_view_is_selection_atomic(view));
2885                 }
2886
2887                 for (p=view->multi_selection_items; p!=NULL; p=p->next) {
2888                         gtk_widget_set_sensitive (GTK_WIDGET(p->data),
2889                                                   !gl_view_is_selection_atomic(view));
2890                 }
2891
2892                 if (view->selection_menu != NULL) {
2893                         gtk_menu_popup (GTK_MENU (view->selection_menu),
2894                                         NULL, NULL, NULL, NULL,
2895                                         event->button.button,
2896                                         event->button.time);
2897                 }
2898
2899         }
2900
2901         gl_debug (DEBUG_VIEW, "END");
2902 }
2903
2904 /*---------------------------------------------------------------------------*/
2905 /* PRIVATE.  Handle "selection-clear" signal.                                */
2906 /*---------------------------------------------------------------------------*/
2907 static void
2908 selection_clear_cb (GtkWidget         *widget,
2909                     GdkEventSelection *event,
2910                     gpointer          data)
2911 {
2912         glView *view = GL_VIEW (data);
2913
2914         gl_debug (DEBUG_VIEW, "START");
2915
2916         g_return_if_fail (GL_IS_VIEW (view));
2917
2918         view->have_selection = FALSE;
2919         g_object_unref (view->selection_data);
2920         view->selection_data = NULL;
2921
2922         gl_debug (DEBUG_VIEW, "END");
2923 }
2924
2925 /*---------------------------------------------------------------------------*/
2926 /* PRIVATE.  Handle "selection-get" signal.                                  */
2927 /*---------------------------------------------------------------------------*/
2928 static void
2929 selection_get_cb (GtkWidget        *widget,
2930                   GtkSelectionData *selection_data,
2931                   guint            info,
2932                   guint            time,
2933                   gpointer         data)
2934 {
2935         glView *view = GL_VIEW (data);
2936         gchar *buffer;
2937         glXMLLabelStatus status;
2938
2939         gl_debug (DEBUG_VIEW, "START");
2940
2941         g_return_if_fail (GL_IS_VIEW (view));
2942
2943         if (view->have_selection) {
2944
2945                 buffer = gl_xml_label_save_buffer (view->selection_data,
2946                                                    &status);
2947                 gtk_selection_data_set (selection_data,
2948                                         GDK_SELECTION_TYPE_STRING, 8, buffer,
2949                                         strlen (buffer));
2950                 g_free (buffer);
2951         }
2952
2953         gl_debug (DEBUG_VIEW, "END");
2954 }
2955
2956 /*---------------------------------------------------------------------------*/
2957 /* PRIVATE.  Handle "selection-received" signal.  (Result of Paste)          */
2958 /*---------------------------------------------------------------------------*/
2959 static void
2960 selection_received_cb (GtkWidget        *widget,
2961                        GtkSelectionData *selection_data,
2962                        guint            time,
2963                        gpointer         data)
2964 {
2965         glView *view = GL_VIEW (data);
2966         glLabel *label = NULL;
2967         glXMLLabelStatus status;
2968         GList *p, *p_next;
2969         glLabelObject *object, *newobject;
2970         glViewObject *view_object;
2971
2972         gl_debug (DEBUG_VIEW, "START");
2973
2974         g_return_if_fail (GL_IS_VIEW (view));
2975
2976         if (selection_data->length < 0) {
2977                 return;
2978         }
2979         if (selection_data->type != GDK_SELECTION_TYPE_STRING) {
2980                 return;
2981         }
2982
2983         gl_view_unselect_all (view);
2984
2985         label = gl_xml_label_open_buffer (selection_data->data, &status);
2986         for (p = label->objects; p != NULL; p = p_next) {
2987                 p_next = p->next;
2988
2989                 object = (glLabelObject *) p->data;
2990                 gl_label_object_set_parent (object, view->label);
2991
2992                 gl_debug (DEBUG_VIEW, "object pasted");
2993
2994                 if (GL_IS_LABEL_BOX (object)) {
2995                         view_object = gl_view_box_new (GL_LABEL_BOX(object),
2996                                                        view);
2997                 } else if (GL_IS_LABEL_ELLIPSE (object)) {
2998                         view_object = gl_view_ellipse_new (GL_LABEL_ELLIPSE(object),
2999                                                            view);
3000                 } else if (GL_IS_LABEL_LINE (object)) {
3001                         view_object = gl_view_line_new (GL_LABEL_LINE(object),
3002                                                         view);
3003                 } else if (GL_IS_LABEL_IMAGE (object)) {
3004                         view_object = gl_view_image_new (GL_LABEL_IMAGE(object),
3005                                                          view);
3006                 } else if (GL_IS_LABEL_TEXT (object)) {
3007                         view_object = gl_view_text_new (GL_LABEL_TEXT(object),
3008                                                         view);
3009                 } else if (GL_IS_LABEL_BARCODE (object)) {
3010                         view_object = gl_view_barcode_new (GL_LABEL_BARCODE(object),
3011                                                            view);
3012                 } else {
3013                         /* Should not happen! */
3014                         view_object = NULL;
3015                         g_warning ("Invalid label object type.");
3016                 }
3017                 gl_view_select_object (view, view_object);
3018         }
3019         g_object_unref (label);
3020
3021         gl_debug (DEBUG_VIEW, "END");
3022 }
3023