linewidth is now working for PS_SOLID
[dia.git] / app / disp_callbacks.c
blob688be8bc230f08d37c837946cc6c9b38c3ce9968
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"
48 /* This contains the point that was clicked to get this menu */
49 static Point object_menu_clicked_point;
51 static void
52 object_menu_proxy(GtkWidget *widget, gpointer data)
54 DiaMenuItem *dia_menu_item;
55 ObjectChange *obj_change;
56 DiaObject *obj;
57 DDisplay *ddisp = ddisplay_active();
59 if (!ddisp) return;
61 obj = (DiaObject *)ddisp->diagram->data->selected->data;
62 dia_menu_item = (DiaMenuItem *) data;
65 object_add_updates(obj, ddisp->diagram);
66 obj_change = (dia_menu_item->callback)(obj, &object_menu_clicked_point,
67 dia_menu_item->callback_data);
68 object_add_updates(obj, ddisp->diagram);
69 diagram_update_connections_object(ddisp->diagram, obj, TRUE);
71 if (obj_change != NULL) {
72 undo_object_change(ddisp->diagram, obj, obj_change);
74 diagram_modified(ddisp->diagram);
76 diagram_update_extents(ddisp->diagram);
78 if (obj_change != NULL) {
79 undo_set_transactionpoint(ddisp->diagram->undo);
80 } else {
81 message_warning(_("This object doesn't support Undo/Redo.\n"
82 "Undo information erased."));
83 undo_clear(ddisp->diagram->undo);
86 diagram_flush(ddisp->diagram);
89 static void
90 dia_menu_free(DiaMenu *dia_menu)
92 if (dia_menu->app_data)
93 gtk_object_destroy((GtkObject *)dia_menu->app_data);
94 dia_menu->app_data = NULL;
95 dia_menu->app_data_free = NULL;
99 This add a Properties... menu item to the GtkMenu passed, at the
100 end and set the callback to raise de properties dialog
102 pass TRUE in separator if you want to insert a separator before the poperty
103 menu item.
105 static void
106 add_properties_menu_item (GtkMenu *menu, gboolean separator)
108 GtkWidget *menu_item = NULL;
110 if (separator) {
111 menu_item = gtk_menu_item_new();
112 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
113 gtk_widget_show(menu_item);
116 menu_item = gtk_menu_item_new_with_label(_("Properties..."));
117 g_signal_connect(GTK_OBJECT(menu_item), "activate", G_CALLBACK(dialogs_properties_callback), NULL);
118 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
119 gtk_widget_show(menu_item);
122 static void
123 create_object_menu(DiaMenu *dia_menu)
125 int i;
126 GtkWidget *menu;
127 GtkWidget *menu_item;
129 menu = gtk_menu_new();
131 if ( dia_menu->title ) {
132 menu_item = gtk_menu_item_new_with_label(gettext(dia_menu->title));
133 gtk_widget_set_sensitive(menu_item, FALSE);
134 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
135 gtk_widget_show(menu_item);
138 menu_item = gtk_menu_item_new();
139 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
140 gtk_widget_show(menu_item);
142 for (i=0;i<dia_menu->num_items;i++) {
143 DiaMenuItem *item = &dia_menu->items[i];
145 if (item->active & DIAMENU_TOGGLE) {
146 if (item->text)
147 menu_item = gtk_check_menu_item_new_with_label(gettext(item->text));
148 else
149 menu_item = gtk_check_menu_item_new();
150 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item),
151 item->active & DIAMENU_TOGGLE_ON);
152 gtk_check_menu_item_set_show_toggle(GTK_CHECK_MENU_ITEM(menu_item),
153 TRUE);
154 } else {
155 if (item->text)
156 menu_item = gtk_menu_item_new_with_label(gettext(item->text));
157 else
158 menu_item = gtk_menu_item_new();
160 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
161 gtk_widget_show(menu_item);
162 item->app_data = menu_item;
163 if ( dia_menu->items[i].callback ) {
164 /* only connect signal handler if there is actually a callback */
165 gtk_signal_connect(GTK_OBJECT(menu_item), "activate",
166 (GtkSignalFunc)object_menu_proxy, &dia_menu->items[i]);
167 } else {
168 if ( item->callback_data ) {
169 /* This menu item is a submenu if it has no callback, but does
170 * Have callback_data. In this case the callback_data is a
171 * DiaMenu pointer for the submenu. */
172 if ( ((DiaMenu*)item->callback_data)->app_data == NULL ) {
173 /* Create the popup menu items for the submenu. */
174 create_object_menu((DiaMenu*)(item->callback_data) ) ;
175 gtk_menu_item_set_submenu( GTK_MENU_ITEM (menu_item),
176 GTK_WIDGET(((DiaMenu*)(item->callback_data))->app_data));
182 /* Finally add a Properties... menu item for objects*/
183 add_properties_menu_item(GTK_MENU_SHELL (menu), i > 0);
185 dia_menu->app_data = menu;
186 dia_menu->app_data_free = dia_menu_free;
189 static DiaMenuItem empty_menu_items[] = { 0, };
190 static DiaMenu empty_menu = {
191 NULL,
192 sizeof(empty_menu_items)/sizeof(DiaMenuItem),
193 empty_menu_items,
194 NULL
197 static void
198 popup_object_menu(DDisplay *ddisp, GdkEventButton *bevent)
200 Diagram *diagram;
201 DiaObject *obj;
202 GtkMenu *menu = NULL;
203 DiaMenu *dia_menu = NULL;
204 GList *selected_list;
205 int i;
206 int num_items;
208 diagram = ddisp->diagram;
209 if (diagram->data->selected_count != 1)
210 return;
212 selected_list = diagram->data->selected;
214 /* Have to have exactly one selected object */
215 if (selected_list == NULL || g_list_next(selected_list) != NULL) {
216 message_error("Selected list is %s while selected_count is %d\n",
217 (selected_list?"long":"empty"), diagram->data->selected_count);
218 return;
221 obj = (DiaObject *)g_list_first(selected_list)->data;
223 /* Possibly react differently at a handle? */
225 /* Get its menu, and remember the # of object-generated items */
226 if (obj->ops->get_object_menu == NULL) {
227 dia_menu = &empty_menu;
228 if (dia_menu->title &&
229 (0 != strcmp(dia_menu->title,obj->type->name))) {
230 dia_menu->app_data_free(dia_menu);
232 dia_menu->title = obj->type->name;
233 num_items = 0;
234 } else {
235 dia_menu = (obj->ops->get_object_menu)(obj, &object_menu_clicked_point);
236 num_items = dia_menu->num_items;
239 if (dia_menu->app_data == NULL) {
240 create_object_menu(dia_menu);
242 /* Update active/nonactive menuitems */
243 for (i=0;i<num_items;i++) {
244 DiaMenuItem *item = &dia_menu->items[i];
245 gtk_widget_set_sensitive(GTK_WIDGET(item->app_data),
246 item->active & DIAMENU_ACTIVE);
247 if (item->active & DIAMENU_TOGGLE) {
248 g_signal_handlers_block_by_func(GTK_CHECK_MENU_ITEM(item->app_data),
249 (GtkSignalFunc)object_menu_proxy, item);
250 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item->app_data),
251 item->active & DIAMENU_TOGGLE_ON);
252 g_signal_handlers_unblock_by_func(GTK_CHECK_MENU_ITEM(item->app_data),
253 (GtkSignalFunc)object_menu_proxy, item);
257 menu = GTK_MENU(dia_menu->app_data);
258 /* add the properties menu item to raise the properties from the contextual menu */
260 popup_shell = ddisp->shell;
261 gtk_menu_popup(menu, NULL, NULL, NULL, NULL, bevent->button, bevent->time);
264 gint
265 ddisplay_focus_in_event(GtkWidget *widget, GdkEventFocus *event, gpointer data)
267 DDisplay *ddisp;
269 g_return_val_if_fail (widget != NULL, FALSE);
270 g_return_val_if_fail (event != NULL, FALSE);
271 g_return_val_if_fail (data != NULL, FALSE);
273 ddisp = (DDisplay *)data;
275 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
277 gtk_im_context_focus_in(GTK_IM_CONTEXT(ddisp->im_context));
279 return FALSE;
282 gint
283 ddisplay_focus_out_event(GtkWidget *widget, GdkEventFocus *event,gpointer data)
285 DDisplay *ddisp;
286 int return_val;
288 g_return_val_if_fail (widget != NULL, FALSE);
289 g_return_val_if_fail (event != NULL, FALSE);
290 g_return_val_if_fail (data != NULL, FALSE);
292 return_val = FALSE;
294 ddisp = (DDisplay *)data;
296 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
298 gtk_im_context_focus_out(GTK_IM_CONTEXT(ddisp->im_context));
300 return return_val;
303 void
304 ddisplay_realize(GtkWidget *widget, gpointer data)
306 DDisplay *ddisp;
308 g_return_if_fail(widget != NULL);
309 g_return_if_fail(data != NULL);
311 ddisp = (DDisplay *)data;
313 gtk_im_context_set_client_window(GTK_IM_CONTEXT(ddisp->im_context),
314 GDK_WINDOW(ddisp->shell->window));
317 void
318 ddisplay_unrealize (GtkWidget *widget, gpointer data)
320 DDisplay *ddisp;
322 g_return_if_fail (widget != NULL);
323 g_return_if_fail (data != NULL);
325 ddisp = (DDisplay *) data;
327 if (ddisp->im_context)
328 gtk_im_context_set_client_window(GTK_IM_CONTEXT(ddisp->im_context),
329 GDK_WINDOW(ddisp->shell->window));
332 void
333 ddisplay_size_allocate (GtkWidget *widget,
334 GtkAllocation *allocation,
335 gpointer data)
337 DDisplay *ddisp;
339 g_return_if_fail (widget != NULL);
340 g_return_if_fail (allocation != NULL);
341 g_return_if_fail (data != NULL);
343 widget->allocation = *allocation;
344 ddisp = (DDisplay *)data;
347 void
348 ddisplay_popup_menu(DDisplay *ddisp, GdkEventButton *event)
350 GtkWidget *menu;
352 popup_shell = ddisp->shell;
353 menus_get_image_menu(&menu, NULL);
355 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
356 event->button, event->time);
359 static void
360 handle_key_event(DDisplay *ddisp, Focus *focus, guint keysym,
361 const gchar *str, int strlen)
363 DiaObject *obj = focus->obj;
364 Point p = obj->position;
365 ObjectChange *obj_change = NULL;
366 gboolean modified;
368 object_add_updates(obj, ddisp->diagram);
370 modified = (focus->key_event)(focus, keysym, str, strlen,
371 &obj_change);
373 /* Make sure object updates its data and its connected: */
374 p = obj->position;
375 (obj->ops->move)(obj,&p);
376 diagram_update_connections_object(ddisp->diagram,obj,TRUE);
378 object_add_updates(obj, ddisp->diagram);
380 if (modified) {
381 if (obj_change != NULL) {
382 undo_object_change(ddisp->diagram, obj, obj_change);
383 undo_set_transactionpoint(ddisp->diagram->undo);
385 diagram_modified(ddisp->diagram);
388 diagram_flush(ddisp->diagram);
392 void
393 ddisplay_im_context_commit(GtkIMContext *context, const gchar *str,
394 DDisplay *ddisp)
396 /* When using IM, we'll not get many key events past the IM filter,
397 mostly IM Commits.
399 regardless of the platform, "str" should be a clean UTF8 string
400 (the default IM on X should perform the local->UTF8 conversion)
403 Focus *focus = active_focus();
405 ddisplay_im_context_preedit_reset(ddisp, focus);
407 if (focus != NULL)
408 handle_key_event(ddisp, focus, 0, str, g_utf8_strlen(str,-1));
411 void
412 ddisplay_im_context_preedit_changed(GtkIMContext *context,
413 DDisplay *ddisp)
415 gint cursor_pos;
416 Focus *focus = active_focus();
418 ddisplay_im_context_preedit_reset(ddisp, focus);
420 gtk_im_context_get_preedit_string(context, &ddisp->preedit_string,
421 &ddisp->preedit_attrs, &cursor_pos);
422 if (ddisp->preedit_string != NULL) {
423 if (focus != NULL) {
424 handle_key_event(ddisp, focus, 0, ddisp->preedit_string,
425 g_utf8_strlen(ddisp->preedit_string,-1));
426 } else {
427 ddisplay_im_context_preedit_reset(ddisp, focus);
432 /** Main input handler for a diagram canvas.
434 gint
435 ddisplay_canvas_events (GtkWidget *canvas,
436 GdkEvent *event,
437 DDisplay *ddisp)
439 GdkEventExpose *eevent;
440 GdkEventMotion *mevent;
441 GdkEventButton *bevent;
442 GdkEventKey *kevent;
443 GdkEventScroll *sevent;
444 gint tx, ty;
445 GdkModifierType tmask;
446 guint state = 0;
447 Focus *focus;
448 DiaObject *obj;
449 Rectangle *visible;
450 Point middle;
451 int return_val;
452 int key_handled;
453 int width, height;
454 int new_size;
456 return_val = FALSE;
458 if (!canvas->window)
459 return FALSE;
461 switch (event->type)
463 case GDK_EXPOSE:
464 eevent = (GdkEventExpose *) event;
465 ddisplay_add_display_area(ddisp,
466 eevent->area.x, eevent->area.y,
467 eevent->area.x + eevent->area.width,
468 eevent->area.y + eevent->area.height);
469 ddisplay_flush(ddisp);
470 break;
472 case GDK_SCROLL:
473 sevent = (GdkEventScroll *) event;
475 switch (sevent->direction)
477 case GDK_SCROLL_UP:
478 if (sevent->state & GDK_SHIFT_MASK)
479 ddisplay_scroll_left(ddisp);
480 else if (sevent->state & GDK_CONTROL_MASK) {
481 ddisplay_untransform_coords(ddisp, sevent->x, sevent->y, &middle.x, &middle.y);
482 ddisplay_zoom(ddisp, &middle, 2);
484 else
485 ddisplay_scroll_up(ddisp);
486 break;
487 case GDK_SCROLL_DOWN:
488 if (sevent->state & GDK_SHIFT_MASK)
489 ddisplay_scroll_right(ddisp);
490 else if (sevent->state & GDK_CONTROL_MASK) {
491 ddisplay_untransform_coords(ddisp, sevent->x, sevent->y, &middle.x, &middle.y);
492 ddisplay_zoom(ddisp, &middle, 0.5);
494 else
495 ddisplay_scroll_down(ddisp);
496 break;
497 case GDK_SCROLL_LEFT:
498 ddisplay_scroll_left(ddisp);
499 break;
500 case GDK_SCROLL_RIGHT:
501 ddisplay_scroll_right(ddisp);
502 break;
503 default:
504 break;
506 ddisplay_flush (ddisp);
507 break;
509 case GDK_CONFIGURE:
510 if (ddisp->renderer != NULL) {
511 width = dia_renderer_get_width_pixels (ddisp->renderer);
512 height = dia_renderer_get_height_pixels (ddisp->renderer);
513 new_size = ((width != ddisp->canvas->allocation.width) ||
514 (height != ddisp->canvas->allocation.height));
515 } else {
516 new_size = TRUE;
518 if (new_size) {
519 ddisplay_resize_canvas(ddisp,
520 ddisp->canvas->allocation.width,
521 ddisp->canvas->allocation.height);
522 ddisplay_update_scrollbars(ddisp);
524 display_set_active(ddisp);
525 break;
527 case GDK_FOCUS_CHANGE: {
528 GdkEventFocus *focus = (GdkEventFocus*)event;
529 if (focus->in) {
530 display_set_active(ddisp);
531 ddisplay_do_update_menu_sensitivity(ddisp);
533 break;
535 case GDK_2BUTTON_PRESS:
536 display_set_active(ddisp);
537 bevent = (GdkEventButton *) event;
538 state = bevent->state;
540 switch (bevent->button)
542 case 1:
543 if (transient_tool)
544 break;
545 if (*active_tool->double_click_func)
546 (*active_tool->double_click_func) (active_tool, bevent, ddisp);
547 break;
549 case 2:
550 break;
552 case 3:
553 break;
555 default:
556 break;
558 break;
560 case GDK_BUTTON_PRESS:
561 display_set_active(ddisp);
562 bevent = (GdkEventButton *) event;
563 state = bevent->state;
565 ddisplay_untransform_coords(ddisp,
566 (int)bevent->x, (int)bevent->y,
567 &object_menu_clicked_point.x,
568 &object_menu_clicked_point.y);
570 switch (bevent->button)
572 case 1:
573 if (transient_tool)
574 break;
575 /* get the focus again, may be lost by zoom combo */
576 gtk_widget_grab_focus(canvas);
577 if (*active_tool->button_press_func)
578 (*active_tool->button_press_func) (active_tool, bevent, ddisp);
579 break;
581 case 2:
582 if (ddisp->menu_bar == NULL) {
583 popup_object_menu(ddisp, bevent);
585 else if (!transient_tool) {
586 gtk_widget_grab_focus(canvas);
587 transient_tool = create_scroll_tool();
588 (*transient_tool->button_press_func) (transient_tool, bevent, ddisp);
590 break;
592 case 3:
593 if (transient_tool)
594 break;
595 if (ddisp->menu_bar == NULL) {
596 if (bevent->state & GDK_CONTROL_MASK) {
597 /* for two button mouse users ... */
598 popup_object_menu(ddisp, bevent);
599 break;
601 ddisplay_popup_menu(ddisp, bevent);
602 break;
604 else {
605 popup_object_menu(ddisp, bevent);
606 break;
608 default:
609 break;
611 break;
613 case GDK_BUTTON_RELEASE:
614 display_set_active(ddisp);
615 bevent = (GdkEventButton *) event;
616 state = bevent->state;
618 switch (bevent->button)
620 case 1:
621 if (*active_tool->button_release_func)
622 (*active_tool->button_release_func) (active_tool,
623 bevent, ddisp);
624 break;
626 case 2:
627 if (transient_tool) {
628 (*transient_tool->button_release_func) (transient_tool,
629 bevent, ddisp);
631 tool_free(transient_tool);
632 transient_tool = NULL;
634 break;
636 case 3:
637 break;
639 default:
640 break;
642 break;
644 case GDK_MOTION_NOTIFY:
645 /* get the pointer position */
646 gdk_window_get_pointer (canvas->window, &tx, &ty, &tmask);
648 mevent = (GdkEventMotion *) event;
649 state = mevent->state;
651 if (mevent->is_hint) {
652 mevent->x = tx;
653 mevent->y = ty;
654 mevent->state = tmask;
655 mevent->is_hint = FALSE;
657 if (transient_tool && (*transient_tool->motion_func))
658 (*transient_tool->motion_func) (transient_tool, mevent, ddisp);
659 else if (*active_tool->motion_func)
660 (*active_tool->motion_func) (active_tool, mevent, ddisp);
661 break;
663 case GDK_KEY_PRESS:
664 display_set_active(ddisp);
665 kevent = (GdkEventKey *)event;
666 state = kevent->state;
667 key_handled = FALSE;
669 focus = active_focus();
670 if (focus != NULL) {
671 if (gtk_im_context_filter_keypress(GTK_IM_CONTEXT(ddisp->im_context), kevent)) {
672 return_val = key_handled = TRUE;
673 } else if (!(state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)) ) {
674 /* Keys goes to the active focus. */
675 obj = focus->obj;
676 if (diagram_is_selected(ddisp->diagram, obj)) {
677 handle_key_event(ddisp, focus, kevent->keyval,
678 kevent->string, kevent->length);
679 diagram_flush(ddisp->diagram);
681 return_val = key_handled = TRUE;
685 if (!key_handled) {
686 /* No focus to receive keys, take care of it ourselves. */
687 return_val = TRUE;
688 gtk_im_context_reset(GTK_IM_CONTEXT(ddisp->im_context));
690 switch(kevent->keyval) {
691 case GDK_Up:
692 ddisplay_scroll_up(ddisp);
693 ddisplay_flush(ddisp);
694 break;
695 case GDK_Down:
696 ddisplay_scroll_down(ddisp);
697 ddisplay_flush(ddisp);
698 break;
699 case GDK_Left:
700 ddisplay_scroll_left(ddisp);
701 ddisplay_flush(ddisp);
702 break;
703 case GDK_Right:
704 ddisplay_scroll_right(ddisp);
705 ddisplay_flush(ddisp);
706 break;
707 case GDK_KP_Add:
708 case GDK_plus:
709 visible = &ddisp->visible;
710 middle.x = visible->left*0.5 + visible->right*0.5;
711 middle.y = visible->top*0.5 + visible->bottom*0.5;
713 ddisplay_zoom(ddisp, &middle, M_SQRT2);
714 break;
715 case GDK_KP_Subtract:
716 case GDK_minus:
717 visible = &ddisp->visible;
718 middle.x = visible->left*0.5 + visible->right*0.5;
719 middle.y = visible->top*0.5 + visible->bottom*0.5;
721 ddisplay_zoom(ddisp, &middle, M_SQRT1_2);
722 break;
723 case GDK_Shift_L:
724 case GDK_Shift_R:
725 if (active_tool->type == MAGNIFY_TOOL)
726 set_zoom_out(active_tool);
727 break;
728 default:
729 if (kevent->string && 0 == strcmp(" ",kevent->string)) {
730 tool_select_former();
731 } else if ((kevent->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) == 0 &&
732 kevent->length != 0) {
733 /* Find first editable */
734 #ifdef NEW_TEXT_EDIT
735 modify_edit_first_text(ddisp);
736 return_val = FALSE;
737 #endif
741 break;
743 case GDK_KEY_RELEASE:
744 kevent = (GdkEventKey *) event;
745 state = kevent->state;
746 if (gtk_im_context_filter_keypress(GTK_IM_CONTEXT(ddisp->im_context),
747 kevent)) {
748 return_val = TRUE;
749 } else {
750 switch(kevent->keyval) {
751 case GDK_Shift_L:
752 case GDK_Shift_R:
753 if (active_tool->type == MAGNIFY_TOOL)
754 set_zoom_in(active_tool);
755 break;
756 default:
757 break;
760 break;
762 default:
763 break;
766 return return_val;
769 gint
770 ddisplay_hsb_update (GtkAdjustment *adjustment,
771 DDisplay *ddisp)
773 ddisplay_set_origo(ddisp, adjustment->value, ddisp->origo.y);
774 ddisplay_add_update_all(ddisp);
775 ddisplay_flush(ddisp);
776 return FALSE;
779 gint
780 ddisplay_vsb_update (GtkAdjustment *adjustment,
781 DDisplay *ddisp)
783 ddisplay_set_origo(ddisp, ddisp->origo.x, adjustment->value);
784 ddisplay_add_update_all(ddisp);
785 ddisplay_flush(ddisp);
786 return FALSE;
789 gint
790 ddisplay_delete (GtkWidget *widget, GdkEvent *event, gpointer data)
792 DDisplay *ddisp;
794 ddisp = (DDisplay *)data;
796 ddisplay_close(ddisp);
797 return TRUE;
800 void
801 ddisplay_destroy (GtkWidget *widget, gpointer data)
803 DDisplay *ddisp;
805 ddisp = (DDisplay *) data;
807 if (popup_shell == ddisp->shell) {
808 popup_shell = NULL;
811 ddisplay_really_destroy(ddisp);
814 inline int
815 round_up (double x)
817 if (x - (int) x > 0.001)
818 return (int) x + 1;
819 else
820 return (int) x ;
824 /* returns NULL if object cannot be created */
825 DiaObject *
826 ddisplay_drop_object(DDisplay *ddisp, gint x, gint y, DiaObjectType *otype,
827 gpointer user_data)
829 Point droppoint;
830 Point droppoint_orig;
831 Handle *handle1, *handle2;
832 DiaObject *obj, *p_obj;
833 GList *list;
834 real click_distance;
836 ddisplay_untransform_coords(ddisp, x, y, &droppoint.x, &droppoint.y);
838 /* save it before snap_to_grid modifies it */
839 droppoint_orig = droppoint;
841 snap_to_grid(ddisp, &droppoint.x, &droppoint.y);
843 obj = dia_object_default_create (otype, &droppoint,
844 user_data,
845 &handle1, &handle2);
848 click_distance = ddisplay_untransform_length(ddisp, 3.0);
850 /* Notice that using diagram_find_clicked_object doesn't allow any object
851 * below the first to be a parent. This should be fixed.
852 * -Lars
854 p_obj = diagram_find_clicked_object(ddisp->diagram, &droppoint_orig,
855 click_distance);
857 if (p_obj && p_obj->can_parent) /* the tool was dropped inside an object that takes children*/
859 Rectangle *p_ext, *c_ext;
860 real parent_height, child_height, parent_width, child_width;
861 real vadjust = 0.0, hadjust = 0.0;
862 Point new_pos;
864 obj->parent = p_obj;
865 p_obj->children = g_list_append(p_obj->children, obj);
867 /* This is not really what we want. We want the box containing all
868 * rendered parts of the object (not the bbox). But it'll do for now,
869 * since we don't have the 'rendered bbox'.
870 * -Lars
872 p_ext = parent_handle_extents(p_obj);
873 c_ext = parent_handle_extents(obj);
875 parent_height = p_ext->bottom - p_ext->top;
876 child_height = c_ext->bottom - c_ext->top;
878 parent_width = p_ext->right - p_ext->left;
879 child_width = c_ext->right - c_ext->left;
881 /* we need the pre-snap position, but must remember that handles can
882 * be to the left of the droppoint */
883 c_ext->left = droppoint_orig.x - (obj->position.x - c_ext->left);
884 c_ext->top = droppoint_orig.y - (obj->position.y - c_ext->top);
885 c_ext->right = c_ext->left + child_width;
886 c_ext->bottom = c_ext->top + child_height;
888 if (c_ext->left < p_ext->left) {
889 hadjust = p_ext->left - c_ext->left;
890 } else if (c_ext->right > p_ext->right) {
891 hadjust = p_ext->right - c_ext->right;
893 if (c_ext->top < p_ext->top) {
894 vadjust = p_ext->top - c_ext->top;
895 } else if (c_ext->bottom > p_ext->bottom) {
896 vadjust = p_ext->bottom - c_ext->bottom;
899 g_free(p_ext);
900 g_free(c_ext);
902 if (child_width > parent_width ||
903 child_height > parent_height) {
904 message_error(_("The object you dropped cannot fit into its parent. \nEither expand the parent object, or drop the object elsewhere."));
905 obj->parent->children = g_list_remove(obj->parent->children, obj);
906 obj->ops->destroy (obj);
907 return NULL;
910 if (hadjust || vadjust) {
911 new_pos.x = droppoint.x + hadjust;
912 new_pos.y = droppoint.y + vadjust;
913 obj->ops->move(obj, &new_pos);
918 diagram_add_object(ddisp->diagram, obj);
919 diagram_remove_all_selected(ddisp->diagram, TRUE); /* unselect all */
920 diagram_select(ddisp->diagram, obj);
921 obj->ops->selectf(obj, &droppoint, ddisp->renderer);
923 /* Connect first handle if possible: */
924 if ((handle1 != NULL) &&
925 (handle1->connect_type != HANDLE_NONCONNECTABLE)) {
926 object_connect_display(ddisp, obj, handle1);
928 object_add_updates(obj, ddisp->diagram);
929 ddisplay_do_update_menu_sensitivity(ddisp);
930 diagram_flush(ddisp->diagram);
932 list = g_list_prepend(NULL, obj);
933 undo_insert_objects(ddisp->diagram, list, 1);
934 diagram_update_extents(ddisp->diagram);
936 undo_set_transactionpoint(ddisp->diagram->undo);
937 diagram_modified(ddisp->diagram);
938 if (prefs.reset_tools_after_create)
939 tool_reset();
940 return obj;