1 /*----------------------------------------------------------------------*/
2 /* menucalls.c --- callback routines from the menu buttons, and 	*/
3 /*		   associated routines (either Tcl/Tk routines or	*/
4 /*		   non-specific;  Xt routines split off in file		*/
5 /*		   xtfuncs.c 3/28/06)					*/
6 /* Copyright (c) 2002  Tim Edwards, Johns Hopkins University        	*/
7 /*----------------------------------------------------------------------*/
8 
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <sys/types.h>
14 #include <errno.h>
15 #include <limits.h>
16 
17 #ifndef XC_WIN32
18 #include <X11/Intrinsic.h>
19 #include <X11/StringDefs.h>
20 #include <X11/Xutil.h>
21 #endif
22 
23 #ifdef TCL_WRAPPER
24 #include <tk.h>
25 #endif
26 
27 /*----------------------------------------------------------------------*/
28 /* Local includes							*/
29 /*----------------------------------------------------------------------*/
30 
31 #include "colordefs.h"
32 #include "xcircuit.h"
33 
34 /*----------------------------------------------------------------------*/
35 /* Function prototype declarations                                      */
36 /*----------------------------------------------------------------------*/
37 #include "prototypes.h"
38 
39 /*----------------------------------------------------------------------*/
40 /* External Variable definitions					*/
41 /*----------------------------------------------------------------------*/
42 
43 extern char	 _STR2[250];
44 extern char	 _STR[150];          /* Generic multipurpose string */
45 extern xcWidget	 top;
46 extern Display   *dpy;
47 extern Globaldata xobjs;
48 extern XCWindowData *areawin;
49 extern int	  number_colors;
50 extern colorindex *colorlist;
51 extern ApplicationData appdata;
52 extern Cursor	  appcursors[NUM_CURSORS];
53 extern fontinfo *fonts;
54 extern short fontcount;
55 
56 #ifdef TCL_WRAPPER
57 extern Tcl_Interp *xcinterp;
58 #endif
59 
60 /*----------------------------------------------------------------------*/
61 /* Local Variable definitions						*/
62 /*----------------------------------------------------------------------*/
63 
64 u_short *fontnumbers;
65 u_char nfontnumbers;
66 
67 /*----------------------------------------------*/
68 /* Set Poly and Arc line styles and fill styles */
69 /*----------------------------------------------*/
70 
71 #define BORDERS  (NOBORDER | DOTTED | DASHED)
72 #define ALLFILLS (FILLSOLID | FILLED)
73 
74 /*----------------------------------------------------------------*/
75 /* setgrid, getgridspace are for grid and snap spacing sizes;	  */
76 /* include routines to parse fractions				  */
77 /*----------------------------------------------------------------*/
78 
setgrid(xcWidget w,float * dataptr)79 void setgrid(xcWidget w, float *dataptr)
80 {
81    float oldvalue = *dataptr;
82    float oscale, iscale = (float)xobjs.pagelist[areawin->page]->drawingscale.y /
83         (float)xobjs.pagelist[areawin->page]->drawingscale.x;
84    float fval;
85 
86    /* For now, assume that the value is in the current display style. */
87    /* Might be nice in the future to make it accept any input. . .    */
88 
89    switch (xobjs.pagelist[areawin->page]->coordstyle) {
90       case INTERNAL:
91 	 if (sscanf(_STR2, "%f", &fval) == 0) {
92 	    *dataptr = oldvalue;
93 	    Wprintf("Illegal value");
94 	 }
95 	 else *dataptr = fval / iscale;
96 	 break;
97       case CM:
98          oscale = xobjs.pagelist[areawin->page]->outscale * CMSCALE;
99 	 if (sscanf(_STR2, "%f", &fval) == 0) {
100 	    *dataptr = oldvalue;
101 	    Wprintf("Illegal value");
102 	 }
103 	 else *dataptr = fval * IN_CM_CONVERT / (iscale * oscale);
104 	 break;
105       case DEC_INCH: case FRAC_INCH: {
106 	 short parts;
107 	 char *sptr;
108 	 int f2, f3;
109 
110          oscale = xobjs.pagelist[areawin->page]->outscale * INCHSCALE;
111 	 for (sptr = _STR2; *sptr != '\0'; sptr++)
112 	    if (*sptr == '/') *sptr = ' ';
113 	 parts = sscanf(_STR2, "%f %d %d", &fval, &f2, &f3);
114 	 if ((parts == 0) || (parts != 1 && (fval != (float)((int)fval)))) {
115 	    *dataptr = oldvalue;
116 	    Wprintf("Illegal value");
117 	    break;
118 	 }
119 	 if (parts == 2) fval /= (float)f2;
120 	 else if (parts == 3) fval += ((float)f2 / (float)f3);
121 	 *dataptr = fval * 72.0 / (iscale * oscale);
122 	 } break;
123    }
124    if (oldvalue != *dataptr) drawarea(NULL, NULL, NULL);
125 }
126 
127 /*----------------------------------------------------------------*/
128 /* Write a measurement value into string "buffer" dependant on    */
129 /* the current default units of measure (centimeters or inches).  */
130 /*----------------------------------------------------------------*/
131 
measurestr(float value,char * buffer)132 void measurestr(float value, char *buffer)
133 {
134    float oscale, iscale;
135    iscale = (float)(xobjs.pagelist[areawin->page]->drawingscale.y) /
136         (float)(xobjs.pagelist[areawin->page]->drawingscale.x);
137 
138    switch (xobjs.pagelist[areawin->page]->coordstyle) {
139       case INTERNAL:
140 	 sprintf(buffer, "%5.3f", value * iscale);
141          break;
142       case CM:
143          oscale = xobjs.pagelist[areawin->page]->outscale * CMSCALE;
144          sprintf(buffer, "%5.3f cm", value * iscale * oscale / IN_CM_CONVERT);
145          break;
146       case DEC_INCH:
147          oscale = xobjs.pagelist[areawin->page]->outscale * INCHSCALE;
148          sprintf(buffer, "%5.3f in", value * iscale * oscale / 72.0);
149          break;
150       case FRAC_INCH:
151          oscale = xobjs.pagelist[areawin->page]->outscale * INCHSCALE;
152          fraccalc(((value * iscale * oscale) / 72.0), buffer);
153          strcat(buffer, " in");
154          break;
155    }
156 }
157 
158 /*----------------------------------------------------------------*/
159 /* set the global default line width.  The unit used internally   */
160 /* is twice the value passed through pointer "dataptr".		  */
161 /*----------------------------------------------------------------*/
162 
setwidth(xcWidget w,float * dataptr)163 void setwidth(xcWidget w, float *dataptr)
164 {
165    float oldvalue = *dataptr;
166    if (sscanf(_STR2, "%f", dataptr) == 0) {
167       *dataptr = oldvalue;
168       Wprintf("Illegal value");
169       return;
170    }
171    (*dataptr) *= 2.0;
172    if (oldvalue != *dataptr) drawarea(NULL, NULL, NULL);
173 }
174 
175 /*--------------------------------------------------------------*/
176 /* Set text scale.						*/
177 /*--------------------------------------------------------------*/
178 
changetextscale(float newscale)179 void changetextscale(float newscale)
180 {
181    short *osel;
182    labelptr settext;
183    stringpart *strptr, *nextptr;
184 
185    /* In edit mode, add font scale change. */
186 
187    if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) {
188       settext = *((labelptr *)EDITPART);
189       if (areawin->textpos > 0 || areawin->textpos < stringlength(settext->string, True,
190 		areawin->topinstance)) {
191 	 undrawtext(settext);
192 	 strptr = findstringpart(areawin->textpos - 1, NULL, settext->string,
193 			areawin->topinstance);
194 	 nextptr = findstringpart(areawin->textpos, NULL, settext->string,
195 			areawin->topinstance);
196 	 if (strptr->type == FONT_SCALE)
197 	    strptr->data.scale = newscale;
198 	 else if (nextptr && nextptr->type == FONT_SCALE)
199 	    nextptr->data.scale = newscale;
200 	 else
201 	    labeltext(FONT_SCALE, (char *)&newscale);
202 	 redrawtext(settext);
203       }
204       else if (stringlength(settext->string, True, areawin->topinstance) > 0)
205 	 labeltext(FONT_SCALE, (char *)&newscale);
206       else (settext->scale = newscale);
207    }
208 
209    /* Change scale on all selected text objects */
210 
211    else if (areawin->selects > 0) {
212       float oldscale;
213       Boolean waschanged = FALSE;
214       for (osel = areawin->selectlist; osel < areawin->selectlist +
215 	     areawin->selects; osel++) {
216 	 if (SELECTTYPE(osel) == LABEL) {
217 	    settext = SELTOLABEL(osel);
218 	    oldscale = settext->scale;
219 	    if (oldscale != newscale) {
220 	       undrawtext(settext);
221                settext->scale = newscale;
222 	       redrawtext(settext);
223 	       register_for_undo(XCF_Rescale, UNDO_MORE, areawin->topinstance,
224 			(genericptr)settext, (double)oldscale);
225 	       waschanged = TRUE;
226 	    }
227 	 }
228       }
229       if (waschanged) undo_finish_series();
230    }
231 }
232 
233 /*--------------------------------------------------------------*/
234 /* Auto-scale the drawing to fit the declared page size.	*/
235 /*								*/
236 /* If the page is declared encapsulated, then do nothing.	*/
237 /* If a frame box is on the page, then scale to fit the frame	*/
238 /* to the declared page size, not the whole object.		*/
239 /*--------------------------------------------------------------*/
240 
autoscale(int page)241 void autoscale(int page)
242 {
243    float newxscale, newyscale;
244    float scalefudge = (xobjs.pagelist[page]->coordstyle
245 	== CM) ? CMSCALE : INCHSCALE;
246    int width, height;
247    polyptr framebox;
248 
249    /* Check if auto-fit flag is selected */
250    if (!(xobjs.pagelist[page]->pmode & 2)) return;
251    /* Ignore auto-fit flag in EPS mode */
252    if (!(xobjs.pagelist[page]->pmode & 1)) return;
253 
254    else if (topobject->bbox.width == 0 || topobject->bbox.height == 0) {
255       // Wprintf("Cannot auto-fit empty page");
256       return;
257    }
258 
259    newxscale = (xobjs.pagelist[page]->pagesize.x -
260 	(2 * xobjs.pagelist[page]->margins.x)) / scalefudge;
261    newyscale = (xobjs.pagelist[page]->pagesize.y -
262 	(2 * xobjs.pagelist[page]->margins.y)) / scalefudge;
263 
264    if ((framebox = checkforbbox(topobject)) != NULL) {
265       int i, minx, miny, maxx, maxy;
266 
267       minx = maxx = framebox->points[0].x;
268       miny = maxy = framebox->points[0].y;
269       for (i = 1; i < framebox->number; i++) {
270 	 if (framebox->points[i].x < minx) minx = framebox->points[i].x;
271 	 else if (framebox->points[i].x > maxx) maxx = framebox->points[i].x;
272 	 if (framebox->points[i].y < miny) miny = framebox->points[i].y;
273 	 else if (framebox->points[i].y > maxy) maxy = framebox->points[i].y;
274       }
275       width = (maxx - minx);
276       height = (maxy - miny);
277    }
278    else {
279 
280       width = toplevelwidth(areawin->topinstance, NULL);
281       height = toplevelheight(areawin->topinstance, NULL);
282    }
283 
284    if (xobjs.pagelist[page]->orient == 0) {	/* Portrait */
285       newxscale /= width;
286       newyscale /= height;
287    }
288    else {
289       newxscale /= height;
290       newyscale /= width;
291    }
292    xobjs.pagelist[page]->outscale = min(newxscale, newyscale);
293 }
294 
295 /*--------------------------------------------------------------*/
296 /* Parse a string for possible units of measure.  Convert to	*/
297 /* current units of measure, if necessary.  Return the value	*/
298 /* in current units, as a type float.				*/
299 /*--------------------------------------------------------------*/
300 
parseunits(char * strptr)301 float parseunits(char *strptr)
302 {
303    short curtype;
304    Boolean inchunits = True;
305    float pv;
306    char units[12];
307 
308    curtype = xobjs.pagelist[areawin->page]->coordstyle;
309 
310    if (sscanf(strptr, "%f %11s", &pv, units) < 2)
311       return pv;
312    else {
313       if (!strncmp(units, "cm", 2) || !strncmp(units, "centimeters", 11))
314 	 inchunits = False;
315       switch(curtype) {
316          case CM:
317 	    return ((inchunits) ? (pv * 2.54) : pv);
318          default:
319 	    return ((inchunits) ? pv : (pv / 2.54));
320       }
321    }
322 }
323 
324 /*--------------------------------------------------------------*/
325 /* Set the output page size, in the current unit of measure	*/
326 /* Return value:  TRUE if _STR2 values were in inches, FALSE	*/
327 /* if in centimeters.						*/
328 /* XXX This API gives no good way to signal errors.             */
329 /*--------------------------------------------------------------*/
330 
setoutputpagesize(XPoint * dataptr)331 Boolean setoutputpagesize(XPoint *dataptr)
332 {
333    float px, py;
334    char units[10], *expos;
335 #ifndef TCL_WRAPPER
336    Arg wargs[1];
337 #endif
338 
339    strcpy(units, "in");
340 
341    if (sscanf(_STR2, "%f %*c %f %9s", &px, &py, units) < 4) {
342       if (sscanf(_STR2, "%f %*c %f", &px, &py) < 3) {
343 	 if ((expos = strchr(_STR2, 'x')) == NULL) {
344             Wprintf("Illegal Form for page size.");
345 	    return FALSE;
346 	 }
347 	 else {
348 	    *expos = '\0';
349 	    if (sscanf(_STR2, "%f", &px) == 0 ||
350 		  sscanf(expos + 1, "%f %9s", &py, units) == 0) {
351                Wprintf("Illegal Form for page size.");
352 	       return FALSE;
353 	    }
354 	 }
355       }
356    }
357 
358    /* Don't reduce page to less than the margins (1") or negative	*/
359    /* scales result.							*/
360 
361    if ((px <= 2.0) || (py <= 2.0)) {
362       Wprintf("Page size too small for margins.");
363       return FALSE;
364    }
365 
366    dataptr->x = (short)(px * 72.0);
367    dataptr->y = (short)(py * 72.0);
368 
369    if (!strcmp(units, "cm")) {
370       dataptr->x /= 2.54;
371       dataptr->y /= 2.54;
372       return FALSE;
373    }
374    return TRUE;
375 }
376 
377 /*--------------------------------------------------------------*/
378 /* Get the text size (global or selected, depending on mode	*/
379 /*--------------------------------------------------------------*/
380 
gettextsize(float ** floatptr)381 labelptr gettextsize(float **floatptr)
382 {
383    labelptr settext = NULL;
384    short    *osel;
385    stringpart *strptr, *nextptr;
386    const float f_one = 1.00;
387 
388    if (floatptr) *floatptr = &areawin->textscale;
389 
390    if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) {
391       if (areawin->textpos > 0 || areawin->textpos < stringlength(settext->string,
392 		True, areawin->topinstance)) {
393          settext = *((labelptr *)EDITPART);
394 	 strptr = findstringpart(areawin->textpos - 1, NULL, settext->string,
395 			areawin->topinstance);
396 	 nextptr = findstringpart(areawin->textpos, NULL, settext->string,
397 			areawin->topinstance);
398 	 if (strptr->type == FONT_SCALE) {
399 	    if (floatptr) *floatptr = &strptr->data.scale;
400 	 }
401 	 else if (nextptr && nextptr->type == FONT_SCALE) {
402 	    if (floatptr) *floatptr = &nextptr->data.scale;
403 	 }
404 	 else if (floatptr) *floatptr = (float *)(&f_one);
405       }
406       else {
407          settext = *((labelptr *)EDITPART);
408          if (floatptr) *floatptr = &(settext->scale);
409       }
410    }
411    else if (areawin->selects > 0) {
412       for (osel = areawin->selectlist; osel < areawin->selectlist +
413 		areawin->selects; osel++) {
414 	 if (SELECTTYPE(osel) == LABEL) {
415             settext = SELTOLABEL(osel);
416             if (floatptr) *floatptr = &(settext->scale);
417 	    break;
418 	 }
419       }
420    }
421    return settext;
422 }
423 
424 /*--------------------------------------------------------------*/
425 /* Set a character kern value					*/
426 /*--------------------------------------------------------------*/
427 
setkern(xcWidget w,stringpart * kpart)428 void setkern(xcWidget w, stringpart *kpart)
429 {
430    char *sptr;
431    short kd[2];
432 
433    kd[0] = kd[1] = 0;
434 
435    if ((sptr = strchr(_STR2, ',')) == NULL)
436       Wprintf("Use notation X,Y");
437    else {
438       *sptr = '\0';
439       sscanf(_STR2, "%hd", &kd[0]);
440       sscanf(sptr + 1, "%hd", &kd[1]);
441       if (kpart == NULL)
442          labeltext(KERN, (char *)kd);
443       else {
444          labelptr curlabel = TOLABEL(EDITPART);
445 	 undrawtext(curlabel);
446 	 kpart->data.kern[0] = kd[0];
447 	 kpart->data.kern[1] = kd[1];
448 	 redrawtext(curlabel);
449       }
450    }
451 }
452 
453 /*----------------------------------------------------------------*/
454 /* Set the drawing scale (specified as ratio X:Y)		  */
455 /*----------------------------------------------------------------*/
456 
setdscale(xcWidget w,XPoint * dataptr)457 void setdscale(xcWidget w, XPoint *dataptr)
458 {
459    char *sptr;
460 
461    if ((sptr = strchr(_STR2, ':')) == NULL)
462       Wprintf("Use ratio X:Y");
463    else {
464       *sptr = '\0';
465       sscanf(_STR2, "%hd", &(dataptr->x));
466       sscanf(sptr + 1, "%hd", &(dataptr->y));
467       Wprintf("New scale is %hd:%hd", dataptr->x, dataptr->y);
468       W1printf(" ");
469    }
470 }
471 
472 /*----------------------------------------------------------------*/
473 /* Set the scale of an object or group of selected objects	  */
474 /*----------------------------------------------------------------*/
475 
setosize(xcWidget w,objinstptr dataptr)476 void setosize(xcWidget w, objinstptr dataptr)
477 {
478    float tmpres, oldsize;
479    Boolean waschanged = FALSE;
480    short *osel;
481    objinstptr nsobj;
482    int res = sscanf(_STR2, "%f", &tmpres);
483 
484    // Negative values are flips---deal with them independently
485 
486    if (tmpres < 0)
487       tmpres = -tmpres;
488 
489    if (res == 0 || tmpres == 0) {
490       Wprintf("Illegal value");
491       return;
492    }
493    for (osel = areawin->selectlist; osel < areawin->selectlist +
494 	     areawin->selects; osel++) {
495       if (SELECTTYPE(osel) == OBJINST) {
496 	 nsobj = SELTOOBJINST(osel);
497 	 oldsize = nsobj->scale;
498          nsobj->scale = (oldsize < 0) ? -tmpres : tmpres;
499 
500          if (oldsize != tmpres) {
501             register_for_undo(XCF_Rescale, UNDO_MORE, areawin->topinstance,
502 			SELTOGENERIC(osel), (double)oldsize);
503 	    waschanged = TRUE;
504 	 }
505       }
506    }
507    if (waschanged) undo_finish_series();
508    pwriteback(areawin->topinstance);
509    drawarea(NULL, NULL, NULL);
510 }
511 
512 /*----------------------------------------------------------------*/
513 /* Set the linewidth of all selected arcs, polygons, splines, and */
514 /* paths.							  */
515 /*----------------------------------------------------------------*/
516 
setwwidth(xcWidget w,void * dataptr)517 void setwwidth(xcWidget w, void *dataptr)
518 {
519    float     tmpres, oldwidth;
520    short     *osel;
521    arcptr    nsarc;
522    polyptr   nspoly;
523    splineptr nsspline;
524    pathptr   nspath;
525 
526    if (sscanf(_STR2, "%f", &tmpres) == 0) {
527       Wprintf("Illegal value");
528       return;
529    }
530    else if (areawin->selects == 0) {
531       areawin->linewidth = tmpres;
532    }
533    else {
534       for (osel = areawin->selectlist; osel < areawin->selectlist +
535 	     areawin->selects; osel++) {
536          if (SELECTTYPE(osel) == ARC) {
537 	    nsarc = SELTOARC(osel);
538 	    oldwidth = nsarc->width;
539             nsarc->width = tmpres;
540          }
541          else if (SELECTTYPE(osel) == POLYGON) {
542 	    nspoly = SELTOPOLY(osel);
543 	    oldwidth = nspoly->width;
544             nspoly->width = tmpres;
545          }
546          else if (SELECTTYPE(osel) == SPLINE) {
547 	    nsspline = SELTOSPLINE(osel);
548 	    oldwidth = nsspline->width;
549             nsspline->width = tmpres;
550          }
551          else if (SELECTTYPE(osel) == PATH) {
552 	    nspath = SELTOPATH(osel);
553 	    oldwidth = nspath->width;
554             nspath->width = tmpres;
555          }
556 
557 	 if (oldwidth != tmpres)
558             register_for_undo(XCF_Rescale, UNDO_MORE, areawin->topinstance,
559 			SELTOGENERIC(osel), (double)oldwidth);
560       }
561       unselect_all();
562       pwriteback(areawin->topinstance);
563       drawarea(NULL, NULL, NULL);
564    }
565 }
566 
567 /*--------------------------------------------------------------*/
568 /* Add a new font name to the list of known fonts		*/
569 /* Register the font number for the Alt-F cycling mechanism	*/
570 /* Tcl: depends on command tag mechanism for GUI menu update.	*/
571 /*--------------------------------------------------------------*/
572 
573 #ifdef TCL_WRAPPER
574 
makenewfontbutton()575 void makenewfontbutton()
576 {
577    nfontnumbers++;
578    if (nfontnumbers == 1)
579       fontnumbers = (u_short *)malloc(sizeof(u_short));
580    else
581       fontnumbers = (u_short *)realloc(fontnumbers, nfontnumbers
582 		* sizeof(u_short));
583    fontnumbers[nfontnumbers - 1] = fontcount - 1;
584 }
585 
586 #endif /* TCL_WRAPPER */
587 
588 /*---------------------------------------------------------------*/
589 /* Some Xcircuit routines using toggle and toggleexcl, 		 */
590 /* put here because they reference the menu structures directly. */
591 /*								 */
592 /* Note that by bypassing addnewcolorentry(), the new colors in	 */
593 /* colorlist are NOT added to the GUI list of colors.		 */
594 /*---------------------------------------------------------------*/
595 
setcolorscheme(Boolean boolvalue)596 void setcolorscheme(Boolean boolvalue)
597 {
598    int i;
599 
600    if (boolvalue) {
601       colorlist[PARAMCOLOR].color.pixel = appdata.parampix;
602       colorlist[AUXCOLOR].color.pixel = appdata.auxpix;
603       colorlist[OFFBUTTONCOLOR].color.pixel = appdata.buttonpix;
604       colorlist[SELECTCOLOR].color.pixel = appdata.selectpix;
605       colorlist[GRIDCOLOR].color.pixel = appdata.gridpix;
606       colorlist[SNAPCOLOR].color.pixel = appdata.snappix;
607       colorlist[AXESCOLOR].color.pixel = appdata.axespix;
608       colorlist[BACKGROUND].color.pixel = appdata.bg;
609       colorlist[FOREGROUND].color.pixel = appdata.fg;
610    }
611    else {
612       colorlist[PARAMCOLOR].color.pixel = appdata.parampix2;
613       colorlist[AUXCOLOR].color.pixel = appdata.auxpix2;
614       colorlist[OFFBUTTONCOLOR].color.pixel = appdata.buttonpix2;
615       colorlist[SELECTCOLOR].color.pixel = appdata.selectpix2;
616       colorlist[GRIDCOLOR].color.pixel = appdata.gridpix2;
617       colorlist[SNAPCOLOR].color.pixel = appdata.snappix2;
618       colorlist[AXESCOLOR].color.pixel = appdata.axespix2;
619       colorlist[BACKGROUND].color.pixel = appdata.bg2;
620       colorlist[FOREGROUND].color.pixel = appdata.fg2;
621    }
622 
623    colorlist[BARCOLOR].color.pixel = appdata.barpix;
624    colorlist[FILTERCOLOR].color.pixel = appdata.filterpix;
625 
626    colorlist[LOCALPINCOLOR].color.pixel = appdata.localcolor;
627    colorlist[GLOBALPINCOLOR].color.pixel = appdata.globalcolor;
628    colorlist[INFOLABELCOLOR].color.pixel = appdata.infocolor;
629    colorlist[RATSNESTCOLOR].color.pixel = appdata.ratsnestcolor;
630    colorlist[BBOXCOLOR].color.pixel = appdata.bboxpix;
631    colorlist[CLIPMASKCOLOR].color.pixel = appdata.clipcolor;
632    colorlist[FIXEDBBOXCOLOR].color.pixel = appdata.fixedbboxpix;
633 
634    /* Fill in pixel information */
635 
636    for (i = 0; i < NUMBER_OF_COLORS; i++) {
637       unsigned short r, g, b;
638 
639       /* Get the color the hard way by querying the X server colormap */
640       xc_get_color_rgb(colorlist[i].color.pixel, &r, &g, &b);
641 
642       /* Store this information locally so we don't have to do	*/
643       /* the lookup the hard way in the future.			*/
644 
645       colorlist[i].color.red = r;
646       colorlist[i].color.green = g;
647       colorlist[i].color.blue = b;
648    }
649    areawin->redraw_needed = True;
650    drawarea(NULL, NULL, NULL);
651 }
652 
653 /*----------------------------------------------------------------*/
654 /* Change menu selection for reported measurement units		  */
655 /*----------------------------------------------------------------*/
656 
657 #ifdef TCL_WRAPPER
658 
togglegrid(u_short type)659 void togglegrid(u_short type)
660 {
661    static char *stylenames[] = {
662       "decimal inches",
663       "fractional inches",
664       "centimeters",
665       "internal units", NULL
666    };
667 
668    XcInternalTagCall(xcinterp, 3, "config", "coordstyle", stylenames[type]);
669 }
670 
671 #endif /* TCL_WRAPPER */
672 
673 /*----------------------------------------------------------------*/
674 /* Called by setgridtype() to complete setting the reported 	  */
675 /* measurement units						  */
676 /*----------------------------------------------------------------*/
677 
getgridtype(xcWidget button,pointertype value,caddr_t calldata)678 void getgridtype(xcWidget button, pointertype value, caddr_t calldata)
679 {
680    short oldtype = xobjs.pagelist[areawin->page]->coordstyle;
681    float scalefac = getpsscale(1.0, areawin->page) / INCHSCALE;
682 
683 #ifndef TCL_WRAPPER
684    togglegridstyles(button);
685 #endif
686    xobjs.pagelist[areawin->page]->coordstyle = (short)value;
687 
688    switch(value) {
689       case FRAC_INCH: case DEC_INCH: case INTERNAL:
690 	 if (oldtype == CM) {
691             xobjs.pagelist[areawin->page]->outscale *= scalefac;
692 #ifndef TCL_WRAPPER
693 	    /* Note:  Tcl defines a method for selecting standard  */
694 	    /* page sizes.  We really DON'T want to reset the size */
695 	    /* just because we switched measurement formats!	   */
696 
697 	    xobjs.pagelist[areawin->page]->pagesize.x = 612;
698 	    xobjs.pagelist[areawin->page]->pagesize.y = 792; /* letter */
699 #endif
700 	 }
701 	 break;
702       case CM:
703 	 if (oldtype != CM) {
704             xobjs.pagelist[areawin->page]->outscale *= scalefac;
705 #ifndef TCL_WRAPPER
706 	    xobjs.pagelist[areawin->page]->pagesize.x = 595;
707 	    xobjs.pagelist[areawin->page]->pagesize.y = 842; /* A4 */
708 #endif
709 	 }
710 	 break;
711    }
712    if (oldtype != xobjs.pagelist[areawin->page]->coordstyle) {
713       drawarea(NULL, NULL, NULL);
714       W1printf(" ");
715    }
716 }
717 
718 /*------------------------------------------------------*/
719 /* Make new library, add new button to the "Libraries"	*/
720 /* cascaded menu, compose the library page, update the  */
721 /* library directory, and go to that library page.	*/
722 /*------------------------------------------------------*/
723 
newlibrary(xcWidget w,caddr_t clientdata,caddr_t calldata)724 void newlibrary(xcWidget w, caddr_t clientdata, caddr_t calldata)
725 {
726    int libnum = createlibrary(FALSE);
727    startcatalog(w, libnum, NULL);
728 }
729 
730 /*----------------------------------------------*/
731 /* Find an empty library, and return its page	*/
732 /* number if it exists.  Otherwise, return -1.	*/
733 /* This search does not include the so-called	*/
734 /* "User Library" (last library in list).	*/
735 /*----------------------------------------------*/
736 
findemptylib()737 int findemptylib()
738 {
739   int i;
740 
741   for (i = 0; i < xobjs.numlibs - 1; i++) {
742      if (xobjs.userlibs[i].number == 0)
743 	return i;
744   }
745   return -1;
746 }
747 
748 /*----------------------------------------------*/
749 /* Make new page; goto that page		*/
750 /* (wrapper for routine events.c:newpage())	*/
751 /*----------------------------------------------*/
752 
newpagemenu(xcWidget w,pointertype value,caddr_t nulldata)753 void newpagemenu(xcWidget w, pointertype value, caddr_t nulldata)
754 {
755    newpage((short)value);
756 }
757 
758 #ifdef TCL_WRAPPER
759 
760 /*----------------------------------------------*/
761 /* Make new library and add a new button to the */
762 /* "Libraries" cascaded menu.			*/
763 /*----------------------------------------------*/
764 
createlibrary(Boolean force)765 int createlibrary(Boolean force)
766 {
767   /* xcWidget libmenu, newbutton, oldbutton; (jdk) */
768 #ifndef TCL_WRAPPER
769    Arg wargs[2];
770 #endif
771    /* char libstring[20]; (jdk) */
772    int libnum;
773    objectptr newlibobj;
774 
775    /* If there's an empty library, return its number */
776    if ((!force) && (libnum = findemptylib()) >= 0) return (libnum + LIBRARY);
777    libnum = (xobjs.numlibs++) + LIBRARY;
778    xobjs.libtop = (objinstptr *)realloc(xobjs.libtop,
779 		(libnum + 1) * sizeof(objinstptr));
780    xobjs.libtop[libnum] = xobjs.libtop[libnum - 1];
781    libnum--;
782 
783    newlibobj = (objectptr) malloc(sizeof(object));
784    initmem(newlibobj);
785    xobjs.libtop[libnum] = newpageinst(newlibobj);
786 
787    sprintf(newlibobj->name, "Library %d", libnum - LIBRARY + 1);
788 
789    /* Create the library */
790 
791    xobjs.userlibs = (Library *) realloc(xobjs.userlibs, xobjs.numlibs
792 	* sizeof(Library));
793    xobjs.userlibs[libnum + 1 - LIBRARY] = xobjs.userlibs[libnum - LIBRARY];
794    xobjs.userlibs[libnum - LIBRARY].library = (objectptr *) malloc(sizeof(objectptr));
795    xobjs.userlibs[libnum - LIBRARY].number = 0;
796    xobjs.userlibs[libnum - LIBRARY].instlist = NULL;
797 
798    sprintf(_STR2, "xcircuit::newlibrarybutton \"%s\"", newlibobj->name);
799    Tcl_Eval(xcinterp, _STR2);
800 
801    /* Update the library directory to include the new page */
802 
803    composelib(LIBLIB);
804 
805    return libnum;
806 }
807 
808 /*--------------------------------------------------------------*/
809 /* Routine called by newpage() if new button needs to be made 	*/
810 /* to add to the "Pages" cascaded menu.				*/
811 /*--------------------------------------------------------------*/
812 
makepagebutton()813 void makepagebutton()
814 {
815   /* xcWidget pagemenu, newbutton; (jdk) */
816   /* char pagestring[10]; (jdk) */
817 
818    /* make new entry in the menu */
819 
820    sprintf(_STR2, "newpagebutton \"Page %d\"", xobjs.pages);
821    Tcl_Eval(xcinterp, _STR2);
822 
823    /* Update the page directory */
824 
825    composelib(PAGELIB);
826 }
827 
828 /*----------------------------------------------------------------*/
829 /* Find the Page menu button associated with the page number	  */
830 /* (passed parameter) and set the label of that button to the	  */
831 /* object name (= page label)					  */
832 /*----------------------------------------------------------------*/
833 
renamepage(short pagenumber)834 void renamepage(short pagenumber)
835 {
836    objinstptr thisinst = xobjs.pagelist[pagenumber]->pageinst;
837    char *pname, *plabel;
838 
839    if ((pagenumber >= 0) && (pagenumber < xobjs.pages - 1) &&
840 	    (thisinst != NULL)) {
841       plabel = thisinst->thisobject->name;
842       pname = (char *)malloc(36 + strlen(plabel));
843       sprintf(pname, "catch {xcircuit::renamepage %d {%s}}", pagenumber + 1, plabel);
844       Tcl_Eval(xcinterp, pname);
845       free(pname);
846    }
847 }
848 
849 /*--------------------------------------------------------------*/
850 /* Same routine as above, for Library page menu buttons		*/
851 /*--------------------------------------------------------------*/
852 
renamelib(short libnumber)853 void renamelib(short libnumber)
854 {
855    if (libnumber <= xobjs.numlibs) return;
856 
857    sprintf(_STR2, "xcircuit::renamelib %d \"%s\"", libnumber - LIBRARY + 1,
858 	xobjs.libtop[libnumber]->thisobject->name);
859    Tcl_Eval(xcinterp, _STR2);
860 }
861 
862 /*--------------------------------------------------------------*/
863 /* Set the menu checkmarks on the color menu			*/
864 /*--------------------------------------------------------------*/
865 
setcolormark(int colorval)866 void setcolormark(int colorval)
867 {
868    /* Set GUI variables and execute any command tags associated */
869    /* with the "color" command */
870 
871 #ifdef TCL_WRAPPER
872    char cstr[6];
873 
874    if (colorval != DEFAULTCOLOR)
875       sprintf(cstr, "%5d", colorval);
876 
877    XcInternalTagCall(xcinterp, 3, "color", "set", (colorval == DEFAULTCOLOR) ?
878 	"inherit" : cstr);
879 #endif
880 }
881 
882 /*----------------------------------------------------------------*/
883 /* Set the checkmarks on the element styles menu		  */
884 /*----------------------------------------------------------------*/
885 
setallstylemarks(u_short styleval)886 void setallstylemarks(u_short styleval)
887 {
888    /* Execute any command tags associated	*/
889    /* with the "fill" and "border" commands.	*/
890 
891    char fstr[10];
892    int fillfactor;
893    const char *bptr;
894 
895    const char *borders[] = {"solid", "unbordered", "dashed", "dotted", NULL};
896    enum BorderIdx { SolidIdx, UnborderedIdx, DashedIdx, DottedIdx };
897 
898    if (styleval & FILLED) {
899       fillfactor = (int)(12.5 * (float)(1 + ((styleval & FILLSOLID) >> 5)));
900       if (fillfactor < 100)
901 	 sprintf(fstr, "%d", fillfactor);
902       else
903 	 strcpy(fstr, "solid");
904    }
905    else
906       strcpy(fstr, "unfilled");
907 
908    switch (styleval & BORDERS) {
909       case DASHED:
910 	 bptr = borders[DashedIdx];
911 	 break;
912       case DOTTED:
913 	 bptr = borders[DottedIdx];
914 	 break;
915       case NOBORDER:
916 	 bptr = borders[UnborderedIdx];
917 	 break;
918       default:
919 	 bptr = borders[SolidIdx];
920 	 break;
921    }
922 
923    XcInternalTagCall(xcinterp, 3, "fill", fstr,
924 		(styleval & OPAQUE) ? "opaque" : "transparent");
925    XcInternalTagCall(xcinterp, 3, "border", "bbox", (styleval & BBOX) ? "true" :
926 		"false");
927    XcInternalTagCall(xcinterp, 3, "border", "clipmask", (styleval & CLIPMASK) ?
928 		"true" : "false");
929    XcInternalTagCall(xcinterp, 2, "border", (styleval & UNCLOSED) ? "unclosed" :
930 		"closed");
931    XcInternalTagCall(xcinterp, 2, "border", bptr);
932 }
933 
934 #endif /* TCL_WRAPPER */
935 
936 /*--------------------------------------------------------------*/
937 /* Check for a bounding box polygon				*/
938 /*--------------------------------------------------------------*/
939 
checkforbbox(objectptr localdata)940 polyptr checkforbbox(objectptr localdata)
941 {
942    polyptr *cbbox;
943 
944    for (cbbox = (polyptr *)localdata->plist; cbbox <
945 	(polyptr *)localdata->plist + localdata->parts; cbbox++)
946       if (IS_POLYGON(*cbbox))
947          if ((*cbbox)->style & BBOX) return *cbbox;
948 
949    return NULL;
950 }
951 
952 /*--------------------------------------------------------------*/
953 /* Set a value for element style.  "Mask" determines the bits	*/
954 /* to be affected, so that "value" may turn bits either on or	*/
955 /* off.								*/
956 /*--------------------------------------------------------------*/
957 
setelementstyle(xcWidget w,u_short value,u_short mask)958 int setelementstyle(xcWidget w, u_short value, u_short mask)
959 {
960    Boolean preselected, selected = False;
961    short *sstyle;
962    u_short newstyle, oldstyle;
963 
964    if (areawin->selects == 0) {
965       preselected = FALSE;
966       if (value & BBOX)
967 	 checkselect(POLYGON);
968       else
969 	 checkselect(ARC | SPLINE | POLYGON | PATH);
970    }
971    else preselected = TRUE;
972 
973    if (areawin->selects > 0) {
974       if (value & BBOX) {
975 	 polyptr ckp;
976 	 if (areawin->selects != 1) {
977 	    Wprintf("Choose only one polygon to be the bounding box");
978 	    return -1;
979 	 }
980 	 else if (SELECTTYPE(areawin->selectlist) != POLYGON) {
981 	    Wprintf("Bounding box can only be a polygon");
982 	    return -1;
983 	 }
984 	 else if (((ckp = checkforbbox(topobject)) != NULL) &&
985 		(ckp != SELTOPOLY(areawin->selectlist))) {
986 	    Wprintf("Only one bounding box allowed per page");
987 	    return -1;
988 	 }
989       }
990 
991       for (sstyle = areawin->selectlist; sstyle < areawin->selectlist
992 	   + areawin->selects; sstyle++) {
993 	 short stype = SELECTTYPE(sstyle);
994 	 if (stype & (ARC | POLYGON | SPLINE | PATH)) {
995 	    short *estyle;
996 	    switch (stype) {
997 	       case ARC:
998 	          estyle = &((SELTOARC(sstyle))->style);
999 		  break;
1000 	       case SPLINE:
1001 	          estyle = &((SELTOSPLINE(sstyle))->style);
1002 		  break;
1003 	       case POLYGON:
1004 	          estyle = &((SELTOPOLY(sstyle))->style);
1005 		  break;
1006 	       case PATH:
1007 	          estyle = &((SELTOPATH(sstyle))->style);
1008 		  break;
1009 	    }
1010 	    oldstyle = newstyle = *estyle;
1011 	    newstyle &= ~(mask);
1012 	    newstyle |= value;
1013 
1014 	    if (oldstyle != newstyle) {
1015 	       if ((newstyle & NOBORDER) && !(newstyle & FILLED)) {
1016 	          Wprintf("Must have either a border or filler");
1017 	          continue;
1018 	       }
1019 
1020 	       SetForeground(dpy, areawin->gc, BACKGROUND);
1021 	       easydraw(*sstyle, DOFORALL);
1022 
1023 	       *estyle = newstyle;
1024 	       if (mask & BBOX)
1025 	          (SELTOPOLY(sstyle))->color = (value & BBOX) ? BBOXCOLOR
1026 				: DEFAULTCOLOR;
1027 
1028 	       SetForeground(dpy, areawin->gc, SELECTCOLOR);
1029 	       easydraw(*sstyle, DOFORALL);
1030 
1031 #ifdef TCL_WRAPPER
1032 	       register_for_undo(XCF_ChangeStyle,
1033 			(sstyle == areawin->selectlist + areawin->selects - 1) ?
1034 			UNDO_DONE : UNDO_MORE, areawin->topinstance,
1035 			SELTOGENERIC(sstyle), (int)oldstyle);
1036 #else
1037 	       /* Tcl version differs in that the element is not deselected after */
1038 
1039 	       register_for_undo(XCF_ChangeStyle, UNDO_MORE, areawin->topinstance,
1040 			SELTOGENERIC(sstyle), (int)oldstyle);
1041 #endif
1042 	    }
1043 	    selected = True;
1044 	 }
1045       }
1046    }
1047    if (selected)
1048       pwriteback(areawin->topinstance);
1049    else {
1050       newstyle = areawin->style;
1051       if (value & BBOX) {
1052 	 Wprintf("Cannot set default style to Bounding Box");
1053 	 newstyle &= ~(BBOX);
1054 	 return -1;
1055       }
1056       else if (value & CLIPMASK) {
1057 	 Wprintf("Cannot set default style to Clip Mask");
1058 	 newstyle &= ~(CLIPMASK);
1059 	 return -1;
1060       }
1061       else {
1062 	 newstyle &= ~mask;
1063 	 newstyle |= value;
1064       }
1065 
1066       if ((newstyle & NOBORDER) && !(newstyle & FILLED)) {
1067 	 Wprintf("Must have either a border or filler");
1068 	 return -1;
1069       }
1070       areawin->style = newstyle;
1071 #ifndef TCL_WRAPPER
1072       overdrawpixmap(w);
1073 #endif
1074    }
1075 #ifndef TCL_WRAPPER
1076    setallstylemarks(newstyle);
1077 #endif
1078    if (!preselected)
1079       unselect_all();
1080 
1081    return (int)newstyle;
1082 }
1083 
1084 /*-----------------------------------------------*/
1085 /* Set the color value for all selected elements */
1086 /*-----------------------------------------------*/
1087 
1088 #ifdef TCL_WRAPPER
1089 
setcolor(xcWidget w,int cindex)1090 void setcolor(xcWidget w, int cindex)
1091 {
1092    short *scolor;
1093    int *ecolor, oldcolor;
1094    Boolean selected = False;
1095    stringpart *strptr, *nextptr;
1096 
1097    if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) {
1098       labelptr curlabel = TOLABEL(EDITPART);
1099       strptr = findstringpart(areawin->textpos - 1, NULL, curlabel->string,
1100 			areawin->topinstance);
1101       nextptr = findstringpart(areawin->textpos, NULL, curlabel->string,
1102 			areawin->topinstance);
1103       if (strptr && strptr->type == FONT_COLOR) {
1104 	 undrawtext(curlabel);
1105 	 strptr->data.color = cindex;
1106 	 redrawtext(curlabel);
1107       }
1108       else if (nextptr && nextptr->type == FONT_COLOR) {
1109 	    undrawtext(curlabel);
1110 	    nextptr->data.color = cindex;
1111 	    redrawtext(curlabel);
1112       }
1113       else {
1114 	 sprintf(_STR2, "%d", cindex);
1115 	 labeltext(FONT_COLOR, (char *)&cindex);
1116       }
1117    }
1118 
1119    else if (areawin->selects > 0) {
1120       for (scolor = areawin->selectlist; scolor < areawin->selectlist
1121 	   + areawin->selects; scolor++) {
1122 	 ecolor = &(SELTOCOLOR(scolor));
1123 	 oldcolor = *ecolor;
1124 	 *ecolor = cindex;
1125 	 selected = True;
1126 
1127 	 register_for_undo(XCF_Color, (scolor == areawin->selectlist
1128 			+ areawin->selects - 1) ?  UNDO_DONE : UNDO_MORE,
1129 			areawin->topinstance,
1130 			SELTOGENERIC(scolor), (int)oldcolor);
1131       }
1132    }
1133 
1134    setcolormark(cindex);
1135    if (!selected) {
1136       if (eventmode != TEXT_MODE && eventmode != ETEXT_MODE)
1137          areawin->color = cindex;
1138    }
1139    else pwriteback(areawin->topinstance);
1140 }
1141 
1142 /*--------------------------------------------------------------*/
1143 /* Set the menu checkmarks on the font menu			*/
1144 /*--------------------------------------------------------------*/
1145 
togglefontmark(int fontval)1146 void togglefontmark(int fontval)
1147 {
1148    if (fonts[fontval].family != NULL)
1149       XcInternalTagCall(xcinterp, 3, "label", "family", fonts[fontval].family);
1150 }
1151 
1152 /*------------------------------------------------------*/
1153 /* Set checkmarks on label style menu 			*/
1154 /* fvalue is for font, jvalue is for anchoring		*/
1155 /*------------------------------------------------------*/
1156 
togglestylemark(int styleval)1157 void togglestylemark(int styleval)
1158 {
1159    char *cstyle = translatestyle(styleval);
1160    if (cstyle != NULL)
1161       XcInternalTagCall(xcinterp, 3, "label", "style", cstyle);
1162 }
1163 
1164 /*------------------------------------------------------*/
1165 /* Set checkmarks on label encoding menu		*/
1166 /*------------------------------------------------------*/
1167 
toggleencodingmark(int encodingval)1168 void toggleencodingmark(int encodingval)
1169 {
1170    char *cenc = translateencoding(encodingval);
1171    if (cenc != NULL)
1172       XcInternalTagCall(xcinterp, 3, "label", "encoding", cenc);
1173 }
1174 
1175 /*------------------------------------------------------*/
1176 /* Set checkmarks on label anchoring & flags menu	*/
1177 /*------------------------------------------------------*/
1178 
toggleanchormarks(int anchorvalue)1179 void toggleanchormarks(int anchorvalue)
1180 {
1181    XcInternalTagCall(xcinterp, 4, "label", "anchor", (anchorvalue & RIGHT) ? "right" :
1182 	(anchorvalue & NOTLEFT) ? "center" : "left",
1183 	(anchorvalue & TOP) ? "top" : (anchorvalue & NOTBOTTOM) ? "middle" : "bottom");
1184    XcInternalTagCall(xcinterp, 3, "label", "justify", (anchorvalue & JUSTIFYRIGHT) ?
1185 	"right" : (anchorvalue & TEXTCENTERED) ? "center" : (anchorvalue & JUSTIFYBOTH)
1186 	? "both" : "left");
1187    XcInternalTagCall(xcinterp, 3, "label", "flipinvariant", (anchorvalue & FLIPINV) ?
1188 	"true" : "false");
1189    XcInternalTagCall(xcinterp, 3, "label", "latex", (anchorvalue & LATEXLABEL) ?
1190 	"true" : "false");
1191    XcInternalTagCall(xcinterp, 3, "label", "visible", (anchorvalue & PINVISIBLE) ?
1192 	"true" : "false");
1193 }
1194 
1195 /*-------------------------------------------------------------*/
1196 /* Simultaneously set all relevant checkmarks for a text label */
1197 /*-------------------------------------------------------------*/
1198 
setfontmarks(short fvalue,short jvalue)1199 void setfontmarks(short fvalue, short jvalue)
1200 {
1201    if ((fvalue >= 0) && (fvalue < fontcount)) {
1202       toggleencodingmark(fvalue);
1203       togglestylemark(fvalue);
1204       togglefontmark(fvalue);
1205    }
1206    toggleanchormarks(jvalue);
1207 }
1208 
1209 #endif /* TCL_WRAPPER */
1210 
1211 /*--------------------------------------------------------------*/
1212 /* Parameterize a label string (wrapper for parameterize()).	*/
1213 /* Assumes that the name has been generated by the popup prompt	*/
1214 /* and is therefore held in variable _STR2			*/
1215 /*--------------------------------------------------------------*/
1216 
stringparam(xcWidget w,caddr_t clientdata,caddr_t calldata)1217 void stringparam(xcWidget w, caddr_t clientdata, caddr_t calldata)
1218 {
1219    genericptr *settext;
1220 
1221    if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) {
1222       settext = (genericptr *)EDITPART;
1223       makeparam(TOLABEL(settext), _STR2);
1224       if (eventmode == ETEXT_MODE)
1225 	 unselect_all();
1226       else
1227 	 /* Move cursor position to account for the parameter	*/
1228 	 /* start and end markers that have been added to the	*/
1229 	 /* string.						*/
1230 	 areawin->textpos += 2;
1231       setparammarks(NULL);
1232    }
1233    else if (checkselect(LABEL)) parameterize(P_SUBSTRING, _STR2, -1);
1234 }
1235 
1236 /*--------------------------------------------------------------*/
1237 /* Numerical parameterization (wrapper for parameterize()).	*/
1238 /*--------------------------------------------------------------*/
1239 
startparam(xcWidget w,pointertype value,caddr_t calldata)1240 void startparam(xcWidget w, pointertype value, caddr_t calldata)
1241 {
1242    if (value == (pointertype)P_SUBSTRING) {
1243       strcpy(_STR2, (calldata != NULL) ? (char *)calldata : "substring");
1244       stringparam(w, NULL, NULL);
1245    }
1246    else if ((eventmode != NORMAL_MODE) || (areawin->selects > 0))
1247 	 parameterize((int)value, (char *)calldata, -1);
1248 }
1249 
1250 /*---------------------------------------------------------------*/
1251 /* Unparameterize a label string (wrapper for unparameterize()). */
1252 /*---------------------------------------------------------------*/
1253 
startunparam(xcWidget w,pointertype value,caddr_t calldata)1254 void startunparam(xcWidget w, pointertype value, caddr_t calldata)
1255 {
1256    if (areawin->selects > 0)
1257       unparameterize((int)value);
1258    unselect_all();
1259    setparammarks(NULL);
1260 }
1261 
1262 /*----------------------------------------------------------------*/
1263 /* Set checkmarks on font menu according to the global defaults	  */
1264 /*----------------------------------------------------------------*/
1265 
setdefaultfontmarks()1266 void setdefaultfontmarks()
1267 {
1268    setfontmarks(areawin->psfont, areawin->anchor);
1269 }
1270 
1271 /*----------------------------------------------------------------*/
1272 /* Pick up font name from _STR2 and pass it to loadfontfile()	  */
1273 /*----------------------------------------------------------------*/
1274 
locloadfont(xcWidget w,char * value)1275 void locloadfont(xcWidget w, char *value)
1276 {
1277    loadfontfile(_STR2);
1278    free(value);
1279 }
1280 
1281 /*----------------------------------------------------------------*/
1282 /* Find the best matching font given new font, style, or encoding */
1283 /*----------------------------------------------------------------*/
1284 /* newfont, style, or encoding = -1 when not applicable		  */
1285 /* Return the number of the best matching font.			  */
1286 /*----------------------------------------------------------------*/
1287 
findbestfont(short curfont,short newfont,short style,short encoding)1288 short findbestfont(short curfont, short newfont, short style, short encoding) {
1289 
1290    char *newfamily;
1291    short i, newstyle, newenc;
1292 
1293    if (fontcount == 0) return -1;
1294    if (curfont < 0) curfont = 0;
1295 
1296    if (newfont < 0)
1297       newfamily = fonts[curfont].family;
1298    else if (newfont >= fontcount) {	/* move to next font family */
1299       short newidx;
1300       newfont = 0;
1301       while (strcmp(fonts[fontnumbers[newfont]].family, fonts[curfont].family))
1302 	 newfont++;
1303       newidx = (newfont + 1) % nfontnumbers;
1304       while (!strcmp(fonts[curfont].family, fonts[fontnumbers[newidx]].family) &&
1305 		newfont != newidx)
1306 	 newidx = (newidx + 1) % nfontnumbers;
1307       newfamily = fonts[fontnumbers[newidx]].family;
1308       newfont = fontnumbers[newidx];
1309    }
1310    else
1311       newfamily = fonts[newfont].family;
1312 
1313    if (style < 0)
1314       newstyle = fonts[curfont].flags & 0x03;
1315    else
1316       newstyle = style & 0x03;
1317 
1318    if (encoding < 0)
1319       newenc = fonts[curfont].flags & 0xf80;
1320    else
1321       newenc = encoding << 7;
1322 
1323    /* Best position is a match on all conditions */
1324 
1325    for (i = 0; i < fontcount; i++)
1326       if ((!strcmp(fonts[i].family, newfamily)) &&
1327 		((fonts[i].flags & 0x03) == newstyle) &&
1328 	 	((fonts[i].flags & 0xf80) == newenc))
1329 	 return i;
1330 
1331    /* Fallback position 1:  Match requested property and one other. 	*/
1332    /* order of preference:  					   	*/
1333    /*   Requested property	Priority 1	Priority 2		*/
1334    /*		Font		  Style		  Encoding		*/
1335    /*		Style		  Font		  (none)		*/
1336    /*		Encoding	  Font		  (none)		*/
1337 
1338    for (i = 0; i < fontcount; i++) {
1339       if (newfont >= 0) {
1340 	 if ((!strcmp(fonts[i].family, newfamily)) &&
1341 		(fonts[i].flags & 0x03) == newstyle) return i;
1342       }
1343       else if (style >= 0) {
1344 	 if (((fonts[i].flags & 0x03) == newstyle) &&
1345 	 	(!strcmp(fonts[i].family, newfamily))) return i;
1346       }
1347       else if (encoding >= 0) {
1348 	 if (((fonts[i].flags & 0xf80) == newenc) &&
1349 	 	(!strcmp(fonts[i].family, newfamily))) return i;
1350       }
1351    }
1352 
1353    for (i = 0; i < fontcount; i++) {
1354       if (newfont >= 0) {
1355 	 if ((!strcmp(fonts[i].family, newfamily)) &&
1356 	    ((fonts[i].flags & 0xf80) >> 7) == newenc) return i;
1357       }
1358    }
1359 
1360    /* Fallback position 2:  Match only the requested property.  */
1361    /* For font selection only:  Don't want to select a new font */
1362    /* just because a certain style or encoding wasn't available.*/
1363 
1364    for (i = 0; i < fontcount; i++) {
1365       if (newfont >= 0) {
1366 	 if (!strcmp(fonts[i].family, newfamily)) return i;
1367       }
1368    }
1369 
1370    /* Failure to find matching font property */
1371 
1372    if (style >= 0) {
1373       Wprintf("Font %s not available in this style", newfamily);
1374    }
1375    else {
1376       Wprintf("Font %s not available in this encoding", newfamily);
1377    }
1378    return (-1);
1379 }
1380 
1381 /*----------------------------------------------------------------*/
1382 /* Set the font.  This depends on the system state as to whether  */
1383 /* font is set at current position in label, for an entire label, */
1384 /* or as the default font to begin new labels.			  */
1385 /*----------------------------------------------------------------*/
1386 
setfontval(xcWidget w,pointertype value,labelptr settext)1387 void setfontval(xcWidget w, pointertype value, labelptr settext)
1388 {
1389    int newfont;
1390    short i, tc;
1391    stringpart *strptr;
1392 
1393    if (settext != NULL) {
1394 
1395       /* if last byte was a font designator, use it */
1396 
1397       if (areawin->textpos > 0 || areawin->textpos < stringlength(settext->string,
1398 			True, areawin->topinstance)) {
1399 	 strptr = findstringpart(areawin->textpos - 1, NULL, settext->string,
1400 			areawin->topinstance);
1401 	 if (strptr->type == FONT_NAME) {
1402 	    tc = strptr->data.font;
1403 	    i = findbestfont(tc, (short)value, -1, -1);
1404 	    if (i >= 0) {
1405 	       undrawtext(settext);
1406 	       strptr->data.font = i;
1407 	       redrawtext(settext);
1408 	       if (w != NULL) {
1409 	          charreport(settext);
1410       		  togglefontmark(i);
1411 	       }
1412 	    }
1413 	    return;
1414          }
1415       }
1416 
1417       /* otherwise, look for the last style used in the string */
1418       tc = findcurfont(areawin->textpos, settext->string, areawin->topinstance);
1419    }
1420    else tc = areawin->psfont;
1421 
1422    /* Font change command will always find a value since at least one	*/
1423    /* font has to exist for the font menu button to exist.		*/
1424 
1425    if ((newfont = (int)findbestfont(tc, (short)value, -1, -1)) < 0) return;
1426 
1427    if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) {
1428       Wprintf("Font is now %s", fonts[newfont].psname);
1429       sprintf(_STR2, "%d", newfont);
1430       labeltext(FONT_NAME, (char *)&newfont);
1431    }
1432    else {
1433       Wprintf("Default font is now %s", fonts[newfont].psname);
1434       areawin->psfont = newfont;
1435    }
1436 
1437    if (w != NULL) togglefontmark(newfont);
1438 }
1439 
1440 /*----------------------------------------------------------------*/
1441 /* Wrapper for routine setfontval()				  */
1442 /*----------------------------------------------------------------*/
1443 
setfont(xcWidget w,pointertype value,caddr_t calldata)1444 void setfont(xcWidget w, pointertype value, caddr_t calldata)
1445 {
1446    short *fselect;
1447    labelptr settext;
1448    short labelcount = 0;
1449    Boolean preselected;
1450 
1451    if (eventmode == CATALOG_MODE || eventmode == FONTCAT_MODE ||
1452 		eventmode == EFONTCAT_MODE) return;
1453 
1454    if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) {
1455       settext = *((labelptr *)EDITPART);
1456       setfontval(w, value, settext);
1457       charreport(settext);
1458    }
1459    else {
1460       if (areawin->selects == 0) {
1461 	 checkselect(LABEL);
1462 	 preselected = FALSE;
1463       }
1464       else preselected = TRUE;
1465       areawin->textpos = 1;
1466       for (fselect = areawin->selectlist; fselect < areawin->selectlist +
1467 	    areawin->selects; fselect++) {
1468          if (SELECTTYPE(fselect) == LABEL) {
1469 	    labelcount++;
1470 	    settext = SELTOLABEL(fselect);
1471             setfontval(NULL, value, settext);
1472          }
1473       }
1474       if (labelcount == 0) setfontval(w, value, NULL);
1475       else if (!preselected) unselect_all();
1476    }
1477 }
1478 
1479 /*----------------------------------------------------------------*/
1480 /* Set the style (bold, italic, normal) for the font, similarly   */
1481 /* to the above routine setfontval().				  */
1482 /*----------------------------------------------------------------*/
1483 
setfontstyle(xcWidget w,pointertype value,labelptr settext)1484 void setfontstyle(xcWidget w, pointertype value, labelptr settext)
1485 {
1486    int newfont;
1487    short i, tc;
1488    stringpart *strptr;
1489 
1490    if (settext != NULL) {
1491 
1492       /* if last byte was a font designator, use it */
1493 
1494       if (areawin->textpos > 0 || areawin->textpos < stringlength(settext->string,
1495 			True, areawin->topinstance)) {
1496 	 strptr = findstringpart(areawin->textpos - 1, NULL, settext->string,
1497 			areawin->topinstance);
1498 	 if (strptr->type == FONT_NAME) {
1499 	    tc = strptr->data.font;
1500 
1501 	    /* find font which matches family and style, if available */
1502 
1503 	    i = findbestfont(tc, -1, (short)value, -1);
1504 	    if (i >= 0) {
1505 	       undrawtext(settext);
1506 	       strptr->data.font = i;
1507 	       redrawtext(settext);
1508 	       if (w != NULL) {
1509 	          charreport(settext);
1510 #ifndef TCL_WRAPPER
1511 	          togglefontstyles(w);
1512 #endif
1513 	       }
1514 	    }
1515             return;
1516          }
1517       }
1518 
1519       /* Otherwise, look for the last font used in the string */
1520       /* Fix by Dimitri Princen.  Was areawin->textpos - 2; was there a */
1521       /* reason for that?						*/
1522 
1523       tc = findcurfont(areawin->textpos, settext->string, areawin->topinstance);
1524    }
1525    else tc = areawin->psfont;
1526 
1527    if ((newfont = (int)findbestfont(tc, -1, (short)value, -1)) < 0) return;
1528 
1529    if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) {
1530       Wprintf("Font is now %s", fonts[newfont].psname);
1531       sprintf(_STR2, "%d", newfont);
1532       labeltext(FONT_NAME, (char *)&newfont);
1533    }
1534    else {
1535       Wprintf("Default font is now %s", fonts[newfont].psname);
1536       areawin->psfont = newfont;
1537    }
1538 #ifdef TCL_WRAPPER
1539    toggleencodingmark(value);
1540 #else
1541    togglefontstyles(w);
1542 #endif
1543 }
1544 
1545 /*----------------------------------------------------------------*/
1546 /* Wrapper for routine setfontstyle()				  */
1547 /*----------------------------------------------------------------*/
1548 
fontstyle(xcWidget w,pointertype value,caddr_t nulldata)1549 void fontstyle(xcWidget w, pointertype value, caddr_t nulldata)
1550 {
1551    short *fselect;
1552    labelptr settext;
1553    short labelcount = 0;
1554    Boolean preselected;
1555 
1556    if (eventmode == CATALOG_MODE || eventmode == FONTCAT_MODE ||
1557 		eventmode == EFONTCAT_MODE) return;
1558 
1559    if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) {
1560       settext = *((labelptr *)EDITPART);
1561       setfontstyle(w, value, settext);
1562       charreport(settext);
1563    }
1564    else {
1565       if (areawin->selects == 0) {
1566 	 checkselect(LABEL);
1567 	 preselected = FALSE;
1568       }
1569       else preselected = TRUE;
1570       areawin->textpos = 1;
1571       for (fselect = areawin->selectlist; fselect < areawin->selectlist +
1572 	    areawin->selects; fselect++) {
1573          if (SELECTTYPE(fselect) == LABEL) {
1574 	    labelcount++;
1575 	    settext = SELTOLABEL(fselect);
1576             setfontstyle(NULL, value, settext);
1577          }
1578       }
1579       if (labelcount == 0) setfontstyle(w, value, NULL);
1580       else if (!preselected) unselect_all();
1581    }
1582 }
1583 
1584 /*----------------------------------------------------------------*/
1585 /* Set the encoding (standard, ISO-Latin1, special) for the font, */
1586 /* similarly to the above routine setfontval().			  */
1587 /*----------------------------------------------------------------*/
1588 
setfontencoding(xcWidget w,pointertype value,labelptr settext)1589 void setfontencoding(xcWidget w, pointertype value, labelptr settext)
1590 {
1591    int newfont;
1592    short i, tc;
1593    stringpart *strptr;
1594 
1595    if (settext != NULL) {
1596 
1597       /* if last byte was a font designator, use it */
1598 
1599       if (areawin->textpos > 0 || areawin->textpos < stringlength(settext->string,
1600 		True, areawin->topinstance)) {
1601 	 strptr = findstringpart(areawin->textpos - 1, NULL, settext->string,
1602 			areawin->topinstance);
1603 	 if (strptr->type == FONT_NAME) {
1604 	    tc = strptr->data.font;
1605 
1606 	    i = findbestfont(tc, -1, -1, (short)value);
1607 	    if (i >= 0) {
1608 	       undrawtext(settext);
1609 	       strptr->data.font = i;
1610 	       redrawtext(settext);
1611 	       if (w != NULL) {
1612 	          charreport(settext);
1613 #ifdef TCL_WRAPPER
1614 		  toggleencodingmark(value);
1615 #else
1616    	          toggleencodings(w);
1617 #endif
1618 	       }
1619 	    }
1620 	    return;
1621 	 }
1622       }
1623 
1624       /* otherwise, look for the last style used in the string */
1625       tc = findcurfont(areawin->textpos - 2, settext->string, areawin->topinstance);
1626    }
1627    else tc = areawin->psfont;
1628 
1629    if ((newfont = (int)findbestfont(tc, -1, -1, (short)value)) < 0) return;
1630 
1631    if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) {
1632       Wprintf("Font is now %s", fonts[newfont].psname);
1633       sprintf(_STR2, "%d", newfont);
1634       labeltext(FONT_NAME, (char *)&newfont);
1635    }
1636    else {
1637       Wprintf("Default font is now %s", fonts[newfont].psname);
1638       areawin->psfont = newfont;
1639    }
1640 
1641 #ifndef TCL_WRAPPER
1642    toggleencodings(w);
1643 #endif
1644 }
1645 
1646 /*----------------------------------------------------------------*/
1647 /* Wrapper for routine setfontencoding()			  */
1648 /*----------------------------------------------------------------*/
1649 
fontencoding(xcWidget w,pointertype value,caddr_t nulldata)1650 void fontencoding(xcWidget w, pointertype value, caddr_t nulldata)
1651 {
1652    short *fselect;
1653    labelptr settext;
1654    short labelcount = 0;
1655    Boolean preselected;
1656 
1657    if (eventmode == CATALOG_MODE || eventmode == FONTCAT_MODE ||
1658 		eventmode == EFONTCAT_MODE) return;
1659 
1660    if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) {
1661       settext = *((labelptr *)EDITPART);
1662       setfontencoding(w, value, settext);
1663       charreport(settext);
1664    }
1665    else {
1666       if (areawin->selects == 0) {
1667   	 checkselect(LABEL);
1668 	 preselected = FALSE;
1669       }
1670       else preselected = TRUE;
1671       areawin->textpos = 1;
1672       for (fselect = areawin->selectlist; fselect < areawin->selectlist +
1673 	    areawin->selects; fselect++) {
1674          if (SELECTTYPE(fselect) == LABEL) {
1675 	    labelcount++;
1676 	    settext = SELTOLABEL(fselect);
1677             setfontencoding(NULL, value, settext);
1678          }
1679       }
1680       if (labelcount == 0) setfontencoding(w, value, NULL);
1681       else if (!preselected) unselect_all();
1682    }
1683 }
1684 
1685 /*----------------------------------------------*/
1686 /* Generate the table of special characters	*/
1687 /*						*/
1688 /* Return FALSE if the edited label is LaTeX-	*/
1689 /* compatible, since LaTeX text does not	*/
1690 /* usually contain special characters, but it	*/
1691 /* does contain a lot of backslashes.		*/
1692 /*----------------------------------------------*/
1693 
dospecial()1694 Boolean dospecial()
1695 {
1696    labelptr curlabel;
1697    int cfont;
1698 
1699    curlabel = TOLABEL(EDITPART);
1700    if (curlabel->anchor & LATEXLABEL) return False;
1701 
1702    cfont = findcurfont(areawin->textpos, curlabel->string, areawin->topinstance);
1703    composefontlib(cfont);
1704    startcatalog(NULL, FONTLIB, NULL);
1705    return True;
1706 }
1707 
1708 /*-------------------------------------------------------------------------*/
1709