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  *
7  * Any party obtaining a copy of these files is granted, free of charge, a
8  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
9  * nonexclusive right and license to deal in this software and documentation
10  * files (the "Software"), including without limitation the rights to use,
11  * copy, modify, merge, publish, distribute, sublicense and/or sell copies of
12  * the Software, and to permit persons who receive copies from any such
13  * party to do so, with the only requirement being that the above copyright
14  * and this permission notice remain intact.
15  *
16  */
17 
18 
19 /* This is for the message window below the command panel */
20 /* The popup message window is handled in the second part of this file */
21 
22 #include "fig.h"
23 #include "figx.h"
24 #include <stdarg.h>
25 #include "resources.h"
26 #include "object.h"
27 #include "mode.h"
28 #include "d_line.h"
29 #include "f_read.h"
30 #include "f_util.h"
31 #include "paintop.h"
32 #include "u_elastic.h"
33 #include "w_canvas.h"
34 #include "w_drawprim.h"
35 #include "w_file.h"
36 #include "w_indpanel.h"
37 #include "w_msgpanel.h"
38 #include "w_util.h"
39 #include "w_setup.h"
40 #include "w_zoom.h"
41 
42 #include "u_geom.h"
43 #include "w_color.h"
44 
45 /********************* EXPORTS *******************/
46 
47 Boolean		popup_up = False;
48 Boolean		file_msg_is_popped=False;
49 Widget		file_msg_popup;
50 Boolean		first_file_msg;
51 Boolean		first_lenmsg = True;
52 
53 /************************  LOCAL ******************/
54 
55 #define		BUF_SIZE		500
56 static char	prompt[BUF_SIZE];
57 
58 DeclareStaticArgs(12);
59 
60 /* for the popup message (file_msg) window */
61 
62 static int	file_msg_length=0;
63 static char	tmpstr[512];
64 static Widget	file_msg_panel,
65 		file_msg_win, file_msg_dismiss;
66 
67 static String	file_msg_translations =
68 	"<Message>WM_PROTOCOLS: DismissFileMsg()";
69 
70 static String	file_msg2_translations =
71 	"<Key>Return: DismissFileMsg()\n\
72 	<Key>Escape: DismissFileMsg()";
73 
74 static void file_msg_panel_dismiss(Widget w, XButtonEvent *ev);
75 static XtActionsRec	file_msg_actions[] =
76 {
77     {"DismissFileMsg", (XtActionProc) file_msg_panel_dismiss},
78 };
79 
80 /* message window code begins */
81 
82 void
init_msg(Widget tool)83 init_msg(Widget tool)
84 {
85     /* now the message panel */
86     FirstArg(XtNfont, roman_font);
87     NextArg(XtNwidth, MSGPANEL_WD);
88     NextArg(XtNheight, MSGPANEL_HT);
89     NextArg(XtNstring, "\0");
90     NextArg(XtNfromVert, cmd_form);
91     NextArg(XtNvertDistance, -INTERNAL_BW);
92     NextArg(XtNborderWidth, INTERNAL_BW);
93     NextArg(XtNtopMargin, 1);
94     NextArg(XtNbottomMargin, 1);
95     NextArg(XtNdisplayCaret, False);
96     NextArg(XtNtop, XtChainTop);
97     NextArg(XtNbottom, XtChainTop);
98     msg_panel = XtCreateManagedWidget("message", asciiTextWidgetClass, tool,
99 				      Args, ArgCount);
100 }
101 
102 /* at this point the widget has been realized so we can do more */
103 
setup_msg(void)104 void setup_msg(void)
105 {
106     if (msg_win == 0)
107 	msg_win = XtWindow(msg_panel);
108     XDefineCursor(tool_d, msg_win, null_cursor);
109 }
110 
111 /* put a message in the message window below the command button panel */
112 /* if global update_figs is true, do a fprintf(stderr,msg) instead of in the window */
113 
114 /* VARARGS1 */
115 void
put_msg(char * format,...)116 put_msg(char *format,...)
117 {
118     va_list ap;
119 
120     va_start(ap, format);
121     vsprintf(prompt, format, ap );
122     va_end(ap);
123     if (update_figs) {
124 	fprintf(stderr,"%s\n",prompt);
125     } else {
126 	FirstArg(XtNstring, prompt);
127 	SetValues(msg_panel);
128     }
129 }
130 
131 static int	  ox = 0,
132 		  oy = 0,
133 		 ofx = 0,
134 		 ofy = 0,
135 		ot1x = 0,
136 		ot1y = 0,
137 		ot2x = 0,
138 		ot2y = 0,
139 		ot3x = 0,
140 		ot3y = 0;
141 
142 static char	bufx[20], bufy[20], bufhyp[20];
143 
144 void
boxsize_msg(int fact)145 boxsize_msg(int fact)
146 {
147     float	dx, dy;
148     int		sdx, sdy;
149     int		t1x, t1y, t2x, t2y;
150     PR_SIZE	sizex, sizey;
151     float	sc_fact, old_dx, old_dy, new_dx, new_dy;
152     float	udx, udy;
153     char	dxstr[80],dystr[80];
154 
155     old_dx = (float)(abs(from_x - fix_x));
156     old_dy = (float)(abs(from_y - fix_y));
157     new_dx = (float)(abs(cur_x - fix_x));
158     new_dy = (float)(abs(cur_y - fix_y));
159     /* compute reasonable scale factor */
160     if ((old_dx != 0.0) && (new_dx != 0.0))
161       sc_fact = new_dx / old_dx;
162     else if ((old_dy != 0.0) && (new_dy != 0.0))
163       sc_fact = new_dy / old_dy;
164     else
165       sc_fact = 0.0;
166 
167     dx = (float) fact * (cur_x - fix_x);
168     dy = (float) fact * (cur_y - fix_y);
169     make_dimension_string(fabs(dx), dxstr, False);
170     make_dimension_string(fabs(dy), dystr, False);
171     put_msg("Width = %s, Height = %s, Factor = %.3f", dxstr, dystr, sc_fact);
172 
173     /* if showing line lengths */
174     if (appres.showlengths && !freehand_line) {
175 	if (dx < 0)
176 	    sdx = -2.0/zoomscale;
177 	else
178 	    sdx = 2.0/zoomscale;
179 	if (dy < 0)
180 	    sdy = 2.0/zoomscale;
181 	else
182 	    sdy = -2.0/zoomscale;
183 
184 	/* erase old text */
185 	if (!first_lenmsg) {
186 	    pw_text(canvas_win, ot1x, ot1y, INV_PAINT, MAX_DEPTH+1, roman_font, 0.0, bufx,
187 			RED, COLOR_NONE);
188 	    pw_text(canvas_win, ot2x, ot2y, INV_PAINT, MAX_DEPTH+1, roman_font, 0.0, bufy,
189 			RED, COLOR_NONE);
190 	}
191 	first_lenmsg = False;
192 
193 	/* draw new text */
194 
195 	/* in user units */
196 	udx = dx*appres.userscale /(double)(appres.INCHES? PIX_PER_INCH: PIX_PER_CM);
197 	udy = dy*appres.userscale /(double)(appres.INCHES? PIX_PER_INCH: PIX_PER_CM);
198 	sprintf(bufx,"%.3f", fabs(udx));
199 	sizex = textsize(roman_font, strlen(bufx), bufx);
200 	sprintf(bufy,"%.3f", fabs(udy));
201 	sizey = textsize(roman_font, strlen(bufy), bufy);
202 
203 	/* dx first */
204 	t1x = (cur_x+fix_x)/2;
205 	if (dy < 0)
206 	    t1y = cur_y + sdy - 5.0/zoomscale;			/* above the line */
207 	else
208 	    t1y = cur_y + sdy + sizey.ascent + 5.0/zoomscale;	/* below the line */
209 	pw_text(canvas_win, t1x, t1y, INV_PAINT, MAX_DEPTH+1, roman_font, 0.0, bufx,
210 			RED, COLOR_NONE);
211 
212 	/* then dy */
213 	t2y = (cur_y+fix_y)/2+sdy;
214 	if (dx < 0)
215 	    t2x = fix_x + sdx + 5.0/zoomscale;			/* right of the line */
216 	else
217 	    t2x = fix_x + sdx - sizex.length - 4.0/zoomscale;	/* left of the line */
218 	pw_text(canvas_win, t2x, t2y, INV_PAINT, MAX_DEPTH+1, roman_font, 0.0, bufy,
219 			RED, COLOR_NONE);
220 
221 	/* now save new values */
222 	ot1x = t1x;
223 	ot1y = t1y;
224 	ot2x = t2x;
225 	ot2y = t2y;
226 	ox = cur_x+sdx;
227 	oy = cur_y+sdy;
228     }
229 }
230 
boxsize_scale_msg(int fact)231 void boxsize_scale_msg(int fact)
232 {
233     float	dx, dy;
234     float	sc_fact, old_dx, old_dy, new_dx, new_dy;
235     char	dxstr[80],dystr[80];
236 
237     old_dx = (float)(abs(from_x - fix_x));
238     old_dy = (float)(abs(from_y - fix_y));
239     new_dx = (float)(abs(cur_x - fix_x));
240     new_dy = (float)(abs(cur_y - fix_y));
241     dx = (float) fact * abs(cur_x - fix_x);
242     dy = (float) fact * abs(cur_y - fix_y);
243     make_dimension_string(dx, dxstr, False);
244     make_dimension_string(dy, dystr, False);
245     /* compute reasonable scale factor */
246     if ((old_dx != 0.0) && (new_dx != 0.0))
247       sc_fact = new_dx / old_dx;
248     else if ((old_dy != 0.0) && (new_dy != 0.0))
249       sc_fact = new_dy / old_dy;
250     else
251       sc_fact = 0.0;
252     put_msg("Width = %s, Length = %s, Factor = %.3f", dxstr, dystr, sc_fact);
253 }
254 
erase_box_lengths(void)255 void erase_box_lengths(void)
256 {
257     if (!first_lenmsg && appres.showlengths && !freehand_line) {
258 	/* erase old text */
259 	pw_text(canvas_win, ot1x, ot1y, INV_PAINT, MAX_DEPTH+1, roman_font, 0.0, bufx,
260 			RED, COLOR_NONE);
261 	pw_text(canvas_win, ot2x, ot2y, INV_PAINT, MAX_DEPTH+1, roman_font, 0.0, bufy,
262 			RED, COLOR_NONE);
263     }
264     first_lenmsg = False;
265 }
266 
erase_lengths(void)267 void erase_lengths(void)
268 {
269     if (!first_lenmsg && appres.showlengths && !freehand_line) {
270 	/* erase old lines first */
271 	pw_vector(canvas_win,  ox, oy, ofx,  oy, INV_PAINT, 1, RUBBER_LINE, 0.0, RED);
272 	pw_vector(canvas_win, ofx, oy, ofx, ofy, INV_PAINT, 1, RUBBER_LINE, 0.0, RED);
273 
274 	/* erase old text */
275 	pw_text(canvas_win, ot1x, ot1y, INV_PAINT, MAX_DEPTH+1, roman_font, 0.0, bufx,
276 			RED, COLOR_NONE);
277 	pw_text(canvas_win, ot2x, ot2y, INV_PAINT, MAX_DEPTH+1, roman_font, 0.0, bufy,
278 			RED, COLOR_NONE);
279 	pw_text(canvas_win, ot3x, ot3y, INV_PAINT, MAX_DEPTH+1, roman_font, 0.0, bufhyp,
280 			RED, COLOR_NONE);
281     }
282     first_lenmsg = False;
283 }
284 
285 void
length_msg(int type)286 length_msg(int type)
287 {
288     altlength_msg(type, fix_x, fix_y);
289 }
290 
291 /*
292 ** In typical usage, point fx,fy is the fixed point.
293 ** Distance will be measured from it to cur_x,cur_y.
294 */
295 
296 void
altlength_msg(int type,int fx,int fy)297 altlength_msg(int type, int fx, int fy)
298 {
299   double	dx,dy;
300   float		len, ulen;
301   float		udx, udy;
302   float		ang;
303   int		sdx, sdy;
304   int		t1x, t1y, t2x, t2y, t3x, t3y;
305   PR_SIZE	sizex, sizey, sizehyp;
306   char		lenstr[80],dxstr[80],dystr[80];
307 
308   dx = (cur_x - fx);
309   dy = (cur_y - fy);
310   len = (float) sqrt(dx*dx + dy*dy);
311   make_dimension_string(dx, dxstr, False);
312   make_dimension_string(dy, dystr, False);
313   make_dimension_string(len, lenstr, False);
314 
315   /* in user units */
316   udx = dx*appres.userscale /(double)(appres.INCHES? PIX_PER_INCH: PIX_PER_CM);
317   udy = dy*appres.userscale /(double)(appres.INCHES? PIX_PER_INCH: PIX_PER_CM);
318   ulen = len*appres.userscale /(double)(appres.INCHES? PIX_PER_INCH: PIX_PER_CM);
319 
320   if (dy != 0.0 || dx != 0.0) {
321 	ang = (float) - atan2(dy,dx) * 180.0/M_PI;
322   } else {
323 	ang = 0.0;
324   }
325   switch (type) {
326     case MSG_RADIUS:
327     case MSG_DIAM:
328 	put_msg("%s = %s, dx = %s, dy = %s",
329                 (type==MSG_RADIUS? "Radius": "Diameter"),
330 		lenstr, dxstr, dystr);
331 	break;
332     case MSG_RADIUS2:
333 	put_msg("Radius1 = %s, Radius2 = %s",
334 		dxstr, dystr);
335 	break;
336     case MSG_PNTS_LENGTH:
337 	put_msg("%d point%s, Length = %s, dx = %s, dy = %s (%.1f deg)",
338 		num_point, ((num_point != 1)? "s": ""),
339 		lenstr, dxstr, dystr, ang );
340 	break;
341     case MSG_RADIUS_ANGLE:
342     case MSG_DIAM_ANGLE:
343 	if (num_point == 0)
344 	  put_msg("%s = %s, Angle = %.1f deg",
345 		  (type==MSG_RADIUS_ANGLE? "Radius":"Diameter"),
346 		  lenstr, ang );
347 	else
348 	  put_msg("%d point%s, Angle = %.1f deg",
349 		  num_point, ((num_point != 1)? "s": ""), ang );
350 	break;
351     default:
352 	put_msg("%s = %s, dx = %s, dy = %s (%.1f) deg",
353 		(type==MSG_LENGTH? "Length": "Distance"),
354 		lenstr, dxstr, dystr, ang);
355 	break;
356   }
357 
358   /* now draw two lines to complete the triangle and label the two sides
359      with the lengths e.g.:
360 			      |\
361 			      | \
362 			      |  \
363 			2.531 |   \ 2.864
364 			      |    \
365 			      |     \
366 			      -------
367 				1.341
368   */
369 
370   if (dx < 0)
371 	sdx = 2.0/zoomscale;
372   else
373 	sdx = -2.0/zoomscale;
374   if (dy < 0)
375 	sdy = -2.0/zoomscale;
376   else
377 	sdy = 2.0/zoomscale;
378 
379   if (appres.showlengths && !freehand_line) {
380     switch (type) {
381 	case MSG_PNTS_LENGTH:
382 	case MSG_LENGTH:
383 	case MSG_DIST:
384 		if (!first_lenmsg) {
385 		    /* erase old lines first */
386 		    pw_vector(canvas_win,ox,oy,ofx,oy,INV_PAINT,1,RUBBER_LINE,0.0,RED);
387 		    pw_vector(canvas_win,ofx,oy,ofx,ofy,INV_PAINT,1,RUBBER_LINE,0.0,RED);
388 
389 		    /* erase old text */
390 		    pw_text(canvas_win, ot1x, ot1y, INV_PAINT, MAX_DEPTH+1, roman_font,
391 					0.0, bufx, RED, COLOR_NONE);
392 		    pw_text(canvas_win, ot2x, ot2y, INV_PAINT, MAX_DEPTH+1, roman_font,
393 					0.0, bufy, RED, COLOR_NONE);
394 		    pw_text(canvas_win, ot3x, ot3y, INV_PAINT, MAX_DEPTH+1, roman_font,
395 					0.0, bufhyp, RED, COLOR_NONE);
396 		}
397 
398 		/* draw new lines */
399 		/* horizontal (dx) */
400 		pw_vector(canvas_win, cur_x+sdx, cur_y+sdy, fx+sdx, cur_y+sdy, INV_PAINT, 1,
401 				RUBBER_LINE, 0.0, RED);
402 		/* vertical (dy) */
403 		pw_vector(canvas_win, fx+sdx, cur_y+sdy, fx+sdx, fy+sdy, INV_PAINT, 1,
404 				RUBBER_LINE, 0.0, RED);
405 
406 		/* draw new text */
407 
408 		/* put the lengths in strings and get their sizes for positioning */
409 		sprintf(bufx,"%.3f", fabs(udx));
410 		sizex = textsize(roman_font, strlen(bufx), bufx);
411 		sprintf(bufy,"%.3f", fabs(udy));
412 		sizey = textsize(roman_font, strlen(bufy), bufy);
413 		sprintf(bufhyp,"%.3f", ulen);
414 		sizehyp = textsize(roman_font, strlen(bufhyp), bufhyp);
415 
416 		/* dx first */
417 		t1x = (cur_x+fx)/2;
418 		if (dy < 0)
419 		    t1y = cur_y + sdy - 3.0/zoomscale;			/* above the line */
420 		else
421 		    t1y = cur_y + sdy + sizey.ascent + 3.0/zoomscale;	/* below the line */
422 		pw_text(canvas_win, t1x, t1y, INV_PAINT, MAX_DEPTH+1, roman_font, 0.0,
423 				bufx, RED, COLOR_NONE);
424 
425 		t2y = (cur_y+fy)/2+sdy;
426 		/* now dy */
427 		if (dx < 0)
428 		    t2x = fx + sdx + 4.0/zoomscale;			/* right of the line */
429 		else
430 		    t2x = fx + sdx - sizex.length - 4.0/zoomscale;	/* left of the line */
431 		pw_text(canvas_win, t2x, t2y, INV_PAINT, MAX_DEPTH+1, roman_font, 0.0,
432 				bufy, RED, COLOR_NONE);
433 
434 		/* finally, the hypotenuse */
435 		if (dx > 0)
436 		    t3x = t1x + 4.0/zoomscale;			/* right of the hyp */
437 		else
438 		    t3x = t1x - sizehyp.length - 4.0/zoomscale;	/* left of the hyp */
439 		if (dy < 0)
440 		    t3y = t2y + sizehyp.ascent + 3.0/zoomscale;	/* below the hyp */
441 		else
442 		    t3y = t2y - 3.0/zoomscale;			/* above the hyp */
443 		pw_text(canvas_win, t3x, t3y, INV_PAINT, MAX_DEPTH+1, roman_font, 0.0,
444 				bufhyp, RED, COLOR_NONE);
445 
446 		break;
447 
448 	default:
449 		break;
450     }
451     first_lenmsg = False;
452   }
453 
454   ot1x = t1x;
455   ot1y = t1y;
456   ot2x = t2x;
457   ot2y = t2y;
458   ot3x = t3x;
459   ot3y = t3y;
460   ox = cur_x+sdx;
461   oy = cur_y+sdy;
462   ofx = fx+sdx;
463   ofy = fy+sdy;
464 }
465 
466 /*
467  * In typical usage, point x3,y3 is the one that is moving,
468  * the other two are fixed.  Distances will be measured from
469  * points 1 -> 3 and 2 -> 3.
470  * Delta X and Y are measured from global from_x and from_y.
471  */
472 
473 void
length_msg2(int x1,int y1,int x2,int y2,int x3,int y3)474 length_msg2(int x1, int y1, int x2, int y2, int x3, int y3)
475 {
476     float	len1, len2;
477     double	dx1, dy1, dx2, dy2;
478     char	len1str[80], len2str[80];
479     char	dx1str[80], dy1str[80], dx2str[80], dy2str[80];
480 
481     len1=len2=0.0;
482     if (x1 != -999) {
483 	    dx1 = x3 - x1;
484 	    dy1 = y3 - y1;
485 	    len1 = (float)(sqrt(dx1*dx1 + dy1*dy1));
486     }
487     if (x2 != -999) {
488 	    dx2 = x3 - x2;
489 	    dy2 = y3 - y2;
490 	    len2 = (float)(sqrt(dx2*dx2 + dy2*dy2));
491     }
492     make_dimension_string(len1, len1str, False);
493     make_dimension_string(len2, len2str, False);
494     make_dimension_string(dx1, dx1str, False);
495     make_dimension_string(dy1, dy1str, False);
496     make_dimension_string(dx2, dx2str, False);
497     make_dimension_string(dy2, dy2str, False);
498     put_msg("Len 1 = %s, Len 2 = %s, dx1 = %s, dy1 = %s, dx2 = %s, dy2 = %s",
499 		len1str, len2str, dx1str, dy1str, dx2str, dy2str);
500 }
501 
502 /* x2,y2 moving middle point */
503 
504 void
arc_msg(int x1,int y1,int x2,int y2,int x3,int y3)505 arc_msg(int x1, int y1, int x2, int y2, int x3, int y3)
506 {
507     float	len1, len2, r;
508     double	dx1, dy1, dx2, dy2;
509     char	len1str[80], len2str[80], radstr[80];
510     char	dx1str[80], dy1str[80], dx2str[80], dy2str[80];
511 
512     if (!compute_arcradius(x1, y1, x2, y2, x3, y3, &r))
513 	length_msg2(x1, y1, x2, y2, x3, y3);
514     else {
515 	dx1 = x3 - x1;
516 	dy1 = y3 - y1;
517 	len1 = (float)(sqrt(dx1*dx1 + dy1*dy1));
518 	dx2 = x3 - x2;
519 	dy2 = y3 - y2;
520 	len2 = (float)(sqrt(dx2*dx2 + dy2*dy2));
521 	make_dimension_string(len1, len1str, False);
522 	make_dimension_string(len2, len2str, False);
523 	make_dimension_string(r, radstr, False);
524 	make_dimension_string(dx1, dx1str, False);
525 	make_dimension_string(dy1, dy1str, False);
526 	make_dimension_string(dx2, dx2str, False);
527 	make_dimension_string(dy2, dy2str, False);
528 	put_msg("Len 1 = %s, Len 2 = %s, Rad = %s, dx1 = %s, dy1 = %s, dx2 = %s, dy2 = %s",
529 		len1str, len2str, radstr, dx1str, dy1str, dx2str, dy2str);
530     }
531 }
532 
533 void
lenmeas_msg(char * msgtext,float len,float totlen)534 lenmeas_msg(char *msgtext, float len, float totlen)
535 {
536     char	lenstr[80],totlenstr[80];
537 
538     make_dimension_string(len, lenstr, False);
539     make_dimension_string(totlen, totlenstr, False);
540 
541     if (totlen >= 0.0)
542 	put_msg("Length of %s is %s, accumulated %s",
543              msgtext, lenstr, totlenstr);
544     else
545 	put_msg("Length of %s is %s",
546              msgtext, lenstr);
547 }
548 
549 void
areameas_msg(char * msgtext,float area,float totarea,int flag)550 areameas_msg(char *msgtext, float area, float totarea, int flag)
551 {
552     char	areastr[80],totareastr[80];
553 
554     make_dimension_string(area, areastr, True);
555     make_dimension_string(totarea, totareastr, True);
556     if (flag)
557 	put_msg("Area of %s is %s, accumulated %s",
558              msgtext, areastr, totareastr);
559     else
560 	put_msg("Area of %s is %s",
561              msgtext, areastr);
562 }
563 
564 
565 /* This is the section for the popup message window (file_msg) */
566 /* if global update_figs is true, do a fprintf(stderr,msg) instead of in the window */
567 
568 /* VARARGS1 */
569 void
file_msg(char * format,...)570 file_msg(char *format,...)
571 {
572     XawTextBlock block;
573     va_list ap;
574 
575     if (!update_figs) {
576 	popup_file_msg();
577 	if (first_file_msg) {
578 	    first_file_msg = False;
579 	    file_msg("---------------------");
580 	    file_msg("File %s:",read_file_name);
581 	}
582     }
583 
584     va_start(ap, format);
585     /* format the string (but leave room for \n and \0) */
586     vsnprintf(tmpstr, sizeof(tmpstr)-2, format, ap);
587     va_end(ap);
588 
589     strcat(tmpstr,"\n");
590     if (update_figs) {
591        fprintf(stderr, "%s", tmpstr);
592     } else {
593 	/* append this message to the file message widget string */
594 	block.firstPos = 0;
595 	block.ptr = tmpstr;
596 	block.length = strlen(tmpstr);
597 	block.format = FMT8BIT;
598 	/* make editable to add new message */
599 	FirstArg(XtNeditType, XawtextEdit);
600 	SetValues(file_msg_win);
601 	/* insert the new message after the end */
602 	(void) XawTextReplace(file_msg_win,file_msg_length,file_msg_length,&block);
603 	(void) XawTextSetInsertionPoint(file_msg_win,file_msg_length);
604 
605 	/* make read-only again */
606 	FirstArg(XtNeditType, XawtextRead);
607 	SetValues(file_msg_win);
608 	file_msg_length += block.length;
609     }
610 }
611 
612 static void
clear_file_message(Widget w,XButtonEvent * ev)613 clear_file_message(Widget w, XButtonEvent *ev)
614 {
615     XawTextBlock	block;
616     int			replcode;
617 
618     if (!file_msg_popup)
619 	return;
620 
621     tmpstr[0]=' ';
622     block.firstPos = 0;
623     block.ptr = tmpstr;
624     block.length = 1;
625     block.format = FMT8BIT;
626 
627     /* make editable to clear message */
628     FirstArg(XtNeditType, XawtextEdit);
629     NextArg(XtNdisplayPosition, 0);
630     SetValues(file_msg_win);
631 
632     /* replace all messages with one blank */
633     replcode = XawTextReplace(file_msg_win,0,file_msg_length,&block);
634     if (replcode == XawPositionError)
635 	fprintf(stderr,"XawTextReplace XawPositionError\n");
636     else if (replcode == XawEditError)
637 	fprintf(stderr,"XawTextReplace XawEditError\n");
638 
639     /* make read-only again */
640     FirstArg(XtNeditType, XawtextRead);
641     SetValues(file_msg_win);
642     file_msg_length = 0;
643 }
644 
645 static void
file_msg_panel_dismiss(Widget w,XButtonEvent * ev)646 file_msg_panel_dismiss(Widget w, XButtonEvent *ev)
647 {
648 	XtPopdown(file_msg_popup);
649 	file_msg_is_popped=False;
650 }
651 
652 void
popup_file_msg(void)653 popup_file_msg(void)
654 {
655 	if (file_msg_popup) {
656 	    if (!file_msg_is_popped) {
657 		XtPopup(file_msg_popup, XtGrabNone);
658 		XSetWMProtocols(tool_d, XtWindow(file_msg_popup), &wm_delete_window, 1);
659 	    }
660 	    /* ensure that the most recent colormap is installed */
661 	    set_cmap(XtWindow(file_msg_popup));
662 	    file_msg_is_popped = True;
663 	    return;
664 	}
665 
666 	file_msg_is_popped = True;
667 	FirstArg(XtNx, 0);
668 	NextArg(XtNy, 0);
669 	NextArg(XtNcolormap, tool_cm);
670 	NextArg(XtNtitle, "Xfig: Error messages");
671 	file_msg_popup = XtCreatePopupShell("file_msg",
672 					transientShellWidgetClass,
673 					tool, Args, ArgCount);
674 	XtOverrideTranslations(file_msg_popup,
675 			XtParseTranslationTable(file_msg_translations));
676 	XtAppAddActions(tool_app, file_msg_actions, XtNumber(file_msg_actions));
677 
678 	file_msg_panel = XtCreateManagedWidget("file_msg_panel", formWidgetClass,
679 					   file_msg_popup, NULL, ZERO);
680 	XtOverrideTranslations(file_msg_panel,
681 			   XtParseTranslationTable(file_msg2_translations));
682 
683 	FirstArg(XtNwidth, 500);
684 	NextArg(XtNheight, 200);
685 	NextArg(XtNeditType, XawtextRead);
686 	NextArg(XtNdisplayCaret, False);
687 	NextArg(XtNborderWidth, INTERNAL_BW);
688 	NextArg(XtNscrollHorizontal, XawtextScrollWhenNeeded);
689 	NextArg(XtNscrollVertical, XawtextScrollAlways);
690 	NextArg(XtNright, XtChainRight);
691 	NextArg(XtNbottom, XtChainBottom);
692 	file_msg_win = XtCreateManagedWidget("file_msg_win", asciiTextWidgetClass,
693 					     file_msg_panel, Args, ArgCount);
694 	XtOverrideTranslations(file_msg_win,
695 			   XtParseTranslationTable(file_msg2_translations));
696 
697 	FirstArg(XtNlabel, "Dismiss");
698 	NextArg(XtNheight, 25);
699 	NextArg(XtNborderWidth, INTERNAL_BW);
700 	NextArg(XtNfromVert, file_msg_win);
701 	NextArg(XtNtop, XtChainBottom);
702 	NextArg(XtNbottom, XtChainBottom);
703 	NextArg(XtNleft, XtChainLeft);
704 	NextArg(XtNright, XtChainLeft);
705 	file_msg_dismiss = XtCreateManagedWidget("dismiss", commandWidgetClass,
706 				       file_msg_panel, Args, ArgCount);
707 	XtAddEventHandler(file_msg_dismiss, ButtonReleaseMask, False,
708 			  (XtEventHandler)file_msg_panel_dismiss, (XtPointer) NULL);
709 
710 	FirstArg(XtNlabel, "Clear");
711 	NextArg(XtNheight, 25);
712 	NextArg(XtNborderWidth, INTERNAL_BW);
713 	NextArg(XtNfromVert, file_msg_win);
714 	NextArg(XtNfromHoriz, file_msg_dismiss);
715 	NextArg(XtNtop, XtChainBottom);
716 	NextArg(XtNbottom, XtChainBottom);
717 	NextArg(XtNleft, XtChainLeft);
718 	NextArg(XtNright, XtChainLeft);
719 	file_msg_dismiss = XtCreateManagedWidget("clear", commandWidgetClass,
720 				       file_msg_panel, Args, ArgCount);
721 	XtAddEventHandler(file_msg_dismiss, ButtonReleaseMask, False,
722 			  (XtEventHandler)clear_file_message, (XtPointer) NULL);
723 
724 	XtPopup(file_msg_popup, XtGrabNone);
725 	XSetWMProtocols(tool_d, XtWindow(file_msg_popup), &wm_delete_window, 1);
726 	/* insure that the most recent colormap is installed */
727 	set_cmap(XtWindow(file_msg_popup));
728 }
729 
730 /*
731    Make a string from the length.
732    If the units are inches and there is a fractional value *and*
733    cur_gridunit == FRACT_UNIT, try to make a fraction out of it, e.g. 3/64
734    If the units are area measure, pass square = True
735 */
736 
737 void
make_dimension_string(float length,char * str,Boolean square)738 make_dimension_string(float length, char *str, Boolean square)
739 {
740     float	 ulen;
741     int		 ilen, ifeet, ifract, iexp;
742     char	 tmpstr[100], *units, format[20];
743 
744     ulen = length/PIX_PER_INCH * appres.userscale;
745 
746     if (!appres.INCHES) {
747 	/* Metric */
748 	if (square)
749 	    sprintf(str, "%.3f square %s", length /
750 			(float)(PIX_PER_CM*PIX_PER_CM)*appres.userscale*appres.userscale,
751 			cur_fig_units);
752 	else {
753 	    /* make a %.xf format where x is the precision the user wants */
754           sprintf(format, "%%.%df %%s", cur_dimline_prec);
755           sprintf(str, format, length / PIX_PER_CM*appres.userscale, cur_fig_units);
756 	}
757 
758     /* Inches */
759     } else if (!square && (!display_fractions || (cur_gridunit != FRACT_UNIT))) {
760 	/* user doesn't want fractions or is in decimal units */
761 	/* make a %.xf format where x is the precision the user wants */
762 	sprintf(format, "%%.%df %%s", cur_dimline_prec);
763 	sprintf(str, format, ulen, cur_fig_units);
764     } else if (!square) {
765 	ilen = (int) ulen;
766 	units = cur_fig_units;
767 	if (ilen == ulen) {
768 	    /* integral */
769 	    sprintf(str, "%d %s", ilen, cur_fig_units);
770 	} else {
771 	    tmpstr[0] = '\0';
772 	    /* first see if the user units are f, ft or feet */
773 	    if (strcmp(cur_fig_units,"f") == 0 ||
774 				strcmp(cur_fig_units,"ft") == 0 ||
775 				strcmp(cur_fig_units,"feet") == 0) {
776 		    /* yes, start with the feet part */
777 		    ifeet = (int) ulen;
778 		    if (abs(ifeet) >= 1)
779 			sprintf(tmpstr,"%d %s ", ifeet, cur_fig_units);
780 		    ulen = (ulen - ifeet) * (square? 144.0: 12.0);
781 		    ilen = (int) ulen;
782 		    units = "in";	/* next part is inches */
783 	    }
784 	    /* see if it is a multiple of 1/64 */
785 	    ifract = (ulen - ilen) * 64.0;
786 	    if (ifract != 0) {
787 		if (ilen + ifract/64.0 == ulen) {
788 		    for (iexp=64; iexp >= 2; ) {
789 			if (ifract%2 == 0) {
790 			    ifract /= 2;
791 			    iexp /= 2;
792 			} else
793 			    break;
794 		    }
795 		    sprintf(str,"%s%d-%d/%d %s", tmpstr, abs(ilen), abs(ifract), iexp, units);
796 		} else {
797 		    /* decimal not near any fraction */
798 		    /* make a %.xf format where x is the precision the user wants */
799 		    sprintf(format, "%%s%%.%df %%s", cur_dimline_prec);
800 		    sprintf(str, format, tmpstr, ulen, units);
801 		}
802 	    } else {
803 		/* no fraction, whole inches */
804 		if (ifeet < 0)
805 		    ilen = abs(ilen);	/* if feet < 0, no need to report negative inches */
806 		sprintf(str,"%s%d %s", tmpstr, ilen, units);
807 	    }
808 	}
809     } else {
810 	/* square IP units */
811 	/* make a %.xf format where x is the precision the user wants */
812 	sprintf(format, "%%.%df square %%s", cur_dimline_prec);
813 	sprintf(str, format, length /
814 			(float)(PIX_PER_INCH*PIX_PER_INCH)*appres.userscale*appres.userscale,
815 			cur_fig_units);
816     }
817 }
818