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"
31 static void create_object_button_press(CreateObjectTool
*tool
, GdkEventButton
*event
,
33 static void create_object_button_release(CreateObjectTool
*tool
, GdkEventButton
*event
,
35 static void create_object_motion(CreateObjectTool
*tool
, GdkEventMotion
*event
,
37 static void create_object_double_click(CreateObjectTool
*tool
, GdkEventMotion
*event
,
42 create_object_button_press(CreateObjectTool
*tool
, GdkEventButton
*event
,
45 Point clickedpoint
, origpoint
;
49 DiaObject
*parent_obj
;
53 ddisplay_untransform_coords(ddisp
,
54 (int)event
->x
, (int)event
->y
,
55 &clickedpoint
.x
, &clickedpoint
.y
);
57 origpoint
= clickedpoint
;
59 snap_to_grid(ddisp
, &clickedpoint
.x
, &clickedpoint
.y
);
61 click_distance
= ddisplay_untransform_length(ddisp
, 3.0);
63 obj
= dia_object_default_create (tool
->objtype
, &clickedpoint
,
67 diagram_add_object(ddisp
->diagram
, obj
);
69 /* Make sure to not parent to itself (!) */
70 avoid
= g_list_prepend(avoid
, obj
);
72 if (handle1
!= NULL
&&
73 handle1
->connect_type
!= HANDLE_NONCONNECTABLE
) {
74 ConnectionPoint
*connectionpoint
;
76 object_find_connectpoint_display(ddisp
, &origpoint
, obj
, TRUE
);
77 if (connectionpoint
!= NULL
) {
78 (obj
->ops
->move
)(obj
, &origpoint
);
79 /* Make sure to not parent to the object connected to */
80 avoid
= g_list_prepend(avoid
, connectionpoint
->object
);
85 parent_obj
= diagram_find_clicked_object_except(ddisp
->diagram
,
92 /* starting point is within another object */
93 if (parent_obj
&& object_flags_set(parent_obj
, DIA_OBJECT_CAN_PARENT
))
95 Change
*change
= undo_parenting(ddisp
->diagram
, parent_obj
, obj
, TRUE
);
96 (change
->apply
)(change
, ddisp
->diagram
);
98 obj->parent = parent_obj;
99 parent_obj->children = g_list_append(parent_obj->children, obj);
103 if (!(event
->state
& GDK_SHIFT_MASK
)) {
104 /* Not Multi-select => remove current selection */
105 diagram_remove_all_selected(ddisp
->diagram
, TRUE
);
107 diagram_select(ddisp
->diagram
, obj
);
111 /* Connect first handle if possible: */
112 if ((handle1
!= NULL
) &&
113 (handle1
->connect_type
!= HANDLE_NONCONNECTABLE
)) {
114 object_connect_display(ddisp
, obj
, handle1
, TRUE
);
117 object_add_updates(obj
, ddisp
->diagram
);
118 ddisplay_do_update_menu_sensitivity(ddisp
);
119 diagram_flush(ddisp
->diagram
);
121 if (handle2
!= NULL
) {
122 tool
->handle
= handle2
;
124 tool
->last_to
= handle2
->pos
;
126 gdk_pointer_grab (ddisp
->canvas
->window
, FALSE
,
127 GDK_POINTER_MOTION_HINT_MASK
| GDK_BUTTON1_MOTION_MASK
| GDK_BUTTON_RELEASE_MASK
,
128 NULL
, NULL
, event
->time
);
129 ddisplay_set_all_cursor(get_cursor(CURSOR_SCROLL
));
131 diagram_update_extents(ddisp
->diagram
);
132 tool
->moving
= FALSE
;
138 create_object_double_click(CreateObjectTool
*tool
, GdkEventMotion
*event
,
144 create_object_button_release(CreateObjectTool
*tool
, GdkEventButton
*event
,
148 DiaObject
*obj
= tool
->obj
;
150 gdk_pointer_ungrab (event
->time
);
152 object_add_updates(tool
->obj
, ddisp
->diagram
);
153 tool
->obj
->ops
->move_handle(tool
->obj
, tool
->handle
, &tool
->last_to
,
154 NULL
, HANDLE_MOVE_CREATE_FINAL
, 0);
155 object_add_updates(tool
->obj
, ddisp
->diagram
);
159 list
= g_list_prepend(list
, tool
->obj
);
161 undo_insert_objects(ddisp
->diagram
, list
, 1);
164 if (tool
->handle
->connect_type
!= HANDLE_NONCONNECTABLE
) {
165 object_connect_display(ddisp
, tool
->obj
, tool
->handle
, TRUE
);
166 diagram_update_connections_selection(ddisp
->diagram
);
167 diagram_flush(ddisp
->diagram
);
169 tool
->moving
= FALSE
;
174 highlight_reset_all(ddisp
->diagram
);
175 textedit_activate_object(ddisp
, obj
, NULL
);
176 diagram_update_extents(ddisp
->diagram
);
177 diagram_modified(ddisp
->diagram
);
179 undo_set_transactionpoint(ddisp
->diagram
->undo
);
181 if (prefs
.reset_tools_after_create
!= tool
->invert_persistence
)
183 ddisplay_set_all_cursor(default_cursor
);
186 create_object_motion(CreateObjectTool
*tool
, GdkEventMotion
*event
,
190 ConnectionPoint
*connectionpoint
= NULL
;
192 GtkStatusbar
*statusbar
;
198 ddisplay_untransform_coords(ddisp
, event
->x
, event
->y
, &to
.x
, &to
.y
);
200 /* make sure the new object is restricted to its parent */
201 parent_handle_move_out_check(tool
->obj
, &to
);
203 /* Move to ConnectionPoint if near: */
204 if (tool
->handle
!= NULL
&&
205 tool
->handle
->connect_type
!= HANDLE_NONCONNECTABLE
) {
207 object_find_connectpoint_display(ddisp
, &to
, tool
->obj
, TRUE
);
209 if (connectionpoint
!= NULL
) {
210 to
= connectionpoint
->pos
;
211 highlight_object(connectionpoint
->object
, NULL
, ddisp
->diagram
);
212 ddisplay_set_all_cursor(get_cursor(CURSOR_CONNECT
));
216 if (connectionpoint
== NULL
) {
217 /* No connectionopoint near, then snap to grid (if enabled) */
218 snap_to_grid(ddisp
, &to
.x
, &to
.y
);
219 highlight_reset_all(ddisp
->diagram
);
220 ddisplay_set_all_cursor(get_cursor(CURSOR_SCROLL
));
223 object_add_updates(tool
->obj
, ddisp
->diagram
);
224 tool
->obj
->ops
->move_handle(tool
->obj
, tool
->handle
, &to
, connectionpoint
,
225 HANDLE_MOVE_CREATE
, 0);
226 object_add_updates(tool
->obj
, ddisp
->diagram
);
228 /* Put current mouse position in status bar */
229 statusbar
= GTK_STATUSBAR (ddisp
->modified_status
);
230 context_id
= gtk_statusbar_get_context_id (statusbar
, "ObjectPos");
232 postext
= g_strdup_printf("%.3f, %.3f - %.3f, %.3f",
233 tool
->obj
->bounding_box
.left
,
234 tool
->obj
->bounding_box
.top
,
235 tool
->obj
->bounding_box
.right
,
236 tool
->obj
->bounding_box
.bottom
);
238 gtk_statusbar_pop (statusbar
, context_id
);
239 gtk_statusbar_push (statusbar
, context_id
, postext
);
243 diagram_flush(ddisp
->diagram
);
253 create_create_object_tool(DiaObjectType
*objtype
, void *user_data
,
254 int invert_persistence
)
256 CreateObjectTool
*tool
;
258 tool
= g_new0(CreateObjectTool
, 1);
259 tool
->tool
.type
= CREATE_OBJECT_TOOL
;
260 tool
->tool
.button_press_func
= (ButtonPressFunc
) &create_object_button_press
;
261 tool
->tool
.button_release_func
= (ButtonReleaseFunc
) &create_object_button_release
;
262 tool
->tool
.motion_func
= (MotionFunc
) &create_object_motion
;
263 tool
->tool
.double_click_func
= (DoubleClickFunc
) &create_object_double_click
;
265 tool
->objtype
= objtype
;
266 tool
->user_data
= user_data
;
267 tool
->moving
= FALSE
;
268 tool
->invert_persistence
= invert_persistence
;
270 return (Tool
*) tool
;
273 void free_create_object_tool(Tool
*tool
)