1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 #include <gdk/gdkkeysyms.h>
35 #include "interface.h"
37 #include "object_ops.h"
38 #include "connectionpoint_ops.h"
45 /* This contains the point that was clicked to get this menu */
46 static Point object_menu_clicked_point
;
49 object_menu_proxy(GtkWidget
*widget
, gpointer data
)
51 DiaMenuItem
*dia_menu_item
;
52 ObjectChange
*obj_change
;
54 DDisplay
*ddisp
= ddisplay_active();
55 Object
*obj
= (Object
*)ddisp
->diagram
->data
->selected
->data
;
57 dia_menu_item
= (DiaMenuItem
*) data
;
60 object_add_updates(obj
, ddisp
->diagram
);
61 obj_change
= (dia_menu_item
->callback
)(obj
, &object_menu_clicked_point
,
62 dia_menu_item
->callback_data
);
63 object_add_updates(obj
, ddisp
->diagram
);
64 diagram_update_connections_object(ddisp
->diagram
, obj
, TRUE
);
66 if (obj_change
!= NULL
) {
67 undo_object_change(ddisp
->diagram
, obj
, obj_change
);
69 diagram_modified(ddisp
->diagram
);
71 diagram_update_extents(ddisp
->diagram
);
73 if (obj_change
!= NULL
) {
74 undo_set_transactionpoint(ddisp
->diagram
->undo
);
76 message_warning(_("This object doesn't support Undo/Redo.\n"
77 "Undo information erased."));
78 undo_clear(ddisp
->diagram
->undo
);
82 diagram_flush(ddisp
->diagram
);
86 dia_menu_free(DiaMenu
*dia_menu
) {
87 if (dia_menu
->app_data
)
88 gtk_object_destroy((GtkObject
*)dia_menu
->app_data
);
89 dia_menu
->app_data
= NULL
;
90 dia_menu
->app_data_free
= NULL
;
94 create_object_menu(DiaMenu
*dia_menu
)
100 menu
= gtk_menu_new();
101 //FIXME?: gtk_menu_ensure_uline_accel_group (GTK_MENU (menu)) ;
103 if ( dia_menu
->title
) {
104 menu_item
= gtk_menu_item_new_with_label(gettext(dia_menu
->title
));
105 gtk_widget_set_sensitive(menu_item
, FALSE
);
106 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menu_item
);
107 gtk_widget_show(menu_item
);
110 menu_item
= gtk_menu_item_new();
111 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menu_item
);
112 gtk_widget_show(menu_item
);
114 for (i
=0;i
<dia_menu
->num_items
;i
++) {
115 DiaMenuItem
*item
= &dia_menu
->items
[i
];
117 if (item
->active
& DIAMENU_TOGGLE
) {
119 menu_item
= gtk_check_menu_item_new_with_label(gettext(item
->text
));
121 menu_item
= gtk_check_menu_item_new();
122 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item
),
123 item
->active
& DIAMENU_TOGGLE_ON
);
124 gtk_check_menu_item_set_show_toggle(GTK_CHECK_MENU_ITEM(menu_item
),
128 menu_item
= gtk_menu_item_new_with_label(gettext(item
->text
));
130 menu_item
= gtk_menu_item_new();
132 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menu_item
);
133 gtk_widget_show(menu_item
);
134 item
->app_data
= menu_item
;
135 if ( dia_menu
->items
[i
].callback
) {
136 /* only connect signal handler if there is actually a callback */
137 gtk_signal_connect(GTK_OBJECT(menu_item
), "activate",
138 (GtkSignalFunc
)object_menu_proxy
, &dia_menu
->items
[i
]);
140 if ( item
->callback_data
) {
141 /* This menu item is a submenu if it has no callback, but does
142 * Have callback_data. In this case the callback_data is a
143 * DiaMenu pointer for the submenu. */
144 if ( ((DiaMenu
*)item
->callback_data
)->app_data
== NULL
) {
145 /* Create the popup menu items for the submenu. */
146 create_object_menu((DiaMenu
*)(item
->callback_data
) ) ;
147 gtk_menu_item_set_submenu( GTK_MENU_ITEM (menu_item
),
148 GTK_WIDGET(((DiaMenu
*)(item
->callback_data
))->app_data
));
154 dia_menu
->app_data
= menu
;
155 dia_menu
->app_data_free
= dia_menu_free
;
159 popup_object_menu(DDisplay
*ddisp
, GdkEventButton
*bevent
)
163 GtkMenu
*menu
= NULL
;
164 DiaMenu
*dia_menu
= NULL
;
165 GtkWidget
*menu_item
;
166 GList
*selected_list
;
167 static GtkWidget
*no_menu
= NULL
;
170 diagram
= ddisp
->diagram
;
171 if (diagram
->data
->selected_count
!= 1)
174 selected_list
= diagram
->data
->selected
;
176 /* Have to have exactly one selected object */
177 if (selected_list
== NULL
|| g_list_next(selected_list
) != NULL
) {
178 message_error("Selected list is %s while selected_count is %d\n",
179 (selected_list
?"long":"empty"), diagram
->data
->selected_count
);
183 obj
= (Object
*)g_list_first(selected_list
)->data
;
185 /* Possibly react differently at a handle? */
188 if (obj
->ops
->get_object_menu
== NULL
) {
191 dia_menu
= (obj
->ops
->get_object_menu
)(obj
, &object_menu_clicked_point
);
194 if (dia_menu
!= NULL
) {
195 if (dia_menu
->app_data
== NULL
)
196 create_object_menu(dia_menu
);
198 /* Update active/nonactive menuitems */
199 for (i
=0;i
<dia_menu
->num_items
;i
++) {
200 DiaMenuItem
*item
= &dia_menu
->items
[i
];
201 gtk_widget_set_sensitive(GTK_WIDGET(item
->app_data
),
202 item
->active
& DIAMENU_ACTIVE
);
203 if (item
->active
& DIAMENU_TOGGLE
)
204 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item
->app_data
),
205 item
->active
& DIAMENU_TOGGLE_ON
);
208 menu
= GTK_MENU(dia_menu
->app_data
);
210 if (no_menu
== NULL
) {
211 no_menu
= gtk_menu_new();
213 menu_item
= gtk_menu_item_new_with_label(_("No object menu"));
214 gtk_menu_shell_append (GTK_MENU_SHELL (no_menu
), menu_item
);
215 gtk_widget_show(menu_item
);
216 gtk_widget_set_sensitive(menu_item
, FALSE
);
218 menu
= GTK_MENU(no_menu
);
221 popup_shell
= ddisp
->shell
;
222 gtk_menu_popup(menu
, NULL
, NULL
, NULL
, NULL
, bevent
->button
, bevent
->time
);
226 ddisplay_focus_in_event(GtkWidget
*widget
, GdkEventFocus
*event
, gpointer data
)
230 g_return_val_if_fail (widget
!= NULL
, FALSE
);
231 g_return_val_if_fail (event
!= NULL
, FALSE
);
232 g_return_val_if_fail (data
!= NULL
, FALSE
);
234 ddisp
= (DDisplay
*)data
;
236 GTK_WIDGET_SET_FLAGS(widget
, GTK_HAS_FOCUS
);
237 /* FIXME?: gtk_widget_draw_focus(widget); */
238 gtk_im_context_focus_in(GTK_IM_CONTEXT(ddisp
->im_context
));
244 ddisplay_focus_out_event(GtkWidget
*widget
, GdkEventFocus
*event
,gpointer data
)
249 g_return_val_if_fail (widget
!= NULL
, FALSE
);
250 g_return_val_if_fail (event
!= NULL
, FALSE
);
251 g_return_val_if_fail (data
!= NULL
, FALSE
);
255 ddisp
= (DDisplay
*)data
;
257 GTK_WIDGET_UNSET_FLAGS (widget
, GTK_HAS_FOCUS
);
259 gtk_im_context_focus_out(GTK_IM_CONTEXT(ddisp
->im_context
));
265 ddisplay_realize(GtkWidget
*widget
, gpointer data
)
269 g_return_if_fail(widget
!= NULL
);
270 g_return_if_fail(data
!= NULL
);
272 ddisp
= (DDisplay
*)data
;
274 gtk_im_context_set_client_window(GTK_IM_CONTEXT(ddisp
->im_context
),
275 GDK_WINDOW(ddisp
->shell
->window
));
279 ddisplay_unrealize (GtkWidget
*widget
, gpointer data
)
283 g_return_if_fail (widget
!= NULL
);
284 g_return_if_fail (data
!= NULL
);
286 ddisp
= (DDisplay
*) data
;
288 if (ddisp
->im_context
)
289 gtk_im_context_set_client_window(GTK_IM_CONTEXT(ddisp
->im_context
),
290 GDK_WINDOW(ddisp
->shell
->window
));
294 ddisplay_size_allocate (GtkWidget
*widget
,
295 GtkAllocation
*allocation
,
300 g_return_if_fail (widget
!= NULL
);
301 g_return_if_fail (allocation
!= NULL
);
302 g_return_if_fail (data
!= NULL
);
304 widget
->allocation
= *allocation
;
305 ddisp
= (DDisplay
*)data
;
309 ddisplay_popup_menu(DDisplay
*ddisp
, GdkEventButton
*event
)
313 popup_shell
= ddisp
->shell
;
314 menus_get_image_menu(&menu
, NULL
);
316 gtk_menu_popup(GTK_MENU(menu
), NULL
, NULL
, NULL
, NULL
,
317 event
->button
, event
->time
);
320 static void handle_key_event(DDisplay
*ddisp
, Focus
*focus
, guint keysym
,
321 const gchar
*str
, int strlen
) {
322 Object
*obj
= focus
->obj
;
323 Point p
= obj
->position
;
324 ObjectChange
*obj_change
= NULL
;
327 object_add_updates(obj
, ddisp
->diagram
);
329 modified
= (focus
->key_event
)(focus
, keysym
, str
, strlen
,
332 /* Make sure object updates its data and its connected: */
334 (obj
->ops
->move
)(obj
,&p
);
335 diagram_update_connections_object(ddisp
->diagram
,obj
,TRUE
);
337 object_add_updates(obj
, ddisp
->diagram
);
340 diagram_modified(ddisp
->diagram
);
341 if (obj_change
!= NULL
) {
342 undo_object_change(ddisp
->diagram
, obj
, obj_change
);
343 undo_set_transactionpoint(ddisp
->diagram
->undo
);
347 diagram_flush(ddisp
->diagram
);
351 void ddisplay_im_context_commit(GtkIMContext
*context
, const gchar
*str
,
353 /* When using IM, we'll not get many key events past the IM filter,
356 regardless of the platform, "str" should be a clean UTF8 string
357 (the default IM on X should perform the local->UTF8 conversion)
360 handle_key_event(ddisp
, active_focus(), 0, str
, g_utf8_strlen(str
,-1));
363 void ddisplay_im_context_preedit_changed(GtkIMContext
*context
,
366 PangoAttrList *attrs;
369 gtk_im_context_get_preedit_string(ddisp->im_context,
370 &str,&attrs,&cursor_pos);
372 g_message("received a 'preedit changed'; str=%s cursor_pos=%i",
376 pango_attr_list_unref(attrs);
381 ddisplay_canvas_events (GtkWidget
*canvas
,
385 GdkEventExpose
*eevent
;
386 GdkEventMotion
*mevent
;
387 GdkEventButton
*bevent
;
389 GdkEventScroll
*sevent
;
391 GdkModifierType tmask
;
410 eevent
= (GdkEventExpose
*) event
;
411 ddisplay_add_display_area(ddisp
,
412 eevent
->area
.x
, eevent
->area
.y
,
413 eevent
->area
.x
+ eevent
->area
.width
,
414 eevent
->area
.y
+ eevent
->area
.height
);
415 ddisplay_flush(ddisp
);
419 sevent
= (GdkEventScroll
*) event
;
421 switch (sevent
->direction
)
424 ddisplay_scroll_up(ddisp
);
426 case GDK_SCROLL_DOWN
:
427 ddisplay_scroll_down(ddisp
);
429 case GDK_SCROLL_LEFT
:
430 ddisplay_scroll_left(ddisp
);
432 case GDK_SCROLL_RIGHT
:
433 ddisplay_scroll_right(ddisp
);
438 ddisplay_flush (ddisp
);
442 if (ddisp
->renderer
!= NULL
) {
443 width
= dia_renderer_get_width_pixels (ddisp
->renderer
);
444 height
= dia_renderer_get_height_pixels (ddisp
->renderer
);
445 new_size
= ((width
!= ddisp
->canvas
->allocation
.width
) ||
446 (height
!= ddisp
->canvas
->allocation
.height
));
451 ddisplay_resize_canvas(ddisp
,
452 ddisp
->canvas
->allocation
.width
,
453 ddisp
->canvas
->allocation
.height
);
454 ddisplay_update_scrollbars(ddisp
);
456 display_set_active(ddisp
);
459 case GDK_FOCUS_CHANGE
: {
460 GdkEventFocus
*focus
= (GdkEventFocus
*)event
;
462 display_set_active(ddisp
);
463 ddisplay_do_update_menu_sensitivity(ddisp
);
467 case GDK_2BUTTON_PRESS
:
468 display_set_active(ddisp
);
469 bevent
= (GdkEventButton
*) event
;
470 state
= bevent
->state
;
472 switch (bevent
->button
)
475 if (*active_tool
->double_click_func
)
476 (*active_tool
->double_click_func
) (active_tool
, bevent
, ddisp
);
490 case GDK_BUTTON_PRESS
:
491 display_set_active(ddisp
);
492 bevent
= (GdkEventButton
*) event
;
493 state
= bevent
->state
;
495 ddisplay_untransform_coords(ddisp
,
496 (int)bevent
->x
, (int)bevent
->y
,
497 &object_menu_clicked_point
.x
,
498 &object_menu_clicked_point
.y
);
500 switch (bevent
->button
)
503 /* get the focus again, may be lost by zoom combo */
504 gtk_widget_grab_focus(canvas
);
505 if (*active_tool
->button_press_func
)
506 (*active_tool
->button_press_func
) (active_tool
, bevent
, ddisp
);
510 if (ddisp
->menu_bar
== NULL
) {
511 popup_object_menu(ddisp
, bevent
);
516 if (ddisp
->menu_bar
== NULL
) {
517 if (bevent
->state
& GDK_CONTROL_MASK
) {
518 /* for two button mouse users ... */
519 popup_object_menu(ddisp
, bevent
);
522 ddisplay_popup_menu(ddisp
, bevent
);
526 popup_object_menu(ddisp
, bevent
);
534 case GDK_BUTTON_RELEASE
:
535 display_set_active(ddisp
);
536 bevent
= (GdkEventButton
*) event
;
537 state
= bevent
->state
;
539 switch (bevent
->button
)
542 if (*active_tool
->button_release_func
)
543 (*active_tool
->button_release_func
) (active_tool
,
558 case GDK_MOTION_NOTIFY
:
559 /* get the pointer position */
560 gdk_window_get_pointer (canvas
->window
, &tx
, &ty
, &tmask
);
562 mevent
= (GdkEventMotion
*) event
;
563 state
= mevent
->state
;
565 if (mevent
->is_hint
) {
568 mevent
->state
= tmask
;
569 mevent
->is_hint
= FALSE
;
571 if (*active_tool
->motion_func
)
572 (*active_tool
->motion_func
) (active_tool
, mevent
, ddisp
);
576 display_set_active(ddisp
);
577 kevent
= (GdkEventKey
*)event
;
578 state
= kevent
->state
;
581 focus
= active_focus();
582 if ((focus
!= NULL
) &&
583 !(state
& (GDK_CONTROL_MASK
| GDK_MOD1_MASK
)) ) {
584 /* Keys goes to the active focus. */
586 if (diagram_is_selected(ddisp
->diagram
, obj
)) {
588 if (!gtk_im_context_filter_keypress(
589 GTK_IM_CONTEXT(ddisp
->im_context
), kevent
)) {
591 /*! key event not swallowed by the input method ? */
592 handle_key_event(ddisp
, focus
, kevent
->keyval
,
593 kevent
->string
, kevent
->length
);
595 diagram_flush(ddisp
->diagram
);
598 return_val
= key_handled
= TRUE
;
602 /* No focus to receive keys, take care of it ourselves. */
604 gtk_im_context_reset(GTK_IM_CONTEXT(ddisp
->im_context
));
606 switch(kevent
->keyval
) {
608 ddisplay_scroll_up(ddisp
);
609 ddisplay_flush(ddisp
);
612 ddisplay_scroll_down(ddisp
);
613 ddisplay_flush(ddisp
);
616 ddisplay_scroll_left(ddisp
);
617 ddisplay_flush(ddisp
);
620 ddisplay_scroll_right(ddisp
);
621 ddisplay_flush(ddisp
);
625 visible
= &ddisp
->visible
;
626 middle
.x
= visible
->left
*0.5 + visible
->right
*0.5;
627 middle
.y
= visible
->top
*0.5 + visible
->bottom
*0.5;
629 ddisplay_zoom(ddisp
, &middle
, M_SQRT2
);
631 case GDK_KP_Subtract
:
633 visible
= &ddisp
->visible
;
634 middle
.x
= visible
->left
*0.5 + visible
->right
*0.5;
635 middle
.y
= visible
->top
*0.5 + visible
->bottom
*0.5;
637 ddisplay_zoom(ddisp
, &middle
, M_SQRT1_2
);
641 if (active_tool
->type
== MAGNIFY_TOOL
)
642 set_zoom_out(active_tool
);
645 if (kevent
->string
&& 0 == strcmp(" ",kevent
->string
)) {
646 tool_select_former();
654 case GDK_KEY_RELEASE
:
655 kevent
= (GdkEventKey
*) event
;
656 state
= kevent
->state
;
657 if (gtk_im_context_filter_keypress(GTK_IM_CONTEXT(ddisp
->im_context
),
661 switch(kevent
->keyval
) {
664 if (active_tool
->type
== MAGNIFY_TOOL
)
665 set_zoom_in(active_tool
);
681 ddisplay_hsb_update (GtkAdjustment
*adjustment
,
684 ddisplay_set_origo(ddisp
, adjustment
->value
, ddisp
->origo
.y
);
685 ddisplay_add_update_all(ddisp
);
686 ddisplay_flush(ddisp
);
691 ddisplay_vsb_update (GtkAdjustment
*adjustment
,
694 ddisplay_set_origo(ddisp
, ddisp
->origo
.x
, adjustment
->value
);
695 ddisplay_add_update_all(ddisp
);
696 ddisplay_flush(ddisp
);
701 ddisplay_delete (GtkWidget
*widget
, GdkEvent
*event
, gpointer data
)
705 ddisp
= (DDisplay
*)data
;
707 ddisplay_close(ddisp
);
712 ddisplay_destroy (GtkWidget
*widget
, gpointer data
)
716 ddisp
= (DDisplay
*) data
;
718 if (popup_shell
== ddisp
->shell
) {
722 ddisplay_really_destroy(ddisp
);
726 ddisplay_drop_object(DDisplay
*ddisp
, gint x
, gint y
, ObjectType
*otype
,
730 Handle
*handle1
, *handle2
;
734 ddisplay_untransform_coords(ddisp
, x
, y
, &droppoint
.x
, &droppoint
.y
);
736 snap_to_grid(ddisp
, &droppoint
.x
, &droppoint
.y
);
738 obj
= dia_object_default_create (otype
, &droppoint
,
742 diagram_add_object(ddisp
->diagram
, obj
);
743 diagram_remove_all_selected(ddisp
->diagram
, TRUE
); /* unselect all */
744 diagram_select(ddisp
->diagram
, obj
);
745 obj
->ops
->selectf(obj
, &droppoint
, ddisp
->renderer
);
747 /* Connect first handle if possible: */
748 if ((handle1
!= NULL
) &&
749 (handle1
->connect_type
!= HANDLE_NONCONNECTABLE
)) {
750 object_connect_display(ddisp
, obj
, handle1
);
752 object_add_updates(obj
, ddisp
->diagram
);
753 diagram_flush(ddisp
->diagram
);
755 list
= g_list_prepend(NULL
, obj
);
756 undo_insert_objects(ddisp
->diagram
, list
, 1);
757 diagram_update_extents(ddisp
->diagram
);
758 diagram_modified(ddisp
->diagram
);
760 undo_set_transactionpoint(ddisp
->diagram
->undo
);