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.
30 #include "connection.h"
31 #include "diarenderer.h"
37 #include "pixmaps/flow.xpm"
39 Color flow_color_energy
= { 1.0f
, 0.0f
, 0.0f
};
40 Color flow_color_material
= { 0.8f
, 0.0f
, 0.8f
};
41 Color flow_color_signal
= { 0.0f
, 0.0f
, 1.0f
};
43 typedef struct _Flow Flow
;
52 Connection connection
;
60 #define FLOW_WIDTH 0.1
61 #define FLOW_MATERIAL_WIDTH 0.2
62 #define FLOW_DASHLEN 0.4
63 #define FLOW_FONTHEIGHT 0.6
64 #define FLOW_ARROWLEN 0.8
65 #define FLOW_ARROWWIDTH 0.5
66 #define HANDLE_MOVE_TEXT (HANDLE_CUSTOM1)
68 static ObjectChange
* flow_move_handle(Flow
*flow
, Handle
*handle
,
69 Point
*to
, ConnectionPoint
*cp
,
70 HandleMoveReason reason
,
71 ModifierKeys modifiers
);
72 static ObjectChange
* flow_move(Flow
*flow
, Point
*to
);
73 static void flow_select(Flow
*flow
, Point
*clicked_point
,
74 DiaRenderer
*interactive_renderer
);
75 static void flow_draw(Flow
*flow
, DiaRenderer
*renderer
);
76 static DiaObject
*flow_create(Point
*startpoint
,
80 static real
flow_distance_from(Flow
*flow
, Point
*point
);
81 static void flow_update_data(Flow
*flow
);
82 static void flow_destroy(Flow
*flow
);
83 static DiaObject
*flow_copy(Flow
*flow
);
84 static void flow_save(Flow
*flow
, ObjectNode obj_node
,
85 const char *filename
);
86 static DiaObject
*flow_load(ObjectNode obj_node
, int version
,
87 const char *filename
);
88 static DiaMenu
*flow_get_object_menu(Flow
*flow
, Point
*clickedpoint
) ;
91 static ObjectTypeOps flow_type_ops
=
93 (CreateFunc
) flow_create
,
96 (GetDefaultsFunc
) NULL
,
97 (ApplyDefaultsFunc
) NULL
,
100 DiaObjectType flow_type
=
102 "FS - Flow", /* name */
104 (char **) flow_xpm
, /* pixmap */
105 &flow_type_ops
/* ops */
108 static ObjectOps flow_ops
= {
109 (DestroyFunc
) flow_destroy
,
110 (DrawFunc
) flow_draw
,
111 (DistanceFunc
) flow_distance_from
,
112 (SelectFunc
) flow_select
,
113 (CopyFunc
) flow_copy
,
114 (MoveFunc
) flow_move
,
115 (MoveHandleFunc
) flow_move_handle
,
116 (GetPropertiesFunc
) object_create_props_dialog
,
117 (ApplyPropertiesFunc
) object_apply_props_from_dialog
,
118 (ObjectMenuFunc
) flow_get_object_menu
,
119 (DescribePropsFunc
) flow_describe_props
,
120 (GetPropsFunc
) flow_get_props
,
121 (SetPropsFunc
) flow_set_props
,
124 static PropEnumData prop_flow_type_data
[] = {
125 { N_("Energy"),FLOW_ENERGY
},
126 { N_("Material"),FLOW_MATERIAL
},
127 { N_("Signal"),FLOW_SIGNAL
},
131 static PropDescription flow_props
[] = {
132 OBJECT_COMMON_PROPERTIES
,
133 { "type", PROP_TYPE_ENUM
, PROP_FLAG_VISIBLE
,
134 N_("Type:"), NULL
, prop_flow_type_data
},
135 { "text", PROP_TYPE_TEXT
, PROP_FLAG_VISIBLE
, NULL
, NULL
},
136 PROP_STD_TEXT_ALIGNMENT
,
138 PROP_STD_TEXT_HEIGHT
,
139 /* Colour determined from type, don't show */
140 { "text_colour", PROP_TYPE_COLOUR
, PROP_FLAG_DONT_SAVE
, },
144 static PropDescription
*
145 flow_describe_props(Flow
*mes
)
147 if (flow_props
[0].quark
== 0)
148 prop_desc_list_calculate_quarks(flow_props
);
153 static PropOffset flow_offsets
[] = {
154 OBJECT_COMMON_PROPERTIES_OFFSETS
,
155 { "type", PROP_TYPE_ENUM
, offsetof(Flow
, type
) },
156 { "text", PROP_TYPE_TEXT
, offsetof (Flow
, text
) },
157 { "text_alignment", PROP_TYPE_ENUM
, offsetof (Flow
, attrs
.alignment
) },
158 { "text_font", PROP_TYPE_FONT
, offsetof (Flow
, attrs
.font
) },
159 { "text_height", PROP_TYPE_REAL
, offsetof (Flow
, attrs
.height
) },
160 { "text_colour", PROP_TYPE_COLOUR
, offsetof (Flow
, attrs
.color
) },
165 flow_get_props(Flow
* flow
, GPtrArray
*props
)
167 text_get_attributes (flow
->text
, &flow
->attrs
);
168 object_get_props_from_offsets(&flow
->connection
.object
,
169 flow_offsets
, props
);
173 flow_set_props(Flow
*flow
, GPtrArray
*props
)
175 object_set_props_from_offsets(&flow
->connection
.object
,
176 flow_offsets
, props
);
177 apply_textattr_properties (props
, flow
->text
, "text", &flow
->attrs
);
178 flow_update_data(flow
);
182 flow_distance_from(Flow
*flow
, Point
*point
)
188 endpoints
= &flow
->connection
.endpoints
[0];
190 linedist
= distance_line_point(&endpoints
[0], &endpoints
[1],
191 flow
->type
== FLOW_MATERIAL
? FLOW_MATERIAL_WIDTH
: FLOW_WIDTH
,
193 textdist
= text_distance_from( flow
->text
, point
) ;
195 return linedist
> textdist
? textdist
: linedist
;
199 flow_select(Flow
*flow
, Point
*clicked_point
,
200 DiaRenderer
*interactive_renderer
)
202 text_set_cursor(flow
->text
, clicked_point
, interactive_renderer
);
203 text_grab_focus(flow
->text
, &flow
->connection
.object
);
205 connection_update_handles(&flow
->connection
);
209 flow_move_handle(Flow
*flow
, Handle
*handle
,
210 Point
*to
, ConnectionPoint
*cp
,
211 HandleMoveReason reason
, ModifierKeys modifiers
)
217 assert(handle
!=NULL
);
220 if (handle
->id
== HANDLE_MOVE_TEXT
) {
221 flow
->text
->position
= *to
;
225 real along_mag
, norm_mag
;
228 endpoints
= &flow
->connection
.endpoints
[0];
229 p1
= flow
->text
->position
;
230 point_sub( &p1
, &endpoints
[0] ) ;
233 point_sub( &p2
, &endpoints
[0] ) ;
234 orig_length2
= point_dot( &p2
, &p2
) ;
236 if ( orig_length2
> 1e-5 ) {
237 along_mag
= point_dot( &p2
, &p1
)/sqrt(orig_length2
) ;
238 along_mag
*= along_mag
;
239 norm_mag
= point_dot( &p1
, &p1
) ;
240 norm_mag
= (real
)sqrt( (double)( norm_mag
- along_mag
) ) ;
241 along_mag
= (real
)sqrt( along_mag
/orig_length2
) ;
242 if ( p1
.x
*p2
.y
- p1
.y
*p2
.x
> 0.0 )
243 norm_mag
= -norm_mag
;
246 norm_mag
= (real
)sqrt( (double) point_dot( &p1
, &p1
) ) ;
249 connection_move_handle(&flow
->connection
, handle
->id
, to
, cp
,
253 point_sub( &p2
, &endpoints
[0] ) ;
254 flow
->text
->position
= endpoints
[0] ;
258 dest_length
= point_dot( &p2
, &p2
) ;
259 if ( dest_length
> 1e-5 ) {
260 point_normalize( &p2
) ;
262 p2
.x
= 0.0 ; p2
.y
= -1.0 ;
264 point_scale( &p2
, norm_mag
) ;
265 point_scale( &along
, along_mag
) ;
266 point_add( &flow
->text
->position
, &p2
) ;
267 point_add( &flow
->text
->position
, &along
) ;
270 flow_update_data(flow
);
276 flow_move(Flow
*flow
, Point
*to
)
279 Point
*endpoints
= &flow
->connection
.endpoints
[0];
283 point_sub(&delta
, &endpoints
[0]);
285 start_to_end
= endpoints
[1];
286 point_sub(&start_to_end
, &endpoints
[0]);
288 endpoints
[1] = endpoints
[0] = *to
;
289 point_add(&endpoints
[1], &start_to_end
);
291 point_add(&flow
->text
->position
, &delta
);
293 flow_update_data(flow
);
299 flow_draw(Flow
*flow
, DiaRenderer
*renderer
)
301 DiaRendererClass
*renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
302 Point
*endpoints
, p1
, p2
, px
;
303 ArrowType arrow_type
;
306 Color
* render_color
;
309 assert(flow
!= NULL
);
310 assert(renderer
!= NULL
);
312 endpoints
= &flow
->connection
.endpoints
[0];
314 renderer_ops
->set_linewidth(renderer
, FLOW_WIDTH
);
316 renderer_ops
->set_linecaps(renderer
, LINECAPS_BUTT
);
319 switch (flow
->type
) {
321 renderer_ops
->set_dashlength(renderer
, FLOW_DASHLEN
);
322 renderer_ops
->set_linestyle(renderer
, LINESTYLE_DASHED
);
323 render_color
= &flow_color_signal
;
326 renderer_ops
->set_linewidth(renderer
, FLOW_MATERIAL_WIDTH
) ;
327 renderer_ops
->set_linestyle(renderer
, LINESTYLE_SOLID
);
328 render_color
= &flow_color_material
;
331 render_color
= &flow_color_energy
;
332 renderer_ops
->set_linestyle(renderer
, LINESTYLE_SOLID
);
338 arrow
.type
= ARROW_FILLED_TRIANGLE
;
339 arrow
.length
= FLOW_ARROWLEN
;
340 arrow
.width
= FLOW_ARROWWIDTH
;
342 renderer_ops
->draw_line_with_arrows(renderer
,
343 &p1
, &p2
, FLOW_WIDTH
,
347 renderer_ops
->set_font(renderer
, flow_font
,
350 text_draw(flow
->text
, renderer
);
354 flow_create(Point
*startpoint
,
360 ConnectionBBExtras
*extra
;
366 flow
= g_malloc0(sizeof(Flow
));
368 conn
= &flow
->connection
;
369 conn
->endpoints
[0] = *startpoint
;
370 conn
->endpoints
[1] = *startpoint
;
371 conn
->endpoints
[1].x
+= 1.5;
374 extra
= &conn
->extra_spacing
;
376 obj
->type
= &flow_type
;
377 obj
->ops
= &flow_ops
;
379 connection_init(conn
, 3, 0);
381 p
= conn
->endpoints
[1] ;
382 point_sub( &p
, &conn
->endpoints
[0] ) ;
383 point_scale( &p
, 0.5 ) ;
386 if ( fabs(n
.x
) < 1.e
-5 && fabs(n
.y
) < 1.e
-5 ) {
390 point_normalize( &n
) ;
392 point_scale( &n
, 0.5*FLOW_FONTHEIGHT
) ;
393 point_add( &p
, &n
) ;
394 point_add( &p
, &conn
->endpoints
[0] ) ;
397 flow
->text_handle
.id
= HANDLE_MOVE_TEXT
;
398 flow
->text_handle
.type
= HANDLE_MINOR_CONTROL
;
399 flow
->text_handle
.connect_type
= HANDLE_NONCONNECTABLE
;
400 flow
->text_handle
.connected_to
= NULL
;
401 obj
->handles
[2] = &flow
->text_handle
;
405 extra
->end_long
= FLOW_WIDTH
/2.0;
406 extra
->end_trans
= MAX(FLOW_WIDTH
,FLOW_ARROWLEN
)/2.0;
408 flow_update_data(flow
);
410 *handle1
= obj
->handles
[0];
411 *handle2
= obj
->handles
[1];
412 return &flow
->connection
.object
;
417 flow_destroy(Flow
*flow
)
419 connection_destroy(&flow
->connection
);
420 text_destroy(flow
->text
) ;
424 flow_copy(Flow
*flow
)
427 Connection
*conn
, *newconn
;
430 conn
= &flow
->connection
;
432 newflow
= g_malloc0(sizeof(Flow
));
433 newconn
= &newflow
->connection
;
434 newobj
= &newconn
->object
;
436 connection_copy(conn
, newconn
);
438 newflow
->text_handle
= flow
->text_handle
;
439 newobj
->handles
[2] = &newflow
->text_handle
;
441 newflow
->text
= text_copy(flow
->text
);
442 newflow
->type
= flow
->type
;
444 return &newflow
->connection
.object
;
449 flow_update_data(Flow
*flow
)
451 Connection
*conn
= &flow
->connection
;
452 DiaObject
*obj
= &conn
->object
;
456 obj
->position
= conn
->endpoints
[0];
458 switch (flow
->type
) {
460 color
= &flow_color_energy
;
463 color
= &flow_color_material
;
466 color
= &flow_color_signal
;
469 text_set_color( flow
->text
, color
) ;
471 flow
->text_handle
.pos
= flow
->text
->position
;
473 connection_update_handles(conn
);
476 connection_update_boundingbox(conn
);
478 /* Add boundingbox for text: */
479 text_calc_boundingbox(flow
->text
, &rect
) ;
480 rectangle_union(&obj
->bounding_box
, &rect
);
485 flow_save(Flow
*flow
, ObjectNode obj_node
, const char *filename
)
487 connection_save(&flow
->connection
, obj_node
);
489 data_add_text(new_attribute(obj_node
, "text"),
491 data_add_int(new_attribute(obj_node
, "type"),
496 flow_load(ObjectNode obj_node
, int version
, const char *filename
)
502 ConnectionBBExtras
*extra
;
504 if (flow_font
== NULL
) {
505 /* choose default font name for your locale. see also font_data structure
507 flow_font
= font_getfont (_("Helvetica-Oblique"));
510 flow
= g_malloc0(sizeof(Flow
));
512 conn
= &flow
->connection
;
514 extra
= &conn
->extra_spacing
;
516 obj
->type
= &flow_type
;
517 obj
->ops
= &flow_ops
;
519 connection_load(conn
, obj_node
);
521 connection_init(conn
, 3, 0);
524 attr
= object_find_attribute(obj_node
, "text");
526 flow
->text
= data_text(attribute_first_data(attr
));
528 attr
= object_find_attribute(obj_node
, "type");
530 flow
->type
= (FlowType
)data_int(attribute_first_data(attr
));
532 flow
->text_handle
.id
= HANDLE_MOVE_TEXT
;
533 flow
->text_handle
.type
= HANDLE_MINOR_CONTROL
;
534 flow
->text_handle
.connect_type
= HANDLE_NONCONNECTABLE
;
535 flow
->text_handle
.connected_to
= NULL
;
536 obj
->handles
[2] = &flow
->text_handle
;
540 extra
->end_long
= FLOW_WIDTH
/2.0;
541 extra
->end_trans
= MAX(FLOW_WIDTH
,FLOW_ARROWLEN
)/2.0;
543 flow_update_data(flow
);
545 return &flow
->connection
.object
;
548 static ObjectChange
*
549 flow_set_type_callback (DiaObject
* obj
, Point
* clicked
, gpointer data
)
551 ((Flow
*)obj
)->type
= (int) data
;
552 flow_update_defaults( (Flow
*) obj
, 1 ) ;
553 if ( defaults_dialog
)
554 fill_in_defaults_dialog() ;
555 flow_update_data((Flow
*)obj
);
560 static DiaMenuItem flow_menu_items
[] = {
561 { N_("Energy"), flow_set_type_callback
, (void*)FLOW_ENERGY
, 1 },
562 { N_("Material"), flow_set_type_callback
, (void*)FLOW_MATERIAL
, 1 },
563 { N_("Signal"), flow_set_type_callback
, (void*)FLOW_SIGNAL
, 1 },
566 static DiaMenu flow_menu
= {
568 sizeof(flow_menu_items
)/sizeof(DiaMenuItem
),
574 flow_get_object_menu(Flow
*flow
, Point
*clickedpoint
)
576 /* Set entries sensitive/selected etc here */
577 flow_menu_items
[0].active
= 1;