2006-12-05 David Lodge <dave@cirt.net>
[dia.git] / objects / UML / actor.c
bloba7f1c8076c016cd56065059333f28748f93406d6
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.
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
22 #include <assert.h>
23 #include <math.h>
24 #include <string.h>
26 #include "intl.h"
27 #include "object.h"
28 #include "element.h"
29 #include "diarenderer.h"
30 #include "attributes.h"
31 #include "text.h"
32 #include "properties.h"
34 #include "pixmaps/actor.xpm"
36 #define NUM_CONNECTIONS 9
38 typedef struct _Actor Actor;
39 struct _Actor {
40 Element element;
42 ConnectionPoint connections[NUM_CONNECTIONS];
44 Text *text;
45 TextAttributes attrs;
47 Color line_color;
48 Color fill_color;
51 #define ACTOR_WIDTH 2.2
52 #define ACTOR_HEIGHT 4.6
53 #define ACTOR_HEAD(h) (h*0.6/4.6)
54 #define ACTOR_BODY(h) (h*4.0/4.6)
55 #define ACTOR_LINEWIDTH 0.1
56 #define ACTOR_MARGIN_X 0.3
57 #define ACTOR_MARGIN_Y 0.3
59 static real actor_distance_from(Actor *actor, Point *point);
60 static void actor_select(Actor *actor, Point *clicked_point,
61 DiaRenderer *interactive_renderer);
62 static ObjectChange* actor_move_handle(Actor *actor, Handle *handle,
63 Point *to, ConnectionPoint *cp,
64 HandleMoveReason reason, ModifierKeys modifiers);
65 static ObjectChange* actor_move(Actor *actor, Point *to);
66 static void actor_draw(Actor *actor, DiaRenderer *renderer);
67 static DiaObject *actor_create(Point *startpoint,
68 void *user_data,
69 Handle **handle1,
70 Handle **handle2);
71 static void actor_destroy(Actor *actor);
72 static DiaObject *actor_load(ObjectNode obj_node, int version,
73 const char *filename);
75 static PropDescription *actor_describe_props(Actor *actor);
76 static void actor_get_props(Actor *actor, GPtrArray *props);
77 static void actor_set_props(Actor *actor, GPtrArray *props);
79 static void actor_update_data(Actor *actor);
81 static ObjectTypeOps actor_type_ops =
83 (CreateFunc) actor_create,
84 (LoadFunc) actor_load,/*using_properties*/ /* load */
85 (SaveFunc) object_save_using_properties, /* save */
86 (GetDefaultsFunc) NULL,
87 (ApplyDefaultsFunc) NULL
90 DiaObjectType actor_type =
92 "UML - Actor", /* name */
93 0, /* version */
94 (char **) actor_xpm, /* pixmap */
96 &actor_type_ops /* ops */
99 static ObjectOps actor_ops = {
100 (DestroyFunc) actor_destroy,
101 (DrawFunc) actor_draw,
102 (DistanceFunc) actor_distance_from,
103 (SelectFunc) actor_select,
104 (CopyFunc) object_copy_using_properties,
105 (MoveFunc) actor_move,
106 (MoveHandleFunc) actor_move_handle,
107 (GetPropertiesFunc) object_create_props_dialog,
108 (ApplyPropertiesFunc) object_apply_props_from_dialog,
109 (ObjectMenuFunc) NULL,
110 (DescribePropsFunc) actor_describe_props,
111 (GetPropsFunc) actor_get_props,
112 (SetPropsFunc) actor_set_props,
115 static PropDescription actor_props[] = {
116 ELEMENT_COMMON_PROPERTIES,
117 PROP_STD_TEXT_FONT,
118 PROP_STD_TEXT_HEIGHT,
119 PROP_STD_TEXT_COLOUR_OPTIONAL,
120 PROP_STD_LINE_COLOUR_OPTIONAL,
121 PROP_STD_FILL_COLOUR_OPTIONAL,
122 { "text", PROP_TYPE_TEXT, 0, N_("Text"), NULL, NULL },
123 PROP_DESC_END
126 static PropDescription *
127 actor_describe_props(Actor *actor)
129 if (actor_props[0].quark == 0) {
130 prop_desc_list_calculate_quarks(actor_props);
132 return actor_props;
135 static PropOffset actor_offsets[] = {
136 ELEMENT_COMMON_PROPERTIES_OFFSETS,
137 {"text",PROP_TYPE_TEXT,offsetof(Actor,text)},
138 {"text_font",PROP_TYPE_FONT,offsetof(Actor,attrs.font)},
139 {"text_height",PROP_TYPE_REAL,offsetof(Actor,attrs.height)},
140 {"text_colour",PROP_TYPE_COLOUR,offsetof(Actor,attrs.color)},
141 {"line_colour",PROP_TYPE_COLOUR,offsetof(Actor,line_color)},
142 {"fill_colour",PROP_TYPE_COLOUR,offsetof(Actor,fill_color)},
143 { NULL, 0, 0 },
146 static void
147 actor_get_props(Actor * actor, GPtrArray *props)
149 text_get_attributes(actor->text,&actor->attrs);
150 object_get_props_from_offsets(&actor->element.object,
151 actor_offsets,props);
154 static void
155 actor_set_props(Actor *actor, GPtrArray *props)
157 object_set_props_from_offsets(&actor->element.object,
158 actor_offsets,props);
159 apply_textattr_properties(props,actor->text,"text",&actor->attrs);
160 actor_update_data(actor);
163 static real
164 actor_distance_from(Actor *actor, Point *point)
166 DiaObject *obj = &actor->element.object;
167 return distance_rectangle_point(&obj->bounding_box, point);
170 static void
171 actor_select(Actor *actor, Point *clicked_point,
172 DiaRenderer *interactive_renderer)
174 text_set_cursor(actor->text, clicked_point, interactive_renderer);
175 text_grab_focus(actor->text, &actor->element.object);
176 element_update_handles(&actor->element);
179 static ObjectChange*
180 actor_move_handle(Actor *actor, Handle *handle,
181 Point *to, ConnectionPoint *cp,
182 HandleMoveReason reason, ModifierKeys modifiers)
184 ObjectChange* oc;
186 assert(actor!=NULL);
187 assert(handle!=NULL);
188 assert(to!=NULL);
190 assert(handle->id < 8);
192 oc = element_move_handle (&(actor->element), handle->id, to, cp, reason, modifiers);
193 actor_update_data (actor);
194 return oc;
197 static ObjectChange*
198 actor_move(Actor *actor, Point *to)
200 Element *elem = &actor->element;
202 elem->corner = *to;
203 elem->corner.x -= elem->width/2.0;
204 elem->corner.y -= elem->height / 2.0;
206 actor_update_data(actor);
208 return NULL;
211 static void
212 actor_draw(Actor *actor, DiaRenderer *renderer)
214 DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
215 Element *elem;
216 real x, y, w, h;
217 real r, r1;
218 Point ch, cb, p1, p2;
219 real actor_height;
221 assert(actor != NULL);
222 assert(renderer != NULL);
224 elem = &actor->element;
226 x = elem->corner.x;
227 y = elem->corner.y;
228 w = elem->width;
229 h = elem->height;
230 actor_height = elem->height - actor->text->height;
232 renderer_ops->set_fillstyle(renderer, FILLSTYLE_SOLID);
233 renderer_ops->set_linewidth(renderer, ACTOR_LINEWIDTH);
234 renderer_ops->set_linestyle(renderer, LINESTYLE_SOLID);
236 r = ACTOR_HEAD(actor_height);
237 r1 = 2*r;
238 ch.x = x + w*0.5;
239 ch.y = y + r + ACTOR_MARGIN_Y;
240 cb.x = ch.x;
241 cb.y = ch.y + r1 + r;
243 /* head */
244 renderer_ops->fill_ellipse(renderer,
245 &ch,
246 r, r,
247 &actor->fill_color);
248 renderer_ops->draw_ellipse(renderer,
249 &ch,
250 r, r,
251 &actor->line_color);
253 /* Arms */
254 p1.x = ch.x - r1;
255 p2.x = ch.x + r1;
256 p1.y = p2.y = ch.y + r;
257 renderer_ops->draw_line(renderer,
258 &p1, &p2,
259 &actor->line_color);
261 p1.x = ch.x;
262 p1.y = ch.y + r*0.5;
263 /* body & legs */
264 renderer_ops->draw_line(renderer,
265 &p1, &cb,
266 &actor->line_color);
268 p2.x = ch.x - r1;
269 p2.y = y + ACTOR_BODY(actor_height);
270 renderer_ops->draw_line(renderer,
271 &cb, &p2,
272 &actor->line_color);
274 p2.x = ch.x + r1;
275 renderer_ops->draw_line(renderer,
276 &cb, &p2,
277 &actor->line_color);
279 text_draw(actor->text, renderer);
282 static void
283 actor_update_data(Actor *actor)
285 Element *elem = &actor->element;
286 DiaObject *obj = &elem->object;
287 Rectangle text_box;
288 Point p;
289 real actor_height;
291 text_calc_boundingbox(actor->text, &text_box);
293 /* minimum size */
294 if (elem->width < ACTOR_WIDTH + ACTOR_MARGIN_X)
295 elem->width = ACTOR_WIDTH + ACTOR_MARGIN_X;
296 if (elem->height < ACTOR_HEIGHT + actor->text->height)
297 elem->height = ACTOR_HEIGHT + actor->text->height;
298 actor_height = elem->height - actor->text->height;
300 /* Update connections: */
301 element_update_connections_rectangle(elem, actor->connections);
303 element_update_boundingbox(elem);
305 p = elem->corner;
306 p.x += elem->width/2;
307 p.y += actor_height + actor->text->ascent;
308 text_set_position(actor->text, &p);
310 /* Add bounding box for text: */
311 rectangle_union(&obj->bounding_box, &text_box);
313 obj->position = elem->corner;
314 obj->position.x += elem->width/2.0;
315 obj->position.y += elem->height / 2.0;
317 element_update_handles(elem);
320 static DiaObject *
321 actor_create(Point *startpoint,
322 void *user_data,
323 Handle **handle1,
324 Handle **handle2)
326 Actor *actor;
327 Element *elem;
328 DiaObject *obj;
329 Point p;
330 DiaFont *font;
331 int i;
333 actor = g_malloc0(sizeof(Actor));
334 elem = &actor->element;
335 obj = &elem->object;
337 obj->type = &actor_type;
338 obj->ops = &actor_ops;
339 elem->corner = *startpoint;
340 elem->width = ACTOR_WIDTH;
341 elem->height = ACTOR_HEIGHT;
343 actor->line_color = attributes_get_foreground();
344 actor->fill_color = attributes_get_background();
346 font = dia_font_new_from_style (DIA_FONT_SANS, 0.8);
347 p = *startpoint;
348 p.x += ACTOR_MARGIN_X;
349 p.y += ACTOR_HEIGHT - dia_font_descent(_("Actor"),font, 0.8);
351 actor->text = new_text(_("Actor"),
352 font, 0.8, &p, &color_black, ALIGN_CENTER);
353 dia_font_unref(font);
355 text_get_attributes(actor->text,&actor->attrs);
357 element_init(elem, 8, NUM_CONNECTIONS);
359 for (i=0;i<NUM_CONNECTIONS;i++) {
360 obj->connections[i] = &actor->connections[i];
361 actor->connections[i].object = obj;
362 actor->connections[i].connected = NULL;
364 actor->connections[8].flags = CP_FLAGS_MAIN;
365 elem->extra_spacing.border_trans = ACTOR_LINEWIDTH/2.0;
366 actor_update_data(actor);
368 for (i=0;i<8;i++) {
369 obj->handles[i]->type = HANDLE_NON_MOVABLE;
372 *handle1 = NULL;
373 *handle2 = NULL;
374 return &actor->element.object;
377 static void
378 actor_destroy(Actor *actor)
380 text_destroy(actor->text);
382 element_destroy(&actor->element);
385 static DiaObject *
386 actor_load(ObjectNode obj_node, int version, const char *filename)
388 return object_load_using_properties(&actor_type,
389 obj_node,version,filename);