More honesty about bug 144394, it's not quite fixed yet.
[dia.git] / app / create_object.c
blobd8d1295b241d99b20c1380e5491fa84c5277524e
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.
18 #include <config.h>
20 #include "create_object.h"
21 #include "connectionpoint_ops.h"
22 #include "handle_ops.h"
23 #include "object_ops.h"
24 #include "preferences.h"
25 #include "undo.h"
26 #include "cursor.h"
27 #include "highlight.h"
28 #include "textedit.h"
29 #include "parent.h"
31 static void create_object_button_press(CreateObjectTool *tool, GdkEventButton *event,
32 DDisplay *ddisp);
33 static void create_object_button_release(CreateObjectTool *tool, GdkEventButton *event,
34 DDisplay *ddisp);
35 static void create_object_motion(CreateObjectTool *tool, GdkEventMotion *event,
36 DDisplay *ddisp);
37 static void create_object_double_click(CreateObjectTool *tool, GdkEventMotion *event,
38 DDisplay *ddisp);
41 static void
42 create_object_button_press(CreateObjectTool *tool, GdkEventButton *event,
43 DDisplay *ddisp)
45 Point clickedpoint, origpoint;
46 Handle *handle1;
47 Handle *handle2;
48 DiaObject *obj;
49 DiaObject *parent_obj;
50 real click_distance;
51 GList *avoid = NULL;
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,
64 tool->user_data,
65 &handle1, &handle2);
67 diagram_add_object(ddisp->diagram, obj);
69 /* Make sure to not parent to itself (!) */
70 avoid = g_list_prepend(avoid, obj);
71 /* Try a connect */
72 if (handle1 != NULL &&
73 handle1->connect_type != HANDLE_NONCONNECTABLE) {
74 ConnectionPoint *connectionpoint;
75 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,
86 &clickedpoint,
87 click_distance,
88 avoid);
90 g_list_free(avoid);
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);
109 tool->obj = 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;
123 tool->moving = TRUE;
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));
130 } else {
131 diagram_update_extents(ddisp->diagram);
132 tool->moving = FALSE;
137 static void
138 create_object_double_click(CreateObjectTool *tool, GdkEventMotion *event,
139 DDisplay *ddisp)
143 static void
144 create_object_button_release(CreateObjectTool *tool, GdkEventButton *event,
145 DDisplay *ddisp)
147 GList *list = NULL;
148 DiaObject *obj = tool->obj;
149 if (tool->moving) {
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);
163 if (tool->moving) {
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;
170 tool->handle = NULL;
171 tool->obj = NULL;
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)
182 tool_reset();
183 ddisplay_set_all_cursor(default_cursor);
185 static void
186 create_object_motion(CreateObjectTool *tool, GdkEventMotion *event,
187 DDisplay *ddisp)
189 Point to;
190 ConnectionPoint *connectionpoint = NULL;
191 gchar *postext;
192 GtkStatusbar *statusbar;
193 guint context_id;
195 if (!tool->moving)
196 return;
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) {
206 connectionpoint =
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);
241 g_free(postext);
243 diagram_flush(ddisp->diagram);
245 tool->last_to = to;
247 return;
252 Tool *
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)
275 g_free(tool);