2006-12-05 David Lodge <dave@cirt.net>
[dia.git] / objects / ER / entity.c
blobf532cac37bbaaf857416f070a933bb0fb1c1f692
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 /* DO NOT USE THIS OBJECT AS A BASIS FOR A NEW OBJECT. */
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <assert.h>
26 #include <math.h>
27 #include <string.h>
29 #include "intl.h"
30 #include "object.h"
31 #include "element.h"
32 #include "connectionpoint.h"
33 #include "diarenderer.h"
34 #include "attributes.h"
35 #include "widgets.h"
36 #include "properties.h"
38 #include "pixmaps/entity.xpm"
40 #define DEFAULT_WIDTH 2.0
41 #define DEFAULT_HEIGHT 1.0
42 #define TEXT_BORDER_WIDTH_X 0.7
43 #define TEXT_BORDER_WIDTH_Y 0.5
44 #define WEAK_BORDER_WIDTH 0.25
45 #define FONT_HEIGHT 0.8
46 #define DIAMOND_RATIO 0.6
48 typedef struct _Entity Entity;
50 #define NUM_CONNECTIONS 9
52 struct _Entity {
53 Element element;
55 ConnectionPoint connections[NUM_CONNECTIONS];
57 real border_width;
58 Color border_color;
59 Color inner_color;
61 gboolean associative;
63 DiaFont *font;
64 real font_height;
65 char *name;
66 real name_width;
68 int weak;
72 static real entity_distance_from(Entity *entity, Point *point);
73 static void entity_select(Entity *entity, Point *clicked_point,
74 DiaRenderer *interactive_renderer);
75 static ObjectChange* entity_move_handle(Entity *entity, Handle *handle,
76 Point *to, ConnectionPoint *cp,
77 HandleMoveReason reason,
78 ModifierKeys modifiers);
79 static ObjectChange* entity_move(Entity *entity, Point *to);
80 static void entity_draw(Entity *entity, DiaRenderer *renderer);
81 static void entity_update_data(Entity *entity);
82 static DiaObject *entity_create(Point *startpoint,
83 void *user_data,
84 Handle **handle1,
85 Handle **handle2);
86 static void entity_destroy(Entity *entity);
87 static DiaObject *entity_copy(Entity *entity);
88 static PropDescription *
89 entity_describe_props(Entity *entity);
90 static void entity_get_props(Entity *entity, GPtrArray *props);
91 static void entity_set_props(Entity *entity, GPtrArray *props);
93 static void entity_save(Entity *entity, ObjectNode obj_node,
94 const char *filename);
95 static DiaObject *entity_load(ObjectNode obj_node, int version,
96 const char *filename);
98 static ObjectTypeOps entity_type_ops =
100 (CreateFunc) entity_create,
101 (LoadFunc) entity_load,
102 (SaveFunc) entity_save
105 DiaObjectType entity_type =
107 "ER - Entity", /* name */
108 0, /* version */
109 (char **) entity_xpm, /* pixmap */
111 &entity_type_ops /* ops */
114 DiaObjectType *_entity_type = (DiaObjectType *) &entity_type;
116 static ObjectOps entity_ops = {
117 (DestroyFunc) entity_destroy,
118 (DrawFunc) entity_draw,
119 (DistanceFunc) entity_distance_from,
120 (SelectFunc) entity_select,
121 (CopyFunc) entity_copy,
122 (MoveFunc) entity_move,
123 (MoveHandleFunc) entity_move_handle,
124 (GetPropertiesFunc) object_create_props_dialog,
125 (ApplyPropertiesFunc) object_apply_props_from_dialog,
126 (ObjectMenuFunc) NULL,
127 (DescribePropsFunc) entity_describe_props,
128 (GetPropsFunc) entity_get_props,
129 (SetPropsFunc) entity_set_props,
132 static PropDescription entity_props[] = {
133 ELEMENT_COMMON_PROPERTIES,
134 { "name", PROP_TYPE_STRING, PROP_FLAG_VISIBLE,
135 N_("Name:"), NULL, NULL },
136 { "weak", PROP_TYPE_BOOL, PROP_FLAG_VISIBLE,
137 N_("Weak:"), NULL, NULL },
138 { "associative", PROP_TYPE_BOOL, PROP_FLAG_VISIBLE,
139 N_("Associative:"), NULL, NULL },
140 PROP_STD_LINE_WIDTH,
141 PROP_STD_LINE_COLOUR,
142 PROP_STD_FILL_COLOUR,
143 PROP_STD_TEXT_FONT,
144 PROP_STD_TEXT_HEIGHT,
145 PROP_DESC_END
148 static PropDescription *
149 entity_describe_props(Entity *entity)
151 if (entity_props[0].quark == 0)
152 prop_desc_list_calculate_quarks(entity_props);
153 return entity_props;
156 static PropOffset entity_offsets[] = {
157 ELEMENT_COMMON_PROPERTIES_OFFSETS,
158 { "name", PROP_TYPE_STRING, offsetof(Entity, name) },
159 { "weak", PROP_TYPE_BOOL, offsetof(Entity, weak) },
160 { "associative", PROP_TYPE_BOOL, offsetof(Entity, associative) },
161 { "line_width", PROP_TYPE_REAL, offsetof(Entity, border_width) },
162 { "line_colour", PROP_TYPE_COLOUR, offsetof(Entity, border_color) },
163 { "fill_colour", PROP_TYPE_COLOUR, offsetof(Entity, inner_color) },
164 { "text_font", PROP_TYPE_FONT, offsetof (Entity, font) },
165 { "text_height", PROP_TYPE_REAL, offsetof(Entity, font_height) },
166 { NULL, 0, 0}
170 static void
171 entity_get_props(Entity *entity, GPtrArray *props)
173 object_get_props_from_offsets(&entity->element.object,
174 entity_offsets, props);
177 static void
178 entity_set_props(Entity *entity, GPtrArray *props)
180 object_set_props_from_offsets(&entity->element.object,
181 entity_offsets, props);
182 entity_update_data(entity);
185 static real
186 entity_distance_from(Entity *entity, Point *point)
188 Element *elem = &entity->element;
189 Rectangle rect;
191 rect.left = elem->corner.x - entity->border_width/2;
192 rect.right = elem->corner.x + elem->width + entity->border_width/2;
193 rect.top = elem->corner.y - entity->border_width/2;
194 rect.bottom = elem->corner.y + elem->height + entity->border_width/2;
195 return distance_rectangle_point(&rect, point);
198 static void
199 entity_select(Entity *entity, Point *clicked_point,
200 DiaRenderer *interactive_renderer)
202 element_update_handles(&entity->element);
205 static ObjectChange*
206 entity_move_handle(Entity *entity, Handle *handle,
207 Point *to, ConnectionPoint *cp,
208 HandleMoveReason reason, ModifierKeys modifiers)
210 assert(entity!=NULL);
211 assert(handle!=NULL);
212 assert(to!=NULL);
214 element_move_handle(&entity->element, handle->id, to, cp, reason, modifiers);
216 entity_update_data(entity);
218 return NULL;
221 static ObjectChange*
222 entity_move(Entity *entity, Point *to)
224 entity->element.corner = *to;
226 entity_update_data(entity);
228 return NULL;
231 static void
232 entity_draw(Entity *entity, DiaRenderer *renderer)
234 DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
235 Point ul_corner, lr_corner;
236 Point p;
237 Element *elem;
238 coord diff;
240 assert(entity != NULL);
241 assert(renderer != NULL);
243 elem = &entity->element;
245 ul_corner.x = elem->corner.x;
246 ul_corner.y = elem->corner.y;
247 lr_corner.x = elem->corner.x + elem->width;
248 lr_corner.y = elem->corner.y + elem->height;
250 renderer_ops->set_fillstyle(renderer, FILLSTYLE_SOLID);
252 renderer_ops->fill_rect(renderer,
253 &ul_corner,
254 &lr_corner,
255 &entity->inner_color);
257 renderer_ops->set_linewidth(renderer, entity->border_width);
258 renderer_ops->set_linestyle(renderer, LINESTYLE_SOLID);
259 renderer_ops->set_linejoin(renderer, LINEJOIN_MITER);
261 renderer_ops->draw_rect(renderer,
262 &ul_corner,
263 &lr_corner,
264 &entity->border_color);
266 if(entity->weak) {
267 diff = WEAK_BORDER_WIDTH/*MIN(elem->width / 2.0 * 0.20, elem->height / 2.0 * 0.20)*/;
268 ul_corner.x += diff;
269 ul_corner.y += diff;
270 lr_corner.x -= diff;
271 lr_corner.y -= diff;
272 renderer_ops->draw_rect(renderer,
273 &ul_corner, &lr_corner,
274 &entity->border_color);
276 if(entity->associative){
277 Point corners[4];
278 corners[0].x = elem->corner.x;
279 corners[0].y = elem->corner.y + elem->height / 2;
280 corners[1].x = elem->corner.x + elem->width / 2;
281 corners[1].y = elem->corner.y;
282 corners[2].x = elem->corner.x + elem->width;
283 corners[2].y = elem->corner.y + elem->height / 2;
284 corners[3].x = elem->corner.x + elem->width / 2;
285 corners[3].y = elem->corner.y + elem->height;
286 renderer_ops->set_fillstyle(renderer, FILLSTYLE_SOLID);
288 renderer_ops->fill_polygon(renderer, corners, 4,
289 &entity->inner_color);
291 renderer_ops->set_linewidth(renderer, entity->border_width);
292 renderer_ops->set_linestyle(renderer, LINESTYLE_SOLID);
293 renderer_ops->set_linejoin(renderer, LINEJOIN_MITER);
295 renderer_ops->draw_polygon(renderer, corners, 4,
296 &entity->border_color);
299 p.x = elem->corner.x + elem->width / 2.0;
300 p.y = elem->corner.y + (elem->height - entity->font_height)/2.0 +
301 dia_font_ascent(entity->name,entity->font, entity->font_height);
302 renderer_ops->set_font(renderer, entity->font, entity->font_height);
303 renderer_ops->draw_string(renderer,
304 entity->name,
305 &p, ALIGN_CENTER,
306 &color_black);
309 static void
310 entity_update_data(Entity *entity)
312 Element *elem = &entity->element;
313 DiaObject *obj = &elem->object;
314 ElementBBExtras *extra = &elem->extra_spacing;
316 entity->name_width =
317 dia_font_string_width(entity->name, entity->font, entity->font_height);
319 if(entity->associative){
320 elem->width = entity->name_width + 2*TEXT_BORDER_WIDTH_X;
321 elem->height = elem->width * DIAMOND_RATIO;
323 else {
324 elem->width = entity->name_width + 2*TEXT_BORDER_WIDTH_X;
325 elem->height = entity->font_height + 2*TEXT_BORDER_WIDTH_Y;
328 /* Update connections: */
329 connpoint_update(&entity->connections[0],
330 elem->corner.x,
331 elem->corner.y,
332 DIR_NORTHWEST);
333 connpoint_update(&entity->connections[1],
334 elem->corner.x + elem->width / 2.0,
335 elem->corner.y,
336 DIR_NORTH);
337 connpoint_update(&entity->connections[2],
338 elem->corner.x + elem->width,
339 elem->corner.y,
340 DIR_NORTHEAST);
341 connpoint_update(&entity->connections[3],
342 elem->corner.x,
343 elem->corner.y + elem->height / 2.0,
344 DIR_WEST);
345 connpoint_update(&entity->connections[4],
346 elem->corner.x + elem->width,
347 elem->corner.y + elem->height / 2.0,
348 DIR_EAST);
349 connpoint_update(&entity->connections[5],
350 elem->corner.x,
351 elem->corner.y + elem->height,
352 DIR_SOUTHWEST);
353 connpoint_update(&entity->connections[6],
354 elem->corner.x + elem->width / 2.0,
355 elem->corner.y + elem->height,
356 DIR_SOUTH);
357 connpoint_update(&entity->connections[7],
358 elem->corner.x + elem->width,
359 elem->corner.y + elem->height,
360 DIR_SOUTHEAST);
361 connpoint_update(&entity->connections[8],
362 elem->corner.x + elem->width / 2.0,
363 elem->corner.y + elem->height / 2.0,
364 DIR_ALL);
366 extra->border_trans = entity->border_width/2.0;
367 element_update_boundingbox(elem);
369 obj->position = elem->corner;
371 element_update_handles(elem);
374 static DiaObject *
375 entity_create(Point *startpoint,
376 void *user_data,
377 Handle **handle1,
378 Handle **handle2)
380 Entity *entity;
381 Element *elem;
382 DiaObject *obj;
383 int i;
385 entity = g_malloc0(sizeof(Entity));
386 elem = &entity->element;
387 obj = &elem->object;
389 obj->type = &entity_type;
391 obj->ops = &entity_ops;
393 elem->corner = *startpoint;
394 elem->width = DEFAULT_WIDTH;
395 elem->height = DEFAULT_HEIGHT;
397 entity->border_width = attributes_get_default_linewidth();
398 entity->border_color = attributes_get_foreground();
399 entity->inner_color = attributes_get_background();
401 element_init(elem, 8, NUM_CONNECTIONS);
403 for (i=0;i<NUM_CONNECTIONS;i++) {
404 obj->connections[i] = &entity->connections[i];
405 entity->connections[i].object = obj;
406 entity->connections[i].connected = NULL;
408 entity->connections[8].flags = CP_FLAGS_MAIN;
410 entity->weak = GPOINTER_TO_INT(user_data);
411 entity->font = dia_font_new_from_style(DIA_FONT_MONOSPACE,FONT_HEIGHT);
412 entity->font_height = FONT_HEIGHT;
413 entity->name = g_strdup(_("Entity"));
415 entity->name_width =
416 dia_font_string_width(entity->name, entity->font, entity->font_height);
418 entity_update_data(entity);
420 for (i=0;i<8;i++) {
421 obj->handles[i]->type = HANDLE_NON_MOVABLE;
424 *handle1 = NULL;
425 *handle2 = obj->handles[0];
426 return &entity->element.object;
429 static void
430 entity_destroy(Entity *entity)
432 dia_font_unref(entity->font);
433 element_destroy(&entity->element);
434 g_free(entity->name);
437 static DiaObject *
438 entity_copy(Entity *entity)
440 int i;
441 Entity *newentity;
442 Element *elem, *newelem;
443 DiaObject *newobj;
445 elem = &entity->element;
447 newentity = g_malloc0(sizeof(Entity));
448 newelem = &newentity->element;
449 newobj = &newelem->object;
451 element_copy(elem, newelem);
453 newentity->border_width = entity->border_width;
454 newentity->border_color = entity->border_color;
455 newentity->inner_color = entity->inner_color;
457 for (i=0;i<NUM_CONNECTIONS;i++) {
458 newobj->connections[i] = &newentity->connections[i];
459 newentity->connections[i].object = newobj;
460 newentity->connections[i].connected = NULL;
461 newentity->connections[i].pos = entity->connections[i].pos;
462 newentity->connections[i].last_pos = entity->connections[i].last_pos;
463 newentity->connections[i].flags = entity->connections[i].flags;
466 newentity->font = dia_font_ref(entity->font);
467 newentity->font_height = entity->font_height;
468 newentity->name = g_strdup(entity->name);
469 newentity->name_width = entity->name_width;
471 newentity->weak = entity->weak;
473 return &newentity->element.object;
476 static void
477 entity_save(Entity *entity, ObjectNode obj_node, const char *filename)
479 element_save(&entity->element, obj_node);
481 data_add_real(new_attribute(obj_node, "border_width"),
482 entity->border_width);
483 data_add_color(new_attribute(obj_node, "border_color"),
484 &entity->border_color);
485 data_add_color(new_attribute(obj_node, "inner_color"),
486 &entity->inner_color);
487 data_add_string(new_attribute(obj_node, "name"),
488 entity->name);
489 data_add_boolean(new_attribute(obj_node, "weak"),
490 entity->weak);
491 data_add_boolean(new_attribute(obj_node, "associative"),
492 entity->associative);
493 data_add_font (new_attribute (obj_node, "font"),
494 entity->font);
495 data_add_real(new_attribute(obj_node, "font_height"),
496 entity->font_height);
499 static DiaObject *
500 entity_load(ObjectNode obj_node, int version, const char *filename)
502 Entity *entity;
503 Element *elem;
504 DiaObject *obj;
505 int i;
506 AttributeNode attr;
508 entity = g_malloc0(sizeof(Entity));
509 elem = &entity->element;
510 obj = &elem->object;
512 obj->type = &entity_type;
513 obj->ops = &entity_ops;
515 element_load(elem, obj_node);
517 entity->border_width = 0.1;
518 attr = object_find_attribute(obj_node, "border_width");
519 if (attr != NULL)
520 entity->border_width = data_real( attribute_first_data(attr) );
522 entity->border_color = color_black;
523 attr = object_find_attribute(obj_node, "border_color");
524 if (attr != NULL)
525 data_color(attribute_first_data(attr), &entity->border_color);
527 entity->inner_color = color_white;
528 attr = object_find_attribute(obj_node, "inner_color");
529 if (attr != NULL)
530 data_color(attribute_first_data(attr), &entity->inner_color);
532 entity->name = NULL;
533 attr = object_find_attribute(obj_node, "name");
534 if (attr != NULL)
535 entity->name = data_string(attribute_first_data(attr));
537 attr = object_find_attribute(obj_node, "weak");
538 if (attr != NULL)
539 entity->weak = data_boolean(attribute_first_data(attr));
541 attr = object_find_attribute(obj_node, "associative");
542 if (attr != NULL)
543 entity->associative = data_boolean(attribute_first_data(attr));
545 if (entity->font != NULL) {
546 /* This shouldn't happen, but doesn't hurt */
547 dia_font_unref(entity->font);
548 entity->font = NULL;
550 attr = object_find_attribute (obj_node, "font");
551 if (attr != NULL)
552 entity->font = data_font (attribute_first_data (attr));
554 entity->font_height = FONT_HEIGHT;
555 attr = object_find_attribute(obj_node, "font_height");
556 if (attr != NULL)
557 entity->font_height = data_real(attribute_first_data(attr));
559 element_init(elem, 8, NUM_CONNECTIONS);
561 for (i=0;i<NUM_CONNECTIONS;i++) {
562 obj->connections[i] = &entity->connections[i];
563 entity->connections[i].object = obj;
564 entity->connections[i].connected = NULL;
566 entity->connections[8].flags = CP_FLAGS_MAIN;
568 if (entity->font == NULL) {
569 entity->font = dia_font_new_from_style(DIA_FONT_MONOSPACE,1.0);
572 entity->name_width =
573 dia_font_string_width(entity->name, entity->font, entity->font_height);
575 entity_update_data(entity);
577 for (i=0;i<8;i++) {
578 obj->handles[i]->type = HANDLE_NON_MOVABLE;
581 return &entity->element.object;