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