2 * (GLABELS) Label and Business Card Creation program for GNOME
4 * display.c: GLabels Display 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
24 #include <gtk/gtkinvisible.h>
34 /*===========================================*/
36 /*===========================================*/
38 static GtkContainerClass *parent_class;
40 /* "CLIPBOARD" selection */
41 static GdkAtom clipboard_atom = GDK_NONE;
43 #define HOME_SCALE 2.0
44 static gdouble scales[] = { 8.0, 6.0, 4.0, 3.0,
50 /*===========================================*/
51 /* Local function prototypes */
52 /*===========================================*/
54 static void gl_display_class_init (glDisplayClass * class);
55 static void gl_display_init (glDisplay * display);
56 static void gl_display_destroy (GtkObject * object);
58 static void gl_display_construct (glDisplay * display);
59 static GtkWidget *gl_display_construct_canvas (glDisplay * display);
60 static void gl_display_construct_selection (glDisplay * display);
62 static gdouble get_apropriate_scale (glLabel * label);
64 static void draw_rect_bg (glDisplay * display);
65 static void draw_rounded_rect_bg (glDisplay * display);
66 static void draw_round_bg (glDisplay * display);
67 static void draw_cd_bg (glDisplay * display);
69 static int canvas_event (GnomeCanvas * canvas,
70 GdkEvent * event, gpointer data);
71 static int canvas_event_arrow_mode (GnomeCanvas * canvas,
72 GdkEvent * event, gpointer data);
74 static GnomeCanvasItem *display_item_at (glDisplay * display,
75 gdouble x, gdouble y);
76 static gboolean item_selected (glDisplay * display,
77 GnomeCanvasItem * item);
78 static gboolean multiple_items_selected (glDisplay * display);
80 static int item_event_arrow_mode (GnomeCanvasItem * item,
81 GdkEvent * event, gpointer data);
83 static void popup_selection_menu (glDisplay * display,
84 GnomeCanvasItem * item, GdkEvent * event);
86 static void delete_item_cb (GtkWidget * widget, GnomeCanvasItem * item);
87 static void raise_item_cb (GtkWidget * widget, GnomeCanvasItem * item);
88 static void lower_item_cb (GtkWidget * widget, GnomeCanvasItem * item);
90 static void move_selected_items (glDisplay * display, gdouble dx, gdouble dy);
91 static void move_item (GnomeCanvasItem * item, gdouble dx, gdouble dy);
93 static void delete_selection_cb (GtkWidget * widget, glDisplay * display);
94 static void raise_selection_cb (GtkWidget * widget, glDisplay * display);
95 static void lower_selection_cb (GtkWidget * widget, glDisplay * display);
97 static void selection_clear_cb (GtkWidget * widget,
98 GdkEventSelection * event, gpointer data);
100 static void selection_get_cb (GtkWidget * widget,
101 GtkSelectionData * selection_data, guint info,
102 guint time, gpointer data);
104 static void selection_received_cb (GtkWidget * widget,
105 GtkSelectionData * selection_data,
106 guint time, gpointer data);
108 /****************************************************************************/
109 /* Boilerplate Object stuff. */
110 /****************************************************************************/
112 gl_display_get_type (void)
114 static guint display_type = 0;
117 GtkTypeInfo display_info = {
120 sizeof (glDisplayClass),
121 (GtkClassInitFunc) gl_display_class_init,
122 (GtkObjectInitFunc) gl_display_init,
123 (GtkArgSetFunc) NULL,
124 (GtkArgGetFunc) NULL,
128 gtk_type_unique (gtk_vbox_get_type (), &display_info);
135 gl_display_class_init (glDisplayClass * class)
137 GtkObjectClass *object_class;
138 GtkWidgetClass *widget_class;
140 object_class = (GtkObjectClass *) class;
141 widget_class = (GtkWidgetClass *) class;
143 parent_class = gtk_type_class (gtk_vbox_get_type ());
145 object_class->destroy = gl_display_destroy;
149 gl_display_init (glDisplay * display)
151 display->label = NULL;
155 gl_display_destroy (GtkObject * object)
158 glDisplayClass *class;
160 g_return_if_fail (object != NULL);
161 g_return_if_fail (GL_IS_DISPLAY (object));
163 display = GL_DISPLAY (object);
164 class = GL_DISPLAY_CLASS (GTK_OBJECT (display)->klass);
166 display->label = NULL;
168 GTK_OBJECT_CLASS (parent_class)->destroy (object);
172 gl_display_new (glLabel * label)
174 glDisplay *display = gtk_type_new (gl_display_get_type ());
176 display->label = label;
178 gl_display_construct (display);
180 gl_display_clear_modified (display);
182 return GTK_WIDGET (display);
185 /*---------------------------------------------------------------------------*/
186 /* PRIVATE. Construct composite widget. */
187 /*---------------------------------------------------------------------------*/
189 gl_display_construct (glDisplay * display)
191 GtkWidget *wvbox, *wscroll;
193 g_return_if_fail (GL_IS_DISPLAY (display));
195 wvbox = GTK_WIDGET (display);
197 display->state = GL_DISPLAY_STATE_ARROW;
198 display->item_list = NULL;
200 gl_display_construct_canvas (display);
201 wscroll = gtk_scrolled_window_new (NULL, NULL);
202 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (wscroll),
203 GTK_POLICY_AUTOMATIC,
204 GTK_POLICY_AUTOMATIC);
205 gtk_box_pack_start (GTK_BOX (wvbox), wscroll, TRUE, TRUE, 0);
206 gtk_container_add (GTK_CONTAINER (wscroll), display->canvas);
208 gl_display_construct_selection (display);
210 display->menu = gl_display_new_selection_menu (display);
212 display->modified = FALSE;
215 /*---------------------------------------------------------------------------*/
216 /* PRIVATE. Create canvas w/ a background in the shape of the label/card. */
217 /*---------------------------------------------------------------------------*/
219 gl_display_construct_canvas (glDisplay * display)
222 glLabel *label = display->label;
224 glLabelObject *object;
225 GnomeCanvasItem *item;
227 g_return_val_if_fail (GL_IS_DISPLAY (display), NULL);
228 g_return_val_if_fail (label != NULL, NULL);
231 gtk_widget_push_visual (gdk_rgb_get_visual ());
232 gtk_widget_push_colormap (gdk_rgb_get_cmap ());
233 display->canvas = gnome_canvas_new_aa ();
234 gtk_widget_pop_colormap ();
235 gtk_widget_pop_visual ();
237 gtk_widget_push_visual (gdk_imlib_get_visual ());
238 gtk_widget_push_colormap (gdk_imlib_get_colormap ());
239 display->canvas = gnome_canvas_new ();
240 gtk_widget_pop_colormap ();
241 gtk_widget_pop_visual ();
244 scale = get_apropriate_scale (label);
246 gtk_widget_set_usize (display->canvas,
247 scale * label->width + 40,
248 scale * label->height + 40);
249 gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (display->canvas),
251 display->scale = scale;
253 gnome_canvas_set_scroll_region (GNOME_CANVAS (display->canvas),
254 0.0, 0.0, label->width, label->height);
256 /* Draw background shape of label/card */
257 switch (label->template->style) {
259 case GL_TEMPLATE_STYLE_RECT:
260 if (label->template->label_round == 0.0) {
261 /* Square corners. */
262 draw_rect_bg (display);
264 /* Rounded corners. */
265 draw_rounded_rect_bg (display);
269 case GL_TEMPLATE_STYLE_ROUND:
270 draw_round_bg (display);
273 case GL_TEMPLATE_STYLE_CD:
274 draw_cd_bg (display);
278 WARN ("Unknown template label style");
282 gtk_signal_connect (GTK_OBJECT (display->canvas), "event",
283 GTK_SIGNAL_FUNC (canvas_event), display);
285 for (p_obj = label->objects; p_obj != NULL; p_obj = p_obj->next) {
286 object = (glLabelObject *) p_obj->data;
287 item = gl_item_new (object, display);
288 gl_display_add_item (display, item);
291 return display->canvas;
294 /*---------------------------------------------------------------------------*/
295 /* PRIVATE. Create selection targets. */
296 /*---------------------------------------------------------------------------*/
298 gl_display_construct_selection (glDisplay * display)
300 g_return_if_fail (GL_IS_DISPLAY (display));
302 display->have_selection = FALSE;
303 display->selection_data = NULL;
304 display->invisible = gtk_invisible_new ();
306 display->selected_item_list = NULL;
308 if (!clipboard_atom) {
309 clipboard_atom = gdk_atom_intern ("GLABELS_CLIPBOARD", FALSE);
312 gtk_selection_add_target (display->invisible,
313 clipboard_atom, GDK_SELECTION_TYPE_STRING, 1);
315 gtk_signal_connect (GTK_OBJECT (display->invisible),
316 "selection_clear_event",
317 GTK_SIGNAL_FUNC (selection_clear_cb), display);
319 gtk_signal_connect (GTK_OBJECT (display->invisible), "selection_get",
320 GTK_SIGNAL_FUNC (selection_get_cb), display);
322 gtk_signal_connect (GTK_OBJECT (display->invisible),
323 "selection_received",
324 GTK_SIGNAL_FUNC (selection_received_cb), display);
328 /*---------------------------------------------------------------------------*/
329 /* PRIVATE. Determine an apropriate scale for given label & screen size */
330 /*---------------------------------------------------------------------------*/
332 get_apropriate_scale (glLabel * label)
335 gdouble w_screen, h_screen;
339 g_return_val_if_fail (label != NULL, 1.0);
343 w_screen = (gdouble) gdk_screen_width ();
344 h_screen = (gdouble) gdk_screen_height ();
346 for (i = 0; scales[i] > 0.0; i++) {
348 if (k <= HOME_SCALE) {
349 if ((k * w < (w_screen - 256))
350 && (k * h < (h_screen - 256)))
358 /*---------------------------------------------------------------------------*/
359 /* PRIVATE. Draw simple recangular background. */
360 /*---------------------------------------------------------------------------*/
362 draw_rect_bg (glDisplay * display)
364 glLabel *label = display->label;
365 GnomeCanvasItem *item;
366 GnomeCanvasGroup *group;
369 g_return_if_fail (GL_IS_DISPLAY (display));
370 g_return_if_fail (label != NULL);
372 display->n_bg_items = 0;
373 display->bg_item_list = NULL;
375 group = gnome_canvas_root (GNOME_CANVAS (display->canvas));
377 item = gnome_canvas_item_new (group,
378 gnome_canvas_rect_get_type (),
383 "fill_color", "white",
385 display->n_bg_items++;
386 display->bg_item_list = g_list_append (display->bg_item_list, item);
388 /* Bounding box @ margin */
389 margin = label->template->label_margin;
390 gnome_canvas_item_new (group,
391 gnome_canvas_rect_get_type (),
394 "x2", label->width - margin,
395 "y2", label->height - margin,
397 "outline_color", "light blue",
399 display->n_bg_items++;
400 display->bg_item_list = g_list_append (display->bg_item_list, item);
403 /*---------------------------------------------------------------------------*/
404 /* PRIVATE. Draw rounded recangular background. */
405 /*---------------------------------------------------------------------------*/
407 draw_rounded_rect_bg (glDisplay * display)
409 glLabel *label = display->label;
410 GnomeCanvasPoints *points;
411 gint i_coords, i_theta;
413 GnomeCanvasItem *item;
414 GnomeCanvasGroup *group;
416 g_return_if_fail (GL_IS_DISPLAY (display));
417 g_return_if_fail (label != NULL);
419 group = gnome_canvas_root (GNOME_CANVAS (display->canvas));
421 display->n_bg_items = 0;
422 display->bg_item_list = NULL;
424 r = label->template->label_round;
427 m = label->template->label_margin;
429 points = gnome_canvas_points_new (4 * (1 + 90 / 5));
431 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
432 points->coords[i_coords++] =
433 r - r * sin (i_theta * M_PI / 180.0);
434 points->coords[i_coords++] =
435 r - r * cos (i_theta * M_PI / 180.0);
437 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
438 points->coords[i_coords++] =
439 r - r * cos (i_theta * M_PI / 180.0);
440 points->coords[i_coords++] =
441 (h - r) + r * sin (i_theta * M_PI / 180.0);
443 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
444 points->coords[i_coords++] =
445 (w - r) + r * sin (i_theta * M_PI / 180.0);
446 points->coords[i_coords++] =
447 (h - r) + r * cos (i_theta * M_PI / 180.0);
449 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
450 points->coords[i_coords++] =
451 (w - r) + r * cos (i_theta * M_PI / 180.0);
452 points->coords[i_coords++] =
453 r - r * sin (i_theta * M_PI / 180.0);
455 item = gnome_canvas_item_new (group,
456 gnome_canvas_polygon_get_type (),
458 "fill_color", "white",
460 gnome_canvas_points_free (points);
461 display->n_bg_items++;
462 display->bg_item_list = g_list_append (display->bg_item_list, item);
464 /* Bounding box @ margin */
465 if (label->template->label_margin >= label->template->label_round) {
466 /* simple rectangle */
467 item = gnome_canvas_item_new (group,
468 gnome_canvas_rect_get_type (),
474 "outline_color", "light blue",
476 display->n_bg_items++;
477 display->bg_item_list =
478 g_list_append (display->bg_item_list, item);
480 r = label->template->label_round - m;
481 w = label->width - 2 * label->template->label_margin;
482 h = label->height - 2 * label->template->label_margin;
484 /* rectangle with rounded corners */
485 points = gnome_canvas_points_new (4 * (1 + 90 / 5));
487 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
488 points->coords[i_coords++] =
489 m + r - r * sin (i_theta * M_PI / 180.0);
490 points->coords[i_coords++] =
491 m + r - r * cos (i_theta * M_PI / 180.0);
493 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
494 points->coords[i_coords++] =
495 m + r - r * cos (i_theta * M_PI / 180.0);
496 points->coords[i_coords++] =
497 m + (h - r) + r * sin (i_theta * M_PI / 180.0);
499 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
500 points->coords[i_coords++] =
501 m + (w - r) + r * sin (i_theta * M_PI / 180.0);
502 points->coords[i_coords++] =
503 m + (h - r) + r * cos (i_theta * M_PI / 180.0);
505 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
506 points->coords[i_coords++] =
507 m + (w - r) + r * cos (i_theta * M_PI / 180.0);
508 points->coords[i_coords++] =
509 m + r - r * sin (i_theta * M_PI / 180.0);
511 item = gnome_canvas_item_new (group,
512 gnome_canvas_polygon_get_type (),
515 "outline_color", "light blue",
517 gnome_canvas_points_free (points);
518 display->n_bg_items++;
519 display->bg_item_list =
520 g_list_append (display->bg_item_list, item);
524 /*---------------------------------------------------------------------------*/
525 /* PRIVATE. Draw round background. */
526 /*---------------------------------------------------------------------------*/
528 draw_round_bg (glDisplay * display)
530 glLabel *label = display->label;
531 GnomeCanvasPoints *points;
532 gint i_coords, i_theta;
534 GnomeCanvasItem *item;
535 GnomeCanvasGroup *group;
537 g_return_if_fail (GL_IS_DISPLAY (display));
538 g_return_if_fail (label != NULL);
540 group = gnome_canvas_root (GNOME_CANVAS (display->canvas));
542 display->n_bg_items = 0;
543 display->bg_item_list = NULL;
545 r1 = label->template->label_radius;
546 points = gnome_canvas_points_new (1 + 360/2);
548 for (i_theta = 0; i_theta <= 360; i_theta += 2) {
549 points->coords[i_coords++] =
550 r1 - r1 * sin (i_theta * M_PI / 180.0);
551 points->coords[i_coords++] =
552 r1 - r1 * cos (i_theta * M_PI / 180.0);
554 item = gnome_canvas_item_new (group,
555 gnome_canvas_polygon_get_type (),
557 "fill_color", "white",
559 gnome_canvas_points_free (points);
560 display->n_bg_items++;
561 display->bg_item_list = g_list_append (display->bg_item_list, item);
563 /* Bounding box @ margin */
564 r = label->template->label_radius - label->template->label_margin;
565 points = gnome_canvas_points_new (360 / 2);
567 for (i_theta = 0; i_theta < 360; i_theta += 2) {
568 points->coords[i_coords++] =
569 r1 - r * sin (i_theta * M_PI / 180.0);
570 points->coords[i_coords++] =
571 r1 - r * cos (i_theta * M_PI / 180.0);
573 item = gnome_canvas_item_new (group,
574 gnome_canvas_polygon_get_type (),
577 "outline_color", "light blue", NULL);
578 gnome_canvas_points_free (points);
579 display->n_bg_items++;
580 display->bg_item_list = g_list_append (display->bg_item_list, item);
583 /*---------------------------------------------------------------------------*/
584 /* PRIVATE. Draw CD style background, circular w/ concentric hole. */
585 /*---------------------------------------------------------------------------*/
587 draw_cd_bg (glDisplay * display)
589 glLabel *label = display->label;
590 GnomeCanvasPoints *points;
591 gint i_coords, i_theta;
593 GnomeCanvasItem *item;
594 GnomeCanvasGroup *group;
596 g_return_if_fail (GL_IS_DISPLAY (display));
597 g_return_if_fail (label != NULL);
599 group = gnome_canvas_root (GNOME_CANVAS (display->canvas));
601 display->n_bg_items = 0;
602 display->bg_item_list = NULL;
604 r1 = label->template->label_radius;
605 r2 = label->template->label_hole;
606 points = gnome_canvas_points_new (2 * (1 + 360 / 2));
608 for (i_theta = 0; i_theta <= 360; i_theta += 2) {
609 points->coords[i_coords++] =
610 r1 - r1 * sin (i_theta * M_PI / 180.0);
611 points->coords[i_coords++] =
612 r1 - r1 * cos (i_theta * M_PI / 180.0);
614 for (i_theta = 0; i_theta <= 360; i_theta += 2) {
615 points->coords[i_coords++] =
616 r1 - r2 * sin (i_theta * M_PI / 180.0);
617 points->coords[i_coords++] =
618 r1 - r2 * cos (i_theta * M_PI / 180.0);
620 item = gnome_canvas_item_new (group,
621 gnome_canvas_polygon_get_type (),
623 "fill_color", "white",
625 gnome_canvas_points_free (points);
626 display->n_bg_items++;
627 display->bg_item_list = g_list_append (display->bg_item_list, item);
629 /* Bounding box @ margin */
631 r = label->template->label_radius - label->template->label_margin;
632 points = gnome_canvas_points_new (360 / 2);
634 for (i_theta = 0; i_theta < 360; i_theta += 2) {
635 points->coords[i_coords++] =
636 r1 - r * sin (i_theta * M_PI / 180.0);
637 points->coords[i_coords++] =
638 r1 - r * cos (i_theta * M_PI / 180.0);
640 item = gnome_canvas_item_new (group,
641 gnome_canvas_polygon_get_type (),
644 "outline_color", "light blue", NULL);
645 gnome_canvas_points_free (points);
646 display->n_bg_items++;
647 display->bg_item_list = g_list_append (display->bg_item_list, item);
650 r = label->template->label_hole + label->template->label_margin;
651 points = gnome_canvas_points_new (360 / 2);
653 for (i_theta = 0; i_theta < 360; i_theta += 2) {
654 points->coords[i_coords++] =
655 r1 - r * sin (i_theta * M_PI / 180.0);
656 points->coords[i_coords++] =
657 r1 - r * cos (i_theta * M_PI / 180.0);
659 item = gnome_canvas_item_new (group,
660 gnome_canvas_polygon_get_type (),
663 "outline_color", "light blue",
665 gnome_canvas_points_free (points);
666 display->n_bg_items++;
667 display->bg_item_list = g_list_append (display->bg_item_list, item);
670 /*****************************************************************************/
671 /* Set arrow mode. */
672 /*****************************************************************************/
674 gl_display_arrow_mode (glDisplay * display)
676 static GdkCursor *cursor = NULL;
678 g_return_if_fail (GL_IS_DISPLAY (display));
681 cursor = gdk_cursor_new (GDK_LEFT_PTR);
684 gdk_window_set_cursor (display->canvas->window, cursor);
686 display->state = GL_DISPLAY_STATE_ARROW;
689 /*****************************************************************************/
690 /* Set create text object mode. */
691 /*****************************************************************************/
693 gl_display_object_create_mode (glDisplay * display,
694 glLabelObjectType type)
698 g_return_if_fail (GL_IS_DISPLAY (display));
700 cursor = gl_item_get_create_cursor (type);
701 gdk_window_set_cursor (display->canvas->window, cursor);
703 display->state = GL_DISPLAY_STATE_OBJECT_CREATE;
704 display->create_type = type;
707 /*****************************************************************************/
708 /* Add canvas item to list of display items. */
709 /*****************************************************************************/
711 gl_display_add_item (glDisplay * display,
712 GnomeCanvasItem * item)
714 g_return_if_fail (GL_IS_DISPLAY (display));
716 display->item_list = g_list_prepend (display->item_list, item);
719 /*****************************************************************************/
720 /* Select all items. */
721 /*****************************************************************************/
723 gl_display_select_all (glDisplay * display)
727 g_return_if_fail (GL_IS_DISPLAY (display));
729 gl_display_unselect_all (display);
731 for (p = display->item_list; p != NULL; p = p->next) {
732 gl_display_select_item (display, GNOME_CANVAS_ITEM (p->data));
736 /*****************************************************************************/
737 /* Select all items within given rectangular region */
738 /*****************************************************************************/
740 gl_display_select_region (glDisplay * display,
747 GnomeCanvasItem *item;
748 gdouble i_x1, i_y1, i_x2, i_y2;
750 g_return_if_fail (GL_IS_DISPLAY (display));
751 g_return_if_fail ((x1 <= x2) && (y1 <= y2));
753 for (p = display->item_list; p != NULL; p = p->next) {
754 item = GNOME_CANVAS_ITEM (p->data);
755 if (!item_selected (display, item)) {
757 gl_item_get_bounds (item, &i_x1, &i_y1, &i_x2, &i_y2);
758 if ((i_x1 >= x1) && (i_x2 <= x2) && (i_y1 >= y1)
760 gl_display_select_item (display, item);
767 /*****************************************************************************/
768 /* Remove all selections */
769 /*****************************************************************************/
771 gl_display_unselect_all (glDisplay * display)
775 g_return_if_fail (GL_IS_DISPLAY (display));
777 for (p = display->selected_item_list; p != NULL; p = p_next) {
779 gl_display_unselect_item (display, GNOME_CANVAS_ITEM (p->data));
783 /*****************************************************************************/
784 /* Select an item. */
785 /*****************************************************************************/
787 gl_display_select_item (glDisplay * display,
788 GnomeCanvasItem * item)
790 g_return_if_fail (GL_IS_DISPLAY (display));
791 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
793 if (!item_selected (display, item)) {
794 display->selected_item_list =
795 g_list_prepend (display->selected_item_list, item);
797 gl_item_highlight (item);
798 gtk_widget_grab_focus (GTK_WIDGET (display->canvas));
801 /*****************************************************************************/
802 /* Un-select items. */
803 /*****************************************************************************/
805 gl_display_unselect_item (glDisplay * display,
806 GnomeCanvasItem * item)
808 g_return_if_fail (GL_IS_DISPLAY (display));
809 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
811 gl_item_unhighlight (item);
813 display->selected_item_list =
814 g_list_remove (display->selected_item_list, item);
817 /*****************************************************************************/
818 /* Has display been modified? */
819 /*****************************************************************************/
821 gl_display_modified (glDisplay * display)
823 g_return_val_if_fail (GL_IS_DISPLAY (display), FALSE);
825 return display->modified;
828 /*****************************************************************************/
829 /* Set to modified state. */
830 /*****************************************************************************/
832 gl_display_set_modified (glDisplay * display)
834 g_return_if_fail (GL_IS_DISPLAY (display));
836 display->modified = TRUE;
839 /*****************************************************************************/
840 /* Reset to un-modified state. */
841 /*****************************************************************************/
843 gl_display_clear_modified (glDisplay * display)
845 g_return_if_fail (GL_IS_DISPLAY (display));
847 display->modified = FALSE;
850 /*****************************************************************************/
851 /* "Cut" selected items and place in clipboard selections. */
852 /*****************************************************************************/
854 gl_display_cut (glDisplay * display)
856 g_return_if_fail (GL_IS_DISPLAY (display));
858 gl_display_copy (display);
859 delete_selection_cb (GTK_WIDGET (display), display);
862 /*****************************************************************************/
863 /* "Copy" selected items to clipboard selections. */
864 /*****************************************************************************/
866 gl_display_copy (glDisplay * display)
869 GnomeCanvasItem *item;
870 glLabelObject *object;
872 g_return_if_fail (GL_IS_DISPLAY (display));
874 if (display->selected_item_list) {
876 gl_label_free (&display->selection_data);
877 display->selection_data =
878 gl_label_new_with_template (display->label->
880 display->label->rotate_flag);
882 for (p = display->selected_item_list; p != NULL; p = p->next) {
884 item = GNOME_CANVAS_ITEM (p->data);
885 object = gl_item_get_object (item);
886 gl_label_object_new_from_object (display->
892 gtk_selection_owner_set (display->invisible,
893 clipboard_atom, GDK_CURRENT_TIME);
894 display->have_selection = TRUE;
899 /*****************************************************************************/
900 /* "Paste" from private clipboard selection. */
901 /*****************************************************************************/
903 gl_display_paste (glDisplay * display)
905 g_return_if_fail (GL_IS_DISPLAY (display));
907 gtk_selection_convert (GTK_WIDGET (display->invisible),
908 clipboard_atom, GDK_SELECTION_TYPE_STRING,
912 /*---------------------------------------------------------------------------*/
913 /* PRIVATE. Canvas event handler. */
914 /*---------------------------------------------------------------------------*/
916 canvas_event (GnomeCanvas * canvas,
920 glDisplay *display = GL_DISPLAY (data);
922 switch (display->state) {
924 case GL_DISPLAY_STATE_ARROW:
925 return canvas_event_arrow_mode (canvas, event, data);
927 case GL_DISPLAY_STATE_OBJECT_CREATE:
928 return gl_item_create_event_handler (canvas, event, data);
931 WARN ("Invalid display state."); /* Should not happen! */
938 /*---------------------------------------------------------------------------*/
939 /* PRIVATE. Canvas event handler (arrow mode) */
940 /*---------------------------------------------------------------------------*/
942 canvas_event_arrow_mode (GnomeCanvas * canvas,
946 static gdouble x0, y0;
947 static gboolean dragging = FALSE;
948 static GnomeCanvasItem *item;
949 glDisplay *display = GL_DISPLAY (data);
950 gdouble x, y, x1, y1, x2, y2;
951 GnomeCanvasGroup *group;
954 switch (event->type) {
956 case GDK_BUTTON_PRESS:
957 switch (event->button.button) {
959 gnome_canvas_window_to_world (canvas,
961 event->button.y, &x, &y);
963 if (display_item_at (display, x, y) == NULL) {
964 if (!(event->button.state & GDK_CONTROL_MASK)) {
965 gl_display_unselect_all (display);
969 gdk_pointer_grab (GTK_WIDGET (display->canvas)->
971 GDK_POINTER_MOTION_MASK |
972 GDK_BUTTON_RELEASE_MASK |
973 GDK_BUTTON_PRESS_MASK, NULL,
974 NULL, event->button.time);
976 gnome_canvas_root (GNOME_CANVAS
979 gnome_canvas_item_new (group,
980 gnome_canvas_rect_get_type (),
984 "outline_color_rgba",
998 case GDK_BUTTON_RELEASE:
999 switch (event->button.button) {
1003 gdk_pointer_ungrab (event->button.time);
1004 gnome_canvas_window_to_world (canvas,
1012 gl_display_select_region (display, x1, y1, x2,
1014 gtk_object_destroy (GTK_OBJECT (item));
1023 case GDK_MOTION_NOTIFY:
1024 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
1025 gnome_canvas_window_to_world (canvas,
1027 event->motion.y, &x, &y);
1029 gnome_canvas_item_set (item,
1033 "y2", MAX (y, y0), NULL);
1041 switch (event->key.keyval) {
1044 move_selected_items (display,
1045 -1.0 / (display->scale),
1050 move_selected_items (display, 0.0,
1051 -1.0 / (display->scale));
1055 move_selected_items (display,
1056 1.0 / (display->scale),
1061 move_selected_items (display, 0.0,
1062 1.0 / (display->scale));
1066 delete_selection_cb (GTK_WIDGET (canvas),
1068 cursor = gdk_cursor_new (GDK_LEFT_PTR);
1069 gdk_window_set_cursor (display->canvas->window,
1071 gdk_cursor_destroy (cursor);
1077 return TRUE; /* We handled this or we were dragging. */
1085 /*****************************************************************************/
1086 /* Item event handler. */
1087 /*****************************************************************************/
1089 gl_display_item_event_handler (GnomeCanvasItem * item,
1093 glDisplay *display = GL_DISPLAY (data);
1095 switch (display->state) {
1097 case GL_DISPLAY_STATE_ARROW:
1098 return item_event_arrow_mode (item, event, data);
1107 /*---------------------------------------------------------------------------*/
1108 /* PRIVATE. Item event handler (arrow mode) */
1109 /*---------------------------------------------------------------------------*/
1111 item_event_arrow_mode (GnomeCanvasItem * item,
1115 glDisplay *display = GL_DISPLAY (data);
1116 static gdouble x, y;
1117 static gboolean dragging = FALSE;
1119 gdouble item_x, item_y;
1120 gdouble new_x, new_y;
1121 gboolean control_key_pressed;
1123 item_x = event->button.x;
1124 item_y = event->button.y;
1125 gnome_canvas_item_w2i (item->parent, &item_x, &item_y);
1127 switch (event->type) {
1129 case GDK_BUTTON_PRESS:
1130 control_key_pressed = event->button.state & GDK_CONTROL_MASK;
1131 switch (event->button.button) {
1133 if (control_key_pressed) {
1134 if (item_selected (display, item)) {
1135 /* Un-selecting an already selected item */
1136 gl_display_unselect_item (display,
1140 /* Add to current selection */
1141 gl_display_select_item (display, item);
1144 if (!item_selected (display, item)) {
1145 /* No control, key so remove any selections before adding */
1146 gl_display_unselect_all (display);
1147 /* Add to current selection */
1148 gl_display_select_item (display, item);
1151 /* Go into dragging mode while button remains pressed. */
1154 cursor = gdk_cursor_new (GDK_FLEUR);
1155 gnome_canvas_item_grab (item,
1156 GDK_POINTER_MOTION_MASK |
1157 GDK_BUTTON_RELEASE_MASK |
1158 GDK_BUTTON_PRESS_MASK,
1159 cursor, event->button.time);
1160 gdk_cursor_destroy (cursor);
1165 if (!item_selected (display, item)) {
1166 if (!control_key_pressed) {
1167 /* No control, key so remove any selections before adding */
1168 gl_display_unselect_all (display);
1171 /* Add to current selection */
1172 gl_display_select_item (display, item);
1173 /* bring up apropriate menu for selection. */
1174 popup_selection_menu (display, item, event);
1181 case GDK_BUTTON_RELEASE:
1182 switch (event->button.button) {
1184 /* Exit dragging mode */
1185 gnome_canvas_item_ungrab (item, event->button.time);
1193 case GDK_MOTION_NOTIFY:
1194 if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
1195 /* Dragging mode, move selection */
1198 move_selected_items (display, (new_x - x), (new_y - y));
1206 case GDK_2BUTTON_PRESS:
1207 switch (event->button.button) {
1209 /* Also exit dragging mode on a a double-click, bring up menu */
1210 gnome_canvas_item_ungrab (item, event->button.time);
1212 gl_display_select_item (display, item);
1213 gl_item_edit_dialog (item);
1220 case GDK_ENTER_NOTIFY:
1221 cursor = gdk_cursor_new (GDK_FLEUR);
1222 gdk_window_set_cursor (display->canvas->window, cursor);
1223 gdk_cursor_destroy (cursor);
1226 case GDK_LEAVE_NOTIFY:
1227 cursor = gdk_cursor_new (GDK_LEFT_PTR);
1228 gdk_window_set_cursor (display->canvas->window, cursor);
1229 gdk_cursor_destroy (cursor);
1238 /*****************************************************************************/
1239 /* create menu for multiple selections. */
1240 /*****************************************************************************/
1242 gl_display_new_selection_menu (glDisplay * display)
1244 GtkWidget *menu, *menuitem;
1246 g_return_val_if_fail (GL_IS_DISPLAY (display), NULL);
1248 menu = gtk_menu_new ();
1250 menuitem = gtk_menu_item_new_with_label (_("Delete"));
1251 gtk_menu_append (GTK_MENU (menu), menuitem);
1252 gtk_widget_show (menuitem);
1253 gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
1254 GTK_SIGNAL_FUNC (delete_selection_cb), display);
1256 menuitem = gtk_menu_item_new ();
1257 gtk_menu_append (GTK_MENU (menu), menuitem);
1258 gtk_widget_show (menuitem);
1260 menuitem = gtk_menu_item_new_with_label (_("Bring to front"));
1261 gtk_menu_append (GTK_MENU (menu), menuitem);
1262 gtk_widget_show (menuitem);
1263 gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
1264 GTK_SIGNAL_FUNC (raise_selection_cb), display);
1266 menuitem = gtk_menu_item_new_with_label (_("Send to back"));
1267 gtk_menu_append (GTK_MENU (menu), menuitem);
1268 gtk_widget_show (menuitem);
1269 gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
1270 GTK_SIGNAL_FUNC (lower_selection_cb), display);
1275 /*****************************************************************************/
1276 /* create menu for given item. */
1277 /*****************************************************************************/
1279 gl_display_new_item_menu (GnomeCanvasItem * item)
1281 GtkWidget *menu, *menuitem;
1283 g_return_val_if_fail (GNOME_IS_CANVAS_ITEM (item), NULL);
1285 menu = gtk_menu_new ();
1287 menuitem = gtk_menu_item_new_with_label (_("Edit properties..."));
1288 gtk_menu_append (GTK_MENU (menu), menuitem);
1289 gtk_widget_show (menuitem);
1290 gtk_signal_connect_object (GTK_OBJECT (menuitem), "activate",
1291 GTK_SIGNAL_FUNC (gl_item_edit_dialog),
1294 menuitem = gtk_menu_item_new ();
1295 gtk_menu_append (GTK_MENU (menu), menuitem);
1296 gtk_widget_show (menuitem);
1298 menuitem = gtk_menu_item_new_with_label (_("Delete"));
1299 gtk_menu_append (GTK_MENU (menu), menuitem);
1300 gtk_widget_show (menuitem);
1301 gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
1302 GTK_SIGNAL_FUNC (delete_item_cb), item);
1304 menuitem = gtk_menu_item_new ();
1305 gtk_menu_append (GTK_MENU (menu), menuitem);
1306 gtk_widget_show (menuitem);
1308 menuitem = gtk_menu_item_new_with_label (_("Bring to front"));
1309 gtk_menu_append (GTK_MENU (menu), menuitem);
1310 gtk_widget_show (menuitem);
1311 gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
1312 GTK_SIGNAL_FUNC (raise_item_cb), item);
1314 menuitem = gtk_menu_item_new_with_label (_("Send to back"));
1315 gtk_menu_append (GTK_MENU (menu), menuitem);
1316 gtk_widget_show (menuitem);
1317 gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
1318 GTK_SIGNAL_FUNC (lower_item_cb), item);
1320 gtk_object_set_data (GTK_OBJECT (item), "object_menu", menu);
1325 /*---------------------------------------------------------------------------*/
1326 /* PRIVATE. popup menu for given item. */
1327 /*---------------------------------------------------------------------------*/
1329 popup_selection_menu (glDisplay * display,
1330 GnomeCanvasItem * item,
1335 g_return_if_fail (GL_IS_DISPLAY (display));
1336 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
1338 if (multiple_items_selected (display)) {
1339 if (display->menu != NULL) {
1340 gtk_menu_popup (GTK_MENU (display->menu),
1341 NULL, NULL, NULL, NULL,
1342 event->button.button,
1343 event->button.time);
1347 menu = gl_item_get_menu (item);
1349 gtk_menu_popup (GTK_MENU (menu),
1350 NULL, NULL, NULL, NULL,
1351 event->button.button,
1352 event->button.time);
1359 /*---------------------------------------------------------------------------*/
1360 /* PRIVATE. delete selection callback. */
1361 /*---------------------------------------------------------------------------*/
1363 delete_selection_cb (GtkWidget * widget,
1364 glDisplay * display)
1368 g_return_if_fail (GL_IS_DISPLAY (display));
1370 for (p = display->selected_item_list; p != NULL; p = p_next) {
1372 delete_item_cb (widget, GNOME_CANVAS_ITEM (p->data));
1376 /*---------------------------------------------------------------------------*/
1377 /* PRIVATE. raise item to front callback. */
1378 /*---------------------------------------------------------------------------*/
1380 raise_selection_cb (GtkWidget * widget,
1381 glDisplay * display)
1385 g_return_if_fail (GL_IS_DISPLAY (display));
1387 for (p = display->selected_item_list; p != NULL; p = p->next) {
1388 raise_item_cb (widget, GNOME_CANVAS_ITEM (p->data));
1392 /*---------------------------------------------------------------------------*/
1393 /* PRIVATE. lower item to back callback. */
1394 /*---------------------------------------------------------------------------*/
1396 lower_selection_cb (GtkWidget * widget,
1397 glDisplay * display)
1401 g_return_if_fail (GL_IS_DISPLAY (display));
1403 for (p = display->selected_item_list; p != NULL; p = p->next) {
1404 lower_item_cb (widget, GNOME_CANVAS_ITEM (p->data));
1408 /*---------------------------------------------------------------------------*/
1409 /* PRIVATE. delete item callback. */
1410 /*---------------------------------------------------------------------------*/
1412 delete_item_cb (GtkWidget * widget,
1413 GnomeCanvasItem * item)
1417 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
1419 display = gl_item_get_display (item);
1421 gl_display_unselect_item (display, item);
1422 display->item_list = g_list_remove (display->item_list, item);
1424 gl_item_free (&item);
1426 gl_display_set_modified (display);
1429 /*---------------------------------------------------------------------------*/
1430 /* PRIVATE. raise item to front callback. */
1431 /*---------------------------------------------------------------------------*/
1433 raise_item_cb (GtkWidget * widget,
1434 GnomeCanvasItem * item)
1436 glLabelObject *object;
1438 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
1440 object = gl_item_get_object (item);
1441 gl_label_object_raise_to_front (object);
1443 gnome_canvas_item_raise_to_top (item);
1446 /*---------------------------------------------------------------------------*/
1447 /* PRIVATE. lower item to back callback. */
1448 /*---------------------------------------------------------------------------*/
1450 lower_item_cb (GtkWidget * widget,
1451 GnomeCanvasItem * item)
1453 glLabelObject *object;
1456 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
1458 object = gl_item_get_object (item);
1459 display = gl_item_get_display (item);
1461 gl_label_object_lower_to_back (object);
1463 /* Send to bottom */
1464 gnome_canvas_item_lower_to_bottom (item);
1466 /* now raise it above all items that form the backgound */
1467 gnome_canvas_item_raise (item, display->n_bg_items);
1470 /*---------------------------------------------------------------------------*/
1471 /* PRIVATE. move selected items */
1472 /*---------------------------------------------------------------------------*/
1474 move_selected_items (glDisplay * display,
1479 GnomeCanvasItem *item;
1481 g_return_if_fail (GL_IS_DISPLAY (display));
1483 for (p = display->selected_item_list; p != NULL; p = p->next) {
1485 item = GNOME_CANVAS_ITEM (p->data);
1487 move_item (item, dx, dy);
1488 gl_item_highlight (item);
1494 /*---------------------------------------------------------------------------*/
1495 /* PRIVATE. move item/object */
1496 /*---------------------------------------------------------------------------*/
1498 move_item (GnomeCanvasItem * item,
1502 glLabelObject *object;
1505 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
1507 object = gl_item_get_object (item);
1512 gnome_canvas_item_move (item, dx, dy);
1514 display = gl_item_get_display (item);
1515 gl_display_set_modified (display);
1518 /*---------------------------------------------------------------------------*/
1519 /* PRIVATE. Return item at (x,y) if it is in our list of managed items. */
1520 /*---------------------------------------------------------------------------*/
1521 static GnomeCanvasItem *
1522 display_item_at (glDisplay * display,
1526 GnomeCanvasItem *item;
1528 g_return_val_if_fail (GL_IS_DISPLAY (display), NULL);
1530 item = gnome_canvas_get_item_at (GNOME_CANVAS (display->canvas), x, y);
1532 /* No item is at x, y */
1536 /* Don't include our background items */
1537 if (g_list_find (display->bg_item_list, item) != NULL)
1543 /*---------------------------------------------------------------------------*/
1544 /* PRIVATE. Is the item in our current selection? */
1545 /*---------------------------------------------------------------------------*/
1547 item_selected (glDisplay * display,
1548 GnomeCanvasItem * item)
1550 g_return_val_if_fail (GL_IS_DISPLAY (display), FALSE);
1551 g_return_val_if_fail (GNOME_IS_CANVAS_ITEM (item), FALSE);
1553 if (g_list_find (display->selected_item_list, item) == NULL) {
1559 /*---------------------------------------------------------------------------*/
1560 /* PRIVATE. Are there multiple items in our current selection? */
1561 /*---------------------------------------------------------------------------*/
1563 multiple_items_selected (glDisplay * display)
1565 g_return_val_if_fail (GL_IS_DISPLAY (display), FALSE);
1567 if (display->selected_item_list == NULL)
1569 if (display->selected_item_list->next == NULL)
1574 /*---------------------------------------------------------------------------*/
1575 /* PRIVATE. Handle "selection-clear" signal. */
1576 /*---------------------------------------------------------------------------*/
1578 selection_clear_cb (GtkWidget * widget,
1579 GdkEventSelection * event,
1582 glDisplay *display = GL_DISPLAY (data);
1584 g_return_if_fail (GL_IS_DISPLAY (display));
1586 display->have_selection = FALSE;
1587 gl_label_free (&display->selection_data);
1588 display->selection_data = NULL;
1591 /*---------------------------------------------------------------------------*/
1592 /* PRIVATE. Handle "selection-get" signal. */
1593 /*---------------------------------------------------------------------------*/
1595 selection_get_cb (GtkWidget * widget,
1596 GtkSelectionData * selection_data,
1601 glDisplay *display = GL_DISPLAY (data);
1604 g_return_if_fail (GL_IS_DISPLAY (display));
1606 if (display->have_selection) {
1608 gl_label_save_xml_buffer (display->selection_data, &buffer);
1609 gtk_selection_data_set (selection_data,
1610 GDK_SELECTION_TYPE_STRING, 8, buffer,
1616 /*---------------------------------------------------------------------------*/
1617 /* PRIVATE. Handle "selection-received" signal. (Result of Paste) */
1618 /*---------------------------------------------------------------------------*/
1620 selection_received_cb (GtkWidget * widget,
1621 GtkSelectionData * selection_data,
1625 glDisplay *display = GL_DISPLAY (data);
1626 glLabel *label = NULL;
1628 glLabelObject *object, *newobject;
1629 GnomeCanvasItem *item;
1631 g_return_if_fail (GL_IS_DISPLAY (display));
1633 if (selection_data->length < 0) {
1636 if (selection_data->type != GDK_SELECTION_TYPE_STRING) {
1640 gl_display_unselect_all (display);
1642 gl_label_open_xml_buffer (&label, selection_data->data);
1643 for (p = label->objects; p != NULL; p = p->next) {
1644 object = (glLabelObject *) p->data;
1646 gl_label_object_new_from_object (display->label, object);
1647 item = gl_item_new (newobject, display);
1648 gl_display_add_item (display, item);
1649 gl_display_select_item (display, item);
1651 gl_label_free (&label);
1653 gl_display_set_modified (display);
1656 /*****************************************************************************/
1657 /* Zoom in one "notch" */
1658 /*****************************************************************************/
1660 gl_display_zoom_in (glDisplay * display)
1663 gdouble dist, dist_min;
1665 g_return_if_fail (GL_IS_DISPLAY (display));
1667 /* Find index of current scale (or best match) */
1668 i_min = 1; /* start with 2nd largest scale */
1669 dist_min = fabs (scales[1] - display->scale);
1670 for (i = 2; scales[i] != 0.0; i++) {
1671 dist = fabs (scales[i] - display->scale);
1672 if (dist < dist_min) {
1678 /* zoom in one "notch" */
1679 i = MAX (0, i_min - 1);
1680 gl_display_set_zoom (display, scales[i] / HOME_SCALE);
1683 /*****************************************************************************/
1684 /* Zoom out one "notch" */
1685 /*****************************************************************************/
1687 gl_display_zoom_out (glDisplay * display)
1690 gdouble dist, dist_min;
1692 g_return_if_fail (GL_IS_DISPLAY (display));
1694 /* Find index of current scale (or best match) */
1695 i_min = 0; /* start with largest scale */
1696 dist_min = fabs (scales[0] - display->scale);
1697 for (i = 1; scales[i] != 0.0; i++) {
1698 dist = fabs (scales[i] - display->scale);
1699 if (dist < dist_min) {
1705 /* zoom out one "notch" */
1706 if (scales[i_min] == 0.0)
1709 if (scales[i] == 0.0)
1711 gl_display_set_zoom (display, scales[i] / HOME_SCALE);
1715 /*****************************************************************************/
1716 /* Set current zoom factor to explicit value. */
1717 /*****************************************************************************/
1719 gl_display_set_zoom (glDisplay * display,
1722 g_return_if_fail (GL_IS_DISPLAY (display));
1723 g_return_if_fail (scale > 0.0);
1725 display->scale = scale * HOME_SCALE;
1726 gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (display->canvas),
1727 scale * HOME_SCALE);
1730 /*****************************************************************************/
1731 /* Get current zoom factor. */
1732 /*****************************************************************************/
1734 gl_display_get_zoom (glDisplay * display)
1736 g_return_val_if_fail (GL_IS_DISPLAY (display), 1.0);
1738 return display->scale / HOME_SCALE;