1 /*
2  * FIG : Facility for Interactive Generation of figures
3  * Copyright (c) 1985-1988 by Supoj Sutanthavibul
4  * Parts Copyright (c) 1989-2007 by Brian V. Smith
5  * Parts Copyright (c) 1991 by Paul King
6  * Parts Copyright (c) 1995 by C. Blanc and C. Schlick
7  *
8  * Any party obtaining a copy of these files is granted, free of charge, a
9  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
10  * nonexclusive right and license to deal in this software and documentation
11  * files (the "Software"), including without limitation the rights to use,
12  * copy, modify, merge, publish, distribute, sublicense and/or sell copies of
13  * the Software, and to permit persons who receive copies from any such
14  * party to do so, with the only requirement being that the above copyright
15  * and this permission notice remain intact.
16  *
17  */
18 
19 #include "fig.h"
20 #include "resources.h"
21 #include "mode.h"
22 #include "object.h"
23 #include "paintop.h"
24 #include "f_read.h"
25 #include "u_create.h"
26 #include "u_list.h"
27 #include "u_elastic.h"
28 #include "u_redraw.h"
29 #include "u_undo.h"
30 #include "w_layers.h"
31 #include "w_setup.h"
32 
33 #include "u_draw.h"
34 #include "u_markers.h"
35 
36 /*************************************/
37 /****** DELETE object from list ******/
38 /*************************************/
39 
40 
41 int point_on_perim (F_point *p, int llx, int lly, int urx, int ury);
42 int point_on_inside (F_point *p, int llx, int lly, int urx, int ury);
43 
44 void
list_delete_arc(F_arc ** arc_list,F_arc * arc)45 list_delete_arc(F_arc **arc_list, F_arc *arc)
46 {
47     F_arc	   *a, *aa;
48 
49     if (*arc_list == NULL)
50 	return;
51     if (arc == NULL)
52 	return;
53 
54     if (arc_list == &objects.arcs)
55 	remove_depth(O_ARC, arc->depth);
56     for (a = aa = *arc_list; aa != NULL; a = aa, aa = aa->next) {
57 	if (aa == arc) {
58 	    if (aa == *arc_list)
59 		*arc_list = (*arc_list)->next;
60 	    else
61 		a->next = aa->next;
62 	    break;
63 	}
64     }
65     arc->next = NULL;
66 }
67 
68 void
list_delete_ellipse(F_ellipse ** ellipse_list,F_ellipse * ellipse)69 list_delete_ellipse(F_ellipse **ellipse_list, F_ellipse *ellipse)
70 {
71     F_ellipse	   *q, *r;
72 
73     if (*ellipse_list == NULL)
74 	return;
75     if (ellipse == NULL)
76 	return;
77 
78     if (ellipse_list == &objects.ellipses)
79 	remove_depth(O_ELLIPSE, ellipse->depth);
80     for (q = r = *ellipse_list; r != NULL; q = r, r = r->next) {
81 	if (r == ellipse) {
82 	    if (r == *ellipse_list)
83 		*ellipse_list = (*ellipse_list)->next;
84 	    else
85 		q->next = r->next;
86 	    break;
87 	}
88     }
89     ellipse->next = NULL;
90 }
91 
92 void
list_delete_line(F_line ** line_list,F_line * line)93 list_delete_line(F_line **line_list, F_line *line)
94 {
95     F_line	   *q, *r;
96 
97     if (*line_list == NULL)
98 	return;
99     if (line == NULL)
100 	return;
101 
102     if (line_list == &objects.lines)
103 	remove_depth(O_POLYLINE, line->depth);
104     for (q = r = *line_list; r != NULL; q = r, r = r->next) {
105 	if (r == line) {
106 	    if (r == *line_list)
107 		*line_list = (*line_list)->next;
108 	    else
109 		q->next = r->next;
110 	    break;
111 	}
112     }
113     line->next = NULL;
114 }
115 
116 void
list_delete_spline(F_spline ** spline_list,F_spline * spline)117 list_delete_spline(F_spline **spline_list, F_spline *spline)
118 {
119     F_spline	   *q, *r;
120 
121     if (*spline_list == NULL)
122 	return;
123     if (spline == NULL)
124 	return;
125 
126     if (spline_list == &objects.splines)
127 	remove_depth(O_SPLINE, spline->depth);
128     for (q = r = *spline_list; r != NULL; q = r, r = r->next) {
129 	if (r == spline) {
130 	    if (r == *spline_list)
131 		*spline_list = (*spline_list)->next;
132 	    else
133 		q->next = r->next;
134 	    break;
135 	}
136     }
137     spline->next = NULL;
138 }
139 
140 void
list_delete_text(F_text ** text_list,F_text * text)141 list_delete_text(F_text **text_list, F_text *text)
142 {
143     F_text	   *q, *r;
144 
145     if (*text_list == NULL)
146 	return;
147     if (text == NULL)
148 	return;
149 
150     if (text_list == &objects.texts)
151 	remove_depth(O_TXT, text->depth);
152     for (q = r = *text_list; r != NULL; q = r, r = r->next)
153 	if (r == text) {
154 	    if (r == *text_list)
155 		*text_list = text->next;
156 	    else
157 		q->next = text->next;
158 	    break;
159 	}
160     text->next = NULL;
161 }
162 
163 void
list_delete_compound(F_compound ** list,F_compound * compound)164 list_delete_compound(F_compound **list, F_compound *compound)
165 {
166     F_compound	   *c, *cc;
167 
168     if (*list == NULL)
169 	return;
170     if (compound == NULL)
171 	return;
172 
173     if (list == &objects.compounds)
174 	remove_compound_depth(compound);
175 
176     for (cc = c = *list; c != NULL; cc = c, c = c->next) {
177 	if (c == compound) {
178 	    if (c == *list)
179 		*list = (*list)->next;
180 	    else
181 		cc->next = c->next;
182 	    break;
183 	}
184     }
185     compound->next = NULL;
186 }
187 
188 void
remove_depth(int type,int depth)189 remove_depth(int type, int depth)
190 {
191     int		    i;
192 
193     object_depths[depth]--;
194     if (appres.DEBUG)
195 	fprintf(stderr,"remove depth %d, count=%d\n",depth,object_depths[depth]);
196     /* now subtract one from the counter for this object type */
197     switch (type) {
198 	case O_ARC:
199 	    --counts[depth].num_arcs;
200 	    if (appres.DEBUG)
201 		fprintf(stderr,"Arc[%d] count=%d\n",depth,counts[depth].num_lines);
202 	    break;
203 	case O_POLYLINE:
204 	    --counts[depth].num_lines;
205 	    if (appres.DEBUG)
206 		fprintf(stderr,"Line[%d] count=%d\n",depth,counts[depth].num_lines);
207 	    break;
208 	case O_ELLIPSE:
209 	    --counts[depth].num_ellipses;
210 	    if (appres.DEBUG)
211 		fprintf(stderr,"Ellipse[%d] count=%d\n",depth,counts[depth].num_ellipses);
212 	    break;
213 	case O_SPLINE:
214 	    --counts[depth].num_splines;
215 	    if (appres.DEBUG)
216 		fprintf(stderr,"Spline[%d] count=%d\n",depth,counts[depth].num_splines);
217 	    break;
218 	case O_TXT:
219 	    --counts[depth].num_texts;
220 	    if (appres.DEBUG)
221 		fprintf(stderr,"Text[%d] count=%d\n",depth,counts[depth].num_texts);
222 	    break;
223     }
224     if (min_depth != -1 && (min_depth < depth && max_depth > depth) &&
225 	object_depths[depth] != 0)
226 	    return;
227     /* if no objects at this depth, find new min/max */
228     for (i=0; i<=MAX_DEPTH; i++)
229 	if (object_depths[i])
230 	    break;
231     if (i<=MAX_DEPTH) {
232 	min_depth = i;
233 	if (appres.DEBUG)
234 	    fprintf(stderr,"New min = %d\n",min_depth);
235 	for (i=MAX_DEPTH; i>=0; i--)
236 	    if (object_depths[i])
237 		break;
238 	if (i>=0) {
239 	    max_depth = i;
240 	    if (appres.DEBUG)
241 		fprintf(stderr,"New max = %d\n",max_depth);
242 	}
243     } else {
244 	min_depth = -1;
245 	if (appres.DEBUG)
246 	    fprintf(stderr,"No objects\n");
247     }
248     /* adjust the layer buttons */
249     update_layers();
250 }
251 
252 void
remove_compound_depth(F_compound * comp)253 remove_compound_depth(F_compound *comp)
254 {
255     F_arc	   *aa;
256     F_ellipse	   *ee;
257     F_line	   *ll;
258     F_spline	   *ss;
259     F_text	   *tt;
260     F_compound	   *cc;
261 
262     if (comp == (F_compound *) 0)
263 	return;
264 
265     /* defer updating of layer buttons until we've added the entire compound */
266     defer_update_layers++;
267     for (aa=comp->arcs; aa; aa=aa->next)
268 	remove_depth(O_ARC, aa->depth);
269     for (ee=comp->ellipses; ee; ee=ee->next)
270 	remove_depth(O_ELLIPSE, ee->depth);
271     for (ll=comp->lines; ll; ll=ll->next)
272 	remove_depth(O_POLYLINE, ll->depth);
273     for (ss=comp->splines; ss; ss=ss->next)
274 	remove_depth(O_SPLINE, ss->depth);
275     for (tt=comp->texts; tt; tt=tt->next)
276 	remove_depth(O_TXT, tt->depth);
277     for (cc=comp->compounds; cc; cc=cc->next)
278 	remove_compound_depth(cc);
279     /* decrement the defer flag and update layer buttons if it hits 0 */
280     defer_update_layers--;
281     update_layers();
282 }
283 
284 
285 /********************************/
286 /****** ADD object to list ******/
287 /********************************/
288 
289 void
list_add_arc(F_arc ** list,F_arc * a)290 list_add_arc(F_arc **list, F_arc *a)
291 {
292     F_arc	   *aa;
293 
294     a->next = NULL;
295     if ((aa = last_arc(*list)) == NULL)
296 	*list = a;
297     else
298 	aa->next = a;
299     if (list == &objects.arcs)
300 	while (a) {
301 	    add_depth(O_ARC, a->depth);
302 	    a = a->next;
303 	}
304 }
305 
306 void
list_add_ellipse(F_ellipse ** list,F_ellipse * e)307 list_add_ellipse(F_ellipse **list, F_ellipse *e)
308 {
309     F_ellipse	   *ee;
310 
311     e->next = NULL;
312     if ((ee = last_ellipse(*list)) == NULL)
313 	*list = e;
314     else
315 	ee->next = e;
316     if (list == &objects.ellipses)
317 	while (e) {
318 	    add_depth(O_ELLIPSE, e->depth);
319 	    e = e->next;
320 	}
321 }
322 
323 void
list_add_line(F_line ** list,F_line * l)324 list_add_line(F_line **list, F_line *l)
325 {
326     F_line	   *ll;
327 
328     l->next = NULL;
329     if ((ll = last_line(*list)) == NULL)
330 	*list = l;
331     else
332 	ll->next = l;
333     if (list == &objects.lines)
334 	while (l) {
335 	    add_depth(O_POLYLINE, l->depth);
336 	    l = l->next;
337 	}
338 }
339 
340 void
list_add_spline(F_spline ** list,F_spline * s)341 list_add_spline(F_spline **list, F_spline *s)
342 {
343     F_spline	   *ss;
344 
345     s->next = NULL;
346     if ((ss = last_spline(*list)) == NULL)
347 	*list = s;
348     else
349 	ss->next = s;
350     if (list == &objects.splines)
351 	while (s) {
352 	    add_depth(O_SPLINE, s->depth);
353 	    s = s->next;
354 	}
355 }
356 
357 void
list_add_text(F_text ** list,F_text * t)358 list_add_text(F_text **list, F_text *t)
359 {
360     F_text	   *tt;
361 
362     t->next = NULL;
363     if ((tt = last_text(*list)) == NULL)
364 	*list = t;
365     else
366 	tt->next = t;
367     if (list == &objects.texts)
368 	while (t) {
369 	    add_depth(O_TXT, t->depth);
370 	    t = t->next;
371 	}
372 }
373 
374 void
list_add_compound(F_compound ** list,F_compound * c)375 list_add_compound(F_compound **list, F_compound *c)
376 {
377     F_compound	   *cc;
378 
379     c->next = NULL;
380     if ((cc = last_compound(*list)) == NULL)
381 	*list = c;
382     else
383 	cc->next = c;
384 
385     if (list == &objects.compounds) {
386 	while (c) {
387 	    add_compound_depth(c);
388 	    c = c->next;
389 	}
390     }
391 }
392 
393 /* increment objects_depth[depth] for a new object, and add to the
394    counter for this "type" (line, arc, etc) */
395 
396 void
add_depth(int type,int depth)397 add_depth(int type, int depth)
398 {
399     int		    i;
400 
401     object_depths[depth]++;
402 
403     if (appres.DEBUG)
404 	fprintf(stderr,"add depth %d, count=%d\n",depth,object_depths[depth]);
405     /* add one to the counter for this object type */
406     switch (type) {
407 	case O_ARC:
408 	    ++counts[depth].num_arcs;
409 	    if (appres.DEBUG)
410 		fprintf(stderr,"Arc[%d] count=%d\n",depth,counts[depth].num_arcs);
411 	    break;
412 	case O_POLYLINE:
413 	    ++counts[depth].num_lines;
414 	    if (appres.DEBUG)
415 		fprintf(stderr,"Line[%d] count=%d\n",depth,counts[depth].num_lines);
416 	    break;
417 	case O_ELLIPSE:
418 	    ++counts[depth].num_ellipses;
419 	    if (appres.DEBUG)
420 		fprintf(stderr,"Ellipse[%d] count=%d\n",depth,counts[depth].num_ellipses);
421 	    break;
422 	case O_SPLINE:
423 	    ++counts[depth].num_splines;
424 	    if (appres.DEBUG)
425 		fprintf(stderr,"Spline[%d] count=%d\n",depth,counts[depth].num_splines);
426 	    break;
427 	case O_TXT:
428 	    ++counts[depth].num_texts;
429 	    if (appres.DEBUG)
430 		fprintf(stderr,"Text[%d] count=%d\n",depth,counts[depth].num_texts);
431 	    break;
432     }
433     if (object_depths[depth] != 1)
434 	return;
435     /* if exactly one object at this depth, see if this is new min or max */
436     for (i=0; i<=MAX_DEPTH; i++)
437 	if (object_depths[i])
438 	    break;
439     min_depth = i;
440     if (appres.DEBUG)
441 	fprintf(stderr,"New min = %d\n",min_depth);
442     for (i=MAX_DEPTH; i>=0; i--)
443 	if (object_depths[i])
444 	    break;
445     if (i>=0) {
446 	max_depth = i;
447 	if (appres.DEBUG)
448 	    fprintf(stderr,"New max = %d\n",max_depth);
449     }
450     /* adjust the layer buttons */
451     update_layers();
452 }
453 
454 void
add_compound_depth(F_compound * comp)455 add_compound_depth(F_compound *comp)
456 {
457     F_arc	   *aa;
458     F_ellipse	   *ee;
459     F_line	   *ll;
460     F_spline	   *ss;
461     F_text	   *tt;
462     F_compound	   *cc;
463 
464     /* defer updating of layer buttons until we've added the entire compound */
465     defer_update_layers++;
466     for (aa=comp->arcs; aa; aa=aa->next)
467 	add_depth(O_ARC, aa->depth);
468     for (ee=comp->ellipses; ee; ee=ee->next)
469 	add_depth(O_ELLIPSE, ee->depth);
470     for (ll=comp->lines; ll; ll=ll->next)
471 	add_depth(O_POLYLINE, ll->depth);
472     for (ss=comp->splines; ss; ss=ss->next)
473 	add_depth(O_SPLINE, ss->depth);
474     for (tt=comp->texts; tt; tt=tt->next)
475 	add_depth(O_TXT, tt->depth);
476     for (cc=comp->compounds; cc; cc=cc->next)
477 	add_compound_depth(cc);
478     /* decrement the defer flag and update layer buttons if it hits 0 */
479     defer_update_layers--;
480     update_layers();
481 }
482 
483 /**********************************/
484 /* routines to delete the objects */
485 /**********************************/
486 
487 void
delete_line(F_line * old_l)488 delete_line(F_line *old_l)
489 {
490     list_delete_line(&objects.lines, old_l);
491     clean_up();
492     set_latestline(old_l);
493     set_action_object(F_DELETE, O_POLYLINE);
494     set_modifiedflag();
495 }
496 
497 void
delete_arc(F_arc * old_a)498 delete_arc(F_arc *old_a)
499 {
500     list_delete_arc(&objects.arcs, old_a);
501     clean_up();
502     set_latestarc(old_a);
503     set_action_object(F_DELETE, O_ARC);
504     set_modifiedflag();
505 }
506 
507 void
delete_ellipse(F_ellipse * old_e)508 delete_ellipse(F_ellipse *old_e)
509 {
510     list_delete_ellipse(&objects.ellipses, old_e);
511     clean_up();
512     set_latestellipse(old_e);
513     set_action_object(F_DELETE, O_ELLIPSE);
514     set_modifiedflag();
515 }
516 
517 void
delete_text(F_text * old_t)518 delete_text(F_text *old_t)
519 {
520     list_delete_text(&objects.texts, old_t);
521     clean_up();
522     set_latesttext(old_t);
523     set_action_object(F_DELETE, O_TXT);
524     set_modifiedflag();
525 }
526 
527 void
delete_spline(F_spline * old_s)528 delete_spline(F_spline *old_s)
529 {
530     list_delete_spline(&objects.splines, old_s);
531     clean_up();
532     set_latestspline(old_s);
533     set_action_object(F_DELETE, O_SPLINE);
534     set_modifiedflag();
535 }
536 
537 void
delete_compound(F_compound * old_c)538 delete_compound(F_compound *old_c)
539 {
540     list_delete_compound(&objects.compounds, old_c);
541     clean_up();
542     set_latestcompound(old_c);
543     set_action_object(F_DELETE, O_COMPOUND);
544     set_modifiedflag();
545 }
546 
547 /*******************************/
548 /* routines to add the objects */
549 /*******************************/
550 
551 void
add_line(F_line * new_l)552 add_line(F_line *new_l)
553 {
554     list_add_line(&objects.lines, new_l);
555     clean_up();
556     set_latestline(new_l);
557     set_action_object(F_ADD, O_POLYLINE);
558     set_modifiedflag();
559 }
560 
561 void
add_arc(F_arc * new_a)562 add_arc(F_arc *new_a)
563 {
564     list_add_arc(&objects.arcs, new_a);
565     clean_up();
566     set_latestarc(new_a);
567     set_action_object(F_ADD, O_ARC);
568     set_modifiedflag();
569 }
570 
571 void
add_ellipse(F_ellipse * new_e)572 add_ellipse(F_ellipse *new_e)
573 {
574     list_add_ellipse(&objects.ellipses, new_e);
575     clean_up();
576     set_latestellipse(new_e);
577     set_action_object(F_ADD, O_ELLIPSE);
578     set_modifiedflag();
579 }
580 
581 void
add_text(F_text * new_t)582 add_text(F_text *new_t)
583 {
584     list_add_text(&objects.texts, new_t);
585     clean_up();
586     set_latesttext(new_t);
587     set_action_object(F_ADD, O_TXT);
588     set_modifiedflag();
589 }
590 
591 void
add_spline(F_spline * new_s)592 add_spline(F_spline *new_s)
593 {
594     list_add_spline(&objects.splines, new_s);
595     clean_up();
596     set_latestspline(new_s);
597     set_action_object(F_ADD, O_SPLINE);
598     set_modifiedflag();
599 }
600 
601 void
add_compound(F_compound * new_c)602 add_compound(F_compound *new_c)
603 {
604     list_add_compound(&objects.compounds, new_c);
605     clean_up();
606     set_latestcompound(new_c);
607     set_action_object(F_ADD, O_COMPOUND);
608     set_modifiedflag();
609 }
610 
611 
612 void
change_line(F_line * old_l,F_line * new_l)613 change_line(F_line *old_l, F_line *new_l)
614 {
615     list_delete_line(&objects.lines, old_l);
616     list_add_line(&objects.lines, new_l);
617     clean_up();
618     old_l->next = new_l;
619     set_latestline(old_l);
620     set_action_object(F_EDIT, O_POLYLINE);
621     set_modifiedflag();
622 }
623 
624 void
change_arc(F_arc * old_a,F_arc * new_a)625 change_arc(F_arc *old_a, F_arc *new_a)
626 {
627     list_delete_arc(&objects.arcs, old_a);
628     list_add_arc(&objects.arcs, new_a);
629     clean_up();
630     old_a->next = new_a;
631     set_latestarc(old_a);
632     set_action_object(F_EDIT, O_ARC);
633     set_modifiedflag();
634 }
635 
636 void
change_ellipse(F_ellipse * old_e,F_ellipse * new_e)637 change_ellipse(F_ellipse *old_e, F_ellipse *new_e)
638 {
639     list_delete_ellipse(&objects.ellipses, old_e);
640     list_add_ellipse(&objects.ellipses, new_e);
641     clean_up();
642     old_e->next = new_e;
643     set_latestellipse(old_e);
644     set_action_object(F_EDIT, O_ELLIPSE);
645     set_modifiedflag();
646 }
647 
648 void
change_text(F_text * old_t,F_text * new_t)649 change_text(F_text *old_t, F_text *new_t)
650 {
651     list_delete_text(&objects.texts, old_t);
652     list_add_text(&objects.texts, new_t);
653     clean_up();
654     old_t->next = new_t;
655     set_latesttext(old_t);
656     set_action_object(F_EDIT, O_TXT);
657     set_modifiedflag();
658 }
659 
660 void
change_spline(F_spline * old_s,F_spline * new_s)661 change_spline(F_spline *old_s, F_spline *new_s)
662 {
663     list_delete_spline(&objects.splines, old_s);
664     list_add_spline(&objects.splines, new_s);
665     clean_up();
666     old_s->next = new_s;
667     set_latestspline(old_s);
668     set_action_object(F_EDIT, O_SPLINE);
669     set_modifiedflag();
670 }
671 
672 void
change_compound(F_compound * old_c,F_compound * new_c)673 change_compound(F_compound *old_c, F_compound *new_c)
674 {
675     list_delete_compound(&objects.compounds, old_c);
676     list_add_compound(&objects.compounds, new_c);
677     clean_up();
678     old_c->next = new_c;
679     set_latestcompound(old_c);
680     set_action_object(F_EDIT, O_COMPOUND);
681     set_modifiedflag();
682 }
683 
684 /* find the tails of all the object lists */
685 
tail(F_compound * ob,F_compound * tails)686 void tail(F_compound *ob, F_compound *tails)
687 {
688     F_arc	   *a;
689     F_compound	   *c;
690     F_ellipse	   *e;
691     F_line	   *l;
692     F_spline	   *s;
693     F_text	   *t;
694 
695     if (NULL != (a = ob->arcs))
696 	for (; a->next != NULL; a = a->next)
697 		;
698     if (NULL != (c = ob->compounds))
699 	for (; c->next != NULL; c = c->next)
700 		;
701     if (NULL != (e = ob->ellipses))
702 	for (; e->next != NULL; e = e->next)
703 		;
704     if (NULL != (l = ob->lines))
705 	for (; l->next != NULL; l = l->next)
706 		;
707     if (NULL != (s = ob->splines))
708 	for (; s->next != NULL; s = s->next)
709 		;
710     if (NULL != (t = ob->texts))
711 	for (; t->next != NULL; t = t->next)
712 		;
713 
714     tails->arcs = a;
715     tails->compounds = c;
716     tails->ellipses = e;
717     tails->lines = l;
718     tails->splines = s;
719     tails->texts = t;
720 }
721 
722 /*
723  * Make pointers in tails point to the last element of each list of l1 and
724  * Append the lists in l2 after those in l1. The tails pointers must be
725  * defined prior to calling append.
726  */
727 
append_objects(F_compound * l1,F_compound * l2,F_compound * tails)728 void append_objects(F_compound *l1, F_compound *l2, F_compound *tails)
729 {
730     /* don't forget to account for the depths */
731     add_compound_depth(l2);
732 
733     if (tails->arcs)
734 	tails->arcs->next = l2->arcs;
735     else
736 	l1->arcs = l2->arcs;
737     if (tails->compounds)
738 	tails->compounds->next = l2->compounds;
739     else
740 	l1->compounds = l2->compounds;
741     if (tails->ellipses)
742 	tails->ellipses->next = l2->ellipses;
743     else
744 	l1->ellipses = l2->ellipses;
745     if (tails->lines)
746 	tails->lines->next = l2->lines;
747     else
748 	l1->lines = l2->lines;
749     if (tails->splines)
750 	tails->splines->next = l2->splines;
751     else
752 	l1->splines = l2->splines;
753     if (tails->texts)
754 	tails->texts->next = l2->texts;
755     else
756 	l1->texts = l2->texts;
757 }
758 
759 /* Cut is the dual of append. */
760 
cut_objects(F_compound * objects,F_compound * tails)761 void cut_objects(F_compound *objects, F_compound *tails)
762 {
763     if (tails->arcs) {
764 	remove_arc_depths(tails->arcs->next);
765 	tails->arcs->next = NULL;
766     } else if (objects->arcs) {
767 	remove_arc_depths(objects->arcs);
768 	objects->arcs = NULL;
769     }
770     if (tails->compounds) {
771 	remove_compound_depth(tails->compounds->next);
772 	tails->compounds->next = NULL;
773     } else if (objects->compounds) {
774 	remove_compound_depth(objects->compounds);
775 	objects->compounds = NULL;
776     }
777     if (tails->ellipses) {
778 	remove_ellipse_depths(tails->ellipses->next);
779 	tails->ellipses->next = NULL;
780     } else if (objects->ellipses) {
781 	remove_ellipse_depths(objects->ellipses);
782 	objects->ellipses = NULL;
783     }
784     if (tails->lines) {
785 	remove_line_depths(tails->lines->next);
786 	tails->lines->next = NULL;
787     } else if (objects->lines) {
788 	remove_line_depths(objects->lines);
789 	objects->lines = NULL;
790     }
791     if (tails->splines) {
792 	remove_spline_depths(tails->splines->next);
793 	tails->splines->next = NULL;
794     } else if (objects->splines) {
795 	remove_spline_depths(objects->splines);
796 	objects->splines = NULL;
797     }
798     if (tails->texts) {
799 	remove_text_depths(tails->texts->next);
800 	tails->texts->next = NULL;
801     } else if (objects->texts) {
802 	remove_text_depths(objects->texts);
803 	objects->texts = NULL;
804     }
805 }
806 
807 void
remove_arc_depths(F_arc * a)808 remove_arc_depths(F_arc *a)
809 {
810     for ( ; a; a= a->next)
811 	remove_depth(O_ARC, a->depth);
812 }
813 
814 void
remove_ellipse_depths(F_ellipse * e)815 remove_ellipse_depths(F_ellipse *e)
816 {
817     for ( ; e; e = e->next)
818 	remove_depth(O_ELLIPSE, e->depth);
819 }
820 
821 void
remove_line_depths(F_line * l)822 remove_line_depths(F_line *l)
823 {
824     for ( ; l; l = l->next)
825 	remove_depth(O_POLYLINE, l->depth);
826 }
827 
828 void
remove_spline_depths(F_spline * s)829 remove_spline_depths(F_spline *s)
830 {
831     for ( ; s; s = s->next)
832 	remove_depth(O_SPLINE, s->depth);
833 }
834 
835 void
remove_text_depths(F_text * t)836 remove_text_depths(F_text *t)
837 {
838     for ( ; t; t = t->next)
839 	remove_depth(O_TXT, t->depth);
840 }
841 
842 void
append_point(int x,int y,F_point ** point)843 append_point(int x, int y, F_point **point)    /** used in d_arcbox **/
844 {
845     F_point	   *p;
846 
847     if ((p = create_point()) == NULL)
848 	return;
849 
850     p->x = x;
851     p->y = y;
852     p->next = NULL;
853     (*point)->next = p;
854     *point = p;
855 }
856 
857 Boolean
insert_point(int x,int y,F_point * point)858 insert_point(int x, int y, F_point *point)
859 {
860     F_point	  *p;
861 
862     if ((p = create_point()) == NULL)
863 	return False;
864 
865     p->x = x;
866     p->y = y;
867     p->next = (point)->next;
868     (point)->next = p;
869     return True;
870 }
871 
872 Boolean
append_sfactor(double s,F_sfactor * cpoint)873 append_sfactor(double s, F_sfactor *cpoint)
874 {
875   F_sfactor *newpoint;
876 
877   if ((newpoint = create_sfactor()) == NULL)
878     return False;
879   newpoint->s = s;
880   newpoint->next = cpoint->next;
881   cpoint->next = newpoint;
882   return True;
883 }
884 
885 
886 Boolean
first_spline_point(int x,int y,double s,F_spline * spline)887 first_spline_point(int x, int y, double s, F_spline *spline)
888 {
889   F_point   *newpoint;
890   F_sfactor *cpoint;
891 
892   if ((newpoint = create_point()) == NULL)
893     return False;
894   if ((cpoint = create_sfactor()) == NULL)
895     return False;
896 
897   newpoint->x = x;
898   newpoint->y = y;
899   newpoint->next = spline->points;
900   spline->points = newpoint;
901   cpoint->s = s;
902   cpoint->next = spline->sfactors;
903   spline->sfactors = cpoint;
904   return True;
905 }
906 
num_points(F_point * points)907 int num_points(F_point *points)
908 {
909     int		    n;
910     F_point	   *p;
911 
912     for (p = points, n = 0; p != NULL; p = p->next, n++)
913 	    ;
914     return (n);
915 }
916 
917 F_text	       *
last_text(F_text * list)918 last_text(F_text *list)
919 {
920     F_text	   *tt;
921 
922     if (list == NULL)
923 	return NULL;
924 
925     for (tt = list; tt->next != NULL; tt = tt->next)
926 	    ;
927     return tt;
928 }
929 
930 F_line	       *
last_line(F_line * list)931 last_line(F_line *list)
932 {
933     F_line	   *ll;
934 
935     if (list == NULL)
936 	return NULL;
937 
938     for (ll = list; ll->next != NULL; ll = ll->next)
939 	    ;
940     return ll;
941 }
942 
943 F_spline       *
last_spline(F_spline * list)944 last_spline(F_spline *list)
945 {
946     F_spline	   *ss;
947 
948     if (list == NULL)
949 	return NULL;
950 
951     for (ss = list; ss->next != NULL; ss = ss->next)
952 	    ;
953     return ss;
954 }
955 
956 F_arc	       *
last_arc(F_arc * list)957 last_arc(F_arc *list)
958 {
959     F_arc	   *tt;
960 
961     if (list == NULL)
962 	return NULL;
963 
964     for (tt = list; tt->next != NULL; tt = tt->next)
965 	    ;
966     return tt;
967 }
968 
969 F_ellipse      *
last_ellipse(F_ellipse * list)970 last_ellipse(F_ellipse *list)
971 {
972     F_ellipse	   *tt;
973 
974     if (list == NULL)
975 	return NULL;
976 
977     for (tt = list; tt->next != NULL; tt = tt->next)
978 	    ;
979     return tt;
980 }
981 
982 F_compound     *
last_compound(F_compound * list)983 last_compound(F_compound *list)
984 {
985     F_compound	   *tt;
986 
987     if (list == NULL)
988 	return NULL;
989 
990     for (tt = list; tt->next != NULL; tt = tt->next)
991 	    ;
992     return tt;
993 }
994 
995 F_point	       *
last_point(F_point * list)996 last_point(F_point *list)
997 {
998     F_point	   *tt;
999 
1000     if (list == NULL)
1001 	return NULL;
1002 
1003     for (tt = list; tt->next != NULL; tt = tt->next)
1004 	    ;
1005     return tt;
1006 }
1007 
1008 F_sfactor       *
last_sfactor(F_sfactor * list)1009 last_sfactor(F_sfactor *list)
1010 {
1011     F_sfactor	   *tt;
1012 
1013     if (list == NULL)
1014 	return NULL;
1015 
1016     for (tt = list; tt->next != NULL; tt = tt->next)
1017 	    ;
1018     return tt;
1019 }
1020 
1021 F_point        *
search_line_point(F_line * line,int x,int y)1022 search_line_point(F_line *line, int x, int y)
1023 {
1024   F_point *point;
1025 
1026   for (point = line->points ;
1027        point != NULL && (point->x != x || point->y != y); point = point->next);
1028   return point;
1029 }
1030 
1031 F_point        *
search_spline_point(F_spline * spline,int x,int y)1032 search_spline_point(F_spline *spline, int x, int y)
1033 {
1034   F_point *point;
1035 
1036   for (point = spline->points ;
1037        point != NULL && (point->x != x || point->y != y); point = point->next);
1038   return point;
1039 }
1040 
1041 
1042 F_sfactor      *
search_sfactor(F_spline * spline,F_point * selected_point)1043 search_sfactor(F_spline *spline, F_point *selected_point)
1044 {
1045   F_sfactor *c_point = spline->sfactors;
1046   F_point *cursor;
1047 
1048   for (cursor = spline->points ; cursor != selected_point ;
1049        cursor = cursor->next)
1050     c_point = c_point->next;
1051   return c_point;
1052 }
1053 
1054 
1055 F_arc	       *
prev_arc(F_arc * list,F_arc * arc)1056 prev_arc(F_arc *list, F_arc *arc)
1057 {
1058     F_arc	   *csr;
1059 
1060     if (list == arc)
1061 	return NULL;
1062 
1063     for (csr = list; csr->next != arc; csr = csr->next)
1064 	    ;
1065     return csr;
1066 }
1067 
1068 F_compound     *
prev_compound(F_compound * list,F_compound * compound)1069 prev_compound(F_compound *list, F_compound *compound)
1070 {
1071     F_compound	   *csr;
1072 
1073     if (list == compound)
1074 	return NULL;
1075 
1076     for (csr = list; csr->next != compound; csr = csr->next)
1077 	    ;
1078     return csr;
1079 }
1080 
1081 F_ellipse      *
prev_ellipse(F_ellipse * list,F_ellipse * ellipse)1082 prev_ellipse(F_ellipse *list, F_ellipse *ellipse)
1083 {
1084     F_ellipse	   *csr;
1085 
1086     if (list == ellipse)
1087 	return NULL;
1088 
1089     for (csr = list; csr->next != ellipse; csr = csr->next)
1090 	    ;
1091     return csr;
1092 }
1093 
1094 F_line	       *
prev_line(F_line * list,F_line * line)1095 prev_line(F_line *list, F_line *line)
1096 {
1097     F_line	   *csr;
1098 
1099     if (list == line)
1100 	return NULL;
1101 
1102     for (csr = list; csr->next != line; csr = csr->next)
1103 	    ;
1104     return csr;
1105 }
1106 
1107 F_spline       *
prev_spline(F_spline * list,F_spline * spline)1108 prev_spline(F_spline *list, F_spline *spline)
1109 {
1110     F_spline	   *csr;
1111 
1112     if (list == spline)
1113 	return NULL;
1114 
1115     for (csr = list; csr->next != spline; csr = csr->next)
1116 	    ;
1117     return csr;
1118 }
1119 
1120 F_text	       *
prev_text(F_text * list,F_text * text)1121 prev_text(F_text *list, F_text *text)
1122 {
1123     F_text	   *csr;
1124 
1125     if (list == text)
1126 	return NULL;
1127 
1128     for (csr = list; csr->next != text; csr = csr->next)
1129 	    ;
1130     return csr;
1131 }
1132 
1133 F_point	       *
prev_point(F_point * list,F_point * point)1134 prev_point(F_point *list, F_point *point)
1135 {
1136     F_point	   *csr;
1137 
1138     if (list == point)
1139 	return NULL;
1140 
1141     for (csr = list; csr->next != point; csr = csr->next)
1142 	    ;
1143     return csr;
1144 }
1145 
1146 int
object_count(F_compound * list)1147 object_count(F_compound *list)
1148 {
1149     register int    cnt;
1150     F_arc	   *a;
1151     F_text	   *t;
1152     F_compound	   *c;
1153     F_ellipse	   *e;
1154     F_line	   *l;
1155     F_spline	   *s;
1156 
1157     cnt = 0;
1158     for (a = list->arcs; a != NULL; a = a->next, cnt++)
1159 	    ;
1160     for (t = list->texts; t != NULL; t = t->next, cnt++)
1161 	    ;
1162     for (c = list->compounds; c != NULL; c = c->next, cnt++)
1163 	    ;
1164     for (e = list->ellipses; e != NULL; e = e->next, cnt++)
1165 	    ;
1166     for (l = list->lines; l != NULL; l = l->next, cnt++)
1167 	    ;
1168     for (s = list->splines; s != NULL; s = s->next, cnt++)
1169 	    ;
1170     return (cnt);
1171 }
1172 
set_tags(F_compound * list,int tag)1173 void set_tags(F_compound *list, int tag)
1174 {
1175     F_arc	   *a;
1176     F_text	   *t;
1177     F_compound	   *c;
1178     F_ellipse	   *e;
1179     F_line	   *l;
1180     F_spline	   *s;
1181 
1182     for (a = list->arcs; a != NULL; a = a->next) {
1183 	mask_toggle_arcmarker(a);
1184 	a->tagged = tag;
1185 	mask_toggle_arcmarker(a);
1186     }
1187     for (t = list->texts; t != NULL; t = t->next) {
1188 	mask_toggle_textmarker(t);
1189 	t->tagged = tag;
1190 	mask_toggle_textmarker(t);
1191     }
1192     for (c = list->compounds; c != NULL; c = c->next) {
1193 	mask_toggle_compoundmarker(c);
1194 	c->tagged = tag;
1195 	mask_toggle_compoundmarker(c);
1196     }
1197     for (e = list->ellipses; e != NULL; e = e->next) {
1198 	mask_toggle_ellipsemarker(e);
1199 	e->tagged = tag;
1200 	mask_toggle_ellipsemarker(e);
1201     }
1202     for (l = list->lines; l != NULL; l = l->next) {
1203 	mask_toggle_linemarker(l);
1204 	l->tagged = tag;
1205 	mask_toggle_linemarker(l);
1206     }
1207     for (s = list->splines; s != NULL; s = s->next) {
1208 	mask_toggle_splinemarker(s);
1209 	s->tagged = tag;
1210 	mask_toggle_splinemarker(s);
1211     }
1212 }
1213 
1214 void
get_links(int llx,int lly,int urx,int ury)1215 get_links(int llx, int lly, int urx, int ury)
1216 {
1217     F_line	   *l;
1218     F_point	   *a;
1219     F_linkinfo	   *j, *k;
1220 
1221     j = NULL;
1222     for (l = objects.lines; l != NULL; l = l->next)
1223 	if (l->type == T_POLYLINE) {
1224 	    a = l->points;
1225 	    if (point_on_perim(a, llx, lly, urx, ury)) {
1226 		if ((k = new_link(l, a, a->next)) == NULL)
1227 		    return;
1228 		if (j == NULL)
1229 		    cur_links = k;
1230 		else
1231 		    j->next = k;
1232 		j = k;
1233 		if (k->prevpt != NULL)
1234 		    k->two_pts = (k->prevpt->next == NULL);
1235 		continue;
1236 	    }
1237 	    if (a->next == NULL)/* single point, no need to check further */
1238 		continue;
1239 	    a = last_point(l->points);
1240 	    if (point_on_perim(a, llx, lly, urx, ury)) {
1241 		if ((k = new_link(l, a, prev_point(l->points, a))) == NULL)
1242 		    return;
1243 		if (j == NULL)
1244 		    cur_links = k;
1245 		else
1246 		    j->next = k;
1247 		j = k;
1248 		if (k->prevpt != NULL)
1249 		    k->two_pts = (prev_point(l->points, k->prevpt) == NULL);
1250 		continue;
1251 	    }
1252 	}
1253 }
1254 
1255 static int LINK_TOL = 3 * PIX_PER_INCH / DISPLAY_PIX_PER_INCH;
1256 
1257 int
point_on_perim(F_point * p,int llx,int lly,int urx,int ury)1258 point_on_perim(F_point *p, int llx, int lly, int urx, int ury)
1259 {
1260     return ((abs(p->x - llx) <= LINK_TOL && p->y >= lly - LINK_TOL
1261 	     && p->y <= ury + LINK_TOL) ||
1262 	    (abs(p->x - urx) <= LINK_TOL && p->y >= lly - LINK_TOL
1263 	     && p->y <= ury + LINK_TOL) ||
1264 	    (abs(p->y - lly) <= LINK_TOL && p->x >= llx - LINK_TOL
1265 	     && p->x <= urx + LINK_TOL) ||
1266 	    (abs(p->y - ury) <= LINK_TOL && p->x >= llx - LINK_TOL
1267 	     && p->x <= urx + LINK_TOL));
1268 }
1269 /*
1270 ** get_interior_links and point_on_inside, added by Ian Brown Feb 1995.
1271 ** This is to allow links within compound objects.
1272 */
1273 
1274 void
get_interior_links(int llx,int lly,int urx,int ury)1275 get_interior_links(int llx, int lly, int urx, int ury)
1276 {
1277     F_line	   *l;
1278     F_point	   *a;
1279     F_linkinfo	   *j, *k;
1280 
1281     j = NULL;
1282     for (l = objects.lines; l != NULL; l = l->next)
1283 	if (l->type == T_POLYLINE) {
1284 	    a = l->points;
1285 	    if (point_on_inside(a, llx, lly, urx, ury)) {
1286 		if ((k = new_link(l, a, a->next)) == NULL)
1287 		    return;
1288 		if (j == NULL)
1289 		    cur_links = k;
1290 		else
1291 		    j->next = k;
1292 		j = k;
1293 		if (k->prevpt != NULL)
1294 		    k->two_pts = (k->prevpt->next == NULL);
1295 		continue;
1296 	    }
1297 	    if (a->next == NULL)/* single point, no need to check further */
1298 		continue;
1299 	    a = last_point(l->points);
1300 	    if (point_on_inside(a, llx, lly, urx, ury)) {
1301 		if ((k = new_link(l, a, prev_point(l->points, a))) == NULL)
1302 		    return;
1303 		if (j == NULL)
1304 		    cur_links = k;
1305 		else
1306 		    j->next = k;
1307 		j = k;
1308 		if (k->prevpt != NULL)
1309 		    k->two_pts = (prev_point(l->points, k->prevpt) == NULL);
1310 		continue;
1311 	    }
1312 	}
1313 }
1314 
1315 int
point_on_inside(F_point * p,int llx,int lly,int urx,int ury)1316 point_on_inside(F_point *p, int llx, int lly, int urx, int ury)
1317 {
1318     return ((p->x >= llx) && (p->x <= urx) &&
1319 	    (p->y >= lly) && (p->y <= ury));
1320 
1321 }
1322 
1323 void
adjust_links(int mode,F_linkinfo * links,int dx,int dy,int cx,int cy,float sx,float sy,Boolean copying)1324 adjust_links(int mode, F_linkinfo *links,
1325 	int dx, int dy,		/* delta */
1326 	int cx, int cy,		/* center of scale - NOT USED YET */
1327 	float sx, float sy,	/* scale factor - NOT USED YET */
1328 	Boolean copying)
1329 {
1330     F_linkinfo	   *k;
1331     F_line	   *l;
1332 
1333     if (mode != SMART_OFF)
1334 	for (k = links; k != NULL; k = k->next) {
1335 	    if (copying) {
1336 		l = copy_line(k->line);
1337 		list_add_line(&objects.lines, l);
1338 	    } else {
1339 		mask_toggle_linemarker(k->line);
1340 		draw_line(k->line, ERASE);
1341 	    }
1342 	    if (mode == SMART_SLIDE && k->prevpt != NULL) {
1343 		if (k->endpt->x == k->prevpt->x)
1344 		    k->prevpt->x += dx;
1345 		else
1346 		    k->prevpt->y += dy;
1347 	    }
1348 	    k->endpt->x += dx;
1349 	    k->endpt->y += dy;
1350 	    draw_line(k->line, PAINT);
1351 	    mask_toggle_linemarker(k->line);
1352 	}
1353 }
1354