1 /* Dia -- an diagram creation/manipulation program
2  * Copyright (C) 1998, 1999 Alexander Larsson
3  *
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.
8  *
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.
13  *
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.
17  */
18 
19 /* If you have a problem with the Function Structure (FS) components,
20  * please send e-mail to David Thompson <dcthomp@mail.utexas.edu>
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <assert.h>
28 #include <math.h>
29 #include <string.h>
30 #include <stdio.h>
31 
32 #include "intl.h"
33 #include "object.h"
34 #include "objchange.h"
35 #include "connection.h"
36 #include "diarenderer.h"
37 #include "handle.h"
38 #include "arrows.h"
39 #include "diamenu.h"
40 #include "text.h"
41 #include "orth_conn.h"
42 #include "element.h"
43 #include "properties.h"
44 
45 #include "pixmaps/orthflow.xpm"
46 
47 
48 typedef struct _Orthflow Orthflow;
49 typedef struct _OrthflowChange OrthflowChange;
50 
51 typedef enum {
52   ORTHFLOW_ENERGY,
53   ORTHFLOW_MATERIAL,
54   ORTHFLOW_SIGNAL
55 } OrthflowType;
56 
57 struct _Orthflow {
58   OrthConn orth ;
59 
60   Handle text_handle;
61 
62   Text* text;
63   TextAttributes attrs;
64   OrthflowType type;
65   Point textpos; /* This is the master position, only overridden in load */
66 };
67 
68 enum OrthflowChangeType {
69   TEXT_EDIT=1,
70   FLOW_TYPE=2,
71   BOTH=3
72 };
73 
74 struct _OrthflowChange {
75   ObjectChange			obj_change ;
76   enum OrthflowChangeType	change_type ;
77   OrthflowType			type ;
78   char*				text ;
79 };
80 
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 };
84 
85 
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)
93 
94 static ObjectChange* orthflow_move_handle(Orthflow *orthflow, Handle *handle,
95 					  Point *to, ConnectionPoint *cp,
96 					  HandleMoveReason reason,
97 					  ModifierKeys modifiers);
98 static ObjectChange* orthflow_move(Orthflow *orthflow, Point *to);
99 static void orthflow_select(Orthflow *orthflow, Point *clicked_point,
100 			    DiaRenderer *interactive_renderer);
101 static void orthflow_draw(Orthflow *orthflow, DiaRenderer *renderer);
102 static DiaObject *orthflow_create(Point *startpoint,
103 			       void *user_data,
104 			       Handle **handle1,
105 			       Handle **handle2);
106 static real orthflow_distance_from(Orthflow *orthflow, Point *point);
107 static void orthflow_update_data(Orthflow *orthflow);
108 static void orthflow_destroy(Orthflow *orthflow);
109 static DiaObject *orthflow_copy(Orthflow *orthflow);
110 static PropDescription *orthflow_describe_props(Orthflow *mes);
111 static void
112 orthflow_get_props(Orthflow * orthflow, GPtrArray *props);
113 static void
114 orthflow_set_props(Orthflow * orthflow, GPtrArray *props);
115 static void orthflow_save(Orthflow *orthflow, ObjectNode obj_node,
116 			  const char *filename);
117 static DiaObject *orthflow_load(ObjectNode obj_node, int version,
118 			     const char *filename);
119 static DiaMenu *orthflow_get_object_menu(Orthflow *orthflow, Point *clickedpoint) ;
120 
121 
122 static ObjectTypeOps orthflow_type_ops =
123 {
124   (CreateFunc)		orthflow_create,
125   (LoadFunc)		orthflow_load,
126   (SaveFunc)		orthflow_save,
127   (GetDefaultsFunc)	NULL,
128   (ApplyDefaultsFunc)	NULL,
129 
130 } ;
131 
132 DiaObjectType orthflow_type =
133 {
134   "FS - Orthflow",		/* name */
135   /* Version 0 had no autorouting and so shouldn't have it set by default. */
136   1,                      /* version */
137   (char **) orthflow_xpm,	/* pixmap */
138   &orthflow_type_ops		/* ops */
139 };
140 
141 static ObjectOps orthflow_ops = {
142   (DestroyFunc)         orthflow_destroy,
143   (DrawFunc)            orthflow_draw,
144   (DistanceFunc)        orthflow_distance_from,
145   (SelectFunc)          orthflow_select,
146   (CopyFunc)            orthflow_copy,
147   (MoveFunc)            orthflow_move,
148   (MoveHandleFunc)      orthflow_move_handle,
149   (GetPropertiesFunc)   object_create_props_dialog,
150   (ApplyPropertiesDialogFunc) object_apply_props_from_dialog,
151   (ObjectMenuFunc)      orthflow_get_object_menu,
152   (DescribePropsFunc)   orthflow_describe_props,
153   (GetPropsFunc)        orthflow_get_props,
154   (SetPropsFunc)        orthflow_set_props,
155   (TextEditFunc) 0,
156   (ApplyPropertiesListFunc) object_apply_props,
157 };
158 
159 static PropEnumData prop_orthflow_type_data[] = {
160   { N_("Energy"),ORTHFLOW_ENERGY },
161   { N_("Material"),ORTHFLOW_MATERIAL },
162   { N_("Signal"),ORTHFLOW_SIGNAL },
163   { NULL, 0 }
164 };
165 
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,
172   PROP_STD_TEXT_FONT,
173   PROP_STD_TEXT_HEIGHT,
174   /* Colour determined from type, don't show */
175   { "text_colour", PROP_TYPE_COLOUR, PROP_FLAG_DONT_SAVE, },
176   PROP_DESC_END
177 };
178 
179 static PropDescription *
orthflow_describe_props(Orthflow * mes)180 orthflow_describe_props(Orthflow *mes)
181 {
182   if (orthflow_props[0].quark == 0)
183     prop_desc_list_calculate_quarks(orthflow_props);
184   return orthflow_props;
185 
186 }
187 
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_ENUM, offsetof (Orthflow, attrs.alignment) },
193   { "text_font", PROP_TYPE_FONT, offsetof (Orthflow, attrs.font) },
194   { PROP_STDNAME_TEXT_HEIGHT, PROP_STDTYPE_TEXT_HEIGHT, offsetof (Orthflow, attrs.height) },
195   { "text_colour", PROP_TYPE_COLOUR, offsetof (Orthflow, attrs.color) },
196   { NULL, 0, 0 }
197 };
198 
199 static void
orthflow_get_props(Orthflow * orthflow,GPtrArray * props)200 orthflow_get_props(Orthflow * orthflow, GPtrArray *props)
201 {
202   text_get_attributes (orthflow->text, &orthflow->attrs);
203   object_get_props_from_offsets(&orthflow->orth.object,
204                                 orthflow_offsets, props);
205 }
206 
207 static void
orthflow_set_props(Orthflow * orthflow,GPtrArray * props)208 orthflow_set_props(Orthflow *orthflow, GPtrArray *props)
209 {
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);
214 }
215 
216 
217 
218 static void
orthflow_change_apply_revert(ObjectChange * objchg,DiaObject * obj)219 orthflow_change_apply_revert(ObjectChange* objchg, DiaObject* obj)
220 {
221   struct _OrthflowChange* change = (struct _OrthflowChange*) objchg ;
222   Orthflow* oflow = (Orthflow*) obj ;
223 
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) ;
229   }
230 
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 ) ;
235     change->text = tmp ;
236   }
237 }
238 
239 static void
orthflow_change_free(ObjectChange * objchg)240 orthflow_change_free(ObjectChange* objchg)
241 {
242   struct _OrthflowChange* change = (struct _OrthflowChange*) objchg ;
243 
244   if (change->change_type & TEXT_EDIT  || change->change_type == BOTH ) {
245     g_free(change->text) ;
246   }
247 }
248 
249 static ObjectChange*
orthflow_create_change(enum OrthflowChangeType change_type,OrthflowType type,Text * text)250 orthflow_create_change( enum OrthflowChangeType change_type,
251 			OrthflowType type, Text* text )
252 {
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 ;
259 
260   change->type = type ;
261   if ( text ) {
262     change->text = text_get_string_copy( text ) ;
263   }
264 
265   return (ObjectChange*) change ;
266 }
267 
268 static real
orthflow_distance_from(Orthflow * orthflow,Point * point)269 orthflow_distance_from(Orthflow *orthflow, Point *point)
270 {
271   real linedist;
272   real textdist;
273 
274   linedist = orthconn_distance_from( &orthflow->orth, point,
275 				     orthflow->type == ORTHFLOW_MATERIAL ?
276 				     ORTHFLOW_MATERIAL_WIDTH :
277 				     ORTHFLOW_WIDTH ) ;
278   textdist = text_distance_from( orthflow->text, point ) ;
279 
280   return linedist > textdist ? textdist : linedist ;
281 }
282 
283 static void
orthflow_select(Orthflow * orthflow,Point * clicked_point,DiaRenderer * interactive_renderer)284 orthflow_select(Orthflow *orthflow, Point *clicked_point,
285 		DiaRenderer *interactive_renderer)
286 {
287   text_set_cursor(orthflow->text, clicked_point, interactive_renderer);
288   text_grab_focus(orthflow->text, &orthflow->orth.object);
289 
290   orthconn_update_data(&orthflow->orth);
291 }
292 
293 static ObjectChange*
orthflow_move_handle(Orthflow * orthflow,Handle * handle,Point * to,ConnectionPoint * cp,HandleMoveReason reason,ModifierKeys modifiers)294 orthflow_move_handle(Orthflow *orthflow, Handle *handle,
295 		     Point *to, ConnectionPoint *cp,
296 		     HandleMoveReason reason, ModifierKeys modifiers)
297 {
298   ObjectChange *change = NULL;
299   assert(orthflow!=NULL);
300   assert(handle!=NULL);
301   assert(to!=NULL);
302 
303   if (handle->id == HANDLE_MOVE_TEXT) {
304     orthflow->textpos = *to;
305   } else {
306     Point along ;
307 
308     along = orthflow->textpos ;
309     point_sub( &along, &(orthconn_get_middle_handle(&orthflow->orth)->pos) ) ;
310 
311     change = orthconn_move_handle( &orthflow->orth, handle, to, cp,
312 				   reason, modifiers);
313     orthconn_update_data( &orthflow->orth ) ;
314 
315     orthflow->textpos = orthconn_get_middle_handle(&orthflow->orth)->pos ;
316     point_add( &orthflow->textpos, &along ) ;
317   }
318 
319   orthflow_update_data(orthflow);
320 
321   return change;
322 }
323 
324 static ObjectChange*
orthflow_move(Orthflow * orthflow,Point * to)325 orthflow_move(Orthflow *orthflow, Point *to)
326 {
327   ObjectChange *change;
328 
329   Point *points = &orthflow->orth.points[0];
330   Point delta;
331 
332   delta = *to;
333   point_sub(&delta, &points[0]);
334   point_add(&orthflow->textpos, &delta);
335 
336   change = orthconn_move( &orthflow->orth, to ) ;
337 
338   orthflow_update_data(orthflow);
339 
340   return change;
341 }
342 
343 static void
orthflow_draw(Orthflow * orthflow,DiaRenderer * renderer)344 orthflow_draw(Orthflow *orthflow, DiaRenderer *renderer)
345 {
346   DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
347   int n = orthflow->orth.numpoints ;
348   Color* render_color = &orthflow_color_signal;
349   Point *points;
350   real linewidth;
351   Arrow arrow;
352 
353   assert(orthflow != NULL);
354   assert(renderer != NULL);
355 
356   arrow.type = ARROW_FILLED_TRIANGLE;
357   arrow.width = ORTHFLOW_ARROWWIDTH;
358   arrow.length = ORTHFLOW_ARROWLEN;
359 
360   points = &orthflow->orth.points[0];
361 
362   renderer_ops->set_linecaps(renderer, LINECAPS_BUTT);
363 
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 ;
370     break ;
371   case ORTHFLOW_MATERIAL:
372     linewidth = ORTHFLOW_MATERIAL_WIDTH;
373     renderer_ops->set_linestyle(renderer, LINESTYLE_SOLID);
374     render_color = &orthflow_color_material ;
375     break ;
376   case ORTHFLOW_ENERGY:
377     linewidth = ORTHFLOW_WIDTH;
378     renderer_ops->set_linestyle(renderer, LINESTYLE_SOLID);
379     render_color = &orthflow_color_energy ;
380     break ;
381   default:
382     linewidth = 0.001;
383     break;
384   }
385 
386   renderer_ops->set_linewidth(renderer, linewidth);
387   renderer_ops->draw_polyline_with_arrows(renderer, points, n,
388 					  ORTHFLOW_WIDTH,
389 					  render_color,
390 					  NULL, &arrow);
391 
392   text_draw(orthflow->text, renderer);
393 }
394 
395 static DiaObject *
orthflow_create(Point * startpoint,void * user_data,Handle ** handle1,Handle ** handle2)396 orthflow_create(Point *startpoint,
397 		void *user_data,
398 		Handle **handle1,
399 		Handle **handle2)
400 {
401   Orthflow *orthflow;
402   OrthConn *orth;
403   DiaObject *obj;
404   Point p;
405   PolyBBExtras *extra;
406   DiaFont *font;
407 
408   orthflow = g_new0(Orthflow,1);
409   orth = &orthflow->orth ;
410   orthconn_init( orth, startpoint ) ;
411 
412   obj = &orth->object;
413   extra = &orth->extra_spacing;
414 
415   obj->type = &orthflow_type;
416   obj->ops = &orthflow_ops;
417 
418   /* Where to put the text */
419   p = *startpoint ;
420   p.y += 0.1 * ORTHFLOW_FONTHEIGHT ;
421   orthflow->textpos = p;
422   font = dia_font_new_from_style(DIA_FONT_SANS, 0.8);
423 
424   orthflow->text = new_text("", font, 0.8, &p, &color_black, ALIGN_CENTER);
425   dia_font_unref(font);
426   text_get_attributes(orthflow->text, &orthflow->attrs);
427 
428 #if 0
429   if ( orthflow_default_label ) {
430     orthflow->text = text_copy( orthflow_default_label ) ;
431     text_set_position( orthflow->text, &p ) ;
432   } else {
433     Color* color = &orthflow_color_signal;
434 
435     switch (orthflow->type) {
436     case ORTHFLOW_ENERGY:
437       color = &orthflow_color_energy ;
438       break ;
439     case ORTHFLOW_MATERIAL:
440       color = &orthflow_color_material ;
441       break ;
442     case ORTHFLOW_SIGNAL:
443       color = &orthflow_color_signal ;
444       break ;
445     }
446 
447   }
448 #endif
449 
450   orthflow->text_handle.id = HANDLE_MOVE_TEXT;
451   orthflow->text_handle.type = HANDLE_MINOR_CONTROL;
452   orthflow->text_handle.connect_type = HANDLE_NONCONNECTABLE;
453   orthflow->text_handle.connected_to = NULL;
454   object_add_handle( obj, &orthflow->text_handle ) ;
455 
456   extra->start_long =
457     extra->start_trans =
458     extra->middle_trans = ORTHFLOW_WIDTH/2.0;
459   extra->end_long =
460     extra->end_trans = ORTHFLOW_WIDTH/2 + ORTHFLOW_ARROWLEN;
461 
462   orthflow_update_data(orthflow);
463 
464   /*obj->handles[1] = orth->handles[2] ;*/
465   *handle1 = obj->handles[0];
466   *handle2 = obj->handles[1];
467   return &orthflow->orth.object;
468 }
469 
470 
471 static void
orthflow_destroy(Orthflow * orthflow)472 orthflow_destroy(Orthflow *orthflow)
473 {
474   orthconn_destroy( &orthflow->orth ) ;
475   text_destroy( orthflow->text ) ;
476 }
477 
478 static DiaObject *
orthflow_copy(Orthflow * orthflow)479 orthflow_copy(Orthflow *orthflow)
480 {
481   Orthflow *neworthflow;
482   OrthConn *orth, *neworth;
483   DiaObject *newobj;
484 
485   orth = &orthflow->orth;
486 
487   neworthflow = g_malloc0(sizeof(Orthflow));
488   neworth = &neworthflow->orth;
489   newobj = &neworth->object;
490 
491   orthconn_copy(orth, neworth);
492 
493   neworthflow->text_handle = orthflow->text_handle;
494   neworthflow->text_handle.connected_to = NULL;
495   newobj->handles[orth->numpoints-1] = &neworthflow->text_handle;
496 
497   neworthflow->text = text_copy(orthflow->text);
498   neworthflow->type = orthflow->type;
499 
500   orthflow_update_data(neworthflow);
501   return &neworthflow->orth.object;
502 }
503 
504 
505 static void
orthflow_update_data(Orthflow * orthflow)506 orthflow_update_data(Orthflow *orthflow)
507 {
508   OrthConn *orth = &orthflow->orth ;
509   DiaObject *obj = &orth->object;
510   Rectangle rect;
511   Color* color = &orthflow_color_signal;
512 
513   switch (orthflow->type) {
514   case ORTHFLOW_ENERGY:
515     color = &orthflow_color_energy ;
516     break ;
517   case ORTHFLOW_MATERIAL:
518     color = &orthflow_color_material ;
519     break ;
520   case ORTHFLOW_SIGNAL:
521     color = &orthflow_color_signal ;
522     break ;
523   }
524   text_set_color( orthflow->text, color ) ;
525 
526   text_set_position( orthflow->text, &orthflow->textpos ) ;
527   orthflow->text_handle.pos = orthflow->textpos;
528 
529   orthconn_update_data(orth);
530   obj->position = orth->points[0];
531 
532   /* Boundingbox: */
533   orthconn_update_boundingbox(orth);
534 
535   /* Add boundingbox for text: */
536   text_calc_boundingbox(orthflow->text, &rect) ;
537   rectangle_union(&obj->bounding_box, &rect);
538 }
539 
540 
541 static void
orthflow_save(Orthflow * orthflow,ObjectNode obj_node,const char * filename)542 orthflow_save(Orthflow *orthflow, ObjectNode obj_node, const char *filename)
543 {
544   orthconn_save(&orthflow->orth, obj_node);
545 
546   data_add_text(new_attribute(obj_node, "text"),
547 		orthflow->text) ;
548   data_add_int(new_attribute(obj_node, "type"),
549 	       orthflow->type);
550 }
551 
552 static DiaObject *
orthflow_load(ObjectNode obj_node,int version,const char * filename)553 orthflow_load(ObjectNode obj_node, int version, const char *filename)
554 {
555   Orthflow *orthflow;
556   AttributeNode attr;
557   OrthConn *orth;
558   DiaObject *obj;
559   PolyBBExtras *extra;
560 
561   orthflow = g_malloc0(sizeof(Orthflow));
562 
563   orth = &orthflow->orth;
564   obj = &orth->object;
565   extra = &orth->extra_spacing;
566 
567   obj->type = &orthflow_type;
568   obj->ops = &orthflow_ops;
569 
570   orthconn_load(orth, obj_node);
571 
572   orthflow->text = NULL;
573   attr = object_find_attribute(obj_node, "text");
574   if (attr != NULL)
575     orthflow->text = data_text(attribute_first_data(attr));
576 
577   attr = object_find_attribute(obj_node, "type");
578   if (attr != NULL)
579     orthflow->type = (OrthflowType)data_int(attribute_first_data(attr));
580 
581   orthflow->text_handle.id = HANDLE_MOVE_TEXT;
582   orthflow->text_handle.type = HANDLE_MINOR_CONTROL;
583   orthflow->text_handle.connect_type = HANDLE_NONCONNECTABLE;
584   orthflow->text_handle.connected_to = NULL;
585   /* Mein Gott!  The extra handle was never added */
586   object_add_handle(obj, &orthflow->text_handle);
587   obj->handles[orth->numpoints-1] = &orthflow->text_handle;
588 
589   extra->start_long =
590     extra->start_trans =
591     extra->middle_trans = ORTHFLOW_WIDTH/2.0;
592   extra->end_long =
593     extra->end_trans = ORTHFLOW_WIDTH/2 + ORTHFLOW_ARROWLEN;
594   orthflow->textpos = orthflow->text->position;
595 
596   orthflow_update_data(orthflow);
597 
598   return &orthflow->orth.object;
599 }
600 
601 static ObjectChange *
orthflow_set_type_callback(DiaObject * obj,Point * clicked,gpointer data)602 orthflow_set_type_callback (DiaObject* obj, Point* clicked, gpointer data)
603 {
604   ObjectChange* change ;
605   change = orthflow_create_change( FLOW_TYPE, ((Orthflow*)obj)->type, 0 ) ;
606 
607   ((Orthflow*)obj)->type = GPOINTER_TO_INT (data);
608   orthflow_update_data((Orthflow*)obj);
609 
610   return change;
611 }
612 
613 static ObjectChange *
orthflow_segment_callback(DiaObject * obj,Point * clicked,gpointer data)614 orthflow_segment_callback (DiaObject* obj, Point* clicked, gpointer data)
615 {
616   if ( GPOINTER_TO_INT (data) )
617      return orthconn_add_segment( (OrthConn*)obj, clicked ) ;
618 
619   return orthconn_delete_segment( (OrthConn*)obj, clicked ) ;
620 }
621 
622 static DiaMenuItem orthflow_menu_items[] = {
623   { N_("Energy"), orthflow_set_type_callback, (void*)ORTHFLOW_ENERGY, 1 },
624   { N_("Material"), orthflow_set_type_callback, (void*)ORTHFLOW_MATERIAL, 1 },
625   { N_("Signal"), orthflow_set_type_callback, (void*)ORTHFLOW_SIGNAL, 1 },
626   { N_("Add segment"), orthflow_segment_callback, (void*)1, 1 },
627   { N_("Delete segment"), orthflow_segment_callback, (void*)0, 1 },
628   ORTHCONN_COMMON_MENUS,
629 };
630 
631 static DiaMenu orthflow_menu = {
632   "Orthflow",
633   sizeof(orthflow_menu_items)/sizeof(DiaMenuItem),
634   orthflow_menu_items,
635   NULL
636 };
637 
638 static DiaMenu *
orthflow_get_object_menu(Orthflow * orthflow,Point * clickedpoint)639 orthflow_get_object_menu(Orthflow *orthflow, Point *clickedpoint)
640 {
641   orthflow_menu_items[4].active = orthflow->orth.numpoints > 3;
642   orthconn_update_object_menu((OrthConn*)orthflow,
643 			      clickedpoint, &orthflow_menu_items[5]);
644   return &orthflow_menu;
645 }
646 
647 
648