1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * This file forked ; added a connection point in the middle of each
5 * segment. C.Chepelov, january 2000.
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.
27 #include <string.h> /* memcpy() */
29 #include "neworth_conn.h"
30 #include "connectionpoint.h"
34 #include "diarenderer.h"
36 static void place_handle_by_swapping(NewOrthConn
*orth
,
37 int index
, Handle
*handle
);
45 midsegment_create_change(NewOrthConn
*orth
, enum change_type type
,
47 Point
*point1
, Point
*point2
,
48 Handle
*handle1
, Handle
*handle2
);
50 struct MidSegmentChange
{
51 ObjectChange obj_change
;
53 /* All additions and deletions of segments in the middle
54 * of the NewOrthConn must delete/add two segments to keep
55 * the horizontal/vertical balance.
57 * None of the end segments must be removed by this change.
60 enum change_type type
;
65 Handle
*handles
[2]; /* These handles cannot be connected */
66 ConnectionPoint
*conn
; /* ? */
67 ObjectChange
*cplchange
[2];
71 endsegment_create_change(NewOrthConn
*orth
, enum change_type type
,
72 int segment
, Point
*point
,
75 struct EndSegmentChange
{
76 ObjectChange obj_change
;
78 /* Additions and deletions of segments of at the endpoints
81 * Addition of an endpoint segment need not store any point.
82 * Deletion of an endpoint segment need to store the endpoint position
83 * so that it can be reverted.
84 * Deleted segments might be connected, so we must store the connection
88 enum change_type type
;
94 Handle
*old_end_handle
;
95 ConnectionPoint
*cp
; /* NULL in add segment and if not connected in
97 ObjectChange
*cplchange
;
101 static void set_midpoint(Point
*point
, NewOrthConn
*orth
, int segment
)
104 point
->x
= 0.5*(orth
->points
[i
].x
+ orth
->points
[i
+1].x
);
105 point
->y
= 0.5*(orth
->points
[i
].y
+ orth
->points
[i
+1].y
);
108 static void setup_midpoint_handle(Handle
*handle
)
110 handle
->id
= HANDLE_MIDPOINT
;
111 handle
->type
= HANDLE_MINOR_CONTROL
;
112 handle
->connect_type
= HANDLE_NONCONNECTABLE
;
113 handle
->connected_to
= NULL
;
116 static void setup_endpoint_handle(Handle
*handle
, HandleId id
)
119 handle
->type
= HANDLE_MAJOR_CONTROL
;
120 handle
->connect_type
= HANDLE_CONNECTABLE
;
121 handle
->connected_to
= NULL
;
124 static int get_handle_nr(NewOrthConn
*orth
, Handle
*handle
)
127 for (i
=0;i
<orth
->numpoints
-1;i
++) {
128 if (orth
->handles
[i
] == handle
)
134 static int get_segment_nr(NewOrthConn
*orth
, Point
*point
, real max_dist
)
138 real distance
, tmp_dist
;
141 distance
= distance_line_point(&orth
->points
[0], &orth
->points
[1], 0, point
);
143 for (i
=1;i
<orth
->numpoints
-1;i
++) {
144 tmp_dist
= distance_line_point(&orth
->points
[i
], &orth
->points
[i
+1], 0, point
);
145 if (tmp_dist
< distance
) {
151 if (distance
< max_dist
)
159 neworthconn_move_handle(NewOrthConn
*orth
, Handle
*handle
,
160 Point
*to
, HandleMoveReason reason
)
166 case HANDLE_MOVE_STARTPOINT
:
167 orth
->points
[0] = *to
;
168 switch (orth
->orientation
[0]) {
170 orth
->points
[1].y
= to
->y
;
173 orth
->points
[1].x
= to
->x
;
177 case HANDLE_MOVE_ENDPOINT
:
178 n
= orth
->numpoints
- 1;
179 orth
->points
[n
] = *to
;
180 switch (orth
->orientation
[n
-1]) {
182 orth
->points
[n
-1].y
= to
->y
;
185 orth
->points
[n
-1].x
= to
->x
;
189 case HANDLE_MIDPOINT
:
190 n
= orth
->numpoints
- 1;
191 handle_nr
= get_handle_nr(orth
, handle
);
193 switch (orth
->orientation
[handle_nr
]) {
195 orth
->points
[handle_nr
].y
= to
->y
;
196 orth
->points
[handle_nr
+1].y
= to
->y
;
199 orth
->points
[handle_nr
].x
= to
->x
;
200 orth
->points
[handle_nr
+1].x
= to
->x
;
205 message_error("Internal error in neworthconn_move_handle.\n");
211 neworthconn_move(NewOrthConn
*orth
, Point
*to
)
217 point_sub(&p
, &orth
->points
[0]);
219 orth
->points
[0] = *to
;
220 for (i
=1;i
<orth
->numpoints
;i
++) {
221 point_add(&orth
->points
[i
], &p
);
226 neworthconn_distance_from(NewOrthConn
*orth
, Point
*point
, real line_width
)
231 dist
= distance_line_point( &orth
->points
[0], &orth
->points
[1],
233 for (i
=1;i
<orth
->numpoints
-1;i
++) {
235 distance_line_point( &orth
->points
[i
], &orth
->points
[i
+1],
242 neworthconn_update_midpoints(NewOrthConn
*orth
)
247 elem
=orth
->midpoints
->connections
;
249 /* Update connection points, using the handles' positions where useful : */
250 set_midpoint(&((ConnectionPoint
*)(elem
->data
))->pos
,orth
,0);
251 elem
=g_slist_next(elem
);
252 for (i
=1; i
<orth
->numpoints
-2; i
++) {
253 ((ConnectionPoint
*)(elem
->data
))->pos
= orth
->handles
[i
]->pos
;
254 elem
= g_slist_next(elem
);
256 set_midpoint(&(((ConnectionPoint
*)(elem
->data
))->pos
),orth
,i
);
263 adjust_handle_count_to(NewOrthConn
*orth
, guint count
) {
264 /* This will shrink or expand orth->handles as necessary (so that
265 orth->numhandles matches orth->numpoints-1, most probably), by adding or
266 removing minor handles and keeping the endpoint handles at the
267 extremities of the array. */
269 if (orth
->numhandles
== count
) return;
270 if (orth
->numhandles
< count
) { /* adding */
272 orth
->handles
= g_realloc(orth
->handles
,
273 (count
)*sizeof(Handle
*));
274 orth
->handles
[count
-1] = orth
->handles
[orth
->numhandles
-1];
275 orth
->handles
[orth
->numhandles
-1] = NULL
;
276 for (i
=orth
->numhandles
-1; i
<count
-1; i
++) {
277 Handle
*handle
= g_new0(Handle
,1);
278 setup_midpoint_handle(handle
);
279 object_add_handle(&orth
->object
,handle
);
280 orth
->handles
[i
] = handle
;
282 } else { /* removing */
284 for (i
=count
-1; i
<orth
->numhandles
-1; i
++) {
285 Handle
*handle
= orth
->handles
[i
];
286 object_remove_handle(&orth
->object
,handle
);
288 orth
->handles
[i
] = NULL
;
290 orth
->handles
[count
-1] = orth
->handles
[orth
->numhandles
-1];
291 orth
->handles
[orth
->numhandles
-1] = NULL
;
292 orth
->handles
= g_realloc(orth
->handles
,
293 (count
)*sizeof(Handle
*));
295 orth
->numhandles
= count
;
296 /* handles' positions will be set now */
301 neworthconn_update_data(NewOrthConn
*orth
)
304 Object
*obj
= (Object
*)orth
;
307 g_warning("This NewOrthConn object is very sick !");
310 obj
->position
= orth
->points
[0];
312 adjust_handle_count_to(orth
,orth
->numpoints
-1);
313 connpointline_adjust_count(orth
->midpoints
,orth
->numpoints
-1,NULL
);
315 /* Make sure start-handle is first and end-handle is second. */
316 place_handle_by_swapping(orth
, 0, orth
->handles
[0]);
317 place_handle_by_swapping(orth
, 1, orth
->handles
[orth
->numpoints
-2]);
319 /* Update handles : */
320 orth
->handles
[0]->pos
= orth
->points
[0];
321 orth
->handles
[orth
->numpoints
-2]->pos
= orth
->points
[orth
->numpoints
-1];
323 for (i
=1;i
<orth
->numpoints
-2;i
++) {
324 set_midpoint(&orth
->handles
[i
]->pos
, orth
, i
);
326 neworthconn_update_midpoints(orth
);
330 neworthconn_update_boundingbox(NewOrthConn
*orth
)
332 assert(orth
!= NULL
);
334 polyline_bbox(&orth
->points
[0],
336 &orth
->extra_spacing
, FALSE
,
337 &orth
->object
.bounding_box
);
341 neworthconn_simple_draw(NewOrthConn
*orth
, DiaRenderer
*renderer
, real width
)
345 assert(orth
!= NULL
);
346 assert(renderer
!= NULL
);
349 g_warning("This NewOrthConn object is very sick !");
353 points
= &orth
->points
[0];
355 DIA_RENDERER_GET_CLASS(renderer
)->set_linewidth(renderer
, width
);
356 DIA_RENDERER_GET_CLASS(renderer
)->set_linestyle(renderer
, LINESTYLE_SOLID
);
357 DIA_RENDERER_GET_CLASS(renderer
)->set_linejoin(renderer
, LINEJOIN_MITER
);
358 DIA_RENDERER_GET_CLASS(renderer
)->set_linecaps(renderer
, LINECAPS_BUTT
);
360 DIA_RENDERER_GET_CLASS(renderer
)->draw_polyline(renderer
, points
, orth
->numpoints
,
366 neworthconn_can_delete_segment(NewOrthConn
*orth
, Point
*clickedpoint
)
370 /* Cannot delete any segments when there are only two left,
371 * and not amy middle segment if there are only three segments.
374 if (orth
->numpoints
==3)
377 segment
= get_segment_nr(orth
, clickedpoint
, 1.0);
382 if ( (segment
!= 0) && (segment
!= orth
->numpoints
-2)) {
384 if (orth
->numpoints
==4)
392 neworthconn_can_add_segment(NewOrthConn
*orth
, Point
*clickedpoint
)
394 int segment
= get_segment_nr(orth
, clickedpoint
, 1000000.0);
402 /* Needs to have at least 2 handles.
403 The handles are stored in order in the NewOrthConn, but need
404 not be stored in order in the Object.handles array. This
405 is so that derived object can do what they want with
409 neworthconn_init(NewOrthConn
*orth
, Point
*startpoint
)
415 object_init(obj
, 3, 0);
418 orth
->numorient
= orth
->numpoints
- 1;
419 orth
->numhandles
= 3;
421 orth
->points
= g_malloc(4*sizeof(Point
));
422 orth
->orientation
= g_malloc(3*sizeof(Orientation
));
423 orth
->handles
= g_malloc(3*sizeof(Handle
*));
425 orth
->handles
[0] = g_new(Handle
, 1);
426 setup_endpoint_handle(orth
->handles
[0], HANDLE_MOVE_STARTPOINT
);
427 obj
->handles
[0] = orth
->handles
[0];
429 orth
->handles
[1] = g_new(Handle
, 1);
430 setup_midpoint_handle(orth
->handles
[1]);
431 obj
->handles
[1] = orth
->handles
[1];
433 orth
->handles
[2] = g_new(Handle
, 1);
434 setup_endpoint_handle(orth
->handles
[2], HANDLE_MOVE_ENDPOINT
);
435 obj
->handles
[2] = orth
->handles
[2];
437 /* Just so we have some position: */
438 orth
->points
[0] = *startpoint
;
439 orth
->points
[1].x
= startpoint
->x
;
440 orth
->points
[1].y
= startpoint
->y
+ 1.0;
441 orth
->points
[2].x
= startpoint
->x
+ 1.0;
442 orth
->points
[2].y
= startpoint
->y
+ 1.0;
443 orth
->points
[3].x
= startpoint
->x
+ 2.0;
444 orth
->points
[3].y
= startpoint
->y
+ 1.0;
446 orth
->orientation
[0] = VERTICAL
;
447 orth
->orientation
[1] = HORIZONTAL
;
448 orth
->orientation
[2] = VERTICAL
;
450 orth
->midpoints
= connpointline_create(obj
,3);
452 neworthconn_update_data(orth
);
456 neworthconn_copy(NewOrthConn
*from
, NewOrthConn
*to
)
459 Object
*toobj
, *fromobj
;
462 fromobj
= &from
->object
;
464 object_copy(fromobj
, toobj
);
466 to
->numpoints
= from
->numpoints
;
467 to
->numorient
= from
->numorient
;
468 to
->numhandles
= from
->numhandles
;
470 to
->points
= g_malloc((to
->numpoints
)*sizeof(Point
));
472 for (i
=0;i
<to
->numpoints
;i
++) {
473 to
->points
[i
] = from
->points
[i
];
476 to
->orientation
= g_malloc((to
->numpoints
-1)*sizeof(Orientation
));
477 to
->handles
= g_malloc((to
->numpoints
-1)*sizeof(Handle
*));
479 for (i
=0;i
<to
->numpoints
-1;i
++) {
480 to
->orientation
[i
] = from
->orientation
[i
];
481 to
->handles
[i
] = g_new(Handle
,1);
482 *to
->handles
[i
] = *from
->handles
[i
];
483 to
->handles
[i
]->connected_to
= NULL
;
484 toobj
->handles
[i
] = to
->handles
[i
];
487 to
->midpoints
= connpointline_copy(toobj
,from
->midpoints
,&rcc
);
488 memcpy(&to
->extra_spacing
,&from
->extra_spacing
,sizeof(to
->extra_spacing
));
493 neworthconn_destroy(NewOrthConn
*orth
)
497 connpointline_destroy(orth
->midpoints
);
498 object_destroy(&orth
->object
);
500 g_free(orth
->points
);
501 g_free(orth
->orientation
);
503 for (i
=0;i
<orth
->numpoints
-1;i
++) {
504 g_free(orth
->handles
[i
]);
506 g_free(orth
->handles
);
510 place_handle_by_swapping(NewOrthConn
*orth
, int index
, Handle
*handle
)
516 obj
= (Object
*)orth
;
517 if (obj
->handles
[index
] == handle
)
518 return; /* Nothing to do */
520 for (j
=0;j
<obj
->num_handles
;j
++) {
521 if (obj
->handles
[j
] == handle
) {
522 /* Swap handle j and index */
523 tmp
= obj
->handles
[j
];
524 obj
->handles
[j
] = obj
->handles
[index
];
525 obj
->handles
[index
] = tmp
;
533 neworthconn_save(NewOrthConn
*orth
, ObjectNode obj_node
)
538 /* Make sure start-handle is first and end-handle is second. */
539 place_handle_by_swapping(orth
, 0, orth
->handles
[0]);
540 place_handle_by_swapping(orth
, 1, orth
->handles
[orth
->numpoints
-2]);
542 object_save(&orth
->object
, obj_node
);
544 attr
= new_attribute(obj_node
, "orth_points");
546 for (i
=0;i
<orth
->numpoints
;i
++) {
547 data_add_point(attr
, &orth
->points
[i
]);
550 attr
= new_attribute(obj_node
, "orth_orient");
551 for (i
=0;i
<orth
->numpoints
-1;i
++) {
552 data_add_enum(attr
, orth
->orientation
[i
]);
557 neworthconn_load(NewOrthConn
*orth
, ObjectNode obj_node
) /* NOTE: Does object_init() */
564 Object
*obj
= &orth
->object
;
566 object_load(obj
, obj_node
);
568 attr
= object_find_attribute(obj_node
, "orth_points");
571 orth
->numpoints
= attribute_num_data(attr
);
575 object_init(obj
, orth
->numpoints
-1,0);
577 orth
->numorient
= orth
->numpoints
- 1;
579 data
= attribute_first_data(attr
);
580 orth
->points
= g_malloc((orth
->numpoints
)*sizeof(Point
));
581 for (i
=0;i
<orth
->numpoints
;i
++) {
582 data_point(data
, &orth
->points
[i
]);
583 data
= data_next(data
);
586 attr
= object_find_attribute(obj_node
, "orth_orient");
588 data
= attribute_first_data(attr
);
589 orth
->orientation
= g_malloc((orth
->numpoints
-1)*sizeof(Orientation
));
590 for (i
=0;i
<orth
->numpoints
-1;i
++) {
591 orth
->orientation
[i
] = data_enum(data
);
592 data
= data_next(data
);
595 orth
->handles
= g_malloc((orth
->numpoints
-1)*sizeof(Handle
*));
597 orth
->handles
[0] = g_new(Handle
, 1);
598 setup_endpoint_handle(orth
->handles
[0], HANDLE_MOVE_STARTPOINT
);
599 orth
->handles
[0]->pos
= orth
->points
[0];
600 obj
->handles
[0] = orth
->handles
[0];
602 n
= orth
->numpoints
-2;
603 orth
->handles
[n
] = g_new(Handle
, 1);
604 setup_endpoint_handle(orth
->handles
[n
], HANDLE_MOVE_ENDPOINT
);
605 orth
->handles
[n
]->pos
= orth
->points
[orth
->numpoints
-1];
606 obj
->handles
[1] = orth
->handles
[n
];
608 for (i
=1; i
<orth
->numpoints
-2; i
++) {
609 orth
->handles
[i
] = g_new(Handle
, 1);
610 setup_midpoint_handle(orth
->handles
[i
]);
611 obj
->handles
[i
+1] = orth
->handles
[i
];
613 orth
->numhandles
= orth
->numpoints
-1;
614 orth
->midpoints
= connpointline_create(obj
,orth
->numpoints
-1);
616 neworthconn_update_data(orth
);
620 neworthconn_get_middle_handle( NewOrthConn
*orth
)
622 int n
= orth
->numpoints
- 1 ;
623 return orth
->handles
[ n
/2 ] ;
627 neworthconn_delete_segment(NewOrthConn
*orth
, Point
*clickedpoint
)
630 ObjectChange
*change
= NULL
;
632 if (orth
->numpoints
==3)
635 segment
= get_segment_nr(orth
, clickedpoint
, 1.0);
640 change
= endsegment_create_change(orth
, TYPE_REMOVE_SEGMENT
, segment
,
641 &orth
->points
[segment
],
642 orth
->handles
[segment
]);
643 } else if (segment
== orth
->numpoints
-2) {
644 change
= endsegment_create_change(orth
, TYPE_REMOVE_SEGMENT
, segment
,
645 &orth
->points
[segment
+1],
646 orth
->handles
[segment
]);
647 } else if (segment
> 0) {
648 /* Don't delete the last midpoint segment.
649 * That would delete also the endpoint segment after it.
651 if (segment
== orth
->numpoints
-3)
654 change
= midsegment_create_change(orth
, TYPE_REMOVE_SEGMENT
, segment
,
655 &orth
->points
[segment
],
656 &orth
->points
[segment
+1],
657 orth
->handles
[segment
],
658 orth
->handles
[segment
+1]);
661 change
->apply(change
, (Object
*)orth
);
667 neworthconn_add_segment(NewOrthConn
*orth
, Point
*clickedpoint
)
669 Handle
*handle1
, *handle2
;
670 ObjectChange
*change
= NULL
;
674 segment
= get_segment_nr(orth
, clickedpoint
, 1.0);
678 if (segment
==0) { /* First segment */
679 handle1
= g_new(Handle
, 1);
680 setup_endpoint_handle(handle1
, HANDLE_MOVE_STARTPOINT
);
681 change
= endsegment_create_change(orth
, TYPE_ADD_SEGMENT
,
684 } else if (segment
== orth
->numpoints
-2) { /* Last segment */
685 handle1
= g_new(Handle
, 1);
686 setup_endpoint_handle(handle1
, HANDLE_MOVE_ENDPOINT
);
687 change
= endsegment_create_change(orth
, TYPE_ADD_SEGMENT
,
688 segment
+1, &orth
->points
[segment
+1],
690 } else if (segment
> 0) {
691 handle1
= g_new(Handle
, 1);
692 setup_midpoint_handle(handle1
);
693 handle2
= g_new(Handle
, 1);
694 setup_midpoint_handle(handle2
);
695 newpoint
= *clickedpoint
;
696 if (orth
->orientation
[segment
]==HORIZONTAL
)
697 newpoint
.y
= orth
->points
[segment
].y
;
699 newpoint
.x
= orth
->points
[segment
].x
;
701 change
= midsegment_create_change(orth
, TYPE_ADD_SEGMENT
, segment
,
708 change
->apply(change
, (Object
*)orth
);
714 delete_point(NewOrthConn
*orth
, int pos
)
719 orth
->numorient
= orth
->numpoints
- 1;
721 for (i
=pos
;i
<orth
->numpoints
;i
++) {
722 orth
->points
[i
] = orth
->points
[i
+1];
725 orth
->points
= g_realloc(orth
->points
, orth
->numpoints
*sizeof(Point
));
728 /* Make sure numpoints have been decreased before calling this function.
729 * ie. call delete_point first.
732 remove_handle(NewOrthConn
*orth
, int segment
)
737 handle
= orth
->handles
[segment
];
739 for (i
=segment
; i
< orth
->numpoints
-1; i
++) {
740 orth
->handles
[i
] = orth
->handles
[i
+1];
741 orth
->orientation
[i
] = orth
->orientation
[i
+1];
744 orth
->orientation
= g_realloc(orth
->orientation
,
745 (orth
->numpoints
-1)*sizeof(Orientation
));
746 orth
->handles
= g_realloc(orth
->handles
,
747 (orth
->numpoints
-1)*sizeof(Handle
*));
749 object_remove_handle(&orth
->object
, handle
);
750 orth
->numhandles
= orth
->numpoints
-1;
755 add_point(NewOrthConn
*orth
, int pos
, Point
*point
)
760 orth
->numorient
= orth
->numpoints
-1;
762 orth
->points
= g_realloc(orth
->points
, orth
->numpoints
*sizeof(Point
));
763 for (i
=orth
->numpoints
-1;i
>pos
;i
--) {
764 orth
->points
[i
] = orth
->points
[i
-1];
766 orth
->points
[pos
] = *point
;
769 /* Make sure numpoints have been increased before calling this function.
770 * ie. call add_point first.
773 insert_handle(NewOrthConn
*orth
, int segment
,
774 Handle
*handle
, Orientation orient
)
778 orth
->orientation
= g_realloc(orth
->orientation
,
779 (orth
->numpoints
-1)*sizeof(Orientation
));
780 orth
->handles
= g_realloc(orth
->handles
,
781 (orth
->numpoints
-1)*sizeof(Handle
*));
782 for (i
=orth
->numpoints
-2;i
>segment
;i
--) {
783 orth
->handles
[i
] = orth
->handles
[i
-1];
784 orth
->orientation
[i
] = orth
->orientation
[i
-1];
786 orth
->handles
[segment
] = handle
;
787 orth
->orientation
[segment
] = orient
;
789 object_add_handle(&orth
->object
, handle
);
790 orth
->numhandles
= orth
->numpoints
-1;
796 endsegment_change_free(struct EndSegmentChange
*change
)
798 if ( (change
->type
==TYPE_ADD_SEGMENT
&& !change
->applied
) ||
799 (change
->type
==TYPE_REMOVE_SEGMENT
&& change
->applied
) ){
801 g_free(change
->handle
);
802 change
->handle
= NULL
;
804 if (change
->cplchange
) {
805 if (change
->cplchange
->free
) change
->cplchange
->free(change
->cplchange
);
806 g_free(change
->cplchange
);
807 change
->cplchange
= NULL
;
812 endsegment_change_apply(struct EndSegmentChange
*change
, Object
*obj
)
814 NewOrthConn
*orth
= (NewOrthConn
*)obj
;
818 switch (change
->type
) {
819 case TYPE_ADD_SEGMENT
:
820 object_unconnect(obj
, change
->old_end_handle
);
821 if (change
->segment
==0) { /* first */
822 add_point(orth
, 0, &change
->point
);
823 insert_handle(orth
, change
->segment
,
824 change
->handle
, FLIP_ORIENT(orth
->orientation
[0]) );
825 setup_midpoint_handle(orth
->handles
[1]);
826 obj
->position
= orth
->points
[0];
827 change
->cplchange
= connpointline_add_point(orth
->midpoints
,
830 add_point(orth
, orth
->numpoints
, &change
->point
);
831 insert_handle(orth
, change
->segment
, change
->handle
,
832 FLIP_ORIENT(orth
->orientation
[orth
->numpoints
-3]) );
833 setup_midpoint_handle(orth
->handles
[orth
->numpoints
-3]);
834 change
->cplchange
= connpointline_add_point(orth
->midpoints
,
835 &orth
->midpoints
->end
);
838 case TYPE_REMOVE_SEGMENT
:
839 object_unconnect(obj
, change
->old_end_handle
);
841 connpointline_remove_point(orth
->midpoints
,
842 &orth
->points
[change
->segment
]);
843 if (change
->segment
==0) { /* first */
844 delete_point(orth
, 0);
845 remove_handle(orth
, 0);
846 setup_endpoint_handle(orth
->handles
[0], HANDLE_MOVE_STARTPOINT
);
847 obj
->position
= orth
->points
[0];
849 delete_point(orth
, orth
->numpoints
-1);
850 remove_handle(orth
, change
->segment
);
851 setup_endpoint_handle(orth
->handles
[orth
->numpoints
-2],
852 HANDLE_MOVE_ENDPOINT
);
856 neworthconn_update_midpoints(orth
); /* useless ? */
860 endsegment_change_revert(struct EndSegmentChange
*change
, Object
*obj
)
862 NewOrthConn
*orth
= (NewOrthConn
*)obj
;
864 change
->cplchange
->revert(change
->cplchange
,obj
);
865 switch (change
->type
) {
866 case TYPE_ADD_SEGMENT
:
867 object_unconnect(obj
, change
->handle
);
868 if (change
->segment
==0) { /* first */
869 delete_point(orth
, 0);
870 remove_handle(orth
, 0);
871 setup_endpoint_handle(orth
->handles
[0], HANDLE_MOVE_STARTPOINT
);
872 obj
->position
= orth
->points
[0];
874 delete_point(orth
, orth
->numpoints
-1);
875 remove_handle(orth
, change
->segment
);
876 setup_endpoint_handle(orth
->handles
[orth
->numpoints
-2],
877 HANDLE_MOVE_ENDPOINT
);
880 case TYPE_REMOVE_SEGMENT
:
881 if (change
->segment
==0) { /* first */
882 add_point(orth
, 0, &change
->point
);
883 insert_handle(orth
, change
->segment
,
884 change
->handle
, FLIP_ORIENT(orth
->orientation
[0]) );
885 setup_midpoint_handle(orth
->handles
[1]);
886 obj
->position
= orth
->points
[0];
888 add_point(orth
, orth
->numpoints
, &change
->point
);
889 insert_handle(orth
, change
->segment
, change
->handle
,
890 FLIP_ORIENT(orth
->orientation
[orth
->numpoints
-3]) );
891 setup_midpoint_handle(orth
->handles
[orth
->numpoints
-3]);
896 neworthconn_update_midpoints(orth
); /* useless ? */
899 static ObjectChange
*
900 endsegment_create_change(NewOrthConn
*orth
, enum change_type type
,
901 int segment
, Point
*point
,
904 struct EndSegmentChange
*change
;
906 change
= g_new0(struct EndSegmentChange
, 1);
908 change
->obj_change
.apply
= (ObjectChangeApplyFunc
) endsegment_change_apply
;
909 change
->obj_change
.revert
= (ObjectChangeRevertFunc
) endsegment_change_revert
;
910 change
->obj_change
.free
= (ObjectChangeFreeFunc
) endsegment_change_free
;
914 change
->segment
= segment
;
915 change
->point
= *point
;
916 change
->handle
= handle
;
918 change
->old_end_handle
= orth
->handles
[0];
920 change
->old_end_handle
= orth
->handles
[orth
->numpoints
-2];
921 change
->cp
= change
->old_end_handle
->connected_to
;
922 return (ObjectChange
*)change
;
927 midsegment_change_free(struct MidSegmentChange
*change
)
929 if ( (change
->type
==TYPE_ADD_SEGMENT
&& !change
->applied
) ||
930 (change
->type
==TYPE_REMOVE_SEGMENT
&& change
->applied
) ){
931 if (change
->handles
[0])
932 g_free(change
->handles
[0]);
933 change
->handles
[0] = NULL
;
934 if (change
->handles
[1])
935 g_free(change
->handles
[1]);
936 change
->handles
[1] = NULL
;
939 if (change
->cplchange
[0]) {
940 if (change
->cplchange
[0]->free
)
941 change
->cplchange
[0]->free(change
->cplchange
[0]);
942 g_free(change
->cplchange
[0]);
943 change
->cplchange
[0] = NULL
;
945 if (change
->cplchange
[1]) {
946 if (change
->cplchange
[1]->free
)
947 change
->cplchange
[1]->free(change
->cplchange
[1]);
948 g_free(change
->cplchange
[1]);
949 change
->cplchange
[1] = NULL
;
954 midsegment_change_apply(struct MidSegmentChange
*change
, Object
*obj
)
956 NewOrthConn
*orth
= (NewOrthConn
*)obj
;
961 switch (change
->type
) {
962 case TYPE_ADD_SEGMENT
:
963 add_point(orth
, change
->segment
+1, &change
->points
[1]);
964 add_point(orth
, change
->segment
+1, &change
->points
[0]);
965 insert_handle(orth
, change
->segment
+1, change
->handles
[1],
966 orth
->orientation
[change
->segment
] );
967 insert_handle(orth
, change
->segment
+1, change
->handles
[0],
968 FLIP_ORIENT(orth
->orientation
[change
->segment
]) );
969 change
->cplchange
[0] =
970 connpointline_add_point(orth
->midpoints
,&change
->points
[0]);
971 change
->cplchange
[1] =
972 connpointline_add_point(orth
->midpoints
,&change
->points
[1]);
974 case TYPE_REMOVE_SEGMENT
:
975 seg
= change
->segment
?change
->segment
:1;
976 change
->cplchange
[0] =
977 connpointline_remove_point(orth
->midpoints
,
978 &orth
->points
[seg
-1]);
979 change
->cplchange
[1] =
980 connpointline_remove_point(orth
->midpoints
,
982 delete_point(orth
, change
->segment
);
983 remove_handle(orth
, change
->segment
);
984 delete_point(orth
, change
->segment
);
985 remove_handle(orth
, change
->segment
);
986 if (orth
->orientation
[change
->segment
]==HORIZONTAL
) {
987 orth
->points
[change
->segment
].x
= change
->points
[0].x
;
989 orth
->points
[change
->segment
].y
= change
->points
[0].y
;
993 neworthconn_update_midpoints(orth
); /* useless ? */
997 midsegment_change_revert(struct MidSegmentChange
*change
, Object
*obj
)
999 NewOrthConn
*orth
= (NewOrthConn
*)obj
;
1001 change
->cplchange
[0]->revert(change
->cplchange
[0],obj
);
1002 change
->cplchange
[1]->revert(change
->cplchange
[1],obj
);
1004 switch (change
->type
) {
1005 case TYPE_ADD_SEGMENT
:
1006 delete_point(orth
, change
->segment
+1);
1007 remove_handle(orth
, change
->segment
+1);
1008 delete_point(orth
, change
->segment
+1);
1009 remove_handle(orth
, change
->segment
+1);
1011 case TYPE_REMOVE_SEGMENT
:
1012 if (orth
->orientation
[change
->segment
]==HORIZONTAL
) {
1013 orth
->points
[change
->segment
].x
= change
->points
[1].x
;
1015 orth
->points
[change
->segment
].y
= change
->points
[1].y
;
1017 add_point(orth
, change
->segment
, &change
->points
[1]);
1018 add_point(orth
, change
->segment
, &change
->points
[0]);
1019 insert_handle(orth
, change
->segment
, change
->handles
[1],
1020 orth
->orientation
[change
->segment
-1] );
1021 insert_handle(orth
, change
->segment
, change
->handles
[0],
1022 FLIP_ORIENT(orth
->orientation
[change
->segment
-1]) );
1025 change
->applied
= 0;
1028 static ObjectChange
*
1029 midsegment_create_change(NewOrthConn
*orth
, enum change_type type
,
1031 Point
*point1
, Point
*point2
,
1032 Handle
*handle1
, Handle
*handle2
)
1034 struct MidSegmentChange
*change
;
1036 change
= g_new(struct MidSegmentChange
, 1);
1038 change
->obj_change
.apply
= (ObjectChangeApplyFunc
) midsegment_change_apply
;
1039 change
->obj_change
.revert
= (ObjectChangeRevertFunc
) midsegment_change_revert
;
1040 change
->obj_change
.free
= (ObjectChangeFreeFunc
) midsegment_change_free
;
1042 change
->type
= type
;
1043 change
->applied
= 0;
1044 change
->segment
= segment
;
1045 change
->points
[0] = *point1
;
1046 change
->points
[1] = *point2
;
1047 change
->handles
[0] = handle1
;
1048 change
->handles
[1] = handle2
;
1050 return (ObjectChange
*)change
;