/********** Copyright 1990 Regents of the University of California. All rights reserved. **********/ #include "ngspice.h" #include "ftegraph.h" #include "ftedev.h" #include "fteinput.h" #include "cpdefs.h" /* for VT_STRING */ #include "ftedefs.h" /* for mylog() */ #include "display.h" /* static declarations */ static int gen_DatatoScreen(GRAPH *graph, double x, double y, int *screenx, int *screeny); static int gen_Input(REQUEST *request, RESPONSE *response); static int nop(void); static int nodev(void); #ifndef X_DISPLAY_MISSING extern int X11_Init(void), X11_NewViewport(GRAPH *graph), X11_Close(void), X11_Clear(void), X11_DrawLine(int x1, int y1, int x2, int y2), X11_Arc(int x0, int y0, int radius, double theta1, double theta2), X11_Text(char *text, int x, int y), X11_DefineColor(int colorid, double red, double green, double blue), X11_DefineLinestyle(int linestyleid, int mask), X11_SetLinestyle(int linestyleid), X11_SetColor(int colorid), X11_Update(void), X11_Input(REQUEST *request, RESPONSE *response); #endif extern int Plt5_Init(void), Plt5_NewViewport(GRAPH *graph), Plt5_Close(void), Plt5_Clear(void), Plt5_DrawLine(int x1, int y1, int x2, int y2), Plt5_Arc(int x0, int y0, int radius, double theta1, double theta2), Plt5_Text(char *text, int x, int y), Plt5_DefineLinestyle(), Plt5_SetLinestyle(int linestyleid), Plt5_SetColor(int colorid), Plt5_Update(void); extern int PS_Init(void), PS_NewViewport(GRAPH *graph), PS_Close(void), PS_Clear(void), PS_DrawLine(int x1, int y1, int x2, int y2), PS_Arc(int x0, int y0, int r, double theta1, double theta2), PS_Text(char *text, int x, int y), PS_DefineLinestyle(), PS_SetLinestyle(int linestyleid), PS_SetColor(int colorid), PS_Update(void); DISPDEVICE device[] = { {"error", 0, 0, 0, 0, 0, 0, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, gen_Input, nop,}, #ifndef X_DISPLAY_MISSING {"X11", 0, 0, 1024, 864, 0, 0, X11_Init, X11_NewViewport, X11_Close, X11_Clear, X11_DrawLine, X11_Arc, X11_Text, X11_DefineColor, X11_DefineLinestyle, X11_SetLinestyle, X11_SetColor, X11_Update, nodev, nodev, nodev, X11_Input, gen_DatatoScreen,}, #endif {"plot5", 0, 0, 1000, 1000, 0, 0, Plt5_Init, Plt5_NewViewport, Plt5_Close, Plt5_Clear, Plt5_DrawLine, Plt5_Arc, Plt5_Text, nodev, nodev, Plt5_SetLinestyle, Plt5_SetColor, Plt5_Update, nodev, nodev, nodev, nodev, gen_DatatoScreen,}, {"postscript", 0, 0, 1000, 1000, 0, 0, PS_Init, PS_NewViewport, PS_Close, PS_Clear, PS_DrawLine, PS_Arc, PS_Text, nodev, nodev, PS_SetLinestyle, PS_SetColor, PS_Update, nodev, nodev, nodev, nodev, gen_DatatoScreen,}, {"printf", 0, 0, 24, 80, 0, 0, nodev, nodev, nodev, nodev, nodev, nodev, nodev, nodev, nodev, nodev, nodev, nodev, nodev, nodev, nodev, gen_Input, nodev,}, }; DISPDEVICE *dispdev = device + NUMELEMS(device) - 1; #define XtNumber(arr) (sizeof(arr) / sizeof(arr[0])) extern void internalerror (char *message); extern void externalerror (char *message); DISPDEVICE *FindDev(char *name) { int i; for (i=0; i < XtNumber(device); i++) { if (!strcmp(name, device[i].name)) { return(&device[i]); } } sprintf(ErrorMessage, "Can't find device %s.", name); internalerror(ErrorMessage); return(&device[0]); } void DevInit(void) { char buf[128]; /* note: do better determination */ /* dumb tradition that got passed on from gi_interface to do compile time determination */ dispdev = NULL; #ifndef X_DISPLAY_MISSING /* determine display type */ if (getenv("DISPLAY") || cp_getvar("display", VT_STRING, buf)) { #ifndef X_DISPLAY_MISSING dispdev = FindDev("X11"); #endif } #endif if (!dispdev) { externalerror( "no graphics interface; please check compiling instructions"); dispdev = FindDev("error"); } else if ((*(dispdev->Init))()) { fprintf(cp_err, "Warning: can't initialize display device for graphics.\n"); dispdev = FindDev("error"); } } /* NewViewport is responsible for filling in graph->viewport */ int NewViewport(GRAPH *pgraph) { return (*(dispdev->NewViewport))(pgraph); } void DevClose(void) { (*(dispdev->Close))(); } void DevClear(void) { (*(dispdev->Clear))(); } void DrawLine(int x1, int y1, int x2, int y2) { (*(dispdev->DrawLine))(x1, y1, x2, y2); } void Arc(int x0, int y0, int radius, double theta1, double theta2) { (*(dispdev->Arc))(x0, y0, radius, theta1, theta2); } void Text(char *text, int x, int y) { (*(dispdev->Text))(text, x, y); } void DefineColor(int colorid, double red, double green, double blue) { (*(dispdev->DefineColor))(colorid, red, green, blue); } void DefineLinestyle(int linestyleid, int mask) { (*(dispdev->DefineLinestyle))(linestyleid, mask); } void SetLinestyle(int linestyleid) { (*(dispdev->SetLinestyle))(linestyleid); } void SetColor(int colorid) { (*(dispdev->SetColor))(colorid); } void Update(void) { if (dispdev) (*(dispdev->Update))(); } /* note: screen coordinates are relative to window so need to add viewport offsets */ static int gen_DatatoScreen(GRAPH *graph, double x, double y, int *screenx, int *screeny) { double low, high; /* note: may want to cache datawindowsize/viewportsize */ /* done */ /* note: think this out---Is 1 part of the viewport? Do we handle this correctly? */ /* have to handle several types of grids */ /* note: we can't compensate for X's demented y-coordinate system here since the grid routines use DrawLine w/o calling this routine */ if ((graph->grid.gridtype == GRID_LOGLOG) || (graph->grid.gridtype == GRID_YLOG)) { low = mylog10(graph->datawindow.ymin); high = mylog10(graph->datawindow.ymax); *screeny = (mylog10(y) - low) / (high - low) * graph->viewport.height + 0.5 + graph->viewportyoff; } else { *screeny = ((y - graph->datawindow.ymin) / graph->aspectratioy) + 0.5 + graph->viewportyoff; } if ((graph->grid.gridtype == GRID_LOGLOG) || (graph->grid.gridtype == GRID_XLOG)) { low = mylog10(graph->datawindow.xmin); high = mylog10(graph->datawindow.xmax); *screenx = (mylog10(x) - low) / (high - low) * graph->viewport.width + 0.5 + graph ->viewportxoff; } else { *screenx = (x - graph->datawindow.xmin) / graph->aspectratiox + 0.5 + graph ->viewportxoff; } } void DatatoScreen(GRAPH *graph, double x, double y, int *screenx, int *screeny) { (*(dispdev->DatatoScreen))(graph, x, y, screenx, screeny); } void Input(REQUEST *request, RESPONSE *response) { (*(dispdev->Input))(request, response); } static int gen_Input(REQUEST *request, RESPONSE *response) { switch (request->option) { case char_option: response->reply.ch = inchar(request->fp); response->option = request->option; break; default: /* just ignore, since we don't want a million error messages */ if (response) response->option = error_option; break; } } /* no operation, do nothing */ static int nop(void) { return(1); /* so NewViewport will fail */ } static int nodev(void) { sprintf(ErrorMessage, "This operation is not defined for display type %s.", dispdev->name); internalerror(ErrorMessage); return(1); } void SaveText(GRAPH *graph, char *text, int x, int y) { struct _keyed *keyed; keyed = (struct _keyed *) calloc(1, sizeof(struct _keyed)); if (!graph->keyed) { graph->keyed = keyed; } else { keyed->next = graph->keyed; graph->keyed = keyed; } keyed->text = tmalloc(strlen(text) + 1); strcpy(keyed->text, text); keyed->x = x; keyed->y = y; keyed->colorindex = graph->currentcolor; } /* if given name of a hardcopy device, finds it and switches devices if given NULL, switches back */ int DevSwitch(char *devname) { static DISPDEVICE *lastdev = NULL; if (devname != NULL) { if (lastdev != NULL) { internalerror("DevSwitch w/o changing back"); return (1); } lastdev = dispdev; dispdev = FindDev(devname); if (!strcmp(dispdev->name, "error")) { internalerror("no hardcopy device"); dispdev = lastdev; /* undo */ lastdev = NULL; return (1); } (*(dispdev->Init))(); } else { (*(dispdev->Close))(); dispdev = lastdev; lastdev = NULL; } return(0); }