1280 lines
32 KiB
C
1280 lines
32 KiB
C
/* $Header$ */
|
||
/*
|
||
* xgraph - A Simple Plotter for X
|
||
*
|
||
* David Harrison
|
||
* University of California, Berkeley
|
||
* 1986, 1987, 1988, 1989
|
||
*
|
||
* Please see copyright.h concerning the formal reproduction rights
|
||
* of this software.
|
||
*
|
||
* $Log$
|
||
* Revision 1.1 2004-01-25 09:00:49 pnenzi
|
||
*
|
||
* Added xgraph plotting program.
|
||
*
|
||
* Revision 1.3 1999/12/19 00:52:07 heideman
|
||
* warning suppresion, slightly different flot ahndling
|
||
*
|
||
* Revision 1.2 1999/12/03 23:17:46 heideman
|
||
* apply xgraph_no_animation.patch
|
||
*
|
||
* Revision 1.1.1.1 1999/12/03 23:15:52 heideman
|
||
* xgraph-12.0
|
||
*
|
||
*/
|
||
#ifndef lint
|
||
static char rcsid[] = "$Id$";
|
||
#endif
|
||
|
||
#include "copyright.h"
|
||
#include <stdio.h>
|
||
#include <math.h>
|
||
#include <pwd.h>
|
||
#include <ctype.h>
|
||
#include "xgraph.h"
|
||
#include "xtb.h"
|
||
#include "hard_devices.h"
|
||
#include "params.h"
|
||
|
||
|
||
extern void init_X();
|
||
extern void do_error();
|
||
|
||
#ifdef DO_DER
|
||
extern void Bounds();
|
||
#endif /* DO_DER */
|
||
|
||
static char *tildeExpand();
|
||
static void ReverseIt();
|
||
static void Traverse();
|
||
static int XErrHandler();
|
||
|
||
|
||
NewDataSet PlotData[MAXSETS],
|
||
DataD1[MAXSETS],
|
||
DataD2[MAXSETS];
|
||
|
||
XSegment *Xsegs[2]; /* Point space for X */
|
||
|
||
/* Basic transformation stuff */
|
||
double llx,
|
||
lly,
|
||
urx,
|
||
ury; /* Bounding box of all data */
|
||
|
||
static XContext win_context = (XContext) 0;
|
||
|
||
/* Other globally set defaults */
|
||
|
||
Display *disp; /* Open display */
|
||
Visual *vis; /* Standard visual */
|
||
Colormap cmap; /* Standard colormap */
|
||
int screen; /* Screen number */
|
||
int depth; /* Depth of screen */
|
||
|
||
int numFiles = 0; /* Number of input files */
|
||
char *inFileNames[MAXSETS]; /* File names */
|
||
|
||
/* Total number of active windows */
|
||
int Num_Windows = 0;
|
||
char *Prog_Name;
|
||
char *disp_name;
|
||
|
||
|
||
|
||
main(argc, argv)
|
||
int argc;
|
||
char *argv[];
|
||
|
||
/*
|
||
* This sets up the hard-wired defaults and reads the X defaults.
|
||
* The command line format is: xgraph [host:display].
|
||
*/
|
||
{
|
||
Window primary,
|
||
NewWindow();
|
||
XEvent theEvent;
|
||
LocalWin *win_info;
|
||
Cursor zoomCursor;
|
||
FILE *strm;
|
||
XColor fg_color,
|
||
bg_color;
|
||
char keys[MAXKEYS];
|
||
int nbytes,
|
||
idx,
|
||
maxitems = 0,
|
||
flags;
|
||
int errs = 0;
|
||
|
||
/* Open up new display */
|
||
Prog_Name = argv[0];
|
||
disp_name = "";
|
||
|
||
/* Parse the argument list looking for input files */
|
||
flags = ParseArgs(argc, argv, 0);
|
||
|
||
if (flags == D_XWINDOWS) {
|
||
disp = XOpenDisplay(disp_name);
|
||
if (!disp) {
|
||
(void) fprintf(stderr,
|
||
"%s: cannot open display `%s'\n",
|
||
argv[0], disp_name);
|
||
exit(1);
|
||
}
|
||
XSetErrorHandler(XErrHandler);
|
||
}
|
||
|
||
/* Set up hard-wired defaults and allocate spaces */
|
||
InitSets(flags);
|
||
|
||
/* Read X defaults and override hard-coded defaults */
|
||
if (PM_INT("Output Device") == D_XWINDOWS)
|
||
ReadDefaults();
|
||
|
||
|
||
/* Read the data into the data sets */
|
||
llx = lly = MAXFLOAT;
|
||
urx = ury = -MAXFLOAT;
|
||
for (idx = 0; idx < numFiles; idx++) {
|
||
strm = fopen(inFileNames[idx], "r");
|
||
if (!strm) {
|
||
(void) fprintf(stderr, "Warning: cannot open file `%s'\n",
|
||
inFileNames[idx]);
|
||
}
|
||
else {
|
||
if ((maxitems = ReadData(strm, inFileNames[idx])) < 0) {
|
||
errs++;
|
||
}
|
||
(void) fclose(strm);
|
||
}
|
||
}
|
||
if (!numFiles) {
|
||
if ((maxitems = ReadData(stdin, (char *) 0)) < 0) {
|
||
errs++;
|
||
}
|
||
}
|
||
if (errs) {
|
||
(void) fprintf(stderr, "Problems found with input data.\n");
|
||
exit(1);
|
||
}
|
||
|
||
/* Parse the argument list to set options */
|
||
(void) ParseArgs(argc, argv, 1);
|
||
if (PM_BOOL("Animate")) param_set("TitleText",STR,"Animated X Graph");
|
||
|
||
if (maxitems == 0) {
|
||
(void) fprintf(stderr, "Nothing to plot.\n");
|
||
exit(1);
|
||
}
|
||
|
||
Xsegs[0] = (XSegment *) Malloc((unsigned) (maxitems * sizeof(XSegment)));
|
||
Xsegs[1] = (XSegment *) Malloc((unsigned) (maxitems * sizeof(XSegment)));
|
||
|
||
/* Reverse Video Hack */
|
||
if (PM_BOOL("ReverseVideo"))
|
||
ReverseIt();
|
||
hard_init();
|
||
if (PM_BOOL("Debug")) {
|
||
if (PM_INT("Output Device") == D_XWINDOWS)
|
||
(void) XSynchronize(disp, 1);
|
||
param_dump();
|
||
}
|
||
|
||
/* Logarithmic and bounding box computation */
|
||
flags = 0;
|
||
if (PM_BOOL("LogX"))
|
||
flags |= LOG_X;
|
||
if (PM_BOOL("LogY"))
|
||
flags |= LOG_Y;
|
||
if (PM_BOOL("StackGraph"))
|
||
flags |= STK;
|
||
if (PM_BOOL("FitX"))
|
||
flags |= FITX;
|
||
if (PM_BOOL("FitY"))
|
||
flags |= FITY;
|
||
Traverse(flags);
|
||
|
||
/* Nasty hack here for bar graphs */
|
||
if (PM_BOOL("BarGraph")) {
|
||
double base;
|
||
|
||
llx -= PM_DBL("BarWidth");
|
||
urx += PM_DBL("BarWidth");
|
||
base = PM_DBL("BarBase");
|
||
if (base < lly)
|
||
lly = base;
|
||
if (base > ury)
|
||
ury = base;
|
||
}
|
||
|
||
/* Create initial window */
|
||
if (PM_INT("Output Device") == D_XWINDOWS) {
|
||
double asp;
|
||
|
||
asp = 1.0;
|
||
xtb_init(disp, screen, PM_PIXEL("Foreground"), PM_PIXEL("Background"),
|
||
PM_FONT("LabelFont"));
|
||
|
||
primary = NewWindow(Prog_Name,
|
||
PM_DBL("XLowLimit"), PM_DBL("YLowLimit"),
|
||
PM_DBL("XHighLimit"), PM_DBL("YHighLimit"),
|
||
asp,0);
|
||
if (!primary) {
|
||
(void) fprintf(stderr, "Main window would not open\n");
|
||
exit(1);
|
||
}
|
||
|
||
zoomCursor = XCreateFontCursor(disp, XC_sizing);
|
||
fg_color = PM_COLOR("Foreground");
|
||
bg_color = PM_COLOR("Background");
|
||
XRecolorCursor(disp, zoomCursor, &fg_color, &bg_color);
|
||
|
||
Num_Windows = 1;
|
||
while (Num_Windows > 0) {
|
||
XNextEvent(disp, &theEvent);
|
||
if (xtb_dispatch(&theEvent) != XTB_NOTDEF)
|
||
continue;
|
||
if (XFindContext(theEvent.xany.display,
|
||
theEvent.xany.window,
|
||
win_context, (caddr_t *) & win_info)) {
|
||
/* Nothing found */
|
||
continue;
|
||
}
|
||
switch (theEvent.type) {
|
||
case Expose:
|
||
if (theEvent.xexpose.count <= 0) {
|
||
XWindowAttributes win_attr;
|
||
|
||
XGetWindowAttributes(disp, theEvent.xany.window, &win_attr);
|
||
win_info->dev_info.area_w = win_attr.width;
|
||
win_info->dev_info.area_h = win_attr.height;
|
||
init_X(win_info->dev_info.user_state);
|
||
EraseData(win_info);
|
||
DrawWindow(win_info);
|
||
}
|
||
break;
|
||
case KeyPress:
|
||
nbytes = XLookupString(&theEvent.xkey, keys, MAXKEYS,
|
||
(KeySym *) 0, (XComposeStatus *) 0);
|
||
for (idx = 0; idx < nbytes; idx++) {
|
||
if (keys[idx] == CONTROL_D) {
|
||
/* Delete this window */
|
||
DelWindow(theEvent.xkey.window, win_info);
|
||
}
|
||
else if (keys[idx] == CONTROL_C) {
|
||
/* Exit program */
|
||
Num_Windows = 0;
|
||
}
|
||
else if (keys[idx] == 'h') {
|
||
PrintWindow(theEvent.xany.window, win_info);
|
||
}
|
||
}
|
||
break;
|
||
case ButtonPress:
|
||
/* Handle creating a new window */
|
||
Num_Windows += HandleZoom(Prog_Name,
|
||
&theEvent.xbutton,
|
||
win_info, zoomCursor);
|
||
break;
|
||
default:
|
||
(void) fprintf(stderr, "Unknown event type: %x\n",
|
||
theEvent.type);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
int Device = PM_INT("Output Device");
|
||
int dflag = strcmp(PM_STR("Disposition"), "To Device") == 0;
|
||
|
||
primary = NewWindow(Prog_Name,
|
||
PM_DBL("XLowLimit"), PM_DBL("YLowLimit"),
|
||
PM_DBL("XHighLimit"), PM_DBL("YHighLimit"),
|
||
1.0,0);
|
||
do_hardcopy(Prog_Name, primary,
|
||
hard_devices[Device].dev_init,
|
||
dflag ? hard_devices[Device].dev_spec : 0,
|
||
PM_STR("FileOrDev"), (double) 19,
|
||
hard_devices[Device].dev_title_font,
|
||
hard_devices[Device].dev_title_size,
|
||
hard_devices[Device].dev_axis_font,
|
||
hard_devices[Device].dev_axis_size,
|
||
PM_BOOL("Document") * D_DOCU);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
|
||
#define BLACK_THRES 30000
|
||
|
||
static void
|
||
ReversePix(param_name)
|
||
char *param_name; /* Name of color parameter */
|
||
|
||
/*
|
||
* Looks up `param_name' in the parameters database. If found, the
|
||
* color is examined and judged to be either black or white based
|
||
* upon its red, green, and blue intensities. The sense of the
|
||
* color is then reversed and reset to its opposite.
|
||
*/
|
||
{
|
||
params val;
|
||
|
||
if (param_get(param_name, &val)) {
|
||
if ((val.pixv.value.red < BLACK_THRES) &&
|
||
(val.pixv.value.green < BLACK_THRES) &&
|
||
(val.pixv.value.blue < BLACK_THRES)) {
|
||
/* Color is black */
|
||
param_reset(param_name, "white");
|
||
}
|
||
else {
|
||
/* Color is white */
|
||
param_reset(param_name, "black");
|
||
}
|
||
}
|
||
else {
|
||
(void) fprintf(stderr, "Cannot reverse color `%s'\n", param_name);
|
||
}
|
||
}
|
||
|
||
static void
|
||
ReverseIt()
|
||
/*
|
||
* This routine attempts to implement reverse video. It steps through
|
||
* all of the important colors in the parameters database and makes
|
||
* black white (and vice versa).
|
||
*/
|
||
{
|
||
int i;
|
||
char buf[1024];
|
||
|
||
for (i = 0; i < MAXATTR; i++) {
|
||
(void) sprintf(buf, "%d.Color", i);
|
||
ReversePix(buf);
|
||
}
|
||
ReversePix("Foreground");
|
||
ReversePix("Border");
|
||
ReversePix("ZeroColor");
|
||
ReversePix("Background");
|
||
}
|
||
|
||
|
||
static void
|
||
Traverse(flags)
|
||
int flags; /* Options */
|
||
|
||
/*
|
||
* Traverses through all of the data applying certain options to the
|
||
* data and computing the overall bounding box. The flags are:
|
||
* LOG_X Take the log of the X axis
|
||
* LOG_Y Take the log of the Y axis
|
||
* STK Stack coordinates.
|
||
* FITX Fit x-coordinates from zero to one
|
||
* FITY Fit y-coordinates from zero to one
|
||
*/
|
||
{
|
||
int i,
|
||
j;
|
||
PointList *spot;
|
||
PointList *pspot;
|
||
|
||
static char *paramstr[] =
|
||
{
|
||
"Cannot plot negative %s values\n",
|
||
"when the logarithmic option is selected.\n",
|
||
"Number of points in %d and %d don't match for stacking.\n",
|
||
"Point %d in %d and %d doesn't match for stacking.\n",
|
||
"Set %d has 0 %s.\n"
|
||
};
|
||
|
||
if (flags & (FITX|FITY))
|
||
for (i = 0; i < MAXSETS; i++)
|
||
for (spot = PlotData[i].list; spot; spot = spot->next) {
|
||
float minx, maxx, miny, maxy;
|
||
minx = maxx = spot->xvec[0];
|
||
maxy = miny = spot->yvec[0];
|
||
for (j = 1; j < spot->numPoints; j++) {
|
||
minx = MIN(minx, spot->xvec[j]);
|
||
miny = MIN(miny, spot->yvec[j]);
|
||
maxx = MAX(maxx, spot->xvec[j]);
|
||
maxy = MAX(maxy, spot->yvec[j]);
|
||
}
|
||
maxx = maxx - minx;
|
||
maxy = maxy - miny;
|
||
if (maxx == 0.0) {
|
||
(void) fprintf(stderr, paramstr[3], i, "width");
|
||
maxx = 1.0;
|
||
}
|
||
if (maxy == 0.0) {
|
||
(void) fprintf(stderr, paramstr[3], i, "height");
|
||
maxy = 1.0;
|
||
}
|
||
switch (flags & (FITX|FITY)) {
|
||
case FITX:
|
||
for (j = 0; j < spot->numPoints; j++)
|
||
spot->xvec[j] = (-minx + spot->xvec[j]) / maxx;
|
||
break;
|
||
case FITY:
|
||
for (j = 0; j < spot->numPoints; j++)
|
||
spot->yvec[j] = (-miny + spot->yvec[j]) / maxy;
|
||
break;
|
||
case FITX|FITY:
|
||
for (j = 0; j < spot->numPoints; j++) {
|
||
spot->xvec[j] = (-minx + spot->xvec[j]) / maxx;
|
||
spot->yvec[j] = (-miny + spot->yvec[j]) / maxy;
|
||
}
|
||
break;
|
||
default:
|
||
abort();
|
||
}
|
||
}
|
||
|
||
if (flags & STK)
|
||
for (i = 1; i < MAXSETS; i++) {
|
||
for (spot = PlotData[i].list, pspot = PlotData[i - 1].list;
|
||
spot && pspot; spot = spot->next, pspot = pspot->next) {
|
||
if (spot->numPoints != pspot->numPoints) {
|
||
(void) fprintf(stderr, paramstr[2], i - 1, i);
|
||
exit(1);
|
||
}
|
||
for (j = 0; j < spot->numPoints; j++) {
|
||
if (spot->xvec[j] != pspot->xvec[j]) {
|
||
(void) fprintf(stderr, paramstr[3], j, i - 1, i);
|
||
exit(1);
|
||
}
|
||
spot->yvec[j] += pspot->yvec[j];
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
for (i = 0; i < MAXSETS; i++) {
|
||
for (spot = PlotData[i].list; spot; spot = spot->next) {
|
||
for (j = 0; j < spot->numPoints; j++) {
|
||
if (flags & LOG_Y) {
|
||
if (spot->yvec[j] > 0.0) {
|
||
spot->yvec[j] = log10(spot->yvec[j]);
|
||
}
|
||
else if (spot->yvec[j] == 0)
|
||
spot->yvec[j] = 0.0;
|
||
else {
|
||
(void) fprintf(stderr, paramstr[0], "Y");
|
||
(void) fprintf(stderr, paramstr[1]);
|
||
exit(1);
|
||
}
|
||
}
|
||
if (flags & LOG_X) {
|
||
if (spot->xvec[j] > 0.0) {
|
||
spot->xvec[j] = log10(spot->xvec[j]);
|
||
}
|
||
else if (spot->xvec[j] == 0)
|
||
spot->xvec[j] = 0.0;
|
||
else {
|
||
(void) fprintf(stderr, paramstr[0], "X");
|
||
(void) fprintf(stderr, paramstr[1]);
|
||
exit(1);
|
||
}
|
||
}
|
||
/* Update global bounding box */
|
||
if (spot->xvec[j] < llx)
|
||
llx = spot->xvec[j];
|
||
if (spot->xvec[j] > urx)
|
||
urx = spot->xvec[j];
|
||
if (spot->yvec[j] < lly)
|
||
lly = spot->yvec[j];
|
||
if (spot->yvec[j] > ury)
|
||
ury = spot->yvec[j];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* Button handling functions
|
||
*/
|
||
|
||
/*ARGSUSED*/
|
||
xtb_hret
|
||
del_func(win, bval, info)
|
||
Window win; /* Button window */
|
||
int bval; /* Button value */
|
||
char *info; /* User information */
|
||
|
||
/*
|
||
* This routine is called when the `Close' button is pressed in
|
||
* an xgraph window. It causes the window to go away.
|
||
*/
|
||
{
|
||
Window the_win = (Window) info;
|
||
LocalWin *win_info;
|
||
|
||
xtb_bt_set(win, 1, (char *) 0, 0);
|
||
if (!XFindContext(disp, the_win, win_context, (caddr_t *) & win_info)) {
|
||
if (win_info->flags & HARDCOPY_IN_PROGRESS) {
|
||
do_error("Can't close window while\nhardcopy dialog is posted.\n");
|
||
xtb_bt_set(win, 0, (char *) 0, 0);
|
||
}
|
||
else {
|
||
DelWindow(the_win, win_info);
|
||
}
|
||
}
|
||
return XTB_HANDLED;
|
||
}
|
||
|
||
/*ARGSUSED*/
|
||
xtb_hret
|
||
hcpy_func(win, bval, info)
|
||
Window win; /* Button Window */
|
||
int bval; /* Button value */
|
||
char *info; /* User Information */
|
||
|
||
/*
|
||
* This routine is called when the hardcopy button is pressed
|
||
* in an xgraph window. It causes the output dialog to be
|
||
* posted.
|
||
*/
|
||
{
|
||
Window the_win = (Window) info;
|
||
LocalWin *win_info;
|
||
|
||
xtb_bt_set(win, 1, (char *) 0, 0);
|
||
if (!XFindContext(disp, the_win, win_context, (caddr_t *) & win_info)) {
|
||
win_info->flags |= HARDCOPY_IN_PROGRESS;
|
||
PrintWindow(the_win, win_info);
|
||
win_info->flags &= (~HARDCOPY_IN_PROGRESS);
|
||
}
|
||
xtb_bt_set(win, 0, (char *) 0, 0);
|
||
return XTB_HANDLED;
|
||
}
|
||
|
||
static
|
||
/*ARGSUSED*/
|
||
xtb_hret
|
||
abt_func(win, bval, info)
|
||
Window win; /* Button window */
|
||
int bval; /* Button value */
|
||
char *info; /* User information */
|
||
{
|
||
static char *msg_fmt =
|
||
"Version %s\n\
|
||
XGraph + Animation and Derivatives\n\
|
||
Modification of code by David Harrison\n\
|
||
University of California, Berkeley\n\
|
||
(davidh@ic.Berkeley.EDU or \n\
|
||
...!ucbvax!ucbic!davidh)\n\
|
||
Animation, differentiation, and a few other\n\
|
||
new features added by Paul Walker,\n\
|
||
National Center for Supercomputer Applications\n\
|
||
and Univ. Illinois at U-C Dept of Physics.\n\
|
||
Send comments or suggestions to\n\
|
||
pwalker@ncsa.uiuc.edu\n";
|
||
static int active = 0;
|
||
char msg_buf[1024];
|
||
|
||
if (!active) {
|
||
active = 1;
|
||
xtb_bt_set(win, 1, (char *) 0, 0);
|
||
(void) sprintf(msg_buf, msg_fmt, VERSION_STRING);
|
||
msg_box("XGraph", msg_buf);
|
||
xtb_bt_set(win, 0, (char *) 0, 0);
|
||
active = 0;
|
||
}
|
||
return XTB_HANDLED;
|
||
}
|
||
|
||
|
||
#ifdef DO_DER
|
||
static
|
||
/*ARGSUSED PW*/
|
||
xtb_hret
|
||
rew_func(win, bval, info)
|
||
Window win; /* Button window */
|
||
int bval; /* Button value */
|
||
char *info; /* User information */
|
||
{
|
||
/* This routine added, Paul Walker, to rewind the animation and start
|
||
it over. The only even moderatly tricky part is erasing the last
|
||
item, which still lives, and redrawing the axis. I do it by just
|
||
copying the "Expose" information from the main routine. */
|
||
Window the_win = (Window) info;
|
||
LocalWin *win_info;
|
||
|
||
/* Set animation to True */
|
||
param_set("Animate",BOOL,"on");
|
||
|
||
if (!XFindContext(disp, the_win, win_context, (caddr_t *) & win_info)) {
|
||
XWindowAttributes win_attr;
|
||
|
||
XGetWindowAttributes(disp, the_win, &win_attr);
|
||
win_info->dev_info.area_w = win_attr.width;
|
||
win_info->dev_info.area_h = win_attr.height;
|
||
init_X(win_info->dev_info.user_state);
|
||
EraseData (win_info);
|
||
DrawWindow(win_info);
|
||
}
|
||
|
||
return XTB_HANDLED;
|
||
}
|
||
|
||
static
|
||
/*ARGSUSED PW*/
|
||
xtb_hret
|
||
der_func(win, bval, info)
|
||
Window win; /* Button window */
|
||
int bval; /* Button value */
|
||
char *info; /* User information */
|
||
{
|
||
/* This routine added, Paul Walker, to rewind the animation and start
|
||
it over. The only even moderatly tricky part is erasing the last
|
||
item, which still lives, and redrawing the axis. I do it by just
|
||
copying the "Expose" information from the main routine. */
|
||
Window the_win = (Window) info;
|
||
Window new_win;
|
||
LocalWin *win_info;
|
||
double loX,loY,hiX,hiY,asp;
|
||
static char *msg_fmt =
|
||
"Version %s\n\
|
||
Currently unable to display\n\
|
||
or calculate derivatives\n\
|
||
higher than 2nd order\n";
|
||
static int active = 0;
|
||
char msg_buf[1024];
|
||
|
||
XFindContext(disp, the_win, win_context, (caddr_t *) & win_info);
|
||
if (win_info->DOrder == 2) {
|
||
|
||
if (!active) {
|
||
active = 1;
|
||
xtb_bt_set(win, 1, (char *) 0, 0);
|
||
(void) sprintf(msg_buf, msg_fmt, VERSION_STRING);
|
||
msg_box("XGraph", msg_buf);
|
||
xtb_bt_set(win, 0, (char *) 0, 0);
|
||
active = 0;
|
||
}
|
||
return XTB_HANDLED;
|
||
}
|
||
Num_Windows += 1;
|
||
asp = 1.0;
|
||
Bounds(&loX,&loY,&hiX,&hiY,win_info->DOrder+1);
|
||
new_win = NewWindow("Derivatives", loX, loY, hiX, hiY, asp,
|
||
win_info->DOrder+1);
|
||
|
||
if (!XFindContext(disp, new_win, win_context, (caddr_t *) & win_info)) {
|
||
XWindowAttributes win_attr;
|
||
|
||
XGetWindowAttributes(disp, new_win, &win_attr);
|
||
win_info->dev_info.area_w = win_attr.width;
|
||
win_info->dev_info.area_h = win_attr.height;
|
||
init_X(win_info->dev_info.user_state);
|
||
EraseData (win_info);
|
||
DrawWindow(win_info);
|
||
}
|
||
|
||
return XTB_HANDLED;
|
||
}
|
||
|
||
|
||
static
|
||
/*ARGSUSED PW*/
|
||
xtb_hret
|
||
rpl_func(win, bval, info)
|
||
Window win; /* Button window */
|
||
int bval; /* Button value */
|
||
char *info; /* User information */
|
||
{
|
||
/* Puts us back into static mode ... */
|
||
Window the_win = (Window) info;
|
||
LocalWin *win_info;
|
||
|
||
/* Set animation to True */
|
||
param_set("Animate",BOOL,"off");
|
||
|
||
if (!XFindContext(disp, the_win, win_context, (caddr_t *) & win_info)) {
|
||
XWindowAttributes win_attr;
|
||
|
||
XGetWindowAttributes(disp, the_win, &win_attr);
|
||
win_info->dev_info.area_w = win_attr.width;
|
||
win_info->dev_info.area_h = win_attr.height;
|
||
init_X(win_info->dev_info.user_state);
|
||
EraseData (win_info);
|
||
DrawWindow(win_info);
|
||
}
|
||
|
||
return XTB_HANDLED;
|
||
}
|
||
/* End change PW */
|
||
|
||
#endif /* DO_DER */
|
||
|
||
#define NORMSIZE 600
|
||
#define MINDIM 100
|
||
|
||
Window
|
||
NewWindow(progname, lowX, lowY, upX, upY, asp, DO)
|
||
char *progname; /* Name of program */
|
||
double lowX,
|
||
lowY; /* Lower left corner */
|
||
double upX,
|
||
upY; /* Upper right corner */
|
||
double asp; /* Aspect ratio */
|
||
int DO; /* Derivative Order. */
|
||
|
||
/*
|
||
* Creates and maps a new window. This includes allocating its
|
||
* local structure and associating it with the XId for the window.
|
||
* The aspect ratio is specified as the ratio of width over height.
|
||
*/
|
||
{
|
||
Window new_window;
|
||
LocalWin *new_info;
|
||
static Cursor theCursor = (Cursor) 0;
|
||
XSizeHints sizehints;
|
||
XSetWindowAttributes wattr;
|
||
XWMHints wmhints;
|
||
XColor fg_color,
|
||
bg_color;
|
||
int geo_mask;
|
||
int width,
|
||
height;
|
||
unsigned long wamask;
|
||
char defSpec[120];
|
||
double pad;
|
||
|
||
new_info = (LocalWin *) Malloc(sizeof(LocalWin));
|
||
new_info->DOrder = DO;
|
||
|
||
if (upX > lowX) {
|
||
new_info->loX = lowX;
|
||
new_info->hiX = upX;
|
||
}
|
||
else {
|
||
new_info->loX = llx;
|
||
new_info->hiX = urx;
|
||
}
|
||
if (upY > lowY) {
|
||
new_info->loY = lowY;
|
||
new_info->hiY = upY;
|
||
}
|
||
else {
|
||
new_info->loY = lly;
|
||
new_info->hiY = ury;
|
||
}
|
||
|
||
/* Increase the padding for aesthetics */
|
||
if (new_info->hiX - new_info->loX == 0.0) {
|
||
pad = MAX(0.5, fabs(new_info->hiX / 2.0));
|
||
new_info->hiX += pad;
|
||
new_info->loX -= pad;
|
||
}
|
||
if (new_info->hiY - new_info->loY == 0) {
|
||
pad = MAX(0.5, fabs(ury / 2.0));
|
||
new_info->hiY += pad;
|
||
new_info->loY -= pad;
|
||
}
|
||
|
||
/* Add 10% padding to bounding box (div by 20 yeilds 5%) */
|
||
pad = (new_info->hiX - new_info->loX) / 20.0;
|
||
new_info->loX -= pad;
|
||
new_info->hiX += pad;
|
||
pad = (new_info->hiY - new_info->loY) / 20.0;
|
||
new_info->loY -= pad;
|
||
new_info->hiY += pad;
|
||
|
||
/* Aspect ratio computation */
|
||
if (asp < 1.0) {
|
||
height = NORMSIZE;
|
||
width = ((int) (((double) NORMSIZE) * asp));
|
||
}
|
||
else {
|
||
width = NORMSIZE;
|
||
height = ((int) (((double) NORMSIZE) / asp));
|
||
}
|
||
height = MAX(MINDIM, height);
|
||
width = MAX(MINDIM, width);
|
||
if (PM_INT("Output Device") == D_XWINDOWS) {
|
||
(void) sprintf(defSpec, "%dx%d+100+100", width, height);
|
||
|
||
wamask = CWBackPixel | CWBorderPixel | CWColormap;
|
||
wattr.background_pixel = PM_PIXEL("Background");
|
||
wattr.border_pixel = PM_PIXEL("Border");
|
||
wattr.colormap = cmap;
|
||
|
||
sizehints.flags = PPosition | PSize;
|
||
sizehints.x = sizehints.y = 100;
|
||
sizehints.width = width;
|
||
sizehints.height = height;
|
||
|
||
geo_mask = XParseGeometry(PM_STR("Geometry"),
|
||
&sizehints.x, &sizehints.y,
|
||
(unsigned int *) &sizehints.width,
|
||
(unsigned int *) &sizehints.height);
|
||
if (geo_mask & (XValue|YValue))
|
||
sizehints.flags = (sizehints.flags & ~PPosition) | USPosition;
|
||
if (geo_mask & (WidthValue | HeightValue))
|
||
sizehints.flags = (sizehints.flags & ~PSize) | USSize;
|
||
|
||
new_window = XCreateWindow(disp, RootWindow(disp, screen),
|
||
sizehints.x, sizehints.y,
|
||
(unsigned int) sizehints.width,
|
||
(unsigned int) sizehints.height,
|
||
(unsigned int) PM_INT("BorderSize"),
|
||
depth, InputOutput, vis,
|
||
wamask, &wattr);
|
||
|
||
|
||
if (new_window) {
|
||
xtb_frame cl_frame,
|
||
hd_frame,
|
||
ab_frame,
|
||
rw_frame,
|
||
rp_frame,
|
||
dx_frame;
|
||
|
||
XStoreName(disp, new_window, progname);
|
||
XSetIconName(disp, new_window, progname);
|
||
|
||
wmhints.flags = InputHint | StateHint;
|
||
wmhints.input = True;
|
||
wmhints.initial_state = NormalState;
|
||
XSetWMHints(disp, new_window, &wmhints);
|
||
|
||
XSetWMNormalHints(disp, new_window, &sizehints);
|
||
|
||
/* Set device info */
|
||
set_X(new_window, &(new_info->dev_info));
|
||
|
||
if (!PM_BOOL("NoButton")) {
|
||
/* Make buttons */
|
||
xtb_bt_new(new_window, "Close", del_func,
|
||
(xtb_data) new_window, &cl_frame);
|
||
new_info->close = cl_frame.win;
|
||
XMoveWindow(disp, new_info->close, (int) BTNPAD, (int) BTNPAD);
|
||
xtb_bt_new(new_window, "Hdcpy", hcpy_func,
|
||
(xtb_data) new_window, &hd_frame);
|
||
new_info->hardcopy = hd_frame.win;
|
||
XMoveWindow(disp, new_info->hardcopy,
|
||
(int) (BTNPAD + cl_frame.width + BTNINTER),
|
||
BTNPAD);
|
||
xtb_bt_new(new_window, "About", abt_func,
|
||
(xtb_data) new_window, &ab_frame);
|
||
new_info->about = ab_frame.win;
|
||
XMoveWindow(disp, new_info->about,
|
||
(int) (BTNPAD + cl_frame.width + BTNINTER +
|
||
hd_frame.width + BTNINTER), BTNPAD);
|
||
#ifdef DO_DER
|
||
/* These buttons added PW */
|
||
xtb_bt_new(new_window, "Anim", rew_func,
|
||
(xtb_data) new_window, &rw_frame);
|
||
new_info->rewind = rw_frame.win;
|
||
XMoveWindow(disp, new_info->rewind,
|
||
(int) (BTNPAD + cl_frame.width + BTNINTER +
|
||
hd_frame.width + BTNINTER +
|
||
ab_frame.width + BTNINTER), BTNPAD);
|
||
xtb_bt_new(new_window, "Replot", rpl_func,
|
||
(xtb_data) new_window, &rp_frame);
|
||
new_info->replot = rp_frame.win;
|
||
XMoveWindow(disp, new_info->replot,
|
||
(int) (BTNPAD + cl_frame.width + BTNINTER +
|
||
hd_frame.width + BTNINTER +
|
||
ab_frame.width + BTNINTER +
|
||
rw_frame.width + BTNINTER), BTNPAD);
|
||
xtb_bt_new(new_window, "Deriv", der_func,
|
||
(xtb_data) new_window, &dx_frame);
|
||
new_info->deriv = dx_frame.win;
|
||
XMoveWindow(disp, new_info->deriv,
|
||
(int) (BTNPAD + cl_frame.width + BTNINTER +
|
||
hd_frame.width + BTNINTER +
|
||
ab_frame.width + BTNINTER +
|
||
rw_frame.width + BTNINTER +
|
||
rp_frame.width + BTNINTER), BTNPAD);
|
||
#endif /* DO_DER */
|
||
|
||
new_info->flags = 0;
|
||
}
|
||
XSelectInput(disp, new_window,
|
||
ExposureMask | KeyPressMask | ButtonPressMask);
|
||
if (!theCursor) {
|
||
theCursor = XCreateFontCursor(disp, XC_top_left_arrow);
|
||
fg_color = PM_COLOR("Foreground");
|
||
bg_color = PM_COLOR("Background");
|
||
XRecolorCursor(disp, theCursor, &fg_color, &bg_color);
|
||
}
|
||
XDefineCursor(disp, new_window, theCursor);
|
||
if (!win_context) {
|
||
win_context = XUniqueContext();
|
||
}
|
||
XSaveContext(disp, new_window, win_context, (caddr_t) new_info);
|
||
XMapWindow(disp, new_window);
|
||
return new_window;
|
||
}
|
||
else {
|
||
return (Window) 0;
|
||
}
|
||
}
|
||
else {
|
||
new_info->dev_info.area_h = 1.0;
|
||
new_info->dev_info.area_w = 1.0;
|
||
return ((Window) new_info);
|
||
}
|
||
}
|
||
|
||
|
||
DelWindow(win, win_info)
|
||
Window win; /* Window */
|
||
LocalWin *win_info; /* Local Info */
|
||
|
||
/*
|
||
* This routine actually deletes the specified window and
|
||
* decrements the window count.
|
||
*/
|
||
{
|
||
xtb_data info;
|
||
|
||
XDeleteContext(disp, win, win_context);
|
||
xtb_bt_del(win_info->close, &info);
|
||
xtb_bt_del(win_info->hardcopy, &info);
|
||
xtb_bt_del(win_info->about, &info);
|
||
Free((char *) win_info);
|
||
XDestroyWindow(disp, win);
|
||
Num_Windows -= 1;
|
||
}
|
||
|
||
PrintWindow(win, win_info)
|
||
Window win; /* Window */
|
||
LocalWin *win_info; /* Local Info */
|
||
|
||
/*
|
||
* This routine posts a dialog asking about the hardcopy
|
||
* options desired. If the user hits `OK', the hard
|
||
* copy is performed.
|
||
*/
|
||
{
|
||
ho_dialog(win, Prog_Name, (char *) win_info);
|
||
}
|
||
|
||
|
||
static XRectangle boxEcho;
|
||
static GC echoGC = (GC) 0;
|
||
|
||
#define DRAWBOX \
|
||
if (startX < curX) { \
|
||
boxEcho.x = startX; \
|
||
boxEcho.width = curX - startX; \
|
||
} else { \
|
||
boxEcho.x = curX; \
|
||
boxEcho.width = startX - curX; \
|
||
} \
|
||
if (startY < curY) { \
|
||
boxEcho.y = startY; \
|
||
boxEcho.height = curY - startY; \
|
||
} else { \
|
||
boxEcho.y = curY; \
|
||
boxEcho.height = startY - curY; \
|
||
} \
|
||
XDrawRectangles(disp, win, echoGC, &boxEcho, 1);
|
||
|
||
#define TRANX(xval) \
|
||
(((double) ((xval) - wi->XOrgX)) * wi->XUnitsPerPixel + wi->UsrOrgX)
|
||
|
||
#define TRANY(yval) \
|
||
(wi->UsrOppY - (((double) ((yval) - wi->XOrgY)) * wi->YUnitsPerPixel))
|
||
|
||
|
||
int
|
||
HandleZoom(progname, evt, wi, cur)
|
||
char *progname;
|
||
XButtonPressedEvent *evt;
|
||
LocalWin *wi;
|
||
Cursor cur;
|
||
{
|
||
Window win,
|
||
new_win;
|
||
Window root_rtn,
|
||
child_rtn;
|
||
XEvent theEvent;
|
||
int startX,
|
||
startY,
|
||
curX,
|
||
curY,
|
||
newX,
|
||
newY,
|
||
stopFlag,
|
||
numwin = 0;
|
||
int root_x,
|
||
root_y;
|
||
unsigned int mask_rtn;
|
||
double loX,
|
||
loY,
|
||
hiX,
|
||
hiY,
|
||
asp;
|
||
|
||
win = evt->window;
|
||
if (XGrabPointer(disp, win, True,
|
||
(unsigned int) (ButtonPressMask | ButtonReleaseMask |
|
||
PointerMotionMask | PointerMotionHintMask),
|
||
GrabModeAsync, GrabModeAsync,
|
||
win, cur, CurrentTime) != GrabSuccess) {
|
||
XBell(disp, 0);
|
||
return 0;
|
||
}
|
||
if (echoGC == (GC) 0) {
|
||
unsigned long gcmask;
|
||
XGCValues gcvals;
|
||
|
||
gcmask = GCForeground | GCFunction;
|
||
gcvals.foreground = PM_PIXEL("ZeroColor") ^ PM_PIXEL("Background");
|
||
gcvals.function = GXxor;
|
||
echoGC = XCreateGC(disp, win, gcmask, &gcvals);
|
||
}
|
||
startX = evt->x;
|
||
startY = evt->y;
|
||
XQueryPointer(disp, win, &root_rtn, &child_rtn, &root_x, &root_y,
|
||
&curX, &curY, &mask_rtn);
|
||
/* Draw first box */
|
||
DRAWBOX;
|
||
stopFlag = 0;
|
||
while (!stopFlag) {
|
||
XNextEvent(disp, &theEvent);
|
||
switch (theEvent.xany.type) {
|
||
case MotionNotify:
|
||
XQueryPointer(disp, win, &root_rtn, &child_rtn, &root_x, &root_y,
|
||
&newX, &newY, &mask_rtn);
|
||
/* Undraw the old one */
|
||
DRAWBOX;
|
||
/* Draw the new one */
|
||
curX = newX;
|
||
curY = newY;
|
||
DRAWBOX;
|
||
break;
|
||
case ButtonRelease:
|
||
DRAWBOX;
|
||
XUngrabPointer(disp, CurrentTime);
|
||
stopFlag = 1;
|
||
if ((startX - curX != 0) && (startY - curY != 0)) {
|
||
/* Figure out relative bounding box */
|
||
loX = TRANX(startX);
|
||
loY = TRANY(startY);
|
||
hiX = TRANX(curX);
|
||
hiY = TRANY(curY);
|
||
if (loX > hiX) {
|
||
double temp;
|
||
|
||
temp = hiX;
|
||
hiX = loX;
|
||
loX = temp;
|
||
}
|
||
if (loY > hiY) {
|
||
double temp;
|
||
|
||
temp = hiY;
|
||
hiY = loY;
|
||
loY = temp;
|
||
}
|
||
/* physical aspect ratio */
|
||
asp = ((double) ABS(startX - curX)) /
|
||
((double) ABS(startY - curY));
|
||
new_win = NewWindow(progname, loX, loY, hiX, hiY, asp,
|
||
wi->DOrder);
|
||
if (new_win) {
|
||
numwin = 1;
|
||
}
|
||
else {
|
||
numwin = 0;
|
||
}
|
||
}
|
||
else {
|
||
numwin = 0;
|
||
}
|
||
break;
|
||
default:
|
||
printf("unknown event: %d\n", theEvent.xany.type);
|
||
break;
|
||
}
|
||
}
|
||
return numwin;
|
||
}
|
||
|
||
|
||
#define RND(val) ((int) ((val) + 0.5))
|
||
|
||
/*ARGSUSED*/
|
||
void
|
||
do_hardcopy(prog, info, init_fun, dev_spec, file_or_dev, maxdim,
|
||
ti_fam, ti_size, ax_fam, ax_size, doc_p)
|
||
char *prog; /* Program name for Xdefaults */
|
||
char *info; /* Some state information */
|
||
int (*init_fun) (); /* Hardcopy init function */
|
||
char *dev_spec; /* Device specification (if any) */
|
||
char *file_or_dev; /* Filename or device spec */
|
||
double maxdim; /* Maximum dimension in cm */
|
||
char *ti_fam,
|
||
*ax_fam; /* Font family names */
|
||
double ti_size,
|
||
ax_size; /* Font sizes in points */
|
||
int doc_p; /* Documentation predicate */
|
||
|
||
/*
|
||
* This routine resets the function pointers to those specified
|
||
* by `init_fun' and causes a screen redisplay. If `dev_spec'
|
||
* is non-zero, it will be considered a sprintf string with
|
||
* one %s which will be filled in with `file_or_dev' and fed
|
||
* to popen(3) to obtain a stream. Otherwise, `file_or_dev'
|
||
* is considered to be a file and is opened for writing. The
|
||
* resulting stream is fed to the initialization routine for
|
||
* the device.
|
||
*/
|
||
{
|
||
LocalWin *curWin = (LocalWin *) info;
|
||
LocalWin thisWin;
|
||
FILE *out_stream;
|
||
char buf[MAXBUFSIZE],
|
||
err[MAXBUFSIZE],
|
||
ierr[ERRBUFSIZE];
|
||
char tilde[MAXBUFSIZE * 10];
|
||
int final_w,
|
||
final_h,
|
||
flags;
|
||
double ratio;
|
||
|
||
if (dev_spec) {
|
||
(void) sprintf(buf, dev_spec, file_or_dev);
|
||
out_stream = popen(buf, "w");
|
||
if (!out_stream) {
|
||
sprintf(err, "Unable to issue command:\n %s\n", buf);
|
||
do_error(err);
|
||
return;
|
||
}
|
||
}
|
||
else {
|
||
tildeExpand(tilde, file_or_dev);
|
||
out_stream = fopen(tilde, "w");
|
||
if (!out_stream) {
|
||
sprintf(err, "Unable to open file `%s'\n", tilde);
|
||
do_error(err);
|
||
return;
|
||
}
|
||
}
|
||
if (curWin != (LocalWin *) 0) {
|
||
thisWin = *curWin;
|
||
ratio = ((double) thisWin.dev_info.area_w) /
|
||
((double) thisWin.dev_info.area_h);
|
||
}
|
||
else
|
||
ratio = 1.0;
|
||
|
||
if (thisWin.dev_info.area_w > thisWin.dev_info.area_h) {
|
||
final_w = RND(maxdim * 10000.0 * PM_DBL("Scale"));
|
||
final_h = RND(maxdim / ratio * 10000.0 * PM_DBL("Scale"));
|
||
}
|
||
else {
|
||
final_w = RND(maxdim * ratio * 10000.0 * PM_DBL("Scale"));
|
||
final_h = RND(maxdim * 10000.0 * PM_DBL("Scale"));
|
||
}
|
||
ierr[0] = '\0';
|
||
flags = 0;
|
||
if (doc_p)
|
||
flags |= D_DOCU;
|
||
if ((*init_fun) (out_stream, final_w, final_h, ti_fam, ti_size,
|
||
ax_fam, ax_size, flags, &(thisWin.dev_info), ierr)) {
|
||
DrawWindow(&thisWin);
|
||
if (thisWin.dev_info.xg_end) {
|
||
thisWin.dev_info.xg_end(thisWin.dev_info.user_state);
|
||
}
|
||
}
|
||
else {
|
||
do_error(ierr);
|
||
}
|
||
if (dev_spec) {
|
||
(void) pclose(out_stream);
|
||
}
|
||
else {
|
||
(void) fclose(out_stream);
|
||
}
|
||
}
|
||
|
||
|
||
static char *
|
||
tildeExpand(out, in)
|
||
char *out; /* Output space for expanded file name */
|
||
char *in; /* Filename with tilde */
|
||
|
||
/*
|
||
* This routine expands out a file name passed in `in' and places
|
||
* the expanded version in `out'. It returns `out'.
|
||
*/
|
||
{
|
||
char username[50],
|
||
*userPntr;
|
||
struct passwd *userRecord;
|
||
|
||
out[0] = '\0';
|
||
|
||
/* Skip over the white space in the initial path */
|
||
while ((*in == ' ') ||(*in == '\t'))
|
||
in ++;
|
||
|
||
/* Tilde? */
|
||
if (in[0] == TILDE) {
|
||
/* Copy user name into 'username' */
|
||
in ++;
|
||
|
||
userPntr = &(username[0]);
|
||
while ((*in !='\0') &&(*in !='/')) {
|
||
*(userPntr++) = *(in ++);
|
||
}
|
||
*(userPntr) = '\0';
|
||
/* See if we have to fill in the user name ourselves */
|
||
if (strlen(username) == 0) {
|
||
userRecord = getpwuid(getuid());
|
||
}
|
||
else {
|
||
userRecord = getpwnam(username);
|
||
}
|
||
if (userRecord) {
|
||
/* Found user in passwd file. Concatenate user directory */
|
||
strcat(out, userRecord->pw_dir);
|
||
}
|
||
}
|
||
|
||
/* Concantenate remaining portion of file name */
|
||
strcat(out, in);
|
||
return out;
|
||
}
|
||
|
||
|
||
|
||
#define ERR_MSG_SIZE 2048
|
||
|
||
/*ARGSUSED*/
|
||
static int
|
||
XErrHandler(disp_ptr, evt)
|
||
Display *disp_ptr;
|
||
XErrorEvent *evt;
|
||
|
||
/*
|
||
* Displays a nicely formatted message and core dumps.
|
||
*/
|
||
{
|
||
char err_buf[ERR_MSG_SIZE],
|
||
mesg[ERR_MSG_SIZE],
|
||
number[ERR_MSG_SIZE];
|
||
char *mtype = "XlibMessage";
|
||
|
||
XGetErrorText(disp_ptr, evt->error_code, err_buf, ERR_MSG_SIZE);
|
||
(void) fprintf(stderr, "X Error: %s\n", err_buf);
|
||
XGetErrorDatabaseText(disp_ptr, mtype, "MajorCode",
|
||
"Request Major code %d", mesg, ERR_MSG_SIZE);
|
||
(void) fprintf(stderr, mesg, evt->request_code);
|
||
(void) sprintf(number, "%d", evt->request_code);
|
||
XGetErrorDatabaseText(disp_ptr, "XRequest", number, "", err_buf,
|
||
ERR_MSG_SIZE);
|
||
(void) fprintf(stderr, " (%s)\n", err_buf);
|
||
|
||
abort();
|
||
}
|