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