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