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