1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * SADT Activity/Data box -- objects for drawing SADT diagrams.
5 * Copyright (C) 2000, 2001 Cyrille Chepelov
7 * Forked from Flowchart toolbox -- objects for drawing flowcharts.
8 * Copyright (C) 1999 James Henstridge.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
38 #include "connectionpoint.h"
40 #include "attributes.h"
44 #include "connpoint_line.h"
46 #include "properties.h"
48 #include "pixmaps/sadtbox.xpm"
50 #define DEFAULT_WIDTH 7.0
51 #define DEFAULT_HEIGHT 5.0
52 #define DEFAULT_BORDER 0.25
53 #define SADTBOX_LINE_WIDTH 0.10
54 #define SADTBOX_FG_COLOR color_black
55 #define SADTBOX_BG_COLOR color_white
67 ConnPointLine
*north
,*south
,*east
,*west
;
76 static real
sadtbox_distance_from(Box
*box
, Point
*point
);
77 static void sadtbox_select(Box
*box
, Point
*clicked_point
,
78 Renderer
*interactive_renderer
);
79 static void sadtbox_move_handle(Box
*box
, Handle
*handle
,
80 Point
*to
, HandleMoveReason reason
,
81 ModifierKeys modifiers
);
82 static void sadtbox_move(Box
*box
, Point
*to
);
83 static void sadtbox_draw(Box
*box
, Renderer
*renderer
);
84 static void sadtbox_update_data(Box
*box
, AnchorShape horix
, AnchorShape vert
);
85 static Object
*sadtbox_create(Point
*startpoint
,
89 static void sadtbox_destroy(Box
*box
);
90 static Object
*sadtbox_load(ObjectNode obj_node
, int version
,
91 const char *filename
);
92 static DiaMenu
*sadtbox_get_object_menu(Box
*box
, Point
*clickedpoint
);
94 static PropDescription
*sadtbox_describe_props(Box
*box
);
95 static void sadtbox_get_props(Box
*box
, GPtrArray
*props
);
96 static void sadtbox_set_props(Box
*box
, GPtrArray
*props
);
98 static ObjectTypeOps sadtbox_type_ops
=
100 (CreateFunc
) sadtbox_create
,
101 (LoadFunc
) sadtbox_load
/*using_properties*/,
102 (SaveFunc
) object_save_using_properties
,
103 (GetDefaultsFunc
) NULL
,
104 (ApplyDefaultsFunc
) NULL
,
107 ObjectType sadtbox_type
=
109 "SADT - box", /* name */
111 (char **) sadtbox_xpm
, /* pixmap */
113 &sadtbox_type_ops
/* ops */
116 static ObjectOps sadtbox_ops
= {
117 (DestroyFunc
) sadtbox_destroy
,
118 (DrawFunc
) sadtbox_draw
,
119 (DistanceFunc
) sadtbox_distance_from
,
120 (SelectFunc
) sadtbox_select
,
121 (CopyFunc
) object_copy_using_properties
,
122 (MoveFunc
) sadtbox_move
,
123 (MoveHandleFunc
) sadtbox_move_handle
,
124 (GetPropertiesFunc
) object_create_props_dialog
,
125 (ApplyPropertiesFunc
) object_apply_props_from_dialog
,
126 (ObjectMenuFunc
) sadtbox_get_object_menu
,
127 (DescribePropsFunc
) sadtbox_describe_props
,
128 (GetPropsFunc
) sadtbox_get_props
,
129 (SetPropsFunc
) sadtbox_set_props
132 static PropNumData text_padding_data
= { 0.0, 10.0, 0.1 };
134 static PropDescription box_props
[] = {
135 ELEMENT_COMMON_PROPERTIES
,
136 { "padding",PROP_TYPE_REAL
,PROP_FLAG_VISIBLE
,
137 N_("Text padding"), NULL
, &text_padding_data
},
138 { "text", PROP_TYPE_TEXT
, 0,NULL
,NULL
},
139 PROP_STD_TEXT_ALIGNMENT
,
141 PROP_STD_TEXT_HEIGHT
,
142 PROP_STD_TEXT_COLOUR
,
143 { "id", PROP_TYPE_STRING
, PROP_FLAG_VISIBLE
|PROP_FLAG_DONT_MERGE
,
144 N_("Activity/Data identifier"),
145 N_("The identifier which appears in the lower right corner of the Box")},
146 { "cpl_north",PROP_TYPE_CONNPOINT_LINE
, 0, NULL
, NULL
},
147 { "cpl_west",PROP_TYPE_CONNPOINT_LINE
, 0, NULL
, NULL
},
148 { "cpl_south",PROP_TYPE_CONNPOINT_LINE
, 0, NULL
, NULL
},
149 { "cpl_east",PROP_TYPE_CONNPOINT_LINE
, 0, NULL
, NULL
},
153 static PropDescription
*
154 sadtbox_describe_props(Box
*box
)
156 if (box_props
[0].quark
== 0) {
157 prop_desc_list_calculate_quarks(box_props
);
162 static PropOffset box_offsets
[] = {
163 ELEMENT_COMMON_PROPERTIES_OFFSETS
,
164 { "padding",PROP_TYPE_REAL
,offsetof(Box
,padding
)},
165 { "text", PROP_TYPE_TEXT
, offsetof(Box
,text
)},
166 { "text_alignment",PROP_TYPE_ENUM
,offsetof(Box
,attrs
.alignment
)},
167 { "text_font",PROP_TYPE_FONT
,offsetof(Box
,attrs
.font
)},
168 { "text_height",PROP_TYPE_REAL
,offsetof(Box
,attrs
.height
)},
169 { "text_colour",PROP_TYPE_COLOUR
,offsetof(Box
,attrs
.color
)},
170 { "id", PROP_TYPE_STRING
, offsetof(Box
,id
)},
171 { "cpl_north",PROP_TYPE_CONNPOINT_LINE
, offsetof(Box
,north
)},
172 { "cpl_west",PROP_TYPE_CONNPOINT_LINE
, offsetof(Box
,west
)},
173 { "cpl_south",PROP_TYPE_CONNPOINT_LINE
, offsetof(Box
,south
)},
174 { "cpl_east",PROP_TYPE_CONNPOINT_LINE
, offsetof(Box
,east
)},
179 sadtbox_get_props(Box
*box
, GPtrArray
*props
)
181 text_get_attributes(box
->text
,&box
->attrs
);
182 object_get_props_from_offsets(&box
->element
.object
,
187 sadtbox_set_props(Box
*box
, GPtrArray
*props
)
189 object_set_props_from_offsets(&box
->element
.object
,
191 apply_textattr_properties(props
,box
->text
,"text",&box
->attrs
);
192 sadtbox_update_data(box
, ANCHOR_MIDDLE
, ANCHOR_MIDDLE
);
196 sadtbox_distance_from(Box
*box
, Point
*point
)
198 Element
*elem
= &box
->element
;
201 rect
.left
= elem
->corner
.x
- SADTBOX_LINE_WIDTH
/2;
202 rect
.right
= elem
->corner
.x
+ elem
->width
+ SADTBOX_LINE_WIDTH
/2;
203 rect
.top
= elem
->corner
.y
- SADTBOX_LINE_WIDTH
/2;
204 rect
.bottom
= elem
->corner
.y
+ elem
->height
+ SADTBOX_LINE_WIDTH
/2;
205 return distance_rectangle_point(&rect
, point
);
209 sadtbox_select(Box
*box
, Point
*clicked_point
,
210 Renderer
*interactive_renderer
)
212 text_set_cursor(box
->text
, clicked_point
, interactive_renderer
);
213 text_grab_focus(box
->text
, &box
->element
.object
);
214 element_update_handles(&box
->element
);
218 sadtbox_move_handle(Box
*box
, Handle
*handle
,
219 Point
*to
, HandleMoveReason reason
, ModifierKeys modifiers
)
221 AnchorShape horiz
= ANCHOR_MIDDLE
, vert
= ANCHOR_MIDDLE
;
224 assert(handle
!=NULL
);
227 element_move_handle(&box
->element
, handle
->id
, to
, reason
);
229 switch (handle
->id
) {
230 case HANDLE_RESIZE_NW
:
231 horiz
= ANCHOR_END
; vert
= ANCHOR_END
; break;
232 case HANDLE_RESIZE_N
:
233 vert
= ANCHOR_END
; break;
234 case HANDLE_RESIZE_NE
:
235 horiz
= ANCHOR_START
; vert
= ANCHOR_END
; break;
236 case HANDLE_RESIZE_E
:
237 horiz
= ANCHOR_START
; break;
238 case HANDLE_RESIZE_SE
:
239 horiz
= ANCHOR_START
; vert
= ANCHOR_START
; break;
240 case HANDLE_RESIZE_S
:
241 vert
= ANCHOR_START
; break;
242 case HANDLE_RESIZE_SW
:
243 horiz
= ANCHOR_END
; vert
= ANCHOR_START
; break;
244 case HANDLE_RESIZE_W
:
245 horiz
= ANCHOR_END
; break;
249 sadtbox_update_data(box
, horiz
, vert
);
253 sadtbox_move(Box
*box
, Point
*to
)
255 box
->element
.corner
= *to
;
257 sadtbox_update_data(box
, ANCHOR_MIDDLE
, ANCHOR_MIDDLE
);
261 sadtbox_draw(Box
*box
, Renderer
*renderer
)
268 assert(renderer
!= NULL
);
270 elem
= &box
->element
;
272 lr_corner
.x
= elem
->corner
.x
+ elem
->width
;
273 lr_corner
.y
= elem
->corner
.y
+ elem
->height
;
275 renderer
->ops
->set_fillstyle(renderer
, FILLSTYLE_SOLID
);
276 renderer
->ops
->fill_rect(renderer
,
282 renderer
->ops
->set_linewidth(renderer
, SADTBOX_LINE_WIDTH
);
283 renderer
->ops
->set_linestyle(renderer
, LINESTYLE_SOLID
);
284 renderer
->ops
->set_linejoin(renderer
, LINEJOIN_MITER
);
286 renderer
->ops
->draw_rect(renderer
,
292 text_draw(box
->text
, renderer
);
294 idfontheight
= .75 * box
->text
->height
;
295 renderer
->ops
->set_font(renderer
, box
->text
->font
, idfontheight
);
297 pos
.x
-= .3 * idfontheight
;
298 pos
.y
-= .3 * idfontheight
;
299 renderer
->ops
->draw_string(renderer
,
306 sadtbox_update_data(Box
*box
, AnchorShape horiz
, AnchorShape vert
)
308 Element
*elem
= &box
->element
;
309 ElementBBExtras
*extra
= &elem
->extra_spacing
;
310 Object
*obj
= &elem
->object
;
311 Point center
, bottom_right
;
316 /* save starting points */
317 center
= bottom_right
= elem
->corner
;
318 center
.x
+= elem
->width
/2;
319 bottom_right
.x
+= elem
->width
;
320 center
.y
+= elem
->height
/2;
321 bottom_right
.y
+= elem
->height
;
323 text_calc_boundingbox(box
->text
, NULL
);
324 width
= box
->text
->max_width
+ box
->padding
*2;
325 height
= box
->text
->height
* box
->text
->numlines
+ box
->padding
*2;
327 if (width
> elem
->width
) elem
->width
= width
;
328 if (height
> elem
->height
) elem
->height
= height
;
330 /* move shape if necessary ... */
333 elem
->corner
.x
= center
.x
- elem
->width
/2; break;
335 elem
->corner
.x
= bottom_right
.x
- elem
->width
; break;
341 elem
->corner
.y
= center
.y
- elem
->height
/2; break;
343 elem
->corner
.y
= bottom_right
.y
- elem
->height
; break;
349 p
.x
+= elem
->width
/ 2.0;
350 p
.y
+= elem
->height
/ 2.0 - box
->text
->height
* box
->text
->numlines
/ 2 +
352 text_set_position(box
->text
, &p
);
354 extra
->border_trans
= SADTBOX_LINE_WIDTH
/ 2.0;
355 element_update_boundingbox(elem
);
357 obj
->position
= elem
->corner
;
359 element_update_handles(elem
);
361 /* Update connections: */
369 connpointline_update(box
->north
);
370 connpointline_putonaline(box
->north
,&ne
,&nw
);
371 connpointline_update(box
->west
);
372 connpointline_putonaline(box
->west
,&nw
,&sw
);
373 connpointline_update(box
->south
);
374 connpointline_putonaline(box
->south
,&sw
,&se
);
375 connpointline_update(box
->east
);
376 connpointline_putonaline(box
->east
,&se
,&ne
);
380 static ConnPointLine
*
381 sadtbox_get_clicked_border(Box
*box
, Point
*clicked
)
387 dist
= distance_line_point(&box
->north
->start
,&box
->north
->end
,0,clicked
);
389 dist2
= distance_line_point(&box
->west
->start
,&box
->west
->end
,0,clicked
);
394 dist2
= distance_line_point(&box
->south
->start
,&box
->south
->end
,0,clicked
);
399 dist2
= distance_line_point(&box
->east
->start
,&box
->east
->end
,0,clicked
);
407 inline static ObjectChange
*
408 sadtbox_create_change(Box
*box
, ObjectChange
*inner
, ConnPointLine
*cpl
) {
409 return (ObjectChange
*)inner
;
412 static ObjectChange
*
413 sadtbox_add_connpoint_callback(Object
*obj
, Point
*clicked
, gpointer data
)
415 ObjectChange
*change
;
417 Box
*box
= (Box
*)obj
;
419 cpl
= sadtbox_get_clicked_border(box
,clicked
);
420 change
= connpointline_add_point(cpl
, clicked
);
421 sadtbox_update_data((Box
*)obj
,ANCHOR_MIDDLE
, ANCHOR_MIDDLE
);
422 return sadtbox_create_change(box
,change
,cpl
);
425 static ObjectChange
*
426 sadtbox_remove_connpoint_callback(Object
*obj
, Point
*clicked
, gpointer data
)
428 ObjectChange
*change
;
430 Box
*box
= (Box
*)obj
;
432 cpl
= sadtbox_get_clicked_border(box
,clicked
);
433 change
= connpointline_remove_point(cpl
, clicked
);
434 sadtbox_update_data((Box
*)obj
,ANCHOR_MIDDLE
, ANCHOR_MIDDLE
);
435 return sadtbox_create_change(box
,change
,cpl
);
438 static DiaMenuItem object_menu_items
[] = {
439 { N_("Add connection point"), sadtbox_add_connpoint_callback
, NULL
, 1 },
440 { N_("Delete connection point"), sadtbox_remove_connpoint_callback
,
444 static DiaMenu object_menu
= {
446 sizeof(object_menu_items
)/sizeof(DiaMenuItem
),
452 sadtbox_get_object_menu(Box
*box
, Point
*clickedpoint
)
456 cpl
= sadtbox_get_clicked_border(box
,clickedpoint
);
457 /* Set entries sensitive/selected etc here */
458 object_menu_items
[0].active
= connpointline_can_add_point(cpl
, clickedpoint
);
459 object_menu_items
[1].active
= connpointline_can_remove_point(cpl
, clickedpoint
);
465 sadtbox_create(Point
*startpoint
,
476 box
= g_malloc0(sizeof(Box
));
477 elem
= &box
->element
;
480 obj
->type
= &sadtbox_type
;
482 obj
->ops
= &sadtbox_ops
;
484 elem
->corner
= *startpoint
;
485 elem
->width
= DEFAULT_WIDTH
;
486 elem
->height
= DEFAULT_HEIGHT
;
488 box
->padding
= 0.5; /* default_values.padding; */
491 p
.x
+= elem
->width
/ 2.0;
492 p
.y
+= elem
->height
/ 2.0 + /*default_properties.font_size*/ 0.8 / 2;
494 font
= dia_font_new(BASIC_SANS_FONT
,STYLE_BOLD
,0.8);
496 box
->text
= new_text("", font
,
500 dia_font_unref(font
);
502 box
->id
= g_strdup("A0"); /* should be made better.
503 Automatic counting ? */
505 element_init(elem
, 8, 0);
507 box
->north
= connpointline_create(obj
,4);
508 box
->west
= connpointline_create(obj
,3);
509 box
->south
= connpointline_create(obj
,1);
510 box
->east
= connpointline_create(obj
,3);
512 box
->element
.extra_spacing
.border_trans
= SADTBOX_LINE_WIDTH
/2.0;
513 sadtbox_update_data(box
, ANCHOR_MIDDLE
, ANCHOR_MIDDLE
);
516 *handle2
= obj
->handles
[7];
517 return &box
->element
.object
;
521 sadtbox_destroy(Box
*box
)
523 text_destroy(box
->text
);
525 connpointline_destroy(box
->east
);
526 connpointline_destroy(box
->south
);
527 connpointline_destroy(box
->west
);
528 connpointline_destroy(box
->north
);
532 element_destroy(&box
->element
);
537 sadtbox_load(ObjectNode obj_node
, int version
, const char *filename
)
539 return object_load_using_properties(&sadtbox_type
,
540 obj_node
,version
,filename
);