2 * (GLABELS) Label and Business Card Creation program for GNOME
4 * view.c: GLabels View module
6 * Copyright (C) 2001-2002 Jim Evins <evins@snaught.com>.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include <gtk/gtkinvisible.h>
32 #include "view-object.h"
34 #include "view-ellipse.h"
35 #include "view-line.h"
36 #include "view-image.h"
37 #include "view-text.h"
38 #include "view-barcode.h"
39 #include "xml-label.h"
43 #define SEL_LINE_COLOR GNOME_CANVAS_COLOR_A (0, 0, 255, 128)
44 #define SEL_FILL_COLOR GNOME_CANVAS_COLOR_A (192, 192, 255, 128)
46 /*===========================================*/
48 /*===========================================*/
50 static GtkContainerClass *parent_class;
52 /* "CLIPBOARD" selection */
53 static GdkAtom clipboard_atom = GDK_NONE;
55 #define HOME_SCALE 2.0
56 static gdouble scales[] = { 8.0, 6.0, 4.0, 3.0,
62 /*===========================================*/
63 /* Local function prototypes */
64 /*===========================================*/
66 static void gl_view_class_init (glViewClass *class);
67 static void gl_view_init (glView * view);
68 static void gl_view_finalize (GObject * object);
70 static void gl_view_construct (glView *view);
71 static GtkWidget *gl_view_construct_canvas (glView *view);
72 static void gl_view_construct_selection (glView *view);
74 static gdouble get_apropriate_scale (gdouble w, gdouble h);
76 static void draw_rect_bg (glView * view);
77 static void draw_rounded_rect_bg (glView * view);
78 static void draw_round_bg (glView * view);
79 static void draw_cd_bg (glView * view);
81 static int canvas_event (GnomeCanvas * canvas,
84 static int canvas_event_arrow_mode (GnomeCanvas * canvas,
85 GdkEvent * event, glView *view);
87 static void select_region (glView * view,
92 static void select_object (glViewObject *view_object);
93 static void unselect_object (glViewObject *view_object);
94 static gboolean object_at (glView * view,
95 gdouble x, gdouble y);
96 static gboolean object_selected (glViewObject *view_object);
97 static gboolean multiple_items_selected (glView * view);
99 static int item_event_arrow_mode (GnomeCanvasItem * item,
101 glViewObject *view_object);
103 static GtkWidget *new_selection_menu (glView * view);
105 static void popup_selection_menu (glView *view,
106 glViewObject *view_object, GdkEvent *event);
108 static void move_selected_items (glView * view, gdouble dx, gdouble dy);
109 static void move_item (GnomeCanvasItem * item, gdouble dx, gdouble dy);
111 static void raise_selection_cb (GtkWidget * widget, glView * view);
112 static void lower_selection_cb (GtkWidget * widget, glView * view);
114 static void selection_clear_cb (GtkWidget * widget,
115 GdkEventSelection * event, gpointer data);
117 static void selection_get_cb (GtkWidget * widget,
118 GtkSelectionData * selection_data, guint info,
119 guint time, gpointer data);
121 static void selection_received_cb (GtkWidget * widget,
122 GtkSelectionData * selection_data,
123 guint time, gpointer data);
125 /****************************************************************************/
126 /* Boilerplate Object stuff. */
127 /****************************************************************************/
129 gl_view_get_type (void)
131 static guint view_type = 0;
134 GTypeInfo view_info = {
135 sizeof (glViewClass),
138 (GClassInitFunc) gl_view_class_init,
143 (GInstanceInitFunc) gl_view_init,
147 g_type_register_static (gtk_vbox_get_type (),
148 "glView", &view_info, 0);
155 gl_view_class_init (glViewClass * class)
157 GObjectClass *object_class = (GObjectClass *) class;
159 gl_debug (DEBUG_VIEW, "START");
161 parent_class = g_type_class_peek_parent (class);
163 object_class->finalize = gl_view_finalize;
165 gl_debug (DEBUG_VIEW, "END");
169 gl_view_init (glView * view)
171 gl_debug (DEBUG_VIEW, "START");
175 gl_debug (DEBUG_VIEW, "END");
179 gl_view_finalize (GObject * object)
183 gl_debug (DEBUG_VIEW, "START");
185 g_return_if_fail (object != NULL);
186 g_return_if_fail (GL_IS_VIEW (object));
188 view = GL_VIEW (object);
190 G_OBJECT_CLASS (parent_class)->finalize (object);
192 gl_debug (DEBUG_VIEW, "END");
196 gl_view_new (glLabel * label)
198 glView *view = g_object_new (gl_view_get_type (), NULL);
200 gl_debug (DEBUG_VIEW, "START");
204 gl_view_construct (view);
206 gl_debug (DEBUG_VIEW, "END");
208 return GTK_WIDGET (view);
211 /*---------------------------------------------------------------------------*/
212 /* PRIVATE. Construct composite widget. */
213 /*---------------------------------------------------------------------------*/
215 gl_view_construct (glView * view)
217 GtkWidget *wvbox, *wscroll;
219 gl_debug (DEBUG_VIEW, "START");
221 g_return_if_fail (GL_IS_VIEW (view));
223 wvbox = GTK_WIDGET (view);
225 view->state = GL_VIEW_STATE_ARROW;
226 view->object_list = NULL;
228 gl_view_construct_canvas (view);
229 wscroll = gtk_scrolled_window_new (NULL, NULL);
230 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (wscroll),
231 GTK_POLICY_AUTOMATIC,
232 GTK_POLICY_AUTOMATIC);
233 gtk_box_pack_start (GTK_BOX (wvbox), wscroll, TRUE, TRUE, 0);
234 gtk_container_add (GTK_CONTAINER (wscroll), view->canvas);
236 gl_view_construct_selection (view);
238 view->menu = new_selection_menu (view);
240 gl_debug (DEBUG_VIEW, "END");
243 /*---------------------------------------------------------------------------*/
244 /* PRIVATE. Create canvas w/ a background in the shape of the label/card. */
245 /*---------------------------------------------------------------------------*/
247 gl_view_construct_canvas (glView * view)
250 glLabel *label = view->label;
251 gdouble label_width, label_height;
252 glTemplate *label_template;
254 glLabelObject *object;
255 glViewObject *view_object;
257 gl_debug (DEBUG_VIEW, "START");
259 g_return_val_if_fail (GL_IS_VIEW (view), NULL);
260 g_return_val_if_fail (label != NULL, NULL);
262 gtk_widget_push_colormap (gdk_rgb_get_colormap ());
263 view->canvas = gnome_canvas_new_aa ();
264 gtk_widget_pop_colormap ();
266 gl_label_get_size (label, &label_width, &label_height);
267 gl_debug (DEBUG_VIEW, "Label size: w=%lf, h=%lf",
268 label_width, label_height);
269 label_template = gl_label_get_template (label);
271 scale = get_apropriate_scale (label_width, label_height);
272 gl_debug (DEBUG_VIEW, "scale =%lf", scale);
274 gl_debug (DEBUG_VIEW, "Canvas size: w=%lf, h=%lf",
275 scale * label_width + 40,
276 scale * label_height + 40);
277 gtk_widget_set_size_request (GTK_WIDGET(view->canvas),
278 scale * label_width + 40,
279 scale * label_height + 40);
280 gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (view->canvas),
284 gnome_canvas_set_scroll_region (GNOME_CANVAS (view->canvas),
285 0.0, 0.0, label_width, label_height);
287 /* Draw background shape of label/card */
288 switch (label_template->style) {
290 case GL_TEMPLATE_STYLE_RECT:
291 if (label_template->label_round == 0.0) {
292 /* Square corners. */
295 /* Rounded corners. */
296 draw_rounded_rect_bg (view);
300 case GL_TEMPLATE_STYLE_ROUND:
301 draw_round_bg (view);
304 case GL_TEMPLATE_STYLE_CD:
309 g_warning ("Unknown template label style");
313 g_signal_connect (G_OBJECT (view->canvas), "event",
314 G_CALLBACK (canvas_event), view);
316 for (p_obj = label->objects; p_obj != NULL; p_obj = p_obj->next) {
317 object = (glLabelObject *) p_obj->data;
319 if (GL_IS_LABEL_BOX (object)) {
320 view_object = gl_view_box_new (GL_LABEL_BOX(object),
322 } else if (GL_IS_LABEL_ELLIPSE (object)) {
323 view_object = gl_view_ellipse_new (GL_LABEL_ELLIPSE(object),
325 } else if (GL_IS_LABEL_LINE (object)) {
326 view_object = gl_view_line_new (GL_LABEL_LINE(object),
328 } else if (GL_IS_LABEL_IMAGE (object)) {
329 view_object = gl_view_image_new (GL_LABEL_IMAGE(object),
331 } else if (GL_IS_LABEL_TEXT (object)) {
332 view_object = gl_view_text_new (GL_LABEL_TEXT(object),
334 } else if (GL_IS_LABEL_BARCODE (object)) {
335 view_object = gl_view_barcode_new (GL_LABEL_BARCODE(object),
338 /* Should not happen! */
340 g_warning ("Invalid label object type.");
344 gl_debug (DEBUG_VIEW, "END");
349 /*---------------------------------------------------------------------------*/
350 /* PRIVATE. Create selection targets. */
351 /*---------------------------------------------------------------------------*/
353 gl_view_construct_selection (glView * view)
355 gl_debug (DEBUG_VIEW, "START");
357 g_return_if_fail (GL_IS_VIEW (view));
359 view->have_selection = FALSE;
360 view->selection_data = NULL;
361 view->invisible = gtk_invisible_new ();
363 view->selected_object_list = NULL;
365 if (!clipboard_atom) {
366 clipboard_atom = gdk_atom_intern ("GLABELS_CLIPBOARD", FALSE);
369 gtk_selection_add_target (view->invisible,
370 clipboard_atom, GDK_SELECTION_TYPE_STRING, 1);
372 g_signal_connect (G_OBJECT (view->invisible),
373 "selection_clear_event",
374 G_CALLBACK (selection_clear_cb), view);
376 g_signal_connect (G_OBJECT (view->invisible), "selection_get",
377 G_CALLBACK (selection_get_cb), view);
379 g_signal_connect (G_OBJECT (view->invisible),
380 "selection_received",
381 G_CALLBACK (selection_received_cb), view);
383 gl_debug (DEBUG_VIEW, "END");
386 /*---------------------------------------------------------------------------*/
387 /* PRIVATE. Determine an apropriate scale for given label & screen size */
388 /*---------------------------------------------------------------------------*/
390 get_apropriate_scale (gdouble w, gdouble h)
392 gdouble w_screen, h_screen;
396 gl_debug (DEBUG_VIEW, "");
398 w_screen = (gdouble) gdk_screen_width ();
399 h_screen = (gdouble) gdk_screen_height ();
401 for (i = 0; scales[i] > 0.0; i++) {
403 if (k <= HOME_SCALE) {
404 if ((k * w < (w_screen - 256))
405 && (k * h < (h_screen - 256)))
413 /*---------------------------------------------------------------------------*/
414 /* PRIVATE. Draw simple recangular background. */
415 /*---------------------------------------------------------------------------*/
417 draw_rect_bg (glView * view)
419 glLabel *label = view->label;
420 glTemplate *template;
421 gdouble w, h, margin;
422 GnomeCanvasItem *item;
423 GnomeCanvasGroup *group;
425 gl_debug (DEBUG_VIEW, "START");
427 g_return_if_fail (GL_IS_VIEW (view));
428 g_return_if_fail (label != NULL);
430 gl_label_get_size (label, &w, &h);
431 template = gl_label_get_template (label);
432 margin = template->label_margin;
434 view->n_bg_items = 0;
435 view->bg_item_list = NULL;
437 group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
439 item = gnome_canvas_item_new (group,
440 gnome_canvas_rect_get_type (),
445 "fill_color", "white",
448 view->bg_item_list = g_list_append (view->bg_item_list, item);
450 /* Bounding box @ margin */
451 gnome_canvas_item_new (group,
452 gnome_canvas_rect_get_type (),
458 "outline_color", "light blue",
461 view->bg_item_list = g_list_append (view->bg_item_list, item);
463 gl_debug (DEBUG_VIEW, "END");
466 /*---------------------------------------------------------------------------*/
467 /* PRIVATE. Draw rounded recangular background. */
468 /*---------------------------------------------------------------------------*/
470 draw_rounded_rect_bg (glView * view)
472 glLabel *label = view->label;
473 GnomeCanvasPoints *points;
474 gint i_coords, i_theta;
475 glTemplate *template;
477 GnomeCanvasItem *item;
478 GnomeCanvasGroup *group;
480 gl_debug (DEBUG_VIEW, "START");
482 g_return_if_fail (GL_IS_VIEW (view));
483 g_return_if_fail (label != NULL);
485 group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
487 view->n_bg_items = 0;
488 view->bg_item_list = NULL;
490 gl_label_get_size (label, &w, &h);
491 template = gl_label_get_template (label);
492 r = template->label_round;
493 m = template->label_margin;
495 points = gnome_canvas_points_new (4 * (1 + 90 / 5));
497 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
498 points->coords[i_coords++] =
499 r - r * sin (i_theta * M_PI / 180.0);
500 points->coords[i_coords++] =
501 r - r * cos (i_theta * M_PI / 180.0);
503 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
504 points->coords[i_coords++] =
505 r - r * cos (i_theta * M_PI / 180.0);
506 points->coords[i_coords++] =
507 (h - r) + r * sin (i_theta * M_PI / 180.0);
509 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
510 points->coords[i_coords++] =
511 (w - r) + r * sin (i_theta * M_PI / 180.0);
512 points->coords[i_coords++] =
513 (h - r) + r * cos (i_theta * M_PI / 180.0);
515 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
516 points->coords[i_coords++] =
517 (w - r) + r * cos (i_theta * M_PI / 180.0);
518 points->coords[i_coords++] =
519 r - r * sin (i_theta * M_PI / 180.0);
521 item = gnome_canvas_item_new (group,
522 gnome_canvas_polygon_get_type (),
524 "fill_color", "white",
526 gnome_canvas_points_free (points);
528 view->bg_item_list = g_list_append (view->bg_item_list, item);
530 /* Bounding box @ margin */
531 if (template->label_margin >= template->label_round) {
532 /* simple rectangle */
533 item = gnome_canvas_item_new (group,
534 gnome_canvas_rect_get_type (),
540 "outline_color", "light blue",
544 g_list_append (view->bg_item_list, item);
550 /* rectangle with rounded corners */
551 points = gnome_canvas_points_new (4 * (1 + 90 / 5));
553 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
554 points->coords[i_coords++] =
555 m + r - r * sin (i_theta * M_PI / 180.0);
556 points->coords[i_coords++] =
557 m + r - r * cos (i_theta * M_PI / 180.0);
559 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
560 points->coords[i_coords++] =
561 m + r - r * cos (i_theta * M_PI / 180.0);
562 points->coords[i_coords++] =
563 m + (h - r) + r * sin (i_theta * M_PI / 180.0);
565 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
566 points->coords[i_coords++] =
567 m + (w - r) + r * sin (i_theta * M_PI / 180.0);
568 points->coords[i_coords++] =
569 m + (h - r) + r * cos (i_theta * M_PI / 180.0);
571 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
572 points->coords[i_coords++] =
573 m + (w - r) + r * cos (i_theta * M_PI / 180.0);
574 points->coords[i_coords++] =
575 m + r - r * sin (i_theta * M_PI / 180.0);
577 item = gnome_canvas_item_new (group,
578 gnome_canvas_polygon_get_type (),
581 "outline_color", "light blue",
583 gnome_canvas_points_free (points);
586 g_list_append (view->bg_item_list, item);
589 gl_debug (DEBUG_VIEW, "END");
592 /*---------------------------------------------------------------------------*/
593 /* PRIVATE. Draw round background. */
594 /*---------------------------------------------------------------------------*/
596 draw_round_bg (glView * view)
598 glLabel *label = view->label;
599 glTemplate *template;
600 GnomeCanvasPoints *points;
601 gint i_coords, i_theta;
603 GnomeCanvasItem *item;
604 GnomeCanvasGroup *group;
606 gl_debug (DEBUG_VIEW, "START");
608 g_return_if_fail (GL_IS_VIEW (view));
609 g_return_if_fail (label != NULL);
611 template = gl_label_get_template (label);
613 group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
615 view->n_bg_items = 0;
616 view->bg_item_list = NULL;
618 r1 = template->label_radius;
619 points = gnome_canvas_points_new (1 + 360/2);
621 for (i_theta = 0; i_theta <= 360; i_theta += 2) {
622 points->coords[i_coords++] =
623 r1 - r1 * sin (i_theta * M_PI / 180.0);
624 points->coords[i_coords++] =
625 r1 - r1 * cos (i_theta * M_PI / 180.0);
627 item = gnome_canvas_item_new (group,
628 gnome_canvas_polygon_get_type (),
630 "fill_color", "white",
632 gnome_canvas_points_free (points);
634 view->bg_item_list = g_list_append (view->bg_item_list, item);
636 /* Bounding box @ margin */
637 r = template->label_radius - template->label_margin;
638 points = gnome_canvas_points_new (360 / 2);
640 for (i_theta = 0; i_theta < 360; i_theta += 2) {
641 points->coords[i_coords++] =
642 r1 - r * sin (i_theta * M_PI / 180.0);
643 points->coords[i_coords++] =
644 r1 - r * cos (i_theta * M_PI / 180.0);
646 item = gnome_canvas_item_new (group,
647 gnome_canvas_polygon_get_type (),
650 "outline_color", "light blue", NULL);
651 gnome_canvas_points_free (points);
653 view->bg_item_list = g_list_append (view->bg_item_list, item);
655 gl_debug (DEBUG_VIEW, "END");
658 /*---------------------------------------------------------------------------*/
659 /* PRIVATE. Draw CD style background, circular w/ concentric hole. */
660 /*---------------------------------------------------------------------------*/
662 draw_cd_bg (glView * view)
664 glLabel *label = view->label;
665 glTemplate *template;
666 GnomeCanvasPoints *points;
667 gint i_coords, i_theta;
669 GnomeCanvasItem *item;
670 GnomeCanvasGroup *group;
672 gl_debug (DEBUG_VIEW, "START");
674 g_return_if_fail (GL_IS_VIEW (view));
675 g_return_if_fail (label != NULL);
677 template = gl_label_get_template (label);
679 group = gnome_canvas_root (GNOME_CANVAS (view->canvas));
681 view->n_bg_items = 0;
682 view->bg_item_list = NULL;
684 r1 = template->label_radius;
685 r2 = template->label_hole;
686 points = gnome_canvas_points_new (2 * (1 + 360 / 2));
688 for (i_theta = 0; i_theta <= 360; i_theta += 2) {
689 points->coords[i_coords++] =
690 r1 - r1 * sin (i_theta * M_PI / 180.0);
691 points->coords[i_coords++] =
692 r1 - r1 * cos (i_theta * M_PI / 180.0);
694 for (i_theta = 0; i_theta <= 360; i_theta += 2) {
695 points->coords[i_coords++] =
696 r1 - r2 * sin (i_theta * M_PI / 180.0);
697 points->coords[i_coords++] =
698 r1 - r2 * cos (i_theta * M_PI / 180.0);
700 item = gnome_canvas_item_new (group,
701 gnome_canvas_polygon_get_type (),
703 "fill_color", "white",
705 gnome_canvas_points_free (points);
707 view->bg_item_list = g_list_append (view->bg_item_list, item);
709 /* Bounding box @ margin */
711 r = template->label_radius - template->label_margin;
712 points = gnome_canvas_points_new (360 / 2);
714 for (i_theta = 0; i_theta < 360; i_theta += 2) {
715 points->coords[i_coords++] =
716 r1 - r * sin (i_theta * M_PI / 180.0);
717 points->coords[i_coords++] =
718 r1 - r * cos (i_theta * M_PI / 180.0);
720 item = gnome_canvas_item_new (group,
721 gnome_canvas_polygon_get_type (),
724 "outline_color", "light blue", NULL);
725 gnome_canvas_points_free (points);
727 view->bg_item_list = g_list_append (view->bg_item_list, item);
730 r = template->label_hole + template->label_margin;
731 points = gnome_canvas_points_new (360 / 2);
733 for (i_theta = 0; i_theta < 360; i_theta += 2) {
734 points->coords[i_coords++] =
735 r1 - r * sin (i_theta * M_PI / 180.0);
736 points->coords[i_coords++] =
737 r1 - r * cos (i_theta * M_PI / 180.0);
739 item = gnome_canvas_item_new (group,
740 gnome_canvas_polygon_get_type (),
743 "outline_color", "light blue",
745 gnome_canvas_points_free (points);
747 view->bg_item_list = g_list_append (view->bg_item_list, item);
749 gl_debug (DEBUG_VIEW, "END");
752 /*****************************************************************************/
753 /* Set arrow mode. */
754 /*****************************************************************************/
756 gl_view_arrow_mode (glView * view)
758 static GdkCursor *cursor = NULL;
760 gl_debug (DEBUG_VIEW, "START");
762 g_return_if_fail (GL_IS_VIEW (view));
765 cursor = gdk_cursor_new (GDK_LEFT_PTR);
768 gdk_window_set_cursor (view->canvas->window, cursor);
770 view->state = GL_VIEW_STATE_ARROW;
772 gl_debug (DEBUG_VIEW, "END");
775 /*****************************************************************************/
776 /* Set create text object mode. */
777 /*****************************************************************************/
779 gl_view_object_create_mode (glView * view,
780 glLabelObjectType type)
784 gl_debug (DEBUG_VIEW, "START");
786 g_return_if_fail (GL_IS_VIEW (view));
789 case GL_LABEL_OBJECT_BOX:
790 cursor = gl_view_box_get_create_cursor ();
792 case GL_LABEL_OBJECT_ELLIPSE:
793 cursor = gl_view_ellipse_get_create_cursor ();
795 case GL_LABEL_OBJECT_LINE:
796 cursor = gl_view_line_get_create_cursor ();
798 case GL_LABEL_OBJECT_IMAGE:
799 cursor = gl_view_image_get_create_cursor ();
801 case GL_LABEL_OBJECT_TEXT:
802 cursor = gl_view_text_get_create_cursor ();
804 case GL_LABEL_OBJECT_BARCODE:
805 cursor = gl_view_barcode_get_create_cursor ();
808 g_warning ("Invalid label object type.");/*Should not happen!*/
812 gdk_window_set_cursor (view->canvas->window, cursor);
814 view->state = GL_VIEW_STATE_OBJECT_CREATE;
815 view->create_type = type;
817 gl_debug (DEBUG_VIEW, "END");
820 /*****************************************************************************/
821 /* Select given object. */
822 /*****************************************************************************/
824 gl_view_select_object (glView *view, glViewObject *view_object)
826 gl_debug (DEBUG_VIEW, "START");
828 select_object (view_object);
830 gl_debug (DEBUG_VIEW, "END");
833 /*****************************************************************************/
834 /* Select all items. */
835 /*****************************************************************************/
837 gl_view_select_all (glView * view)
841 gl_debug (DEBUG_VIEW, "START");
843 g_return_if_fail (GL_IS_VIEW (view));
845 gl_view_unselect_all (view);
847 for (p = view->object_list; p != NULL; p = p->next) {
848 select_object (GL_VIEW_OBJECT (p->data));
851 gl_debug (DEBUG_VIEW, "END");
854 /*****************************************************************************/
855 /* Remove all selections */
856 /*****************************************************************************/
858 gl_view_unselect_all (glView * view)
862 gl_debug (DEBUG_VIEW, "START");
864 g_return_if_fail (GL_IS_VIEW (view));
866 for (p = view->selected_object_list; p != NULL; p = p_next) {
868 unselect_object (GL_VIEW_OBJECT (p->data));
871 gl_debug (DEBUG_VIEW, "END");
874 /*****************************************************************************/
875 /* "Cut" selected items and place in clipboard selections. */
876 /*****************************************************************************/
878 gl_view_cut (glView * view)
880 gl_debug (DEBUG_VIEW, "START");
882 g_return_if_fail (GL_IS_VIEW (view));
885 gl_view_delete_selection (view);
887 gl_debug (DEBUG_VIEW, "END");
890 /*****************************************************************************/
891 /* "Copy" selected items to clipboard selections. */
892 /*****************************************************************************/
894 gl_view_copy (glView * view)
897 glViewObject *view_object;
898 glLabelObject *object;
899 glTemplate *template;
900 gboolean rotate_flag;
902 gl_debug (DEBUG_VIEW, "START");
904 g_return_if_fail (GL_IS_VIEW (view));
906 if (view->selected_object_list) {
908 if ( view->selection_data ) {
909 g_object_unref (view->selection_data);
911 template = gl_label_get_template (view->label);
912 rotate_flag = gl_label_get_rotate_flag (view->label);
913 view->selection_data = GL_LABEL(gl_label_new ());
914 gl_label_set_template (view->selection_data, template);
915 gl_label_set_rotate_flag (view->selection_data, rotate_flag);
916 gl_template_free (&template);
918 for (p = view->selected_object_list; p != NULL; p = p->next) {
920 view_object = GL_VIEW_OBJECT (p->data);
921 object = gl_view_object_get_object (view_object);
923 gl_debug (DEBUG_VIEW, "Object copied");
925 if (GL_IS_LABEL_BOX (object)) {
926 gl_label_box_dup (GL_LABEL_BOX(object),
927 view->selection_data);
928 } else if (GL_IS_LABEL_ELLIPSE (object)) {
929 gl_label_ellipse_dup (GL_LABEL_ELLIPSE(object),
930 view->selection_data);
931 } else if (GL_IS_LABEL_LINE (object)) {
932 gl_label_line_dup (GL_LABEL_LINE(object),
933 view->selection_data);
934 } else if (GL_IS_LABEL_IMAGE (object)) {
935 gl_label_image_dup (GL_LABEL_IMAGE(object),
936 view->selection_data);
937 } else if (GL_IS_LABEL_TEXT (object)) {
938 gl_label_text_dup (GL_LABEL_TEXT(object),
939 view->selection_data);
940 } else if (GL_IS_LABEL_BARCODE (object)) {
941 gl_label_barcode_dup (GL_LABEL_BARCODE(object),
942 view->selection_data);
944 /* Should not happen! */
945 g_warning ("Invalid label object type.");
951 gtk_selection_owner_set (view->invisible,
952 clipboard_atom, GDK_CURRENT_TIME);
953 view->have_selection = TRUE;
957 gl_debug (DEBUG_VIEW, "END");
960 /*****************************************************************************/
961 /* "Paste" from private clipboard selection. */
962 /*****************************************************************************/
964 gl_view_paste (glView * view)
966 gl_debug (DEBUG_VIEW, "START");
968 g_return_if_fail (GL_IS_VIEW (view));
970 gtk_selection_convert (GTK_WIDGET (view->invisible),
971 clipboard_atom, GDK_SELECTION_TYPE_STRING,
974 gl_debug (DEBUG_VIEW, "END");
977 /*---------------------------------------------------------------------------*/
978 /* PRIVATE. Canvas event handler. */
979 /*---------------------------------------------------------------------------*/
981 canvas_event (GnomeCanvas *canvas,
985 gl_debug (DEBUG_VIEW, "");
987 switch (view->state) {
989 case GL_VIEW_STATE_ARROW:
990 return canvas_event_arrow_mode (canvas, event, view);
992 case GL_VIEW_STATE_OBJECT_CREATE:
993 switch (view->create_type) {
994 case GL_LABEL_OBJECT_BOX:
995 return gl_view_box_create_event_handler (canvas,
999 case GL_LABEL_OBJECT_ELLIPSE:
1000 return gl_view_ellipse_create_event_handler (canvas,
1004 case GL_LABEL_OBJECT_LINE:
1005 return gl_view_line_create_event_handler (canvas,
1009 case GL_LABEL_OBJECT_IMAGE:
1010 return gl_view_image_create_event_handler (canvas,
1014 case GL_LABEL_OBJECT_TEXT:
1015 return gl_view_text_create_event_handler (canvas,
1019 case GL_LABEL_OBJECT_BARCODE:
1020 return gl_view_barcode_create_event_handler (canvas,
1025 /*Should not happen!*/
1026 g_warning ("Invalid label object type.");
1031 g_warning ("Invalid view state."); /*Should not happen!*/
1037 /*---------------------------------------------------------------------------*/
1038 /* PRIVATE. Canvas event handler (arrow mode) */
1039 /*---------------------------------------------------------------------------*/
1041 canvas_event_arrow_mode (GnomeCanvas *canvas,
1045 static gdouble x0, y0;
1046 static gboolean dragging = FALSE;
1047 static GnomeCanvasItem *item;
1048 gdouble x, y, x1, y1, x2, y2;
1049 GnomeCanvasGroup *group;
1052 gl_debug (DEBUG_VIEW, "");
1054 switch (event->type) {
1056 case GDK_BUTTON_PRESS:
1057 gl_debug (DEBUG_VIEW, "BUTTON_PRESS");
1058 switch (event->button.button) {
1060 gnome_canvas_window_to_world (canvas,
1062 event->button.y, &x, &y);
1064 if (!object_at (view, x, y)) {
1065 if (!(event->button.state & GDK_CONTROL_MASK)) {
1066 gl_view_unselect_all (view);
1070 gdk_pointer_grab (GTK_WIDGET (view->canvas)->
1072 GDK_POINTER_MOTION_MASK |
1073 GDK_BUTTON_RELEASE_MASK |
1074 GDK_BUTTON_PRESS_MASK, NULL,
1075 NULL, event->button.time);
1077 gnome_canvas_root (GNOME_CANVAS
1080 gnome_canvas_item_new (group,
1081 gnome_canvas_rect_get_type (),
1085 "outline_color_rgba",
1100 case GDK_BUTTON_RELEASE:
1101 gl_debug (DEBUG_VIEW, "BUTTON_RELEASE");
1102 switch (event->button.button) {
1106 gdk_pointer_ungrab (event->button.time);
1107 gnome_canvas_window_to_world (canvas,
1115 select_region (view, x1, y1, x2, y2);
1116 gtk_object_destroy (GTK_OBJECT (item));
1125 case GDK_MOTION_NOTIFY:
1126 gl_debug (DEBUG_VIEW, "MOTION_NOTIFY");
1127 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
1128 gnome_canvas_window_to_world (canvas,
1130 event->button.y, &x, &y);
1132 gnome_canvas_item_set (item,
1136 "y2", MAX (y, y0), NULL);
1143 gl_debug (DEBUG_VIEW, "KEY_PRESS");
1145 switch (event->key.keyval) {
1148 move_selected_items (view,
1149 -1.0 / (view->scale),
1154 move_selected_items (view, 0.0,
1155 -1.0 / (view->scale));
1159 move_selected_items (view,
1160 1.0 / (view->scale),
1165 move_selected_items (view, 0.0,
1166 1.0 / (view->scale));
1170 gl_view_delete_selection (view);
1171 cursor = gdk_cursor_new (GDK_LEFT_PTR);
1172 gdk_window_set_cursor (view->canvas->window,
1174 gdk_cursor_unref (cursor);
1180 return TRUE; /* We handled this or we were dragging. */
1183 gl_debug (DEBUG_VIEW, "default");
1189 /*---------------------------------------------------------------------------*/
1190 /* PRIVATE. Select all objects within given rectangular region. */
1191 /*---------------------------------------------------------------------------*/
1193 select_region (glView * view,
1200 glViewObject *view_object;
1201 glLabelObject *object;
1202 gdouble i_x1, i_y1, i_x2, i_y2, w, h;
1204 gl_debug (DEBUG_VIEW, "START");
1206 g_return_if_fail (GL_IS_VIEW (view));
1207 g_return_if_fail ((x1 <= x2) && (y1 <= y2));
1209 for (p = view->object_list; p != NULL; p = p->next) {
1210 view_object = GL_VIEW_OBJECT(p->data);
1211 if (!object_selected (view_object)) {
1213 object = gl_view_object_get_object (view_object);
1215 gl_label_object_get_position (object, &i_x1, &i_y1);
1216 gl_label_object_get_size (object, &w, &h);
1219 if ((i_x1 >= x1) && (i_x2 <= x2) && (i_y1 >= y1)
1221 select_object (view_object);
1227 gl_debug (DEBUG_VIEW, "END");
1230 /*---------------------------------------------------------------------------*/
1231 /* PRIVATE. Select an object. */
1232 /*---------------------------------------------------------------------------*/
1234 select_object (glViewObject *view_object)
1238 gl_debug (DEBUG_VIEW, "START");
1240 g_return_if_fail (GL_IS_VIEW_OBJECT (view_object));
1242 view = gl_view_object_get_view (view_object);
1244 if (!object_selected (view_object)) {
1245 view->selected_object_list =
1246 g_list_prepend (view->selected_object_list, view_object);
1248 gl_view_object_show_highlight (view_object);
1249 gtk_widget_grab_focus (GTK_WIDGET (view->canvas));
1251 gl_debug (DEBUG_VIEW, "END");
1254 /*---------------------------------------------------------------------------*/
1255 /* PRIVATE. Un-select object. */
1256 /*---------------------------------------------------------------------------*/
1258 unselect_object (glViewObject *view_object)
1262 gl_debug (DEBUG_VIEW, "START");
1264 g_return_if_fail (GL_IS_VIEW_OBJECT (view_object));
1266 view = gl_view_object_get_view (view_object);
1268 gl_view_object_hide_highlight (view_object);
1270 view->selected_object_list =
1271 g_list_remove (view->selected_object_list, view_object);
1273 gl_debug (DEBUG_VIEW, "END");
1276 /*---------------------------------------------------------------------------*/
1277 /* PRIVATE. Return object at (x,y). */
1278 /*---------------------------------------------------------------------------*/
1280 object_at (glView * view,
1284 GnomeCanvasItem *item, *p_item;
1287 gl_debug (DEBUG_VIEW, "");
1289 g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
1291 item = gnome_canvas_get_item_at (GNOME_CANVAS (view->canvas), x, y);
1293 /* No item is at x, y */
1297 /* ignore our background items */
1298 if (g_list_find (view->bg_item_list, item) != NULL)
1304 /*---------------------------------------------------------------------------*/
1305 /* PRIVATE. Is the object in our current selection? */
1306 /*---------------------------------------------------------------------------*/
1308 object_selected (glViewObject *view_object)
1312 gl_debug (DEBUG_VIEW, "");
1314 g_return_val_if_fail (GL_IS_VIEW_OBJECT (view_object), FALSE);
1316 view = gl_view_object_get_view (view_object);
1317 if (g_list_find (view->selected_object_list, view_object) == NULL) {
1323 /*---------------------------------------------------------------------------*/
1324 /* PRIVATE. Are there multiple objects in our current selection? */
1325 /*---------------------------------------------------------------------------*/
1327 multiple_items_selected (glView * view)
1329 gl_debug (DEBUG_VIEW, "");
1331 g_return_val_if_fail (GL_IS_VIEW (view), FALSE);
1333 if (view->selected_object_list == NULL)
1335 if (view->selected_object_list->next == NULL)
1340 /*****************************************************************************/
1341 /* Item event handler. */
1342 /*****************************************************************************/
1344 gl_view_item_event_handler (GnomeCanvasItem *item,
1346 glViewObject *view_object)
1350 gl_debug (DEBUG_VIEW, "");
1352 view = gl_view_object_get_view(view_object);
1353 switch (view->state) {
1355 case GL_VIEW_STATE_ARROW:
1356 return item_event_arrow_mode (item, event, view_object);
1365 /*---------------------------------------------------------------------------*/
1366 /* PRIVATE. Item event handler (arrow mode) */
1367 /*---------------------------------------------------------------------------*/
1369 item_event_arrow_mode (GnomeCanvasItem *item,
1371 glViewObject *view_object)
1373 static gdouble x, y;
1374 static gboolean dragging = FALSE;
1377 gdouble item_x, item_y;
1378 gdouble new_x, new_y;
1379 gboolean control_key_pressed;
1381 gl_debug (DEBUG_VIEW, "");
1383 item_x = event->button.x;
1384 item_y = event->button.y;
1385 gnome_canvas_item_w2i (item->parent, &item_x, &item_y);
1387 view = gl_view_object_get_view(view_object);
1389 switch (event->type) {
1391 case GDK_BUTTON_PRESS:
1392 gl_debug (DEBUG_VIEW, "BUTTON_PRESS");
1393 control_key_pressed = event->button.state & GDK_CONTROL_MASK;
1394 switch (event->button.button) {
1396 if (control_key_pressed) {
1397 if (object_selected (view_object)) {
1398 /* Un-selecting a selected item */
1399 unselect_object (view_object);
1402 /* Add to current selection */
1403 select_object (view_object);
1406 if (!object_selected (view_object)) {
1407 /* No control, key so remove any selections before adding */
1408 gl_view_unselect_all (view);
1409 /* Add to current selection */
1410 select_object (view_object);
1413 /* Go into dragging mode while button remains pressed. */
1416 cursor = gdk_cursor_new (GDK_FLEUR);
1417 gnome_canvas_item_grab (item,
1418 GDK_POINTER_MOTION_MASK |
1419 GDK_BUTTON_RELEASE_MASK |
1420 GDK_BUTTON_PRESS_MASK,
1421 cursor, event->button.time);
1422 gdk_cursor_unref (cursor);
1427 if (!object_selected (view_object)) {
1428 if (!control_key_pressed) {
1429 /* No control, key so remove any selections before adding */
1430 gl_view_unselect_all (view);
1433 /* Add to current selection */
1434 select_object (view_object);
1435 /* bring up apropriate menu for selection. */
1436 popup_selection_menu (view, view_object, event);
1443 case GDK_BUTTON_RELEASE:
1444 gl_debug (DEBUG_VIEW, "BUTTON_RELEASE");
1445 switch (event->button.button) {
1447 /* Exit dragging mode */
1448 gnome_canvas_item_ungrab (item, event->button.time);
1456 case GDK_MOTION_NOTIFY:
1457 gl_debug (DEBUG_VIEW, "MOTION_NOTIFY");
1458 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
1459 /* Dragging mode, move selection */
1462 move_selected_items (view, (new_x - x), (new_y - y));
1470 case GDK_2BUTTON_PRESS:
1471 gl_debug (DEBUG_VIEW, "2BUTTON_PRESS");
1472 switch (event->button.button) {
1474 /* Also exit dragging mode w/ double-click, run dlg */
1475 gnome_canvas_item_ungrab (item, event->button.time);
1477 select_object (view_object);
1478 gl_view_object_show_dialog (view_object);
1485 case GDK_ENTER_NOTIFY:
1486 gl_debug (DEBUG_VIEW, "ENTER_NOTIFY");
1487 cursor = gdk_cursor_new (GDK_FLEUR);
1488 gdk_window_set_cursor (view->canvas->window, cursor);
1489 gdk_cursor_unref (cursor);
1492 case GDK_LEAVE_NOTIFY:
1493 gl_debug (DEBUG_VIEW, "LEAVE_NOTIFY");
1494 cursor = gdk_cursor_new (GDK_LEFT_PTR);
1495 gdk_window_set_cursor (view->canvas->window, cursor);
1496 gdk_cursor_unref (cursor);
1500 gl_debug (DEBUG_VIEW, "default");
1506 /*---------------------------------------------------------------------------*/
1507 /* PRIVATE. create menu for multiple selections. */
1508 /*---------------------------------------------------------------------------*/
1510 new_selection_menu (glView * view)
1512 GtkWidget *menu, *menuitem;
1514 gl_debug (DEBUG_VIEW, "START");
1516 g_return_val_if_fail (GL_IS_VIEW (view), NULL);
1518 menu = gtk_menu_new ();
1520 menuitem = gtk_menu_item_new_with_label (_("Delete"));
1521 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1522 gtk_widget_show (menuitem);
1523 g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
1524 G_CALLBACK (gl_view_delete_selection), view);
1526 menuitem = gtk_menu_item_new ();
1527 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1528 gtk_widget_show (menuitem);
1530 menuitem = gtk_menu_item_new_with_label (_("Bring to front"));
1531 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1532 gtk_widget_show (menuitem);
1533 g_signal_connect (G_OBJECT (menuitem), "activate",
1534 G_CALLBACK (raise_selection_cb), view);
1536 menuitem = gtk_menu_item_new_with_label (_("Send to back"));
1537 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1538 gtk_widget_show (menuitem);
1539 g_signal_connect (G_OBJECT (menuitem), "activate",
1540 G_CALLBACK (lower_selection_cb), view);
1542 gl_debug (DEBUG_VIEW, "END");
1547 /*---------------------------------------------------------------------------*/
1548 /* PRIVATE. popup menu for given item. */
1549 /*---------------------------------------------------------------------------*/
1551 popup_selection_menu (glView *view,
1552 glViewObject *view_object,
1557 gl_debug (DEBUG_VIEW, "START");
1559 g_return_if_fail (GL_IS_VIEW (view));
1560 g_return_if_fail (GL_IS_VIEW_OBJECT (view_object));
1562 if (multiple_items_selected (view)) {
1563 if (view->menu != NULL) {
1564 gtk_menu_popup (GTK_MENU (view->menu),
1565 NULL, NULL, NULL, NULL,
1566 event->button.button,
1567 event->button.time);
1571 menu = gl_view_object_get_menu (view_object);
1573 gtk_menu_popup (GTK_MENU (menu),
1574 NULL, NULL, NULL, NULL,
1575 event->button.button,
1576 event->button.time);
1581 gl_debug (DEBUG_VIEW, "END");
1584 /*---------------------------------------------------------------------------*/
1585 /* Delete selected objects. */
1586 /*---------------------------------------------------------------------------*/
1588 gl_view_delete_selection (glView * view)
1592 gl_debug (DEBUG_VIEW, "START");
1594 g_return_if_fail (GL_IS_VIEW (view));
1596 for (p = view->selected_object_list; p != NULL; p = p_next) {
1598 g_object_unref (G_OBJECT (p->data));
1601 gl_debug (DEBUG_VIEW, "END");
1604 /*---------------------------------------------------------------------------*/
1605 /* PRIVATE. raise item to front callback. */
1606 /*---------------------------------------------------------------------------*/
1608 raise_selection_cb (GtkWidget * widget,
1613 gl_debug (DEBUG_VIEW, "START");
1615 g_return_if_fail (GL_IS_VIEW (view));
1617 for (p = view->selected_object_list; p != NULL; p = p->next) {
1618 gl_label_object_raise_to_top (GL_LABEL_OBJECT (p->data));
1621 gl_debug (DEBUG_VIEW, "END");
1624 /*---------------------------------------------------------------------------*/
1625 /* PRIVATE. lower item to back callback. */
1626 /*---------------------------------------------------------------------------*/
1628 lower_selection_cb (GtkWidget * widget,
1633 gl_debug (DEBUG_VIEW, "START");
1635 g_return_if_fail (GL_IS_VIEW (view));
1637 for (p = view->selected_object_list; p != NULL; p = p->next) {
1638 gl_label_object_lower_to_bottom (GL_LABEL_OBJECT (p->data));
1641 gl_debug (DEBUG_VIEW, "END");
1644 /*---------------------------------------------------------------------------*/
1645 /* PRIVATE. move selected items */
1646 /*---------------------------------------------------------------------------*/
1648 move_selected_items (glView * view,
1653 glLabelObject *object;
1655 gl_debug (DEBUG_VIEW, "START");
1657 g_return_if_fail (GL_IS_VIEW (view));
1659 for (p = view->selected_object_list; p != NULL; p = p->next) {
1661 object = gl_view_object_get_object(GL_VIEW_OBJECT (p->data));
1662 gl_label_object_set_position_relative (object, dx, dy);
1666 gl_debug (DEBUG_VIEW, "END");
1669 /*---------------------------------------------------------------------------*/
1670 /* PRIVATE. Handle "selection-clear" signal. */
1671 /*---------------------------------------------------------------------------*/
1673 selection_clear_cb (GtkWidget * widget,
1674 GdkEventSelection * event,
1677 glView *view = GL_VIEW (data);
1679 gl_debug (DEBUG_VIEW, "START");
1681 g_return_if_fail (GL_IS_VIEW (view));
1683 view->have_selection = FALSE;
1684 g_object_unref (view->selection_data);
1685 view->selection_data = NULL;
1687 gl_debug (DEBUG_VIEW, "END");
1690 /*---------------------------------------------------------------------------*/
1691 /* PRIVATE. Handle "selection-get" signal. */
1692 /*---------------------------------------------------------------------------*/
1694 selection_get_cb (GtkWidget * widget,
1695 GtkSelectionData * selection_data,
1700 glView *view = GL_VIEW (data);
1702 glXMLLabelStatus status;
1704 gl_debug (DEBUG_VIEW, "START");
1706 g_return_if_fail (GL_IS_VIEW (view));
1708 if (view->have_selection) {
1710 buffer = gl_xml_label_save_buffer (view->selection_data,
1712 gtk_selection_data_set (selection_data,
1713 GDK_SELECTION_TYPE_STRING, 8, buffer,
1718 gl_debug (DEBUG_VIEW, "END");
1721 /*---------------------------------------------------------------------------*/
1722 /* PRIVATE. Handle "selection-received" signal. (Result of Paste) */
1723 /*---------------------------------------------------------------------------*/
1725 selection_received_cb (GtkWidget * widget,
1726 GtkSelectionData * selection_data,
1730 glView *view = GL_VIEW (data);
1731 glLabel *label = NULL;
1732 glXMLLabelStatus status;
1734 glLabelObject *object, *newobject;
1735 glViewObject *view_object;
1737 gl_debug (DEBUG_VIEW, "START");
1739 g_return_if_fail (GL_IS_VIEW (view));
1741 if (selection_data->length < 0) {
1744 if (selection_data->type != GDK_SELECTION_TYPE_STRING) {
1748 gl_view_unselect_all (view);
1750 label = gl_xml_label_open_buffer (selection_data->data, &status);
1751 for (p = label->objects; p != NULL; p = p_next) {
1754 object = (glLabelObject *) p->data;
1755 gl_label_object_set_parent (object, view->label);
1757 gl_debug (DEBUG_VIEW, "object pasted");
1759 if (GL_IS_LABEL_BOX (object)) {
1760 view_object = gl_view_box_new (GL_LABEL_BOX(object),
1762 } else if (GL_IS_LABEL_ELLIPSE (object)) {
1763 view_object = gl_view_ellipse_new (GL_LABEL_ELLIPSE(object),
1765 } else if (GL_IS_LABEL_LINE (object)) {
1766 view_object = gl_view_line_new (GL_LABEL_LINE(object),
1768 } else if (GL_IS_LABEL_IMAGE (object)) {
1769 view_object = gl_view_image_new (GL_LABEL_IMAGE(object),
1771 } else if (GL_IS_LABEL_TEXT (object)) {
1772 view_object = gl_view_text_new (GL_LABEL_TEXT(object),
1774 } else if (GL_IS_LABEL_BARCODE (object)) {
1775 view_object = gl_view_barcode_new (GL_LABEL_BARCODE(object),
1778 /* Should not happen! */
1780 g_warning ("Invalid label object type.");
1782 select_object (view_object);
1784 g_object_unref (label);
1786 gl_debug (DEBUG_VIEW, "END");
1789 /*****************************************************************************/
1790 /* Zoom in one "notch" */
1791 /*****************************************************************************/
1793 gl_view_zoom_in (glView * view)
1796 gdouble dist, dist_min;
1798 gl_debug (DEBUG_VIEW, "START");
1800 g_return_if_fail (GL_IS_VIEW (view));
1802 /* Find index of current scale (or best match) */
1803 i_min = 1; /* start with 2nd largest scale */
1804 dist_min = fabs (scales[1] - view->scale);
1805 for (i = 2; scales[i] != 0.0; i++) {
1806 dist = fabs (scales[i] - view->scale);
1807 if (dist < dist_min) {
1813 /* zoom in one "notch" */
1814 i = MAX (0, i_min - 1);
1815 gl_view_set_zoom (view, scales[i] / HOME_SCALE);
1817 gl_debug (DEBUG_VIEW, "END");
1820 /*****************************************************************************/
1821 /* Zoom out one "notch" */
1822 /*****************************************************************************/
1824 gl_view_zoom_out (glView * view)
1827 gdouble dist, dist_min;
1829 gl_debug (DEBUG_VIEW, "START");
1831 g_return_if_fail (GL_IS_VIEW (view));
1833 /* Find index of current scale (or best match) */
1834 i_min = 0; /* start with largest scale */
1835 dist_min = fabs (scales[0] - view->scale);
1836 for (i = 1; scales[i] != 0.0; i++) {
1837 dist = fabs (scales[i] - view->scale);
1838 if (dist < dist_min) {
1844 /* zoom out one "notch" */
1845 if (scales[i_min] == 0.0)
1848 if (scales[i] == 0.0)
1850 gl_view_set_zoom (view, scales[i] / HOME_SCALE);
1852 gl_debug (DEBUG_VIEW, "END");
1855 /*****************************************************************************/
1856 /* Set current zoom factor to explicit value. */
1857 /*****************************************************************************/
1859 gl_view_set_zoom (glView * view,
1862 gl_debug (DEBUG_VIEW, "START");
1864 g_return_if_fail (GL_IS_VIEW (view));
1865 g_return_if_fail (scale > 0.0);
1867 view->scale = scale * HOME_SCALE;
1868 gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (view->canvas),
1869 scale * HOME_SCALE);
1871 gl_debug (DEBUG_VIEW, "END");
1874 /*****************************************************************************/
1875 /* Get current zoom factor. */
1876 /*****************************************************************************/
1878 gl_view_get_zoom (glView * view)
1880 gl_debug (DEBUG_VIEW, "");
1882 g_return_val_if_fail (GL_IS_VIEW (view), 1.0);
1884 return view->scale / HOME_SCALE;