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"
33 #include "properties.h"
34 #include "stereotype.h"
37 #include "pixmaps/realizes.xpm"
39 typedef struct _Realizes Realizes
;
52 char *stereotype
; /* excluding << and >> */
53 char *st_stereotype
; /* including << and >> */
57 #define REALIZES_WIDTH 0.1
58 #define REALIZES_TRIANGLESIZE 0.8
59 #define REALIZES_DASHLEN 0.4
60 #define REALIZES_FONTHEIGHT 0.8
62 static DiaFont
*realize_font
= NULL
;
64 static real
realizes_distance_from(Realizes
*realize
, Point
*point
);
65 static void realizes_select(Realizes
*realize
, Point
*clicked_point
,
66 DiaRenderer
*interactive_renderer
);
67 static ObjectChange
* realizes_move_handle(Realizes
*realize
, Handle
*handle
,
68 Point
*to
, ConnectionPoint
*cp
,
69 HandleMoveReason reason
, ModifierKeys modifiers
);
70 static ObjectChange
* realizes_move(Realizes
*realize
, Point
*to
);
71 static void realizes_draw(Realizes
*realize
, DiaRenderer
*renderer
);
72 static DiaObject
*realizes_create(Point
*startpoint
,
76 static void realizes_destroy(Realizes
*realize
);
77 static DiaMenu
*realizes_get_object_menu(Realizes
*realize
,
80 static PropDescription
*realizes_describe_props(Realizes
*realizes
);
81 static void realizes_get_props(Realizes
* realizes
, GPtrArray
*props
);
82 static void realizes_set_props(Realizes
* realizes
, GPtrArray
*props
);
84 static DiaObject
*realizes_load(ObjectNode obj_node
, int version
,
85 const char *filename
);
87 static void realizes_update_data(Realizes
*realize
);
89 static ObjectTypeOps realizes_type_ops
=
91 (CreateFunc
) realizes_create
,
92 (LoadFunc
) realizes_load
,/*using_properties*/ /* load */
93 (SaveFunc
) object_save_using_properties
, /* save */
94 (GetDefaultsFunc
) NULL
,
95 (ApplyDefaultsFunc
) NULL
98 DiaObjectType realizes_type
=
100 "UML - Realizes", /* name */
101 /* Version 0 had no autorouting and so shouldn't have it set by default. */
103 (char **) realizes_xpm
, /* pixmap */
105 &realizes_type_ops
, /* ops */
106 NULL
, /* pixmap_file */
107 0 /* default_user_data */
110 static ObjectOps realizes_ops
= {
111 (DestroyFunc
) realizes_destroy
,
112 (DrawFunc
) realizes_draw
,
113 (DistanceFunc
) realizes_distance_from
,
114 (SelectFunc
) realizes_select
,
115 (CopyFunc
) object_copy_using_properties
,
116 (MoveFunc
) realizes_move
,
117 (MoveHandleFunc
) realizes_move_handle
,
118 (GetPropertiesFunc
) object_create_props_dialog
,
119 (ApplyPropertiesFunc
) object_apply_props_from_dialog
,
120 (ObjectMenuFunc
) realizes_get_object_menu
,
121 (DescribePropsFunc
) realizes_describe_props
,
122 (GetPropsFunc
) realizes_get_props
,
123 (SetPropsFunc
) realizes_set_props
126 static PropDescription realizes_props
[] = {
127 ORTHCONN_COMMON_PROPERTIES
,
128 PROP_STD_LINE_COLOUR_OPTIONAL
,
129 /* can't use PROP_STD_TEXT_COLOUR_OPTIONAL cause it has PROP_FLAG_DONT_SAVE. It is designed to fill the Text object - not some subset */
130 PROP_STD_TEXT_COLOUR_OPTIONS(PROP_FLAG_VISIBLE
|PROP_FLAG_STANDARD
|PROP_FLAG_OPTIONAL
),
131 { "name", PROP_TYPE_STRING
, PROP_FLAG_VISIBLE
,
132 N_("Name:"), NULL
, NULL
},
133 { "stereotype", PROP_TYPE_STRING
, PROP_FLAG_VISIBLE
,
134 N_("Stereotype:"), NULL
, NULL
},
138 static PropDescription
*
139 realizes_describe_props(Realizes
*realizes
)
141 if (realizes_props
[0].quark
== 0) {
142 prop_desc_list_calculate_quarks(realizes_props
);
144 return realizes_props
;
147 static PropOffset realizes_offsets
[] = {
148 ORTHCONN_COMMON_PROPERTIES_OFFSETS
,
149 { "line_colour", PROP_TYPE_COLOUR
, offsetof(Realizes
, line_color
) },
150 { "text_colour", PROP_TYPE_COLOUR
, offsetof(Realizes
, text_color
) },
151 { "name", PROP_TYPE_STRING
, offsetof(Realizes
, name
) },
152 { "stereotype", PROP_TYPE_STRING
, offsetof(Realizes
, stereotype
) },
157 realizes_get_props(Realizes
* realizes
, GPtrArray
*props
)
159 object_get_props_from_offsets(&realizes
->orth
.object
,
160 realizes_offsets
,props
);
164 realizes_set_props(Realizes
*realizes
, GPtrArray
*props
)
166 object_set_props_from_offsets(&realizes
->orth
.object
,
167 realizes_offsets
, props
);
168 g_free(realizes
->st_stereotype
);
169 realizes
->st_stereotype
= NULL
;
170 realizes_update_data(realizes
);
175 realizes_distance_from(Realizes
*realize
, Point
*point
)
177 OrthConn
*orth
= &realize
->orth
;
178 return orthconn_distance_from(orth
, point
, REALIZES_WIDTH
);
182 realizes_select(Realizes
*realize
, Point
*clicked_point
,
183 DiaRenderer
*interactive_renderer
)
185 orthconn_update_data(&realize
->orth
);
189 realizes_move_handle(Realizes
*realize
, Handle
*handle
,
190 Point
*to
, ConnectionPoint
*cp
,
191 HandleMoveReason reason
, ModifierKeys modifiers
)
193 ObjectChange
*change
;
194 assert(realize
!=NULL
);
195 assert(handle
!=NULL
);
198 change
= orthconn_move_handle(&realize
->orth
, handle
, to
, cp
, reason
, modifiers
);
199 realizes_update_data(realize
);
205 realizes_move(Realizes
*realize
, Point
*to
)
207 orthconn_move(&realize
->orth
, to
);
208 realizes_update_data(realize
);
214 realizes_draw(Realizes
*realize
, DiaRenderer
*renderer
)
216 DiaRendererClass
*renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
217 OrthConn
*orth
= &realize
->orth
;
223 points
= &orth
->points
[0];
226 renderer_ops
->set_linewidth(renderer
, REALIZES_WIDTH
);
227 renderer_ops
->set_linestyle(renderer
, LINESTYLE_DASHED
);
228 renderer_ops
->set_dashlength(renderer
, REALIZES_DASHLEN
);
229 renderer_ops
->set_linejoin(renderer
, LINEJOIN_MITER
);
230 renderer_ops
->set_linecaps(renderer
, LINECAPS_BUTT
);
232 arrow
.type
= ARROW_HOLLOW_TRIANGLE
;
233 arrow
.width
= REALIZES_TRIANGLESIZE
;
234 arrow
.length
= REALIZES_TRIANGLESIZE
;
235 renderer_ops
->draw_polyline_with_arrows(renderer
, points
, n
,
237 &realize
->line_color
,
240 renderer_ops
->set_font(renderer
, realize_font
, REALIZES_FONTHEIGHT
);
241 pos
= realize
->text_pos
;
243 if (realize
->st_stereotype
!= NULL
&& realize
->st_stereotype
[0] != '\0') {
244 renderer_ops
->draw_string(renderer
,
245 realize
->st_stereotype
,
246 &pos
, realize
->text_align
,
247 &realize
->text_color
);
249 pos
.y
+= REALIZES_FONTHEIGHT
;
252 if (realize
->name
!= NULL
&& realize
->name
[0] != '\0') {
253 renderer_ops
->draw_string(renderer
,
255 &pos
, realize
->text_align
,
256 &realize
->text_color
);
262 realizes_update_data(Realizes
*realize
)
264 OrthConn
*orth
= &realize
->orth
;
265 DiaObject
*obj
= &orth
->object
;
271 orthconn_update_data(orth
);
273 realize
->text_width
= 0.0;
275 realize
->stereotype
= remove_stereotype_from_string(realize
->stereotype
);
276 if (!realize
->st_stereotype
) {
277 realize
->st_stereotype
= string_to_stereotype(realize
->stereotype
);
281 realize
->text_width
= dia_font_string_width(realize
->name
, realize_font
,
282 REALIZES_FONTHEIGHT
);
283 if (realize
->stereotype
)
284 realize
->text_width
= MAX(realize
->text_width
,
285 dia_font_string_width(realize
->stereotype
,
287 REALIZES_FONTHEIGHT
));
289 extra
= &orth
->extra_spacing
;
291 extra
->start_trans
= REALIZES_WIDTH
/2.0 + REALIZES_TRIANGLESIZE
;
293 extra
->middle_trans
=
295 extra
->end_long
= REALIZES_WIDTH
/2.0;
297 orthconn_update_boundingbox(orth
);
300 num_segm
= realize
->orth
.numpoints
- 1;
301 points
= realize
->orth
.points
;
304 if ((num_segm
% 2) == 0) { /* If no middle segment, use horizontal */
305 if (realize
->orth
.orientation
[i
]==VERTICAL
)
309 switch (realize
->orth
.orientation
[i
]) {
311 realize
->text_align
= ALIGN_CENTER
;
312 realize
->text_pos
.x
= 0.5*(points
[i
].x
+points
[i
+1].x
);
313 realize
->text_pos
.y
= points
[i
].y
;
315 realize
->text_pos
.y
-=
316 dia_font_descent(realize
->name
,realize_font
, REALIZES_FONTHEIGHT
);
319 realize
->text_align
= ALIGN_LEFT
;
320 realize
->text_pos
.x
= points
[i
].x
+ 0.1;
321 realize
->text_pos
.y
= 0.5*(points
[i
].y
+points
[i
+1].y
);
323 realize
->text_pos
.y
-=
324 dia_font_descent(realize
->name
, realize_font
, REALIZES_FONTHEIGHT
);
328 /* Add the text recangle to the bounding box: */
329 rect
.left
= realize
->text_pos
.x
;
330 if (realize
->text_align
== ALIGN_CENTER
)
331 rect
.left
-= realize
->text_width
/2.0;
332 rect
.right
= rect
.left
+ realize
->text_width
;
333 rect
.top
= realize
->text_pos
.y
;
335 rect
.top
-= dia_font_ascent(realize
->name
,realize_font
, REALIZES_FONTHEIGHT
);
336 rect
.bottom
= rect
.top
+ 2*REALIZES_FONTHEIGHT
;
338 rectangle_union(&obj
->bounding_box
, &rect
);
341 static ObjectChange
*
342 realizes_add_segment_callback(DiaObject
*obj
, Point
*clicked
, gpointer data
)
344 ObjectChange
*change
;
345 change
= orthconn_add_segment((OrthConn
*)obj
, clicked
);
346 realizes_update_data((Realizes
*)obj
);
350 static ObjectChange
*
351 realizes_delete_segment_callback(DiaObject
*obj
, Point
*clicked
, gpointer data
)
353 ObjectChange
*change
;
354 change
= orthconn_delete_segment((OrthConn
*)obj
, clicked
);
355 realizes_update_data((Realizes
*)obj
);
360 static DiaMenuItem object_menu_items
[] = {
361 { N_("Add segment"), realizes_add_segment_callback
, NULL
, 1 },
362 { N_("Delete segment"), realizes_delete_segment_callback
, NULL
, 1 },
363 ORTHCONN_COMMON_MENUS
,
366 static DiaMenu object_menu
= {
368 sizeof(object_menu_items
)/sizeof(DiaMenuItem
),
374 realizes_get_object_menu(Realizes
*realize
, Point
*clickedpoint
)
378 orth
= &realize
->orth
;
379 /* Set entries sensitive/selected etc here */
380 object_menu_items
[0].active
= orthconn_can_add_segment(orth
, clickedpoint
);
381 object_menu_items
[1].active
= orthconn_can_delete_segment(orth
, clickedpoint
);
382 orthconn_update_object_menu(orth
, clickedpoint
, &object_menu_items
[2]);
387 realizes_create(Point
*startpoint
,
397 if (realize_font
== NULL
) {
399 dia_font_new_from_style (DIA_FONT_MONOSPACE
, REALIZES_FONTHEIGHT
);
402 realize
= g_malloc0(sizeof(Realizes
));
403 orth
= &realize
->orth
;
405 extra
= &orth
->extra_spacing
;
407 obj
->type
= &realizes_type
;
409 obj
->ops
= &realizes_ops
;
411 orthconn_init(orth
, startpoint
);
413 realize
->text_color
= color_black
;
414 realize
->line_color
= attributes_get_foreground();
416 realize
->name
= NULL
;
417 realize
->stereotype
= NULL
;
418 realize
->st_stereotype
= NULL
;
419 realize
->text_width
= 0;
421 extra
->start_trans
= REALIZES_WIDTH
/2.0 + REALIZES_TRIANGLESIZE
;
423 extra
->middle_trans
=
425 extra
->end_long
= REALIZES_WIDTH
/2.0;
427 realizes_update_data(realize
);
429 *handle1
= orth
->handles
[0];
430 *handle2
= orth
->handles
[orth
->numpoints
-2];
431 return &realize
->orth
.object
;
435 realizes_destroy(Realizes
*realize
)
437 g_free(realize
->name
);
438 g_free(realize
->stereotype
);
439 g_free(realize
->st_stereotype
);
440 orthconn_destroy(&realize
->orth
);
444 realizes_load(ObjectNode obj_node
, int version
, const char *filename
)
446 DiaObject
*obj
= object_load_using_properties(&realizes_type
,
447 obj_node
,version
,filename
);
450 /* In old objects with no autorouting, set it to false. */
451 attr
= object_find_attribute(obj_node
, "autorouting");
453 ((OrthConn
*)obj
)->autorouting
= FALSE
;