3 * Copyright (C) 2001-2009 Jim Evins <evins@snaught.com>.
5 * This file is part of gLabels.
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.
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.
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/>.
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"
32 #include <glib/gi18n.h>
34 #include <gdk/gdkkeysyms.h>
39 #include "cairo-label-path.h"
40 #include "cairo-markup-path.h"
43 #include "units-util.h"
49 /*==========================================================================*/
50 /* Private macros and constants. */
51 /*==========================================================================*/
53 #define BG_COLOR GL_COLOR (204, 204, 204)
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
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
68 #define ZOOMTOFIT_PAD 16
70 #define SHADOW_OFFSET_PIXELS (ZOOMTOFIT_PAD/4)
72 #define POINTS_PER_MM 2.83464566929
75 /*==========================================================================*/
77 /*==========================================================================*/
80 CONTEXT_MENU_ACTIVATE,
89 /*==========================================================================*/
91 /*==========================================================================*/
93 static guint signals[LAST_SIGNAL] = {0};
95 static gdouble zooms[] = {
112 #define N_ZOOMS G_N_ELEMENTS(zooms)
115 /*==========================================================================*/
116 /* Local function prototypes */
117 /*==========================================================================*/
119 static void gl_view_finalize (GObject *object);
121 static void gl_view_construct (glView *view,
124 static gdouble get_home_scale (glView *view);
126 static void prefs_changed_cb (glView *view);
128 static gboolean draw_cb (glView *view,
131 static void realize_cb (glView *view);
133 static void size_allocate_cb (glView *view,
134 GtkAllocation *allocation);
136 static void screen_changed_cb (glView *view);
138 static void label_changed_cb (glView *view);
140 static void label_resized_cb (glView *view);
142 static void draw_layers (glView *view,
145 static void draw_bg_layer (glView *view,
147 static void draw_grid_layer (glView *view,
149 static void draw_markup_layer (glView *view,
151 static void draw_objects_layer (glView *view,
153 static void draw_fg_layer (glView *view,
155 static void draw_highlight_layer (glView *view,
157 static void draw_select_region_layer (glView *view,
160 static void set_zoom_real (glView *view,
162 gboolean scale_to_fit_flag);
164 static gboolean focus_in_event_cb (glView *view,
165 GdkEventFocus *event);
167 static gboolean focus_out_event_cb (glView *view,
168 GdkEventFocus *event);
170 static gboolean enter_notify_event_cb (glView *view,
171 GdkEventCrossing *event);
173 static gboolean leave_notify_event_cb (glView *view,
174 GdkEventCrossing *event);
176 static gboolean motion_notify_event_cb (glView *view,
177 GdkEventMotion *event);
179 static gboolean button_press_event_cb (glView *view,
180 GdkEventButton *event);
182 static gboolean button_release_event_cb (glView *view,
183 GdkEventButton *event);
185 static gboolean key_press_event_cb (glView *view,
188 static void move_event (glView *view,
191 gboolean keep_direction);
193 static void resize_event (glView *view,
198 gboolean keep_direction);
200 /****************************************************************************/
201 /* Boilerplate Object stuff. */
202 /****************************************************************************/
203 G_DEFINE_TYPE (glView, gl_view, GTK_TYPE_VBOX)
207 gl_view_class_init (glViewClass *class)
209 GObjectClass *object_class = G_OBJECT_CLASS (class);
211 gl_debug (DEBUG_VIEW, "START");
213 gl_view_parent_class = g_type_class_peek_parent (class);
215 object_class->finalize = gl_view_finalize;
217 signals[CONTEXT_MENU_ACTIVATE] =
218 g_signal_new ("context_menu_activate",
219 G_OBJECT_CLASS_TYPE (object_class),
221 G_STRUCT_OFFSET (glViewClass, context_menu_activate),
223 gl_marshal_VOID__INT_UINT,
225 2, G_TYPE_INT, G_TYPE_UINT);
227 signals[ZOOM_CHANGED] =
228 g_signal_new ("zoom_changed",
229 G_OBJECT_CLASS_TYPE (object_class),
231 G_STRUCT_OFFSET (glViewClass, zoom_changed),
233 gl_marshal_VOID__DOUBLE,
237 signals[POINTER_MOVED] =
238 g_signal_new ("pointer_moved",
239 G_OBJECT_CLASS_TYPE (object_class),
241 G_STRUCT_OFFSET (glViewClass, pointer_moved),
243 gl_marshal_VOID__DOUBLE_DOUBLE,
245 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
247 signals[POINTER_EXIT] =
248 g_signal_new ("pointer_exit",
249 G_OBJECT_CLASS_TYPE (object_class),
251 G_STRUCT_OFFSET (glViewClass, pointer_exit),
253 gl_marshal_VOID__VOID,
257 signals[MODE_CHANGED] =
258 g_signal_new ("mode_changed",
259 G_OBJECT_CLASS_TYPE (object_class),
261 G_STRUCT_OFFSET (glViewClass, mode_changed),
263 gl_marshal_VOID__VOID,
267 gl_debug (DEBUG_VIEW, "END");
272 gl_view_init (glView *view)
278 gl_debug (DEBUG_VIEW, "START");
280 units = gl_prefs_model_get_units (gl_prefs);
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;
288 view->home_scale = get_home_scale (view);
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);
301 bg_color = gl_color_to_gdk_color (BG_COLOR);
302 gtk_widget_modify_bg (GTK_WIDGET (view->canvas), GTK_STATE_NORMAL, bg_color);
305 gtk_widget_set_can_focus (GTK_WIDGET (view->canvas), TRUE);
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));
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);
343 gl_debug (DEBUG_VIEW, "END");
348 gl_view_finalize (GObject *object)
350 glView *view = GL_VIEW (object);
352 gl_debug (DEBUG_VIEW, "START");
354 g_return_if_fail (object != NULL);
355 g_return_if_fail (GL_IS_VIEW (view));
357 g_signal_handlers_disconnect_by_func (G_OBJECT (gl_prefs),
358 G_CALLBACK (prefs_changed_cb), view);
360 G_OBJECT_CLASS (gl_view_parent_class)->finalize (object);
362 gl_debug (DEBUG_VIEW, "END");
366 /****************************************************************************/
367 /* NEW view object. */
368 /****************************************************************************/
370 gl_view_new (glLabel *label)
374 gl_debug (DEBUG_VIEW, "START");
376 g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
378 view = g_object_new (GL_TYPE_VIEW, NULL);
380 gl_view_construct (view, label);
382 gl_debug (DEBUG_VIEW, "END");
384 return GTK_WIDGET (view);
388 /*---------------------------------------------------------------------------*/
389 /* PRIVATE. Construct composite widget. */
390 /*---------------------------------------------------------------------------*/
392 gl_view_construct (glView *view,
395 gl_debug (DEBUG_VIEW, "START");
397 g_return_if_fail (GL_IS_VIEW (view));
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);
408 gl_debug (DEBUG_VIEW, "END");
412 /*---------------------------------------------------------------------------*/
413 /* PRIAVTE. Calculate 1:1 scale for screen. */
414 /*---------------------------------------------------------------------------*/
416 get_home_scale (glView *view)
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;
427 if (view->canvas == NULL) return 1.0;
429 if (!gtk_widget_has_screen (GTK_WIDGET (view->canvas))) return 1.0;
431 screen = gtk_widget_get_screen (GTK_WIDGET (view->canvas));
433 gl_debug (DEBUG_VIEW, "Screen = %p", screen);
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);
440 x_pixels_per_mm = screen_width_pixels / screen_width_mm;
441 y_pixels_per_mm = screen_height_pixels / screen_height_mm;
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);
448 scale = (x_pixels_per_mm + y_pixels_per_mm) / 2.0;
450 gl_debug (DEBUG_VIEW, "Average dot pitch: %g pixels/mm (%g dpi)",
451 scale, scale * 25.4);
453 scale /= POINTS_PER_MM;
455 gl_debug (DEBUG_VIEW, "Scale = %g pixels/point", scale);
457 /* Make sure scale is somewhat sane. */
458 if ( (scale < 0.25) || (scale > 4.0) ) return 1.0;
464 /*---------------------------------------------------------------------------*/
465 /* Prefs "changed" callback. */
466 /*---------------------------------------------------------------------------*/
468 prefs_changed_cb (glView *view)
472 units = gl_prefs_model_get_units (gl_prefs);
473 view->grid_spacing = gl_units_util_get_grid_size (units);
475 gl_view_update (view);
479 /*---------------------------------------------------------------------------*/
480 /* Schedule canvas update. */
481 /*---------------------------------------------------------------------------*/
483 gl_view_update (glView *view)
486 GtkAllocation allocation;
488 gl_debug (DEBUG_VIEW, "START");
490 window = gtk_widget_get_window (GTK_WIDGET (view->canvas));
495 if ( !view->update_scheduled_flag )
497 view->update_scheduled_flag = TRUE;
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);
508 gl_debug (DEBUG_VIEW, "END");
512 /*---------------------------------------------------------------------------*/
513 /* Schedule canvas region update. */
514 /*---------------------------------------------------------------------------*/
516 gl_view_update_region (glView *view,
518 glLabelRegion *region)
524 gl_debug (DEBUG_VIEW, "START");
526 window = gtk_widget_get_window (GTK_WIDGET (view->canvas));
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);
535 cairo_user_to_device (cr, &x, &y);
536 cairo_user_to_device_distance (cr, &w, &h);
543 gdk_window_invalidate_rect (window, &rect, TRUE);
545 gl_debug (DEBUG_VIEW, "END");
549 /*---------------------------------------------------------------------------*/
550 /* PRIVATE. Expose handler. */
551 /*---------------------------------------------------------------------------*/
553 draw_cb (glView *view,
556 GdkWindow *bin_window;
559 gl_debug (DEBUG_VIEW, "START");
561 view->update_scheduled_flag = FALSE;
563 bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (view->canvas));
564 bin_cr = gdk_cairo_create (bin_window);
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);
577 draw_layers (view, bin_cr);
579 cairo_destroy (bin_cr);
581 gl_debug (DEBUG_VIEW, "END");
587 /*---------------------------------------------------------------------------*/
588 /* PRIVATE. Realize handler. */
589 /*---------------------------------------------------------------------------*/
591 realize_cb (glView *view)
593 g_return_if_fail (view && GL_IS_VIEW (view));
595 gl_debug (DEBUG_VIEW, "START");
597 if (view->zoom_to_fit_flag) {
598 /* Maintain best fit zoom */
599 gl_view_zoom_to_fit (view);
602 gl_debug (DEBUG_VIEW, "END");
606 /*---------------------------------------------------------------------------*/
607 /* PRIVATE. Size allocation changed callback. */
608 /*---------------------------------------------------------------------------*/
610 size_allocate_cb (glView *view,
611 GtkAllocation *allocation)
613 GtkAdjustment *hadjustment;
614 GtkAdjustment *vadjustment;
616 gl_debug (DEBUG_VIEW, "START");
618 hadjustment = gtk_scrollable_get_hadjustment(GTK_SCROLLABLE (view->canvas));
619 vadjustment = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE (view->canvas));
621 gtk_adjustment_set_page_size( hadjustment, allocation->width);
622 gtk_adjustment_set_page_increment( hadjustment, allocation->width / 2);
624 gtk_adjustment_set_page_size( vadjustment, allocation->height);
625 gtk_adjustment_set_page_increment( vadjustment, allocation->height / 2);
627 g_signal_emit_by_name (hadjustment, "changed");
628 g_signal_emit_by_name (vadjustment, "changed");
630 if (view->zoom_to_fit_flag) {
631 /* Maintain best fit zoom */
632 gl_view_zoom_to_fit (view);
635 gl_debug (DEBUG_VIEW, "END");
639 /*---------------------------------------------------------------------------*/
640 /* PRIVATE. Screen changed callback. */
641 /*---------------------------------------------------------------------------*/
643 screen_changed_cb (glView *view)
645 gl_debug (DEBUG_VIEW, "START");
647 if (gtk_widget_has_screen (GTK_WIDGET (view->canvas))) {
649 view->home_scale = get_home_scale (view);
651 if (view->zoom_to_fit_flag) {
652 /* Maintain best fit zoom */
653 gl_view_zoom_to_fit (view);
657 gl_debug (DEBUG_VIEW, "END");
661 /*---------------------------------------------------------------------------*/
662 /* PRIVATE. Handle label changed event. */
663 /*---------------------------------------------------------------------------*/
665 label_changed_cb (glView *view)
667 g_return_if_fail (view && GL_IS_VIEW (view));
669 gl_debug (DEBUG_VIEW, "START");
671 gl_view_update (view);
673 gl_debug (DEBUG_VIEW, "END");
677 /*---------------------------------------------------------------------------*/
678 /* PRIVATE. Handle label resize event. */
679 /*---------------------------------------------------------------------------*/
681 label_resized_cb (glView *view)
683 GtkAdjustment *hadjustment;
684 GtkAdjustment *vadjustment;
686 g_return_if_fail (view && GL_IS_VIEW (view));
688 gl_debug (DEBUG_VIEW, "START");
690 hadjustment = gtk_scrollable_get_hadjustment(GTK_SCROLLABLE (view->canvas));
691 vadjustment = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE (view->canvas));
693 g_signal_emit_by_name (hadjustment, "changed");
694 g_signal_emit_by_name (vadjustment, "changed");
696 gl_view_update (view);
698 gl_debug (DEBUG_VIEW, "END");
702 /*---------------------------------------------------------------------------*/
703 /* PRIVATE. Create, draw and order layers. */
704 /*---------------------------------------------------------------------------*/
706 draw_layers (glView *view,
709 GdkWindow *bin_window;
712 gint canvas_w, canvas_h;
714 g_return_if_fail (view && GL_IS_VIEW (view));
715 g_return_if_fail (view->label && GL_IS_LABEL (view->label));
717 gl_debug (DEBUG_VIEW, "START");
719 bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (view->canvas));
721 scale = view->zoom * view->home_scale;
723 gl_label_get_size (view->label, &w, &h);
725 scale = view->home_scale * view->zoom;
726 gtk_layout_set_size (GTK_LAYOUT (view->canvas), w*scale+8, h*scale+8);
728 canvas_w = gdk_window_get_width (bin_window);
729 canvas_h = gdk_window_get_height (bin_window);
731 view->x0 = (canvas_w/scale - w) / 2.0;
732 view->y0 = (canvas_h/scale - h) / 2.0;
738 cairo_scale (cr, scale, scale);
739 cairo_translate (cr, view->x0, view->y0);
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);
751 gl_debug (DEBUG_VIEW, "END");
756 /*---------------------------------------------------------------------------*/
757 /* PRIVATE. Draw background */
758 /*---------------------------------------------------------------------------*/
760 draw_bg_layer (glView *view,
764 const lglTemplate *template;
765 gboolean rotate_flag;
767 g_return_if_fail (view && GL_IS_VIEW (view));
768 g_return_if_fail (view->label && GL_IS_LABEL (view->label));
770 scale = view->home_scale * view->zoom;
772 template = gl_label_get_template (view->label);
773 rotate_flag = gl_label_get_rotate_flag (view->label);
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);
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);
790 /*---------------------------------------------------------------------------*/
791 /* PRIVATE. Draw grid lines. */
792 /*---------------------------------------------------------------------------*/
794 draw_grid_layer (glView *view,
797 const lglTemplate *template;
798 gboolean rotate_flag;
799 const lglTemplateFrame *frame;
804 gl_debug (DEBUG_VIEW, "START");
806 g_return_if_fail (view && GL_IS_VIEW (view));
807 g_return_if_fail (view->label && GL_IS_LABEL(view->label));
809 if (view->grid_visible)
812 template = gl_label_get_template (view->label);
813 rotate_flag = gl_label_get_rotate_flag (view->label);
814 frame = (lglTemplateFrame *)template->frames->data;
816 gl_label_get_size (view->label, &w, &h);
818 if (frame->shape == LGL_TEMPLATE_FRAME_SHAPE_RECT) {
819 x0 = view->grid_spacing;
820 y0 = view->grid_spacing;
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);
830 gl_cairo_label_path (cr, template, rotate_flag, FALSE);
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);
837 for ( x=x0; x < w; x += view->grid_spacing )
839 cairo_move_to (cr, x, 0);
840 cairo_line_to (cr, x, h);
844 for ( y=y0; y < h; y += view->grid_spacing )
846 cairo_move_to (cr, 0, y);
847 cairo_line_to (cr, w, y);
855 gl_debug (DEBUG_VIEW, "END");
859 /*---------------------------------------------------------------------------*/
860 /* PRIVATE. Draw markup layer. */
861 /*---------------------------------------------------------------------------*/
863 draw_markup_layer (glView *view,
866 const lglTemplate *template;
867 const lglTemplateFrame *frame;
868 gboolean rotate_flag;
870 lglTemplateMarkup *markup;
871 gdouble width, height;
873 g_return_if_fail (view && GL_IS_VIEW (view));
874 g_return_if_fail (view->label && GL_IS_LABEL (view->label));
876 if (view->markup_visible)
879 template = gl_label_get_template (view->label);
880 frame = (lglTemplateFrame *)template->frames->data;
881 rotate_flag = gl_label_get_rotate_flag (view->label);
887 lgl_template_frame_get_size (frame, &width, &height);
888 cairo_rotate (cr, -G_PI/2.0);
889 cairo_translate (cr, -width, 0.0);
892 cairo_set_line_width (cr, MARKUP_LINE_WIDTH_PIXELS/(view->home_scale * view->zoom));
893 cairo_set_source_rgb (cr, MARKUP_RGB_ARGS);
895 for ( p=frame->all.markups; p != NULL; p=p->next )
897 markup = (lglTemplateMarkup *)p->data;
899 gl_cairo_markup_path (cr, markup, view->label);
910 /*---------------------------------------------------------------------------*/
911 /* PRIVATE. Draw objects layer. */
912 /*---------------------------------------------------------------------------*/
914 draw_objects_layer (glView *view,
917 gl_label_draw (view->label, cr, TRUE, NULL);
921 /*---------------------------------------------------------------------------*/
922 /* PRIVATE. Draw foreground */
923 /*---------------------------------------------------------------------------*/
925 draw_fg_layer (glView *view,
928 const lglTemplate *template;
929 gboolean rotate_flag;
931 g_return_if_fail (view && GL_IS_VIEW (view));
932 g_return_if_fail (view->label && GL_IS_LABEL (view->label));
934 template = gl_label_get_template (view->label);
935 rotate_flag = gl_label_get_rotate_flag (view->label);
937 gl_cairo_label_path (cr, template, rotate_flag, FALSE);
939 cairo_set_line_width (cr, OUTLINE_WIDTH_PIXELS/(view->home_scale * view->zoom));
940 cairo_set_source_rgb (cr, OUTLINE_RGB_ARGS);
945 /*---------------------------------------------------------------------------*/
946 /* PRIVATE. Create highlight layer. */
947 /*---------------------------------------------------------------------------*/
949 draw_highlight_layer (glView *view,
952 GList *selection_list;
954 glLabelObject *object;
956 g_return_if_fail (view && GL_IS_VIEW (view));
960 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
962 selection_list = gl_label_get_selection_list (view->label);
964 for (p_obj = selection_list; p_obj != NULL; p_obj = p_obj->next)
966 object = GL_LABEL_OBJECT (p_obj->data);
968 gl_label_object_draw_handles (object, cr);
971 g_list_free (selection_list);
977 /*---------------------------------------------------------------------------*/
978 /* PRIVATE. Draw select region layer. */
979 /*---------------------------------------------------------------------------*/
981 draw_select_region_layer (glView *view,
987 g_return_if_fail (view && GL_IS_VIEW (view));
989 if (view->select_region_visible)
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);
998 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
1000 cairo_rectangle (cr, x1, y1, w, h);
1002 cairo_set_source_rgba (cr, SELECT_FILL_RGBA_ARGS);
1003 cairo_fill_preserve (cr);
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);
1014 /*****************************************************************************/
1016 /*****************************************************************************/
1018 gl_view_show_grid (glView *view)
1020 g_return_if_fail (view && GL_IS_VIEW (view));
1022 view->grid_visible = TRUE;
1023 gl_view_update (view);
1027 /*****************************************************************************/
1029 /*****************************************************************************/
1031 gl_view_hide_grid (glView *view)
1033 g_return_if_fail (view && GL_IS_VIEW (view));
1035 view->grid_visible = FALSE;
1036 gl_view_update (view);
1040 /*****************************************************************************/
1042 /*****************************************************************************/
1044 gl_view_show_markup (glView *view)
1046 g_return_if_fail (view && GL_IS_VIEW (view));
1048 view->markup_visible = TRUE;
1049 gl_view_update (view);
1053 /*****************************************************************************/
1055 /*****************************************************************************/
1057 gl_view_hide_markup (glView *view)
1059 g_return_if_fail (view && GL_IS_VIEW (view));
1061 view->markup_visible = FALSE;
1062 gl_view_update (view);
1066 /*****************************************************************************/
1067 /* Set arrow mode. */
1068 /*****************************************************************************/
1070 gl_view_arrow_mode (glView *view)
1075 gl_debug (DEBUG_VIEW, "START");
1077 g_return_if_fail (view && GL_IS_VIEW (view));
1079 window = gtk_widget_get_window (view->canvas);
1081 cursor = gdk_cursor_new (GDK_LEFT_PTR);
1082 gdk_window_set_cursor (window, cursor);
1083 g_object_unref (G_OBJECT (cursor));
1085 view->mode = GL_VIEW_MODE_ARROW;
1086 view->state = GL_VIEW_IDLE;
1088 gl_debug (DEBUG_VIEW, "END");
1092 /*****************************************************************************/
1093 /* Set create text object mode. */
1094 /*****************************************************************************/
1096 gl_view_object_create_mode (glView *view,
1097 glLabelObjectType type)
1100 GdkCursor *cursor = NULL;
1102 gl_debug (DEBUG_VIEW, "START");
1104 g_return_if_fail (view && GL_IS_VIEW (view));
1106 window = gtk_widget_get_window (view->canvas);
1110 case GL_LABEL_OBJECT_BOX:
1111 cursor = gl_view_box_get_create_cursor ();
1113 case GL_LABEL_OBJECT_ELLIPSE:
1114 cursor = gl_view_ellipse_get_create_cursor ();
1116 case GL_LABEL_OBJECT_LINE:
1117 cursor = gl_view_line_get_create_cursor ();
1119 case GL_LABEL_OBJECT_IMAGE:
1120 cursor = gl_view_image_get_create_cursor ();
1122 case GL_LABEL_OBJECT_TEXT:
1123 cursor = gl_view_text_get_create_cursor ();
1125 case GL_LABEL_OBJECT_BARCODE:
1126 cursor = gl_view_barcode_get_create_cursor ();
1129 g_message ("Invalid label object type.");/*Should not happen!*/
1133 gdk_window_set_cursor (window, cursor);
1134 g_object_unref (G_OBJECT (cursor));
1136 view->mode = GL_VIEW_MODE_OBJECT_CREATE;
1137 view->state = GL_VIEW_IDLE;
1138 view->create_type = type;
1140 gl_debug (DEBUG_VIEW, "END");
1144 /*****************************************************************************/
1145 /* Zoom in one "notch" */
1146 /*****************************************************************************/
1148 gl_view_zoom_in (glView *view)
1151 gdouble dist, dist_min;
1153 gl_debug (DEBUG_VIEW, "START");
1155 g_return_if_fail (view && GL_IS_VIEW (view));
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) {
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);
1173 gl_debug (DEBUG_VIEW, "END");
1177 /*****************************************************************************/
1178 /* Zoom out one "notch" */
1179 /*****************************************************************************/
1181 gl_view_zoom_out (glView *view)
1184 gdouble dist, dist_min;
1186 gl_debug (DEBUG_VIEW, "START");
1188 g_return_if_fail (view && GL_IS_VIEW (view));
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) {
1201 /* zoom out one "notch" */
1202 if (i_min >= N_ZOOMS)
1207 set_zoom_real (view, zooms[i], FALSE);
1209 gl_debug (DEBUG_VIEW, "END");
1213 /*****************************************************************************/
1214 /* Set zoom to best fit. */
1215 /*****************************************************************************/
1217 gl_view_zoom_to_fit (glView *view)
1219 GtkAllocation allocation;
1220 gint w_view, h_view;
1221 gdouble w_label, h_label;
1222 gdouble x_scale, y_scale, scale;
1224 gl_debug (DEBUG_VIEW, "");
1226 if ( ! gtk_widget_get_window (GTK_WIDGET (view)) ) {
1227 /* Delay until realized. */
1228 view->zoom_to_fit_flag = TRUE;
1232 gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
1233 w_view = allocation.width;
1234 h_view = allocation.height;
1236 gl_label_get_size (GL_LABEL(view->label), &w_label, &h_label);
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);
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);
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);
1253 set_zoom_real (view, scale/view->home_scale, TRUE);
1257 /*****************************************************************************/
1258 /* Set current zoom factor to explicit value. */
1259 /*****************************************************************************/
1261 gl_view_set_zoom (glView *view,
1264 gl_debug (DEBUG_VIEW, "START");
1266 set_zoom_real (view, zoom, FALSE);
1268 gl_debug (DEBUG_VIEW, "END");
1272 /*---------------------------------------------------------------------------*/
1273 /* PRIVATE. Set canvas scale. */
1274 /*---------------------------------------------------------------------------*/
1276 set_zoom_real (glView *view,
1278 gboolean zoom_to_fit_flag)
1280 gl_debug (DEBUG_VIEW, "START");
1282 g_return_if_fail (view && GL_IS_VIEW (view));
1283 g_return_if_fail (zoom > 0.0);
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);
1291 if ( zoom != view->zoom ) {
1294 view->zoom_to_fit_flag = zoom_to_fit_flag;
1296 gl_view_update (view);
1298 g_signal_emit (G_OBJECT(view), signals[ZOOM_CHANGED], 0, zoom);
1302 gl_debug (DEBUG_VIEW, "END");
1307 /*****************************************************************************/
1308 /* Get current zoom factor. */
1309 /*****************************************************************************/
1311 gl_view_get_zoom (glView *view)
1313 gl_debug (DEBUG_VIEW, "");
1315 g_return_val_if_fail (view && GL_IS_VIEW (view), 1.0);
1321 /*****************************************************************************/
1322 /* Is this the maximum zoom level. */
1323 /*****************************************************************************/
1325 gl_view_is_zoom_max (glView *view)
1327 gl_debug (DEBUG_VIEW, "");
1329 g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
1331 return view->zoom >= zooms[0];
1335 /*****************************************************************************/
1336 /* Is this the minimum zoom level. */
1337 /*****************************************************************************/
1339 gl_view_is_zoom_min (glView *view)
1341 gl_debug (DEBUG_VIEW, "");
1343 g_return_val_if_fail (view && GL_IS_VIEW (view), FALSE);
1345 return view->zoom <= zooms[N_ZOOMS-1];
1349 /*---------------------------------------------------------------------------*/
1350 /* PRIVATE. Focus in event handler. */
1351 /*---------------------------------------------------------------------------*/
1353 focus_in_event_cb (glView *view,
1354 GdkEventFocus *event)
1360 /*---------------------------------------------------------------------------*/
1361 /* PRIVATE. Focus out event handler. */
1362 /*---------------------------------------------------------------------------*/
1364 focus_out_event_cb (glView *view,
1365 GdkEventFocus *event)
1371 /*---------------------------------------------------------------------------*/
1372 /* PRIVATE. Enter notify event handler. */
1373 /*---------------------------------------------------------------------------*/
1375 enter_notify_event_cb (glView *view,
1376 GdkEventCrossing *event)
1382 /*---------------------------------------------------------------------------*/
1383 /* PRIVATE. Leave notify event handler. */
1384 /*---------------------------------------------------------------------------*/
1386 leave_notify_event_cb (glView *view,
1387 GdkEventCrossing *event)
1390 g_signal_emit (G_OBJECT(view), signals[POINTER_EXIT], 0);
1396 /*---------------------------------------------------------------------------*/
1397 /* PRIVATE. Motion notify event handler. */
1398 /*---------------------------------------------------------------------------*/
1400 motion_notify_event_cb (glView *view,
1401 GdkEventMotion *event)
1403 gboolean return_value = FALSE;
1404 GdkWindow *bin_window;
1410 glLabelObjectHandle handle;
1412 bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (view->canvas));
1413 window = gtk_widget_get_window (view->canvas);
1415 cr = gdk_cairo_create (bin_window);
1418 * Translate to label coordinates
1420 scale = view->zoom * view->home_scale;
1421 cairo_scale (cr, scale, scale);
1422 cairo_translate (cr, view->x0, view->y0);
1426 cairo_device_to_user (cr, &x, &y);
1429 * Emit signal regardless of mode
1431 g_signal_emit (G_OBJECT(view), signals[POINTER_MOVED], 0, x, y);
1434 * Handle event as appropriate for mode
1439 case GL_VIEW_MODE_ARROW:
1440 switch (view->state)
1444 if ( gl_label_is_selection_atomic (view->label) &&
1445 gl_label_get_handle_at (view->label, cr, event->x, event->y, &handle) )
1447 cursor = gdk_cursor_new (GDK_CROSSHAIR);
1449 else if (gl_label_object_at (view->label, cr, event->x, event->y))
1451 cursor = gdk_cursor_new (GDK_FLEUR);
1455 cursor = gdk_cursor_new (GDK_LEFT_PTR);
1457 gdk_window_set_cursor (window, cursor);
1458 g_object_unref (G_OBJECT (cursor));
1461 case GL_VIEW_ARROW_SELECT_REGION:
1463 gl_view_update_region (view, cr, &view->select_region);
1465 view->select_region.x2 = x;
1466 view->select_region.y2 = y;
1468 gl_view_update_region (view, cr, &view->select_region);
1470 gl_view_update (view);
1474 case GL_VIEW_ARROW_MOVE:
1475 move_event (view, x, y, event->state & GDK_SHIFT_MASK);
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);
1483 g_message ("Invalid arrow state."); /*Should not happen!*/
1485 return_value = TRUE;
1489 case GL_VIEW_MODE_OBJECT_CREATE:
1490 if (view->state != GL_VIEW_IDLE)
1492 switch (view->create_type)
1494 case GL_LABEL_OBJECT_BOX:
1495 gl_view_box_create_motion_event (view, x, y, event->state & GDK_CONTROL_MASK);
1497 case GL_LABEL_OBJECT_ELLIPSE:
1498 gl_view_ellipse_create_motion_event (view, x, y, event->state & GDK_CONTROL_MASK);
1500 case GL_LABEL_OBJECT_LINE:
1501 gl_view_line_create_motion_event (view, x, y, event->state & GDK_SHIFT_MASK);
1503 case GL_LABEL_OBJECT_IMAGE:
1504 gl_view_image_create_motion_event (view, x, y);
1506 case GL_LABEL_OBJECT_TEXT:
1507 gl_view_text_create_motion_event (view, x, y);
1509 case GL_LABEL_OBJECT_BARCODE:
1510 gl_view_barcode_create_motion_event (view, x, y);
1513 g_message ("Invalid create type."); /*Should not happen!*/
1520 g_message ("Invalid view mode."); /*Should not happen!*/
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
1531 if (view->grabbed_flag && !gdk_pointer_is_grabbed ())
1533 gdk_pointer_grab (bin_window,
1535 (GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK),
1541 return return_value;
1545 /*---------------------------------------------------------------------------*/
1546 /* PRIVATE. Button press event handler. */
1547 /*---------------------------------------------------------------------------*/
1549 button_press_event_cb (glView *view,
1550 GdkEventButton *event)
1552 gboolean return_value = FALSE;
1553 GdkWindow *bin_window;
1557 glLabelObject *object;
1558 glLabelObjectHandle handle;
1560 gtk_widget_grab_focus(GTK_WIDGET (view->canvas));
1562 bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (view->canvas));
1564 cr = gdk_cairo_create (bin_window);
1567 * Translate to label coordinates
1569 scale = view->zoom * view->home_scale;
1570 cairo_scale (cr, scale, scale);
1571 cairo_translate (cr, view->x0, view->y0);
1575 cairo_device_to_user (cr, &x, &y);
1577 switch (event->button)
1582 * Handle event as appropriate for mode
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)) )
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;
1597 view->state = GL_VIEW_ARROW_RESIZE;
1599 else if ((object = gl_label_object_at (view->label, cr, event->x, event->y)))
1601 if (event->state & GDK_CONTROL_MASK)
1603 if (gl_label_object_is_selected (object))
1605 /* Un-selecting a selected item */
1606 gl_label_unselect_object (view->label, object);
1608 /* Add to current selection */
1609 gl_label_select_object (view->label, object);
1614 if (!gl_label_object_is_selected (object))
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);
1622 view->move_last_x = x;
1623 view->move_last_y = y;
1627 view->state = GL_VIEW_ARROW_MOVE;
1631 if (!(event->state & GDK_CONTROL_MASK))
1633 gl_label_unselect_all (view->label);
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;
1642 view->state = GL_VIEW_ARROW_SELECT_REGION;
1646 return_value = TRUE;
1649 case GL_VIEW_MODE_OBJECT_CREATE:
1650 switch (view->create_type)
1652 case GL_LABEL_OBJECT_BOX:
1653 gl_view_box_create_button_press_event (view, x, y);
1655 case GL_LABEL_OBJECT_ELLIPSE:
1656 gl_view_ellipse_create_button_press_event (view, x, y);
1658 case GL_LABEL_OBJECT_LINE:
1659 gl_view_line_create_button_press_event (view, x, y);
1661 case GL_LABEL_OBJECT_IMAGE:
1662 gl_view_image_create_button_press_event (view, x, y);
1664 case GL_LABEL_OBJECT_TEXT:
1665 gl_view_text_create_button_press_event (view, x, y);
1667 case GL_LABEL_OBJECT_BARCODE:
1668 gl_view_barcode_create_button_press_event (view, x, y);
1671 g_message ("Invalid create type."); /*Should not happen!*/
1673 view->state = GL_VIEW_CREATE_DRAG;
1674 return_value = TRUE;
1678 g_message ("Invalid view mode."); /*Should not happen!*/
1681 view->grabbed_flag = TRUE;
1682 gdk_pointer_grab (bin_window,
1684 (GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK),
1691 g_signal_emit (G_OBJECT (view),
1692 signals[CONTEXT_MENU_ACTIVATE], 0,
1693 event->button, event->time);
1694 return_value = TRUE;
1701 return return_value;
1705 /*---------------------------------------------------------------------------*/
1706 /* PRIVATE. Button release event handler. */
1707 /*---------------------------------------------------------------------------*/
1709 button_release_event_cb (glView *view,
1710 GdkEventButton *event)
1712 gboolean return_value = FALSE;
1713 GdkWindow *bin_window;
1720 bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (view->canvas));
1721 window = gtk_widget_get_window (view->canvas);
1723 cr = gdk_cairo_create (bin_window);
1726 * Translate to label coordinates
1728 scale = view->zoom * view->home_scale;
1729 cairo_scale (cr, scale, scale);
1730 cairo_translate (cr, view->x0, view->y0);
1734 cairo_device_to_user (cr, &x, &y);
1736 switch (event->button)
1740 view->grabbed_flag = FALSE;
1741 gdk_pointer_ungrab (event->time);
1743 * Handle event as appropriate for mode
1747 case GL_VIEW_MODE_ARROW:
1748 switch (view->state)
1750 case GL_VIEW_ARROW_RESIZE:
1751 view->resize_object = NULL;
1753 view->state = GL_VIEW_IDLE;
1756 case GL_VIEW_ARROW_SELECT_REGION:
1758 gl_view_update_region (view, cr, &view->select_region);
1760 gl_view_update (view);
1763 view->select_region_visible = FALSE;
1764 view->select_region.x2 = x;
1765 view->select_region.y2 = y;
1767 gl_label_select_region (view->label, &view->select_region);
1769 view->state = GL_VIEW_IDLE;
1773 view->state = GL_VIEW_IDLE;
1778 return_value = TRUE;
1782 case GL_VIEW_MODE_OBJECT_CREATE:
1783 switch (view->create_type)
1785 case GL_LABEL_OBJECT_BOX:
1786 gl_view_box_create_button_release_event (view, x, y, event->state & GDK_CONTROL_MASK);
1788 case GL_LABEL_OBJECT_ELLIPSE:
1789 gl_view_ellipse_create_button_release_event (view, x, y, event->state & GDK_CONTROL_MASK);
1791 case GL_LABEL_OBJECT_LINE:
1792 gl_view_line_create_button_release_event (view, x, y, event->state & GDK_CONTROL_MASK);
1794 case GL_LABEL_OBJECT_IMAGE:
1795 gl_view_image_create_button_release_event (view, x, y);
1797 case GL_LABEL_OBJECT_TEXT:
1798 gl_view_text_create_button_release_event (view, x, y);
1800 case GL_LABEL_OBJECT_BARCODE:
1801 gl_view_barcode_create_button_release_event (view, x, y);
1804 g_message ("Invalid create type."); /*Should not happen!*/
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));
1812 gl_label_select_object (view->label, view->create_object);
1817 g_message ("Invalid view mode."); /*Should not happen!*/
1824 return return_value;
1828 /*---------------------------------------------------------------------------*/
1829 /* PRIVATE. Key press event handler. */
1830 /*---------------------------------------------------------------------------*/
1832 key_press_event_cb (glView *view,
1838 gl_debug (DEBUG_VIEW, "");
1840 window = gtk_widget_get_window (view->canvas);
1842 if ( (view->mode == GL_VIEW_MODE_ARROW) &&
1843 (view->state == GL_VIEW_IDLE) )
1845 switch (event->keyval) {
1848 case GDK_KEY_KP_Left:
1849 gl_label_move_selection (view->label, -1.0 / (view->zoom), 0.0);
1853 gl_label_move_selection (view->label, 0.0, -1.0 / (view->zoom));
1856 case GDK_KEY_KP_Right:
1857 gl_label_move_selection (view->label, 1.0 / (view->zoom), 0.0);
1860 case GDK_KEY_KP_Down:
1861 gl_label_move_selection (view->label, 0.0, 1.0 / (view->zoom));
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));
1875 return TRUE; /* We handled this or we were dragging. */
1879 /*---------------------------------------------------------------------------*/
1880 /* PRIVATE. Move object. */
1881 /*---------------------------------------------------------------------------*/
1883 move_event (glView *view,
1886 gboolean keep_direction)
1888 gdouble delta_x, delta_y;
1892 /* Move only on one axis */
1893 if (ABS (x - view->saved_x) > ABS (y - view->saved_y))
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)
1900 /* Already on origin y */
1905 /* Move back to origin y */
1906 delta_y = view->saved_y - view->move_last_y;
1907 view->move_last_y = view->saved_y;
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)
1917 /* Already on origin x */
1922 /* Move back to origin x */
1923 delta_x = view->saved_x - view->move_last_x;
1924 view->move_last_x = view->saved_x;
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;
1937 gl_label_move_selection (view->label, delta_x, delta_y);
1941 /*---------------------------------------------------------------------------*/
1942 /* PRIVATE. Resize object. */
1943 /*---------------------------------------------------------------------------*/
1945 resize_event (glView *view,
1949 gboolean keep_ratio,
1950 gboolean keep_direction)
1952 cairo_matrix_t matrix;
1953 gdouble x0, y0, x1, y1, x2, y2;
1957 gl_debug (DEBUG_VIEW, "x,y world = %g, %g", x, y);
1960 * Change to item relative coordinates
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);
1969 * Initialize origin and 2 corners in object relative coordinates.
1977 gl_label_object_get_size (view->resize_object, &x2, &y2);
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);
1984 * Translate x,y into object relative coordinates.
1986 cairo_device_to_user (cr, &x, &y);
1988 gl_debug (DEBUG_VIEW, "x,y object = %g, %g", x, y);
1993 switch (view->resize_handle)
1996 case GL_LABEL_OBJECT_HANDLE_NW:
1997 w = MAX (x2 - x, 0);
1998 h = MAX (y2 - y, 0);
2001 if (h/w > view->saved_ratio)
2002 w = h / view->saved_ratio;
2004 h = w * view->saved_ratio;
2008 case GL_LABEL_OBJECT_HANDLE_N:
2009 h = MAX (y2 - y, 0);
2011 w = h / view->saved_ratio;
2014 x0 = ((x2 - x1) - w)/2;
2017 case GL_LABEL_OBJECT_HANDLE_NE:
2018 w = MAX (x - x1, 0);
2019 h = MAX (y2 - y, 0);
2022 if (h/w > view->saved_ratio)
2023 w = h / view->saved_ratio;
2025 h = w * view->saved_ratio;
2029 case GL_LABEL_OBJECT_HANDLE_E:
2030 w = MAX (x - x1, 0);
2032 h = w * view->saved_ratio;
2035 y0 = ((y2 - y1) - h)/2;
2038 case GL_LABEL_OBJECT_HANDLE_SE:
2039 w = MAX (x - x1, 0);
2040 h = MAX (y - y1, 0);
2043 if (h/w > view->saved_ratio)
2044 w = h / view->saved_ratio;
2046 h = w * view->saved_ratio;
2050 case GL_LABEL_OBJECT_HANDLE_S:
2051 h = MAX (y - y1, 0);
2053 w = h / view->saved_ratio;
2056 x0 = ((x2 - x1) - w)/2;
2059 case GL_LABEL_OBJECT_HANDLE_SW:
2060 w = MAX (x2 - x, 0);
2061 h = MAX (y - y1, 0);
2064 if (h/w > view->saved_ratio)
2065 w = h / view->saved_ratio;
2067 h = w * view->saved_ratio;
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;
2077 y0 = ((y2 - y1) - h)/2;
2080 case GL_LABEL_OBJECT_HANDLE_P1:
2088 !keep_direction) /* Keep direction with Shift has priority to keep aspect ratio with Ctrl */
2090 if (dy/dx > view->saved_ratio)
2092 dx = dy / view->saved_ratio;
2093 x0 = x0 - (dx - (x2 - x));
2097 dy = dx * view->saved_ratio;
2098 y0 = y0 - (dy - (y2 - y));
2101 else if (keep_direction &&
2102 dy != 0) /*avoid div by 0*/
2104 if (ABS (dx) / ABS (dy) < 0.414213562) /* precalculated tangent of 22,5 degree */
2106 dx = 0; /* horizontal line */
2109 else if (ABS (dx) / ABS (dy) > 2.414213562) /* precalculated tangent of 67,5 degree */
2111 dy = 0; /* vertical line */
2114 else /* diagonal line */
2118 dy = SIGN_AND_VALUE(dy, dx);
2119 y0 = y0 - (dy - (y2 - y));
2123 dx = SIGN_AND_VALUE(dx, dy);
2124 x0 = x0 - (dx - (x2 - x));
2130 case GL_LABEL_OBJECT_HANDLE_P2:
2133 if (keep_ratio && !keep_direction)
2135 if (dy/dx > view->saved_ratio)
2136 dx = dy / view->saved_ratio;
2138 dy = dx * view->saved_ratio;
2140 else if (keep_direction && dy != 0 /*avoid div by 0*/)
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 */
2148 dy = SIGN_AND_VALUE(dy, dx);//(dy < 0 ? -ABS (dx) : ABS (dx));
2150 dx = SIGN_AND_VALUE(dx, dy);//(dx < 0 ? -ABS (dy) : ABS (dy));
2157 g_print ("Invalid handle.\n"); /* Should not happen! */
2161 if ( (view->resize_handle != GL_LABEL_OBJECT_HANDLE_P1) &&
2162 (view->resize_handle != GL_LABEL_OBJECT_HANDLE_P2) )
2164 gl_label_object_set_size (view->resize_object, w, h, TRUE);
2167 * Query the new size in case it was constrained.
2169 gl_label_object_get_size (view->resize_object, &w, &h);
2174 switch (view->resize_handle)
2177 case GL_LABEL_OBJECT_HANDLE_NW:
2182 case GL_LABEL_OBJECT_HANDLE_N:
2183 case GL_LABEL_OBJECT_HANDLE_NE:
2188 case GL_LABEL_OBJECT_HANDLE_E:
2189 case GL_LABEL_OBJECT_HANDLE_SE:
2190 case GL_LABEL_OBJECT_HANDLE_S:
2194 case GL_LABEL_OBJECT_HANDLE_SW:
2195 case GL_LABEL_OBJECT_HANDLE_W:
2201 g_print ("Invalid handle.\n"); /* Should not happen! */
2206 gl_label_object_set_size (view->resize_object, dx, dy, TRUE);
2210 * Put new origin back into world coordinates and set.
2212 cairo_user_to_device (cr, &x0, &y0);
2214 cairo_device_to_user (cr, &x0, &y0);
2215 gl_label_object_set_position (view->resize_object, x0, y0, FALSE);
2222 * Local Variables: -- emacs
2224 * c-basic-offset: 8 -- emacs
2225 * tab-width: 8 -- emacs
2226 * indent-tabs-mode: nil -- emacs