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"
38 #include "pixmaps/generalization.xpm"
40 typedef struct _Generalization Generalization
;
42 struct _Generalization
{
53 char *stereotype
; /* excluding << and >> */
54 char *st_stereotype
; /* including << and >> */
57 #define GENERALIZATION_WIDTH 0.1
58 #define GENERALIZATION_TRIANGLESIZE 0.8
59 #define GENERALIZATION_FONTHEIGHT 0.8
61 static DiaFont
*genlz_font
= NULL
;
63 static real
generalization_distance_from(Generalization
*genlz
, Point
*point
);
64 static void generalization_select(Generalization
*genlz
, Point
*clicked_point
,
65 DiaRenderer
*interactive_renderer
);
66 static ObjectChange
* generalization_move_handle(Generalization
*genlz
, Handle
*handle
,
67 Point
*to
, ConnectionPoint
*cp
,
68 HandleMoveReason reason
, ModifierKeys modifiers
);
69 static ObjectChange
* generalization_move(Generalization
*genlz
, Point
*to
);
70 static void generalization_draw(Generalization
*genlz
, DiaRenderer
*renderer
);
71 static DiaObject
*generalization_create(Point
*startpoint
,
75 static void generalization_destroy(Generalization
*genlz
);
76 static DiaMenu
*generalization_get_object_menu(Generalization
*genlz
,
79 static PropDescription
*generalization_describe_props(Generalization
*generalization
);
80 static void generalization_get_props(Generalization
* generalization
, GPtrArray
*props
);
81 static void generalization_set_props(Generalization
* generalization
, GPtrArray
*props
);
83 static DiaObject
*generalization_load(ObjectNode obj_node
, int version
,
84 const char *filename
);
86 static void generalization_update_data(Generalization
*genlz
);
88 static ObjectTypeOps generalization_type_ops
=
90 (CreateFunc
) generalization_create
,
91 (LoadFunc
) generalization_load
,/*using_properties*/ /* load */
92 (SaveFunc
) object_save_using_properties
, /* save */
93 (GetDefaultsFunc
) NULL
,
94 (ApplyDefaultsFunc
) NULL
97 DiaObjectType generalization_type
=
99 "UML - Generalization", /* name */
100 /* Version 0 had no autorouting and so shouldn't have it set by default. */
102 (char **) generalization_xpm
, /* pixmap */
104 &generalization_type_ops
, /* ops */
105 NULL
, /* pixmap_file */
106 0 /* default_user_data */
109 static ObjectOps generalization_ops
= {
110 (DestroyFunc
) generalization_destroy
,
111 (DrawFunc
) generalization_draw
,
112 (DistanceFunc
) generalization_distance_from
,
113 (SelectFunc
) generalization_select
,
114 (CopyFunc
) object_copy_using_properties
,
115 (MoveFunc
) generalization_move
,
116 (MoveHandleFunc
) generalization_move_handle
,
117 (GetPropertiesFunc
) object_create_props_dialog
,
118 (ApplyPropertiesFunc
) object_apply_props_from_dialog
,
119 (ObjectMenuFunc
) generalization_get_object_menu
,
120 (DescribePropsFunc
) generalization_describe_props
,
121 (GetPropsFunc
) generalization_get_props
,
122 (SetPropsFunc
) generalization_set_props
125 static PropDescription generalization_props
[] = {
126 ORTHCONN_COMMON_PROPERTIES
,
127 /* 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 */
128 PROP_STD_TEXT_COLOUR_OPTIONS(PROP_FLAG_VISIBLE
|PROP_FLAG_STANDARD
|PROP_FLAG_OPTIONAL
),
129 PROP_STD_LINE_COLOUR_OPTIONAL
,
130 { "name", PROP_TYPE_STRING
, PROP_FLAG_VISIBLE
,
131 N_("Name:"), NULL
, NULL
},
132 { "stereotype", PROP_TYPE_STRING
, PROP_FLAG_VISIBLE
,
133 N_("Stereotype:"), NULL
, NULL
},
137 static PropDescription
*
138 generalization_describe_props(Generalization
*generalization
)
140 if (generalization_props
[0].quark
== 0) {
141 prop_desc_list_calculate_quarks(generalization_props
);
143 return generalization_props
;
146 static PropOffset generalization_offsets
[] = {
147 ORTHCONN_COMMON_PROPERTIES_OFFSETS
,
148 {"text_colour",PROP_TYPE_COLOUR
,offsetof(Generalization
,text_color
)},
149 {"line_colour",PROP_TYPE_COLOUR
,offsetof(Generalization
,line_color
)},
150 { "name", PROP_TYPE_STRING
, offsetof(Generalization
, name
) },
151 { "stereotype", PROP_TYPE_STRING
, offsetof(Generalization
, stereotype
) },
156 generalization_get_props(Generalization
* generalization
, GPtrArray
*props
)
158 object_get_props_from_offsets(&generalization
->orth
.object
,
159 generalization_offsets
,props
);
163 generalization_set_props(Generalization
*generalization
, GPtrArray
*props
)
165 object_set_props_from_offsets(&generalization
->orth
.object
,
166 generalization_offsets
, props
);
167 g_free(generalization
->st_stereotype
);
168 generalization
->st_stereotype
= NULL
;
169 generalization_update_data(generalization
);
173 generalization_distance_from(Generalization
*genlz
, Point
*point
)
175 OrthConn
*orth
= &genlz
->orth
;
176 return orthconn_distance_from(orth
, point
, GENERALIZATION_WIDTH
);
180 generalization_select(Generalization
*genlz
, Point
*clicked_point
,
181 DiaRenderer
*interactive_renderer
)
183 orthconn_update_data(&genlz
->orth
);
187 generalization_move_handle(Generalization
*genlz
, Handle
*handle
,
188 Point
*to
, ConnectionPoint
*cp
,
189 HandleMoveReason reason
, ModifierKeys modifiers
)
191 ObjectChange
*change
;
193 assert(handle
!=NULL
);
196 change
= orthconn_move_handle(&genlz
->orth
, handle
, to
, cp
, reason
, modifiers
);
197 generalization_update_data(genlz
);
203 generalization_move(Generalization
*genlz
, Point
*to
)
205 ObjectChange
*change
;
207 change
= orthconn_move(&genlz
->orth
, to
);
208 generalization_update_data(genlz
);
214 generalization_draw(Generalization
*genlz
, DiaRenderer
*renderer
)
216 DiaRendererClass
*renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
217 OrthConn
*orth
= &genlz
->orth
;
223 points
= &orth
->points
[0];
226 renderer_ops
->set_linewidth(renderer
, GENERALIZATION_WIDTH
);
227 renderer_ops
->set_linestyle(renderer
, LINESTYLE_SOLID
);
228 renderer_ops
->set_linejoin(renderer
, LINEJOIN_MITER
);
229 renderer_ops
->set_linecaps(renderer
, LINECAPS_BUTT
);
231 arrow
.type
= ARROW_HOLLOW_TRIANGLE
;
232 arrow
.length
= GENERALIZATION_TRIANGLESIZE
;
233 arrow
.width
= GENERALIZATION_TRIANGLESIZE
;
235 renderer_ops
->draw_polyline_with_arrows(renderer
,
237 GENERALIZATION_WIDTH
,
241 renderer_ops
->set_font(renderer
, genlz_font
, GENERALIZATION_FONTHEIGHT
);
242 pos
= genlz
->text_pos
;
244 if (genlz
->st_stereotype
!= NULL
&& genlz
->st_stereotype
[0] != '\0') {
245 renderer_ops
->draw_string(renderer
,
246 genlz
->st_stereotype
,
247 &pos
, genlz
->text_align
,
250 pos
.y
+= GENERALIZATION_FONTHEIGHT
;
253 if (genlz
->name
!= NULL
&& genlz
->name
[0] != '\0') {
254 renderer_ops
->draw_string(renderer
,
256 &pos
, genlz
->text_align
,
263 generalization_update_data(Generalization
*genlz
)
265 OrthConn
*orth
= &genlz
->orth
;
266 DiaObject
*obj
= &orth
->object
;
274 orthconn_update_data(orth
);
276 genlz
->stereotype
= remove_stereotype_from_string(genlz
->stereotype
);
277 if (!genlz
->st_stereotype
) {
278 genlz
->st_stereotype
= string_to_stereotype(genlz
->stereotype
);
281 genlz
->text_width
= 0.0;
286 genlz
->text_width
= dia_font_string_width(genlz
->name
, genlz_font
,
287 GENERALIZATION_FONTHEIGHT
);
288 descent
= dia_font_descent(genlz
->name
,
289 genlz_font
,GENERALIZATION_FONTHEIGHT
);
290 ascent
= dia_font_ascent(genlz
->name
,
291 genlz_font
,GENERALIZATION_FONTHEIGHT
);
293 if (genlz
->stereotype
) {
294 genlz
->text_width
= MAX(genlz
->text_width
,
295 dia_font_string_width(genlz
->stereotype
,
297 GENERALIZATION_FONTHEIGHT
));
299 descent
= dia_font_descent(genlz
->stereotype
,
300 genlz_font
,GENERALIZATION_FONTHEIGHT
);
302 ascent
= dia_font_ascent(genlz
->stereotype
,
303 genlz_font
,GENERALIZATION_FONTHEIGHT
);
306 extra
= &orth
->extra_spacing
;
308 extra
->start_trans
= GENERALIZATION_WIDTH
/2.0 + GENERALIZATION_TRIANGLESIZE
;
310 extra
->middle_trans
=
312 extra
->end_long
= GENERALIZATION_WIDTH
/2.0;
314 orthconn_update_boundingbox(orth
);
317 num_segm
= genlz
->orth
.numpoints
- 1;
318 points
= genlz
->orth
.points
;
321 if ((num_segm
% 2) == 0) { /* If no middle segment, use horizontal */
322 if (genlz
->orth
.orientation
[i
]==VERTICAL
)
326 switch (genlz
->orth
.orientation
[i
]) {
328 genlz
->text_align
= ALIGN_CENTER
;
329 genlz
->text_pos
.x
= 0.5*(points
[i
].x
+points
[i
+1].x
);
330 genlz
->text_pos
.y
= points
[i
].y
- descent
;
333 genlz
->text_align
= ALIGN_LEFT
;
334 genlz
->text_pos
.x
= points
[i
].x
+ 0.1;
335 genlz
->text_pos
.y
= 0.5*(points
[i
].y
+points
[i
+1].y
) - descent
;
339 /* Add the text recangle to the bounding box: */
340 rect
.left
= genlz
->text_pos
.x
;
341 if (genlz
->text_align
== ALIGN_CENTER
)
342 rect
.left
-= genlz
->text_width
/2.0;
343 rect
.right
= rect
.left
+ genlz
->text_width
;
344 rect
.top
= genlz
->text_pos
.y
- ascent
;
345 rect
.bottom
= rect
.top
+ 2*GENERALIZATION_FONTHEIGHT
;
347 rectangle_union(&obj
->bounding_box
, &rect
);
350 static ObjectChange
*
351 generalization_add_segment_callback(DiaObject
*obj
, Point
*clicked
, gpointer data
)
353 ObjectChange
*change
;
354 change
= orthconn_add_segment((OrthConn
*)obj
, clicked
);
355 generalization_update_data((Generalization
*)obj
);
359 static ObjectChange
*
360 generalization_delete_segment_callback(DiaObject
*obj
, Point
*clicked
, gpointer data
)
362 ObjectChange
*change
;
363 change
= orthconn_delete_segment((OrthConn
*)obj
, clicked
);
364 generalization_update_data((Generalization
*)obj
);
369 static DiaMenuItem object_menu_items
[] = {
370 { N_("Add segment"), generalization_add_segment_callback
, NULL
, 1 },
371 { N_("Delete segment"), generalization_delete_segment_callback
, NULL
, 1 },
372 ORTHCONN_COMMON_MENUS
,
375 static DiaMenu object_menu
= {
377 sizeof(object_menu_items
)/sizeof(DiaMenuItem
),
383 generalization_get_object_menu(Generalization
*genlz
, Point
*clickedpoint
)
389 /* Set entries sensitive/selected etc here */
390 object_menu_items
[0].active
= orthconn_can_add_segment(orth
, clickedpoint
);
391 object_menu_items
[1].active
= orthconn_can_delete_segment(orth
, clickedpoint
);
392 orthconn_update_object_menu(orth
, clickedpoint
, &object_menu_items
[2]);
398 generalization_create(Point
*startpoint
,
403 Generalization
*genlz
;
408 if (genlz_font
== NULL
) {
409 genlz_font
= dia_font_new_from_style(DIA_FONT_MONOSPACE
, GENERALIZATION_FONTHEIGHT
);
412 genlz
= g_new0(Generalization
, 1);
414 obj
= (DiaObject
*)genlz
;
415 extra
= &orth
->extra_spacing
;
417 obj
->type
= &generalization_type
;
419 obj
->ops
= &generalization_ops
;
421 orthconn_init(orth
, startpoint
);
423 genlz
->text_color
= color_black
;
424 genlz
->line_color
= attributes_get_foreground();
426 genlz
->stereotype
= NULL
;
427 genlz
->st_stereotype
= NULL
;
429 generalization_update_data(genlz
);
431 *handle1
= orth
->handles
[0];
432 *handle2
= orth
->handles
[orth
->numpoints
-2];
434 return (DiaObject
*)genlz
;
438 generalization_destroy(Generalization
*genlz
)
441 g_free(genlz
->stereotype
);
442 g_free(genlz
->st_stereotype
);
444 orthconn_destroy(&genlz
->orth
);
448 generalization_load(ObjectNode obj_node
, int version
,
449 const char *filename
)
451 DiaObject
*obj
= object_load_using_properties(&generalization_type
,
452 obj_node
,version
,filename
);
455 /* In old objects with no autorouting, set it to false. */
456 attr
= object_find_attribute(obj_node
, "autorouting");
458 ((OrthConn
*)obj
)->autorouting
= FALSE
;