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