]> git.sur5r.net Git - glabels/blob - src/view.c
Refactored glLabel and glView
[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 "view-box.h"
26 #include "view-ellipse.h"
27 #include "view-line.h"
28 #include "view-image.h"
29 #include "view-text.h"
30 #include "view-barcode.h"
31
32 #include <glib/gi18n.h>
33 #include <gtk/gtk.h>
34 #include <gdk/gdkkeysyms.h>
35 #include <string.h>
36 #include <math.h>
37
38 #include "label.h"
39 #include "cairo-label-path.h"
40 #include "cairo-markup-path.h"
41 #include "color.h"
42 #include "prefs.h"
43 #include "marshal.h"
44
45 #include "debug.h"
46
47
48 /*==========================================================================*/
49 /* Private macros and constants.                                            */
50 /*==========================================================================*/
51
52 #define BG_COLOR        GL_COLOR (192, 192, 192)
53
54 #define PAPER_RGB_ARGS          1.0,   1.0,   1.0
55 #define GRID_RGB_ARGS           0.753, 0.753, 0.753
56 #define MARKUP_RGB_ARGS         0.94,  0.39,  0.39
57 #define OUTLINE_RGB_ARGS        0.68,  0.85,  0.90
58 #define SELECT_LINE_RGBA_ARGS   0.0,   0.0,   1.0,   0.5
59 #define SELECT_FILL_RGBA_ARGS   0.75,  0.75,  1.0,   0.5
60
61 #define GRID_LINE_WIDTH_PIXELS    1.0
62 #define MARKUP_LINE_WIDTH_PIXELS  1.0
63 #define OUTLINE_WIDTH_PIXELS      3.0
64 #define SELECT_LINE_WIDTH_PIXELS  3.0
65
66 #define ZOOMTOFIT_PAD   16
67
68 #define POINTS_PER_MM    2.83464566929
69
70
71 /*==========================================================================*/
72 /* Private types.                                                           */
73 /*==========================================================================*/
74
75 enum {
76         CONTEXT_MENU_ACTIVATE,
77         ZOOM_CHANGED,
78         POINTER_MOVED,
79         POINTER_EXIT,
80         MODE_CHANGED,
81         LAST_SIGNAL
82 };
83
84
85 /*==========================================================================*/
86 /* Private globals                                                          */
87 /*==========================================================================*/
88
89 static guint signals[LAST_SIGNAL] = {0};
90
91 static gdouble zooms[] = {
92         8.00,
93         6.00,
94         4.00,
95         3.00,
96         2.00,
97         1.50,
98         1.00,
99         0.75,
100         0.67,
101         0.50,
102         0.33,
103         0.25,
104         0.20,
105         0.15,
106         0.10,
107 };
108 #define N_ZOOMS G_N_ELEMENTS(zooms)
109
110
111 /*==========================================================================*/
112 /* Local function prototypes                                                */
113 /*==========================================================================*/
114
115 static void       gl_view_finalize                (GObject        *object);
116
117 static void       gl_view_construct               (glView         *view,
118                                                    glLabel        *label);
119
120 static gdouble    get_home_scale                  (glView         *view);
121
122 static gboolean   expose_cb                       (glView         *view,
123                                                    GdkEventExpose *event);
124
125 static void       realize_cb                      (glView         *view);
126
127 static void       size_allocate_cb                (glView         *view,
128                                                    GtkAllocation  *allocation);
129
130 static void       screen_changed_cb               (glView         *view);
131
132 static void       label_changed_cb                (glView         *view);
133
134 static void       label_resized_cb                (glView         *view);
135
136 static void       draw_layers                     (glView         *view,
137                                                    cairo_t        *cr);
138
139 static void       draw_bg_layer                   (glView         *view,
140                                                    cairo_t        *cr);
141 static void       draw_grid_layer                 (glView         *view,
142                                                    cairo_t        *cr);
143 static void       draw_markup_layer               (glView         *view,
144                                                    cairo_t        *cr);
145 static void       draw_objects_layer              (glView         *view,
146                                                    cairo_t        *cr);
147 static void       draw_fg_layer                   (glView         *view,
148                                                    cairo_t        *cr);
149 static void       draw_highlight_layer            (glView         *view,
150                                                    cairo_t        *cr);
151 static void       draw_select_region_layer        (glView         *view,
152                                                    cairo_t        *cr);
153
154 static void       set_zoom_real                   (glView         *view,
155                                                    gdouble         zoom,
156                                                    gboolean        scale_to_fit_flag);
157
158 static gboolean   focus_in_event_cb               (glView            *view,
159                                                    GdkEventFocus     *event);
160
161 static gboolean   focus_out_event_cb              (glView            *view,
162                                                    GdkEventFocus     *event);
163
164 static gboolean   enter_notify_event_cb           (glView            *view,
165                                                    GdkEventCrossing  *event);
166
167 static gboolean   leave_notify_event_cb           (glView            *view,
168                                                    GdkEventCrossing  *event);
169
170 static gboolean   motion_notify_event_cb          (glView            *view,
171                                                    GdkEventMotion    *event);
172
173 static gboolean   button_press_event_cb           (glView            *view,
174                                                    GdkEventButton    *event);
175
176 static gboolean   button_release_event_cb         (glView            *view,
177                                                    GdkEventButton    *event);
178
179 static gboolean   key_press_event_cb              (glView            *view,
180                                                    GdkEventKey       *event);
181
182 static void       resize_event                    (glView            *view,
183                                                    cairo_t           *cr,
184                                                    gdouble            x,
185                                                    gdouble            y);
186
187 /****************************************************************************/
188 /* Boilerplate Object stuff.                                                */
189 /****************************************************************************/
190 G_DEFINE_TYPE (glView, gl_view, GTK_TYPE_VBOX);
191
192
193 static void
194 gl_view_class_init (glViewClass *class)
195 {
196         GObjectClass *object_class = G_OBJECT_CLASS (class);
197
198         gl_debug (DEBUG_VIEW, "START");
199
200         gl_view_parent_class = g_type_class_peek_parent (class);
201
202         object_class->finalize = gl_view_finalize;
203
204         signals[CONTEXT_MENU_ACTIVATE] =
205                 g_signal_new ("context_menu_activate",
206                               G_OBJECT_CLASS_TYPE (object_class),
207                               G_SIGNAL_RUN_LAST,
208                               G_STRUCT_OFFSET (glViewClass, context_menu_activate),
209                               NULL, NULL,
210                               gl_marshal_VOID__INT_UINT,
211                               G_TYPE_NONE,
212                               2, G_TYPE_INT, G_TYPE_UINT);
213
214         signals[ZOOM_CHANGED] =
215                 g_signal_new ("zoom_changed",
216                               G_OBJECT_CLASS_TYPE (object_class),
217                               G_SIGNAL_RUN_LAST,
218                               G_STRUCT_OFFSET (glViewClass, zoom_changed),
219                               NULL, NULL,
220                               gl_marshal_VOID__DOUBLE,
221                               G_TYPE_NONE,
222                               1, G_TYPE_DOUBLE);
223
224         signals[POINTER_MOVED] =
225                 g_signal_new ("pointer_moved",
226                               G_OBJECT_CLASS_TYPE (object_class),
227                               G_SIGNAL_RUN_LAST,
228                               G_STRUCT_OFFSET (glViewClass, pointer_moved),
229                               NULL, NULL,
230                               gl_marshal_VOID__DOUBLE_DOUBLE,
231                               G_TYPE_NONE,
232                               2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
233
234         signals[POINTER_EXIT] =
235                 g_signal_new ("pointer_exit",
236                               G_OBJECT_CLASS_TYPE (object_class),
237                               G_SIGNAL_RUN_LAST,
238                               G_STRUCT_OFFSET (glViewClass, pointer_exit),
239                               NULL, NULL,
240                               gl_marshal_VOID__VOID,
241                               G_TYPE_NONE,
242                               0);
243
244         signals[MODE_CHANGED] =
245                 g_signal_new ("mode_changed",
246                               G_OBJECT_CLASS_TYPE (object_class),
247                               G_SIGNAL_RUN_LAST,
248                               G_STRUCT_OFFSET (glViewClass, mode_changed),
249                               NULL, NULL,
250                               gl_marshal_VOID__VOID,
251                               G_TYPE_NONE,
252                               0);
253
254         gl_debug (DEBUG_VIEW, "END");
255 }
256
257
258 static void
259 gl_view_init (glView *view)
260 {
261         GtkWidget *wscroll;
262         GdkColor  *bg_color;
263
264         gl_debug (DEBUG_VIEW, "START");
265
266         view->label                = NULL;
267         view->grid_visible         = TRUE;
268         view->grid_spacing         = 9;
269         view->markup_visible       = TRUE;
270         view->mode                 = GL_VIEW_MODE_ARROW;
271         view->zoom                 = 1.0;
272         view->home_scale           = get_home_scale (view);
273
274         /*
275          * Canvas
276          */
277         view->canvas = gtk_layout_new (NULL, NULL);
278         wscroll = gtk_scrolled_window_new (NULL, NULL);
279         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (wscroll),
280                                         GTK_POLICY_AUTOMATIC,
281                                         GTK_POLICY_AUTOMATIC);
282         gtk_box_pack_start (GTK_BOX (view), wscroll, TRUE, TRUE, 0);
283         gtk_container_add (GTK_CONTAINER (wscroll), view->canvas);
284
285         bg_color = gl_color_to_gdk_color (BG_COLOR);
286         gtk_widget_modify_bg (GTK_WIDGET (view->canvas), GTK_STATE_NORMAL, bg_color);
287         g_free (bg_color);
288
289         gtk_widget_set_can_focus (GTK_WIDGET (view->canvas), TRUE);
290
291         gtk_widget_add_events (GTK_WIDGET (view->canvas),
292                                (GDK_FOCUS_CHANGE_MASK   |
293                                 GDK_ENTER_NOTIFY_MASK   |
294                                 GDK_LEAVE_NOTIFY_MASK   |
295                                 GDK_POINTER_MOTION_MASK |
296                                 GDK_BUTTON_PRESS_MASK   |
297                                 GDK_BUTTON_RELEASE_MASK |
298                                 GDK_KEY_PRESS_MASK));
299
300         g_signal_connect_swapped (G_OBJECT (view->canvas), "expose-event",
301                                   G_CALLBACK (expose_cb), view);
302         g_signal_connect_swapped (G_OBJECT (view->canvas), "realize",
303                                   G_CALLBACK (realize_cb), view);
304         g_signal_connect_swapped (G_OBJECT (view->canvas), "size-allocate",
305                                   G_CALLBACK (size_allocate_cb), view);
306         g_signal_connect_swapped (G_OBJECT (view->canvas), "screen-changed",
307                                   G_CALLBACK (screen_changed_cb), view);
308         g_signal_connect_swapped (G_OBJECT (view->canvas), "focus-in-event",
309                                   G_CALLBACK (focus_in_event_cb), view);
310         g_signal_connect_swapped (G_OBJECT (view->canvas), "focus-out-event",
311                                   G_CALLBACK (focus_out_event_cb), view);
312         g_signal_connect_swapped (G_OBJECT (view->canvas), "enter-notify-event",
313                                   G_CALLBACK (enter_notify_event_cb), view);
314         g_signal_connect_swapped (G_OBJECT (view->canvas), "leave-notify-event",
315                                   G_CALLBACK (leave_notify_event_cb), view);
316         g_signal_connect_swapped (G_OBJECT (view->canvas), "motion-notify-event",
317                                   G_CALLBACK (motion_notify_event_cb), view);
318         g_signal_connect_swapped (G_OBJECT (view->canvas), "button-press-event",
319                                   G_CALLBACK (button_press_event_cb), view);
320         g_signal_connect_swapped (G_OBJECT (view->canvas), "button-release-event",
321                                   G_CALLBACK (button_release_event_cb), view);
322         g_signal_connect_swapped (G_OBJECT (view->canvas), "key-press-event",
323                                   G_CALLBACK (key_press_event_cb), view);
324
325         gl_debug (DEBUG_VIEW, "END");
326 }
327
328
329 static void
330 gl_view_finalize (GObject *object)
331 {
332         glView *view = GL_VIEW (object);
333
334         gl_debug (DEBUG_VIEW, "START");
335
336         g_return_if_fail (object != NULL);
337         g_return_if_fail (GL_IS_VIEW (view));
338
339         G_OBJECT_CLASS (gl_view_parent_class)->finalize (object);
340
341         gl_debug (DEBUG_VIEW, "END");
342 }
343
344
345 /****************************************************************************/
346 /* NEW view object.                                                         */
347 /****************************************************************************/
348 GtkWidget *
349 gl_view_new (glLabel *label)
350 {
351         glView *view;
352
353         gl_debug (DEBUG_VIEW, "START");
354
355         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
356
357         view = g_object_new (GL_TYPE_VIEW, NULL);
358
359         gl_view_construct (view, label);
360
361         gl_debug (DEBUG_VIEW, "END");
362
363         return GTK_WIDGET (view);
364 }
365
366
367 /*---------------------------------------------------------------------------*/
368 /* PRIVATE.  Construct composite widget.                                     */
369 /*---------------------------------------------------------------------------*/
370 static void
371 gl_view_construct (glView  *view,
372                    glLabel *label)
373 {
374         gl_debug (DEBUG_VIEW, "START");
375
376         g_return_if_fail (GL_IS_VIEW (view));
377
378         view->label = label;
379
380         g_signal_connect_swapped (G_OBJECT (view->label), "selection_changed",
381                                   G_CALLBACK (label_changed_cb), view);
382         g_signal_connect_swapped (G_OBJECT (view->label), "changed",
383                                   G_CALLBACK (label_changed_cb), view);
384         g_signal_connect_swapped (G_OBJECT (view->label), "size_changed",
385                                   G_CALLBACK (label_resized_cb), view);
386
387         gl_debug (DEBUG_VIEW, "END");
388 }
389
390
391 /*---------------------------------------------------------------------------*/
392 /* PRIAVTE.  Calculate 1:1 scale for screen.                                 */
393 /*---------------------------------------------------------------------------*/
394 static gdouble
395 get_home_scale (glView *view)
396 {
397         GdkScreen *screen;
398         gdouble    screen_width_pixels;
399         gdouble    screen_width_mm;
400         gdouble    screen_height_pixels;
401         gdouble    screen_height_mm;
402         gdouble    x_pixels_per_mm;
403         gdouble    y_pixels_per_mm;
404         gdouble    scale;
405
406         if (view->canvas == NULL) return 1.0;
407
408         if (!gtk_widget_has_screen (GTK_WIDGET (view->canvas))) return 1.0;
409
410         screen = gtk_widget_get_screen (GTK_WIDGET (view->canvas));
411
412         gl_debug (DEBUG_VIEW, "Screen = %p", screen);
413
414         screen_width_pixels  = gdk_screen_get_width (screen);
415         screen_width_mm      = gdk_screen_get_width_mm (screen);
416         screen_height_pixels = gdk_screen_get_height (screen);
417         screen_height_mm     = gdk_screen_get_height_mm (screen);
418
419         x_pixels_per_mm      = screen_width_pixels / screen_width_mm;
420         y_pixels_per_mm      = screen_height_pixels / screen_height_mm;
421
422         gl_debug (DEBUG_VIEW, "Horizontal dot pitch: %g pixels/mm (%g dpi)",
423                   x_pixels_per_mm, x_pixels_per_mm * 25.4);
424         gl_debug (DEBUG_VIEW, "Vertical dot pitch: %g pixels/mm (%g dpi)",
425                   y_pixels_per_mm, y_pixels_per_mm * 25.4);
426
427         scale = (x_pixels_per_mm + y_pixels_per_mm) / 2.0;
428
429         gl_debug (DEBUG_VIEW, "Average dot pitch: %g pixels/mm (%g dpi)",
430                   scale, scale * 25.4);
431
432         scale /= POINTS_PER_MM;
433
434         gl_debug (DEBUG_VIEW, "Scale = %g pixels/point", scale);
435
436         /* Make sure scale is somewhat sane. */
437         if ( (scale < 0.25) || (scale > 4.0) ) return 1.0;
438
439         return scale;
440 }
441
442
443 /*---------------------------------------------------------------------------*/
444 /* Schedule canvas update.                                                   */
445 /*---------------------------------------------------------------------------*/
446 void
447 gl_view_update (glView  *view)
448 {
449         GdkWindow *window;
450         GdkRegion *region;
451         
452         gl_debug (DEBUG_VIEW, "START");
453
454         window = gtk_widget_get_window (GTK_WIDGET (view->canvas));
455         
456         if (!window) return;
457
458         if ( !view->update_scheduled_flag )
459         {
460                 view->update_scheduled_flag = TRUE;
461
462                 region = gdk_drawable_get_clip_region (window);
463                 /* redraw the cairo canvas completely by exposing it */
464                 gdk_window_invalidate_region (window, region, TRUE);
465                 gdk_region_destroy (region);
466         }
467
468         gl_debug (DEBUG_VIEW, "END");
469 }
470
471
472 /*---------------------------------------------------------------------------*/
473 /* Schedule canvas region update.                                            */
474 /*---------------------------------------------------------------------------*/
475 void
476 gl_view_update_region (glView        *view,
477                        cairo_t       *cr,
478                        glLabelRegion *region)
479 {
480         GdkWindow    *window;
481         GdkRectangle  rect;
482         gdouble       x, y, w, h;
483
484         gl_debug (DEBUG_VIEW, "START");
485
486         window = gtk_widget_get_window (GTK_WIDGET (view->canvas));
487
488         if (!window) return;
489
490         x = MIN (region->x1, region->x2);
491         y = MIN (region->y1, region->y2);
492         w = fabs (region->x2 - region->x1);
493         h = fabs (region->y2 - region->y1);
494
495         cairo_user_to_device (cr, &x, &y);
496         cairo_user_to_device_distance (cr, &w, &h);
497
498         rect.x      = x - 3;
499         rect.y      = y - 3;
500         rect.width  = w + 6;
501         rect.height = h + 6;
502
503         gdk_window_invalidate_rect (window, &rect, TRUE);
504
505         gl_debug (DEBUG_VIEW, "END");
506 }
507
508
509 /*---------------------------------------------------------------------------*/
510 /* PRIVATE.  Expose handler.                                                 */
511 /*---------------------------------------------------------------------------*/
512 static gboolean
513 expose_cb (glView         *view,
514            GdkEventExpose *event)
515 {
516         GdkWindow *bin_window;
517         cairo_t   *cr;
518
519         gl_debug (DEBUG_VIEW, "START");
520
521         view->update_scheduled_flag = FALSE;
522
523         bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (view->canvas));
524         cr = gdk_cairo_create (bin_window);
525
526         cairo_rectangle (cr,
527                         event->area.x, event->area.y,
528                         event->area.width, event->area.height);
529         cairo_clip (cr);
530         
531         draw_layers (view, cr);
532
533         cairo_destroy (cr);
534
535         gl_debug (DEBUG_VIEW, "END");
536
537         return FALSE;
538 }
539
540
541 /*---------------------------------------------------------------------------*/
542 /* PRIVATE.  Realize handler.                                                */
543 /*---------------------------------------------------------------------------*/
544 static void
545 realize_cb (glView  *view)
546 {
547         g_return_if_fail (view && GL_IS_VIEW (view));
548
549         gl_debug (DEBUG_VIEW, "START");
550
551         gl_debug (DEBUG_VIEW, "END");
552 }
553
554
555 /*---------------------------------------------------------------------------*/
556 /* PRIVATE. Size allocation changed callback.                                */
557 /*---------------------------------------------------------------------------*/
558 static void
559 size_allocate_cb (glView         *view,
560                   GtkAllocation  *allocation)
561 {
562         GtkAdjustment *hadjustment;
563         GtkAdjustment *vadjustment;
564
565         gl_debug (DEBUG_VIEW, "START");
566
567         hadjustment = gtk_layout_get_hadjustment(GTK_LAYOUT (view->canvas));
568         vadjustment = gtk_layout_get_vadjustment(GTK_LAYOUT (view->canvas));
569
570         gtk_adjustment_set_page_size( hadjustment, allocation->width);
571         gtk_adjustment_set_page_increment( hadjustment, allocation->width / 2);
572
573         gtk_adjustment_set_page_size( vadjustment, allocation->height);
574         gtk_adjustment_set_page_increment( vadjustment, allocation->height / 2);
575
576         g_signal_emit_by_name (hadjustment, "changed");
577         g_signal_emit_by_name (vadjustment, "changed");
578
579         if (view->zoom_to_fit_flag) {
580                 /* Maintain best fit zoom */
581                 gl_view_zoom_to_fit (view);
582         }
583
584         gl_debug (DEBUG_VIEW, "END");
585 }
586
587
588 /*---------------------------------------------------------------------------*/
589 /* PRIVATE. Screen changed callback.                                         */
590 /*---------------------------------------------------------------------------*/
591 static void
592 screen_changed_cb (glView *view)
593 {
594         gl_debug (DEBUG_VIEW, "START");
595
596         if (gtk_widget_has_screen (GTK_WIDGET (view->canvas))) {
597
598                 view->home_scale = get_home_scale (view);
599
600                 if (view->zoom_to_fit_flag) {
601                         /* Maintain best fit zoom */
602                         gl_view_zoom_to_fit (view);
603                 }
604         }
605
606         gl_debug (DEBUG_VIEW, "END");
607 }
608
609
610 /*---------------------------------------------------------------------------*/
611 /* PRIVATE.  Handle label changed event.                                     */
612 /*---------------------------------------------------------------------------*/
613 static void
614 label_changed_cb (glView  *view)
615 {
616         g_return_if_fail (view && GL_IS_VIEW (view));
617
618         gl_debug (DEBUG_VIEW, "START");
619
620         gl_view_update (view);
621
622         gl_debug (DEBUG_VIEW, "END");
623 }
624
625
626 /*---------------------------------------------------------------------------*/
627 /* PRIVATE.  Handle label resize event.                                      */
628 /*---------------------------------------------------------------------------*/
629 static void
630 label_resized_cb (glView  *view)
631 {
632         GtkAdjustment *hadjustment;
633         GtkAdjustment *vadjustment;
634
635         g_return_if_fail (view && GL_IS_VIEW (view));
636
637         gl_debug (DEBUG_VIEW, "START");
638
639         hadjustment = gtk_layout_get_hadjustment(GTK_LAYOUT (view->canvas));
640         vadjustment = gtk_layout_get_vadjustment(GTK_LAYOUT (view->canvas));
641
642         g_signal_emit_by_name (hadjustment, "changed");
643         g_signal_emit_by_name (vadjustment, "changed");
644
645         gl_view_update (view);
646
647         gl_debug (DEBUG_VIEW, "END");
648 }
649
650
651 /*---------------------------------------------------------------------------*/
652 /* PRIVATE.  Create, draw and order layers.                                  */
653 /*---------------------------------------------------------------------------*/
654 static void
655 draw_layers (glView  *view,
656              cairo_t *cr)
657 {
658         GdkWindow                 *bin_window;
659         gdouble                    scale;
660         gdouble                    w, h;
661         gint                       canvas_w, canvas_h;
662
663         g_return_if_fail (view && GL_IS_VIEW (view));
664         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
665
666         gl_debug (DEBUG_VIEW, "START");
667
668         bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (view->canvas));
669
670         scale = view->zoom * view->home_scale;
671
672         gl_label_get_size (view->label, &w, &h);
673
674         scale = view->home_scale * view->zoom;
675         gtk_layout_set_size (GTK_LAYOUT (view->canvas), w*scale+8, h*scale+8);
676
677         gdk_drawable_get_size (bin_window, &canvas_w, &canvas_h);
678
679         view->x0 = (canvas_w/scale - w) / 2.0;
680         view->y0 = (canvas_h/scale - h) / 2.0;
681         view->w  = w;
682         view->h  = h;
683
684         cairo_save (cr);
685
686         cairo_scale (cr, scale, scale);
687         cairo_translate (cr, view->x0, view->y0);
688
689         draw_bg_layer (view, cr);
690         draw_grid_layer (view, cr);
691         draw_markup_layer (view, cr);
692         draw_objects_layer (view, cr);
693         draw_fg_layer (view, cr);
694         draw_highlight_layer (view, cr);
695         draw_select_region_layer (view, cr);
696
697         cairo_restore (cr);
698
699         gl_debug (DEBUG_VIEW, "END");
700
701 }
702
703
704 /*---------------------------------------------------------------------------*/
705 /* PRIVATE.  Draw background                                                 */
706 /*---------------------------------------------------------------------------*/
707 static void
708 draw_bg_layer (glView  *view,
709                cairo_t *cr)
710 {
711         const lglTemplate *template;
712         gboolean           rotate_flag;
713
714         g_return_if_fail (view && GL_IS_VIEW (view));
715         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
716
717         template    = gl_label_get_template (view->label);
718         rotate_flag = gl_label_get_rotate_flag (view->label);
719         gl_cairo_label_path (cr, template, rotate_flag, FALSE);
720
721         cairo_set_source_rgb (cr, PAPER_RGB_ARGS);
722         cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
723         cairo_fill (cr);
724 }
725
726
727 /*---------------------------------------------------------------------------*/
728 /* PRIVATE.  Draw grid lines.                                                */
729 /*---------------------------------------------------------------------------*/
730 static void
731 draw_grid_layer (glView  *view,
732                  cairo_t *cr)
733 {
734         const lglTemplate         *template;
735         const lglTemplateFrame    *frame;
736         gdouble                    w, h;
737         gdouble                    x, y;
738         gdouble                    x0, y0;
739
740         gl_debug (DEBUG_VIEW, "START");
741
742         g_return_if_fail (view && GL_IS_VIEW (view));
743         g_return_if_fail (view->label && GL_IS_LABEL(view->label));
744
745         if (view->grid_visible)
746         {
747
748                 template = gl_label_get_template (view->label);
749                 frame = (lglTemplateFrame *)template->frames->data;
750
751                 gl_label_get_size (view->label, &w, &h);
752         
753                 if (frame->shape == LGL_TEMPLATE_FRAME_SHAPE_RECT) {
754                         x0 = 0.0;
755                         y0 = 0.0;
756                 } else {
757                         /* round labels, adjust grid to line up with center of label. */
758                         x0 = fmod (w/2.0, view->grid_spacing);
759                         y0 = fmod (h/2.0, view->grid_spacing);
760                 }
761
762
763                 cairo_save (cr);
764
765                 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
766                 cairo_set_line_width (cr, GRID_LINE_WIDTH_PIXELS/(view->home_scale * view->zoom));
767                 cairo_set_source_rgb (cr, GRID_RGB_ARGS);
768
769                 for ( x=x0+view->grid_spacing; x < w; x += view->grid_spacing )
770                 {
771                         cairo_move_to (cr, x, 0);
772                         cairo_line_to (cr, x, h);
773                         cairo_stroke (cr);
774                 }
775
776                 for ( y=y0+view->grid_spacing; y < h; y += view->grid_spacing )
777                 {
778                         cairo_move_to (cr, 0, y);
779                         cairo_line_to (cr, w, y);
780                         cairo_stroke (cr);
781                 }
782
783                 cairo_restore (cr);
784
785         }
786
787         gl_debug (DEBUG_VIEW, "END");
788 }
789
790
791 /*---------------------------------------------------------------------------*/
792 /* PRIVATE.  Draw markup layer.                                              */
793 /*---------------------------------------------------------------------------*/
794 static void
795 draw_markup_layer (glView  *view,
796                    cairo_t *cr)
797 {
798         const lglTemplate         *template;
799         const lglTemplateFrame    *frame;
800         gboolean                   rotate_flag;
801         GList                     *p;
802         lglTemplateMarkup         *markup;
803         gdouble                    width, height;
804
805         g_return_if_fail (view && GL_IS_VIEW (view));
806         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
807
808         if (view->markup_visible)
809         {
810
811                 template    = gl_label_get_template (view->label);
812                 frame       = (lglTemplateFrame *)template->frames->data;
813                 rotate_flag = gl_label_get_rotate_flag (view->label);
814
815                 cairo_save (cr);
816
817                 if (rotate_flag)
818                 {
819                         lgl_template_frame_get_size (frame, &width, &height);
820                         cairo_rotate (cr, -M_PI/2.0);
821                         cairo_translate (cr, -width, 0.0);
822                 }
823
824                 cairo_set_line_width (cr, MARKUP_LINE_WIDTH_PIXELS/(view->home_scale * view->zoom));
825                 cairo_set_source_rgb (cr, MARKUP_RGB_ARGS);
826
827                 for ( p=frame->all.markups; p != NULL; p=p->next )
828                 {
829                         markup = (lglTemplateMarkup *)p->data;
830
831                         gl_cairo_markup_path (cr, markup, view->label);
832
833                         cairo_stroke (cr);
834                 }
835
836                 cairo_restore (cr);
837         }
838
839 }
840
841
842 /*---------------------------------------------------------------------------*/
843 /* PRIVATE.  Draw objects layer.                                             */
844 /*---------------------------------------------------------------------------*/
845 static void
846 draw_objects_layer (glView  *view,
847                     cairo_t *cr)
848 {
849         gl_label_draw (view->label, cr, TRUE, NULL);
850 }
851
852
853 /*---------------------------------------------------------------------------*/
854 /* PRIVATE.  Draw foreground                                                 */
855 /*---------------------------------------------------------------------------*/
856 static void
857 draw_fg_layer (glView  *view,
858                cairo_t *cr)
859 {
860         const lglTemplate *template;
861         gboolean           rotate_flag;
862
863         g_return_if_fail (view && GL_IS_VIEW (view));
864         g_return_if_fail (view->label && GL_IS_LABEL (view->label));
865
866         template    = gl_label_get_template (view->label);
867         rotate_flag = gl_label_get_rotate_flag (view->label);
868
869         gl_cairo_label_path (cr, template, rotate_flag, FALSE);
870
871         cairo_set_line_width (cr, OUTLINE_WIDTH_PIXELS/(view->home_scale * view->zoom));
872         cairo_set_source_rgb (cr, OUTLINE_RGB_ARGS);
873         cairo_stroke (cr);
874 }
875
876
877 /*---------------------------------------------------------------------------*/
878 /* PRIVATE.  Create highlight layer.                                         */
879 /*---------------------------------------------------------------------------*/
880 static void
881 draw_highlight_layer (glView  *view,
882                       cairo_t *cr)
883 {
884         GList            *selection_list;
885         GList            *p_obj;
886         glLabelObject    *object;
887
888         g_return_if_fail (view && GL_IS_VIEW (view));
889
890         cairo_save (cr);
891
892         cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
893
894         selection_list = gl_label_get_selection_list (view->label);
895
896         for (p_obj = selection_list; p_obj != NULL; p_obj = p_obj->next)
897         {
898                 object = GL_LABEL_OBJECT (p_obj->data);
899
900                 gl_label_object_draw_handles (object, cr);
901         }
902
903         g_list_free (selection_list);
904
905         cairo_restore (cr);
906 }
907
908
909 /*---------------------------------------------------------------------------*/
910 /* PRIVATE.  Draw select region layer.                                       */
911 /*---------------------------------------------------------------------------*/
912 static void
913 draw_select_region_layer (glView  *view,
914                           cairo_t *cr)
915 {
916         gdouble x1, y1;
917         gdouble w, h;
918
919         g_return_if_fail (view && GL_IS_VIEW (view));
920
921         if (view->select_region_visible)
922         {
923                 x1 = MIN (view->select_region.x1, view->select_region.x2);
924                 y1 = MIN (view->select_region.y1, view->select_region.y2);
925                 w  = fabs (view->select_region.x2 - view->select_region.x1);
926                 h  = fabs (view->select_region.y2 - view->select_region.y1);
927
928                 cairo_save (cr);
929
930                 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
931
932                 cairo_rectangle (cr, x1, y1, w, h);
933
934                 cairo_set_source_rgba (cr, SELECT_FILL_RGBA_ARGS);
935                 cairo_fill_preserve (cr);
936
937                 cairo_set_line_width (cr, SELECT_LINE_WIDTH_PIXELS/(view->home_scale * view->zoom));
938                 cairo_set_source_rgba (cr, SELECT_LINE_RGBA_ARGS);
939                 cairo_stroke (cr);
940
941                 cairo_restore (cr);
942         }
943 }
944
945
946 /*****************************************************************************/
947 /* Show grid.                                                                */
948 /*****************************************************************************/
949 void
950 gl_view_show_grid (glView *view)
951 {
952         g_return_if_fail (view && GL_IS_VIEW (view));
953
954         view->grid_visible = TRUE;
955         gl_view_update (view);
956 }
957
958
959 /*****************************************************************************/
960 /* Hide grid.                                                                */
961 /*****************************************************************************/
962 void
963 gl_view_hide_grid (glView *view)
964 {
965         g_return_if_fail (view && GL_IS_VIEW (view));
966
967         view->grid_visible = FALSE;
968         gl_view_update (view);
969 }
970
971
972 /*****************************************************************************/
973 /* Set grid spacing.                                                         */
974 /*****************************************************************************/
975 void
976 gl_view_set_grid_spacing (glView  *view,
977                           gdouble  spacing)
978 {
979         g_return_if_fail (view && GL_IS_VIEW (view));
980
981         view->grid_spacing = spacing;
982         gl_view_update (view);
983 }
984
985
986 /*****************************************************************************/
987 /* Show markup.                                                              */
988 /*****************************************************************************/
989 void
990 gl_view_show_markup (glView *view)
991 {
992         g_return_if_fail (view && GL_IS_VIEW (view));
993
994         view->markup_visible = TRUE;
995         gl_view_update (view);
996 }
997
998
999 /*****************************************************************************/
1000 /* Hide markup.                                                              */
1001 /*****************************************************************************/
1002 void
1003 gl_view_hide_markup (glView *view)
1004 {
1005         g_return_if_fail (view && GL_IS_VIEW (view));
1006
1007         view->markup_visible = FALSE;
1008         gl_view_update (view);
1009 }
1010
1011
1012 /*****************************************************************************/
1013 /* Set arrow mode.                                                           */
1014 /*****************************************************************************/
1015 void
1016 gl_view_arrow_mode (glView *view)
1017 {
1018         GdkWindow *window;
1019         GdkCursor *cursor;
1020
1021         gl_debug (DEBUG_VIEW, "START");
1022
1023         g_return_if_fail (view && GL_IS_VIEW (view));
1024
1025         window = gtk_widget_get_window (view->canvas);
1026
1027         cursor = gdk_cursor_new (GDK_LEFT_PTR);
1028         gdk_window_set_cursor (window, cursor);
1029         gdk_cursor_unref (cursor);
1030
1031         view->mode = GL_VIEW_MODE_ARROW;
1032         view->state = GL_VIEW_IDLE;
1033
1034         gl_debug (DEBUG_VIEW, "END");
1035 }
1036
1037
1038 /*****************************************************************************/
1039 /* Set create text object mode.                                              */
1040 /*****************************************************************************/
1041 void
1042 gl_view_object_create_mode (glView            *view,
1043                             glLabelObjectType  type)
1044 {
1045         GdkWindow *window;
1046         GdkCursor *cursor = NULL;
1047
1048         gl_debug (DEBUG_VIEW, "START");
1049
1050         g_return_if_fail (view && GL_IS_VIEW (view));
1051
1052         window = gtk_widget_get_window (view->canvas);
1053
1054         switch (type)
1055         {
1056         case GL_LABEL_OBJECT_BOX:
1057                 cursor = gl_view_box_get_create_cursor ();
1058                 break;
1059         case GL_LABEL_OBJECT_ELLIPSE:
1060                 cursor = gl_view_ellipse_get_create_cursor ();
1061                 break;
1062         case GL_LABEL_OBJECT_LINE:
1063                 cursor = gl_view_line_get_create_cursor ();
1064                 break;
1065         case GL_LABEL_OBJECT_IMAGE:
1066                 cursor = gl_view_image_get_create_cursor ();
1067                 break;
1068         case GL_LABEL_OBJECT_TEXT:
1069                 cursor = gl_view_text_get_create_cursor ();
1070                 break;
1071         case GL_LABEL_OBJECT_BARCODE:
1072                 cursor = gl_view_barcode_get_create_cursor ();
1073                 break;
1074         default:
1075                 g_message ("Invalid label object type.");/*Should not happen!*/
1076                 break;
1077         }
1078
1079         gdk_window_set_cursor (window, cursor);
1080         gdk_cursor_unref (cursor);
1081
1082         view->mode = GL_VIEW_MODE_OBJECT_CREATE;
1083         view->state = GL_VIEW_IDLE;
1084         view->create_type = type;
1085
1086         gl_debug (DEBUG_VIEW, "END");
1087 }
1088
1089
1090 /*****************************************************************************/
1091 /* Zoom in one "notch"                                                       */
1092 /*****************************************************************************/
1093 void
1094 gl_view_zoom_in (glView *view)
1095 {
1096         gint    i, i_min;
1097         gdouble dist, dist_min;
1098
1099         gl_debug (DEBUG_VIEW, "START");
1100
1101         g_return_if_fail (view && GL_IS_VIEW (view));
1102
1103         /* Find index of current scale (or best match) */
1104         i_min = 1;              /* start with 2nd largest scale */
1105         dist_min = fabs (zooms[1] - view->zoom);
1106         for (i = 2; i < N_ZOOMS; i++) {
1107                 dist = fabs (zooms[i] - view->zoom);
1108                 if (dist < dist_min) {
1109                         i_min = i;
1110                         dist_min = dist;
1111                 }
1112         }
1113
1114         /* zoom in one "notch" */
1115         i = MAX (0, i_min - 1);
1116         gl_debug (DEBUG_VIEW, "zoom[%d] = %g", i, zooms[i]);
1117         set_zoom_real (view, zooms[i], FALSE);
1118
1119         gl_debug (DEBUG_VIEW, "END");
1120 }
1121
1122
1123 /*****************************************************************************/
1124 /* Zoom out one "notch"                                                      */
1125 /*****************************************************************************/
1126 void
1127 gl_view_zoom_out (glView *view)
1128 {
1129         gint    i, i_min;
1130         gdouble dist, dist_min;
1131
1132         gl_debug (DEBUG_VIEW, "START");
1133
1134         g_return_if_fail (view && GL_IS_VIEW (view));
1135
1136         /* Find index of current scale (or best match) */
1137         i_min = 0;              /* start with largest scale */
1138         dist_min = fabs (zooms[0] - view->zoom);
1139         for (i = 1; i < N_ZOOMS; i++) {
1140                 dist = fabs (zooms[i] - view->zoom);
1141                 if (dist < dist_min) {
1142                         i_min = i;
1143                         dist_min = dist;
1144                 }
1145         }
1146
1147         /* zoom out one "notch" */
1148         if (i_min >= N_ZOOMS)
1149                 return;
1150         i = i_min + 1;
1151         if (i >= N_ZOOMS)
1152                 return;
1153         set_zoom_real (view, zooms[i], FALSE);
1154
1155         gl_debug (DEBUG_VIEW, "END");
1156 }
1157
1158
1159 /*****************************************************************************/
1160 /* Set zoom to best fit.                                                     */
1161 /*****************************************************************************/
1162 void
1163 gl_view_zoom_to_fit (glView *view)
1164 {
1165         GtkAllocation  allocation;
1166         gint           w_view, h_view;
1167         gdouble        w_label, h_label;
1168         gdouble        x_scale, y_scale, scale;
1169
1170         gl_debug (DEBUG_VIEW, "");
1171
1172         if ( ! gtk_widget_get_window (GTK_WIDGET (view)) ) {
1173                 set_zoom_real (view, 1.0, TRUE);
1174                 return;
1175         }
1176
1177         gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
1178         w_view = allocation.width;
1179         h_view = allocation.height;
1180
1181         gl_label_get_size (GL_LABEL(view->label), &w_label, &h_label);
1182
1183         gl_debug (DEBUG_VIEW, "View size: %d, %d", w_view, h_view);
1184         gl_debug (DEBUG_VIEW, "Label size: %g, %g", w_label, h_label);
1185
1186         /* Calculate best scale */
1187         x_scale = (double)(w_view - ZOOMTOFIT_PAD) / w_label;
1188         y_scale = (double)(h_view - ZOOMTOFIT_PAD) / h_label;
1189         scale = MIN (x_scale, y_scale);
1190         gl_debug (DEBUG_VIEW, "Candidate zooms: %g, %g => %g", x_scale, y_scale, scale);
1191
1192         /* Limit */
1193         gl_debug (DEBUG_VIEW, "Scale: %g", scale);
1194         scale = MIN (scale, zooms[0]*view->home_scale);
1195         scale = MAX (scale, zooms[N_ZOOMS-1]*view->home_scale);
1196         gl_debug (DEBUG_VIEW, "Limitted scale: %g", scale);
1197
1198         set_zoom_real (view, scale/view->home_scale, TRUE);
1199 }
1200
1201
1202 /*****************************************************************************/
1203 /* Set current zoom factor to explicit value.                                */
1204 /*****************************************************************************/
1205 void
1206 gl_view_set_zoom (glView  *view,
1207                   gdouble  zoom)
1208 {
1209         gl_debug (DEBUG_VIEW, "START");
1210
1211         set_zoom_real (view, zoom, FALSE);
1212
1213         gl_debug (DEBUG_VIEW, "END");
1214 }
1215
1216
1217 /*---------------------------------------------------------------------------*/
1218 /* PRIVATE.  Set canvas scale.                                               */
1219 /*---------------------------------------------------------------------------*/
1220 static void
1221 set_zoom_real (glView   *view,
1222                gdouble   zoom,
1223                gboolean  zoom_to_fit_flag)
1224 {
1225         gl_debug (DEBUG_VIEW, "START");
1226
1227         g_return_if_fail (view && GL_IS_VIEW (view));
1228         g_return_if_fail (zoom > 0.0);
1229
1230         /* Limit, if needed */
1231         gl_debug (DEBUG_VIEW, "Zoom requested: %g", zoom);
1232         zoom = MIN (zoom, zooms[0]);
1233         zoom = MAX (zoom, zooms[N_ZOOMS-1]);
1234         gl_debug (DEBUG_VIEW, "Limitted zoom: %g", zoom);
1235
1236         if ( zoom != view->zoom ) {
1237
1238                 view->zoom = zoom;
1239                 view->zoom_to_fit_flag = zoom_to_fit_flag;
1240
1241                 gl_view_update (view);
1242
1243                 g_signal_emit (G_OBJECT(view), signals[ZOOM_CHANGED], 0, zoom);
1244
1245         }
1246
1247         gl_debug (DEBUG_VIEW, "END");
1248
1249 }
1250
1251
1252 /*****************************************************************************/
1253 /* Get current zoom factor.                                                  */
1254 /*****************************************************************************/
1255 gdouble
1256 gl_view_get_zoom (glView *view)
1257 {
1258         gl_debug (DEBUG_VIEW, "");
1259
1260         g_return_val_if_fail (view && GL_IS_VIEW (view), 1.0);
1261
1262         return view->zoom;
1263 }
1264
1265
1266 /*****************************************************************************/
1267 /* Is this the maximum zoom level.                                           */
1268 /*****************************************************************************/
1269 gboolean
1270 gl_view_is_zoom_max (glView *view)
1271 {
1272         gl_debug (DEBUG_VIEW, "");
1273
1274         g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
1275
1276         return view->zoom >= zooms[0];
1277 }
1278
1279
1280 /*****************************************************************************/
1281 /* Is this the minimum zoom level.                                           */
1282 /*****************************************************************************/
1283 gboolean
1284 gl_view_is_zoom_min (glView *view)
1285 {
1286         gl_debug (DEBUG_VIEW, "");
1287
1288         g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
1289
1290         return view->zoom <= zooms[N_ZOOMS-1];
1291 }
1292
1293
1294 /*---------------------------------------------------------------------------*/
1295 /* PRIVATE.  Focus in event handler.                                         */
1296 /*---------------------------------------------------------------------------*/
1297 static gboolean
1298 focus_in_event_cb (glView            *view,
1299                    GdkEventFocus     *event)
1300 {
1301         return FALSE;
1302 }
1303
1304
1305 /*---------------------------------------------------------------------------*/
1306 /* PRIVATE.  Focus out event handler.                                        */
1307 /*---------------------------------------------------------------------------*/
1308 static gboolean
1309 focus_out_event_cb (glView            *view,
1310                     GdkEventFocus     *event)
1311 {
1312         return FALSE;
1313 }
1314
1315
1316 /*---------------------------------------------------------------------------*/
1317 /* PRIVATE.  Enter notify event handler.                                     */
1318 /*---------------------------------------------------------------------------*/
1319 static gboolean
1320 enter_notify_event_cb (glView            *view,
1321                        GdkEventCrossing  *event)
1322 {
1323         return FALSE;
1324 }
1325
1326
1327 /*---------------------------------------------------------------------------*/
1328 /* PRIVATE.  Leave notify event handler.                                     */
1329 /*---------------------------------------------------------------------------*/
1330 static gboolean
1331 leave_notify_event_cb (glView            *view,
1332                        GdkEventCrossing  *event)
1333 {
1334
1335         g_signal_emit (G_OBJECT(view), signals[POINTER_EXIT], 0);
1336
1337         return FALSE;
1338 }
1339
1340
1341 /*---------------------------------------------------------------------------*/
1342 /* PRIVATE.  Motion notify event handler.                                    */
1343 /*---------------------------------------------------------------------------*/
1344 static gboolean
1345 motion_notify_event_cb (glView            *view,
1346                         GdkEventMotion    *event)
1347 {
1348         gboolean            return_value = FALSE;
1349         GdkWindow          *bin_window;
1350         GdkWindow          *window;
1351         cairo_t            *cr;
1352         gdouble             scale;
1353         gdouble             x, y;
1354         GdkCursor          *cursor;
1355         glLabelObjectHandle handle;
1356
1357         bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (view->canvas));
1358         window = gtk_widget_get_window (view->canvas);
1359
1360         cr = gdk_cairo_create (bin_window);
1361
1362         /*
1363          * Translate to label coordinates
1364          */
1365         scale = view->zoom * view->home_scale;
1366         cairo_scale (cr, scale, scale);
1367         cairo_translate (cr, view->x0, view->y0);
1368
1369         x = event->x;
1370         y = event->y;
1371         cairo_device_to_user (cr, &x, &y);
1372
1373         /*
1374          * Emit signal regardless of mode
1375          */
1376         g_signal_emit (G_OBJECT(view), signals[POINTER_MOVED], 0, x, y);
1377
1378         /*
1379          * Handle event as appropriate for mode
1380          */
1381         switch (view->mode)
1382         {
1383
1384         case GL_VIEW_MODE_ARROW:
1385                 switch (view->state)
1386                 {
1387
1388                 case GL_VIEW_IDLE:
1389                         if ( gl_label_is_selection_atomic (view->label) &&
1390                              gl_label_get_handle_at (view->label, cr, event->x, event->y, &handle) )
1391                         {
1392                                 cursor = gdk_cursor_new (GDK_CROSSHAIR);
1393                         }
1394                         else if (gl_label_object_at (view->label, cr, event->x, event->y))
1395                         {
1396                                 cursor = gdk_cursor_new (GDK_FLEUR);
1397                         }
1398                         else
1399                         {
1400                                 cursor = gdk_cursor_new (GDK_LEFT_PTR);
1401                         }
1402                         gdk_window_set_cursor (window, cursor);
1403                         gdk_cursor_unref (cursor);
1404                         break;
1405
1406                 case GL_VIEW_ARROW_SELECT_REGION:
1407 #ifdef CLIP_UPDATES                                
1408                         gl_view_update_region (view, cr, &view->select_region);
1409 #endif
1410                         view->select_region.x2 = x;
1411                         view->select_region.y2 = y;
1412 #ifdef CLIP_UPDATES                                
1413                         gl_view_update_region (view, cr, &view->select_region);
1414 #else
1415                         gl_view_update (view);
1416 #endif
1417                         break;
1418
1419                 case GL_VIEW_ARROW_MOVE:
1420                         gl_label_move_selection (view->label,
1421                                                 (x - view->move_last_x),
1422                                                 (y - view->move_last_y));
1423                         view->move_last_x = x;
1424                         view->move_last_y = y;
1425                         break;
1426
1427                 case GL_VIEW_ARROW_RESIZE:
1428                         resize_event (view, cr, event->x, event->y);
1429                         break;
1430
1431                 default:
1432                         g_message ("Invalid arrow state.");      /*Should not happen!*/
1433                 }
1434                 return_value = TRUE;
1435                 break;
1436
1437
1438         case GL_VIEW_MODE_OBJECT_CREATE:
1439                 if (view->state != GL_VIEW_IDLE)
1440                 {
1441                         switch (view->create_type)
1442                         {
1443                         case GL_LABEL_OBJECT_BOX:
1444                                 gl_view_box_create_motion_event (view, x, y);
1445                                 break;
1446                         case GL_LABEL_OBJECT_ELLIPSE:
1447                                 gl_view_ellipse_create_motion_event (view, x, y);
1448                                 break;
1449                         case GL_LABEL_OBJECT_LINE: 
1450                                 gl_view_line_create_motion_event (view, x, y);
1451                                 break;
1452                         case GL_LABEL_OBJECT_IMAGE:
1453                                 gl_view_image_create_motion_event (view, x, y);
1454                                 break;
1455                         case GL_LABEL_OBJECT_TEXT:
1456                                 gl_view_text_create_motion_event (view, x, y);
1457                                 break;
1458                         case GL_LABEL_OBJECT_BARCODE:
1459                                 gl_view_barcode_create_motion_event (view, x, y);
1460                                 break;
1461                         default:
1462                                 g_message ("Invalid create type.");   /*Should not happen!*/
1463                         }
1464                 }
1465                 break;
1466
1467
1468         default:
1469                 g_message ("Invalid view mode.");      /*Should not happen!*/
1470
1471         }
1472
1473         cairo_destroy (cr);
1474
1475         /*
1476          * FIXME: we re-establish grabs here if the grab has been lost.  We seem to be
1477          *        losing grabs when we emit signals that lead to the manipulation of
1478          *        the GtkUIManager.  Needs more investigation
1479          */
1480         if (view->grabbed_flag && !gdk_pointer_is_grabbed ())
1481         {
1482                 gdk_pointer_grab (bin_window,
1483                                   FALSE,
1484                                   (GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK),
1485                                   NULL,
1486                                   NULL,
1487                                   event->time);
1488         }
1489
1490         return return_value;
1491 }
1492
1493
1494 /*---------------------------------------------------------------------------*/
1495 /* PRIVATE.  Button press event handler.                                     */
1496 /*---------------------------------------------------------------------------*/
1497 static gboolean
1498 button_press_event_cb (glView            *view,
1499                        GdkEventButton    *event)
1500 {
1501         gboolean            return_value = FALSE;
1502         GdkWindow          *bin_window;
1503         cairo_t            *cr;
1504         gdouble             scale;
1505         gdouble             x, y;
1506         glLabelObject      *object;
1507         glLabelObjectHandle handle;
1508
1509         gtk_widget_grab_focus(GTK_WIDGET (view->canvas));
1510
1511         bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (view->canvas));
1512
1513         cr = gdk_cairo_create (bin_window);
1514
1515         /*
1516          * Translate to label coordinates
1517          */
1518         scale = view->zoom * view->home_scale;
1519         cairo_scale (cr, scale, scale);
1520         cairo_translate (cr, view->x0, view->y0);
1521
1522         x = event->x;
1523         y = event->y;
1524         cairo_device_to_user (cr, &x, &y);
1525
1526         switch (event->button)
1527         {
1528
1529         case 1:
1530                 /*
1531                  * Handle event as appropriate for mode
1532                  */
1533                 switch (view->mode)
1534                 {
1535                 case GL_VIEW_MODE_ARROW:
1536                         if ( gl_label_is_selection_atomic (view->label) &&
1537                              (object = gl_label_get_handle_at (view->label, cr, event->x, event->y, &handle)) )
1538                         {
1539                                 view->resize_object = object;
1540                                 view->resize_handle = handle;
1541                                 view->resize_honor_aspect = event->state & GDK_CONTROL_MASK;
1542
1543                                 view->state = GL_VIEW_ARROW_RESIZE;
1544                         }
1545                         else if ((object = gl_label_object_at (view->label, cr, event->x, event->y)))
1546                         {
1547                                 if (event->state & GDK_CONTROL_MASK)
1548                                 {
1549                                         if (gl_label_object_is_selected (object))
1550                                         {
1551                                                 /* Un-selecting a selected item */
1552                                                 gl_label_unselect_object (view->label, object);
1553                                         } else {
1554                                                 /* Add to current selection */
1555                                                 gl_label_select_object (view->label, object);
1556                                         }
1557                                 }
1558                                 else
1559                                 {
1560                                         if (!gl_label_object_is_selected (object))
1561                                         {
1562                                                 /* remove any selections before adding */
1563                                                 gl_label_unselect_all (view->label);
1564                                                 /* Add to current selection */
1565                                                 gl_label_select_object (view->label, object);
1566                                         }
1567                                 }
1568                                 view->move_last_x = x;
1569                                 view->move_last_y = y;
1570
1571                                 view->state = GL_VIEW_ARROW_MOVE;
1572                         }
1573                         else
1574                         {
1575                                 if (!(event->state & GDK_CONTROL_MASK))
1576                                 {
1577                                         gl_label_unselect_all (view->label);
1578                                 }
1579
1580                                 view->select_region_visible = TRUE;
1581                                 view->select_region.x1 = x;
1582                                 view->select_region.y1 = y;
1583                                 view->select_region.x2 = x;
1584                                 view->select_region.y2 = y;
1585
1586                                 view->state = GL_VIEW_ARROW_SELECT_REGION;
1587                         }
1588
1589
1590                         return_value = TRUE;
1591                         break;
1592
1593                 case GL_VIEW_MODE_OBJECT_CREATE:
1594                         switch (view->create_type)
1595                         {
1596                         case GL_LABEL_OBJECT_BOX:
1597                                 gl_view_box_create_button_press_event (view, x, y);
1598                                 break;
1599                         case GL_LABEL_OBJECT_ELLIPSE:
1600                                 gl_view_ellipse_create_button_press_event (view, x, y);
1601                                 break;
1602                         case GL_LABEL_OBJECT_LINE:
1603                                 gl_view_line_create_button_press_event (view, x, y);
1604                                 break;
1605                         case GL_LABEL_OBJECT_IMAGE:
1606                                 gl_view_image_create_button_press_event (view, x, y);
1607                                 break;
1608                         case GL_LABEL_OBJECT_TEXT:
1609                                 gl_view_text_create_button_press_event (view, x, y);
1610                                 break;
1611                         case GL_LABEL_OBJECT_BARCODE:
1612                                 gl_view_barcode_create_button_press_event (view, x, y);
1613                                 break;
1614                         default:
1615                                 g_message ("Invalid create type.");   /*Should not happen!*/
1616                         }
1617                         view->state = GL_VIEW_CREATE_DRAG;
1618                         return_value = TRUE;
1619                         break;
1620
1621                 default:
1622                         g_message ("Invalid view mode.");      /*Should not happen!*/
1623                 }
1624
1625                 view->grabbed_flag = TRUE;
1626                 gdk_pointer_grab (bin_window,
1627                                   FALSE,
1628                                   (GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK),
1629                                   NULL,
1630                                   NULL,
1631                                   event->time);
1632                 break;
1633
1634         case 3:
1635                 g_signal_emit (G_OBJECT (view),
1636                                signals[CONTEXT_MENU_ACTIVATE], 0,
1637                                event->button, event->time);
1638                 return_value = TRUE;
1639                 break;
1640
1641         }
1642
1643         cairo_destroy (cr);
1644
1645         return return_value;
1646 }
1647
1648
1649 /*---------------------------------------------------------------------------*/
1650 /* PRIVATE.  Button release event handler.                                   */
1651 /*---------------------------------------------------------------------------*/
1652 static gboolean
1653 button_release_event_cb (glView            *view,
1654                          GdkEventButton    *event)
1655 {
1656         gboolean     return_value = FALSE;
1657         GdkWindow   *bin_window;
1658         GdkWindow   *window;
1659         cairo_t     *cr;
1660         gdouble      scale;
1661         gdouble      x, y;
1662         GdkCursor   *cursor;
1663
1664         bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (view->canvas));
1665         window = gtk_widget_get_window (view->canvas);
1666
1667         cr = gdk_cairo_create (bin_window);
1668
1669         /*
1670          * Translate to label coordinates
1671          */
1672         scale = view->zoom * view->home_scale;
1673         cairo_scale (cr, scale, scale);
1674         cairo_translate (cr, view->x0, view->y0);
1675
1676         x = event->x;
1677         y = event->y;
1678         cairo_device_to_user (cr, &x, &y);
1679
1680         switch (event->button)
1681         {
1682
1683         case 1:
1684                 view->grabbed_flag = FALSE;
1685                 gdk_pointer_ungrab (event->time);
1686                 /*
1687                  * Handle event as appropriate for mode
1688                  */
1689                 switch (view->mode)
1690                 {
1691                 case GL_VIEW_MODE_ARROW:
1692                         switch (view->state)
1693                         {
1694                         case GL_VIEW_ARROW_RESIZE:
1695                                 view->resize_object = NULL;
1696
1697                                 view->state = GL_VIEW_IDLE;
1698                                 break;
1699
1700                         case GL_VIEW_ARROW_SELECT_REGION:
1701 #ifdef CLIP_UPDATES                                
1702                                 gl_view_update_region (view, cr, &view->select_region);
1703 #else
1704                                 gl_view_update (view);
1705 #endif
1706
1707                                 view->select_region_visible = FALSE;
1708                                 view->select_region.x2 = x;
1709                                 view->select_region.y2 = y;
1710
1711                                 gl_label_select_region (view->label, &view->select_region);
1712
1713                                 view->state = GL_VIEW_IDLE;
1714                                 break;
1715
1716                         default:
1717                                 view->state = GL_VIEW_IDLE;
1718                                 break;
1719                                 
1720                         }
1721
1722                         return_value = TRUE;
1723                         break;
1724
1725
1726                 case GL_VIEW_MODE_OBJECT_CREATE:
1727                         switch (view->create_type)
1728                         {
1729                         case GL_LABEL_OBJECT_BOX:
1730                                 gl_view_box_create_button_release_event (view, x, y);
1731                                 break;
1732                         case GL_LABEL_OBJECT_ELLIPSE:
1733                                 gl_view_ellipse_create_button_release_event (view, x, y);
1734                                 break;
1735                         case GL_LABEL_OBJECT_LINE:
1736                                 gl_view_line_create_button_release_event (view, x, y);
1737                                 break;
1738                         case GL_LABEL_OBJECT_IMAGE:
1739                                 gl_view_image_create_button_release_event (view, x, y);
1740                                 break;
1741                         case GL_LABEL_OBJECT_TEXT:
1742                                 gl_view_text_create_button_release_event (view, x, y);
1743                                 break;
1744                         case GL_LABEL_OBJECT_BARCODE:
1745                                 gl_view_barcode_create_button_release_event (view, x, y);
1746                                 break;
1747                         default:
1748                                 g_message ("Invalid create type.");   /*Should not happen!*/
1749                         }
1750                         view->mode = GL_VIEW_MODE_ARROW;
1751                         view->state = GL_VIEW_IDLE;
1752                         cursor = gdk_cursor_new (GDK_LEFT_PTR);
1753                         gdk_window_set_cursor (window, cursor);
1754                         gdk_cursor_unref (cursor);
1755
1756                         gl_label_select_object (view->label, view->create_object);
1757                         break;
1758
1759
1760                 default:
1761                         g_message ("Invalid view mode.");      /*Should not happen!*/
1762                 }
1763
1764         }
1765
1766         cairo_destroy (cr);
1767
1768         return return_value;
1769 }
1770
1771
1772 /*---------------------------------------------------------------------------*/
1773 /* PRIVATE.  Key press event handler.                                        */
1774 /*---------------------------------------------------------------------------*/
1775 static gboolean
1776 key_press_event_cb (glView            *view,
1777                     GdkEventKey       *event)
1778 {
1779         GdkWindow *window;
1780         GdkCursor *cursor;
1781
1782         gl_debug (DEBUG_VIEW, "");
1783
1784         window = gtk_widget_get_window (view->canvas);
1785
1786         if ( (view->mode == GL_VIEW_MODE_ARROW) &&
1787              (view->state == GL_VIEW_IDLE) )
1788         {
1789                 switch (event->keyval) {
1790
1791                 case GDK_Left:
1792                 case GDK_KP_Left:
1793                         gl_label_move_selection (view->label, -1.0 / (view->zoom), 0.0);
1794                         break;
1795                 case GDK_Up:
1796                 case GDK_KP_Up:
1797                         gl_label_move_selection (view->label, 0.0, -1.0 / (view->zoom));
1798                         break;
1799                 case GDK_Right:
1800                 case GDK_KP_Right:
1801                         gl_label_move_selection (view->label, 1.0 / (view->zoom), 0.0);
1802                         break;
1803                 case GDK_Down:
1804                 case GDK_KP_Down:
1805                         gl_label_move_selection (view->label, 0.0, 1.0 / (view->zoom));
1806                         break;
1807                 case GDK_Delete:
1808                 case GDK_KP_Delete:
1809                         gl_label_delete_selection (view->label);
1810                         cursor = gdk_cursor_new (GDK_LEFT_PTR);
1811                         gdk_window_set_cursor (window, cursor);
1812                         gdk_cursor_unref (cursor);
1813                         break;
1814                 default:
1815                         return FALSE;
1816  
1817                }
1818         }
1819         return TRUE;    /* We handled this or we were dragging. */
1820 }
1821
1822
1823 /*---------------------------------------------------------------------------*/
1824 /* PRIVATE.  Resize object.                                                  */
1825 /*---------------------------------------------------------------------------*/
1826 static void
1827 resize_event (glView             *view,
1828               cairo_t            *cr,
1829               gdouble             x,
1830               gdouble             y)
1831 {
1832         cairo_matrix_t matrix;
1833         gdouble        x0, y0, x1, y1, x2, y2;
1834         gdouble        w, h;
1835         gdouble        dx=0, dy=0;
1836
1837         gl_debug (DEBUG_VIEW, "x,y world = %g, %g", x, y);
1838
1839         /*
1840          * Change to item relative coordinates
1841          */
1842         cairo_save (cr);
1843         gl_label_object_get_position (view->resize_object, &x0, &y0);
1844         cairo_translate (cr, x0, y0);
1845         gl_label_object_get_matrix (view->resize_object, &matrix);
1846         cairo_transform (cr, &matrix);
1847
1848         /*
1849          * Initialize origin and 2 corners in object relative coordinates.
1850          */
1851         x0 = 0.0;
1852         y0 = 0.0;
1853
1854         x1 = 0.0;
1855         y1 = 0.0;
1856
1857         gl_label_object_get_size (view->resize_object, &x2, &y2);
1858
1859         gl_debug (DEBUG_VIEW, "x0,y0 object = %g, %g", x0, y0);
1860         gl_debug (DEBUG_VIEW, "x1,y1 object = %g, %g", x1, y1);
1861         gl_debug (DEBUG_VIEW, "x2,y2 object = %g, %g", x2, y2);
1862
1863         /*
1864          * Translate x,y into object relative coordinates.
1865          */
1866         cairo_device_to_user (cr, &x, &y);
1867
1868         gl_debug (DEBUG_VIEW, "x,y object = %g, %g", x, y);
1869         
1870         /*
1871          * Get new size
1872          */
1873         switch (view->resize_handle)
1874         {
1875
1876         case GL_LABEL_OBJECT_HANDLE_NW:
1877                 w = MAX (x2 - x, 0);
1878                 h = MAX (y2 - y, 0);
1879                 break;
1880
1881         case GL_LABEL_OBJECT_HANDLE_N:
1882                 w = x2 - x1;
1883                 h = MAX (y2 - y, 0);
1884                 break;
1885
1886         case GL_LABEL_OBJECT_HANDLE_NE:
1887                 w = MAX (x - x1, 0);
1888                 h = MAX (y2 - y, 0);
1889                 break;
1890
1891         case GL_LABEL_OBJECT_HANDLE_E:
1892                 w = MAX (x - x1, 0);
1893                 h = y2 - y1;
1894                 break;
1895
1896         case GL_LABEL_OBJECT_HANDLE_SE:
1897                 w = MAX (x - x1, 0);
1898                 h = MAX (y - y1, 0);
1899                 break;
1900
1901         case GL_LABEL_OBJECT_HANDLE_S:
1902                 w = x2 - x1;
1903                 h = MAX (y - y1, 0);
1904                 break;
1905
1906         case GL_LABEL_OBJECT_HANDLE_SW:
1907                 w = MAX (x2 - x, 0);
1908                 h = MAX (y - y1, 0);
1909                 break;
1910
1911         case GL_LABEL_OBJECT_HANDLE_W:
1912                 w = MAX (x2 - x, 0);
1913                 h = y2 - y1;
1914                 break;
1915         case GL_LABEL_OBJECT_HANDLE_P1:
1916                 x1 = x;
1917                 y1 = y;
1918                 dx = (x2 - x);
1919                 dy = (y2 - y);
1920                 x0 = x0 + x1;
1921                 y0 = y0 + y1;
1922                 break;
1923
1924         case GL_LABEL_OBJECT_HANDLE_P2:
1925                 dx = x - x1;
1926                 dy = y - y1;
1927                 x0 = x0 + x1;
1928                 y0 = y0 + y1;
1929                 break;
1930
1931         default:
1932                 g_print ("Invalid handle.\n");  /* Should not happen! */
1933
1934         }
1935         if ( (view->resize_handle != GL_LABEL_OBJECT_HANDLE_P1) &&
1936              (view->resize_handle != GL_LABEL_OBJECT_HANDLE_P2) )
1937         {
1938                 if ( view->resize_honor_aspect )
1939                 {
1940                         gl_label_object_set_size_honor_aspect (view->resize_object, w, h);
1941                 }
1942                 else
1943                 {
1944                         gl_label_object_set_size (view->resize_object, w, h);
1945                 }
1946
1947                 /*
1948                  * Query the new size in case it was constrained.
1949                  */
1950                 gl_label_object_get_size (view->resize_object, &w, &h);
1951
1952                 /*
1953                  * Get new position
1954                  */
1955                 switch (view->resize_handle)
1956                 {
1957
1958                 case GL_LABEL_OBJECT_HANDLE_NW:
1959                         x0 += x2 - w;
1960                         y0 += y2 - h;
1961                         break;
1962
1963                 case GL_LABEL_OBJECT_HANDLE_N:
1964                 case GL_LABEL_OBJECT_HANDLE_NE:
1965                         /* x unchanged */
1966                         y0 += y2 - h;
1967                         break;
1968
1969                 case GL_LABEL_OBJECT_HANDLE_E:
1970                 case GL_LABEL_OBJECT_HANDLE_SE:
1971                 case GL_LABEL_OBJECT_HANDLE_S:
1972                         /* unchanged */
1973                         break;
1974
1975                 case GL_LABEL_OBJECT_HANDLE_SW:
1976                 case GL_LABEL_OBJECT_HANDLE_W:
1977                         x0 += x2 - w;
1978                         /* y unchanged */
1979                         break;
1980
1981                 default:
1982                         g_print ("Invalid handle.\n");  /* Should not happen! */
1983                 }
1984         }
1985         else
1986         {
1987                 gl_label_object_set_size (view->resize_object, dx, dy);
1988         }
1989
1990         /*
1991          * Put new origin back into world coordinates and set.
1992          */
1993         cairo_user_to_device (cr, &x0, &y0);
1994         cairo_restore (cr);
1995         cairo_device_to_user (cr, &x0, &y0);
1996         gl_label_object_set_position (view->resize_object, x0, y0);
1997 }
1998
1999
2000
2001
2002 /*
2003  * Local Variables:       -- emacs
2004  * mode: C                -- emacs
2005  * c-basic-offset: 8      -- emacs
2006  * tab-width: 8           -- emacs
2007  * indent-tabs-mode: nil  -- emacs
2008  * End:                   -- emacs
2009  */