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.
20 #include "create_object.h"
21 #include "connectionpoint_ops.h"
22 #include "handle_ops.h"
23 #include "object_ops.h"
24 #include "preferences.h"
27 #include "highlight.h"
30 static void create_object_button_press(CreateObjectTool
*tool
, GdkEventButton
*event
,
32 static void create_object_button_release(CreateObjectTool
*tool
, GdkEventButton
*event
,
34 static void create_object_motion(CreateObjectTool
*tool
, GdkEventMotion
*event
,
36 static void create_object_double_click(CreateObjectTool
*tool
, GdkEventMotion
*event
,
41 create_object_button_press(CreateObjectTool
*tool
, GdkEventButton
*event
,
44 Point clickedpoint
, origpoint
;
48 DiaObject
*parent_obj
;
52 ddisplay_untransform_coords(ddisp
,
53 (int)event
->x
, (int)event
->y
,
54 &clickedpoint
.x
, &clickedpoint
.y
);
56 origpoint
= clickedpoint
;
58 snap_to_grid(ddisp
, &clickedpoint
.x
, &clickedpoint
.y
);
60 click_distance
= ddisplay_untransform_length(ddisp
, 3.0);
62 obj
= dia_object_default_create (tool
->objtype
, &clickedpoint
,
66 diagram_add_object(ddisp
->diagram
, obj
);
68 /* Make sure to not parent to itself (!) */
69 avoid
= g_list_prepend(avoid
, obj
);
71 if (handle1
!= NULL
&&
72 handle1
->connect_type
!= HANDLE_NONCONNECTABLE
) {
73 ConnectionPoint
*connectionpoint
;
75 object_find_connectpoint_display(ddisp
, &origpoint
, obj
, TRUE
);
76 if (connectionpoint
!= NULL
) {
77 (obj
->ops
->move
)(obj
, &origpoint
);
78 /* Make sure to not parent to the object connected to */
79 avoid
= g_list_prepend(avoid
, connectionpoint
->object
);
84 parent_obj
= diagram_find_clicked_object_except(ddisp
->diagram
,
91 if (parent_obj
&& parent_obj
->can_parent
) /* starting point is within another object */
93 Change
*change
= undo_parenting(ddisp
->diagram
, parent_obj
, obj
, TRUE
);
94 (change
->apply
)(change
, ddisp
->diagram
);
96 obj->parent = parent_obj;
97 parent_obj->children = g_list_append(parent_obj->children, obj);
101 if (!(event
->state
& GDK_SHIFT_MASK
)) {
102 /* Not Multi-select => remove current selection */
103 diagram_remove_all_selected(ddisp
->diagram
, TRUE
);
105 diagram_select(ddisp
->diagram
, obj
);
109 /* Connect first handle if possible: */
110 if ((handle1
!= NULL
) &&
111 (handle1
->connect_type
!= HANDLE_NONCONNECTABLE
)) {
112 object_connect_display(ddisp
, obj
, handle1
, TRUE
);
115 object_add_updates(obj
, ddisp
->diagram
);
116 ddisplay_do_update_menu_sensitivity(ddisp
);
117 diagram_flush(ddisp
->diagram
);
119 if (handle2
!= NULL
) {
120 tool
->handle
= handle2
;
122 tool
->last_to
= handle2
->pos
;
124 gdk_pointer_grab (ddisp
->canvas
->window
, FALSE
,
125 GDK_POINTER_MOTION_HINT_MASK
| GDK_BUTTON1_MOTION_MASK
| GDK_BUTTON_RELEASE_MASK
,
126 NULL
, NULL
, event
->time
);
127 ddisplay_set_all_cursor(get_cursor(CURSOR_SCROLL
));
129 diagram_update_extents(ddisp
->diagram
);
130 tool
->moving
= FALSE
;
136 create_object_double_click(CreateObjectTool
*tool
, GdkEventMotion
*event
,
142 create_object_button_release(CreateObjectTool
*tool
, GdkEventButton
*event
,
146 DiaObject
*obj
= tool
->obj
;
148 gdk_pointer_ungrab (event
->time
);
150 object_add_updates(tool
->obj
, ddisp
->diagram
);
151 tool
->obj
->ops
->move_handle(tool
->obj
, tool
->handle
, &tool
->last_to
,
152 NULL
, HANDLE_MOVE_CREATE_FINAL
, 0);
153 object_add_updates(tool
->obj
, ddisp
->diagram
);
157 list
= g_list_prepend(list
, tool
->obj
);
159 undo_insert_objects(ddisp
->diagram
, list
, 1);
162 if (tool
->handle
->connect_type
!= HANDLE_NONCONNECTABLE
) {
163 object_connect_display(ddisp
, tool
->obj
, tool
->handle
, TRUE
);
164 diagram_update_connections_selection(ddisp
->diagram
);
165 diagram_flush(ddisp
->diagram
);
167 tool
->moving
= FALSE
;
172 highlight_reset_all(ddisp
->diagram
);
173 textedit_activate_object(ddisp
, obj
, NULL
);
174 diagram_update_extents(ddisp
->diagram
);
175 diagram_modified(ddisp
->diagram
);
177 undo_set_transactionpoint(ddisp
->diagram
->undo
);
179 if (prefs
.reset_tools_after_create
!= tool
->invert_persistence
)
181 ddisplay_set_all_cursor(default_cursor
);
184 create_object_motion(CreateObjectTool
*tool
, GdkEventMotion
*event
,
188 ConnectionPoint
*connectionpoint
= NULL
;
190 GtkStatusbar
*statusbar
;
196 ddisplay_untransform_coords(ddisp
, event
->x
, event
->y
, &to
.x
, &to
.y
);
198 /* make sure the new object is restricted to its parent */
199 parent_handle_move_out_check(tool
->obj
, &to
);
201 /* Move to ConnectionPoint if near: */
202 if (tool
->handle
!= NULL
&&
203 tool
->handle
->connect_type
!= HANDLE_NONCONNECTABLE
) {
205 object_find_connectpoint_display(ddisp
, &to
, tool
->obj
, TRUE
);
207 if (connectionpoint
!= NULL
) {
208 to
= connectionpoint
->pos
;
209 highlight_object(connectionpoint
->object
, NULL
, ddisp
->diagram
);
210 ddisplay_set_all_cursor(get_cursor(CURSOR_CONNECT
));
214 if (connectionpoint
== NULL
) {
215 /* No connectionopoint near, then snap to grid (if enabled) */
216 snap_to_grid(ddisp
, &to
.x
, &to
.y
);
217 highlight_reset_all(ddisp
->diagram
);
218 ddisplay_set_all_cursor(get_cursor(CURSOR_SCROLL
));
221 object_add_updates(tool
->obj
, ddisp
->diagram
);
222 tool
->obj
->ops
->move_handle(tool
->obj
, tool
->handle
, &to
, connectionpoint
,
223 HANDLE_MOVE_CREATE
, 0);
224 object_add_updates(tool
->obj
, ddisp
->diagram
);
226 /* Put current mouse position in status bar */
227 statusbar
= GTK_STATUSBAR (ddisp
->modified_status
);
228 context_id
= gtk_statusbar_get_context_id (statusbar
, "ObjectPos");
230 postext
= g_strdup_printf("%.3f, %.3f - %.3f, %.3f",
231 tool
->obj
->bounding_box
.left
,
232 tool
->obj
->bounding_box
.top
,
233 tool
->obj
->bounding_box
.right
,
234 tool
->obj
->bounding_box
.bottom
);
236 gtk_statusbar_pop (statusbar
, context_id
);
237 gtk_statusbar_push (statusbar
, context_id
, postext
);
241 diagram_flush(ddisp
->diagram
);
251 create_create_object_tool(DiaObjectType
*objtype
, void *user_data
,
252 int invert_persistence
)
254 CreateObjectTool
*tool
;
256 tool
= g_new0(CreateObjectTool
, 1);
257 tool
->tool
.type
= CREATE_OBJECT_TOOL
;
258 tool
->tool
.button_press_func
= (ButtonPressFunc
) &create_object_button_press
;
259 tool
->tool
.button_release_func
= (ButtonReleaseFunc
) &create_object_button_release
;
260 tool
->tool
.motion_func
= (MotionFunc
) &create_object_motion
;
261 tool
->tool
.double_click_func
= (DoubleClickFunc
) &create_object_double_click
;
263 tool
->objtype
= objtype
;
264 tool
->user_data
= user_data
;
265 tool
->moving
= FALSE
;
266 tool
->invert_persistence
= invert_persistence
;
268 return (Tool
*) tool
;
271 void free_create_object_tool(Tool
*tool
)