/*ScianDraw.c
  Drawing routines for various types of objects
  Eric Pepke
  March 28, 1990
*/

/* JEL added PostScript drawing 4/2/92 */

#include "Scian.h"
#include "ScianTypes.h"
#include "ScianArrays.h"
#include "ScianLists.h"
#include "ScianIDs.h"
#include "ScianWindows.h"
#include "ScianDraw.h"
#include "ScianObjWindows.h"
#include "ScianColors.h"
#include "ScianPictures.h"
#include "ScianStyle.h"
#include "ScianFontSystem.h"

extern short LinToGamma[];

DrawingState drawingStates[NDRAWINGSTATES];	/*Stack of drawing states*/
int curDrawingStateIndex = 0;			/*Current drawing state*/

Bool drawMouse = false;				/*True iff draw on next mouse*/
extern int curMouse;				/*Current mouse button*/

int drawingMode = DRAW_SCREEN;			/*Drawing to the screen*/
FILE *drawFile = 0;				/*File in which to draw*/

Bool fullScreen = false;			/*True iff drawing to full screen*/

Matrix Identity = {{1.0, 0.0, 0.0, 0.0},
		   {0.0, 1.0, 0.0, 0.0},
		   {0.0, 0.0, 1.0, 0.0},
		   {0.0, 0.0, 0.0, 1.0}};

/* globals used for PostScript drawing */
FILE *psFile;		/* pointer to temp file */
int iconsUsed[32];	/* maximum number of *different* icons in EPS file is 32 */
int numIconsUsed;	/* number used so far = next index to use */

#if 0
void EchoDraw(s)
char *s;
{
    int k;
    for (k = 0; k < curDrawingStateIndex; ++k) printf("  ");
    printf("%s\n", s);
}
#else
#define EchoDraw(s)
#endif

void PushDrawingState()
/*Pushes the drawing state, producing a copy of the top drawing state*/
{
    int k;

    ++curDrawingStateIndex;
    if (curDrawingStateIndex >= NDRAWINGSTATES)
    {
	fprintf(stderr, "SciAn: Panic, drawing state overflow\n");
	exit(-1);
    }

    CURSTATE . window = LASTSTATE . window;
    CURSTATE . initialWindow = false;
    for (k = 0; k < 4; ++k)
    {
	CURSTATE . screenMask[k] = LASTSTATE . screenMask[k];
	CURSTATE . viewport[k] = LASTSTATE . viewport[k];
    }
    for (k = 0; k < 2; ++k)
    {
	CURSTATE . origin[k] = LASTSTATE . origin[k];
	CURSTATE . translation[k] = LASTSTATE . translation[k];
    }
}

void PopDrawingState()
/*Pops the drawing state and sets everything back to what it was.
  As a side-effect, may set the window*/
{
    Bool setViewport = false;	/*True iff the viewport needs to be set*/

    --curDrawingStateIndex;

    if (curDrawingStateIndex < 0)
    {
	fprintf(stderr, "SciAn: Panic, drawing state underflow\n");
	exit(-1);
    }

    if (!(CURSTATE . window))
    {
	/*No window, do nothing*/
	return;
    }

    if (NEXTSTATE . initialWindow)
    {
	/*New window!  Need to set everything*/
	SelWindow(CURSTATE . window);

#ifdef GRAPHICS
	shademodel(FLAT);
	concave(TRUE);
	backface(FALSE);
	lmcolor(LMC_COLOR);
	{
	    float n[3];
	    n[0] = 0.0;
	    n[1] = 0.0;
	    n[2] = 1.0;
	    n3f(n);
	}
#endif
	setViewport = true;
    }

    if (setViewport ||
	(CURSTATE . viewport[0] != NEXTSTATE . viewport[0]) ||
	(CURSTATE . viewport[1] != NEXTSTATE . viewport[1]) ||
	(CURSTATE . viewport[2] != NEXTSTATE . viewport[2]) ||
	(CURSTATE . viewport[3] != NEXTSTATE . viewport[3]))
    {
	/*New viewport.  Need to set viewport*/
	setViewport = true;

#ifdef GRAPHICS
	if (drawingMode == DRAW_SCREEN)
	{
	    /*Set the viewport in pixel-centered coordinates*/
	    viewport((Screencoord) CURSTATE . viewport[0],
		 (Screencoord) CURSTATE . viewport[1] - 1, 
		 (Screencoord) CURSTATE . viewport[2],
		 (Screencoord) CURSTATE . viewport[3] - 1);

	    /*Set up an orthographic perspective setup to map to this viewport*/
	    MakeOrthoXform();
	}
	else if (drawingMode == DRAW_POSTSCRIPT && psFile)
	{
	    fprintf(psFile, "%%new viewport\n%d %d translate\n",
	    (int) CURSTATE . translation[0], (int) CURSTATE . translation[1]);

	}
#endif
    }

    if (setViewport || 
	(CURSTATE . screenMask[0] != NEXTSTATE . screenMask[0]) ||
	(CURSTATE . screenMask[1] != NEXTSTATE . screenMask[1]) ||
	(CURSTATE . screenMask[2] != NEXTSTATE . screenMask[2]) ||
	(CURSTATE . screenMask[3] != NEXTSTATE . screenMask[3]))
    {
	/*New screen mask.  Need to set it*/

	if (drawingMode == DRAW_SCREEN)
	{
#ifdef GRAPHICS
	    scrmask((Screencoord) CURSTATE . screenMask[0],
		(Screencoord) CURSTATE . screenMask[1] - 1, 
		(Screencoord) CURSTATE . screenMask[2],
		(Screencoord) CURSTATE . screenMask[3] - 1);
#endif
	}
	else if (drawingMode == DRAW_POSTSCRIPT && psFile)
	{
	    int sl, sr, sb, st;
	    sl = CURSTATE . screenMask[0];
	    sr = CURSTATE . screenMask[1];
	    sb = CURSTATE . screenMask[2];
	    st = CURSTATE . screenMask[3];

	    fprintf(psFile,
"resetclip newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto closepath clip newpath\n",
		sl, st, sr, st, sr, sb, sl, sb);
	}
    }

    if ((setViewport == false) &&
	(CURSTATE . translation[0] != NEXTSTATE . translation[0] ||
	 CURSTATE . translation[1] != NEXTSTATE . translation[1]))
    {
	if (drawingMode == DRAW_SCREEN)
	{
#ifdef GRAPHICS
	    /*Translate back, but only if only the translation is different*/
	    translate(	(Coord) (CURSTATE . translation[0] - NEXTSTATE . translation[0]),
			(Coord) (CURSTATE . translation[1] - NEXTSTATE . translation[1]),
			(Coord) 0.0);
#endif
	}
	else if (drawingMode == DRAW_POSTSCRIPT && psFile)
	{
            fprintf(psFile, "%d %d translate\n",
        	(int) (CURSTATE . translation[0] - NEXTSTATE . translation[0]),
		(int) (CURSTATE . translation[1] - NEXTSTATE . translation[1]));
	}
    }
}

#ifdef PROTO
void SetDrawingWindow(WinInfoPtr window)
#else
void SetDrawingWindow(window)
WinInfoPtr window;
#endif
/*Sets to draw into a new window.  Side effect--selects the window*/
{
    int k;
    int l, r, b, t, ox, oy;

    EchoDraw("SetDrawingWindow");

    /*Save the current window, etc.*/
    PushDrawingState();

    /*Select this window and use it*/
    SelWindow(window);
#ifdef GRAPHICS
    shademodel(FLAT);
    concave(TRUE);
    backface(FALSE);
    lmcolor(LMC_COLOR);
	{
	    float n[3];
	    n[0] = 0.0;
	    n[1] = 0.0;
	    n[2] = 1.0;
	    n3f(n);
	}
#endif

    CURSTATE . window = window;
    CURSTATE . initialWindow = true;

    /*Zero translation*/
    for (k = 0; k < 2; ++k)
    {
	CURSTATE . translation[k] = 0;
    }

    /*Get the bounds of the window, in Mac style coordinates*/
    GetWindowBounds(&l, &r, &b, &t);

    /*Save the bounds as the viewport and mask*/
    CURSTATE . screenMask[0] = CURSTATE . viewport[0] = l;
    CURSTATE . screenMask[1] = CURSTATE . viewport[1] = r;
    CURSTATE . screenMask[2] = CURSTATE . viewport[2] = b;
    CURSTATE . screenMask[3] = CURSTATE . viewport[3] = t;

    /*Get the origin of the window*/
    GetWindowOrigin(&ox, &oy);
    CURSTATE . origin[0] = ox;
    CURSTATE . origin[1] = oy;
    
#ifdef GRAPHICS
    if (drawingMode == DRAW_SCREEN)
    {
	/*Set the viewport in pixel-centered coordinates*/
	viewport((Screencoord) l, (Screencoord) r - 1, 
	 (Screencoord) b, (Screencoord) t - 1);

	/*Set up an orthographic perspective setup to map to this viewport*/
	MakeOrthoXform();
    }
#endif
}

void RestoreDrawingWindow()
/*Restores the window area to what it was before.  Side effect--sets the
  window*/
{
    /*Pop the drawing state*/
    PopDrawingState();
    EchoDraw("RestoreDrawingWIndow");
}

#ifdef PROTO
void SetSubPort(int l, int r, int b, int t)
#else
void SetSubPort(l, r, b, t)
int l, r, b, t;
#endif
/*Sets to draw into a subport.  Side effect--selects the window*/
{
    int k;

    EchoDraw("SetSubPort");

    /*Save the current state.*/
    PushDrawingState();

    /*Pretend its a new window*/
    CURSTATE . initialWindow = true;

    /*Save the bounds as the viewport*/
    CURSTATE . viewport[0] = l;
    CURSTATE . viewport[1] = r;
    CURSTATE . viewport[2] = b;
    CURSTATE . viewport[3] = t;

    /*Shift the mask over by the effective offset*/
    CURSTATE . screenMask[0] -= CURSTATE . translation[0];
    CURSTATE . screenMask[1] -= CURSTATE . translation[0];
    CURSTATE . screenMask[2] -= CURSTATE . translation[1];
    CURSTATE . screenMask[3] -= CURSTATE . translation[1];

    /*Make a screen mask that is the intersection*/
    if (CURSTATE . viewport[0] > CURSTATE . screenMask[0])
	CURSTATE . screenMask[0] = CURSTATE . viewport[0];
    if (CURSTATE . viewport[1] < CURSTATE . screenMask[1])
	CURSTATE . screenMask[1] = CURSTATE . viewport[1];
    if (CURSTATE . viewport[2] > CURSTATE . screenMask[2])
	CURSTATE . screenMask[2] = CURSTATE . viewport[2];
    if (CURSTATE . viewport[3] < CURSTATE . screenMask[3])
	CURSTATE . screenMask[3] = CURSTATE . viewport[3];

    /*Zero translation*/
    for (k = 0; k < 2; ++k)
    {
	CURSTATE . translation[k] = 0;
    }

    /*Bump up origin*/
    CURSTATE . origin[0] += l;
    CURSTATE . origin[1] += b;

    /*Save the bounds as the viewport and mask*/
    CURSTATE . screenMask[0] = CURSTATE . viewport[0] = l;
    CURSTATE . screenMask[1] = CURSTATE . viewport[1] = r;
    CURSTATE . screenMask[2] = CURSTATE . viewport[2] = b;
    CURSTATE . screenMask[3] = CURSTATE . viewport[3] = t;

#ifdef GRAPHICS
    if (drawingMode == DRAW_SCREEN)
    {
	/*Set the viewport in pixel-centered coordinates*/
	viewport((Screencoord) l, (Screencoord) r - 1, 
	     (Screencoord) b, (Screencoord) t - 1);

	/*Set up an orthographic perspective setup to map to this viewport*/
	MakeOrthoXform();

	/*Set the screen mask*/
	scrmask((Screencoord) CURSTATE . screenMask[0],
		(Screencoord) CURSTATE . screenMask[1] - 1, 
		(Screencoord) CURSTATE . screenMask[2],
		(Screencoord) CURSTATE . screenMask[3] - 1);
    }
    else if (drawingMode == DRAW_POSTSCRIPT && psFile)
    {
	fprintf(psFile, "%%Call to SetSubPort!\n");
    }
#endif
}

void RestoreSubPort()
/*Restores the window area to what it was before.  Side effect--sets the
  window*/
{
    /*Pop the drawing state*/
    PopDrawingState();
    EchoDraw("RestoreSubPort");
}

#ifdef PROTO
void SetOrthoPick(void)
#else
void SetOrthoPick()
#endif
/*Sets to do an ortho pick.*/
{
    int k;

    EchoDraw("SetOrthoPick");

    /*Save the current state.*/
    PushDrawingState();

    /*Pretend its a new window*/
    CURSTATE . initialWindow = true;
}

#ifdef PROTO
void RestoreOrthoPick(void)
#else
void RestoreOrthoPick()
#endif
/*Restores the pickiness to what it was before.  Side effect--sets the
  window*/
{
    /*Pop the drawing state*/
    PopDrawingState();
    EchoDraw("RestoreOrthoPick");
}

void SetOrigin(x, y)
int x, y;
/*Sets the origin to x, y WITHIN current translation*/
{
    EchoDraw("SetOrigin");
    /*Save drawing state*/
    PushDrawingState();
  
    CURSTATE . translation[0] += x;
    CURSTATE . translation[1] += y;

    if (drawingMode == DRAW_SCREEN)
    {
#ifdef GRAPHICS
	translate((Coord) x, (Coord) y, (Coord) 0.0);
#endif
    }
    else if (drawingMode == DRAW_POSTSCRIPT && psFile)
    {
        fprintf(psFile, "%d %d translate\n", x, y);
    }
}

void RestoreOrigin()
/*Restores the origin to what it was*/
{
    PopDrawingState();
    EchoDraw("RestoreOrigin");
}

#ifdef PROTO
void FullScreen(Bool whether)
#else
void FullScreen(whether)
Bool whether;
#endif
/*Sets full screen mode to whether*/
{
    if (whether == fullScreen) return;

    fullScreen = whether;

#ifdef GRAPHICS
    if (fullScreen)
    {
	fullscrn();
    }
    else
    {
	endfullscrn();
    }
#endif
}

void MakeOrthoXform()
/*Makes an orthographic transformation based on the current state.*/
{
    if (drawingMode == DRAW_SCREEN)
    {
#ifdef GRAPHICS
	mmode(MSINGLE);
	ortho2( 0.0,
		(float) (CURSTATE . viewport[1] - CURSTATE . viewport[0]),
		0.0,
		(float) (CURSTATE . viewport[3] - CURSTATE . viewport[2]));
	translate((Coord) CURSTATE . translation[0],
		  (Coord) CURSTATE . translation[1], (Coord) 0.0);
	mmode(MPROJECTION);
	ortho2( 0.0,
		(float) (CURSTATE . viewport[1] - CURSTATE . viewport[0]),
		0.0,
		(float) (CURSTATE . viewport[3] - CURSTATE . viewport[2]));
	mmode(MVIEWING);
	loadmatrix(Identity);

	translate((Coord) CURSTATE . translation[0],
		  (Coord) CURSTATE . translation[1], (Coord) 0.0);
#endif
    }
}

void MakePickOrthoXform()
/*Makes an orthographic transformation based on the current state.*/
{
#ifdef GRAPHICS
	ortho2( 0.0,
		(float) (CURSTATE . viewport[1] - CURSTATE . viewport[0]),
		0.0,
		(float) (CURSTATE . viewport[3] - CURSTATE . viewport[2]));
#endif
}

#ifdef PROTO
void SetClipRect(int left, int right, int bottom, int top)
#else
void SetClipRect(left, right, bottom, top)
int left, right, bottom, top;
#endif
/*Sets the current clipping rectangle to left, right, bottom, top*/
{
    int sl, sr, sb, st;

    EchoDraw("SetClipRect");

    /*Save the current state*/
    PushDrawingState();

    left += CURSTATE . translation[0];
    right += CURSTATE . translation[0];
    bottom += CURSTATE . translation[1];
    top += CURSTATE . translation[1];

    sl = CURSTATE . screenMask[0];
    sr = CURSTATE . screenMask[1];
    sb = CURSTATE . screenMask[2];
    st = CURSTATE . screenMask[3];

    if (left > sl) sl = MIN(left, sr);
    if (right < sr) sr = MAX(right, sl);
    if (bottom > sb) sb = MIN(bottom, st);
    if (top < st) st = MAX(top, sb);

    CURSTATE . screenMask[0] = sl;
    CURSTATE . screenMask[1] = sr;
    CURSTATE . screenMask[2] = sb;
    CURSTATE . screenMask[3] = st;

    if (drawingMode == DRAW_SCREEN)
    {
#ifdef GRAPHICS
	scrmask(sl, sr - 1, sb, st - 1);
#endif
    }
    else if (drawingMode == DRAW_POSTSCRIPT && psFile)
    {
        fprintf(psFile,
"resetclip newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto closepath clip newpath\n",
	    sl, st, sr, st, sr, sb, sl, sb);
    }
}

void RestoreClipRect()
/*Restores the clipping rectangle to what it was before*/
{
    PopDrawingState();
    EchoDraw("RestoreClipRect");
}

void CurOffset(x, y)
int *x, *y;
/*Returns the current offset of the internal mouse coords from global*/
{
    int ox, oy;

    *x = CURSTATE . origin[0] + CURSTATE . translation[0];
    *y = CURSTATE . origin[1] + CURSTATE . translation[1];
}

void UD(void)
/*Updated drawing according to belated DrawMe's*/
{
#ifdef GRAPHICS
    if (drawMouse)
    {
	IdleAllWindows();
	drawMouse = false;
    }
#endif
}

void UpdateDrawing(void)
/*Updates drawing according to belated DrawMe's*/
{
   UD();
}

#ifdef GRAPHICS
void DrawObj2(origObj, obj)
ObjPtr origObj, obj;
/*Draws origObj according to method in obj*/
{
    FuncTyp DrawFunction;			/*Method*/

    if (obj)
    {
	DrawObj2(origObj, ClassOf(obj));
	DrawFunction = Get1Method(obj, DRAW);
	if (DrawFunction)
	{
	    (*DrawFunction)(origObj);
	}
    }
}
#endif

void DrawObject(obj)
ObjPtr obj;
/*Draws obj.*/
{
#ifdef GRAPHICS
    ObjPtr picState;

    if (GetPredicate(obj, INHIBITDRAWING))
    {
	return;
    }

    if (GetPredicate(obj, HIDDEN))
    {
	return;
    }

    if (GetPredicate(obj, MULTIDRAW))
    {
	DrawObj2(obj, obj);
    }
    else
    {
	FuncTyp DrawFunction;			/*Method*/

	DrawFunction = GetMethod(obj, DRAW);
	if (DrawFunction)
	{
	    (*DrawFunction)(obj);
	}
    }
#endif
}

void ClipToMe(object)
ObjPtr object;
/*Sets the clipping rectangle to object*/
{
    int l, r, b, t;

    Get2DIntBounds(object, &l, &r, &b, &t);

    SetClipRect(l, r, b, t);
}

#ifdef INTERACTIVE
ObjPtr PressObject(obj, x, y, flags)
ObjPtr obj;
int x, y;
long flags;
/*Presses in obj at x, y*/
{
    FuncTyp PressFunction;
    PressFunction = GetMethod(obj, PRESS);
    if (PressFunction)
    {
	return (*PressFunction)(obj, x, y, flags);
    }
    else
    {
	return ObjFalse;
    }
}
#endif

ObjPtr DropObjects(obj, dropObj, x, y)
ObjPtr obj, dropObj;
int x, y;
/*Drops dropObj in obj at x, y*/
{
    FuncTyp method;
    method = GetMethod(obj, DROPOBJECTS);
    if (method)
    {
	return (*method)(obj, dropObj, x, y);
    }
    else
    {
	return ObjFalse;
    }
}

#ifdef PROTO
ObjPtr KeyDownObject(ObjPtr obj, int key, long flags)
#else
ObjPtr KeyDownObject(obj, key, flags)
ObjPtr obj;
int key;
long flags;
#endif
/*Does a keydown in obj*/
{
    FuncTyp method;
    method = GetMethod(obj, KEYDOWN);
    if (method)
    {
	return (*method)(obj, key, flags);
    }
    else
    {
	return ObjFalse;
    }
}

void FrameUIRect(left, right, bottom, top, uiColor)
int left, right, bottom, top, uiColor;
/*Frames a user interface rectangle*/
{
#ifdef GRAPHICS
    SetUIColor(uiColor);
    FrameRect(left, right, bottom, top);
#endif
}

void FrameRect(left, right, bottom, top)
int left, right, bottom, top;
/*Frames a rectangle*/
{
#ifdef GRAPHICS

    if (drawingMode == DRAW_SCREEN)
    {
#ifdef V3FISBUGGED
	move2(left + 0.5, top - 0.5);
	draw2(left + 0.5, bottom + 0.5);
	draw2(right - 0.5, bottom + 0.5);
	draw2(right - 0.5, top - 0.5);
	draw2(left + 0.5, top - 0.5);
#else
	float v[5][2];
	v[0][0] = left + 0.5;
	v[0][1] = top - 0.5;
	v[1][0] = left + 0.5;
	v[1][1] = bottom + 0.5;
	v[2][0] = right - 0.5;
	v[2][1] = bottom + 0.5;
	v[3][0] = right - 0.5;
	v[3][1] = top - 0.5;
	v[4][0] = left + 0.5;
	v[4][1] = top - 0.5;
	bgnline();
	v2f(v[0]);
	v2f(v[1]);
	v2f(v[2]);
	v2f(v[3]);
	v2f(v[4]);
	endline();
#endif
    }
    else if (drawingMode == DRAW_POSTSCRIPT && psFile)
    {
	fprintf(psFile, "%f setgray\n", PSColor());
        fprintf(psFile, "%d %d moveto %d %d lineto %d %d lineto %d %d lineto closepath stroke\n",
            left, top, right, top, right, bottom, left, bottom); 
    }
#endif
}

void FillUIRect(left, right, bottom, top, uiColor)
int left, right, bottom, top, uiColor;
/*Fills a user interface rectangle*/
{
#ifdef GRAPHICS

    SetUIColor(uiColor);
    FillRect(left, right, bottom, top);
#endif
}

void FillRect(left, right, bottom, top)
int left, right, bottom, top;
/*Fills a rectangle*/
{
#ifdef GRAPHICS
    FillRealQuad((real) left, (real) (top),
		 (real) left, (real) bottom,
		 (real) (right), (real) bottom,
		 (real) (right), (real) (top));
#endif
}

void FillUIGauzeDisc(x, y, radius, uiColor)
int x, y, radius, uiColor;
/*Fills a disc in uiColor with gauze pattern*/
{
#ifdef GRAPHICS
    SetUIColor(uiColor);
    setpattern(GREYPAT);
    circfi(x, y, radius);
    setpattern(SOLIDPAT);
#endif
}

void FillUIDisc(x, y, radius, uiColor)
int x, y, radius, uiColor;
/*Fills a disc in uiColor*/
{
#ifdef GRAPHICS
    SetUIColor(uiColor);
    if (drawingMode == DRAW_SCREEN)
    {
        circfi(x, y, radius);
    }
    else if (drawingMode == DRAW_POSTSCRIPT && psFile)
    {
	fprintf(psFile, "%f setgray\n", PSColor());
        fprintf(psFile, "newpath %d %d %d 0 360 arc fill\n", x, y, radius);
    }
#endif
}

void FillTri(x1, y1, x2, y2, x3, y3)
int x1, y1, x2, y2, x3, y3;
/*Fills a triangle*/
{
#ifdef GRAPHICS

    if (drawingMode == DRAW_SCREEN)
    {
#ifdef V3FISBUGGED
	float v[3][2];
	v[0][0] = x1;
	v[0][1] = y1;
	v[1][0] = x2;
	v[1][1] = y2;
	v[2][0] = x3;
	v[2][1] = y3;
	polf(3, v);
#else
	float v[3][2];
	v[0][0] = x1;
	v[0][1] = y1;
	v[1][0] = x2;
	v[1][1] = y2;
	v[2][0] = x3;
	v[2][1] = y3;
	bgnpolygon();
	v2f(v[0]);
	v2f(v[1]);
	v2f(v[2]);
	endpolygon();
#endif
    }
    else if (drawingMode == DRAW_POSTSCRIPT && psFile)
    {
	fprintf(psFile, "%f setgray\n", PSColor());
        fprintf(psFile, "%d %d moveto %d %d lineto %d %d lineto closepath fill\n",
            x1, y1, x2, y2, x3, y3); 
    }
#endif
}

void FillUITri(x1, y1, x2, y2, x3, y3, uiColor)
int x1, y1, x2, y2, x3, y3, uiColor;
/*Fills a triangle in uiColor*/ 
{ 
#ifdef GRAPHICS 
    SetUIColor(uiColor);
    FillTri(x1, y1, x2, y2, x3, y3);
#endif
}

void FillUIGauzeRect(left, right, bottom, top, uiColor)
int left, right, bottom, top, uiColor;
/*Fills a user interface rectangle as if it were gauze*/
{
#ifdef GRAPHICS

    SetUIColor(uiColor);
    setpattern(GREYPAT);
    FillRealQuad((real) left, (real) (top),
		 (real) left, (real) bottom,
		 (real) (right), (real) bottom,
		 (real) (right), (real) (top));
    setpattern(SOLIDPAT);
#endif
}

void DrawUILine(x1, y1, x2, y2, uiColor)
int x1, y1, x2, y2, uiColor;
{
#ifdef GRAPHICS

    SetUIColor(uiColor);
    DrawLine(x1, y1, x2, y2);
#endif
}

void DrawLine(x1, y1, x2, y2)
int x1, y1, x2, y2;
{
#ifdef GRAPHICS
    if (drawingMode == DRAW_SCREEN)
    {
#ifdef V3FISBUGGED
	move2(x1 + 0.5, y1 + 0.5);
	draw2(x2 + 0.5, y2 + 0.5);
#else
	float v[2][2];
	v[0][0] = x1 + 0.5;
	v[0][1] = y1 + 0.5;
	v[1][0] = x2 + 0.5;
	v[1][1] = y2 + 0.5;
	bgnline();
	v2f(v[0]);
	v2f(v[1]);
	endline();
#endif
    }
    else if (drawingMode == DRAW_POSTSCRIPT && psFile)
    {
	fprintf(psFile, "%f setgray\n", PSColor());
        fprintf(psFile, "%d %d moveto %d %d lineto stroke\n",
            x1, y1, x2, y2);
    }
#endif
}

void FillUIWedge(x, y, radius, start, end, uiColor)
int x, y, radius, start, end, uiColor;
/*Fills a solid wege at x, y with radius from start to end degrees*/
{
#ifdef GRAPHICS
    SetUIColor(uiColor);
    if (drawingMode == DRAW_SCREEN)
    {
	arcfi(x, y, radius, start * 10, end * 10);
    }
    else if (drawingMode == DRAW_POSTSCRIPT && psFile)
    {
	fprintf(psFile, "%f setgray\n", PSColor());
	fprintf(psFile, "newpath %d %d moveto %d %d %d %d %d arc closepath fill\n", 
	    x, y, x, y, radius, start, end);
    }
#endif
}

void DrawArc(x, y, radius, start, end)
int x, y, radius, start, end;
/*Draws an arc in the current color.  start and end are in degrees.*/
{
    if (drawingMode == DRAW_SCREEN)
    {
#ifdef GRAPHICS
	arci(x, y, radius, start * 10, end * 10);
#endif
    }
    else if (drawingMode == DRAW_POSTSCRIPT && psFile)
    {
	fprintf(psFile, "%f setgray\n", PSColor());
	fprintf(psFile, "newpath %d %d %d %d %d arc stroke\n", 
	    x, y, radius, start, end);
    }
}

#ifdef PROTO
void DrawSpaceLine(real x1, real y1, real z1, real x2, real y2, real z2)
#else
void DrawSpaceLine(x1, y1, z1, x1, y1, z1)
real x1; real y1; real z1;
real x2; real y2; real z2;
#endif
/*Draws a line in a space*/
{
    float v[2][3];
#ifdef GRAPHICS

#ifdef V3FISBUGGED
    move(x1, y1, z1);
    draw(x2, y2, z2);
#else
    /*Draws a line in a space*/
    v[0][0] = x1;
    v[0][1] = y1;
    v[0][2] = z1;
    v[1][0] = x2;
    v[1][1] = y2;
    v[1][2] = z2;
    bgnline();
    v3f(v[0]);
    v3f(v[1]);
    endline();
#endif
#endif
}

#ifdef PROTO
void DrawSpacePanelLine(real x1, real y1, real x2, real y2, real width, int arrow,
                real arrowParams[4][2])
#else
void DrawSpacePanelLine(x1, y1, x2, y2, width, arrow, arrowParams)
real x1, y1, x2, y2, width;
int arrow;
real arrowParams[4][2];
#endif
/*Draws a space panel line*/
/* DIK need to make PostScript version */
{
#ifdef GRAPHICS
    if (x1 == y1 && x2 == y2)
    {
	/*Just a point*/
	long v[2];

	bgnpoint();
	v[0] = x1;
	v[1] = y1;
	v2i(v);
	endpoint();
    }
    else if (width <= 1 && arrow == AH_NO_ARROW)
    {
	/*Plain line*/
	long v[2][2];

	v[0][0] = x1;
	v[0][1] = y1;
	v[1][0] = x2;
	v[1][1] = y2;
	bgnline();
	v2i(v[0]);
	v2i(v[1]);
	endline();
    }
    else
    {
	/*Solid line*/
	real ax, ay, nx, ny, rr, mx, my;
	float v[10][2];

	/*Calculate the axial unit vector*/
	ax = x2 - x1;
	ay = y2 - y1;
	rr = 1.0 / sqrt(ax * ax + ay * ay);
	ax *= rr;
	ay *= rr;

	/*Now the normal unit vector*/
	nx = -ay;
	ny = ax;

	concave(TRUE);	/*DIK what is this supposed to return to?*/

	switch(arrow)
	{
	    case AH_NO_ARROW:
		v[0][0] = x1 - nx * width * 0.5;
		v[0][1] = y1 - ny * width * 0.5; 
		v[1][0] = x2 - nx * width * 0.5;
		v[1][1] = y2 - ny * width * 0.5; 
		v[2][0] = x2 + nx * width * 0.5;
		v[2][1] = y2 + ny * width * 0.5; 
		v[3][0] = x1 + nx * width * 0.5;
		v[3][1] = y1 + ny * width * 0.5; 
	        bgnpolygon();
		v2f(v[0]);
		v2f(v[1]);
		v2f(v[2]);
		v2f(v[3]);
		endpolygon();
		break;
	    case AH_AT_END:

		/*Arrow base*/
		v[0][0] = x1;
		v[0][1] = y1;

		/*Down to fletching*/
		v[1][0] = x1 + ax * width * arrowParams[0][0] -
				 nx * width * arrowParams[0][1];
		v[1][1] = y1 + ay * width * arrowParams[0][0] -
				 ny * width * arrowParams[0][1];

		/*Over to shaft*/
		v[2][0] = x2 + ax * width * arrowParams[1][0] -
				 nx * width * arrowParams[1][1];
		v[2][1] = y2 + ay * width * arrowParams[1][0] -
				 ny * width * arrowParams[1][1];

		/*To first arrowhead tip*/
		v[3][0] = x2 + ax * width * arrowParams[2][0] -
				 nx * width * arrowParams[2][1];
		v[3][1] = y2 + ay * width * arrowParams[2][0] -
				 ny * width * arrowParams[2][1];

		/*To second arrowhead tip*/
		v[4][0] = x2 + ax * width * arrowParams[3][0] -
				 nx * width * arrowParams[3][1];
		v[4][1] = y2 + ay * width * arrowParams[3][0] -
				 ny * width * arrowParams[3][1];

		/*To end of arrow*/
		v[5][0] = x2;
		v[5][1] = y2;

		/*Up to second arrowhead tip*/
		v[6][0] = x2 + ax * width * arrowParams[3][0] +
				 nx * width * arrowParams[3][1];
		v[6][1] = y2 + ay * width * arrowParams[3][0] +
				 ny * width * arrowParams[3][1];

		/*Back to first arrowhead tip*/
		v[7][0] = x2 + ax * width * arrowParams[2][0] +
				 nx * width * arrowParams[2][1];
		v[7][1] = y2 + ay * width * arrowParams[2][0] +
				 ny * width * arrowParams[2][1];

		/*Down to shaft*/
		v[8][0] = x2 + ax * width * arrowParams[1][0] +
				 nx * width * arrowParams[1][1];
		v[8][1] = y2 + ay * width * arrowParams[1][0] +
				 ny * width * arrowParams[1][1];

		/*Back to fletching*/
		v[9][0] = x1 + ax * width * arrowParams[0][0] +
				 nx * width * arrowParams[0][1];
		v[9][1] = y1 + ay * width * arrowParams[0][0] +
				 ny * width * arrowParams[0][1];

	        bgnpolygon();
		v2f(v[0]);
		v2f(v[1]);
		v2f(v[2]);
		v2f(v[3]);
		v2f(v[4]);
		v2f(v[5]);
		v2f(v[6]);
		v2f(v[7]);
		v2f(v[8]);
		v2f(v[9]);
		endpolygon();
		break;
	    case AH_AT_START:

		/*Arrow base*/
		v[0][0] = x2;
		v[0][1] = y2;

		/*Down to fletching*/
		v[1][0] = x2 - ax * width * arrowParams[0][0] +
				 nx * width * arrowParams[0][1];
		v[1][1] = y2 - ay * width * arrowParams[0][0] +
				 ny * width * arrowParams[0][1];

		/*Over to shaft*/
		v[2][0] = x1 - ax * width * arrowParams[1][0] +
				 nx * width * arrowParams[1][1];
		v[2][1] = y1 - ay * width * arrowParams[1][0] +
				 ny * width * arrowParams[1][1];

		/*To first arrowhead tip*/
		v[3][0] = x1 - ax * width * arrowParams[2][0] +
				 nx * width * arrowParams[2][1];
		v[3][1] = y1 - ay * width * arrowParams[2][0] +
				 ny * width * arrowParams[2][1];

		/*To second arrowhead tip*/
		v[4][0] = x1 - ax * width * arrowParams[3][0] +
				 nx * width * arrowParams[3][1];
		v[4][1] = y1 - ay * width * arrowParams[3][0] +
				 ny * width * arrowParams[3][1];

		/*To end of arrow*/
		v[5][0] = x1;
		v[5][1] = y1;

		/*Up to second arrowhead tip*/
		v[6][0] = x1 - ax * width * arrowParams[3][0] -
				 nx * width * arrowParams[3][1];
		v[6][1] = y1 - ay * width * arrowParams[3][0] -
				 ny * width * arrowParams[3][1];

		/*Back to first arrowhead tip*/
		v[7][0] = x1 - ax * width * arrowParams[2][0] -
				 nx * width * arrowParams[2][1];
		v[7][1] = y1 - ay * width * arrowParams[2][0] -
				 ny * width * arrowParams[2][1];

		/*Down to shaft*/
		v[8][0] = x1 - ax * width * arrowParams[1][0] -
				 nx * width * arrowParams[1][1];
		v[8][1] = y1 - ay * width * arrowParams[1][0] -
				 ny * width * arrowParams[1][1];

		/*Back to fletching*/
		v[9][0] = x2 - ax * width * arrowParams[0][0] -
				 nx * width * arrowParams[0][1];
		v[9][1] = y2 - ay * width * arrowParams[0][0] -
				 ny * width * arrowParams[0][1];

	        bgnpolygon();
		v2f(v[0]);
		v2f(v[1]);
		v2f(v[2]);
		v2f(v[3]);
		v2f(v[4]);
		v2f(v[5]);
		v2f(v[6]);
		v2f(v[7]);
		v2f(v[8]);
		v2f(v[9]);
		endpolygon();
		break;

	    case AH_BOTH_ENDS:
		/*Calculate midpoints*/
		mx = (x1 + x2) * 0.5;
		my = (y1 + y2) * 0.5;

		/*Do at end first*/

		/*Arrow base*/
		v[0][0] = mx;
		v[0][1] = my;

		/*Down to fletching*/
		v[1][0] = mx + ax * width * arrowParams[0][0] -
				 nx * width * arrowParams[0][1];
		v[1][1] = my + ay * width * arrowParams[0][0] -
				 ny * width * arrowParams[0][1];

		/*Over to shaft*/
		v[2][0] = x2 + ax * width * arrowParams[1][0] -
				 nx * width * arrowParams[1][1];
		v[2][1] = y2 + ay * width * arrowParams[1][0] -
				 ny * width * arrowParams[1][1];

		/*To first arrowhead tip*/
		v[3][0] = x2 + ax * width * arrowParams[2][0] -
				 nx * width * arrowParams[2][1];
		v[3][1] = y2 + ay * width * arrowParams[2][0] -
				 ny * width * arrowParams[2][1];

		/*To second arrowhead tip*/
		v[4][0] = x2 + ax * width * arrowParams[3][0] -
				 nx * width * arrowParams[3][1];
		v[4][1] = y2 + ay * width * arrowParams[3][0] -
				 ny * width * arrowParams[3][1];

		/*To end of arrow*/
		v[5][0] = x2;
		v[5][1] = y2;

		/*Up to second arrowhead tip*/
		v[6][0] = x2 + ax * width * arrowParams[3][0] +
				 nx * width * arrowParams[3][1];
		v[6][1] = y2 + ay * width * arrowParams[3][0] +
				 ny * width * arrowParams[3][1];

		/*Back to first arrowhead tip*/
		v[7][0] = x2 + ax * width * arrowParams[2][0] +
				 nx * width * arrowParams[2][1];
		v[7][1] = y2 + ay * width * arrowParams[2][0] +
				 ny * width * arrowParams[2][1];

		/*Down to shaft*/
		v[8][0] = x2 + ax * width * arrowParams[1][0] +
				 nx * width * arrowParams[1][1];
		v[8][1] = y2 + ay * width * arrowParams[1][0] +
				 ny * width * arrowParams[1][1];

		/*Back to fletching*/
		v[9][0] = mx + ax * width * arrowParams[0][0] +
				 nx * width * arrowParams[0][1];
		v[9][1] = my + ay * width * arrowParams[0][0] +
				 ny * width * arrowParams[0][1];

	        bgnpolygon();
		v2f(v[0]);
		v2f(v[1]);
		v2f(v[2]);
		v2f(v[3]);
		v2f(v[4]);
		v2f(v[5]);
		v2f(v[6]);
		v2f(v[7]);
		v2f(v[8]);
		v2f(v[9]);
		endpolygon();

		/*Now do at start*/
	        bgnpolygon();

		/*Arrow base*/
		v[0][0] = mx;
		v[0][1] = my;

		/*Down to fletching*/
		v[1][0] = mx - ax * width * arrowParams[0][0] +
				 nx * width * arrowParams[0][1];
		v[1][1] = my - ay * width * arrowParams[0][0] +
				 ny * width * arrowParams[0][1];

		/*Over to shaft*/
		v[2][0] = x1 - ax * width * arrowParams[1][0] +
				 nx * width * arrowParams[1][1];
		v[2][1] = y1 - ay * width * arrowParams[1][0] +
				 ny * width * arrowParams[1][1];

		/*To first arrowhead tip*/
		v[3][0] = x1 - ax * width * arrowParams[2][0] +
				 nx * width * arrowParams[2][1];
		v[3][1] = y1 - ay * width * arrowParams[2][0] +
				 ny * width * arrowParams[2][1];

		/*To second arrowhead tip*/
		v[4][0] = x1 - ax * width * arrowParams[3][0] +
				 nx * width * arrowParams[3][1];
		v[4][1] = y1 - ay * width * arrowParams[3][0] +
				 ny * width * arrowParams[3][1];

		/*To end of arrow*/
		v[5][0] = x1;
		v[5][1] = y1;

		/*Up to second arrowhead tip*/
		v[6][0] = x1 - ax * width * arrowParams[3][0] -
				 nx * width * arrowParams[3][1];
		v[6][1] = y1 - ay * width * arrowParams[3][0] -
				 ny * width * arrowParams[3][1];
		
		/*Back to first arrowhead tip*/
		v[7][0] = x1 - ax * width * arrowParams[2][0] -
				 nx * width * arrowParams[2][1];
		v[7][1] = y1 - ay * width * arrowParams[2][0] -
				 ny * width * arrowParams[2][1];
		
		/*Down to shaft*/
		v[8][0] = x1 - ax * width * arrowParams[1][0] -
				 nx * width * arrowParams[1][1];
		v[8][1] = y1 - ay * width * arrowParams[1][0] -
				 ny * width * arrowParams[1][1];

		/*Back to fletching*/
		v[9][0] = mx - ax * width * arrowParams[0][0] -
				 nx * width * arrowParams[0][1];
		v[9][1] = my - ay * width * arrowParams[0][0] -
				 ny * width * arrowParams[0][1];

	        bgnpolygon();
		v2f(v[0]);
		v2f(v[1]);
		v2f(v[2]);
		v2f(v[3]);
		v2f(v[4]);
		v2f(v[5]);
		v2f(v[6]);
		v2f(v[7]);
		v2f(v[8]);
		v2f(v[9]);
		endpolygon();
		break;
	}	
    }
#endif
}

void DrawVCursor(x, yt, yb)
int x, yt, yb;
/*Draws a vertical cursor*/
{
#ifdef GRAPHICS
    DrawUILine(x, yt, x, yb, UIRED);
    DrawUILine(x + 1, yt, x + 1, yb, UIBLACK);
#endif
}

#ifdef GRAPHICS
#ifdef FONTS4D
extern fmfonthandle currentFontHandle;
#endif
#endif

#ifdef PROTO
void DrawSpaceString(real x, real y, real z, char *s)
#else
void DrawSpaceString(x, y, z, s)
real x, y, z;
char *s;
#endif
/*Draws a string beginning at x, y, z in a space*/
/* DIK need PostScript version? */
{
#ifdef GRAPHICS

    cmov((Coord) x, (Coord) y, (Coord) z);
#ifdef FONTS4D
	if (currentFontHandle)
	{
		fmprstr(s);
	}
	else
	{
		charstr(s);
	}
#else
	charstr(s);
#endif
#endif
}

#ifdef PROTO
void DrawWFSphere(real x, real y, real z, real radius)
#else
void DrawWFSphere(x, y, z, radius)
real x, y, z, radius;
#endif
/*Draws a wire frame sphere*/
{
#ifdef GRAPHICS
    pushmatrix();
    translate(x, y, z);
    circ(0.0, 0.0, radius);
    translate(0.0, 0.0, radius * SQ22);
    circ(0.0, 0.0, radius * SQ22);
    translate(0.0, 0.0, -radius * 2.0 * SQ22);
    circ(0.0, 0.0, radius * SQ22);
    translate(0.0, 0.0, radius * SQ22);
    rotate(900, 'y');
    circ(0.0, 0.0, radius);
    rotate(450, 'x');
    circ(0.0, 0.0, radius);
    rotate(450, 'x');
    circ(0.0, 0.0, radius);
    rotate(450, 'x');
    circ(0.0, 0.0, radius);
    popmatrix();
#endif
}

#ifdef PROTO
void FillRealQuad(real x1, real y1, real x2, real y2, real x3, real y3, real x4, real y4)
#else
void FillRealQuad(x1, y1, x2, y2, x3, y3, x4, y4)
real x1, y1, x2, y2, x3, y3, x4, y4;
#endif
/*Fills a quadrilateral given real coordinates*/
{
#ifdef GRAPHICS
    if (drawingMode == DRAW_SCREEN)
    {
#ifdef V3FISBUGGED
	Coord v[4][2];
	v[0][0] = x1;
	v[0][1] = y1;
	v[1][0] = x2;
	v[1][1] = y2;
	v[2][0] = x3;
	v[2][1] = y3;
	v[3][0] = x4;
	v[3][1] = y4;

	polf2(4, v);
#else
	float v[4][2];
	v[0][0] = x1;
	v[0][1] = y1;
	v[1][0] = x2;
	v[1][1] = y2;
	v[2][0] = x3;
	v[2][1] = y3;
	v[3][0] = x4;
	v[3][1] = y4;
	bgnpolygon();
	v2f(v[0]);
	v2f(v[1]);
	v2f(v[2]);
	v2f(v[3]);
	endpolygon();
#endif
    }
    else if (drawingMode == DRAW_POSTSCRIPT && psFile)
    {
	fprintf(psFile, "%f setgray\n", PSColor());
        fprintf(psFile, "%g %g moveto %g %g lineto %g %g lineto %g %g lineto closepath fill\n",
            x1, y1, x2, y2, x3, y3, x4, y4); 
    }
#endif
}

#ifdef PROTO
void FillRealQuint(real x1, real y1, real x2, real y2, real x3, real y3, real x4, real y4, real x5, real y5)
#else
void FillRealQuint(x1, y1, x2, y2, x3, y3, x4, y4, x5, y5)
real x1, y1, x2, y2, x3, y3, x4, y4, x5, y5;
#endif
/*Fills a quintalateral given real coordinates*/
{
#ifdef GRAPHICS
    if (drawingMode == DRAW_SCREEN)
    {
#ifdef V3FISBUGGED
	Coord v[5][2];
	v[0][0] = x1;
	v[0][1] = y1;
	v[1][0] = x2;
	v[1][1] = y2;
	v[2][0] = x3;
	v[2][1] = y3;
	v[3][0] = x4;
	v[3][1] = y4;
	v[4][0] = x5;
	v[4][1] = y5;
	polf(5, v);
#else
	float v[5][2];
	v[0][0] = x1;
	v[0][1] = y1;
	v[1][0] = x2;
	v[1][1] = y2;
	v[2][0] = x3;
	v[2][1] = y3;
	v[3][0] = x4;
	v[3][1] = y4;
	v[4][0] = x5;
	v[4][1] = y5;
	bgnpolygon();
	v2f(v[0]);
	v2f(v[1]);
	v2f(v[2]);
	v2f(v[3]);
	v2f(v[4]);
	endpolygon();
#endif
    }
    else if (drawingMode == DRAW_POSTSCRIPT && psFile)
    {
	fprintf(psFile, "%f setgray\n", PSColor());
        fprintf(psFile, "%g %g moveto %g %g lineto %g %g lineto %g %g lineto %g %g lineto closepath fill\n",
            x1, y1, x2, y2, x3, y3, x4, y4, x5, y5); 
    }
#endif
}

#ifdef PROTO
void FillRealHex(real x1, real y1, real x2, real y2, real x3, real y3, real x4, real y4, real x5, real y5, real x6, real y6)
#else
void FillRealHex(x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, x6, y6)
real x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, x6, y6;
#endif
/*Fills a hexalateral given real coordinates*/
{
#ifdef GRAPHICS
    if (drawingMode == DRAW_SCREEN)
    {
#ifdef V3FISBUGGED
	float v[6][2];
	v[0][0] = x1;
	v[0][1] = y1;
	v[1][0] = x2;
	v[1][1] = y2;
	v[2][0] = x3;
	v[2][1] = y3;
	v[3][0] = x4;
	v[3][1] = y4;
	v[4][0] = x5;
	v[4][1] = y5;
	v[5][0] = x6;
	v[5][1] = y6;
	polf(4, v);
#else
	float v[6][2];
	v[0][0] = x1;
	v[0][1] = y1;
	v[1][0] = x2;
	v[1][1] = y2;
	v[2][0] = x3;
	v[2][1] = y3;
	v[3][0] = x4;
	v[3][1] = y4;
	v[4][0] = x5;
	v[4][1] = y5;
	v[5][0] = x6;
	v[5][1] = y6;
	bgnpolygon();
	v2f(v[0]);
	v2f(v[1]);
	v2f(v[2]);
	v2f(v[3]);
	v2f(v[4]);
	v2f(v[5]);
	endpolygon();
#endif
    }
    else if (drawingMode == DRAW_POSTSCRIPT && psFile)
    {
	fprintf(psFile, "%f setgray\n", PSColor());
        fprintf(psFile, "%g %g moveto %g %g lineto %g %g lineto %g %g lineto %g %g lineto %g %g lineto closepath fill\n",
            x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, x6, y6); 
    }
#endif
}

#ifdef PROTO
void FillRealRect(real left, real right, real bottom, real top)
#else
void FillRealRect(left, right, bottom, top)
real left, right, bottom, top;
#endif
/*Fills a rectangle, taking real coordinates*/
{
#ifdef GRAPHICS
    FillRealQuad(left, top, left, bottom, right, bottom, right, top);
#endif
}


#ifdef PROTO
void FrameRealWideRect(real left, real right, real bottom, real top, real width)
#else
void FrameRealWideRect(left, right, bottom, top, width)
real left, right, bottom, top, width;
#endif
/*Frames a wide rectangle taking real variables*/
{
#ifdef GRAPHICS
    FillRealRect(left, right, top - width, top);
    FillRealRect(left, right, bottom, bottom + width);
    FillRealRect(left, left + width, bottom, top);
    FillRealRect(right - width, right, bottom, top);
#endif
}

#ifdef PROTO
void FrameWideRect(int left, int right, int bottom, int top, int width)
#else
void FrameWideRect(left, right, bottom, top, width)
int left, right, bottom, top, width;
#endif
/*Frames a wide rectangle*/
{
#ifdef GRAPHICS
    FillRect(left, right, top - width + 1, top);
    FillRect(left, right, bottom, bottom + width - 1);
    FillRect(left, left + width - 1, bottom, top);
    FillRect(right - width + 1, right, bottom, top);
#endif
}

#ifdef PROTO
void FrameUIWideRect(int left, int right, int bottom, int top, int width, int color)
#else
void FrameUIWideRect(left, right, bottom, top, width, color)
int left, right, bottom, top, width, color;
#endif
/*Frames a wide rectangle in UI color*/
{
#ifdef GRAPHICS
    SetUIColor(color);
    FrameWideRect(left, right, bottom, top, width);
#endif
}

#ifdef PROTO
void DrawHandle(int x, int y)
#else
void DrawHandle(x, y)
int x, y;
#endif
/* Draws a handle at x,y */
{
#ifdef GRAPHICS
	FillUIRect(x - HANDLESIZE/2, x + HANDLESIZE / 2,
		y - HANDLESIZE/2, y + HANDLESIZE/2, OUTSIDEFRAMECOLOR);
	FillUIRect(x - HANDLESIZE/2 + OUTSIDEFRAMEWEIGHT,
		x + HANDLESIZE/2 - OUTSIDEFRAMEWEIGHT,
		y - HANDLESIZE/2 + OUTSIDEFRAMEWEIGHT,
		y + HANDLESIZE/2 - OUTSIDEFRAMEWEIGHT, INSIDEFRAMECOLOR);
#endif
}

#ifdef PROTO
Bool PointInHandle(int pointX, int pointY, int handleX, int handleY)
#else
Bool PointInHandle(pointX, pointY, handleX, handleY)
int pointX; int pointY; int handleX; int handleY;
#endif
/*Returns true if a point is inside a handle*/
{
#ifdef INTERACTIVE
    return (pointX >= handleX - HANDLESIZE / 2 &&
	    pointX <= handleX + HANDLESIZE / 2 &&
	    pointY >= handleY - HANDLESIZE / 2 &&
	    pointY <= handleY + HANDLESIZE / 2) ? true : false;
#endif
}

#ifdef PROTO
void DrawRaisedEdge(int left, int right, int bottom, int top)
#else
void DrawRaisedEdge(left, right, bottom, top)
int left; int right; int bottom; int top;
#endif
/* draws a rectangular raised edge (JEL) */
{
#ifdef GRAPHICS
    /* bottom */
    SetUIColor(UIBOTTOMEDGE);
    FillRealQuad(left + EDGE, bottom + EDGE,
		 right - EDGE, bottom + EDGE,
		 right, bottom, left, bottom);

    /* left */
    SetUIColor(UILEFTEDGE);
    FillRealQuad(left, top,
		 left + EDGE, top - EDGE,
		 left + EDGE, bottom + EDGE,
		 left,  bottom);

    /* right */
    SetUIColor(UIRIGHTEDGE);
    FillRealQuad(right - EDGE, top - EDGE,
		 right, top,
		 right, bottom,
		 right - EDGE, bottom + EDGE);

    /* top */
    SetUIColor(UITOPEDGE);
    FillRealQuad(left, top,
		 right, top,
		 right - EDGE, top - EDGE,
		 left + EDGE, top - EDGE);
    return;
#endif
}

#ifdef PROTO
void DrawSunkenEdge(int left, int right, int bottom, int top)
#else
void DrawSunkenEdge(left, right, bottom, top)
int left; int right; int bottom; int top;
#endif
/* draws a rectanglar sunken edge (JEL) */
{
#ifdef GRAPHICS
    /* bottom */
    SetUIColor(UITOPEDGE);
    FillRealQuad(left + EDGE, bottom + EDGE,
		 right - EDGE, bottom + EDGE,
		 right, bottom, left, bottom);

    /* left */
    SetUIColor(UIRIGHTEDGE);
    FillRealQuad(left, top,
		 left + EDGE, top - EDGE,
		 left + EDGE, bottom + EDGE,
		 left,  bottom);

    /* right */
    SetUIColor(UILEFTEDGE);
    FillRealQuad(right - EDGE, top - EDGE,
		 right, top,
		 right, bottom,
		 right - EDGE, bottom + EDGE);

    /* top */
    SetUIColor(UIBOTTOMEDGE);
    FillRealQuad(left, top,
		 right, top,
		 right - EDGE, top - EDGE,
		 left + EDGE, top - EDGE);
    return;
#endif
}

#ifdef PROTO
void DrawInsetRect(int left, int right, int bottom, int top)
#else
void DrawInsetRect(left, right, bottom, top)
int left; int right; int bottom; int top;
#endif
/* draws a rectangle filled with uiColor inset by EDGE from the given bounds */
{
#ifdef GRAPHICS
	FillRect(left + EDGE, right - EDGE, bottom + EDGE,
		top - EDGE);
#endif
}

#ifdef PROTO
void DrawInsetWashedRect(int left, int right, int bottom, int top, int washColor)
#else
void DrawInsetWashedRect(left, right, bottom, top, int washColor)
int left; int right; int bottom; int top; int washColor;
#endif
/* draws a rectangle filled with uiColor inset by EDGE from the given bounds */
{
#ifdef GRAPHICS
	FillUIRect(left + EDGE, right - EDGE, bottom + EDGE,
		top - EDGE, UIGRAY75);
	FillUIGauzeRect(left + EDGE, right - EDGE, bottom + EDGE,
		top - EDGE, washColor);
#endif
}

#ifdef PROTO
void DrawRaisedRect(int left, int right, int bottom, int top, int uiColor)
#else
void DrawRaisedRect(left, right, bottom, top, uiColor)
int left; int right; int bottom; int top; int uiColor;
#endif
/* draws a raised edge with filled rectangle inside */
{
#ifdef GRAPHICS
	SetUIColor(uiColor);
	DrawInsetRect(left, right, bottom, top);
	DrawRaisedEdge(left, right, bottom, top);
#endif
}

#ifdef PROTO
void DrawSunkenRect(int left, int right, int bottom, int top, int uiColor)
#else
void DrawSunkenRect(left, right, bottom, top, uiColor)
int left; int right; int bottom; int top; int uiColor;
#endif
/* draws a sunken edge with filled rectangle inside */
{
#ifdef GRAPHICS
	SetUIColor(uiColor);
	DrawInsetRect(left, right, bottom, top);
	DrawSunkenEdge(left, right, bottom, top);
#endif
}

void SetLineWidth(width)
int width;
/*Sets the line width to width*/
{
#ifdef GRAPHICS
    if (drawingMode == DRAW_SCREEN)
    {
        linewidth(width);
    }
    else if (drawingMode == DRAW_POSTSCRIPT && psFile)
    {
        fprintf(psFile, "%d setlinewidth\n", width);
    }
#endif
}

void SetPointWidth(width)
int width;
/*Sets the line width to width*/
{
#ifdef GRAPHICS
    if (drawingMode == DRAW_SCREEN)
    {
#if MACHINE != RS6000
        pntsize((short) width);
#endif
    }
#endif
}

void	DrawMarkerSplat(left, right, bottom, top)
{

#ifdef GRAPHICS

    SetUIColor(UITEXT);
    if (drawingMode == DRAW_SCREEN)
    {
	Coord v[4][2];

	/*Draw part of button '*', the left-bottom to top-right part */
	v[0][0] = left + 2.5;
	v[0][1] = bottom + 3.5;
	v[1][0] = left + 3.5;
	v[1][1] = bottom + 2.5;
	v[2][0] = right - 2.5;
	v[2][1] = top - 3.5;
	v[3][0] = right - 3.5;
	v[3][1] = top - 2.5;
	polf2(4, v);

	/*Draw rest of button '*', the left-top to right-bottom part*/
	v[0][0] = left + 2.5;
	v[0][1] = top - 3.5;
	v[1][0] = left + 3.5;
	v[1][1] = top - 2.5;
	v[2][0] = right - 2.5;
	v[2][1] = bottom + 3.5;
	v[3][0] = right - 3.5;
	v[3][1] = bottom + 2.5;
	polf2(4, v);

	/*Draw rest of button '*', the left-to-right part*/
	v[0][0] = left + 1.5;
	v[0][1] = (top+bottom)/2.0 - 0.5;
	v[1][0] = left + 1.5;
	v[1][1] = (top+bottom)/2.0 + 0.5;
	v[2][0] = right - 1.5;
	v[2][1] = (top+bottom)/2.0 + 0.5;
	v[3][0] = right - 1.5;
	v[3][1] = (top+bottom)/2.0 - 0.5;
	polf2(4, v);

	/*Draw rest of button '*', the top-to-bottom part*/
	v[0][0] = (left+right)/2.0 - 0.5;
	v[0][1] = top - 1.5;
	v[1][0] = (left+right)/2.0 + 0.5;
	v[1][1] = top - 1.5;
	v[2][0] = (left+right)/2.0 + 0.5;
	v[2][1] = bottom + 1.5;
	v[3][0] = (left+right)/2.0 - 0.5;
	v[3][1] = bottom + 1.5;
	polf2(4, v);
    }
    else if (drawingMode == DRAW_POSTSCRIPT && psFile)
    {
	fprintf(psFile, "%f setgray\n", PSColor());
        fprintf(psFile,
		"%.1f %.1f moveto %.1f %.1f lineto %.1f %.1f lineto %.1f %.1f lineto closepath fill\n",
		left + 2.5, bottom + 3.5, left + 3.5, bottom + 2.5,
		right - 2.5, top - 3.5, right - 3.5, top - 2.5); 
        fprintf(psFile,
		"%.1f %.1f moveto %.1f %.1f lineto %.1f %.1f lineto %.1f %.1f lineto closepath fill\n",
		left + 2.5, top - 3.5, left + 3.5, top - 2.5,
		right - 2.5, bottom + 3.5, right - 3.5, bottom + 2.5); 
        fprintf(psFile,
		"%.1f %.1f moveto %.1f %.1f lineto %.1f %.1f lineto %.1f %.1f lineto closepath fill\n",
		left + 1.5, (top+bottom)/2.0 - 0.5, left + 1.5, (top+bottom)/2.0 + 0.5,
		right - 1.5, (top+bottom)/2.0 + 0.5, right - 1.5, (top+bottom)/2.0 - 0.5); 
        fprintf(psFile,
		"%.1f %.1f moveto %.1f %.1f lineto %.1f %.1f lineto %.1f %.1f lineto closepath fill\n",
		(left+right)/2.0 - 0.5, top - 1.5, (left+right)/2.0 + 0.5, top - 1.5,
		(left+right)/2.0 + 0.5, bottom + 1.5, (left+right)/2.0 - 0.5, bottom + 1.5); 
    }
#endif /* GRAPHICS */
}

void    DrawMarkerBlot(left, right, bottom, top)
int     left, right, bottom, top;
{
#ifdef GRAPHICS
    SetUIColor(UITEXT);
    FillRect(left+2.5, right-2.5, bottom+2.5, top-2.5);
#endif /*GRAPHICS*/
}

void	DrawMarkerCheck(left, right, bottom, top)
int	left, right, bottom, top;
{
#ifdef GRAPHICS
    Coord v[4][2];

    SetUIColor(UITEXT);
    if (drawingMode == DRAW_SCREEN)
    {
	/*Draw part of checkmark*/
	v[0][0] = left + 1.5;
	v[0][1] = (top + bottom) / 2 - 0.5;
	v[1][0] = left + 2.5;
	v[1][1] = (top + bottom) / 2 + 1.5;
	v[2][0] = left + (right - left) / 3 + 1.5;
	v[2][1] = bottom + 1.5;
	v[3][0] = left + (right - left) / 3 - 0.5;
	v[3][1] = bottom + 1.5;
	polf2(4, v);
    
	/*Draw rest of checkmark*/
	v[0][0] = left + (right - left) / 3 + 1.5;
	v[0][1] = bottom + 1.5;
	v[1][0] = left + (right - left) / 3 - 0.5;
	v[1][1] = bottom + 1.5;
	v[2][0] = right - 1.5;
	v[2][1] = top - 1.5;
	polf2(3, v);
    }
    else if (drawingMode == DRAW_POSTSCRIPT && psFile)
    {
	fprintf(psFile, "%f setgray\n", PSColor());
	fprintf(psFile,
		"%.1f %.1f moveto %.1f %.1f lineto %.1f %.1f lineto %.1f %.1f lineto closepath fill\n",
		left + 1.5, (top + bottom) / 2 - 0.5, left + 2.5, (top + bottom) / 2 + 1.5, 
		left + (right - left) / 3 + 1.5, bottom + 1.5, left + (right - left) / 3 - 0.5, 
		bottom + 1.5);
	fprintf(psFile, "%.1f %.1f moveto %.1f %.1f lineto %.1f %.1f lineto closepath fill\n", 
		left + (right - left) / 3 + 1.5, bottom + 1.5, left + (right - left) / 3 - 0.5, 
		bottom + 1.5, right - 1.5, top - 1.5);
    }
#endif /*GRAPHICS */
}

void	DrawMarkerX(left, right, bottom, top)
int	left, right, bottom, top;
{
#ifdef GRAPHICS
    Coord v[4][2];

    SetUIColor(UITEXT);
    /*Draw part of button 'X'*/
    v[0][0] = left + 1.5;
    v[0][1] = bottom + 2.5;
    v[1][0] = left + 2.5;
    v[1][1] = bottom + 1.5;
    v[2][0] = right - 1.5;
    v[2][1] = top - 2.5;
    v[3][0] = right - 2.5;
    v[3][1] = top - 1.5;
    polf2(4, v);

    /*Draw rest of button 'X'*/
    v[0][0] = left + 1.5;
    v[0][1] = top - 2.5;
    v[1][0] = left + 2.5;
    v[1][1] = top - 1.5;
    v[2][0] = right - 1.5;
    v[2][1] = bottom + 2.5;
    v[3][0] = right - 2.5;
    v[3][1] = bottom + 1.5;
    polf2(4, v);
#endif /*GRAPHICS */
}

#ifdef PROTO
void DrawCtlLeft(int left, int right, int bottom, int top, int uiColor)
#else
void DrawCtlLeft(left, right, bottom, top, uiColor)
int left, right, bottom, top;
Bool highlight;
#endif
{
#ifdef GRAPHICS
    float a, b, c, d;

    a = left - 0.5 + 1.4142 * EDGE;
    b = left - 0.5 + 0.4142 * EDGE + (top - bottom) / 2;
    c = (top + bottom) / 2;
    d = (top - bottom) / 2;

    /* bottom */
    SetUIColor(UIBOTTOMEDGE);
    FillRealHex(right, bottom, left + d, bottom, left, c, a, c, b, bottom + EDGE, right - EDGE, bottom + EDGE);

    /* top */
    SetUIColor(UITOPEDGE);
    FillRealHex(a, c, left, c, left + d, top, right, top, right - EDGE, top - EDGE, b, top - EDGE);

    /* right */
    SetUIColor(UIRIGHTEDGE);
    FillRealQuad(right, top, right - EDGE, top - EDGE, right - EDGE, bottom + EDGE, right, bottom);

    /* surface */
    SetUIColor(uiColor);
    FillRealQuint(right - EDGE, bottom + EDGE, b, bottom + EDGE, a, c, b, top - EDGE, right - EDGE, top - EDGE);
#endif
}

#ifdef PROTO
void DrawCtlRight(int left, int right, int bottom, int top, int uiColor)
#else
void DrawCtlRight(left, right, bottom, top, uiColor)
int left, right, bottom, top;
Bool highlight;
#endif
{
#ifdef GRAPHICS
    float a, b, c, d;

    a = right + 0.5 - 1.4142 * EDGE;
    b = right + 0.5 - 0.4142 * EDGE - (top - bottom) / 2;
    c = (top + bottom) / 2;
    d = (top - bottom) / 2;

    /* bottom */
    SetUIColor(UIBOTTOMEDGE);
    FillRealHex(right, c, right - d, bottom, left, bottom, left + EDGE, bottom + EDGE, b, bottom + EDGE, a, c);

    /* top */
    SetUIColor(UITOPEDGE);
    FillRealHex(right, c, a, c, b, top - EDGE, left + EDGE, top - EDGE, left, top, right - d, top);

    /* left */
    SetUIColor(UILEFTEDGE);
    FillRealQuad(left, bottom, left, top, left + EDGE, top - EDGE, left + EDGE, bottom + EDGE);

    /* surface */
    SetUIColor(uiColor);
    FillRealQuint(a, c, b, bottom + EDGE, left + EDGE, bottom + EDGE, left + EDGE, top - EDGE, b, top - EDGE);
#endif
}

#ifdef PROTO
void DrawCtlUp(int left, int right, int bottom, int top, int uiColor)
#else
void DrawCtlUp(left, right, bottom, top, uiColor)
int left, right, bottom, top;
Bool highlight;
#endif
{
#ifdef GRAPHICS
    float a, b, c, d;

    a = top - 1.4142 * EDGE + 0.5;
    b = top - 0.4142 * EDGE - (right - left) /2;
    c = (right + left) / 2;
    d = (right - left) / 2;

    /* left */
    SetUIColor(UILEFTEDGE);
    FillRealHex(c, top, c, a, left + EDGE, b, left + EDGE, bottom + EDGE, left, bottom, left, top - d);

    /* right */
    SetUIColor(UIRIGHTEDGE);
    FillRealHex(c, top, right, top - d, right, bottom, right - EDGE, bottom + EDGE, right - EDGE, b, c, a);

    /* bottom */
    SetUIColor(UIBOTTOMEDGE);
    FillRealQuad(right, bottom, left, bottom, left + EDGE, bottom + EDGE, right - EDGE, bottom + EDGE);

    /* surface */
    SetUIColor(uiColor);
    FillRealQuint(c, a, right - EDGE, b, right - EDGE, bottom + EDGE, left + EDGE, bottom + EDGE, left + EDGE, b);
#endif
}

#ifdef PROTO
void DrawCtlDown(int left, int right, int bottom, int top, int uiColor)
#else
void DrawCtlDown(left, right, bottom, top, uiColor)
int left, right, bottom, top;
Bool highlight;
#endif
{
#ifdef GRAPHICS
    float a, b, c, d;

    a = bottom + 1.4142 * EDGE - 0.5;
    b = bottom + 0.4142 * EDGE - (right - left) /2;
    c = (right + left) / 2;
    d = (right - left) / 2;

    /* left */
    SetUIColor(UILEFTEDGE);
    FillRealHex(c, bottom, left, bottom + d, left, top, left + EDGE, top - EDGE, left + EDGE, b, c, a);

    /* right */
    SetUIColor(UIRIGHTEDGE);
    FillRealHex(c, bottom, c, a, right - EDGE, b, right - EDGE, top - EDGE, right, top, right, bottom + d);

    /* top */
    SetUIColor(UITOPEDGE);
    FillRealQuad(right, top, right - EDGE, top - EDGE, left + EDGE, top - EDGE, left, top);

    /* surface */
    SetUIColor(uiColor);
    FillRealQuint(c, a, left + EDGE, b, left + EDGE, top - EDGE, right - EDGE, top - EDGE, right - EDGE, b);
#endif
}

#ifdef PROTO
void SavePSImage(FILE *psFile, Pixel *imageBuffer, int left, int right, int bottom, int top)
#else
void SavePSImage(psFile, imageBuffer, left, right, bottom, top)
FILE *psFile;
Pixel *imageBuffer;
int left;
int right;
int bottom;
int top;
#endif
/*Saves an image in imageBuffer within left, right, bottom, top into psFile*/
{
    real y, dummy;
    int iVal;
    long k;
    int pixWrap;
    long nPixels;
    long i, j, ip, jp;
    long width, height;


#define PIXPERLINE	10

#define SUBSAMPLE	3

    width = right - left;
    height = top - bottom;

#ifdef COLORPOST
    /*Color image.  Do stuff before pixels*/
    fprintf(psFile, "%% Color Space image within %d %d %d %d\n",
		left, right, bottom, top);
    fprintf(psFile, "%d %d moveto\n", left, bottom);
    fprintf(psFile, "/imgstr %d string def\n", 3 * width);
    fprintf(psFile, "%d %d %d matrix \n", right - left, top - bottom, 8);

    /*Do pixels*/
    nPixels = width * height;
    pixWrap = 0;
    fprintf(psFile, "{currentfile imgstr readhexstring pop} false 3 colorimage\n");
    for (k = 0; k < nPixels; ++k)
    {
	fprintf(psFile, "%02X%02X%02X%s",
		LinToGamma[imageBuffer[k] . red],
		LinToGamma[imageBuffer[k] . green],
		LinToGamma[imageBuffer[k] . blue],
		(++pixWrap) % PIXPERLINE ? " " : "\n");
    }
    fprintf(psFile, "\n\n");
#else
    /*B/W image.  Do stuff before pixels*/
    fprintf(psFile, "%% B/W Space image within %d %d %d %d\n",
		left, right, bottom, top);
#ifdef SUBSAMPLE
    fprintf(psFile, "/imgstr %d string def\n", width / SUBSAMPLE);
    fprintf(psFile, "%d %d %d\n", width / SUBSAMPLE, height / SUBSAMPLE, 8);
    fprintf(psFile, "%d %d matrix translate\n",
		-left, -bottom);
    fprintf(psFile, "%lg %lg matrix scale\n",
		1.0 / (double) SUBSAMPLE, 1.0 / (double) SUBSAMPLE);
    fprintf(psFile, " matrix concatmatrix\n");
#else
    fprintf(psFile, "/imgstr %d string def\n", right - left);
    fprintf(psFile, "%d %d %d %d %d matrix translate\n",
	right - left, top - bottom, 8, -left, -bottom);
#endif

#ifdef SUBSAMPLE
    /*Do pixels*/
    nPixels = (right - left) * (top - bottom);
    pixWrap = 0;
    fprintf(psFile, "{currentfile imgstr readhexstring pop} image\n");


    for (j = 0; j < height; j += SUBSAMPLE)
    {
	for (i = 0; i < width; i += SUBSAMPLE)
	{
	    real avgPixel;

	    avgPixel = 0.0;

	    /*Calculate an average pixel*/
	    for (jp = j; jp < j + SUBSAMPLE; ++jp)
	    {
		for (ip = i; ip < i + SUBSAMPLE; ++ip)
		{
		    k = ip + jp * width;

		    RGB2YIQ(&y, &dummy, &dummy,
			imageBuffer[k] . red / 255.0,
			imageBuffer[k] . green / 255.0,
			imageBuffer[k] . blue / 255.0);

		    avgPixel += y;
		}
	    }
	    avgPixel /= (real) SUBSAMPLE;
	    avgPixel /= (real) SUBSAMPLE;

	    iVal = avgPixel * 255.0;
	    if (iVal < 0) iVal = 0;
	    if (iVal > 255) iVal = 255;
	    fprintf(psFile, "%02X%s", LinToGamma[iVal],
		(++pixWrap) % PIXPERLINE ? " " : "\n");
	}
    }

    fprintf(psFile, "\n\n");
#else
    /*Do pixels*/
    nPixels = (right - left) * (top - bottom);
    pixWrap = 0;
    fprintf(psFile, "{currentfile imgstr readhexstring pop} image\n");
    for (k = 0; k < nPixels; ++k)
    {
	RGB2YIQ(&y, &dummy, &dummy,
		imageBuffer[k] . red / 255.0,
		imageBuffer[k] . green / 255.0,
		imageBuffer[k] . blue / 255.0);
	iVal = y * 255.0;
	fprintf(psFile, "%02X%s", LinToGamma[iVal],
		(++pixWrap) % PIXPERLINE ? " " : "\n");
    }
    fprintf(psFile, "\n\n");
#endif

#endif

#undef PIXPERLINE

}

/*
 * Icons in eps files 10/28/92
 * In order to make the eps file of a window self contained, a bit-mapped
 * font of just the icons used in that window is defined in the file. In PS
 * drawing mode, RegisterIconUsed keeps a list of the icon numbers used.
 * It returns the index of the icon in the list. EndDrawing uses the list
 * to create the font definition. If there are any icons in the window, the
 * file must be rewritten with the font definition in the header. The font
 * definition is generated by GenIconDef() in ScianIcons.c.
 */

#define WINFRAMEWID 6
#define WINTITLEHT  20
#define WINTITLEFONT "Helvetica-BoldOblique"

#ifdef PROTO
void BeginDrawing(char *name, int left, int right, int bottom, int top)
#else
void BeginDrawing(name, left, right, bottom, top)
char *name;			/*Window title*/
int left, right, bottom, top;	/*Coordinates of window INTERIOR*/
#endif
{
#ifdef GRAPHICS
    psFile = tmpfile();
    if (drawingMode == DRAW_POSTSCRIPT && psFile)
    {
	struct timeval date;

	if (!(selWinInfo->flags & WINNOFRAME))
	{
	    right += 2*WINFRAMEWID;
	    top += 2*WINFRAMEWID + WINTITLEHT;
	}
        gettimeofday(&date, (struct timezone *)0);
	
	/* "normalize" bounds */
	right -= left;
	top -= bottom;

	/* initialize counters */
	numFontsUsed = 0;
	numIconsUsed = 0;

        /* write EPS header */
        fprintf(psFile,
"\
%%!PS-Adobe-2.0 EPSF-2.0\n\
%%%%Title: %s\n\
%%%%Creator: SciAn\n\
%%%%CreationDate: %s\
%%%%For: %s\n\
%%%%DocumentFonts: (atend)\n\
%%%%BoundingBox: 0 0 %d %d\n\
%%%%EndComments\n\
save\n\n",	/* NOTE: icon font def is inserted after first blank line of file */
	    name, ctime(&date.tv_sec), getenv("USER"),
	    (int) ((right + 1)/2), (int) ((top + 1)/2));
    
	fprintf(psFile, 
"/resetclip {matrix currentmatrix currentfont currentlinewidth\n\
grestore gsave setlinewidth setfont setmatrix } def\n\
\n\
currentscreen 3 1 roll pop pop 75 0 3 -1 roll setscreen\n\
gsave\n\
1 setlinewidth\n\
.5 .5 scale\n\n");

	if (!(selWinInfo -> flags & WINNOFRAME))
	{
	    /* draw a generic window frame with title only */
	    fprintf(psFile,
"newpath 0 0 moveto 0 %d lineto %d %d lineto %d 0 lineto closepath stroke\n", 
		top, right, top, right);
	    fprintf(psFile, 
"newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto closepath stroke\n", 
		WINFRAMEWID - 1, WINFRAMEWID - 1,
		WINFRAMEWID - 1, top - WINFRAMEWID + 1,
		right - WINFRAMEWID + 1, top - WINFRAMEWID + 1,
		right - WINFRAMEWID + 1, WINFRAMEWID - 1);
	    fprintf(psFile, "newpath %d %d moveto %d %d lineto stroke\n", 
		WINFRAMEWID - 1, top - WINFRAMEWID - WINTITLEHT + 1, 
		right - WINFRAMEWID + 1, top - WINFRAMEWID - WINTITLEHT + 1);
	    SetupFont(WINTITLEFONT, 12);
	    fprintf(psFile, "%d %d moveto (%s) show\n", 
		WINFRAMEWID + 20, top - WINFRAMEWID - WINTITLEHT + 5, show(name));
	    fprintf(psFile, "%d %d translate\n", WINFRAMEWID,  WINFRAMEWID);
	    RegisterFontUsed(WINTITLEFONT);
	}
    }
#endif
}

void EndDrawing()
{
#ifdef GRAPHICS
    if (drawingMode == DRAW_POSTSCRIPT && psFile && drawFile)
    {
	char buf[256];
        int i;
	
	/* copy header from temp file (copies to first blank line) */
	rewind(psFile);
	while (fgets(buf, 256, psFile))
	{
	    fputs(buf, drawFile);
	    if (*buf == '\n') break;
	}
	
	/* generate font of icons used, if needed */
	GenIconDef(drawFile);
	
	/* copy the rest of the temp file */
	while (fgets(buf, 256, psFile))
	{
	    fputs(buf, drawFile);
	}
	fclose(psFile);

        /* write PostScript trailer -- list fonts used */
        fprintf(drawFile, "\nrestore\n\n%%%%Trailer\n%%%%DocumentFonts:");
	for (i=0; i<numFontsUsed; ++i)
        {
            fprintf(drawFile, " %s", fontsUsed[i]);

	    /* free the fontsUsed string space */
            free(fontsUsed[i]);
            fontsUsed[i] = NIL;
        }
        fprintf(drawFile, "\n");
    }
#endif
}

#ifdef PROTO
int RegisterIconUsed(int icon)
#else
int RegisterIconUsed(icon)
int icon;
#endif
{
#ifdef GRAPHICS
    int i;

    /* check list of icons used */
    for (i = 0; i < numIconsUsed; ++i)
    {
        if (icon == iconsUsed[i]) return i; /* already got it */
    }
    if (numIconsUsed >= 32)
    {
        ReportError("RegisterIconUsed","Too many different icons!");
        return -1;
    }
    iconsUsed[numIconsUsed] = icon;
    return numIconsUsed++;
#else
    return 0;
#endif
}

void EraseAll()
/*Erases everything*/
{
    SetUIColor(UIBLACK);
    clear();
}

void InitDraw()
/*Initializes the drawing system*/
{
    int k;

    /*No window at the beginning*/
    curDrawingStateIndex = 0;
    CURSTATE . window = 0;
    CURSTATE . initialWindow = false;
    for (k = 0; k < 4; ++k)
    {
	CURSTATE . screenMask[k] = 0;
	CURSTATE . viewport[k] = 0;
    }
    for (k = 0; k < 2; ++k)
    {
	CURSTATE . origin[k] = 0;
	CURSTATE . translation[k] = 0;
    }
}

void KillDraw()
{
}
