UML comments bug #303744
[dia.git] / objects / UML / constraint.c
blob3218eac5de2e36c233703299ce23c4f45c47c7ee
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 <assert.h>
24 #include <math.h>
25 #include <string.h>
27 #include "intl.h"
28 #include "object.h"
29 #include "connection.h"
30 #include "diarenderer.h"
31 #include "handle.h"
32 #include "arrows.h"
33 #include "properties.h"
34 #include "stereotype.h"
35 #include "attributes.h"
37 #include "pixmaps/constraint.xpm"
39 typedef struct _Constraint Constraint;
41 struct _Constraint {
42 Connection connection;
44 Handle text_handle;
46 char *text;
47 char *brtext;
48 Point text_pos;
49 real text_width;
51 Color text_color;
52 Color line_color;
56 #define CONSTRAINT_WIDTH 0.1
57 #define CONSTRAINT_DASHLEN 0.4
58 #define CONSTRAINT_FONTHEIGHT 0.8
59 #define CONSTRAINT_ARROWLEN 0.8
60 #define CONSTRAINT_ARROWWIDTH 0.5
62 #define HANDLE_MOVE_TEXT (HANDLE_CUSTOM1)
65 static DiaFont *constraint_font = NULL;
67 static ObjectChange* constraint_move_handle(Constraint *constraint, Handle *handle,
68 Point *to, ConnectionPoint *cp,
69 HandleMoveReason reason, ModifierKeys modifiers);
70 static ObjectChange* constraint_move(Constraint *constraint, Point *to);
71 static void constraint_select(Constraint *constraint, Point *clicked_point,
72 DiaRenderer *interactive_renderer);
73 static void constraint_draw(Constraint *constraint, DiaRenderer *renderer);
74 static DiaObject *constraint_create(Point *startpoint,
75 void *user_data,
76 Handle **handle1,
77 Handle **handle2);
78 static real constraint_distance_from(Constraint *constraint, Point *point);
79 static void constraint_update_data(Constraint *constraint);
80 static void constraint_destroy(Constraint *constraint);
82 static PropDescription *constraint_describe_props(Constraint *constraint);
83 static void constraint_get_props(Constraint * constraint, GPtrArray *props);
84 static void constraint_set_props(Constraint * constraint, GPtrArray *props);
86 static DiaObject *constraint_load(ObjectNode obj_node, int version,
87 const char *filename);
89 static ObjectTypeOps constraint_type_ops =
91 (CreateFunc) constraint_create,
92 (LoadFunc) constraint_load,/*using_properties*/ /* load */
93 (SaveFunc) object_save_using_properties, /* save */
94 (GetDefaultsFunc) NULL,
95 (ApplyDefaultsFunc) NULL
98 DiaObjectType constraint_type =
100 "UML - Constraint", /* name */
101 0, /* version */
102 (char **) constraint_xpm, /* pixmap */
103 &constraint_type_ops /* ops */
106 static ObjectOps constraint_ops = {
107 (DestroyFunc) constraint_destroy,
108 (DrawFunc) constraint_draw,
109 (DistanceFunc) constraint_distance_from,
110 (SelectFunc) constraint_select,
111 (CopyFunc) object_copy_using_properties,
112 (MoveFunc) constraint_move,
113 (MoveHandleFunc) constraint_move_handle,
114 (GetPropertiesFunc) object_create_props_dialog,
115 (ApplyPropertiesFunc) object_apply_props_from_dialog,
116 (ObjectMenuFunc) NULL,
117 (DescribePropsFunc) constraint_describe_props,
118 (GetPropsFunc) constraint_get_props,
119 (SetPropsFunc) constraint_set_props
122 static PropDescription constraint_props[] = {
123 CONNECTION_COMMON_PROPERTIES,
124 { "constraint", PROP_TYPE_STRING, PROP_FLAG_VISIBLE,
125 N_("Constraint:"), NULL, NULL },
126 { "text_pos", PROP_TYPE_POINT, 0, NULL, NULL, NULL},
127 PROP_STD_TEXT_COLOUR_OPTIONAL,
128 PROP_STD_LINE_COLOUR_OPTIONAL,
129 PROP_DESC_END
132 static PropDescription *
133 constraint_describe_props(Constraint *constraint)
135 if (constraint_props[0].quark == 0) {
136 prop_desc_list_calculate_quarks(constraint_props);
138 return constraint_props;
141 static PropOffset constraint_offsets[] = {
142 CONNECTION_COMMON_PROPERTIES_OFFSETS,
143 { "constraint", PROP_TYPE_STRING, offsetof(Constraint, text) },
144 { "text_pos", PROP_TYPE_POINT, offsetof(Constraint, text_pos) },
145 { "text_colour",PROP_TYPE_COLOUR,offsetof(Constraint, text_color)},
146 { "line_colour",PROP_TYPE_COLOUR,offsetof(Constraint, line_color)},
147 { NULL, 0, 0 }
150 static void
151 constraint_get_props(Constraint * constraint, GPtrArray *props)
153 object_get_props_from_offsets(&constraint->connection.object,
154 constraint_offsets, props);
157 static void
158 constraint_set_props(Constraint *constraint, GPtrArray *props)
160 object_set_props_from_offsets(&constraint->connection.object,
161 constraint_offsets, props);
162 g_free(constraint->brtext);
163 constraint->brtext = NULL;
164 constraint_update_data(constraint);
167 static real
168 constraint_distance_from(Constraint *constraint, Point *point)
170 Point *endpoints;
171 real dist;
173 endpoints = &constraint->connection.endpoints[0];
175 dist = distance_line_point(&endpoints[0], &endpoints[1],
176 CONSTRAINT_WIDTH, point);
177 return dist;
180 static void
181 constraint_select(Constraint *constraint, Point *clicked_point,
182 DiaRenderer *interactive_renderer)
184 connection_update_handles(&constraint->connection);
187 static ObjectChange*
188 constraint_move_handle(Constraint *constraint, Handle *handle,
189 Point *to, ConnectionPoint *cp,
190 HandleMoveReason reason, ModifierKeys modifiers)
192 Point p1, p2;
193 Point *endpoints;
195 assert(constraint!=NULL);
196 assert(handle!=NULL);
197 assert(to!=NULL);
199 if (handle->id == HANDLE_MOVE_TEXT) {
200 constraint->text_pos = *to;
201 } else {
202 endpoints = &constraint->connection.endpoints[0];
203 p1.x = 0.5*(endpoints[0].x + endpoints[1].x);
204 p1.y = 0.5*(endpoints[0].y + endpoints[1].y);
205 connection_move_handle(&constraint->connection, handle->id, to, cp,
206 reason, modifiers);
207 p2.x = 0.5*(endpoints[0].x + endpoints[1].x);
208 p2.y = 0.5*(endpoints[0].y + endpoints[1].y);
209 point_sub(&p2, &p1);
210 point_add(&constraint->text_pos, &p2);
213 constraint_update_data(constraint);
215 return NULL;
218 static ObjectChange*
219 constraint_move(Constraint *constraint, Point *to)
221 Point start_to_end;
222 Point *endpoints = &constraint->connection.endpoints[0];
223 Point delta;
225 delta = *to;
226 point_sub(&delta, &endpoints[0]);
228 start_to_end = endpoints[1];
229 point_sub(&start_to_end, &endpoints[0]);
231 endpoints[1] = endpoints[0] = *to;
232 point_add(&endpoints[1], &start_to_end);
234 point_add(&constraint->text_pos, &delta);
236 constraint_update_data(constraint);
238 return NULL;
241 static void
242 constraint_draw(Constraint *constraint, DiaRenderer *renderer)
244 DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
245 Point *endpoints;
246 Arrow arrow;
248 assert(constraint != NULL);
249 assert(renderer != NULL);
251 endpoints = &constraint->connection.endpoints[0];
253 renderer_ops->set_linewidth(renderer, CONSTRAINT_WIDTH);
254 renderer_ops->set_dashlength(renderer, CONSTRAINT_DASHLEN);
255 renderer_ops->set_linestyle(renderer, LINESTYLE_DASHED);
256 renderer_ops->set_linecaps(renderer, LINECAPS_BUTT);
258 arrow.type = ARROW_LINES;
259 arrow.length = CONSTRAINT_ARROWLEN;
260 arrow.width = CONSTRAINT_ARROWWIDTH;
262 renderer_ops->draw_line_with_arrows(renderer,
263 &endpoints[0], &endpoints[1],
264 CONSTRAINT_WIDTH,
265 &constraint->line_color,
266 NULL, &arrow);
268 renderer_ops->set_font(renderer, constraint_font,
269 CONSTRAINT_FONTHEIGHT);
270 renderer_ops->draw_string(renderer,
271 constraint->brtext,
272 &constraint->text_pos, ALIGN_LEFT,
273 &constraint->text_color);
276 static DiaObject *
277 constraint_create(Point *startpoint,
278 void *user_data,
279 Handle **handle1,
280 Handle **handle2)
282 Constraint *constraint;
283 Connection *conn;
284 DiaObject *obj;
285 Point defaultlen = { 1.0, 1.0 };
287 if (constraint_font == NULL) {
288 constraint_font =
289 dia_font_new_from_style (DIA_FONT_MONOSPACE, CONSTRAINT_FONTHEIGHT);
292 constraint = g_malloc0(sizeof(Constraint));
294 conn = &constraint->connection;
295 conn->endpoints[0] = *startpoint;
296 conn->endpoints[1] = *startpoint;
297 point_add(&conn->endpoints[1], &defaultlen);
299 obj = &conn->object;
301 obj->type = &constraint_type;
302 obj->ops = &constraint_ops;
304 connection_init(conn, 3, 0);
306 constraint->text_color = color_black;
307 constraint->line_color = attributes_get_foreground();
308 constraint->text = g_strdup("");
309 constraint->text_pos.x = 0.5*(conn->endpoints[0].x + conn->endpoints[1].x);
310 constraint->text_pos.y = 0.5*(conn->endpoints[0].y + conn->endpoints[1].y) - 0.2;
312 constraint->text_handle.id = HANDLE_MOVE_TEXT;
313 constraint->text_handle.type = HANDLE_MINOR_CONTROL;
314 constraint->text_handle.connect_type = HANDLE_NONCONNECTABLE;
315 constraint->text_handle.connected_to = NULL;
316 obj->handles[2] = &constraint->text_handle;
318 constraint->brtext = NULL;
319 constraint_update_data(constraint);
321 *handle1 = obj->handles[0];
322 *handle2 = obj->handles[1];
323 return &constraint->connection.object;
327 static void
328 constraint_destroy(Constraint *constraint)
330 connection_destroy(&constraint->connection);
331 g_free(constraint->brtext);
332 g_free(constraint->text);
335 static void
336 constraint_update_data(Constraint *constraint)
338 Connection *conn = &constraint->connection;
339 DiaObject *obj = &conn->object;
340 Rectangle rect;
341 LineBBExtras *extra;
343 if ((constraint->text) && (constraint->text[0] == '{')) {
344 /* we might have a string loaded from an older dia. Clean it up. */
345 g_free(constraint->brtext);
346 constraint->brtext = constraint->text;
347 constraint->text = bracketted_to_string(constraint->text,"{","}");
348 } else if (!constraint->brtext) {
349 constraint->brtext = string_to_bracketted(constraint->text, "{", "}");
352 obj->position = conn->endpoints[0];
354 constraint->text_width = dia_font_string_width(constraint->brtext,
355 constraint_font,
356 CONSTRAINT_FONTHEIGHT);
358 constraint->text_handle.pos = constraint->text_pos;
360 connection_update_handles(conn);
362 /* Boundingbox: */
363 extra = &conn->extra_spacing;
365 extra->start_long =
366 extra->start_trans =
367 extra->end_long = CONSTRAINT_WIDTH/2.0;
368 extra->end_trans = MAX(CONSTRAINT_WIDTH,CONSTRAINT_ARROWLEN)/2.0;
370 connection_update_boundingbox(conn);
372 /* Add boundingbox for text: */
373 rect.left = constraint->text_pos.x;
374 rect.right = rect.left + constraint->text_width;
375 rect.top = constraint->text_pos.y -
376 dia_font_ascent(constraint->brtext,
377 constraint_font, CONSTRAINT_FONTHEIGHT);
378 rect.bottom = rect.top + CONSTRAINT_FONTHEIGHT;
379 rectangle_union(&obj->bounding_box, &rect);
383 static DiaObject *
384 constraint_load(ObjectNode obj_node, int version, const char *filename)
386 return object_load_using_properties(&constraint_type,
387 obj_node,version,filename);