Logo Search packages:      
Sourcecode: xcircuit version File versions

menucalls.c

/*----------------------------------------------------------------------*/
/* menucalls.c --- callback routines from the menu buttons        */
/*             and associated routines                      */
/* Copyright (c) 2002  Tim Edwards, Johns Hopkins University            */
/*----------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <errno.h>
#include <limits.h>

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xutil.h>

#ifdef TCL_WRAPPER 
#include <tk.h>
#else
#include "Xw/Xw.h"
#include "Xw/MenuBtn.h"
#include "Xw/PopupMgr.h"
#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 short       popups;         /* total number of popup windows */
extern xcWidget    menuwidgets[];
extern xcWidget    toolbar;
extern Globaldata xobjs;
extern Clientdata areastruct;
extern int    *appcolors;
extern int    number_colors;
extern colorindex *colorlist;
extern ApplicationData appdata;
extern Cursor       appcursors[NUM_CURSORS];
extern fontinfo *fonts;
extern short fontcount;
extern short eventmode, textpos, textend;

#ifdef TCL_WRAPPER
extern Tcl_Interp *xcinterp;
#endif

/*----------------------------------------------------------------------*/
/* The rest of the local includes depend on the prototype declarations  */
/* and some of the external global variable declarations.         */
/*----------------------------------------------------------------------*/
#ifndef TCL_WRAPPER
#include "menus.h"
#include "menudep.h"
#endif

/*----------------------------------------------------------------------*/
/* Local Variable definitions                               */
/*----------------------------------------------------------------------*/

u_short *fontnumbers;
u_char nfontnumbers;

/*--------------------------------------------------------------*/
/* Enable or Disable the toolbar                      */
/*--------------------------------------------------------------*/

#ifdef HAVE_XPM
void dotoolbar(xcWidget w, caddr_t clientdata, caddr_t calldata)   
{
   Arg wargs[1];

#ifndef TCL_WRAPPER
   if (areastruct.toolbar_on) {
      areastruct.toolbar_on = False;
      XtUnmanageChild(toolbar);
      XtSetArg(wargs[0], XtNlabel, "Enable Toolbar");
      XtSetValues(OptionsDisableToolbarButton, wargs, 1);
      XtRemoveCallback(areastruct.area, XtNresize, (XtCallbackProc)resizetoolbar, NULL);
   }
   else {
      areastruct.toolbar_on = True;
      XtManageChild(toolbar);
      XtSetArg(wargs[0], XtNlabel, "Disable Toolbar");
      XtSetValues(OptionsDisableToolbarButton, wargs, 1);
      XtAddCallback(areastruct.area, XtNresize, (XtCallbackProc)resizetoolbar, NULL);
   }
#endif
}  

#ifndef TCL_WRAPPER

/*--------------------------------------------------------------*/
/* Overwrite the toolbar pixmap for color or stipple entries      */
/*--------------------------------------------------------------*/

void overdrawpixmap(xcWidget button)
{
   xcWidget pbutton;
   Arg args[3];
   int ltype, color;
   Pixmap stippix;

   if (button == NULL) return;

   XtSetArg(args[0], XtNlabelType, &ltype);
   XtGetValues(button, args, 1);

   if (ltype != XwRECT && button != ColorInheritColorButton) return;

   XtSetArg(args[0], XtNrectColor, &color);
   XtSetArg(args[1], XtNrectStipple, &stippix);
   XtGetValues(button, args, 2);

   if (stippix == (Pixmap)NULL && button != FillBlackButton)
      pbutton = ColorsToolButton;
   else
      pbutton = FillsToolButton;

   if (button == ColorInheritColorButton) {
      XtSetArg(args[0], XtNlabelType, XwIMAGE);
      XtSetValues(pbutton, args, 1);
   }
   else if (button == FillBlackButton) {
      XtSetArg(args[0], XtNlabelType, XwRECT);
      XtSetArg(args[1], XtNrectColor, color);
      XtSetArg(args[2], XtNrectStipple, (Pixmap)NULL);
      XtSetValues(pbutton, args, 3);
   }
   else if (button != FillOpaqueButton) {
      XtSetArg(args[0], XtNlabelType, XwRECT);
      if (stippix == (Pixmap)NULL)
         XtSetArg(args[1], XtNrectColor, color);
      else
         XtSetArg(args[1], XtNrectStipple, stippix);

      XtSetValues(pbutton, args, 2);
   }
}
#else
#define overdrawpixmap(a)
#endif  /* TCL */
#else
#define overdrawpixmap(a)
#endif      /* XPM */

/*--------------------------------------------------------------*/
/* Generic routine for use by all other data handling routines    */
/*--------------------------------------------------------------*/

void getgeneric(buttonsave *saveptr, xcWidget button, void (*getfunction)(),
      void *dataptr)
{
   Arg  wargs[1];

   saveptr->button = button;
   saveptr->buttoncall = getfunction;
   saveptr->dataptr = dataptr;

#ifndef TCL_WRAPPER
   if (button != NULL) {
      XtSetArg(wargs[0], XtNforeground, &saveptr->foreground);
      XtGetValues(button, wargs, 1);
      XtSetArg(wargs[0], XtNforeground, OFFBUTTONCOLOR);
      XtSetValues(button, wargs, 1);
      XtRemoveAllCallbacks(button, XtNselect);
   }
#endif
}


/*----------------------------------------------------------------*/
/* 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[areastruct.page]->drawingscale.y /
        (float)xobjs.pagelist[areastruct.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[areastruct.page]->coordstyle) {
      case CM:
         oscale = xobjs.pagelist[areastruct.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[areastruct.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[areastruct.page]->drawingscale.y) /
        (float)(xobjs.pagelist[areastruct.page]->drawingscale.x);

   switch (xobjs.pagelist[areastruct.page]->coordstyle) {
      case CM:
         oscale = xobjs.pagelist[areastruct.page]->outscale * CMSCALE;
         sprintf(buffer, "%5.3f cm", value * iscale * oscale / IN_CM_CONVERT);
         break; 
      case DEC_INCH:
         oscale = xobjs.pagelist[areastruct.page]->outscale * INCHSCALE;
         sprintf(buffer, "%5.3f in", value * iscale * oscale / 72.0);
         break;
      case FRAC_INCH:
         oscale = xobjs.pagelist[areastruct.page]->outscale * INCHSCALE;
         fraccalc(((value * iscale * oscale) / 72.0), buffer);
         strcat(buffer, " in");
         break;
   }
}        

/*--------------------------------------------------------------*/
/* Generate popup dialog for snap space value input         */
/*--------------------------------------------------------------*/

void getsnapspace(xcWidget button, caddr_t clientdata, caddr_t calldata)
{
   char buffer[50];
   buttonsave *savebutton = (buttonsave *)malloc(sizeof(buttonsave));
   float *floatptr = &xobjs.pagelist[areastruct.page]->snapspace;

   getgeneric(savebutton, button, getsnapspace, (void *)floatptr);
   measurestr(*floatptr, buffer);
   popupprompt(button, "Enter value:", buffer, setgrid, savebutton, NULL);
}

/*--------------------------------------------------------------*/
/* Generate popup dialog for grid space value input         */
/*--------------------------------------------------------------*/

void getgridspace(xcWidget button, caddr_t clientdata, caddr_t calldata)
{
   char buffer[50];
   buttonsave *savebutton = (buttonsave *)malloc(sizeof(buttonsave));
   float *floatptr = &xobjs.pagelist[areastruct.page]->gridspace;

   getgeneric(savebutton, button, getgridspace, (void *)floatptr);
   measurestr(*floatptr, buffer);
   popupprompt(button, "Enter value:", buffer, setgrid, savebutton, NULL);
}

/*----------------------------------------------------------------*/
/* Generic routine for setting a floating-point value (through a  */
/* (float *) pointer passed as the second parameter)          */
/*----------------------------------------------------------------*/

void setfloat(xcWidget w, float *dataptr)
{
   float oldvalue = *dataptr;
   int res = sscanf(_STR2, "%f", dataptr);

   if (res == 0 || *dataptr <= 0) {
      *dataptr = oldvalue;
      Wprintf("Illegal value");
   }
   if (oldvalue != *dataptr) drawarea(NULL, NULL, NULL);
}

/*----------------------------------------------------------------*/
/* 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 settsize(xcWidget w, labelptr settext)
{
   float tmpres;
   short *osel;
   labelptr nstext;
   stringpart *strptr, *nextptr;
   int res = sscanf(_STR2, "%f", &tmpres);

   if (res == 0 || tmpres <= 0) {  /* can't interpret value or bad value */
      Wprintf("Illegal value");
      return;
   }

   /* In edit mode, add font scale change. */

   if (eventmode == TEXT2_MODE || eventmode == TEXT3_MODE) {
      if (textpos > 0 || textpos < stringlength(settext->string, True, areastruct.topinstance)) {
       undrawtext(settext);
       strptr = findstringpart(textpos - 1, NULL, settext->string, areastruct.topinstance);
       nextptr = findstringpart(textpos, NULL, settext->string, areastruct.topinstance);
       if (strptr->type == FONT_SCALE)
          strptr->data.scale = tmpres;
       else if (nextptr && nextptr->type == FONT_SCALE)
          nextptr->data.scale = tmpres;
       else
          labeltext(FONT_SCALE, (char *)&tmpres);
       redrawtext(settext);
      }
      else if (stringlength(settext->string, True, areastruct.topinstance) > 0)
       labeltext(FONT_SCALE, (char *)&tmpres);
      else (settext->scale = tmpres);
   }

   /* Change scale on all selected text objects */

   else if (areastruct.selects > 0) {
      for (osel = areastruct.selectlist; osel < areastruct.selectlist +
           areastruct.selects; osel++) {
       if (SELECTTYPE(osel) == LABEL) {
          nstext = SELTOLABEL(osel);
          undrawtext(nstext);
            nstext->scale = tmpres;
          redrawtext(nstext);
       }
      }
      objectdeselect();
   }
}

#ifndef TCL_WRAPPER
/*--------------------------------------------------------------*/
/* Auto-set:  Enable automatic scaling                      */
/*--------------------------------------------------------------*/

void autoset(xcWidget w, xcWidgetList entertext, caddr_t nulldata)
{
   xobjs.pagelist[areastruct.page]->pmode |= 2;
   updatetext(w, entertext, nulldata);
}

/*--------------------------------------------------------------*/

void autostop(xcWidget w, caddr_t clientdata, caddr_t nulldata)
{
   xobjs.pagelist[areastruct.page]->pmode &= 1;
}
#endif

/*--------------------------------------------------------------*/
/* Auto-scale                                         */
/* (for now, with fixed 1" margins)                   */
/*--------------------------------------------------------------*/

void autoscale(int page)
{
   float newxscale, newyscale;
   float scalefudge = (xobjs.pagelist[page]->coordstyle
      == CM) ? CMSCALE : INCHSCALE;
   float margin = 144.0;
   int width, height;

   if (!(xobjs.pagelist[page]->pmode & 2)) return;
   else if (topobject->bbox.width == 0 || topobject->bbox.height == 0) {
      Wprintf("Cannot auto-fit empty page");
      return;
   }

   newxscale = (xobjs.pagelist[page]->pagesize.x - margin)
      / scalefudge;
   newyscale = (xobjs.pagelist[page]->pagesize.y - margin)
      / scalefudge;

#ifdef SCHEMA
   width = toplevelwidth(areastruct.topinstance);
   height = toplevelheight(areastruct.topinstance);
#else
   width = topobject->bbox.width;
   height = topobject->bbox.height;
#endif

   if (xobjs.pagelist[page]->orient == 0) {     /* Portrait */
      newxscale /= width;
      newyscale /= height;
   }
   else {
      newxscale /= height;
      newyscale /= width;
   }

   xobjs.pagelist[page]->outscale = min(newxscale, newyscale);
}

/*--------------------------------------------------------------*/
/* Set the denomenator value of the drawing scale           */ 
/*--------------------------------------------------------------*/

void setscaley(xcWidget w, float *dataptr)
{
   float oldvalue = *dataptr;
   int res = sscanf(_STR2, "%f", dataptr);

   if (res == 0 || *dataptr <= 0 || topobject->bbox.height == 0) {
      *dataptr = oldvalue;
      Wprintf("Illegal value");
   }
   else {
      *dataptr = (*dataptr * 72) / topobject->bbox.height;
      *dataptr /= getpsscale(1.0, areastruct.page);
   }
}

/*----------------------------------------------------------------*/
/* Set the numerator value of the drawing scale               */
/*----------------------------------------------------------------*/

void setscalex(xcWidget w, float *dataptr)
{
   float oldvalue = *dataptr;
   int res = sscanf(_STR2, "%f", dataptr);

   if (res == 0 || *dataptr <= 0 || topobject->bbox.width == 0) {
      *dataptr = oldvalue;
      Wprintf("Illegal value");
   }
   else {
      *dataptr = (*dataptr * 72) / topobject->bbox.width;
      *dataptr /= getpsscale(1.0, areastruct.page);
   }
}

/*----------------------------------------------------------------*/
/* Set the page orientation (either Landscape or Portrait)    */
/*----------------------------------------------------------------*/

void setorient(xcWidget w, short *dataptr)
{
   Arg wargs[1];

#ifndef TCL_WRAPPER
   if (*dataptr == 0) {
      *dataptr = 90;
      XtSetArg(wargs[0], XtNlabel, "Landscape");
   }
   else {
      *dataptr = 0;
      XtSetArg(wargs[0], XtNlabel, "Portrait");
   }
   XtSetValues(w, wargs, 1);
#endif
}

/*----------------------------------------------------------------*/
/* Set the output mode to "Full Page" (unencapsulated PostScript) */
/* or "Embedded" (encapsulated PostScript)                    */
/*----------------------------------------------------------------*/

void setpmode(xcWidget w, short *dataptr)
{
   Arg wargs[1];
#ifndef TCL_WRAPPER
   xcWidget pwidg = XtParent(w);
   xcWidget autowidg = XtNameToWidget(pwidg, "Auto-fit");

   if (!(*dataptr & 1)) {
      *dataptr = 1;
      XtSetArg(wargs[0], XtNlabel, "Full Page");

      XtManageChild(XtNameToWidget(pwidg, "fpedit"));
      XtManageChild(XtNameToWidget(pwidg, "fpokay"));
      XtManageChild(autowidg);
   }
   else {
      *dataptr = 0;     /* This also turns off auto-fit */
      XtSetArg(wargs[0], XtNset, False);
      XtSetValues(autowidg, wargs, 1);
      XtSetArg(wargs[0], XtNlabel, "Embedded");

      XtUnmanageChild(XtNameToWidget(pwidg, "fpedit"));
      XtUnmanageChild(XtNameToWidget(pwidg, "fpokay"));
      XtUnmanageChild(autowidg);
   }
   XtSetValues(w, wargs, 1);
#endif
}

#ifdef TCL_WRAPPER

/*--------------------------------------------------------------*/
/* 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[areastruct.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));
      }
   }
}

#endif

/*--------------------------------------------------------------*/
/* Set the output page size, in the current unit of measure */
/*--------------------------------------------------------------*/

void setpagesize(xcWidget w, XPoint *dataptr)
{
   float px, py;
   char units[10], *expos, fpedit[75];
   Arg wargs[1];

   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;
       }
       else {
          *expos = '\0';
          if (sscanf(_STR2, "%f", &px) == 0 ||
              sscanf(expos + 1, "%f %9s", &py, units) == 0) {
               Wprintf("Illegal Form for page size.");
             return;
          }
       }
      }
   }

   /* 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;
   }

   dataptr->x = (short)(px * 72.0);
   dataptr->y = (short)(py * 72.0);

   if (!strcmp(units, "cm")) {
      sprintf(fpedit, "%3.2f x %3.2f cm",
        (float)xobjs.pagelist[areastruct.page]->pagesize.x
        / 72.0, (float)xobjs.pagelist[areastruct.page]->pagesize.y / 72.0);
      dataptr->x /= 2.54;
      dataptr->y /= 2.54;
   }
   else {
      sprintf(fpedit, "%3.2f x %3.2f in",
        (float)xobjs.pagelist[areastruct.page]->pagesize.x
        / 72.0, (float)xobjs.pagelist[areastruct.page]->pagesize.y / 72.0);
   }

#ifndef TCL_WRAPPER
   XtSetArg(wargs[0], XtNstring, fpedit);
   XtSetValues(XtNameToWidget(XtParent(w), "fpedit"), wargs, 1);
#endif
}

/*--------------------------------------------------------------*/
/* Generate popup dialog to get a character kern value, which     */
/* is two integer numbers in the range -128 to +127 (size char)   */
/*--------------------------------------------------------------*/

void getkern(xcWidget button, caddr_t nulldata, caddr_t calldata)
{
   char buffer[50];
   buttonsave *savebutton = (buttonsave *)malloc(sizeof(buttonsave));
   int kx, ky;
   stringpart *strptr, *nextptr;

   strcpy(buffer, "0,0");

   if (eventmode == TEXT2_MODE || eventmode == TEXT3_MODE) {
      labelptr curlabel = TOLABEL(EDITPART);
      strptr = findstringpart(textpos - 1, NULL, curlabel->string, areastruct.topinstance);
      nextptr = findstringpart(textpos, NULL, curlabel->string, areastruct.topinstance);
      if (strptr->type == KERN) {
       kx = strptr->data.kern[0];
       ky = strptr->data.kern[1];
         sprintf(buffer, "%d,%d", kx, ky);
      }
      else if (nextptr && nextptr->type == KERN) {
       strptr = nextptr;
       kx = strptr->data.kern[0];
       ky = strptr->data.kern[1];
         sprintf(buffer, "%d,%d", kx, ky);
      }
      else strptr = NULL;
   }

   getgeneric(savebutton, button, getkern, strptr);
   popupprompt(button, "Enter Kern X,Y:", buffer, setkern, savebutton, NULL);
}

/*--------------------------------------------------------------*/
/* 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);
      }
   }
}

/*----------------------------------------------------------------*/
/* Generate popup dialog to get the drawing scale, specified as a */
/* whole-number ratio X:Y                               */
/*----------------------------------------------------------------*/

void getdscale(xcWidget button, caddr_t nulldata, caddr_t calldata)
{
   char buffer[50];
   buttonsave *savebutton = (buttonsave *)malloc(sizeof(buttonsave));
   XPoint *ptptr = &(xobjs.pagelist[areastruct.page]->drawingscale);

   getgeneric(savebutton, button, getdscale, ptptr);
   sprintf(buffer, "%d:%d", ptptr->x, ptptr->y);
   popupprompt(button, "Enter Scale:", buffer, setdscale, savebutton, NULL);
}

/*----------------------------------------------------------------*/
/* 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));
      sprintf(_STR2, "New scale is %hd:%hd", dataptr->x, dataptr->y);
      Wprintf(_STR2);
      W1printf(" ");
   }
}

/*--------------------------------------------------------------*/
/* 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 = &areastruct.textscale;

   if (eventmode == TEXT2_MODE || eventmode == TEXT3_MODE) {
      if (textpos > 0 || textpos < stringlength(settext->string, True,
            areastruct.topinstance)) {
         settext = *((labelptr *)EDITPART);
       strptr = findstringpart(textpos - 1, NULL, settext->string,
                  areastruct.topinstance);
       nextptr = findstringpart(textpos, NULL, settext->string,
                  areastruct.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 (areastruct.selects > 0) {
      for (osel = areastruct.selectlist; osel < areastruct.selectlist +
            areastruct.selects; osel++) {
       if (SELECTTYPE(osel) == LABEL) {
            settext = SELTOLABEL(osel);
            if (floatptr) *floatptr = &(settext->scale);
          break;
       }
      }
   }
   return settext;
}

/*--------------------------------------------------------------*/
/* Generate the popup dialog for getting text scale.        */ 
/*--------------------------------------------------------------*/

void gettsize(xcWidget button, caddr_t nulldata, caddr_t calldata)
{
   char buffer[50];
   buttonsave *savebutton = (buttonsave *)malloc(sizeof(buttonsave));
   float *floatptr;
   Boolean local;
   labelptr settext;

   settext = gettextsize(&floatptr);
   sprintf(buffer, "%5.2f", *floatptr);

   if (settext) {
      getgeneric(savebutton, button, gettsize, settext);
      popupprompt(button, "Enter text scale:", buffer, settsize, savebutton, NULL);
   }
   else {
      getgeneric(savebutton, button, gettsize, floatptr);
      popupprompt(button,
          "Enter default text scale:", buffer, setfloat, savebutton, NULL);
   }
}

/*----------------------------------------------------------------*/
/* Set the scale of an object or group of selected objects    */
/*----------------------------------------------------------------*/

void setosize(xcWidget w, objinstptr dataptr)
{
   float tmpres;
   short *osel;
   objinstptr nsobj;
   int res = sscanf(_STR2, "%f", &tmpres);

   if (res == 0 || tmpres <= 0) {
      Wprintf("Illegal value");
      return;
   }
   for (osel = areastruct.selectlist; osel < areastruct.selectlist +
           areastruct.selects; osel++) {
      if (SELECTTYPE(osel) == OBJECT) {
       nsobj = SELTOOBJINST(osel);
         nsobj->scale = tmpres;
      }
   }
   objectdeselect();
   pwriteback(areastruct.topinstance);
   drawarea(NULL, NULL, NULL);
}

/*----------------------------------------------------------------*/
/* Generate popup dialog for getting object scale             */
/*----------------------------------------------------------------*/

void getosize(xcWidget button, caddr_t clientdata, caddr_t calldata)
{
   char buffer[50];
   float flval;
   buttonsave *savebutton = (buttonsave *)malloc(sizeof(buttonsave));
   short *osel = areastruct.selectlist;
   short selects = 0;
   objinstptr setobj = NULL;

   for (; osel < areastruct.selectlist + areastruct.selects; osel++)
      if (SELECTTYPE(osel) == OBJECT) {
       setobj = SELTOOBJINST(osel);
       selects++;
       break;
      }
   if (setobj == NULL) {
      Wprintf("No objects were selected for scaling.");
      return;
   }
   flval = setobj->scale;
   getgeneric(savebutton, button, getosize, setobj);
   sprintf(buffer, "%4.2f", flval);
   popupprompt(button, "Enter object scale:", buffer, setosize, savebutton, NULL);
}

/*----------------------------------------------------------------*/
/* Generate popup prompt for getting global linewidth         */
/*----------------------------------------------------------------*/

void getwirewidth(xcWidget button, caddr_t clientdata, caddr_t calldata)
{
   char buffer[50];
   buttonsave *savebutton = (buttonsave *)malloc(sizeof(buttonsave));
   float *widthptr;

   widthptr = &(xobjs.pagelist[areastruct.page]->wirewidth);
   getgeneric(savebutton, button, getwirewidth, widthptr);
   sprintf(buffer, "%4.2f", *widthptr / 2.0);
   popupprompt(button, "Enter new global linewidth:", buffer, setwidth,
      savebutton, NULL);
}

/*----------------------------------------------------------------*/
/* Set the linewidth of all selected arcs, polygons, splines, and */
/* paths.                                         */
/*----------------------------------------------------------------*/

void setwwidth(xcWidget w, void *dataptr)
{
   float     tmpres;
   short     *osel;
   arcptr    nsarc;
   polyptr   nspoly;
   splineptr nsspline;
   pathptr   nspath;

   if (sscanf(_STR2, "%f", &tmpres) == 0) {
      Wprintf("Illegal value");
      return;
   }
   else if (areastruct.selects == 0) {
      areastruct.linewidth = tmpres;
   }
   else {
      for (osel = areastruct.selectlist; osel < areastruct.selectlist +
           areastruct.selects; osel++) {
         if (SELECTTYPE(osel) == ARC) {
          nsarc = SELTOARC(osel);
            nsarc->width = tmpres;
         }
         else if (SELECTTYPE(osel) == POLYGON) {
          nspoly = SELTOPOLY(osel);
            nspoly->width = tmpres;
         }
         else if (SELECTTYPE(osel) == SPLINE) {
          nsspline = SELTOSPLINE(osel);
            nsspline->width = tmpres;
         }
         else if (SELECTTYPE(osel) == PATH) {
          nspath = SELTOPATH(osel);
            nspath->width = tmpres;
         }
      }
      objectdeselect();
      pwriteback(areastruct.topinstance);
      drawarea(NULL, NULL, NULL);
   }
}

/*----------------------------------------------------------------*/
/* Generate popup dialong for getting linewidths of elements        */ 
/*----------------------------------------------------------------*/

void getwwidth(xcWidget button, caddr_t clientdata, caddr_t calldata)
{
   char buffer[50];
   buttonsave *savebutton = (buttonsave *)malloc(sizeof(buttonsave));
   short *osel = areastruct.selectlist;
   genericptr setel;
   float flval;

   for (; osel < areastruct.selectlist + areastruct.selects; osel++) {
      setel = *(topobject->plist + (*osel));
      if (setel->type == ARC) {
       flval = ((arcptr)setel)->width;
       break;
      }
      else if (setel->type == POLYGON) {
       flval = ((polyptr)setel)->width;
       break;
      }
      else if (setel->type == SPLINE) {
       flval = ((splineptr)setel)->width;
       break;
      }
      else if (setel->type == PATH) {
       flval = ((pathptr)setel)->width;
       break;
      }
   }
   getgeneric(savebutton, button, getwwidth, setel);
   if (osel == areastruct.selectlist + areastruct.selects) {
      sprintf(buffer, "%4.2f", areastruct.linewidth);
      popupprompt(button, "Enter new default line width:", buffer, setwwidth,
            savebutton, NULL);
   }
   else {
      sprintf(buffer, "%4.2f", flval);
      popupprompt(button, "Enter new line width:", buffer, setwwidth,
            savebutton, NULL);
   }
}

/*----------------------------------------------------------------*/
/* Generic popup prompt for getting a floating-point value    */
/*----------------------------------------------------------------*/

void getfloat(xcWidget button, float *floatptr, caddr_t calldata)
{
   char buffer[50];
   buttonsave *savebutton = (buttonsave *)malloc(sizeof(buttonsave));

   getgeneric(savebutton, button, getfloat, floatptr);
   sprintf(buffer, "%4.2f", *floatptr);
   popupprompt(button, "Enter value:", buffer, setfloat, savebutton, NULL);
}

/*----------------------------------------------------------------*/
/* Set the filename for the current page                */
/*----------------------------------------------------------------*/

void setfilename(xcWidget w, char **dataptr)
{
   short cpage, depend = 0;
   objectptr checkpage;
   char *oldstr = xobjs.pagelist[areastruct.page]->filename;

   if (!strcmp(*dataptr, _STR2)) return;   /* no change in string */

   /* Make the change to the current page */
   xobjs.pagelist[areastruct.page]->filename = strdup(_STR2);

   /* All existing filenames which match the old string should also be changed */
   for (cpage = 0; cpage < xobjs.pages; cpage++) {
      if ((xobjs.pagelist[cpage]->pageinst != NULL) && (cpage != areastruct.page)) {
       if (!strcmp(xobjs.pagelist[cpage]->filename, oldstr)) {
          free(xobjs.pagelist[cpage]->filename);
          xobjs.pagelist[cpage]->filename = strdup(_STR2);
       }
      }
   }
   free(oldstr);
}

/*----------------------------------------------------------------*/
/* Set the page label for the current page                    */
/*----------------------------------------------------------------*/

void setpagelabel(xcWidget w, char *dataptr)
{
   short i;

   /* Whitespace and non-printing characters not allowed */

   for (i = 0; i < strlen(_STR2); i++) {
      if ((!isprint(_STR2[i])) || (isspace(_STR2[i]))) {
         _STR2[i] = '_';
         Wprintf("Replaced illegal whitespace in name with underscore");
      }
   }

   if (!strcmp(dataptr, _STR2)) return; /* no change in string */
   if (strlen(_STR2) == 0)
      sprintf(topobject->name, "Page %d", areastruct.page + 1);
   else
      sprintf(topobject->name, "%.79s", _STR2);

#ifdef SCHEMA
   /* For schematics, all pages with associations to symbols must have  */
   /* unique names.                                         */
   if (topobject->symschem != NULL) checkpagename(topobject);
#endif

   printname(topobject);
   renamepage(areastruct.page);
}

/*--------------------------------------------------------------*/
/* 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.     */
/*--------------------------------------------------------------*/

void makenewfontbutton()
{

#ifndef TCL_WRAPPER
   Arg      wargs[1];
   int  n = 0;
   xcWidget newbutton, cascade;

   if (fontcount == 0) return;

   cascade = XtParent(FontAddNewFontButton);
   XtnSetArg(XtNfont, appdata.xcfont);
   newbutton = XtCreateWidget(fonts[fontcount - 1].family, XwmenubuttonWidgetClass,
       cascade, wargs, n);

   XtAddCallback (newbutton, XtNselect, (XtCallbackProc)setfont,
            Number(fontcount - 1));
   XtManageChild(newbutton);
#endif

   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;
}

#ifndef TCL_WRAPPER

/*--------------------------------------------------------------*/
/* Make new encoding menu button                      */
/*--------------------------------------------------------------*/

void makenewencodingbutton(char *ename, char value)
{
   Arg      wargs[1];
   int  n = 0;
   xcWidget newbutton, cascade;

   cascade = XtParent(EncodingStandardButton);

   /* return if button has already been made */
   newbutton = XtNameToWidget(cascade, ename);
   if (newbutton != NULL) return;

   XtnSetArg(XtNfont, appdata.xcfont);
   newbutton = XtCreateWidget(ename, XwmenubuttonWidgetClass,
       cascade, wargs, n);

   XtAddCallback (newbutton, XtNselect, (XtCallbackProc)setfontencoding,
            Number(value));
   XtManageChild(newbutton);
}

#endif

/*--------------------------------------------------------------*/
/* Set the menu checkmarks on the font menu                 */
/*--------------------------------------------------------------*/

#ifdef TCL_WRAPPER

void togglefontmark(int fontval)
{
   Tcl_SetVar(xcinterp, "fontfamily", fonts[fontval].family, TCL_NAMESPACE_ONLY);
}

#else

void togglefontmark(int fontval)
{
   Arg args[1];
   xcWidget widget, cascade, sibling;
   short i;

   cascade = XtParent(FontAddNewFontButton);
   widget = XtNameToWidget(cascade, fonts[fontval].family);

   /* Remove checkmark from all widgets in the list */

   XtSetArg(args[0], XtNsetMark, False);
   for (i = 0; i < fontcount; i++) {
      if (i != fontval) {
         sibling = XtNameToWidget(cascade, fonts[i].family);
         XtSetValues(sibling, args, 1);
      }
   }

   /* Add checkmark to designated font */

   XtSetArg(args[0], XtNsetMark, True);
   XtSetValues(widget, args, 1);
}

#endif

#ifndef TCL_WRAPPER

/*--------------------------------------------------------------------*/
/* Toggle one of a set of menu items, only one of which can be active */
/*--------------------------------------------------------------------*/

void toggleexcl(xcWidget widget, menuptr menu, int menulength)
{
   Arg          args[1];
   xcWidget     parent = xcParent(widget);
   xcWidget     sibling;
   menuptr  mitem, mtest;
   short    i;

   /* find the menu item which corresponds to the widget which was pushed */

   for (mtest = menu; mtest < menu + menulength; mtest++) {
      sibling = XtNameToWidget(parent, mtest->name);
      if (sibling == widget) break;
   }

   /* remove checkmark from other widgets in the list */

   XtSetArg(args[0], XtNsetMark, False);
   if (menu == Fonts) {             /* special action for font list */
      for (i = 0; i < fontcount; i++) {
       sibling = XtNameToWidget(parent, fonts[i].family);
       if (sibling != widget)
          XtSetValues(sibling, args, 1);
      }
      mtest = &Fonts[3];   /* so that mtest->func has correct value below */
   }
   else if (mtest == menu + menulength) return;  /* something went wrong? */

   for (mitem = menu; mitem < menu + menulength; mitem++) {
      sibling = XtNameToWidget(parent, mitem->name);
      if (mitem->func == mtest->func)
         XtSetValues(sibling, args, 1);
   }

   /* Now set the currently pushed widget */

   XtSetArg(args[0], XtNsetMark, True);
   XtSetValues(widget, args, 1);
}

#endif

/*--------------------*/
/* Toggle a menu item */
/*--------------------*/

#ifdef TCL_WRAPPER

void toggle(xcWidget w, Boolean *boolvalue, caddr_t calldata)
{
}

#else

void toggle(xcWidget w, Boolean *boolvalue, caddr_t calldata)
{
   Arg      wargs[1];

   *boolvalue = !(*boolvalue);
   XtSetArg(wargs[0], XtNsetMark, *boolvalue);
   XtSetValues(w, wargs, 1);
   drawarea(w, NULL, NULL);
}

#endif

/*---------------------------------------------------------------*/
/* 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;
      BARCOLOR = appdata.barpix;
      OFFBUTTONCOLOR = appdata.buttonpix;
      SELECTCOLOR = appdata.selectpix;
      QUERYCOLOR = appdata.querypix;
      FILTERCOLOR = appdata.filterpix;
      GRIDCOLOR = appdata.gridpix;
      SNAPCOLOR = appdata.snappix;
      AXESCOLOR = appdata.axespix;
      BACKGROUND = appdata.bg;
      FOREGROUND = appdata.fg;
   }
   else {
      PARAMCOLOR = appdata.parampix2;
      AUXCOLOR = appdata.auxpix2;
      BARCOLOR = appdata.barpix2;
      OFFBUTTONCOLOR = appdata.buttonpix2;
      SELECTCOLOR = appdata.selectpix2;
      QUERYCOLOR = appdata.querypix2;
      FILTERCOLOR = appdata.filterpix2;
      GRIDCOLOR = appdata.gridpix2;
      SNAPCOLOR = appdata.snappix2;
      AXESCOLOR = appdata.axespix2;
      BACKGROUND = appdata.bg2;
      FOREGROUND = appdata.fg2;
   }

   makecursors();
}

/*----------------------------------------------------------------*/
/* Invert the color scheme used for the background/foreground       */
/*----------------------------------------------------------------*/

#ifndef TCL_WRAPPER

void inversecolor(xcWidget w, Boolean *boolvalue, caddr_t calldata)
{
   /* change color scheme */

   setcolorscheme(*boolvalue);

   /* toggle checkmark in menu on "Alt colors" */

   if (w == NULL) w = OptionsAltColorsButton;
   if (w != NULL) toggle(w, boolvalue, calldata);
   if (eventmode == NORMAL_MODE) XDefineCursor (dpy, areastruct.areawin, CROSS);
}

#endif

/*----------------------------------------------------------------*/
/* Change menu selection for reported measurement units             */
/*----------------------------------------------------------------*/

#ifdef TCL_WRAPPER

void togglegrid(u_short type)
{
   static char *stylenames[] = {
      "decimal inches",
      "fractional inches",
      "centimeters",
   };

   /* Note that Tcl_SetVar() doesn't require double-quotes around the   */
   /* string; doing so prevents the menu from recognizing the variable  */
   /* value.                                                */

   Tcl_SetVar(xcinterp, "gridstyle", stylenames[type], TCL_NAMESPACE_ONLY);
}

#else

void togglegrid(u_short type)
{
   xcWidget button, bparent = XtParent(GridtypedisplayDecimalInchesButton);

   if (type == CM) button = XtNameToWidget(bparent, "Centimeters");
   else if (type == FRAC_INCH) button = XtNameToWidget(bparent, "Fractional Inches");
   else if (type == DEC_INCH) button = XtNameToWidget(bparent, "Decimal Inches");
   else button = XtNameToWidget(bparent, "Coordinates");
   toggleexcl(button, GridStyles, XtNumber(GridStyles));
   W1printf(" ");
}

#endif

/*----------------------------------------------------------------*/
/* Set the default reported grid units to inches or centimeters   */
/*----------------------------------------------------------------*/

#ifdef TCL_WRAPPER

void setgridtype(char *string)
{
}

#else

void setgridtype(char *string)
{
   xcWidget button, bparent = XtParent(GridtypedisplayDecimalInchesButton);

   if (!strcmp(string, "inchscale")) {
      button = XtNameToWidget(bparent, "Fractional Inches");
      getgridtype(button, FRAC_INCH, NULL);
   }
   else if (!strcmp(string, "cmscale")) {
      button = XtNameToWidget(bparent, "Centimeters");
      getgridtype(button, CM, NULL);
   }
}

#endif

/*----------------------------------------------------------------*/
/* Called by setgridtype() to complete setting the reported         */
/* measurement units                                    */
/*----------------------------------------------------------------*/

void getgridtype(xcWidget button, pointertype value, caddr_t calldata)
{
   short oldtype = xobjs.pagelist[areastruct.page]->coordstyle;
   float scalefac = getpsscale(1.0, areastruct.page) / INCHSCALE;

#ifndef TCL_WRAPPER
   toggleexcl(button, GridStyles, XtNumber(GridStyles));
#endif
   xobjs.pagelist[areastruct.page]->coordstyle = (short)value;

   switch(value) {
      case FRAC_INCH: case DEC_INCH:
       if (oldtype == CM) {
            xobjs.pagelist[areastruct.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[areastruct.page]->pagesize.x = 612;
          xobjs.pagelist[areastruct.page]->pagesize.y = 792; /* letter */
#endif
       }
       break;
      case CM:
       if (oldtype != CM) {
            xobjs.pagelist[areastruct.page]->outscale *= scalefac;
#ifndef TCL_WRAPPER
          xobjs.pagelist[areastruct.page]->pagesize.x = 595;
          xobjs.pagelist[areastruct.page]->pagesize.y = 842; /* A4 */
#endif
       }
       break;
   }
   if (oldtype != xobjs.pagelist[areastruct.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();
   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 library and add a new button to the */
/* "Libraries" cascaded menu.             */
/*----------------------------------------------*/

int createlibrary()
{
   xcWidget libmenu, newbutton, oldbutton;
   Arg wargs[2];
   char libstring[20];
   int libnum;
   objectptr newlibobj;

   /* If there's an empty library, return its number */
   if ((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;

#ifdef TCL_WRAPPER

   sprintf(_STR2, "xcircuit::newlibrarybutton \"%s\"", newlibobj->name);
   Tcl_Eval(xcinterp, _STR2);

#else

   /* Previously last button becomes new library pointer */

   oldbutton = GotoLibraryLibrary2Button;
   XtRemoveAllCallbacks (oldbutton, XtNselect);
   XtAddCallback (oldbutton, XtNselect, (XtCallbackProc)startcatalog,
      Number(libnum));
   XtSetArg(wargs[0], XtNlabel, xobjs.libtop[libnum]->thisobject->name);
   XtSetValues(oldbutton, wargs, 1);

   /* Make new entry in the menu to replace the User Library button */
   /* xcWidget name is unique so button can be found later.  Label is */
   /* always set to "User Library"                        */

   sprintf(libstring, "Library %d", libnum - LIBRARY + 2);
   libmenu = XtParent(GotoLibraryAddNewLibraryButton);
   XtSetArg(wargs[0], XtNfont, appdata.xcfont);
   XtSetArg(wargs[1], XtNlabel, "User Library");
   newbutton = XtCreateWidget(libstring, XwmenubuttonWidgetClass,
         libmenu, wargs, 2);
   XtAddCallback (newbutton, XtNselect, (XtCallbackProc)startcatalog,
      Number(libnum + 1));
   XtManageChild(newbutton);
   GotoLibraryLibrary2Button = newbutton;
#endif

   /* Update the library directory to include the new page */

   composelib(LIBLIB);

   return libnum;
}

/*----------------------------------------------*/
/* Make new page; goto that page          */
/* (wrapper for routine events.c:newpage())     */
/*----------------------------------------------*/

void newpagemenu(xcWidget w, pointertype value, caddr_t nulldata)
{
   newpage((short)value);
}

/*--------------------------------------------------------------*/
/* Routine called by newpage() if new button needs to be made     */
/* to add to the "Pages" cascaded menu.                     */
/*--------------------------------------------------------------*/

void makepagebutton()
{
   xcWidget pagemenu, newbutton;
   Arg wargs[1];
   char pagestring[10];

   /* make new entry in the menu */

#ifdef TCL_WRAPPER
   sprintf(_STR2, "newpagebutton \"Page %d\"", xobjs.pages);
   Tcl_Eval(xcinterp, _STR2);
#else
   pagemenu = XtParent(GotoPageAddNewPageButton);
   XtSetArg(wargs[0], XtNfont, appdata.xcfont);
   sprintf(pagestring, "Page %d", xobjs.pages);
   newbutton = XtCreateWidget(pagestring, XwmenubuttonWidgetClass,
         pagemenu, wargs, 1);
   XtAddCallback (newbutton, XtNselect, (XtCallbackProc)newpagemenu,
      Number(xobjs.pages - 1));
   XtManageChild(newbutton);
#endif

   /* 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)
{
#ifdef TCL_WRAPPER
   char *pname, *plabel;

   if ((pagenumber >= 0) && (pagenumber < xobjs.pages - 1) &&
          (xobjs.pagelist[pagenumber]->pageinst != NULL)) {
      plabel = xobjs.pagelist[pagenumber]->pageinst->thisobject->name;
      pname = (char *)malloc(28 + strlen(plabel));
      sprintf(pname, "xcircuit::renamepage %d {%s}", pagenumber + 1, plabel);
      Tcl_Eval(xcinterp, pname);
      free(pname);
   }
#else
   Arg wargs[1];
   xcWidget parent = XtParent(GotoPageAddNewPageButton);
   xcWidget button;
   char bname[10];

   sprintf(bname, "Page %d", pagenumber + 1);
   button = XtNameToWidget(parent, bname);

   if ((button != NULL) && (xobjs.pagelist[pagenumber]->pageinst != NULL)) {
      if (xobjs.pagelist[pagenumber]->pageinst->thisobject->name != NULL)
         XtSetArg(wargs[0], XtNlabel,
            xobjs.pagelist[pagenumber]->pageinst->thisobject->name);
      else
         XtSetArg(wargs[0], XtNlabel, bname);
      XtSetValues(button, wargs, 1);
   }
   else if (button == NULL)
      Fprintf(stderr, "Error:  No Button Widget named \"%9s\"\n", bname);
#endif
}

/*--------------------------------------------------------------*/
/* Same routine as above, for Library page menu buttons           */
/*--------------------------------------------------------------*/

void renamelib(short libnumber)
{
#ifdef TCL_WRAPPER
   sprintf(_STR2, "xcircuit::renamelib %d \"%s\"", libnumber - LIBRARY + 1,
      xobjs.libtop[libnumber]->thisobject->name);
   Tcl_Eval(xcinterp, _STR2);
#else
   Arg wargs[1];
   xcWidget parent = XtParent(GotoLibraryAddNewLibraryButton);
   xcWidget button;
   char bname[13];

   sprintf(bname, "Library %d", libnumber - LIBRARY + 1);
   button = XtNameToWidget(parent, bname);

   if (button != NULL) {
      if (xobjs.libtop[libnumber]->thisobject->name != NULL)
         XtSetArg(wargs[0], XtNlabel, xobjs.libtop[libnumber]->thisobject->name);
      else
         XtSetArg(wargs[0], XtNlabel, bname);
      XtSetValues(button, wargs, 1);
   }
   else
      Fprintf(stderr, "Error:  No Button Widget named \"%12s\"\n", bname);
#endif
}

/*----------------------------------------------*/
/* Set Poly and Arc line styles and fill styles */
/*----------------------------------------------*/

#define BORDERS  (NOBORDER | DOTTED | DASHED)
#define ALLFILLS (FILLSOLID | FILLED)

/*--------------------------------------------------------------*/
/* Set the menu checkmarks on the color menu                */
/*--------------------------------------------------------------*/

void setcolormark(int colorval)
{
#ifndef TCL_WRAPPER
   Arg args[1];
   xcWidget w = NULL;
   short i;

   if (colorval == DEFAULTCOLOR)
      w = ColorInheritColorButton;
   else {
      for (i = 0; i < number_colors; i++)
         if (colorlist[i].color.pixel == colorval) {
            w = colorlist[i].cbutton;
          break;
         }
   }

   /* Remove mark from all menu items */

   XtSetArg(args[0], XtNsetMark, False);
   for (i = 0; i < number_colors; i++)
      XtSetValues(colorlist[i].cbutton, args, 1);
   XtSetValues(ColorInheritColorButton, args, 1);

   /* Add mark to the menu button for the chosen color */

   if (w != (xcWidget)NULL) {
      overdrawpixmap(w);
      XtSetArg(args[0], XtNsetMark, True);
      XtSetValues(w, args, 1);
   }
#else
   /* Set GUI variables and execute any command tags associated */
   /* with the "color" command */

   Tcl_Obj *objv[2];
   int i;

   objv[0] = Tcl_NewStringObj("color", 5);
   if (colorval == DEFAULTCOLOR)
      objv[1] = Tcl_NewStringObj("inherit", 7);
   else {
      for (i = 0; i < number_colors; i++)
         if (colorlist[i].color.pixel == colorval)
          break;
      objv[1] = Tcl_NewIntObj((int)i);
   }
   Tcl_SetVar2Ex(xcinterp, "colorval", NULL, objv[1], TCL_NAMESPACE_ONLY);

   XcTagCallback(xcinterp, 2, objv);
#endif
}

/*----------------------------------------------------------------*/
/* Set the checkmarks on the element styles menu              */
/*----------------------------------------------------------------*/

void setallstylemarks(u_short styleval)
{
#ifndef TCL_WRAPPER
   xcWidget w;
   Arg      wargs[1];

   XtSetArg(wargs[0], XtNsetMark, (styleval & UNCLOSED) ? 0 : 1);
   XtSetValues(BorderClosedButton, wargs, 1);

   XtSetArg(wargs[0], XtNsetMark, (styleval & BBOX) ? 1 : 0);
   XtSetValues(BorderBoundingBoxButton, wargs, 1);

   if (styleval & NOBORDER)
      w = BorderUnborderedButton;
   else if (styleval & DASHED)
      w = BorderDashedButton;
   else if (styleval & DOTTED)
      w = BorderDottedButton;
   else
      w = BorderSolidButton;
   toggleexcl(w, BorderStyles, XtNumber(BorderStyles));

   if (styleval & OPAQUE)
      w = FillOpaqueButton;
   else
      w = FillTransparentButton;
   toggleexcl(w, Stipples, XtNumber(Stipples));

   if (!(styleval & FILLED))
      w = FillWhiteButton;
   else {
      styleval &= FILLSOLID;
      styleval /= STIP0;
      switch(styleval) {
       case 0: w = FillGray87Button; break;
       case 1: w = FillGray75Button; break;
       case 2: w = FillGray62Button; break;
       case 3: w = FillGray50Button; break;
       case 4: w = FillGray37Button; break;
       case 5: w = FillGray25Button; break;
       case 6: w = FillGray12Button; break;
       case 7: w = FillBlackButton;  break;
      }
   }
   toggleexcl(w, Stipples, XtNumber(Stipples));
#else

   /* Set GUI variables and execute any command tags associated   */
   /* with the "fill" and "border" commands.                */

   Tcl_Obj *objv[2];
   int fillfactor;
   const char *bptr;

   const char *borders[] = {"solid", "unbordered", "dashed", "dotted"};
   enum BorderIdx { SolidIdx, UnborderedIdx, DashedIdx, DottedIdx };

   objv[0] = Tcl_NewStringObj("fill", 4);

   if (styleval & FILLED) {
      fillfactor = (int)(12.5 * (float)(1 + ((styleval & FILLSOLID) >> 5)));
      if (fillfactor == 100)
         objv[1] = Tcl_NewStringObj("solid", 5);
      else
         objv[1] = Tcl_NewIntObj(fillfactor);
   }
   else
      objv[1] = Tcl_NewStringObj("unfilled", 8);

   Tcl_SetVar2Ex(xcinterp, "fillamount", NULL, objv[1], TCL_NAMESPACE_ONLY);
   Tcl_SetVar(xcinterp, "opaque", (styleval & OPAQUE) ? "true" : "false",
            TCL_NAMESPACE_ONLY);
   Tcl_SetVar(xcinterp, "bboxtype", (styleval & BBOX) ? "true" : "false",
            TCL_NAMESPACE_ONLY);
   Tcl_SetVar(xcinterp, "polyclosed", (styleval & UNCLOSED) ? "false" : "true",
            TCL_NAMESPACE_ONLY);

   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;
   }
   Tcl_SetVar(xcinterp, "linestyle", (char *)bptr, TCL_NAMESPACE_ONLY);

   XcTagCallback(xcinterp, 2, objv);

#endif
}

/*--------------------------------------------------------------*/
/* 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 ((*cbbox)->type == POLYGON)
         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.                                               */
/*--------------------------------------------------------------*/

void setelementstyle(xcWidget w, u_short value, u_short mask)
{
   Boolean selected = False;
   short *sstyle;
   u_short newstyle;

   if (areastruct.selects > 0) {
      if (value & BBOX) {
       polyptr ckp;
       if (areastruct.selects != 1) {
          Wprintf("Choose only one polygon to be the bounding box");
          return;
       }
       else if (SELECTTYPE(areastruct.selectlist) != POLYGON) {
          Wprintf("Bounding box can only be a polygon");
          return;
       }
       else if (((ckp = checkforbbox(topobject)) != NULL) &&
            (ckp != SELTOPOLY(areastruct.selectlist))) {
          Wprintf("Only one bounding box allowed per page");
          return;
       }
      }

      for (sstyle = areastruct.selectlist; sstyle < areastruct.selectlist
         + areastruct.selects; sstyle++) {
       short stype = SELECTTYPE(sstyle);
       if (stype == ARC || stype == POLYGON || stype == SPLINE || stype == 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;
          }
          newstyle = *estyle;
          newstyle &= ~(mask);
          newstyle |= value;

          if ((newstyle & NOBORDER) && !(newstyle & FILLED)) {
             Wprintf("Must have either a border or filler");
             continue;
          }

          XSetFunction(dpy, areastruct.gc, GXcopy);
          XSetForeground(dpy, areastruct.gc, BACKGROUND);
          easydraw(*sstyle, DOFORALL);

          *estyle = newstyle;
          if (mask & BBOX)
             (SELTOPOLY(sstyle))->color = (value & BBOX) ? BBOXCOLOR : DEFAULTCOLOR;

          XSetFunction(dpy, areastruct.gc, GXxor);
          XSetForeground(dpy, areastruct.gc, SELECTCOLOR ^ BACKGROUND);
          easydraw(*sstyle, DOFORALL);
          selected = True;
       }
      }
   }
   if (selected)
      pwriteback(areastruct.topinstance);
   else {
      newstyle = areastruct.style;
      if (value & BBOX) {
       Wprintf("Cannot set default style to Bounding Box");
       newstyle &= ~(BBOX);
       return;
      }
      else {
       newstyle &= ~mask;
       newstyle |= value;
      }

      if ((newstyle & NOBORDER) && !(newstyle & FILLED)) {
       Wprintf("Must have either a border or filler");
       return;
      }
      areastruct.style = newstyle;
      overdrawpixmap(w);
   }
   setallstylemarks(newstyle);
   objectdeselect();
}

/*--------------------------------------------------------------*/
/* The following four routines are all wrappers for         */
/* setelementstyle(),                                 */
/* used in menudefs to differentiate between sections, each of  */
/* which has settings independent of the others.            */
/*--------------------------------------------------------------*/

void setfill(xcWidget w, pointertype value, caddr_t calldata)
{
   setelementstyle(w, (u_short)value, OPAQUE | FILLED | FILLSOLID);
}

/*--------------------------------------------------------------*/

void makebbox(xcWidget w, pointertype value, caddr_t calldata)
{
   setelementstyle(w, (u_short)value, BBOX);
}

/*--------------------------------------------------------------*/

void setclosure(xcWidget w, pointertype value, caddr_t calldata)
{
   setelementstyle(w, (u_short)value, UNCLOSED);
}

/*----------------------------------------------------------------*/

void setline(xcWidget w, pointertype value, caddr_t calldata)
{
   setelementstyle(w, (u_short)value, BORDERS);
}

/*----------------------------------------------------------------*/

void setopaque(xcWidget w, pointertype value, caddr_t calldata)
{
   setelementstyle(w, (u_short)value, OPAQUE);
}
   
/*-----------------------------------------------*/
/* Set the color value for all selected elements */
/*-----------------------------------------------*/

#ifdef TCL_WRAPPER
void setcolor(xcWidget w, int cindex)
{
   short *scolor;
   int *ecolor, cval;
   Boolean selected = False;
   stringpart *strptr, *nextptr;

   if (cindex == -1) cval = -1;
   else cval = colorlist[cindex].color.pixel;

#else

void setcolor(xcWidget w, pointertype value, caddr_t calldata)
{
   short *scolor;
   int *ecolor, cindex, cval;
   Arg wargs[1];
   Boolean selected = False;
   stringpart *strptr, *nextptr;

   /* Get the color index value from the menu button widget itself */

   if (value == 1)
      cindex = cval = -1;
   else {
      XtSetArg(wargs[0], XtNrectColor, &cval);
      XtGetValues(w, wargs, 1);

      for (cindex = 0; cindex < number_colors; cindex++)
         if (colorlist[cindex].color.pixel == cval)
          break;
      if (cindex >= number_colors) {
       Wprintf("Error: No such color!");
       return;
      }
   }

#endif
   
   if (eventmode == TEXT2_MODE || eventmode == TEXT3_MODE) {
      labelptr curlabel = TOLABEL(EDITPART);
      strptr = findstringpart(textpos - 1, NULL, curlabel->string, areastruct.topinstance);
      nextptr = findstringpart(textpos, NULL, curlabel->string, areastruct.topinstance);
      if (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 (areastruct.selects > 0) {
      for (scolor = areastruct.selectlist; scolor < areastruct.selectlist
         + areastruct.selects; scolor++) {
       ecolor = &(SELTOCOLOR(scolor));

       *ecolor = cval;
       selected = True;
      }
   }

   setcolormark(cval);
   if (!selected) {
      if (eventmode != TEXT2_MODE && eventmode != TEXT3_MODE)
         areastruct.color = cval;      
      overdrawpixmap(w);
   }

   objectdeselect();
}

/*----------------------------------------------------------------*/
/* Parse a new color entry and add it to the color list.      */
/*----------------------------------------------------------------*/

void setnewcolor(xcWidget w, caddr_t nullptr)
{
   int ccolor, red, green, blue;
   char *ppos, *cpos;

   ppos = strchr(_STR2, '#');
   cpos = strchr(_STR2, ',');

   if (cpos != NULL || ppos != NULL) {
      if (cpos != NULL || strlen(ppos + 1) == 6) {
       if (cpos != NULL)
            sscanf(_STR2, "%d, %d, %d", &red, &green, &blue);
       else
            sscanf(ppos + 1, "%2x%2x%2x", &red, &green, &blue);
       red *= 256;
       green *= 256;
       blue *= 256;
      }
      else if (sscanf(ppos + 1, "%4x%4x%4x", &red, &green, &blue) != 3) {
       Wprintf("Bad color entry.  Use #rrggbb");
       return;
      }
      ccolor = rgb_alloccolor(red, green, blue);
   }
   else
      ccolor = xc_alloccolor(_STR2);

   addnewcolorentry(ccolor);
}

/*----------------------------------------------------------------*/
/* Generate popup dialog for adding a new color name or RGB value */
/*----------------------------------------------------------------*/

void addnewcolor(xcWidget w, caddr_t clientdata, caddr_t calldata)
{
   buttonsave *savebutton = (buttonsave *)malloc(sizeof(buttonsave));

   getgeneric(savebutton, w, addnewcolor, NULL);
   popupprompt(w, "Enter color name or #rgb or r,g,b:", "\0", setnewcolor,
      savebutton, NULL);
}

/*------------------------------------------------------*/
/* Set checkmarks on label style menu                 */
/* fvalue is for font, jvalue is for justification    */
/*------------------------------------------------------*/

#ifdef TCL_WRAPPER

void togglestylemark(int styleval)
{
   switch(styleval) {
      case 0: Tcl_SetVar(xcinterp, "fontstyle", "normal", TCL_NAMESPACE_ONLY);
       break;
      case 1: Tcl_SetVar(xcinterp, "fontstyle", "bold", TCL_NAMESPACE_ONLY);
       break;
      case 2: Tcl_SetVar(xcinterp, "fontstyle", "italic", TCL_NAMESPACE_ONLY);
       break;
      case 3: Tcl_SetVar(xcinterp, "fontstyle", "bolditalic", TCL_NAMESPACE_ONLY);
       break;
   }
}

/*------------------------------------------------------*/

void toggleencodingmark(int encodingval)
{
   switch(encodingval) {
      case 0: Tcl_SetVar(xcinterp, "fontencoding", "Standard", TCL_NAMESPACE_ONLY);
       break;
      case 1: Tcl_SetVar(xcinterp, "fontencoding", "special", TCL_NAMESPACE_ONLY);
       break;
      case 2: Tcl_SetVar(xcinterp, "fontencoding", "ISOLatin1", TCL_NAMESPACE_ONLY);
       break;
      case 3: Tcl_SetVar(xcinterp, "fontencoding", "ISOLatin2", TCL_NAMESPACE_ONLY);
       break;
      case 4: Tcl_SetVar(xcinterp, "fontencoding", "ISOLatin3", TCL_NAMESPACE_ONLY);
       break;
      case 5: Tcl_SetVar(xcinterp, "fontencoding", "ISOLatin4", TCL_NAMESPACE_ONLY);
       break;
      case 6: Tcl_SetVar(xcinterp, "fontencoding", "ISOLatin5", TCL_NAMESPACE_ONLY);
       break;
      case 7: Tcl_SetVar(xcinterp, "fontencoding", "ISOLatin6", TCL_NAMESPACE_ONLY);
       break;
   }
}

/*------------------------------------------------------*/

void togglejustmarks(int justvalue)
{
   switch(justvalue & (NOTLEFT | RIGHT)) {
      case NORMAL: Tcl_SetVar(xcinterp, "jhoriz", "left", TCL_NAMESPACE_ONLY);
       break;
      case NOTLEFT: Tcl_SetVar(xcinterp, "jhoriz", "center", TCL_NAMESPACE_ONLY);
       break;
      case RIGHT|NOTLEFT: Tcl_SetVar(xcinterp, "jhoriz", "right", TCL_NAMESPACE_ONLY);
       break;
   }
   switch(justvalue & (NOTBOTTOM | TOP)) {
      case NORMAL: Tcl_SetVar(xcinterp, "jvert", "bottom", TCL_NAMESPACE_ONLY);
       break;
      case NOTBOTTOM: Tcl_SetVar(xcinterp, "jvert", "middle", TCL_NAMESPACE_ONLY);
       break;
      case TOP|NOTBOTTOM: Tcl_SetVar(xcinterp, "jvert", "top", TCL_NAMESPACE_ONLY);
       break;
   }

   /* Flip Invariance property */
   Tcl_SetVar(xcinterp, "flipinvariant", (justvalue & FLIPINV) ? "true" : "false",
      TCL_NAMESPACE_ONLY);
     
#ifdef SCHEMA
   /* Pin visibility property */
   Tcl_SetVar(xcinterp, "pinvisible", (justvalue & PINVISIBLE) ? "true" : "false",
      TCL_NAMESPACE_ONLY);
#endif
}

/*------------------------------------------------------*/

void setfontmarks(short fvalue, short jvalue)
{
   if ((fvalue >= 0) && (fontcount > 0)) {
      togglestylemark(fonts[fvalue].flags & 0x03);
      toggleencodingmark((fonts[fvalue].flags & 0xf80) >> 7);
      togglefontmark(fvalue);
   }
   if (jvalue >= 0) {
      togglejustmarks(jvalue);
   }
}

/*------------------------------------------------------*/

#else /* !TCL_WRAPPER */

void setfontmarks(short fvalue, short jvalue)
{
   xcWidget w;
   Arg wargs[1];

   if ((fvalue >= 0) && (fontcount > 0)) {
      switch(fonts[fvalue].flags & 0x03) {
         case 0: w = StyleNormalButton; break;
         case 1: w = StyleBoldButton; break;
         case 2: w = StyleItalicButton; break;
         case 3: w = StyleBoldItalicButton; break;
      }
      toggleexcl(w, FontStyles, XtNumber(FontStyles));

      switch((fonts[fvalue].flags & 0xf80) >> 7) {
         case 0: w = EncodingStandardButton; break;
         case 2: w = EncodingISOLatin1Button; break;
       default: w = NULL;
      }
      if (w != NULL) toggleexcl(w, FontEncodings, XtNumber(FontEncodings));

      togglefontmark(fvalue);
   }
   if (jvalue >= 0) {
      switch(jvalue & (NOTLEFT | RIGHT)) {
         case NORMAL: w = JustificationLeftJustifiedButton; break;
         case NOTLEFT: w = JustificationCenterJustifiedButton; break;
         case RIGHT|NOTLEFT: w = JustificationRightJustifiedButton; break;
      }
      toggleexcl(w, Justifs, XtNumber(Justifs));

      switch(jvalue & (NOTBOTTOM | TOP)) {
         case NORMAL: w = JustificationBottomJustifiedButton; break;
         case NOTBOTTOM: w = JustificationMiddleJustifiedButton; break;
         case TOP|NOTBOTTOM: w = JustificationTopJustifiedButton; break;
      }

      toggleexcl(w, Justifs, XtNumber(Justifs));

      /* Flip Invariance property */
      w = JustificationFlipInvariantButton;
      if (jvalue & FLIPINV)
         XtSetArg(wargs[0], XtNsetMark, True);
      else
         XtSetArg(wargs[0], XtNsetMark, False);
      XtSetValues(w, wargs, 1);

#ifdef SCHEMA
      /* Pin visibility property */
      w = NetlistPinVisibilityButton;
      if (jvalue & PINVISIBLE)
         XtSetArg(wargs[0], XtNsetMark, True);
      else
         XtSetArg(wargs[0], XtNsetMark, False);
      XtSetValues(w, wargs, 1);
#endif
   }
}

#endif /* !TCL_WRAPPER */

/*--------------------------------------------------------------*/
/* Parameterize a label string (wrapper for parameterize()).      */
/*--------------------------------------------------------------*/

void startparam(xcWidget w, pointertype value, caddr_t calldata)
{
   genericptr *settext;

   if (value == P_SUBSTRING) {
      if (eventmode == TEXT2_MODE || eventmode == TEXT3_MODE) {
         settext = (genericptr *)EDITPART;
         makeparam(TOLABEL(settext));
         objectdeselect();
       setparammarks(NULL);
      }
      else if (checkselect(LABEL)) parameterize((int)value);
      else
         eventmode = LPARAM_MODE;
   }
   else {
      if ((eventmode == NORMAL_MODE) && (areastruct.selects == 0)) { 
         eventmode = IPARAM_MODE;
         Wprintf("Click on object to parameterize.");
      }      
      else parameterize((int)value);
   }
}

/*--------------------------------------------------------------*/
/* Unparameterize a label string (wrapper for parameterize()).    */
/*--------------------------------------------------------------*/

void startunparam(xcWidget w, pointertype value, caddr_t calldata)
{
   if (areastruct.selects == 0) {
      if (value == LABEL)
         eventmode = ULPARAM_MODE;
      else
         eventmode = UIPARAM_MODE;
      Wprintf("Select element or substring to remove parameters.");
   }
   else
      unparameterize((int)value);
   objectdeselect();
   setparammarks(NULL);
}

/*----------------------------------------------------------------*/
/* Set checkmarks on font menu according to the global defaults     */
/*----------------------------------------------------------------*/

void setdefaultfontmarks()
{
   setfontmarks(areastruct.psfont, areastruct.justify);
}

/*----------------------------------------------------------------*/
/* Change flip invariance on the label passed as 2nd parameter      */
/*----------------------------------------------------------------*/

void doflipflip(xcWidget w, labelptr settext)
{
   short newjust;
   Boolean boolval;
   u_short value;

   if (settext != NULL) {
      boolval = (settext->justify & FLIPINV) ? True : False;
      value = boolval ? 0 : FLIPINV;
      newjust = (settext->justify & (~FLIPINV)) | value;

      undrawtext(settext);
      settext->justify = newjust;
      redrawtext(settext);
      pwriteback(areastruct.topinstance);
   }
   else {
      boolval = (areastruct.justify & FLIPINV) ? True : False;
      value = boolval ? 0 : FLIPINV;
      newjust = (areastruct.justify & (~FLIPINV)) | value;
      areastruct.justify = newjust;
   }
   if (w != NULL) toggle(w, &boolval, NULL);
}

/*----------------------------------------------------------------*/
/* Change pin visibility on the label passed as 2nd parameter       */
/*----------------------------------------------------------------*/

void dopinvisible(xcWidget w, labelptr settext)
{
   short newjust;
   Boolean boolval;
   u_short value;

   if (settext != NULL && settext->pin) {
      boolval = (settext->justify & PINVISIBLE) ? True : False;
      value = boolval ? 0 : PINVISIBLE;
      newjust = (settext->justify & (~PINVISIBLE)) | value;

      undrawtext(settext);
      settext->justify = newjust;
      redrawtext(settext);
      pwriteback(areastruct.topinstance);
      if (w != NULL) toggle(w, &boolval, NULL);
   }
}

/*----------------------------------------------------------------*/
/* Set the justification for the label passed as 3rd parameter      */
/*----------------------------------------------------------------*/

void setjust(xcWidget w, pointertype value, labelptr settext, short mode)
{
   short newjust;

   if (settext != NULL) {

      if (mode == 1)
         newjust = (settext->justify & (PINVISIBLE | FLIPINV | TOP | NOTBOTTOM))
                  | value;
      else
         newjust = (settext->justify & (PINVISIBLE | FLIPINV | RIGHT | NOTLEFT))
                  | value;

      undrawtext(settext);
      settext->justify = newjust;
      redrawtext(settext);
      pwriteback(areastruct.topinstance);
   }
   else {
      if (mode == 1)
         newjust = (areastruct.justify & (PINVISIBLE | FLIPINV | TOP | NOTBOTTOM))
                  | value;
      else
         newjust = (areastruct.justify & (PINVISIBLE | FLIPINV | RIGHT | NOTLEFT))
                  | value;
      areastruct.justify = newjust;
   }
#ifndef TCL_WRAPPER
   if (w != NULL) toggleexcl(w, Justifs, XtNumber(Justifs));
#endif
}

/*----------------------------------------------------------------*/
/* Set vertical justification (top, middle, bottom) on all    */
/* selected labels                                      */
/*----------------------------------------------------------------*/

void setvjust(xcWidget w, pointertype value, caddr_t nulldata)
{
   short *fselect;
   labelptr settext;
   short labelcount = 0;

   if (eventmode == TEXT2_MODE || eventmode == TEXT3_MODE) {
      settext = *((labelptr *)EDITPART);
      setjust(w, value, settext, 2);
   }
   else {
      for (fselect = areastruct.selectlist; fselect < areastruct.selectlist +
            areastruct.selects; fselect++) {
         if (SELECTTYPE(fselect) == LABEL) {
            labelcount++;
            settext = SELTOLABEL(fselect);
            setjust(NULL, value, settext, 2);
         }
      }
      if (labelcount == 0) setjust(w, value, NULL, 2);
      else objectdeselect();
   }
}

/*----------------------------------------------------------------*/
/* Set horizontal justification (left, center, right) on all        */
/* selected labels                                      */
/*----------------------------------------------------------------*/

void sethjust(xcWidget w, pointertype value, caddr_t nulldata)
{
   short *fselect;
   labelptr settext;
   short labelcount = 0;

   if (eventmode == TEXT2_MODE || eventmode == TEXT3_MODE) {
      settext = *((labelptr *)EDITPART);
      setjust(w, value, settext, 1);
   }
   else {
      for (fselect = areastruct.selectlist; fselect < areastruct.selectlist +
            areastruct.selects; fselect++) {
         if (SELECTTYPE(fselect) == LABEL) {
            labelcount++;
            settext = SELTOLABEL(fselect);
            setjust(NULL, value, settext, 1);
         }
      }
      if (labelcount == 0) setjust(w, value, NULL, 1);
      else objectdeselect();
   }
}

/*----------------------------------------------------------------*/
/* Set flip invariance on all selected labels                 */ 
/*----------------------------------------------------------------*/

void setflipinv(xcWidget w, pointertype value, caddr_t nulldata)
{
   short *fselect;
   labelptr settext;
   short labelcount = 0;

   if (eventmode == TEXT2_MODE || eventmode == TEXT3_MODE) {
      settext = *((labelptr *)EDITPART);
      doflipflip(w, settext);
   }
   else {
      for (fselect = areastruct.selectlist; fselect < areastruct.selectlist +
            areastruct.selects; fselect++) {
         if (SELECTTYPE(fselect) == LABEL) {
            labelcount++;
            settext = SELTOLABEL(fselect);
            doflipflip(NULL, settext);
         }
      }
      if (labelcount == 0) doflipflip(w, NULL);
      else objectdeselect();
   }
}

/*----------------------------------------------------------------*/
/* Set pin visibility on all selected pins                    */ 
/*----------------------------------------------------------------*/

void setpinvisible(xcWidget w, pointertype value, caddr_t nulldata)
{
   short *fselect;
   labelptr settext;
   short labelcount = 0;

   if (eventmode == TEXT2_MODE || eventmode == TEXT3_MODE) {
      settext = *((labelptr *)EDITPART);
      if (settext->pin)
       dopinvisible(w, settext);
   }
   else {
      for (fselect = areastruct.selectlist; fselect < areastruct.selectlist +
            areastruct.selects; fselect++) {
         if (SELECTTYPE(fselect) == LABEL) {
            labelcount++;
            settext = SELTOLABEL(fselect);
          if (settext->pin)
               dopinvisible(NULL, settext);
         }
      }
      objectdeselect();
   }
}

/*---------------------------*/
/* Set polygon editing style */
/*---------------------------*/

#ifdef TCL_WRAPPER

void boxedit(xcWidget w, pointertype value, caddr_t nulldata)
{
   switch (value) {
      case MANHATTAN:
       Tcl_SetVar(xcinterp, "polyedittype", "manhattan", TCL_NAMESPACE_ONLY);
       break;
      case RHOMBOIDX:
       Tcl_SetVar(xcinterp, "polyedittype", "rhomboidx", TCL_NAMESPACE_ONLY);
       break;
      case RHOMBOIDY:
       Tcl_SetVar(xcinterp, "polyedittype", "rhomboidy", TCL_NAMESPACE_ONLY);
       break;
      case RHOMBOIDA:
       Tcl_SetVar(xcinterp, "polyedittype", "rhomboida", TCL_NAMESPACE_ONLY);
       break;
      case NORMAL:
       Tcl_SetVar(xcinterp, "polyedittype", "normal", TCL_NAMESPACE_ONLY);
       break;
   }

   if (areastruct.boxedit == value) return;
   areastruct.boxedit = value;
}

#else

void boxedit(xcWidget w, pointertype value, caddr_t nulldata)
{
   if (w == NULL) {
      switch (value) {
         case MANHATTAN: w = PolygonEditManhattanBoxEditButton; break;
         case RHOMBOIDX: w = PolygonEditRhomboidXButton; break;
       case RHOMBOIDY: w = PolygonEditRhomboidYButton; break;
       case RHOMBOIDA: w = PolygonEditRhomboidAButton; break;
       case NORMAL: w = PolygonEditNormalButton; break;
      }
   }

   if (areastruct.boxedit == value) return;

   toggleexcl(w, BoxEditStyles, XtNumber(BoxEditStyles));
   areastruct.boxedit = value;
}

#endif

/*----------------------------------------------------------------*/
/* Pick up font name from _STR2 and pass it to loadfontfile()       */
/*----------------------------------------------------------------*/

void locloadfont(xcWidget w, char *value)
{
   loadfontfile(_STR2);
   free(value);
}

/*----------------------------------------------------*/
/* Generate popup dialog for entering a new font name */
/*----------------------------------------------------*/

void addnewfont(xcWidget w, caddr_t clientdata, caddr_t calldata)
{
   buttonsave *savebutton = (buttonsave *)malloc(sizeof(buttonsave));
   char *tempstr = malloc(2 * sizeof(char));
   tempstr[0] = '\0';
   getgeneric(savebutton, w, addnewfont, tempstr);
   popupprompt(w, "Enter font name:", tempstr, locloadfont, savebutton, NULL);
}

/*----------------------------------------------------------------*/
/* 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 (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) {
      sprintf(_STR, "Font %s not available in this style", newfamily);
   }
   else {
      sprintf(_STR, "Font %s not available in this encoding", newfamily);
   }
   Wprintf(_STR);
   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 (textpos > 0 || textpos < stringlength(settext->string, True, areastruct.topinstance)) {
       strptr = findstringpart(textpos - 1, NULL, settext->string, areastruct.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(textpos, settext->string, areastruct.topinstance);
   }
   else tc = areastruct.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 == TEXT2_MODE || eventmode == TEXT3_MODE) {
      sprintf(_STR, "Font is now %s", fonts[newfont].psname);
      sprintf(_STR2, "%d", newfont);
      labeltext(FONT_NAME, (char *)&newfont);
   }
   else {
      sprintf(_STR, "Default font is now %s", fonts[newfont].psname);
      areastruct.psfont = newfont;
   }
   Wprintf(_STR);

   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;

   if (eventmode == CATALOG_MODE || eventmode == FONTCAT_MODE ||
            eventmode == FONTCAT2_MODE) return;

   if (eventmode == TEXT2_MODE || eventmode == TEXT3_MODE) {
      settext = *((labelptr *)EDITPART);
      setfontval(w, value, settext);
      charreport(settext);
   }
   else {
      textpos = 1;
      for (fselect = areastruct.selectlist; fselect < areastruct.selectlist +
          areastruct.selects; fselect++) {
         if (SELECTTYPE(fselect) == LABEL) {
          labelcount++;
          settext = SELTOLABEL(fselect);
            setfontval(NULL, value, settext);
         }
      }
      if (labelcount == 0) setfontval(w, value, NULL);
      else objectdeselect();
   }
}

/*----------------------------------------------------------------*/
/* 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 (textpos > 0 || textpos < stringlength(settext->string, True, areastruct.topinstance)) {
       strptr = findstringpart(textpos - 1, NULL, settext->string, areastruct.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
                toggleexcl(w, FontStyles, XtNumber(FontStyles));
#endif
             }
          }
            return;
         }
      }

      /* otherwise, look for the last font used in the string */
      tc = findcurfont(textpos - 2, settext->string, areastruct.topinstance);
   }
   else tc = areastruct.psfont;

   if ((newfont = (int)findbestfont(tc, -1, (short)value, -1)) < 0) return;

   if (eventmode == TEXT2_MODE || eventmode == TEXT3_MODE) {
      sprintf(_STR, "Font is now %s", fonts[newfont].psname);
      sprintf(_STR2, "%d", newfont);
      labeltext(FONT_NAME, (char *)&newfont);
   }
   else {
      sprintf(_STR, "Default font is now %s", fonts[newfont].psname);
      areastruct.psfont = newfont;
   }
#ifdef TCL_WRAPPER
   toggleencodingmark(value);
#else
   if (w != NULL) toggleexcl(w, FontStyles, XtNumber(FontStyles));
#endif

   Wprintf(_STR);
}

/*----------------------------------------------------------------*/
/* Wrapper for routine setfontstyle()                         */
/*----------------------------------------------------------------*/

void fontstyle(xcWidget w, pointertype value, caddr_t nulldata)
{
   short *fselect;
   labelptr settext;
   short labelcount = 0;

   if (eventmode == CATALOG_MODE || eventmode == FONTCAT_MODE ||
            eventmode == FONTCAT2_MODE) return;

   if (eventmode == TEXT2_MODE || eventmode == TEXT3_MODE) {
      settext = *((labelptr *)EDITPART);
      setfontstyle(w, value, settext);
      charreport(settext);
   }
   else {
      textpos = 1;
      for (fselect = areastruct.selectlist; fselect < areastruct.selectlist +
          areastruct.selects; fselect++) {
         if (SELECTTYPE(fselect) == LABEL) {
          labelcount++;
          settext = SELTOLABEL(fselect);
            setfontstyle(NULL, value, settext);
         }
      }
      if (labelcount == 0) setfontstyle(w, value, NULL);
      else objectdeselect();
   }
}

/*----------------------------------------------------------------*/
/* 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 (textpos > 0 || textpos < stringlength(settext->string, True, areastruct.topinstance)) {
       strptr = findstringpart(textpos - 1, NULL, settext->string, areastruct.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
                toggleexcl(w, FontEncodings, XtNumber(FontEncodings));
#endif
             }
          }
          return;
       }
      }

      /* otherwise, look for the last style used in the string */
      tc = findcurfont(textpos - 2, settext->string, areastruct.topinstance);
   }
   else tc = areastruct.psfont;

   if ((newfont = (int)findbestfont(tc, -1, -1, (short)value)) < 0) return;

   if (eventmode == TEXT2_MODE || eventmode == TEXT3_MODE) {
      sprintf(_STR, "Font is now %s", fonts[newfont].psname);
      sprintf(_STR2, "%d", newfont);
      labeltext(FONT_NAME, (char *)&newfont);
   }
   else {
      sprintf(_STR, "Default font is now %s", fonts[newfont].psname);
      areastruct.psfont = newfont;
   }

#ifndef TCL_WRAPPER
   if (w != NULL) toggleexcl(w, FontEncodings, XtNumber(FontEncodings));
#endif

   Wprintf(_STR);
}

/*----------------------------------------------------------------*/
/* Wrapper for routine setfontencoding()                */
/*----------------------------------------------------------------*/

void fontencoding(xcWidget w, pointertype value, caddr_t nulldata)
{
   short *fselect;
   labelptr settext;
   short labelcount = 0;

   if (eventmode == CATALOG_MODE || eventmode == FONTCAT_MODE ||
            eventmode == FONTCAT2_MODE) return;

   if (eventmode == TEXT2_MODE || eventmode == TEXT3_MODE) {
      settext = *((labelptr *)EDITPART);
      setfontencoding(w, value, settext);
      charreport(settext);
   }
   else {
      textpos = 1;
      for (fselect = areastruct.selectlist; fselect < areastruct.selectlist +
          areastruct.selects; fselect++) {
         if (SELECTTYPE(fselect) == LABEL) {
          labelcount++;
          settext = SELTOLABEL(fselect);
            setfontencoding(NULL, value, settext);
         }
      }
      if (labelcount == 0) setfontencoding(w, value, NULL);
      else objectdeselect();
   }
}

/*----------------------------------------------*/
/* Generate the table of special characters     */
/*----------------------------------------------*/

void dospecial()
{
   labelptr curlabel;
   int cfont;

   curlabel = TOLABEL(EDITPART);
   cfont = findcurfont(textpos, curlabel->string, areastruct.topinstance);
   composefontlib(cfont);
   startcatalog(NULL, FONTLIB, NULL);
}

/*-------------------------------------------------*/
/* Wrapper for labeltext when called from the menu */
/*-------------------------------------------------*/

void addtotext(xcWidget w, pointertype value, caddr_t nulldata)
{
   if (eventmode != TEXT2_MODE && eventmode != TEXT3_MODE) return;
   if (value == (pointertype)SPECIAL)
      dospecial();
   else
      labeltext((int)value, (char *)1);
}

/*----------------------------------------------------------*/
/* Position a popup menu directly beside the toolbar button */
/*----------------------------------------------------------*/

void position_popup(xcWidget toolbutton, xcWidget menubutton)
{
   int n = 0;
   Arg wargs[2];
   Position pz, pw, ph;
   int dx, dy;

#ifndef TCL_WRAPPER
   xcWidget cascade = XtParent(menubutton);
   xcWidget pshell = XtParent(XtParent(cascade));

   XtnSetArg(XtNheight, &pz);
   XtGetValues(toolbutton, wargs, n); n = 0;

   XtnSetArg(XtNwidth, &pw);
   XtnSetArg(XtNheight, &ph);
   XtGetValues(cascade, wargs, n); n = 0;

   dx = -pw - 6;
   dy = (pz - ph) >> 1;

   XwPostPopup(pshell, cascade, toolbutton, dx, dy);
#endif
}

/*------------------------------------------------------*/
/* Functions which pop up a menu cascade in sticky mode */
/*------------------------------------------------------*/

void border_popup(xcWidget w, caddr_t clientdata, caddr_t calldata)
{ 
#ifndef TCL_WRAPPER
   position_popup(w, BorderLinewidthButton);
#endif
}

/*-------------------------------------------------------------------------*/

void color_popup(xcWidget w, caddr_t clientdata, caddr_t calldata)
{ 
#ifndef TCL_WRAPPER
   position_popup(w, ColorAddNewColorButton);
#endif
}

/*-------------------------------------------------------------------------*/

void fill_popup(xcWidget w, caddr_t clientdata, caddr_t calldata)
{ 
#ifndef TCL_WRAPPER
   position_popup(w, FillOpaqueButton);
#endif
}

/*-------------------------------------------------------------------------*/

void param_popup(xcWidget w, caddr_t clientdata, caddr_t calldata)
{ 
#ifndef TCL_WRAPPER
   position_popup(w, ParametersSubstringButton);
#endif
}

/*-------------------------------------------------------------------------*/

Generated by  Doxygen 1.6.0   Back to index