2006-12-05 David Lodge <dave@cirt.net>
[dia.git] / objects / UML / realizes.c
blob0ca5881aabf65103cf0ca6e64f0e1680c9c300f4
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.
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <assert.h>
24 #include <math.h>
25 #include <string.h>
27 #include "intl.h"
28 #include "object.h"
29 #include "orth_conn.h"
30 #include "diarenderer.h"
31 #include "attributes.h"
32 #include "arrows.h"
33 #include "properties.h"
34 #include "stereotype.h"
35 #include "uml.h"
37 #include "pixmaps/realizes.xpm"
39 typedef struct _Realizes Realizes;
41 struct _Realizes {
42 OrthConn orth;
44 Point text_pos;
45 Alignment text_align;
46 real text_width;
48 Color text_color;
49 Color line_color;
51 char *name;
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,
73 void *user_data,
74 Handle **handle1,
75 Handle **handle2);
76 static void realizes_destroy(Realizes *realize);
77 static DiaMenu *realizes_get_object_menu(Realizes *realize,
78 Point *clickedpoint);
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. */
102 1, /* version */
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 },
135 PROP_DESC_END
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) },
153 { NULL, 0, 0 }
156 static void
157 realizes_get_props(Realizes * realizes, GPtrArray *props)
159 object_get_props_from_offsets(&realizes->orth.object,
160 realizes_offsets,props);
163 static void
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);
174 static real
175 realizes_distance_from(Realizes *realize, Point *point)
177 OrthConn *orth = &realize->orth;
178 return orthconn_distance_from(orth, point, REALIZES_WIDTH);
181 static void
182 realizes_select(Realizes *realize, Point *clicked_point,
183 DiaRenderer *interactive_renderer)
185 orthconn_update_data(&realize->orth);
188 static ObjectChange*
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);
196 assert(to!=NULL);
198 change = orthconn_move_handle(&realize->orth, handle, to, cp, reason, modifiers);
199 realizes_update_data(realize);
201 return change;
204 static ObjectChange*
205 realizes_move(Realizes *realize, Point *to)
207 orthconn_move(&realize->orth, to);
208 realizes_update_data(realize);
210 return NULL;
213 static void
214 realizes_draw(Realizes *realize, DiaRenderer *renderer)
216 DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
217 OrthConn *orth = &realize->orth;
218 Point *points;
219 int n;
220 Point pos;
221 Arrow arrow;
223 points = &orth->points[0];
224 n = orth->numpoints;
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,
236 REALIZES_WIDTH,
237 &realize->line_color,
238 &arrow, NULL);
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,
254 realize->name,
255 &pos, realize->text_align,
256 &realize->text_color);
261 static void
262 realizes_update_data(Realizes *realize)
264 OrthConn *orth = &realize->orth;
265 DiaObject *obj = &orth->object;
266 int num_segm, i;
267 Point *points;
268 Rectangle rect;
269 PolyBBExtras *extra;
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);
280 if (realize->name)
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,
286 realize_font,
287 REALIZES_FONTHEIGHT));
289 extra = &orth->extra_spacing;
291 extra->start_trans = REALIZES_WIDTH/2.0 + REALIZES_TRIANGLESIZE;
292 extra->start_long =
293 extra->middle_trans =
294 extra->end_trans =
295 extra->end_long = REALIZES_WIDTH/2.0;
297 orthconn_update_boundingbox(orth);
299 /* Calc text pos: */
300 num_segm = realize->orth.numpoints - 1;
301 points = realize->orth.points;
302 i = num_segm / 2;
304 if ((num_segm % 2) == 0) { /* If no middle segment, use horizontal */
305 if (realize->orth.orientation[i]==VERTICAL)
306 i--;
309 switch (realize->orth.orientation[i]) {
310 case HORIZONTAL:
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;
314 if (realize->name)
315 realize->text_pos.y -=
316 dia_font_descent(realize->name,realize_font, REALIZES_FONTHEIGHT);
317 break;
318 case VERTICAL:
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);
322 if (realize->name)
323 realize->text_pos.y -=
324 dia_font_descent(realize->name, realize_font, REALIZES_FONTHEIGHT);
325 break;
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;
334 if (realize->name)
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);
347 return change;
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);
356 return change;
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 = {
367 "Realizes",
368 sizeof(object_menu_items)/sizeof(DiaMenuItem),
369 object_menu_items,
370 NULL
373 static DiaMenu *
374 realizes_get_object_menu(Realizes *realize, Point *clickedpoint)
376 OrthConn *orth;
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]);
383 return &object_menu;
386 static DiaObject *
387 realizes_create(Point *startpoint,
388 void *user_data,
389 Handle **handle1,
390 Handle **handle2)
392 Realizes *realize;
393 OrthConn *orth;
394 DiaObject *obj;
395 PolyBBExtras *extra;
397 if (realize_font == NULL) {
398 realize_font =
399 dia_font_new_from_style (DIA_FONT_MONOSPACE, REALIZES_FONTHEIGHT);
402 realize = g_malloc0(sizeof(Realizes));
403 orth = &realize->orth;
404 obj = &orth->object;
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;
422 extra->start_long =
423 extra->middle_trans =
424 extra->end_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;
434 static void
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);
443 static DiaObject *
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);
448 if (version == 0) {
449 AttributeNode attr;
450 /* In old objects with no autorouting, set it to false. */
451 attr = object_find_attribute(obj_node, "autorouting");
452 if (attr == NULL)
453 ((OrthConn*)obj)->autorouting = FALSE;
455 return obj;