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. */
32 #include "connectionpoint.h"
33 #include "diarenderer.h"
34 #include "attributes.h"
36 #include "properties.h"
38 #include "pixmaps/attribute.xpm"
40 #define DEFAULT_WIDTH 2.0
41 #define DEFAULT_HEIGHT 1.0
42 #define FONT_HEIGHT 0.8
43 #define MULTIVALUE_BORDER_WIDTH_X 0.4
44 #define MULTIVALUE_BORDER_WIDTH_Y 0.2
45 #define TEXT_BORDER_WIDTH_X 1.0
46 #define TEXT_BORDER_WIDTH_Y 0.5
48 #define NUM_CONNECTIONS 9
50 typedef struct _Attribute Attribute
;
52 struct _AttributeState
{
53 ObjectState obj_state
;
76 ConnectionPoint connections
[NUM_CONNECTIONS
];
88 static real
attribute_distance_from(Attribute
*attribute
, Point
*point
);
89 static void attribute_select(Attribute
*attribute
, Point
*clicked_point
,
90 DiaRenderer
*interactive_renderer
);
91 static ObjectChange
* attribute_move_handle(Attribute
*attribute
, Handle
*handle
,
92 Point
*to
, ConnectionPoint
*cp
,
93 HandleMoveReason reason
,
94 ModifierKeys modifiers
);
95 static ObjectChange
* attribute_move(Attribute
*attribute
, Point
*to
);
96 static void attribute_draw(Attribute
*attribute
, DiaRenderer
*renderer
);
97 static void attribute_update_data(Attribute
*attribute
);
98 static DiaObject
*attribute_create(Point
*startpoint
,
102 static void attribute_destroy(Attribute
*attribute
);
103 static DiaObject
*attribute_copy(Attribute
*attribute
);
104 static PropDescription
*
105 attribute_describe_props(Attribute
*attribute
);
107 attribute_get_props(Attribute
*attribute
, GPtrArray
*props
);
109 attribute_set_props(Attribute
*attribute
, GPtrArray
*props
);
111 static void attribute_save(Attribute
*attribute
, ObjectNode obj_node
,
112 const char *filename
);
113 static DiaObject
*attribute_load(ObjectNode obj_node
, int version
,
114 const char *filename
);
116 static ObjectTypeOps attribute_type_ops
=
118 (CreateFunc
) attribute_create
,
119 (LoadFunc
) attribute_load
,
120 (SaveFunc
) attribute_save
123 DiaObjectType attribute_type
=
125 "ER - Attribute", /* name */
127 (char **) attribute_xpm
, /* pixmap */
129 &attribute_type_ops
/* ops */
132 DiaObjectType
*_attribute_type
= (DiaObjectType
*) &attribute_type
;
134 static ObjectOps attribute_ops
= {
135 (DestroyFunc
) attribute_destroy
,
136 (DrawFunc
) attribute_draw
,
137 (DistanceFunc
) attribute_distance_from
,
138 (SelectFunc
) attribute_select
,
139 (CopyFunc
) attribute_copy
,
140 (MoveFunc
) attribute_move
,
141 (MoveHandleFunc
) attribute_move_handle
,
142 (GetPropertiesFunc
) object_create_props_dialog
,
143 (ApplyPropertiesFunc
) object_apply_props_from_dialog
,
144 (ObjectMenuFunc
) NULL
,
145 (DescribePropsFunc
) attribute_describe_props
,
146 (GetPropsFunc
) attribute_get_props
,
147 (SetPropsFunc
) attribute_set_props
,
150 static PropDescription attribute_props
[] = {
151 ELEMENT_COMMON_PROPERTIES
,
152 { "name", PROP_TYPE_STRING
, PROP_FLAG_VISIBLE
,
153 N_("Name:"), NULL
, NULL
},
154 { "key", PROP_TYPE_BOOL
, PROP_FLAG_VISIBLE
,
155 N_("Key:"), NULL
, NULL
},
156 { "weakkey", PROP_TYPE_BOOL
, PROP_FLAG_VISIBLE
,
157 N_("Weak key:"), NULL
, NULL
},
158 { "derived", PROP_TYPE_BOOL
, PROP_FLAG_VISIBLE
,
159 N_("Derived:"), NULL
, NULL
},
160 { "multivalue", PROP_TYPE_BOOL
, PROP_FLAG_VISIBLE
,
161 N_("Multivalue:"), NULL
, NULL
},
163 PROP_STD_LINE_COLOUR
,
164 PROP_STD_FILL_COLOUR
,
166 PROP_STD_TEXT_HEIGHT
,
170 static PropDescription
*
171 attribute_describe_props(Attribute
*attribute
)
173 if (attribute_props
[0].quark
== 0)
174 prop_desc_list_calculate_quarks(attribute_props
);
175 return attribute_props
;
178 static PropOffset attribute_offsets
[] = {
179 ELEMENT_COMMON_PROPERTIES_OFFSETS
,
180 { "name", PROP_TYPE_STRING
, offsetof(Attribute
, name
) },
181 { "key", PROP_TYPE_BOOL
, offsetof(Attribute
, key
) },
182 { "weakkey", PROP_TYPE_BOOL
, offsetof(Attribute
, weakkey
) },
183 { "derived", PROP_TYPE_BOOL
, offsetof(Attribute
, derived
) },
184 { "multivalue", PROP_TYPE_BOOL
, offsetof(Attribute
, multivalue
) },
185 { "line_width", PROP_TYPE_REAL
, offsetof(Attribute
, border_width
) },
186 { "line_colour", PROP_TYPE_COLOUR
, offsetof(Attribute
, border_color
) },
187 { "fill_colour", PROP_TYPE_COLOUR
, offsetof(Attribute
, inner_color
) },
188 { "text_font", PROP_TYPE_FONT
, offsetof(Attribute
, font
) },
189 { "text_height", PROP_TYPE_REAL
, offsetof(Attribute
, font_height
) },
195 attribute_get_props(Attribute
*attribute
, GPtrArray
*props
)
197 object_get_props_from_offsets(&attribute
->element
.object
,
198 attribute_offsets
, props
);
202 attribute_set_props(Attribute
*attribute
, GPtrArray
*props
)
204 object_set_props_from_offsets(&attribute
->element
.object
,
205 attribute_offsets
, props
);
206 attribute_update_data(attribute
);
210 attribute_distance_from(Attribute
*attribute
, Point
*point
)
212 Element
*elem
= &attribute
->element
;
215 center
.x
= elem
->corner
.x
+elem
->width
/2;
216 center
.y
= elem
->corner
.y
+elem
->height
/2;
218 return distance_ellipse_point(¢er
, elem
->width
, elem
->height
,
219 attribute
->border_width
, point
);
223 attribute_select(Attribute
*attribute
, Point
*clicked_point
,
224 DiaRenderer
*interactive_renderer
)
226 element_update_handles(&attribute
->element
);
230 attribute_move_handle(Attribute
*attribute
, Handle
*handle
,
231 Point
*to
, ConnectionPoint
*cp
,
232 HandleMoveReason reason
, ModifierKeys modifiers
)
234 assert(attribute
!=NULL
);
235 assert(handle
!=NULL
);
238 assert(handle
->id
< 8);
239 element_move_handle(&attribute
->element
, handle
->id
, to
, cp
,
241 attribute_update_data(attribute
);
247 attribute_move(Attribute
*attribute
, Point
*to
)
249 attribute
->element
.corner
= *to
;
250 attribute_update_data(attribute
);
256 attribute_draw(Attribute
*attribute
, DiaRenderer
*renderer
)
258 DiaRendererClass
*renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
265 assert(attribute
!= NULL
);
266 assert(renderer
!= NULL
);
268 elem
= &attribute
->element
;
270 center
.x
= elem
->corner
.x
+ elem
->width
/2;
271 center
.y
= elem
->corner
.y
+ elem
->height
/2;
273 renderer_ops
->set_fillstyle(renderer
, FILLSTYLE_SOLID
);
274 renderer_ops
->fill_ellipse(renderer
, ¢er
,
275 elem
->width
, elem
->height
,
276 &attribute
->inner_color
);
278 renderer_ops
->set_linewidth(renderer
, attribute
->border_width
);
279 if (attribute
->derived
) {
280 renderer_ops
->set_linestyle(renderer
, LINESTYLE_DASHED
);
281 renderer_ops
->set_dashlength(renderer
, 0.3);
283 renderer_ops
->set_linestyle(renderer
, LINESTYLE_SOLID
);
286 renderer_ops
->draw_ellipse(renderer
, ¢er
,
287 elem
->width
, elem
->height
,
288 &attribute
->border_color
);
290 if(attribute
->multivalue
) {
291 renderer_ops
->draw_ellipse(renderer
, ¢er
,
292 elem
->width
- 2*MULTIVALUE_BORDER_WIDTH_X
,
293 elem
->height
- 2*MULTIVALUE_BORDER_WIDTH_Y
,
294 &attribute
->border_color
);
297 p
.x
= elem
->corner
.x
+ elem
->width
/ 2.0;
298 p
.y
= elem
->corner
.y
+ (elem
->height
- attribute
->font_height
)/2.0 +
299 dia_font_ascent(attribute
->name
,
300 attribute
->font
, attribute
->font_height
);
302 renderer_ops
->set_font(renderer
, attribute
->font
, attribute
->font_height
);
303 renderer_ops
->draw_string(renderer
, attribute
->name
,
307 if (attribute
->key
|| attribute
->weakkey
) {
308 if (attribute
->weakkey
) {
309 renderer_ops
->set_linestyle(renderer
, LINESTYLE_DASHED
);
310 renderer_ops
->set_dashlength(renderer
, 0.3);
312 renderer_ops
->set_linestyle(renderer
, LINESTYLE_SOLID
);
314 width
= dia_font_string_width(attribute
->name
,
315 attribute
->font
, attribute
->font_height
);
316 start
.x
= center
.x
- width
/ 2;
317 start
.y
= center
.y
+ 0.4;
318 end
.x
= center
.x
+ width
/ 2;
319 end
.y
= center
.y
+ 0.4;
320 renderer_ops
->draw_line(renderer
, &start
, &end
, &color_black
);
325 attribute_update_data(Attribute
*attribute
)
327 Element
*elem
= &attribute
->element
;
328 DiaObject
*obj
= &elem
->object
;
330 ElementBBExtras
*extra
= &elem
->extra_spacing
;
333 attribute
->name_width
=
334 dia_font_string_width(attribute
->name
,
335 attribute
->font
, attribute
->font_height
);
337 elem
->width
= attribute
->name_width
+ 2*TEXT_BORDER_WIDTH_X
;
338 elem
->height
= attribute
->font_height
+ 2*TEXT_BORDER_WIDTH_Y
;
340 center
.x
= elem
->corner
.x
+ elem
->width
/ 2.0;
341 center
.y
= elem
->corner
.y
+ elem
->height
/ 2.0;
343 half_x
= elem
->width
* M_SQRT1_2
/ 2.0;
344 half_y
= elem
->height
* M_SQRT1_2
/ 2.0;
346 /* Update connections: */
347 connpoint_update(&attribute
->connections
[0],
351 connpoint_update(&attribute
->connections
[1],
355 connpoint_update(&attribute
->connections
[2],
359 connpoint_update(&attribute
->connections
[3],
363 connpoint_update(&attribute
->connections
[4],
364 elem
->corner
.x
+ elem
->width
,
365 elem
->corner
.y
+ elem
->height
/ 2.0,
367 connpoint_update(&attribute
->connections
[5],
371 connpoint_update(&attribute
->connections
[6],
372 elem
->corner
.x
+ elem
->width
/ 2.0,
373 elem
->corner
.y
+ elem
->height
,
375 connpoint_update(&attribute
->connections
[7],
379 connpoint_update(&attribute
->connections
[8],
384 extra
->border_trans
= attribute
->border_width
/2.0;
385 element_update_boundingbox(elem
);
387 obj
->position
= elem
->corner
;
389 element_update_handles(elem
);
394 attribute_create(Point
*startpoint
,
399 Attribute
*attribute
;
404 attribute
= g_malloc0(sizeof(Attribute
));
405 elem
= &attribute
->element
;
408 obj
->type
= &attribute_type
;
409 obj
->ops
= &attribute_ops
;
411 elem
->corner
= *startpoint
;
412 elem
->width
= DEFAULT_WIDTH
;
413 elem
->height
= DEFAULT_HEIGHT
;
415 attribute
->border_width
= attributes_get_default_linewidth();
416 attribute
->border_color
= attributes_get_foreground();
417 attribute
->inner_color
= attributes_get_background();
419 element_init(elem
, 8, NUM_CONNECTIONS
);
421 for (i
=0;i
<NUM_CONNECTIONS
;i
++) {
422 obj
->connections
[i
] = &attribute
->connections
[i
];
423 attribute
->connections
[i
].object
= obj
;
424 attribute
->connections
[i
].connected
= NULL
;
426 attribute
->connections
[8].flags
= CP_FLAGS_MAIN
;
428 attribute
->key
= FALSE
;
429 attribute
->weakkey
= FALSE
;
430 attribute
->derived
= FALSE
;
431 attribute
->multivalue
= FALSE
;
432 attribute
->font
= dia_font_new_from_style(DIA_FONT_MONOSPACE
,FONT_HEIGHT
);
433 attribute
->font_height
= FONT_HEIGHT
;
434 attribute
->name
= g_strdup(_("Attribute"));
436 attribute
->name_width
=
437 dia_font_string_width(attribute
->name
,
438 attribute
->font
, attribute
->font_height
);
440 attribute_update_data(attribute
);
443 obj
->handles
[i
]->type
= HANDLE_NON_MOVABLE
;
447 *handle2
= obj
->handles
[0];
448 return &attribute
->element
.object
;
452 attribute_destroy(Attribute
*attribute
)
454 element_destroy(&attribute
->element
);
455 g_free(attribute
->name
);
459 attribute_copy(Attribute
*attribute
)
462 Attribute
*newattribute
;
463 Element
*elem
, *newelem
;
466 elem
= &attribute
->element
;
468 newattribute
= g_malloc0(sizeof(Attribute
));
469 newelem
= &newattribute
->element
;
470 newobj
= &newelem
->object
;
472 element_copy(elem
, newelem
);
474 newattribute
->border_width
= attribute
->border_width
;
475 newattribute
->border_color
= attribute
->border_color
;
476 newattribute
->inner_color
= attribute
->inner_color
;
478 for (i
=0;i
<NUM_CONNECTIONS
;i
++) {
479 newobj
->connections
[i
] = &newattribute
->connections
[i
];
480 newattribute
->connections
[i
].object
= newobj
;
481 newattribute
->connections
[i
].connected
= NULL
;
482 newattribute
->connections
[i
].pos
= attribute
->connections
[i
].pos
;
483 newattribute
->connections
[i
].last_pos
= attribute
->connections
[i
].last_pos
;
484 newattribute
->connections
[i
].flags
= attribute
->connections
[i
].flags
;
487 newattribute
->font
= dia_font_ref(attribute
->font
);
488 newattribute
->font_height
= attribute
->font_height
;
489 newattribute
->name
= g_strdup(attribute
->name
);
490 newattribute
->name_width
= attribute
->name_width
;
492 newattribute
->key
= attribute
->key
;
493 newattribute
->weakkey
= attribute
->weakkey
;
494 newattribute
->derived
= attribute
->derived
;
495 newattribute
->multivalue
= attribute
->multivalue
;
497 return &newattribute
->element
.object
;
502 attribute_save(Attribute
*attribute
, ObjectNode obj_node
,
503 const char *filename
)
505 element_save(&attribute
->element
, obj_node
);
507 data_add_real(new_attribute(obj_node
, "border_width"),
508 attribute
->border_width
);
509 data_add_color(new_attribute(obj_node
, "border_color"),
510 &attribute
->border_color
);
511 data_add_color(new_attribute(obj_node
, "inner_color"),
512 &attribute
->inner_color
);
513 data_add_string(new_attribute(obj_node
, "name"),
515 data_add_boolean(new_attribute(obj_node
, "key"),
517 data_add_boolean(new_attribute(obj_node
, "weak_key"),
519 data_add_boolean(new_attribute(obj_node
, "derived"),
521 data_add_boolean(new_attribute(obj_node
, "multivalued"),
522 attribute
->multivalue
);
523 data_add_font (new_attribute (obj_node
, "font"),
525 data_add_real(new_attribute(obj_node
, "font_height"),
526 attribute
->font_height
);
529 static DiaObject
*attribute_load(ObjectNode obj_node
, int version
,
530 const char *filename
)
532 Attribute
*attribute
;
538 attribute
= g_malloc0(sizeof(Attribute
));
539 elem
= &attribute
->element
;
542 obj
->type
= &attribute_type
;
543 obj
->ops
= &attribute_ops
;
545 element_load(elem
, obj_node
);
547 attribute
->border_width
= 0.1;
548 attr
= object_find_attribute(obj_node
, "border_width");
550 attribute
->border_width
= data_real( attribute_first_data(attr
) );
552 attribute
->border_color
= color_black
;
553 attr
= object_find_attribute(obj_node
, "border_color");
555 data_color(attribute_first_data(attr
), &attribute
->border_color
);
557 attribute
->inner_color
= color_white
;
558 attr
= object_find_attribute(obj_node
, "inner_color");
560 data_color(attribute_first_data(attr
), &attribute
->inner_color
);
562 attribute
->name
= NULL
;
563 attr
= object_find_attribute(obj_node
, "name");
565 attribute
->name
= data_string(attribute_first_data(attr
));
567 attr
= object_find_attribute(obj_node
, "key");
569 attribute
->key
= data_boolean(attribute_first_data(attr
));
571 attr
= object_find_attribute(obj_node
, "weak_key");
573 attribute
->weakkey
= data_boolean(attribute_first_data(attr
));
575 attr
= object_find_attribute(obj_node
, "derived");
577 attribute
->derived
= data_boolean(attribute_first_data(attr
));
579 attr
= object_find_attribute(obj_node
, "multivalued");
581 attribute
->multivalue
= data_boolean(attribute_first_data(attr
));
583 if (attribute
->font
!= NULL
) {
584 /* This shouldn't happen, but doesn't hurt */
585 dia_font_unref(attribute
->font
);
586 attribute
->font
= NULL
;
588 attr
= object_find_attribute (obj_node
, "font");
590 attribute
->font
= data_font (attribute_first_data (attr
));
592 attribute
->font_height
= FONT_HEIGHT
;
593 attr
= object_find_attribute (obj_node
, "font_height");
595 attribute
->font_height
= data_real( attribute_first_data(attr
) );
597 element_init(elem
, 8, NUM_CONNECTIONS
);
599 for (i
=0;i
<NUM_CONNECTIONS
;i
++) {
600 obj
->connections
[i
] = &attribute
->connections
[i
];
601 attribute
->connections
[i
].object
= obj
;
602 attribute
->connections
[i
].connected
= NULL
;
604 attribute
->connections
[8].flags
= CP_FLAGS_MAIN
;
606 if (attribute
->font
== NULL
) {
607 attribute
->font
= dia_font_new_from_style(DIA_FONT_MONOSPACE
,
608 attribute
->font_height
);
611 attribute
->name_width
= dia_font_string_width(attribute
->name
,
613 attribute
->font_height
);
614 attribute_update_data(attribute
);
617 obj
->handles
[i
]->type
= HANDLE_NON_MOVABLE
;
620 return &attribute
->element
.object
;