date and time created 83/04/18 13:45:59 by slatteng
authorDave Slattengren <slatteng@ucbvax.Berkeley.EDU>
Tue, 19 Apr 1983 04:45:59 +0000 (20:45 -0800)
committerDave Slattengren <slatteng@ucbvax.Berkeley.EDU>
Tue, 19 Apr 1983 04:45:59 +0000 (20:45 -0800)
SCCS-vsn: local/ditroff/ditroff.old.okeeffe/gremlin.aed/gremlin/short.c 1.1

usr/src/local/ditroff/ditroff.old.okeeffe/gremlin.aed/gremlin/short.c [new file with mode: 0644]

diff --git a/usr/src/local/ditroff/ditroff.old.okeeffe/gremlin.aed/gremlin/short.c b/usr/src/local/ditroff/ditroff.old.okeeffe/gremlin.aed/gremlin/short.c
new file mode 100644 (file)
index 0000000..a08e4fa
--- /dev/null
@@ -0,0 +1,976 @@
+\f
+/* short.c -
+ *
+ * Copyright -C- 1982 Barry S. Roitblat
+ *
+ *
+ *      This file contains routines to implement the short commands
+ * of the gremlin picture editor.
+ *
+ */
+
+#include "gremlin.h"
+#include "grem2.h"
+#include <signal.h>
+#include <sgtty.h>
+
+/* imports from graphics files */
+
+extern GRVector(), GRPutText();
+extern GRCurve();
+extern GRClear();
+extern int GRArc(); 
+extern charxsize, charysize;
+
+/* imports from display.c */
+
+extern DISScreenAdd(), DISScreenErase();
+extern DISDisplaySet(), DISEraseSet(), DISClearSetDisplay();
+
+/* imports from database files */
+
+extern ELT *DBInit(), *DBCreateElt(); 
+extern DBDelete(), DBGravitate(), DBClearElt();
+extern ELT *DBCopy();
+extern DBXform(), DBBounded();
+extern DBAddSet(), DBClearSet();
+extern POINT *PTInit(), *PTMakePoint();
+extern PTDeletePoint();
+
+/* imports from long.c */
+
+extern LGIncludeSet();
+
+/* imports from menu.c  */
+
+extern MNHighLt(), MNUnHighLt();
+extern HiMen[], HiFont[], HiBrush[], HiMode[];
+
+int adj[4] = { 0, 0, 1, 2 };
+
+/* imports from textio.c */
+
+extern TxMsgOK(), TxPutString(), TxGetLine(), TxRedisplay(), TxPutMsg();
+extern char TxGetChar();
+extern TXFIELD TAlign, TAdjust, TBrush, TFont, TGravity, TCSize;
+extern TXFIELD TEdit, TJustmode;
+
+/* imports from c */
+
+extern char *malloc();
+extern char *sprintf();
+
+/* imports from main.c */
+
+extern globinit();                  /* global initialization routine */
+extern ELT *PICTURE;                /* current PICTURE database      */
+extern ELT *cset;                   /* current set database          */
+extern CBRUSH, CSIZE, CFONT;        /* current brush, size, font     */
+extern CJUST;                       /* text justification mode       */
+extern Gridon;                      /* grid mode flag                */
+extern Orientation;                 /* orientation of workspace      */
+extern Alignment;                   /* point alignment indicator     */
+extern float PX, PY;                /* cursor coordinates            */
+extern float Lastx, Lasty;          /* previous cursor coordinates   */
+extern SEQ;                         /* point sequence number         */
+extern char *Editfile;              /* current edit file             */
+extern POINT *POINTLIST;            /* accumulated point list        */
+extern Adjustment;                  /* point adjustment mode         */
+extern GravityOn;                   /* gravity mode flag             */
+extern Consume;                     /* point clear flag              */
+extern CHANGED;                     /* PICTURE changed flag          */
+extern ELT *MEN[];                  /* pointers for user symbols     */
+extern POINT MENPOINT[];            /* pointers used fo user symbols */
+extern cmdbuf[];                    /* line buffer for commands      */
+extern ELT arhead;                  /* arrow head template           */
+extern char *textpos[], *dispmode[];/* text positioning modes        */
+extern int textmode[];              /* text positioning              */
+
+\f
+extern SHUpdate(), SHDrawArc(), SHDrawCurve(), SHCopy(), SHRedis(),
+       SHDefineSet(), SHErase(), SHSetArea(), SHGravity(),
+       SHGrid(), SHRotate(), SHScale(), SHTranslate(), SHShellEsc(),
+       SHDrawVector(), SHMAdjust(), SHBox(), SHArrow(),
+       SHSave1(), SHSave2(), SHSave3(), SHSave4();
+
+/* The following two arrays define the short commands and the routines
+ * that process them.
+ */
+static char shcmds[] = { '\14', '!', '1', '2', '3', '4', 'a', 'b',
+                          'c', 'd', 'e', 'f', 'g', 'l', 'q', 'r',
+                          's', 't', 'v', 'w', 'x', 'z', '\0'};
+static (*(shrtns[]))() = {
+    SHUpdate,                  /* redraw screen */
+    SHShellEsc,                 /* shell escape */
+    SHSave1,                    /* save user symbol */
+    SHSave2,                    /* save user symbol */
+    SHSave3,                    /* save user symbol */
+    SHSave4,                    /* save user symbol */
+    SHDrawArc,                 /* draw arc */
+    SHDrawCurve,               /* draw curve */
+    SHCopy,                    /* copy current set */
+    SHDefineSet,               /* define current set */
+    SHErase,                   /* erase elements */
+    SHSetArea,                 /* select area for current set */
+    SHGravity,                 /* gravity */
+    SHRedis,                    /* text screen redisplay */
+    SHGrid,                    /* toggle grid display */
+    SHRotate,                  /* rotate current set */
+    SHScale,                   /* scale current set */
+    SHTranslate,               /* translate current set */
+    SHDrawVector,              /* draw vectors */
+    SHArrow,                    /* arrowhead */
+    SHBox,                      /* rectangle from two points */
+    SHMAdjust};                        /* manhattan adjust */
+  
+\f
+int
+SHLookup(c, table)
+char c;                                /* Pointer to a char to be looked up */
+char table[];                  /* Pointer to an array of characters
+                                * which are the valid commands.  The array
+                                * must be sorted by ascii value.
+                                */
+
+/*---------------------------------------------------------
+ *     SHLookup searches a table of characters to find one that matches a
+ *     the given character.
+ *
+ *      Results: If c is a valid command character, its index is 
+ * returned, otherwise, if c is the null command, -2 is returned
+ * else -1 is returned.
+ *
+ *     Side Effects:   None.
+ *
+ * (Modified from software written by John Ousterhout for the caesar
+ *  program)
+ *---------------------------------------------------------
+ */
+
+{
+    int index;
+
+    if ((c == ' ') || (c == '\0')) return(-2);
+    for (index=0; table[index] != '\0'; index++)
+    {
+        if (table[index] == c) return(index);
+        if (table[index] > c) return(-1);
+    }
+    return(-1);
+}  /* end SHLookup */
+
+\f
+SHCommand(command)
+char *command;
+
+/*---------------------------------------------------------
+ *     This routine reads in, looks up, and executes a long command.
+ *
+ *     Results:        None.
+ *
+ *     Side Effects:
+ *     Depends on the command that is invoked.
+ *---------------------------------------------------------
+ */
+
+{
+    int index;
+    index = SHLookup(*command, shcmds);
+    if (index == -2) return;
+    if (index >= 0)
+    {
+
+       (*(shrtns[index]))();
+    }
+    else
+    {
+       error("no such command");
+    }
+}  /* end SHCommand */
+\f
+static char nopnt[18] = "not enough points";
+static char noset[15] = "no current set";
+
+SHDrawVector()
+/*
+ *      This routine creates and displays a VECTOR element from the
+ * points previously specified.
+ */
+
+{
+       ELT *e1;
+       POINT *plist, *p1, *p2;
+       char *txt;
+
+       if (SEQ < 2)        /* not enough points */
+       {
+               error(nopnt);
+               return;
+       }
+       DBClearSet();         /* Clear current set in preparation */
+       DISClearSetDisplay(); /* for making this the new one */
+       GRsetwmask(linemask | setmask);
+       plist = PTInit();
+       p1 = POINTLIST;
+       (void) PTMakePoint(p1->x, p1->y, &plist);
+       p2 = PTNextPoint(p1);
+       while ( !Nullpoint(p2) )
+       {
+               (void) PTMakePoint(p2->x, p2->y, &plist);
+               GRVector(p1, p2, CBRUSH);
+               p1 = p2;
+               p2 = PTNextPoint(p1);
+       }  /* end while */;
+       txt = malloc(1);
+       *txt = '\0';
+       e1 = DBCreateElt(VECTOR, plist, CBRUSH, 0, txt, &PICTURE);
+       DBAddSet(e1);
+       CHANGED = TRUE;
+}  /* end SHDrawVector */
+
+#define twoPi 6.2832
+
+SHDrawArc()
+/*
+ *      This routine creates and displays an ARC element based on the 
+ * points previously defined.  If 3 or more points are defined, the
+ * extent of the arc is calculated as the angle formed by the 
+ * respective lines through the second and third points and the first
+ * point.  If only 2 points are specified, a full circle is drawn.
+ */
+
+{
+       ELT *e1;
+       POINT *plist, *p1, *p2;
+       char *txt;
+       double a1, a2, angle, radius;
+       int stat;
+
+       if (SEQ < 2)         /* not enough points */
+       {
+               error(nopnt);
+               return;
+       }
+       plist = PTInit();
+       p1 = POINTLIST;
+       p2 = PTNextPoint(p1);
+       radius = sqrt( pow((p2->x - p1->x), 2.0)
+                    + pow((p2->y - p1->y), 2.0));
+       if (SEQ == 2)         /* draw full circle */
+       {
+               angle = 0;
+         /* Add extra positioning points  */
+               (void) PTMakePoint(p1->x, p1->y, &plist);
+               (void) PTMakePoint(p2->x, p2->y, &plist);
+               (void) PTMakePoint(p1->x, p1->y + radius, &plist);
+               (void) PTMakePoint(p1->x, p1->y - radius, &plist);
+               (void) PTMakePoint(p1->x + radius, p1->y, &plist);
+               (void) PTMakePoint(p1->x - radius, p1->y, &plist);
+       }  /* end if */
+       else
+       {
+               (void) PTMakePoint(POINTLIST->x, POINTLIST->y, &plist);
+               p1 = PTNextPoint(POINTLIST);
+               (void) PTMakePoint(p1->x, p1->y, &plist);
+               p2 = PTNextPoint(p1);
+               a1 =  atan2((p1->x - POINTLIST->x), (p1->y - POINTLIST->y));
+               a2 =  atan2((p2->x - POINTLIST->x), (p2->y - POINTLIST->y));
+               angle = a1 - a2;
+               if (angle < 0.0) angle += twoPi;
+
+                      /* Set second point to lie on arc */
+               (void) PTMakePoint((radius * sin(a2) + POINTLIST->x),
+                                   (radius * cos(a2) + POINTLIST->y),
+                                    &plist);
+
+               angle *= 360.0/twoPi;      /* convert to degrees */
+       };
+       p1 = PTNextPoint(POINTLIST);
+       DBClearSet();         /* Clear current set, this element becomes */
+       DISClearSetDisplay(); /* the new current set                     */
+       GRsetwmask(linemask | setmask);
+       stat = GRArc(POINTLIST, p1, angle, CBRUSH);
+       if (stat > -1)
+       {
+               txt = malloc(1);
+               *txt = '\0';
+               e1 = DBCreateElt(ARC, plist, CBRUSH, (int) (angle + 0.5),
+                               txt, &PICTURE);
+               DBAddSet(e1);
+               CHANGED = TRUE;
+       }
+}  /* end SHDrawARc */
+
+\f
+SHDrawCurve()
+/*
+ *      This routine creates and displays a curve using points previously
+ * defined.  This is dependent on DISCurve which is not yet implemented.
+ */
+
+{
+       ELT *e1;
+       char *txt;
+       POINT *p1, *p2, *plist;
+       int stat;
+
+       stat = 0;
+       if (SEQ < 2)       /* not enough points */
+       {
+               error("need at least 2 points");
+               return;
+       }
+       plist = PTInit();
+       p1 = POINTLIST;
+       (void) PTMakePoint(p1->x, p1->y, &plist);
+       p2 = PTNextPoint(p1);
+       while ( !Nullpoint(p2) )
+       {
+               (void) PTMakePoint(p2->x, p2->y, &plist);
+               p1 = p2;
+               p2 = PTNextPoint(p1);
+       }  /* end while */;
+       DBClearSet();         /* Clear current set, this element */
+       DISClearSetDisplay(); /* the new current set             */
+       GRsetwmask(linemask | setmask);
+       stat = GRCurve(plist, CBRUSH);
+       if (stat != 0)   /* bad knots */
+       {
+               error("too many consecutive knots at same place");
+               return;
+       }
+       txt = malloc(1);
+       *txt = '\0';
+       e1 = DBCreateElt(CURVE, plist, CBRUSH, 0, txt, &PICTURE);
+       DBAddSet(e1);
+       CHANGED = TRUE;
+}  /* end SHDrawCurve */
+
+SHErase()
+/*
+ *     This routine erases selected elements from the screen and deletes
+ * them from the picture database.  
+ */
+
+{
+       ELT *e1;
+
+       while ( !DBNullelt(cset) )     /* delete elements in current set */
+       {
+               DISScreenErase(cset, (linemask | setmask));
+               e1 = DBNextofSet(cset);
+               DBDelete(cset, &PICTURE);
+               cset = e1;
+       };
+       CHANGED = TRUE;
+}  /* end SHErase */
+
+\f
+SHGravity()
+/*
+ *      This routine toggles the gravity mode.
+ */
+
+{
+       if (GravityOn) 
+       {
+               MNUnHighLt(HiMode[3]);
+               GravityOn = FALSE;
+               TxPutString(&TGravity, "OFF");
+       }
+       else    
+       {
+               MNHighLt(HiMode[3], hicolor);
+               GravityOn = TRUE;
+               TxPutString(&TGravity, " ON");
+       }
+       Consume = FALSE;
+}  /* End GravityOn */
+
+SHGrid()
+/*
+ *      This routine toggles the display of the grid 
+ */
+
+{
+       if (Gridon)
+       {
+               Gridon = FALSE;
+               GRBlankGrid();
+       }
+       else
+       {
+               Gridon = TRUE;
+               GRDisplayGrid();
+       }
+       Consume = FALSE;
+}  /* end SHGrid */
+
+\f
+SHMAdjust()
+/*
+ * Manhattan Adjust -
+ *      This routine toggles the adjustment mode.
+ */
+
+{
+       if (Adjustment == MAN)
+       {
+               MNUnHighLt(HiMode[adj[MAN]]);
+               Adjustment = NOADJ;
+               TxPutString(&TAdjust, "NO ADJUSTMENT");
+       }
+       else    
+       {
+               MNUnHighLt(HiMode[adj[Adjustment]]);
+               MNHighLt(HiMode[adj[MAN]], hicolor);
+               Adjustment = MAN;
+               TxPutString(&TAdjust, "  MANHATTAN  ");
+       }
+       Consume = FALSE;
+}
+
+\f
+SHDefineSet()
+/*
+ *      This routine defines the current set based upon previously
+ * defined points to select elements.  The action is performed by
+ * clearing the current set and calling LGIncludeSet.
+ */
+
+{
+       DBClearSet();
+       DISClearSetDisplay();
+       LGIncludeSet("");
+}  /* end SHDefineSet */
+
+SHSetArea()
+/*
+ *      This routine defines the current set by selecting all elements
+ * bounded by a rectangle whose diagonal is defined by specifed points.
+ */
+
+{
+       ELT *e1;
+       POINT *p1;
+       float x1, y1, x2, y2;
+
+       if (SEQ < 2)
+       {
+               error(nopnt);
+               return;
+       }
+       DBClearSet();
+       DISClearSetDisplay();
+       x1 = POINTLIST->x;
+       y1 = POINTLIST->y;
+       p1 = PTNextPoint(POINTLIST);
+       x2 = p1->x;
+       y2 = p1->y;
+       e1 = PICTURE;
+       while ( !DBNullelt(e1) )
+       {
+               if ( DBBounded(e1, x1, y1, x2, y2) )
+               {
+                       DBAddSet(e1);
+                       DISDisplaySet(e1);
+               }  /* end if */
+               e1 = DBNextElt(e1);
+       }  /* end while */
+}  /* end SHSetArea */
+
+\f
+SHTranslate()
+/*
+ *      This routine translates the elements in the current set as defined
+ * by points.  The translation is accomplished by defining a transformation
+ * matrix and calling DBXform.
+ */
+
+{
+       ELT *e1;
+       POINT *p1;
+       float xmat[3][2];
+
+       if (SEQ < 2)        /* not enough points */
+       {
+               error(nopnt);
+               return;
+       }
+       if (DBNullelt(cset))
+       {
+               error(noset);
+               return;
+       }
+       p1 = PTNextPoint(POINTLIST);
+       xmat[0][0] = xmat[1][1] = 1;    /* set up translation matrix */
+       xmat[1][0] = xmat[0][1] = 0;
+       xmat[2][0] = p1->x - POINTLIST->x;
+       xmat[2][1] = p1->y - POINTLIST->y;
+       e1 = cset;
+       while ( !DBNullelt(e1) )
+       {
+               DISScreenErase(e1, (linemask | setmask));
+               TxMsgOK();
+               DBXform(e1, xmat, &PICTURE);
+               DISScreenAdd(e1, (linemask | setmask));
+               e1 = DBNextofSet(e1);
+       }  /* end while */
+       CHANGED = TRUE;
+}  /* end SHTranslate */
+
+\f
+SHCopy()
+/*
+ *      This routine copies the elements in the current set as defined
+ * by points.  To copy, the current set pointer is cleared so that new
+ * elements as added by DBCopy can be used to comprise the new current
+ * set.  A pointer is maintained to the old current set which is traversed
+ * to determine the elements to be copied.  This process continues for all
+ * points specified.
+ *
+ * NOTE:  This assumes that the DBClearSet routine does not alter the
+ *        pointers between elements in the set (which is currently true),
+ *        and must be changed it this does not hold.
+ */
+
+{
+       ELT *e1, *e2;
+       POINT *p1, *p2;
+       float xmat[3][2];
+
+       if (SEQ < 2)        /* not enough points */
+       {
+               error(nopnt);
+               return;
+       }
+       if (DBNullelt(cset))
+       {
+               error(noset);
+               return;
+       }
+       p1 = POINTLIST;
+       p2 = PTNextPoint(POINTLIST);
+       while ( !Nullpoint(p2) )
+       {
+               xmat[0][0] = xmat[1][1] = 1;    /* set up translation matrix */
+               xmat[1][0] = xmat[0][1] = 0;
+               xmat[2][0] = p2->x - p1->x;
+               xmat[2][1] = p2->y - p1->y;
+               DISClearSetDisplay();
+               e1 = cset;
+               DBClearSet();    /* Dependent on Clearset preserving pointers */
+               while ( !DBNullelt(e1) )
+               {
+                       e2 = DBCopy(e1, xmat, &PICTURE);
+                       DBAddSet(e2);
+                       DISScreenAdd(e2, (linemask | setmask));
+                       e1 = DBNextofSet(e1);
+               }  /* end while ! null elt */
+               p1 = p2;
+               p2 = PTNextPoint(p2);
+       }  /* end while ! null point */
+       CHANGED = TRUE;
+}  /* end SHCopy */
+
+\f
+SHRotate()
+/*
+ *      This routine rotates the elements in the current set as defined
+ * by points.  The rotation is accomplished by defining a transformation
+ * matrix and calling DBXform.
+ */
+
+{
+       ELT *e1;
+       POINT pos, *p1, *p2;
+       float xmat[3][2], angle, s, c;
+       int i, j;
+
+       if (SEQ < 3)        /* not enough points */
+       {
+               error(nopnt);
+               return;
+       }
+       if (DBNullelt(cset))
+       {
+               error(noset);
+               return;
+       }
+       p1 = PTNextPoint(POINTLIST);  /* calculate rotation angle */
+       p2 = PTNextPoint(p1);
+       angle = (float) atan2((p2->x - POINTLIST->x),(p2->y - POINTLIST->y))
+              -(float) atan2((p1->x - POINTLIST->x),(p1->y - POINTLIST->y));
+       s = (float) sin(angle);      
+       c = (float) cos(angle);      
+
+   /* Define transformation matrix to translate set to origin, rotate,
+      and translate back.                                              */
+
+       xmat[0][0] = c;
+       xmat[0][1] = -s;
+       xmat[1][0] = s;
+       xmat[1][1] = c;
+       xmat[2][0] = (-c) * POINTLIST->x - s * POINTLIST->y + POINTLIST->x;
+       xmat[2][1] = (-c) * POINTLIST->y + s * POINTLIST->x + POINTLIST->y;
+       e1 = cset;
+       while ( !DBNullelt(e1) )
+       {
+               DISScreenErase(e1, (linemask | setmask));
+               TxMsgOK();
+               DBXform(e1, xmat, &PICTURE);
+               if (TEXT(e1->type))
+               {
+                       GRsetwmask(textmask | setmask);
+                       p1 = e1->ptlist;
+                       GRPutText(e1->type, p1, e1->brushf,
+                                 e1->size,e1->textpt, &pos);
+                       i= strlen(e1->textpt);
+                       p2 = PTInit();
+                       (void) PTMakePoint(p1->x, p1->y, &p2);
+                           /* add extra positioning points */
+                       (void) PTMakePoint(pos.x, pos.y, &p2);   
+                       (void) PTMakePoint(pos.x + i * charxsize / 2, 
+                                          pos.y, &p2);
+                       (void) PTMakePoint(pos.x + i * charxsize, 
+                                          pos.y, &p2);
+                       e1->ptlist = p2;
+               }  /* end if TEXT */
+               else
+                       DISScreenAdd(e1, (linemask | setmask));
+               e1 = DBNextofSet(e1);
+       }  /* end while */
+       CHANGED = TRUE;
+}  /* end SHRotate */
+
+\f
+SHScale()
+/*
+ *      This routine scales the elements in the current set as defined
+ * by points.  The scaling is accomplished by defining a transformation
+ * matrix and calling DBXform.
+ */
+
+{
+       ELT *e1;
+       POINT pos, *p1, *p2;
+       float xmat[3][2], d1, d2, scalex, scaley;
+       int i, j;
+
+       if (SEQ < 3)        /* not enough points */
+       {
+               error(nopnt);
+               return;
+       }
+       if (DBNullelt(cset))
+       {
+               error(noset);
+               return;
+       }
+       p1 = PTNextPoint(POINTLIST);
+       p2 = PTNextPoint(p1);
+       d1 = sqrt( pow((p1->x - POINTLIST->x), 2.0)
+                + pow((p1->y - POINTLIST->y), 2.0));
+       d2 = sqrt( pow((p2->x - POINTLIST->x), 2.0)
+                + pow((p2->y - POINTLIST->y), 2.0));
+       if (d1 == 0)
+       {
+               error("infinite scale");
+               return;
+       }
+       scalex = scaley = d2 / d1;
+
+    /* create transformation matrix to translate set to origin, 
+       performaing the scaling and translating back               */
+
+       xmat[0][0] = scalex;
+       xmat[1][1] = scaley;
+       xmat[1][0] = xmat[0][1] = 0;
+       xmat[2][0] = - POINTLIST->x * (scalex - 1.0);
+       xmat[2][1] = - POINTLIST->y * (scaley - 1.0);
+       e1 = cset;
+       while ( !DBNullelt(e1) )
+       {
+               DISScreenErase(e1, (linemask | setmask));
+               TxMsgOK();
+               DBXform(e1, xmat, &PICTURE);
+               if (TEXT(e1->type))
+               {
+                       GRsetwmask(textmask | setmask);
+                       p1 = e1->ptlist;
+                       GRPutText(e1->type, p1, e1->brushf,
+                                 e1->size,e1->textpt, &pos);
+                       i= strlen(e1->textpt);
+                       p2 = PTInit();
+                       (void) PTMakePoint(p1->x, p1->y, &p2);
+                       /* add extra positioning points */
+                       (void) PTMakePoint(pos.x, pos.y, &p2);   
+                       (void) PTMakePoint(pos.x + i * charxsize / 2, 
+                                          pos.y, &p2);
+                       (void) PTMakePoint(pos.x + i * charxsize, 
+                                          pos.y, &p2);
+                       e1->ptlist = p2;
+               }  /* end if TEXT */
+               else
+                       DISScreenAdd(e1, (linemask | setmask));
+               e1 = DBNextofSet(e1);
+       }  /* end while */
+       CHANGED = TRUE;
+}  /* end SHScale */
+
+\f
+SHUpdate()
+/*
+ *      This routine redraws the graphics screen by clearing the screen ,
+ * redisplaying the menu and adding each element back to the display.
+ */
+
+{
+       ELT *e1;
+       int i;
+
+       GRClear(linemask | setmask | textmask);
+       MNDisplayMenu();
+       e1 = PICTURE;
+       while ( !DBNullelt(e1) )
+       {
+               DISScreenAdd(e1, linemask);
+               e1 = DBNextElt(e1);
+       };
+       e1 = cset;
+       while ( !DBNullelt(e1) )
+       {
+               DISScreenAdd(e1, setmask);
+               e1 = DBNextofSet(e1);
+       };
+       if ( Adjustment != NOADJ) MNHighLt(HiMode[adj[Adjustment]], hicolor);
+       if (GravityOn) MNHighLt(HiMode[3], hicolor); /* re highlight  */
+       MNHighLt(HiFont[CFONT-1], hicolor);          /* selected menu */
+       MNHighLt(HiBrush[CBRUSH-1], hicolor);        /* menu attributes */
+       for (i = 0; i < NUSER; ++i)
+               if ( !DBNullelt(MEN[i]) ) MNHighLt(HiMen[i], hicolor);
+       Consume = FALSE;
+}  /* end SHUpdate */
+
+\f
+SHRedis()
+/*
+ *      This routine is used to redisplay the text screen.
+ * It clears the screen, then redisplays the text and each of the 
+ * defined fields.
+ */
+
+{
+       char string[4];
+
+       TxRedisplay();
+       TxPutString(&TEdit, Editfile);
+       (void) sprintf(string,"%1d",CBRUSH);
+       TxPutString(&TBrush,string);
+       (void) sprintf(string, "%1d",CFONT);
+       TxPutString(&TFont,string);
+       (void) sprintf(string, "%1d",CSIZE);
+       TxPutString(&TCSize,string);
+       TxPutString(&TJustmode,dispmode[CJUST]);
+       (void) sprintf(string, "%3d",Alignment);
+       TxPutString(&TAlign,string);
+       (void) sprintf(string,"%1d",CBRUSH);
+       TxPutString(&TBrush,string);
+       if (GravityOn) TxPutString(&TGravity, " ON");
+       else TxPutString(&TGravity, "OFF");
+       switch(Adjustment)
+       {
+         case NOADJ: TxPutString(&TAdjust, "NO ADJUSTMENT");
+                     break;
+          case HORZ: TxPutString(&TAdjust, " HORIZONTAL  ");
+                     break;
+          case VERT: TxPutString(&TAdjust, "  VERTICAL   ");
+                     break;
+           case MAN: TxPutString(&TAdjust, "  MANHATTAN  ");
+                     break;
+       }  /* end switch */;
+        Consume = FALSE;
+}  /* end SHRedis */
+
+\f
+SHShellEsc()
+/* 
+ *      This routine performs a shell escape through the c 'system'
+ * function.  It first retrieves the command line through TxGetLine.
+ */
+
+{
+       char line[80];
+
+       TxGetLine("!",line,80);
+       TxClose();     /* Restore text terminal to 'normal' state */
+       (void) system(line);  /* do command */
+          /* allow time for user to digest command */
+       printf("Type <cr> to continue");
+       (void) fflush(stdout);
+       line[1] = TxGetChar();
+       SHRedis();  /* reclaim terminal */
+}  /* end ShellEsc */
+
+\f
+static savemen(sym)
+int sym;
+/*
+ *      This local routine stores the current set in the specified
+ * user symbol.
+ */
+
+{
+       ELT *elist;
+       float xmat[3][2];
+
+       xmat[0][0] = xmat[1][1] = 1;  /* set up copy transformation */
+       xmat[0][1] = xmat[1][0] = 0;  /* matrix for no              */
+       xmat[2][0] = xmat[2][1] = 0;  /* transformation             */
+       while ( !DBNullelt(MEN[sym]) )
+       {                             /* clear out existing symbol */
+               elist = DBNextElt(MEN[sym]);
+               DBClearElt(MEN[sym]);     
+               MEN[sym] = elist;
+       };
+       elist = cset;          /* copy current set to symbol */
+       while ( !DBNullelt(elist) )
+       {
+               (void) DBCopy(elist, xmat, &(MEN[sym]));
+               elist = DBNextofSet(elist);
+       }  /* end while */;
+       if (SEQ = 0)     /* no positioning points */
+       {
+               MENPOINT[sym].x = 0;
+               MENPOINT[sym].y = 0;
+       }
+       else
+       {
+               MENPOINT[sym].x = POINTLIST->x;
+               MENPOINT[sym].y = POINTLIST->y;
+       }
+       if ( !DBNullelt(MEN[sym]) ) MNHighLt(HiMen[sym], hicolor);
+       else     MNUnHighLt(HiMen[sym]);
+       CHANGED = TRUE;
+}  /* end savemen */
+
+SHSave1()
+/*
+ *      This routine saves the current set in user symbol 1 by
+ * calling savemen.
+ */
+
+{
+       savemen(0);
+}
+
+SHSave2()
+/*
+ *      This routine saves the current set in user symbol 2 by
+ * calling savemen.
+ */
+
+{
+       savemen(1);
+}
+
+SHSave3()
+/*
+ *      This routine saves the current set in user symbol 3 by
+ * calling savemen.
+ */
+
+{
+       savemen(2);
+}
+
+SHSave4()
+/*
+ *      This routine saves the current set in user symbol 4 by
+ * calling savemen.
+ */
+
+{
+       savemen(3);
+}
+
+
+\f
+SHBox()
+/*
+ *      This routine creates and displays a rectangle whose diagonal is
+ * defined by two points.  The routine uses the coordinates of these
+ * points to define a VECTOR element with the appropriate vertices.
+ */
+
+{
+       POINT *plist, *p1, *p2;
+       char *txt;
+       ELT *e1;
+       
+       if (SEQ < 2)
+       {
+               error("not enough points");
+               return;
+       }
+       p1 = POINTLIST;
+       p2 = PTNextPoint(p1);
+       plist = PTInit();   /* create points for vector element which defines 
+                              the rectangle                                 */
+       (void) PTMakePoint(p1->x, p1->y, &plist);
+       (void) PTMakePoint(p1->x, p2->y, &plist);
+       (void) PTMakePoint(p2->x, p2->y, &plist);
+       (void) PTMakePoint(p2->x, p1->y, &plist);
+       (void) PTMakePoint(p1->x, p1->y, &plist);   /* close rectangle */
+       txt = malloc(1);
+       *txt = '\0';
+       DBClearSet();         /* clear old set in preparation to make */
+       DISClearSetDisplay(); /* the new current set */
+       e1 = DBCreateElt(VECTOR, plist, CBRUSH, 0, txt, &PICTURE);
+       DBAddSet(e1);
+       DISScreenAdd(e1, (linemask | setmask));
+       CHANGED = TRUE;
+}  /* end LGBox */
+
+SHArrow()
+/*
+ *      This routine draws arrow heads by 'copying' the arrow head template
+ * into the picture appropriately transformed.
+ */
+
+{
+       ELT *e1;
+       POINT p1, *p2;
+       float xmat[3][2], angle, s, c;
+
+       if (SEQ < 2)        /* not enough points */
+       {
+               error(nopnt);
+               return;
+       }
+       p1.x = POINTLIST->x - 1;
+       p1.y = POINTLIST->y;
+       p2 = PTNextPoint(POINTLIST);
+       angle = (float) atan2((p2->x - POINTLIST->x),(p2->y - POINTLIST->y))
+              -(float) atan2((p1.x - POINTLIST->x),(p1.y - POINTLIST->y));
+       s = (float) sin(angle);      
+       c = (float) cos(angle);      
+
+   /* Define transformation matrix to translate element from origin
+      and rotate.                                                   */
+
+       xmat[0][0] = c;
+       xmat[0][1] = -s;
+       xmat[1][0] = s;
+       xmat[1][1] = c;
+       xmat[2][0] = POINTLIST->x;
+       xmat[2][1] = POINTLIST->y;
+
+       DBClearSet();         /* clear old set in preparation to make */
+       DISClearSetDisplay(); /* the new current set */
+       arhead.brushf = CBRUSH;
+       e1 = DBCopy(&arhead, xmat, &PICTURE);
+       DBAddSet(e1);
+       DISScreenAdd(e1, (linemask | setmask));
+       CHANGED = TRUE;
+}  /* end SHArrow */