more quieting of Qt6 build warnings
[NetHack.git] / win / X11 / winstat.c
blob4e520203c266d9e92b3330b88c80729fda7c3f60
1 /* NetHack 3.7 winstat.c $NHDT-Date: 1649269127 2022/04/06 18:18:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.37 $ */
2 /* Copyright (c) Dean Luick, 1992 */
3 /* NetHack may be freely redistributed. See license for details. */
5 /*
6 * Status window routines. This file supports both the "traditional"
7 * tty status display and a "fancy" status display. A tty status is
8 * made if a popup window is requested, otherwise a fancy status is
9 * made. This code assumes that only one fancy status will ever be made.
10 * Currently, only one status window (of any type) is _ever_ made.
13 #ifndef SYSV
14 #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */
15 #endif
17 #include <X11/Intrinsic.h>
18 #include <X11/IntrinsicP.h> /* for XtResizeWidget() and XtConfigureWidget() */
19 #include <X11/StringDefs.h>
20 #include <X11/Shell.h>
21 #include <X11/Xaw/AsciiText.h>
22 #include <X11/Xaw/Cardinals.h> /* just for ONE, TWO */
23 #include <X11/Xaw/Form.h>
24 #include <X11/Xaw/Paned.h>
25 #include <X11/Xaw/Label.h>
26 #include <X11/Xaw/Viewport.h>
27 /*#include <X11/Xatom.h>*/
29 #ifdef PRESERVE_NO_SYSV
30 #ifdef SYSV
31 #undef SYSV
32 #endif
33 #undef PRESERVE_NO_SYSV
34 #endif
36 #include "hack.h"
37 #include "winX.h"
38 #include "xwindow.h"
41 * Fancy status form entry storage indices.
43 #define F_DUMMY 0
44 #define F_STR 1
45 #define F_DEX 2
46 #define F_CON 3
47 #define F_INT 4
48 #define F_WIS 5
49 #define F_CHA 6
51 #define F_NAME 7 /* title: "Name the Rank" where rank is role-specific */
52 #define F_DLEVEL 8 /* location: dungeon branch and level */
53 #define F_GOLD 9
54 #define F_HP 10
55 #define F_MAXHP 11
56 #define F_POWER 12
57 #define F_MAXPOWER 13
58 #define F_AC 14
59 #define F_XP_LEVL 15
60 /*#define F_HD F_XP_LEVL*/
61 #define F_EXP_PTS 16
62 #define F_ALIGN 17
63 #define F_TIME 18
64 #define F_SCORE 19
66 /* status conditions grouped by columns; tty orders these differently;
67 hunger/encumbrance/movement used to be in the middle with fatal
68 conditions on the left but those columns have been swapped and
69 renumbered to match new order (forcing shown_stats[] to be reordered);
70 some mutually exclusive conditions are overloaded during display--
71 they're separate within shown_stats[] but share the same widget */
72 #define F_HUNGER 20
73 #define F_ENCUMBER 21
74 #define F_TRAPPED 22
75 #define F_TETHERED 23 /* overloads trapped rather than having its own slot */
76 #define F_LEV 24
77 #define F_FLY 25
78 #define F_RIDE 26
80 #define F_GRABBED 27
81 #define F_STONE 28
82 #define F_SLIME 29
83 #define F_STRNGL 30
84 #define F_FOODPOIS 31
85 #define F_TERMILL 32
86 #define F_IN_LAVA 33 /* could overload trapped but severity differs a lot */
88 #define F_HELD 34 /* could overload grabbed but severity differs a lot */
89 #define F_HOLDING 35 /* overloads held */
90 #define F_BLIND 36
91 #define F_DEAF 37
92 #define F_STUN 38
93 #define F_CONF 39
94 #define F_HALLU 40
96 #define F_VERS 41 /* version info */
97 #define NUM_STATS 42
99 static int condcolor(long, unsigned long *);
100 static int condattr(long, unsigned long *);
101 static void HiliteField(Widget, int, int, int, XFontStruct **);
102 static void PrepStatusField(int, Widget, const char *);
103 static void DisplayCond(int, unsigned long *);
104 static int render_conditions(int, int);
105 #ifdef STATUS_HILITES
106 static void tt_reset_color(int, int, unsigned long *);
107 #endif
108 static void tt_status_fixup(void);
109 static Widget create_tty_status_field(int, int, Widget, Widget);
110 static Widget create_tty_status(Widget, Widget);
111 static void stat_resized(Widget, XtPointer, XtPointer);
112 static void update_fancy_status_field(int, int, int);
113 static void update_fancy_status(boolean);
114 static Widget create_fancy_status(Widget, Widget);
115 static void destroy_fancy_status(struct xwindow *);
116 static void create_status_window_fancy(struct xwindow *, boolean, Widget);
117 static void create_status_window_tty(struct xwindow *, boolean, Widget);
118 static void destroy_status_window_fancy(struct xwindow *);
119 static void destroy_status_window_tty(struct xwindow *);
120 static void adjust_status_fancy(struct xwindow *, const char *);
121 static void adjust_status_tty(struct xwindow *, const char *);
123 extern const char *status_fieldfmt[MAXBLSTATS];
124 extern char *status_vals[MAXBLSTATS];
125 extern boolean status_activefields[MAXBLSTATS];
127 static unsigned long X11_condition_bits, old_condition_bits;
128 static int X11_status_colors[MAXBLSTATS],
129 old_field_colors[MAXBLSTATS],
130 old_cond_colors[32];
131 static int hpbar_percent, hpbar_color;
132 /* Number of conditions displayed during this update and last update.
133 When the last update had more, the excess need to be erased. */
134 static int next_cond_indx = 0, prev_cond_indx = 0;
136 /* TODO: support statuslines:3 in addition to 2 for the tty-style status */
137 #define X11_NUM_STATUS_LINES 2
138 #define X11_NUM_STATUS_FIELD 16
140 static enum statusfields X11_fieldorder[][X11_NUM_STATUS_FIELD] = {
141 { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN,
142 BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH,
143 BL_FLUSH, BL_FLUSH },
144 { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX,
145 BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER,
146 BL_CAP, BL_CONDITION, BL_VERS, BL_FLUSH }
149 /* condition list for tty-style display, roughly in order of importance */
150 static struct tt_condinfo {
151 unsigned long mask;
152 const char *text;
153 } tt_condorder[] = {
154 { BL_MASK_GRAB, "Grabbed!" },
155 { BL_MASK_STONE, "Stone" },
156 { BL_MASK_SLIME, "Slime" },
157 { BL_MASK_STRNGL, "Strngl" },
158 { BL_MASK_FOODPOIS, "FoodPois" },
159 { BL_MASK_TERMILL, "TermIll" },
160 { BL_MASK_INLAVA, "InLava" },
161 { BL_MASK_HELD, "Held" },
162 { BL_MASK_HOLDING, "Holding" },
163 { BL_MASK_BLIND, "Blind" },
164 { BL_MASK_DEAF, "Deaf" },
165 { BL_MASK_STUN, "Stun" },
166 { BL_MASK_CONF, "Conf" },
167 { BL_MASK_HALLU, "Hallu" },
168 { BL_MASK_TRAPPED, "Trapped" },
169 { BL_MASK_TETHERED, "Tethered", },
170 { BL_MASK_LEV, "Lev" },
171 { BL_MASK_FLY, "Fly" },
172 { BL_MASK_RIDE, "Ride" },
175 static const char *const fancy_status_hilite_colors[] = {
176 "grey15",
177 "red3",
178 "dark green",
179 "saddle brown",
180 "blue",
181 "magenta3",
182 "dark cyan",
183 "web gray",
184 "", /* NO_COLOR */
185 "orange",
186 "green3",
187 "goldenrod",
188 "royal blue",
189 "magenta",
190 "cyan",
191 "white",
194 static Widget X11_status_widget;
195 static Widget X11_status_labels[MAXBLSTATS];
196 static Widget X11_cond_labels[32]; /* Ugh */
197 static XFontStruct *X11_status_font;
198 static Pixel X11_status_fg, X11_status_bg;
200 struct xwindow *xw_status_win;
202 static int
203 condcolor(long bm, unsigned long *bmarray)
205 int i;
207 if (bm && bmarray)
208 for (i = 0; i < CLR_MAX; ++i) {
209 if (bmarray[i] && (bm & bmarray[i]))
210 return i;
212 return NO_COLOR;
215 static int
216 condattr(long bm, unsigned long *bmarray)
218 int attr = 0;
219 int i;
221 if (bm && bmarray) {
222 for (i = HL_ATTCLR_BOLD; i < BL_ATTCLR_MAX; ++i) {
223 if (bmarray[i] && (bm & bmarray[i])) {
224 switch(i) {
225 case HL_ATTCLR_BOLD:
226 attr |= HL_BOLD;
227 break;
228 case HL_ATTCLR_DIM:
229 attr |= HL_DIM;
230 break;
231 case HL_ATTCLR_ITALIC:
232 attr |= HL_ITALIC;
233 break;
234 case HL_ATTCLR_ULINE:
235 attr |= HL_ULINE;
236 break;
237 case HL_ATTCLR_BLINK:
238 attr |= HL_BLINK;
239 break;
240 case HL_ATTCLR_INVERSE:
241 attr |= HL_INVERSE;
242 break;
247 return attr;
250 void
251 X11_status_init(void)
253 int i;
255 /* no color and no attributes */
256 for (i = 0; i < MAXBLSTATS; ++i)
257 X11_status_colors[i] = old_field_colors[i] = NO_COLOR;
258 for (i = 0; i < SIZE(old_cond_colors); ++i)
259 old_cond_colors[i] = NO_COLOR;
260 hpbar_percent = 0, hpbar_color = NO_COLOR;
261 X11_condition_bits = old_condition_bits = 0L;
262 /* let genl_status_init do most of the initialization */
263 genl_status_init();
266 void
267 X11_status_finish(void)
269 /* nothing */
270 return;
273 void
274 X11_status_enablefield(int fieldidx, const char *nm,
275 const char *fmt, boolean enable)
277 genl_status_enablefield(fieldidx, nm, fmt, enable);
280 #if 0
282 cond_bm2idx(unsigned long bm)
284 int i;
286 for (i = 0; i < 32; i++)
287 if ((1 << i) == bm)
288 return i;
289 return -1;
291 #endif
293 /* highlight a tty-style status field (or condition) */
294 static void
295 HiliteField(Widget label,
296 int fld, int cond, int colrattr,
297 XFontStruct **font_p)
299 #ifdef STATUS_HILITES
300 static Pixel grayPxl, blackPxl, whitePxl;
301 Arg args[6];
302 Cardinal num_args;
303 XFontStruct *font = X11_status_font;
304 Pixel px, fg = X11_status_fg, bg = X11_status_bg;
305 struct xwindow *xw = xw_status_win;
306 int colr, attr;
308 if ((colrattr & 0x00ff) >= CLR_MAX)
309 colrattr = (colrattr & ~0x00ff) | NO_COLOR;
310 colr = colrattr & 0x00ff; /* guaranteed to be >= 0 and < CLR_MAX */
311 attr = (colrattr >> 8) & 0x00ff;
313 if (!grayPxl) {/* one-time init */
314 grayPxl = get_nhcolor(xw, CLR_GRAY).pixel;
315 blackPxl = get_nhcolor(xw, CLR_BLACK).pixel;
316 whitePxl = get_nhcolor(xw, CLR_WHITE).pixel;
318 /* [shouldn't be necessary; setting up gray will set up all colors] */
319 if (colr != NO_COLOR && !xw->nh_colors[colr].pixel)
320 (void) get_nhcolor(xw, colr);
322 /* handle highlighting if caller has specified that; set foreground,
323 background, and font even if not specified this time in case they
324 used modified values last time (which would stick if not reset) */
325 (void) memset((genericptr_t) args, 0, sizeof args);
326 num_args = 0;
327 if (colr != NO_COLOR)
328 fg = xw->nh_colors[colr].pixel;
329 if ((attr & HL_INVERSE) != 0) {
330 px = fg;
331 fg = bg;
332 bg = px;
334 /* foreground and background might both default to black, so we
335 need to force one to be different if/when they're the same
336 (actually, tt_status_fixup() takes care of that nowadays);
337 using gray to implement 'dim' only works for black and white
338 (or color+'inverse' when former background was black or white) */
339 if (fg == bg
340 || ((attr & HL_DIM) != 0 && (fg == whitePxl || fg == blackPxl)))
341 fg = (fg != grayPxl) ? grayPxl
342 : (fg != blackPxl) ? blackPxl
343 : whitePxl;
344 XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++;
345 XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++;
346 if (attr & HL_BOLD) {
347 load_boldfont(xw_status_win, label);
348 if (xw_status_win->boldfs)
349 font = xw_status_win->boldfs;
351 XtSetArg(args[num_args], nhStr(XtNfont), font); num_args++;
352 XtSetValues(label, args, num_args);
354 /* return possibly modified font to caller so that text width
355 measurement can use it */
356 if (font_p)
357 *font_p = font;
358 #else /*!STATUS_HILITES*/
359 nhUse(label);
360 nhUse(font_p);
361 #endif /*?STATUS_HILITES*/
362 if (fld != BL_CONDITION)
363 old_field_colors[fld] = colrattr;
364 else
365 old_cond_colors[cond] = colrattr;
368 /* set up a specific field other than 'condition'; its general location
369 was specified during widget creation but it might need adjusting */
370 static void
371 PrepStatusField(int fld, Widget label, const char *text)
373 Arg args[6];
374 Cardinal num_args;
375 Dimension lbl_wid;
376 XFontStruct *font = X11_status_font;
377 int colrattr = X11_status_colors[fld];
378 struct status_info_t *si = xw_status_win->Win_info.Status_info;
380 /* highlight if color and/or attribute(s) are different from last time */
381 if (colrattr != old_field_colors[fld])
382 HiliteField(label, fld, 0, colrattr, &font);
384 num_args = 0;
385 (void) memset((genericptr_t) args, 0, sizeof args);
386 /* set up the current text to be displayed */
387 if (text && *text) {
388 lbl_wid = 2 * si->in_wd + XTextWidth(font, text, (int) strlen(text));
389 } else {
390 text = "";
391 lbl_wid = 1;
393 XtSetArg(args[num_args], nhStr(XtNlabel), text); num_args++;
394 /*XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++;*/
395 XtSetValues(label, args, num_args);
396 XtResizeWidget(label, lbl_wid, si->ht, si->brd);
399 /* set up one status condition for tty-style status display */
400 static void
401 DisplayCond(
402 int c_idx, /* index into tt_condorder[] */
403 unsigned long *colormasks)
405 Widget label;
406 Arg args[6];
407 Cardinal num_args;
408 Dimension lbl_wid;
409 XFontStruct *font = X11_status_font;
410 int coloridx, attrmask, colrattr, idx;
411 unsigned long bm = tt_condorder[c_idx].mask;
412 const char *text = tt_condorder[c_idx].text;
413 struct status_info_t *si = xw_status_win->Win_info.Status_info;
415 if ((X11_condition_bits & bm) == 0)
416 return;
418 /* widgets have been created for every condition; we allocate them
419 from left to right rather than keeping their original assignments */
420 idx = next_cond_indx;
421 label = X11_cond_labels[idx];
423 /* handle highlighting if caller requests it */
424 coloridx = condcolor(bm, colormasks);
425 attrmask = condattr(bm, colormasks);
426 colrattr = (attrmask << 8) | coloridx;
427 if (colrattr != old_cond_colors[c_idx])
428 HiliteField(label, BL_CONDITION, c_idx, colrattr, &font);
430 (void) memset((genericptr_t) args, 0, sizeof args);
431 num_args = 0;
432 /* set the condition text and its width; this widget might have
433 been displaying a different condition last time around */
434 XtSetArg(args[num_args], nhStr(XtNlabel), text); num_args++;
435 /* measure width after maybe changing font [HiliteField()] */
436 lbl_wid = 2 * si->in_wd + XTextWidth(font, text, (int) strlen(text));
437 /*XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++;*/
439 /* make this condition widget be ready for display */
440 XtSetValues(label, args, num_args);
441 XtResizeWidget(label, lbl_wid, si->ht, si->brd);
443 ++next_cond_indx;
446 /* display the tty-style status conditions; the number shown varies and
447 we might be showing more, same, or fewer than during previous status */
448 static int
449 render_conditions(int row, int dx)
451 Widget label;
452 Arg args[6];
453 Cardinal num_args;
454 Position lbl_x;
455 int i, gap = 5;
456 struct status_info_t *si = xw_status_win->Win_info.Status_info;
457 Dimension lbl_wid, brd_wid = si->brd;
459 for (i = 0; i < next_cond_indx; i++) {
460 label = X11_cond_labels[i];
462 /* width of this widget was set in DisplayCond(); fetch it */
463 (void) memset((genericptr_t) args, 0, sizeof args);
464 num_args = 0;
465 XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++;
466 XtGetValues(label, args, num_args);
468 /* figure out where to draw this widget and place it there */
469 lbl_x = (Position) (dx + 1 + gap);
471 XtConfigureWidget(label, lbl_x, si->y[row], lbl_wid, si->ht, brd_wid);
473 /* keep track of where the end of our text appears */
474 dx = (int) lbl_x + (int) (lbl_wid + 2 * brd_wid) - 1;
477 /* if we have fewer conditions shown now than last time, set the
478 excess ones to blank; unlike the set drawn above, these haven't
479 been prepared in advance by DisplayCond because they aren't
480 being displayed; they might have been highlighted last time so
481 we need to specify more than just an empty text string */
482 if (next_cond_indx < prev_cond_indx) {
483 XFontStruct *font = X11_status_font;
484 Pixel fg = X11_status_fg, bg = X11_status_bg;
486 lbl_x = dx + 1;
487 lbl_wid = 1 + 2 * brd_wid;
488 for (i = next_cond_indx; i < prev_cond_indx; ++i) {
489 label = X11_cond_labels[i];
491 (void) memset((genericptr_t) args, 0, sizeof args);
492 num_args = 0;
493 XtSetArg(args[num_args], nhStr(XtNlabel), ""); num_args++;
494 XtSetArg(args[num_args], nhStr(XtNfont), font); num_args++;
495 XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++;
496 XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++;
497 /*XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++;*/
498 /*XtSetArg(args[num_args], nhStr(XtNx), lbl_x); num_args++;*/
499 XtSetValues(label, args, num_args);
500 old_cond_colors[i] = NO_COLOR; /* fg, bg, font were just reset */
501 XtConfigureWidget(label, lbl_x, si->y[row], lbl_wid, si->ht, 0);
502 /* don't advance 'dx' here */
506 return dx;
509 #ifdef STATUS_HILITES
510 /* reset status_hilite for BL_RESET; if highlighting has been disabled or
511 this field is disabled, clear highlighting for this field or condition */
512 static void
513 tt_reset_color(
514 int fld,
515 int cond,
516 unsigned long *colormasks)
518 Widget label;
519 int colrattr = NO_COLOR;
521 if (fld != BL_CONDITION) {
522 if (iflags.hilite_delta != 0L && status_activefields[fld])
523 colrattr = X11_status_colors[fld];
524 cond = 0;
525 label = X11_status_labels[fld];
526 } else {
527 unsigned long bm = tt_condorder[cond].mask;
529 if (iflags.hilite_delta != 0L && (X11_condition_bits & bm) != 0) {
530 /* BL_RESET before first BL_CONDITION will have colormasks==Null
531 but condcolor() and condattr() can cope with that */
532 colrattr = condcolor(bm, colormasks);
533 colrattr |= (condattr(bm, colormasks) << 8);
535 label = X11_cond_labels[cond];
537 HiliteField(label, fld, cond, colrattr, (XFontStruct **) 0);
539 #endif
541 /* make sure foreground, background, and font have reasonable values,
542 then explicitly set them for all the status widgets;
543 also cache some geometry settings in (*xw_status_win).Status_info */
544 static void
545 tt_status_fixup(void)
547 Arg args[6];
548 Cardinal num_args;
549 Widget w;
550 Position lbl_y;
551 int x, y, ci, fld;
552 XFontStruct *font = 0;
553 Pixel fg = 0, bg = 0;
554 struct status_info_t *si = xw_status_win->Win_info.Status_info;
556 (void) memset((genericptr_t) args, 0, sizeof args);
557 num_args = 0;
558 XtSetArg(args[num_args], nhStr(XtNfont), &font); num_args++;
559 XtSetArg(args[num_args], nhStr(XtNforeground), &fg); num_args++;
560 XtSetArg(args[num_args], nhStr(XtNbackground), &bg); num_args++;
561 XtGetValues(X11_status_widget, args, num_args);
562 if (fg == bg) {
563 XColor black = get_nhcolor(xw_status_win, CLR_BLACK),
564 white = get_nhcolor(xw_status_win, CLR_WHITE);
566 fg = (bg == white.pixel) ? black.pixel : white.pixel;
568 X11_status_fg = si->fg = fg, X11_status_bg = si->bg = bg;
570 if (!font) {
571 w = X11_status_widget;
572 XtSetArg(args[0], nhStr(XtNfont), &font);
573 do {
574 XtGetValues(w, args, ONE);
575 } while (!font && (w = XtParent(w)) != 0);
577 if (!font) {
578 /* trial and error time -- this is where we've actually
579 been obtaining the font even though we aren't setting
580 it for any of the field widgets (until for(y,x) below) */
581 XtGetValues(X11_status_labels[0], args, ONE);
583 if (!font) { /* this bit is untested... */
584 /* write some text and hope Xaw sets up font for us */
585 XtSetArg(args[0], nhStr(XtNlabel), "NetHack");
586 XtSetValues(X11_status_labels[0], args, ONE);
587 (void) XFlush(XtDisplay(X11_status_labels[0]));
589 XtSetArg(args[0], nhStr(XtNfont), &font);
590 XtGetValues(X11_status_labels[0], args, ONE);
592 /* if still Null, XTextWidth() would crash so bail out */
593 if (!font)
594 panic("X11 status can't determine font.");
598 X11_status_font = si->fs = font;
600 /* amount of space to advance a widget's location by one space;
601 increase width a tiny bit beyond the actual space */
602 si->spacew = XTextWidth(X11_status_font, " ", 1) + (Dimension) 1;
604 (void) memset((genericptr_t) args, 0, sizeof args);
605 num_args = 0;
606 XtSetArg(args[num_args], nhStr(XtNfont), font); num_args++;
607 XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++;
608 XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++;
609 XtSetValues(X11_status_widget, args, num_args);
611 for (y = 0; y < X11_NUM_STATUS_LINES; y++) {
612 for (x = 0; x < X11_NUM_STATUS_FIELD; x++) {
613 fld = X11_fieldorder[y][x]; /* next field to handle */
614 if (fld <= BL_FLUSH)
615 continue; /* skip fieldorder[][] padding */
617 XtSetValues(X11_status_labels[fld], args, num_args);
618 old_field_colors[fld] = NO_COLOR;
620 if (fld == BL_CONDITION) {
621 for (ci = 0; ci < SIZE(X11_cond_labels); ++ci) { /* 0..31 */
622 XtSetValues(X11_cond_labels[ci], args, num_args);
623 old_cond_colors[ci] = NO_COLOR;
629 /* cache the y coordinate of each row for XtConfigureWidget() */
630 (void) memset((genericptr_t) args, 0, sizeof args);
631 num_args = 0;
632 XtSetArg(args[0], nhStr(XtNy), &lbl_y); num_args++;
633 for (y = 0; y < X11_NUM_STATUS_LINES; y++) {
634 fld = X11_fieldorder[y][0];
635 XtGetValues(X11_status_labels[fld], args, num_args);
636 si->y[y] = lbl_y;
639 /* cache height, borderWidth, and internalWidth for XtResizeWidget() */
640 (void) memset((genericptr_t) args, 0, sizeof args);
641 num_args = 0;
642 XtSetArg(args[num_args], nhStr(XtNheight), &si->ht); num_args++;
643 XtSetArg(args[num_args], nhStr(XtNborderWidth), &si->brd); num_args++;
644 XtSetArg(args[num_args], nhStr(XtNinternalWidth), &si->in_wd); num_args++;
645 XtGetValues(X11_status_labels[0], args, num_args);
647 /* X11_status_update_tty() wants this in order to right justify 'vers' */
648 if (!xw_status_win->pixel_width) {
649 XtSetArg(args[0], nhStr(XtNwidth), &xw_status_win->pixel_width);
650 XtGetValues(xw_status_win->w, args, ONE);
654 DISABLE_WARNING_FORMAT_NONLITERAL
656 /* core requests updating one status field (or is indicating that it's time
657 to flush all updated fields); tty-style handling */
658 static void
659 X11_status_update_tty(
660 int fld,
661 genericptr_t ptr,
662 int chg UNUSED,
663 int percent,
664 int color,
665 unsigned long *colormasks) /* bitmask of highlights for conditions */
667 static int xtra_space[MAXBLSTATS];
668 static unsigned long *cond_colormasks = (unsigned long *) 0;
670 Arg args[6];
671 Cardinal num_args;
672 Position lbl_x;
673 Dimension lbl_wid, brd_wid;
674 Widget label;
676 struct status_info_t *si;
677 char goldbuf[40];
678 const char *fmt;
679 const char *text;
680 unsigned long *condptr;
681 int f, x, y, dx;
683 if (X11_status_fg == X11_status_bg || !X11_status_font)
684 tt_status_fixup();
686 if (fld == BL_RESET) {
687 #ifdef STATUS_HILITES
688 for (y = 0; y < X11_NUM_STATUS_LINES; y++) {
689 for (x = 0; x < X11_NUM_STATUS_FIELD; x++) {
690 f = X11_fieldorder[y][x];
691 if (f <= BL_FLUSH)
692 continue; /* skip padding in the fieldorder[][] layout */
693 if (f != BL_CONDITION) {
694 tt_reset_color(f, 0, (unsigned long *) 0);
695 } else {
696 int c_i;
698 for (c_i = 0; c_i < SIZE(tt_condorder); ++c_i)
699 tt_reset_color(f, c_i, cond_colormasks);
703 #endif
704 fld = BL_FLUSH;
707 if (fld == BL_CONDITION) {
708 condptr = (unsigned long *) ptr;
709 X11_condition_bits = *condptr;
710 cond_colormasks = colormasks; /* expected to be non-Null */
712 prev_cond_indx = next_cond_indx;
713 next_cond_indx = 0;
714 /* if any conditions are active, set up their widgets */
715 if (X11_condition_bits)
716 for (f = 0; f < SIZE(tt_condorder); ++f)
717 DisplayCond(f, cond_colormasks);
718 return;
720 } else if (fld != BL_FLUSH) {
721 /* set up a specific field other than 'condition' */
722 text = (char *) ptr;
723 if (fld == BL_GOLD)
724 text = decode_mixed(goldbuf, text);
725 xtra_space[fld] = 0;
726 if (status_activefields[fld]) {
727 fmt = (fld == BL_TITLE && iflags.wc2_hitpointbar) ? "%-30s"
728 : status_fieldfmt[fld] ? status_fieldfmt[fld] : "%s";
729 if (*fmt == ' ') {
730 ++xtra_space[fld];
731 ++fmt;
733 Sprintf(status_vals[fld], fmt, text);
734 } else {
735 /* don't expect this since core won't call status_update()
736 for a field which isn't active */
737 *status_vals[fld] = '\0';
739 #ifdef STATUS_HILITES
740 if (!iflags.hilite_delta)
741 color = NO_COLOR;
742 #endif
743 X11_status_colors[fld] = color;
744 if (iflags.wc2_hitpointbar && fld == BL_HP) {
745 hpbar_percent = percent;
746 hpbar_color = color;
749 label = X11_status_labels[fld];
750 text = status_vals[fld];
751 PrepStatusField(fld, label, text);
752 return;
756 * BL_FLUSH: draw all the status fields.
758 si = xw_status_win->Win_info.Status_info; /* for cached geometry */
760 for (y = 0; y < X11_NUM_STATUS_LINES; y++) { /* row */
761 dx = 0; /* no pixels written to this row yet */
763 for (x = 0; x < X11_NUM_STATUS_FIELD; x++) { /* 'column' */
764 f = X11_fieldorder[y][x];
765 if (f <= BL_FLUSH)
766 continue; /* skip padding in the fieldorder[][] layout */
768 if (f == BL_CONDITION) {
769 if (next_cond_indx > 0 || prev_cond_indx > 0)
770 dx = render_conditions(y, dx);
771 continue;
774 label = X11_status_labels[f];
775 text = status_vals[f];
777 (void) memset((genericptr_t) args, 0, sizeof args);
778 num_args = 0;
779 XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++;
780 XtGetValues(label, args, num_args);
781 brd_wid = si->brd;
783 /* for a field which shouldn't be shown, we can't just skip
784 it because we might need to remove its previous content
785 if it has just been toggled off */
786 if (!status_activefields[f]) {
787 if (lbl_wid <= 1)
788 continue;
789 text = "";
790 lbl_wid = (Dimension) 1;
791 brd_wid = (Dimension) 0;
792 } else if (xtra_space[f]) {
793 /* if this field was to be formatted with a leading space
794 to separate it from the preceding field, we suppressed
795 that space during formatting; insert separation between
796 fields here; this prevents inverse video highlighting
797 from inverting the separating space along with the text */
798 dx += xtra_space[f] * si->spacew;
801 /* where to display the current widget */
802 lbl_x = (Position) (dx + 1);
803 if (f == BL_VERS) {
804 Dimension win_wid = xw_status_win->pixel_width,
805 fld_wid = lbl_wid + 2 * brd_wid;
807 /* in case the doodad for resizing the window via click and
808 drag is in the lower right corner; justifying all the way
809 to the edge results in the last character being obscured;
810 avoid that by treating the 'vers' widget as one char
811 bigger than it actually is (an implicit trailing space) */
812 fld_wid += si->spacew;
813 /* right justify if there's room */
814 if (dx < win_wid - fld_wid)
815 lbl_x = win_wid - fld_wid;
818 (void) memset((genericptr_t) args, 0, sizeof args);
819 num_args = 0;
820 XtSetArg(args[num_args], nhStr(XtNlabel), text); num_args++;
821 /*XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++;*/
822 /*XtSetArg(args[num_args], nhStr(XtNx), lbl_x); num_args++;*/
823 XtSetValues(label, args, num_args);
824 XtConfigureWidget(label, lbl_x, si->y[y],
825 lbl_wid, si->ht, brd_wid);
827 /* track the right-most pixel written so far */
828 dx = (int) lbl_x + (int) (lbl_wid + 2 * brd_wid) - 1;
829 } /* [x] fields/columns in current row */
830 } /* [y] rows */
832 /* this probably doesn't buy us anything but it isn't a sure thing
833 that nethack will immediately ask for input (triggering auto-flush) */
834 (void) XFlush(XtDisplay(X11_status_labels[0]));
837 RESTORE_WARNING_FORMAT_NONLITERAL
839 /*ARGSUSED*/
840 static void
841 X11_status_update_fancy(
842 int fld,
843 genericptr_t ptr,
844 int chg UNUSED, int percent UNUSED,
845 int colrattr,
846 unsigned long *colormasks UNUSED)
848 static const struct bl_to_ff {
849 int bl, ff;
850 } bl_to_fancyfield[] = {
851 { BL_TITLE, F_NAME },
852 { BL_STR, F_STR },
853 { BL_DX, F_DEX },
854 { BL_CO, F_CON },
855 { BL_IN, F_INT },
856 { BL_WI, F_WIS },
857 { BL_CH, F_CHA },
858 { BL_ALIGN, F_ALIGN },
859 { BL_SCORE, F_SCORE },
860 { BL_CAP, F_ENCUMBER },
861 { BL_GOLD, F_GOLD },
862 { BL_ENE, F_POWER },
863 { BL_ENEMAX, F_MAXPOWER },
864 { BL_XP, F_XP_LEVL }, /* shares with BL_HD, depending upon Upolyd */
865 { BL_AC, F_AC },
866 { BL_TIME, F_TIME },
867 { BL_HUNGER, F_HUNGER },
868 { BL_HP, F_HP },
869 { BL_HPMAX, F_MAXHP },
870 { BL_LEVELDESC, F_DLEVEL },
871 { BL_VERS, F_VERS },
872 { BL_EXP, F_EXP_PTS }
874 static const struct mask_to_ff {
875 unsigned long mask;
876 int ff;
877 } mask_to_fancyfield[] = {
878 { BL_MASK_GRAB, F_GRABBED },
879 { BL_MASK_STONE, F_STONE },
880 { BL_MASK_SLIME, F_SLIME },
881 { BL_MASK_STRNGL, F_STRNGL },
882 { BL_MASK_FOODPOIS, F_FOODPOIS },
883 { BL_MASK_TERMILL, F_TERMILL },
884 { BL_MASK_INLAVA, F_IN_LAVA },
885 { BL_MASK_HELD, F_HELD },
886 { BL_MASK_HOLDING, F_HOLDING },
887 { BL_MASK_BLIND, F_BLIND },
888 { BL_MASK_DEAF, F_DEAF },
889 { BL_MASK_STUN, F_STUN },
890 { BL_MASK_CONF, F_CONF },
891 { BL_MASK_HALLU, F_HALLU },
892 { BL_MASK_TRAPPED, F_TRAPPED },
893 { BL_MASK_TETHERED, F_TETHERED },
894 { BL_MASK_LEV, F_LEV },
895 { BL_MASK_FLY, F_FLY },
896 { BL_MASK_RIDE, F_RIDE }
898 int i;
900 if (fld == BL_RESET || fld == BL_FLUSH) {
901 if (WIN_STATUS != WIN_ERR) {
902 update_fancy_status(FALSE);
904 return;
907 if (fld == BL_CONDITION) {
908 unsigned long changed_bits, *condptr = (unsigned long *) ptr;
910 X11_condition_bits = *condptr;
911 /* process the bits that are different from last time */
912 changed_bits = (X11_condition_bits ^ old_condition_bits);
913 if (changed_bits) {
914 for (i = 0; i < SIZE(mask_to_fancyfield); i++)
915 if ((changed_bits & mask_to_fancyfield[i].mask) != 0L)
916 update_fancy_status_field(mask_to_fancyfield[i].ff,
917 condcolor(mask_to_fancyfield[i].mask, colormasks),
918 condattr(mask_to_fancyfield[i].mask, colormasks));
919 old_condition_bits = X11_condition_bits; /* remember 'On' bits */
921 } else {
922 int colr, attr;
924 if ((colrattr & 0x00ff) >= CLR_MAX)
925 colrattr = (colrattr & ~0x00ff) | NO_COLOR;
926 colr = colrattr & 0x00ff; /* guaranteed to be >= 0 and < CLR_MAX */
927 attr = (colrattr >> 8) & 0x00ff;
929 for (i = 0; i < SIZE(bl_to_fancyfield); i++)
930 if (bl_to_fancyfield[i].bl == fld) {
931 update_fancy_status_field(bl_to_fancyfield[i].ff, colr, attr);
932 break;
937 void
938 X11_status_update(
939 int fld,
940 genericptr_t ptr,
941 int chg, int percent,
942 int color,
943 unsigned long *colormasks)
945 if (fld < BL_RESET || fld >= MAXBLSTATS)
946 panic("X11_status_update(%d) -- invalid field", fld);
948 if (appResources.fancy_status)
949 X11_status_update_fancy(fld, ptr, chg, percent, color, colormasks);
950 else
951 X11_status_update_tty(fld, ptr, chg, percent, color, colormasks);
954 /* create a widget for a particular status field or potential condition */
955 static Widget
956 create_tty_status_field(int fld, int condindx, Widget above, Widget left)
958 Arg args[16];
959 Cardinal num_args;
960 char labelname[40];
961 int gap = condindx ? 5 : 0;
963 if (!condindx)
964 Sprintf(labelname, "label_%s", bl_idx_to_fldname(fld));
965 else
966 Sprintf(labelname, "cond_%02d", condindx);
968 /* set up widget attributes which (mostly) aren't going to be changing */
969 (void) memset((genericptr_t) args, 0, sizeof args);
970 num_args = 0;
971 if (above) {
972 XtSetArg(args[num_args], nhStr(XtNfromVert), above); num_args++;
974 if (left) {
975 XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); num_args++;
978 XtSetArg(args[num_args], nhStr(XtNhorizDistance), gap); num_args++;
979 XtSetArg(args[num_args], nhStr(XtNvertDistance), 0); num_args++;
981 XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++;
982 XtSetArg(args[num_args], nhStr(XtNbottomMargin), 0); num_args++;
983 XtSetArg(args[num_args], nhStr(XtNleftMargin), 0); num_args++;
984 XtSetArg(args[num_args], nhStr(XtNrightMargin), 0); num_args++;
985 XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++;
986 /* internalWidth: default is 4; cut that it half and adjust regular
987 width to have it on both left and right instead of just on the left */
988 XtSetArg(args[num_args], nhStr(XtNinternalWidth), 2); num_args++;
989 XtSetArg(args[num_args], nhStr(XtNborderWidth), 0); num_args++;
990 XtSetArg(args[num_args], nhStr(XtNlabel), ""); num_args++;
991 return XtCreateManagedWidget(labelname, labelWidgetClass,
992 X11_status_widget, args, num_args);
995 /* create an overall status widget (X11_status_widget) and also
996 separate widgets for all status fields and potential conditions */
997 static Widget
998 create_tty_status(Widget parent, Widget top)
1000 Widget form; /* viewport that holds the form that surrounds everything */
1001 Widget w, over_w, prev_w;
1002 Arg args[6];
1003 Cardinal num_args;
1004 int x, y, i, fld;
1006 (void) memset((genericptr_t) args, 0, sizeof args);
1007 num_args = 0;
1008 if (top) {
1009 XtSetArg(args[num_args], nhStr(XtNfromVert), top); num_args++;
1011 XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0); num_args++;
1012 XtSetArg(args[num_args], XtNborderWidth, 0); num_args++;
1013 XtSetArg(args[num_args], XtNwidth, 400); num_args++;
1014 XtSetArg(args[num_args], XtNheight, 100); num_args++;
1015 form = XtCreateManagedWidget("status_viewport", viewportWidgetClass,
1016 parent, args, num_args);
1018 (void) memset((genericptr_t) args, 0, sizeof args);
1019 num_args = 0;
1020 XtSetArg(args[num_args], XtNwidth, 400); num_args++;
1021 XtSetArg(args[num_args], XtNheight, 100); num_args++;
1022 X11_status_widget = XtCreateManagedWidget("status_form", formWidgetClass,
1023 form, args, num_args);
1025 for (y = 0; y < X11_NUM_STATUS_LINES; y++) {
1026 fld = (y > 0) ? X11_fieldorder[y - 1][0] : 0; /* temp, for over_w */
1027 /* for row(s) beyond the first, pick a widget in the previous
1028 row to put this one underneath (in 'y' terms; 'x' is fluid) */
1029 over_w = (y > 0) ? X11_status_labels[fld] : (Widget) 0;
1030 /* widget on current row to put the next one to the right of ('x') */
1031 prev_w = (Widget) 0;
1032 for (x = 0; x < X11_NUM_STATUS_FIELD; x++) {
1033 fld = X11_fieldorder[y][x]; /* next field to handle */
1034 if (fld <= BL_FLUSH)
1035 continue; /* skip fieldorder[][] padding */
1037 w = create_tty_status_field(fld, 0, over_w, prev_w);
1038 X11_status_labels[fld] = prev_w = w;
1040 if (fld == BL_CONDITION) {
1041 for (i = 1; i <= SIZE(X11_cond_labels); ++i) { /* 1..32 */
1042 w = create_tty_status_field(fld, i, over_w, prev_w);
1043 X11_cond_labels[i - 1] = prev_w = w;
1048 return X11_status_widget;
1051 /*ARGSUSED*/
1052 void
1053 create_status_window_tty(struct xwindow *wp, /* window pointer */
1054 boolean create_popup UNUSED, Widget parent)
1056 wp->type = NHW_STATUS;
1057 wp->w = create_tty_status(parent, (Widget) 0);
1060 void
1061 destroy_status_window_tty(struct xwindow *wp)
1063 /* if status_information is defined, then it is a "text" status window */
1064 if (wp->status_information) {
1065 if (wp->popup) {
1066 nh_XtPopdown(wp->popup);
1067 if (!wp->keep_window)
1068 XtDestroyWidget(wp->popup), wp->popup = (Widget) 0;
1070 free((genericptr_t) wp->status_information);
1071 wp->status_information = 0;
1072 } else {
1075 if (!wp->keep_window)
1076 wp->type = NHW_NONE;
1079 /*ARGSUSED*/
1080 void
1081 adjust_status_tty(struct xwindow *wp UNUSED, const char *str UNUSED)
1083 /* nothing */
1084 return;
1087 void
1088 create_status_window(
1089 struct xwindow *wp, /* window pointer */
1090 boolean create_popup,
1091 Widget parent)
1093 struct status_info_t *si = (struct status_info_t *) alloc(sizeof *si);
1095 xw_status_win = wp;
1096 if (wp->Win_info.Status_info)
1097 free((genericptr_t) wp->Win_info.Status_info);
1098 wp->Win_info.Status_info = si;
1099 (void) memset((genericptr_t) si, 0, sizeof *si);
1101 if (!appResources.fancy_status)
1102 create_status_window_tty(wp, create_popup, parent);
1103 else
1104 create_status_window_fancy(wp, create_popup, parent);
1106 #if 0 /*
1107 * this does not work as intended; it triggers
1108 * "Warning: Cannot find callback list in XtAddCallback"
1110 XtAddCallback(wp->w, XtNresizeCallback, stat_resized, (XtPointer) 0);
1111 #else
1112 nhUse(stat_resized);
1113 #endif
1116 /* callback to deal with the game window being resized */
1117 static void
1118 stat_resized(Widget w, XtPointer call_data, XtPointer client_data)
1120 Arg args[4];
1121 Cardinal num_args;
1122 struct xwindow *wp = xw_status_win;
1124 nhUse(call_data);
1125 nhUse(client_data);
1127 if (w == wp->w) {
1128 num_args = 0;
1129 XtSetArg(args[num_args], XtNwidth, &wp->pixel_width); num_args++;
1130 XtSetArg(args[num_args], XtNwidth, &wp->pixel_height); num_args++;
1131 XtGetValues(w, args, num_args);
1132 } else {
1133 impossible("Status Window resized, but of what widget?");
1136 /* tell core to call us back for a full status update */
1137 disp.botlx = TRUE;
1140 void
1141 destroy_status_window(struct xwindow *wp)
1143 if (appResources.fancy_status)
1144 destroy_status_window_fancy(wp);
1145 else
1146 destroy_status_window_tty(wp);
1149 void
1150 adjust_status(struct xwindow *wp, const char *str)
1152 if (appResources.fancy_status)
1153 adjust_status_fancy(wp, str);
1154 else
1155 adjust_status_tty(wp, str);
1158 void
1159 create_status_window_fancy(struct xwindow *wp, /* window pointer */
1160 boolean create_popup, Widget parent)
1162 XFontStruct *fs;
1163 Arg args[8];
1164 Cardinal num_args;
1165 Position top_margin, bottom_margin, left_margin, right_margin;
1167 wp->type = NHW_STATUS;
1169 if (!create_popup) {
1171 * If we are not creating a popup, then we must be the "main" status
1172 * window.
1174 if (!parent)
1175 panic("create_status_window_fancy: no parent for fancy status");
1176 wp->status_information = 0;
1177 wp->w = create_fancy_status(parent, (Widget) 0);
1178 return;
1181 wp->status_information =
1182 (struct status_info_t *) alloc(sizeof (struct status_info_t));
1184 init_text_buffer(&wp->status_information->text);
1186 num_args = 0;
1187 XtSetArg(args[num_args], XtNallowShellResize, False); num_args++;
1188 XtSetArg(args[num_args], XtNinput, False); num_args++;
1190 wp->popup = parent = XtCreatePopupShell("status_popup",
1191 topLevelShellWidgetClass,
1192 toplevel, args, num_args);
1194 * If we're here, then this is an auxiliary status window. If we're
1195 * cancelled via a delete window message, we should just pop down.
1198 num_args = 0;
1199 XtSetArg(args[num_args], nhStr(XtNdisplayCaret), False); num_args++;
1200 XtSetArg(args[num_args], nhStr(XtNscrollHorizontal),
1201 XawtextScrollWhenNeeded); num_args++;
1202 XtSetArg(args[num_args], nhStr(XtNscrollVertical),
1203 XawtextScrollWhenNeeded); num_args++;
1205 wp->w = XtCreateManagedWidget("status", /* name */
1206 asciiTextWidgetClass,
1207 parent, /* parent widget */
1208 args, /* set some values */
1209 num_args); /* number of values to set */
1212 * Adjust the height and width of the message window so that it
1213 * is two lines high and COLNO of the widest characters wide.
1216 /* Get the font and margin information. */
1217 num_args = 0;
1218 XtSetArg(args[num_args], XtNfont, &fs); num_args++;
1219 XtSetArg(args[num_args], nhStr(XtNtopMargin), &top_margin); num_args++;
1220 XtSetArg(args[num_args], nhStr(XtNbottomMargin),
1221 &bottom_margin); num_args++;
1222 XtSetArg(args[num_args], nhStr(XtNleftMargin), &left_margin); num_args++;
1223 XtSetArg(args[num_args], nhStr(XtNrightMargin),
1224 &right_margin); num_args++;
1225 XtGetValues(wp->w, args, num_args);
1227 wp->pixel_height = 2 * nhFontHeight(wp->w) + top_margin + bottom_margin;
1228 wp->pixel_width = COLNO * fs->max_bounds.width
1229 + left_margin + right_margin;
1231 /* Set the new width and height. */
1232 num_args = 0;
1233 XtSetArg(args[num_args], XtNwidth, wp->pixel_width); num_args++;
1234 XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++;
1235 XtSetValues(wp->w, args, num_args);
1238 void
1239 destroy_status_window_fancy(struct xwindow *wp)
1241 /* If status_information is defined, then it a "text" status window. */
1242 if (wp->status_information) {
1243 if (wp->popup) {
1244 nh_XtPopdown(wp->popup);
1245 if (!wp->keep_window)
1246 XtDestroyWidget(wp->popup), wp->popup = (Widget) 0;
1248 free((genericptr_t) wp->status_information);
1249 wp->status_information = 0;
1250 } else {
1251 destroy_fancy_status(wp);
1253 if (!wp->keep_window)
1254 wp->type = NHW_NONE;
1258 * This assumes several things:
1259 * + Status has only 2 lines
1260 * + That both lines are updated in succession in line order.
1261 * + We didn't set stringInPlace on the widget.
1263 void
1264 adjust_status_fancy(struct xwindow *wp, const char *str)
1266 Arg args[2];
1267 Cardinal num_args;
1269 if (!wp->status_information) {
1270 update_fancy_status(TRUE);
1271 return;
1274 if (wp->cursy == 0) {
1275 clear_text_buffer(&wp->status_information->text);
1276 append_text_buffer(&wp->status_information->text, str, FALSE);
1277 return;
1279 append_text_buffer(&wp->status_information->text, str, FALSE);
1281 /* Set new buffer as text. */
1282 num_args = 0;
1283 XtSetArg(args[num_args], XtNstring,
1284 wp->status_information->text.text); num_args++;
1285 XtSetValues(wp->w, args, num_args);
1288 /* Fancy ================================================================== */
1289 extern const char *const hu_stat[]; /* from eat.c */
1290 extern const char *const enc_stat[]; /* from botl.c */
1292 struct X_status_value {
1293 /* we have to cast away 'const' when assigning new names */
1294 const char *name; /* text name */
1295 int type; /* status type */
1296 Widget w; /* widget of name/value pair */
1297 long last_value; /* value displayed */
1298 int turn_count; /* last time the value changed */
1299 boolean set; /* if highlighted */
1300 boolean after_init; /* don't highlight on first change (init) */
1301 boolean inverted_hilite; /* if highlit due to hilite_status inverse rule */
1302 Pixel default_fg; /* what FG color it initialized with */
1303 int colr, attr; /* color and attribute */
1306 /* valid type values */
1307 #define SV_VALUE 0 /* displays a label:value pair */
1308 #define SV_LABEL 1 /* displays a changeable label */
1309 #define SV_NAME 2 /* displays an unchangeable name */
1311 /* for overloaded conditions */
1312 struct ovld_item {
1313 unsigned long ovl_mask;
1314 int ff;
1316 #define NUM_OVLD 4 /* peak number of overloads for a single field */
1317 struct f_overload {
1318 unsigned long all_mask;
1319 struct ovld_item conds[NUM_OVLD];
1322 static const struct f_overload *ff_ovld_from_mask(unsigned long);
1323 static const struct f_overload *ff_ovld_from_indx(int);
1324 static void hilight_label(Widget);
1325 static void update_val(struct X_status_value *, long);
1326 static void skip_cond_val(struct X_status_value *);
1327 static void update_color(struct X_status_value *, int);
1328 static boolean name_widget_has_label(struct X_status_value *);
1329 static void apply_hilite_attributes(struct X_status_value *, int);
1330 static const char *width_string(int);
1331 static void create_widget(Widget, struct X_status_value *, int);
1332 static void get_widths(struct X_status_value *, int *, int *);
1333 static void set_widths(struct X_status_value *, int, int);
1334 static Widget init_column(const char *, Widget, Widget, Widget, int *, int);
1335 static void fixup_cond_widths(void);
1336 static Widget init_info_form(Widget, Widget, Widget);
1338 /* narrower values for the array initializer */
1339 #define W0 (Widget) 0
1340 #define P0 (Pixel) 0
1342 * Notes:
1343 * + Alignment needs a different init value, because -1 is an alignment.
1344 * + Armor Class is an schar, so 256 is out of range.
1345 * + Blank value is 0 and should never change.
1347 * - These must be in the same order as the F_foo numbers.
1349 static struct X_status_value shown_stats[NUM_STATS] = {
1350 /* 0 */
1351 { "", SV_NAME, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1352 /* 1 */
1353 { "Strength", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1354 { "Dexterity", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1355 { "Constitution", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1356 { "Intelligence", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1357 /* 5 */
1358 { "Wisdom", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1359 { "Charisma", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1360 /* F_NAME: 7 */
1361 { "", SV_LABEL, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1362 /* F_DLEVEL: 8 */
1363 { "", SV_LABEL, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1364 { "Gold", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1365 /* F_HP: 10 */
1366 { "Hit Points", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1367 { "Max HP", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1368 { "Power", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1369 { "Max Power", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1370 { "Armor Class", SV_VALUE, W0, 256L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1371 /* F_XP_LEVL: 15 */
1372 { "Xp Level", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1373 /* also 15 (overloaded field) */
1374 /*{ "Hit Dice", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },*/
1375 /* F_EXP_PTS: 16 (optionally displayed) */
1376 { "Exp Points", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1377 { "Alignment", SV_VALUE, W0, -2L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1378 /* 18, optionally displayed */
1379 { "Time", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1380 /* 19, conditionally present, optionally displayed when present */
1381 { "Score", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1382 /* F_HUNGER: 20 (blank if 'normal') */
1383 { "", SV_NAME, W0, -1L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1384 /* F_ENCUMBER: 21 (blank if unencumbered) */
1385 { "", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1386 { "Trapped", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1387 { "Tethered", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1388 { "Levitating", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1389 /* 25 */
1390 { "Flying", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1391 { "Riding", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1392 { "Grabbed!", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1393 /* F_STONE: 28 */
1394 { "Petrifying", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1395 { "Slimed", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1396 /* 30 */
1397 { "Strangled", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1398 { "Food Pois", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1399 { "Term Ill", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1400 /* F_IN_LAVA: 33 */
1401 { "Sinking", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1402 { "Held", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1403 /* 35 */
1404 { "Holding", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1405 { "Blind", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1406 { "Deaf", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1407 { "Stunned", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1408 { "Confused", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1409 /* F_HALLU: 40 (full spelling truncated due to space limitations) */
1410 { "Hallucinat", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
1411 /* F_VERS; optionally shown, generally treated as a pseudo-condition */
1412 { "Version 1.2.3", SV_LABEL, W0, 0L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
1414 #undef W0
1415 #undef P0
1417 * The following are supported by the core but not yet handled here:
1418 * bareh 'bare handed' (no weapon and no gloves)
1419 * busy involved in some multi-turn activity, possibly involuntarily
1420 * elf_iron elf being harmed by contact with iron (not implemented)
1421 * glowhands 'glowing hands' (inflict confuse monster for next N melee hits)
1422 * icy on or above ice terrain (temporary fumbling; might melt)
1423 * parlyz paralyzed (can't move)
1424 * sleeping asleep (can't move; might wake if attacked)
1425 * slippery 'slippery hands' or gloves (will drop non-cursed weapons)
1426 * submerged underwater (severely restricted vision, hampered movement)
1427 * unconsc unconscious (can't move; includes fainted)
1428 * woundedl 'wounded legs' (can't kick; temporary dex loss)
1431 /* some conditions are mutually exclusive so we overload their fields in
1432 order to share same display slot */
1433 static const struct f_overload cond_ovl[] = {
1434 { (BL_MASK_TRAPPED | BL_MASK_TETHERED),
1435 { { BL_MASK_TRAPPED, F_TRAPPED },
1436 { BL_MASK_TETHERED, F_TETHERED } },
1439 /* BL_GRABBED is mutually exclusive with these but is more severe so
1440 is shown separately rather than being overloaded with them */
1441 (BL_MASK_HELD | BL_MASK_HOLDING),
1442 { { BL_MASK_HELD, F_HELD },
1443 { BL_MASK_HOLDING, F_HOLDING } },
1445 #if 0 /* not yet implemented */
1446 { (BL_MASK_BUSY | BL_MASK_PARALYZ | BL_MASK_SLEEPING | BL_MASK_UNCONSC),
1447 { { BL_MASK_BUSY, F_BUSY }, /* can't move but none of the below... */
1448 { BL_MASK_PARALYZ, F_PARALYZED }
1449 { BL_MASK_SLEEPING, F_SLEEPING }
1450 { BL_MASK_UNCONSC, F_UNCONSCIOUS } },
1452 #endif
1455 static const struct f_overload *
1456 ff_ovld_from_mask(unsigned long mask)
1458 const struct f_overload *fo;
1460 for (fo = cond_ovl; fo < cond_ovl + SIZE(cond_ovl); ++fo) {
1461 if ((fo->all_mask & mask) != 0L)
1462 return fo;
1464 return (struct f_overload *) 0;
1467 static const struct f_overload *
1468 ff_ovld_from_indx(int indx) /* F_foo number, index into shown_stats[] */
1470 const struct f_overload *fo;
1471 int i, ff;
1473 if (indx > 0) { /* skip 0 (F_DUMMY) */
1474 for (fo = cond_ovl; fo < cond_ovl + SIZE(cond_ovl); ++fo) {
1475 for (i = 0; i < NUM_OVLD && (ff = fo->conds[i].ff) > 0; ++i)
1476 if (ff == indx)
1477 return fo;
1480 return (struct f_overload *) 0;
1484 * Set all widget values to a null string. This is used after all spacings
1485 * have been calculated so that when the window is popped up we don't get all
1486 * kinds of funny values being displayed.
1488 void
1489 null_out_status(void)
1491 int i;
1492 struct X_status_value *sv;
1493 Arg args[1];
1495 for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) {
1496 switch (sv->type) {
1497 case SV_VALUE:
1498 set_value(sv->w, "");
1499 break;
1501 case SV_LABEL:
1502 case SV_NAME:
1503 XtSetArg(args[0], XtNlabel, "");
1504 XtSetValues(sv->w, args, ONE);
1505 break;
1507 default:
1508 impossible("null_out_status: unknown type %d\n", sv->type);
1509 break;
1514 /* this is almost an exact duplicate of hilight_value() */
1515 static void
1516 hilight_label(Widget w) /* label widget */
1519 * This predates STATUS_HILITES.
1520 * It is used to show any changed item in inverse and gets
1521 * reset on the next turn.
1523 swap_fg_bg(w);
1526 DISABLE_WARNING_FORMAT_NONLITERAL
1528 static void
1529 update_val(struct X_status_value *attr_rec, long new_value)
1531 static boolean Exp_shown = TRUE, time_shown = TRUE, score_shown = TRUE,
1532 Xp_was_HD = FALSE;
1533 char buf[BUFSZ];
1534 Arg args[4];
1536 if (attr_rec->type == SV_LABEL) {
1537 if (attr_rec == &shown_stats[F_NAME]) {
1538 Strcpy(buf, svp.plname);
1539 buf[0] = highc(buf[0]);
1540 Strcat(buf, " the ");
1541 if (Upolyd) {
1542 char mnam[BUFSZ];
1543 int k;
1545 Strcpy(mnam, pmname(&mons[u.umonnum], Ugender));
1546 for (k = 0; mnam[k] != '\0'; k++) {
1547 if (k == 0 || mnam[k - 1] == ' ')
1548 mnam[k] = highc(mnam[k]);
1550 Strcat(buf, mnam);
1551 } else {
1552 Strcat(buf,
1553 rank_of(u.ulevel, svp.pl_character[0], flags.female));
1556 } else if (attr_rec == &shown_stats[F_DLEVEL]) {
1557 if (!describe_level(buf, 0)) {
1558 Strcpy(buf, svd.dungeons[u.uz.dnum].dname);
1559 Sprintf(eos(buf), ", level %d", depth(&u.uz));
1561 } else if (attr_rec == &shown_stats[F_VERS]) {
1562 if (flags.showvers)
1563 (void) status_version(buf, sizeof buf, FALSE);
1564 else
1565 buf[0] = '\0';
1566 } else {
1567 impossible("update_val: unknown label type \"%s\"",
1568 attr_rec->name);
1569 return;
1572 if (!strcmp(buf, attr_rec->name))
1573 return; /* same */
1575 /* Set the label. 'name' field is const for most entries;
1576 we need to cast away that const for this assignment */
1577 Strcpy((char *) attr_rec->name, buf);
1578 XtSetArg(args[0], XtNlabel, buf);
1579 XtSetValues(attr_rec->w, args, ONE);
1581 } else if (attr_rec->type == SV_NAME) {
1582 if (attr_rec->last_value == new_value)
1583 return; /* no change */
1585 attr_rec->last_value = new_value;
1587 /* special cases: hunger and encumbrance */
1588 if (attr_rec == &shown_stats[F_HUNGER]) {
1589 Strcpy(buf, hu_stat[new_value]);
1590 (void) mungspaces(buf);
1591 } else if (attr_rec == &shown_stats[F_ENCUMBER]) {
1592 Strcpy(buf, enc_stat[new_value]);
1593 } else if (new_value) {
1594 Strcpy(buf, attr_rec->name); /* condition name On */
1595 } else {
1596 *buf = '\0'; /* condition name Off */
1599 XtSetArg(args[0], XtNlabel, buf);
1600 XtSetValues(attr_rec->w, args, ONE);
1602 } else { /* a value pair */
1603 boolean force_update = FALSE;
1605 /* special case: time can be enabled & disabled */
1606 if (attr_rec == &shown_stats[F_TIME]) {
1607 if (flags.time && !time_shown) {
1608 set_name(attr_rec->w, shown_stats[F_TIME].name);
1609 force_update = TRUE;
1610 time_shown = TRUE;
1611 } else if (!flags.time && time_shown) {
1612 set_name(attr_rec->w, "");
1613 set_value(attr_rec->w, "");
1614 time_shown = FALSE;
1616 if (!time_shown)
1617 return;
1619 /* special case: experience points can be enabled & disabled */
1620 } else if (attr_rec == &shown_stats[F_EXP_PTS]) {
1621 boolean showexp = flags.showexp && !Upolyd;
1623 if (showexp && !Exp_shown) {
1624 set_name(attr_rec->w, shown_stats[F_EXP_PTS].name);
1625 force_update = TRUE;
1626 Exp_shown = TRUE;
1627 } else if (!showexp && Exp_shown) {
1628 set_name(attr_rec->w, "");
1629 set_value(attr_rec->w, "");
1630 Exp_shown = FALSE;
1632 if (!Exp_shown)
1633 return;
1635 /* special case: when available, score can be enabled & disabled */
1636 } else if (attr_rec == &shown_stats[F_SCORE]) {
1637 #ifdef SCORE_ON_BOTL
1638 if (flags.showscore && !score_shown) {
1639 set_name(attr_rec->w, shown_stats[F_SCORE].name);
1640 force_update = TRUE;
1641 score_shown = TRUE;
1642 } else
1643 #endif
1644 if (!flags.showscore && score_shown) {
1645 set_name(attr_rec->w, "");
1646 set_value(attr_rec->w, "");
1647 score_shown = FALSE;
1649 if (!score_shown)
1650 return;
1652 /* special case: when polymorphed, show "Hit Dice" and disable Exp */
1653 } else if (attr_rec == &shown_stats[F_XP_LEVL]) {
1654 if (Upolyd && !Xp_was_HD) {
1655 force_update = TRUE;
1656 set_name(attr_rec->w, "Hit Dice");
1657 Xp_was_HD = TRUE;
1658 } else if (!Upolyd && Xp_was_HD) {
1659 force_update = TRUE;
1660 set_name(attr_rec->w, shown_stats[F_XP_LEVL].name);
1661 Xp_was_HD = FALSE;
1663 /* core won't call status_update() for Exp when it hasn't changed
1664 so do so ourselves (to get Exp_shown flag to match display) */
1665 if (force_update)
1666 update_fancy_status_field(F_EXP_PTS, NO_COLOR, HL_UNDEF);
1669 if (attr_rec->last_value == new_value && !force_update) /* same */
1670 return;
1672 attr_rec->last_value = new_value;
1674 /* Special cases: strength and other characteristics, alignment
1675 and "clear". */
1676 if (attr_rec >= &shown_stats[F_STR]
1677 && attr_rec <= &shown_stats[F_CHA]) {
1678 static const char fmt1[] = "%ld%s", fmt2[] = "%2ld%s";
1679 struct xwindow *wp;
1680 const char *fmt = fmt1, *padding = "";
1682 /* for full-fledged fancy status, force two digits for all
1683 six characteristics, followed by three spaces of padding
1684 to match "/xx" exceptional strength */
1685 wp = (WIN_STATUS != WIN_ERR) ? &window_list[WIN_STATUS] : 0;
1686 if (wp && !wp->status_information)
1687 fmt = fmt2, padding = " ";
1689 if (new_value > 18L && attr_rec == &shown_stats[F_STR]) {
1690 if (new_value > 118L) /* 19..25 encoded as 119..125 */
1691 Sprintf(buf, fmt, new_value - 100L, padding);
1692 else if (new_value < 118L) /* 18/01..18/99 as 19..117*/
1693 Sprintf(buf, "18/%02ld", new_value - 18L);
1694 else
1695 Strcpy(buf, "18/**"); /* 18/100 encoded as 118 */
1696 } else { /* non-strength or less than 18/01 strength (3..18) */
1697 Sprintf(buf, fmt, new_value, padding); /* 3..25 */
1699 } else if (attr_rec == &shown_stats[F_ALIGN]) {
1700 Strcpy(buf, (new_value == A_CHAOTIC) ? "Chaotic"
1701 : (new_value == A_NEUTRAL) ? "Neutral" : "Lawful");
1702 } else {
1703 Sprintf(buf, "%ld", new_value);
1705 set_value(attr_rec->w, buf);
1709 * Now highlight the changed information. Don't highlight Time because
1710 * it's continually changing. Don't highlight version because once set
1711 * it only changes if player modifies 'versinfo' option. For others,
1712 * don't highlight if this is the first update.
1713 * If already highlighted, don't change it unless
1714 * it's being set to blank (where that item should be reset now instead
1715 * of showing highlighted blank until the next expiration check).
1717 * 3.7: highlight non-labelled 'name' items (conditions plus hunger
1718 * and encumbrance) when they come On. For all conditions going Off,
1719 * or changing to not-hungry or not-encumbered, there's nothing to
1720 * highlight because the field becomes blank.
1722 if (attr_rec->after_init) {
1723 /* toggle if not highlighted and being set to nonblank or if
1724 already highlighted and being set to blank */
1725 if (attr_rec != &shown_stats[F_TIME]
1726 && attr_rec != &shown_stats[F_VERS]
1727 && !attr_rec->set ^ !*buf) {
1728 /* But don't hilite if inverted from status_hilite since
1729 it will already be hilited by apply_hilite_attributes(). */
1730 if (!attr_rec->inverted_hilite) {
1731 if (attr_rec->type == SV_VALUE)
1732 hilight_value(attr_rec->w);
1733 else
1734 hilight_label(attr_rec->w);
1736 attr_rec->set = !attr_rec->set;
1738 attr_rec->turn_count = 0;
1739 } else {
1740 XtSetArg(args[0], XtNforeground, &attr_rec->default_fg);
1741 XtGetValues(attr_rec->w, args, ONE);
1742 attr_rec->after_init = TRUE;
1746 RESTORE_WARNING_FORMAT_NONLITERAL
1748 /* overloaded condition is being cleared without going through update_val()
1749 so that an alternate can be shown; put this one back to default settings */
1750 static void
1751 skip_cond_val(struct X_status_value *sv)
1753 sv->last_value = 0L; /* Off */
1754 if (sv->set) {
1755 /* if condition was highlighted and the alternate value has
1756 also requested to be highlighted, it used its own copy of
1757 'set' but the same widget so the highlighting got toggled
1758 off; this will turn in back on in that exceptional case */
1759 hilight_label(sv->w);
1760 sv->set = FALSE;
1764 static void
1765 update_color(struct X_status_value *sv, int color)
1767 Pixel pixel = 0;
1768 Arg args[1];
1769 XrmValue source;
1770 XrmValue dest;
1771 Widget w = (sv->type == SV_LABEL || sv->type == SV_NAME) ? sv->w
1772 : get_value_widget(sv->w);
1774 if (color == NO_COLOR) {
1775 if (sv->after_init)
1776 pixel = sv->default_fg;
1777 sv->colr = NO_COLOR;
1778 } else {
1779 source.addr = (XPointer) fancy_status_hilite_colors[color];
1780 source.size = (unsigned int) strlen((const char *) source.addr) + 1;
1781 dest.size = (unsigned int) sizeof (Pixel);
1782 dest.addr = (XPointer) &pixel;
1783 if (XtConvertAndStore(w, XtRString, &source, XtRPixel, &dest))
1784 sv->colr = color;
1786 if (pixel != 0) {
1787 char *arg_name = (sv->set || sv->inverted_hilite) ? XtNbackground
1788 : XtNforeground;
1790 XtSetArg(args[0], arg_name, pixel);
1791 XtSetValues(w, args, ONE);
1795 static boolean
1796 name_widget_has_label(struct X_status_value *sv)
1798 Arg args[1];
1799 const char *label;
1801 XtSetArg(args[0], XtNlabel, &label);
1802 XtGetValues(sv->w, args, ONE);
1803 return (*label != '\0');
1806 static void
1807 apply_hilite_attributes(struct X_status_value *sv, int attributes)
1809 boolean attr_inversion = ((HL_INVERSE & attributes)
1810 && (sv->type != SV_NAME
1811 || name_widget_has_label(sv)));
1813 if (sv->inverted_hilite != attr_inversion) {
1814 sv->inverted_hilite = attr_inversion;
1815 if (!sv->set) {
1816 if (sv->type == SV_VALUE)
1817 hilight_value(sv->w);
1818 else
1819 hilight_label(sv->w);
1822 sv->attr = attributes;
1823 /* Could possibly add more attributes here: HL_ATTCLR_DIM,
1824 HL_ATTCLR_BLINK, HL_ATTCLR_ULINE, and HL_ATTCLR_BOLD. If so,
1825 extract the above into its own function apply_hilite_inverse()
1826 and each other attribute into its own to keep the code clean. */
1830 * Update the displayed status. The current code in botl.c updates
1831 * two lines of information. Both lines are always updated one after
1832 * the other. So only do our update when we update the second line.
1834 * Information on the first line:
1835 * name, characteristics, alignment, score
1837 * Information on the second line:
1838 * dlvl, gold, hp, power, ac, {level & exp or HD **}, time,
1839 * status * (stone, slime, strngl, foodpois, termill,
1840 * hunger, encumbrance, lev, fly, ride,
1841 * blind, deaf, stun, conf, hallu, version ***)
1843 * [*] order of status fields is different on tty.
1844 * [**] HD is shown instead of level and exp if Upolyd.
1845 * [***] version is optional, right-justified after conditions
1847 static void
1848 update_fancy_status_field(int i, int color, int attributes)
1850 struct X_status_value *sv = &shown_stats[i];
1851 unsigned long condmask = 0L;
1852 long val = 0L;
1854 switch (i) {
1855 case F_DUMMY:
1856 val = 0L;
1857 break;
1858 case F_STR:
1859 val = (long) ACURR(A_STR);
1860 break;
1861 case F_DEX:
1862 val = (long) ACURR(A_DEX);
1863 break;
1864 case F_CON:
1865 val = (long) ACURR(A_CON);
1866 break;
1867 case F_INT:
1868 val = (long) ACURR(A_INT);
1869 break;
1870 case F_WIS:
1871 val = (long) ACURR(A_WIS);
1872 break;
1873 case F_CHA:
1874 val = (long) ACURR(A_CHA);
1875 break;
1877 * Label stats. With the exceptions of hunger and encumbrance
1878 * these are either on or off. Please leave the ternary operators
1879 * the way they are. I want to specify 0 or 1, not a boolean.
1881 case F_HUNGER:
1882 val = (long) u.uhs;
1883 break;
1884 case F_ENCUMBER:
1885 val = (long) near_capacity();
1886 break;
1888 case F_TRAPPED: /* belongs with non-fatal but fits with 'other' */
1889 condmask = BL_MASK_TRAPPED;
1890 break;
1891 case F_TETHERED: /* overloaded with 'trapped' */
1892 condmask = BL_MASK_TETHERED;
1893 break;
1894 /* 'other' status conditions */
1895 case F_LEV:
1896 condmask = BL_MASK_LEV;
1897 break;
1898 case F_FLY:
1899 condmask = BL_MASK_FLY;
1900 break;
1901 case F_RIDE:
1902 condmask = BL_MASK_RIDE;
1903 break;
1904 /* fatal status conditions */
1905 case F_GRABBED:
1906 condmask = BL_MASK_GRAB;
1907 break;
1908 case F_STONE:
1909 condmask = BL_MASK_STONE;
1910 break;
1911 case F_SLIME:
1912 condmask = BL_MASK_SLIME;
1913 break;
1914 case F_STRNGL:
1915 condmask = BL_MASK_STRNGL;
1916 break;
1917 case F_FOODPOIS:
1918 condmask = BL_MASK_FOODPOIS;
1919 break;
1920 case F_TERMILL:
1921 condmask = BL_MASK_TERMILL;
1922 break;
1923 case F_IN_LAVA: /* could overload with 'trapped' but is more severe */
1924 condmask = BL_MASK_INLAVA;
1925 break;
1926 /* non-fatal status conditions */
1927 case F_HELD:
1928 condmask = BL_MASK_HELD;
1929 break;
1930 case F_HOLDING: /* belongs with 'other' but overloads 'held' */
1931 condmask = BL_MASK_HOLDING;
1932 break;
1933 case F_BLIND:
1934 condmask = BL_MASK_BLIND;
1935 break;
1936 case F_DEAF:
1937 condmask = BL_MASK_DEAF;
1938 break;
1939 case F_STUN:
1940 condmask = BL_MASK_STUN;
1941 break;
1942 case F_CONF:
1943 condmask = BL_MASK_CONF;
1944 break;
1945 case F_HALLU:
1946 condmask = BL_MASK_HALLU;
1947 break;
1949 /* pseudo-condition */
1950 case F_VERS:
1951 val = (long) flags.versinfo; /* 1..7 */
1952 break;
1954 case F_NAME:
1955 case F_DLEVEL:
1956 val = (long) 0L;
1957 break; /* special */
1959 case F_GOLD:
1960 val = money_cnt(gi.invent);
1961 if (val < 0L)
1962 val = 0L; /* ought to issue impossible() and discard gold */
1963 break;
1964 case F_HP:
1965 val = (long) (Upolyd ? (u.mh > 0 ? u.mh : 0)
1966 : (u.uhp > 0 ? u.uhp : 0));
1967 break;
1968 case F_MAXHP:
1969 val = (long) (Upolyd ? u.mhmax : u.uhpmax);
1970 break;
1971 case F_POWER:
1972 val = (long) u.uen;
1973 break;
1974 case F_MAXPOWER:
1975 val = (long) u.uenmax;
1976 break;
1977 case F_AC:
1978 val = (long) u.uac;
1979 break;
1980 case F_XP_LEVL:
1981 val = (long) (Upolyd ? mons[u.umonnum].mlevel : u.ulevel);
1982 break;
1983 case F_EXP_PTS:
1984 val = flags.showexp ? u.uexp : 0L;
1985 break;
1986 case F_ALIGN:
1987 val = (long) u.ualign.type;
1988 break;
1989 case F_TIME:
1990 val = flags.time ? (long) svm.moves : 0L;
1991 break;
1992 case F_SCORE:
1993 #ifdef SCORE_ON_BOTL
1994 val = flags.showscore ? botl_score() : 0L;
1995 #else
1996 val = 0L;
1997 #endif
1998 break;
1999 default: {
2001 * There is a possible infinite loop that occurs with:
2003 * impossible->pline->flush_screen->bot->bot{1,2}->
2004 * putstr->adjust_status->update_other->impossible
2006 * Break out with this.
2008 static boolean isactive = FALSE;
2010 if (!isactive) {
2011 isactive = TRUE;
2012 impossible("update_other: unknown shown value");
2013 isactive = FALSE;
2015 val = 0L;
2016 break;
2017 } /* default */
2018 } /* switch */
2020 if (condmask) {
2021 const struct f_overload *fo = ff_ovld_from_mask(condmask);
2023 val = ((X11_condition_bits & condmask) != 0L);
2024 /* if we're turning an overloaded field Off, don't do it if any
2025 of the other alternatives are being set On because we would
2026 clobber that if the other one happens to be drawn first */
2027 if (!val && fo && (X11_condition_bits & fo->all_mask) != 0L) {
2028 skip_cond_val(sv);
2029 return;
2032 update_val(sv, val);
2033 if (color != sv->colr)
2034 update_color(sv, color);
2035 if (attributes != sv->attr)
2036 apply_hilite_attributes(sv, attributes);
2039 /* fully update status after bl_flush or window resize */
2040 static void
2041 update_fancy_status(boolean force_update)
2043 static boolean old_showtime, old_showexp, old_showscore, old_showvers;
2044 static int old_upolyd = -1; /* -1: force first time update */
2045 int i;
2047 if (force_update
2048 || Upolyd != old_upolyd /* Xp vs HD */
2049 || flags.time != old_showtime
2050 || flags.showexp != old_showexp
2051 || flags.showscore != old_showscore
2052 || flags.showvers != old_showvers) {
2053 /* update everything; usually only need this on the very first
2054 time, then later if the window gets resized or if poly/unpoly
2055 triggers Xp <-> HD switch or if an optional field gets
2056 toggled off since there won't be a status_update() call for
2057 the no longer displayed field; we're a bit more conservative
2058 than that and do this when toggling on as well as off */
2059 for (i = 0; i < NUM_STATS; i++)
2060 update_fancy_status_field(i, NO_COLOR, HL_UNDEF);
2061 old_condition_bits = X11_condition_bits;
2063 old_upolyd = Upolyd;
2064 old_showtime = flags.time;
2065 old_showexp = flags.showexp;
2066 old_showscore = flags.showscore;
2067 old_showvers = flags.showvers;
2072 * Turn off hilighted status values after a certain amount of turns.
2074 void
2075 check_turn_events(void)
2077 int i;
2078 struct X_status_value *sv;
2079 int hilight_time = 1;
2081 #ifdef STATUS_HILITES
2082 if (iflags.hilite_delta)
2083 hilight_time = (int) iflags.hilite_delta;
2084 #endif
2085 for (sv = shown_stats, i = 0; i < NUM_STATS; i++, sv++) {
2086 if (!sv->set)
2087 continue;
2089 if (sv->turn_count++ >= hilight_time) {
2090 /* unhighlights by toggling a highlighted item back off again,
2091 unless forced inverted by a status_hilite rule */
2092 if (!sv->inverted_hilite) {
2093 if (sv->type == SV_VALUE)
2094 hilight_value(sv->w);
2095 else
2096 hilight_label(sv->w);
2098 sv->set = FALSE;
2103 /* Initialize alternate status ============================================ */
2105 /* Return a string for the initial width, so use longest possible value. */
2106 static const char *
2107 width_string(int sv_index)
2109 switch (sv_index) {
2110 case F_DUMMY:
2111 return " ";
2113 case F_STR:
2114 return "018/**";
2115 case F_DEX:
2116 case F_CON:
2117 case F_INT:
2118 case F_WIS:
2119 case F_CHA:
2120 return "088"; /* all but str never get bigger */
2122 case F_HUNGER:
2123 return "Satiated";
2124 case F_ENCUMBER:
2125 return "Overloaded";
2127 case F_LEV:
2128 case F_FLY:
2129 case F_RIDE:
2130 case F_TRAPPED:
2131 case F_TETHERED:
2132 case F_GRABBED:
2133 case F_STONE:
2134 case F_SLIME:
2135 case F_STRNGL:
2136 case F_FOODPOIS:
2137 case F_TERMILL:
2138 case F_IN_LAVA:
2139 case F_HELD:
2140 case F_HOLDING:
2141 case F_BLIND:
2142 case F_DEAF:
2143 case F_STUN:
2144 case F_CONF:
2145 case F_HALLU:
2146 return shown_stats[sv_index].name;
2148 case F_NAME:
2149 case F_DLEVEL:
2150 return ""; /* longest possible value not needed for these */
2152 case F_HP:
2153 case F_MAXHP:
2154 return "9999";
2155 case F_POWER:
2156 case F_MAXPOWER:
2157 return "9999";
2158 case F_AC:
2159 return "-127";
2160 case F_XP_LEVL:
2161 return "99";
2162 case F_GOLD:
2163 /* strongest hero can pick up roughly 30% of this much */
2164 return "999999"; /* same limit as tty */
2165 case F_EXP_PTS:
2166 case F_TIME:
2167 case F_SCORE:
2168 return "123456789"; /* a tenth digit will still fit legibly */
2169 case F_ALIGN:
2170 return "Neutral";
2172 impossible("width_string: unknown index %d\n", sv_index);
2173 return "";
2176 static void
2177 create_widget(Widget parent, struct X_status_value *sv, int sv_index)
2179 Arg args[4];
2180 Cardinal num_args;
2182 switch (sv->type) {
2183 case SV_VALUE:
2184 sv->w = create_value(parent, sv->name);
2185 set_value(sv->w, width_string(sv_index));
2186 break;
2187 case SV_LABEL:
2188 /* Labels get their own buffer. */
2189 sv->name = (char *) alloc(BUFSZ);
2190 /* we need to cast away 'const' when assigning a value */
2191 *(char *) (sv->name) = '\0';
2193 num_args = 0;
2194 XtSetArg(args[num_args], XtNborderWidth, 0); num_args++;
2195 XtSetArg(args[num_args], XtNinternalHeight, 0); num_args++;
2196 sv->w = XtCreateManagedWidget((sv_index == F_NAME)
2197 ? "name"
2198 : "dlevel",
2199 labelWidgetClass, parent,
2200 args, num_args);
2201 break;
2202 case SV_NAME: {
2203 char buf[BUFSZ];
2204 const char *txt;
2205 const struct f_overload *fo = ff_ovld_from_indx(sv_index);
2206 int baseindx = fo ? fo->conds[0].ff : sv_index;
2208 if (sv_index != baseindx) {
2209 /* this code isn't actually executed; only the base condition
2210 is in one of the fancy status columns and only the fields
2211 in those columns are passed to this routine; the real
2212 initialization--this same assignment--for overloaded
2213 conditions takes place at the end of create_fancy_status() */
2214 sv->w = shown_stats[baseindx].w;
2215 break;
2217 txt = width_string(sv_index); /* for conditions, it's just sv->name */
2218 if (fo) {
2219 int i, ff, altln, ln = (int) strlen(txt);
2221 /* make the initial value have the width of the longest of
2222 these overloaded conditions; used for widget sizing, not for
2223 display, and ultimately only matters if one of the overloads
2224 happens to be the longest string in its whole column */
2225 for (i = 1; i < NUM_OVLD && (ff = fo->conds[i].ff) > 0; ++i)
2226 if ((altln = (int) strlen(width_string(ff))) > ln)
2227 ln = altln;
2228 Sprintf(buf, "%*s", ln, txt);
2229 txt = buf;
2231 num_args = 0;
2232 XtSetArg(args[0], XtNlabel, txt); num_args++;
2233 XtSetArg(args[num_args], XtNborderWidth, 0); num_args++;
2234 XtSetArg(args[num_args], XtNinternalHeight, 0); num_args++;
2235 sv->w = XtCreateManagedWidget(sv->name, labelWidgetClass, parent,
2236 args, num_args);
2237 break;
2239 default:
2240 panic("create_widget: unknown type %d", sv->type);
2245 * Get current width of value. width2p is only valid for SV_VALUE types.
2247 static void
2248 get_widths(struct X_status_value *sv, int *width1p, int *width2p)
2250 Arg args[1];
2251 Dimension width;
2253 switch (sv->type) {
2254 case SV_VALUE:
2255 *width1p = get_name_width(sv->w);
2256 *width2p = get_value_width(sv->w);
2257 break;
2258 case SV_LABEL:
2259 case SV_NAME:
2260 XtSetArg(args[0], XtNwidth, &width);
2261 XtGetValues(sv->w, args, ONE);
2262 *width1p = width;
2263 *width2p = 0;
2264 break;
2265 default:
2266 panic("get_widths: unknown type %d", sv->type);
2270 static void
2271 set_widths(struct X_status_value *sv, int width1, int width2)
2273 Arg args[1];
2275 switch (sv->type) {
2276 case SV_VALUE:
2277 set_name_width(sv->w, width1);
2278 set_value_width(sv->w, width2);
2279 break;
2280 case SV_LABEL:
2281 case SV_NAME:
2282 XtSetArg(args[0], XtNwidth, (width1 + width2));
2283 XtSetValues(sv->w, args, ONE);
2284 break;
2285 default:
2286 panic("set_widths: unknown type %d", sv->type);
2290 static Widget
2291 init_column(
2292 const char *name,
2293 Widget parent, Widget top, Widget left,
2294 int *col_indices, int xtrawidth)
2296 Widget form;
2297 Arg args[4];
2298 Cardinal num_args;
2299 int max_width1, width1, max_width2, width2;
2300 int *ip;
2301 struct X_status_value *sv;
2303 num_args = 0;
2304 if (top != (Widget) 0) {
2305 XtSetArg(args[num_args], nhStr(XtNfromVert), top); num_args++;
2307 if (left != (Widget) 0) {
2308 XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); num_args++;
2310 /* this was 0 but that resulted in the text being crammed together */
2311 XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 2); num_args++;
2312 form = XtCreateManagedWidget(name, formWidgetClass, parent,
2313 args, num_args);
2315 max_width1 = max_width2 = 0;
2316 for (ip = col_indices; *ip >= 0; ip++) {
2317 sv = &shown_stats[*ip];
2318 create_widget(form, sv, *ip); /* will set init width */
2319 if (ip != col_indices) { /* not first */
2320 num_args = 0;
2321 XtSetArg(args[num_args], nhStr(XtNfromVert),
2322 shown_stats[*(ip - 1)].w); num_args++;
2323 XtSetValues(sv->w, args, num_args);
2325 get_widths(sv, &width1, &width2);
2326 if (width1 > max_width1)
2327 max_width1 = width1;
2328 if (width2 > max_width2)
2329 max_width2 = width2;
2332 /* insert some extra spacing between columns */
2333 max_width1 += xtrawidth;
2335 for (ip = col_indices; *ip >= 0; ip++) {
2336 set_widths(&shown_stats[*ip], max_width1, max_width2);
2339 /* There is room behind the end marker for the two widths. */
2340 *++ip = max_width1;
2341 *++ip = max_width2;
2343 return form;
2347 * These are the orders of the displayed columns. Change to suit. The -1
2348 * indicates the end of the column. The two numbers after that are used
2349 * to store widths that are calculated at run-time.
2351 * 3.7: changed so that all 6 columns have 8 rows, but a few entries
2352 * are left blank <>. Exp-points, Score, and Time are optional depending
2353 * on run-time settings; Xp-level is replaced by Hit-Dice (and Exp-points
2354 * suppressed) when the hero is polymorphed. Title and Dungeon-Level span
2355 * two columns and might expand to more if 'hitpointbar' is implemented.
2356 * Version is optional, right justified, and much wider than the others.
2358 Title ("Plname the Rank") <> <> <> <>
2359 Dungeon-Branch-and-Level <> Hunger Grabbed Held
2360 Hit-points Max-HP Strength Encumbrance Petrifying Blind
2361 Power-points Max-Power Dexterity Trapped Slimed Deaf
2362 Armor-class Alignment Constitution Levitation Strangled Stunned
2363 Xp-level [Exp-points] Intelligence Flying Food-Pois Confused
2364 Gold [Score] Wisdom Riding Term-Ill Hallucinat
2365 <> [Time] Charisma <> Sinking Version
2367 * A seventh column is going to be needed to fit in more conditions.
2370 /* including F_DUMMY makes the three status condition columns evenly
2371 spaced with regard to the adjacent characteristics (Str,Dex,&c) column;
2372 we lose track of the Widget pointer for F_DUMMY, each use clobbering the
2373 one before, leaving the one from leftover_indices[]; since they're never
2374 updated, that shouldn't matter */
2375 static int status_indices[3][11] = {
2376 { F_DUMMY, F_HUNGER, F_ENCUMBER, F_TRAPPED,
2377 F_LEV, F_FLY, F_RIDE, F_DUMMY, -1, 0, 0 },
2378 { F_DUMMY, F_GRABBED, F_STONE, F_SLIME, F_STRNGL,
2379 F_FOODPOIS, F_TERMILL, F_IN_LAVA, -1, 0, 0 },
2380 { F_DUMMY, F_HELD, F_BLIND, F_DEAF, F_STUN,
2381 F_CONF, F_HALLU, F_VERS, -1, 0, 0 },
2383 /* used to fill up the empty space to right of 3rd status condition column */
2384 static int leftover_indices[] = { F_DUMMY, -1, 0, 0 };
2385 /* -2: top two rows of these columns are reserved for title and location */
2386 static int col1_indices[11 - 2] = {
2387 F_HP, F_POWER, F_AC, F_XP_LEVL, F_GOLD, F_DUMMY, -1, 0, 0
2389 static int col2_indices[11 - 2] = {
2390 F_MAXHP, F_MAXPOWER, F_ALIGN, F_EXP_PTS, F_SCORE, F_TIME, -1, 0, 0
2392 static int characteristics_indices[11 - 2] = {
2393 F_STR, F_DEX, F_CON, F_INT, F_WIS, F_CHA, -1, 0, 0
2397 * Produce a form that looks like the following:
2399 * title
2400 * location
2401 * col1_indices[0] col2_indices[0] col3_indices[0]
2402 * col1_indices[1] col2_indices[1] col3_indices[1]
2403 * ... ... ...
2404 * col1_indices[5] col2_indices[5] col3_indices[5]
2406 * The status conditions are managed separately and appear to the right
2407 * of this form.
2409 * TODO: widen title field and implement hitpoint bar on it.
2411 static Widget
2412 init_info_form(Widget parent, Widget top, Widget left)
2414 Widget form, col1, col2;
2415 struct X_status_value *sv_name, *sv_dlevel;
2416 Arg args[6];
2417 Cardinal num_args;
2418 int total_width, *ip;
2420 num_args = 0;
2421 if (top != (Widget) 0) {
2422 XtSetArg(args[num_args], nhStr(XtNfromVert), top); num_args++;
2424 if (left != (Widget) 0) {
2425 XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); num_args++;
2427 XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 2); num_args++;
2428 form = XtCreateManagedWidget("status_info", formWidgetClass, parent,
2429 args, num_args);
2431 /* top line/row of form */
2432 sv_name = &shown_stats[F_NAME]; /* title */
2433 create_widget(form, sv_name, F_NAME);
2435 /* second line/row */
2436 sv_dlevel = &shown_stats[F_DLEVEL]; /* location */
2437 create_widget(form, sv_dlevel, F_DLEVEL);
2439 num_args = 0;
2440 XtSetArg(args[num_args], nhStr(XtNfromVert), sv_name->w); num_args++;
2441 XtSetValues(sv_dlevel->w, args, num_args);
2443 /* there are 3 columns beneath but top 2 rows are centered over first 2 */
2444 col1 = init_column("name_col1", form, sv_dlevel->w, (Widget) 0,
2445 col1_indices, 0);
2446 col2 = init_column("name_col2", form, sv_dlevel->w, col1,
2447 col2_indices, 5);
2448 (void) init_column("status_characteristics", form, sv_dlevel->w, col2,
2449 characteristics_indices, 15);
2451 /* Add calculated widths. */
2452 for (ip = col1_indices; *ip >= 0; ip++)
2453 ; /* skip to end */
2454 total_width = *++ip;
2455 total_width += *++ip;
2456 for (ip = col2_indices; *ip >= 0; ip++)
2457 ; /* skip to end */
2458 total_width += *++ip;
2459 total_width += *++ip;
2461 XtSetArg(args[0], XtNwidth, total_width);
2462 XtSetValues(sv_name->w, args, ONE);
2463 XtSetArg(args[0], XtNwidth, total_width);
2464 XtSetValues(sv_dlevel->w, args, ONE);
2466 return form;
2469 /* give the three status condition columns the same width */
2470 static void
2471 fixup_cond_widths(void)
2473 int pass, i, *ip, w1, w2;
2475 w1 = w2 = 0;
2476 for (pass = 1; pass <= 2; ++pass) { /* two passes... */
2477 for (i = 0; i < 3; i++) { /* three columns */
2478 for (ip = status_indices[i]; *ip != -1; ++ip) { /* X fields */
2479 /* pass 1: find -1; pass 2: update field widths, find -1 */
2480 if (pass == 2)
2481 set_widths(&shown_stats[*ip], w1, w2);
2483 /* found -1; the two slots beyond it contain column widths */
2484 if (pass == 1) { /* pass 1: collect maxima */
2485 if (ip[1] > w1)
2486 w1 = ip[1];
2487 if (ip[2] > w2)
2488 w2 = ip[2];
2489 } else { /* pass 2: update column widths with maxima */
2490 ip[1] = w1;
2491 ip[2] = w2;
2494 /* ascetics: expand the maximum width to make cond columns wider */
2495 if (pass == 1) {
2496 w1 += 15;
2497 if (w2 > 0)
2498 w2 += 15;
2503 Arg args[3];
2504 Dimension vers_width = 0;
2505 struct X_status_value *sv = &shown_stats[F_VERS];
2507 if (sv) {
2508 XtSetArg(args[0], XtNwidth, &vers_width);
2509 XtGetValues(sv->w, args, ONE);
2510 if (vers_width) {
2511 vers_width *= 3;
2512 XtSetArg(args[0], XtNwidth, vers_width);
2513 XtSetArg(args[1], nhStr(XtNjustify), XtJustifyRight);
2514 XtSetValues(sv->w, args, TWO);
2521 * Create the layout for the fancy status. Return a form widget that
2522 * contains everything.
2524 static Widget
2525 create_fancy_status(Widget parent, Widget top)
2527 Widget form; /* The form that surrounds everything. */
2528 Widget w;
2529 Arg args[8];
2530 Cardinal num_args;
2531 char buf[32];
2532 const struct f_overload *fo;
2533 int i, ff;
2535 num_args = 0;
2536 if (top != (Widget) 0) {
2537 XtSetArg(args[num_args], nhStr(XtNfromVert), top); num_args++;
2539 XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 2); num_args++;
2540 XtSetArg(args[num_args], XtNborderWidth, 0); num_args++;
2541 XtSetArg(args[num_args], XtNorientation, XtorientHorizontal); num_args++;
2542 form = XtCreateManagedWidget("fancy_status", panedWidgetClass, parent,
2543 args, num_args);
2545 w = init_info_form(form, (Widget) 0, (Widget) 0);
2546 #if 0 /* moved to init_info_form() */
2547 w = init_column("status_characteristics", form, (Widget) 0, w,
2548 characteristics_indices, 15);
2549 #endif
2550 for (i = 0; i < 3; i++) {
2551 Sprintf(buf, "status_condition%d", i + 1);
2552 w = init_column(buf, form, (Widget) 0, w, status_indices[i], 0);
2554 fixup_cond_widths(); /* make all 3 status_conditionN columns same width
2555 * (actually, the slot for F_VERS is much wider) */
2556 /* TODO:
2557 * Calculate and set the width of the F_VERS widjet to be from the
2558 * start of the third condition column through the right edge and
2559 * get rid of the dummy column.
2562 /* extra dummy 'column' to allocate any remaining space below the map */
2563 (void) init_column("status_leftover", form, (Widget) 0, w,
2564 leftover_indices, 0);
2566 /* handle overloading; extra conditions don't start out in any column
2567 so need to be initialized separately; the only initialization they
2568 need is to share the widget of the base condition which is present
2569 in one of the columns [could be deferred until first use] */
2570 for (fo = cond_ovl; fo < cond_ovl + SIZE(cond_ovl); ++fo)
2571 for (i = 1; i < NUM_OVLD && (ff = fo->conds[i].ff) > 0; ++i)
2572 if (!shown_stats[ff].w)
2573 shown_stats[ff].w = shown_stats[fo->conds[0].ff].w;
2575 return form;
2578 static void
2579 destroy_fancy_status(struct xwindow *wp)
2581 int i;
2582 struct X_status_value *sv;
2584 if (!wp->keep_window)
2585 XtDestroyWidget(wp->w), wp->w = (Widget) 0;
2587 for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++)
2588 if (sv->type == SV_LABEL) {
2589 free((genericptr_t) sv->name);
2590 sv->name = 0;
2594 /*winstat.c*/