/* * File: graphics.c * Last modified on Mon Jul 25 11:53:41 1994 by eroberts * ----------------------------------------------------- * This file is the top-level file in the implementation of the * graphics.h interface for X windows. The complete implementation * also includes the following subsidiary modules: * * glibrary.h Various low-level mathematical functions * xmanager.h Mediates communication with the X operations * xdisplay.h Performs the actual drawing operations */ #include #include #include #include #include #include #include "genlib.h" #include "gcalloc.h" #include "simpio.h" #include "strlib.h" #include "extgraph.h" #include "glibrary.h" #include "xmanager.h" #include "xcompat.h" /* * Parameters * ---------- * DefaultSize -- Default point size */ #define DefaultSize 12 /* * Type: graphicsStateT * -------------------- * This structure holds the variables that make up the graphics state. */ typedef struct graphicsStateT { double cx, cy; string font; int size; bool erase; struct graphicsStateT *link; } *graphicsStateT; /* * Type: regionStateT * ------------------ * The region assembly process has the character of a finite state * machine with the following four states: * * NoRegion Region has not yet been started * RegionStarting Region is started but no line segments yet * RegionActive First line segment appears * PenHasMoved Pen has moved during definition * * The current state determines whether other operations are legal * at that point. */ typedef enum { NoRegion, RegionStarting, RegionActive, PenHasMoved } regionStateT; /* * Global variables * ---------------- * initialized TRUE if initialization has been done * windowTitle Current window title (initialized statically) * cmdBuffer Static buffer for sending commands * regionState Current state of the region * stateStack Stack of graphicStateT blocks * cx, cy Current coordinates | These four variable * eraseMode Setting of erase flag | consititute the * textFont Current font | current graphics * pointSize Current point size | state */ static bool initialized = FALSE; static string windowTitle = "Graphics Window"; static char cmdBuffer[CommandBufferSize]; static regionStateT regionState; static graphicsStateT stateStack; static double cx, cy; static bool eraseMode; static string textFont; static int pointSize; /* Private function prototypes */ static void InitCheck(void); static void InitGraphicsState(void); /* Exported entries */ /* Section 1 -- Basic functions from graphics.h */ /* * Function: InitGraphics * ---------------------- * The implementation below hides considerable complexity underneath * the InitXHandler call. If you are trying to modify or maintain * this implementation, it is important to understand how that * function is implemented. For details, see the xhandler.c * implementation. */ void InitGraphics(void) { if (initialized) { SendCommand(ClearCmd, ""); } else { ProtectVariable(stateStack); ProtectVariable(windowTitle); ProtectVariable(textFont); InitXManager(windowTitle); initialized = TRUE; } InitGraphicsState(); SetFont("Default"); } void MovePen(double x, double y) { InitCheck(); if (regionState == RegionActive) regionState = PenHasMoved; cx = x; cy = y; } void DrawLine(double dx, double dy) { InitCheck(); switch (regionState) { case NoRegion: case RegionActive: break; case RegionStarting: regionState = RegionActive; break; case PenHasMoved: Error("Region segments must be contiguous"); } sprintf(cmdBuffer, "%g %g %g %g", cx, cy, dx, dy); SendCommand(LineCmd, cmdBuffer); cx += dx; cy += dy; } void DrawArc(double r, double start, double sweep) { DrawEllipticalArc(r, r, start, sweep); } double GetWindowWidth(void) { string line; double width; InitCheck(); SendCommand(GetWidthCmd, cmdBuffer); line = GetResponse(); width = StringToReal(line); FreeBlock(line); return (width); } double GetWindowHeight(void) { string line; double height; InitCheck(); SendCommand(GetHeightCmd, cmdBuffer); line = GetResponse(); height = StringToReal(line); FreeBlock(line); return (height); } double GetCurrentX(void) { InitCheck(); return (cx); } double GetCurrentY(void) { InitCheck(); return (cy); } /* Section 2 -- Elliptical arcs */ void DrawEllipticalArc(double rx, double ry, double start, double sweep) { double x, y; InitCheck(); switch (regionState) { case NoRegion: case RegionActive: break; case RegionStarting: regionState = RegionActive; break; case PenHasMoved: Error("Region segments must be contiguous"); } x = cx + rx * cos(Radians(start + 180)); y = cy + ry * sin(Radians(start + 180)); sprintf(cmdBuffer, "%g %g %g %g %g %g", x, y, rx, ry, start, sweep); SendCommand(ArcCmd, cmdBuffer); cx = x + rx * cos(Radians(start + sweep)); cy = y + ry * sin(Radians(start + sweep)); } /* Section 3 -- Graphical structures */ void StartFilledRegion(double grayScale) { InitCheck(); if (regionState != NoRegion) { Error("Region is already in progress"); } if (grayScale < 0 || grayScale > 1) { Error("Gray scale for regions must be between 0 and 1"); } regionState = RegionStarting; sprintf(cmdBuffer, "%g", grayScale); SendCommand(StartRegionCmd, cmdBuffer); } void EndFilledRegion(void) { InitCheck(); if (regionState == NoRegion) { Error("EndFilledRegion without StartFilledRegion"); } regionState = NoRegion; SendCommand(EndRegionCmd, ""); } /* Section 4 -- String functions */ void DrawTextString(string text) { InitCheck(); if (regionState != NoRegion) { Error("Text strings are illegal inside a region"); } if (strlen(text) > MaxTextString) { Error("Text string too long"); } sprintf(cmdBuffer, "%g %g %s", cx, cy, text); SendCommand(TextCmd, cmdBuffer); cx += TextStringWidth(text); } double TextStringWidth(string text) { string line; double result; InitCheck(); if (strlen(text) > MaxTextString) { Error("Text string too long"); } sprintf(cmdBuffer, "%s", text); SendCommand(WidthCmd, cmdBuffer); line = GetResponse(); result = StringToReal(line); FreeBlock(line); return (result); } void SetFont(string font) { InitCheck(); if (strlen(font) > MaxFontName) Error("Font name too long"); textFont = font; SetPointSize(pointSize); } string GetFont(void) { InitCheck(); return (CopyString(textFont)); } void SetPointSize(int size) { string line; InitCheck(); sprintf(cmdBuffer, "%d %s", size, textFont); SendCommand(SetFontCmd, cmdBuffer); line = GetResponse(); pointSize = atoi(line); textFont = CopyString(line + FindChar(' ', line, 0) + 1); } int GetPointSize(void) { InitCheck(); return (pointSize); } /* Section 5 -- Miscellaneous functions */ void SetEraseMode(bool mode) { InitCheck(); eraseMode = mode; sprintf(cmdBuffer, "%d", (int) mode); SendCommand(SetEraseCmd, cmdBuffer); } bool GetEraseMode(void) { InitCheck(); return (eraseMode); } void SetWindowTitle(string title) { windowTitle = CopyString(title); if (initialized) { sprintf(cmdBuffer, "%s", windowTitle); SendCommand(SetTitleCmd, cmdBuffer); } } string GetWindowTitle(void) { return (CopyString(windowTitle)); } void UpdateDisplay(void) { int cnt; InitCheck(); SendCommand(UpdateCmd, ""); } void Pause(double seconds) { if (initialized) UpdateDisplay(); usleep((unsigned) (seconds * 1000000)); } void SaveGraphicsState(void) { graphicsStateT sb; InitCheck(); sb = New(graphicsStateT); sb->cx = cx; sb->cy = cy; sb->font = textFont; sb->size = pointSize; sb->erase = eraseMode; sb->link = stateStack; stateStack = sb; } void RestoreGraphicsState(void) { graphicsStateT sb; InitCheck(); if (stateStack == NULL) { Error("RestoreGraphicsState called before SaveGraphicsState"); } sb = stateStack; cx = sb->cx; cy = sb->cy; textFont = sb->font; pointSize = sb->size; eraseMode = sb->erase; stateStack = sb->link; FreeBlock(sb); } /* Private functions */ /* * Function: InitCheck * Usage: InitCheck(); * ------------------- * This function merely ensures that the package has been * initialized before the client functions are called. */ static void InitCheck(void) { if (!initialized) Error("InitGraphics has not been called"); } /* * Function: InitGraphicsState * Usage: InitGraphicsState(); * --------------------------- * This function initializes the graphics state elements to * their default values. */ static void InitGraphicsState(void) { cx = cy = 0; eraseMode = FALSE; textFont = "Default"; pointSize = DefaultSize; stateStack = NULL; regionState = NoRegion; }