1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998, 1999 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 /* If you have a problem with the Function Structure (FS) components,
20 * please send e-mail to David Thompson <dcthomp@mail.utexas.edu>
34 #include "objchange.h"
35 #include "connection.h"
36 #include "diarenderer.h"
41 #include "orth_conn.h"
43 #include "properties.h"
45 #include "pixmaps/orthflow.xpm"
48 typedef struct _Orthflow Orthflow
;
49 typedef struct _OrthflowChange OrthflowChange
;
65 Point textpos
; /* This is the master position, only overridden in load */
68 enum OrthflowChangeType
{
74 struct _OrthflowChange
{
75 ObjectChange obj_change
;
76 enum OrthflowChangeType change_type
;
81 Color orthflow_color_energy
= { 1.0f
, 0.0f
, 0.0f
};
82 Color orthflow_color_material
= { 0.8f
, 0.0f
, 0.8f
};
83 Color orthflow_color_signal
= { 0.0f
, 0.0f
, 1.0f
};
86 #define ORTHFLOW_WIDTH 0.1
87 #define ORTHFLOW_MATERIAL_WIDTH 0.2
88 #define ORTHFLOW_DASHLEN 0.4
89 #define ORTHFLOW_FONTHEIGHT 0.6
90 #define ORTHFLOW_ARROWLEN 0.8
91 #define ORTHFLOW_ARROWWIDTH 0.5
92 #define HANDLE_MOVE_TEXT (HANDLE_CUSTOM2)
94 static DiaFont
*orthflow_font
= NULL
;
96 static ObjectChange
* orthflow_move_handle(Orthflow
*orthflow
, Handle
*handle
,
97 Point
*to
, ConnectionPoint
*cp
,
98 HandleMoveReason reason
,
99 ModifierKeys modifiers
);
100 static ObjectChange
* orthflow_move(Orthflow
*orthflow
, Point
*to
);
101 static void orthflow_select(Orthflow
*orthflow
, Point
*clicked_point
,
102 DiaRenderer
*interactive_renderer
);
103 static void orthflow_draw(Orthflow
*orthflow
, DiaRenderer
*renderer
);
104 static DiaObject
*orthflow_create(Point
*startpoint
,
108 static real
orthflow_distance_from(Orthflow
*orthflow
, Point
*point
);
109 static void orthflow_update_data(Orthflow
*orthflow
);
110 static void orthflow_destroy(Orthflow
*orthflow
);
111 static DiaObject
*orthflow_copy(Orthflow
*orthflow
);
112 static PropDescription
*orthflow_describe_props(Orthflow
*mes
);
114 orthflow_get_props(Orthflow
* orthflow
, GPtrArray
*props
);
116 orthflow_set_props(Orthflow
* orthflow
, GPtrArray
*props
);
117 static void orthflow_save(Orthflow
*orthflow
, ObjectNode obj_node
,
118 const char *filename
);
119 static DiaObject
*orthflow_load(ObjectNode obj_node
, int version
,
120 const char *filename
);
121 static DiaMenu
*orthflow_get_object_menu(Orthflow
*orthflow
, Point
*clickedpoint
) ;
124 static ObjectTypeOps orthflow_type_ops
=
126 (CreateFunc
) orthflow_create
,
127 (LoadFunc
) orthflow_load
,
128 (SaveFunc
) orthflow_save
,
129 (GetDefaultsFunc
) NULL
,
130 (ApplyDefaultsFunc
) NULL
,
134 DiaObjectType orthflow_type
=
136 "FS - Orthflow", /* name */
137 /* Version 0 had no autorouting and so shouldn't have it set by default. */
139 (char **) orthflow_xpm
, /* pixmap */
140 &orthflow_type_ops
/* ops */
143 static ObjectOps orthflow_ops
= {
144 (DestroyFunc
) orthflow_destroy
,
145 (DrawFunc
) orthflow_draw
,
146 (DistanceFunc
) orthflow_distance_from
,
147 (SelectFunc
) orthflow_select
,
148 (CopyFunc
) orthflow_copy
,
149 (MoveFunc
) orthflow_move
,
150 (MoveHandleFunc
) orthflow_move_handle
,
151 (GetPropertiesFunc
) object_create_props_dialog
,
152 (ApplyPropertiesFunc
) object_apply_props_from_dialog
,
153 (ObjectMenuFunc
) orthflow_get_object_menu
,
154 (DescribePropsFunc
) orthflow_describe_props
,
155 (GetPropsFunc
) orthflow_get_props
,
156 (SetPropsFunc
) orthflow_set_props
,
159 static PropEnumData prop_orthflow_type_data
[] = {
160 { N_("Energy"),ORTHFLOW_ENERGY
},
161 { N_("Material"),ORTHFLOW_MATERIAL
},
162 { N_("Signal"),ORTHFLOW_SIGNAL
},
166 static PropDescription orthflow_props
[] = {
167 ELEMENT_COMMON_PROPERTIES
,
168 { "type", PROP_TYPE_ENUM
, PROP_FLAG_VISIBLE
,
169 N_("Type:"), NULL
, prop_orthflow_type_data
},
170 { "text", PROP_TYPE_TEXT
, 0, NULL
, NULL
},
171 PROP_STD_TEXT_ALIGNMENT
,
173 PROP_STD_TEXT_HEIGHT
,
174 /* Colour determined from type, don't show */
175 { "text_colour", PROP_TYPE_COLOUR
, PROP_FLAG_DONT_SAVE
, },
179 static PropDescription
*
180 orthflow_describe_props(Orthflow
*mes
)
182 if (orthflow_props
[0].quark
== 0)
183 prop_desc_list_calculate_quarks(orthflow_props
);
184 return orthflow_props
;
188 static PropOffset orthflow_offsets
[] = {
189 OBJECT_COMMON_PROPERTIES_OFFSETS
,
190 { "type", PROP_TYPE_ENUM
, offsetof(Orthflow
, type
) },
191 { "text", PROP_TYPE_TEXT
, offsetof (Orthflow
, text
) },
192 { "text_alignment", PROP_TYPE_REAL
, offsetof (Orthflow
, attrs
.alignment
) },
193 { "text_font", PROP_TYPE_FONT
, offsetof (Orthflow
, attrs
.font
) },
194 { "text_height", PROP_TYPE_REAL
, offsetof (Orthflow
, attrs
.height
) },
195 { "text_colour", PROP_TYPE_COLOUR
, offsetof (Orthflow
, attrs
.color
) },
200 orthflow_get_props(Orthflow
* orthflow
, GPtrArray
*props
)
202 text_get_attributes (orthflow
->text
, &orthflow
->attrs
);
203 object_get_props_from_offsets(&orthflow
->orth
.object
,
204 orthflow_offsets
, props
);
208 orthflow_set_props(Orthflow
*orthflow
, GPtrArray
*props
)
210 object_set_props_from_offsets(&orthflow
->orth
.object
,
211 orthflow_offsets
, props
);
212 apply_textattr_properties (props
, orthflow
->text
, "text", &orthflow
->attrs
);
213 orthflow_update_data(orthflow
);
219 orthflow_change_apply_revert(ObjectChange
* objchg
, DiaObject
* obj
)
221 struct _OrthflowChange
* change
= (struct _OrthflowChange
*) objchg
;
222 Orthflow
* oflow
= (Orthflow
*) obj
;
224 if ( change
->change_type
== FLOW_TYPE
|| change
->change_type
== BOTH
) {
225 OrthflowType type
= oflow
->type
;
226 oflow
->type
= change
->type
;
227 change
->type
= type
;
228 orthflow_update_data(oflow
) ;
231 if ( change
->change_type
& TEXT_EDIT
|| change
->change_type
== BOTH
) {
232 char* tmp
= text_get_string_copy( oflow
->text
) ;
233 text_set_string( oflow
->text
, change
->text
) ;
234 g_free( change
->text
) ;
240 orthflow_change_free(ObjectChange
* objchg
)
242 struct _OrthflowChange
* change
= (struct _OrthflowChange
*) objchg
;
244 if (change
->change_type
& TEXT_EDIT
|| change
->change_type
== BOTH
) {
245 g_free(change
->text
) ;
250 orthflow_create_change( enum OrthflowChangeType change_type
,
251 OrthflowType type
, Text
* text
)
253 struct _OrthflowChange
* change
;
254 change
= g_new0( struct _OrthflowChange
, 1 ) ;
255 change
->obj_change
.apply
= (ObjectChangeApplyFunc
) orthflow_change_apply_revert
;
256 change
->obj_change
.revert
= (ObjectChangeRevertFunc
) orthflow_change_apply_revert
;
257 change
->obj_change
.free
= (ObjectChangeFreeFunc
) orthflow_change_free
;
258 change
->change_type
= change_type
;
260 change
->type
= type
;
262 change
->text
= text_get_string_copy( text
) ;
265 return (ObjectChange
*) change
;
269 orthflow_distance_from(Orthflow
*orthflow
, Point
*point
)
274 linedist
= orthconn_distance_from( &orthflow
->orth
, point
,
275 orthflow
->type
== ORTHFLOW_MATERIAL
?
276 ORTHFLOW_MATERIAL_WIDTH
:
278 textdist
= text_distance_from( orthflow
->text
, point
) ;
280 return linedist
> textdist
? textdist
: linedist
;
284 orthflow_select(Orthflow
*orthflow
, Point
*clicked_point
,
285 DiaRenderer
*interactive_renderer
)
287 text_set_cursor(orthflow
->text
, clicked_point
, interactive_renderer
);
288 text_grab_focus(orthflow
->text
, &orthflow
->orth
.object
);
290 orthconn_update_data(&orthflow
->orth
);
294 orthflow_move_handle(Orthflow
*orthflow
, Handle
*handle
,
295 Point
*to
, ConnectionPoint
*cp
,
296 HandleMoveReason reason
, ModifierKeys modifiers
)
298 ObjectChange
*change
= NULL
;
299 assert(orthflow
!=NULL
);
300 assert(handle
!=NULL
);
303 if (handle
->id
== HANDLE_MOVE_TEXT
) {
304 orthflow
->textpos
= *to
;
308 along
= orthflow
->textpos
;
309 point_sub( &along
, &(orthconn_get_middle_handle(&orthflow
->orth
)->pos
) ) ;
311 change
= orthconn_move_handle( &orthflow
->orth
, handle
, to
, cp
,
313 orthconn_update_data( &orthflow
->orth
) ;
315 orthflow
->textpos
= orthconn_get_middle_handle(&orthflow
->orth
)->pos
;
316 point_add( &orthflow
->textpos
, &along
) ;
319 orthflow_update_data(orthflow
);
325 orthflow_move(Orthflow
*orthflow
, Point
*to
)
327 ObjectChange
*change
;
329 Point
*points
= &orthflow
->orth
.points
[0];
333 point_sub(&delta
, &points
[0]);
334 point_add(&orthflow
->textpos
, &delta
);
336 change
= orthconn_move( &orthflow
->orth
, to
) ;
338 orthflow_update_data(orthflow
);
344 orthflow_draw(Orthflow
*orthflow
, DiaRenderer
*renderer
)
346 DiaRendererClass
*renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
347 int n
= orthflow
->orth
.numpoints
;
348 Color
* render_color
= &orthflow_color_signal
;
353 assert(orthflow
!= NULL
);
354 assert(renderer
!= NULL
);
356 arrow
.type
= ARROW_FILLED_TRIANGLE
;
357 arrow
.width
= ORTHFLOW_ARROWWIDTH
;
358 arrow
.length
= ORTHFLOW_ARROWLEN
;
360 points
= &orthflow
->orth
.points
[0];
362 renderer_ops
->set_linecaps(renderer
, LINECAPS_BUTT
);
364 switch (orthflow
->type
) {
365 case ORTHFLOW_SIGNAL
:
366 linewidth
= ORTHFLOW_WIDTH
;
367 renderer_ops
->set_dashlength(renderer
, ORTHFLOW_DASHLEN
);
368 renderer_ops
->set_linestyle(renderer
, LINESTYLE_DASHED
);
369 render_color
= &orthflow_color_signal
;
371 case ORTHFLOW_MATERIAL
:
372 linewidth
= ORTHFLOW_MATERIAL_WIDTH
;
373 renderer_ops
->set_linestyle(renderer
, LINESTYLE_SOLID
);
374 render_color
= &orthflow_color_material
;
376 case ORTHFLOW_ENERGY
:
377 linewidth
= ORTHFLOW_WIDTH
;
378 renderer_ops
->set_linestyle(renderer
, LINESTYLE_SOLID
);
379 render_color
= &orthflow_color_energy
;
386 renderer_ops
->set_linewidth(renderer
, linewidth
);
387 renderer_ops
->draw_polyline_with_arrows(renderer
, points
, n
,
392 renderer_ops
->set_font(renderer
, orthflow_font
,
393 ORTHFLOW_FONTHEIGHT
);
395 text_draw(orthflow
->text
, renderer
);
399 orthflow_create(Point
*startpoint
,
411 orthflow
= g_new0(Orthflow
,1);
412 orth
= &orthflow
->orth
;
413 orthconn_init( orth
, startpoint
) ;
416 extra
= &orth
->extra_spacing
;
418 obj
->type
= &orthflow_type
;
419 obj
->ops
= &orthflow_ops
;
421 /* Where to put the text */
423 p
.y
+= 0.1 * ORTHFLOW_FONTHEIGHT
;
424 orthflow
->textpos
= p
;
425 font
= dia_font_new_from_style(DIA_FONT_SANS
, 0.8);
427 orthflow
->text
= new_text("", font
, 0.8, &p
, &color_black
, ALIGN_CENTER
);
428 dia_font_unref(font
);
429 text_get_attributes(orthflow
->text
, &orthflow
->attrs
);
432 if ( orthflow_default_label
) {
433 orthflow
->text
= text_copy( orthflow_default_label
) ;
434 text_set_position( orthflow
->text
, &p
) ;
436 Color
* color
= &orthflow_color_signal
;
438 if (orthflow_font
== NULL
) {
439 orthflow_font
= dia_font_new_from_style(DIA_FONT_SANS
|DIA_FONT_ITALIC
,
443 switch (orthflow
->type
) {
444 case ORTHFLOW_ENERGY
:
445 color
= &orthflow_color_energy
;
447 case ORTHFLOW_MATERIAL
:
448 color
= &orthflow_color_material
;
450 case ORTHFLOW_SIGNAL
:
451 color
= &orthflow_color_signal
;
455 orthflow
->text
= new_text("", orthflow_font
, ORTHFLOW_FONTHEIGHT
,
456 &p
, color
, ALIGN_CENTER
);
460 orthflow
->text_handle
.id
= HANDLE_MOVE_TEXT
;
461 orthflow
->text_handle
.type
= HANDLE_MINOR_CONTROL
;
462 orthflow
->text_handle
.connect_type
= HANDLE_NONCONNECTABLE
;
463 orthflow
->text_handle
.connected_to
= NULL
;
464 object_add_handle( obj
, &orthflow
->text_handle
) ;
468 extra
->middle_trans
= ORTHFLOW_WIDTH
/2.0;
470 extra
->end_trans
= ORTHFLOW_WIDTH
/2 + ORTHFLOW_ARROWLEN
;
472 orthflow_update_data(orthflow
);
474 /*obj->handles[1] = orth->handles[2] ;*/
475 *handle1
= obj
->handles
[0];
476 *handle2
= obj
->handles
[1];
477 return &orthflow
->orth
.object
;
482 orthflow_destroy(Orthflow
*orthflow
)
484 orthconn_destroy( &orthflow
->orth
) ;
485 text_destroy( orthflow
->text
) ;
489 orthflow_copy(Orthflow
*orthflow
)
491 Orthflow
*neworthflow
;
492 OrthConn
*orth
, *neworth
;
495 orth
= &orthflow
->orth
;
497 neworthflow
= g_malloc0(sizeof(Orthflow
));
498 neworth
= &neworthflow
->orth
;
499 newobj
= &neworth
->object
;
501 orthconn_copy(orth
, neworth
);
503 neworthflow
->text_handle
= orthflow
->text_handle
;
504 newobj
->handles
[orth
->numpoints
-1] = &neworthflow
->text_handle
;
506 neworthflow
->text
= text_copy(orthflow
->text
);
507 neworthflow
->type
= orthflow
->type
;
509 return &neworthflow
->orth
.object
;
514 orthflow_update_data(Orthflow
*orthflow
)
516 OrthConn
*orth
= &orthflow
->orth
;
517 DiaObject
*obj
= &orth
->object
;
519 Color
* color
= &orthflow_color_signal
;
521 switch (orthflow
->type
) {
522 case ORTHFLOW_ENERGY
:
523 color
= &orthflow_color_energy
;
525 case ORTHFLOW_MATERIAL
:
526 color
= &orthflow_color_material
;
528 case ORTHFLOW_SIGNAL
:
529 color
= &orthflow_color_signal
;
532 text_set_color( orthflow
->text
, color
) ;
534 text_set_position( orthflow
->text
, &orthflow
->textpos
) ;
535 orthflow
->text_handle
.pos
= orthflow
->textpos
;
537 orthconn_update_data(orth
);
538 obj
->position
= orth
->points
[0];
541 orthconn_update_boundingbox(orth
);
543 /* Add boundingbox for text: */
544 text_calc_boundingbox(orthflow
->text
, &rect
) ;
545 rectangle_union(&obj
->bounding_box
, &rect
);
550 orthflow_save(Orthflow
*orthflow
, ObjectNode obj_node
, const char *filename
)
552 orthconn_save(&orthflow
->orth
, obj_node
);
554 data_add_text(new_attribute(obj_node
, "text"),
556 data_add_int(new_attribute(obj_node
, "type"),
561 orthflow_load(ObjectNode obj_node
, int version
, const char *filename
)
569 if (orthflow_font
== NULL
) {
570 orthflow_font
= dia_font_new_from_style(DIA_FONT_SANS
|DIA_FONT_ITALIC
,
574 orthflow
= g_malloc0(sizeof(Orthflow
));
576 orth
= &orthflow
->orth
;
578 extra
= &orth
->extra_spacing
;
580 obj
->type
= &orthflow_type
;
581 obj
->ops
= &orthflow_ops
;
583 orthconn_load(orth
, obj_node
);
585 orthflow
->text
= NULL
;
586 attr
= object_find_attribute(obj_node
, "text");
588 orthflow
->text
= data_text(attribute_first_data(attr
));
590 attr
= object_find_attribute(obj_node
, "type");
592 orthflow
->type
= (OrthflowType
)data_int(attribute_first_data(attr
));
594 orthflow
->text_handle
.id
= HANDLE_MOVE_TEXT
;
595 orthflow
->text_handle
.type
= HANDLE_MINOR_CONTROL
;
596 orthflow
->text_handle
.connect_type
= HANDLE_NONCONNECTABLE
;
597 orthflow
->text_handle
.connected_to
= NULL
;
598 /* Mein Gott! The extra handle was never added */
599 object_add_handle(obj
, &orthflow
->text_handle
);
600 obj
->handles
[orth
->numpoints
-1] = &orthflow
->text_handle
;
604 extra
->middle_trans
= ORTHFLOW_WIDTH
/2.0;
606 extra
->end_trans
= ORTHFLOW_WIDTH
/2 + ORTHFLOW_ARROWLEN
;
607 orthflow
->textpos
= orthflow
->text
->position
;
609 orthflow_update_data(orthflow
);
611 return &orthflow
->orth
.object
;
614 static ObjectChange
*
615 orthflow_set_type_callback (DiaObject
* obj
, Point
* clicked
, gpointer data
)
617 ObjectChange
* change
;
618 change
= orthflow_create_change( FLOW_TYPE
, ((Orthflow
*)obj
)->type
, 0 ) ;
620 ((Orthflow
*)obj
)->type
= (int) data
;
621 orthflow_update_data((Orthflow
*)obj
);
626 static ObjectChange
*
627 orthflow_segment_callback (DiaObject
* obj
, Point
* clicked
, gpointer data
)
630 return orthconn_add_segment( (OrthConn
*)obj
, clicked
) ;
632 return orthconn_delete_segment( (OrthConn
*)obj
, clicked
) ;
635 static DiaMenuItem orthflow_menu_items
[] = {
636 { N_("Energy"), orthflow_set_type_callback
, (void*)ORTHFLOW_ENERGY
, 1 },
637 { N_("Material"), orthflow_set_type_callback
, (void*)ORTHFLOW_MATERIAL
, 1 },
638 { N_("Signal"), orthflow_set_type_callback
, (void*)ORTHFLOW_SIGNAL
, 1 },
639 { N_("Add segment"), orthflow_segment_callback
, (void*)1, 1 },
640 { N_("Delete segment"), orthflow_segment_callback
, (void*)0, 1 },
641 ORTHCONN_COMMON_MENUS
,
644 static DiaMenu orthflow_menu
= {
646 sizeof(orthflow_menu_items
)/sizeof(DiaMenuItem
),
652 orthflow_get_object_menu(Orthflow
*orthflow
, Point
*clickedpoint
)
654 orthflow_menu_items
[4].active
= orthflow
->orth
.numpoints
> 3;
655 orthconn_update_object_menu((OrthConn
*)orthflow
,
656 clickedpoint
, &orthflow_menu_items
[5]);
657 return &orthflow_menu
;