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 /****************************************************************************/
G_DEFINE_TYPE(glView,gl_view,GTK_TYPE_VBOX)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
gl_view_init(glView * view)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
gl_view_finalize(GObject * object)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 *
gl_view_new(glLabel * label)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
gl_view_construct(glView * view,glLabel * label)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
get_home_scale(glView * view)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
prefs_changed_cb(glView * view)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
gl_view_update(glView * view)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
gl_view_update_region(glView * view,cairo_t * cr,glLabelRegion * region)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
draw_cb(glView * view,cairo_t * cr)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
realize_cb(glView * view)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
size_allocate_cb(glView * view,GtkAllocation * allocation)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
screen_changed_cb(glView * view)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
label_changed_cb(glView * view)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
label_resized_cb(glView * view)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
draw_layers(glView * view,cairo_t * cr)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
draw_bg_layer(glView * view,cairo_t * cr)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
draw_grid_layer(glView * view,cairo_t * cr)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
draw_markup_layer(glView * view,cairo_t * cr)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
draw_objects_layer(glView * view,cairo_t * cr)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
draw_fg_layer(glView * view,cairo_t * cr)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
draw_highlight_layer(glView * view,cairo_t * cr)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
draw_select_region_layer(glView * view,cairo_t * cr)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
gl_view_show_grid(glView * view)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
gl_view_hide_grid(glView * view)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
gl_view_show_markup(glView * view)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
gl_view_hide_markup(glView * view)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
gl_view_arrow_mode(glView * view)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
gl_view_object_create_mode(glView * view,glLabelObjectType type)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
gl_view_zoom_in(glView * view)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
gl_view_zoom_out(glView * view)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
gl_view_zoom_to_fit(glView * view)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
gl_view_set_zoom(glView * view,gdouble zoom)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
set_zoom_real(glView * view,gdouble zoom,gboolean zoom_to_fit_flag)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
gl_view_get_zoom(glView * view)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
gl_view_is_zoom_max(glView * view)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
gl_view_is_zoom_min(glView * view)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
focus_in_event_cb(glView * view,GdkEventFocus * event)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
focus_out_event_cb(glView * view,GdkEventFocus * event)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
enter_notify_event_cb(glView * view,GdkEventCrossing * event)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
leave_notify_event_cb(glView * view,GdkEventCrossing * event)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
motion_notify_event_cb(glView * view,GdkEventMotion * event)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
button_press_event_cb(glView * view,GdkEventButton * event)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
button_release_event_cb(glView * view,GdkEventButton * event)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
key_press_event_cb(glView * view,GdkEventKey * event)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
move_event(glView * view,gdouble x,gdouble y,gboolean keep_direction)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
resize_event(glView * view,cairo_t * cr,gdouble x,gdouble y,gboolean keep_ratio,gboolean keep_direction)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  */
2229