Files
nethack/win/X11/winstat.c
PatR 3546b2f016 X11 'fancy' status condition highlighting
X11's "fancy status" does its own highlighting that predates
STATUS_HILITES, showing things which have changed in inverse video
for a turn.  However, it excluded conditions plus hunger and
encumbrance.  Make it highlight those similarly when they come On
(and when they change from one non-blank state to another in the
case of hunger or encumbrance).  There's no corresponding
unhighlight when going Off because they're blanked out instead.
2020-03-17 15:04:54 -07:00

2236 lines
73 KiB
C

/* NetHack 3.6 winstat.c $NHDT-Date: 1584482684 2020/03/17 22:04:44 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.26 $ */
/* Copyright (c) Dean Luick, 1992 */
/* NetHack may be freely redistributed. See license for details. */
/*
* Status window routines. This file supports both the "traditional"
* tty status display and a "fancy" status display. A tty status is
* made if a popup window is requested, otherewise a fancy status is
* made. This code assumes that only one fancy status will ever be made.
* Currently, only one status window (of any type) is _ever_ made.
*/
#ifndef SYSV
#define PRESERVE_NO_SYSV /* X11 include files may define SYSV */
#endif
#include <X11/Intrinsic.h>
#include <X11/IntrinsicP.h> /* for XtResizeWidget() and XtConfigureWidget() */
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Cardinals.h> /* just for ONE, TWO */
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Viewport.h>
/*#include <X11/Xatom.h>*/
#ifdef PRESERVE_NO_SYSV
#ifdef SYSV
#undef SYSV
#endif
#undef PRESERVE_NO_SYSV
#endif
#include "hack.h"
#include "winX.h"
#include "xwindow.h"
/*
* Fancy status form entry storage indices.
*/
#define F_DUMMY 0
#define F_STR 1
#define F_DEX 2
#define F_CON 3
#define F_INT 4
#define F_WIS 5
#define F_CHA 6
#define F_NAME 7 /* title: "Name the Rank" where rank is role-specific */
#define F_DLEVEL 8 /* location: dungeon branch and level */
#define F_GOLD 9
#define F_HP 10
#define F_MAXHP 11
#define F_POWER 12
#define F_MAXPOWER 13
#define F_AC 14
#define F_XP_LEVL 15
/*#define F_HD F_XP_LEVL*/
#define F_EXP_PTS 16
#define F_ALIGN 17
#define F_TIME 18
#define F_SCORE 19
/* status conditions grouped by columns; tty orders these differently;
hunger/encumbrance/movement used to be in the middle with fatal
conditions on the left but those columns have been swapped and
renumbered to match new order (forcing shown_stat[] to be reordered) */
#define F_HUNGER 20
#define F_ENCUMBER 21
#define F_TRAPPED 22
#define F_LEV 23
#define F_FLY 24
#define F_RIDE 25
#define F_GRABBED 26
#define F_STONE 27
#define F_SLIME 28
#define F_STRNGL 29
#define F_FOODPOIS 30
#define F_TERMILL 31
#define F_IN_LAVA 32
#define F_HELD 33
#define F_BLIND 34
#define F_DEAF 35
#define F_STUN 36
#define F_CONF 37
#define F_HALLU 38
#define NUM_STATS 39
static int FDECL(condcolor, (long, unsigned long *));
static int FDECL(condattr, (long, unsigned long *));
static void FDECL(HiliteField, (Widget, int, int, int, XFontStruct **));
static void FDECL(PrepStatusField, (int, Widget, const char *));
static void FDECL(DisplayCond, (int, unsigned long *));
static int FDECL(render_conditions, (int, int));
#ifdef STATUS_HILITES
static void FDECL(tt_reset_color, (int, int, unsigned long *));
#endif
static void NDECL(tt_status_fixup);
static Widget FDECL(create_tty_status_field, (int, int, Widget, Widget));
static Widget FDECL(create_tty_status, (Widget, Widget));
static void FDECL(update_fancy_status_field, (int));
static void FDECL(update_fancy_status, (BOOLEAN_P));
static Widget FDECL(create_fancy_status, (Widget, Widget));
static void FDECL(destroy_fancy_status, (struct xwindow *));
static void FDECL(create_status_window_fancy, (struct xwindow *,
BOOLEAN_P, Widget));
static void FDECL(create_status_window_tty, (struct xwindow *,
BOOLEAN_P, Widget));
static void FDECL(destroy_status_window_fancy, (struct xwindow *));
static void FDECL(destroy_status_window_tty, (struct xwindow *));
static void FDECL(adjust_status_fancy, (struct xwindow *, const char *));
static void FDECL(adjust_status_tty, (struct xwindow *, const char *));
extern const char *status_fieldfmt[MAXBLSTATS];
extern char *status_vals[MAXBLSTATS];
extern boolean status_activefields[MAXBLSTATS];
static unsigned long X11_condition_bits, old_condition_bits;
static int X11_status_colors[MAXBLSTATS],
old_field_colors[MAXBLSTATS],
old_cond_colors[32];
static int hpbar_percent, hpbar_color;
/* Number of conditions displayed during this update and last update.
When the last update had more, the excess need to be erased. */
static int next_cond_indx = 0, prev_cond_indx = 0;
/* TODO: support statuslines:3 in addition to 2 for the tty-style status */
#define X11_NUM_STATUS_LINES 2
#define X11_NUM_STATUS_FIELD 15
static enum statusfields X11_fieldorder[][X11_NUM_STATUS_FIELD] = {
{ BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN,
BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH,
BL_FLUSH },
{ BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX,
BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER,
BL_CAP, BL_CONDITION, BL_FLUSH }
};
/* condition list for tty-style display, roughly in order of importance */
static struct tt_condinfo {
unsigned long mask;
const char *text;
} tt_condorder[] = {
{ BL_MASK_GRAB, "Grab!" },
{ BL_MASK_STONE, "Stone" },
{ BL_MASK_SLIME, "Slime" },
{ BL_MASK_STRNGL, "Strngl" },
{ BL_MASK_FOODPOIS, "FoodPois" },
{ BL_MASK_TERMILL, "TermIll" },
{ BL_MASK_INLAVA, "Lava" },
{ BL_MASK_HELD, "Held" },
{ BL_MASK_BLIND, "Blind" },
{ BL_MASK_DEAF, "Deaf" },
{ BL_MASK_STUN, "Stun" },
{ BL_MASK_CONF, "Conf" },
{ BL_MASK_HALLU, "Hallu" },
{ BL_MASK_TRAPPED, "Trap" },
{ BL_MASK_LEV, "Lev" },
{ BL_MASK_FLY, "Fly" },
{ BL_MASK_RIDE, "Ride" },
};
static Widget X11_status_widget;
static Widget X11_status_labels[MAXBLSTATS];
static Widget X11_cond_labels[32]; /* Ugh */
static XFontStruct *X11_status_font;
static Pixel X11_status_fg, X11_status_bg;
struct xwindow *xw_status_win;
static int
condcolor(bm, bmarray)
long bm;
unsigned long *bmarray;
{
int i;
if (bm && bmarray)
for (i = 0; i < CLR_MAX; ++i) {
if (bmarray[i] && (bm & bmarray[i]))
return i;
}
return NO_COLOR;
}
static int
condattr(bm, bmarray)
long bm;
unsigned long *bmarray;
{
int attr = 0;
int i;
if (bm && bmarray) {
for (i = HL_ATTCLR_DIM; i < BL_ATTCLR_MAX; ++i) {
if (bmarray[i] && (bm & bmarray[i])) {
switch(i) {
case HL_ATTCLR_DIM:
attr |= HL_DIM;
break;
case HL_ATTCLR_BLINK:
attr |= HL_BLINK;
break;
case HL_ATTCLR_ULINE:
attr |= HL_ULINE;
break;
case HL_ATTCLR_INVERSE:
attr |= HL_INVERSE;
break;
case HL_ATTCLR_BOLD:
attr |= HL_BOLD;
break;
}
}
}
}
return attr;
}
void
X11_status_init()
{
int i;
/* no color and no attributes */
for (i = 0; i < MAXBLSTATS; ++i)
X11_status_colors[i] = old_field_colors[i] = NO_COLOR;
for (i = 0; i < SIZE(old_cond_colors); ++i)
old_cond_colors[i] = NO_COLOR;
hpbar_percent = 0, hpbar_color = NO_COLOR;
X11_condition_bits = old_condition_bits = 0L;
/* let genl_status_init do most of the initialization */
genl_status_init();
}
void
X11_status_finish()
{
/* nothing */
return;
}
void
X11_status_enablefield(fieldidx, nm, fmt, enable)
int fieldidx;
const char *nm;
const char *fmt;
boolean enable;
{
genl_status_enablefield(fieldidx, nm, fmt, enable);
}
#if 0
int
cond_bm2idx(bm)
unsigned long bm;
{
int i;
for (i = 0; i < 32; i++)
if ((1 << i) == bm)
return i;
return -1;
}
#endif
/* highlight a tty-style status field (or condition) */
static void
HiliteField(label, fld, cond, colrattr, font_p)
Widget label;
int fld, cond, colrattr;
XFontStruct **font_p;
{
#ifdef STATUS_HILITES
static Pixel grayPxl, blackPxl, whitePxl;
Arg args[6];
Cardinal num_args;
XFontStruct *font = X11_status_font;
Pixel px, fg = X11_status_fg, bg = X11_status_bg;
struct xwindow *xw = xw_status_win;
int colr, attr;
#ifdef TEXTCOLOR
if ((colrattr & 0x00ff) >= CLR_MAX)
/* for !TEXTCOLOR, the following line is unconditional */
#endif
colrattr = (colrattr & ~0x00ff) | NO_COLOR;
colr = colrattr & 0x00ff; /* guaranteed to be >= 0 and < CLR_MAX */
attr = (colrattr >> 8) & 0x00ff;
/* potentially used even for !TEXTCOLOR configuration */
if (!grayPxl) {/* one-time init */
grayPxl = get_nhcolor(xw, CLR_GRAY).pixel;
blackPxl = get_nhcolor(xw, CLR_BLACK).pixel;
whitePxl = get_nhcolor(xw, CLR_WHITE).pixel;
}
/* [shouldn't be necessary; setting up gray will set up all colors] */
if (colr != NO_COLOR && !xw->nh_colors[colr].pixel)
(void) get_nhcolor(xw, colr);
/* handle highlighting if caller has specified that; set foreground,
background, and font even if not specified this time in case they
used modified values last time (which would stick if not reset) */
(void) memset((genericptr_t) args, 0, sizeof args);
num_args = 0;
if (colr != NO_COLOR)
fg = xw->nh_colors[colr].pixel;
if ((attr & HL_INVERSE) != 0) {
px = fg;
fg = bg;
bg = px;
}
/* foreground and background might both default to black, so we
need to force one to be different if/when they're the same
(actually, tt_status_fixup() takes care of that nowadays);
using gray to implement 'dim' only works for black and white
(or color+'inverse' when former background was black or white) */
if (fg == bg
|| ((attr & HL_DIM) != 0 && (fg == whitePxl || fg == blackPxl)))
fg = (fg != grayPxl) ? grayPxl
: (fg != blackPxl) ? blackPxl
: whitePxl;
XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++;
XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++;
if (attr & HL_BOLD) {
load_boldfont(xw_status_win, label);
if (xw_status_win->boldfs)
font = xw_status_win->boldfs;
}
XtSetArg(args[num_args], nhStr(XtNfont), font); num_args++;
XtSetValues(label, args, num_args);
/* return possibly modified font to caller so that text width
measurement can use it */
if (font_p)
*font_p = font;
#else /*!STATUS_HILITES*/
nhUse(label);
nhUse(font_p);
#endif /*?STATUS_HILITES*/
if (fld != BL_CONDITION)
old_field_colors[fld] = colrattr;
else
old_cond_colors[cond] = colrattr;
}
/* set up a specific field other than 'condition'; its general location
was specified during widget creation but it might need adjusting */
static void
PrepStatusField(fld, label, text)
int fld;
Widget label;
const char *text;
{
Arg args[6];
Cardinal num_args;
Dimension lbl_wid;
XFontStruct *font = X11_status_font;
int colrattr = X11_status_colors[fld];
struct status_info_t *si = xw_status_win->Win_info.Status_info;
/* highlight if color and/or attribute(s) are different from last time */
if (colrattr != old_field_colors[fld])
HiliteField(label, fld, 0, colrattr, &font);
num_args = 0;
(void) memset((genericptr_t) args, 0, sizeof args);
/* set up the current text to be displayed */
if (text && *text) {
lbl_wid = 2 * si->in_wd + XTextWidth(font, text, (int) strlen(text));
} else {
text = "";
lbl_wid = 1;
}
XtSetArg(args[num_args], nhStr(XtNlabel), text); num_args++;
/*XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++;*/
XtSetValues(label, args, num_args);
XtResizeWidget(label, lbl_wid, si->ht, si->brd);
}
/* set up one status condition for tty-style status display */
static void
DisplayCond(c_idx, colormasks)
int c_idx; /* index into tt_condorder[] */
unsigned long *colormasks;
{
Widget label;
Arg args[6];
Cardinal num_args;
Dimension lbl_wid;
XFontStruct *font = X11_status_font;
int coloridx, attrmask, colrattr, idx;
unsigned long bm = tt_condorder[c_idx].mask;
const char *text = tt_condorder[c_idx].text;
struct status_info_t *si = xw_status_win->Win_info.Status_info;
if ((X11_condition_bits & bm) == 0)
return;
/* widgets have been created for every condition; we allocate them
from left to right rather than keeping their original assignments */
idx = next_cond_indx;
label = X11_cond_labels[idx];
/* handle highlighting if caller requests it */
coloridx = condcolor(bm, colormasks);
attrmask = condattr(bm, colormasks);
colrattr = (attrmask << 8) | coloridx;
if (colrattr != old_cond_colors[c_idx])
HiliteField(label, BL_CONDITION, c_idx, colrattr, &font);
(void) memset((genericptr_t) args, 0, sizeof args);
num_args = 0;
/* set the condition text and its width; this widget might have
been displaying a different condition last time around */
XtSetArg(args[num_args], nhStr(XtNlabel), text); num_args++;
/* measure width after maybe changing font [HiliteField()] */
lbl_wid = 2 * si->in_wd + XTextWidth(font, text, (int) strlen(text));
/*XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++;*/
/* make this condition widget be ready for display */
XtSetValues(label, args, num_args);
XtResizeWidget(label, lbl_wid, si->ht, si->brd);
++next_cond_indx;
}
/* display the tty-style status conditions; the number shown varies and
we might be showing more, same, or fewer than during previous status */
static int
render_conditions(row, dx)
int row, dx;
{
Widget label;
Arg args[6];
Cardinal num_args;
Position lbl_x;
int i, gap = 5;
struct status_info_t *si = xw_status_win->Win_info.Status_info;
Dimension lbl_wid, brd_wid = si->brd;
for (i = 0; i < next_cond_indx; i++) {
label = X11_cond_labels[i];
/* width of this widget was set in DisplayCond(); fetch it */
(void) memset((genericptr_t) args, 0, sizeof args);
num_args = 0;
XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++;
XtGetValues(label, args, num_args);
/* figure out where to draw this widget and place it there */
lbl_x = (Position) (dx + 1 + gap);
XtConfigureWidget(label, lbl_x, si->y[row], lbl_wid, si->ht, brd_wid);
/* keep track of where the end of our text appears */
dx = (int) lbl_x + (int) (lbl_wid + 2 * brd_wid) - 1;
}
/* if we have fewer conditions shown now than last time, set the
excess ones to blank; unlike the set drawn above, these haven't
been prepared in advance by DisplayCond because they aren't
being displayed; they might have been highlighted last time so
we need to specify more than just an empty text string */
if (next_cond_indx < prev_cond_indx) {
XFontStruct *font = X11_status_font;
Pixel fg = X11_status_fg, bg = X11_status_bg;
lbl_x = dx + 1;
lbl_wid = 1 + 2 * brd_wid;
for (i = next_cond_indx; i < prev_cond_indx; ++i) {
label = X11_cond_labels[i];
(void) memset((genericptr_t) args, 0, sizeof args);
num_args = 0;
XtSetArg(args[num_args], nhStr(XtNlabel), ""); num_args++;
XtSetArg(args[num_args], nhStr(XtNfont), font); num_args++;
XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++;
XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++;
/*XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++;*/
/*XtSetArg(args[num_args], nhStr(XtNx), lbl_x); num_args++;*/
XtSetValues(label, args, num_args);
old_cond_colors[i] = NO_COLOR; /* fg, bg, font were just reset */
XtConfigureWidget(label, lbl_x, si->y[row], lbl_wid, si->ht, 0);
/* don't advance 'dx' here */
}
}
return dx;
}
#ifdef STATUS_HILITES
/* reset status_hilite for BL_RESET; if highlighting has been disabled or
this field is disabled, clear highlighting for this field or condition */
static void
tt_reset_color(fld, cond, colormasks)
int fld, cond;
unsigned long *colormasks;
{
Widget label;
int colrattr = NO_COLOR;
if (fld != BL_CONDITION) {
if (iflags.hilite_delta != 0L && status_activefields[fld])
colrattr = X11_status_colors[fld];
cond = 0;
label = X11_status_labels[fld];
} else {
unsigned long bm = tt_condorder[cond].mask;
if (iflags.hilite_delta != 0L && (X11_condition_bits & bm) != 0) {
/* BL_RESET before first BL_CONDITION will have colormasks==Null
but condcolor() and condattr() can cope with that */
#ifdef TEXTCOLOR
colrattr = condcolor(bm, colormasks);
#endif
colrattr |= (condattr(bm, colormasks) << 8);
}
label = X11_cond_labels[cond];
}
HiliteField(label, fld, cond, colrattr, (XFontStruct **) 0);
}
#endif
/* make sure foreground, background, and font have reasonable values,
then explicitly set them for all the status widgets;
also cache some geometry settings in (*xw_status_win).Status_info */
static void
tt_status_fixup()
{
Arg args[6];
Cardinal num_args;
Widget w;
Position lbl_y;
int x, y, ci, fld;
XFontStruct *font = 0;
Pixel fg = 0, bg = 0;
struct status_info_t *si = xw_status_win->Win_info.Status_info;
(void) memset((genericptr_t) args, 0, sizeof args);
num_args = 0;
XtSetArg(args[num_args], nhStr(XtNfont), &font); num_args++;
XtSetArg(args[num_args], nhStr(XtNforeground), &fg); num_args++;
XtSetArg(args[num_args], nhStr(XtNbackground), &bg); num_args++;
XtGetValues(X11_status_widget, args, num_args);
if (fg == bg) {
XColor black = get_nhcolor(xw_status_win, CLR_BLACK),
white = get_nhcolor(xw_status_win, CLR_WHITE);
fg = (bg == white.pixel) ? black.pixel : white.pixel;
}
X11_status_fg = si->fg = fg, X11_status_bg = si->bg = bg;
if (!font) {
w = X11_status_widget;
XtSetArg(args[0], nhStr(XtNfont), &font);
do {
XtGetValues(w, args, ONE);
} while (!font && (w = XtParent(w)) != 0);
if (!font) {
/* trial and error time -- this is where we've actually
been obtaining the font even though we aren't setting
it for any of the field widgets (until for(y,x) below) */
XtGetValues(X11_status_labels[0], args, ONE);
if (!font) { /* this bit is untested... */
/* write some text and hope Xaw sets up font for us */
XtSetArg(args[0], nhStr(XtNlabel), "NetHack");
XtSetValues(X11_status_labels[0], args, ONE);
(void) XFlush(XtDisplay(X11_status_labels[0]));
XtSetArg(args[0], nhStr(XtNfont), &font);
XtGetValues(X11_status_labels[0], args, ONE);
/* if still Null, XTextWidth() would crash so bail out */
if (!font)
panic("X11 status can't determine font.");
}
}
}
X11_status_font = si->fs = font;
/* amount of space to advance a widget's location by one space;
increase width a tiny bit beyond the actual space */
si->spacew = XTextWidth(X11_status_font, " ", 1) + (Dimension) 1;
(void) memset((genericptr_t) args, 0, sizeof args);
num_args = 0;
XtSetArg(args[num_args], nhStr(XtNfont), font); num_args++;
XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++;
XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++;
XtSetValues(X11_status_widget, args, num_args);
for (y = 0; y < X11_NUM_STATUS_LINES; y++) {
for (x = 0; x < X11_NUM_STATUS_FIELD; x++) {
fld = X11_fieldorder[y][x]; /* next field to handle */
if (fld <= BL_FLUSH)
continue; /* skip fieldorder[][] padding */
XtSetValues(X11_status_labels[fld], args, num_args);
old_field_colors[fld] = NO_COLOR;
if (fld == BL_CONDITION) {
for (ci = 0; ci < SIZE(X11_cond_labels); ++ci) { /* 0..31 */
XtSetValues(X11_cond_labels[ci], args, num_args);
old_cond_colors[ci] = NO_COLOR;
}
}
}
}
/* cache the y coordinate of each row for XtConfigureWidget() */
(void) memset((genericptr_t) args, 0, sizeof args);
num_args = 0;
XtSetArg(args[0], nhStr(XtNy), &lbl_y); num_args++;
for (y = 0; y < X11_NUM_STATUS_LINES; y++) {
fld = X11_fieldorder[y][0];
XtGetValues(X11_status_labels[fld], args, num_args);
si->y[y] = lbl_y;
}
/* cache height, borderWidth, and internalWidth for XtResizeWidget() */
(void) memset((genericptr_t) args, 0, sizeof args);
num_args = 0;
XtSetArg(args[num_args], nhStr(XtNheight), &si->ht); num_args++;
XtSetArg(args[num_args], nhStr(XtNborderWidth), &si->brd); num_args++;
XtSetArg(args[num_args], nhStr(XtNinternalWidth), &si->in_wd); num_args++;
XtGetValues(X11_status_labels[0], args, num_args);
}
/* core requests updating one status field (or is indicating that it's time
to flush all updated fields); tty-style handling */
static void
X11_status_update_tty(fld, ptr, chg, percent, color, colormasks)
int fld, chg UNUSED, percent, color;
genericptr_t ptr;
unsigned long *colormasks; /* bitmask of highlights for conditions */
{
static int xtra_space[MAXBLSTATS];
static unsigned long *cond_colormasks = (unsigned long *) 0;
Arg args[6];
Cardinal num_args;
Position lbl_x;
Dimension lbl_wid, brd_wid;
Widget label;
struct status_info_t *si;
char goldbuf[40];
const char *fmt;
const char *text;
unsigned long *condptr;
int f, x, y, dx;
if (X11_status_fg == X11_status_bg || !X11_status_font)
tt_status_fixup();
if (fld == BL_RESET) {
#ifdef STATUS_HILITES
for (y = 0; y < X11_NUM_STATUS_LINES; y++) {
for (x = 0; x < X11_NUM_STATUS_FIELD; x++) {
f = X11_fieldorder[y][x];
if (f <= BL_FLUSH)
continue; /* skip padding in the fieldorder[][] layout */
if (f != BL_CONDITION) {
tt_reset_color(f, 0, (unsigned long *) 0);
} else {
int c_i;
for (c_i = 0; c_i < SIZE(tt_condorder); ++c_i)
tt_reset_color(f, c_i, cond_colormasks);
}
}
}
#endif
fld = BL_FLUSH;
}
if (fld == BL_CONDITION) {
condptr = (unsigned long *) ptr;
X11_condition_bits = *condptr;
cond_colormasks = colormasks; /* expected to be non-Null */
prev_cond_indx = next_cond_indx;
next_cond_indx = 0;
/* if any conditions are active, set up their widgets */
if (X11_condition_bits)
for (f = 0; f < SIZE(tt_condorder); ++f)
DisplayCond(f, cond_colormasks);
return;
} else if (fld != BL_FLUSH) {
/* set up a specific field other than 'condition' */
text = (char *) ptr;
if (fld == BL_GOLD)
text = decode_mixed(goldbuf, text);
xtra_space[fld] = 0;
if (status_activefields[fld]) {
fmt = (fld == BL_TITLE && iflags.wc2_hitpointbar) ? "%-30s"
: status_fieldfmt[fld] ? status_fieldfmt[fld] : "%s";
if (*fmt == ' ') {
++xtra_space[fld];
++fmt;
}
Sprintf(status_vals[fld], fmt, text);
} else {
/* don't expect this since core won't call status_update()
for a field which isn't active */
*status_vals[fld] = '\0';
}
#ifndef TEXTCOLOR
/* even without color, attribute(s) bits still apply */
color = (color & ~0x00ff) | NO_COLOR;
#endif
#ifdef STATUS_HILITES
if (!iflags.hilite_delta)
color = NO_COLOR;
#endif
X11_status_colors[fld] = color;
if (iflags.wc2_hitpointbar && fld == BL_HP) {
hpbar_percent = percent;
hpbar_color = color;
}
label = X11_status_labels[fld];
text = status_vals[fld];
PrepStatusField(fld, label, text);
return;
}
/*
* BL_FLUSH: draw all the status fields.
*/
si = xw_status_win->Win_info.Status_info; /* for cached geometry */
for (y = 0; y < X11_NUM_STATUS_LINES; y++) { /* row */
dx = 0; /* no pixels written to this row yet */
for (x = 0; x < X11_NUM_STATUS_FIELD; x++) { /* 'column' */
f = X11_fieldorder[y][x];
if (f <= BL_FLUSH)
continue; /* skip padding in the fieldorder[][] layout */
if (f == BL_CONDITION) {
if (next_cond_indx > 0 || prev_cond_indx > 0)
dx = render_conditions(y, dx);
continue;
}
label = X11_status_labels[f];
text = status_vals[f];
(void) memset((genericptr_t) args, 0, sizeof args);
num_args = 0;
XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++;
XtGetValues(label, args, num_args);
brd_wid = si->brd;
/* for a field which shouldn't be shown, we can't just skip
it because we might need to remove its previous content
if it has just been toggled off */
if (!status_activefields[f]) {
if (lbl_wid <= 1)
continue;
text = "";
lbl_wid = (Dimension) 1;
brd_wid = (Dimension) 0;
} else if (xtra_space[f]) {
/* if this field was to be formatted with a leading space
to separate it from the preceding field, we suppressed
that space during formatting; insert separation between
fields here; this prevents inverse video highlighting
from inverting the separating space along with the text */
dx += xtra_space[f] * si->spacew;
}
/* where to display the current widget */
lbl_x = (Position) (dx + 1);
(void) memset((genericptr_t) args, 0, sizeof args);
num_args = 0;
XtSetArg(args[num_args], nhStr(XtNlabel), text); num_args++;
/*XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++;*/
/*XtSetArg(args[num_args], nhStr(XtNx), lbl_x); num_args++;*/
XtSetValues(label, args, num_args);
XtConfigureWidget(label, lbl_x, si->y[y],
lbl_wid, si->ht, brd_wid);
/* track the right-most pixel written so far */
dx = (int) lbl_x + (int) (lbl_wid + 2 * brd_wid) - 1;
} /* [x] fields/columns in current row */
} /* [y] rows */
/* this probably doesn't buy us anything but it isn't a sure thing
that nethack will immediately ask for input (triggering auto-flush) */
(void) XFlush(XtDisplay(X11_status_labels[0]));
}
/*ARGSUSED*/
static void
X11_status_update_fancy(fld, ptr, chg, percent, color, colormasks)
int fld, chg UNUSED, percent UNUSED, color UNUSED;
genericptr_t ptr;
unsigned long *colormasks UNUSED;
{
static const struct bl_to_ff {
int bl, ff;
} bl_to_fancyfield[] = {
{ BL_TITLE, F_NAME },
{ BL_STR, F_STR },
{ BL_DX, F_DEX },
{ BL_CO, F_CON },
{ BL_IN, F_INT },
{ BL_WI, F_WIS },
{ BL_CH, F_CHA },
{ BL_ALIGN, F_ALIGN },
{ BL_SCORE, F_SCORE },
{ BL_CAP, F_ENCUMBER },
{ BL_GOLD, F_GOLD },
{ BL_ENE, F_POWER },
{ BL_ENEMAX, F_MAXPOWER },
{ BL_XP, F_XP_LEVL }, /* shares with BL_HD, depending upon Upolyd */
{ BL_AC, F_AC },
{ BL_TIME, F_TIME },
{ BL_HUNGER, F_HUNGER },
{ BL_HP, F_HP },
{ BL_HPMAX, F_MAXHP },
{ BL_LEVELDESC, F_DLEVEL },
{ BL_EXP, F_EXP_PTS }
};
static const struct mask_to_ff {
unsigned long mask;
int ff;
} mask_to_fancyfield[] = {
{ BL_MASK_GRAB, F_GRABBED },
{ BL_MASK_STONE, F_STONE },
{ BL_MASK_SLIME, F_SLIME },
{ BL_MASK_STRNGL, F_STRNGL },
{ BL_MASK_FOODPOIS, F_FOODPOIS },
{ BL_MASK_TERMILL, F_TERMILL },
{ BL_MASK_INLAVA, F_IN_LAVA },
{ BL_MASK_HELD, F_HELD },
{ BL_MASK_BLIND, F_BLIND },
{ BL_MASK_DEAF, F_DEAF },
{ BL_MASK_STUN, F_STUN },
{ BL_MASK_CONF, F_CONF },
{ BL_MASK_HALLU, F_HALLU },
{ BL_MASK_TRAPPED, F_TRAPPED },
{ BL_MASK_LEV, F_LEV },
{ BL_MASK_FLY, F_FLY },
{ BL_MASK_RIDE, F_RIDE }
};
int i;
if (fld == BL_RESET || fld == BL_FLUSH) {
if (WIN_STATUS != WIN_ERR) {
update_fancy_status(FALSE);
}
return;
}
if (fld == BL_CONDITION) {
unsigned long changed_bits, *condptr = (unsigned long *) ptr;
X11_condition_bits = *condptr;
/* process the bits that are different from last time */
changed_bits = (X11_condition_bits ^ old_condition_bits);
if (changed_bits) {
for (i = 0; i < SIZE(mask_to_fancyfield); i++)
if ((changed_bits & mask_to_fancyfield[i].mask) != 0L)
update_fancy_status_field(mask_to_fancyfield[i].ff);
old_condition_bits = X11_condition_bits;
}
} else {
for (i = 0; i < SIZE(bl_to_fancyfield); i++)
if (bl_to_fancyfield[i].bl == fld) {
update_fancy_status_field(bl_to_fancyfield[i].ff);
break;
}
}
}
void
X11_status_update(fld, ptr, chg, percent, color, colormasks)
int fld, chg UNUSED, percent UNUSED, color;
genericptr_t ptr;
unsigned long *colormasks;
{
if (fld < BL_RESET || fld >= MAXBLSTATS)
panic("X11_status_update(%d) -- invalid field", fld);
if (appResources.fancy_status)
X11_status_update_fancy(fld, ptr, chg, percent, color, colormasks);
else
X11_status_update_tty(fld, ptr, chg, percent, color, colormasks);
}
/* create a widget for a particular status field or potential condition */
static Widget
create_tty_status_field(fld, condindx, above, left)
int fld, condindx;
Widget above, left;
{
Arg args[16];
Cardinal num_args;
char labelname[40];
int gap = condindx ? 5 : 0;
if (!condindx)
Sprintf(labelname, "label_%s", bl_idx_to_fldname(fld));
else
Sprintf(labelname, "cond_%02d", condindx);
/* set up widget attributes which (mostly) aren't going to be changing */
(void) memset((genericptr_t) args, 0, sizeof args);
num_args = 0;
if (above)
XtSetArg(args[num_args], nhStr(XtNfromVert), above); num_args++;
if (left)
XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); num_args++;
XtSetArg(args[num_args], nhStr(XtNhorizDistance), gap); num_args++;
XtSetArg(args[num_args], nhStr(XtNvertDistance), 0); num_args++;
XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++;
XtSetArg(args[num_args], nhStr(XtNbottomMargin), 0); num_args++;
XtSetArg(args[num_args], nhStr(XtNleftMargin), 0); num_args++;
XtSetArg(args[num_args], nhStr(XtNrightMargin), 0); num_args++;
XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++;
/* internalWidth: default is 4; cut that it half and adjust regular
width to have it on both left and right instead of just on the left */
XtSetArg(args[num_args], nhStr(XtNinternalWidth), 2); num_args++;
XtSetArg(args[num_args], nhStr(XtNborderWidth), 0); num_args++;
XtSetArg(args[num_args], nhStr(XtNlabel), ""); num_args++;
return XtCreateManagedWidget(labelname, labelWidgetClass,
X11_status_widget, args, num_args);
}
/* create an overall status widget (X11_status_widget) and also
separate widgets for all status fields and potential conditions */
static Widget
create_tty_status(parent, top)
Widget parent, top;
{
Widget form; /* viewport that holds the form that surrounds everything */
Widget w, over_w, prev_w;
Arg args[6];
Cardinal num_args;
int x, y, i, fld;
(void) memset((genericptr_t) args, 0, sizeof args);
num_args = 0;
if (top)
XtSetArg(args[num_args], nhStr(XtNfromVert), top); num_args++;
XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0); num_args++;
XtSetArg(args[num_args], XtNborderWidth, 0); num_args++;
XtSetArg(args[num_args], XtNwidth, 400); num_args++;
XtSetArg(args[num_args], XtNheight, 100); num_args++;
form = XtCreateManagedWidget("status_viewport", viewportWidgetClass,
parent, args, num_args);
(void) memset((genericptr_t) args, 0, sizeof args);
num_args = 0;
XtSetArg(args[num_args], XtNwidth, 400); num_args++;
XtSetArg(args[num_args], XtNheight, 100); num_args++;
X11_status_widget = XtCreateManagedWidget("status_form", formWidgetClass,
form, args, num_args);
for (y = 0; y < X11_NUM_STATUS_LINES; y++) {
fld = (y > 0) ? X11_fieldorder[y - 1][0] : 0; /* temp, for over_w */
/* for row(s) beyond the first, pick a widget in the previous
row to put this one underneath (in 'y' terms; 'x' is fluid) */
over_w = (y > 0) ? X11_status_labels[fld] : (Widget) 0;
/* widget on current row to put the next one to the right of ('x') */
prev_w = (Widget) 0;
for (x = 0; x < X11_NUM_STATUS_FIELD; x++) {
fld = X11_fieldorder[y][x]; /* next field to handle */
if (fld <= BL_FLUSH)
continue; /* skip fieldorder[][] padding */
w = create_tty_status_field(fld, 0, over_w, prev_w);
X11_status_labels[fld] = prev_w = w;
if (fld == BL_CONDITION) {
for (i = 1; i <= SIZE(X11_cond_labels); ++i) { /* 1..32 */
w = create_tty_status_field(fld, i, over_w, prev_w);
X11_cond_labels[i - 1] = prev_w = w;
}
}
}
}
return X11_status_widget;
}
/*ARGSUSED*/
void
create_status_window_tty(wp, create_popup, parent)
struct xwindow *wp; /* window pointer */
boolean create_popup UNUSED;
Widget parent;
{
wp->type = NHW_STATUS;
wp->w = create_tty_status(parent, (Widget) 0);
}
void
destroy_status_window_tty(wp)
struct xwindow *wp;
{
/* If status_information is defined, then it a "text" status window. */
if (wp->status_information) {
if (wp->popup) {
nh_XtPopdown(wp->popup);
if (!wp->keep_window)
XtDestroyWidget(wp->popup), wp->popup = (Widget) 0;
}
free((genericptr_t) wp->status_information);
wp->status_information = 0;
} else {
;
}
if (!wp->keep_window)
wp->type = NHW_NONE;
}
/*ARGSUSED*/
void
adjust_status_tty(wp, str)
struct xwindow *wp UNUSED;
const char *str UNUSED;
{
/* nothing */
return;
}
void
create_status_window(wp, create_popup, parent)
struct xwindow *wp; /* window pointer */
boolean create_popup;
Widget parent;
{
struct status_info_t *si = (struct status_info_t *) alloc(sizeof *si);
xw_status_win = wp;
if (wp->Win_info.Status_info)
free((genericptr_t) wp->Win_info.Status_info);
wp->Win_info.Status_info = si;
(void) memset((genericptr_t) si, 0, sizeof *si);
if (!appResources.fancy_status)
create_status_window_tty(wp, create_popup, parent);
else
create_status_window_fancy(wp, create_popup, parent);
}
void
destroy_status_window(wp)
struct xwindow *wp;
{
if (appResources.fancy_status)
destroy_status_window_fancy(wp);
else
destroy_status_window_tty(wp);
}
void
adjust_status(wp, str)
struct xwindow *wp;
const char *str;
{
if (appResources.fancy_status)
adjust_status_fancy(wp, str);
else
adjust_status_tty(wp, str);
}
void
create_status_window_fancy(wp, create_popup, parent)
struct xwindow *wp; /* window pointer */
boolean create_popup;
Widget parent;
{
XFontStruct *fs;
Arg args[8];
Cardinal num_args;
Position top_margin, bottom_margin, left_margin, right_margin;
wp->type = NHW_STATUS;
if (!create_popup) {
/*
* If we are not creating a popup, then we must be the "main" status
* window.
*/
if (!parent)
panic("create_status_window_fancy: no parent for fancy status");
wp->status_information = 0;
wp->w = create_fancy_status(parent, (Widget) 0);
return;
}
wp->status_information =
(struct status_info_t *) alloc(sizeof (struct status_info_t));
init_text_buffer(&wp->status_information->text);
num_args = 0;
XtSetArg(args[num_args], XtNallowShellResize, False); num_args++;
XtSetArg(args[num_args], XtNinput, False); num_args++;
wp->popup = parent = XtCreatePopupShell("status_popup",
topLevelShellWidgetClass,
toplevel, args, num_args);
/*
* If we're here, then this is an auxiliary status window. If we're
* cancelled via a delete window message, we should just pop down.
*/
num_args = 0;
XtSetArg(args[num_args], nhStr(XtNdisplayCaret), False); num_args++;
XtSetArg(args[num_args], nhStr(XtNscrollHorizontal),
XawtextScrollWhenNeeded); num_args++;
XtSetArg(args[num_args], nhStr(XtNscrollVertical),
XawtextScrollWhenNeeded); num_args++;
wp->w = XtCreateManagedWidget("status", /* name */
asciiTextWidgetClass,
parent, /* parent widget */
args, /* set some values */
num_args); /* number of values to set */
/*
* Adjust the height and width of the message window so that it
* is two lines high and COLNO of the widest characters wide.
*/
/* Get the font and margin information. */
num_args = 0;
XtSetArg(args[num_args], XtNfont, &fs); num_args++;
XtSetArg(args[num_args], nhStr(XtNtopMargin), &top_margin); num_args++;
XtSetArg(args[num_args], nhStr(XtNbottomMargin),
&bottom_margin); num_args++;
XtSetArg(args[num_args], nhStr(XtNleftMargin), &left_margin); num_args++;
XtSetArg(args[num_args], nhStr(XtNrightMargin),
&right_margin); num_args++;
XtGetValues(wp->w, args, num_args);
wp->pixel_height = 2 * nhFontHeight(wp->w) + top_margin + bottom_margin;
wp->pixel_width = COLNO * fs->max_bounds.width
+ left_margin + right_margin;
/* Set the new width and height. */
num_args = 0;
XtSetArg(args[num_args], XtNwidth, wp->pixel_width); num_args++;
XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++;
XtSetValues(wp->w, args, num_args);
}
void
destroy_status_window_fancy(wp)
struct xwindow *wp;
{
/* If status_information is defined, then it a "text" status window. */
if (wp->status_information) {
if (wp->popup) {
nh_XtPopdown(wp->popup);
if (!wp->keep_window)
XtDestroyWidget(wp->popup), wp->popup = (Widget) 0;
}
free((genericptr_t) wp->status_information);
wp->status_information = 0;
} else {
destroy_fancy_status(wp);
}
if (!wp->keep_window)
wp->type = NHW_NONE;
}
/*
* This assumes several things:
* + Status has only 2 lines
* + That both lines are updated in succession in line order.
* + We didn't set stringInPlace on the widget.
*/
void
adjust_status_fancy(wp, str)
struct xwindow *wp;
const char *str;
{
Arg args[2];
Cardinal num_args;
if (!wp->status_information) {
update_fancy_status(TRUE);
return;
}
if (wp->cursy == 0) {
clear_text_buffer(&wp->status_information->text);
append_text_buffer(&wp->status_information->text, str, FALSE);
return;
}
append_text_buffer(&wp->status_information->text, str, FALSE);
/* Set new buffer as text. */
num_args = 0;
XtSetArg(args[num_args], XtNstring,
wp->status_information->text.text); num_args++;
XtSetValues(wp->w, args, num_args);
}
/* Fancy ================================================================== */
static int hilight_time = 1; /* number of turns to hilight a changed value */
struct X_status_value {
/* we have to cast away 'const' when assigning new names */
const char *name; /* text name */
int type; /* status type */
Widget w; /* widget of name/value pair */
long last_value; /* value displayed */
int turn_count; /* last time the value changed */
boolean set; /* if highlighted */
boolean after_init; /* don't highlight on first change (init) */
};
/* valid type values */
#define SV_VALUE 0 /* displays a label:value pair */
#define SV_LABEL 1 /* displays a changable label */
#define SV_NAME 2 /* displays an unchangeable name */
static void FDECL(hilight_label, (Widget));
static void FDECL(update_val, (struct X_status_value *, long));
static const char *FDECL(width_string, (int));
static void FDECL(create_widget, (Widget, struct X_status_value *, int));
static void FDECL(get_widths, (struct X_status_value *, int *, int *));
static void FDECL(set_widths, (struct X_status_value *, int, int));
static Widget FDECL(init_column, (const char *, Widget, Widget, Widget,
int *, int));
static void NDECL(fixup_cond_widths);
static Widget FDECL(init_info_form, (Widget, Widget, Widget));
/*
* Notes:
* + Alignment needs a different init value, because -1 is an alignment.
* + Armor Class is an schar, so 256 is out of range.
* + Blank value is 0 and should never change.
*
* - These must be in the same order as the F_foo numbers.
*/
static struct X_status_value shown_stats[NUM_STATS] = {
{ "", SV_NAME, (Widget) 0, -1, 0, FALSE, FALSE }, /* 0, F_DUMMY */
{ "Strength", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /* 1*/
{ "Dexterity", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "Constitution", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "Intelligence", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "Wisdom", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /* 5*/
{ "Charisma", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "", SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* 7, F_NAME */
{ "", SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* F_DLEVEL */
{ "Gold", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "Hit Points", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /*10*/
{ "Max HP", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "Power", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "Max Power", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "Armor Class", SV_VALUE, (Widget) 0, 256, 0, FALSE, FALSE },
{ "Xp Level", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /*15*/
/*{ "Hit Dice", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },==15*/
{ "Exp Points", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "Alignment", SV_VALUE, (Widget) 0, -2, 0, FALSE, FALSE },
{ "Time", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "Score", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
{ "", SV_NAME, (Widget) 0, -1, 0, FALSE, TRUE }, /*20, F_HUNGER */
{ "", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /* F_ENCUMBER */
{ "Trapped", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
{ "Levitating", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
{ "Flying", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
{ "Riding", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*25, F_RIDE */
{ "Grabbed!", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*26, F_GRAB */
{ "Petrifying", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /* F_STONE */
{ "Slimed", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
{ "Strangled", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
{ "Food Pois", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*30*/
{ "Term Ill", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
{ "Sinking", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /* 32, F_IN_LAVA */
{ "Held", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*33*/
{ "Blind", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
{ "Deaf", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*35*/
{ "Stunned", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
{ "Confused", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
{ "Hallucinating", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*38*/
};
extern const char *hu_stat[]; /* from eat.c */
extern const char *enc_stat[]; /* from botl.c */
/*
* Set all widget values to a null string. This is used after all spacings
* have been calculated so that when the window is popped up we don't get all
* kinds of funny values being displayed.
*/
void
null_out_status()
{
int i;
struct X_status_value *sv;
Arg args[1];
for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) {
switch (sv->type) {
case SV_VALUE:
set_value(sv->w, "");
break;
case SV_LABEL:
case SV_NAME:
XtSetArg(args[0], XtNlabel, "");
XtSetValues(sv->w, args, ONE);
break;
default:
impossible("null_out_status: unknown type %d\n", sv->type);
break;
}
}
}
/* this is almost an exact duplicate of hilight_value() */
static void
hilight_label(w)
Widget w; /* label widget */
{
/*
* This predates STATUS_HILITES.
* It is used to show any changed item in inverse and gets
* reset on the next turn.
*/
swap_fg_bg(w);
}
static void
update_val(attr_rec, new_value)
struct X_status_value *attr_rec;
long new_value;
{
static boolean Exp_shown = TRUE, time_shown = TRUE, score_shown = TRUE,
Xp_was_HD = FALSE;
char buf[BUFSZ];
Arg args[4];
if (attr_rec->type == SV_LABEL) {
if (attr_rec == &shown_stats[F_NAME]) {
Strcpy(buf, g.plname);
buf[0] = highc(buf[0]);
Strcat(buf, " the ");
if (Upolyd) {
char mname[BUFSZ];
int k;
Strcpy(mname, mons[u.umonnum].mname);
for (k = 0; mname[k] != '\0'; k++) {
if (k == 0 || mname[k - 1] == ' ')
mname[k] = highc(mname[k]);
}
Strcat(buf, mname);
} else
Strcat(buf,
rank_of(u.ulevel, g.pl_character[0], flags.female));
} else if (attr_rec == &shown_stats[F_DLEVEL]) {
if (!describe_level(buf)) {
Strcpy(buf, g.dungeons[u.uz.dnum].dname);
Sprintf(eos(buf), ", level %d", depth(&u.uz));
}
} else {
impossible("update_val: unknown label type \"%s\"",
attr_rec->name);
return;
}
if (strcmp(buf, attr_rec->name) == 0)
return; /* same */
/* Set the label. 'name' field is const for most entries;
we need to cast away that const for this assignment */
Strcpy((char *) attr_rec->name, buf);
XtSetArg(args[0], XtNlabel, buf);
XtSetValues(attr_rec->w, args, ONE);
} else if (attr_rec->type == SV_NAME) {
if (attr_rec->last_value == new_value)
return; /* no change */
attr_rec->last_value = new_value;
/* special cases: hunger and encumbrance */
if (attr_rec == &shown_stats[F_HUNGER]) {
Strcpy(buf, hu_stat[new_value]);
(void) mungspaces(buf);
} else if (attr_rec == &shown_stats[F_ENCUMBER]) {
Strcpy(buf, enc_stat[new_value]);
} else if (new_value) {
Strcpy(buf, attr_rec->name); /* condition name On */
} else {
*buf = '\0'; /* condition name Off */
}
XtSetArg(args[0], XtNlabel, buf);
XtSetValues(attr_rec->w, args, ONE);
} else { /* a value pair */
boolean force_update = FALSE;
/* special case: time can be enabled & disabled */
if (attr_rec == &shown_stats[F_TIME]) {
if (flags.time && !time_shown) {
set_name(attr_rec->w, shown_stats[F_TIME].name);
force_update = TRUE;
time_shown = TRUE;
} else if (!flags.time && time_shown) {
set_name(attr_rec->w, "");
set_value(attr_rec->w, "");
time_shown = FALSE;
}
if (!time_shown)
return;
/* special case: experience points can be enabled & disabled */
} else if (attr_rec == &shown_stats[F_EXP_PTS]) {
boolean showexp = flags.showexp && !Upolyd;
if (showexp && !Exp_shown) {
set_name(attr_rec->w, shown_stats[F_EXP_PTS].name);
force_update = TRUE;
Exp_shown = TRUE;
} else if (!showexp && Exp_shown) {
set_name(attr_rec->w, "");
set_value(attr_rec->w, "");
Exp_shown = FALSE;
}
if (!Exp_shown)
return;
/* special case: when available, score can be enabled & disabled */
} else if (attr_rec == &shown_stats[F_SCORE]) {
#ifdef SCORE_ON_BOTL
if (flags.showscore && !score_shown) {
set_name(attr_rec->w, shown_stats[F_SCORE].name);
force_update = TRUE;
score_shown = TRUE;
} else
#endif
if (!flags.showscore && score_shown) {
set_name(attr_rec->w, "");
set_value(attr_rec->w, "");
score_shown = FALSE;
}
if (!score_shown)
return;
/* special case: when polymorphed, show "Hit Dice" and disable Exp */
} else if (attr_rec == &shown_stats[F_XP_LEVL]) {
if (Upolyd && !Xp_was_HD) {
force_update = TRUE;
set_name(attr_rec->w, "Hit Dice");
Xp_was_HD = TRUE;
} else if (!Upolyd && Xp_was_HD) {
force_update = TRUE;
set_name(attr_rec->w, shown_stats[F_XP_LEVL].name);
Xp_was_HD = FALSE;
}
/* core won't call status_update() for Exp when it hasn't changed
so do so ourselves (to get Exp_shown flag to match display) */
if (force_update)
update_fancy_status_field(F_EXP_PTS);
}
if (attr_rec->last_value == new_value && !force_update) /* same */
return;
attr_rec->last_value = new_value;
/* Special cases: strength and other characteristics, alignment
and "clear". */
if (attr_rec >= &shown_stats[F_STR]
&& attr_rec <= &shown_stats[F_CHA]) {
static const char fmt1[] = "%ld%s", fmt2[] = "%2ld%s";
struct xwindow *wp;
const char *fmt = fmt1, *padding = "";
/* for full-fledged fancy status, force two digits for all
six characteristics, followed by three spaces of padding
to match "/xx" exceptional strength */
wp = (WIN_STATUS != WIN_ERR) ? &window_list[WIN_STATUS] : 0;
if (wp && !wp->status_information)
fmt = fmt2, padding = " ";
if (new_value > 18L && attr_rec == &shown_stats[F_STR]) {
if (new_value > 118L) /* 19..25 encoded as 119..125 */
Sprintf(buf, fmt, new_value - 100L, padding);
else if (new_value < 118L) /* 18/01..18/99 as 19..117*/
Sprintf(buf, "18/%02ld", new_value - 18L);
else
Strcpy(buf, "18/**"); /* 18/100 encoded as 118 */
} else { /* non-strength or less than 18/01 strength (3..18) */
Sprintf(buf, fmt, new_value, padding); /* 3..25 */
}
} else if (attr_rec == &shown_stats[F_ALIGN]) {
Strcpy(buf, (new_value == A_CHAOTIC) ? "Chaotic"
: (new_value == A_NEUTRAL) ? "Neutral" : "Lawful");
} else {
Sprintf(buf, "%ld", new_value);
}
set_value(attr_rec->w, buf);
}
/*
* Now highlight the changed information. Don't highlight Time because
* it's continually changing. For others, don't highlight if this is
* the first update. If already highlighted, don't change it unless
* it's being set to blank (where that item should be reset now instead
* of showing highlighted blank until the next expiration check).
*
* 3.7: highlight non-labelled 'name' items (conditions plus hunger
* and encumbrance) when they come On. For all conditions going Off,
* or changing to not-hungry or not-encumbered, there's nothing to
* highlight because the field becomes blank.
*/
if (attr_rec != &shown_stats[F_TIME]) {
if (attr_rec->after_init) {
/* toggle if not highlighted and just set to nonblank or if
already highlighted and just set to blank */
if (!attr_rec->set ^ !*buf) {
if (attr_rec->type == SV_LABEL || attr_rec->type == SV_NAME)
hilight_label(attr_rec->w);
else
hilight_value(attr_rec->w);
attr_rec->set = !attr_rec->set;
}
attr_rec->turn_count = 0;
} else {
attr_rec->after_init = TRUE;
}
}
}
/*
* Update the displayed status. The current code in botl.c updates
* two lines of information. Both lines are always updated one after
* the other. So only do our update when we update the second line.
*
* Information on the first line:
* name, characteristics, alignment, score
*
* Information on the second line:
* dlvl, gold, hp, power, ac, {level & exp or HD **}, time,
* status * (stone, slime, strngl, foodpois, termill,
* hunger, encumbrance, lev, fly, ride,
* blind, deaf, stun, conf, hallu)
*
* [*] order of status fields is different on tty.
* [**] HD is shown instead of level and exp if Upolyd.
*/
static void
update_fancy_status_field(i)
int i;
{
struct X_status_value *sv = &shown_stats[i];
unsigned long condmask = 0L;
long val = 0L;
switch (i) {
case F_DUMMY:
val = 0L;
break;
case F_STR:
val = (long) ACURR(A_STR);
break;
case F_DEX:
val = (long) ACURR(A_DEX);
break;
case F_CON:
val = (long) ACURR(A_CON);
break;
case F_INT:
val = (long) ACURR(A_INT);
break;
case F_WIS:
val = (long) ACURR(A_WIS);
break;
case F_CHA:
val = (long) ACURR(A_CHA);
break;
/*
* Label stats. With the exceptions of hunger and encumbrance
* these are either on or off. Pleae leave the ternary operators
* the way they are. I want to specify 0 or 1, not a boolean.
*/
case F_HUNGER:
val = (long) u.uhs;
break;
case F_ENCUMBER:
val = (long) near_capacity();
break;
case F_TRAPPED:
condmask = BL_MASK_TRAPPED;
break;
case F_LEV:
condmask = BL_MASK_LEV;
break;
case F_FLY:
condmask = BL_MASK_FLY;
break;
case F_RIDE:
condmask = BL_MASK_RIDE;
break;
/* fatal status conditions */
case F_GRABBED:
condmask = BL_MASK_GRAB;
break;
case F_STONE:
condmask = BL_MASK_STONE;
break;
case F_SLIME:
condmask = BL_MASK_SLIME;
break;
case F_STRNGL:
condmask = BL_MASK_STRNGL;
break;
case F_FOODPOIS:
condmask = BL_MASK_FOODPOIS;
break;
case F_TERMILL:
condmask = BL_MASK_TERMILL;
break;
case F_IN_LAVA:
condmask = BL_MASK_INLAVA;
break;
/* non-fatal status conditions */
case F_HELD:
condmask = BL_MASK_HELD;
break;
case F_BLIND:
condmask = BL_MASK_BLIND;
break;
case F_DEAF:
condmask = BL_MASK_DEAF;
break;
case F_STUN:
condmask = BL_MASK_STUN;
break;
case F_CONF:
condmask = BL_MASK_CONF;
break;
case F_HALLU:
condmask = BL_MASK_HALLU;
break;
case F_NAME:
case F_DLEVEL:
val = (long) 0L;
break; /* special */
case F_GOLD:
val = money_cnt(g.invent);
if (val < 0L)
val = 0L; /* ought to issue impossible() and discard gold */
break;
case F_HP:
val = (long) (Upolyd ? (u.mh > 0 ? u.mh : 0)
: (u.uhp > 0 ? u.uhp : 0));
break;
case F_MAXHP:
val = (long) (Upolyd ? u.mhmax : u.uhpmax);
break;
case F_POWER:
val = (long) u.uen;
break;
case F_MAXPOWER:
val = (long) u.uenmax;
break;
case F_AC:
val = (long) u.uac;
break;
case F_XP_LEVL:
val = (long) (Upolyd ? mons[u.umonnum].mlevel : u.ulevel);
break;
case F_EXP_PTS:
val = flags.showexp ? u.uexp : 0L;
break;
case F_ALIGN:
val = (long) u.ualign.type;
break;
case F_TIME:
val = flags.time ? (long) g.moves : 0L;
break;
case F_SCORE:
#ifdef SCORE_ON_BOTL
val = flags.showscore ? botl_score() : 0L;
#else
val = 0L;
#endif
break;
default: {
/*
* There is a possible infinite loop that occurs with:
*
* impossible->pline->flush_screen->bot->bot{1,2}->
* putstr->adjust_status->update_other->impossible
*
* Break out with this.
*/
static boolean active = FALSE;
if (!active) {
active = TRUE;
impossible("update_other: unknown shown value");
active = FALSE;
}
val = 0L;
break;
} /* default */
} /* switch */
if (condmask)
val = ((X11_condition_bits & condmask) != 0L);
update_val(sv, val);
}
/* fully update status after bl_flush or window resize */
static void
update_fancy_status(force_update)
boolean force_update;
{
static boolean old_showtime, old_showexp, old_showscore;
static int old_upolyd = -1; /* -1: force first time update */
int i;
if (force_update
|| Upolyd != old_upolyd /* Xp vs HD */
|| flags.time != old_showtime
|| flags.showexp != old_showexp
|| flags.showscore != old_showscore) {
/* update everything; usually only need this on the very first
time, then later if the window gets resized or if poly/unpoly
triggers Xp <-> HD switch or if an optional field gets
toggled off since there won't be a status_update() call for
the no longer displayed field; we're a bit more conservative
than that and do this when toggling on as well as off */
for (i = 0; i < NUM_STATS; i++)
update_fancy_status_field(i);
old_upolyd = Upolyd;
old_showtime = flags.time;
old_showexp = flags.showexp;
old_showscore = flags.showscore;
}
}
/*
* Turn off hilighted status values after a certain amount of turns.
*/
void
check_turn_events()
{
int i;
struct X_status_value *sv;
for (sv = shown_stats, i = 0; i < NUM_STATS; i++, sv++) {
if (!sv->set)
continue;
if (sv->turn_count++ >= hilight_time) {
/* unhighlights by toggling a highlighted item back off again */
if (sv->type == SV_LABEL || sv->type == SV_NAME)
hilight_label(sv->w);
else
hilight_value(sv->w);
sv->set = FALSE;
}
}
}
/* Initialize alternate status ============================================ */
/* Return a string for the initial width, so use longest possible value. */
static const char *
width_string(sv_index)
int sv_index;
{
switch (sv_index) {
case F_DUMMY:
return " ";
case F_STR:
return "018/**";
case F_DEX:
case F_CON:
case F_INT:
case F_WIS:
case F_CHA:
return "088"; /* all but str never get bigger */
case F_HUNGER:
return "Satiated";
case F_ENCUMBER:
return "Overloaded";
case F_LEV:
case F_FLY:
case F_RIDE:
case F_TRAPPED:
case F_GRABBED:
case F_STONE:
case F_SLIME:
case F_STRNGL:
case F_FOODPOIS:
case F_TERMILL:
case F_IN_LAVA:
case F_HELD:
case F_BLIND:
case F_DEAF:
case F_STUN:
case F_CONF:
case F_HALLU:
return shown_stats[sv_index].name;
case F_NAME:
case F_DLEVEL:
return ""; /* longest possible value not needed for these */
case F_HP:
case F_MAXHP:
return "9999";
case F_POWER:
case F_MAXPOWER:
return "9999";
case F_AC:
return "-127";
case F_XP_LEVL:
return "99";
case F_GOLD:
/* strongest hero can pick up roughly 30% of this much */
return "999999"; /* same limit as tty */
case F_EXP_PTS:
case F_TIME:
case F_SCORE:
return "123456789"; /* a tenth digit will still fit legibly */
case F_ALIGN:
return "Neutral";
}
impossible("width_string: unknown index %d\n", sv_index);
return "";
}
static void
create_widget(parent, sv, sv_index)
Widget parent;
struct X_status_value *sv;
int sv_index;
{
Arg args[4];
Cardinal num_args;
switch (sv->type) {
case SV_VALUE:
sv->w = create_value(parent, sv->name);
set_value(sv->w, width_string(sv_index));
break;
case SV_LABEL:
/* Labels get their own buffer. */
sv->name = (char *) alloc(BUFSZ);
/* we need to cast away 'const' when assigning a value */
*(char *) (sv->name) = '\0';
num_args = 0;
XtSetArg(args[num_args], XtNborderWidth, 0); num_args++;
XtSetArg(args[num_args], XtNinternalHeight, 0); num_args++;
sv->w = XtCreateManagedWidget((sv_index == F_NAME)
? "name"
: "dlevel",
labelWidgetClass, parent,
args, num_args);
break;
case SV_NAME:
num_args = 0;
XtSetArg(args[0], XtNlabel, width_string(sv_index)); num_args++;
XtSetArg(args[num_args], XtNborderWidth, 0); num_args++;
XtSetArg(args[num_args], XtNinternalHeight, 0); num_args++;
sv->w = XtCreateManagedWidget(sv->name, labelWidgetClass, parent,
args, num_args);
break;
default:
panic("create_widget: unknown type %d", sv->type);
}
}
/*
* Get current width of value. width2p is only valid for SV_VALUE types.
*/
static void
get_widths(sv, width1p, width2p)
struct X_status_value *sv;
int *width1p, *width2p;
{
Arg args[1];
Dimension width;
switch (sv->type) {
case SV_VALUE:
*width1p = get_name_width(sv->w);
*width2p = get_value_width(sv->w);
break;
case SV_LABEL:
case SV_NAME:
XtSetArg(args[0], XtNwidth, &width);
XtGetValues(sv->w, args, ONE);
*width1p = width;
*width2p = 0;
break;
default:
panic("get_widths: unknown type %d", sv->type);
}
}
static void
set_widths(sv, width1, width2)
struct X_status_value *sv;
int width1, width2;
{
Arg args[1];
switch (sv->type) {
case SV_VALUE:
set_name_width(sv->w, width1);
set_value_width(sv->w, width2);
break;
case SV_LABEL:
case SV_NAME:
XtSetArg(args[0], XtNwidth, (width1 + width2));
XtSetValues(sv->w, args, ONE);
break;
default:
panic("set_widths: unknown type %d", sv->type);
}
}
static Widget
init_column(name, parent, top, left, col_indices, xtrawidth)
const char *name;
Widget parent, top, left;
int *col_indices, xtrawidth;
{
Widget form;
Arg args[4];
Cardinal num_args;
int max_width1, width1, max_width2, width2;
int *ip;
struct X_status_value *sv;
num_args = 0;
if (top != (Widget) 0) {
XtSetArg(args[num_args], nhStr(XtNfromVert), top); num_args++;
}
if (left != (Widget) 0) {
XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); num_args++;
}
/* this was 0 but that resulted in the text being crammed together */
XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 2); num_args++;
form = XtCreateManagedWidget(name, formWidgetClass, parent,
args, num_args);
max_width1 = max_width2 = 0;
for (ip = col_indices; *ip >= 0; ip++) {
sv = &shown_stats[*ip];
create_widget(form, sv, *ip); /* will set init width */
if (ip != col_indices) { /* not first */
num_args = 0;
XtSetArg(args[num_args], nhStr(XtNfromVert),
shown_stats[*(ip - 1)].w); num_args++;
XtSetValues(sv->w, args, num_args);
}
get_widths(sv, &width1, &width2);
if (width1 > max_width1)
max_width1 = width1;
if (width2 > max_width2)
max_width2 = width2;
}
/* insert some extra spacing between columns */
max_width1 += xtrawidth;
for (ip = col_indices; *ip >= 0; ip++) {
set_widths(&shown_stats[*ip], max_width1, max_width2);
}
/* There is room behind the end marker for the two widths. */
*++ip = max_width1;
*++ip = max_width2;
return form;
}
/*
* These are the orders of the displayed columns. Change to suit. The -1
* indicates the end of the column. The two numbers after that are used
* to store widths that are calculated at run-time.
*
* 3.7: changed so that all 6 columns have 8 rows, but a few entries
* are left blank <>. Exp-points, Score, and Time are optional depending
* on run-time settings; Xp-level is replaced by Hit-Dice (and Exp-points
* suppressed) when the hero is polymorphed. Title and Dungeon-Level span
* two columns and might expand to more if 'hitpointbar' is implemented.
*
Title ("Plname the Rank") <> <> <> <>
Dungeon-Branch-and-Level <> Hunger Grabbed Held
Hit-points Max-HP Strength Encumbrance Petrifying Blind
Power-points Max-Power Dexterity Trapped Slimed Deaf
Armor-class Alignment Constitution Levitation Strangled Stunned
Xp-level [Exp-points] Intelligence Flying Food-Pois Confused
Gold [Score] Wisdom Riding Term-Ill Hallucinatg
<> [Time] Charisma <> Sinking <>
*
* A seventh column is going to be needed to fit in more conditions.
*
* Possible enhancement: if Exp-points and Score are both disabled, move
* Gold to the Exp-points slot.
*/
/* including F_DUMMY makes the three status condition columns evenly
spaced with regard to the adjacent characteristics (Str,Dex,&c) column;
we lose track of the Widget pointer for F_DUMMY, each use clobbering the
one before, leaving the one from leftover_indices[]; since they're never
updated, that shouldn't matter */
static int status_indices[3][11] = {
{ F_DUMMY, F_HUNGER, F_ENCUMBER, F_TRAPPED,
F_LEV, F_FLY, F_RIDE, F_DUMMY, -1, 0, 0 },
{ F_DUMMY, F_GRABBED, F_STONE, F_SLIME, F_STRNGL,
F_FOODPOIS, F_TERMILL, F_IN_LAVA, -1, 0, 0 },
{ F_DUMMY, F_HELD, F_BLIND, F_DEAF, F_STUN,
F_CONF, F_HALLU, F_DUMMY, -1, 0, 0 },
};
/* used to fill up the empty space to right of 3rd status condition column */
static int leftover_indices[] = { F_DUMMY, -1, 0, 0 };
/* -2: top two rows of these columns are reserved for title and location */
static int col1_indices[11 - 2] = {
F_HP, F_POWER, F_AC, F_XP_LEVL, F_GOLD, F_DUMMY, -1, 0, 0
};
static int col2_indices[11 - 2] = {
F_MAXHP, F_MAXPOWER, F_ALIGN, F_EXP_PTS, F_SCORE, F_TIME, -1, 0, 0
};
static int characteristics_indices[11 - 2] = {
F_STR, F_DEX, F_CON, F_INT, F_WIS, F_CHA, -1, 0, 0
};
/*
* Produce a form that looks like the following:
*
* title
* location
* col1_indices[0] col2_indices[0] col3_indices[0]
* col1_indices[1] col2_indices[1] col3_indices[1]
* ... ... ...
* col1_indices[5] col2_indices[5] col3_indices[5]
*
* The status conditions are managed separately and appear to the right
* of this form.
*
* TODO: widen title field and implement hitpoint bar on it.
*/
static Widget
init_info_form(parent, top, left)
Widget parent, top, left;
{
Widget form, col1, col2;
struct X_status_value *sv_name, *sv_dlevel;
Arg args[6];
Cardinal num_args;
int total_width, *ip;
num_args = 0;
if (top != (Widget) 0) {
XtSetArg(args[num_args], nhStr(XtNfromVert), top); num_args++;
}
if (left != (Widget) 0) {
XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); num_args++;
}
XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 2); num_args++;
form = XtCreateManagedWidget("status_info", formWidgetClass, parent,
args, num_args);
/* top line/row of form */
sv_name = &shown_stats[F_NAME]; /* title */
create_widget(form, sv_name, F_NAME);
/* second line/row */
sv_dlevel = &shown_stats[F_DLEVEL]; /* location */
create_widget(form, sv_dlevel, F_DLEVEL);
num_args = 0;
XtSetArg(args[num_args], nhStr(XtNfromVert), sv_name->w); num_args++;
XtSetValues(sv_dlevel->w, args, num_args);
/* there are 3 columns beneath but top 2 rows are centered over first 2 */
col1 = init_column("name_col1", form, sv_dlevel->w, (Widget) 0,
col1_indices, 0);
col2 = init_column("name_col2", form, sv_dlevel->w, col1,
col2_indices, 5);
(void) init_column("status_characteristics", form, sv_dlevel->w, col2,
characteristics_indices, 15);
/* Add calculated widths. */
for (ip = col1_indices; *ip >= 0; ip++)
; /* skip to end */
total_width = *++ip;
total_width += *++ip;
for (ip = col2_indices; *ip >= 0; ip++)
; /* skip to end */
total_width += *++ip;
total_width += *++ip;
XtSetArg(args[0], XtNwidth, total_width);
XtSetValues(sv_name->w, args, ONE);
XtSetArg(args[0], XtNwidth, total_width);
XtSetValues(sv_dlevel->w, args, ONE);
return form;
}
/* give the three status condition columns the same width */
static void
fixup_cond_widths()
{
int pass, i, *ip, w1, w2;
w1 = w2 = 0;
for (pass = 1; pass <= 2; ++pass) { /* two passes... */
for (i = 0; i < 3; i++) { /* three columns */
for (ip = status_indices[i]; *ip != -1; ++ip) { /* X fields */
/* pass 1: find -1; pass 2: update field widths, find -1 */
if (pass == 2)
set_widths(&shown_stats[*ip], w1, w2);
}
/* found -1; the two slots beyond it contain column widths */
if (pass == 1) { /* pass 1: collect maxima */
if (ip[1] > w1)
w1 = ip[1];
if (ip[2] > w2)
w2 = ip[2];
} else { /* pass 2: update column widths with maxima */
ip[1] = w1;
ip[2] = w2;
}
}
/* ascetics: expand the maximum width to make cond columns wider */
if (pass == 1) {
w1 += 15;
if (w2 > 0)
w2 += 15;
}
}
}
/*
* Create the layout for the fancy status. Return a form widget that
* contains everything.
*/
static Widget
create_fancy_status(parent, top)
Widget parent, top;
{
Widget form; /* The form that surrounds everything. */
Widget w;
Arg args[8];
Cardinal num_args;
char buf[32];
int i;
num_args = 0;
if (top != (Widget) 0) {
XtSetArg(args[num_args], nhStr(XtNfromVert), top); num_args++;
}
XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 2); num_args++;
XtSetArg(args[num_args], XtNborderWidth, 0); num_args++;
XtSetArg(args[num_args], XtNorientation, XtorientHorizontal); num_args++;
form = XtCreateManagedWidget("fancy_status", panedWidgetClass, parent,
args, num_args);
w = init_info_form(form, (Widget) 0, (Widget) 0);
#if 0 /* moved to init_info_form() */
w = init_column("status_characteristics", form, (Widget) 0, w,
characteristics_indices, 15);
#endif
for (i = 0; i < 3; i++) {
Sprintf(buf, "status_condition%d", i + 1);
w = init_column(buf, form, (Widget) 0, w, status_indices[i], 0);
}
fixup_cond_widths(); /* make all 3 status_conditionN columns same width */
w = init_column("status_leftover", form, (Widget) 0, w,
leftover_indices, 0);
nhUse(w);
return form;
}
static void
destroy_fancy_status(wp)
struct xwindow *wp;
{
int i;
struct X_status_value *sv;
if (!wp->keep_window)
XtDestroyWidget(wp->w), wp->w = (Widget) 0;
for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++)
if (sv->type == SV_LABEL) {
free((genericptr_t) sv->name);
sv->name = 0;
}
}
/*winstat.c*/