1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * GRAFCET charts support for Dia
5 * Copyright (C) 2000, 2001 Cyrille Chepelov
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
36 #include "connectionpoint.h"
38 #include "attributes.h"
40 #include "properties.h"
44 #include "pixmaps/etape.xpm"
46 #define STEP_FONT BASIC_SANS_FONT
47 #define STEP_FONT_STYLE STYLE_BOLD
48 #define STEP_FONT_HEIGHT 1
49 #define STEP_LINE_WIDTH GRAFCET_GENERAL_LINE_WIDTH
50 #define STEP_WIDTH 3.0
51 #define STEP_DECLAREDWIDTH 4.0
52 #define STEP_HEIGHT 4.0
53 #define STEP_DOT_RADIUS .35
55 #define HANDLE_NORTH HANDLE_CUSTOM1
56 #define HANDLE_SOUTH HANDLE_CUSTOM2
65 STEP_SUBPCALL
} StepType
;
67 typedef struct _Step
{
70 ConnectionPoint connections
[4];
81 Point SD1
,SD2
,NU1
,NU2
;
83 /* These are useful points for drawing.
84 Must be in sequence, A first, Z last. */
85 Point A
,B
,C
,D
,E
,F
,G
,H
,I
,J
,Z
;
88 static real
step_distance_from(Step
*step
, Point
*point
);
89 static void step_select(Step
*step
, Point
*clicked_point
,
90 Renderer
*interactive_renderer
);
91 static void step_move_handle(Step
*step
, Handle
*handle
,
92 Point
*to
, HandleMoveReason reason
, ModifierKeys modifiers
);
93 static void step_move(Step
*step
, Point
*to
);
94 static void step_draw(Step
*step
, Renderer
*renderer
);
95 static void step_update_data(Step
*step
);
96 static Object
*step_create(Point
*startpoint
,
100 static void step_destroy(Step
*step
);
102 static void step_been_renamed(const gchar
*sid
);
104 static Object
*step_load(ObjectNode obj_node
, int version
,
105 const char *filename
);
106 static PropDescription
*step_describe_props(Step
*step
);
107 static void step_get_props(Step
*step
,
109 static void step_set_props(Step
*step
,
112 static ObjectTypeOps step_type_ops
=
114 (CreateFunc
) step_create
,
115 (LoadFunc
) step_load
/*using properties*/,
116 (SaveFunc
) object_save_using_properties
,
117 (GetDefaultsFunc
) NULL
,
118 (ApplyDefaultsFunc
) NULL
,
121 ObjectType step_type
=
123 "GRAFCET - Step", /* name */
125 (char **) etape_xpm
, /* pixmap */
127 &step_type_ops
/* ops */
130 static ObjectOps step_ops
= {
131 (DestroyFunc
) step_destroy
,
132 (DrawFunc
) step_draw
,
133 (DistanceFunc
) step_distance_from
,
134 (SelectFunc
) step_select
,
135 (CopyFunc
) object_copy_using_properties
,
136 (MoveFunc
) step_move
,
137 (MoveHandleFunc
) step_move_handle
,
138 (GetPropertiesFunc
) object_create_props_dialog
,
139 (ApplyPropertiesFunc
) object_apply_props_from_dialog
,
140 (ObjectMenuFunc
) NULL
,
141 (DescribePropsFunc
) step_describe_props
,
142 (GetPropsFunc
) step_get_props
,
143 (SetPropsFunc
) step_set_props
146 PropEnumData step_style
[] = {
147 { N_("Regular step"),STEP_NORMAL
},
148 { N_("Initial step"),STEP_INITIAL
},
149 { N_("Macro entry step"),STEP_MACROENTRY
},
150 { N_("Macro exit step"),STEP_MACROEXIT
},
151 { N_("Macro call step"),STEP_MACROCALL
},
152 { N_("Subprogram call step"), STEP_SUBPCALL
},
155 static PropDescription step_props
[] = {
156 ELEMENT_COMMON_PROPERTIES
,
157 { "id", PROP_TYPE_STRING
, PROP_FLAG_VISIBLE
|PROP_FLAG_DONT_MERGE
,
158 N_("Step name"),N_("The name of the step")},
159 { "type", PROP_TYPE_ENUM
, PROP_FLAG_VISIBLE
,
160 N_("Step type"),N_("The kind of step"),step_style
},
161 { "active", PROP_TYPE_BOOL
, PROP_FLAG_VISIBLE
,
162 N_("Active"), N_("Shows a red dot to figure the step's activity")},
163 { "font", PROP_TYPE_FONT
, PROP_FLAG_VISIBLE
,
165 { "font_size", PROP_TYPE_REAL
, PROP_FLAG_VISIBLE
,
166 N_("Font size"), NULL
, &prop_std_text_height_data
},
167 { "font_color", PROP_TYPE_COLOUR
, PROP_FLAG_VISIBLE
,
168 N_("Text colour"), NULL
},
169 { "north_pos", PROP_TYPE_POINT
, 0},
170 { "south_pos", PROP_TYPE_POINT
, 0},
174 static PropDescription
*
175 step_describe_props(Step
*step
)
177 if (step_props
[0].quark
== 0) {
178 prop_desc_list_calculate_quarks(step_props
);
183 static PropOffset step_offsets
[] = {
184 ELEMENT_COMMON_PROPERTIES_OFFSETS
,
185 { "id", PROP_TYPE_STRING
, offsetof(Step
,id
)},
186 { "type", PROP_TYPE_ENUM
, offsetof(Step
,type
)},
187 { "active", PROP_TYPE_BOOL
, offsetof(Step
,active
)},
188 { "font", PROP_TYPE_FONT
, offsetof(Step
,font
)},
189 { "font_size", PROP_TYPE_REAL
, offsetof(Step
,font_size
)},
190 { "font_color", PROP_TYPE_COLOUR
, offsetof(Step
,font_color
)},
191 { "north_pos", PROP_TYPE_POINT
, offsetof(Step
,north
.pos
)},
192 { "south_pos", PROP_TYPE_POINT
, offsetof(Step
,south
.pos
)},
197 step_get_props(Step
*step
, GPtrArray
*props
)
199 object_get_props_from_offsets(&step
->element
.object
,
204 step_set_props(Step
*step
, GPtrArray
*props
)
206 object_set_props_from_offsets(&step
->element
.object
,
208 step_been_renamed(step
->id
);
209 step_update_data(step
);
212 /* the following two functions try to be clever when allocating
215 static int __stepnum
= 0;
216 static int __Astyle
= 0;
217 static gchar
*new_step_name()
222 if (__Astyle
) *p
++ = 'A';
224 g_snprintf(p
,sizeof(snum
)-2,"%d",__stepnum
++);
225 return g_strdup(snum
);
228 static void step_been_renamed(const gchar
*sid
)
234 sid
++; /* for the "A01" numbering style */
240 snum
= strtol(sid
,&endptr
,10);
241 if (*endptr
== '\0') __stepnum
= snum
+ 1;
244 static Color color_red
= { 1.0f
, 0.0f
, 0.0f
};
247 step_distance_from(Step
*step
, Point
*point
)
249 Element
*elem
= &step
->element
;
253 dist
= distance_line_point(&step
->north
.pos
,&step
->NU1
,
254 STEP_LINE_WIDTH
,point
);
255 dist
= MIN(dist
,distance_line_point(&step
->NU1
,&step
->NU2
,
256 STEP_LINE_WIDTH
,point
));
257 dist
= MIN(dist
,distance_line_point(&step
->NU2
,&step
->A
,
258 STEP_LINE_WIDTH
,point
));
259 dist
= MIN(dist
,distance_line_point(&step
->D
,&step
->SD1
,
260 STEP_LINE_WIDTH
,point
));
261 dist
= MIN(dist
,distance_line_point(&step
->SD1
,&step
->SD2
,
262 STEP_LINE_WIDTH
,point
));
263 dist
= MIN(dist
,distance_line_point(&step
->SD2
,&step
->south
.pos
,
264 STEP_LINE_WIDTH
,point
));
266 rect
.left
= elem
->corner
.x
;
267 rect
.right
= elem
->corner
.x
+ elem
->width
;
268 rect
.top
= elem
->corner
.y
;
269 rect
.bottom
= elem
->corner
.y
+ elem
->height
;
270 dist
= MIN(dist
,distance_rectangle_point(&rect
, point
));
275 step_select(Step
*step
, Point
*clicked_point
,
276 Renderer
*interactive_renderer
)
278 element_update_handles(&step
->element
);
282 step_move_handle(Step
*step
, Handle
*handle
,
283 Point
*to
, HandleMoveReason reason
, ModifierKeys modifiers
)
286 assert(handle
!=NULL
);
291 step
->north
.pos
= *to
;
292 if (step
->north
.pos
.y
> step
->A
.y
) step
->north
.pos
.y
= step
->A
.y
;
295 step
->south
.pos
= *to
;
296 if (step
->south
.pos
.y
< step
->D
.y
) step
->south
.pos
.y
= step
->D
.y
;
299 element_move_handle(&step
->element
, handle
->id
, to
, reason
);
302 step_update_data(step
);
306 step_move(Step
*step
, Point
*to
)
309 point_sub(&delta
,&step
->element
.corner
);
310 step
->element
.corner
= *to
;
311 point_add(&step
->north
.pos
,&delta
);
312 point_add(&step
->south
.pos
,&delta
);
314 step_update_data(step
);
319 step_draw(Step
*step
, Renderer
*renderer
)
322 assert(step
!= NULL
);
323 assert(renderer
!= NULL
);
325 renderer
->ops
->set_fillstyle(renderer
, FILLSTYLE_SOLID
);
326 renderer
->ops
->set_linewidth(renderer
, STEP_LINE_WIDTH
);
327 renderer
->ops
->set_linestyle(renderer
, LINESTYLE_SOLID
);
328 renderer
->ops
->set_linejoin(renderer
, LINEJOIN_MITER
);
330 pts
[0] = step
->north
.pos
;
334 renderer
->ops
->draw_polyline(renderer
,pts
,sizeof(pts
)/sizeof(pts
[0]),
339 pts
[3] = step
->south
.pos
;
340 renderer
->ops
->draw_polyline(renderer
,pts
,sizeof(pts
)/sizeof(pts
[0]),
343 if ((step
->type
== STEP_INITIAL
) ||
344 (step
->type
== STEP_MACROCALL
) ||
345 (step
->type
== STEP_SUBPCALL
)) {
346 renderer
->ops
->fill_rect(renderer
, &step
->I
, &step
->J
, &color_white
);
347 renderer
->ops
->draw_rect(renderer
, &step
->I
, &step
->J
, &color_black
);
349 renderer
->ops
->fill_rect(renderer
, &step
->E
, &step
->F
, &color_white
);
351 renderer
->ops
->draw_rect(renderer
, &step
->E
, &step
->F
, &color_black
);
353 if (step
->type
!= STEP_MACROENTRY
)
354 renderer
->ops
->draw_line(renderer
,&step
->A
,&step
->B
,&color_black
);
355 if (step
->type
!= STEP_MACROEXIT
)
356 renderer
->ops
->draw_line(renderer
,&step
->C
,&step
->D
,&color_black
);
358 renderer
->ops
->set_font(renderer
, step
->font
, step
->font_size
);
360 renderer
->ops
->draw_string(renderer
,
362 &step
->G
, ALIGN_CENTER
,
365 renderer
->ops
->fill_ellipse(renderer
,
367 STEP_DOT_RADIUS
,STEP_DOT_RADIUS
,
372 step_update_data(Step
*step
)
374 Element
*elem
= &step
->element
;
375 Object
*obj
= &elem
->object
;
376 ElementBBExtras
*extra
= &elem
->extra_spacing
;
380 ulc
.x
+= ((STEP_DECLAREDWIDTH
- STEP_WIDTH
) / 2.0); /* we cheat a little */
382 step
->A
.x
= 0.0 + (STEP_WIDTH
/ 2.0); step
->A
.y
= 0.0;
383 step
->D
.x
= 0.0 + (STEP_WIDTH
/ 2.0); step
->D
.y
= 0.0 + STEP_HEIGHT
;
385 step
->E
.x
= 0.0; step
->E
.y
= 0.5;
386 step
->F
.x
= STEP_WIDTH
; step
->F
.y
= STEP_HEIGHT
- 0.5;
391 step
->I
.x
= step
->E
.x
- 2 * STEP_LINE_WIDTH
;
392 step
->I
.y
= step
->E
.y
- 2 * STEP_LINE_WIDTH
;
393 step
->J
.x
= step
->F
.x
+ 2 * STEP_LINE_WIDTH
;
394 step
->J
.y
= step
->F
.y
+ 2 * STEP_LINE_WIDTH
;
396 step
->B
.x
= step
->A
.x
; step
->B
.y
= step
->I
.y
;
397 step
->C
.x
= step
->D
.x
; step
->C
.y
= step
->J
.y
;
398 step
->Z
.x
= step
->J
.x
; step
->Z
.y
= STEP_HEIGHT
/ 2;
401 step
->I
.x
= step
->E
.x
;
402 step
->I
.y
= step
->E
.y
- 2 * STEP_LINE_WIDTH
;
403 step
->J
.x
= step
->F
.x
;
404 step
->J
.y
= step
->F
.y
+ 2 * STEP_LINE_WIDTH
;
406 step
->B
.x
= step
->A
.x
; step
->B
.y
= step
->I
.y
;
407 step
->C
.x
= step
->D
.x
; step
->C
.y
= step
->J
.y
;
408 step
->Z
.x
= step
->J
.x
; step
->Z
.y
= STEP_HEIGHT
/ 2;
411 step
->I
.x
= step
->E
.x
- 2 * STEP_LINE_WIDTH
;
412 step
->I
.y
= step
->E
.y
;
413 step
->J
.x
= step
->F
.x
+ 2 * STEP_LINE_WIDTH
;
414 step
->J
.y
= step
->F
.y
;
416 step
->B
.x
= step
->A
.x
; step
->B
.y
= step
->I
.y
;
417 step
->C
.x
= step
->D
.x
; step
->C
.y
= step
->J
.y
;
418 step
->Z
.x
= step
->J
.x
; step
->Z
.y
= STEP_HEIGHT
/ 2;
420 default: /* regular or macro end steps */
421 step
->B
.x
= step
->A
.x
; step
->B
.y
= step
->E
.y
;
422 step
->C
.x
= step
->D
.x
; step
->C
.y
= step
->F
.y
;
423 step
->Z
.x
= step
->F
.x
; step
->Z
.y
= STEP_HEIGHT
/ 2;
426 step
->G
.x
= step
->A
.x
;
427 step
->G
.y
= (STEP_HEIGHT
/ 2) + (.3 * step
->font_size
);
428 step
->H
.x
= step
->E
.x
+ (1.2 * STEP_DOT_RADIUS
);
429 step
->H
.y
= step
->F
.y
- (1.2 * STEP_DOT_RADIUS
);
431 for (p
=&(step
->A
); p
<=&(step
->Z
) ; p
++)
434 /* Update handles: */
435 if (step
->north
.pos
.x
== -65536.0) {
436 step
->north
.pos
= step
->A
;
437 step
->south
.pos
= step
->D
;
439 step
->NU1
.x
= step
->north
.pos
.x
;
440 step
->NU2
.x
= step
->A
.x
;
441 step
->NU1
.y
= step
->NU2
.y
= (step
->north
.pos
.y
+ step
->A
.y
) / 2.0;
442 step
->SD1
.x
= step
->D
.x
;
443 step
->SD2
.x
= step
->south
.pos
.x
;
444 step
->SD1
.y
= step
->SD2
.y
= (step
->south
.pos
.y
+ step
->D
.y
) / 2.0;
446 /* Update connections: */
447 step
->connections
[0].pos
= step
->A
;
448 step
->connections
[1].pos
= step
->D
;
449 step
->connections
[2].pos
= step
->Z
;
450 step
->connections
[3].pos
= step
->H
;
452 /* recalc the bounding box : */
453 if ((step
->type
== STEP_INITIAL
) || (step
->type
== STEP_SUBPCALL
)) {
454 extra
->border_trans
= 2.5 * STEP_LINE_WIDTH
;
456 extra
->border_trans
= STEP_LINE_WIDTH
/ 2;
459 element_update_boundingbox(elem
);
460 rectangle_add_point(&obj
->bounding_box
,&step
->north
.pos
);
461 rectangle_add_point(&obj
->bounding_box
,&step
->south
.pos
);
463 obj
->position
= elem
->corner
;
465 element_update_handles(elem
);
469 step_create(Point
*startpoint
,
480 step
= g_new0(Step
,1);
481 elem
= &step
->element
;
484 obj
->type
= &step_type
;
485 obj
->ops
= &step_ops
;
487 elem
->corner
= *startpoint
;
488 elem
->width
= STEP_DECLAREDWIDTH
;
489 elem
->height
= STEP_HEIGHT
;
491 element_init(elem
, 10, 4);
494 obj
->connections
[i
] = &step
->connections
[i
];
495 step
->connections
[i
].object
= obj
;
496 step
->connections
[i
].connected
= NULL
;
499 step
->id
= new_step_name();
501 step
->font
= dia_font_new (STEP_FONT
,STEP_FONT_STYLE
,STEP_FONT_HEIGHT
);
502 step
->font_size
= STEP_FONT_HEIGHT
;
503 step
->font_color
= color_black
;
505 type
= GPOINTER_TO_INT(user_data
);
509 case STEP_MACROENTRY
:
516 step
->type
= STEP_NORMAL
;
521 obj
->handles
[i
]->type
= HANDLE_NON_MOVABLE
;
523 obj
->handles
[8] = &step
->north
;
524 obj
->handles
[9] = &step
->south
;
525 step
->north
.connect_type
= HANDLE_CONNECTABLE
;
526 step
->north
.type
= HANDLE_MAJOR_CONTROL
;
527 step
->north
.id
= HANDLE_NORTH
;
528 step
->south
.connect_type
= HANDLE_CONNECTABLE
;
529 step
->south
.type
= HANDLE_MAJOR_CONTROL
;
530 step
->south
.id
= HANDLE_SOUTH
;
531 step
->north
.pos
.x
= -65536.0; /* magic */
533 step_update_data(step
);
536 *handle2
= obj
->handles
[0];
537 return &step
->element
.object
;
541 step_destroy(Step
*step
)
543 dia_font_unref(step
->font
);
545 element_destroy(&step
->element
);
549 step_load(ObjectNode obj_node
, int version
, const char *filename
)
551 return object_load_using_properties(&step_type
,
552 obj_node
,version
,filename
);