New cisco icons, and a fix in element.h
[dia.git] / app / disp_callbacks.c
blob8d3d2377cf11e1911407632c9cbb6486143e8aea
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.
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <string.h>
25 #include <math.h>
26 #include <gtk/gtk.h>
27 #include <gdk/gdkkeysyms.h>
29 #ifdef GNOME
30 #include <gnome.h>
31 #endif
32 #include "display.h"
33 #include "diagram.h"
34 #include "tool.h"
35 #include "interface.h"
36 #include "focus.h"
37 #include "object_ops.h"
38 #include "connectionpoint_ops.h"
39 #include "menus.h"
40 #include "message.h"
41 #include "intl.h"
42 #include "magnify.h"
43 #include "diamenu.h"
44 #include "preferences.h"
45 #include "scroll_tool.h"
46 #include "commands.h"
47 #include "highlight.h"
48 #include "textedit.h"
50 /* This contains the point that was clicked to get this menu */
51 static Point object_menu_clicked_point;
53 static void
54 object_menu_proxy(GtkWidget *widget, gpointer data)
56 DiaMenuItem *dia_menu_item;
57 ObjectChange *obj_change;
58 DiaObject *obj;
59 DDisplay *ddisp = ddisplay_active();
61 if (!ddisp) return;
63 obj = (DiaObject *)ddisp->diagram->data->selected->data;
64 dia_menu_item = (DiaMenuItem *) data;
67 object_add_updates(obj, ddisp->diagram);
68 obj_change = (dia_menu_item->callback)(obj, &object_menu_clicked_point,
69 dia_menu_item->callback_data);
70 object_add_updates(obj, ddisp->diagram);
71 diagram_update_connections_object(ddisp->diagram, obj, TRUE);
73 if (obj_change != NULL) {
74 undo_object_change(ddisp->diagram, obj, obj_change);
76 diagram_modified(ddisp->diagram);
78 diagram_update_extents(ddisp->diagram);
80 if (obj_change != NULL) {
81 undo_set_transactionpoint(ddisp->diagram->undo);
82 } else {
83 message_warning(_("This object doesn't support Undo/Redo.\n"
84 "Undo information erased."));
85 undo_clear(ddisp->diagram->undo);
88 diagram_flush(ddisp->diagram);
91 static void
92 dia_menu_free(DiaMenu *dia_menu)
94 if (dia_menu->app_data)
95 gtk_object_destroy((GtkObject *)dia_menu->app_data);
96 dia_menu->app_data = NULL;
97 dia_menu->app_data_free = NULL;
101 This add a Properties... menu item to the GtkMenu passed, at the
102 end and set the callback to raise de properties dialog
104 pass TRUE in separator if you want to insert a separator before the poperty
105 menu item.
107 static void
108 add_properties_menu_item (GtkMenu *menu, gboolean separator)
110 GtkWidget *menu_item = NULL;
112 if (separator) {
113 menu_item = gtk_menu_item_new();
114 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
115 gtk_widget_show(menu_item);
118 menu_item = gtk_menu_item_new_with_label(_("Properties..."));
119 g_signal_connect(GTK_OBJECT(menu_item), "activate", G_CALLBACK(dialogs_properties_callback), NULL);
120 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
121 gtk_widget_show(menu_item);
124 static void
125 create_object_menu(DiaMenu *dia_menu)
127 int i;
128 GtkWidget *menu;
129 GtkWidget *menu_item;
131 menu = gtk_menu_new();
133 if ( dia_menu->title ) {
134 menu_item = gtk_menu_item_new_with_label(gettext(dia_menu->title));
135 gtk_widget_set_sensitive(menu_item, FALSE);
136 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
137 gtk_widget_show(menu_item);
140 menu_item = gtk_menu_item_new();
141 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
142 gtk_widget_show(menu_item);
144 for (i=0;i<dia_menu->num_items;i++) {
145 DiaMenuItem *item = &dia_menu->items[i];
147 if (item->active & DIAMENU_TOGGLE) {
148 if (item->text)
149 menu_item = gtk_check_menu_item_new_with_label(gettext(item->text));
150 else
151 menu_item = gtk_check_menu_item_new();
152 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item),
153 item->active & DIAMENU_TOGGLE_ON);
154 gtk_check_menu_item_set_show_toggle(GTK_CHECK_MENU_ITEM(menu_item),
155 TRUE);
156 } else {
157 if (item->text)
158 menu_item = gtk_menu_item_new_with_label(gettext(item->text));
159 else
160 menu_item = gtk_menu_item_new();
162 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
163 gtk_widget_show(menu_item);
164 item->app_data = menu_item;
165 if ( dia_menu->items[i].callback ) {
166 /* only connect signal handler if there is actually a callback */
167 gtk_signal_connect(GTK_OBJECT(menu_item), "activate",
168 (GtkSignalFunc)object_menu_proxy, &dia_menu->items[i]);
169 } else {
170 if ( item->callback_data ) {
171 /* This menu item is a submenu if it has no callback, but does
172 * Have callback_data. In this case the callback_data is a
173 * DiaMenu pointer for the submenu. */
174 if ( ((DiaMenu*)item->callback_data)->app_data == NULL ) {
175 /* Create the popup menu items for the submenu. */
176 create_object_menu((DiaMenu*)(item->callback_data) ) ;
177 gtk_menu_item_set_submenu( GTK_MENU_ITEM (menu_item),
178 GTK_WIDGET(((DiaMenu*)(item->callback_data))->app_data));
184 /* Finally add a Properties... menu item for objects*/
185 add_properties_menu_item(GTK_MENU (menu), i > 0);
187 dia_menu->app_data = menu;
188 dia_menu->app_data_free = dia_menu_free;
191 static DiaMenuItem empty_menu_items[] = { {0, } };
192 static DiaMenu empty_menu = {
193 NULL,
194 sizeof(empty_menu_items)/sizeof(DiaMenuItem),
195 empty_menu_items,
196 NULL
199 static void
200 popup_object_menu(DDisplay *ddisp, GdkEventButton *bevent)
202 Diagram *diagram;
203 DiaObject *obj;
204 GtkMenu *menu = NULL;
205 DiaMenu *dia_menu = NULL;
206 GList *selected_list;
207 int i;
208 int num_items;
210 diagram = ddisp->diagram;
211 if (g_list_length (diagram->data->selected) != 1)
212 return;
214 selected_list = diagram->data->selected;
216 /* Have to have exactly one selected object */
217 if (selected_list == NULL || g_list_next(selected_list) != NULL) {
218 message_error("Selected list is %s while selected_count is %d\n",
219 (selected_list?"long":"empty"), g_list_length (diagram->data->selected));
220 return;
223 obj = (DiaObject *)g_list_first(selected_list)->data;
225 /* Possibly react differently at a handle? */
227 /* Get its menu, and remember the # of object-generated items */
228 if (obj->ops->get_object_menu == NULL) {
229 dia_menu = &empty_menu;
230 if (dia_menu->title &&
231 (0 != strcmp(dia_menu->title,obj->type->name))) {
232 dia_menu->app_data_free(dia_menu);
234 dia_menu->title = obj->type->name;
235 num_items = 0;
236 } else {
237 dia_menu = (obj->ops->get_object_menu)(obj, &object_menu_clicked_point);
238 num_items = dia_menu->num_items;
241 if (dia_menu->app_data == NULL) {
242 create_object_menu(dia_menu);
244 /* Update active/nonactive menuitems */
245 for (i=0;i<num_items;i++) {
246 DiaMenuItem *item = &dia_menu->items[i];
247 gtk_widget_set_sensitive(GTK_WIDGET(item->app_data),
248 item->active & DIAMENU_ACTIVE);
249 if (item->active & DIAMENU_TOGGLE) {
250 g_signal_handlers_block_by_func(GTK_CHECK_MENU_ITEM(item->app_data),
251 (GtkSignalFunc)object_menu_proxy, item);
252 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item->app_data),
253 item->active & DIAMENU_TOGGLE_ON);
254 g_signal_handlers_unblock_by_func(GTK_CHECK_MENU_ITEM(item->app_data),
255 (GtkSignalFunc)object_menu_proxy, item);
259 menu = GTK_MENU(dia_menu->app_data);
260 /* add the properties menu item to raise the properties from the contextual menu */
262 popup_shell = ddisp->shell;
263 gtk_menu_popup(menu, NULL, NULL, NULL, NULL, bevent->button, bevent->time);
266 gint
267 ddisplay_focus_in_event(GtkWidget *widget, GdkEventFocus *event, gpointer data)
269 DDisplay *ddisp;
271 g_return_val_if_fail (widget != NULL, FALSE);
272 g_return_val_if_fail (event != NULL, FALSE);
273 g_return_val_if_fail (data != NULL, FALSE);
275 ddisp = (DDisplay *)data;
277 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
279 gtk_im_context_focus_in(GTK_IM_CONTEXT(ddisp->im_context));
281 return FALSE;
284 gint
285 ddisplay_focus_out_event(GtkWidget *widget, GdkEventFocus *event,gpointer data)
287 DDisplay *ddisp;
288 int return_val;
290 g_return_val_if_fail (widget != NULL, FALSE);
291 g_return_val_if_fail (event != NULL, FALSE);
292 g_return_val_if_fail (data != NULL, FALSE);
294 return_val = FALSE;
296 ddisp = (DDisplay *)data;
298 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
300 gtk_im_context_focus_out(GTK_IM_CONTEXT(ddisp->im_context));
302 return return_val;
305 void
306 ddisplay_realize(GtkWidget *widget, gpointer data)
308 DDisplay *ddisp;
310 g_return_if_fail(widget != NULL);
311 g_return_if_fail(data != NULL);
313 ddisp = (DDisplay *)data;
315 gtk_im_context_set_client_window(GTK_IM_CONTEXT(ddisp->im_context),
316 GDK_WINDOW(ddisp->shell->window));
319 void
320 ddisplay_unrealize (GtkWidget *widget, gpointer data)
322 DDisplay *ddisp;
324 g_return_if_fail (widget != NULL);
325 g_return_if_fail (data != NULL);
327 ddisp = (DDisplay *) data;
329 if (ddisp->im_context)
330 gtk_im_context_set_client_window(GTK_IM_CONTEXT(ddisp->im_context),
331 GDK_WINDOW(ddisp->shell->window));
334 void
335 ddisplay_size_allocate (GtkWidget *widget,
336 GtkAllocation *allocation,
337 gpointer data)
339 DDisplay *ddisp;
341 g_return_if_fail (widget != NULL);
342 g_return_if_fail (allocation != NULL);
343 g_return_if_fail (data != NULL);
345 #if 0
346 g_print ("ddisp::size_allocate: %d,%d -> %d,%d\n", allocation->width, allocation->height,
347 widget->allocation.width, widget->allocation.height);
348 #endif
349 widget->allocation = *allocation;
350 ddisp = (DDisplay *)data;
353 void
354 ddisplay_popup_menu(DDisplay *ddisp, GdkEventButton *event)
356 GtkWidget *menu;
358 popup_shell = ddisp->shell;
359 menus_get_image_menu(&menu, NULL);
361 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
362 event->button, event->time);
364 static void
365 handle_key_event(DDisplay *ddisp, Focus *focus, guint keysym,
366 const gchar *str, int strlen)
368 DiaObject *obj = focus_get_object(focus);
369 Point p = obj->position;
370 ObjectChange *obj_change = NULL;
371 gboolean modified;
373 object_add_updates(obj, ddisp->diagram);
375 modified = (focus->key_event)(focus, keysym, str, strlen,
376 &obj_change);
378 /* Make sure object updates its data and its connected: */
379 p = obj->position;
380 (obj->ops->move)(obj,&p);
381 diagram_update_connections_object(ddisp->diagram,obj,TRUE);
383 object_add_updates(obj, ddisp->diagram);
385 if (modified) {
386 if (obj_change != NULL) {
387 undo_object_change(ddisp->diagram, obj, obj_change);
388 undo_set_transactionpoint(ddisp->diagram->undo);
390 diagram_modified(ddisp->diagram);
393 diagram_flush(ddisp->diagram);
397 void
398 ddisplay_im_context_commit(GtkIMContext *context, const gchar *str,
399 DDisplay *ddisp)
401 /* When using IM, we'll not get many key events past the IM filter,
402 mostly IM Commits.
404 regardless of the platform, "str" should be a clean UTF8 string
405 (the default IM on X should perform the local->UTF8 conversion)
408 Focus *focus = active_focus();
410 ddisplay_im_context_preedit_reset(ddisp, focus);
412 if (focus != NULL)
413 handle_key_event(ddisp, focus, 0, str, g_utf8_strlen(str,-1));
416 void
417 ddisplay_im_context_preedit_changed(GtkIMContext *context,
418 DDisplay *ddisp)
420 gint cursor_pos;
421 Focus *focus = active_focus();
423 ddisplay_im_context_preedit_reset(ddisp, focus);
425 gtk_im_context_get_preedit_string(context, &ddisp->preedit_string,
426 &ddisp->preedit_attrs, &cursor_pos);
427 if (ddisp->preedit_string != NULL) {
428 if (focus != NULL) {
429 handle_key_event(ddisp, focus, 0, ddisp->preedit_string,
430 g_utf8_strlen(ddisp->preedit_string,-1));
431 } else {
432 ddisplay_im_context_preedit_reset(ddisp, focus);
437 /** Main input handler for a diagram canvas.
439 gint
440 ddisplay_canvas_events (GtkWidget *canvas,
441 GdkEvent *event,
442 DDisplay *ddisp)
444 GdkEventExpose *eevent;
445 GdkEventMotion *mevent;
446 GdkEventButton *bevent;
447 GdkEventKey *kevent;
448 GdkEventScroll *sevent;
449 gint tx, ty;
450 GdkModifierType tmask;
451 guint state = 0;
452 Focus *focus;
453 DiaObject *obj;
454 Rectangle *visible;
455 Point middle;
456 int return_val;
457 int key_handled;
458 int width, height;
459 int new_size;
460 int im_context_used;
461 static gboolean moving = FALSE;
463 return_val = FALSE;
465 if (!canvas->window)
466 return FALSE;
468 switch (event->type)
470 case GDK_EXPOSE:
471 eevent = (GdkEventExpose *) event;
472 ddisplay_add_display_area(ddisp,
473 eevent->area.x, eevent->area.y,
474 eevent->area.x + eevent->area.width,
475 eevent->area.y + eevent->area.height);
476 ddisplay_flush(ddisp);
477 break;
479 case GDK_SCROLL:
480 sevent = (GdkEventScroll *) event;
482 switch (sevent->direction)
484 case GDK_SCROLL_UP:
485 if (sevent->state & GDK_SHIFT_MASK)
486 ddisplay_scroll_left(ddisp);
487 else if (sevent->state & GDK_CONTROL_MASK) {
488 ddisplay_untransform_coords(ddisp, sevent->x, sevent->y, &middle.x, &middle.y);
489 ddisplay_zoom(ddisp, &middle, 2);
491 else
492 ddisplay_scroll_up(ddisp);
493 break;
494 case GDK_SCROLL_DOWN:
495 if (sevent->state & GDK_SHIFT_MASK)
496 ddisplay_scroll_right(ddisp);
497 else if (sevent->state & GDK_CONTROL_MASK) {
498 ddisplay_untransform_coords(ddisp, sevent->x, sevent->y, &middle.x, &middle.y);
499 ddisplay_zoom(ddisp, &middle, 0.5);
501 else
502 ddisplay_scroll_down(ddisp);
503 break;
504 case GDK_SCROLL_LEFT:
505 ddisplay_scroll_left(ddisp);
506 break;
507 case GDK_SCROLL_RIGHT:
508 ddisplay_scroll_right(ddisp);
509 break;
510 default:
511 break;
513 ddisplay_flush (ddisp);
514 break;
516 case GDK_CONFIGURE:
517 if (ddisp->renderer != NULL) {
518 width = dia_renderer_get_width_pixels (ddisp->renderer);
519 height = dia_renderer_get_height_pixels (ddisp->renderer);
520 new_size = ((width != ddisp->canvas->allocation.width) ||
521 (height != ddisp->canvas->allocation.height));
522 } else {
523 new_size = TRUE;
525 if (new_size) {
526 ddisplay_resize_canvas(ddisp,
527 ddisp->canvas->allocation.width,
528 ddisp->canvas->allocation.height);
529 ddisplay_update_scrollbars(ddisp);
531 display_set_active(ddisp);
532 break;
534 case GDK_FOCUS_CHANGE: {
535 GdkEventFocus *focus = (GdkEventFocus*)event;
536 if (focus->in) {
537 display_set_active(ddisp);
538 ddisplay_do_update_menu_sensitivity(ddisp);
540 break;
542 case GDK_2BUTTON_PRESS:
543 display_set_active(ddisp);
544 bevent = (GdkEventButton *) event;
545 state = bevent->state;
547 switch (bevent->button)
549 case 1:
550 if (transient_tool)
551 break;
552 if (active_tool->double_click_func)
553 (*active_tool->double_click_func) (active_tool, bevent, ddisp);
554 break;
556 case 2:
557 break;
559 case 3:
560 break;
562 default:
563 break;
565 break;
567 case GDK_BUTTON_PRESS:
568 display_set_active(ddisp);
569 bevent = (GdkEventButton *) event;
570 state = bevent->state;
572 ddisplay_untransform_coords(ddisp,
573 (int)bevent->x, (int)bevent->y,
574 &object_menu_clicked_point.x,
575 &object_menu_clicked_point.y);
577 switch (bevent->button)
579 case 1:
580 if (transient_tool)
581 break;
582 /* get the focus again, may be lost by zoom combo */
583 moving = TRUE;
584 gtk_widget_grab_focus(canvas);
585 if (active_tool->button_press_func)
586 (*active_tool->button_press_func) (active_tool, bevent, ddisp);
587 break;
589 case 2:
590 if (ddisp->menu_bar == NULL) {
591 popup_object_menu(ddisp, bevent);
593 else if (!transient_tool) {
594 gtk_widget_grab_focus(canvas);
595 transient_tool = create_scroll_tool();
596 (*transient_tool->button_press_func) (transient_tool, bevent, ddisp);
598 break;
600 case 3:
601 if (transient_tool)
602 break;
603 if (ddisp->menu_bar == NULL) {
604 if (bevent->state & GDK_CONTROL_MASK) {
605 /* for two button mouse users ... */
606 popup_object_menu(ddisp, bevent);
607 break;
609 ddisplay_popup_menu(ddisp, bevent);
610 break;
612 else {
613 popup_object_menu(ddisp, bevent);
614 break;
616 default:
617 break;
619 break;
621 case GDK_BUTTON_RELEASE:
622 display_set_active(ddisp);
623 bevent = (GdkEventButton *) event;
624 state = bevent->state;
626 switch (bevent->button)
628 case 1:
629 if (moving)
630 moving = FALSE;
631 if (active_tool->button_release_func)
632 (*active_tool->button_release_func) (active_tool,
633 bevent, ddisp);
634 break;
636 case 2:
637 if (transient_tool) {
638 (*transient_tool->button_release_func) (transient_tool,
639 bevent, ddisp);
641 tool_free(transient_tool);
642 transient_tool = NULL;
644 break;
646 case 3:
647 break;
649 default:
650 break;
652 break;
654 case GDK_MOTION_NOTIFY:
655 /* get the pointer position */
656 gdk_window_get_pointer (canvas->window, &tx, &ty, &tmask);
658 mevent = (GdkEventMotion *) event;
659 state = mevent->state;
661 if (mevent->is_hint) {
662 mevent->x = tx;
663 mevent->y = ty;
664 mevent->state = tmask;
665 mevent->is_hint = FALSE;
667 if (transient_tool && (*transient_tool->motion_func))
668 (*transient_tool->motion_func) (transient_tool, mevent, ddisp);
669 else if (active_tool->motion_func)
670 (*active_tool->motion_func) (active_tool, mevent, ddisp);
671 break;
673 case GDK_KEY_PRESS:
674 if (moving) /*Disable Keyboard accels whilst draggin an object*/
675 break;
676 display_set_active(ddisp);
677 kevent = (GdkEventKey *)event;
678 state = kevent->state;
679 key_handled = FALSE;
680 im_context_used = FALSE;
682 focus = active_focus();
683 if (focus != NULL) {
684 /* Keys goes to the active focus. */
685 obj = focus_get_object(focus);
686 if (diagram_is_selected(ddisp->diagram, obj)) {
688 if (!gtk_im_context_filter_keypress(
689 GTK_IM_CONTEXT(ddisp->im_context), kevent)) {
691 if (kevent->keyval == GDK_Tab) {
692 focus = textedit_move_focus(ddisp, focus,
693 (state & GDK_SHIFT_MASK) == 0);
694 obj = focus_get_object(focus);
695 } else {
696 /*! key event not swallowed by the input method ? */
697 handle_key_event(ddisp, focus, kevent->keyval,
698 kevent->string, kevent->length);
700 diagram_flush(ddisp->diagram);
703 return_val = key_handled = im_context_used = TRUE;
707 #if 0 /* modifier requirment added 2004-07-17, IMO reenabling unmodified keys here
708 * shouldn't break im_context handling. How to test? --hb
710 if (!key_handled && (state & (GDK_CONTROL_MASK | GDK_MOD1_MASK))) {
711 #else
712 if (!key_handled) {
713 #endif
714 /* IM doesn't need receive keys, take care of it ourselves. */
715 return_val = TRUE;
717 switch(kevent->keyval) {
718 case GDK_Up:
719 ddisplay_scroll_up(ddisp);
720 ddisplay_flush(ddisp);
721 break;
722 case GDK_Down:
723 ddisplay_scroll_down(ddisp);
724 ddisplay_flush(ddisp);
725 break;
726 case GDK_Left:
727 ddisplay_scroll_left(ddisp);
728 ddisplay_flush(ddisp);
729 break;
730 case GDK_Right:
731 ddisplay_scroll_right(ddisp);
732 ddisplay_flush(ddisp);
733 break;
734 case GDK_KP_Add:
735 case GDK_plus:
736 visible = &ddisp->visible;
737 middle.x = visible->left*0.5 + visible->right*0.5;
738 middle.y = visible->top*0.5 + visible->bottom*0.5;
740 ddisplay_zoom(ddisp, &middle, M_SQRT2);
741 break;
742 case GDK_KP_Subtract:
743 case GDK_minus:
744 visible = &ddisp->visible;
745 middle.x = visible->left*0.5 + visible->right*0.5;
746 middle.y = visible->top*0.5 + visible->bottom*0.5;
748 ddisplay_zoom(ddisp, &middle, M_SQRT1_2);
749 break;
750 case GDK_Shift_L:
751 case GDK_Shift_R:
752 if (active_tool->type == MAGNIFY_TOOL)
753 set_zoom_out(active_tool);
754 break;
755 case GDK_Escape:
756 view_unfullscreen();
757 break;
758 default:
759 if (kevent->string && kevent->keyval == ' ') {
760 tool_select_former();
761 } else if ((kevent->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) == 0 &&
762 kevent->length != 0) {
763 /* Find first editable */
764 #ifdef NEW_TEXT_EDIT
765 modify_edit_first_text(ddisp);
766 return_val = FALSE;
767 #endif
772 if (!im_context_used)
773 gtk_im_context_reset(GTK_IM_CONTEXT(ddisp->im_context));
775 break;
777 case GDK_KEY_RELEASE:
778 kevent = (GdkEventKey *) event;
779 state = kevent->state;
780 if (gtk_im_context_filter_keypress(GTK_IM_CONTEXT(ddisp->im_context),
781 kevent)) {
782 return_val = TRUE;
783 } else {
784 switch(kevent->keyval) {
785 case GDK_Shift_L:
786 case GDK_Shift_R:
787 if (active_tool->type == MAGNIFY_TOOL)
788 set_zoom_in(active_tool);
789 break;
790 default:
791 break;
794 break;
796 default:
797 break;
800 return return_val;
803 gint
804 ddisplay_hsb_update (GtkAdjustment *adjustment,
805 DDisplay *ddisp)
807 ddisplay_set_origo(ddisp, adjustment->value, ddisp->origo.y);
808 ddisplay_add_update_all(ddisp);
809 ddisplay_flush(ddisp);
810 return FALSE;
813 gint
814 ddisplay_vsb_update (GtkAdjustment *adjustment,
815 DDisplay *ddisp)
817 ddisplay_set_origo(ddisp, ddisp->origo.x, adjustment->value);
818 ddisplay_add_update_all(ddisp);
819 ddisplay_flush(ddisp);
820 return FALSE;
823 gint
824 ddisplay_delete (GtkWidget *widget, GdkEvent *event, gpointer data)
826 DDisplay *ddisp;
828 ddisp = (DDisplay *)data;
830 ddisplay_close(ddisp);
831 return TRUE;
834 void
835 ddisplay_destroy (GtkWidget *widget, gpointer data)
837 DDisplay *ddisp;
839 ddisp = (DDisplay *) data;
841 if (popup_shell == ddisp->shell) {
842 popup_shell = NULL;
845 ddisplay_really_destroy(ddisp);
848 /* returns NULL if object cannot be created */
849 DiaObject *
850 ddisplay_drop_object(DDisplay *ddisp, gint x, gint y, DiaObjectType *otype,
851 gpointer user_data)
853 Point droppoint;
854 Point droppoint_orig;
855 Handle *handle1, *handle2;
856 DiaObject *obj, *p_obj;
857 GList *list;
858 real click_distance;
860 ddisplay_untransform_coords(ddisp, x, y, &droppoint.x, &droppoint.y);
862 /* save it before snap_to_grid modifies it */
863 droppoint_orig = droppoint;
865 snap_to_grid(ddisp, &droppoint.x, &droppoint.y);
867 obj = dia_object_default_create (otype, &droppoint,
868 user_data,
869 &handle1, &handle2);
872 click_distance = ddisplay_untransform_length(ddisp, 3.0);
874 /* Notice that using diagram_find_clicked_object doesn't allow any object
875 * below the first to be a parent. This should be fixed.
876 * -Lars
878 p_obj = diagram_find_clicked_object(ddisp->diagram, &droppoint_orig,
879 click_distance);
881 if (p_obj && p_obj->can_parent) /* the tool was dropped inside an object that takes children*/
883 Rectangle p_ext, c_ext;
884 real parent_height, child_height, parent_width, child_width;
885 real vadjust = 0.0, hadjust = 0.0;
886 Point new_pos;
888 obj->parent = p_obj;
889 p_obj->children = g_list_append(p_obj->children, obj);
891 /* This is not really what we want. We want the box containing all
892 * rendered parts of the object (not the bbox). But it'll do for now,
893 * since we don't have the 'rendered bbox'.
894 * -Lars
896 parent_handle_extents(p_obj, &p_ext);
897 parent_handle_extents(obj, &c_ext);
899 parent_height = p_ext.bottom - p_ext.top;
900 child_height = c_ext.bottom - c_ext.top;
902 parent_width = p_ext.right - p_ext.left;
903 child_width = c_ext.right - c_ext.left;
905 /* we need the pre-snap position, but must remember that handles can
906 * be to the left of the droppoint */
907 c_ext.left = droppoint_orig.x - (obj->position.x - c_ext.left);
908 c_ext.top = droppoint_orig.y - (obj->position.y - c_ext.top);
909 c_ext.right = c_ext.left + child_width;
910 c_ext.bottom = c_ext.top + child_height;
912 if (c_ext.left < p_ext.left) {
913 hadjust = p_ext.left - c_ext.left;
914 } else if (c_ext.right > p_ext.right) {
915 hadjust = p_ext.right - c_ext.right;
917 if (c_ext.top < p_ext.top) {
918 vadjust = p_ext.top - c_ext.top;
919 } else if (c_ext.bottom > p_ext.bottom) {
920 vadjust = p_ext.bottom - c_ext.bottom;
923 if (child_width > parent_width ||
924 child_height > parent_height) {
925 message_error(_("The object you dropped cannot fit into its parent. \nEither expand the parent object, or drop the object elsewhere."));
926 obj->parent->children = g_list_remove(obj->parent->children, obj);
927 obj->ops->destroy (obj);
928 return NULL;
931 if (hadjust || vadjust) {
932 new_pos.x = droppoint.x + hadjust;
933 new_pos.y = droppoint.y + vadjust;
934 obj->ops->move(obj, &new_pos);
938 diagram_add_object(ddisp->diagram, obj);
939 diagram_remove_all_selected(ddisp->diagram, TRUE); /* unselect all */
940 diagram_select(ddisp->diagram, obj);
941 obj->ops->selectf(obj, &droppoint, ddisp->renderer);
942 textedit_activate_object(ddisp, obj, NULL);
944 /* Connect first handle if possible: */
945 if ((handle1 != NULL) &&
946 (handle1->connect_type != HANDLE_NONCONNECTABLE)) {
947 object_connect_display(ddisp, obj, handle1, FALSE);
949 object_add_updates(obj, ddisp->diagram);
950 ddisplay_do_update_menu_sensitivity(ddisp);
951 diagram_flush(ddisp->diagram);
953 list = g_list_prepend(NULL, obj);
954 undo_insert_objects(ddisp->diagram, list, 1);
955 diagram_update_extents(ddisp->diagram);
957 undo_set_transactionpoint(ddisp->diagram->undo);
958 diagram_modified(ddisp->diagram);
959 if (prefs.reset_tools_after_create)
960 tool_reset();
961 return obj;