a08e4fa32b4e78ebe0b800b1cab318e5a8a2a12a
* Copyright -C- 1982 Barry S. Roitblat
* This file contains routines to implement the short commands
* of the gremlin picture editor.
/* imports from graphics files */
extern GRVector(), GRPutText();
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 DBXform(), DBBounded();
extern DBAddSet(), DBClearSet();
extern POINT
*PTInit(), *PTMakePoint();
/* imports from long.c */
/* 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 TXFIELD TAlign
, TAdjust
, TBrush
, TFont
, TGravity
, TCSize
;
extern TXFIELD TEdit
, TJustmode
;
/* 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 */
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
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 */
SHRedis
, /* text screen redisplay */
SHGrid
, /* toggle grid display */
SHRotate
, /* rotate current set */
SHScale
, /* scale current set */
SHTranslate
, /* translate current set */
SHDrawVector
, /* draw vectors */
SHBox
, /* rectangle from two points */
SHMAdjust
}; /* manhattan adjust */
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
* Results: If c is a valid command character, its index is
* returned, otherwise, if c is the null command, -2 is returned
* (Modified from software written by John Ousterhout for the caesar
*---------------------------------------------------------
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);
/*---------------------------------------------------------
* This routine reads in, looks up, and executes a long command.
* Depends on the command that is invoked.
*---------------------------------------------------------
index
= SHLookup(*command
, shcmds
);
error("no such command");
static char nopnt
[18] = "not enough points";
static char noset
[15] = "no current set";
* This routine creates and displays a VECTOR element from the
* points previously specified.
if (SEQ
< 2) /* not enough points */
DBClearSet(); /* Clear current set in preparation */
DISClearSetDisplay(); /* for making this the new one */
GRsetwmask(linemask
| setmask
);
(void) PTMakePoint(p1
->x
, p1
->y
, &plist
);
(void) PTMakePoint(p2
->x
, p2
->y
, &plist
);
GRVector(p1
, p2
, CBRUSH
);
e1
= DBCreateElt(VECTOR
, plist
, CBRUSH
, 0, txt
, &PICTURE
);
* 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.
double a1
, a2
, angle
, radius
;
if (SEQ
< 2) /* not enough points */
radius
= sqrt( pow((p2
->x
- p1
->x
), 2.0)
+ pow((p2
->y
- p1
->y
), 2.0));
if (SEQ
== 2) /* draw full circle */
/* 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
);
(void) PTMakePoint(POINTLIST
->x
, POINTLIST
->y
, &plist
);
p1
= PTNextPoint(POINTLIST
);
(void) PTMakePoint(p1
->x
, p1
->y
, &plist
);
a1
= atan2((p1
->x
- POINTLIST
->x
), (p1
->y
- POINTLIST
->y
));
a2
= atan2((p2
->x
- POINTLIST
->x
), (p2
->y
- POINTLIST
->y
));
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
),
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
);
e1
= DBCreateElt(ARC
, plist
, CBRUSH
, (int) (angle
+ 0.5),
* This routine creates and displays a curve using points previously
* defined. This is dependent on DISCurve which is not yet implemented.
if (SEQ
< 2) /* not enough points */
error("need at least 2 points");
(void) PTMakePoint(p1
->x
, p1
->y
, &plist
);
(void) PTMakePoint(p2
->x
, p2
->y
, &plist
);
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");
e1
= DBCreateElt(CURVE
, plist
, CBRUSH
, 0, txt
, &PICTURE
);
* This routine erases selected elements from the screen and deletes
* them from the picture database.
while ( !DBNullelt(cset
) ) /* delete elements in current set */
DISScreenErase(cset
, (linemask
| setmask
));
DBDelete(cset
, &PICTURE
);
* This routine toggles the gravity mode.
TxPutString(&TGravity
, "OFF");
MNHighLt(HiMode
[3], hicolor
);
TxPutString(&TGravity
, " ON");
* This routine toggles the display of the grid
* This routine toggles the adjustment mode.
MNUnHighLt(HiMode
[adj
[MAN
]]);
TxPutString(&TAdjust
, "NO ADJUSTMENT");
MNUnHighLt(HiMode
[adj
[Adjustment
]]);
MNHighLt(HiMode
[adj
[MAN
]], hicolor
);
TxPutString(&TAdjust
, " MANHATTAN ");
* 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.
* This routine defines the current set by selecting all elements
* bounded by a rectangle whose diagonal is defined by specifed points.
p1
= PTNextPoint(POINTLIST
);
if ( DBBounded(e1
, x1
, y1
, x2
, y2
) )
* 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.
if (SEQ
< 2) /* not enough points */
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
;
DISScreenErase(e1
, (linemask
| setmask
));
DBXform(e1
, xmat
, &PICTURE
);
DISScreenAdd(e1
, (linemask
| setmask
));
* 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
* 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.
if (SEQ
< 2) /* not enough points */
p2
= PTNextPoint(POINTLIST
);
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
;
DBClearSet(); /* Dependent on Clearset preserving pointers */
e2
= DBCopy(e1
, xmat
, &PICTURE
);
DISScreenAdd(e2
, (linemask
| setmask
));
} /* end while ! null elt */
} /* end while ! null point */
* 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.
float xmat
[3][2], angle
, s
, c
;
if (SEQ
< 3) /* not enough points */
p1
= PTNextPoint(POINTLIST
); /* calculate rotation angle */
angle
= (float) atan2((p2
->x
- POINTLIST
->x
),(p2
->y
- POINTLIST
->y
))
-(float) atan2((p1
->x
- POINTLIST
->x
),(p1
->y
- POINTLIST
->y
));
/* Define transformation matrix to translate set to origin, rotate,
xmat
[2][0] = (-c
) * POINTLIST
->x
- s
* POINTLIST
->y
+ POINTLIST
->x
;
xmat
[2][1] = (-c
) * POINTLIST
->y
+ s
* POINTLIST
->x
+ POINTLIST
->y
;
DISScreenErase(e1
, (linemask
| setmask
));
DBXform(e1
, xmat
, &PICTURE
);
GRsetwmask(textmask
| setmask
);
GRPutText(e1
->type
, p1
, e1
->brushf
,
e1
->size
,e1
->textpt
, &pos
);
(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,
(void) PTMakePoint(pos
.x
+ i
* charxsize
,
DISScreenAdd(e1
, (linemask
| setmask
));
* 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.
float xmat
[3][2], d1
, d2
, scalex
, scaley
;
if (SEQ
< 3) /* not enough points */
p1
= PTNextPoint(POINTLIST
);
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));
scalex
= scaley
= d2
/ d1
;
/* create transformation matrix to translate set to origin,
performaing the scaling and translating back */
xmat
[1][0] = xmat
[0][1] = 0;
xmat
[2][0] = - POINTLIST
->x
* (scalex
- 1.0);
xmat
[2][1] = - POINTLIST
->y
* (scaley
- 1.0);
DISScreenErase(e1
, (linemask
| setmask
));
DBXform(e1
, xmat
, &PICTURE
);
GRsetwmask(textmask
| setmask
);
GRPutText(e1
->type
, p1
, e1
->brushf
,
e1
->size
,e1
->textpt
, &pos
);
(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,
(void) PTMakePoint(pos
.x
+ i
* charxsize
,
DISScreenAdd(e1
, (linemask
| setmask
));
* This routine redraws the graphics screen by clearing the screen ,
* redisplaying the menu and adding each element back to the display.
GRClear(linemask
| setmask
| textmask
);
DISScreenAdd(e1
, linemask
);
DISScreenAdd(e1
, setmask
);
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
);
* This routine is used to redisplay the text screen.
* It clears the screen, then redisplays the text and each of the
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");
case NOADJ
: TxPutString(&TAdjust
, "NO ADJUSTMENT");
case HORZ
: TxPutString(&TAdjust
, " HORIZONTAL ");
case VERT
: TxPutString(&TAdjust
, " VERTICAL ");
case MAN
: TxPutString(&TAdjust
, " MANHATTAN ");
* This routine performs a shell escape through the c 'system'
* function. It first retrieves the command line through TxGetLine.
TxClose(); /* Restore text terminal to 'normal' state */
(void) system(line
); /* do command */
/* allow time for user to digest command */
printf("Type <cr> to continue");
SHRedis(); /* reclaim terminal */
* This local routine stores the current set in the specified
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
]);
elist
= cset
; /* copy current set to symbol */
while ( !DBNullelt(elist
) )
(void) DBCopy(elist
, xmat
, &(MEN
[sym
]));
elist
= DBNextofSet(elist
);
if (SEQ
= 0) /* no positioning points */
MENPOINT
[sym
].x
= POINTLIST
->x
;
MENPOINT
[sym
].y
= POINTLIST
->y
;
if ( !DBNullelt(MEN
[sym
]) ) MNHighLt(HiMen
[sym
], hicolor
);
else MNUnHighLt(HiMen
[sym
]);
* This routine saves the current set in user symbol 1 by
* This routine saves the current set in user symbol 2 by
* This routine saves the current set in user symbol 3 by
* This routine saves the current set in user symbol 4 by
* 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.
error("not enough points");
plist
= PTInit(); /* create points for vector element which defines
(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 */
DBClearSet(); /* clear old set in preparation to make */
DISClearSetDisplay(); /* the new current set */
e1
= DBCreateElt(VECTOR
, plist
, CBRUSH
, 0, txt
, &PICTURE
);
DISScreenAdd(e1
, (linemask
| setmask
));
* This routine draws arrow heads by 'copying' the arrow head template
* into the picture appropriately transformed.
float xmat
[3][2], angle
, s
, c
;
if (SEQ
< 2) /* not enough points */
p2
= PTNextPoint(POINTLIST
);
angle
= (float) atan2((p2
->x
- POINTLIST
->x
),(p2
->y
- POINTLIST
->y
))
-(float) atan2((p1
.x
- POINTLIST
->x
),(p1
.y
- POINTLIST
->y
));
/* Define transformation matrix to translate element from origin
xmat
[2][0] = POINTLIST
->x
;
xmat
[2][1] = POINTLIST
->y
;
DBClearSet(); /* clear old set in preparation to make */
DISClearSetDisplay(); /* the new current set */
e1
= DBCopy(&arhead
, xmat
, &PICTURE
);
DISScreenAdd(e1
, (linemask
| setmask
));