📄 xdriver.c
字号:
/*
** Astrolog (Version 4.00) File: xdriver.c
**
** IMPORTANT NOTICE: the graphics database and chart display routines
** used in this program are Copyright (C) 1991-1993 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 12/31/1993.
*/
#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 += 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 >= DEGR) /* For animating globe display, add */
degree -= DEGR; /* in appropriate degree value. */
else if (degree < 0)
degree += DEGR;
} 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 update 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 */
}
/* 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,
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 = DEGR*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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -