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