]> git.sur5r.net Git - glabels/blob - src/view.c
Use accessor functions instead direct access
[glabels] / src / view.c
1 /*
2  *  view.c
3  *  Copyright (C) 2001-2009  Jim Evins <evins@snaught.com>.
4  *
5  *  This file is part of gLabels.
6  *
7  *  gLabels is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  gLabels is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with gLabels.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #include "view.h"
24
25 #include <glib/gi18n.h>
26 #include <gtk/gtk.h>
27 #include <gdk/gdkkeysyms.h>
28 #include <string.h>
29 #include <math.h>
30
31 #include "label.h"
32 #include "cairo-label-path.h"
33 #include "cairo-markup-path.h"
34 #include "view-object.h"
35 #include "view-box.h"
36 #include "view-ellipse.h"
37 #include "view-line.h"
38 #include "view-image.h"
39 #include "view-text.h"
40 #include "view-barcode.h"
41 #include "xml-label.h"
42 #include "color.h"
43 #include "prefs.h"
44 #include "marshal.h"
45
46 #include "debug.h"
47
48
49 /*==========================================================================*/
50 /* Private macros and constants.                                            */
51 /*==========================================================================*/
52
53 #define BG_COLOR        GL_COLOR (192, 192, 192)
54
55 #define PAPER_RGB_ARGS          1.0,   1.0,   1.0
56 #define GRID_RGB_ARGS           0.753, 0.753, 0.753
57 #define MARKUP_RGB_ARGS         0.94,  0.39,  0.39
58 #define OUTLINE_RGB_ARGS        0.68,  0.85,  0.90
59 #define SELECT_LINE_RGBA_ARGS   0.0,   0.0,   1.0,   0.5
60 #define SELECT_FILL_RGBA_ARGS   0.75,  0.75,  1.0,   0.5
61
62 #define GRID_LINE_WIDTH_PIXELS    1.0
63 #define MARKUP_LINE_WIDTH_PIXELS  1.0
64 #define OUTLINE_WIDTH_PIXELS      3.0
65 #define SELECT_LINE_WIDTH_PIXELS  3.0
66
67 #define ZOOMTOFIT_PAD   16
68
69 #define POINTS_PER_MM    2.83464566929
70
71
72 /*==========================================================================*/
73 /* Private types.                                                           */
74 /*==========================================================================*/
75
76 enum {
77         SELECTION_CHANGED,
78         CONTEXT_MENU_ACTIVATE,
79         ZOOM_CHANGED,
80         POINTER_MOVED,
81         POINTER_EXIT,
82         MODE_CHANGED,
83         LAST_SIGNAL
84 };
85
86
87 /*==========================================================================*/
88 /* Private globals                                                          */
89 /*==========================================================================*/
90
91 static guint signals[LAST_SIGNAL] = {0};
92
93 /* "CLIPBOARD" selection */
94 static GdkAtom clipboard_atom = GDK_NONE;
95
96 static gdouble zooms[] = {
97         8.00,
98         6.00,
99         4.00,
100         3.00,
101         2.00,
102         1.50,
103         1.00,
104         0.75,
105         0.67,
106         0.50,
107         0.33,
108         0.25,
109         0.20,
110         0.15,
111         0.10,
112 };
113 #define N_ZOOMS G_N_ELEMENTS(zooms)
114
115
116 /*==========================================================================*/
117 /* Local function prototypes                                                */
118 /*==========================================================================*/
119
120 static void       gl_view_finalize                (GObject        *object);
121
122 static void       gl_view_construct               (glView         *view,
123                                                    glLabel        *label);
124
125 static gdouble    get_home_scale                  (glView         *view);
126
127 static gboolean   expose_cb                       (glView         *view,
128                                                    GdkEventExpose *event);
129
130 static void       realize_cb                      (glView         *view);
131
132 static void       size_allocate_cb                (glView         *view,
133                                                    GtkAllocation  *allocation);
134
135 static void       screen_changed_cb               (glView         *view);
136
137 static void       label_changed_cb                (glView         *view);
138
139 static void       label_resized_cb                (glView         *view);
140
141 static void       label_object_added_cb           (glView         *view,
142                                                    glLabelObject  *object);
143
144 static void       draw_layers                     (glView         *view,
145                                                    cairo_t        *cr);
146
147 static void       draw_bg_layer                   (glView         *view,
148                                                    cairo_t        *cr);
149 static void       draw_grid_layer                 (glView         *view,
150                                                    cairo_t        *cr);
151 static void       draw_markup_layer               (glView         *view,
152                                                    cairo_t        *cr);
153 static void       draw_objects_layer              (glView         *view,
154                                                    cairo_t        *cr);
155 static void       draw_fg_layer                   (glView         *view,
156                                                    cairo_t        *cr);
157 static void       draw_highlight_layer            (glView         *view,
158                                                    cairo_t        *cr);
159 static void       draw_select_region_layer        (glView         *view,
160                                                    cairo_t        *cr);
161
162 static void       select_object_real              (glView         *view,
163                                                    glViewObject   *view_object);
164 static void       unselect_object_real            (glView         *view,
165                                                    glViewObject   *view_object);
166
167 static glViewObject *view_view_object_at          (glView         *view,
168                                                    cairo_t        *cr,
169                                                    gdouble         x,
170                                                    gdouble         y);
171
172 static void       set_zoom_real                   (glView         *view,
173                                                    gdouble         zoom,
174                                                    gboolean        scale_to_fit_flag);
175
176 static void       selection_clear_cb              (GtkWidget         *widget,
177                                                    GdkEventSelection *event,
178                                                    glView            *view);
179
180 static void       selection_get_cb                (GtkWidget         *widget,
181                                                    GtkSelectionData  *selection_data,
182                                                    guint              info,
183                                                    guint              time,
184                                                    glView            *view);
185
186 static void       selection_received_cb           (GtkWidget         *widget,
187                                                    GtkSelectionData  *selection_data,
188                                                    guint              time,
189                                                    glView            *view);
190
191 static gboolean   focus_in_event_cb               (glView            *view,
192                                                    GdkEventFocus     *event);
193
194 static gboolean   focus_out_event_cb              (glView            *view,
195                                                    GdkEventFocus     *event);
196
197 static gboolean   enter_notify_event_cb           (glView            *view,
198                                                    GdkEventCrossing  *event);
199
200 static gboolean   leave_notify_event_cb           (glView            *view,
201                                                    GdkEventCrossing  *event);
202
203 static gboolean   motion_notify_event_cb          (glView            *view,
204                                                    GdkEventMotion    *event);
205
206 static gboolean   button_press_event_cb           (glView            *view,
207                                                    GdkEventButton    *event);
208
209 static gboolean   button_release_event_cb         (glView            *view,
210                                                    GdkEventButton    *event);
211
212 static gboolean   key_press_event_cb              (glView            *view,
213                                                    GdkEventKey       *event);
214
215
216 /****************************************************************************/
217 /* Boilerplate Object stuff.                                                */
218 /****************************************************************************/
219 G_DEFINE_TYPE (glView, gl_view, GTK_TYPE_VBOX);
220
221
222 static void
223 gl_view_class_init (glViewClass *class)
224 {
225         GObjectClass *object_class = G_OBJECT_CLASS (class);
226
227         gl_debug (DEBUG_VIEW, "START");
228
229         gl_view_parent_class = g_type_class_peek_parent (class);
230
231         object_class->finalize = gl_view_finalize;
232
233         signals[SELECTION_CHANGED] =
234                 g_signal_new ("selection_changed",
235                               G_OBJECT_CLASS_TYPE (object_class),
236                               G_SIGNAL_RUN_LAST,
237                               G_STRUCT_OFFSET (glViewClass, selection_changed),
238                               NULL, NULL,
239                               gl_marshal_VOID__VOID,
240                               G_TYPE_NONE,
241                               0);
242
243         signals[CONTEXT_MENU_ACTIVATE] =
244                 g_signal_new ("context_menu_activate",
245                               G_OBJECT_CLASS_TYPE (object_class),
246                               G_SIGNAL_RUN_LAST,
247                               G_STRUCT_OFFSET (glViewClass, context_menu_activate),
248                               NULL, NULL,
249                               gl_marshal_VOID__INT_UINT,
250                               G_TYPE_NONE,
251                               2, G_TYPE_INT, G_TYPE_UINT);
252
253         signals[ZOOM_CHANGED] =
254                 g_signal_new ("zoom_changed",
255                               G_OBJECT_CLASS_TYPE (object_class),
256                               G_SIGNAL_RUN_LAST,
257                               G_STRUCT_OFFSET (glViewClass, zoom_changed),
258                               NULL, NULL,
259                               gl_marshal_VOID__DOUBLE,
260                               G_TYPE_NONE,
261                               1, G_TYPE_DOUBLE);
262
263         signals[POINTER_MOVED] =
264                 g_signal_new ("pointer_moved",
265                               G_OBJECT_CLASS_TYPE (object_class),
266                               G_SIGNAL_RUN_LAST,
267                               G_STRUCT_OFFSET (glViewClass, pointer_moved),
268                               NULL, NULL,
269                               gl_marshal_VOID__DOUBLE_DOUBLE,
270                               G_TYPE_NONE,
271                               2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
272
273         signals[POINTER_EXIT] =
274                 g_signal_new ("pointer_exit",
275                               G_OBJECT_CLASS_TYPE (object_class),
276                               G_SIGNAL_RUN_LAST,
277                               G_STRUCT_OFFSET (glViewClass, pointer_exit),
278                               NULL, NULL,
279                               gl_marshal_VOID__VOID,
280                               G_TYPE_NONE,
281                               0);
282
283         signals[MODE_CHANGED] =
284                 g_signal_new ("mode_changed",
285                               G_OBJECT_CLASS_TYPE (object_class),
286                               G_SIGNAL_RUN_LAST,
287                               G_STRUCT_OFFSET (glViewClass, mode_changed),
288                               NULL, NULL,
289                               gl_marshal_VOID__VOID,
290                               G_TYPE_NONE,
291                               0);
292
293         gl_debug (DEBUG_VIEW, "END");
294 }
295
296
297 static void
298 gl_view_init (glView *view)
299 {
300         GtkWidget *wscroll;
301         GdkColor  *bg_color;
302
303         gl_debug (DEBUG_VIEW, "START");
304
305         view->label                = NULL;
306         view->grid_visible         = TRUE;
307         view->grid_spacing         = 9;
308         view->markup_visible       = TRUE;
309         view->default_font_family  = NULL;
310         view->mode                 = GL_VIEW_MODE_ARROW;
311         view->object_list          = NULL;
312         view->selected_object_list = NULL;
313         view->zoom                 = 1.0;
314         view->home_scale           = get_home_scale (view);
315
316         /*
317          * Canvas
318          */
319         view->canvas = gtk_layout_new (NULL, NULL);
320         wscroll = gtk_scrolled_window_new (NULL, NULL);
321         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (wscroll),
322                                         GTK_POLICY_AUTOMATIC,
323                                         GTK_POLICY_AUTOMATIC);
324         gtk_box_pack_start (GTK_BOX (view), wscroll, TRUE, TRUE, 0);
325         gtk_container_add (GTK_CONTAINER (wscroll), view->canvas);
326
327         bg_color = gl_color_to_gdk_color (BG_COLOR);
328         gtk_widget_modify_bg (GTK_WIDGET (view->canvas), GTK_STATE_NORMAL, bg_color);
329         g_free (bg_color);
330
331         gtk_widget_set_can_focus (GTK_WIDGET (view->canvas), TRUE);
332
333         gtk_widget_add_events (GTK_WIDGET (view->canvas),
334                                (GDK_FOCUS_CHANGE_MASK   |
335                                 GDK_ENTER_NOTIFY_MASK   |
336                                 GDK_LEAVE_NOTIFY_MASK   |
337                                 GDK_POINTER_MOTION_MASK |
338                                 GDK_BUTTON_PRESS_MASK   |
339                                 GDK_BUTTON_RELEASE_MASK |
340                                 GDK_KEY_PRESS_MASK));
341
342         g_signal_connect_swapped (G_OBJECT (view->canvas), "expose-event",
343                                   G_CALLBACK (expose_cb), view);
344         g_signal_connect_swapped (G_OBJECT (view->canvas), "realize",
345                                   G_CALLBACK (realize_cb), view);
346         g_signal_connect_swapped (G_OBJECT (view->canvas), "size-allocate",
347                                   G_CALLBACK (size_allocate_cb), view);
348         g_signal_connect_swapped (G_OBJECT (view->canvas), "screen-changed",
349                                   G_CALLBACK (screen_changed_cb), view);
350         g_signal_connect_swapped (G_OBJECT (view->canvas), "focus-in-event",
351                                   G_CALLBACK (focus_in_event_cb), view);
352         g_signal_connect_swapped (G_OBJECT (view->canvas), "focus-out-event",
353                                   G_CALLBACK (focus_out_event_cb), view);
354         g_signal_connect_swapped (G_OBJECT (view->canvas), "enter-notify-event",
355                                   G_CALLBACK (enter_notify_event_cb), view);
356         g_signal_connect_swapped (G_OBJECT (view->canvas), "leave-notify-event",
357                                   G_CALLBACK (leave_notify_event_cb), view);
358         g_signal_connect_swapped (G_OBJECT (view->canvas), "motion-notify-event",
359                                   G_CALLBACK (motion_notify_event_cb), view);
360         g_signal_connect_swapped (G_OBJECT (view->canvas), "button-press-event",
361                                   G_CALLBACK (button_press_event_cb), view);
362         g_signal_connect_swapped (G_OBJECT (view->canvas), "button-release-event",
363                                   G_CALLBACK (button_release_event_cb), view);
364         g_signal_connect_swapped (G_OBJECT (view->canvas), "key-press-event",
365                                   G_CALLBACK (key_press_event_cb), view);
366
367         /*
368          * Clipboard
369          */
370         view->have_selection       = FALSE;
371         view->selection_data       = NULL;
372         view->invisible            = gtk_invisible_new ();
373         if (!clipboard_atom) {
374                 clipboard_atom = gdk_atom_intern ("GLABELS_CLIPBOARD", FALSE);
375         }
376         gtk_selection_add_target (view->invisible,
377                                   clipboard_atom, GDK_SELECTION_TYPE_STRING, 1);
378         g_signal_connect (G_OBJECT (view->invisible),
379                           "selection_clear_event",
380                           G_CALLBACK (selection_clear_cb), view);
381         g_signal_connect (G_OBJECT (view->invisible), "selection_get",
382                           G_CALLBACK (selection_get_cb), view);
383         g_signal_connect (G_OBJECT (view->invisible),
384                           "selection_received",
385                           G_CALLBACK (selection_received_cb), view);
386
387         /*
388          * Defaults from preferences
389          */
390         gl_view_set_default_font_family       (view, gl_prefs_model_get_default_font_family (gl_prefs));
391         gl_view_set_default_font_size         (view, gl_prefs_model_get_default_font_size (gl_prefs));
392         gl_view_set_default_font_weight       (view, gl_prefs_model_get_default_font_weight (gl_prefs));
393         gl_view_set_default_font_italic_flag  (view, gl_prefs_model_get_default_font_italic_flag (gl_prefs));
394         gl_view_set_default_text_color        (view, gl_prefs_model_get_default_text_color (gl_prefs));
395         gl_view_set_default_text_alignment    (view, gl_prefs_model_get_default_text_alignment (gl_prefs));
396         gl_view_set_default_text_line_spacing (view, gl_prefs_model_get_default_text_line_spacing (gl_prefs));
397         gl_view_set_default_line_width        (view, gl_prefs_model_get_default_line_width (gl_prefs));
398         gl_view_set_default_line_color        (view, gl_prefs_model_get_default_line_color (gl_prefs));
399         gl_view_set_default_fill_color        (view, gl_prefs_model_get_default_fill_color (gl_prefs));
400
401         gl_debug (DEBUG_VIEW, "END");
402 }
403
404
405 static void
406 gl_view_finalize (GObject *object)
407 {
408         glView *view = GL_VIEW (object);
409
410         gl_debug (DEBUG_VIEW, "START");
411
412         g_return_if_fail (object != NULL);
413         g_return_if_fail (GL_IS_VIEW (object));
414
415         if (view->default_font_family) {
416                 g_free (view->default_font_family);
417         }
418
419         G_OBJECT_CLASS (gl_view_parent_class)->finalize (object);
420
421         gl_debug (DEBUG_VIEW, "END");
422 }
423
424
425 /****************************************************************************/
426 /* NEW view object.                                                         */
427 /****************************************************************************/
428 GtkWidget *
429 gl_view_new (glLabel *label)
430 {
431         glView *view;
432
433         gl_debug (DEBUG_VIEW, "START");
434
435         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
436
437         view = g_object_new (GL_TYPE_VIEW, NULL);
438
439         gl_view_construct (view, label);
440
441         gl_debug (DEBUG_VIEW, "END");
442
443         return GTK_WIDGET (view);
444 }
445
446
447 /*---------------------------------------------------------------------------*/
448 /* PRIVATE.  Construct composite widget.                                     */
449 /*---------------------------------------------------------------------------*/
450 static void
451 gl_view_construct (glView  *view,
452                    glLabel *label)
453 {
454         GList            *p_obj;
455         glLabelObject    *object;
456
457         gl_debug (DEBUG_VIEW, "START");
458
459         g_return_if_fail (GL_IS_VIEW (view));
460
461         view->label = label;
462
463         for (p_obj = label->objects; p_obj != NULL; p_obj = p_obj->next)
464         {
465                 object = GL_LABEL_OBJECT (p_obj->data);
466
467                 if (GL_IS_LABEL_BOX (object)) {
468                         gl_view_box_new (GL_LABEL_BOX(object), view);
469                 } else if (GL_IS_LABEL_ELLIPSE (object)) {
470                         gl_view_ellipse_new (GL_LABEL_ELLIPSE(object), view);
471                 } else if (GL_IS_LABEL_LINE (object)) {
472                         gl_view_line_new (GL_LABEL_LINE(object), view);
473                 } else if (GL_IS_LABEL_IMAGE (object)) {
474                         gl_view_image_new (GL_LABEL_IMAGE(object), view);
475                 } else if (GL_IS_LABEL_TEXT (object)) {
476                         gl_view_text_new (GL_LABEL_TEXT(object), view);
477                 } else if (GL_IS_LABEL_BARCODE (object)) {
478                         gl_view_barcode_new (GL_LABEL_BARCODE(object), view);
479                 } else {
480                         /* Should not happen! */
481                         g_message ("Invalid label object type.");
482                 }
483         }
484
485         g_signal_connect_swapped (G_OBJECT (view->label), "changed",
486                                   G_CALLBACK (label_changed_cb), view);
487         g_signal_connect_swapped (G_OBJECT (view->label), "size_changed",
488                                   G_CALLBACK (label_resized_cb), view);
489         g_signal_connect_swapped (G_OBJECT (view->label), "object_added",
490                                   G_CALLBACK (label_object_added_cb), view);
491
492         gl_debug (DEBUG_VIEW, "END");
493 }
494
495
496 /*---------------------------------------------------------------------------*/
497 /* PRIAVTE.  Calculate 1:1 scale for screen.                                 */
498 /*---------------------------------------------------------------------------*/
499 static gdouble
500 get_home_scale (glView *view)
501 {
502         GdkScreen *screen;
503         gdouble    screen_width_pixels;
504         gdouble    screen_width_mm;
505         gdouble    screen_height_pixels;
506         gdouble    screen_height_mm;
507         gdouble    x_pixels_per_mm;
508         gdouble    y_pixels_per_mm;
509         gdouble    scale;
510
511         if (view->canvas == NULL) return 1.0;
512
513         if (!gtk_widget_has_screen (GTK_WIDGET (view->canvas))) return 1.0;
514
515         screen = gtk_widget_get_screen (GTK_WIDGET (view->canvas));
516
517         gl_debug (DEBUG_VIEW, "Screen = %p", screen);
518
519         screen_width_pixels  = gdk_screen_get_width (screen);
520         screen_width_mm      = gdk_screen_get_width_mm (screen);
521         screen_height_pixels = gdk_screen_get_height (screen);
522         screen_height_mm     = gdk_screen_get_height_mm (screen);
523
524         x_pixels_per_mm      = screen_width_pixels / screen_width_mm;
525         y_pixels_per_mm      = screen_height_pixels / screen_height_mm;
526
527         gl_debug (DEBUG_VIEW, "Horizontal dot pitch: %g pixels/mm (%g dpi)",
528                   x_pixels_per_mm, x_pixels_per_mm * 25.4);
529         gl_debug (DEBUG_VIEW, "Vertical dot pitch: %g pixels/mm (%g dpi)",
530                   y_pixels_per_mm, y_pixels_per_mm * 25.4);
531
532         scale = (x_pixels_per_mm + y_pixels_per_mm) / 2.0;
533
534         gl_debug (DEBUG_VIEW, "Average dot pitch: %g pixels/mm (%g dpi)",
535                   scale, scale * 25.4);
536
537         scale /= POINTS_PER_MM;
538
539         gl_debug (DEBUG_VIEW, "Scale = %g pixels/point", scale);
540
541         /* Make sure scale is somewhat sane. */
542         if ( (scale < 0.25) || (scale > 4.0) ) return 1.0;
543
544         return scale;
545 }
546
547
548 /*---------------------------------------------------------------------------*/
549 /* Schedule canvas update.                                                   */
550 /*---------------------------------------------------------------------------*/
551 void
552 gl_view_update (glView  *view)
553 {
554         GdkWindow *window;
555         GdkRegion *region;
556         
557         gl_debug (DEBUG_VIEW, "START");
558
559         window = gtk_widget_get_window (GTK_WIDGET (view->canvas));
560         
561         if (!window) return;
562
563         if ( !view->update_scheduled_flag )
564         {
565                 view->update_scheduled_flag = TRUE;
566
567                 region = gdk_drawable_get_clip_region (window);
568                 /* redraw the cairo canvas completely by exposing it */
569                 gdk_window_invalidate_region (window, region, TRUE);
570                 gdk_region_destroy (region);
571         }
572
573         gl_debug (DEBUG_VIEW, "END");
574 }
575
576
577 /*---------------------------------------------------------------------------*/
578 /* Schedule canvas region update.                                            */
579 /*---------------------------------------------------------------------------*/
580 void
581 gl_view_update_region (glView        *view,
582                        cairo_t       *cr,
583                        glLabelRegion *region)
584 {
585         GdkWindow    *window;
586         GdkRectangle  rect;
587         gdouble       x, y, w, h;
588
589         gl_debug (DEBUG_VIEW, "START");
590
591         window = gtk_widget_get_window (GTK_WIDGET (view->canvas));
592
593         if (!window) return;
594
595         x = MIN (region->x1, region->x2);
596         y = MIN (region->y1, region->y2);
597         w = fabs (region->x2 - region->x1);
598         h = fabs (region->y2 - region->y1);
599
600         cairo_user_to_device (cr, &x, &y);
601         cairo_user_to_device_distance (cr, &w, &h);
602
603         rect.x      = x - 3;
604         rect.y      = y - 3;
605         rect.width  = w + 6;
606         rect.height = h + 6;
607
608         gdk_window_invalidate_rect (window, &rect, TRUE);
609
610         gl_debug (DEBUG_VIEW, "END");
611 }
612
613
614 /*---------------------------------------------------------------------------*/
615 /* PRIVATE.  Expose handler.                                                 */
616 /*---------------------------------------------------------------------------*/
617 static gboolean
618 expose_cb (glView         *view,
619            GdkEventExpose *event)
620 {
621         GdkWindow *bin_window;
622         cairo_t   *cr;
623
624         gl_debug (DEBUG_VIEW, "START");
625
626         view->update_scheduled_flag = FALSE;
627
628         bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (view->canvas));
629         cr = gdk_cairo_create (bin_window);
630
631         cairo_rectangle (cr,
632                         event->area.x, event->area.y,
633                         event->area.width, event->area.height);
634         cairo_clip (cr);
635         
636         draw_layers (view, cr);
637
638         cairo_destroy (cr);
639
640         gl_debug (DEBUG_VIEW, "END");
641
642         return FALSE;
643 }
644
645
646 /*---------------------------------------------------------------------------*/
647 /* PRIVATE.  Realize handler.                                                */
648 /*---------------------------------------------------------------------------*/
649 static void
650 realize_cb (glView  *view)
651 {
652         g_return_if_fail (view && GL_IS_VIEW (view));
653
654         gl_debug (DEBUG_VIEW, "START");
655
656         gl_debug (DEBUG_VIEW, "END");
657 }
658
659
660 /*---------------------------------------------------------------------------*/
661 /* PRIVATE. Size allocation changed callback.                                */
662 /*---------------------------------------------------------------------------*/
663 static void
664 size_allocate_cb (glView         *view,
665                   GtkAllocation  *allocation)
666 {
667         GtkAdjustment *hadjustment;
668         GtkAdjustment *vadjustment;
669
670         gl_debug (DEBUG_VIEW, "START");
671
672         hadjustment = gtk_layout_get_hadjustment(GTK_LAYOUT (view->canvas));
673         vadjustment = gtk_layout_get_vadjustment(GTK_LAYOUT (view->canvas));
674
675         gtk_adjustment_set_page_size( hadjustment, allocation->width);
676         gtk_adjustment_set_page_increment( hadjustment, allocation->width / 2);
677
678         gtk_adjustment_set_page_size( vadjustment, allocation->height);
679         gtk_adjustment_set_page_increment( vadjustment, allocation->height / 2);
680
681         g_signal_emit_by_name (hadjustment, "changed");
682         g_signal_emit_by_name (vadjustment, "changed");
683
684         if (view->zoom_to_fit_flag) {
685                 /* Maintain best fit zoom */
686                 gl_view_zoom_to_fit (view);
687         }
688
689         gl_debug (DEBUG_VIEW, "END");
690 }
691
692
693 /*---------------------------------------------------------------------------*/
694 /* PRIVATE. Screen changed callback.                                         */
695 /*---------------------------------------------------------------------------*/
696 static void
697 screen_changed_cb (glView *view)
698 {
699         gl_debug (DEBUG_VIEW, "START");
700
701         if (gtk_widget_has_screen (GTK_WIDGET (view->canvas))) {
702
703                 view->home_scale = get_home_scale (view);
704
705                 if (view->zoom_to_fit_flag) {
706                         /* Maintain best fit zoom */
707                         gl_view_zoom_to_fit (view);
708                 }
709         }
710
711         gl_debug (DEBUG_VIEW, "END");
712 }
713
714
715 /*---------------------------------------------------------------------------*/
716 /* PRIVATE.  Handle label changed event.                                     */
717 /*---------------------------------------------------------------------------*/
718 static void
719 label_changed_cb (glView  *view)
720 {
721         g_return_if_fail (view && GL_IS_VIEW (view));
722
723         gl_debug (DEBUG_VIEW, "START");
724
725         gl_view_update (view);
726
727         gl_debug (DEBUG_VIEW, "END");
728 }
729
730
731 /*---------------------------------------------------------------------------*/
732 /* PRIVATE.  Handle label resize event.                                      */
733 /*---------------------------------------------------------------------------*/
734 static void
735 label_resized_cb (glView  *view)
736 {
737         GtkAdjustment *hadjustment;
738         GtkAdjustment *vadjustment;
739
740         g_return_if_fail (view && GL_IS_VIEW (view));
741
742         gl_debug (DEBUG_VIEW, "START");
743
744         hadjustment = gtk_layout_get_hadjustment(GTK_LAYOUT (view->canvas));
745         vadjustment = gtk_layout_get_vadjustment(GTK_LAYOUT (view->canvas));
746
747         g_signal_emit_by_name (hadjustment, "changed");
748         g_signal_emit_by_name (vadjustment, "changed");
749
750         gl_view_update (view);
751
752         gl_debug (DEBUG_VIEW, "END");
753 }
754
755
756 /*---------------------------------------------------------------------------*/
757 /* PRIVATE.  Handle new label object.                                        */
758 /*---------------------------------------------------------------------------*/
759 static void
760 label_object_added_cb (glView         *view,
761                        glLabelObject  *object)
762 {
763         glViewObject *view_object;
764
765         g_return_if_fail (view && GL_IS_VIEW (view));
766         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
767
768         if (GL_IS_LABEL_BOX (object)) {
769                 view_object = gl_view_box_new (GL_LABEL_BOX(object), view);
770         } else if (GL_IS_LABEL_ELLIPSE (object)) {
771                 view_object = gl_view_ellipse_new (GL_LABEL_ELLIPSE(object), view);
772         } else if (GL_IS_LABEL_LINE (object)) {
773                 view_object = gl_view_line_new (GL_LABEL_LINE(object), view);
774         } else if (GL_IS_LABEL_IMAGE (object)) {
775                 view_object = gl_view_image_new (GL_LABEL_IMAGE(object), view);
776         } else if (GL_IS_LABEL_TEXT (object)) {
777                 view_object = gl_view_text_new (GL_LABEL_TEXT(object), view);
778         } else if (GL_IS_LABEL_BARCODE (object)) {
779                 view_object = gl_view_barcode_new (GL_LABEL_BARCODE(object), view);
780         } else {
781                 /* Should not happen! */
782                 view_object = NULL;
783                 g_message ("Invalid label object type.");
784         }
785
786         gl_view_select_object (view, view_object);
787 }
788
789
790 /*---------------------------------------------------------------------------*/
791 /* PRIVATE.  Create, draw and order layers.                                  */
792 /*---------------------------------------------------------------------------*/
793 static void
794 draw_layers (glView  *view,
795              cairo_t *cr)
796 {
797         GdkWindow                 *bin_window;
798         gdouble                    scale;
799         gdouble                    w, h;
800         gint                       canvas_w, canvas_h;
801
802         g_return_if_fail (view && GL_IS_VIEW (view));
803         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
804
805         gl_debug (DEBUG_VIEW, "START");
806
807         bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (view->canvas));
808
809         scale = view->zoom * view->home_scale;
810
811         gl_label_get_size (view->label, &w, &h);
812
813         scale = view->home_scale * view->zoom;
814         gtk_layout_set_size (GTK_LAYOUT (view->canvas), w*scale+8, h*scale+8);
815
816         gdk_drawable_get_size (bin_window, &canvas_w, &canvas_h);
817
818         view->x0 = (canvas_w/scale - w) / 2.0;
819         view->y0 = (canvas_h/scale - h) / 2.0;
820         view->w  = w;
821         view->h  = h;
822
823         cairo_save (cr);
824
825         cairo_scale (cr, scale, scale);
826         cairo_translate (cr, view->x0, view->y0);
827
828         draw_bg_layer (view, cr);
829         draw_grid_layer (view, cr);
830         draw_markup_layer (view, cr);
831         draw_objects_layer (view, cr);
832         draw_fg_layer (view, cr);
833         draw_highlight_layer (view, cr);
834         draw_select_region_layer (view, cr);
835
836         cairo_restore (cr);
837
838         gl_debug (DEBUG_VIEW, "END");
839
840 }
841
842
843 /*---------------------------------------------------------------------------*/
844 /* PRIVATE.  Draw background                                                 */
845 /*---------------------------------------------------------------------------*/
846 static void
847 draw_bg_layer (glView  *view,
848                cairo_t *cr)
849 {
850         g_return_if_fail (view && GL_IS_VIEW (view));
851         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
852
853         gl_cairo_label_path (cr, view->label->template, view->label->rotate_flag, FALSE);
854
855         cairo_set_source_rgb (cr, PAPER_RGB_ARGS);
856         cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
857         cairo_fill (cr);
858 }
859
860
861 /*---------------------------------------------------------------------------*/
862 /* PRIVATE.  Draw grid lines.                                                */
863 /*---------------------------------------------------------------------------*/
864 static void
865 draw_grid_layer (glView  *view,
866                  cairo_t *cr)
867 {
868         gdouble                    w, h;
869         gdouble                    x, y;
870         gdouble                    x0, y0;
871         const lglTemplateFrame    *frame;
872
873         gl_debug (DEBUG_VIEW, "START");
874
875         g_return_if_fail (view && GL_IS_VIEW (view));
876         g_return_if_fail (view->label && GL_IS_LABEL(view->label));
877
878         if (view->grid_visible)
879         {
880
881                 frame = (lglTemplateFrame *)view->label->template->frames->data;
882
883                 gl_label_get_size (view->label, &w, &h);
884         
885                 if (frame->shape == LGL_TEMPLATE_FRAME_SHAPE_RECT) {
886                         x0 = 0.0;
887                         y0 = 0.0;
888                 } else {
889                         /* round labels, adjust grid to line up with center of label. */
890                         x0 = fmod (w/2.0, view->grid_spacing);
891                         y0 = fmod (h/2.0, view->grid_spacing);
892                 }
893
894
895                 cairo_save (cr);
896
897                 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
898                 cairo_set_line_width (cr, GRID_LINE_WIDTH_PIXELS/(view->home_scale * view->zoom));
899                 cairo_set_source_rgb (cr, GRID_RGB_ARGS);
900
901                 for ( x=x0+view->grid_spacing; x < w; x += view->grid_spacing )
902                 {
903                         cairo_move_to (cr, x, 0);
904                         cairo_line_to (cr, x, h);
905                         cairo_stroke (cr);
906                 }
907
908                 for ( y=y0+view->grid_spacing; y < h; y += view->grid_spacing )
909                 {
910                         cairo_move_to (cr, 0, y);
911                         cairo_line_to (cr, w, y);
912                         cairo_stroke (cr);
913                 }
914
915                 cairo_restore (cr);
916
917         }
918
919         gl_debug (DEBUG_VIEW, "END");
920 }
921
922
923 /*---------------------------------------------------------------------------*/
924 /* PRIVATE.  Draw markup layer.                                              */
925 /*---------------------------------------------------------------------------*/
926 static void
927 draw_markup_layer (glView  *view,
928                    cairo_t *cr)
929 {
930         glLabel                   *label;
931         const lglTemplateFrame    *frame;
932         GList                     *p;
933         lglTemplateMarkup         *markup;
934         gdouble                    width, height;
935
936         g_return_if_fail (view && GL_IS_VIEW (view));
937         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
938
939         if (view->markup_visible)
940         {
941
942                 label      = view->label;
943                 frame = (lglTemplateFrame *)view->label->template->frames->data;
944
945                 cairo_save (cr);
946
947                 if (label->rotate_flag)
948                 {
949                         lgl_template_frame_get_size (frame, &width, &height);
950                         cairo_rotate (cr, -M_PI/2.0);
951                         cairo_translate (cr, -width, 0.0);
952                 }
953
954                 cairo_set_line_width (cr, MARKUP_LINE_WIDTH_PIXELS/(view->home_scale * view->zoom));
955                 cairo_set_source_rgb (cr, MARKUP_RGB_ARGS);
956
957                 for ( p=frame->all.markups; p != NULL; p=p->next )
958                 {
959                         markup = (lglTemplateMarkup *)p->data;
960
961                         gl_cairo_markup_path (cr, markup, label);
962
963                         cairo_stroke (cr);
964                 }
965
966                 cairo_restore (cr);
967         }
968
969 }
970
971
972 /*---------------------------------------------------------------------------*/
973 /* PRIVATE.  Draw objects layer.                                             */
974 /*---------------------------------------------------------------------------*/
975 static void
976 draw_objects_layer (glView  *view,
977                     cairo_t *cr)
978 {
979         gl_label_draw (view->label, cr, TRUE, NULL);
980 }
981
982
983 /*---------------------------------------------------------------------------*/
984 /* PRIVATE.  Draw foreground                                                 */
985 /*---------------------------------------------------------------------------*/
986 static void
987 draw_fg_layer (glView  *view,
988                cairo_t *cr)
989 {
990         g_return_if_fail (view && GL_IS_VIEW (view));
991         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
992
993         gl_cairo_label_path (cr, view->label->template, view->label->rotate_flag, FALSE);
994
995         cairo_set_line_width (cr, OUTLINE_WIDTH_PIXELS/(view->home_scale * view->zoom));
996         cairo_set_source_rgb (cr, OUTLINE_RGB_ARGS);
997         cairo_stroke (cr);
998 }
999
1000
1001 /*---------------------------------------------------------------------------*/
1002 /* PRIVATE.  Create highlight layer.                                         */
1003 /*---------------------------------------------------------------------------*/
1004 static void
1005 draw_highlight_layer (glView  *view,
1006                       cairo_t *cr)
1007 {
1008         GList            *p_obj;
1009         glViewObject     *view_object;
1010
1011         g_return_if_fail (view && GL_IS_VIEW (view));
1012
1013         cairo_save (cr);
1014
1015         cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
1016
1017         for (p_obj = view->selected_object_list; p_obj != NULL; p_obj = p_obj->next)
1018         {
1019                 view_object = GL_VIEW_OBJECT (p_obj->data);
1020
1021                 gl_view_object_draw_handles (view_object, cr);
1022         }
1023
1024         cairo_restore (cr);
1025 }
1026
1027
1028 /*---------------------------------------------------------------------------*/
1029 /* PRIVATE.  Draw select region layer.                                       */
1030 /*---------------------------------------------------------------------------*/
1031 static void
1032 draw_select_region_layer (glView  *view,
1033                           cairo_t *cr)
1034 {
1035         gdouble x1, y1;
1036         gdouble w, h;
1037
1038         g_return_if_fail (view && GL_IS_VIEW (view));
1039
1040         if (view->select_region_visible)
1041         {
1042                 x1 = MIN (view->select_region.x1, view->select_region.x2);
1043                 y1 = MIN (view->select_region.y1, view->select_region.y2);
1044                 w  = fabs (view->select_region.x2 - view->select_region.x1);
1045                 h  = fabs (view->select_region.y2 - view->select_region.y1);
1046
1047                 cairo_save (cr);
1048
1049                 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
1050
1051                 cairo_rectangle (cr, x1, y1, w, h);
1052
1053                 cairo_set_source_rgba (cr, SELECT_FILL_RGBA_ARGS);
1054                 cairo_fill_preserve (cr);
1055
1056                 cairo_set_line_width (cr, SELECT_LINE_WIDTH_PIXELS/(view->home_scale * view->zoom));
1057                 cairo_set_source_rgba (cr, SELECT_LINE_RGBA_ARGS);
1058                 cairo_stroke (cr);
1059
1060                 cairo_restore (cr);
1061         }
1062 }
1063
1064
1065 /*****************************************************************************/
1066 /* Show grid.                                                                */
1067 /*****************************************************************************/
1068 void
1069 gl_view_show_grid (glView *view)
1070 {
1071         g_return_if_fail (view && GL_IS_VIEW (view));
1072
1073         view->grid_visible = TRUE;
1074         gl_view_update (view);
1075 }
1076
1077
1078 /*****************************************************************************/
1079 /* Hide grid.                                                                */
1080 /*****************************************************************************/
1081 void
1082 gl_view_hide_grid (glView *view)
1083 {
1084         g_return_if_fail (view && GL_IS_VIEW (view));
1085
1086         view->grid_visible = FALSE;
1087         gl_view_update (view);
1088 }
1089
1090
1091 /*****************************************************************************/
1092 /* Set grid spacing.                                                         */
1093 /*****************************************************************************/
1094 void
1095 gl_view_set_grid_spacing (glView  *view,
1096                           gdouble  spacing)
1097 {
1098         g_return_if_fail (view && GL_IS_VIEW (view));
1099
1100         view->grid_spacing = spacing;
1101         gl_view_update (view);
1102 }
1103
1104
1105 /*****************************************************************************/
1106 /* Show markup.                                                              */
1107 /*****************************************************************************/
1108 void
1109 gl_view_show_markup (glView *view)
1110 {
1111         g_return_if_fail (view && GL_IS_VIEW (view));
1112
1113         view->markup_visible = TRUE;
1114         gl_view_update (view);
1115 }
1116
1117
1118 /*****************************************************************************/
1119 /* Hide markup.                                                              */
1120 /*****************************************************************************/
1121 void
1122 gl_view_hide_markup (glView *view)
1123 {
1124         g_return_if_fail (view && GL_IS_VIEW (view));
1125
1126         view->markup_visible = FALSE;
1127         gl_view_update (view);
1128 }
1129
1130
1131 /*****************************************************************************/
1132 /* Set arrow mode.                                                           */
1133 /*****************************************************************************/
1134 void
1135 gl_view_arrow_mode (glView *view)
1136 {
1137         GdkWindow *window;
1138         GdkCursor *cursor;
1139
1140         gl_debug (DEBUG_VIEW, "START");
1141
1142         g_return_if_fail (view && GL_IS_VIEW (view));
1143
1144         window = gtk_widget_get_window (view->canvas);
1145
1146         cursor = gdk_cursor_new (GDK_LEFT_PTR);
1147         gdk_window_set_cursor (window, cursor);
1148         gdk_cursor_unref (cursor);
1149
1150         view->mode = GL_VIEW_MODE_ARROW;
1151         view->state = GL_VIEW_IDLE;
1152
1153         gl_debug (DEBUG_VIEW, "END");
1154 }
1155
1156
1157 /*****************************************************************************/
1158 /* Set create text object mode.                                              */
1159 /*****************************************************************************/
1160 void
1161 gl_view_object_create_mode (glView            *view,
1162                             glLabelObjectType  type)
1163 {
1164         GdkWindow *window;
1165         GdkCursor *cursor = NULL;
1166
1167         gl_debug (DEBUG_VIEW, "START");
1168
1169         g_return_if_fail (view && GL_IS_VIEW (view));
1170
1171         window = gtk_widget_get_window (view->canvas);
1172
1173         switch (type)
1174         {
1175         case GL_LABEL_OBJECT_BOX:
1176                 cursor = gl_view_box_get_create_cursor ();
1177                 break;
1178         case GL_LABEL_OBJECT_ELLIPSE:
1179                 cursor = gl_view_ellipse_get_create_cursor ();
1180                 break;
1181         case GL_LABEL_OBJECT_LINE:
1182                 cursor = gl_view_line_get_create_cursor ();
1183                 break;
1184         case GL_LABEL_OBJECT_IMAGE:
1185                 cursor = gl_view_image_get_create_cursor ();
1186                 break;
1187         case GL_LABEL_OBJECT_TEXT:
1188                 cursor = gl_view_text_get_create_cursor ();
1189                 break;
1190         case GL_LABEL_OBJECT_BARCODE:
1191                 cursor = gl_view_barcode_get_create_cursor ();
1192                 break;
1193         default:
1194                 g_message ("Invalid label object type.");/*Should not happen!*/
1195                 break;
1196         }
1197
1198         gdk_window_set_cursor (window, cursor);
1199         gdk_cursor_unref (cursor);
1200
1201         view->mode = GL_VIEW_MODE_OBJECT_CREATE;
1202         view->state = GL_VIEW_IDLE;
1203         view->create_type = type;
1204
1205         gl_debug (DEBUG_VIEW, "END");
1206 }
1207
1208
1209 /*****************************************************************************/
1210 /* Select given object (adding to current selection).                        */
1211 /*****************************************************************************/
1212 void
1213 gl_view_select_object (glView       *view,
1214                        glViewObject *view_object)
1215 {
1216         gl_debug (DEBUG_VIEW, "START");
1217
1218         g_return_if_fail (view && GL_IS_VIEW (view));
1219
1220         select_object_real (view, view_object);
1221
1222         g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
1223
1224         gl_debug (DEBUG_VIEW, "END");
1225 }
1226
1227
1228 /*****************************************************************************/
1229 /* Unselect given object (removing from current selection).                  */
1230 /*****************************************************************************/
1231 void
1232 gl_view_unselect_object (glView       *view,
1233                          glViewObject *view_object)
1234 {
1235         gl_debug (DEBUG_VIEW, "START");
1236
1237         g_return_if_fail (view && GL_IS_VIEW (view));
1238
1239         unselect_object_real (view, view_object);
1240
1241         g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
1242
1243         gl_debug (DEBUG_VIEW, "END");
1244 }
1245
1246
1247 /*****************************************************************************/
1248 /* Select all items.                                                         */
1249 /*****************************************************************************/
1250 void
1251 gl_view_select_all (glView *view)
1252 {
1253         GList *p, *p_next;
1254
1255         gl_debug (DEBUG_VIEW, "START");
1256
1257         g_return_if_fail (view && GL_IS_VIEW (view));
1258
1259         /* 1st unselect anything already selected. */
1260         for (p = view->selected_object_list; p != NULL; p = p_next) {
1261                 p_next = p->next;
1262                 unselect_object_real (view, GL_VIEW_OBJECT (p->data));
1263         }
1264
1265         /* Finally select all objects. */
1266         for (p = view->object_list; p != NULL; p = p->next) {
1267                 select_object_real (view, GL_VIEW_OBJECT (p->data));
1268         }
1269
1270         g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
1271
1272         gl_debug (DEBUG_VIEW, "END");
1273 }
1274
1275
1276 /*****************************************************************************/
1277 /* Remove all selections                                                     */
1278 /*****************************************************************************/
1279 void
1280 gl_view_unselect_all (glView *view)
1281 {
1282         GList *p;
1283         GList *p_next;
1284
1285         gl_debug (DEBUG_VIEW, "START");
1286
1287         g_return_if_fail (view && GL_IS_VIEW (view));
1288
1289         for (p = view->selected_object_list; p != NULL; p = p_next) {
1290                 p_next = p->next;
1291                 unselect_object_real (view, GL_VIEW_OBJECT (p->data));
1292         }
1293
1294         g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
1295
1296         gl_debug (DEBUG_VIEW, "END");
1297 }
1298
1299
1300 /*****************************************************************************/
1301 /* Select all objects within given rectangular region (adding to selection). */
1302 /*****************************************************************************/
1303 void
1304 gl_view_select_region (glView        *view,
1305                        glLabelRegion *region)
1306 {
1307         GList         *p;
1308         glViewObject  *view_object;
1309         glLabelObject *object;
1310         gdouble        r_x1, r_y1;
1311         gdouble        r_x2, r_y2;
1312         glLabelRegion  obj_extent;
1313
1314         gl_debug (DEBUG_VIEW, "START");
1315
1316         g_return_if_fail (view && GL_IS_VIEW (view));
1317
1318         r_x1 = MIN (region->x1, region->x2);
1319         r_y1 = MIN (region->y1, region->y2);
1320         r_x2 = MAX (region->x1, region->x2);
1321         r_y2 = MAX (region->y1, region->y2);
1322
1323         for (p = view->object_list; p != NULL; p = p->next)
1324         {
1325                 view_object = GL_VIEW_OBJECT(p->data);
1326                 if (!gl_view_is_object_selected (view, view_object))
1327                 {
1328
1329                         object = gl_view_object_get_object (view_object);
1330
1331                         gl_label_object_get_extent (object, &obj_extent);
1332                         if ((obj_extent.x1 >= r_x1) &&
1333                             (obj_extent.x2 <= r_x2) &&
1334                             (obj_extent.y1 >= r_y1) &&
1335                             (obj_extent.y2 <= r_y2))
1336                         {
1337                                 select_object_real (view, view_object);
1338                         }
1339
1340                 }
1341         }
1342
1343         g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
1344
1345         gl_debug (DEBUG_VIEW, "END");
1346 }
1347
1348
1349 /*---------------------------------------------------------------------------*/
1350 /* PRIVATE. Select an object.                                                */
1351 /*---------------------------------------------------------------------------*/
1352 static void
1353 select_object_real (glView       *view,
1354                     glViewObject *view_object)
1355 {
1356         gl_debug (DEBUG_VIEW, "START");
1357
1358         g_return_if_fail (view && GL_IS_VIEW (view));
1359         g_return_if_fail (GL_IS_VIEW_OBJECT (view_object));
1360
1361         if (!gl_view_is_object_selected (view, view_object)) {
1362                 view->selected_object_list =
1363                     g_list_append (view->selected_object_list, view_object);
1364         }
1365         gtk_widget_grab_focus (GTK_WIDGET (view->canvas));
1366
1367         gl_view_update (view);
1368
1369         gl_debug (DEBUG_VIEW, "END");
1370 }
1371
1372
1373 /*---------------------------------------------------------------------------*/
1374 /* PRIVATE.  Un-select object.                                               */
1375 /*---------------------------------------------------------------------------*/
1376 static void
1377 unselect_object_real (glView       *view,
1378                       glViewObject *view_object)
1379 {
1380         gl_debug (DEBUG_VIEW, "START");
1381
1382         g_return_if_fail (view && GL_IS_VIEW (view));
1383         g_return_if_fail (GL_IS_VIEW_OBJECT (view_object));
1384
1385         view->selected_object_list =
1386             g_list_remove (view->selected_object_list, view_object);
1387
1388         gl_view_update (view);
1389
1390         gl_debug (DEBUG_VIEW, "END");
1391 }
1392
1393
1394 /*---------------------------------------------------------------------------*/
1395 /* PRIVATE. Return object at (x,y).                                          */
1396 /*---------------------------------------------------------------------------*/
1397 static glViewObject *
1398 view_view_object_at (glView  *view,
1399                      cairo_t *cr,
1400                      gdouble  x,
1401                      gdouble  y)
1402 {
1403         GList            *p_obj;
1404         glViewObject     *view_object;
1405
1406         g_return_val_if_fail (view && GL_IS_VIEW (view), NULL);
1407
1408         for (p_obj = g_list_last (view->object_list); p_obj != NULL; p_obj = p_obj->prev)
1409         {
1410
1411                 view_object = GL_VIEW_OBJECT (p_obj->data);
1412
1413                 if (gl_view_object_at (view_object, cr, x, y))
1414                 {
1415                         return view_object;
1416                 }
1417
1418         }
1419
1420         return NULL;
1421 }
1422
1423
1424 /*---------------------------------------------------------------------------*/
1425 /* PRIVATE. Return object handle at (x,y).                                   */
1426 /*---------------------------------------------------------------------------*/
1427 static glViewObject *
1428 view_handle_at (glView             *view,
1429                 cairo_t            *cr,
1430                 gdouble             x,
1431                 gdouble             y,
1432                 glViewObjectHandle *handle)
1433 {
1434         GList            *p_obj;
1435         glViewObject     *view_object;
1436
1437         g_return_val_if_fail (view && GL_IS_VIEW (view), NULL);
1438
1439         for (p_obj = g_list_last (view->selected_object_list); p_obj != NULL; p_obj = p_obj->prev)
1440         {
1441
1442                 view_object = GL_VIEW_OBJECT (p_obj->data);
1443
1444                 if ((*handle = gl_view_object_handle_at (view_object, cr, x, y)))
1445                 {
1446                         return view_object;
1447                 }
1448
1449         }
1450
1451         return NULL;
1452 }
1453
1454
1455 /*****************************************************************************/
1456 /* Is the object in our current selection?                                   */
1457 /*****************************************************************************/
1458 gboolean
1459 gl_view_is_object_selected (glView       *view,
1460                             glViewObject *view_object)
1461 {
1462         gl_debug (DEBUG_VIEW, "");
1463
1464         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
1465         g_return_val_if_fail (GL_IS_VIEW_OBJECT (view_object), FALSE);
1466
1467         if (g_list_find (view->selected_object_list, view_object) == NULL) {
1468                 return FALSE;
1469         }
1470         return TRUE;
1471 }
1472
1473
1474 /*****************************************************************************/
1475 /* Is our current selection empty?                                           */
1476 /*****************************************************************************/
1477 gboolean
1478 gl_view_is_selection_empty (glView *view)
1479 {
1480         gl_debug (DEBUG_VIEW, "");
1481
1482         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
1483
1484         if (view->selected_object_list == NULL) {
1485                 return TRUE;
1486         } else {
1487                 return FALSE;
1488         }
1489 }
1490
1491
1492 /*****************************************************************************/
1493 /* Is our current selection atomic?  I.e. only one item selected.            */
1494 /*****************************************************************************/
1495 gboolean
1496 gl_view_is_selection_atomic (glView *view)
1497 {
1498         gl_debug (DEBUG_VIEW, "");
1499
1500         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
1501
1502         if (view->selected_object_list == NULL)
1503                 return FALSE;
1504         if (view->selected_object_list->next == NULL)
1505                 return TRUE;
1506         return FALSE;
1507 }
1508
1509
1510 /*****************************************************************************/
1511 /* Delete selected objects. (Bypass clipboard)                               */
1512 /*****************************************************************************/
1513 void
1514 gl_view_delete_selection (glView *view)
1515 {
1516         GList         *object_list;
1517         GList         *p;
1518         GList         *p_next;
1519         glViewObject  *view_object;
1520         glLabelObject *object;
1521
1522         gl_debug (DEBUG_VIEW, "START");
1523
1524         g_return_if_fail (view && GL_IS_VIEW (view));
1525
1526         object_list = view->selected_object_list;
1527         view->selected_object_list = NULL;
1528         g_signal_emit (G_OBJECT(view), signals[SELECTION_CHANGED], 0);
1529
1530         for (p = object_list; p != NULL; p = p_next) {
1531                 p_next = p->next;
1532                 view_object = GL_VIEW_OBJECT (p->data);
1533                 object = gl_view_object_get_object (view_object);
1534                 gl_label_object_remove (object);
1535         }
1536
1537         g_list_free (object_list);
1538
1539         gl_debug (DEBUG_VIEW, "END");
1540 }
1541
1542
1543 /*****************************************************************************/
1544 /* Get object property editor of first selected object.                      */
1545 /*****************************************************************************/
1546 GtkWidget *
1547 gl_view_get_editor (glView *view)
1548 {
1549         glViewObject *view_object;
1550         GtkWidget    *editor = NULL;
1551
1552         gl_debug (DEBUG_VIEW, "START");
1553
1554         g_return_val_if_fail (view && GL_IS_VIEW (view), NULL);
1555
1556         if (!gl_view_is_selection_empty (view)) {
1557
1558                 view_object = GL_VIEW_OBJECT(view->selected_object_list->data);
1559                 editor = gl_view_object_get_editor (view_object);
1560
1561         }
1562
1563         gl_debug (DEBUG_VIEW, "END");
1564
1565         return editor;
1566 }
1567
1568
1569 /*****************************************************************************/
1570 /* Raise selected items to top.                                              */
1571 /*****************************************************************************/
1572 void
1573 gl_view_raise_selection (glView *view)
1574 {
1575         GList         *p;
1576         glViewObject  *view_object;
1577         glLabelObject *object;
1578
1579         gl_debug (DEBUG_VIEW, "START");
1580
1581         g_return_if_fail (view && GL_IS_VIEW (view));
1582
1583         for (p = view->selected_object_list; p != NULL; p = p->next) {
1584                 view_object = GL_VIEW_OBJECT (p->data);
1585                 object = gl_view_object_get_object (view_object);
1586                 gl_label_object_raise_to_top (object);
1587         }
1588
1589         gl_debug (DEBUG_VIEW, "END");
1590 }
1591
1592
1593 /*****************************************************************************/
1594 /* Lower selected items to bottom.                                           */
1595 /*****************************************************************************/
1596 void
1597 gl_view_lower_selection (glView *view)
1598 {
1599         GList         *p;
1600         glViewObject  *view_object;
1601         glLabelObject *object;
1602
1603         gl_debug (DEBUG_VIEW, "START");
1604
1605         g_return_if_fail (view && GL_IS_VIEW (view));
1606
1607         for (p = view->selected_object_list; p != NULL; p = p->next) {
1608                 view_object = GL_VIEW_OBJECT (p->data);
1609                 object = gl_view_object_get_object (view_object);
1610                 gl_label_object_lower_to_bottom (object);
1611         }
1612
1613         gl_debug (DEBUG_VIEW, "END");
1614 }
1615
1616
1617 /*****************************************************************************/
1618 /* Rotate selected objects by given angle.                                   */
1619 /*****************************************************************************/
1620 void
1621 gl_view_rotate_selection (glView *view,
1622                           gdouble theta_degs)
1623 {
1624         GList         *p;
1625         glViewObject  *view_object;
1626         glLabelObject *object;
1627
1628         gl_debug (DEBUG_VIEW, "START");
1629
1630         g_return_if_fail (view && GL_IS_VIEW (view));
1631
1632         for (p = view->selected_object_list; p != NULL; p = p->next) {
1633                 view_object = GL_VIEW_OBJECT (p->data);
1634                 object = gl_view_object_get_object (view_object);
1635                 gl_label_object_rotate (object, theta_degs);
1636         }
1637
1638         gl_debug (DEBUG_VIEW, "END");
1639 }
1640
1641
1642 /*****************************************************************************/
1643 /* Rotate selected objects 90 degrees left.                                  */
1644 /*****************************************************************************/
1645 void
1646 gl_view_rotate_selection_left (glView *view)
1647 {
1648         GList         *p;
1649         glViewObject  *view_object;
1650         glLabelObject *object;
1651
1652         gl_debug (DEBUG_VIEW, "START");
1653
1654         g_return_if_fail (view && GL_IS_VIEW (view));
1655
1656         for (p = view->selected_object_list; p != NULL; p = p->next) {
1657                 view_object = GL_VIEW_OBJECT (p->data);
1658                 object = gl_view_object_get_object (view_object);
1659                 gl_label_object_rotate (object, -90.0);
1660         }
1661
1662         gl_debug (DEBUG_VIEW, "END");
1663 }
1664
1665
1666 /*****************************************************************************/
1667 /* Rotate selected objects 90 degrees right.                                 */
1668 /*****************************************************************************/
1669 void
1670 gl_view_rotate_selection_right (glView *view)
1671 {
1672         GList         *p;
1673         glViewObject  *view_object;
1674         glLabelObject *object;
1675
1676         gl_debug (DEBUG_VIEW, "START");
1677
1678         g_return_if_fail (view && GL_IS_VIEW (view));
1679
1680         for (p = view->selected_object_list; p != NULL; p = p->next) {
1681                 view_object = GL_VIEW_OBJECT (p->data);
1682                 object = gl_view_object_get_object (view_object);
1683                 gl_label_object_rotate (object, 90.0);
1684         }
1685
1686         gl_debug (DEBUG_VIEW, "END");
1687 }
1688
1689
1690 /*****************************************************************************/
1691 /* Flip selected objects horizontally.                                       */
1692 /*****************************************************************************/
1693 void
1694 gl_view_flip_selection_horiz (glView *view)
1695 {
1696         GList         *p;
1697         glViewObject  *view_object;
1698         glLabelObject *object;
1699
1700         gl_debug (DEBUG_VIEW, "START");
1701
1702         g_return_if_fail (view && GL_IS_VIEW (view));
1703
1704         for (p = view->selected_object_list; p != NULL; p = p->next) {
1705                 view_object = GL_VIEW_OBJECT (p->data);
1706                 object = gl_view_object_get_object (view_object);
1707                 gl_label_object_flip_horiz (object);
1708         }
1709
1710         gl_debug (DEBUG_VIEW, "END");
1711 }
1712
1713
1714 /*****************************************************************************/
1715 /* Flip selected objects vertically.                                         */
1716 /*****************************************************************************/
1717 void
1718 gl_view_flip_selection_vert (glView *view)
1719 {
1720         GList         *p;
1721         glViewObject  *view_object;
1722         glLabelObject *object;
1723
1724         gl_debug (DEBUG_VIEW, "START");
1725
1726         g_return_if_fail (view && GL_IS_VIEW (view));
1727
1728         for (p = view->selected_object_list; p != NULL; p = p->next) {
1729                 view_object = GL_VIEW_OBJECT (p->data);
1730                 object = gl_view_object_get_object (view_object);
1731                 gl_label_object_flip_vert (object);
1732         }
1733
1734         gl_debug (DEBUG_VIEW, "END");
1735 }
1736
1737
1738 /*****************************************************************************/
1739 /* Align selected objects to left most edge.                                 */
1740 /*****************************************************************************/
1741 void
1742 gl_view_align_selection_left (glView *view)
1743 {
1744         GList         *p;
1745         glViewObject  *view_object;
1746         glLabelObject *object;
1747         gdouble        dx, x1_min;
1748         glLabelRegion  obj_extent;
1749
1750         gl_debug (DEBUG_VIEW, "START");
1751
1752         g_return_if_fail (view && GL_IS_VIEW (view));
1753
1754         g_return_if_fail (!gl_view_is_selection_empty (view) &&
1755                           !gl_view_is_selection_atomic (view));
1756
1757         /* find left most edge */
1758         p = view->selected_object_list;
1759         view_object = GL_VIEW_OBJECT (p->data);
1760         object = gl_view_object_get_object (view_object);
1761         gl_label_object_get_extent (object, &obj_extent);
1762         x1_min = obj_extent.x1;
1763         for (p = p->next; p != NULL; p = p->next)
1764         {
1765                 view_object = GL_VIEW_OBJECT (p->data);
1766                 object = gl_view_object_get_object (view_object);
1767                 gl_label_object_get_extent (object, &obj_extent);
1768                 if ( obj_extent.x1 < x1_min ) x1_min = obj_extent.x1;
1769         }
1770
1771         /* now adjust the object positions to line up the left edges */
1772         for (p = view->selected_object_list; p != NULL; p = p->next)
1773         {
1774                 view_object = GL_VIEW_OBJECT (p->data);
1775                 object = gl_view_object_get_object (view_object);
1776                 gl_label_object_get_extent (object, &obj_extent);
1777                 dx = x1_min - obj_extent.x1;
1778                 gl_label_object_set_position_relative (object, dx, 0.0);
1779         }
1780
1781         gl_debug (DEBUG_VIEW, "END");
1782 }
1783
1784
1785 /*****************************************************************************/
1786 /* Align selected objects to right most edge.                                */
1787 /*****************************************************************************/
1788 void
1789 gl_view_align_selection_right (glView *view)
1790 {
1791         GList         *p;
1792         glViewObject  *view_object;
1793         glLabelObject *object;
1794         gdouble        dx, x2_max;
1795         glLabelRegion  obj_extent;
1796
1797         gl_debug (DEBUG_VIEW, "START");
1798
1799         g_return_if_fail (view && GL_IS_VIEW (view));
1800
1801         g_return_if_fail (!gl_view_is_selection_empty (view) &&
1802                           !gl_view_is_selection_atomic (view));
1803
1804         /* find right most edge */
1805         p = view->selected_object_list;
1806         view_object = GL_VIEW_OBJECT (p->data);
1807         object = gl_view_object_get_object (view_object);
1808         gl_label_object_get_extent (object, &obj_extent);
1809         x2_max = obj_extent.x2;
1810         for (p = p->next; p != NULL; p = p->next)
1811         {
1812                 view_object = GL_VIEW_OBJECT (p->data);
1813                 object = gl_view_object_get_object (view_object);
1814                 gl_label_object_get_extent (object, &obj_extent);
1815                 if ( obj_extent.x2 > x2_max ) x2_max = obj_extent.x2;
1816         }
1817
1818         /* now adjust the object positions to line up the right edges */
1819         for (p = view->selected_object_list; p != NULL; p = p->next)
1820         {
1821                 view_object = GL_VIEW_OBJECT (p->data);
1822                 object = gl_view_object_get_object (view_object);
1823                 gl_label_object_get_extent (object, &obj_extent);
1824                 dx = x2_max - obj_extent.x2;
1825                 gl_label_object_set_position_relative (object, dx, 0.0);
1826         }
1827
1828         gl_debug (DEBUG_VIEW, "END");
1829 }
1830
1831
1832 /*****************************************************************************/
1833 /* Align selected objects to horizontal center of objects.                   */
1834 /*****************************************************************************/
1835 void
1836 gl_view_align_selection_hcenter (glView *view)
1837 {
1838         GList         *p;
1839         glViewObject  *view_object;
1840         glLabelObject *object;
1841         gdouble        dx;
1842         gdouble        dxmin;
1843         gdouble        xsum, xavg;
1844         glLabelRegion  obj_extent;
1845         gdouble        xcenter;
1846         gint           n;
1847
1848         gl_debug (DEBUG_VIEW, "START");
1849
1850         g_return_if_fail (view && GL_IS_VIEW (view));
1851
1852         g_return_if_fail (!gl_view_is_selection_empty (view) &&
1853                           !gl_view_is_selection_atomic (view));
1854
1855         /* find average center of objects */
1856         xsum = 0.0;
1857         n = 0;
1858         for (p = view->selected_object_list; p != NULL; p = p->next)
1859         {
1860                 view_object = GL_VIEW_OBJECT (p->data);
1861                 object = gl_view_object_get_object (view_object);
1862                 gl_label_object_get_extent (object, &obj_extent);
1863                 xsum += (obj_extent.x1 + obj_extent.x2) / 2.0;
1864                 n++;
1865         }
1866         xavg = xsum / n;
1867
1868         /* find center of object closest to average center */
1869         p = view->selected_object_list;
1870         view_object = GL_VIEW_OBJECT (p->data);
1871         object = gl_view_object_get_object (view_object);
1872         gl_label_object_get_extent (object, &obj_extent);
1873         dxmin = fabs (xavg - (obj_extent.x1 + obj_extent.x2)/2.0);
1874         xcenter = (obj_extent.x1 + obj_extent.x2)/2.0;
1875         for (p = p->next; p != NULL; p = p->next)
1876         {
1877                 view_object = GL_VIEW_OBJECT (p->data);
1878                 object = gl_view_object_get_object (view_object);
1879                 gl_label_object_get_extent (object, &obj_extent);
1880                 dx = fabs (xavg - (obj_extent.x1 + obj_extent.x2)/2.0);
1881                 if ( dx < dxmin )
1882                 {
1883                         dxmin = dx;
1884                         xcenter = (obj_extent.x1 + obj_extent.x2)/2.0;
1885                 }
1886         }
1887
1888         /* now adjust the object positions to line up this center */
1889         for (p = view->selected_object_list; p != NULL; p = p->next) {
1890                 view_object = GL_VIEW_OBJECT (p->data);
1891                 object = gl_view_object_get_object (view_object);
1892                 gl_label_object_get_extent (object, &obj_extent);
1893                 dx = xcenter - (obj_extent.x1 + obj_extent.x2)/2.0;
1894                 gl_label_object_set_position_relative (object, dx, 0.0);
1895         }
1896
1897         gl_debug (DEBUG_VIEW, "END");
1898 }
1899
1900
1901 /*****************************************************************************/
1902 /* Align selected objects to top most edge.                                  */
1903 /*****************************************************************************/
1904 void
1905 gl_view_align_selection_top (glView *view)
1906 {
1907         GList         *p;
1908         glViewObject  *view_object;
1909         glLabelObject *object;
1910         gdouble        dy, y1_min;
1911         glLabelRegion  obj_extent;
1912
1913         gl_debug (DEBUG_VIEW, "START");
1914
1915         g_return_if_fail (view && GL_IS_VIEW (view));
1916
1917         g_return_if_fail (!gl_view_is_selection_empty (view) &&
1918                           !gl_view_is_selection_atomic (view));
1919
1920         /* find top most edge */
1921         p = view->selected_object_list;
1922         view_object = GL_VIEW_OBJECT (p->data);
1923         object = gl_view_object_get_object (view_object);
1924         gl_label_object_get_extent (object, &obj_extent);
1925         y1_min = obj_extent.y1;
1926         for (p = p->next; p != NULL; p = p->next)
1927         {
1928                 view_object = GL_VIEW_OBJECT (p->data);
1929                 object = gl_view_object_get_object (view_object);
1930                 gl_label_object_get_extent (object, &obj_extent);
1931                 if ( obj_extent.y1 < y1_min ) y1_min = obj_extent.y1;
1932         }
1933
1934         /* now adjust the object positions to line up the top edges */
1935         for (p = view->selected_object_list; p != NULL; p = p->next)
1936         {
1937                 view_object = GL_VIEW_OBJECT (p->data);
1938                 object = gl_view_object_get_object (view_object);
1939                 gl_label_object_get_extent (object, &obj_extent);
1940                 dy = y1_min - obj_extent.y1;
1941                 gl_label_object_set_position_relative (object, 0.0, dy);
1942         }
1943
1944         gl_debug (DEBUG_VIEW, "END");
1945 }
1946
1947
1948 /*****************************************************************************/
1949 /* Align selected objects to bottom most edge.                               */
1950 /*****************************************************************************/
1951 void
1952 gl_view_align_selection_bottom (glView *view)
1953 {
1954         GList         *p;
1955         glViewObject  *view_object;
1956         glLabelObject *object;
1957         gdouble        dy, y2_max;
1958         glLabelRegion  obj_extent;
1959
1960         gl_debug (DEBUG_VIEW, "START");
1961
1962         g_return_if_fail (view && GL_IS_VIEW (view));
1963
1964         g_return_if_fail (!gl_view_is_selection_empty (view) &&
1965                           !gl_view_is_selection_atomic (view));
1966
1967         /* find bottom most edge */
1968         p = view->selected_object_list;
1969         view_object = GL_VIEW_OBJECT (p->data);
1970         object = gl_view_object_get_object (view_object);
1971         gl_label_object_get_extent (object, &obj_extent);
1972         y2_max = obj_extent.y2;
1973         for (p = p->next; p != NULL; p = p->next)
1974         {
1975                 view_object = GL_VIEW_OBJECT (p->data);
1976                 object = gl_view_object_get_object (view_object);
1977                 gl_label_object_get_extent (object, &obj_extent);
1978                 if ( obj_extent.y2 > y2_max ) y2_max = obj_extent.y2;
1979         }
1980
1981         /* now adjust the object positions to line up the bottom edges */
1982         for (p = view->selected_object_list; p != NULL; p = p->next)
1983         {
1984                 view_object = GL_VIEW_OBJECT (p->data);
1985                 object = gl_view_object_get_object (view_object);
1986                 gl_label_object_get_extent (object, &obj_extent);
1987                 dy = y2_max - obj_extent.y2;
1988                 gl_label_object_set_position_relative (object, 0.0, dy);
1989         }
1990
1991         gl_debug (DEBUG_VIEW, "END");
1992 }
1993
1994
1995 /*****************************************************************************/
1996 /* Align selected objects to viertical center of objects.                    */
1997 /*****************************************************************************/
1998 void
1999 gl_view_align_selection_vcenter (glView *view)
2000 {
2001         GList         *p;
2002         glViewObject  *view_object;
2003         glLabelObject *object;
2004         gdouble        dy;
2005         gdouble        dymin;
2006         gdouble        ysum, yavg;
2007         glLabelRegion  obj_extent;
2008         gdouble        ycenter;
2009         gint           n;
2010
2011         gl_debug (DEBUG_VIEW, "START");
2012
2013         g_return_if_fail (view && GL_IS_VIEW (view));
2014
2015         g_return_if_fail (!gl_view_is_selection_empty (view) &&
2016                           !gl_view_is_selection_atomic (view));
2017
2018         /* find average center of objects */
2019         ysum = 0.0;
2020         n = 0;
2021         for (p = view->selected_object_list; p != NULL; p = p->next)
2022         {
2023                 view_object = GL_VIEW_OBJECT (p->data);
2024                 object = gl_view_object_get_object (view_object);
2025                 gl_label_object_get_extent (object, &obj_extent);
2026                 ysum += (obj_extent.y1 + obj_extent.y2) / 2.0;
2027                 n++;
2028         }
2029         yavg = ysum / n;
2030
2031         /* find center of object closest to average center */
2032         p = view->selected_object_list;
2033         view_object = GL_VIEW_OBJECT (p->data);
2034         object = gl_view_object_get_object (view_object);
2035         gl_label_object_get_extent (object, &obj_extent);
2036         dymin = fabs (yavg - (obj_extent.y1 + obj_extent.y2)/2.0);
2037         ycenter = (obj_extent.y1 + obj_extent.y2)/2.0;
2038         for (p = p->next; p != NULL; p = p->next)
2039         {
2040                 view_object = GL_VIEW_OBJECT (p->data);
2041                 object = gl_view_object_get_object (view_object);
2042                 gl_label_object_get_extent (object, &obj_extent);
2043                 dy = fabs (yavg - (obj_extent.y1 + obj_extent.y2)/2.0);
2044                 if ( dy < dymin )
2045                 {
2046                         dymin = dy;
2047                         ycenter = (obj_extent.y1 + obj_extent.y2)/2.0;
2048                 }
2049         }
2050
2051         /* now adjust the object positions to line up this center */
2052         for (p = view->selected_object_list; p != NULL; p = p->next)
2053         {
2054                 view_object = GL_VIEW_OBJECT (p->data);
2055                 object = gl_view_object_get_object (view_object);
2056                 gl_label_object_get_extent (object, &obj_extent);
2057                 dy = ycenter - (obj_extent.y1 + obj_extent.y2)/2.0;
2058                 gl_label_object_set_position_relative (object, 0.0, dy);
2059         }
2060
2061         gl_debug (DEBUG_VIEW, "END");
2062 }
2063
2064
2065 /*****************************************************************************/
2066 /* Center selected objects to in center of label.                            */
2067 /*****************************************************************************/
2068 void
2069 gl_view_center_selection_horiz (glView *view)
2070 {
2071         GList         *p;
2072         glViewObject  *view_object;
2073         glLabelObject *object;
2074         gdouble        dx;
2075         gdouble        x_label_center;
2076         gdouble        x_obj_center;
2077         glLabelRegion  obj_extent;
2078         gdouble        w, h;
2079
2080         gl_debug (DEBUG_VIEW, "START");
2081
2082         g_return_if_fail (view && GL_IS_VIEW (view));
2083
2084         g_return_if_fail (!gl_view_is_selection_empty (view));
2085
2086         gl_label_get_size (view->label, &w, &h);
2087         x_label_center = w / 2.0;
2088
2089         /* adjust the object positions */
2090         for (p = view->selected_object_list; p != NULL; p = p->next)
2091         {
2092                 view_object = GL_VIEW_OBJECT (p->data);
2093                 object = gl_view_object_get_object (view_object);
2094                 gl_label_object_get_extent (object, &obj_extent);
2095                 x_obj_center = (obj_extent.x1 + obj_extent.x2) / 2.0;
2096                 dx = x_label_center - x_obj_center;
2097                 gl_label_object_set_position_relative (object, dx, 0.0);
2098         }
2099
2100         gl_debug (DEBUG_VIEW, "END");
2101 }
2102
2103
2104 /*****************************************************************************/
2105 /* Center selected objects to in center of label.                            */
2106 /*****************************************************************************/
2107 void
2108 gl_view_center_selection_vert (glView *view)
2109 {
2110         GList         *p;
2111         glViewObject  *view_object;
2112         glLabelObject *object;
2113         gdouble        dy;
2114         gdouble        y_label_center;
2115         gdouble        y_obj_center;
2116         glLabelRegion  obj_extent;
2117         gdouble        w, h;
2118
2119         gl_debug (DEBUG_VIEW, "START");
2120
2121         g_return_if_fail (view && GL_IS_VIEW (view));
2122
2123         g_return_if_fail (!gl_view_is_selection_empty (view));
2124
2125         gl_label_get_size (view->label, &w, &h);
2126         y_label_center = h / 2.0;
2127
2128         /* adjust the object positions */
2129         for (p = view->selected_object_list; p != NULL; p = p->next)
2130         {
2131                 view_object = GL_VIEW_OBJECT (p->data);
2132                 object = gl_view_object_get_object (view_object);
2133                 gl_label_object_get_extent (object, &obj_extent);
2134                 y_obj_center = (obj_extent.y1 + obj_extent.y2) / 2.0;
2135                 dy = y_label_center - y_obj_center;
2136                 gl_label_object_set_position_relative (object, 0.0, dy);
2137         }
2138
2139         gl_debug (DEBUG_VIEW, "END");
2140 }
2141
2142
2143 /*****************************************************************************/
2144 /* Move selected objects                                                     */
2145 /*****************************************************************************/
2146 void
2147 gl_view_move_selection (glView  *view,
2148                         gdouble  dx,
2149                         gdouble  dy)
2150 {
2151         GList         *p;
2152         glLabelObject *object;
2153
2154         gl_debug (DEBUG_VIEW, "START");
2155
2156         g_return_if_fail (view && GL_IS_VIEW (view));
2157
2158         for (p = view->selected_object_list; p != NULL; p = p->next)
2159         {
2160
2161                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2162                 gl_label_object_set_position_relative (object, dx, dy);
2163
2164         }
2165
2166         gl_debug (DEBUG_VIEW, "END");
2167 }
2168
2169
2170 /*****************************************************************************/
2171 /* Can text properties be set for selection?                                 */
2172 /*****************************************************************************/
2173 gboolean
2174 gl_view_can_selection_text (glView *view)
2175 {
2176         GList         *p;
2177         glLabelObject *object;
2178
2179         gl_debug (DEBUG_VIEW, "");
2180
2181         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
2182
2183         for (p = view->selected_object_list; p != NULL; p = p->next)
2184         {
2185
2186                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2187                 if (gl_label_object_can_text (object))
2188                 {
2189                         return TRUE;
2190                 }
2191
2192         }
2193
2194         return FALSE;
2195 }
2196
2197
2198 /*****************************************************************************/
2199 /* Set font family for all text contained in selected objects.               */
2200 /*****************************************************************************/
2201 void
2202 gl_view_set_selection_font_family (glView      *view,
2203                                    const gchar *font_family)
2204 {
2205         GList         *p;
2206         glLabelObject *object;
2207
2208         gl_debug (DEBUG_VIEW, "START");
2209
2210         g_return_if_fail (view && GL_IS_VIEW (view));
2211
2212         for (p = view->selected_object_list; p != NULL; p = p->next) {
2213
2214                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2215                 gl_label_object_set_font_family (object, font_family);
2216
2217         }
2218
2219         gl_debug (DEBUG_VIEW, "END");
2220 }
2221
2222
2223 /*****************************************************************************/
2224 /* Set font size for all text contained in selected objects.                 */
2225 /*****************************************************************************/
2226 void
2227 gl_view_set_selection_font_size (glView  *view,
2228                                  gdouble  font_size)
2229 {
2230         GList         *p;
2231         glLabelObject *object;
2232
2233         gl_debug (DEBUG_VIEW, "START");
2234
2235         g_return_if_fail (view && GL_IS_VIEW (view));
2236
2237         for (p = view->selected_object_list; p != NULL; p = p->next) {
2238
2239                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2240                 gl_label_object_set_font_size (object, font_size);
2241
2242         }
2243
2244         gl_debug (DEBUG_VIEW, "END");
2245 }
2246
2247
2248 /*****************************************************************************/
2249 /* Set font weight for all text contained in selected objects.               */
2250 /*****************************************************************************/
2251 void
2252 gl_view_set_selection_font_weight (glView      *view,
2253                                    PangoWeight  font_weight)
2254 {
2255         GList         *p;
2256         glLabelObject *object;
2257
2258         gl_debug (DEBUG_VIEW, "START");
2259
2260         g_return_if_fail (view && GL_IS_VIEW (view));
2261
2262         for (p = view->selected_object_list; p != NULL; p = p->next) {
2263
2264                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2265                 gl_label_object_set_font_weight (object, font_weight);
2266
2267         }
2268
2269         gl_debug (DEBUG_VIEW, "END");
2270 }
2271
2272
2273 /*****************************************************************************/
2274 /* Set font italic flag for all text contained in selected objects.          */
2275 /*****************************************************************************/
2276 void
2277 gl_view_set_selection_font_italic_flag (glView   *view,
2278                                         gboolean  font_italic_flag)
2279 {
2280         GList         *p;
2281         glLabelObject *object;
2282
2283         gl_debug (DEBUG_VIEW, "START");
2284
2285         g_return_if_fail (view && GL_IS_VIEW (view));
2286
2287         for (p = view->selected_object_list; p != NULL; p = p->next) {
2288
2289                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2290                 gl_label_object_set_font_italic_flag (object, font_italic_flag);
2291
2292         }
2293
2294         gl_debug (DEBUG_VIEW, "END");
2295 }
2296
2297
2298 /*****************************************************************************/
2299 /* Set text alignment for all text contained in selected objects.            */
2300 /*****************************************************************************/
2301 void
2302 gl_view_set_selection_text_alignment (glView            *view,
2303                                       PangoAlignment     text_alignment)
2304 {
2305         GList         *p;
2306         glLabelObject *object;
2307
2308         gl_debug (DEBUG_VIEW, "START");
2309
2310         g_return_if_fail (view && GL_IS_VIEW (view));
2311
2312         for (p = view->selected_object_list; p != NULL; p = p->next) {
2313
2314                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2315                 gl_label_object_set_text_alignment (object, text_alignment);
2316
2317         }
2318
2319         gl_debug (DEBUG_VIEW, "END");
2320 }
2321
2322
2323 /*****************************************************************************/
2324 /* Set text line spacing for all text contained in selected objects.         */
2325 /*****************************************************************************/
2326 void
2327 gl_view_set_selection_text_line_spacing (glView  *view,
2328                                          gdouble  text_line_spacing)
2329 {
2330         GList         *p;
2331         glLabelObject *object;
2332
2333         gl_debug (DEBUG_VIEW, "START");
2334
2335         g_return_if_fail (view && GL_IS_VIEW (view));
2336
2337         for (p = view->selected_object_list; p != NULL; p = p->next) {
2338
2339                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2340                 gl_label_object_set_text_line_spacing (object, text_line_spacing);
2341
2342         }
2343
2344         gl_debug (DEBUG_VIEW, "END");
2345 }
2346
2347
2348 /*****************************************************************************/
2349 /* Set text color for all text contained in selected objects.                */
2350 /*****************************************************************************/
2351 void
2352 gl_view_set_selection_text_color (glView      *view,
2353                                   glColorNode *text_color_node)
2354 {
2355         GList         *p;
2356         glLabelObject *object;
2357
2358         gl_debug (DEBUG_VIEW, "START");
2359
2360         g_return_if_fail (view && GL_IS_VIEW (view));
2361
2362         for (p = view->selected_object_list; p != NULL; p = p->next) {
2363
2364                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2365                 gl_label_object_set_text_color (object, text_color_node);
2366
2367         }
2368
2369         gl_debug (DEBUG_VIEW, "END");
2370 }
2371
2372
2373 /*****************************************************************************/
2374 /* Can fill properties be set for selection?                                 */
2375 /*****************************************************************************/
2376 gboolean
2377 gl_view_can_selection_fill (glView *view)
2378 {
2379         GList         *p;
2380         glLabelObject *object;
2381
2382         gl_debug (DEBUG_VIEW, "");
2383
2384         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
2385
2386         for (p = view->selected_object_list; p != NULL; p = p->next) {
2387
2388                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2389                 if (gl_label_object_can_fill (object)) {
2390                         return TRUE;
2391                 }
2392
2393         }
2394
2395         return FALSE;
2396 }
2397
2398
2399 /*****************************************************************************/
2400 /* Set fill color for all selected objects.                                  */
2401 /*****************************************************************************/
2402 void
2403 gl_view_set_selection_fill_color (glView      *view,
2404                                   glColorNode *fill_color_node)
2405 {
2406         GList         *p;
2407         glLabelObject *object;
2408
2409         gl_debug (DEBUG_VIEW, "START");
2410
2411         g_return_if_fail (view && GL_IS_VIEW (view));
2412
2413         for (p = view->selected_object_list; p != NULL; p = p->next) {
2414
2415                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2416                 gl_label_object_set_fill_color (object, fill_color_node);
2417
2418         }
2419
2420         gl_debug (DEBUG_VIEW, "END");
2421 }
2422
2423
2424 /*****************************************************************************/
2425 /* Can line color properties be set for selection?                           */
2426 /*****************************************************************************/
2427 gboolean
2428 gl_view_can_selection_line_color (glView *view)
2429 {
2430         GList         *p;
2431         glLabelObject *object;
2432
2433         gl_debug (DEBUG_VIEW, "");
2434
2435         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
2436
2437         for (p = view->selected_object_list; p != NULL; p = p->next) {
2438
2439                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2440                 if (gl_label_object_can_line_color (object)) {
2441                         return TRUE;
2442                 }
2443
2444         }
2445
2446         return FALSE;
2447 }
2448
2449
2450 /*****************************************************************************/
2451 /* Set line color for all selected objects.                                  */
2452 /*****************************************************************************/
2453 void
2454 gl_view_set_selection_line_color (glView      *view,
2455                                   glColorNode *line_color_node)
2456 {
2457         GList         *p;
2458         glLabelObject *object;
2459
2460         gl_debug (DEBUG_VIEW, "START");
2461
2462         g_return_if_fail (view && GL_IS_VIEW (view));
2463
2464         for (p = view->selected_object_list; p != NULL; p = p->next) {
2465
2466                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2467                 gl_label_object_set_line_color (object, line_color_node);
2468
2469         }
2470
2471         gl_debug (DEBUG_VIEW, "END");
2472 }
2473
2474
2475 /*****************************************************************************/
2476 /* Can line width properties be set for selection?                           */
2477 /*****************************************************************************/
2478 gboolean
2479 gl_view_can_selection_line_width (glView *view)
2480 {
2481         GList         *p;
2482         glLabelObject *object;
2483
2484         gl_debug (DEBUG_VIEW, "");
2485
2486         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
2487
2488         for (p = view->selected_object_list; p != NULL; p = p->next) {
2489
2490                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2491                 if (gl_label_object_can_line_width (object)) {
2492                         return TRUE;
2493                 }
2494
2495         }
2496
2497         return FALSE;
2498 }
2499
2500
2501 /*****************************************************************************/
2502 /* Set line width for all selected objects.                                  */
2503 /*****************************************************************************/
2504 void
2505 gl_view_set_selection_line_width (glView  *view,
2506                                   gdouble  line_width)
2507 {
2508         GList         *p;
2509         glLabelObject *object;
2510
2511         gl_debug (DEBUG_VIEW, "START");
2512
2513         g_return_if_fail (view && GL_IS_VIEW (view));
2514
2515         for (p = view->selected_object_list; p != NULL; p = p->next) {
2516
2517                 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
2518                 gl_label_object_set_line_width (object, line_width);
2519
2520         }
2521
2522         gl_debug (DEBUG_VIEW, "END");
2523 }
2524
2525
2526 /*****************************************************************************/
2527 /* "Cut" selected items and place in clipboard selections.                   */
2528 /*****************************************************************************/
2529 void
2530 gl_view_cut (glView *view)
2531 {
2532         gl_debug (DEBUG_VIEW, "START");
2533
2534         g_return_if_fail (view && GL_IS_VIEW (view));
2535
2536         gl_view_copy (view);
2537         gl_view_delete_selection (view);
2538
2539         gl_debug (DEBUG_VIEW, "END");
2540 }
2541
2542
2543 /*****************************************************************************/
2544 /* "Copy" selected items to clipboard selections.                            */
2545 /*****************************************************************************/
2546 void
2547 gl_view_copy (glView *view)
2548 {
2549         GList         *p;
2550         glViewObject  *view_object;
2551         glLabelObject *object;
2552
2553         gl_debug (DEBUG_VIEW, "START");
2554
2555         g_return_if_fail (view && GL_IS_VIEW (view));
2556
2557         if (view->selected_object_list) {
2558
2559                 if ( view->selection_data ) {
2560                         g_object_unref (view->selection_data);
2561                 }
2562                 view->selection_data = GL_LABEL(gl_label_new ());
2563                 gl_label_set_template (view->selection_data, view->label->template);
2564                 gl_label_set_rotate_flag (view->selection_data, view->label->rotate_flag);
2565
2566                 for (p = view->selected_object_list; p != NULL; p = p->next) {
2567
2568                         view_object = GL_VIEW_OBJECT (p->data);
2569                         object = gl_view_object_get_object (view_object);
2570
2571                         gl_label_object_dup (object, view->selection_data);
2572
2573                 }
2574
2575                 gtk_selection_owner_set (view->invisible,
2576                                          clipboard_atom, GDK_CURRENT_TIME);
2577                 view->have_selection = TRUE;
2578
2579         }
2580
2581         gl_debug (DEBUG_VIEW, "END");
2582 }
2583
2584
2585 /*****************************************************************************/
2586 /* "Paste" from private clipboard selection.                                 */
2587 /*****************************************************************************/
2588 void
2589 gl_view_paste (glView *view)
2590 {
2591         gl_debug (DEBUG_VIEW, "START");
2592
2593         g_return_if_fail (view && GL_IS_VIEW (view));
2594
2595         gtk_selection_convert (GTK_WIDGET (view->invisible),
2596                                clipboard_atom, GDK_SELECTION_TYPE_STRING,
2597                                GDK_CURRENT_TIME);
2598
2599         gl_debug (DEBUG_VIEW, "END");
2600 }
2601
2602
2603 /*****************************************************************************/
2604 /* Zoom in one "notch"                                                       */
2605 /*****************************************************************************/
2606 void
2607 gl_view_zoom_in (glView *view)
2608 {
2609         gint    i, i_min;
2610         gdouble dist, dist_min;
2611
2612         gl_debug (DEBUG_VIEW, "START");
2613
2614         g_return_if_fail (view && GL_IS_VIEW (view));
2615
2616         /* Find index of current scale (or best match) */
2617         i_min = 1;              /* start with 2nd largest scale */
2618         dist_min = fabs (zooms[1] - view->zoom);
2619         for (i = 2; i < N_ZOOMS; i++) {
2620                 dist = fabs (zooms[i] - view->zoom);
2621                 if (dist < dist_min) {
2622                         i_min = i;
2623                         dist_min = dist;
2624                 }
2625         }
2626
2627         /* zoom in one "notch" */
2628         i = MAX (0, i_min - 1);
2629         gl_debug (DEBUG_VIEW, "zoom[%d] = %g", i, zooms[i]);
2630         set_zoom_real (view, zooms[i], FALSE);
2631
2632         gl_debug (DEBUG_VIEW, "END");
2633 }
2634
2635
2636 /*****************************************************************************/
2637 /* Zoom out one "notch"                                                      */
2638 /*****************************************************************************/
2639 void
2640 gl_view_zoom_out (glView *view)
2641 {
2642         gint    i, i_min;
2643         gdouble dist, dist_min;
2644
2645         gl_debug (DEBUG_VIEW, "START");
2646
2647         g_return_if_fail (view && GL_IS_VIEW (view));
2648
2649         /* Find index of current scale (or best match) */
2650         i_min = 0;              /* start with largest scale */
2651         dist_min = fabs (zooms[0] - view->zoom);
2652         for (i = 1; i < N_ZOOMS; i++) {
2653                 dist = fabs (zooms[i] - view->zoom);
2654                 if (dist < dist_min) {
2655                         i_min = i;
2656                         dist_min = dist;
2657                 }
2658         }
2659
2660         /* zoom out one "notch" */
2661         if (i_min >= N_ZOOMS)
2662                 return;
2663         i = i_min + 1;
2664         if (i >= N_ZOOMS)
2665                 return;
2666         set_zoom_real (view, zooms[i], FALSE);
2667
2668         gl_debug (DEBUG_VIEW, "END");
2669 }
2670
2671
2672 /*****************************************************************************/
2673 /* Set zoom to best fit.                                                     */
2674 /*****************************************************************************/
2675 void
2676 gl_view_zoom_to_fit (glView *view)
2677 {
2678         GtkAllocation  allocation;
2679         gint           w_view, h_view;
2680         gdouble        w_label, h_label;
2681         gdouble        x_scale, y_scale, scale;
2682
2683         gl_debug (DEBUG_VIEW, "");
2684
2685         if ( ! gtk_widget_get_window (GTK_WIDGET (view)) ) {
2686                 set_zoom_real (view, 1.0, TRUE);
2687                 return;
2688         }
2689
2690         gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
2691         w_view = allocation.width;
2692         h_view = allocation.height;
2693
2694         gl_label_get_size (GL_LABEL(view->label), &w_label, &h_label);
2695
2696         gl_debug (DEBUG_VIEW, "View size: %d, %d", w_view, h_view);
2697         gl_debug (DEBUG_VIEW, "Label size: %g, %g", w_label, h_label);
2698
2699         /* Calculate best scale */
2700         x_scale = (double)(w_view - ZOOMTOFIT_PAD) / w_label;
2701         y_scale = (double)(h_view - ZOOMTOFIT_PAD) / h_label;
2702         scale = MIN (x_scale, y_scale);
2703         gl_debug (DEBUG_VIEW, "Candidate zooms: %g, %g => %g", x_scale, y_scale, scale);
2704
2705         /* Limit */
2706         gl_debug (DEBUG_VIEW, "Scale: %g", scale);
2707         scale = MIN (scale, zooms[0]*view->home_scale);
2708         scale = MAX (scale, zooms[N_ZOOMS-1]*view->home_scale);
2709         gl_debug (DEBUG_VIEW, "Limitted scale: %g", scale);
2710
2711         set_zoom_real (view, scale/view->home_scale, TRUE);
2712 }
2713
2714
2715 /*****************************************************************************/
2716 /* Set current zoom factor to explicit value.                                */
2717 /*****************************************************************************/
2718 void
2719 gl_view_set_zoom (glView  *view,
2720                   gdouble  zoom)
2721 {
2722         gl_debug (DEBUG_VIEW, "START");
2723
2724         set_zoom_real (view, zoom, FALSE);
2725
2726         gl_debug (DEBUG_VIEW, "END");
2727 }
2728
2729
2730 /*---------------------------------------------------------------------------*/
2731 /* PRIVATE.  Set canvas scale.                                               */
2732 /*---------------------------------------------------------------------------*/
2733 static void
2734 set_zoom_real (glView   *view,
2735                gdouble   zoom,
2736                gboolean  zoom_to_fit_flag)
2737 {
2738         gl_debug (DEBUG_VIEW, "START");
2739
2740         g_return_if_fail (view && GL_IS_VIEW (view));
2741         g_return_if_fail (zoom > 0.0);
2742
2743         /* Limit, if needed */
2744         gl_debug (DEBUG_VIEW, "Zoom requested: %g", zoom);
2745         zoom = MIN (zoom, zooms[0]);
2746         zoom = MAX (zoom, zooms[N_ZOOMS-1]);
2747         gl_debug (DEBUG_VIEW, "Limitted zoom: %g", zoom);
2748
2749         if ( zoom != view->zoom ) {
2750
2751                 view->zoom = zoom;
2752                 view->zoom_to_fit_flag = zoom_to_fit_flag;
2753
2754                 gl_view_update (view);
2755
2756                 g_signal_emit (G_OBJECT(view), signals[ZOOM_CHANGED], 0, zoom);
2757
2758         }
2759
2760         gl_debug (DEBUG_VIEW, "END");
2761
2762 }
2763
2764
2765 /*****************************************************************************/
2766 /* Get current zoom factor.                                                  */
2767 /*****************************************************************************/
2768 gdouble
2769 gl_view_get_zoom (glView *view)
2770 {
2771         gl_debug (DEBUG_VIEW, "");
2772
2773         g_return_val_if_fail (view && GL_IS_VIEW (view), 1.0);
2774
2775         return view->zoom;
2776 }
2777
2778
2779 /*****************************************************************************/
2780 /* Is this the maximum zoom level.                                           */
2781 /*****************************************************************************/
2782 gboolean
2783 gl_view_is_zoom_max (glView *view)
2784 {
2785         gl_debug (DEBUG_VIEW, "");
2786
2787         g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
2788
2789         return view->zoom >= zooms[0];
2790 }
2791
2792
2793 /*****************************************************************************/
2794 /* Is this the minimum zoom level.                                           */
2795 /*****************************************************************************/
2796 gboolean
2797 gl_view_is_zoom_min (glView *view)
2798 {
2799         gl_debug (DEBUG_VIEW, "");
2800
2801         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
2802
2803         return view->zoom <= zooms[N_ZOOMS-1];
2804 }
2805
2806
2807 /*---------------------------------------------------------------------------*/
2808 /* PRIVATE.  Handle "selection-clear" signal.                                */
2809 /*---------------------------------------------------------------------------*/
2810 static void
2811 selection_clear_cb (GtkWidget         *widget,
2812                     GdkEventSelection *event,
2813                     glView            *view)
2814 {
2815         gl_debug (DEBUG_VIEW, "START");
2816
2817         g_return_if_fail (view && GL_IS_VIEW (view));
2818
2819         view->have_selection = FALSE;
2820         g_object_unref (view->selection_data);
2821         view->selection_data = NULL;
2822
2823         gl_debug (DEBUG_VIEW, "END");
2824 }
2825
2826
2827 /*---------------------------------------------------------------------------*/
2828 /* PRIVATE.  Handle "selection-get" signal.                                  */
2829 /*---------------------------------------------------------------------------*/
2830 static void
2831 selection_get_cb (GtkWidget        *widget,
2832                   GtkSelectionData *sd,
2833                   guint             info,
2834                   guint             time,
2835                   glView           *view)
2836 {
2837         gchar            *buffer;
2838         glXMLLabelStatus  status;
2839
2840         gl_debug (DEBUG_VIEW, "START");
2841
2842         g_return_if_fail (view && GL_IS_VIEW (view));
2843
2844         if (view->have_selection) {
2845
2846                 buffer = gl_xml_label_save_buffer (view->selection_data,
2847                                                    &status);
2848                 gtk_selection_data_set (sd,
2849                                         GDK_SELECTION_TYPE_STRING, 8,
2850                                         (guchar *)buffer, strlen (buffer));
2851                 g_free (buffer);
2852         }
2853
2854         gl_debug (DEBUG_VIEW, "END");
2855 }
2856
2857
2858 /*---------------------------------------------------------------------------*/
2859 /* PRIVATE.  Handle "selection-received" signal.  (Result of Paste)          */
2860 /*---------------------------------------------------------------------------*/
2861 static void
2862 selection_received_cb (GtkWidget        *widget,
2863                        GtkSelectionData *sd,
2864                        guint             time,
2865                        glView           *view)
2866 {
2867         glLabel          *label = NULL;
2868         glXMLLabelStatus  status;
2869         GList            *p, *p_next;
2870         glLabelObject    *object, *newobject;
2871
2872         gl_debug (DEBUG_VIEW, "START");
2873
2874         g_return_if_fail (view && GL_IS_VIEW (view));
2875
2876         if (gtk_selection_data_get_length (sd) < 0)
2877         {
2878                 return;
2879         }
2880         if (gtk_selection_data_get_data_type (sd) != GDK_SELECTION_TYPE_STRING)
2881         {
2882                 return;
2883         }
2884
2885         gl_view_unselect_all (view);
2886
2887         label = gl_xml_label_open_buffer ((gchar *)gtk_selection_data_get_data (sd), &status);
2888         for (p = label->objects; p != NULL; p = p_next)
2889         {
2890                 p_next = p->next;
2891
2892                 object = (glLabelObject *) p->data;
2893                 newobject = gl_label_object_dup (object, view->label);
2894
2895                 gl_debug (DEBUG_VIEW, "object pasted");
2896         }
2897         g_object_unref (label);
2898
2899         gl_debug (DEBUG_VIEW, "END");
2900 }
2901
2902
2903 /****************************************************************************/
2904 /* Set default font family.                                                 */
2905 /****************************************************************************/
2906 void
2907 gl_view_set_default_font_family (glView      *view,
2908                                  const gchar *font_family)
2909 {
2910         gl_debug (DEBUG_VIEW, "START");
2911
2912         g_return_if_fail (view && GL_IS_VIEW (view));
2913
2914         if (view->default_font_family) {
2915                 g_free (view->default_font_family);
2916         }
2917         view->default_font_family = g_strdup (font_family);
2918
2919         gl_debug (DEBUG_VIEW, "END");
2920 }
2921
2922
2923 /****************************************************************************/
2924 /* Set default font size.                                                   */
2925 /****************************************************************************/
2926 void
2927 gl_view_set_default_font_size (glView  *view,
2928                                gdouble  font_size)
2929 {
2930         gl_debug (DEBUG_VIEW, "START");
2931
2932         g_return_if_fail (view && GL_IS_VIEW (view));
2933
2934         view->default_font_size = font_size;
2935
2936         gl_debug (DEBUG_VIEW, "END");
2937 }
2938
2939
2940 /****************************************************************************/
2941 /* Set default font weight.                                                 */
2942 /****************************************************************************/
2943 void
2944 gl_view_set_default_font_weight (glView      *view,
2945                                  PangoWeight  font_weight)
2946 {
2947         gl_debug (DEBUG_VIEW, "START");
2948
2949         g_return_if_fail (view && GL_IS_VIEW (view));
2950
2951         view->default_font_weight = font_weight;
2952
2953         gl_debug (DEBUG_VIEW, "END");
2954 }
2955
2956
2957 /****************************************************************************/
2958 /* Set default font italic flag.                                            */
2959 /****************************************************************************/
2960 void
2961 gl_view_set_default_font_italic_flag (glView   *view,
2962                                       gboolean  font_italic_flag)
2963 {
2964         gl_debug (DEBUG_VIEW, "START");
2965
2966         g_return_if_fail (view && GL_IS_VIEW (view));
2967
2968         view->default_font_italic_flag = font_italic_flag;
2969
2970         gl_debug (DEBUG_VIEW, "END");
2971 }
2972
2973
2974 /****************************************************************************/
2975 /* Set default text color.                                                  */
2976 /****************************************************************************/
2977 void
2978 gl_view_set_default_text_color (glView *view,
2979                                 guint   text_color)
2980 {
2981         gl_debug (DEBUG_VIEW, "START");
2982
2983         g_return_if_fail (view && GL_IS_VIEW (view));
2984
2985         view->default_text_color = text_color;
2986
2987         gl_debug (DEBUG_VIEW, "END");
2988 }
2989
2990
2991 /****************************************************************************/
2992 /* Set default text alignment.                                              */
2993 /****************************************************************************/
2994 void
2995 gl_view_set_default_text_alignment (glView           *view,
2996                                     PangoAlignment    text_alignment)
2997 {
2998         gl_debug (DEBUG_VIEW, "START");
2999
3000         g_return_if_fail (view && GL_IS_VIEW (view));
3001
3002         view->default_text_alignment = text_alignment;
3003         gl_debug (DEBUG_VIEW, "END");
3004 }
3005
3006
3007 /****************************************************************************/
3008 /* Set default text line spacing.                                           */
3009 /****************************************************************************/
3010 void
3011 gl_view_set_default_text_line_spacing (glView  *view,
3012                                        gdouble  text_line_spacing)
3013 {
3014         gl_debug (DEBUG_VIEW, "START");
3015
3016         g_return_if_fail (view && GL_IS_VIEW (view));
3017
3018         view->default_text_line_spacing = text_line_spacing;
3019
3020         gl_debug (DEBUG_VIEW, "END");
3021 }
3022
3023
3024 /****************************************************************************/
3025 /* Set default line width.                                                  */
3026 /****************************************************************************/
3027 void
3028 gl_view_set_default_line_width (glView  *view,
3029                                 gdouble  line_width)
3030 {
3031         gl_debug (DEBUG_VIEW, "START");
3032
3033         g_return_if_fail (view && GL_IS_VIEW (view));
3034
3035         view->default_line_width = line_width;
3036
3037         gl_debug (DEBUG_VIEW, "END");
3038 }
3039
3040
3041 /****************************************************************************/
3042 /* Set default line color.                                                  */
3043 /****************************************************************************/
3044 void
3045 gl_view_set_default_line_color (glView *view,
3046                                 guint   line_color)
3047 {
3048         gl_debug (DEBUG_VIEW, "START");
3049
3050         g_return_if_fail (view && GL_IS_VIEW (view));
3051
3052         view->default_line_color = line_color;
3053
3054         gl_debug (DEBUG_VIEW, "END");
3055 }
3056
3057
3058 /****************************************************************************/
3059 /* Set default fill color.                                                  */
3060 /****************************************************************************/
3061 void
3062 gl_view_set_default_fill_color (glView *view,
3063                                 guint   fill_color)
3064 {
3065         gl_debug (DEBUG_VIEW, "START");
3066
3067         g_return_if_fail (view && GL_IS_VIEW (view));
3068
3069         view->default_fill_color = fill_color;
3070
3071         gl_debug (DEBUG_VIEW, "END");
3072 }
3073
3074
3075 /****************************************************************************/
3076 /* Get default font family.                                                 */
3077 /****************************************************************************/
3078 gchar *
3079 gl_view_get_default_font_family (glView *view)
3080 {
3081         gl_debug (DEBUG_VIEW, "START");
3082
3083         g_return_val_if_fail (view && GL_IS_VIEW (view), NULL);
3084
3085         gl_debug (DEBUG_VIEW, "END");
3086
3087         return g_strdup (view->default_font_family);
3088 }
3089
3090
3091 /****************************************************************************/
3092 /* Get default font size.                                                   */
3093 /****************************************************************************/
3094 gdouble
3095 gl_view_get_default_font_size (glView *view)
3096 {
3097         gl_debug (DEBUG_VIEW, "START");
3098
3099         g_return_val_if_fail (view && GL_IS_VIEW (view), 12.0);
3100
3101         gl_debug (DEBUG_VIEW, "END");
3102
3103         return view->default_font_size;
3104 }
3105
3106
3107 /****************************************************************************/
3108 /* Get default font weight.                                                 */
3109 /****************************************************************************/
3110 PangoWeight
3111 gl_view_get_default_font_weight (glView *view)
3112 {
3113         gl_debug (DEBUG_VIEW, "START");
3114
3115         g_return_val_if_fail (view && GL_IS_VIEW (view), PANGO_WEIGHT_NORMAL);
3116
3117         gl_debug (DEBUG_VIEW, "END");
3118
3119         return view->default_font_weight;
3120 }
3121
3122
3123 /****************************************************************************/
3124 /* Get default font italic flag.                                            */
3125 /****************************************************************************/
3126 gboolean
3127 gl_view_get_default_font_italic_flag (glView *view)
3128 {
3129         gl_debug (DEBUG_VIEW, "START");
3130
3131         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
3132
3133         gl_debug (DEBUG_VIEW, "END");
3134
3135         return view->default_font_italic_flag;
3136 }
3137
3138
3139 /****************************************************************************/
3140 /* Get default text color.                                                  */
3141 /****************************************************************************/
3142 guint
3143 gl_view_get_default_text_color (glView *view)
3144 {
3145         gl_debug (DEBUG_VIEW, "START");
3146
3147         g_return_val_if_fail (view && GL_IS_VIEW (view), 0);
3148
3149         gl_debug (DEBUG_VIEW, "END");
3150
3151         return view->default_text_color;
3152 }
3153
3154
3155 /****************************************************************************/
3156 /* Get default text alignment.                                              */
3157 /****************************************************************************/
3158 PangoAlignment
3159 gl_view_get_default_text_alignment (glView *view)
3160 {
3161         gl_debug (DEBUG_VIEW, "START");
3162
3163         g_return_val_if_fail (view && GL_IS_VIEW (view), PANGO_ALIGN_LEFT);
3164
3165         gl_debug (DEBUG_VIEW, "END");
3166
3167         return view->default_text_alignment;
3168 }
3169
3170
3171 /****************************************************************************/
3172 /* Get default text line spacing.                                           */
3173 /****************************************************************************/
3174 gdouble
3175 gl_view_get_default_text_line_spacing (glView *view)
3176 {
3177         gl_debug (DEBUG_VIEW, "START");
3178
3179         g_return_val_if_fail (view && GL_IS_VIEW (view), 1.0);
3180
3181         gl_debug (DEBUG_VIEW, "END");
3182
3183         return view->default_text_line_spacing;
3184 }
3185
3186
3187 /****************************************************************************/
3188 /* Get default line width.                                                  */
3189 /****************************************************************************/
3190 gdouble
3191 gl_view_get_default_line_width (glView *view)
3192 {
3193         gl_debug (DEBUG_VIEW, "START");
3194
3195         g_return_val_if_fail (view && GL_IS_VIEW (view), 1.0);
3196
3197         gl_debug (DEBUG_VIEW, "END");
3198
3199         return view->default_line_width;
3200 }
3201
3202
3203 /****************************************************************************/
3204 /* Get default line color.                                                  */
3205 /****************************************************************************/
3206 guint
3207 gl_view_get_default_line_color (glView *view)
3208 {
3209         gl_debug (DEBUG_VIEW, "START");
3210
3211         g_return_val_if_fail (view && GL_IS_VIEW (view), 0);
3212
3213         gl_debug (DEBUG_VIEW, "END");
3214
3215         return view->default_line_color;
3216 }
3217
3218
3219 /****************************************************************************/
3220 /* Get default fill color.                                                  */
3221 /****************************************************************************/
3222 guint
3223 gl_view_get_default_fill_color (glView *view)
3224 {
3225         gl_debug (DEBUG_VIEW, "START");
3226
3227         g_return_val_if_fail (view && GL_IS_VIEW (view), 0);
3228
3229         gl_debug (DEBUG_VIEW, "END");
3230
3231         return view->default_fill_color;
3232 }
3233
3234
3235 /*---------------------------------------------------------------------------*/
3236 /* PRIVATE.  Focus in event handler.                                         */
3237 /*---------------------------------------------------------------------------*/
3238 static gboolean
3239 focus_in_event_cb (glView            *view,
3240                    GdkEventFocus     *event)
3241 {
3242         return FALSE;
3243 }
3244
3245
3246 /*---------------------------------------------------------------------------*/
3247 /* PRIVATE.  Focus out event handler.                                        */
3248 /*---------------------------------------------------------------------------*/
3249 static gboolean
3250 focus_out_event_cb (glView            *view,
3251                     GdkEventFocus     *event)
3252 {
3253         return FALSE;
3254 }
3255
3256
3257 /*---------------------------------------------------------------------------*/
3258 /* PRIVATE.  Enter notify event handler.                                     */
3259 /*---------------------------------------------------------------------------*/
3260 static gboolean
3261 enter_notify_event_cb (glView            *view,
3262                        GdkEventCrossing  *event)
3263 {
3264         return FALSE;
3265 }
3266
3267
3268 /*---------------------------------------------------------------------------*/
3269 /* PRIVATE.  Leave notify event handler.                                     */
3270 /*---------------------------------------------------------------------------*/
3271 static gboolean
3272 leave_notify_event_cb (glView            *view,
3273                        GdkEventCrossing  *event)
3274 {
3275
3276         g_signal_emit (G_OBJECT(view), signals[POINTER_EXIT], 0);
3277
3278         return FALSE;
3279 }
3280
3281
3282 /*---------------------------------------------------------------------------*/
3283 /* PRIVATE.  Motion notify event handler.                                    */
3284 /*---------------------------------------------------------------------------*/
3285 static gboolean
3286 motion_notify_event_cb (glView            *view,
3287                         GdkEventMotion    *event)
3288 {
3289         gboolean            return_value = FALSE;
3290         GdkWindow          *bin_window;
3291         GdkWindow          *window;
3292         cairo_t            *cr;
3293         gdouble             scale;
3294         gdouble             x, y;
3295         GdkCursor          *cursor;
3296         glViewObjectHandle  handle;
3297
3298         bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (view->canvas));
3299         window = gtk_widget_get_window (view->canvas);
3300
3301         cr = gdk_cairo_create (bin_window);
3302
3303         /*
3304          * Translate to label coordinates
3305          */
3306         scale = view->zoom * view->home_scale;
3307         cairo_scale (cr, scale, scale);
3308         cairo_translate (cr, view->x0, view->y0);
3309
3310         x = event->x;
3311         y = event->y;
3312         cairo_device_to_user (cr, &x, &y);
3313
3314         /*
3315          * Emit signal regardless of mode
3316          */
3317         g_signal_emit (G_OBJECT(view), signals[POINTER_MOVED], 0, x, y);
3318
3319         /*
3320          * Handle event as appropriate for mode
3321          */
3322         switch (view->mode)
3323         {
3324
3325         case GL_VIEW_MODE_ARROW:
3326                 switch (view->state)
3327                 {
3328
3329                 case GL_VIEW_IDLE:
3330                         if ( gl_view_is_selection_atomic (view) &&
3331                              view_handle_at (view, cr, event->x, event->y, &handle) )
3332                         {
3333                                 cursor = gdk_cursor_new (GDK_CROSSHAIR);
3334                         }
3335                         else if (view_view_object_at (view, cr, event->x, event->y))
3336                         {
3337                                 cursor = gdk_cursor_new (GDK_FLEUR);
3338                         }
3339                         else
3340                         {
3341                                 cursor = gdk_cursor_new (GDK_LEFT_PTR);
3342                         }
3343                         gdk_window_set_cursor (window, cursor);
3344                         gdk_cursor_unref (cursor);
3345                         break;
3346
3347                 case GL_VIEW_ARROW_SELECT_REGION:
3348 #ifdef CLIP_UPDATES                                
3349                         gl_view_update_region (view, cr, &view->select_region);
3350 #endif
3351                         view->select_region.x2 = x;
3352                         view->select_region.y2 = y;
3353 #ifdef CLIP_UPDATES                                
3354                         gl_view_update_region (view, cr, &view->select_region);
3355 #else
3356                         gl_view_update (view);
3357 #endif
3358                         break;
3359
3360                 case GL_VIEW_ARROW_MOVE:
3361                         gl_view_move_selection (view,
3362                                                 (x - view->move_last_x),
3363                                                 (y - view->move_last_y));
3364                         view->move_last_x = x;
3365                         view->move_last_y = y;
3366                         break;
3367
3368                 case GL_VIEW_ARROW_RESIZE:
3369                         gl_view_object_resize_event (view->resize_object,
3370                                                      view->resize_handle,
3371                                                      view->resize_honor_aspect,
3372                                                      cr,
3373                                                      event->x,
3374                                                      event->y);
3375                         break;
3376
3377                 default:
3378                         g_message ("Invalid arrow state.");      /*Should not happen!*/
3379                 }
3380                 return_value = TRUE;
3381                 break;
3382
3383
3384         case GL_VIEW_MODE_OBJECT_CREATE:
3385                 if (view->state != GL_VIEW_IDLE)
3386                 {
3387                         switch (view->create_type)
3388                         {
3389                         case GL_LABEL_OBJECT_BOX:
3390                                 gl_view_box_create_motion_event (view, x, y);
3391                                 break;
3392                         case GL_LABEL_OBJECT_ELLIPSE:
3393                                 gl_view_ellipse_create_motion_event (view, x, y);
3394                                 break;
3395                         case GL_LABEL_OBJECT_LINE: 
3396                                 gl_view_line_create_motion_event (view, x, y);
3397                                 break;
3398                         case GL_LABEL_OBJECT_IMAGE:
3399                                 gl_view_image_create_motion_event (view, x, y);
3400                                 break;
3401                         case GL_LABEL_OBJECT_TEXT:
3402                                 gl_view_text_create_motion_event (view, x, y);
3403                                 break;
3404                         case GL_LABEL_OBJECT_BARCODE:
3405                                 gl_view_barcode_create_motion_event (view, x, y);
3406                                 break;
3407                         default:
3408                                 g_message ("Invalid create type.");   /*Should not happen!*/
3409                         }
3410                 }
3411                 break;
3412
3413
3414         default:
3415                 g_message ("Invalid view mode.");      /*Should not happen!*/
3416
3417         }
3418
3419         cairo_destroy (cr);
3420
3421         /*
3422          * FIXME: we re-establish grabs here if the grab has been lost.  We seem to be
3423          *        losing grabs when we emit signals that lead to the manipulation of
3424          *        the GtkUIManager.  Needs more investigation
3425          */
3426         if (view->grabbed_flag && !gdk_pointer_is_grabbed ())
3427         {
3428                 gdk_pointer_grab (bin_window,
3429                                   FALSE,
3430                                   (GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK),
3431                                   NULL,
3432                                   NULL,
3433                                   event->time);
3434         }
3435
3436         return return_value;
3437 }
3438
3439
3440 /*---------------------------------------------------------------------------*/
3441 /* PRIVATE.  Button press event handler.                                     */
3442 /*---------------------------------------------------------------------------*/
3443 static gboolean
3444 button_press_event_cb (glView            *view,
3445                        GdkEventButton    *event)
3446 {
3447         gboolean            return_value = FALSE;
3448         GdkWindow          *bin_window;
3449         cairo_t            *cr;
3450         gdouble             scale;
3451         gdouble             x, y;
3452         glViewObject       *view_object;
3453         glViewObjectHandle  handle;
3454
3455         gtk_widget_grab_focus(GTK_WIDGET (view->canvas));
3456
3457         bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (view->canvas));
3458
3459         cr = gdk_cairo_create (bin_window);
3460
3461         /*
3462          * Translate to label coordinates
3463          */
3464         scale = view->zoom * view->home_scale;
3465         cairo_scale (cr, scale, scale);
3466         cairo_translate (cr, view->x0, view->y0);
3467
3468         x = event->x;
3469         y = event->y;
3470         cairo_device_to_user (cr, &x, &y);
3471
3472         switch (event->button)
3473         {
3474
3475         case 1:
3476                 /*
3477                  * Handle event as appropriate for mode
3478                  */
3479                 switch (view->mode)
3480                 {
3481                 case GL_VIEW_MODE_ARROW:
3482                         if ( gl_view_is_selection_atomic (view) &&
3483                              (view_object = view_handle_at (view, cr, event->x, event->y, &handle)) )
3484                         {
3485                                 view->resize_object = view_object;
3486                                 view->resize_handle = handle;
3487                                 view->resize_honor_aspect = event->state & GDK_CONTROL_MASK;
3488
3489                                 view->state = GL_VIEW_ARROW_RESIZE;
3490                         }
3491                         else if ((view_object = view_view_object_at (view, cr, event->x, event->y)))
3492                         {
3493                                 if (event->state & GDK_CONTROL_MASK)
3494                                 {
3495                                         if (gl_view_is_object_selected (view, view_object))
3496                                         {
3497                                                 /* Un-selecting a selected item */
3498                                                 gl_view_unselect_object (view, view_object);
3499                                         } else {
3500                                                 /* Add to current selection */
3501                                                 gl_view_select_object (view, view_object);
3502                                         }
3503                                 }
3504                                 else
3505                                 {
3506                                         if (!gl_view_is_object_selected (view, view_object))
3507                                         {
3508                                                 /* remove any selections before adding */
3509                                                 gl_view_unselect_all (view);
3510                                                 /* Add to current selection */
3511                                                 gl_view_select_object (view, view_object);
3512                                         }
3513                                 }
3514                                 view->move_last_x = x;
3515                                 view->move_last_y = y;
3516
3517                                 view->state = GL_VIEW_ARROW_MOVE;
3518                         }
3519                         else
3520                         {
3521                                 if (!(event->state & GDK_CONTROL_MASK))
3522                                 {
3523                                         gl_view_unselect_all (view);
3524                                 }
3525
3526                                 view->select_region_visible = TRUE;
3527                                 view->select_region.x1 = x;
3528                                 view->select_region.y1 = y;
3529                                 view->select_region.x2 = x;
3530                                 view->select_region.y2 = y;
3531
3532                                 view->state = GL_VIEW_ARROW_SELECT_REGION;
3533                         }
3534
3535
3536                         return_value = TRUE;
3537                         break;
3538
3539                 case GL_VIEW_MODE_OBJECT_CREATE:
3540                         switch (view->create_type)
3541                         {
3542                         case GL_LABEL_OBJECT_BOX:
3543                                 gl_view_box_create_button_press_event (view, x, y);
3544                                 break;
3545                         case GL_LABEL_OBJECT_ELLIPSE:
3546                                 gl_view_ellipse_create_button_press_event (view, x, y);
3547                                 break;
3548                         case GL_LABEL_OBJECT_LINE:
3549                                 gl_view_line_create_button_press_event (view, x, y);
3550                                 break;
3551                         case GL_LABEL_OBJECT_IMAGE:
3552                                 gl_view_image_create_button_press_event (view, x, y);
3553                                 break;
3554                         case GL_LABEL_OBJECT_TEXT:
3555                                 gl_view_text_create_button_press_event (view, x, y);
3556                                 break;
3557                         case GL_LABEL_OBJECT_BARCODE:
3558                                 gl_view_barcode_create_button_press_event (view, x, y);
3559                                 break;
3560                         default:
3561                                 g_message ("Invalid create type.");   /*Should not happen!*/
3562                         }
3563                         view->state = GL_VIEW_CREATE_DRAG;
3564                         return_value = TRUE;
3565                         break;
3566
3567                 default:
3568                         g_message ("Invalid view mode.");      /*Should not happen!*/
3569                 }
3570
3571                 view->grabbed_flag = TRUE;
3572                 gdk_pointer_grab (bin_window,
3573                                   FALSE,
3574                                   (GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK),
3575                                   NULL,
3576                                   NULL,
3577                                   event->time);
3578                 break;
3579
3580         case 3:
3581                 g_signal_emit (G_OBJECT (view),
3582                                signals[CONTEXT_MENU_ACTIVATE], 0,
3583                                event->button, event->time);
3584                 return_value = TRUE;
3585                 break;
3586
3587         }
3588
3589         cairo_destroy (cr);
3590
3591         return return_value;
3592 }
3593
3594
3595 /*---------------------------------------------------------------------------*/
3596 /* PRIVATE.  Button release event handler.                                   */
3597 /*---------------------------------------------------------------------------*/
3598 static gboolean
3599 button_release_event_cb (glView            *view,
3600                          GdkEventButton    *event)
3601 {
3602         gboolean     return_value = FALSE;
3603         GdkWindow   *bin_window;
3604         GdkWindow   *window;
3605         cairo_t     *cr;
3606         gdouble      scale;
3607         gdouble      x, y;
3608         GdkCursor   *cursor;
3609
3610         bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (view->canvas));
3611         window = gtk_widget_get_window (view->canvas);
3612
3613         cr = gdk_cairo_create (bin_window);
3614
3615         /*
3616          * Translate to label coordinates
3617          */
3618         scale = view->zoom * view->home_scale;
3619         cairo_scale (cr, scale, scale);
3620         cairo_translate (cr, view->x0, view->y0);
3621
3622         x = event->x;
3623         y = event->y;
3624         cairo_device_to_user (cr, &x, &y);
3625
3626         switch (event->button)
3627         {
3628
3629         case 1:
3630                 view->grabbed_flag = FALSE;
3631                 gdk_pointer_ungrab (event->time);
3632                 /*
3633                  * Handle event as appropriate for mode
3634                  */
3635                 switch (view->mode)
3636                 {
3637                 case GL_VIEW_MODE_ARROW:
3638                         switch (view->state)
3639                         {
3640                         case GL_VIEW_ARROW_RESIZE:
3641                                 view->resize_object = NULL;
3642
3643                                 view->state = GL_VIEW_IDLE;
3644                                 break;
3645
3646                         case GL_VIEW_ARROW_SELECT_REGION:
3647 #ifdef CLIP_UPDATES                                
3648                                 gl_view_update_region (view, cr, &view->select_region);
3649 #else
3650                                 gl_view_update (view);
3651 #endif
3652
3653                                 view->select_region_visible = FALSE;
3654                                 view->select_region.x2 = x;
3655                                 view->select_region.y2 = y;
3656
3657                                 gl_view_select_region (view, &view->select_region);
3658
3659                                 view->state = GL_VIEW_IDLE;
3660                                 break;
3661
3662                         default:
3663                                 view->state = GL_VIEW_IDLE;
3664                                 break;
3665                                 
3666                         }
3667
3668                         return_value = TRUE;
3669                         break;
3670
3671
3672                 case GL_VIEW_MODE_OBJECT_CREATE:
3673                         switch (view->create_type)
3674                         {
3675                         case GL_LABEL_OBJECT_BOX:
3676                                 gl_view_box_create_button_release_event (view, x, y);
3677                                 break;
3678                         case GL_LABEL_OBJECT_ELLIPSE:
3679                                 gl_view_ellipse_create_button_release_event (view, x, y);
3680                                 break;
3681                         case GL_LABEL_OBJECT_LINE:
3682                                 gl_view_line_create_button_release_event (view, x, y);
3683                                 break;
3684                         case GL_LABEL_OBJECT_IMAGE:
3685                                 gl_view_image_create_button_release_event (view, x, y);
3686                                 break;
3687                         case GL_LABEL_OBJECT_TEXT:
3688                                 gl_view_text_create_button_release_event (view, x, y);
3689                                 break;
3690                         case GL_LABEL_OBJECT_BARCODE:
3691                                 gl_view_barcode_create_button_release_event (view, x, y);
3692                                 break;
3693                         default:
3694                                 g_message ("Invalid create type.");   /*Should not happen!*/
3695                         }
3696                         view->mode = GL_VIEW_MODE_ARROW;
3697                         view->state = GL_VIEW_IDLE;
3698                         cursor = gdk_cursor_new (GDK_LEFT_PTR);
3699                         gdk_window_set_cursor (window, cursor);
3700                         gdk_cursor_unref (cursor);
3701                         break;
3702
3703
3704                 default:
3705                         g_message ("Invalid view mode.");      /*Should not happen!*/
3706                 }
3707
3708         }
3709
3710         cairo_destroy (cr);
3711
3712         return return_value;
3713 }
3714
3715
3716 /*---------------------------------------------------------------------------*/
3717 /* PRIVATE.  Key press event handler.                                        */
3718 /*---------------------------------------------------------------------------*/
3719 static gboolean
3720 key_press_event_cb (glView            *view,
3721                     GdkEventKey       *event)
3722 {
3723         GdkWindow *window;
3724         GdkCursor *cursor;
3725
3726         gl_debug (DEBUG_VIEW, "");
3727
3728         window = gtk_widget_get_window (view->canvas);
3729
3730         if ( (view->mode == GL_VIEW_MODE_ARROW) &&
3731              (view->state == GL_VIEW_IDLE) )
3732         {
3733                 switch (event->keyval) {
3734
3735                 case GDK_Left:
3736                 case GDK_KP_Left:
3737                         gl_view_move_selection (view, -1.0 / (view->zoom), 0.0);
3738                         break;
3739                 case GDK_Up:
3740                 case GDK_KP_Up:
3741                         gl_view_move_selection (view, 0.0, -1.0 / (view->zoom));
3742                         break;
3743                 case GDK_Right:
3744                 case GDK_KP_Right:
3745                         gl_view_move_selection (view, 1.0 / (view->zoom), 0.0);
3746                         break;
3747                 case GDK_Down:
3748                 case GDK_KP_Down:
3749                         gl_view_move_selection (view, 0.0, 1.0 / (view->zoom));
3750                         break;
3751                 case GDK_Delete:
3752                 case GDK_KP_Delete:
3753                         gl_view_delete_selection (view);
3754                         cursor = gdk_cursor_new (GDK_LEFT_PTR);
3755                         gdk_window_set_cursor (window, cursor);
3756                         gdk_cursor_unref (cursor);
3757                         break;
3758                 default:
3759                         return FALSE;
3760  
3761                }
3762         }
3763         return TRUE;    /* We handled this or we were dragging. */
3764 }
3765
3766
3767
3768 /*
3769  * Local Variables:       -- emacs
3770  * mode: C                -- emacs
3771  * c-basic-offset: 8      -- emacs
3772  * tab-width: 8           -- emacs
3773  * indent-tabs-mode: nil  -- emacs
3774  * End:                   -- emacs
3775  */