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 "orth_conn.h"
30 #include "diarenderer.h"
31 #include "attributes.h"
34 #include "properties.h"
36 #include "stereotype.h"
39 #include "pixmaps/dependency.xpm"
41 typedef struct _Dependency Dependency
;
55 char *stereotype
; /* excluding << and >> */
56 char *st_stereotype
; /* including << and >> */
60 #define DEPENDENCY_WIDTH 0.1
61 #define DEPENDENCY_ARROWLEN 0.8
62 #define DEPENDENCY_ARROWWIDTH 0.5
63 #define DEPENDENCY_DASHLEN 0.4
64 #define DEPENDENCY_FONTHEIGHT 0.8
66 static DiaFont
*dep_font
= NULL
;
68 static real
dependency_distance_from(Dependency
*dep
, Point
*point
);
69 static void dependency_select(Dependency
*dep
, Point
*clicked_point
,
70 DiaRenderer
*interactive_renderer
);
71 static ObjectChange
* dependency_move_handle(Dependency
*dep
, Handle
*handle
,
72 Point
*to
, ConnectionPoint
*cp
,
73 HandleMoveReason reason
, ModifierKeys modifiers
);
74 static ObjectChange
* dependency_move(Dependency
*dep
, Point
*to
);
75 static void dependency_draw(Dependency
*dep
, DiaRenderer
*renderer
);
76 static DiaObject
*dependency_create(Point
*startpoint
,
80 static void dependency_destroy(Dependency
*dep
);
81 static DiaMenu
*dependency_get_object_menu(Dependency
*dep
,
84 static DiaObject
*dependency_load(ObjectNode obj_node
, int version
,
85 const char *filename
);
86 static PropDescription
*dependency_describe_props(Dependency
*dependency
);
87 static void dependency_get_props(Dependency
* dependency
, GPtrArray
*props
);
88 static void dependency_set_props(Dependency
* dependency
, GPtrArray
*props
);
90 static void dependency_update_data(Dependency
*dep
);
92 static ObjectTypeOps dependency_type_ops
=
94 (CreateFunc
) dependency_create
,
95 (LoadFunc
) dependency_load
,/*using_properties*/ /* load */
96 (SaveFunc
) object_save_using_properties
, /* save */
97 (GetDefaultsFunc
) NULL
,
98 (ApplyDefaultsFunc
) NULL
101 DiaObjectType dependency_type
=
103 "UML - Dependency", /* name */
104 /* Version 0 had no autorouting and so shouldn't have it set by default. */
106 (char **) dependency_xpm
, /* pixmap */
108 &dependency_type_ops
, /* ops */
109 NULL
, /* pixmap_file */
110 0 /* default_user_data */
113 static ObjectOps dependency_ops
= {
114 (DestroyFunc
) dependency_destroy
,
115 (DrawFunc
) dependency_draw
,
116 (DistanceFunc
) dependency_distance_from
,
117 (SelectFunc
) dependency_select
,
118 (CopyFunc
) object_copy_using_properties
,
119 (MoveFunc
) dependency_move
,
120 (MoveHandleFunc
) dependency_move_handle
,
121 (GetPropertiesFunc
) object_create_props_dialog
,
122 (ApplyPropertiesFunc
) object_apply_props_from_dialog
,
123 (ObjectMenuFunc
) dependency_get_object_menu
,
124 (DescribePropsFunc
) dependency_describe_props
,
125 (GetPropsFunc
) dependency_get_props
,
126 (SetPropsFunc
) dependency_set_props
129 static PropDescription dependency_props
[] = {
130 ORTHCONN_COMMON_PROPERTIES
,
131 PROP_STD_TEXT_COLOUR_OPTIONAL
,
132 PROP_STD_LINE_COLOUR_OPTIONAL
,
133 { "name", PROP_TYPE_STRING
, PROP_FLAG_VISIBLE
,
134 N_("Name:"), NULL
, NULL
},
135 { "stereotype", PROP_TYPE_STRING
, PROP_FLAG_VISIBLE
,
136 N_("Stereotype:"), NULL
, NULL
},
137 { "draw_arrow", PROP_TYPE_BOOL
, PROP_FLAG_VISIBLE
,
138 N_("Show arrow:"), NULL
, NULL
},
142 static PropDescription
*
143 dependency_describe_props(Dependency
*dependency
)
145 if (dependency_props
[0].quark
== 0) {
146 prop_desc_list_calculate_quarks(dependency_props
);
148 return dependency_props
;
151 static PropOffset dependency_offsets
[] = {
152 ORTHCONN_COMMON_PROPERTIES_OFFSETS
,
153 { "text_colour", PROP_TYPE_COLOUR
, offsetof(Dependency
, text_color
) },
154 { "line_colour", PROP_TYPE_COLOUR
, offsetof(Dependency
, line_color
) },
155 { "name", PROP_TYPE_STRING
, offsetof(Dependency
, name
) },
156 { "stereotype", PROP_TYPE_STRING
, offsetof(Dependency
, stereotype
) },
157 { "draw_arrow", PROP_TYPE_BOOL
, offsetof(Dependency
, draw_arrow
) },
162 dependency_get_props(Dependency
* dependency
, GPtrArray
*props
)
164 object_get_props_from_offsets(&dependency
->orth
.object
,
165 dependency_offsets
,props
);
169 dependency_set_props(Dependency
*dependency
, GPtrArray
*props
)
171 object_set_props_from_offsets(&dependency
->orth
.object
,
172 dependency_offsets
, props
);
173 g_free(dependency
->st_stereotype
);
174 dependency
->st_stereotype
= NULL
;
175 dependency_update_data(dependency
);
179 dependency_distance_from(Dependency
*dep
, Point
*point
)
181 OrthConn
*orth
= &dep
->orth
;
182 return orthconn_distance_from(orth
, point
, DEPENDENCY_WIDTH
);
186 dependency_select(Dependency
*dep
, Point
*clicked_point
,
187 DiaRenderer
*interactive_renderer
)
189 orthconn_update_data(&dep
->orth
);
193 dependency_move_handle(Dependency
*dep
, Handle
*handle
,
194 Point
*to
, ConnectionPoint
*cp
,
195 HandleMoveReason reason
, ModifierKeys modifiers
)
197 ObjectChange
*change
;
199 assert(handle
!=NULL
);
202 change
= orthconn_move_handle(&dep
->orth
, handle
, to
, cp
, reason
, modifiers
);
203 dependency_update_data(dep
);
209 dependency_move(Dependency
*dep
, Point
*to
)
211 ObjectChange
*change
;
213 change
= orthconn_move(&dep
->orth
, to
);
214 dependency_update_data(dep
);
220 dependency_draw(Dependency
*dep
, DiaRenderer
*renderer
)
222 DiaRendererClass
*renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
223 OrthConn
*orth
= &dep
->orth
;
229 points
= &orth
->points
[0];
232 renderer_ops
->set_linewidth(renderer
, DEPENDENCY_WIDTH
);
233 renderer_ops
->set_linestyle(renderer
, LINESTYLE_DASHED
);
234 renderer_ops
->set_dashlength(renderer
, DEPENDENCY_DASHLEN
);
235 renderer_ops
->set_linejoin(renderer
, LINEJOIN_MITER
);
236 renderer_ops
->set_linecaps(renderer
, LINECAPS_BUTT
);
238 arrow
.type
= ARROW_LINES
;
239 arrow
.length
= DEPENDENCY_ARROWLEN
;
240 arrow
.width
= DEPENDENCY_ARROWWIDTH
;
242 renderer_ops
->draw_polyline_with_arrows(renderer
,
248 renderer_ops
->set_font(renderer
, dep_font
, DEPENDENCY_FONTHEIGHT
);
251 if (dep
->st_stereotype
!= NULL
&& dep
->st_stereotype
[0] != '\0') {
252 renderer_ops
->draw_string(renderer
,
254 &pos
, dep
->text_align
,
257 pos
.y
+= DEPENDENCY_FONTHEIGHT
;
260 if (dep
->name
!= NULL
&& dep
->name
[0] != '\0') {
261 renderer_ops
->draw_string(renderer
,
263 &pos
, dep
->text_align
,
270 dependency_update_data(Dependency
*dep
)
272 OrthConn
*orth
= &dep
->orth
;
273 DiaObject
*obj
= &orth
->object
;
274 PolyBBExtras
*extra
= &orth
->extra_spacing
;
279 orthconn_update_data(orth
);
281 dep
->stereotype
= remove_stereotype_from_string(dep
->stereotype
);
282 if (!dep
->st_stereotype
) {
283 dep
->st_stereotype
= string_to_stereotype(dep
->stereotype
);
286 dep
->text_width
= 0.0;
288 dep
->text_width
= dia_font_string_width(dep
->name
, dep_font
,
289 DEPENDENCY_FONTHEIGHT
);
291 dep
->text_width
= MAX(dep
->text_width
,
292 dia_font_string_width(dep
->stereotype
, dep_font
,
293 DEPENDENCY_FONTHEIGHT
));
297 extra
->middle_trans
= DEPENDENCY_WIDTH
/2.0;
300 extra
->end_long
= (dep
->draw_arrow
?
301 (DEPENDENCY_WIDTH
+ DEPENDENCY_ARROWLEN
)/2.0:
302 DEPENDENCY_WIDTH
/2.0);
304 orthconn_update_boundingbox(orth
);
307 num_segm
= dep
->orth
.numpoints
- 1;
308 points
= dep
->orth
.points
;
311 if ((num_segm
% 2) == 0) { /* If no middle segment, use horizontal */
312 if (dep
->orth
.orientation
[i
]==VERTICAL
)
316 switch (dep
->orth
.orientation
[i
]) {
318 dep
->text_align
= ALIGN_CENTER
;
319 dep
->text_pos
.x
= 0.5*(points
[i
].x
+points
[i
+1].x
);
320 dep
->text_pos
.y
= points
[i
].y
;
322 dep
->text_pos
.y
-= dia_font_descent(dep
->name
,
324 DEPENDENCY_FONTHEIGHT
);
327 dep
->text_align
= ALIGN_LEFT
;
328 dep
->text_pos
.x
= points
[i
].x
+ 0.1;
330 0.5*(points
[i
].y
+points
[i
+1].y
);
332 dep
->text_pos
.y
-= dia_font_descent(dep
->name
,
334 DEPENDENCY_FONTHEIGHT
);
338 /* Add the text recangle to the bounding box: */
339 rect
.left
= dep
->text_pos
.x
;
340 if (dep
->text_align
== ALIGN_CENTER
)
341 rect
.left
-= dep
->text_width
/2.0;
342 rect
.right
= rect
.left
+ dep
->text_width
;
343 rect
.top
= dep
->text_pos
.y
;
345 rect
.top
-= dia_font_ascent(dep
->name
,
347 DEPENDENCY_FONTHEIGHT
);
348 rect
.bottom
= rect
.top
+ 2*DEPENDENCY_FONTHEIGHT
;
350 rectangle_union(&obj
->bounding_box
, &rect
);
353 static ObjectChange
*
354 dependency_add_segment_callback(DiaObject
*obj
, Point
*clicked
, gpointer data
)
356 ObjectChange
*change
;
357 change
= orthconn_add_segment((OrthConn
*)obj
, clicked
);
358 dependency_update_data((Dependency
*)obj
);
362 static ObjectChange
*
363 dependency_delete_segment_callback(DiaObject
*obj
, Point
*clicked
, gpointer data
)
365 ObjectChange
*change
;
366 change
= orthconn_delete_segment((OrthConn
*)obj
, clicked
);
367 dependency_update_data((Dependency
*)obj
);
372 static DiaMenuItem object_menu_items
[] = {
373 { N_("Add segment"), dependency_add_segment_callback
, NULL
, 1 },
374 { N_("Delete segment"), dependency_delete_segment_callback
, NULL
, 1 },
375 ORTHCONN_COMMON_MENUS
,
378 static DiaMenu object_menu
= {
380 sizeof(object_menu_items
)/sizeof(DiaMenuItem
),
386 dependency_get_object_menu(Dependency
*dep
, Point
*clickedpoint
)
391 /* Set entries sensitive/selected etc here */
392 object_menu_items
[0].active
= orthconn_can_add_segment(orth
, clickedpoint
);
393 object_menu_items
[1].active
= orthconn_can_delete_segment(orth
, clickedpoint
);
394 orthconn_update_object_menu(orth
, clickedpoint
, &object_menu_items
[2]);
400 dependency_create(Point
*startpoint
,
409 if (dep_font
== NULL
) {
410 dep_font
= dia_font_new_from_style(DIA_FONT_MONOSPACE
, DEPENDENCY_FONTHEIGHT
);
413 dep
= g_new0(Dependency
, 1);
415 obj
= (DiaObject
*)dep
;
417 obj
->type
= &dependency_type
;
419 obj
->ops
= &dependency_ops
;
421 orthconn_init(orth
, startpoint
);
423 dep
->text_color
= color_black
;
424 dep
->line_color
= attributes_get_foreground();
425 dep
->draw_arrow
= TRUE
;
427 dep
->stereotype
= NULL
;
428 dep
->st_stereotype
= NULL
;
431 dependency_update_data(dep
);
433 *handle1
= orth
->handles
[0];
434 *handle2
= orth
->handles
[orth
->numpoints
-2];
436 return (DiaObject
*)dep
;
440 dependency_destroy(Dependency
*dep
)
443 g_free(dep
->stereotype
);
444 g_free(dep
->st_stereotype
);
446 orthconn_destroy(&dep
->orth
);
450 dependency_load(ObjectNode obj_node
, int version
, const char *filename
)
452 DiaObject
*obj
= object_load_using_properties(&dependency_type
,
453 obj_node
,version
,filename
);
456 /* In old objects with no autorouting, set it to false. */
457 attr
= object_find_attribute(obj_node
, "autorouting");
459 ((OrthConn
*)obj
)->autorouting
= FALSE
;