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