1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1999 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.
30 #include "diarenderer.h"
31 #include "attributes.h"
33 #include "properties.h"
35 #include "stereotype.h"
37 #include "pixmaps/component.xpm"
39 #define NUM_CONNECTIONS 11
41 typedef struct _Component Component
;
45 ConnectionPoint connections
[NUM_CONNECTIONS
];
57 #define COMPONENT_BORDERWIDTH 0.1
58 #define COMPONENT_CHEIGHT 0.7
59 #define COMPONENT_CWIDTH 2.0
60 #define COMPONENT_MARGIN_X 0.4
61 #define COMPONENT_MARGIN_Y 0.3
63 static real
component_distance_from(Component
*cmp
, Point
*point
);
64 static void component_select(Component
*cmp
, Point
*clicked_point
,
65 DiaRenderer
*interactive_renderer
);
66 static ObjectChange
* component_move_handle(Component
*cmp
, Handle
*handle
,
67 Point
*to
, ConnectionPoint
*cp
,
68 HandleMoveReason reason
, ModifierKeys modifiers
);
69 static ObjectChange
* component_move(Component
*cmp
, Point
*to
);
70 static void component_draw(Component
*cmp
, DiaRenderer
*renderer
);
71 static DiaObject
*component_create(Point
*startpoint
,
75 static void component_destroy(Component
*cmp
);
76 static DiaObject
*component_load(ObjectNode obj_node
, int version
,
77 const char *filename
);
79 static PropDescription
*component_describe_props(Component
*component
);
80 static void component_get_props(Component
*component
, GPtrArray
*props
);
81 static void component_set_props(Component
*component
, GPtrArray
*props
);
83 static void component_update_data(Component
*cmp
);
85 static ObjectTypeOps component_type_ops
=
87 (CreateFunc
) component_create
,
88 (LoadFunc
) component_load
,/*using_properties*/ /* load */
89 (SaveFunc
) object_save_using_properties
, /* save */
90 (GetDefaultsFunc
) NULL
,
91 (ApplyDefaultsFunc
) NULL
94 DiaObjectType component_type
=
96 "UML - Component", /* name */
98 (char **) component_xpm
, /* pixmap */
100 &component_type_ops
/* ops */
103 static ObjectOps component_ops
= {
104 (DestroyFunc
) component_destroy
,
105 (DrawFunc
) component_draw
,
106 (DistanceFunc
) component_distance_from
,
107 (SelectFunc
) component_select
,
108 (CopyFunc
) object_copy_using_properties
,
109 (MoveFunc
) component_move
,
110 (MoveHandleFunc
) component_move_handle
,
111 (GetPropertiesFunc
) object_create_props_dialog
,
112 (ApplyPropertiesFunc
) object_apply_props_from_dialog
,
113 (ObjectMenuFunc
) NULL
,
114 (DescribePropsFunc
) component_describe_props
,
115 (GetPropsFunc
) component_get_props
,
116 (SetPropsFunc
) component_set_props
119 static PropDescription component_props
[] = {
120 ELEMENT_COMMON_PROPERTIES
,
121 PROP_STD_LINE_COLOUR_OPTIONAL
,
122 PROP_STD_FILL_COLOUR_OPTIONAL
,
123 { "stereotype", PROP_TYPE_STRING
, PROP_FLAG_VISIBLE
,
124 N_("Stereotype"), NULL
, NULL
},
126 PROP_STD_TEXT_HEIGHT
,
127 PROP_STD_TEXT_COLOUR
,
128 { "text", PROP_TYPE_TEXT
, 0, N_("Text"), NULL
, NULL
},
132 static PropDescription
*
133 component_describe_props(Component
*component
)
135 if (component_props
[0].quark
== 0) {
136 prop_desc_list_calculate_quarks(component_props
);
138 return component_props
;
141 static PropOffset component_offsets
[] = {
142 ELEMENT_COMMON_PROPERTIES_OFFSETS
,
143 {"line_colour",PROP_TYPE_COLOUR
,offsetof(Component
,line_color
)},
144 {"fill_colour",PROP_TYPE_COLOUR
,offsetof(Component
,fill_color
)},
145 {"stereotype", PROP_TYPE_STRING
, offsetof(Component
, stereotype
) },
146 {"text",PROP_TYPE_TEXT
,offsetof(Component
,text
)},
147 {"text_font",PROP_TYPE_FONT
,offsetof(Component
,attrs
.font
)},
148 {"text_height",PROP_TYPE_REAL
,offsetof(Component
,attrs
.height
)},
149 {"text_colour",PROP_TYPE_COLOUR
,offsetof(Component
,attrs
.color
)},
155 component_get_props(Component
* component
, GPtrArray
*props
)
157 text_get_attributes(component
->text
,&component
->attrs
);
158 object_get_props_from_offsets(&component
->element
.object
,
159 component_offsets
,props
);
163 component_set_props(Component
*component
, GPtrArray
*props
)
165 object_set_props_from_offsets(&component
->element
.object
,
166 component_offsets
, props
);
167 apply_textattr_properties(props
,component
->text
,"text",&component
->attrs
);
168 g_free(component
->st_stereotype
);
169 component
->st_stereotype
= NULL
;
170 component_update_data(component
);
174 component_distance_from(Component
*cmp
, Point
*point
)
176 DiaObject
*obj
= &cmp
->element
.object
;
177 return distance_rectangle_point(&obj
->bounding_box
, point
);
181 component_select(Component
*cmp
, Point
*clicked_point
,
182 DiaRenderer
*interactive_renderer
)
184 text_set_cursor(cmp
->text
, clicked_point
, interactive_renderer
);
185 text_grab_focus(cmp
->text
, &cmp
->element
.object
);
186 element_update_handles(&cmp
->element
);
190 component_move_handle(Component
*cmp
, Handle
*handle
,
191 Point
*to
, ConnectionPoint
*cp
,
192 HandleMoveReason reason
, ModifierKeys modifiers
)
195 assert(handle
!=NULL
);
198 assert(handle
->id
< 8);
204 component_move(Component
*cmp
, Point
*to
)
206 cmp
->element
.corner
= *to
;
208 component_update_data(cmp
);
214 component_draw(Component
*cmp
, DiaRenderer
*renderer
)
216 DiaRendererClass
*renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
222 assert(renderer
!= NULL
);
224 elem
= &cmp
->element
;
231 renderer_ops
->set_fillstyle(renderer
, FILLSTYLE_SOLID
);
232 renderer_ops
->set_linewidth(renderer
, COMPONENT_BORDERWIDTH
);
233 renderer_ops
->set_linestyle(renderer
, LINESTYLE_SOLID
);
235 p1
.x
= x
+ COMPONENT_CWIDTH
/2; p1
.y
= y
;
236 p2
.x
= x
+w
; p2
.y
= y
+h
;
238 renderer_ops
->fill_rect(renderer
,
241 renderer_ops
->draw_rect(renderer
,
245 p1
.x
= x
; p1
.y
= y
+(h
- 3*COMPONENT_CHEIGHT
)/2.0;
246 p2
.x
= x
+COMPONENT_CWIDTH
; p2
.y
= p1
.y
+ COMPONENT_CHEIGHT
;
248 renderer_ops
->fill_rect(renderer
,
252 renderer_ops
->draw_rect(renderer
,
256 p1
.y
= p2
.y
+ COMPONENT_CHEIGHT
;
257 p2
.y
= p1
.y
+ COMPONENT_CHEIGHT
;
259 renderer_ops
->fill_rect(renderer
,
263 renderer_ops
->draw_rect(renderer
,
267 if (cmp
->st_stereotype
!= NULL
&&
268 cmp
->st_stereotype
[0] != '\0') {
269 p1
= cmp
->text
->position
;
270 p1
.y
-= cmp
->text
->height
;
271 renderer_ops
->set_font(renderer
, cmp
->text
->font
, cmp
->text
->height
);
272 renderer_ops
->draw_string(renderer
, cmp
->st_stereotype
, &p1
,
273 ALIGN_LEFT
, &cmp
->attrs
.color
);
276 text_draw(cmp
->text
, renderer
);
280 component_update_data(Component
*cmp
)
282 Element
*elem
= &cmp
->element
;
283 DiaObject
*obj
= &elem
->object
;
287 cmp
->stereotype
= remove_stereotype_from_string(cmp
->stereotype
);
288 if (!cmp
->st_stereotype
) {
289 cmp
->st_stereotype
= string_to_stereotype(cmp
->stereotype
);
292 text_calc_boundingbox(cmp
->text
, NULL
);
293 elem
->width
= cmp
->text
->max_width
+ 2*COMPONENT_MARGIN_X
+ COMPONENT_CWIDTH
;
294 elem
->width
= MAX(elem
->width
, 2*COMPONENT_CWIDTH
);
295 elem
->height
= cmp
->text
->height
*cmp
->text
->numlines
+
296 cmp
->text
->descent
+ 0.1 + 2*COMPONENT_MARGIN_Y
;
297 elem
->height
= MAX(elem
->height
, 5*COMPONENT_CHEIGHT
);
300 p
.x
+= COMPONENT_CWIDTH
+ COMPONENT_MARGIN_X
;
301 p
.y
+= COMPONENT_CHEIGHT
;
302 p
.y
+= cmp
->text
->ascent
;
303 if (cmp
->stereotype
&&
304 cmp
->stereotype
[0] != '\0') {
305 p
.y
+= cmp
->text
->height
;
307 text_set_position(cmp
->text
, &p
);
309 if (cmp
->st_stereotype
&&
310 cmp
->st_stereotype
[0] != '\0') {
312 font
= cmp
->text
->font
;
313 elem
->height
+= cmp
->text
->height
;
314 elem
->width
= MAX(elem
->width
, dia_font_string_width(cmp
->st_stereotype
,
315 font
, cmp
->text
->height
) +
316 2*COMPONENT_MARGIN_X
+ COMPONENT_CWIDTH
);
319 cw2
= COMPONENT_CWIDTH
/2;
320 ch
= COMPONENT_CHEIGHT
;
321 /* Update connections: */
322 connpoint_update(&cmp
->connections
[0],
323 elem
->corner
.x
+ cw2
,
326 connpoint_update(&cmp
->connections
[1],
327 elem
->corner
.x
+ cw2
+ (elem
->width
- cw2
) / 2,
330 connpoint_update(&cmp
->connections
[2],
331 elem
->corner
.x
+ elem
->width
,
334 connpoint_update(&cmp
->connections
[3],
335 elem
->corner
.x
+ cw2
,
336 elem
->corner
.y
+ elem
->height
/ 2.0,
338 connpoint_update(&cmp
->connections
[4],
339 elem
->corner
.x
+ elem
->width
,
340 elem
->corner
.y
+ elem
->height
/ 2.0,
342 connpoint_update(&cmp
->connections
[5],
343 elem
->corner
.x
+ cw2
,
344 elem
->corner
.y
+ elem
->height
,
346 connpoint_update(&cmp
->connections
[6],
347 elem
->corner
.x
+ cw2
+ (elem
->width
- cw2
)/2,
348 elem
->corner
.y
+ elem
->height
,
350 connpoint_update(&cmp
->connections
[7],
351 elem
->corner
.x
+ elem
->width
,
352 elem
->corner
.y
+ elem
->height
,
354 connpoint_update(&cmp
->connections
[8],
356 elem
->corner
.y
+ elem
->height
/ 2.0 - ch
,
358 connpoint_update(&cmp
->connections
[9],
360 elem
->corner
.y
+ elem
->height
/ 2.0 + ch
,
362 connpoint_update(&cmp
->connections
[10],
363 elem
->corner
.x
+ (elem
->width
-cw2
)/2,
364 elem
->corner
.y
+ elem
->height
/ 2.0 + ch
,
367 element_update_boundingbox(elem
);
369 obj
->position
= elem
->corner
;
371 element_update_handles(elem
);
375 component_create(Point
*startpoint
,
387 cmp
= g_malloc0(sizeof(Component
));
388 elem
= &cmp
->element
;
391 obj
->type
= &component_type
;
393 obj
->ops
= &component_ops
;
395 obj
->can_parent
= TRUE
;
397 elem
->corner
= *startpoint
;
398 cmp
->line_color
= attributes_get_foreground();
399 cmp
->fill_color
= attributes_get_background();
401 font
= dia_font_new_from_style (DIA_FONT_SANS
, 0.8);
403 p
.x
+= COMPONENT_CWIDTH
+ COMPONENT_MARGIN_X
;
404 p
.y
+= 2*COMPONENT_CHEIGHT
;
406 cmp
->text
= new_text("", font
, 0.8, &p
, &color_black
, ALIGN_LEFT
);
407 text_get_attributes(cmp
->text
,&cmp
->attrs
);
409 dia_font_unref(font
);
411 element_init(elem
, 8, NUM_CONNECTIONS
);
413 for (i
=0;i
<NUM_CONNECTIONS
;i
++) {
414 obj
->connections
[i
] = &cmp
->connections
[i
];
415 cmp
->connections
[i
].object
= obj
;
416 cmp
->connections
[i
].connected
= NULL
;
418 cmp
->connections
[10].flags
= CP_FLAGS_MAIN
;
419 elem
->extra_spacing
.border_trans
= COMPONENT_BORDERWIDTH
/2.0;
420 cmp
->stereotype
= NULL
;
421 cmp
->st_stereotype
= NULL
;
422 component_update_data(cmp
);
425 obj
->handles
[i
]->type
= HANDLE_NON_MOVABLE
;
430 return &cmp
->element
.object
;
434 component_destroy(Component
*cmp
)
436 text_destroy(cmp
->text
);
437 g_free(cmp
->stereotype
);
438 g_free(cmp
->st_stereotype
);
439 element_destroy(&cmp
->element
);
443 component_load(ObjectNode obj_node
, int version
, const char *filename
)
445 return object_load_using_properties(&component_type
,
446 obj_node
,version
,filename
);