* added GDK_PIXBUF_LIBS in order to create pixbuf.dll
[dia.git] / lib / neworth_conn.c
bloba39c7c9e4e967a81c6389fad27405a747b28c438
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.
21 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <assert.h>
26 #include <math.h>
27 #include <string.h> /* memcpy() */
29 #include "neworth_conn.h"
30 #include "connectionpoint.h"
31 #include "message.h"
32 #include "diamenu.h"
33 #include "handle.h"
34 #include "diarenderer.h"
36 static void place_handle_by_swapping(NewOrthConn *orth,
37 int index, Handle *handle);
39 enum change_type {
40 TYPE_ADD_SEGMENT,
41 TYPE_REMOVE_SEGMENT
44 static ObjectChange *
45 midsegment_create_change(NewOrthConn *orth, enum change_type type,
46 int segment,
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;
61 int applied;
63 int segment;
64 Point points[2];
65 Handle *handles[2]; /* These handles cannot be connected */
66 ConnectionPoint *conn; /* ? */
67 ObjectChange *cplchange[2];
70 static ObjectChange *
71 endsegment_create_change(NewOrthConn *orth, enum change_type type,
72 int segment, Point *point,
73 Handle *handle);
75 struct EndSegmentChange {
76 ObjectChange obj_change;
78 /* Additions and deletions of segments of at the endpoints
79 * of the NewOrthConn.
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
85 * point.
88 enum change_type type;
89 int applied;
91 int segment;
92 Point point;
93 Handle *handle;
94 Handle *old_end_handle;
95 ConnectionPoint *cp; /* NULL in add segment and if not connected in
96 remove segment */
97 ObjectChange *cplchange;
101 static void set_midpoint(Point *point, NewOrthConn *orth, int segment)
103 int i = 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 )
118 handle->id = 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)
126 int i = 0;
127 for (i=0;i<orth->numpoints-1;i++) {
128 if (orth->handles[i] == handle)
129 return i;
131 return -1;
134 static int get_segment_nr(NewOrthConn *orth, Point *point, real max_dist)
136 int i;
137 int segment;
138 real distance, tmp_dist;
140 segment = 0;
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) {
146 segment = i;
147 distance = tmp_dist;
151 if (distance < max_dist)
152 return segment;
154 return -1;
158 void
159 neworthconn_move_handle(NewOrthConn *orth, Handle *handle,
160 Point *to, HandleMoveReason reason)
162 int n;
163 int handle_nr;
165 switch(handle->id) {
166 case HANDLE_MOVE_STARTPOINT:
167 orth->points[0] = *to;
168 switch (orth->orientation[0]) {
169 case HORIZONTAL:
170 orth->points[1].y = to->y;
171 break;
172 case VERTICAL:
173 orth->points[1].x = to->x;
174 break;
176 break;
177 case HANDLE_MOVE_ENDPOINT:
178 n = orth->numpoints - 1;
179 orth->points[n] = *to;
180 switch (orth->orientation[n-1]) {
181 case HORIZONTAL:
182 orth->points[n-1].y = to->y;
183 break;
184 case VERTICAL:
185 orth->points[n-1].x = to->x;
186 break;
188 break;
189 case HANDLE_MIDPOINT:
190 n = orth->numpoints - 1;
191 handle_nr = get_handle_nr(orth, handle);
193 switch (orth->orientation[handle_nr]) {
194 case HORIZONTAL:
195 orth->points[handle_nr].y = to->y;
196 orth->points[handle_nr+1].y = to->y;
197 break;
198 case VERTICAL:
199 orth->points[handle_nr].x = to->x;
200 orth->points[handle_nr+1].x = to->x;
201 break;
203 break;
204 default:
205 message_error("Internal error in neworthconn_move_handle.\n");
206 break;
210 void
211 neworthconn_move(NewOrthConn *orth, Point *to)
213 Point p;
214 int i;
216 p = *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);
225 real
226 neworthconn_distance_from(NewOrthConn *orth, Point *point, real line_width)
228 int i;
229 real dist;
231 dist = distance_line_point( &orth->points[0], &orth->points[1],
232 line_width, point);
233 for (i=1;i<orth->numpoints-1;i++) {
234 dist = MIN(dist,
235 distance_line_point( &orth->points[i], &orth->points[i+1],
236 line_width, point));
238 return dist;
241 static void
242 neworthconn_update_midpoints(NewOrthConn *orth)
244 int i;
245 GSList *elem;
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);
262 static void
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 */
271 int i;
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 */
283 int i;
284 for (i=count-1; i<orth->numhandles-1; i++) {
285 Handle *handle = orth->handles[i];
286 object_remove_handle(&orth->object,handle);
287 g_free(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 */
300 void
301 neworthconn_update_data(NewOrthConn *orth)
303 int i;
304 Object *obj = (Object *)orth;
306 if (!orth->points) {
307 g_warning("This NewOrthConn object is very sick !");
308 return;
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);
329 void
330 neworthconn_update_boundingbox(NewOrthConn *orth)
332 assert(orth != NULL);
334 polyline_bbox(&orth->points[0],
335 orth->numpoints,
336 &orth->extra_spacing, FALSE,
337 &orth->object.bounding_box);
340 void
341 neworthconn_simple_draw(NewOrthConn *orth, DiaRenderer *renderer, real width)
343 Point *points;
345 assert(orth != NULL);
346 assert(renderer != NULL);
348 if (!orth->points) {
349 g_warning("This NewOrthConn object is very sick !");
350 return;
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,
361 &color_black);
366 neworthconn_can_delete_segment(NewOrthConn *orth, Point *clickedpoint)
368 int segment;
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)
375 return 0;
377 segment = get_segment_nr(orth, clickedpoint, 1.0);
379 if (segment<0)
380 return 0;
382 if ( (segment != 0) && (segment != orth->numpoints-2)) {
383 /* middle segment */
384 if (orth->numpoints==4)
385 return 0;
388 return 1;
392 neworthconn_can_add_segment(NewOrthConn *orth, Point *clickedpoint)
394 int segment = get_segment_nr(orth, clickedpoint, 1000000.0);
396 if (segment<0)
397 return 0;
399 return 1;
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
406 Object.handles. */
408 void
409 neworthconn_init(NewOrthConn *orth, Point *startpoint)
411 Object *obj;
413 obj = &orth->object;
415 object_init(obj, 3, 0);
417 orth->numpoints = 4;
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);
455 void
456 neworthconn_copy(NewOrthConn *from, NewOrthConn *to)
458 int i,rcc;
459 Object *toobj, *fromobj;
461 toobj = &to->object;
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];
486 rcc = 0;
487 to->midpoints = connpointline_copy(toobj,from->midpoints,&rcc);
488 memcpy(&to->extra_spacing,&from->extra_spacing,sizeof(to->extra_spacing));
492 void
493 neworthconn_destroy(NewOrthConn *orth)
495 int i;
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);
509 static void
510 place_handle_by_swapping(NewOrthConn *orth, int index, Handle *handle)
512 Object *obj;
513 Handle *tmp;
514 int j;
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;
527 return;
532 void
533 neworthconn_save(NewOrthConn *orth, ObjectNode obj_node)
535 int i;
536 AttributeNode attr;
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]);
556 void
557 neworthconn_load(NewOrthConn *orth, ObjectNode obj_node) /* NOTE: Does object_init() */
559 int i;
560 AttributeNode attr;
561 DataNode data;
562 int n;
564 Object *obj = &orth->object;
566 object_load(obj, obj_node);
568 attr = object_find_attribute(obj_node, "orth_points");
570 if (attr != NULL)
571 orth->numpoints = attribute_num_data(attr);
572 else
573 orth->numpoints = 0;
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);
619 Handle*
620 neworthconn_get_middle_handle( NewOrthConn *orth )
622 int n = orth->numpoints - 1 ;
623 return orth->handles[ n/2 ] ;
626 ObjectChange *
627 neworthconn_delete_segment(NewOrthConn *orth, Point *clickedpoint)
629 int segment;
630 ObjectChange *change = NULL;
632 if (orth->numpoints==3)
633 return NULL;
635 segment = get_segment_nr(orth, clickedpoint, 1.0);
636 if (segment < 0)
637 return NULL;
639 if (segment==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)
652 segment--;
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);
663 return change;
666 ObjectChange *
667 neworthconn_add_segment(NewOrthConn *orth, Point *clickedpoint)
669 Handle *handle1, *handle2;
670 ObjectChange *change = NULL;
671 int segment;
672 Point newpoint;
674 segment = get_segment_nr(orth, clickedpoint, 1.0);
675 if (segment < 0)
676 return NULL;
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,
682 0, &orth->points[0],
683 handle1);
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],
689 handle1);
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;
698 else
699 newpoint.x = orth->points[segment].x;
701 change = midsegment_create_change(orth, TYPE_ADD_SEGMENT, segment,
702 &newpoint,
703 &newpoint,
704 handle1,
705 handle2);
708 change->apply(change, (Object *)orth);
710 return change;
713 static void
714 delete_point(NewOrthConn *orth, int pos)
716 int i;
718 orth->numpoints--;
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.
731 static void
732 remove_handle(NewOrthConn *orth, int segment)
734 int i;
735 Handle *handle;
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;
754 static void
755 add_point(NewOrthConn *orth, int pos, Point *point)
757 int i;
759 orth->numpoints++;
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.
772 static void
773 insert_handle(NewOrthConn *orth, int segment,
774 Handle *handle, Orientation orient)
776 int i;
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;
795 static void
796 endsegment_change_free(struct EndSegmentChange *change)
798 if ( (change->type==TYPE_ADD_SEGMENT && !change->applied) ||
799 (change->type==TYPE_REMOVE_SEGMENT && change->applied) ){
800 if (change->handle)
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;
811 static void
812 endsegment_change_apply(struct EndSegmentChange *change, Object *obj)
814 NewOrthConn *orth = (NewOrthConn *)obj;
816 change->applied = 1;
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,
828 &change->point);
829 } else { /* last */
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);
837 break;
838 case TYPE_REMOVE_SEGMENT:
839 object_unconnect(obj, change->old_end_handle);
840 change->cplchange =
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];
848 } else { /* last */
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);
854 break;
856 neworthconn_update_midpoints(orth); /* useless ? */
859 static void
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];
873 } else { /* last */
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);
879 break;
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];
887 } else { /* last */
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]);
893 break;
895 change->applied = 0;
896 neworthconn_update_midpoints(orth); /* useless ? */
899 static ObjectChange *
900 endsegment_create_change(NewOrthConn *orth, enum change_type type,
901 int segment, Point *point,
902 Handle *handle)
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;
912 change->type = type;
913 change->applied = 0;
914 change->segment = segment;
915 change->point = *point;
916 change->handle = handle;
917 if (segment == 0)
918 change->old_end_handle = orth->handles[0];
919 else
920 change->old_end_handle = orth->handles[orth->numpoints-2];
921 change->cp = change->old_end_handle->connected_to;
922 return (ObjectChange *)change;
926 static void
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;
953 static void
954 midsegment_change_apply(struct MidSegmentChange *change, Object *obj)
956 NewOrthConn *orth = (NewOrthConn *)obj;
957 int seg;
959 change->applied = 1;
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]);
973 break;
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,
981 &orth->points[seg]);
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;
988 } else {
989 orth->points[change->segment].y = change->points[0].y;
991 break;
993 neworthconn_update_midpoints(orth); /* useless ? */
996 static void
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);
1010 break;
1011 case TYPE_REMOVE_SEGMENT:
1012 if (orth->orientation[change->segment]==HORIZONTAL) {
1013 orth->points[change->segment].x = change->points[1].x;
1014 } else {
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]) );
1023 break;
1025 change->applied = 0;
1028 static ObjectChange *
1029 midsegment_create_change(NewOrthConn *orth, enum change_type type,
1030 int segment,
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;