/*----------------------------------------------------------------------*/ /* menucalls.c --- callback routines from the menu buttons, and */ /* associated routines (either Tcl/Tk routines or */ /* non-specific; Xt routines split off in file */ /* xtfuncs.c 3/28/06) */ /* Copyright (c) 2002 Tim Edwards, Johns Hopkins University */ /*----------------------------------------------------------------------*/ #include #include #include #include #include #include #include #ifndef XC_WIN32 #include #include #include #endif #ifdef TCL_WRAPPER #include #endif /*----------------------------------------------------------------------*/ /* Local includes */ /*----------------------------------------------------------------------*/ #include "colordefs.h" #include "xcircuit.h" /*----------------------------------------------------------------------*/ /* Function prototype declarations */ /*----------------------------------------------------------------------*/ #include "prototypes.h" /*----------------------------------------------------------------------*/ /* External Variable definitions */ /*----------------------------------------------------------------------*/ extern char _STR2[250]; extern char _STR[150]; /* Generic multipurpose string */ extern xcWidget top; extern Display *dpy; extern Globaldata xobjs; extern XCWindowData *areawin; extern int *appcolors; extern int number_colors; extern colorindex *colorlist; extern ApplicationData appdata; extern Cursor appcursors[NUM_CURSORS]; extern fontinfo *fonts; extern short fontcount; #ifdef TCL_WRAPPER extern Tcl_Interp *xcinterp; #endif /*----------------------------------------------------------------------*/ /* Local Variable definitions */ /*----------------------------------------------------------------------*/ u_short *fontnumbers; u_char nfontnumbers; /*----------------------------------------------*/ /* Set Poly and Arc line styles and fill styles */ /*----------------------------------------------*/ #define BORDERS (NOBORDER | DOTTED | DASHED) #define ALLFILLS (FILLSOLID | FILLED) /*----------------------------------------------------------------*/ /* setgrid, getgridspace are for grid and snap spacing sizes; */ /* include routines to parse fractions */ /*----------------------------------------------------------------*/ void setgrid(xcWidget w, float *dataptr) { float oldvalue = *dataptr; float oscale, iscale = (float)xobjs.pagelist[areawin->page]->drawingscale.y / (float)xobjs.pagelist[areawin->page]->drawingscale.x; float fval; /* For now, assume that the value is in the current display style. */ /* Might be nice in the future to make it accept any input. . . */ switch (xobjs.pagelist[areawin->page]->coordstyle) { case INTERNAL: if (sscanf(_STR2, "%f", &fval) == 0) { *dataptr = oldvalue; Wprintf("Illegal value"); } else *dataptr = fval / iscale; break; case CM: oscale = xobjs.pagelist[areawin->page]->outscale * CMSCALE; if (sscanf(_STR2, "%f", &fval) == 0) { *dataptr = oldvalue; Wprintf("Illegal value"); } else *dataptr = fval * IN_CM_CONVERT / (iscale * oscale); break; case DEC_INCH: case FRAC_INCH: { short parts; char *sptr; int f2, f3; oscale = xobjs.pagelist[areawin->page]->outscale * INCHSCALE; for (sptr = _STR2; *sptr != '\0'; sptr++) if (*sptr == '/') *sptr = ' '; parts = sscanf(_STR2, "%f %d %d", &fval, &f2, &f3); if ((parts == 0) || (parts != 1 && (fval != (float)((int)fval)))) { *dataptr = oldvalue; Wprintf("Illegal value"); break; } if (parts == 2) fval /= (float)f2; else if (parts == 3) fval += ((float)f2 / (float)f3); *dataptr = fval * 72.0 / (iscale * oscale); } break; } if (oldvalue != *dataptr) drawarea(NULL, NULL, NULL); } /*----------------------------------------------------------------*/ /* Write a measurement value into string "buffer" dependant on */ /* the current default units of measure (centimeters or inches). */ /*----------------------------------------------------------------*/ void measurestr(float value, char *buffer) { float oscale, iscale; iscale = (float)(xobjs.pagelist[areawin->page]->drawingscale.y) / (float)(xobjs.pagelist[areawin->page]->drawingscale.x); switch (xobjs.pagelist[areawin->page]->coordstyle) { case INTERNAL: sprintf(buffer, "%5.3f", value * iscale); break; case CM: oscale = xobjs.pagelist[areawin->page]->outscale * CMSCALE; sprintf(buffer, "%5.3f cm", value * iscale * oscale / IN_CM_CONVERT); break; case DEC_INCH: oscale = xobjs.pagelist[areawin->page]->outscale * INCHSCALE; sprintf(buffer, "%5.3f in", value * iscale * oscale / 72.0); break; case FRAC_INCH: oscale = xobjs.pagelist[areawin->page]->outscale * INCHSCALE; fraccalc(((value * iscale * oscale) / 72.0), buffer); strcat(buffer, " in"); break; } } /*----------------------------------------------------------------*/ /* set the global default line width. The unit used internally */ /* is twice the value passed through pointer "dataptr". */ /*----------------------------------------------------------------*/ void setwidth(xcWidget w, float *dataptr) { float oldvalue = *dataptr; if (sscanf(_STR2, "%f", dataptr) == 0) { *dataptr = oldvalue; Wprintf("Illegal value"); return; } (*dataptr) *= 2.0; if (oldvalue != *dataptr) drawarea(NULL, NULL, NULL); } /*--------------------------------------------------------------*/ /* Set text scale. */ /*--------------------------------------------------------------*/ void changetextscale(float newscale) { short *osel; labelptr settext; stringpart *strptr, *nextptr; /* In edit mode, add font scale change. */ if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) { settext = *((labelptr *)EDITPART); if (areawin->textpos > 0 || areawin->textpos < stringlength(settext->string, True, areawin->topinstance)) { undrawtext(settext); strptr = findstringpart(areawin->textpos - 1, NULL, settext->string, areawin->topinstance); nextptr = findstringpart(areawin->textpos, NULL, settext->string, areawin->topinstance); if (strptr->type == FONT_SCALE) strptr->data.scale = newscale; else if (nextptr && nextptr->type == FONT_SCALE) nextptr->data.scale = newscale; else labeltext(FONT_SCALE, (char *)&newscale); redrawtext(settext); } else if (stringlength(settext->string, True, areawin->topinstance) > 0) labeltext(FONT_SCALE, (char *)&newscale); else (settext->scale = newscale); } /* Change scale on all selected text objects */ else if (areawin->selects > 0) { float oldscale; Boolean waschanged = FALSE; for (osel = areawin->selectlist; osel < areawin->selectlist + areawin->selects; osel++) { if (SELECTTYPE(osel) == LABEL) { settext = SELTOLABEL(osel); oldscale = settext->scale; if (oldscale != newscale) { undrawtext(settext); settext->scale = newscale; redrawtext(settext); register_for_undo(XCF_Rescale, UNDO_MORE, areawin->topinstance, (genericptr)settext, (double)oldscale); waschanged = TRUE; } } } if (waschanged) undo_finish_series(); } } /*--------------------------------------------------------------*/ /* Auto-scale the drawing to fit the declared page size. */ /* */ /* If the page is declared encapsulated, then do nothing. */ /* If a frame box is on the page, then scale to fit the frame */ /* to the declared page size, not the whole object. */ /*--------------------------------------------------------------*/ void autoscale(int page) { float newxscale, newyscale; float scalefudge = (xobjs.pagelist[page]->coordstyle == CM) ? CMSCALE : INCHSCALE; int width, height; polyptr framebox; /* Check if auto-fit flag is selected */ if (!(xobjs.pagelist[page]->pmode & 2)) return; /* Ignore auto-fit flag in EPS mode */ if (!(xobjs.pagelist[page]->pmode & 1)) return; else if (topobject->bbox.width == 0 || topobject->bbox.height == 0) { // Wprintf("Cannot auto-fit empty page"); return; } newxscale = (xobjs.pagelist[page]->pagesize.x - (2 * xobjs.pagelist[page]->margins.x)) / scalefudge; newyscale = (xobjs.pagelist[page]->pagesize.y - (2 * xobjs.pagelist[page]->margins.y)) / scalefudge; if ((framebox = checkforbbox(topobject)) != NULL) { int i, minx, miny, maxx, maxy; minx = maxx = framebox->points[0].x; miny = maxy = framebox->points[0].y; for (i = 1; i < framebox->number; i++) { if (framebox->points[i].x < minx) minx = framebox->points[i].x; else if (framebox->points[i].x > maxx) maxx = framebox->points[i].x; if (framebox->points[i].y < miny) miny = framebox->points[i].y; else if (framebox->points[i].y > maxy) maxy = framebox->points[i].y; } width = (maxx - minx); height = (maxy - miny); } else { width = toplevelwidth(areawin->topinstance, NULL); height = toplevelheight(areawin->topinstance, NULL); } if (xobjs.pagelist[page]->orient == 0) { /* Portrait */ newxscale /= width; newyscale /= height; } else { newxscale /= height; newyscale /= width; } xobjs.pagelist[page]->outscale = min(newxscale, newyscale); } /*--------------------------------------------------------------*/ /* Parse a string for possible units of measure. Convert to */ /* current units of measure, if necessary. Return the value */ /* in current units, as a type float. */ /*--------------------------------------------------------------*/ float parseunits(char *strptr) { short curtype; Boolean inchunits = True; float pv; char units[12]; curtype = xobjs.pagelist[areawin->page]->coordstyle; if (sscanf(strptr, "%f %11s", &pv, units) < 2) return pv; else { if (!strncmp(units, "cm", 2) || !strncmp(units, "centimeters", 11)) inchunits = False; switch(curtype) { case CM: return ((inchunits) ? (pv * 2.54) : pv); default: return ((inchunits) ? pv : (pv / 2.54)); } } } /*--------------------------------------------------------------*/ /* Set the output page size, in the current unit of measure */ /* Return value: TRUE if _STR2 values were in inches, FALSE */ /* if in centimeters. */ /* XXX This API gives no good way to signal errors. */ /*--------------------------------------------------------------*/ Boolean setoutputpagesize(XPoint *dataptr) { float px, py; char units[10], *expos; #ifndef TCL_WRAPPER Arg wargs[1]; #endif strcpy(units, "in"); if (sscanf(_STR2, "%f %*c %f %9s", &px, &py, units) < 4) { if (sscanf(_STR2, "%f %*c %f", &px, &py) < 3) { if ((expos = strchr(_STR2, 'x')) == NULL) { Wprintf("Illegal Form for page size."); return FALSE; } else { *expos = '\0'; if (sscanf(_STR2, "%f", &px) == 0 || sscanf(expos + 1, "%f %9s", &py, units) == 0) { Wprintf("Illegal Form for page size."); return FALSE; } } } } /* Don't reduce page to less than the margins (1") or negative */ /* scales result. */ if ((px <= 2.0) || (py <= 2.0)) { Wprintf("Page size too small for margins."); return FALSE; } dataptr->x = (short)(px * 72.0); dataptr->y = (short)(py * 72.0); if (!strcmp(units, "cm")) { dataptr->x /= 2.54; dataptr->y /= 2.54; return FALSE; } return TRUE; } /*--------------------------------------------------------------*/ /* Get the text size (global or selected, depending on mode */ /*--------------------------------------------------------------*/ labelptr gettextsize(float **floatptr) { labelptr settext = NULL; short *osel; stringpart *strptr, *nextptr; const float f_one = 1.00; if (floatptr) *floatptr = &areawin->textscale; if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) { if (areawin->textpos > 0 || areawin->textpos < stringlength(settext->string, True, areawin->topinstance)) { settext = *((labelptr *)EDITPART); strptr = findstringpart(areawin->textpos - 1, NULL, settext->string, areawin->topinstance); nextptr = findstringpart(areawin->textpos, NULL, settext->string, areawin->topinstance); if (strptr->type == FONT_SCALE) { if (floatptr) *floatptr = &strptr->data.scale; } else if (nextptr && nextptr->type == FONT_SCALE) { if (floatptr) *floatptr = &nextptr->data.scale; } else if (floatptr) *floatptr = (float *)(&f_one); } else { settext = *((labelptr *)EDITPART); if (floatptr) *floatptr = &(settext->scale); } } else if (areawin->selects > 0) { for (osel = areawin->selectlist; osel < areawin->selectlist + areawin->selects; osel++) { if (SELECTTYPE(osel) == LABEL) { settext = SELTOLABEL(osel); if (floatptr) *floatptr = &(settext->scale); break; } } } return settext; } /*--------------------------------------------------------------*/ /* Set a character kern value */ /*--------------------------------------------------------------*/ void setkern(xcWidget w, stringpart *kpart) { char *sptr; short kd[2]; kd[0] = kd[1] = 0; if ((sptr = strchr(_STR2, ',')) == NULL) Wprintf("Use notation X,Y"); else { *sptr = '\0'; sscanf(_STR2, "%hd", &kd[0]); sscanf(sptr + 1, "%hd", &kd[1]); if (kpart == NULL) labeltext(KERN, (char *)kd); else { labelptr curlabel = TOLABEL(EDITPART); undrawtext(curlabel); kpart->data.kern[0] = kd[0]; kpart->data.kern[1] = kd[1]; redrawtext(curlabel); } } } /*----------------------------------------------------------------*/ /* Set the drawing scale (specified as ratio X:Y) */ /*----------------------------------------------------------------*/ void setdscale(xcWidget w, XPoint *dataptr) { char *sptr; if ((sptr = strchr(_STR2, ':')) == NULL) Wprintf("Use ratio X:Y"); else { *sptr = '\0'; sscanf(_STR2, "%hd", &(dataptr->x)); sscanf(sptr + 1, "%hd", &(dataptr->y)); Wprintf("New scale is %hd:%hd", dataptr->x, dataptr->y); W1printf(" "); } } /*----------------------------------------------------------------*/ /* Set the scale of an object or group of selected objects */ /*----------------------------------------------------------------*/ void setosize(xcWidget w, objinstptr dataptr) { float tmpres, oldsize; Boolean waschanged = FALSE; short *osel; objinstptr nsobj; int res = sscanf(_STR2, "%f", &tmpres); // Negative values are flips---deal with them independently if (tmpres < 0) tmpres = -tmpres; if (res == 0 || tmpres == 0) { Wprintf("Illegal value"); return; } for (osel = areawin->selectlist; osel < areawin->selectlist + areawin->selects; osel++) { if (SELECTTYPE(osel) == OBJINST) { nsobj = SELTOOBJINST(osel); oldsize = nsobj->scale; nsobj->scale = (oldsize < 0) ? -tmpres : tmpres; if (oldsize != tmpres) { register_for_undo(XCF_Rescale, UNDO_MORE, areawin->topinstance, SELTOGENERIC(osel), (double)oldsize); waschanged = TRUE; } } } /* unselect_all(); */ if (waschanged) undo_finish_series(); pwriteback(areawin->topinstance); drawarea(NULL, NULL, NULL); } /*----------------------------------------------------------------*/ /* Set the linewidth of all selected arcs, polygons, splines, and */ /* paths. */ /*----------------------------------------------------------------*/ void setwwidth(xcWidget w, void *dataptr) { float tmpres, oldwidth; short *osel; arcptr nsarc; polyptr nspoly; splineptr nsspline; pathptr nspath; if (sscanf(_STR2, "%f", &tmpres) == 0) { Wprintf("Illegal value"); return; } else if (areawin->selects == 0) { areawin->linewidth = tmpres; } else { for (osel = areawin->selectlist; osel < areawin->selectlist + areawin->selects; osel++) { if (SELECTTYPE(osel) == ARC) { nsarc = SELTOARC(osel); oldwidth = nsarc->width; nsarc->width = tmpres; } else if (SELECTTYPE(osel) == POLYGON) { nspoly = SELTOPOLY(osel); oldwidth = nspoly->width; nspoly->width = tmpres; } else if (SELECTTYPE(osel) == SPLINE) { nsspline = SELTOSPLINE(osel); oldwidth = nsspline->width; nsspline->width = tmpres; } else if (SELECTTYPE(osel) == PATH) { nspath = SELTOPATH(osel); oldwidth = nspath->width; nspath->width = tmpres; } if (oldwidth != tmpres) register_for_undo(XCF_Rescale, UNDO_MORE, areawin->topinstance, SELTOGENERIC(osel), (double)oldwidth); } unselect_all(); pwriteback(areawin->topinstance); drawarea(NULL, NULL, NULL); } } /*--------------------------------------------------------------*/ /* Add a new font name to the list of known fonts */ /* Register the font number for the Alt-F cycling mechanism */ /* Tcl: depends on command tag mechanism for GUI menu update. */ /*--------------------------------------------------------------*/ #ifdef TCL_WRAPPER void makenewfontbutton() { nfontnumbers++; if (nfontnumbers == 1) fontnumbers = (u_short *)malloc(sizeof(u_short)); else fontnumbers = (u_short *)realloc(fontnumbers, nfontnumbers * sizeof(u_short)); fontnumbers[nfontnumbers - 1] = fontcount - 1; } #endif /* TCL_WRAPPER */ /*---------------------------------------------------------------*/ /* Some Xcircuit routines using toggle and toggleexcl, */ /* put here because they reference the menu structures directly. */ /*---------------------------------------------------------------*/ void setcolorscheme(Boolean boolvalue) { if (boolvalue) { PARAMCOLOR = appdata.parampix; AUXCOLOR = appdata.auxpix; OFFBUTTONCOLOR = appdata.buttonpix; SELECTCOLOR = appdata.selectpix; GRIDCOLOR = appdata.gridpix; SNAPCOLOR = appdata.snappix; AXESCOLOR = appdata.axespix; BACKGROUND = appdata.bg; FOREGROUND = appdata.fg; } else { PARAMCOLOR = appdata.parampix2; AUXCOLOR = appdata.auxpix2; OFFBUTTONCOLOR = appdata.buttonpix2; SELECTCOLOR = appdata.selectpix2; GRIDCOLOR = appdata.gridpix2; SNAPCOLOR = appdata.snappix2; AXESCOLOR = appdata.axespix2; BACKGROUND = appdata.bg2; FOREGROUND = appdata.fg2; } BARCOLOR = appdata.barpix; FILTERCOLOR = appdata.filterpix; LOCALPINCOLOR = appdata.localcolor; GLOBALPINCOLOR = appdata.globalcolor; INFOLABELCOLOR = appdata.infocolor; RATSNESTCOLOR = appdata.ratsnestcolor; BBOXCOLOR = appdata.bboxpix; CLIPMASKCOLOR = appdata.clipcolor; #if !defined(TCL_WRAPPER) && !defined(DOUBLEBUFFER) { Arg wargs[1]; XtSetArg(wargs[0], XtNbackground, BACKGROUND); XtSetValues(areawin->area, wargs, 1); } #endif } /*----------------------------------------------------------------*/ /* Change menu selection for reported measurement units */ /*----------------------------------------------------------------*/ #ifdef TCL_WRAPPER void togglegrid(u_short type) { static char *stylenames[] = { "decimal inches", "fractional inches", "centimeters", "internal units", NULL }; XcInternalTagCall(xcinterp, 3, "config", "coordstyle", stylenames[type]); } #endif /* TCL_WRAPPER */ /*----------------------------------------------------------------*/ /* Called by setgridtype() to complete setting the reported */ /* measurement units */ /*----------------------------------------------------------------*/ void getgridtype(xcWidget button, pointertype value, caddr_t calldata) { short oldtype = xobjs.pagelist[areawin->page]->coordstyle; float scalefac = getpsscale(1.0, areawin->page) / INCHSCALE; #ifndef TCL_WRAPPER togglegridstyles(button); #endif xobjs.pagelist[areawin->page]->coordstyle = (short)value; switch(value) { case FRAC_INCH: case DEC_INCH: case INTERNAL: if (oldtype == CM) { xobjs.pagelist[areawin->page]->outscale *= scalefac; #ifndef TCL_WRAPPER /* Note: Tcl defines a method for selecting standard */ /* page sizes. We really DON'T want to reset the size */ /* just because we switched measurement formats! */ xobjs.pagelist[areawin->page]->pagesize.x = 612; xobjs.pagelist[areawin->page]->pagesize.y = 792; /* letter */ #endif } break; case CM: if (oldtype != CM) { xobjs.pagelist[areawin->page]->outscale *= scalefac; #ifndef TCL_WRAPPER xobjs.pagelist[areawin->page]->pagesize.x = 595; xobjs.pagelist[areawin->page]->pagesize.y = 842; /* A4 */ #endif } break; } if (oldtype != xobjs.pagelist[areawin->page]->coordstyle) { drawarea(NULL, NULL, NULL); W1printf(" "); } } /*------------------------------------------------------*/ /* Make new library, add new button to the "Libraries" */ /* cascaded menu, compose the library page, update the */ /* library directory, and go to that library page. */ /*------------------------------------------------------*/ void newlibrary(xcWidget w, caddr_t clientdata, caddr_t calldata) { int libnum = createlibrary(FALSE); startcatalog(w, libnum, NULL); } /*----------------------------------------------*/ /* Find an empty library, and return its page */ /* number if it exists. Otherwise, return -1. */ /* This search does not include the so-called */ /* "User Library" (last library in list). */ /*----------------------------------------------*/ int findemptylib() { int i; for (i = 0; i < xobjs.numlibs - 1; i++) { if (xobjs.userlibs[i].number == 0) return i; } return -1; } /*----------------------------------------------*/ /* Make new page; goto that page */ /* (wrapper for routine events.c:newpage()) */ /*----------------------------------------------*/ void newpagemenu(xcWidget w, pointertype value, caddr_t nulldata) { newpage((short)value); } #ifdef TCL_WRAPPER /*----------------------------------------------*/ /* Make new library and add a new button to the */ /* "Libraries" cascaded menu. */ /*----------------------------------------------*/ int createlibrary(Boolean force) { /* xcWidget libmenu, newbutton, oldbutton; (jdk) */ #ifndef TCL_WRAPPER Arg wargs[2]; #endif /* char libstring[20]; (jdk) */ int libnum; objectptr newlibobj; /* If there's an empty library, return its number */ if ((!force) && (libnum = findemptylib()) >= 0) return (libnum + LIBRARY); libnum = (xobjs.numlibs++) + LIBRARY; xobjs.libtop = (objinstptr *)realloc(xobjs.libtop, (libnum + 1) * sizeof(objinstptr)); xobjs.libtop[libnum] = xobjs.libtop[libnum - 1]; libnum--; newlibobj = (objectptr) malloc(sizeof(object)); initmem(newlibobj); xobjs.libtop[libnum] = newpageinst(newlibobj); sprintf(newlibobj->name, "Library %d", libnum - LIBRARY + 1); /* Create the library */ xobjs.userlibs = (Library *) realloc(xobjs.userlibs, xobjs.numlibs * sizeof(Library)); xobjs.userlibs[libnum + 1 - LIBRARY] = xobjs.userlibs[libnum - LIBRARY]; xobjs.userlibs[libnum - LIBRARY].library = (objectptr *) malloc(sizeof(objectptr)); xobjs.userlibs[libnum - LIBRARY].number = 0; xobjs.userlibs[libnum - LIBRARY].instlist = NULL; sprintf(_STR2, "xcircuit::newlibrarybutton \"%s\"", newlibobj->name); Tcl_Eval(xcinterp, _STR2); /* Update the library directory to include the new page */ composelib(LIBLIB); return libnum; } /*--------------------------------------------------------------*/ /* Routine called by newpage() if new button needs to be made */ /* to add to the "Pages" cascaded menu. */ /*--------------------------------------------------------------*/ void makepagebutton() { /* xcWidget pagemenu, newbutton; (jdk) */ /* char pagestring[10]; (jdk) */ /* make new entry in the menu */ sprintf(_STR2, "newpagebutton \"Page %d\"", xobjs.pages); Tcl_Eval(xcinterp, _STR2); /* Update the page directory */ composelib(PAGELIB); } /*----------------------------------------------------------------*/ /* Find the Page menu button associated with the page number */ /* (passed parameter) and set the label of that button to the */ /* object name (= page label) */ /*----------------------------------------------------------------*/ void renamepage(short pagenumber) { objinstptr thisinst = xobjs.pagelist[pagenumber]->pageinst; char *pname, *plabel; if ((pagenumber >= 0) && (pagenumber < xobjs.pages - 1) && (thisinst != NULL)) { plabel = thisinst->thisobject->name; pname = (char *)malloc(28 + strlen(plabel)); sprintf(pname, "xcircuit::renamepage %d {%s}", pagenumber + 1, plabel); Tcl_Eval(xcinterp, pname); free(pname); } } /*--------------------------------------------------------------*/ /* Same routine as above, for Library page menu buttons */ /*--------------------------------------------------------------*/ void renamelib(short libnumber) { if (libnumber <= xobjs.numlibs) return; sprintf(_STR2, "xcircuit::renamelib %d \"%s\"", libnumber - LIBRARY + 1, xobjs.libtop[libnumber]->thisobject->name); Tcl_Eval(xcinterp, _STR2); } /*--------------------------------------------------------------*/ /* Set the menu checkmarks on the color menu */ /*--------------------------------------------------------------*/ void setcolormark(int colorval) { /* Set GUI variables and execute any command tags associated */ /* with the "color" command */ char cstr[6]; int i; if (colorval != DEFAULTCOLOR) { for (i = 0; i < number_colors; i++) if (colorlist[i].color.pixel == colorval) { sprintf(cstr, "%5d", i); break; } } #ifdef TCL_WRAPPER XcInternalTagCall(xcinterp, 3, "color", "set", (colorval == DEFAULTCOLOR) ? "inherit" : cstr); #endif } /*----------------------------------------------------------------*/ /* Set the checkmarks on the element styles menu */ /*----------------------------------------------------------------*/ void setallstylemarks(u_short styleval) { /* Execute any command tags associated */ /* with the "fill" and "border" commands. */ char fstr[10]; int fillfactor; const char *bptr; const char *borders[] = {"solid", "unbordered", "dashed", "dotted", NULL}; enum BorderIdx { SolidIdx, UnborderedIdx, DashedIdx, DottedIdx }; if (styleval & FILLED) { fillfactor = (int)(12.5 * (float)(1 + ((styleval & FILLSOLID) >> 5))); if (fillfactor < 100) sprintf(fstr, "%d", fillfactor); else strcpy(fstr, "solid"); } else strcpy(fstr, "unfilled"); switch (styleval & BORDERS) { case DASHED: bptr = borders[DashedIdx]; break; case DOTTED: bptr = borders[DottedIdx]; break; case NOBORDER: bptr = borders[UnborderedIdx]; break; default: bptr = borders[SolidIdx]; break; } XcInternalTagCall(xcinterp, 3, "fill", fstr, (styleval & OPAQUE) ? "opaque" : "transparent"); XcInternalTagCall(xcinterp, 3, "border", "bbox", (styleval & BBOX) ? "true" : "false"); XcInternalTagCall(xcinterp, 3, "border", "clipmask", (styleval & CLIPMASK) ? "true" : "false"); XcInternalTagCall(xcinterp, 2, "border", (styleval & UNCLOSED) ? "unclosed" : "closed"); XcInternalTagCall(xcinterp, 2, "border", bptr); } #endif /* TCL_WRAPPER */ /*--------------------------------------------------------------*/ /* Check for a bounding box polygon */ /*--------------------------------------------------------------*/ polyptr checkforbbox(objectptr localdata) { polyptr *cbbox; for (cbbox = (polyptr *)localdata->plist; cbbox < (polyptr *)localdata->plist + localdata->parts; cbbox++) if (IS_POLYGON(*cbbox)) if ((*cbbox)->style & BBOX) return *cbbox; return NULL; } /*--------------------------------------------------------------*/ /* Set a value for element style. "Mask" determines the bits */ /* to be affected, so that "value" may turn bits either on or */ /* off. */ /*--------------------------------------------------------------*/ int setelementstyle(xcWidget w, u_short value, u_short mask) { Boolean preselected, selected = False; short *sstyle; u_short newstyle, oldstyle; if (areawin->selects == 0) { preselected = FALSE; if (value & BBOX) checkselect(POLYGON); else checkselect(ARC | SPLINE | POLYGON | PATH); } else preselected = TRUE; if (areawin->selects > 0) { if (value & BBOX) { polyptr ckp; if (areawin->selects != 1) { Wprintf("Choose only one polygon to be the bounding box"); return -1; } else if (SELECTTYPE(areawin->selectlist) != POLYGON) { Wprintf("Bounding box can only be a polygon"); return -1; } else if (((ckp = checkforbbox(topobject)) != NULL) && (ckp != SELTOPOLY(areawin->selectlist))) { Wprintf("Only one bounding box allowed per page"); return -1; } } for (sstyle = areawin->selectlist; sstyle < areawin->selectlist + areawin->selects; sstyle++) { short stype = SELECTTYPE(sstyle); if (stype & (ARC | POLYGON | SPLINE | PATH)) { short *estyle; switch (stype) { case ARC: estyle = &((SELTOARC(sstyle))->style); break; case SPLINE: estyle = &((SELTOSPLINE(sstyle))->style); break; case POLYGON: estyle = &((SELTOPOLY(sstyle))->style); break; case PATH: estyle = &((SELTOPATH(sstyle))->style); break; } oldstyle = newstyle = *estyle; newstyle &= ~(mask); newstyle |= value; if (oldstyle != newstyle) { if ((newstyle & NOBORDER) && !(newstyle & FILLED)) { Wprintf("Must have either a border or filler"); continue; } XSetFunction(dpy, areawin->gc, GXcopy); XSetForeground(dpy, areawin->gc, BACKGROUND); easydraw(*sstyle, DOFORALL); *estyle = newstyle; if (mask & BBOX) (SELTOPOLY(sstyle))->color = (value & BBOX) ? BBOXCOLOR : DEFAULTCOLOR; XSetFunction(dpy, areawin->gc, GXxor); XSetForeground(dpy, areawin->gc, SELECTCOLOR ^ BACKGROUND); easydraw(*sstyle, DOFORALL); #ifdef TCL_WRAPPER register_for_undo(XCF_ChangeStyle, (sstyle == areawin->selectlist + areawin->selects - 1) ? UNDO_DONE : UNDO_MORE, areawin->topinstance, SELTOGENERIC(sstyle), (int)oldstyle); #else /* Tcl version differs in that the element is not deselected after */ register_for_undo(XCF_ChangeStyle, UNDO_MORE, areawin->topinstance, SELTOGENERIC(sstyle), (int)oldstyle); #endif } selected = True; } } } if (selected) pwriteback(areawin->topinstance); else { newstyle = areawin->style; if (value & BBOX) { Wprintf("Cannot set default style to Bounding Box"); newstyle &= ~(BBOX); return -1; } else if (value & CLIPMASK) { Wprintf("Cannot set default style to Clip Mask"); newstyle &= ~(CLIPMASK); return -1; } else { newstyle &= ~mask; newstyle |= value; } if ((newstyle & NOBORDER) && !(newstyle & FILLED)) { Wprintf("Must have either a border or filler"); return -1; } areawin->style = newstyle; #ifndef TCL_WRAPPER overdrawpixmap(w); #endif } #ifndef TCL_WRAPPER setallstylemarks(newstyle); #endif if (!preselected) unselect_all(); return (int)newstyle; } /*-----------------------------------------------*/ /* Set the color value for all selected elements */ /*-----------------------------------------------*/ #ifdef TCL_WRAPPER void setcolor(xcWidget w, int cindex) { short *scolor; int *ecolor, cval, oldcolor; Boolean selected = False; stringpart *strptr, *nextptr; if (cindex == -1) cval = -1; else cval = colorlist[cindex].color.pixel; if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) { labelptr curlabel = TOLABEL(EDITPART); strptr = findstringpart(areawin->textpos - 1, NULL, curlabel->string, areawin->topinstance); nextptr = findstringpart(areawin->textpos, NULL, curlabel->string, areawin->topinstance); if (strptr && strptr->type == FONT_COLOR) { undrawtext(curlabel); strptr->data.color = cindex; redrawtext(curlabel); } else if (nextptr && nextptr->type == FONT_COLOR) { undrawtext(curlabel); nextptr->data.color = cindex; redrawtext(curlabel); } else { sprintf(_STR2, "%d", cindex); labeltext(FONT_COLOR, (char *)&cindex); } } else if (areawin->selects > 0) { for (scolor = areawin->selectlist; scolor < areawin->selectlist + areawin->selects; scolor++) { ecolor = &(SELTOCOLOR(scolor)); oldcolor = *ecolor; *ecolor = cval; selected = True; register_for_undo(XCF_Color, (scolor == areawin->selectlist + areawin->selects - 1) ? UNDO_DONE : UNDO_MORE, areawin->topinstance, SELTOGENERIC(scolor), (int)oldcolor); } } setcolormark(cval); if (!selected) { if (eventmode != TEXT_MODE && eventmode != ETEXT_MODE) areawin->color = cval; } else pwriteback(areawin->topinstance); } /*--------------------------------------------------------------*/ /* Set the menu checkmarks on the font menu */ /*--------------------------------------------------------------*/ void togglefontmark(int fontval) { if (fonts[fontval].family != NULL) XcInternalTagCall(xcinterp, 3, "label", "family", fonts[fontval].family); } /*------------------------------------------------------*/ /* Set checkmarks on label style menu */ /* fvalue is for font, jvalue is for justification */ /*------------------------------------------------------*/ void togglestylemark(int styleval) { char *cstyle = translatestyle(styleval); if (cstyle != NULL) XcInternalTagCall(xcinterp, 3, "label", "style", cstyle); } /*------------------------------------------------------*/ /* Set checkmarks on label encoding menu */ /*------------------------------------------------------*/ void toggleencodingmark(int encodingval) { char *cenc = translateencoding(encodingval); if (cenc != NULL) XcInternalTagCall(xcinterp, 3, "label", "encoding", cenc); } /*------------------------------------------------------*/ /* Set checkmarks on label justification & flags menu */ /*------------------------------------------------------*/ void togglejustmarks(int justvalue) { XcInternalTagCall(xcinterp, 4, "label", "justify", (justvalue & RIGHT) ? "right" : (justvalue & NOTLEFT) ? "center" : "left", (justvalue & TOP) ? "top" : (justvalue & NOTBOTTOM) ? "middle" : "bottom"); XcInternalTagCall(xcinterp, 3, "label", "flipinvariant", (justvalue & FLIPINV) ? "true" : "false"); XcInternalTagCall(xcinterp, 3, "label", "latex", (justvalue & LATEXLABEL) ? "true" : "false"); XcInternalTagCall(xcinterp, 3, "label", "visible", (justvalue & PINVISIBLE) ? "true" : "false"); } /*-------------------------------------------------------------*/ /* Simultaneously set all relevant checkmarks for a text label */ /*-------------------------------------------------------------*/ void setfontmarks(short fvalue, short jvalue) { if ((fvalue >= 0) && (fvalue < fontcount)) { toggleencodingmark(fvalue); togglestylemark(fvalue); togglefontmark(fvalue); } togglejustmarks(jvalue); } #endif /* TCL_WRAPPER */ /*--------------------------------------------------------------*/ /* Parameterize a label string (wrapper for parameterize()). */ /* Assumes that the name has been generated by the popup prompt */ /* and is therefore held in variable _STR2 */ /*--------------------------------------------------------------*/ void stringparam(xcWidget w, caddr_t clientdata, caddr_t calldata) { genericptr *settext; if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) { settext = (genericptr *)EDITPART; makeparam(TOLABEL(settext), _STR2); unselect_all(); setparammarks(NULL); } else if (checkselect(LABEL)) parameterize(P_SUBSTRING, _STR2, -1); } /*--------------------------------------------------------------*/ /* Numerical parameterization (wrapper for parameterize()). */ /*--------------------------------------------------------------*/ void startparam(xcWidget w, pointertype value, caddr_t calldata) { if (value == (pointertype)P_SUBSTRING) { strcpy(_STR2, (calldata != NULL) ? (char *)calldata : "substring"); stringparam(w, NULL, NULL); } else if ((eventmode != NORMAL_MODE) || (areawin->selects > 0)) parameterize((int)value, (char *)calldata, -1); } /*---------------------------------------------------------------*/ /* Unparameterize a label string (wrapper for unparameterize()). */ /*---------------------------------------------------------------*/ void startunparam(xcWidget w, pointertype value, caddr_t calldata) { if (areawin->selects > 0) unparameterize((int)value); unselect_all(); setparammarks(NULL); } /*----------------------------------------------------------------*/ /* Set checkmarks on font menu according to the global defaults */ /*----------------------------------------------------------------*/ void setdefaultfontmarks() { setfontmarks(areawin->psfont, areawin->justify); } /*----------------------------------------------------------------*/ /* Pick up font name from _STR2 and pass it to loadfontfile() */ /*----------------------------------------------------------------*/ void locloadfont(xcWidget w, char *value) { loadfontfile(_STR2); free(value); } /*----------------------------------------------------------------*/ /* Find the best matching font given new font, style, or encoding */ /*----------------------------------------------------------------*/ /* newfont, style, or encoding = -1 when not applicable */ /* Return the number of the best matching font. */ /*----------------------------------------------------------------*/ short findbestfont(short curfont, short newfont, short style, short encoding) { char *newfamily; short i, newstyle, newenc; if (fontcount == 0) return -1; if (curfont < 0) curfont = 0; if (newfont < 0) newfamily = fonts[curfont].family; else if (newfont >= fontcount) { /* move to next font family */ short newidx; newfont = 0; while (strcmp(fonts[fontnumbers[newfont]].family, fonts[curfont].family)) newfont++; newidx = (newfont + 1) % nfontnumbers; while (!strcmp(fonts[curfont].family, fonts[fontnumbers[newidx]].family) && newfont != newidx) newidx = (newidx + 1) % nfontnumbers; newfamily = fonts[fontnumbers[newidx]].family; newfont = fontnumbers[newidx]; } else newfamily = fonts[newfont].family; if (style < 0) newstyle = fonts[curfont].flags & 0x03; else newstyle = style & 0x03; if (encoding < 0) newenc = fonts[curfont].flags & 0xf80; else newenc = encoding << 7; /* Best position is a match on all conditions */ for (i = 0; i < fontcount; i++) if ((!strcmp(fonts[i].family, newfamily)) && ((fonts[i].flags & 0x03) == newstyle) && ((fonts[i].flags & 0xf80) == newenc)) return i; /* Fallback position 1: Match requested property and one other. */ /* order of preference: */ /* Requested property Priority 1 Priority 2 */ /* Font Style Encoding */ /* Style Font (none) */ /* Encoding Font (none) */ for (i = 0; i < fontcount; i++) { if (newfont >= 0) { if ((!strcmp(fonts[i].family, newfamily)) && (fonts[i].flags & 0x03) == newstyle) return i; } else if (style >= 0) { if (((fonts[i].flags & 0x03) == newstyle) && (!strcmp(fonts[i].family, newfamily))) return i; } else if (encoding >= 0) { if (((fonts[i].flags & 0xf80) == newenc) && (!strcmp(fonts[i].family, newfamily))) return i; } } for (i = 0; i < fontcount; i++) { if (newfont >= 0) { if ((!strcmp(fonts[i].family, newfamily)) && ((fonts[i].flags & 0xf80) >> 7) == newenc) return i; } } /* Fallback position 2: Match only the requested property. */ /* For font selection only: Don't want to select a new font */ /* just because a certain style or encoding wasn't available.*/ for (i = 0; i < fontcount; i++) { if (newfont >= 0) { if (!strcmp(fonts[i].family, newfamily)) return i; } } /* Failure to find matching font property */ if (style >= 0) { Wprintf("Font %s not available in this style", newfamily); } else { Wprintf("Font %s not available in this encoding", newfamily); } return (-1); } /*----------------------------------------------------------------*/ /* Set the font. This depends on the system state as to whether */ /* font is set at current position in label, for an entire label, */ /* or as the default font to begin new labels. */ /*----------------------------------------------------------------*/ void setfontval(xcWidget w, pointertype value, labelptr settext) { int newfont; short i, tc; stringpart *strptr; if (settext != NULL) { /* if last byte was a font designator, use it */ if (areawin->textpos > 0 || areawin->textpos < stringlength(settext->string, True, areawin->topinstance)) { strptr = findstringpart(areawin->textpos - 1, NULL, settext->string, areawin->topinstance); if (strptr->type == FONT_NAME) { tc = strptr->data.font; i = findbestfont(tc, (short)value, -1, -1); if (i >= 0) { undrawtext(settext); strptr->data.font = i; redrawtext(settext); if (w != NULL) { charreport(settext); togglefontmark(i); } } return; } } /* otherwise, look for the last style used in the string */ tc = findcurfont(areawin->textpos, settext->string, areawin->topinstance); } else tc = areawin->psfont; /* Font change command will always find a value since at least one */ /* font has to exist for the font menu button to exist. */ if ((newfont = (int)findbestfont(tc, (short)value, -1, -1)) < 0) return; if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) { Wprintf("Font is now %s", fonts[newfont].psname); sprintf(_STR2, "%d", newfont); labeltext(FONT_NAME, (char *)&newfont); } else { Wprintf("Default font is now %s", fonts[newfont].psname); areawin->psfont = newfont; } if (w != NULL) togglefontmark(newfont); } /*----------------------------------------------------------------*/ /* Wrapper for routine setfontval() */ /*----------------------------------------------------------------*/ void setfont(xcWidget w, pointertype value, caddr_t calldata) { short *fselect; labelptr settext; short labelcount = 0; Boolean preselected; if (eventmode == CATALOG_MODE || eventmode == FONTCAT_MODE || eventmode == EFONTCAT_MODE) return; if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) { settext = *((labelptr *)EDITPART); setfontval(w, value, settext); charreport(settext); } else { if (areawin->selects == 0) { checkselect(LABEL); preselected = FALSE; } else preselected = TRUE; areawin->textpos = 1; for (fselect = areawin->selectlist; fselect < areawin->selectlist + areawin->selects; fselect++) { if (SELECTTYPE(fselect) == LABEL) { labelcount++; settext = SELTOLABEL(fselect); setfontval(NULL, value, settext); } } if (labelcount == 0) setfontval(w, value, NULL); else if (!preselected) unselect_all(); } } /*----------------------------------------------------------------*/ /* Set the style (bold, italic, normal) for the font, similarly */ /* to the above routine setfontval(). */ /*----------------------------------------------------------------*/ void setfontstyle(xcWidget w, pointertype value, labelptr settext) { int newfont; short i, tc; stringpart *strptr; if (settext != NULL) { /* if last byte was a font designator, use it */ if (areawin->textpos > 0 || areawin->textpos < stringlength(settext->string, True, areawin->topinstance)) { strptr = findstringpart(areawin->textpos - 1, NULL, settext->string, areawin->topinstance); if (strptr->type == FONT_NAME) { tc = strptr->data.font; /* find font which matches family and style, if available */ i = findbestfont(tc, -1, (short)value, -1); if (i >= 0) { undrawtext(settext); strptr->data.font = i; redrawtext(settext); if (w != NULL) { charreport(settext); #ifndef TCL_WRAPPER togglefontstyles(w); #endif } } return; } } /* Otherwise, look for the last font used in the string */ /* Fix by Dimitri Princen. Was areawin->textpos - 2; was there a */ /* reason for that? */ tc = findcurfont(areawin->textpos, settext->string, areawin->topinstance); } else tc = areawin->psfont; if ((newfont = (int)findbestfont(tc, -1, (short)value, -1)) < 0) return; if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) { Wprintf("Font is now %s", fonts[newfont].psname); sprintf(_STR2, "%d", newfont); labeltext(FONT_NAME, (char *)&newfont); } else { Wprintf("Default font is now %s", fonts[newfont].psname); areawin->psfont = newfont; } #ifdef TCL_WRAPPER toggleencodingmark(value); #else togglefontstyles(w); #endif } /*----------------------------------------------------------------*/ /* Wrapper for routine setfontstyle() */ /*----------------------------------------------------------------*/ void fontstyle(xcWidget w, pointertype value, caddr_t nulldata) { short *fselect; labelptr settext; short labelcount = 0; Boolean preselected; if (eventmode == CATALOG_MODE || eventmode == FONTCAT_MODE || eventmode == EFONTCAT_MODE) return; if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) { settext = *((labelptr *)EDITPART); setfontstyle(w, value, settext); charreport(settext); } else { if (areawin->selects == 0) { checkselect(LABEL); preselected = FALSE; } else preselected = TRUE; areawin->textpos = 1; for (fselect = areawin->selectlist; fselect < areawin->selectlist + areawin->selects; fselect++) { if (SELECTTYPE(fselect) == LABEL) { labelcount++; settext = SELTOLABEL(fselect); setfontstyle(NULL, value, settext); } } if (labelcount == 0) setfontstyle(w, value, NULL); else if (!preselected) unselect_all(); } } /*----------------------------------------------------------------*/ /* Set the encoding (standard, ISO-Latin1, special) for the font, */ /* similarly to the above routine setfontval(). */ /*----------------------------------------------------------------*/ void setfontencoding(xcWidget w, pointertype value, labelptr settext) { int newfont; short i, tc; stringpart *strptr; if (settext != NULL) { /* if last byte was a font designator, use it */ if (areawin->textpos > 0 || areawin->textpos < stringlength(settext->string, True, areawin->topinstance)) { strptr = findstringpart(areawin->textpos - 1, NULL, settext->string, areawin->topinstance); if (strptr->type == FONT_NAME) { tc = strptr->data.font; i = findbestfont(tc, -1, -1, (short)value); if (i >= 0) { undrawtext(settext); strptr->data.font = i; redrawtext(settext); if (w != NULL) { charreport(settext); #ifdef TCL_WRAPPER toggleencodingmark(value); #else toggleencodings(w); #endif } } return; } } /* otherwise, look for the last style used in the string */ tc = findcurfont(areawin->textpos - 2, settext->string, areawin->topinstance); } else tc = areawin->psfont; if ((newfont = (int)findbestfont(tc, -1, -1, (short)value)) < 0) return; if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) { Wprintf("Font is now %s", fonts[newfont].psname); sprintf(_STR2, "%d", newfont); labeltext(FONT_NAME, (char *)&newfont); } else { Wprintf("Default font is now %s", fonts[newfont].psname); areawin->psfont = newfont; } #ifndef TCL_WRAPPER toggleencodings(w); #endif } /*----------------------------------------------------------------*/ /* Wrapper for routine setfontencoding() */ /*----------------------------------------------------------------*/ void fontencoding(xcWidget w, pointertype value, caddr_t nulldata) { short *fselect; labelptr settext; short labelcount = 0; Boolean preselected; if (eventmode == CATALOG_MODE || eventmode == FONTCAT_MODE || eventmode == EFONTCAT_MODE) return; if (eventmode == TEXT_MODE || eventmode == ETEXT_MODE) { settext = *((labelptr *)EDITPART); setfontencoding(w, value, settext); charreport(settext); } else { if (areawin->selects == 0) { checkselect(LABEL); preselected = FALSE; } else preselected = TRUE; areawin->textpos = 1; for (fselect = areawin->selectlist; fselect < areawin->selectlist + areawin->selects; fselect++) { if (SELECTTYPE(fselect) == LABEL) { labelcount++; settext = SELTOLABEL(fselect); setfontencoding(NULL, value, settext); } } if (labelcount == 0) setfontencoding(w, value, NULL); else if (!preselected) unselect_all(); } } /*----------------------------------------------*/ /* Generate the table of special characters */ /* */ /* Return FALSE if the edited label is LaTeX- */ /* compatible, since LaTeX text does not */ /* usually contain special characters, but it */ /* does contain a lot of backslashes. */ /*----------------------------------------------*/ Boolean dospecial() { labelptr curlabel; int cfont; curlabel = TOLABEL(EDITPART); if (curlabel->justify & LATEXLABEL) return False; cfont = findcurfont(areawin->textpos, curlabel->string, areawin->topinstance); composefontlib(cfont); startcatalog(NULL, FONTLIB, NULL); return True; } /*-------------------------------------------------------------------------*/