ngspice/src/frontend/display.c

462 lines
12 KiB
C

/**********
Copyright 1990 Regents of the University of California. All rights reserved.
**********/
#include "ngspice/ngspice.h"
#include "ngspice/graph.h"
#include "ngspice/ftedev.h"
#include "ngspice/fteinput.h"
#include "ngspice/cpdefs.h"
#include "ngspice/ftedefs.h"
#ifdef TCL_MODULE
#include "ngspice/tclspice.h"
#endif
#include "display.h"
#include "variable.h"
static void gen_DatatoScreen(GRAPH *graph, double x, double y, int *screenx, int *screeny);
static int gen_Input(REQUEST *request, RESPONSE *response);
static int nop(void);
#define NOP ((void *)nop)
static int nodev(void);
#define NODEV ((void *)nodev)
#ifndef X_DISPLAY_MISSING
#include "plotting/x11.h"
#endif
#ifdef HAS_WINGUI /* Graphic-IO under MS Windows */
#include "wdisp/windisp.h"
//#include "wdisp/winprint.h"
#endif
#include "plotting/plot5.h"
#include "postsc.h"
#include "hpgl.h"
#include "svg.h"
DISPDEVICE device[] = {
{ "error", 0, 0, 0, 0, 0, 0,
(disp_fn_Init_t *) NOP, (disp_fn_NewViewport_t *) NOP,
(disp_fn_Close_t *) NOP, (disp_fn_Clear_t *) NOP,
(disp_fn_DrawLine_t *) NOP, (disp_fn_Arc_t *) NOP, (disp_fn_Text_t *) NOP,
(disp_fn_DefineColor_t *) NOP, (disp_fn_DefineLinestyle_t *) NOP,
(disp_fn_SetLinestyle_t *) NOP, (disp_fn_SetColor_t *) NOP, (disp_fn_Update_t *) NOP, (disp_fn_Finalize_t *) NOP,
(disp_fn_Track_t *) NOP, (disp_fn_MakeMenu_t *) NOP, (disp_fn_MakeDialog_t *) NOP, gen_Input,
(disp_fn_DatatoScreen_t *) 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, (disp_fn_Finalize_t*) NOP,
(disp_fn_Track_t *) NODEV, (disp_fn_MakeMenu_t *) NODEV, (disp_fn_MakeDialog_t *) NODEV, X11_Input,
gen_DatatoScreen,},
#endif
#ifdef HAS_WINGUI /* Graphic-IO under MS Windows */
{ "Windows", 0, 0, 1000, 1000, 0, 0,
WIN_Init, WIN_NewViewport,
WIN_Close, WIN_Clear,
WIN_DrawLine, WIN_Arc, WIN_Text,
WIN_DefineColor, WIN_DefineLinestyle,
WIN_SetLinestyle, WIN_SetColor, WIN_Update, (disp_fn_Finalize_t*) NOP,
(disp_fn_Track_t *) NODEV, (disp_fn_MakeMenu_t *) NODEV, (disp_fn_MakeDialog_t *) NODEV, gen_Input,
gen_DatatoScreen, }, /* WIN_DiagramReady */
/* Warning: name "WinPrint" do not change! */
{ "WinPrint", 0, 0, 1000, 1000, 0, 0,
WPRINT_Init, WPRINT_NewViewport,
WPRINT_Close, WPRINT_Clear,
WPRINT_DrawLine, WPRINT_Arc, WPRINT_Text,
WPRINT_DefineColor, WPRINT_DefineLinestyle,
WPRINT_SetLinestyle, WPRINT_SetColor, WPRINT_Update, (disp_fn_Finalize_t*) NOP,
(disp_fn_Track_t *) NODEV, (disp_fn_MakeMenu_t *) NODEV, (disp_fn_MakeDialog_t *) NODEV, (disp_fn_Input_t *) NODEV,
gen_DatatoScreen, }, /* WPRINT_DiagramReady */
#endif
#ifdef TCL_MODULE
{ "Tk", 0, 0, 1024, 864, 0, 0,
sp_Tk_Init, sp_Tk_NewViewport,
sp_Tk_Close, sp_Tk_Clear,
sp_Tk_DrawLine, sp_Tk_Arc, sp_Tk_Text,
sp_Tk_DefineColor, sp_Tk_DefineLinestyle,
sp_Tk_SetLinestyle, sp_Tk_SetColor, sp_Tk_Update, (disp_fn_Finalize_t*) NOP,
(disp_fn_Track_t *) NODEV, (disp_fn_MakeMenu_t *) NODEV, (disp_fn_MakeDialog_t *) NODEV, (disp_fn_Input_t *) NODEV,
gen_DatatoScreen, },
#endif
{ "plot5", 0, 0, 1000, 1000, 0, 0,
Plt5_Init, Plt5_NewViewport,
Plt5_Close, Plt5_Clear,
Plt5_DrawLine, Plt5_Arc, Plt5_Text,
(disp_fn_DefineColor_t *) NODEV, (disp_fn_DefineLinestyle_t *) NODEV,
Plt5_SetLinestyle, Plt5_SetColor, Plt5_Update, (disp_fn_Finalize_t*) NOP,
(disp_fn_Track_t *) NODEV, (disp_fn_MakeMenu_t *) NODEV, (disp_fn_MakeDialog_t *) NODEV, (disp_fn_Input_t *) NODEV,
gen_DatatoScreen, },
{ "postscript", 0, 0, 1000, 1000, 0, 0,
PS_Init, PS_NewViewport,
PS_Close, PS_Clear,
PS_DrawLine, PS_Arc, PS_Text,
(disp_fn_DefineColor_t *) NODEV, (disp_fn_DefineLinestyle_t *) NODEV,
PS_SetLinestyle, PS_SetColor, PS_Update, PS_Finalize,
(disp_fn_Track_t *) NODEV, (disp_fn_MakeMenu_t *) NODEV, (disp_fn_MakeDialog_t *) NODEV, (disp_fn_Input_t *) NODEV,
gen_DatatoScreen, },
{ "svg", 0, 0, 1000, 1000, 0, 0,
SVG_Init, SVG_NewViewport,
SVG_Close, SVG_Clear,
SVG_DrawLine, SVG_Arc, SVG_Text,
(disp_fn_DefineColor_t*)NODEV, (disp_fn_DefineLinestyle_t*)NODEV,
SVG_SetLinestyle, SVG_SetColor, SVG_Update, SVG_Finalize,
(disp_fn_Track_t*)NODEV, (disp_fn_MakeMenu_t*)NODEV, (disp_fn_MakeDialog_t*)NODEV, (disp_fn_Input_t*)NODEV,
gen_DatatoScreen, },
{ "hpgl", 0, 0, 1000, 1000, 0, 0,
GL_Init, GL_NewViewport,
GL_Close, GL_Clear,
GL_DrawLine, GL_Arc, GL_Text,
(disp_fn_DefineColor_t *) NODEV, (disp_fn_DefineLinestyle_t *) NODEV,
GL_SetLinestyle, GL_SetColor, GL_Update, (disp_fn_Finalize_t*) NOP,
(disp_fn_Track_t *) NODEV, (disp_fn_MakeMenu_t *) NODEV, (disp_fn_MakeDialog_t *) NODEV, (disp_fn_Input_t *) NODEV,
gen_DatatoScreen, },
{ "PrinterOnly", 0, 0, 24, 80, 0, 0,
(disp_fn_Init_t *) NODEV, (disp_fn_NewViewport_t *) NODEV,
(disp_fn_Close_t *) NOP, (disp_fn_Clear_t *) NODEV,
(disp_fn_DrawLine_t *) NODEV, (disp_fn_Arc_t *) NODEV, (disp_fn_Text_t *) NODEV,
(disp_fn_DefineColor_t *) NODEV, (disp_fn_DefineLinestyle_t *) NODEV,
(disp_fn_SetLinestyle_t *) NODEV, (disp_fn_SetColor_t *) NODEV, (disp_fn_Update_t *) NOP, (disp_fn_Finalize_t*) NOP,
(disp_fn_Track_t *) NODEV, (disp_fn_MakeMenu_t *) NODEV, (disp_fn_MakeDialog_t *) NODEV, gen_Input,
(disp_fn_DatatoScreen_t *) NODEV, },
};
DISPDEVICE *dispdev = device + NUMELEMS(device) - 1;
DISPDEVICE *
FindDev(char *name)
{
size_t i;
for (i = 0; i < NUMELEMS(device); i++)
if (strcmp(name, device[i].name) == 0)
return (device + i);
sprintf(ErrorMessage, "Can't find device %s.", name);
internalerror(ErrorMessage);
return (device + 0);
}
void
DevInit(void)
{
#ifndef X_DISPLAY_MISSING
char buf[128];
#endif
/* 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", CP_STRING, buf, sizeof(buf)))
dispdev = FindDev("X11");
#endif
#ifdef HAS_WINGUI
if (!dispdev)
dispdev = FindDev("Windows");
#endif
#ifdef TCL_MODULE
dispdev = FindDev("Tk");
#endif
if (!dispdev) {
#if !defined(HAS_WINGUI) && !defined(TCL_MODULE) && !defined(SHARED_MODULE) && (defined(_MSC_VER) || defined(__MINGW32__))
/* console application under MS Windows */
fprintf
(cp_err,
"Warning: no graphics interface!\n"
" You may use command 'gnuplot'\n"
" if GnuPlot is installed.\n");
#elif !defined(X_DISPLAY_MISSING)
externalerror
("no graphics interface;\n"
" please check if X-server is running,\n"
" or ngspice is compiled properly (see INSTALL)");
#endif
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
DevDrawLine(int x1, int y1, int x2, int y2, bool isgrid)
{
dispdev->DrawLine (x1, y1, x2, y2, isgrid);
}
void
DevDrawArc(int x0, int y0, int radius, double theta, double delta_theta, bool isgrid)
{
dispdev->DrawArc (x0, y0, radius, theta, delta_theta, isgrid);
}
void DevDrawText(const char *text, int x, int y, int angle)
{
dispdev->DrawText(text, x, y, angle);
}
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
DevUpdate(void)
{
if (dispdev)
dispdev->Update();
}
void
DevFinalize(void)
{
if (dispdev)
dispdev->Finalize();
}
/* note: screen coordinates are relative to window
so need to add viewport offsets */
static void
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 DevDrawLine 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 = (int)((mylog10(y) - low) / (high - low) * graph->viewport.height
+ 0.5 + graph->viewportyoff);
} else {
*screeny = (int)(((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 = (int)((mylog10(x) - low) / (high - low) * graph->viewport.width
+ 0.5 + graph ->viewportxoff);
} else {
*screenx = (int)((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:
if (response)
response->option = request->option;
break;
default:
/* just ignore, since we don't want a million error messages */
if (response)
response->option = error_option;
break;
}
return (0);
}
/* 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 = TMALLOC(struct _keyed, 1);
if (!graph->keyed) {
graph->keyed = keyed;
} else {
keyed->next = graph->keyed;
graph->keyed = keyed;
}
keyed->text = TMALLOC(char, 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) {
if (lastdev) {
internalerror("DevSwitch w/o changing back");
return (1);
}
lastdev = dispdev;
dispdev = FindDev(devname);
if (!strcmp(dispdev->name, "error")) {
internalerror("no hardcopy device");
/* undo */
dispdev = lastdev;
lastdev = NULL;
return (1);
}
dispdev->Init();
} else {
if (dispdev)
dispdev->Close();
dispdev = lastdev;
lastdev = NULL;
}
return (0);
}