This is xdriver.c in view mode; [Download] [Up]
/*
** Astrolog (Version 4.10) File: xdriver.c
**
** IMPORTANT NOTICE: the graphics database and chart display routines
** used in this program are Copyright (C) 1991-1994 by Walter D. Pullen
** (cruiser1@stein.u.washington.edu). Permission is granted to freely
** use and distribute these routines provided one doesn't sell,
** restrict, or profit from them in any way. Modification is allowed
** provided these notices remain with any altered or edited versions of
** the program.
**
** The main planetary calculation routines used in this program have
** been Copyrighted and the core of this program is basically a
** conversion to C of the routines created by James Neely as listed in
** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
** available from Matrix Software. The copyright gives us permission to
** use the routines for personal use but not to sell them or profit from
** them in any way.
**
** The PostScript code within the core graphics routines are programmed
** and Copyright (C) 1992-1993 by Brian D. Willoughby
** (brianw@sounds.wa.com). Conditions are identical to those above.
**
** The extended accurate ephemeris databases and formulas are from the
** calculation routines in the program "Placalc" and are programmed and
** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
** (alois@azur.ch). The use of that source code is subject to
** regulations made by Astrodienst Zurich, and the code is not in the
** public domain. This copyright notice must not be changed or removed
** by any user of this program.
**
** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
** X Window graphics initially programmed 10/23-29/1991.
** PostScript graphics initially programmed 11/29-30/1992.
** Last code change made 3/19/1994.
*/
#include "astrolog.h"
#ifdef GRAPH
#ifdef X11
/* Size of the Astrolog X11 icon. These values are defined in xdata.c too. */
#define icon_width 63
#define icon_height 32
#endif
#ifdef MSG
/* PC specific global variables. */
int hiresmode = DEFHIRESMODE; /* 'High-resolution' graphics mode. */
int loresmode = DEFLORESMODE; /* 'Flicker-free' graphics mode. */
int xscreen = -1000; /* Current graphics mode. */
struct videoconfig config; /* State of current graphics mode. */
#endif
/*
******************************************************************************
** Interactive Screen Graphics Routines.
******************************************************************************
*/
#ifdef X11
/* Allocate a color from the present colormap. Given a string like "red" or */
/* "blue" allocate this color and return a value specifying it. */
colrgb XMakeColor(name)
char *name;
{
XColor col;
XParseColor(disp, cmap, name, &col);
XAllocColor(disp, cmap, &col);
return col.pixel;
}
#endif
/* Set up all the colors used by the program, i.e. the foreground and */
/* background colors, and all the colors in the object arrays, based on */
/* whether or not we are in monochrome and/or reverse video mode. */
void XColorInit()
{
int i;
#ifdef X11
if (!xfile) {
cmap = XDefaultColormap(disp, screen);
for (i = 0; i < 16; i++)
rgbind[i] = XMakeColor(rgbname[i]);
}
#endif
on = mainansi[!xreverse];
off = mainansi[xreverse];
hilite = xcolor ? mainansi[2+xreverse] : on;
gray = xcolor ? mainansi[3-xreverse] : on;
for (i = 0; i <= 6; i++)
maincolor[i] = xcolor ? mainansi[i] : on;
for (i = 0; i <= 7; i++)
rainbowcolor[i] = xcolor ? rainbowansi[i] : on;
for (i = 0; i < 4; i++)
elemcolor[i] = xcolor ? elemansi[i] : on;
for (i = 0; i <= ASPECTS; i++)
aspectcolor[i] = xcolor ? aspectansi[i] : on;
for (i = 0; i <= total; i++)
objectcolor[i] = xcolor ? objectansi[i] : on;
#ifdef X11
if (!xfile) {
XSetBackground(disp, gc, rgbind[off]); /* Initialize X window colors. */
XSetForeground(disp, pmgc, rgbind[off]);
}
#endif
}
#ifdef ISG
/* This routine opens up and initializes a window and prepares it to be */
/* drawn upon, and gets various information about the display, too. */
void XBegin()
{
#ifdef X11
disp = XOpenDisplay(dispname);
if (!disp) {
PrintError("Can't open display.");
Terminate(_FATAL);
}
screen = DefaultScreen(disp);
bg = BlackPixel(disp, screen);
fg = WhitePixel(disp, screen);
hint.x = offsetx; hint.y = offsety;
hint.width = chartx; hint.height = charty;
hint.min_width = BITMAPX1; hint.min_height = BITMAPY1;
hint.max_width = BITMAPX; hint.max_height = BITMAPY;
hint.flags = PPosition | PSize | PMaxSize | PMinSize;
#if FALSE
wmhint = XGetWMHints(disp, window);
wmhint->input = True;
XSetWMHints(disp, window, wmhint);
#endif
depth = DefaultDepth(disp, screen);
if (depth < 5) {
xmono = TRUE; /* Is this a monochrome monitor? */
xcolor = FALSE;
}
root = RootWindow(disp, screen);
if (xroot)
window = root; /* If -XB in effect, we'll use the root window. */
else
window = XCreateSimpleWindow(disp, DefaultRootWindow(disp),
hint.x, hint.y, hint.width, hint.height, 5, fg, bg);
pixmap = XCreatePixmap(disp, window, chartx, charty, depth);
icon = XCreateBitmapFromData(disp, DefaultRootWindow(disp),
icon_bits, icon_width, icon_height);
if (!xroot)
XSetStandardProperties(disp, window, appname, appname, icon,
(char PTR PTR)xkey, 0, &hint);
/* We have two graphics workareas. One is what the user currently sees in */
/* the window, and the other is what we are currently drawing on. When */
/* done, we can quickly copy this to the viewport for a smooth look. */
gc = XCreateGC(disp, window, 0, 0);
XSetGraphicsExposures(disp, gc, 0);
pmgc = XCreateGC(disp, window, 0, 0);
XColorInit(); /* Go set up colors. */
if (!xroot)
XSelectInput(disp, window, KeyPressMask | StructureNotifyMask |
ExposureMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask);
XMapRaised(disp, window);
XSync(disp, 0);
XFillRectangle(disp, pixmap, pmgc, 0, 0, chartx, charty);
#else /* MSG */
if (!IsValidResmode(xscreen)) /* Initialize graphics mode to hi-res. */
xscreen = hiresmode;
_setvideomode(xscreen);
if (_grstatus()) {
PrintError("Can't enter graphics mode.");
Terminate(_FATAL);
}
_getvideoconfig((struct videoconfig far *) &config);
if (config.numcolors < 16) {
xmono = TRUE;
xcolor = FALSE;
}
_remapallpalette((long FAR *) rgb);
_setactivepage(0);
_setvisualpage(0);
XColorInit();
#ifdef MOUSE
if (MouseInit() > 0)
SetPtrVis(SHOW);
#endif
textrows = abs(textrows); /* Make sure we reset textrows upon restart. */
#endif /* MSG */
}
/* Add a certain amount of time to the current hour/day/month/year quantity */
/* defining the present chart. This is used by the chart animation feature. */
/* We can add or subtract anywhere from 1 to 9 seconds, minutes, hours, */
/* days, months, years, decades, centuries, or millenia in any one call. */
/* This is mainly just addition to the appropriate quantity, but we have */
/* to check for overflows, e.g. Dec 30 + 3 days = Jan 2 of Current year + 1 */
void AddTime(mode, toadd)
int mode, toadd;
{
int d;
real h, m;
h = floor(TT);
m = FRACT(TT)*100.0;
if (mode == 1)
m += 1.0/60.0*(real)toadd; /* Add seconds. */
else if (mode == 2)
m += (real)toadd; /* add minutes. */
/* Add hours, either naturally or if minute value overflowed. */
if (m < 0.0 || m >= 60.0 || mode == 3) {
if (m >= 60.0) {
m -= 60.0; toadd = SGN(toadd);
} else if (m < 0.0) {
m += 60.0; toadd = SGN(toadd);
}
h += (real)toadd;
}
/* Add days, either naturally or if hour value overflowed. */
if (h >= 24.0 || h < 0.0 || mode == 4) {
if (h >= 24.0) {
h -= 24.0; toadd = SGN(toadd);
} else if (h < 0.0) {
h += 24.0; toadd = SGN(toadd);
}
DD = AddDay(MM, DD, YY, toadd);
}
/* Add months, either naturally or if day value overflowed. */
if (DD > (d = DayInMonth(MM, YY)) || DD < 1 || mode == 5) {
if (DD > d) {
DD -= d; toadd = SGN(toadd);
} else if (DD < 1) {
DD += DayInMonth(Mod12(MM - 1), YY);
toadd = SGN(toadd);
}
MM += toadd;
}
/* Add years, either naturally or if month value overflowed. */
if (MM > 12 || MM < 1 || mode == 6) {
if (MM > 12) {
MM -= 12; toadd = SGN(toadd);
} else if (MM < 1) {
MM += 12; toadd = SGN(toadd);
}
YY += toadd;
}
if (mode == 7)
YY += 10 * toadd; /* Add decades. */
else if (mode == 8)
YY += 100 * toadd; /* Add centuries. */
else if (mode == 9)
YY += 1000 * toadd; /* Add millenia. */
TT = h+m/100.0; /* Recalibrate hour time. */
}
/* Animate the current chart based on the given values indicating how much */
/* to update by. We update and recast the current chart info appropriately. */
void Animate(mode, toadd)
int mode, toadd;
{
if (modex == MODEW || modex == MODEG || modex == MODEP) {
degree += toadd;
if (degree >= DEGD) /* For animating globe display, add */
degree -= DEGD; /* in appropriate degree value. */
else if (degree < 0)
degree += DEGD;
} else {
if (mode == 10) {
#ifdef TIME
/* For the continuous chart update to present moment */
/* animation mode, go get whatever time it is now. */
InputData("now");
#else
SetCore(Mon, Day, Yea, Tim, Zon, Lon, Lat);
AddTime(1, toadd);
#endif
} else { /* Otherwise add on appropriate time vector to chart info. */
SetCore(Mon, Day, Yea, Tim, Zon, Lon, Lat);
AddTime(mode, toadd);
}
SetMain(MM, DD, YY, TT, ZZ, OO, AA);
if (relation)
CastRelation(FALSE);
else
CastChart(TRUE);
}
}
/* Print a list of every key that one can press in an X window to do a */
/* certain function, and a description of what it does. This list gets */
/* displayed whenever one presses the 'H' or '?' key in the window. */
void XDisplayKeys()
{
char string[STRING];
sprintf(string, "\n%s window keypress options (version %s):", appname,
VERSION);
Prints(string);
Prints(" Press 'H' or '?' to display this list of key options.");
Prints(" Press 'p' to toggle pause status on or off.");
Prints(" Press 'x' to toggle fg/bg colors on screen.");
Prints(" Press 'm' to toggle color/monochrome display on screen.");
Prints(" Press 'i' to toggle status of the minor chart modification.");
Prints(" Press 'T' to toggle header info on current chart on screen.");
Prints(" Press 'b' to toggle drawing of a border around the chart.");
Prints(" Press 'l' to toggle labeling of object points in chart.");
Prints(" Press 'v' to display current chart positions on text screen.");
Prints(" Press 'R', 'C', 'u', 'U' to toggle restriction status of minor");
Prints(" objects, minor house cusps, uranian planets, and stars.");
Prints(" Press 'c' to toggle relationship comparison chart mode.");
Prints(" Press 's', 'h', 'f', 'F' to toggle status of sidereal zodiac,");
Prints(" heliocentric charts, domal charts, and decan charts.");
Prints(" Press 'O' and 'o' to recall/store a previous chart from memory.");
#ifdef X11
Prints(" Press 'B' to dump current window contents to root background.");
#else
Prints(" Press 'B' to resize chart display to full size of screen.");
#endif
Prints(" Press 'Q' to resize chart display to a square.");
Prints(" Press '<' and '>' to decrease/increase the scale size of the");
Prints(" glyphs and the size of world map.");
Prints(" Press '[' and ']' to decrease/increase tilt in globe display.");
Prints(" Press '+' and '-' to add/subtract a day from current chart.");
#ifdef TIME
Prints(" Press 'n' to set chart information to current time now.");
#endif
Prints(" Press 'N' to toggle animation status on or off. Charts will");
Prints(" be updated to current status and globe will rotate.");
Prints(" Press '!'-'(' to begin updating current chart by adding times.");
Prints(" !: seconds, @: minutes, #: hours, $: days, %: months,");
Prints(" ^: years, &: years*10, *: years*100, (: years*1000.");
Prints(" Press 'r' to reverse direction of time-lapse or animation.");
Prints(" Press '1'-'9' to set rate of animation to 'n' degrees, etc.");
#ifdef MSG
Prints(" Press '1'-'9' to determine section of chart to show if clipped.");
#endif
Prints(
" Press 'V','L','A','Z','S','E','W','G','P' to switch to normal (_v),");
Prints(
" astro-graph (_L), grid (_g), local (_Z), space (_S), ephemeris");
Prints(" (_E), world map (_XW), globe (_XG), and polar (_XP) modes.");
Prints(" Press '0' to toggle between _Z,_Z0 & _XW,_XW0 & _E,_Ey modes.");
Prints(" Press 'space' to force redraw of current graphics display.");
#ifdef MSG
Prints(" Press 'tab' to toggle between graphics resolutions.");
#endif
Prints(" Press 'q' to terminate the window and program.");
#ifdef MOUSE
printl();
#ifdef X11
Prints(" Left mouse button: Draw line strokes on chart in window.");
Prints(" Middle mouse button: Print coordinates of pointer on world map.");
Prints(" Right mouse button: Terminate the window and program.");
#endif
#ifdef MSG
Prints(" Left mouse button: Draw line strokes on chart in screen.");
Prints(" Right mouse button: Set coordinates to pointer on world map.");
#endif
#endif /* MOUSE */
}
/* Given two chart size values, adjust them such that the chart will look */
/* "square". We round the higher value down and check certain conditions. */
void XSquare(x, y, force)
int *x, *y, force;
{
if (!force && !ISSQUARE) /* Unless we want to force a square, realize */
return; /* that some chart look better rectangular. */
if (*x > *y)
*x = *y;
else
*y = *x;
#ifdef MSG
if (ISEGA(xscreen)) /* Scale horizontal size if we're in a PC */
*x = EGATOVGA(*x); /* graphics mode without "square" pixels. */
else if (ISCGA(xscreen))
*x = CGATOVGA(*x);
#endif
if (ISSIDEBAR) /* Take into account chart's sidebar, if any. */
*x += SIDET;
}
/* This routine gets called after an X window is brought up and displayed */
/* on the screen. It loops, processing key presses, mouse clicks, etc, that */
/* the window receives, until the user specifies they want to exit program. */
void XSpin()
{
#ifdef X11
XEvent event;
int xresize = FALSE, xredraw = TRUE;
#else
#ifdef MOUSE
EVENT event;
#endif
int xresize = TRUE, xredraw = FALSE;
#endif
int xbreak = FALSE, xpause = FALSE, xcast = FALSE, xcorner = 7,
mousex = -1, mousey = -1, buttonx = -1, buttony = -1, dir = 1, length, i;
colpal coldrw = hilite;
xnow = -xnow;
while (!xbreak) {
/* Some chart windows, like the world maps and aspect grids, should */
/* always be a certian size, so correct if a resize was attempted. */
if (modex == MODEL || modex == MODEW) {
length = DEGD*SCALE+2;
if (chartx != length) {
chartx = length;
xresize = TRUE;
}
length = (90*2+1)*SCALE+2;
if (charty != length) {
charty = length;
xresize = TRUE;
}
} else if (modex == MODEg) {
if (chartx !=
(length = (gridobjects + (relation <= DASHr0))*CELLSIZE*SCALE+1)) {
chartx = length;
xresize = TRUE;
} if (charty != length) {
charty = length;
xresize = TRUE;
}
/* Make sure the window isn't too large or too small. */
} else {
if (chartx < BITMAPX1) {
chartx = BITMAPX1;
xresize = TRUE;
} else if (chartx > BITMAPX) {
chartx = BITMAPX;
xresize = TRUE;
}
if (charty < BITMAPY1) {
charty = BITMAPY1;
xresize = TRUE;
} else if (charty > BITMAPY) {
charty = BITMAPY;
xresize = TRUE;
}
}
/* If in animation mode, ensure we are in the flicker free resolution. */
if (xnow < 0) {
xnow = -xnow;
#ifdef MSG
if (xscreen == hiresmode) {
xscreen = loresmode;
XBegin();
chartx = config.numxpixels;
charty = config.numypixels;
XSquare(&chartx, &charty, FALSE);
xresize = TRUE;
}
#endif
}
/* Physically resize window if we've changed the size parameters. */
if (xresize) {
xresize = FALSE;
#ifdef X11
XResizeWindow(disp, window, chartx, charty);
XFreePixmap(disp, pixmap);
pixmap = XCreatePixmap(disp, window, chartx, charty, depth);
#else
if (config.numxpixels > chartx)
offsetx = (config.numxpixels - chartx) >> 1;
else {
if (xcorner % 3 == 1)
offsetx = 0;
else if (xcorner % 3 == 0)
offsetx = -chartx + config.numxpixels;
else
offsetx = -(chartx - config.numxpixels) / 2;
}
if (config.numypixels > charty)
offsety = (config.numypixels - charty) >> 1;
else {
if (xcorner > 6)
offsety = 0;
else if (xcorner < 4)
offsety = -charty + config.numypixels;
else
offsety = -(charty - config.numypixels) / 2;
}
#endif
xredraw = TRUE;
}
/* Recast chart if the chart information has changed any. */
if (xcast) {
xcast = FALSE;
SetCore(Mon, Day, Yea, Tim, Zon, Lon, Lat);
if (relation)
CastRelation(FALSE);
else
CastChart(TRUE);
xredraw = TRUE;
}
if (xnow && !xpause)
xredraw = TRUE;
/* Update the screen if anything has changed since last time around. */
if (xredraw) {
xredraw = FALSE;
/* If we're in animation mode, change the chart info appropriately. */
if (xnow)
Animate(xnow, dir);
#ifdef X11
XFillRectangle(disp, pixmap, pmgc, 0, 0, chartx, charty);
#else /* MSG */
#ifdef MOUSE
SetPtrVis(HIDE);
#endif
if (config.numvideopages > 1)
_setactivepage(_getactivepage() == 0);
#endif /* MSG */
XChart();
#ifdef X11
XSync(disp, 0);
XCopyArea(disp, pixmap, window, gc, 0, 0, chartx, charty, 0, 0);
#else /* MSG */
if (config.numvideopages > 1)
_setvisualpage(_getactivepage());
#ifdef MOUSE
if (!xnow)
SetPtrVis(SHOW);
#endif
#endif /* MSG */
} /* if */
/* Now process what's on the event queue, i.e. any keys pressed, etc. */
#ifdef X11
if (XEventsQueued(disp, QueuedAfterFlush /*QueuedAfterReading*/ )) {
XNextEvent(disp, &event);
/* Restore what's on window if a part of it gets uncovered. */
if (event.type == Expose && event.xexpose.count == 0) {
XSync(disp, 0);
XCopyArea(disp, pixmap, window, gc, 0, 0, chartx, charty, 0, 0);
}
switch (event.type) {
/* Check for a manual resize of window by user. */
case ConfigureNotify:
chartx = event.xconfigure.width;
charty = event.xconfigure.height;
XFreePixmap(disp, pixmap);
pixmap = XCreatePixmap(disp, window, chartx, charty, depth);
xredraw = TRUE;
break;
case MappingNotify:
XRefreshKeyboardMapping((XMappingEvent PTR)&event);
break;
#ifdef MOUSE
/* Process any mouse buttons the user pressed. */
case ButtonPress:
mousex = event.xbutton.x; mousey = event.xbutton.y;
if (event.xbutton.button == Button1) {
DrawColor(hilite);
DrawPoint(mousex, mousey);
XSync(disp, 0);
XCopyArea(disp, pixmap, window, gc, 0, 0, chartx, charty, 0, 0);
} else if (event.xbutton.button == Button2 &&
(modex == MODEL || modex == MODEW) && degree == 0) {
Lon = DEGHALF-(real)(event.xbutton.x-1)/(real)(chartx-2)*DEGREES;
Lat = DEGQUAD-(real)(event.xbutton.y-1)/(real)(charty-2)*181.0;
fprintf(S, "Mouse is at %s.\n", CharLocation(Lon, Lat, 60.0));
} else if (event.xbutton.button == Button3)
xbreak = TRUE;
break;
/* Check for user dragging any of the mouse buttons across window. */
case MotionNotify:
DrawColor(coldrw);
DrawLine(mousex, mousey, event.xbutton.x, event.xbutton.y);
XSync(disp, 0);
XCopyArea(disp, pixmap, window, gc, 0, 0, chartx, charty, 0, 0);
mousex = event.xbutton.x; mousey = event.xbutton.y;
break;
#endif
/* Process any keys user pressed in window. */
case KeyPress:
length = XLookupString((XKeyEvent PTR)&event, xkey, 10, &key, 0);
if (length == 1) {
i = xkey[0];
#else /* MSG */
#ifdef MOUSE
if (!xnow && GetMouseEvent((EVENT *)&event)) {
/* If the left button is down, draw on the screen. */
if (event.fsBtn == LEFT_DOWN && mousex >= 0) {
SetPtrVis(HIDE);
DrawColor(coldrw);
_moveto(mousex, mousey);
buttonx = event.x; buttony = event.y;
_lineto(buttonx, buttony);
/* If the right button is down, change the default location. */
} else if (event.fsBtn == RIGHT_DOWN) {
if ((modex == MODEL || modex == MODEW) && degree == 0) {
Lon = DEGHALF-(real)(event.x-offsetx)/(real)(chartx-2)*DEGREES;
if (Lon < -DEGHALF)
Lon = -DEGHALF;
else if (Lon > DEGHALF)
Lon = DEGHALF;
Lat = DEGQUAD-(real)(event.y-offsety)/(real)(charty-2)*181.0;
if (Lat < -DEGQUAD)
Lat = -DEGQUAD;
else if (Lat > DEGQUAD)
Lat = DEGQUAD;
xcast = TRUE;
/* Right button means draw lines if not in a world map mode. */
} else if (buttonx >= 0) {
SetPtrVis(HIDE);
DrawColor(coldrw);
_moveto(buttonx, buttony);
_lineto(event.x, event.y);
}
/* Middle button (which most PC's don't have) mean exit program. */
} else if (event.fsBtn == MIDDLE_DOWN)
xbreak = TRUE;
mousex = event.x; mousey = event.y;
SetPtrVis(SHOW);
} else
#endif
if (kbhit()) {
i = getch();
#endif /* MSG */
switch (i) {
case ' ':
xredraw = TRUE;
break;
case 'p':
xpause = !xpause;
break;
case 'r':
dir = -dir;
break;
case 'x':
xreverse = !xreverse;
XColorInit();
xredraw = TRUE;
break;
case 'm':
if (!xmono) {
xcolor = !xcolor;
#ifdef MSG
_getvideoconfig((struct videoconfig far *) &config);
#endif
XColorInit();
xredraw = TRUE;
}
break;
case 'B':
#ifdef X11
XSetWindowBackgroundPixmap(disp, root, pixmap);
XClearWindow(disp, root);
#else
chartx = config.numxpixels;
charty = config.numypixels;
XSquare(&chartx, &charty, FALSE);
xresize = TRUE;
#endif
break;
case 'T':
xtext = !xtext;
xredraw = TRUE;
break;
case 'i':
xbonus = !xbonus;
xredraw = TRUE;
break;
case 'b':
xborder = !xborder;
xredraw = TRUE;
break;
case 'l':
xlabel = !xlabel;
xredraw = TRUE;
break;
case '<':
if (scale > 100) {
scale -= 100;
xresize = TRUE;
}
break;
case '>':
if (scale < 400) {
scale += 100;
xresize = TRUE;
}
break;
case '[':
if (modex == MODEG) {
tilt = tilt > -DEGQUAD ? tilt-11.25 : -DEGQUAD;
xredraw = TRUE;
}
break;
case ']':
if (modex == MODEG) {
tilt = tilt < DEGQUAD ? tilt+11.25 : DEGQUAD;
xredraw = TRUE;
}
break;
case 'Q':
XSquare(&chartx, &charty, TRUE);
xresize = TRUE;
break;
case 'R':
for (i = _CHI; i < THINGS; i++)
ignore[i] = !ignore[i];
ignore[_FOR] = !ignore[_FOR]; ignore[_VTX] = !ignore[_VTX];
xredraw = TRUE;
break;
case 'C':
operation ^= DASHC;
for (i = C_LO; i <= C_HI; i++)
ignore[i] = !(operation & DASHC) || !ignore[i];
xcast = TRUE;
break;
case 'u':
operation ^= DASHu;
for (i = U_LO; i <= U_HI; i++)
ignore[i] = !(operation & DASHu) || !ignore[i];
xcast = TRUE;
break;
case 'U':
universe = !universe;
for (i = S_LO; i <= S_HI; i++)
ignore[i] = !universe || !ignore[i];
xcast = TRUE;
break;
case 'c':
if (!relation) {
relation = DASHr0;
SetTwin(Mon, Day, Yea, Tim, Zon, Lon, Lat);
} else
relation = 0;
xcast = TRUE;
break;
case 's':
operation ^= DASHs;
xcast = TRUE;
break;
case 'h':
centerplanet = centerplanet ? 0 : 1;
xcast = TRUE;
break;
case 'f':
operation ^= DASHf;
xcast = TRUE;
break;
case 'F':
operation ^= DASH3;
xcast = TRUE;
break;
case '+':
Animate(4, abs(dir));
xcast = TRUE;
break;
case '-':
Animate(4, -abs(dir));
xcast = TRUE;
break;
case 'o':
SetSave(Mon, Day, Yea, Tim, Zon, Lon, Lat);
break;
case 'O':
SetMain(MonX, DayX, YeaX, TimX, ZonX, LonX, LatX);
xcast = TRUE;
break;
#ifdef TIME
case 'n':
InputData("now");
SetMain(MM, DD, YY, TT, ZZ, OO, AA);
xcast = TRUE;
break;
#endif
case 'N': /* The continuous update animation. */
xnow = xnow ? 0 : -10;
break;
case '!': xnow = -1; break; /* These are the nine different */
case '@': xnow = -2; break; /* "add time to chart" animations. */
case '#': xnow = -3; break;
case '$': xnow = -4; break;
case '%': xnow = -5; break;
case '^': xnow = -6; break;
case '&': xnow = -7; break;
case '*': xnow = -8; break;
case '(': xnow = -9; break;
case 'V': modex = MODEv; xredraw = TRUE; break; /* Should we go */
case 'L': modex = MODEL; xredraw = TRUE; break; /* switch to a */
case 'A': modex = MODEg; xredraw = TRUE; break; /* new chart type? */
case 'Z': modex = MODEZ; xredraw = TRUE; break;
case 'S': modex = MODES; xredraw = TRUE; break;
case 'E': modex = MODEE; xredraw = TRUE; break;
case 'W': modex = MODEW; xredraw = TRUE; break;
case 'G': modex = MODEG; xredraw = TRUE; break;
case 'P': modex = MODEP; xredraw = TRUE; break;
#ifdef BIORHYTHM
case 'Y': /* Should we switch to biorhythm chart? */
if (!relation) {
SetTwin(Mon, Day, Yea, Tim, Zon, Lon, Lat);
}
relation = DASHrb;
modex = MODEb;
xcast = TRUE;
break;
#endif
case '0':
exdisplay ^= DASHZ0 | DASHEy | DASHXW0;
modex = (modex == MODEv ? MODEw : (modex == MODEw ? MODEv :
modex));
xredraw = TRUE;
break;
case 'v': case 'H': case '?':
#ifdef MSG
_setvideomode(_DEFAULTMODE);
if (i != 'v')
_settextrows(43);
#endif
if (i == 'v')
ChartLocation();
else
XDisplayKeys();
#ifdef MSG
while (!kbhit())
;
i = getch();
if (i == 'q' || i == ESCAPE || i == '\3') {
xbreak = TRUE;
break;
}
XBegin();
xresize = TRUE;
#endif
break;
#ifdef MSG
case '\t':
if (xscreen == hiresmode)
xscreen = loresmode;
else
xscreen = hiresmode;
XBegin();
chartx = config.numxpixels;
charty = config.numypixels;
XSquare(&chartx, &charty, FALSE);
xresize = TRUE;
break;
#endif
case '\b':
#ifdef MSG
#ifdef MOUSE
SetPtrVis(HIDE);
#endif
#endif /* MSG */
DrawClearScreen();
break;
#ifdef MOUSE
case 'z'-'`': coldrw = BLACK; break;
case 'e'-'`': coldrw = MAROON; break;
case 'f'-'`': coldrw = DKGREEN; break;
case 'o'-'`': coldrw = ORANGE; break;
case 'n'-'`': coldrw = DKBLUE; break;
case 'u'-'`': coldrw = PURPLE; break;
case 'k'-'`': coldrw = DKCYAN; break;
case 'l'-'`': coldrw = LTGRAY; break;
case 'd'-'`': coldrw = DKGRAY; break;
case 'r'-'`': coldrw = RED; break;
case 'g'-'`': coldrw = GREEN; break;
case 'y'-'`': coldrw = YELLOW; break;
case 'b'-'`': coldrw = BLUE; break;
case 'v'-'`': coldrw = MAGENTA; break;
case 'j'-'`': coldrw = CYAN; break;
case 'a'-'`': coldrw = WHITE; break;
#ifdef MSG
case 't'-'`':
SetPtrVis(HIDE);
if (buttonx >= 0)
_rectangle(_GBORDER, buttonx, buttony, mousex, mousey);
SetPtrVis(SHOW);
break;
case 'x'-'`':
SetPtrVis(HIDE);
if (buttonx >= 0)
_ellipse(_GBORDER, buttonx, buttony, mousex, mousey);
SetPtrVis(SHOW);
break;
#endif
#endif /* MOUSE */
case 'q': case ESCAPE: case '\3':
xbreak = TRUE;
break;
default:
if (i > '0' && i <= '9') {
#ifdef MSG
if (xnow)
#endif
/* Process numbers 1..9 signifying animation rate. */
dir = (dir > 0 ? 1 : -1)*(i-'0');
#ifdef MSG
else {
/* If we aren't in animation mode, then 1..9 refers to the */
/* clipping "quadrant" to use if chart size > screen size. */
xcorner = i-'0';
xresize = TRUE;
}
#endif
break;
}
printc(BELL); /* Any key not bound will sound a beep. */
} /* switch */
} /* if */
#ifdef X11
default:
;
} /* switch */
} /* if */
#endif
} /* while */
}
/* This is called right before program termination to get rid of the window. */
void XEnd()
{
#ifdef X11
XFreeGC(disp, gc);
XFreeGC(disp, pmgc);
XFreePixmap(disp, pixmap);
XDestroyWindow(disp, window);
XCloseDisplay(disp);
#else
_setvideomode(_DEFAULTMODE);
#endif
}
#endif /* ISG */
/*
******************************************************************************
** Main graphics processing
******************************************************************************
*/
/* Print a list of every command switch dealing with the graphics features */
/* that can be passed to the program, and a description of what it does. */
/* This is part of what the -H switch prints, if graphics were compiled in. */
void XDisplaySwitches()
{
Prints(" _X: Create a graphics chart instead of displaying it as text.");
#ifdef ISG
Prints(" _Xb: Create bitmap file instead of putting graphics on screen.");
#endif
Prints(" _Xb[n,c,v,a,b]: Set bitmap file output mode to X11 normal,");
Prints(" compacted, very compact, Ascii (bmtoa), or Windows bmp.");
#ifdef PS
Prints(" _Xp: Create PostScript stroke graphic instead of bitmap file.");
Prints(" _Xp0: Like _Xp but create complete instead of encapsulated file.");
#endif
#ifdef META
Prints(" _XM[0]: Create Windows metafile stroke graphic instead of bitmap.");
#endif
Prints(" _Xo <file>: Write output bitmap or graphic to specified file.");
#ifdef X11
Prints(" _XB: Display X chart on root instead of in a separate window.");
#endif
Prints(" _Xm: Create monochrome graphic instead of one in color.");
Prints(" _Xr: Create chart graphic in reversed colors (white background).");
#ifdef X11
Prints(" _Xw <hor> [<ver>], _ge[..]: Change the size of chart graphic.");
#else
Prints(" _Xw <hor> [<ver>]: Change the size of chart graphic.");
#endif
Prints(" _Xs <100,200,300,400>: Change the size of map or characters by %.");
Prints(" _Xi: Create chart graphic in slightly modified form.");
Prints(" _XT: Inhibit display of chart info at bottom of graphic.");
Prints(" _Xl: Inhibit labeling of object points in chart graphic.");
Prints(" _X1 <object>: Rotate wheel charts so object is at left edge.");
Prints(" _X2 <object>: Rotate wheel charts so object is at top edge.");
#ifdef X11
Prints(" _Xd <name>, _di[..] <name>: Open X window on specified display.");
#endif
Prints(" _XW: Simply create an image of the world map.");
Prints(" _XW0: Like _XW but do a non-rectangular Mollewide projection.");
Prints(" _XP: Create just the world map, but from a polar projection.");
Prints(" _XG [<degrees>]: Display the image of the world as a globe.");
#ifdef ISG
Prints(" _Xn [<mode>]: Start up chart or globe display in animation mode.");
Prints("Also, press 'H' while running for list of key press options.");
#endif
}
/* Process a command line switch passed to the program dealing with the */
/* graphics features. This is just like the processing of each switch in the */
/* main program; however, here each switch has been prefixed with an 'X'. */
int XProcessSwitches(argc, argv, pos)
int argc, pos;
char **argv;
{
int i = 0;
char string[STRING], c;
switch (argv[0][pos]) {
case '\0':
break;
case 'b':
c = CAP(argv[0][pos+1]);
if (IsValidBmpmode(c))
bitmapmode = c;
xbitmap = TRUE;
psfile = metafile = FALSE;
break;
#ifdef PS
case 'p':
psfile = TRUE + (argv[0][pos+1] != '0');
xbitmap = metafile = FALSE;
break;
#endif
#ifdef META
case 'M':
if (argv[0][pos+1] == '0')
xfont = !xfont;
metafile = TRUE;
xbitmap = psfile = FALSE;
break;
#endif
case 'o':
if (argc <= 1) {
TooFew("Xo");
return -1;
}
if (!xbitmap && !psfile && !metafile)
xbitmap = TRUE;
outputfile = argv[1];
i++;
break;
#ifdef X11
case 'B':
xroot = !xroot;
break;
#endif
case 'm':
xcolor = !xcolor;
break;
case 'r':
xreverse = !xreverse;
break;
case 'w':
if (argc <= 1) {
TooFew("Xw");
return -1;
}
chartx = atoi(argv[1]);
if (argc > 2 && (charty = atoi(argv[2]))) {
argc--; argv++;
i++;
} else
charty = chartx;
if (!IsValidGraphx(chartx)) {
BadVal("Xw", chartx);
return -1;
}
if (!IsValidGraphy(charty)) {
BadVal("Xw", charty);
return -1;
}
i++;
break;
case 's':
if (argc <= 1) {
TooFew("Xs");
return -1;
}
scale = atoi(argv[1]);
if (scale < 100)
scale *= 100;
if (!IsValidScale(scale)) {
BadVal("Xs", scale);
return -1;
}
i++;
break;
case 'i':
xbonus = !xbonus;
break;
case 'T':
xtext = !xtext;
break;
case 'l':
xlabel = !xlabel;
break;
case '1':
if (argc <= 1) {
TooFew("X1");
return -1;
}
xeast = atoi(argv[1]);
if (!IsItem(xeast)) {
BadVal("X1", xeast);
return -1;
}
i++;
break;
case '2':
if (argc <= 1) {
TooFew("X2");
return -1;
}
xeast = atoi(argv[1]);
if (!IsItem(xeast)) {
BadVal("X2", xeast);
return -1;
}
xeast = -xeast;
i++;
break;
case 'd':
if (argc <= 1) {
TooFew("Xd");
return -1;
}
dispname = argv[1];
i++;
break;
case 'W':
if (argc > 1 && ((degree = atoi(argv[1])) || argv[1][0] == '0')) {
i++;
if (degree < 0 || degree >= DEGD) {
BadVal("XW", degree);
return -1;
}
} else
degree = 0;
modex = MODEW;
if (argv[0][pos+1] == '0')
exdisplay |= DASHXW0;
autom = TRUE;
break;
case 'P':
if (argc > 1 && ((degree = atoi(argv[1])) || argv[1][0] == '0')) {
i++;
if (degree < 0 || degree >= DEGD) {
BadVal("XP", degree);
return -1;
}
} else
degree = 0;
modex = MODEP;
if (argv[0][pos+1] == '0')
exdisplay |= DASHXP0;
autom = TRUE;
break;
case 'G':
if (argc > 1 && ((degree = atoi(argv[1])) || argv[1][0] == '0')) {
i++;
if (degree < 0 || degree >= DEGD) {
BadVal("XG", degree);
return -1;
}
if (argc > 2 && ((tilt = atof(argv[2])) || argv[2][0] == '0')) {
i++;
if (tilt < -DEGQUAD || tilt > DEGQUAD) {
BadVal2("XG", tilt);
return -1;
}
}
}
modex = MODEG;
autom = TRUE;
break;
#ifdef ISG
case 'n':
if (argc > 1 && (xnow = atoi(argv[1])))
i++;
else
xnow = 10;
if (xnow < 1 || xnow > 10) {
BadVal("Xn", xnow);
return -1;
}
break;
#endif
default:
sprintf(string, "Unknown switch '%s'", argv[0]);
PrintError(string);
return -1;
}
return i; /* 'i' contains the value to be added to argc when we return. */
}
/* This is the main interface to all the graphics features. This routine */
/* is called from the main program if any of the -X switches were specified, */
/* and it sets up for and goes and generates the appropriate graphics chart. */
/* We return TRUE if successfull, FALSE if some non-fatal error occurred. */
bool XAction()
{
char string[STRING];
xfile = (xbitmap || psfile || metafile);
/* First figure out what graphic mode to generate the chart in, based on */
/* various non-X command switches, e.g. -L combined with -X, -g combined */
/* with -X, and so on, and determine the size the window is to be, too. */
if (modex == MODEv) {
if (todisplay & DASHw)
modex = MODEw;
else if (todisplay & DASHL)
modex = MODEL;
else if ((todisplay & DASHg) | (todisplay & DASHm)) {
modex = MODEg;
if (relation <= DASHr0 &&
(todisplay & DASHm) > 0 && (exdisplay & DASHm0) == 0)
exdisplay |= DASHg0;
chartx = charty =
(gridobjects + (relation <= DASHr0))*CELLSIZE*SCALE + 1;
} else if (todisplay & DASHZ)
modex = MODEZ;
else if (todisplay & DASHS)
modex = MODES;
else if (todisplay & DASHE)
modex = MODEE;
else if (relation == DASHrb)
modex = MODEb;
}
if (ISSIDEBAR)
chartx += SIDESIZE;
if (modex == MODEL || modex == MODEW) {
chartx = DEGD*SCALE+2;
charty = (90*2+1)*SCALE+2;
}
scalet = psfile ? PSMUL : (metafile ? METAMUL : 1);
if (xfile) {
if (chartx > BITMAPX)
chartx = BITMAPX;
if (charty > BITMAPY)
charty = BITMAPY;
if (xbitmap) {
bitmaprow = (chartx + 1) >> 1;
Allocate(bm, (long)bitmaprow * charty, bitmap);
if (bm == NULL) {
sprintf(string,
"Not enough memory for %d by %d bitmap (%ld bytes).",
chartx, charty, (long)bitmaprow * charty);
PrintError(string);
return FALSE;
}
}
#ifdef PS
else if (psfile)
PSbegin();
#endif
else {
Allocate(bm, MAXMETA, bitmap);
if (bm == NULL) {
sprintf(string,
"Not enough memory for metafile. (%ld bytes.)", MAXMETA);
PrintError(string);
return FALSE;
}
chartx *= METAMUL; /* Increase chart sizes and scales behind the */
charty *= METAMUL; /* scenes to make graphics look smoother. */
scale *= METAMUL;
}
XColorInit();
}
#ifdef ISG
else
XBegin();
#endif
if (xroot || xfile) /* Go draw the graphic chart. */
XChart();
if (xfile) { /* Write bitmap to file if in that mode. */
WriteFile();
if (!psfile)
Deallocate(bm);
}
#ifdef ISG
else {
#ifdef X11
if (xroot) {
XSetWindowBackgroundPixmap(disp, root, pixmap); /* Process -XB. */
XClearWindow(disp, root);
/* If -Xn in effect with -XB, then enter infinite loop where we */
/* calculate and animate chart, displaying on the root window. */
if (xnow)
loop {
Animate(xnow, 1);
if (relation > DASHr0 || (modex != MODEZ && modex != MODES))
XFillRectangle(disp, pixmap, pmgc, 0, 0, chartx, charty);
XChart();
XSetWindowBackgroundPixmap(disp, root, pixmap);
XClearWindow(disp, root);
}
} else
#endif
XSpin(); /* Window's up; process commands given to window now. */
XEnd();
}
#endif /* ISG */
return TRUE;
}
#endif /* GRAPH */
/* xdriver.c */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.