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.
29 #include "connection.h"
30 #include "diarenderer.h"
33 #include "properties.h"
34 #include "stereotype.h"
35 #include "attributes.h"
37 #include "pixmaps/constraint.xpm"
39 typedef struct _Constraint Constraint
;
42 Connection connection
;
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
,
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 */
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
,
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
)},
151 constraint_get_props(Constraint
* constraint
, GPtrArray
*props
)
153 object_get_props_from_offsets(&constraint
->connection
.object
,
154 constraint_offsets
, props
);
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
);
168 constraint_distance_from(Constraint
*constraint
, Point
*point
)
173 endpoints
= &constraint
->connection
.endpoints
[0];
175 dist
= distance_line_point(&endpoints
[0], &endpoints
[1],
176 CONSTRAINT_WIDTH
, point
);
181 constraint_select(Constraint
*constraint
, Point
*clicked_point
,
182 DiaRenderer
*interactive_renderer
)
184 connection_update_handles(&constraint
->connection
);
188 constraint_move_handle(Constraint
*constraint
, Handle
*handle
,
189 Point
*to
, ConnectionPoint
*cp
,
190 HandleMoveReason reason
, ModifierKeys modifiers
)
195 assert(constraint
!=NULL
);
196 assert(handle
!=NULL
);
199 if (handle
->id
== HANDLE_MOVE_TEXT
) {
200 constraint
->text_pos
= *to
;
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
,
207 p2
.x
= 0.5*(endpoints
[0].x
+ endpoints
[1].x
);
208 p2
.y
= 0.5*(endpoints
[0].y
+ endpoints
[1].y
);
210 point_add(&constraint
->text_pos
, &p2
);
213 constraint_update_data(constraint
);
219 constraint_move(Constraint
*constraint
, Point
*to
)
222 Point
*endpoints
= &constraint
->connection
.endpoints
[0];
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
);
242 constraint_draw(Constraint
*constraint
, DiaRenderer
*renderer
)
244 DiaRendererClass
*renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
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],
265 &constraint
->line_color
,
268 renderer_ops
->set_font(renderer
, constraint_font
,
269 CONSTRAINT_FONTHEIGHT
);
270 renderer_ops
->draw_string(renderer
,
272 &constraint
->text_pos
, ALIGN_LEFT
,
273 &constraint
->text_color
);
277 constraint_create(Point
*startpoint
,
282 Constraint
*constraint
;
285 Point defaultlen
= { 1.0, 1.0 };
287 if (constraint_font
== NULL
) {
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
);
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
;
328 constraint_destroy(Constraint
*constraint
)
330 connection_destroy(&constraint
->connection
);
331 g_free(constraint
->brtext
);
332 g_free(constraint
->text
);
336 constraint_update_data(Constraint
*constraint
)
338 Connection
*conn
= &constraint
->connection
;
339 DiaObject
*obj
= &conn
->object
;
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
,
356 CONSTRAINT_FONTHEIGHT
);
358 constraint
->text_handle
.pos
= constraint
->text_pos
;
360 connection_update_handles(conn
);
363 extra
= &conn
->extra_spacing
;
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
);
384 constraint_load(ObjectNode obj_node
, int version
, const char *filename
)
386 return object_load_using_properties(&constraint_type
,
387 obj_node
,version
,filename
);