2002-06-23 Hans Breuer <hans@breuer.org>
[dia.git] / objects / ER / entity.c
blobdd62d9cbd8584f0a9340ba13461974e182518d48
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 <gtk/gtk.h>
27 #include <math.h>
28 #include <string.h>
30 #include "intl.h"
31 #include "object.h"
32 #include "element.h"
33 #include "connectionpoint.h"
34 #include "render.h"
35 #include "attributes.h"
36 #include "widgets.h"
37 #include "properties.h"
39 #include "pixmaps/entity.xpm"
41 #define DEFAULT_WIDTH 2.0
42 #define DEFAULT_HEIGHT 1.0
43 #define TEXT_BORDER_WIDTH_X 0.7
44 #define TEXT_BORDER_WIDTH_Y 0.5
45 #define WEAK_BORDER_WIDTH 0.25
46 #define FONT_HEIGHT 0.8
48 typedef struct _Entity Entity;
50 struct _Entity {
51 Element element;
53 ConnectionPoint connections[8];
55 real border_width;
56 Color border_color;
57 Color inner_color;
59 DiaFont *font;
60 real font_height;
61 char *name;
62 real name_width;
64 int weak;
68 static real entity_distance_from(Entity *entity, Point *point);
69 static void entity_select(Entity *entity, Point *clicked_point,
70 Renderer *interactive_renderer);
71 static void entity_move_handle(Entity *entity, Handle *handle,
72 Point *to, HandleMoveReason reason, ModifierKeys modifiers);
73 static void entity_move(Entity *entity, Point *to);
74 static void entity_draw(Entity *entity, Renderer *renderer);
75 static void entity_update_data(Entity *entity);
76 static Object *entity_create(Point *startpoint,
77 void *user_data,
78 Handle **handle1,
79 Handle **handle2);
80 static void entity_destroy(Entity *entity);
81 static Object *entity_copy(Entity *entity);
82 static PropDescription *
83 entity_describe_props(Entity *entity);
84 static void entity_get_props(Entity *entity, GPtrArray *props);
85 static void entity_set_props(Entity *entity, GPtrArray *props);
87 static void entity_save(Entity *entity, ObjectNode obj_node,
88 const char *filename);
89 static Object *entity_load(ObjectNode obj_node, int version,
90 const char *filename);
92 static ObjectTypeOps entity_type_ops =
94 (CreateFunc) entity_create,
95 (LoadFunc) entity_load,
96 (SaveFunc) entity_save
99 ObjectType entity_type =
101 "ER - Entity", /* name */
102 0, /* version */
103 (char **) entity_xpm, /* pixmap */
105 &entity_type_ops /* ops */
108 ObjectType *_entity_type = (ObjectType *) &entity_type;
110 static ObjectOps entity_ops = {
111 (DestroyFunc) entity_destroy,
112 (DrawFunc) entity_draw,
113 (DistanceFunc) entity_distance_from,
114 (SelectFunc) entity_select,
115 (CopyFunc) entity_copy,
116 (MoveFunc) entity_move,
117 (MoveHandleFunc) entity_move_handle,
118 (GetPropertiesFunc) object_create_props_dialog,
119 (ApplyPropertiesFunc) object_apply_props_from_dialog,
120 (ObjectMenuFunc) NULL,
121 (DescribePropsFunc) entity_describe_props,
122 (GetPropsFunc) entity_get_props,
123 (SetPropsFunc) entity_set_props,
126 static PropDescription entity_props[] = {
127 ELEMENT_COMMON_PROPERTIES,
128 { "name", PROP_TYPE_STRING, PROP_FLAG_VISIBLE,
129 N_("Name:"), NULL, NULL },
130 { "weak", PROP_TYPE_BOOL, PROP_FLAG_VISIBLE,
131 N_("Weak:"), NULL, NULL },
132 PROP_STD_LINE_WIDTH,
133 PROP_STD_LINE_COLOUR,
134 PROP_STD_FILL_COLOUR,
135 PROP_STD_TEXT_FONT,
136 PROP_STD_TEXT_HEIGHT,
137 PROP_DESC_END
140 static PropDescription *
141 entity_describe_props(Entity *entity)
143 if (entity_props[0].quark == 0)
144 prop_desc_list_calculate_quarks(entity_props);
145 return entity_props;
148 static PropOffset entity_offsets[] = {
149 ELEMENT_COMMON_PROPERTIES_OFFSETS,
150 { "name", PROP_TYPE_STRING, offsetof(Entity, name) },
151 { "weak", PROP_TYPE_BOOL, offsetof(Entity, weak) },
152 { "line_width", PROP_TYPE_REAL, offsetof(Entity, border_width) },
153 { "line_colour", PROP_TYPE_COLOUR, offsetof(Entity, border_color) },
154 { "fill_colour", PROP_TYPE_COLOUR, offsetof(Entity, inner_color) },
155 { "text_font", PROP_TYPE_FONT, offsetof (Entity, font) },
156 { "text_height", PROP_TYPE_REAL, offsetof(Entity, font_height) },
157 { NULL, 0, 0}
161 static void
162 entity_get_props(Entity *entity, GPtrArray *props)
164 object_get_props_from_offsets(&entity->element.object,
165 entity_offsets, props);
168 static void
169 entity_set_props(Entity *entity, GPtrArray *props)
171 object_set_props_from_offsets(&entity->element.object,
172 entity_offsets, props);
173 entity_update_data(entity);
176 static real
177 entity_distance_from(Entity *entity, Point *point)
179 Element *elem = &entity->element;
180 Rectangle rect;
182 rect.left = elem->corner.x - entity->border_width/2;
183 rect.right = elem->corner.x + elem->width + entity->border_width/2;
184 rect.top = elem->corner.y - entity->border_width/2;
185 rect.bottom = elem->corner.y + elem->height + entity->border_width/2;
186 return distance_rectangle_point(&rect, point);
189 static void
190 entity_select(Entity *entity, Point *clicked_point,
191 Renderer *interactive_renderer)
193 element_update_handles(&entity->element);
196 static void
197 entity_move_handle(Entity *entity, Handle *handle,
198 Point *to, HandleMoveReason reason, ModifierKeys modifiers)
200 assert(entity!=NULL);
201 assert(handle!=NULL);
202 assert(to!=NULL);
204 element_move_handle(&entity->element, handle->id, to, reason);
206 entity_update_data(entity);
209 static void
210 entity_move(Entity *entity, Point *to)
212 entity->element.corner = *to;
214 entity_update_data(entity);
217 static void
218 entity_draw(Entity *entity, Renderer *renderer)
220 Point ul_corner, lr_corner;
221 Point p;
222 Element *elem;
223 coord diff;
225 assert(entity != NULL);
226 assert(renderer != NULL);
228 elem = &entity->element;
230 ul_corner.x = elem->corner.x;
231 ul_corner.y = elem->corner.y;
232 lr_corner.x = elem->corner.x + elem->width;
233 lr_corner.y = elem->corner.y + elem->height;
235 renderer->ops->set_fillstyle(renderer, FILLSTYLE_SOLID);
237 renderer->ops->fill_rect(renderer,
238 &ul_corner,
239 &lr_corner,
240 &entity->inner_color);
242 renderer->ops->set_linewidth(renderer, entity->border_width);
243 renderer->ops->set_linestyle(renderer, LINESTYLE_SOLID);
244 renderer->ops->set_linejoin(renderer, LINEJOIN_MITER);
246 renderer->ops->draw_rect(renderer,
247 &ul_corner,
248 &lr_corner,
249 &entity->border_color);
251 if(entity->weak) {
252 diff = WEAK_BORDER_WIDTH/*MIN(elem->width / 2.0 * 0.20, elem->height / 2.0 * 0.20)*/;
253 ul_corner.x += diff;
254 ul_corner.y += diff;
255 lr_corner.x -= diff;
256 lr_corner.y -= diff;
257 renderer->ops->draw_rect(renderer,
258 &ul_corner, &lr_corner,
259 &entity->border_color);
262 p.x = elem->corner.x + elem->width / 2.0;
263 p.y = elem->corner.y + (elem->height - entity->font_height)/2.0 +
264 dia_font_ascent(entity->name,entity->font, entity->font_height);
265 renderer->ops->set_font(renderer, entity->font, entity->font_height);
266 renderer->ops->draw_string(renderer,
267 entity->name,
268 &p, ALIGN_CENTER,
269 &color_black);
272 static void
273 entity_update_data(Entity *entity)
275 Element *elem = &entity->element;
276 Object *obj = &elem->object;
277 ElementBBExtras *extra = &elem->extra_spacing;
279 entity->name_width =
280 dia_font_string_width(entity->name, entity->font, entity->font_height);
282 elem->width = entity->name_width + 2*TEXT_BORDER_WIDTH_X;
283 elem->height = entity->font_height + 2*TEXT_BORDER_WIDTH_Y;
285 /* Update connections: */
286 entity->connections[0].pos = elem->corner;
287 entity->connections[1].pos.x = elem->corner.x + elem->width / 2.0;
288 entity->connections[1].pos.y = elem->corner.y;
289 entity->connections[2].pos.x = elem->corner.x + elem->width;
290 entity->connections[2].pos.y = elem->corner.y;
291 entity->connections[3].pos.x = elem->corner.x;
292 entity->connections[3].pos.y = elem->corner.y + elem->height / 2.0;
293 entity->connections[4].pos.x = elem->corner.x + elem->width;
294 entity->connections[4].pos.y = elem->corner.y + elem->height / 2.0;
295 entity->connections[5].pos.x = elem->corner.x;
296 entity->connections[5].pos.y = elem->corner.y + elem->height;
297 entity->connections[6].pos.x = elem->corner.x + elem->width / 2.0;
298 entity->connections[6].pos.y = elem->corner.y + elem->height;
299 entity->connections[7].pos.x = elem->corner.x + elem->width;
300 entity->connections[7].pos.y = elem->corner.y + elem->height;
302 extra->border_trans = entity->border_width/2.0;
303 element_update_boundingbox(elem);
305 obj->position = elem->corner;
307 element_update_handles(elem);
310 static Object *
311 entity_create(Point *startpoint,
312 void *user_data,
313 Handle **handle1,
314 Handle **handle2)
316 Entity *entity;
317 Element *elem;
318 Object *obj;
319 int i;
321 entity = g_malloc0(sizeof(Entity));
322 elem = &entity->element;
323 obj = &elem->object;
325 obj->type = &entity_type;
327 obj->ops = &entity_ops;
329 elem->corner = *startpoint;
330 elem->width = DEFAULT_WIDTH;
331 elem->height = DEFAULT_WIDTH;
333 entity->border_width = attributes_get_default_linewidth();
334 entity->border_color = attributes_get_foreground();
335 entity->inner_color = attributes_get_background();
337 element_init(elem, 8, 8);
339 for (i=0;i<8;i++) {
340 obj->connections[i] = &entity->connections[i];
341 entity->connections[i].object = obj;
342 entity->connections[i].connected = NULL;
345 entity->weak = GPOINTER_TO_INT(user_data);
346 entity->font = dia_font_new(BASIC_MONOSPACE_FONT,STYLE_NORMAL,FONT_HEIGHT);
347 entity->font_height = FONT_HEIGHT;
348 entity->name = g_strdup(_("Entity"));
350 entity->name_width =
351 dia_font_string_width(entity->name, entity->font, entity->font_height);
353 entity_update_data(entity);
355 for (i=0;i<8;i++) {
356 obj->handles[i]->type = HANDLE_NON_MOVABLE;
359 *handle1 = NULL;
360 *handle2 = obj->handles[0];
361 return &entity->element.object;
364 static void
365 entity_destroy(Entity *entity)
367 dia_font_unref(entity->font);
368 element_destroy(&entity->element);
369 g_free(entity->name);
372 static Object *
373 entity_copy(Entity *entity)
375 int i;
376 Entity *newentity;
377 Element *elem, *newelem;
378 Object *newobj;
380 elem = &entity->element;
382 newentity = g_malloc0(sizeof(Entity));
383 newelem = &newentity->element;
384 newobj = &newelem->object;
386 element_copy(elem, newelem);
388 newentity->border_width = entity->border_width;
389 newentity->border_color = entity->border_color;
390 newentity->inner_color = entity->inner_color;
392 for (i=0;i<8;i++) {
393 newobj->connections[i] = &newentity->connections[i];
394 newentity->connections[i].object = newobj;
395 newentity->connections[i].connected = NULL;
396 newentity->connections[i].pos = entity->connections[i].pos;
397 newentity->connections[i].last_pos = entity->connections[i].last_pos;
400 newentity->font = dia_font_ref(entity->font);
401 newentity->font_height = entity->font_height;
402 newentity->name = strdup(entity->name);
403 newentity->name_width = entity->name_width;
405 newentity->weak = entity->weak;
407 return &newentity->element.object;
410 static void
411 entity_save(Entity *entity, ObjectNode obj_node, const char *filename)
413 element_save(&entity->element, obj_node);
415 data_add_real(new_attribute(obj_node, "border_width"),
416 entity->border_width);
417 data_add_color(new_attribute(obj_node, "border_color"),
418 &entity->border_color);
419 data_add_color(new_attribute(obj_node, "inner_color"),
420 &entity->inner_color);
421 data_add_string(new_attribute(obj_node, "name"),
422 entity->name);
423 data_add_boolean(new_attribute(obj_node, "weak"),
424 entity->weak);
425 data_add_font (new_attribute (obj_node, "font"),
426 entity->font);
427 data_add_real(new_attribute(obj_node, "font_height"),
428 entity->font_height);
431 static Object *
432 entity_load(ObjectNode obj_node, int version, const char *filename)
434 Entity *entity;
435 Element *elem;
436 Object *obj;
437 int i;
438 AttributeNode attr;
440 entity = g_malloc0(sizeof(Entity));
441 elem = &entity->element;
442 obj = &elem->object;
444 obj->type = &entity_type;
445 obj->ops = &entity_ops;
447 element_load(elem, obj_node);
449 entity->border_width = 0.1;
450 attr = object_find_attribute(obj_node, "border_width");
451 if (attr != NULL)
452 entity->border_width = data_real( attribute_first_data(attr) );
454 entity->border_color = color_black;
455 attr = object_find_attribute(obj_node, "border_color");
456 if (attr != NULL)
457 data_color(attribute_first_data(attr), &entity->border_color);
459 entity->inner_color = color_white;
460 attr = object_find_attribute(obj_node, "inner_color");
461 if (attr != NULL)
462 data_color(attribute_first_data(attr), &entity->inner_color);
464 entity->name = NULL;
465 attr = object_find_attribute(obj_node, "name");
466 if (attr != NULL)
467 entity->name = data_string(attribute_first_data(attr));
469 attr = object_find_attribute(obj_node, "weak");
470 if (attr != NULL)
471 entity->weak = data_boolean(attribute_first_data(attr));
473 dia_font_unref(entity->font);
474 entity->font = NULL;
475 attr = object_find_attribute (obj_node, "font");
476 if (attr != NULL)
477 entity->font = data_font (attribute_first_data (attr));
479 entity->font_height = FONT_HEIGHT;
480 attr = object_find_attribute(obj_node, "font_height");
481 if (attr != NULL)
482 entity->font_height = data_real(attribute_first_data(attr));
484 element_init(elem, 8, 8);
486 for (i=0;i<8;i++) {
487 obj->connections[i] = &entity->connections[i];
488 entity->connections[i].object = obj;
489 entity->connections[i].connected = NULL;
492 if (entity->font == NULL) {
493 entity->font = dia_font_new("Monospace",STYLE_NORMAL,1.0);
496 entity->name_width =
497 dia_font_string_width(entity->name, entity->font, entity->font_height);
499 entity_update_data(entity);
501 for (i=0;i<8;i++) {
502 obj->handles[i]->type = HANDLE_NON_MOVABLE;
505 return &entity->element.object;