1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 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.
24 #include <string.h> /* memcpy() */
27 #include "orth_conn.h"
31 #include "diarenderer.h"
32 #include "autoroute.h"
34 static void place_handle_by_swapping(OrthConn
*orth
,
35 int index
, Handle
*handle
);
36 static ObjectChange
*orthconn_set_autorouting(OrthConn
*orth
, gboolean on
);
44 midsegment_create_change(OrthConn
*orth
, enum change_type type
,
46 Point
*point1
, Point
*point2
,
47 Handle
*handle1
, Handle
*handle2
);
49 struct MidSegmentChange
{
50 ObjectChange obj_change
;
52 /* All additions and deletions of segments in the middle
53 * of the orthconn must delete/add two segments to keep
54 * the horizontal/vertical balance.
56 * None of the end segments must be removed by this change.
59 enum change_type type
;
64 Handle
*handles
[2]; /* These handles cannot be connected */
68 endsegment_create_change(OrthConn
*orth
, enum change_type type
,
69 int segment
, Point
*point
,
72 place_handle_by_swapping(OrthConn
*orth
, int index
, Handle
*handle
);
74 struct EndSegmentChange
{
75 ObjectChange obj_change
;
77 /* Additions and deletions of segments of at the endpoints
80 * Addition of an endpoint segment need not store any point.
81 * Deletion of an endpoint segment need to store the endpoint position
82 * so that it can be reverted.
83 * Deleted segments might be connected, so we must store the connection
87 enum change_type type
;
93 Handle
*old_end_handle
;
94 ConnectionPoint
*cp
; /* NULL in add segment and if not connected in
99 autoroute_create_change(OrthConn
*orth
, gboolean on
);
101 struct AutorouteChange
{
102 ObjectChange obj_change
;
107 static void set_midpoint(Point
*point
, OrthConn
*orth
, int segment
)
110 point
->x
= 0.5*(orth
->points
[i
].x
+ orth
->points
[i
+1].x
);
111 point
->y
= 0.5*(orth
->points
[i
].y
+ orth
->points
[i
+1].y
);
114 static void setup_midpoint_handle(Handle
*handle
)
116 handle
->id
= HANDLE_MIDPOINT
;
117 handle
->type
= HANDLE_MINOR_CONTROL
;
118 handle
->connect_type
= HANDLE_NONCONNECTABLE
;
119 handle
->connected_to
= NULL
;
122 static void setup_endpoint_handle(Handle
*handle
, HandleId id
)
125 handle
->type
= HANDLE_MAJOR_CONTROL
;
126 handle
->connect_type
= HANDLE_CONNECTABLE
;
127 handle
->connected_to
= NULL
;
130 static int get_handle_nr(OrthConn
*orth
, Handle
*handle
)
133 for (i
=0;i
<orth
->numpoints
-1;i
++) {
134 if (orth
->handles
[i
] == handle
)
140 static int get_segment_nr(OrthConn
*orth
, Point
*point
, real max_dist
)
144 real distance
, tmp_dist
;
147 distance
= distance_line_point(&orth
->points
[0], &orth
->points
[1], 0, point
);
149 for (i
=1;i
<orth
->numpoints
-1;i
++) {
150 tmp_dist
= distance_line_point(&orth
->points
[i
], &orth
->points
[i
+1], 0, point
);
151 if (tmp_dist
< distance
) {
157 if (distance
< max_dist
)
165 orthconn_move_handle(OrthConn
*orth
, Handle
*handle
,
166 Point
*to
, ConnectionPoint
*cp
,
167 HandleMoveReason reason
, ModifierKeys modifiers
)
171 DiaObject
*obj
= (DiaObject
*)orth
;
172 ObjectChange
*change
= NULL
;
175 case HANDLE_MOVE_STARTPOINT
:
176 orth
->points
[0] = *to
;
177 if (orth
->autorouting
&&
178 autoroute_layout_orthconn(orth
, cp
,
179 obj
->handles
[1]->connected_to
))
181 switch (orth
->orientation
[0]) {
183 orth
->points
[1].y
= to
->y
;
186 orth
->points
[1].x
= to
->x
;
190 case HANDLE_MOVE_ENDPOINT
:
191 n
= orth
->numpoints
- 1;
192 orth
->points
[n
] = *to
;
193 if (orth
->autorouting
&&
194 autoroute_layout_orthconn(orth
, obj
->handles
[0]->connected_to
,
197 switch (orth
->orientation
[n
-1]) {
199 orth
->points
[n
-1].y
= to
->y
;
202 orth
->points
[n
-1].x
= to
->x
;
206 case HANDLE_MIDPOINT
:
207 n
= orth
->numpoints
- 1;
208 handle_nr
= get_handle_nr(orth
, handle
);
209 if (orth
->autorouting
)
210 change
= orthconn_set_autorouting(orth
, FALSE
);
211 switch (orth
->orientation
[handle_nr
]) {
213 orth
->points
[handle_nr
].y
= to
->y
;
214 orth
->points
[handle_nr
+1].y
= to
->y
;
217 orth
->points
[handle_nr
].x
= to
->x
;
218 orth
->points
[handle_nr
+1].x
= to
->x
;
223 message_error("Internal error in orthconn_move_handle.\n");
231 orthconn_move(OrthConn
*orth
, Point
*to
)
237 point_sub(&p
, &orth
->points
[0]);
239 orth
->points
[0] = *to
;
240 for (i
=1;i
<orth
->numpoints
;i
++) {
241 point_add(&orth
->points
[i
], &p
);
247 orthconn_distance_from(OrthConn
*orth
, Point
*point
, real line_width
)
252 dist
= distance_line_point( &orth
->points
[0], &orth
->points
[1],
254 for (i
=1;i
<orth
->numpoints
-1;i
++) {
256 distance_line_point( &orth
->points
[i
], &orth
->points
[i
+1],
264 adjust_handle_count_to(OrthConn
*orth
, guint count
) {
265 /* This will shrink or expand orth->handles as necessary (so that
266 orth->numhandles matches orth->numpoints-1, most probably), by adding or
267 removing minor handles and keeping the endpoint handles at the
268 extremities of the array. */
270 if (orth
->numhandles
== count
) return;
271 if (orth
->numhandles
< count
) { /* adding */
273 orth
->handles
= g_realloc(orth
->handles
,
274 (count
)*sizeof(Handle
*));
275 orth
->handles
[count
-1] = orth
->handles
[orth
->numhandles
-1];
276 orth
->handles
[orth
->numhandles
-1] = NULL
;
277 for (i
=orth
->numhandles
-1; i
<count
-1; i
++) {
278 Handle
*handle
= g_new0(Handle
,1);
279 setup_midpoint_handle(handle
);
280 object_add_handle(&orth
->object
,handle
);
281 orth
->handles
[i
] = handle
;
283 } else { /* removing */
285 for (i
=count
-1; i
<orth
->numhandles
-1; i
++) {
286 Handle
*handle
= orth
->handles
[i
];
287 object_remove_handle(&orth
->object
,handle
);
289 orth
->handles
[i
] = NULL
;
291 orth
->handles
[count
-1] = orth
->handles
[orth
->numhandles
-1];
292 orth
->handles
[orth
->numhandles
-1] = NULL
;
293 orth
->handles
= g_realloc(orth
->handles
,
294 (count
)*sizeof(Handle
*));
296 orth
->numhandles
= count
;
297 /* handles' positions will be set now */
301 orthconn_update_data(OrthConn
*orth
)
304 DiaObject
*obj
= (DiaObject
*)orth
;
306 ConnectionPoint
*start_cp
;
307 ConnectionPoint
*end_cp
;
309 obj
->position
= orth
->points
[0];
311 /* During startup, handles may not have been setup yet, so do so
312 * temporarily to be able to get the last handle connection.
314 adjust_handle_count_to(orth
, orth
->numpoints
-1);
316 start_cp
= orth
->handles
[0]->connected_to
;
317 end_cp
= orth
->handles
[orth
->numpoints
-2]->connected_to
;
320 g_warning("very sick OrthConn object...");
324 points
= orth
->points
;
325 if (!orth
->autorouting
&&
326 (connpoint_is_autogap(start_cp
) ||
327 connpoint_is_autogap(end_cp
))) {
328 Point
* new_points
= g_new(Point
, orth
->numpoints
);
330 for (i
= 0; i
< orth
->numpoints
; i
++) {
331 new_points
[i
] = points
[i
];
334 if (connpoint_is_autogap(start_cp
)) {
335 new_points
[0] = calculate_object_edge(&start_cp
->pos
, &new_points
[1],
338 printf("Moved start to %f, %f\n",
339 new_points[0].x, new_points[0].y);
342 if (connpoint_is_autogap(end_cp
)) {
343 new_points
[orth
->numpoints
-1] =
344 calculate_object_edge(&end_cp
->pos
, &new_points
[orth
->numpoints
-2],
347 printf("Moved end to %f, %f\n",
348 new_points[orth->numpoints-1].x, new_points[orth->numpoints-1].y);
352 orth
->points
= new_points
;
355 obj
->position
= orth
->points
[0];
357 adjust_handle_count_to(orth
, orth
->numpoints
-1);
359 /* Make sure start-handle is first and end-handle is second. */
360 place_handle_by_swapping(orth
, 0, orth
->handles
[0]);
361 place_handle_by_swapping(orth
, 1, orth
->handles
[orth
->numpoints
-2]);
363 /* Update handles: */
364 orth
->handles
[0]->pos
= orth
->points
[0];
365 orth
->handles
[orth
->numpoints
-2]->pos
= orth
->points
[orth
->numpoints
-1];
367 for (i
=1;i
<orth
->numpoints
-2;i
++) {
368 set_midpoint(&orth
->handles
[i
]->pos
, orth
, i
);
373 orthconn_update_boundingbox(OrthConn
*orth
)
375 assert(orth
!= NULL
);
376 polyline_bbox(&orth
->points
[0],
378 &orth
->extra_spacing
, FALSE
,
379 &orth
->object
.bounding_box
);
383 orthconn_simple_draw(OrthConn
*orth
, DiaRenderer
*renderer
, real width
)
387 assert(orth
!= NULL
);
388 assert(renderer
!= NULL
);
391 g_warning("very sick OrthConn object...");
395 /* When not autorouting, need to take gap into account here. */
396 points
= &orth
->points
[0];
398 DIA_RENDERER_GET_CLASS(renderer
)->set_linewidth(renderer
, width
);
399 DIA_RENDERER_GET_CLASS(renderer
)->set_linestyle(renderer
, LINESTYLE_SOLID
);
400 DIA_RENDERER_GET_CLASS(renderer
)->set_linejoin(renderer
, LINEJOIN_MITER
);
401 DIA_RENDERER_GET_CLASS(renderer
)->set_linecaps(renderer
, LINECAPS_BUTT
);
403 DIA_RENDERER_GET_CLASS(renderer
)->draw_polyline(renderer
, points
,
410 orthconn_can_delete_segment(OrthConn
*orth
, Point
*clickedpoint
)
414 /* Cannot delete any segments when there are only two left,
415 * and not amy middle segment if there are only three segments.
418 if (orth
->numpoints
==3)
421 segment
= get_segment_nr(orth
, clickedpoint
, 1.0);
426 if ( (segment
!= 0) && (segment
!= orth
->numpoints
-2)) {
428 if (orth
->numpoints
==4)
436 orthconn_can_add_segment(OrthConn
*orth
, Point
*clickedpoint
)
438 int segment
= get_segment_nr(orth
, clickedpoint
, 1000000.0);
447 /* Needs to have at least 2 handles.
448 The handles are stored in order in the OrthConn, but need
449 not be stored in order in the DiaObject.handles array. This
450 is so that derived object can do what they want with
451 DiaObject.handles. */
454 orthconn_init(OrthConn
*orth
, Point
*startpoint
)
460 object_init(obj
, 3, 0);
463 orth
->numorient
= orth
->numpoints
- 1;
465 orth
->points
= g_malloc0(4*sizeof(Point
));
467 orth
->orientation
= g_malloc0(3*sizeof(Orientation
));
469 orth
->numhandles
= 3;
470 orth
->handles
= g_malloc0(3*sizeof(Handle
*));
472 orth
->handles
[0] = g_new(Handle
, 1);
473 setup_endpoint_handle(orth
->handles
[0], HANDLE_MOVE_STARTPOINT
);
474 obj
->handles
[0] = orth
->handles
[0];
476 orth
->handles
[1] = g_new(Handle
, 1);
477 setup_midpoint_handle(orth
->handles
[1]);
478 obj
->handles
[1] = orth
->handles
[1];
480 orth
->handles
[2] = g_new(Handle
, 1);
481 setup_endpoint_handle(orth
->handles
[2], HANDLE_MOVE_ENDPOINT
);
482 obj
->handles
[2] = orth
->handles
[2];
484 orth
->autorouting
= TRUE
;
486 /* Just so we have some position: */
487 orth
->points
[0] = *startpoint
;
488 orth
->points
[1].x
= startpoint
->x
;
489 orth
->points
[1].y
= startpoint
->y
+ 1.0;
490 orth
->points
[2].x
= startpoint
->x
+ 1.0;
491 orth
->points
[2].y
= startpoint
->y
+ 1.0;
492 orth
->points
[3].x
= startpoint
->x
+ 2.0;
493 orth
->points
[3].y
= startpoint
->y
+ 1.0;
495 orth
->orientation
[0] = VERTICAL
;
496 orth
->orientation
[1] = HORIZONTAL
;
497 orth
->orientation
[2] = VERTICAL
;
499 orthconn_update_data(orth
);
502 /** This function does *not* set up handles */
504 orthconn_set_points(OrthConn
*orth
, int num_points
, Point
*points
)
509 orth
->numpoints
= num_points
;
512 g_free(orth
->points
);
514 orth
->points
= g_malloc((orth
->numpoints
)*sizeof(Point
));
516 for (i
=0;i
<orth
->numpoints
;i
++) {
517 orth
->points
[i
] = points
[i
];
520 /* Set up the orientation array. */
521 /* Maybe we could get rid of this array altogether? */
522 orth
->numorient
= orth
->numpoints
-1;
523 if (orth
->orientation
) g_free(orth
->orientation
);
524 orth
->orientation
= g_new(Orientation
, orth
->numorient
);
525 horiz
= (fabs(orth
->points
[0].y
-orth
->points
[1].y
) < 0.00001);
526 for (i
= 0; i
< orth
->numorient
; i
++) {
527 if (horiz
) orth
->orientation
[i
] = HORIZONTAL
;
528 else orth
->orientation
[i
] = VERTICAL
;
534 orthconn_copy(OrthConn
*from
, OrthConn
*to
)
537 DiaObject
*toobj
, *fromobj
;
540 fromobj
= &from
->object
;
542 object_copy(fromobj
, toobj
);
544 to
->numpoints
= from
->numpoints
;
545 to
->numorient
= from
->numorient
;
547 to
->points
= g_malloc0((to
->numpoints
)*sizeof(Point
));
549 for (i
=0;i
<to
->numpoints
;i
++) {
550 to
->points
[i
] = from
->points
[i
];
553 to
->autorouting
= from
->autorouting
;
554 to
->orientation
= g_malloc0((to
->numpoints
-1)*sizeof(Orientation
));
555 to
->numhandles
= from
->numhandles
;
556 to
->handles
= g_malloc0((to
->numpoints
-1)*sizeof(Handle
*));
558 for (i
=0;i
<to
->numpoints
-1;i
++) {
559 to
->orientation
[i
] = from
->orientation
[i
];
560 to
->handles
[i
] = g_new(Handle
,1);
561 *to
->handles
[i
] = *from
->handles
[i
];
562 to
->handles
[i
]->connected_to
= NULL
;
563 toobj
->handles
[i
] = to
->handles
[i
];
565 memcpy(&to
->extra_spacing
,&from
->extra_spacing
,sizeof(to
->extra_spacing
));
569 orthconn_destroy(OrthConn
*orth
)
573 object_destroy(&orth
->object
);
575 g_free(orth
->points
);
576 g_free(orth
->orientation
);
578 for (i
=0;i
<orth
->numpoints
-1;i
++)
579 g_free(orth
->handles
[i
]);
581 g_free(orth
->handles
);
585 place_handle_by_swapping(OrthConn
*orth
, int index
, Handle
*handle
)
591 obj
= (DiaObject
*)orth
;
592 if (obj
->handles
[index
] == handle
)
593 return; /* Nothing to do */
595 for (j
=0;j
<obj
->num_handles
;j
++) {
596 if (obj
->handles
[j
] == handle
) {
597 /* Swap handle j and index */
598 tmp
= obj
->handles
[j
];
599 obj
->handles
[j
] = obj
->handles
[index
];
600 obj
->handles
[index
] = tmp
;
608 orthconn_save(OrthConn
*orth
, ObjectNode obj_node
)
613 /* Make sure start-handle is first and end-handle is second. */
614 place_handle_by_swapping(orth
, 0, orth
->handles
[0]);
615 place_handle_by_swapping(orth
, 1, orth
->handles
[orth
->numpoints
-2]);
617 object_save(&orth
->object
, obj_node
);
619 attr
= new_attribute(obj_node
, "orth_points");
621 for (i
=0;i
<orth
->numpoints
;i
++) {
622 data_add_point(attr
, &orth
->points
[i
]);
625 attr
= new_attribute(obj_node
, "orth_orient");
626 for (i
=0;i
<orth
->numpoints
-1;i
++) {
627 data_add_enum(attr
, orth
->orientation
[i
]);
630 data_add_boolean(new_attribute(obj_node
, "autorouting"), orth
->autorouting
);
634 orthconn_load(OrthConn
*orth
, ObjectNode obj_node
) /* NOTE: Does object_init() */
642 DiaObject
*obj
= &orth
->object
;
644 object_load(obj
, obj_node
);
646 attr
= object_find_attribute(obj_node
, "version");
648 version
= attribute_num_data(attr
);
650 attr
= object_find_attribute(obj_node
, "orth_points");
653 orth
->numpoints
= attribute_num_data(attr
);
657 orth
->numorient
= orth
->numpoints
- 1;
659 object_init(obj
, orth
->numpoints
-1, 0);
661 data
= attribute_first_data(attr
);
662 orth
->points
= g_malloc0((orth
->numpoints
)*sizeof(Point
));
663 for (i
=0;i
<orth
->numpoints
;i
++) {
664 data_point(data
, &orth
->points
[i
]);
665 data
= data_next(data
);
668 attr
= object_find_attribute(obj_node
, "orth_orient");
670 data
= attribute_first_data(attr
);
671 orth
->orientation
= g_malloc0((orth
->numpoints
-1)*sizeof(Orientation
));
672 for (i
=0;i
<orth
->numpoints
-1;i
++) {
673 orth
->orientation
[i
] = data_enum(data
);
674 data
= data_next(data
);
677 orth
->autorouting
= TRUE
;
678 attr
= object_find_attribute(obj_node
, "autorouting");
680 orth
->autorouting
= data_boolean(attribute_first_data(attr
));
681 else if (version
== 0) {
682 /* Version 0 orthconns have no autorouting. */
683 orth
->autorouting
= FALSE
;
686 orth
->handles
= g_malloc0((orth
->numpoints
-1)*sizeof(Handle
*));
688 orth
->handles
[0] = g_new(Handle
, 1);
689 setup_endpoint_handle(orth
->handles
[0], HANDLE_MOVE_STARTPOINT
);
690 orth
->handles
[0]->pos
= orth
->points
[0];
691 obj
->handles
[0] = orth
->handles
[0];
693 n
= orth
->numpoints
-2;
694 orth
->handles
[n
] = g_new(Handle
, 1);
695 setup_endpoint_handle(orth
->handles
[n
], HANDLE_MOVE_ENDPOINT
);
696 orth
->handles
[n
]->pos
= orth
->points
[orth
->numpoints
-1];
697 obj
->handles
[1] = orth
->handles
[n
];
699 for (i
=1; i
<orth
->numpoints
-2; i
++) {
700 orth
->handles
[i
] = g_new(Handle
, 1);
701 setup_midpoint_handle(orth
->handles
[i
]);
702 obj
->handles
[i
+1] = orth
->handles
[i
];
704 orth
->numhandles
= orth
->numpoints
-1;
706 orthconn_update_data(orth
);
710 orthconn_get_middle_handle( OrthConn
*orth
)
712 int n
= orth
->numpoints
- 1 ;
713 return orth
->handles
[ n
/2 ] ;
717 orthconn_delete_segment(OrthConn
*orth
, Point
*clickedpoint
)
720 ObjectChange
*change
= NULL
;
722 if (orth
->numpoints
==3)
725 segment
= get_segment_nr(orth
, clickedpoint
, 1.0);
730 change
= endsegment_create_change(orth
, TYPE_REMOVE_SEGMENT
, segment
,
731 &orth
->points
[segment
],
732 orth
->handles
[segment
]);
733 } else if (segment
== orth
->numpoints
-2) {
734 change
= endsegment_create_change(orth
, TYPE_REMOVE_SEGMENT
, segment
,
735 &orth
->points
[segment
+1],
736 orth
->handles
[segment
]);
737 } else if (segment
> 0) {
738 /* Don't delete the last midpoint segment.
739 * That would delete also the endpoint segment after it.
741 if (segment
== orth
->numpoints
-3)
744 change
= midsegment_create_change(orth
, TYPE_REMOVE_SEGMENT
, segment
,
745 &orth
->points
[segment
],
746 &orth
->points
[segment
+1],
747 orth
->handles
[segment
],
748 orth
->handles
[segment
+1]);
751 change
->apply(change
, (DiaObject
*)orth
);
757 orthconn_add_segment(OrthConn
*orth
, Point
*clickedpoint
)
759 Handle
*handle1
, *handle2
;
760 ObjectChange
*change
= NULL
;
764 segment
= get_segment_nr(orth
, clickedpoint
, 1.0);
768 if (segment
==0) { /* First segment */
769 handle1
= g_new(Handle
, 1);
770 setup_endpoint_handle(handle1
, HANDLE_MOVE_STARTPOINT
);
771 change
= endsegment_create_change(orth
, TYPE_ADD_SEGMENT
,
774 } else if (segment
== orth
->numpoints
-2) { /* Last segment */
775 handle1
= g_new(Handle
, 1);
776 setup_endpoint_handle(handle1
, HANDLE_MOVE_ENDPOINT
);
777 change
= endsegment_create_change(orth
, TYPE_ADD_SEGMENT
,
778 segment
+1, &orth
->points
[segment
+1],
780 } else if (segment
> 0) {
781 handle1
= g_new(Handle
, 1);
782 setup_midpoint_handle(handle1
);
783 handle2
= g_new(Handle
, 1);
784 setup_midpoint_handle(handle2
);
785 newpoint
= *clickedpoint
;
786 if (orth
->orientation
[segment
]==HORIZONTAL
)
787 newpoint
.y
= orth
->points
[segment
].y
;
789 newpoint
.x
= orth
->points
[segment
].x
;
791 change
= midsegment_create_change(orth
, TYPE_ADD_SEGMENT
, segment
,
798 change
->apply(change
, (DiaObject
*)orth
);
804 /* Set autorouting on or off. If setting on, try to autoroute and
805 * return the changes from that.
807 static ObjectChange
*
808 orthconn_set_autorouting(OrthConn
*conn
, gboolean on
)
810 DiaObject
*obj
= (DiaObject
*)conn
;
811 ObjectChange
*change
;
813 change
= autoroute_create_change(conn
, on
);
814 change
->apply(change
, obj
);
819 delete_point(OrthConn
*orth
, int pos
)
824 orth
->numorient
= orth
->numpoints
- 1;
826 for (i
=pos
;i
<orth
->numpoints
;i
++) {
827 orth
->points
[i
] = orth
->points
[i
+1];
830 orth
->points
= g_realloc(orth
->points
, orth
->numpoints
*sizeof(Point
));
833 /* Make sure numpoints have been decreased before calling this function.
834 * ie. call delete_point first.
837 remove_handle(OrthConn
*orth
, int segment
)
842 handle
= orth
->handles
[segment
];
844 for (i
=segment
; i
< orth
->numpoints
-1; i
++) {
845 orth
->handles
[i
] = orth
->handles
[i
+1];
846 orth
->orientation
[i
] = orth
->orientation
[i
+1];
849 orth
->orientation
= g_realloc(orth
->orientation
,
850 (orth
->numpoints
-1)*sizeof(Orientation
));
851 orth
->handles
= g_realloc(orth
->handles
,
852 (orth
->numpoints
-1)*sizeof(Handle
*));
854 object_remove_handle(&orth
->object
, handle
);
855 orth
->numhandles
= orth
->numpoints
-1;
860 add_point(OrthConn
*orth
, int pos
, Point
*point
)
865 orth
->numorient
= orth
->numpoints
-1;
867 orth
->points
= g_realloc(orth
->points
, orth
->numpoints
*sizeof(Point
));
868 for (i
=orth
->numpoints
-1;i
>pos
;i
--) {
869 orth
->points
[i
] = orth
->points
[i
-1];
871 orth
->points
[pos
] = *point
;
874 /* Make sure numpoints have been increased before calling this function.
875 * ie. call add_point first.
878 insert_handle(OrthConn
*orth
, int segment
,
879 Handle
*handle
, Orientation orient
)
883 orth
->orientation
= g_realloc(orth
->orientation
,
884 (orth
->numpoints
-1)*sizeof(Orientation
));
885 orth
->handles
= g_realloc(orth
->handles
,
886 (orth
->numpoints
-1)*sizeof(Handle
*));
887 for (i
=orth
->numpoints
-2;i
>segment
;i
--) {
888 orth
->handles
[i
] = orth
->handles
[i
-1];
889 orth
->orientation
[i
] = orth
->orientation
[i
-1];
891 orth
->handles
[segment
] = handle
;
892 orth
->orientation
[segment
] = orient
;
894 object_add_handle(&orth
->object
, handle
);
895 orth
->numhandles
= orth
->numpoints
-1;
899 endsegment_change_free(struct EndSegmentChange
*change
)
901 if ( (change
->type
==TYPE_ADD_SEGMENT
&& !change
->applied
) ||
902 (change
->type
==TYPE_REMOVE_SEGMENT
&& change
->applied
) ){
904 g_free(change
->handle
);
905 change
->handle
= NULL
;
910 endsegment_change_apply(struct EndSegmentChange
*change
, DiaObject
*obj
)
912 OrthConn
*orth
= (OrthConn
*)obj
;
916 switch (change
->type
) {
917 case TYPE_ADD_SEGMENT
:
918 object_unconnect(obj
, change
->old_end_handle
);
919 if (change
->segment
==0) { /* first */
920 add_point(orth
, 0, &change
->point
);
921 insert_handle(orth
, change
->segment
,
922 change
->handle
, FLIP_ORIENT(orth
->orientation
[0]) );
923 setup_midpoint_handle(orth
->handles
[1]);
924 obj
->position
= orth
->points
[0];
926 add_point(orth
, orth
->numpoints
, &change
->point
);
927 insert_handle(orth
, change
->segment
, change
->handle
,
928 FLIP_ORIENT(orth
->orientation
[orth
->numpoints
-3]) );
929 setup_midpoint_handle(orth
->handles
[orth
->numpoints
-3]);
932 object_connect(obj
, change
->handle
, change
->cp
);
934 case TYPE_REMOVE_SEGMENT
:
935 object_unconnect(obj
, change
->old_end_handle
);
936 if (change
->segment
==0) { /* first */
937 delete_point(orth
, 0);
938 remove_handle(orth
, 0);
939 setup_endpoint_handle(orth
->handles
[0], HANDLE_MOVE_STARTPOINT
);
940 obj
->position
= orth
->points
[0];
942 delete_point(orth
, orth
->numpoints
-1);
943 remove_handle(orth
, change
->segment
);
944 setup_endpoint_handle(orth
->handles
[orth
->numpoints
-2],
945 HANDLE_MOVE_ENDPOINT
);
952 endsegment_change_revert(struct EndSegmentChange
*change
, DiaObject
*obj
)
954 OrthConn
*orth
= (OrthConn
*)obj
;
956 switch (change
->type
) {
957 case TYPE_ADD_SEGMENT
:
958 object_unconnect(obj
, change
->handle
);
959 if (change
->segment
==0) { /* first */
960 delete_point(orth
, 0);
961 remove_handle(orth
, 0);
962 setup_endpoint_handle(orth
->handles
[0], HANDLE_MOVE_STARTPOINT
);
963 obj
->position
= orth
->points
[0];
965 delete_point(orth
, orth
->numpoints
-1);
966 remove_handle(orth
, change
->segment
);
967 setup_endpoint_handle(orth
->handles
[orth
->numpoints
-2],
968 HANDLE_MOVE_ENDPOINT
);
971 object_connect(obj
, change
->old_end_handle
, change
->cp
);
973 case TYPE_REMOVE_SEGMENT
:
974 if (change
->segment
==0) { /* first */
975 add_point(orth
, 0, &change
->point
);
976 insert_handle(orth
, change
->segment
,
977 change
->handle
, FLIP_ORIENT(orth
->orientation
[0]) );
978 setup_midpoint_handle(orth
->handles
[1]);
979 obj
->position
= orth
->points
[0];
981 add_point(orth
, orth
->numpoints
, &change
->point
);
982 insert_handle(orth
, change
->segment
, change
->handle
,
983 FLIP_ORIENT(orth
->orientation
[orth
->numpoints
-3]) );
984 setup_midpoint_handle(orth
->handles
[orth
->numpoints
-3]);
987 object_connect(obj
, change
->old_end_handle
, change
->cp
);
993 static ObjectChange
*
994 endsegment_create_change(OrthConn
*orth
, enum change_type type
,
995 int segment
, Point
*point
,
998 struct EndSegmentChange
*change
;
1000 change
= g_new(struct EndSegmentChange
, 1);
1002 change
->obj_change
.apply
= (ObjectChangeApplyFunc
) endsegment_change_apply
;
1003 change
->obj_change
.revert
= (ObjectChangeRevertFunc
) endsegment_change_revert
;
1004 change
->obj_change
.free
= (ObjectChangeFreeFunc
) endsegment_change_free
;
1006 change
->type
= type
;
1007 change
->applied
= 0;
1008 change
->segment
= segment
;
1009 change
->point
= *point
;
1010 change
->handle
= handle
;
1012 change
->old_end_handle
= orth
->handles
[0];
1014 change
->old_end_handle
= orth
->handles
[orth
->numpoints
-2];
1015 change
->cp
= change
->old_end_handle
->connected_to
;
1017 return (ObjectChange
*)change
;
1022 midsegment_change_free(struct MidSegmentChange
*change
)
1024 if ( (change
->type
==TYPE_ADD_SEGMENT
&& !change
->applied
) ||
1025 (change
->type
==TYPE_REMOVE_SEGMENT
&& change
->applied
) ){
1026 if (change
->handles
[0])
1027 g_free(change
->handles
[0]);
1028 change
->handles
[0] = NULL
;
1029 if (change
->handles
[1])
1030 g_free(change
->handles
[1]);
1031 change
->handles
[1] = NULL
;
1036 midsegment_change_apply(struct MidSegmentChange
*change
, DiaObject
*obj
)
1038 OrthConn
*orth
= (OrthConn
*)obj
;
1039 change
->applied
= 1;
1041 switch (change
->type
) {
1042 case TYPE_ADD_SEGMENT
:
1043 add_point(orth
, change
->segment
+1, &change
->points
[1]);
1044 add_point(orth
, change
->segment
+1, &change
->points
[0]);
1045 insert_handle(orth
, change
->segment
+1, change
->handles
[1],
1046 orth
->orientation
[change
->segment
] );
1047 insert_handle(orth
, change
->segment
+1, change
->handles
[0],
1048 FLIP_ORIENT(orth
->orientation
[change
->segment
]) );
1050 case TYPE_REMOVE_SEGMENT
:
1051 delete_point(orth
, change
->segment
);
1052 remove_handle(orth
, change
->segment
);
1053 delete_point(orth
, change
->segment
);
1054 remove_handle(orth
, change
->segment
);
1055 if (orth
->orientation
[change
->segment
]==HORIZONTAL
) {
1056 orth
->points
[change
->segment
].x
= change
->points
[0].x
;
1058 orth
->points
[change
->segment
].y
= change
->points
[0].y
;
1065 midsegment_change_revert(struct MidSegmentChange
*change
, DiaObject
*obj
)
1067 OrthConn
*orth
= (OrthConn
*)obj
;
1069 switch (change
->type
) {
1070 case TYPE_ADD_SEGMENT
:
1071 delete_point(orth
, change
->segment
+1);
1072 remove_handle(orth
, change
->segment
+1);
1073 delete_point(orth
, change
->segment
+1);
1074 remove_handle(orth
, change
->segment
+1);
1076 case TYPE_REMOVE_SEGMENT
:
1077 if (orth
->orientation
[change
->segment
]==HORIZONTAL
) {
1078 orth
->points
[change
->segment
].x
= change
->points
[1].x
;
1080 orth
->points
[change
->segment
].y
= change
->points
[1].y
;
1082 add_point(orth
, change
->segment
, &change
->points
[1]);
1083 add_point(orth
, change
->segment
, &change
->points
[0]);
1084 insert_handle(orth
, change
->segment
, change
->handles
[1],
1085 orth
->orientation
[change
->segment
-1] );
1086 insert_handle(orth
, change
->segment
, change
->handles
[0],
1087 FLIP_ORIENT(orth
->orientation
[change
->segment
-1]) );
1090 change
->applied
= 0;
1093 static ObjectChange
*
1094 midsegment_create_change(OrthConn
*orth
, enum change_type type
,
1096 Point
*point1
, Point
*point2
,
1097 Handle
*handle1
, Handle
*handle2
)
1099 struct MidSegmentChange
*change
;
1101 change
= g_new(struct MidSegmentChange
, 1);
1103 change
->obj_change
.apply
= (ObjectChangeApplyFunc
) midsegment_change_apply
;
1104 change
->obj_change
.revert
= (ObjectChangeRevertFunc
) midsegment_change_revert
;
1105 change
->obj_change
.free
= (ObjectChangeFreeFunc
) midsegment_change_free
;
1107 change
->type
= type
;
1108 change
->applied
= 0;
1109 change
->segment
= segment
;
1110 change
->points
[0] = *point1
;
1111 change
->points
[1] = *point2
;
1112 change
->handles
[0] = handle1
;
1113 change
->handles
[1] = handle2
;
1115 return (ObjectChange
*)change
;
1119 autoroute_change_free(struct AutorouteChange
*change
)
1121 g_free(change
->points
);
1125 autoroute_change_apply(struct AutorouteChange
*change
, DiaObject
*obj
)
1127 OrthConn
*orth
= (OrthConn
*)obj
;
1130 orth
->autorouting
= TRUE
;
1131 autoroute_layout_orthconn(orth
, obj
->handles
[0]->connected_to
,
1132 obj
->handles
[1]->connected_to
);
1134 orth
->autorouting
= FALSE
;
1135 orthconn_set_points(orth
, orth
->numpoints
, change
->points
);
1140 autoroute_change_revert(struct AutorouteChange
*change
, DiaObject
*obj
)
1142 OrthConn
*orth
= (OrthConn
*)obj
;
1145 orth
->autorouting
= FALSE
;
1146 orthconn_set_points(orth
, orth
->numpoints
, change
->points
);
1148 orth
->autorouting
= TRUE
;
1149 autoroute_layout_orthconn(orth
, obj
->handles
[0]->connected_to
,
1150 obj
->handles
[1]->connected_to
);
1154 static ObjectChange
*
1155 autoroute_create_change(OrthConn
*orth
, gboolean on
)
1157 struct AutorouteChange
*change
;
1160 change
= g_new(struct AutorouteChange
, 1);
1162 change
->obj_change
.apply
= (ObjectChangeApplyFunc
) autoroute_change_apply
;
1163 change
->obj_change
.revert
= (ObjectChangeRevertFunc
) autoroute_change_revert
;
1164 change
->obj_change
.free
= (ObjectChangeFreeFunc
) autoroute_change_free
;
1167 change
->points
= g_new(Point
, orth
->numpoints
);
1168 for (i
= 0; i
< orth
->numpoints
; i
++)
1169 change
->points
[i
] = orth
->points
[i
];
1171 return (ObjectChange
*)change
;
1175 orthconn_toggle_autorouting_callback(DiaObject
*obj
, Point
*clicked
, gpointer data
)
1177 ObjectChange
*change
;
1178 /* This is kinda hackish. Since we can't see the menu item, we have to
1179 * assume that we're right about toggling and just send !orth->autorouting.
1181 change
= orthconn_set_autorouting((OrthConn
*)obj
,
1182 !((OrthConn
*)obj
)->autorouting
);
1183 orthconn_update_data((OrthConn
*)obj
);
1188 orthconn_update_object_menu(OrthConn
*orth
, Point
*clicked
,
1189 DiaMenuItem
*object_menu_items
)
1191 object_menu_items
[0].active
= DIAMENU_ACTIVE
|DIAMENU_TOGGLE
|
1192 (orth
->autorouting
?DIAMENU_TOGGLE_ON
:0);