1 /*
2  * FIG : Facility for Interactive Generation of figures
3  * Copyright (c) 1985-1988 by Supoj Sutanthavibul
4  * Parts Copyright (c) 1989-2015 by Brian V. Smith
5  * Parts Copyright (c) 1991 by Paul King
6  * Parts Copyright (c) 2016-2020 by Thomas Loimer
7  *
8  * Parts Copyright (c) 1995 by C. Blanc and C. Schlick
9  *
10  * Any party obtaining a copy of these files is granted, free of charge, a
11  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
12  * nonexclusive right and license to deal in this software and documentation
13  * files (the "Software"), including without limitation the rights to use,
14  * copy, modify, merge, publish, distribute, sublicense and/or sell copies of
15  * the Software, and to permit persons who receive copies from any such
16  * party to do so, with the only requirement being that the above copyright
17  * and this permission notice remain intact.
18  *
19  */
20 
21 
22 #include <stdlib.h>
23 #include <stdio.h>
24 
25 #include "mode.h"
26 #include "object.h"
27 #include "e_edit.h"
28 #include "e_scale.h"
29 #include "u_create.h"
30 #include "u_free.h"
31 #include "u_list.h"
32 #include "w_cursor.h"
33 #include "w_modepanel.h"
34 #include "w_mousefun.h"
35 #include "w_msgpanel.h"
36 #include "w_setup.h"
37 #include "w_util.h"
38 
39 static char	Err_mem[] = "Running out of memory.";
40 
41 
42 /****************** ARROWS ****************/
43 
44 
45 F_arrow *
create_arrow(void)46 create_arrow(void)
47 {
48     F_arrow	   *a;
49 
50     if ((a = (F_arrow *) malloc(ARROW_SIZE)) == NULL)
51 	put_msg(Err_mem);
52     return a;
53 }
54 
55 F_arrow	       *
forward_arrow(void)56 forward_arrow(void)
57 {
58     F_arrow	   *a;
59 
60     if ((a = create_arrow()) == NULL) {
61 	put_msg(Err_mem);
62 	return NULL;
63     }
64 
65     a->type = ARROW_TYPE(cur_arrowtype);
66     a->style = ARROW_STYLE(cur_arrowtype);
67     if (use_abs_arrowvals) {
68 	a->thickness = cur_arrowthick;
69 	a->wd = cur_arrowwidth;
70 	a->ht = cur_arrowheight;
71     } else {
72 	a->thickness = cur_arrow_multthick*cur_linewidth;
73 	a->wd = cur_arrow_multwidth*cur_linewidth;
74 	a->ht = cur_arrow_multheight*cur_linewidth;
75     }
76     return a;
77 }
78 
79 F_arrow	       *
backward_arrow(void)80 backward_arrow(void)
81 {
82     F_arrow	   *a;
83 
84     if ((a = create_arrow()) == NULL) {
85 	put_msg(Err_mem);
86 	return NULL;
87     }
88 
89     a->type = ARROW_TYPE(cur_arrowtype);
90     a->style = ARROW_STYLE(cur_arrowtype);
91     if (use_abs_arrowvals) {
92 	a->thickness = cur_arrowthick;
93 	a->wd = cur_arrowwidth;
94 	a->ht = cur_arrowheight;
95     } else {
96 	a->thickness = cur_arrow_multthick*cur_linewidth;
97 	a->wd = cur_arrow_multwidth*cur_linewidth;
98 	a->ht = cur_arrow_multheight*cur_linewidth;
99     }
100     return a;
101 }
102 
103 F_arrow	       *
new_arrow(int type,int style,float thickness,float wd,float ht)104 new_arrow(int type, int style, float thickness, float wd, float ht)
105 {
106     F_arrow	   *a;
107 
108     if ((a = create_arrow()) == NULL) {
109 	put_msg(Err_mem);
110 	return NULL;
111     }
112 
113     /* check arrow type for legality */
114     if (type > NUM_ARROW_TYPES/2) { /* type*2+style = NUM_ARROW_TYPES */
115 	type = style = 0;
116     }
117     /* only open or filled allowed */
118     if (style > 1)
119 	style = 0;
120 
121     /* if thickness is <= 0 or > 10 inches, make reasonable values */
122     if (thickness <= 0.0 || thickness > 10.0 * DISPLAY_PIX_PER_INCH)
123 	thickness = cur_arrowthick;
124     /* if width is <= 0 or > 20 inches, make reasonable values */
125     if (wd <= 0.0)
126 	wd = cur_arrowwidth;
127     /* if height is < 0 or > 50 inches, make reasonable values */
128     if (ht < 0.0 || ht > 50.0 * DISPLAY_PIX_PER_INCH)
129 	ht = cur_arrowheight;
130     a->type = type;
131     a->style = style;
132     a->thickness = thickness;
133     a->wd = wd;
134     a->ht = ht;
135     return a;
136 }
137 
138 /************************ COMMENTS *************************/
139 
140 void
copy_comments(char ** source,char ** dest)141 copy_comments(char **source, char **dest)
142 {
143     if (*source == NULL) {
144 	*dest = NULL;
145 	return;
146     }
147     if ((*dest = (char*) new_string(strlen(*source))) == NULL)
148 	return;
149     strcpy(*dest,*source);
150 }
151 
152 /************************ SMART LINKS *************************/
153 
154 F_linkinfo     *
new_link(F_line * l,F_point * ep,F_point * pp)155 new_link(F_line *l, F_point *ep, F_point *pp)
156 {
157     F_linkinfo	   *k;
158 
159     if ((k = (F_linkinfo *) malloc(LINKINFO_SIZE)) == NULL) {
160 	put_msg(Err_mem);
161 	return NULL;
162     }
163     k->line = l;
164     k->endpt = ep;
165     k->prevpt = pp;
166     k->next = NULL;
167     return k;
168 }
169 
170 /************************ POINTS *************************/
171 
172 F_point	       *
create_point(void)173 create_point(void)
174 {
175     F_point	   *p;
176 
177     if ((p = (F_point *) malloc(POINT_SIZE)) == NULL) {
178 	put_msg(Err_mem);
179 	return NULL;
180     }
181     p->x = 0;
182     p->y = 0;
183     p->next = NULL;
184     return p;
185 }
186 
187 F_sfactor      *
create_sfactor(void)188 create_sfactor(void)
189 {
190     F_sfactor	   *cp;
191 
192     if ((cp = (F_sfactor *) malloc(CONTROL_SIZE)) == NULL) {
193 	put_msg(Err_mem);
194 	return NULL;
195     }
196     cp->next = NULL;
197     return cp;
198 }
199 
200 F_point	       *
copy_points(F_point * orig_pt)201 copy_points(F_point *orig_pt)
202 {
203     F_point	   *new_pt, *prev_pt, *first_pt;
204 
205     if ((new_pt = create_point()) == NULL)
206 	return NULL;
207 
208     first_pt = new_pt;
209     *new_pt = *orig_pt;
210     new_pt->next = NULL;
211     prev_pt = new_pt;
212     for (orig_pt = orig_pt->next; orig_pt != NULL; orig_pt = orig_pt->next) {
213 	if ((new_pt = create_point()) == NULL) {
214 	    free_points(first_pt);
215 	    return NULL;
216 	}
217 	prev_pt->next = new_pt;
218 	*new_pt = *orig_pt;
219 	new_pt->next = NULL;
220 	prev_pt = new_pt;
221     }
222     return first_pt;
223 }
224 
225 F_sfactor *
copy_sfactors(F_sfactor * orig_sf)226 copy_sfactors(F_sfactor *orig_sf)
227 {
228     F_sfactor	 *new_sf, *prev_sf, *first_sf;
229 
230     if ((new_sf = create_sfactor()) == NULL)
231 	return NULL;
232 
233     first_sf = new_sf;
234     *new_sf = *orig_sf;
235     new_sf->next = NULL;
236     prev_sf = new_sf;
237     for (orig_sf = orig_sf->next; orig_sf != NULL; orig_sf = orig_sf->next) {
238 	if ((new_sf = create_sfactor()) == NULL) {
239 	    free_sfactors(first_sf);
240 	    return NULL;
241 	}
242 	prev_sf->next = new_sf;
243 	*new_sf = *orig_sf;
244 	new_sf->next = NULL;
245 	prev_sf = new_sf;
246     }
247     return first_sf;
248 }
249 
250 /* reverse points in list */
251 
252 void
reverse_points(F_point * orig_pt)253 reverse_points(F_point *orig_pt)
254 {
255     F_point	   *cur_pt;
256     int		    npts,i;
257     F_point	   *tmp_pts;
258 
259     /* count how many points are in the list */
260     cur_pt = orig_pt;
261     for (npts=0; cur_pt; cur_pt=cur_pt->next)
262 	npts++;
263     /* make a temporary stack (array) */
264     tmp_pts = (F_point *) malloc(npts*sizeof(F_point));
265     cur_pt = orig_pt;
266     /* and put them on in reverse order */
267     for (i=npts-1; i>=0; i--) {
268 	tmp_pts[i].x = cur_pt->x;
269 	tmp_pts[i].y = cur_pt->y;
270 	cur_pt = cur_pt->next;
271     }
272     /* now reverse them */
273     cur_pt = orig_pt;
274     for (i=0; i<npts; i++) {
275 	cur_pt->x = tmp_pts[i].x;
276 	cur_pt->y = tmp_pts[i].y;
277 	cur_pt = cur_pt->next;
278     }
279     /* free the temp array */
280     free(tmp_pts);
281 }
282 
283 /* reverse sfactors in list */
284 
285 void
reverse_sfactors(F_sfactor * orig_sf)286 reverse_sfactors(F_sfactor *orig_sf)
287 {
288     F_sfactor	   *cur_sf;
289     int		    nsf,i;
290     F_sfactor	   *tmp_sf;
291 
292     /* count how many sfactors are in the list */
293     cur_sf = orig_sf;
294     for (nsf=0; cur_sf; cur_sf=cur_sf->next)
295 	nsf++;
296     /* make a temporary stack (array) */
297     tmp_sf = (F_sfactor *) malloc(nsf*sizeof(F_sfactor));
298     cur_sf = orig_sf;
299     /* and put them on in reverse order */
300     for (i=nsf-1; i>=0; i--) {
301 	tmp_sf[i].s = cur_sf->s;
302 	cur_sf = cur_sf->next;
303     }
304     /* now reverse them */
305     cur_sf = orig_sf;
306     for (i=0; i<nsf; i++) {
307 	cur_sf->s = tmp_sf[i].s;
308 	cur_sf = cur_sf->next;
309     }
310     /* free the temp array */
311     free(tmp_sf);
312 }
313 
314 /************************ ARCS *************************/
315 
316 F_arc	       *
create_arc(void)317 create_arc(void)
318 {
319     F_arc	   *a;
320 
321     if ((a = (F_arc *) malloc(ARCOBJ_SIZE)) == NULL) {
322 	put_msg(Err_mem);
323 	return NULL;
324     }
325     a->tagged = 0;
326     a->next = NULL;
327     a->type = 0;
328     a->for_arrow = NULL;
329     a->back_arrow = NULL;
330     a->comments = NULL;
331     a->depth = 0;
332     a->thickness = 0;
333     a->pen_color = BLACK;
334     a->fill_color = DEFAULT;
335     a->fill_style = UNFILLED;
336     a->pen_style = -1;
337     a->style = SOLID_LINE;
338     a->style_val = 0.0;
339     a->cap_style = CAP_BUTT;
340     a->direction = 0;
341     a->angle = 0.0;
342     return a;
343 }
344 
345 F_arc	       *
copy_arc(F_arc * a)346 copy_arc(F_arc *a)
347 {
348     F_arc	   *arc;
349     F_arrow	   *arrow;
350 
351     if ((arc = create_arc()) == NULL)
352 	return NULL;
353 
354     /* copy static items first */
355     *arc = *a;
356     arc->next = NULL;
357 
358     /* do comments next */
359     copy_comments(&a->comments, &arc->comments);
360 
361     if (a->for_arrow) {
362 	if ((arrow = create_arrow()) == NULL) {
363 	    free((char *) arc);
364 	    return NULL;
365 	}
366 	arc->for_arrow = arrow;
367 	*arrow = *a->for_arrow;
368     }
369     if (a->back_arrow) {
370 	if ((arrow = create_arrow()) == NULL) {
371 	    free((char *) arc);
372 	    return NULL;
373 	}
374 	arc->back_arrow = arrow;
375 	*arrow = *a->back_arrow;
376     }
377     return arc;
378 }
379 
380 /************************ ELLIPSES *************************/
381 
382 F_ellipse      *
create_ellipse(void)383 create_ellipse(void)
384 {
385     F_ellipse	   *e;
386 
387     if ((e = (F_ellipse *) malloc(ELLOBJ_SIZE)) == NULL) {
388 	put_msg(Err_mem);
389 	return NULL;
390     }
391     e->tagged = 0;
392     e->next = NULL;
393     e->comments = NULL;
394     return e;
395 }
396 
397 F_ellipse      *
copy_ellipse(F_ellipse * e)398 copy_ellipse(F_ellipse *e)
399 {
400     F_ellipse	   *ellipse;
401 
402     if ((ellipse = create_ellipse()) == NULL)
403 	return NULL;
404 
405     /* copy static items first */
406     *ellipse = *e;
407     ellipse->next = NULL;
408 
409     /* do comments next */
410     copy_comments(&e->comments, &ellipse->comments);
411 
412     return ellipse;
413 }
414 
415 /************************ LINES *************************/
416 
417 F_line	       *
create_line(void)418 create_line(void)
419 {
420     F_line	   *l;
421 
422     if ((l = (F_line *) malloc(LINOBJ_SIZE)) == NULL) {
423 	put_msg(Err_mem);
424 	return NULL;
425     }
426     l->tagged = 0;
427     l->next = NULL;
428     l->pic = NULL;
429     l->for_arrow = NULL;
430     l->back_arrow = NULL;
431     l->points = NULL;
432     l->radius = DEFAULT;
433     l->comments = NULL;
434     return l;
435 }
436 
437 F_pic	       *
create_pic(void)438 create_pic(void)
439 {
440     F_pic	   *pic;
441 
442     if ((pic = (F_pic *) malloc(PIC_SIZE)) == NULL) {
443 	put_msg(Err_mem);
444 	return NULL;
445     }
446     pic->mask = (Pixmap) 0;
447     pic->new = False;
448     pic->pic_cache = NULL;
449     return pic;
450 }
451 
452 /* create a new picture entry for the repository */
453 
454 struct _pics *
create_picture_entry(void)455 create_picture_entry(void)
456 {
457     struct _pics *picture;
458 
459     picture = malloc(sizeof(struct _pics));
460 
461     picture->file = NULL;
462     picture->bitmap = NULL;
463     picture->transp = TRANSP_NONE;
464     picture->numcols = 0;
465     picture->refcount = 0;
466     picture->prev = picture->next = NULL;
467     if (appres.DEBUG)
468 	fprintf(stderr,"create picture entry %p\n", picture);
469     return picture;
470 }
471 
472 F_line	       *
copy_line(F_line * l)473 copy_line(F_line *l)
474 {
475     F_line	   *line;
476     F_arrow	   *arrow;
477     int		    width, height;
478     GC		    one_bit_gc;
479 
480     if ((line = create_line()) == NULL)
481 	return NULL;
482 
483     /* copy static items first */
484     *line = *l;
485     line->next = NULL;
486 
487     /* do comments next */
488     copy_comments(&l->comments, &line->comments);
489 
490     if (l->for_arrow) {
491 	if ((arrow = create_arrow()) == NULL) {
492 	    free((char *) line);
493 	    return NULL;
494 	}
495 	line->for_arrow = arrow;
496 	*arrow = *l->for_arrow;
497     }
498     if (l->back_arrow) {
499 	if ((arrow = create_arrow()) == NULL) {
500 	    free((char *) line);
501 	    return NULL;
502 	}
503 	line->back_arrow = arrow;
504 	*arrow = *l->back_arrow;
505     }
506     line->points = copy_points(l->points);
507     if (NULL == line->points) {
508 	put_msg(Err_mem);
509 	free_linestorage(line);
510 	return NULL;
511     }
512     /* copy picture information */
513     if (l->pic) {
514 	if ((line->pic = create_pic()) == NULL) {
515 	    free((char *) line);
516 	    return NULL;
517 	}
518 	/* copy all the numbers and the pointer to the picture repository (pic->pic_cache) */
519 	memcpy(line->pic, l->pic, PIC_SIZE);
520 	/* increase reference count for this picture */
521 	if (line->pic->pic_cache)
522 	    line->pic->pic_cache->refcount++;
523 
524 	width = l->pic->pix_width;
525 	height = l->pic->pix_height;
526 	/* copy pixmap */
527 	if (l->pic->pixmap != 0) {
528 	    line->pic->pixmap = XCreatePixmap(tool_d, tool_w,
529 				width, height, tool_dpth);
530 	    XCopyArea(tool_d, l->pic->pixmap, line->pic->pixmap, gccache[PAINT],
531 				0, 0, width, height, 0, 0);
532 	}
533 	/* and copy any mask (GIF transparency) */
534 	if (l->pic->mask != 0) {
535             line->pic->mask = XCreatePixmap(tool_d, tool_w, width, height, 1);
536 	    /* need a 1-bit deep GC to copy it */
537 	    one_bit_gc = XCreateGC(tool_d, line->pic->mask, (unsigned long) 0, 0);
538 	    XSetForeground(tool_d, one_bit_gc, 0);
539 	    XCopyArea(tool_d, l->pic->mask, line->pic->mask, one_bit_gc,
540 				0, 0, width, height, 0, 0);
541 	}
542     }
543     return line;
544 }
545 
546 /************************ SPLINES *************************/
547 
548 F_spline       *
create_spline(void)549 create_spline(void)
550 {
551     F_spline	   *s;
552 
553     if ((s = (F_spline *) malloc(SPLOBJ_SIZE)) == NULL) {
554 	put_msg(Err_mem);
555 	return NULL;
556     }
557     s->tagged = 0;
558     s->next = NULL;
559     s->comments = NULL;
560     return s;
561 }
562 
563 F_spline       *
copy_spline(F_spline * s)564 copy_spline(F_spline *s)
565 {
566     F_spline	   *spline;
567     F_arrow	   *arrow;
568 
569     if ((spline = create_spline()) == NULL)
570 	return NULL;
571 
572     /* copy static items first */
573     *spline = *s;
574     spline->next = NULL;
575 
576     /* do comments next */
577     copy_comments(&s->comments, &spline->comments);
578 
579     if (s->for_arrow) {
580 	if ((arrow = create_arrow()) == NULL) {
581 	    free((char *) spline);
582 	    return NULL;
583 	}
584 	spline->for_arrow = arrow;
585 	*arrow = *s->for_arrow;
586     }
587     if (s->back_arrow) {
588 	if ((arrow = create_arrow()) == NULL) {
589 	    free((char *) spline);
590 	    return NULL;
591 	}
592 	spline->back_arrow = arrow;
593 	*arrow = *s->back_arrow;
594     }
595     spline->points = copy_points(s->points);
596     if (NULL == spline->points) {
597 	put_msg(Err_mem);
598 	free_splinestorage(spline);
599 	return NULL;
600     }
601 
602     if (s->sfactors == NULL)
603 	return spline;
604     spline->sfactors = copy_sfactors(s->sfactors);
605     if (NULL == spline->sfactors) {
606 	put_msg(Err_mem);
607 	free_splinestorage(spline);
608 	return NULL;
609     }
610 
611     return spline;
612 }
613 
614 /************************ TEXTS *************************/
615 
616 F_text	       *
create_text(void)617 create_text(void)
618 {
619     F_text	   *t;
620 
621     if ((t = (F_text *) malloc(TEXOBJ_SIZE)) == NULL) {
622 	put_msg(Err_mem);
623 	return NULL;
624     }
625     t->tagged = 0;
626     t->fontstruct = 0;
627     t->comments = NULL;
628     t->cstring = NULL;
629     t->next = NULL;
630     return t;
631 }
632 
633 /* allocate len+1 characters in a new string */
634 
635 char	       *
new_string(int len)636 new_string(int len)
637 {
638     char	   *c;
639 
640     if ((c = (char *) calloc((unsigned) len + 1, sizeof(char))) == NULL)
641 	put_msg(Err_mem);
642     return c;
643 }
644 
645 F_text	       *
copy_text(F_text * t)646 copy_text(F_text *t)
647 {
648     F_text	   *text;
649 
650     if ((text = create_text()) == NULL)
651 	return NULL;
652 
653     /* copy static items first */
654     *text = *t;
655     text->next = NULL;
656 
657     /* do comments next */
658     copy_comments(&t->comments, &text->comments);
659 
660     if ((text->cstring = new_string(strlen(t->cstring))) == NULL) {
661 	free((char *) text);
662 	return NULL;
663     }
664     strcpy(text->cstring, t->cstring);
665     return text;
666 }
667 
668 /************************ COMPOUNDS *************************/
669 
670 F_compound     *
create_compound(void)671 create_compound(void)
672 {
673     F_compound	   *c;
674 
675     if ((c = (F_compound *) malloc(COMOBJ_SIZE)) == NULL) {
676 	put_msg(Err_mem);
677 	return NULL;
678     }
679     c->nwcorner.x = 0;
680     c->nwcorner.y = 0;
681     c->secorner.x = 0;
682     c->secorner.y = 0;
683     c->distrib = 0;
684     c->tagged = 0;
685     c->arcs = NULL;
686     c->compounds = NULL;
687     c->ellipses = NULL;
688     c->lines = NULL;
689     c->splines = NULL;
690     c->texts = NULL;
691     c->comments = NULL;
692     c->parent = NULL;
693     c->GABPtr = NULL;
694     c->next = NULL;
695 
696     return c;
697 }
698 
699 F_compound     *
copy_compound(F_compound * c)700 copy_compound(F_compound *c)
701 {
702     F_ellipse	   *e, *ee;
703     F_arc	   *a, *aa;
704     F_line	   *l, *ll;
705     F_spline	   *s, *ss;
706     F_text	   *t, *tt;
707     F_compound	   *cc, *ccc, *compound;
708 
709     if ((compound = create_compound()) == NULL)
710 	return NULL;
711 
712     compound->nwcorner = c->nwcorner;
713     compound->secorner = c->secorner;
714     compound->arcs = NULL;
715     compound->ellipses = NULL;
716     compound->lines = NULL;
717     compound->splines = NULL;
718     compound->texts = NULL;
719     compound->compounds = NULL;
720     compound->next = NULL;
721 
722     /* do comments first */
723     copy_comments(&c->comments, &compound->comments);
724 
725     for (e = c->ellipses; e != NULL; e = e->next) {
726 	if (NULL == (ee = copy_ellipse(e))) {
727 	    put_msg(Err_mem);
728 	    return NULL;
729 	}
730 	list_add_ellipse(&compound->ellipses, ee);
731     }
732     for (a = c->arcs; a != NULL; a = a->next) {
733 	if (NULL == (aa = copy_arc(a))) {
734 	    put_msg(Err_mem);
735 	    return NULL;
736 	}
737 	list_add_arc(&compound->arcs, aa);
738     }
739     for (l = c->lines; l != NULL; l = l->next) {
740 	if (NULL == (ll = copy_line(l))) {
741 	    put_msg(Err_mem);
742 	    return NULL;
743 	}
744 	list_add_line(&compound->lines, ll);
745     }
746     for (s = c->splines; s != NULL; s = s->next) {
747 	if (NULL == (ss = copy_spline(s))) {
748 	    put_msg(Err_mem);
749 	    return NULL;
750 	}
751 	list_add_spline(&compound->splines, ss);
752     }
753     for (t = c->texts; t != NULL; t = t->next) {
754 	if (NULL == (tt = copy_text(t))) {
755 	    put_msg(Err_mem);
756 	    return NULL;
757 	}
758 	list_add_text(&compound->texts, tt);
759     }
760     for (cc = c->compounds; cc != NULL; cc = cc->next) {
761 	if (NULL == (ccc = copy_compound(cc))) {
762 	    put_msg(Err_mem);
763 	    return NULL;
764 	}
765 	list_add_compound(&compound->compounds, ccc);
766     }
767     return compound;
768 }
769 
770 /********************** DIMENSION LINES **********************/
771 
772 /* Make a dimension line given an ordinary line
773 
774    It consists of:
775    1. the line drawn by the user,
776    2. "tick" lines at each endpoint if cur_dimline_ticks == True,
777    3. the length in a box overlaid in the middle of the line
778 
779    all rolled into a compound object
780 
781    Call with add_to_figure = True to add to main figure objects
782 */
783 
784 F_compound*
create_dimension_line(F_line * line,Boolean add_to_figure)785 create_dimension_line(F_line *line, Boolean add_to_figure)
786 {
787     F_compound	   *comp;
788     F_line	   *box, *tick1, *tick2;
789     F_text	   *text;
790     F_point	   *pnt;
791 
792     /* make a new compound */
793     comp = create_compound();
794     /* if fixed text, put in an unchanging comment for the compound */
795     /* (rescale_dimension_line will create the comment if the text not fixed (=length)) */
796     if (cur_dimline_fixed) {
797 	comp->comments = strdup("Dimension line: User-defined text");
798     } else {
799 	comp->comments = strdup("Dimension line:");
800     }
801 
802     /* need two objects *on top of* the basic line */
803     if (line->depth < 2) {
804 	line->depth = 2;
805     }
806 
807     /* put the main line in the compound */
808     comp->lines = line;
809 
810     /* put a comment in the main line */
811     line->comments = strdup("main dimension line");
812     line->thickness = cur_dimline_thick;
813     line->fill_style = UNFILLED;
814     line->style = cur_dimline_style;
815     if (line->style == DOTTED_LINE)
816 	line->style_val = cur_dotgap * (cur_dimline_thick + 1) / 2;
817     else
818 	line->style_val = cur_dashlength * (cur_dimline_thick + 1) / 2;
819     line->pen_color = cur_dimline_color;
820     if (cur_dimline_leftarrow != -1) {
821 	line->back_arrow = backward_dim_arrow();
822     }
823     if (cur_dimline_rightarrow != -1) {
824 	line->for_arrow = forward_dim_arrow();
825     }
826 
827     /***************************************/
828     /* make the text object for the length */
829     /***************************************/
830 
831     text = create_text();
832     text->depth  = line->depth-2;
833     text->cstring = (char *) NULL;	/* the string will be put in later */
834     text->color = cur_dimline_textcolor;
835     text->font = cur_dimline_font;
836     text->size = cur_dimline_fontsize;
837     text->flags = cur_dimline_psflag? PSFONT_TEXT: 0;
838     text->pen_style = -1;
839     text->type = T_CENTER_JUSTIFIED;
840 
841     /* put it in the compound */
842     comp->texts = text;
843 
844     /*****************************/
845     /* make the box for the text */
846     /*****************************/
847 
848     box = create_line();
849     box->comments = strdup("text box");
850     box->depth = line->depth-1;
851     box->type = T_POLYGON;
852     box->style = SOLID_LINE;
853     box->style_val = 0.0;
854     box->thickness = cur_dimline_boxthick;
855     box->pen_color = cur_pencolor;
856     box->fill_color = cur_dimline_boxcolor;
857     box->fill_style = NUMSHADEPATS-1;	 /* full saturation color */
858     box->pen_style = -1;
859     box->join_style = cur_joinstyle;
860     box->cap_style = CAP_BUTT;
861 
862     /* make 5 points for the box */
863     pnt = create_point();
864     box->points = pnt;
865     pnt->next = create_point();
866     pnt = pnt->next;
867     pnt->next = create_point();
868     pnt = pnt->next;
869     pnt->next = create_point();
870     pnt = pnt->next;
871     pnt->next = create_point();
872 
873     /* add this to the lines in the compound */
874     comp->lines->next = box;
875 
876     /********************************************************************/
877     /* make the two ticks at the endpoints if cur_dimline_ticks == True */
878     /********************************************************************/
879 
880     if (cur_dimline_ticks) {
881 	create_dimline_ticks(line, &tick1, &tick2);
882 
883 	/* add this to the lines in the compound */
884 	box->next = tick1;
885 
886 	/* add this to the lines in the compound */
887 	tick1->next = tick2;
888     } else
889 	box->next = (F_line *) NULL;
890 
891     /* if user wants fixed text, add an empty string and a comment to the text part. */
892     if (cur_dimline_fixed) {
893 	text->comments = strdup("fixed text");
894 	/* if not adding to figure, this must be the dimension line setting panel */
895 	if (!add_to_figure)
896 	    text->cstring = strdup("user text");
897 	else
898 	    text->cstring = strdup("");
899     }
900 
901     /* add it to the figure */
902     if (add_to_figure) {
903 	add_compound(comp);
904 	/* if fixed text, popup editor so user can edit text */
905 	if (cur_dimline_fixed) {
906 	    clear_mousefun();
907 	    set_mousefun("","","", "", "", "");
908 	    turn_off_current();
909 	    set_cursor(arrow_cursor);
910 	    /* make the shapes (ticks, etc) */
911 	    rescale_dimension_line(comp, 1.0, 1.0, 0, 0);
912 	    /* tells the editor to switch back to line mode when done */
913 	    edit_remember_dimline_mode = True;
914 	    /* now let the user change the text */
915 	    edit_item(comp, O_COMPOUND, 0, 0);
916 	}
917     }
918     /* calculate angles, box size etc */
919     /* if user just edited it (both cur_dimline_fixed and add_to_figure = True) then
920        it has already been scaled */
921     if (!cur_dimline_fixed || !add_to_figure) {
922 	rescale_dimension_line(comp, 1.0, 1.0, 0, 0);
923     }
924 
925     /* return it to the caller */
926     return comp;
927 }
928 
929 /*
930  * make the two ticks for the endpoints
931  * the actual values of the ticks' points are computed in rescale_dimension_line()
932  */
933 
934 void
create_dimline_ticks(F_line * line,F_line ** tick1,F_line ** tick2)935 create_dimline_ticks(F_line *line, F_line **tick1, F_line **tick2)
936 {
937 	F_point	   *pnt;
938 	F_line	   *tick;
939 
940 	/* first tick */
941 
942 	tick = create_line();
943 	/* copy the attributes from the main line */
944 	*tick = *line;
945 	/* set thickness */
946 	tick->thickness = cur_dimline_tickthick;
947 	/* make solid */
948 	tick->style = SOLID_LINE;
949 	tick->comments = strdup("tick");
950 	/* zero the arrows and next pointer */
951 	tick->for_arrow = tick->back_arrow = (F_arrow *) NULL;
952 	tick->next = (F_line *) NULL;
953 	pnt = create_point();
954 	tick->points = pnt;
955 	pnt->next = create_point();
956 	*tick1 = tick;
957 
958 	/* now the other tick */
959 
960 	tick = create_line();
961 	/* copy the attributes from the main line */
962 	*tick = *line;
963 	/* set thickness */
964 	tick->thickness = cur_dimline_tickthick;
965 	/* make solid */
966 	tick->style = SOLID_LINE;
967 	tick->comments = strdup("tick");
968 	/* zero the arrows and next pointer */
969 	tick->for_arrow = tick->back_arrow = (F_arrow *) NULL;
970 	tick->next = (F_line *) NULL;
971 	pnt = create_point();
972 	tick->points = pnt;
973 	pnt->next = create_point();
974 	*tick2 = tick;
975 }
976 
977 F_arrow*
backward_dim_arrow(void)978 backward_dim_arrow(void)
979 {
980     F_arrow	   *a;
981 
982     if ((a = create_arrow()) == NULL) {
983 	put_msg("Running out of memory");
984 	return NULL;
985     }
986 
987     a->type = ARROW_TYPE(cur_dimline_leftarrow);
988     a->style = ARROW_STYLE(cur_dimline_leftarrow);
989     a->thickness = cur_dimline_thick;
990     if (a->thickness == 0.0)
991 	    a->thickness = 1.0;
992     a->wd = cur_dimline_arrowwidth*cur_dimline_thick;
993     a->ht = cur_dimline_arrowlength*cur_dimline_thick;
994     if (a->wd == 0.0)
995 	    a->wd = 1.0;
996     if (a->ht == 0.0)
997 	    a->ht = 1.0;
998     return a;
999 }
1000 
1001 F_arrow*
forward_dim_arrow(void)1002 forward_dim_arrow(void)
1003 {
1004     F_arrow	   *a;
1005 
1006     if ((a = create_arrow()) == NULL) {
1007 	put_msg("Running out of memory");
1008 	return NULL;
1009     }
1010 
1011     a->type = ARROW_TYPE(cur_dimline_rightarrow);
1012     a->style = ARROW_STYLE(cur_dimline_rightarrow);
1013     a->thickness = cur_dimline_thick;
1014     if (a->thickness == 0.0)
1015 	    a->thickness = 1.0;
1016     a->wd = cur_dimline_arrowwidth*cur_dimline_thick;
1017     a->ht = cur_dimline_arrowlength*cur_dimline_thick;
1018     if (a->wd == 0.0)
1019 	    a->wd = 1.0;
1020     if (a->ht == 0.0)
1021 	    a->ht = 1.0;
1022     return a;
1023 }
1024