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