]> git.sur5r.net Git - glabels/blob - glabels2/src/view.c
Initial revision
[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
41 #include "debug.h"
42
43 #define SEL_LINE_COLOR  GNOME_CANVAS_COLOR_A (0, 0, 255, 128)
44 #define SEL_FILL_COLOR  GNOME_CANVAS_COLOR_A (192, 192, 255, 128)
45
46 /*===========================================*/
47 /* Private globals                           */
48 /*===========================================*/
49
50 static GtkContainerClass *parent_class;
51
52 /* "CLIPBOARD" selection */
53 static GdkAtom clipboard_atom = GDK_NONE;
54
55 #define HOME_SCALE 2.0
56 static gdouble scales[] = { 8.0, 6.0, 4.0, 3.0,
57         2.0,
58         1.5, 1.0, 0.5, 0.25,
59         0.0
60 };
61
62 /*===========================================*/
63 /* Local function prototypes                 */
64 /*===========================================*/
65
66 static void gl_view_class_init (glViewClass *class);
67 static void gl_view_init       (glView * view);
68 static void gl_view_finalize   (GObject * object);
69
70 static void      gl_view_construct           (glView *view);
71 static GtkWidget *gl_view_construct_canvas   (glView *view);
72 static void      gl_view_construct_selection (glView *view);
73
74 static gdouble get_apropriate_scale (gdouble w, gdouble h);
75
76 static void draw_rect_bg         (glView * view);
77 static void draw_rounded_rect_bg (glView * view);
78 static void draw_round_bg        (glView * view);
79 static void draw_cd_bg           (glView * view);
80
81 static int canvas_event            (GnomeCanvas * canvas,
82                                     GdkEvent * event,
83                                     glView *view);
84 static int canvas_event_arrow_mode (GnomeCanvas * canvas,
85                                     GdkEvent * event, glView *view);
86
87 static void         select_region           (glView * view,
88                                              gdouble x1,
89                                              gdouble y1,
90                                              gdouble x2,
91                                              gdouble y2);
92 static void         select_object           (glViewObject *view_object);
93 static void         unselect_object         (glViewObject *view_object);
94 static gboolean     object_at               (glView * view,
95                                              gdouble x, gdouble y);
96 static gboolean     object_selected         (glViewObject *view_object);
97 static gboolean     multiple_items_selected (glView * view);
98
99 static int item_event_arrow_mode (GnomeCanvasItem * item,
100                                   GdkEvent * event,
101                                   glViewObject *view_object);
102
103 static GtkWidget *new_selection_menu (glView * view);
104
105 static void popup_selection_menu (glView *view,
106                                   glViewObject *view_object, GdkEvent *event);
107
108 static void move_selected_items (glView * view, gdouble dx, gdouble dy);
109 static void move_item (GnomeCanvasItem * item, gdouble dx, gdouble dy);
110
111 static void raise_selection_cb (GtkWidget * widget, glView * view);
112 static void lower_selection_cb (GtkWidget * widget, glView * view);
113
114 static void selection_clear_cb (GtkWidget * widget,
115                                 GdkEventSelection * event, gpointer data);
116
117 static void selection_get_cb (GtkWidget * widget,
118                               GtkSelectionData * selection_data, guint info,
119                               guint time, gpointer data);
120
121 static void selection_received_cb (GtkWidget * widget,
122                                    GtkSelectionData * selection_data,
123                                    guint time, gpointer data);
124 \f
125 /****************************************************************************/
126 /* Boilerplate Object stuff.                                                */
127 /****************************************************************************/
128 guint
129 gl_view_get_type (void)
130 {
131         static guint view_type = 0;
132
133         if (!view_type) {
134                 GTypeInfo view_info = {
135                         sizeof (glViewClass),
136                         NULL,
137                         NULL,
138                         (GClassInitFunc) gl_view_class_init,
139                         NULL,
140                         NULL,
141                         sizeof (glView),
142                         0,
143                         (GInstanceInitFunc) gl_view_init,
144                 };
145
146                 view_type =
147                     g_type_register_static (gtk_vbox_get_type (),
148                                             "glView", &view_info, 0);
149         }
150
151         return view_type;
152 }
153
154 static void
155 gl_view_class_init (glViewClass * class)
156 {
157         GObjectClass *object_class = (GObjectClass *) class;
158
159         gl_debug (DEBUG_VIEW, "START");
160
161         parent_class = g_type_class_peek_parent (class);
162
163         object_class->finalize = gl_view_finalize;
164
165         gl_debug (DEBUG_VIEW, "END");
166 }
167
168 static void
169 gl_view_init (glView * view)
170 {
171         gl_debug (DEBUG_VIEW, "START");
172
173         view->label = NULL;
174
175         gl_debug (DEBUG_VIEW, "END");
176 }
177
178 static void
179 gl_view_finalize (GObject * object)
180 {
181         glView *view;
182
183         gl_debug (DEBUG_VIEW, "START");
184
185         g_return_if_fail (object != NULL);
186         g_return_if_fail (GL_IS_VIEW (object));
187
188         view = GL_VIEW (object);
189
190         G_OBJECT_CLASS (parent_class)->finalize (object);
191
192         gl_debug (DEBUG_VIEW, "END");
193 }
194
195 GtkWidget *
196 gl_view_new (glLabel * label)
197 {
198         glView *view = g_object_new (gl_view_get_type (), NULL);
199
200         gl_debug (DEBUG_VIEW, "START");
201
202         view->label = label;
203
204         gl_view_construct (view);
205
206         gl_debug (DEBUG_VIEW, "END");
207
208         return GTK_WIDGET (view);
209 }
210
211 /*---------------------------------------------------------------------------*/
212 /* PRIVATE.  Construct composite widget.                                     */
213 /*---------------------------------------------------------------------------*/
214 static void
215 gl_view_construct (glView * view)
216 {
217         GtkWidget *wvbox, *wscroll;
218
219         gl_debug (DEBUG_VIEW, "START");
220
221         g_return_if_fail (GL_IS_VIEW (view));
222
223         wvbox = GTK_WIDGET (view);
224
225         view->state = GL_VIEW_STATE_ARROW;
226         view->object_list = NULL;
227
228         gl_view_construct_canvas (view);
229         wscroll = gtk_scrolled_window_new (NULL, NULL);
230         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (wscroll),
231                                         GTK_POLICY_AUTOMATIC,
232                                         GTK_POLICY_AUTOMATIC);
233         gtk_box_pack_start (GTK_BOX (wvbox), wscroll, TRUE, TRUE, 0);
234         gtk_container_add (GTK_CONTAINER (wscroll), view->canvas);
235
236         gl_view_construct_selection (view);
237
238         view->menu = new_selection_menu (view);
239
240         gl_debug (DEBUG_VIEW, "END");
241 }
242
243 /*---------------------------------------------------------------------------*/
244 /* PRIVATE.  Create canvas w/ a background in the shape of the label/card.   */
245 /*---------------------------------------------------------------------------*/
246 static GtkWidget *
247 gl_view_construct_canvas (glView * view)
248 {
249         gdouble scale;
250         glLabel *label = view->label;
251         gdouble label_width, label_height;
252         glTemplate *label_template;
253         GList *p_obj;
254         glLabelObject *object;
255         glViewObject *view_object;
256
257         gl_debug (DEBUG_VIEW, "START");
258
259         g_return_val_if_fail (GL_IS_VIEW (view), NULL);
260         g_return_val_if_fail (label != NULL, NULL);
261
262         gtk_widget_push_colormap (gdk_rgb_get_colormap ());
263         view->canvas = gnome_canvas_new_aa ();
264         gtk_widget_pop_colormap ();
265
266         gl_label_get_size (label, &label_width, &label_height);
267         gl_debug (DEBUG_VIEW, "Label size: w=%lf, h=%lf",
268                   label_width, label_height);
269         label_template = gl_label_get_template (label);
270
271         scale = get_apropriate_scale (label_width, label_height);
272         gl_debug (DEBUG_VIEW, "scale =%lf", scale);
273
274         gl_debug (DEBUG_VIEW, "Canvas size: w=%lf, h=%lf",
275                               scale * label_width + 40,
276                               scale * label_height + 40);
277         gtk_widget_set_size_request (GTK_WIDGET(view->canvas),
278                                      scale * label_width + 40,
279                                      scale * label_height + 40);
280         gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (view->canvas),
281                                           scale);
282         view->scale = scale;
283
284         gnome_canvas_set_scroll_region (GNOME_CANVAS (view->canvas),
285                                         0.0, 0.0, label_width, label_height);
286
287         /* Draw background shape of label/card */
288         switch (label_template->style) {
289
290         case GL_TEMPLATE_STYLE_RECT:
291                 if (label_template->label_round == 0.0) {
292                         /* Square corners. */
293                         draw_rect_bg (view);
294                 } else {
295                         /* Rounded corners. */
296                         draw_rounded_rect_bg (view);
297                 }
298                 break;
299
300         case GL_TEMPLATE_STYLE_ROUND:
301                 draw_round_bg (view);
302                 break;
303
304         case GL_TEMPLATE_STYLE_CD:
305                 draw_cd_bg (view);
306                 break;
307
308         default:
309                 g_warning ("Unknown template label style");
310                 break;
311         }
312
313         g_signal_connect (G_OBJECT (view->canvas), "event",
314                           G_CALLBACK (canvas_event), view);
315
316         for (p_obj = label->objects; p_obj != NULL; p_obj = p_obj->next) {
317                 object = (glLabelObject *) p_obj->data;
318
319                 if (GL_IS_LABEL_BOX (object)) {
320                         view_object = gl_view_box_new (GL_LABEL_BOX(object),
321                                                        view);
322                 } else if (GL_IS_LABEL_ELLIPSE (object)) {
323                         view_object = gl_view_ellipse_new (GL_LABEL_ELLIPSE(object),
324                                                            view);
325                 } else if (GL_IS_LABEL_LINE (object)) {
326                         view_object = gl_view_line_new (GL_LABEL_LINE(object),
327                                                         view);
328                 } else if (GL_IS_LABEL_IMAGE (object)) {
329                         view_object = gl_view_image_new (GL_LABEL_IMAGE(object),
330                                                          view);
331                 } else if (GL_IS_LABEL_TEXT (object)) {
332                         view_object = gl_view_text_new (GL_LABEL_TEXT(object),
333                                                         view);
334                 } else if (GL_IS_LABEL_BARCODE (object)) {
335                         view_object = gl_view_barcode_new (GL_LABEL_BARCODE(object),
336                                                            view);
337                 } else {
338                         /* Should not happen! */
339                         view_object = NULL;
340                         g_warning ("Invalid label object type.");
341                 }
342         }
343
344         gl_debug (DEBUG_VIEW, "END");
345
346         return view->canvas;
347 }
348
349 /*---------------------------------------------------------------------------*/
350 /* PRIVATE.  Create selection targets.                                       */
351 /*---------------------------------------------------------------------------*/
352 static void
353 gl_view_construct_selection (glView * view)
354 {
355         gl_debug (DEBUG_VIEW, "START");
356
357         g_return_if_fail (GL_IS_VIEW (view));
358
359         view->have_selection = FALSE;
360         view->selection_data = NULL;
361         view->invisible = gtk_invisible_new ();
362
363         view->selected_object_list = NULL;
364
365         if (!clipboard_atom) {
366                 clipboard_atom = gdk_atom_intern ("GLABELS_CLIPBOARD", FALSE);
367         }
368
369         gtk_selection_add_target (view->invisible,
370                                   clipboard_atom, GDK_SELECTION_TYPE_STRING, 1);
371
372         g_signal_connect (G_OBJECT (view->invisible),
373                           "selection_clear_event",
374                           G_CALLBACK (selection_clear_cb), view);
375
376         g_signal_connect (G_OBJECT (view->invisible), "selection_get",
377                           G_CALLBACK (selection_get_cb), view);
378
379         g_signal_connect (G_OBJECT (view->invisible),
380                           "selection_received",
381                           G_CALLBACK (selection_received_cb), view);
382
383         gl_debug (DEBUG_VIEW, "END");
384 }
385
386 /*---------------------------------------------------------------------------*/
387 /* PRIVATE.  Determine an apropriate scale for given label & screen size     */
388 /*---------------------------------------------------------------------------*/
389 static gdouble
390 get_apropriate_scale (gdouble w, gdouble h)
391 {
392         gdouble w_screen, h_screen;
393         gint i;
394         gdouble k;
395
396         gl_debug (DEBUG_VIEW, "");
397
398         w_screen = (gdouble) gdk_screen_width ();
399         h_screen = (gdouble) gdk_screen_height ();
400
401         for (i = 0; scales[i] > 0.0; i++) {
402                 k = scales[i];
403                 if (k <= HOME_SCALE) {
404                         if ((k * w < (w_screen - 256))
405                             && (k * h < (h_screen - 256)))
406                                 return k;
407                 }
408         }
409
410         return 0.25;
411 }
412
413 /*---------------------------------------------------------------------------*/
414 /* PRIVATE.  Draw simple recangular background.                              */
415 /*---------------------------------------------------------------------------*/
416 static void
417 draw_rect_bg (glView * view)
418 {
419         glLabel *label = view->label;
420         glTemplate *template;
421         gdouble w, h, margin;
422         GnomeCanvasItem *item;
423         GnomeCanvasGroup *group;
424
425         gl_debug (DEBUG_VIEW, "START");
426
427         g_return_if_fail (GL_IS_VIEW (view));
428         g_return_if_fail (label != NULL);
429
430         gl_label_get_size (label, &w, &h);
431         template = gl_label_get_template (label);
432         margin = template->label_margin;
433
434         view->n_bg_items = 0;
435         view->bg_item_list = NULL;
436
437         group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
438
439         item = gnome_canvas_item_new (group,
440                                       gnome_canvas_rect_get_type (),
441                                       "x1", 0.0,
442                                       "y1", 0.0,
443                                       "x2", w,
444                                       "y2", h,
445                                       "fill_color", "white",
446                                       NULL);
447         view->n_bg_items++;
448         view->bg_item_list = g_list_append (view->bg_item_list, item);
449
450         /* Bounding box @ margin */
451         gnome_canvas_item_new (group,
452                                gnome_canvas_rect_get_type (),
453                                "x1", margin,
454                                "y1", margin,
455                                "x2", w - margin,
456                                "y2", h - margin,
457                                "width_pixels", 1,
458                                "outline_color", "light blue",
459                                NULL);
460         view->n_bg_items++;
461         view->bg_item_list = g_list_append (view->bg_item_list, item);
462
463         gl_debug (DEBUG_VIEW, "END");
464 }
465
466 /*---------------------------------------------------------------------------*/
467 /* PRIVATE.  Draw rounded recangular background.                             */
468 /*---------------------------------------------------------------------------*/
469 static void
470 draw_rounded_rect_bg (glView * view)
471 {
472         glLabel *label = view->label;
473         GnomeCanvasPoints *points;
474         gint i_coords, i_theta;
475         glTemplate *template;
476         gdouble r, w, h, m;
477         GnomeCanvasItem *item;
478         GnomeCanvasGroup *group;
479
480         gl_debug (DEBUG_VIEW, "START");
481
482         g_return_if_fail (GL_IS_VIEW (view));
483         g_return_if_fail (label != NULL);
484
485         group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
486
487         view->n_bg_items = 0;
488         view->bg_item_list = NULL;
489
490         gl_label_get_size (label, &w, &h);
491         template = gl_label_get_template (label);
492         r = template->label_round;
493         m = template->label_margin;
494
495         points = gnome_canvas_points_new (4 * (1 + 90 / 5));
496         i_coords = 0;
497         for (i_theta = 0; i_theta <= 90; i_theta += 5) {
498                 points->coords[i_coords++] =
499                     r - r * sin (i_theta * M_PI / 180.0);
500                 points->coords[i_coords++] =
501                     r - r * cos (i_theta * M_PI / 180.0);
502         }
503         for (i_theta = 0; i_theta <= 90; i_theta += 5) {
504                 points->coords[i_coords++] =
505                     r - r * cos (i_theta * M_PI / 180.0);
506                 points->coords[i_coords++] =
507                     (h - r) + r * sin (i_theta * M_PI / 180.0);
508         }
509         for (i_theta = 0; i_theta <= 90; i_theta += 5) {
510                 points->coords[i_coords++] =
511                     (w - r) + r * sin (i_theta * M_PI / 180.0);
512                 points->coords[i_coords++] =
513                     (h - r) + r * cos (i_theta * M_PI / 180.0);
514         }
515         for (i_theta = 0; i_theta <= 90; i_theta += 5) {
516                 points->coords[i_coords++] =
517                     (w - r) + r * cos (i_theta * M_PI / 180.0);
518                 points->coords[i_coords++] =
519                     r - r * sin (i_theta * M_PI / 180.0);
520         }
521         item = gnome_canvas_item_new (group,
522                                       gnome_canvas_polygon_get_type (),
523                                       "points", points,
524                                       "fill_color", "white",
525                                       NULL);
526         gnome_canvas_points_free (points);
527         view->n_bg_items++;
528         view->bg_item_list = g_list_append (view->bg_item_list, item);
529
530         /* Bounding box @ margin */
531         if (template->label_margin >= template->label_round) {
532                 /* simple rectangle */
533                 item = gnome_canvas_item_new (group,
534                                               gnome_canvas_rect_get_type (),
535                                               "x1", m,
536                                               "y1", m,
537                                               "x2", w - m,
538                                               "y2", h - m,
539                                               "width_pixels", 1,
540                                               "outline_color", "light blue",
541                                               NULL);
542                 view->n_bg_items++;
543                 view->bg_item_list =
544                     g_list_append (view->bg_item_list, item);
545         } else {
546                 r = r - m;
547                 w = w - 2 * m;
548                 h = h - 2 * m;
549
550                 /* rectangle with rounded corners */
551                 points = gnome_canvas_points_new (4 * (1 + 90 / 5));
552                 i_coords = 0;
553                 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
554                         points->coords[i_coords++] =
555                             m + r - r * sin (i_theta * M_PI / 180.0);
556                         points->coords[i_coords++] =
557                             m + r - r * cos (i_theta * M_PI / 180.0);
558                 }
559                 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
560                         points->coords[i_coords++] =
561                             m + r - r * cos (i_theta * M_PI / 180.0);
562                         points->coords[i_coords++] =
563                             m + (h - r) + r * sin (i_theta * M_PI / 180.0);
564                 }
565                 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
566                         points->coords[i_coords++] =
567                             m + (w - r) + r * sin (i_theta * M_PI / 180.0);
568                         points->coords[i_coords++] =
569                             m + (h - r) + r * cos (i_theta * M_PI / 180.0);
570                 }
571                 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
572                         points->coords[i_coords++] =
573                             m + (w - r) + r * cos (i_theta * M_PI / 180.0);
574                         points->coords[i_coords++] =
575                             m + r - r * sin (i_theta * M_PI / 180.0);
576                 }
577                 item = gnome_canvas_item_new (group,
578                                               gnome_canvas_polygon_get_type (),
579                                               "points", points,
580                                               "width_pixels", 1,
581                                               "outline_color", "light blue",
582                                               NULL);
583                 gnome_canvas_points_free (points);
584                 view->n_bg_items++;
585                 view->bg_item_list =
586                     g_list_append (view->bg_item_list, item);
587         }
588
589         gl_debug (DEBUG_VIEW, "END");
590 }
591
592 /*---------------------------------------------------------------------------*/
593 /* PRIVATE.  Draw round background.                                          */
594 /*---------------------------------------------------------------------------*/
595 static void
596 draw_round_bg (glView * view)
597 {
598         glLabel *label = view->label;
599         glTemplate *template;
600         GnomeCanvasPoints *points;
601         gint i_coords, i_theta;
602         gdouble r, r1;
603         GnomeCanvasItem *item;
604         GnomeCanvasGroup *group;
605
606         gl_debug (DEBUG_VIEW, "START");
607
608         g_return_if_fail (GL_IS_VIEW (view));
609         g_return_if_fail (label != NULL);
610
611         template = gl_label_get_template (label);
612
613         group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
614
615         view->n_bg_items = 0;
616         view->bg_item_list = NULL;
617
618         r1 = template->label_radius;
619         points = gnome_canvas_points_new (1 + 360/2);
620         i_coords = 0;
621         for (i_theta = 0; i_theta <= 360; i_theta += 2) {
622                 points->coords[i_coords++] =
623                     r1 - r1 * sin (i_theta * M_PI / 180.0);
624                 points->coords[i_coords++] =
625                     r1 - r1 * cos (i_theta * M_PI / 180.0);
626         }
627         item = gnome_canvas_item_new (group,
628                                       gnome_canvas_polygon_get_type (),
629                                       "points", points,
630                                       "fill_color", "white",
631                                       NULL);
632         gnome_canvas_points_free (points);
633         view->n_bg_items++;
634         view->bg_item_list = g_list_append (view->bg_item_list, item);
635
636         /* Bounding box @ margin */
637         r = template->label_radius - template->label_margin;
638         points = gnome_canvas_points_new (360 / 2);
639         i_coords = 0;
640         for (i_theta = 0; i_theta < 360; i_theta += 2) {
641                 points->coords[i_coords++] =
642                     r1 - r * sin (i_theta * M_PI / 180.0);
643                 points->coords[i_coords++] =
644                     r1 - r * cos (i_theta * M_PI / 180.0);
645         }
646         item = gnome_canvas_item_new (group,
647                                       gnome_canvas_polygon_get_type (),
648                                       "points", points,
649                                       "width_pixels", 1,
650                                       "outline_color", "light blue", NULL);
651         gnome_canvas_points_free (points);
652         view->n_bg_items++;
653         view->bg_item_list = g_list_append (view->bg_item_list, item);
654
655         gl_debug (DEBUG_VIEW, "END");
656 }
657
658 /*---------------------------------------------------------------------------*/
659 /* PRIVATE.  Draw CD style background, circular w/ concentric hole.          */
660 /*---------------------------------------------------------------------------*/
661 static void
662 draw_cd_bg (glView * view)
663 {
664         glLabel *label = view->label;
665         glTemplate *template;
666         GnomeCanvasPoints *points;
667         gint i_coords, i_theta;
668         gdouble r, r1, r2;
669         GnomeCanvasItem *item;
670         GnomeCanvasGroup *group;
671
672         gl_debug (DEBUG_VIEW, "START");
673
674         g_return_if_fail (GL_IS_VIEW (view));
675         g_return_if_fail (label != NULL);
676
677         template = gl_label_get_template (label);
678
679         group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
680
681         view->n_bg_items = 0;
682         view->bg_item_list = NULL;
683
684         r1 = template->label_radius;
685         r2 = template->label_hole;
686         points = gnome_canvas_points_new (2 * (1 + 360 / 2));
687         i_coords = 0;
688         for (i_theta = 0; i_theta <= 360; i_theta += 2) {
689                 points->coords[i_coords++] =
690                     r1 - r1 * sin (i_theta * M_PI / 180.0);
691                 points->coords[i_coords++] =
692                     r1 - r1 * cos (i_theta * M_PI / 180.0);
693         }
694         for (i_theta = 0; i_theta <= 360; i_theta += 2) {
695                 points->coords[i_coords++] =
696                     r1 - r2 * sin (i_theta * M_PI / 180.0);
697                 points->coords[i_coords++] =
698                     r1 - r2 * cos (i_theta * M_PI / 180.0);
699         }
700         item = gnome_canvas_item_new (group,
701                                       gnome_canvas_polygon_get_type (),
702                                       "points", points,
703                                       "fill_color", "white",
704                                       NULL);
705         gnome_canvas_points_free (points);
706         view->n_bg_items++;
707         view->bg_item_list = g_list_append (view->bg_item_list, item);
708
709         /* Bounding box @ margin */
710         /* outer margin */
711         r = template->label_radius - template->label_margin;
712         points = gnome_canvas_points_new (360 / 2);
713         i_coords = 0;
714         for (i_theta = 0; i_theta < 360; i_theta += 2) {
715                 points->coords[i_coords++] =
716                     r1 - r * sin (i_theta * M_PI / 180.0);
717                 points->coords[i_coords++] =
718                     r1 - r * cos (i_theta * M_PI / 180.0);
719         }
720         item = gnome_canvas_item_new (group,
721                                       gnome_canvas_polygon_get_type (),
722                                       "points", points,
723                                       "width_pixels", 1,
724                                       "outline_color", "light blue", NULL);
725         gnome_canvas_points_free (points);
726         view->n_bg_items++;
727         view->bg_item_list = g_list_append (view->bg_item_list, item);
728
729         /* inner margin */
730         r = template->label_hole + template->label_margin;
731         points = gnome_canvas_points_new (360 / 2);
732         i_coords = 0;
733         for (i_theta = 0; i_theta < 360; i_theta += 2) {
734                 points->coords[i_coords++] =
735                     r1 - r * sin (i_theta * M_PI / 180.0);
736                 points->coords[i_coords++] =
737                     r1 - r * cos (i_theta * M_PI / 180.0);
738         }
739         item = gnome_canvas_item_new (group,
740                                       gnome_canvas_polygon_get_type (),
741                                       "points", points,
742                                       "width_pixels", 1,
743                                       "outline_color", "light blue",
744                                       NULL);
745         gnome_canvas_points_free (points);
746         view->n_bg_items++;
747         view->bg_item_list = g_list_append (view->bg_item_list, item);
748
749         gl_debug (DEBUG_VIEW, "END");
750 }
751
752 /*****************************************************************************/
753 /* Set arrow mode.                                                           */
754 /*****************************************************************************/
755 void
756 gl_view_arrow_mode (glView * view)
757 {
758         static GdkCursor *cursor = NULL;
759
760         gl_debug (DEBUG_VIEW, "START");
761
762         g_return_if_fail (GL_IS_VIEW (view));
763
764         if (!cursor) {
765                 cursor = gdk_cursor_new (GDK_LEFT_PTR);
766         }
767
768         gdk_window_set_cursor (view->canvas->window, cursor);
769
770         view->state = GL_VIEW_STATE_ARROW;
771
772         gl_debug (DEBUG_VIEW, "END");
773 }
774
775 /*****************************************************************************/
776 /* Set create text object mode.                                              */
777 /*****************************************************************************/
778 void
779 gl_view_object_create_mode (glView * view,
780                             glLabelObjectType type)
781 {
782         GdkCursor *cursor;
783
784         gl_debug (DEBUG_VIEW, "START");
785
786         g_return_if_fail (GL_IS_VIEW (view));
787
788         switch (type) {
789         case GL_LABEL_OBJECT_BOX:
790                 cursor = gl_view_box_get_create_cursor ();
791                 break;
792         case GL_LABEL_OBJECT_ELLIPSE:
793                 cursor = gl_view_ellipse_get_create_cursor ();
794                 break;
795         case GL_LABEL_OBJECT_LINE:
796                 cursor = gl_view_line_get_create_cursor ();
797                 break;
798         case GL_LABEL_OBJECT_IMAGE:
799                 cursor = gl_view_image_get_create_cursor ();
800                 break;
801         case GL_LABEL_OBJECT_TEXT:
802                 cursor = gl_view_text_get_create_cursor ();
803                 break;
804         case GL_LABEL_OBJECT_BARCODE:
805                 cursor = gl_view_barcode_get_create_cursor ();
806                 break;
807         default:
808                 g_warning ("Invalid label object type.");/*Should not happen!*/
809                 break;
810         }
811
812         gdk_window_set_cursor (view->canvas->window, cursor);
813
814         view->state = GL_VIEW_STATE_OBJECT_CREATE;
815         view->create_type = type;
816
817         gl_debug (DEBUG_VIEW, "END");
818 }
819
820 /*****************************************************************************/
821 /* Select given object.                                                      */
822 /*****************************************************************************/
823 void
824 gl_view_select_object (glView *view, glViewObject *view_object)
825 {
826         gl_debug (DEBUG_VIEW, "START");
827
828         select_object (view_object);
829
830         gl_debug (DEBUG_VIEW, "END");
831 }
832
833 /*****************************************************************************/
834 /* Select all items.                                                         */
835 /*****************************************************************************/
836 void
837 gl_view_select_all (glView * view)
838 {
839         GList *p;
840
841         gl_debug (DEBUG_VIEW, "START");
842
843         g_return_if_fail (GL_IS_VIEW (view));
844
845         gl_view_unselect_all (view);
846
847         for (p = view->object_list; p != NULL; p = p->next) {
848                 select_object (GL_VIEW_OBJECT (p->data));
849         }
850
851         gl_debug (DEBUG_VIEW, "END");
852 }
853
854 /*****************************************************************************/
855 /* Remove all selections                                                     */
856 /*****************************************************************************/
857 void
858 gl_view_unselect_all (glView * view)
859 {
860         GList *p, *p_next;
861
862         gl_debug (DEBUG_VIEW, "START");
863
864         g_return_if_fail (GL_IS_VIEW (view));
865
866         for (p = view->selected_object_list; p != NULL; p = p_next) {
867                 p_next = p->next;
868                 unselect_object (GL_VIEW_OBJECT (p->data));
869         }
870
871         gl_debug (DEBUG_VIEW, "END");
872 }
873
874 /*****************************************************************************/
875 /* "Cut" selected items and place in clipboard selections.                   */
876 /*****************************************************************************/
877 void
878 gl_view_cut (glView * view)
879 {
880         gl_debug (DEBUG_VIEW, "START");
881
882         g_return_if_fail (GL_IS_VIEW (view));
883
884         gl_view_copy (view);
885         gl_view_delete_selection (view);
886
887         gl_debug (DEBUG_VIEW, "END");
888 }
889
890 /*****************************************************************************/
891 /* "Copy" selected items to clipboard selections.                            */
892 /*****************************************************************************/
893 void
894 gl_view_copy (glView * view)
895 {
896         GList *p;
897         glViewObject *view_object;
898         glLabelObject *object;
899         glTemplate *template;
900         gboolean rotate_flag;
901
902         gl_debug (DEBUG_VIEW, "START");
903
904         g_return_if_fail (GL_IS_VIEW (view));
905
906         if (view->selected_object_list) {
907
908                 if ( view->selection_data ) {
909                         g_object_unref (view->selection_data);
910                 }
911                 template = gl_label_get_template (view->label);
912                 rotate_flag = gl_label_get_rotate_flag (view->label);
913                 view->selection_data = GL_LABEL(gl_label_new ());
914                 gl_label_set_template (view->selection_data, template);
915                 gl_label_set_rotate_flag (view->selection_data, rotate_flag);
916                 gl_template_free (&template);
917
918                 for (p = view->selected_object_list; p != NULL; p = p->next) {
919
920                         view_object = GL_VIEW_OBJECT (p->data);
921                         object = gl_view_object_get_object (view_object);
922
923                         gl_debug (DEBUG_VIEW, "Object copied");
924
925                         if (GL_IS_LABEL_BOX (object)) {
926                                 gl_label_box_dup (GL_LABEL_BOX(object),
927                                                   view->selection_data);
928                         } else if (GL_IS_LABEL_ELLIPSE (object)) {
929                                 gl_label_ellipse_dup (GL_LABEL_ELLIPSE(object),
930                                                       view->selection_data);
931                         } else if (GL_IS_LABEL_LINE (object)) {
932                                 gl_label_line_dup (GL_LABEL_LINE(object),
933                                                    view->selection_data);
934                         } else if (GL_IS_LABEL_IMAGE (object)) {
935                                 gl_label_image_dup (GL_LABEL_IMAGE(object),
936                                                     view->selection_data);
937                         } else if (GL_IS_LABEL_TEXT (object)) {
938                                 gl_label_text_dup (GL_LABEL_TEXT(object),
939                                                    view->selection_data);
940                         } else if (GL_IS_LABEL_BARCODE (object)) {
941                                 gl_label_barcode_dup (GL_LABEL_BARCODE(object),
942                                                       view->selection_data);
943                         } else {
944                                 /* Should not happen! */
945                                 g_warning ("Invalid label object type.");
946                         }
947
948
949                 }
950
951                 gtk_selection_owner_set (view->invisible,
952                                          clipboard_atom, GDK_CURRENT_TIME);
953                 view->have_selection = TRUE;
954
955         }
956
957         gl_debug (DEBUG_VIEW, "END");
958 }
959
960 /*****************************************************************************/
961 /* "Paste" from private clipboard selection.                                 */
962 /*****************************************************************************/
963 void
964 gl_view_paste (glView * view)
965 {
966         gl_debug (DEBUG_VIEW, "START");
967
968         g_return_if_fail (GL_IS_VIEW (view));
969
970         gtk_selection_convert (GTK_WIDGET (view->invisible),
971                                clipboard_atom, GDK_SELECTION_TYPE_STRING,
972                                GDK_CURRENT_TIME);
973
974         gl_debug (DEBUG_VIEW, "END");
975 }
976
977 /*---------------------------------------------------------------------------*/
978 /* PRIVATE.  Canvas event handler.                                           */
979 /*---------------------------------------------------------------------------*/
980 static int
981 canvas_event (GnomeCanvas *canvas,
982               GdkEvent    *event,
983               glView      *view)
984 {
985         gl_debug (DEBUG_VIEW, "");
986
987         switch (view->state) {
988
989         case GL_VIEW_STATE_ARROW:
990                 return canvas_event_arrow_mode (canvas, event, view);
991
992         case GL_VIEW_STATE_OBJECT_CREATE:
993                 switch (view->create_type) {
994                 case GL_LABEL_OBJECT_BOX:
995                         return gl_view_box_create_event_handler (canvas,
996                                                                  event,
997                                                                  view);
998                         break;
999                 case GL_LABEL_OBJECT_ELLIPSE:
1000                         return gl_view_ellipse_create_event_handler (canvas,
1001                                                                      event,
1002                                                                      view);
1003                         break;
1004                 case GL_LABEL_OBJECT_LINE:
1005                         return gl_view_line_create_event_handler (canvas,
1006                                                                   event,
1007                                                                   view);
1008                         break;
1009                 case GL_LABEL_OBJECT_IMAGE:
1010                         return gl_view_image_create_event_handler (canvas,
1011                                                                    event,
1012                                                                    view);
1013                         break;
1014                 case GL_LABEL_OBJECT_TEXT:
1015                         return gl_view_text_create_event_handler (canvas,
1016                                                                   event,
1017                                                                   view);
1018                         break;
1019                 case GL_LABEL_OBJECT_BARCODE:
1020                         return gl_view_barcode_create_event_handler (canvas,
1021                                                                      event,
1022                                                                      view);
1023                         break;
1024                 default:
1025                         /*Should not happen!*/
1026                         g_warning ("Invalid label object type.");
1027                         return FALSE;
1028         }
1029
1030         default:
1031                 g_warning ("Invalid view state.");      /*Should not happen!*/
1032                 return FALSE;
1033
1034         }
1035 }
1036
1037 /*---------------------------------------------------------------------------*/
1038 /* PRIVATE.  Canvas event handler (arrow mode)                               */
1039 /*---------------------------------------------------------------------------*/
1040 static int
1041 canvas_event_arrow_mode (GnomeCanvas *canvas,
1042                          GdkEvent    *event,
1043                          glView      *view)
1044 {
1045         static gdouble x0, y0;
1046         static gboolean dragging = FALSE;
1047         static GnomeCanvasItem *item;
1048         gdouble x, y, x1, y1, x2, y2;
1049         GnomeCanvasGroup *group;
1050         GdkCursor *cursor;
1051
1052         gl_debug (DEBUG_VIEW, "");
1053
1054         switch (event->type) {
1055
1056         case GDK_BUTTON_PRESS:
1057                 gl_debug (DEBUG_VIEW, "BUTTON_PRESS");
1058                 switch (event->button.button) {
1059                 case 1:
1060                         gnome_canvas_window_to_world (canvas,
1061                                                       event->button.x,
1062                                                       event->button.y, &x, &y);
1063
1064                         if (!object_at (view, x, y)) {
1065                                 if (!(event->button.state & GDK_CONTROL_MASK)) {
1066                                         gl_view_unselect_all (view);
1067                                 }
1068
1069                                 dragging = TRUE;
1070                                 gdk_pointer_grab (GTK_WIDGET (view->canvas)->
1071                                                   window, FALSE,
1072                                                   GDK_POINTER_MOTION_MASK |
1073                                                   GDK_BUTTON_RELEASE_MASK |
1074                                                   GDK_BUTTON_PRESS_MASK, NULL,
1075                                                   NULL, event->button.time);
1076                                 group =
1077                                     gnome_canvas_root (GNOME_CANVAS
1078                                                        (view->canvas));
1079                                 item =
1080                                     gnome_canvas_item_new (group,
1081                                                            gnome_canvas_rect_get_type (),
1082                                                            "x1", x, "y1", y,
1083                                                            "x2", x, "y2", y,
1084                                                            "width_pixels", 2,
1085                                                            "outline_color_rgba",
1086                                                            SEL_LINE_COLOR,
1087                                                            "fill_color_rgba",
1088                                                            SEL_FILL_COLOR,
1089                                                            NULL);
1090                                 x0 = x;
1091                                 y0 = y;
1092
1093                         }
1094                         return FALSE;
1095
1096                 default:
1097                         return FALSE;
1098                 }
1099
1100         case GDK_BUTTON_RELEASE:
1101                 gl_debug (DEBUG_VIEW, "BUTTON_RELEASE");
1102                 switch (event->button.button) {
1103                 case 1:
1104                         if (dragging) {
1105                                 dragging = FALSE;
1106                                 gdk_pointer_ungrab (event->button.time);
1107                                 gnome_canvas_window_to_world (canvas,
1108                                                               event->button.x,
1109                                                               event->button.y,
1110                                                               &x, &y);
1111                                 x1 = MIN (x, x0);
1112                                 y1 = MIN (y, y0);
1113                                 x2 = MAX (x, x0);
1114                                 y2 = MAX (y, y0);
1115                                 select_region (view, x1, y1, x2, y2);
1116                                 gtk_object_destroy (GTK_OBJECT (item));
1117                                 return TRUE;
1118                         }
1119                         return FALSE;
1120
1121                 default:
1122                         return FALSE;
1123                 }
1124
1125         case GDK_MOTION_NOTIFY:
1126                 gl_debug (DEBUG_VIEW, "MOTION_NOTIFY");
1127                 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
1128                         gnome_canvas_window_to_world (canvas,
1129                                                       event->button.x,
1130                                                       event->button.y, &x, &y);
1131
1132                         gnome_canvas_item_set (item,
1133                                                "x1", MIN (x, x0),
1134                                                "y1", MIN (y, y0),
1135                                                "x2", MAX (x, x0),
1136                                                "y2", MAX (y, y0), NULL);
1137                         return TRUE;
1138                 } else {
1139                         return FALSE;
1140                 }
1141
1142         case GDK_KEY_PRESS:
1143                 gl_debug (DEBUG_VIEW, "KEY_PRESS");
1144                 if (!dragging) {
1145                         switch (event->key.keyval) {
1146                         case GDK_Left:
1147                         case GDK_KP_Left:
1148                                 move_selected_items (view,
1149                                                      -1.0 / (view->scale),
1150                                                      0.0);
1151                                 break;
1152                         case GDK_Up:
1153                         case GDK_KP_Up:
1154                                 move_selected_items (view, 0.0,
1155                                                      -1.0 / (view->scale));
1156                                 break;
1157                         case GDK_Right:
1158                         case GDK_KP_Right:
1159                                 move_selected_items (view,
1160                                                      1.0 / (view->scale),
1161                                                      0.0);
1162                                 break;
1163                         case GDK_Down:
1164                         case GDK_KP_Down:
1165                                 move_selected_items (view, 0.0,
1166                                                      1.0 / (view->scale));
1167                                 break;
1168                         case GDK_Delete:
1169                         case GDK_KP_Delete:
1170                                 gl_view_delete_selection (view);
1171                                 cursor = gdk_cursor_new (GDK_LEFT_PTR);
1172                                 gdk_window_set_cursor (view->canvas->window,
1173                                                        cursor);
1174                                 gdk_cursor_unref (cursor);
1175                                 break;
1176                         default:
1177                                 return FALSE;
1178                         }
1179                 }
1180                 return TRUE;    /* We handled this or we were dragging. */
1181
1182         default:
1183                 gl_debug (DEBUG_VIEW, "default");
1184                 return FALSE;
1185         }
1186
1187 }
1188
1189 /*---------------------------------------------------------------------------*/
1190 /* PRIVATE.  Select all objects within given rectangular region.             */
1191 /*---------------------------------------------------------------------------*/
1192 static void
1193 select_region (glView * view,
1194                gdouble x1,
1195                gdouble y1,
1196                gdouble x2,
1197                gdouble y2)
1198 {
1199         GList *p;
1200         glViewObject *view_object;
1201         glLabelObject *object;
1202         gdouble i_x1, i_y1, i_x2, i_y2, w, h;
1203
1204         gl_debug (DEBUG_VIEW, "START");
1205
1206         g_return_if_fail (GL_IS_VIEW (view));
1207         g_return_if_fail ((x1 <= x2) && (y1 <= y2));
1208
1209         for (p = view->object_list; p != NULL; p = p->next) {
1210                 view_object = GL_VIEW_OBJECT(p->data);
1211                 if (!object_selected (view_object)) {
1212
1213                         object = gl_view_object_get_object (view_object);
1214
1215                         gl_label_object_get_position (object, &i_x1, &i_y1);
1216                         gl_label_object_get_size (object, &w, &h);
1217                         i_x2 = i_x1 + w;
1218                         i_y2 = i_y1 + h;
1219                         if ((i_x1 >= x1) && (i_x2 <= x2) && (i_y1 >= y1)
1220                             && (i_y2 <= y2)) {
1221                                 select_object (view_object);
1222                         }
1223
1224                 }
1225         }
1226
1227         gl_debug (DEBUG_VIEW, "END");
1228 }
1229
1230 /*---------------------------------------------------------------------------*/
1231 /* PRIVATE. Select an object.                                                */
1232 /*---------------------------------------------------------------------------*/
1233 static void
1234 select_object (glViewObject *view_object)
1235 {
1236         glView * view;
1237
1238         gl_debug (DEBUG_VIEW, "START");
1239
1240         g_return_if_fail (GL_IS_VIEW_OBJECT (view_object));
1241
1242         view = gl_view_object_get_view (view_object);
1243
1244         if (!object_selected (view_object)) {
1245                 view->selected_object_list =
1246                     g_list_prepend (view->selected_object_list, view_object);
1247         }
1248         gl_view_object_show_highlight (view_object);
1249         gtk_widget_grab_focus (GTK_WIDGET (view->canvas));
1250
1251         gl_debug (DEBUG_VIEW, "END");
1252 }
1253
1254 /*---------------------------------------------------------------------------*/
1255 /* PRIVATE.  Un-select object.                                               */
1256 /*---------------------------------------------------------------------------*/
1257 static void
1258 unselect_object (glViewObject *view_object)
1259 {
1260         glView * view;
1261
1262         gl_debug (DEBUG_VIEW, "START");
1263
1264         g_return_if_fail (GL_IS_VIEW_OBJECT (view_object));
1265
1266         view = gl_view_object_get_view (view_object);
1267
1268         gl_view_object_hide_highlight (view_object);
1269
1270         view->selected_object_list =
1271             g_list_remove (view->selected_object_list, view_object);
1272
1273         gl_debug (DEBUG_VIEW, "END");
1274 }
1275
1276 /*---------------------------------------------------------------------------*/
1277 /* PRIVATE. Return object at (x,y).                                          */
1278 /*---------------------------------------------------------------------------*/
1279 static gboolean
1280 object_at (glView * view,
1281            gdouble x,
1282            gdouble y)
1283 {
1284         GnomeCanvasItem *item, *p_item;
1285         GList *p;
1286
1287         gl_debug (DEBUG_VIEW, "");
1288
1289         g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
1290
1291         item = gnome_canvas_get_item_at (GNOME_CANVAS (view->canvas), x, y);
1292
1293         /* No item is at x, y */
1294         if (item == NULL)
1295                 return FALSE;
1296
1297         /* ignore our background items */
1298         if (g_list_find (view->bg_item_list, item) != NULL)
1299                 return FALSE;
1300
1301         return TRUE;
1302 }
1303
1304 /*---------------------------------------------------------------------------*/
1305 /* PRIVATE.  Is the object in our current selection?                         */
1306 /*---------------------------------------------------------------------------*/
1307 static gboolean
1308 object_selected (glViewObject *view_object)
1309 {
1310         glView *view;
1311
1312         gl_debug (DEBUG_VIEW, "");
1313
1314         g_return_val_if_fail (GL_IS_VIEW_OBJECT (view_object), FALSE);
1315
1316         view = gl_view_object_get_view (view_object);
1317         if (g_list_find (view->selected_object_list, view_object) == NULL) {
1318                 return FALSE;
1319         }
1320         return TRUE;
1321 }
1322
1323 /*---------------------------------------------------------------------------*/
1324 /* PRIVATE.  Are there multiple objects in our current selection?            */
1325 /*---------------------------------------------------------------------------*/
1326 static gboolean
1327 multiple_items_selected (glView * view)
1328 {
1329         gl_debug (DEBUG_VIEW, "");
1330
1331         g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
1332
1333         if (view->selected_object_list == NULL)
1334                 return FALSE;
1335         if (view->selected_object_list->next == NULL)
1336                 return FALSE;
1337         return TRUE;
1338 }
1339
1340 /*****************************************************************************/
1341 /* Item event handler.                                                       */
1342 /*****************************************************************************/
1343 gint
1344 gl_view_item_event_handler (GnomeCanvasItem *item,
1345                             GdkEvent        *event,
1346                             glViewObject    *view_object)
1347 {
1348         glView *view;
1349
1350         gl_debug (DEBUG_VIEW, "");
1351
1352         view = gl_view_object_get_view(view_object);
1353         switch (view->state) {
1354
1355         case GL_VIEW_STATE_ARROW:
1356                 return item_event_arrow_mode (item, event, view_object);
1357
1358         default:
1359                 return FALSE;
1360
1361         }
1362
1363 }
1364
1365 /*---------------------------------------------------------------------------*/
1366 /* PRIVATE.  Item event handler (arrow mode)                                 */
1367 /*---------------------------------------------------------------------------*/
1368 static int
1369 item_event_arrow_mode (GnomeCanvasItem *item,
1370                        GdkEvent        *event,
1371                        glViewObject    *view_object)
1372 {
1373         static gdouble x, y;
1374         static gboolean dragging = FALSE;
1375         glView *view;
1376         GdkCursor *cursor;
1377         gdouble item_x, item_y;
1378         gdouble new_x, new_y;
1379         gboolean control_key_pressed;
1380
1381         gl_debug (DEBUG_VIEW, "");
1382
1383         item_x = event->button.x;
1384         item_y = event->button.y;
1385         gnome_canvas_item_w2i (item->parent, &item_x, &item_y);
1386
1387         view = gl_view_object_get_view(view_object);
1388
1389         switch (event->type) {
1390
1391         case GDK_BUTTON_PRESS:
1392                 gl_debug (DEBUG_VIEW, "BUTTON_PRESS");
1393                 control_key_pressed = event->button.state & GDK_CONTROL_MASK;
1394                 switch (event->button.button) {
1395                 case 1:
1396                         if (control_key_pressed) {
1397                                 if (object_selected (view_object)) {
1398                                         /* Un-selecting a selected item */
1399                                         unselect_object (view_object);
1400                                         return TRUE;
1401                                 } else {
1402                                         /* Add to current selection */
1403                                         select_object (view_object);
1404                                 }
1405                         } else {
1406                                 if (!object_selected (view_object)) {
1407                                         /* No control, key so remove any selections before adding */
1408                                         gl_view_unselect_all (view);
1409                                         /* Add to current selection */
1410                                         select_object (view_object);
1411                                 }
1412                         }
1413                         /* Go into dragging mode while button remains pressed. */
1414                         x = item_x;
1415                         y = item_y;
1416                         cursor = gdk_cursor_new (GDK_FLEUR);
1417                         gnome_canvas_item_grab (item,
1418                                                 GDK_POINTER_MOTION_MASK |
1419                                                 GDK_BUTTON_RELEASE_MASK |
1420                                                 GDK_BUTTON_PRESS_MASK,
1421                                                 cursor, event->button.time);
1422                         gdk_cursor_unref (cursor);
1423                         dragging = TRUE;
1424                         return TRUE;
1425
1426                 case 3:
1427                         if (!object_selected (view_object)) {
1428                                 if (!control_key_pressed) {
1429                                         /* No control, key so remove any selections before adding */
1430                                         gl_view_unselect_all (view);
1431                                 }
1432                         }
1433                         /* Add to current selection */
1434                         select_object (view_object);
1435                         /* bring up apropriate menu for selection. */
1436                         popup_selection_menu (view, view_object, event);
1437                         return TRUE;
1438
1439                 default:
1440                         return FALSE;
1441                 }
1442
1443         case GDK_BUTTON_RELEASE:
1444                 gl_debug (DEBUG_VIEW, "BUTTON_RELEASE");
1445                 switch (event->button.button) {
1446                 case 1:
1447                         /* Exit dragging mode */
1448                         gnome_canvas_item_ungrab (item, event->button.time);
1449                         dragging = FALSE;
1450                         return TRUE;
1451
1452                 default:
1453                         return FALSE;
1454                 }
1455
1456         case GDK_MOTION_NOTIFY:
1457                 gl_debug (DEBUG_VIEW, "MOTION_NOTIFY");
1458                 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
1459                         /* Dragging mode, move selection */
1460                         new_x = item_x;
1461                         new_y = item_y;
1462                         move_selected_items (view, (new_x - x), (new_y - y));
1463                         x = new_x;
1464                         y = new_y;
1465                         return TRUE;
1466                 } else {
1467                         return FALSE;
1468                 }
1469
1470         case GDK_2BUTTON_PRESS:
1471                 gl_debug (DEBUG_VIEW, "2BUTTON_PRESS");
1472                 switch (event->button.button) {
1473                 case 1:
1474                         /* Also exit dragging mode w/ double-click, run dlg */
1475                         gnome_canvas_item_ungrab (item, event->button.time);
1476                         dragging = FALSE;
1477                         select_object (view_object);
1478                         gl_view_object_show_dialog (view_object);
1479                         return TRUE;
1480
1481                 default:
1482                         return FALSE;
1483                 }
1484
1485         case GDK_ENTER_NOTIFY:
1486                 gl_debug (DEBUG_VIEW, "ENTER_NOTIFY");
1487                 cursor = gdk_cursor_new (GDK_FLEUR);
1488                 gdk_window_set_cursor (view->canvas->window, cursor);
1489                 gdk_cursor_unref (cursor);
1490                 return TRUE;
1491
1492         case GDK_LEAVE_NOTIFY:
1493                 gl_debug (DEBUG_VIEW, "LEAVE_NOTIFY");
1494                 cursor = gdk_cursor_new (GDK_LEFT_PTR);
1495                 gdk_window_set_cursor (view->canvas->window, cursor);
1496                 gdk_cursor_unref (cursor);
1497                 return TRUE;
1498
1499         default:
1500                 gl_debug (DEBUG_VIEW, "default");
1501                 return FALSE;
1502         }
1503
1504 }
1505
1506 /*---------------------------------------------------------------------------*/
1507 /* PRIVATE.  create menu for multiple selections.                            */
1508 /*---------------------------------------------------------------------------*/
1509 GtkWidget *
1510 new_selection_menu (glView * view)
1511 {
1512         GtkWidget *menu, *menuitem;
1513
1514         gl_debug (DEBUG_VIEW, "START");
1515
1516         g_return_val_if_fail (GL_IS_VIEW (view), NULL);
1517
1518         menu = gtk_menu_new ();
1519
1520         menuitem = gtk_menu_item_new_with_label (_("Delete"));
1521         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1522         gtk_widget_show (menuitem);
1523         g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
1524                                   G_CALLBACK (gl_view_delete_selection), view);
1525
1526         menuitem = gtk_menu_item_new ();
1527         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1528         gtk_widget_show (menuitem);
1529
1530         menuitem = gtk_menu_item_new_with_label (_("Bring to front"));
1531         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1532         gtk_widget_show (menuitem);
1533         g_signal_connect (G_OBJECT (menuitem), "activate",
1534                           G_CALLBACK (raise_selection_cb), view);
1535
1536         menuitem = gtk_menu_item_new_with_label (_("Send to back"));
1537         gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1538         gtk_widget_show (menuitem);
1539         g_signal_connect (G_OBJECT (menuitem), "activate",
1540                           G_CALLBACK (lower_selection_cb), view);
1541
1542         gl_debug (DEBUG_VIEW, "END");
1543
1544         return menu;
1545 }
1546
1547 /*---------------------------------------------------------------------------*/
1548 /* PRIVATE.  popup menu for given item.                                      */
1549 /*---------------------------------------------------------------------------*/
1550 static void
1551 popup_selection_menu (glView       *view,
1552                       glViewObject *view_object,
1553                       GdkEvent     *event)
1554 {
1555         GtkMenu *menu;
1556
1557         gl_debug (DEBUG_VIEW, "START");
1558
1559         g_return_if_fail (GL_IS_VIEW (view));
1560         g_return_if_fail (GL_IS_VIEW_OBJECT (view_object));
1561
1562         if (multiple_items_selected (view)) {
1563                 if (view->menu != NULL) {
1564                         gtk_menu_popup (GTK_MENU (view->menu),
1565                                         NULL, NULL, NULL, NULL,
1566                                         event->button.button,
1567                                         event->button.time);
1568                 }
1569         } else {
1570
1571                 menu = gl_view_object_get_menu (view_object);
1572                 if (menu != NULL) {
1573                         gtk_menu_popup (GTK_MENU (menu),
1574                                         NULL, NULL, NULL, NULL,
1575                                         event->button.button,
1576                                         event->button.time);
1577                 }
1578
1579         }
1580
1581         gl_debug (DEBUG_VIEW, "END");
1582 }
1583
1584 /*---------------------------------------------------------------------------*/
1585 /* Delete selected objects.                                                  */
1586 /*---------------------------------------------------------------------------*/
1587 void
1588 gl_view_delete_selection (glView * view)
1589 {
1590         GList *p, *p_next;
1591
1592         gl_debug (DEBUG_VIEW, "START");
1593
1594         g_return_if_fail (GL_IS_VIEW (view));
1595
1596         for (p = view->selected_object_list; p != NULL; p = p_next) {
1597                 p_next = p->next;
1598                 g_object_unref (G_OBJECT (p->data));
1599         }
1600
1601         gl_debug (DEBUG_VIEW, "END");
1602 }
1603
1604 /*---------------------------------------------------------------------------*/
1605 /* PRIVATE.  raise item to front callback.                                   */
1606 /*---------------------------------------------------------------------------*/
1607 static void
1608 raise_selection_cb (GtkWidget * widget,
1609                     glView * view)
1610 {
1611         GList *p;
1612
1613         gl_debug (DEBUG_VIEW, "START");
1614
1615         g_return_if_fail (GL_IS_VIEW (view));
1616
1617         for (p = view->selected_object_list; p != NULL; p = p->next) {
1618                 gl_label_object_raise_to_top (GL_LABEL_OBJECT (p->data));
1619         }
1620
1621         gl_debug (DEBUG_VIEW, "END");
1622 }
1623
1624 /*---------------------------------------------------------------------------*/
1625 /* PRIVATE.  lower item to back callback.                                    */
1626 /*---------------------------------------------------------------------------*/
1627 static void
1628 lower_selection_cb (GtkWidget * widget,
1629                     glView * view)
1630 {
1631         GList *p;
1632
1633         gl_debug (DEBUG_VIEW, "START");
1634
1635         g_return_if_fail (GL_IS_VIEW (view));
1636
1637         for (p = view->selected_object_list; p != NULL; p = p->next) {
1638                 gl_label_object_lower_to_bottom (GL_LABEL_OBJECT (p->data));
1639         }
1640
1641         gl_debug (DEBUG_VIEW, "END");
1642 }
1643
1644 /*---------------------------------------------------------------------------*/
1645 /* PRIVATE.  move selected items                                             */
1646 /*---------------------------------------------------------------------------*/
1647 static void
1648 move_selected_items (glView * view,
1649                      gdouble dx,
1650                      gdouble dy)
1651 {
1652         GList *p;
1653         glLabelObject *object;
1654
1655         gl_debug (DEBUG_VIEW, "START");
1656
1657         g_return_if_fail (GL_IS_VIEW (view));
1658
1659         for (p = view->selected_object_list; p != NULL; p = p->next) {
1660
1661                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
1662                 gl_label_object_set_position_relative (object, dx, dy);
1663
1664         }
1665
1666         gl_debug (DEBUG_VIEW, "END");
1667 }
1668
1669 /*---------------------------------------------------------------------------*/
1670 /* PRIVATE.  Handle "selection-clear" signal.                                */
1671 /*---------------------------------------------------------------------------*/
1672 static void
1673 selection_clear_cb (GtkWidget * widget,
1674                     GdkEventSelection * event,
1675                     gpointer data)
1676 {
1677         glView *view = GL_VIEW (data);
1678
1679         gl_debug (DEBUG_VIEW, "START");
1680
1681         g_return_if_fail (GL_IS_VIEW (view));
1682
1683         view->have_selection = FALSE;
1684         g_object_unref (view->selection_data);
1685         view->selection_data = NULL;
1686
1687         gl_debug (DEBUG_VIEW, "END");
1688 }
1689
1690 /*---------------------------------------------------------------------------*/
1691 /* PRIVATE.  Handle "selection-get" signal.                                  */
1692 /*---------------------------------------------------------------------------*/
1693 static void
1694 selection_get_cb (GtkWidget * widget,
1695                   GtkSelectionData * selection_data,
1696                   guint info,
1697                   guint time,
1698                   gpointer data)
1699 {
1700         glView *view = GL_VIEW (data);
1701         gchar *buffer;
1702         glXMLLabelStatus status;
1703
1704         gl_debug (DEBUG_VIEW, "START");
1705
1706         g_return_if_fail (GL_IS_VIEW (view));
1707
1708         if (view->have_selection) {
1709
1710                 buffer = gl_xml_label_save_buffer (view->selection_data,
1711                                                    &status);
1712                 gtk_selection_data_set (selection_data,
1713                                         GDK_SELECTION_TYPE_STRING, 8, buffer,
1714                                         strlen (buffer));
1715                 g_free (buffer);
1716         }
1717
1718         gl_debug (DEBUG_VIEW, "END");
1719 }
1720
1721 /*---------------------------------------------------------------------------*/
1722 /* PRIVATE.  Handle "selection-received" signal.  (Result of Paste)          */
1723 /*---------------------------------------------------------------------------*/
1724 static void
1725 selection_received_cb (GtkWidget * widget,
1726                        GtkSelectionData * selection_data,
1727                        guint time,
1728                        gpointer data)
1729 {
1730         glView *view = GL_VIEW (data);
1731         glLabel *label = NULL;
1732         glXMLLabelStatus status;
1733         GList *p, *p_next;
1734         glLabelObject *object, *newobject;
1735         glViewObject *view_object;
1736
1737         gl_debug (DEBUG_VIEW, "START");
1738
1739         g_return_if_fail (GL_IS_VIEW (view));
1740
1741         if (selection_data->length < 0) {
1742                 return;
1743         }
1744         if (selection_data->type != GDK_SELECTION_TYPE_STRING) {
1745                 return;
1746         }
1747
1748         gl_view_unselect_all (view);
1749
1750         label = gl_xml_label_open_buffer (selection_data->data, &status);
1751         for (p = label->objects; p != NULL; p = p_next) {
1752                 p_next = p->next;
1753
1754                 object = (glLabelObject *) p->data;
1755                 gl_label_object_set_parent (object, view->label);
1756
1757                 gl_debug (DEBUG_VIEW, "object pasted");
1758
1759                 if (GL_IS_LABEL_BOX (object)) {
1760                         view_object = gl_view_box_new (GL_LABEL_BOX(object),
1761                                                        view);
1762                 } else if (GL_IS_LABEL_ELLIPSE (object)) {
1763                         view_object = gl_view_ellipse_new (GL_LABEL_ELLIPSE(object),
1764                                                            view);
1765                 } else if (GL_IS_LABEL_LINE (object)) {
1766                         view_object = gl_view_line_new (GL_LABEL_LINE(object),
1767                                                         view);
1768                 } else if (GL_IS_LABEL_IMAGE (object)) {
1769                         view_object = gl_view_image_new (GL_LABEL_IMAGE(object),
1770                                                          view);
1771                 } else if (GL_IS_LABEL_TEXT (object)) {
1772                         view_object = gl_view_text_new (GL_LABEL_TEXT(object),
1773                                                         view);
1774                 } else if (GL_IS_LABEL_BARCODE (object)) {
1775                         view_object = gl_view_barcode_new (GL_LABEL_BARCODE(object),
1776                                                            view);
1777                 } else {
1778                         /* Should not happen! */
1779                         view_object = NULL;
1780                         g_warning ("Invalid label object type.");
1781                 }
1782                 select_object (view_object);
1783         }
1784         g_object_unref (label);
1785
1786         gl_debug (DEBUG_VIEW, "END");
1787 }
1788
1789 /*****************************************************************************/
1790 /* Zoom in one "notch"                                                       */
1791 /*****************************************************************************/
1792 void
1793 gl_view_zoom_in (glView * view)
1794 {
1795         gint i, i_min;
1796         gdouble dist, dist_min;
1797
1798         gl_debug (DEBUG_VIEW, "START");
1799
1800         g_return_if_fail (GL_IS_VIEW (view));
1801
1802         /* Find index of current scale (or best match) */
1803         i_min = 1;              /* start with 2nd largest scale */
1804         dist_min = fabs (scales[1] - view->scale);
1805         for (i = 2; scales[i] != 0.0; i++) {
1806                 dist = fabs (scales[i] - view->scale);
1807                 if (dist < dist_min) {
1808                         i_min = i;
1809                         dist_min = dist;
1810                 }
1811         }
1812
1813         /* zoom in one "notch" */
1814         i = MAX (0, i_min - 1);
1815         gl_view_set_zoom (view, scales[i] / HOME_SCALE);
1816
1817         gl_debug (DEBUG_VIEW, "END");
1818 }
1819
1820 /*****************************************************************************/
1821 /* Zoom out one "notch"                                                      */
1822 /*****************************************************************************/
1823 void
1824 gl_view_zoom_out (glView * view)
1825 {
1826         gint i, i_min;
1827         gdouble dist, dist_min;
1828
1829         gl_debug (DEBUG_VIEW, "START");
1830
1831         g_return_if_fail (GL_IS_VIEW (view));
1832
1833         /* Find index of current scale (or best match) */
1834         i_min = 0;              /* start with largest scale */
1835         dist_min = fabs (scales[0] - view->scale);
1836         for (i = 1; scales[i] != 0.0; i++) {
1837                 dist = fabs (scales[i] - view->scale);
1838                 if (dist < dist_min) {
1839                         i_min = i;
1840                         dist_min = dist;
1841                 }
1842         }
1843
1844         /* zoom out one "notch" */
1845         if (scales[i_min] == 0.0)
1846                 return;
1847         i = i_min + 1;
1848         if (scales[i] == 0.0)
1849                 return;
1850         gl_view_set_zoom (view, scales[i] / HOME_SCALE);
1851
1852         gl_debug (DEBUG_VIEW, "END");
1853 }
1854
1855 /*****************************************************************************/
1856 /* Set current zoom factor to explicit value.                                */
1857 /*****************************************************************************/
1858 void
1859 gl_view_set_zoom (glView * view,
1860                      gdouble scale)
1861 {
1862         gl_debug (DEBUG_VIEW, "START");
1863
1864         g_return_if_fail (GL_IS_VIEW (view));
1865         g_return_if_fail (scale > 0.0);
1866
1867         view->scale = scale * HOME_SCALE;
1868         gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (view->canvas),
1869                                           scale * HOME_SCALE);
1870
1871         gl_debug (DEBUG_VIEW, "END");
1872 }
1873
1874 /*****************************************************************************/
1875 /* Get current zoom factor.                                                  */
1876 /*****************************************************************************/
1877 gdouble
1878 gl_view_get_zoom (glView * view)
1879 {
1880         gl_debug (DEBUG_VIEW, "");
1881
1882         g_return_val_if_fail (GL_IS_VIEW (view), 1.0);
1883
1884         return view->scale / HOME_SCALE;
1885 }