1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * Jackson diagram - adapted by Christophe Ponsard
5 * This class captures all kind of domains (given, designed, machine)
6 * both for generic problems and for problem frames (ie. with domain kinds)
8 * based on SADT diagrams copyright (C) 2000, 2001 Cyrille Chepelov
10 * Forked from Flowchart toolbox -- objects for drawing flowcharts.
11 * Copyright (C) 1999 James Henstridge.
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
39 #include "diarenderer.h"
40 #include "attributes.h"
42 #include "properties.h"
44 #include "pixmaps/requirement.xpm"
46 typedef struct _RequirementPropertiesDialog RequirementPropertiesDialog
;
47 typedef struct _Requirement Requirement
;
48 typedef struct _RequirementState RequirementState
;
50 #define NUM_CONNECTIONS 9
55 ConnectionPoint connections
[NUM_CONNECTIONS
];
66 struct _RequirementPropertiesDialog
{
69 GtkToggleButton
*text_out
;
70 GtkToggleButton
*collaboration
;
75 #define REQ_WIDTH 3.25
77 #define REQ_MIN_RATIO 1.5
78 #define REQ_MAX_RATIO 3
79 #define REQ_LINEWIDTH 0.09
80 #define REQ_MARGIN_Y 0.3
81 #define REQ_DASHLEN 0.5
83 static real
req_distance_from(Requirement
*req
, Point
*point
);
84 static void req_select(Requirement
*req
, Point
*clicked_point
,
85 DiaRenderer
*interactive_renderer
);
86 static ObjectChange
* req_move_handle(Requirement
*req
, Handle
*handle
,
87 Point
*to
, ConnectionPoint
*cp
,
88 HandleMoveReason reason
, ModifierKeys modifiers
);
89 static ObjectChange
* req_move(Requirement
*req
, Point
*to
);
90 static void req_draw(Requirement
*req
, DiaRenderer
*renderer
);
91 static DiaObject
*req_create(Point
*startpoint
,
95 static void req_destroy(Requirement
*req
);
96 static DiaObject
*req_load(ObjectNode obj_node
, int version
,
97 const char *filename
);
98 static void req_update_data(Requirement
*req
);
99 static PropDescription
*req_describe_props(Requirement
*req
);
100 static void req_get_props(Requirement
*req
, GPtrArray
*props
);
101 static void req_set_props(Requirement
*req
, GPtrArray
*props
);
103 static ObjectTypeOps req_type_ops
=
105 (CreateFunc
) req_create
,
106 (LoadFunc
) req_load
,/*using_properties*/ /* load */
107 (SaveFunc
) object_save_using_properties
, /* save */
108 (GetDefaultsFunc
) NULL
,
109 (ApplyDefaultsFunc
) NULL
112 DiaObjectType jackson_requirement_type
=
114 "Jackson - requirement", /* name */
116 (char **)jackson_requirement_xpm
, /* pixmap */
118 &req_type_ops
/* ops */
121 static ObjectOps req_ops
= {
122 (DestroyFunc
) req_destroy
,
124 (DistanceFunc
) req_distance_from
,
125 (SelectFunc
) req_select
,
126 (CopyFunc
) object_copy_using_properties
,
128 (MoveHandleFunc
) req_move_handle
,
129 (GetPropertiesFunc
) object_create_props_dialog
,
130 (ApplyPropertiesFunc
) object_apply_props_from_dialog
,
131 (ObjectMenuFunc
) NULL
,
132 (DescribePropsFunc
) req_describe_props
,
133 (GetPropsFunc
) req_get_props
,
134 (SetPropsFunc
) req_set_props
137 static PropDescription req_props
[] = {
138 ELEMENT_COMMON_PROPERTIES
,
140 PROP_STD_TEXT_HEIGHT
,
141 PROP_STD_TEXT_COLOUR
,
142 { "text", PROP_TYPE_TEXT
, 0, N_("Text"), NULL
, NULL
},
147 static PropDescription
*
148 req_describe_props(Requirement
*req
)
153 static PropOffset req_offsets
[] = {
154 ELEMENT_COMMON_PROPERTIES_OFFSETS
,
155 {"text",PROP_TYPE_TEXT
,offsetof(Requirement
,text
)},
156 {"text_font",PROP_TYPE_FONT
,offsetof(Requirement
,attrs
.font
)},
157 {"text_height",PROP_TYPE_REAL
,offsetof(Requirement
,attrs
.height
)},
158 {"text_colour",PROP_TYPE_COLOUR
,offsetof(Requirement
,attrs
.color
)},
163 req_get_props(Requirement
* req
, GPtrArray
*props
)
165 text_get_attributes(req
->text
,&req
->attrs
);
166 object_get_props_from_offsets(&req
->element
.object
,
171 req_set_props(Requirement
*req
, GPtrArray
*props
)
173 if (req
->init
==-1) { req
->init
++; return; } /* workaround init bug */
175 object_set_props_from_offsets(&req
->element
.object
,
177 apply_textattr_properties(props
,req
->text
,"text",&req
->attrs
);
178 req_update_data(req
);
182 req_distance_from(Requirement
*req
, Point
*point
)
184 DiaObject
*obj
= &req
->element
.object
;
185 return distance_rectangle_point(&obj
->bounding_box
, point
);
189 req_select(Requirement
*req
, Point
*clicked_point
,
190 DiaRenderer
*interactive_renderer
)
192 text_set_cursor(req
->text
, clicked_point
, interactive_renderer
);
193 text_grab_focus(req
->text
, &req
->element
.object
);
194 element_update_handles(&req
->element
);
198 req_move_handle(Requirement
*req
, Handle
*handle
,
199 Point
*to
, ConnectionPoint
*cp
,
200 HandleMoveReason reason
, ModifierKeys modifiers
)
203 assert(handle
!=NULL
);
206 assert(handle
->id
< 8);
211 req_move(Requirement
*req
, Point
*to
)
216 req
->element
.corner
= *to
;
217 h
= req
->text
->height
*req
->text
->numlines
;
220 p
.x
+= req
->element
.width
/2.0;
221 if (req
->text_outside
) {
222 p
.y
+= req
->element
.height
- h
+ req
->text
->ascent
;
224 p
.y
+= (req
->element
.height
- h
)/2.0 + req
->text
->ascent
;
226 text_set_position(req
->text
, &p
);
227 req_update_data(req
);
233 req_draw(Requirement
*req
, DiaRenderer
*renderer
)
235 DiaRendererClass
*renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
241 assert(renderer
!= NULL
);
243 elem
= &req
->element
;
249 if (req->text_outside) {
252 c.x = x + elem->width/2.0;
253 c.y = y + REQ_HEIGHT / 2.0;
262 renderer_ops
->set_fillstyle(renderer
, FILLSTYLE_SOLID
);
263 renderer_ops
->set_linewidth(renderer
, REQ_LINEWIDTH
);
265 renderer_ops
->set_dashlength(renderer
, REQ_DASHLEN
);
266 renderer_ops
->set_linestyle(renderer
, LINESTYLE_DASHED
);
268 renderer_ops
->fill_ellipse(renderer
, &c
, w
, h
, &color_white
);
269 renderer_ops
->draw_ellipse(renderer
, &c
, w
, h
, &color_black
);
271 text_draw(req
->text
, renderer
);
276 req_update_data(Requirement
*req
)
281 Element
*elem
= &req
->element
;
282 DiaObject
*obj
= &elem
->object
;
284 text_calc_boundingbox(req
->text
, NULL
);
285 w
= req
->text
->max_width
;
286 h
= req
->text
->height
*req
->text
->numlines
;
288 if (!req
->text_outside
) {
291 if (ratio
> REQ_MAX_RATIO
)
292 ratio
= REQ_MAX_RATIO
;
294 if (ratio
< REQ_MIN_RATIO
) {
295 ratio
= REQ_MIN_RATIO
;
304 if (r
.y
< REQ_HEIGHT
)
314 if (req
->text_outside
) {
315 elem
->width
= MAX(elem
->width
, w
);
316 elem
->height
+= h
+ REQ_MARGIN_Y
;
321 c
.x
= elem
->corner
.x
+ elem
->width
/ 2.0;
322 c
.y
= elem
->corner
.y
+ r
.y
;
323 half
.x
= r
.x
* M_SQRT1_2
;
324 half
.y
= r
.y
* M_SQRT1_2
;
326 /* Update connections: */
327 req
->connections
[0].pos
.x
= c
.x
- half
.x
;
328 req
->connections
[0].pos
.y
= c
.y
- half
.y
;
329 req
->connections
[1].pos
.x
= c
.x
;
330 req
->connections
[1].pos
.y
= elem
->corner
.y
;
331 req
->connections
[2].pos
.x
= c
.x
+ half
.x
;
332 req
->connections
[2].pos
.y
= c
.y
- half
.y
;
333 req
->connections
[3].pos
.x
= c
.x
- r
.x
;
334 req
->connections
[3].pos
.y
= c
.y
;
335 req
->connections
[4].pos
.x
= c
.x
+ r
.x
;
336 req
->connections
[4].pos
.y
= c
.y
;
338 if (req
->text_outside
) {
339 req
->connections
[5].pos
.x
= elem
->corner
.x
;
340 req
->connections
[5].pos
.y
= elem
->corner
.y
+ elem
->height
;
341 req
->connections
[6].pos
.x
= c
.x
;
342 req
->connections
[6].pos
.y
= elem
->corner
.y
+ elem
->height
;
343 req
->connections
[7].pos
.x
= elem
->corner
.x
+ elem
->width
;
344 req
->connections
[7].pos
.y
= elem
->corner
.y
+ elem
->height
;
346 req
->connections
[5].pos
.x
= c
.x
- half
.x
;
347 req
->connections
[5].pos
.y
= c
.y
+ half
.y
;
348 req
->connections
[6].pos
.x
= c
.x
;
349 req
->connections
[6].pos
.y
= elem
->corner
.y
+ elem
->height
;
350 req
->connections
[7].pos
.x
= c
.x
+ half
.x
;
351 req
->connections
[7].pos
.y
= c
.y
+ half
.y
;
353 req
->connections
[8].pos
.x
= elem
->corner
.x
+ elem
->width
/2;
354 req
->connections
[8].pos
.y
= elem
->corner
.y
+ elem
->height
/2;
356 h
= req
->text
->height
*req
->text
->numlines
;
357 p
= req
->element
.corner
;
358 p
.x
+= req
->element
.width
/2.0;
359 if (req
->text_outside
) {
360 p
.y
+= req
->element
.height
- h
+ req
->text
->ascent
;
362 p
.y
+= (req
->element
.height
- h
)/2.0 + req
->text
->ascent
;
364 text_set_position(req
->text
, &p
);
366 element_update_boundingbox(elem
);
368 obj
->position
= elem
->corner
;
370 element_update_handles(elem
);
376 req_create(Point
*startpoint
,
388 req
= g_malloc0(sizeof(Requirement
));
389 elem
= &req
->element
;
392 obj
->type
= &jackson_requirement_type
;
395 elem
->corner
= *startpoint
;
396 elem
->width
= REQ_WIDTH
;
397 elem
->height
= REQ_HEIGHT
;
399 font
= dia_font_new_from_style(DIA_FONT_SANS
, REQ_FONT
);
401 p
.x
+= REQ_WIDTH
/2.0;
402 p
.y
+= REQ_HEIGHT
/2.0;
404 req
->text
= new_text("", font
, REQ_FONT
, &p
, &color_black
, ALIGN_CENTER
);
405 dia_font_unref(font
);
406 text_get_attributes(req
->text
,&req
->attrs
);
407 req
->text_outside
= 0;
408 req
->collaboration
= 0;
409 element_init(elem
, 8, NUM_CONNECTIONS
);
411 for (i
=0;i
<NUM_CONNECTIONS
;i
++) {
412 obj
->connections
[i
] = &req
->connections
[i
];
413 req
->connections
[i
].object
= obj
;
414 req
->connections
[i
].connected
= NULL
;
416 req
->connections
[8].flags
= CP_FLAGS_MAIN
;
417 elem
->extra_spacing
.border_trans
= 0.0;
418 req_update_data(req
);
421 obj
->handles
[i
]->type
= HANDLE_NON_MOVABLE
;
427 if (GPOINTER_TO_INT(user_data
)!=0) req
->init
=-1; else req
->init
=0;
429 return &req
->element
.object
;
433 req_destroy(Requirement
*req
)
435 text_destroy(req
->text
);
437 element_destroy(&req
->element
);
441 req_load(ObjectNode obj_node
, int version
, const char *filename
)
443 return object_load_using_properties(&jackson_requirement_type
,
444 obj_node
,version
,filename
);