OSDN Git Service

update year to 2020
[jnethack/source.git] / win / X11 / winstat.c
1 /* NetHack 3.6  winstat.c       $NHDT-Date: 1543447325 2018/11/28 23:22:05 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.20 $ */
2 /* Copyright (c) Dean Luick, 1992                                 */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 /* JNetHack Copyright */
6 /* (c) Issei Numata 1994-1999                                      */
7 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020            */
8 /* JNetHack may be freely redistributed.  See license for details. */
9
10 /*
11  * Status window routines.  This file supports both the "traditional"
12  * tty status display and a "fancy" status display.  A tty status is
13  * made if a popup window is requested, otherewise a fancy status is
14  * made.  This code assumes that only one fancy status will ever be made.
15  * Currently, only one status window (of any type) is _ever_ made.
16  */
17
18 #ifndef SYSV
19 #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */
20 #endif
21
22 #include <X11/Intrinsic.h>
23 #include <X11/IntrinsicP.h>
24 #include <X11/StringDefs.h>
25 #include <X11/Shell.h>
26 #include <X11/Xaw/AsciiText.h>
27 #include <X11/Xaw/Cardinals.h>
28 #include <X11/Xaw/Form.h>
29 #include <X11/Xaw/Paned.h>
30 #include <X11/Xaw/Label.h>
31 #include <X11/Xaw/Viewport.h>
32 #include <X11/Xatom.h>
33
34 #ifdef PRESERVE_NO_SYSV
35 #ifdef SYSV
36 #undef SYSV
37 #endif
38 #undef PRESERVE_NO_SYSV
39 #endif
40
41 #include "hack.h"
42 #include "winX.h"
43 #include "xwindow.h"
44
45 /*
46  * Fancy status form entry storage indices.
47  */
48 #define F_DUMMY     0
49 #define F_STR       1
50 #define F_DEX       2
51 #define F_CON       3
52 #define F_INT       4
53 #define F_WIS       5
54 #define F_CHA       6
55
56 #define F_NAME      7
57 #define F_DLEVEL    8
58 #define F_GOLD      9
59 #define F_HP       10
60 #define F_MAXHP    11
61 #define F_POWER    12
62 #define F_MAXPOWER 13
63 #define F_AC       14
64 #define F_LEVEL    15
65 #define F_EXP      16
66 #define F_ALIGN    17
67 #define F_TIME     18
68 #define F_SCORE    19
69
70 /* status conditions grouped by columns; tty orders these differently */
71 #define F_STONE    20
72 #define F_SLIME    21
73 #define F_STRNGL   22
74 #define F_FOODPOIS 23
75 #define F_TERMILL  24
76
77 #define F_HUNGER   25
78 #define F_ENCUMBER 26
79 #define F_LEV      27
80 #define F_FLY      28
81 #define F_RIDE     29
82
83 #define F_BLIND    30
84 #define F_DEAF     31
85 #define F_STUN     32
86 #define F_CONF     33
87 #define F_HALLU    34
88
89 #define NUM_STATS 35
90
91 static void FDECL(update_fancy_status, (struct xwindow *));
92 static void FDECL(update_fancy_status_field, (int));
93 static Widget FDECL(create_fancy_status, (Widget, Widget));
94 static void FDECL(destroy_fancy_status, (struct xwindow *));
95 static void FDECL(create_status_window_fancy, (struct xwindow *, BOOLEAN_P, Widget));
96 static void FDECL(create_status_window_tty, (struct xwindow *, BOOLEAN_P, Widget));
97 static void FDECL(destroy_status_window_fancy, (struct xwindow *));
98 static void FDECL(destroy_status_window_tty, (struct xwindow *));
99 static void FDECL(adjust_status_fancy, (struct xwindow *, const char *));
100 static void FDECL(adjust_status_tty, (struct xwindow *, const char *));
101
102 extern const char *status_fieldfmt[MAXBLSTATS];
103 extern char *status_vals[MAXBLSTATS];
104 extern boolean status_activefields[MAXBLSTATS];
105 static long X11_condition_bits;
106 static int X11_status_colors[MAXBLSTATS];
107 static int hpbar_percent, hpbar_color;
108
109 #define X11_NUM_STATUS_LINES 2
110 #define X11_NUM_STATUS_FIELD 15
111
112 static enum statusfields X11_fieldorder[X11_NUM_STATUS_LINES][X11_NUM_STATUS_FIELD] = {
113     { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN,
114       BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH,
115       BL_FLUSH },
116     { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX,
117       BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER,
118       BL_CAP, BL_CONDITION, BL_FLUSH }
119 };
120
121 static Widget X11_status_widget;
122 static Widget X11_status_labels[MAXBLSTATS];
123 static Widget X11_cond_labels[32]; /* Ugh */
124
125 struct xwindow *xw_status_win;
126 static Pixel X11_status_widget_fg, X11_status_widget_bg;
127
128
129 int
130 condcolor(bm, bmarray)
131 long bm;
132 unsigned long *bmarray;
133 {
134     int i;
135
136     if (bm && bmarray)
137         for (i = 0; i < CLR_MAX; ++i) {
138             if (bmarray[i] && (bm & bmarray[i]))
139                 return i;
140         }
141     return NO_COLOR;
142 }
143
144 int
145 condattr(bm, bmarray)
146 long bm;
147 unsigned long *bmarray;
148 {
149     int attr = 0;
150     int i;
151
152     if (bm && bmarray) {
153         for (i = HL_ATTCLR_DIM; i < BL_ATTCLR_MAX; ++i) {
154             if (bmarray[i] && (bm & bmarray[i])) {
155                 switch(i) {
156                 case HL_ATTCLR_DIM:
157                     attr |= HL_DIM;
158                     break;
159                 case HL_ATTCLR_BLINK:
160                     attr |= HL_BLINK;
161                     break;
162                 case HL_ATTCLR_ULINE:
163                     attr |= HL_ULINE;
164                     break;
165                 case HL_ATTCLR_INVERSE:
166                     attr |= HL_INVERSE;
167                     break;
168                 case HL_ATTCLR_BOLD:
169                     attr |= HL_BOLD;
170                     break;
171                 }
172             }
173         }
174     }
175     return attr;
176 }
177
178 void
179 X11_status_init()
180 {
181 #ifdef STATUS_HILITES
182     int i;
183
184     for (i = 0; i < MAXBLSTATS; ++i)
185         X11_status_colors[i] = NO_COLOR; /* no color */
186     X11_condition_bits = 0L;
187     hpbar_percent = 0, hpbar_color = NO_COLOR;
188 #endif /* STATUS_HILITES */
189     /* let genl_status_init do most of the initialization */
190     genl_status_init();
191 }
192
193 void
194 X11_status_finish()
195 {
196     /* nothing */
197 }
198
199 void
200 X11_status_enablefield(fieldidx, nm, fmt, enable)
201 int fieldidx;
202 const char *nm;
203 const char *fmt;
204 boolean enable;
205 {
206     genl_status_enablefield(fieldidx, nm, fmt, enable);
207 }
208
209
210 int
211 cond_bm2idx(bm)
212 unsigned long bm;
213 {
214     int i;
215     for (i = 0; i < 32; i++)
216         if ((1 << i) == bm)
217             return i;
218     return -1;
219 }
220
221 void
222 MaybeDisplayCond(bm, colormasks, text)
223 unsigned long bm;
224 unsigned long *colormasks;
225 const char *text;
226 {
227     int idx = cond_bm2idx(bm);
228     Widget label;
229     Arg args[10];
230     Cardinal num_args;
231     Pixel fg = X11_status_widget_fg, bg = X11_status_widget_bg;
232     Dimension lbl_wid;
233     Dimension lbl_hei;
234     Dimension lbl_border_wid;
235     Dimension lbl_iwidth;
236
237     if (idx < 0)
238         return;
239
240     label = X11_cond_labels[idx];
241     if ((X11_condition_bits & bm) != 0) {
242         int attrmask, coloridx;
243         XFontStruct *font;
244         Position lbl_x;
245         Position lbl_y;
246
247 #ifdef TEXTCOLOR
248         coloridx = condcolor(bm, colormasks);
249 #else
250         coloridx = NO_COLOR;
251 #endif
252         attrmask = condattr(bm, colormasks);
253         num_args = 0;
254         XtSetArg(args[num_args], nhStr(XtNfont), &font); num_args++;
255         XtSetArg(args[num_args], nhStr(XtNx), &lbl_x); num_args++;
256         XtSetArg(args[num_args], nhStr(XtNy), &lbl_y); num_args++;
257         XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++;
258         XtSetArg(args[num_args], nhStr(XtNheight), &lbl_hei); num_args++;
259         XtSetArg(args[num_args], nhStr(XtNinternalWidth), &lbl_iwidth); num_args++;
260         XtSetArg(args[num_args], nhStr(XtNborderWidth), &lbl_border_wid); num_args++;
261         XtGetValues(label, args, num_args);
262
263         if (text && *text)
264             lbl_wid = lbl_iwidth + font->max_bounds.width * strlen(text);
265         else
266             lbl_wid = 1;
267
268         num_args = 0;
269         XtSetArg(args[num_args], nhStr(XtNlabel), (text && *text) ? text : ""); num_args++;
270         XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++;
271
272         fg = (coloridx != NO_COLOR) ? get_nhcolor(xw_status_win, coloridx).pixel
273                                     : X11_status_widget_fg;
274         if (attrmask & HL_INVERSE) {
275             Pixel tmppx = fg;
276             fg = bg;
277             bg = tmppx;
278         }
279
280         if (attrmask & HL_BOLD) {
281             load_boldfont(xw_status_win, label);
282             XtSetArg(args[num_args], nhStr(XtNfont),
283                      xw_status_win->boldfs); num_args++;
284         }
285
286         if (fg == bg)
287             fg = get_nhcolor(xw_status_win, CLR_GRAY).pixel;
288
289         XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++;
290         XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++;
291         XtSetValues(label, args, num_args);
292         XtResizeWidget(label, lbl_wid, lbl_hei, lbl_border_wid);
293     } else {
294         num_args = 0;
295         XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++;
296         XtSetArg(args[num_args], nhStr(XtNheight), &lbl_hei); num_args++;
297         XtSetArg(args[num_args], nhStr(XtNinternalWidth), &lbl_iwidth); num_args++;
298         XtSetArg(args[num_args], nhStr(XtNborderWidth), &lbl_border_wid); num_args++;
299         XtGetValues(label, args, num_args);
300
301         num_args = 0;
302         XtSetArg(args[num_args], nhStr(XtNlabel), ""); num_args++;
303         XtSetArg(args[num_args], nhStr(XtNwidth), 1); num_args++;
304         XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++;
305         XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++;
306         XtSetValues(label, args, num_args);
307
308         XtResizeWidget(label, lbl_wid, lbl_hei, lbl_border_wid);
309     }
310 }
311
312
313 void
314 X11_status_update_tty(fld, ptr, chg, percent, color, colormasks)
315 int fld, chg UNUSED, percent, color;
316 genericptr_t ptr;
317 unsigned long *colormasks;
318 {
319     static boolean oncearound = FALSE; /* prevent premature partial display */
320     long *condptr = (long *) ptr;
321     int coloridx = NO_COLOR;
322     const char *text = (char *) ptr;
323     char tmpbuf[BUFSZ];
324     int attridx = 0;
325
326     XFontStruct *font;
327     Arg args[10];
328     Cardinal num_args;
329     Position lbl_x;
330     Position lbl_y;
331     Dimension lbl_wid;
332     Dimension lbl_hei;
333     Dimension lbl_border_wid;
334     Dimension lbl_iwidth;
335     Widget label;
336     Pixel fg = X11_status_widget_fg, bg = X11_status_widget_bg;
337
338 #ifndef TEXTCOLOR
339     color = NO_COLOR;
340 #endif
341
342     if (fld < BL_RESET || fld >= MAXBLSTATS)
343         return;
344
345     if ((fld >= 0 && fld < MAXBLSTATS) && !status_activefields[fld])
346         return;
347
348     if (fld != BL_FLUSH && fld != BL_RESET) {
349         if (!status_activefields[fld])
350             return;
351         switch (fld) {
352         case BL_CONDITION:
353             X11_condition_bits = *condptr;
354             oncearound = TRUE;
355             break;
356         default:
357             Sprintf(status_vals[fld],
358                     (fld == BL_TITLE && iflags.wc2_hitpointbar) ? "%-30s" :
359                     status_fieldfmt[fld] ? status_fieldfmt[fld] : "%s",
360                     text);
361             X11_status_colors[fld] = color;
362             if (iflags.wc2_hitpointbar && fld == BL_HP) {
363                 hpbar_percent = percent;
364                 hpbar_color = color;
365              }
366              break;
367         }
368         if (fld == BL_CONDITION) {
369             MaybeDisplayCond(BL_MASK_STONE, colormasks, "Stone");
370             MaybeDisplayCond(BL_MASK_SLIME, colormasks, "Slime");
371             MaybeDisplayCond(BL_MASK_STRNGL, colormasks, "Strngl");
372             MaybeDisplayCond(BL_MASK_FOODPOIS, colormasks, "FoodPois");
373             MaybeDisplayCond(BL_MASK_TERMILL, colormasks, "TermIll");
374             MaybeDisplayCond(BL_MASK_BLIND, colormasks, "Blind");
375             MaybeDisplayCond(BL_MASK_DEAF, colormasks, "Deaf");
376             MaybeDisplayCond(BL_MASK_STUN, colormasks, "Stun");
377             MaybeDisplayCond(BL_MASK_CONF, colormasks, "Conf");
378             MaybeDisplayCond(BL_MASK_HALLU, colormasks, "Hallu");
379             MaybeDisplayCond(BL_MASK_LEV, colormasks, "Lev");
380             MaybeDisplayCond(BL_MASK_FLY, colormasks, "Fly");
381             MaybeDisplayCond(BL_MASK_RIDE, colormasks, "Ride");
382         } else {
383             label = X11_status_labels[fld];
384             text = status_vals[fld];
385             if (fld == BL_GOLD)
386                 text = decode_mixed(tmpbuf, text);
387 #ifdef TEXTCOLOR
388             coloridx = X11_status_colors[fld] & 0x00FF;
389 #endif
390             attridx = (X11_status_colors[fld] & 0xFF00) >> 8;
391
392             num_args = 0;
393             XtSetArg(args[num_args], nhStr(XtNfont), &font); num_args++;
394             XtSetArg(args[num_args], nhStr(XtNx), &lbl_x); num_args++;
395             XtSetArg(args[num_args], nhStr(XtNy), &lbl_y); num_args++;
396             XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++;
397             XtSetArg(args[num_args], nhStr(XtNheight), &lbl_hei); num_args++;
398             XtSetArg(args[num_args], nhStr(XtNinternalWidth), &lbl_iwidth); num_args++;
399             XtSetArg(args[num_args], nhStr(XtNborderWidth), &lbl_border_wid); num_args++;
400             XtGetValues(label, args, num_args);
401
402             /*raw_printf("font: %i-%i",
403                          font->min_bounds.width, font->max_bounds.width);*/
404
405             if (text && *text)
406                 lbl_wid = lbl_iwidth + font->max_bounds.width * strlen(text);
407             else
408                 lbl_wid = 1;
409
410             /*raw_printf("1:lbl_wid=%i('%s')", lbl_wid, text);*/
411
412             num_args = 0;
413             XtSetArg(args[num_args], nhStr(XtNlabel),
414                      (text && *text) ? text : ""); num_args++;
415             XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++;
416
417             fg = (coloridx != NO_COLOR) ? get_nhcolor(xw_status_win, coloridx).pixel
418                                         : X11_status_widget_fg;
419             if (attridx & HL_INVERSE) {
420                 Pixel tmppx = fg;
421
422                 fg = bg;
423                 bg = tmppx;
424             }
425
426             if (attridx & HL_BOLD) {
427                 load_boldfont(xw_status_win, label);
428                 XtSetArg(args[num_args], nhStr(XtNfont),
429                          xw_status_win->boldfs); num_args++;
430             }
431
432             if (fg == bg)
433                 fg = get_nhcolor(xw_status_win, CLR_GRAY).pixel;
434
435             XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++;
436             XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++;
437             XtSetValues(label, args, num_args);
438             XtResizeWidget(label, lbl_wid, lbl_hei, lbl_border_wid);
439         }
440     } else {
441         int x, y;
442
443         for (y = 0; y < X11_NUM_STATUS_LINES; y++) {
444             Cardinal dx = 0;
445
446             for (x = 0; x < X11_NUM_STATUS_FIELD; x++) {
447                 int f = X11_fieldorder[y][x];
448
449                 if (f <= BL_FLUSH)
450                     continue;
451                 if (!status_activefields[f])
452                     continue;
453
454                 if (f == BL_CONDITION) {
455                     int i;
456
457                     for (i = 0; i < 32; i++) {
458                         label = X11_cond_labels[i];
459
460                         num_args = 0;
461                         XtSetArg(args[num_args], nhStr(XtNx), &lbl_x); num_args++;
462                         XtSetArg(args[num_args], nhStr(XtNy), &lbl_y); num_args++;
463                         XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++;
464                         XtSetArg(args[num_args], nhStr(XtNheight), &lbl_hei); num_args++;
465                         XtSetArg(args[num_args], nhStr(XtNborderWidth),
466                                  &lbl_border_wid); num_args++;
467                         XtGetValues(label, args, num_args);
468
469                         lbl_x = dx;
470
471                         num_args = 0;
472                         XtSetArg(args[num_args], nhStr(XtNx), lbl_x); num_args++;
473                         XtSetValues(label, args, num_args);
474                         XtConfigureWidget(label, lbl_x, lbl_y,
475                                           lbl_wid, lbl_hei, lbl_border_wid);
476
477                         if (lbl_wid > 1)
478                             dx += lbl_wid;
479                     }
480                     continue;
481                 }
482                 label = X11_status_labels[f];
483
484                 text = status_vals[f];
485                 if (f == BL_GOLD)
486                     text = decode_mixed(tmpbuf, text);
487
488                 num_args = 0;
489                 XtSetArg(args[num_args], nhStr(XtNx), &lbl_x); num_args++;
490                 XtSetArg(args[num_args], nhStr(XtNy), &lbl_y); num_args++;
491                 XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++;
492                 XtSetArg(args[num_args], nhStr(XtNheight), &lbl_hei); num_args++;
493                 XtSetArg(args[num_args], nhStr(XtNborderWidth),
494                          &lbl_border_wid); num_args++;
495                 XtGetValues(label, args, num_args);
496
497                 lbl_x = dx;
498                 /*raw_printf("2:lbl_wid=%i('%s')", lbl_wid, text);*/
499
500                 num_args = 0;
501                 XtSetArg(args[num_args], nhStr(XtNx), lbl_x); num_args++;
502                 XtSetArg(args[num_args], nhStr(XtNlabel), text); num_args++;
503                 XtSetValues(label, args, num_args);
504                 XtConfigureWidget(label, lbl_x, lbl_y,
505                                   lbl_wid, lbl_hei, lbl_border_wid);
506
507                 dx += lbl_wid;
508             }
509         }
510     }
511 }
512
513 /*ARGSUSED*/
514 void
515 X11_status_update_fancy(fld, ptr, chg, percent, color, colormasks)
516 int fld, chg UNUSED, percent UNUSED, color UNUSED;
517 genericptr_t ptr;
518 unsigned long *colormasks UNUSED;
519 {
520     static const struct {
521         int bl, ff;
522     } bl_to_fancyfield[] = {
523         { BL_TITLE, F_NAME },
524         { BL_STR, F_STR },
525         { BL_DX, F_DEX },
526         { BL_CO, F_CON },
527         { BL_IN, F_INT },
528         { BL_WI, F_WIS },
529         { BL_CH, F_CHA },
530         { BL_ALIGN, F_ALIGN },
531         { BL_SCORE, F_SCORE },
532         { BL_CAP, F_ENCUMBER },
533         { BL_GOLD, F_GOLD },
534         { BL_ENE, F_POWER },
535         { BL_ENEMAX, F_MAXPOWER },
536         { BL_XP, F_LEVEL },
537         { BL_AC, F_AC },
538         /*{ BL_HD, F_ },*/
539         { BL_TIME, F_TIME },
540         { BL_HUNGER, F_HUNGER },
541         { BL_HP, F_HP },
542         { BL_HPMAX, F_MAXHP },
543         { BL_LEVELDESC, F_DLEVEL },
544         { BL_EXP, F_EXP }
545     };
546     static const struct {
547         unsigned long mask;
548         int ff;
549     } mask_to_fancyfield[] = {
550         { BL_MASK_STONE, F_STONE },
551         { BL_MASK_SLIME, F_SLIME },
552         { BL_MASK_STRNGL, F_STRNGL },
553         { BL_MASK_FOODPOIS, F_FOODPOIS },
554         { BL_MASK_TERMILL, F_TERMILL },
555         { BL_MASK_BLIND, F_BLIND },
556         { BL_MASK_DEAF, F_DEAF },
557         { BL_MASK_STUN, F_STUN },
558         { BL_MASK_CONF, F_CONF },
559         { BL_MASK_HALLU, F_HALLU },
560         { BL_MASK_LEV, F_LEV },
561         { BL_MASK_FLY, F_FLY },
562         { BL_MASK_RIDE, F_RIDE }
563     };
564     int i;
565
566     if (fld == BL_RESET || fld == BL_FLUSH) {
567         if (WIN_STATUS != WIN_ERR) {
568             struct xwindow *wp = &window_list[WIN_STATUS];
569
570             update_fancy_status(wp);
571         }
572         return;
573     }
574
575     if (fld == BL_CONDITION) {
576         unsigned long mask = (unsigned long) ptr;
577
578         for (i = 0; i < SIZE(mask_to_fancyfield); i++)
579             if (mask_to_fancyfield[i].mask == mask)
580                 update_fancy_status_field(mask_to_fancyfield[i].ff);
581     } else {
582         for (i = 0; i < SIZE(bl_to_fancyfield); i++)
583             if (bl_to_fancyfield[i].bl == fld)
584                 update_fancy_status_field(bl_to_fancyfield[i].ff);
585     }
586 }
587
588 void
589 X11_status_update(fld, ptr, chg, percent, color, colormasks)
590 int fld, chg UNUSED, percent UNUSED, color;
591 genericptr_t ptr;
592 unsigned long *colormasks;
593 {
594     if (appResources.fancy_status)
595         X11_status_update_fancy(fld, ptr, chg, percent, color, colormasks);
596     else
597         X11_status_update_tty(fld, ptr, chg, percent, color, colormasks);
598 }
599
600 Widget
601 create_tty_status(parent, top)
602 Widget parent, top;
603 {
604     Widget form; /* The form that surrounds everything. */
605     Widget w;
606     Arg args[16];
607     Cardinal num_args;
608     int i, x, y;
609
610     num_args = 0;
611     if (top != (Widget) 0) {
612         XtSetArg(args[num_args], nhStr(XtNfromVert), top);
613         num_args++;
614     }
615     XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0);
616     num_args++;
617     XtSetArg(args[num_args], XtNborderWidth, 0);
618     num_args++;
619     XtSetArg(args[num_args], XtNwidth, 400); num_args++;
620     XtSetArg(args[num_args], XtNheight, 100); num_args++;
621     form = XtCreateManagedWidget("status_viewport", viewportWidgetClass,
622                                  parent, args, num_args);
623
624     num_args = 0;
625     XtSetArg(args[num_args], XtNwidth, 400); num_args++;
626     XtSetArg(args[num_args], XtNheight, 100); num_args++;
627     w = XtCreateManagedWidget("status_form", formWidgetClass,
628                              form, args, num_args);
629     for (y = 0; y < X11_NUM_STATUS_LINES; y++) {
630         for (x = 0; x < X11_NUM_STATUS_FIELD; x++) {
631             int fld = X11_fieldorder[y][x];
632             char labelname[BUFSZ];
633             int prevfld;
634
635             if (fld <= BL_FLUSH)
636                 continue;
637             Sprintf(labelname, "label_%s", bl_idx_to_fldname(fld));
638             num_args = 0;
639             if (y > 0) {
640                 prevfld = X11_fieldorder[y-1][0];
641                 XtSetArg(args[num_args], nhStr(XtNfromVert),
642                          X11_status_labels[prevfld]); num_args++;
643             }
644             if (x > 0) {
645                 prevfld = X11_fieldorder[y][x-1];
646                 XtSetArg(args[num_args], nhStr(XtNfromHoriz),
647                          X11_status_labels[prevfld]); num_args++;
648             }
649
650             XtSetArg(args[num_args], nhStr(XtNhorizDistance), 0); num_args++;
651             XtSetArg(args[num_args], nhStr(XtNvertDistance), 0); num_args++;
652
653             XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++;
654             XtSetArg(args[num_args], nhStr(XtNbottomMargin), 0); num_args++;
655             XtSetArg(args[num_args], nhStr(XtNleftMargin), 0); num_args++;
656             XtSetArg(args[num_args], nhStr(XtNrightMargin), 0); num_args++;
657             XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++;
658             XtSetArg(args[num_args], nhStr(XtNborderWidth), 0); num_args++;
659             /*
660             XtSetArg(args[num_args], nhStr(XtNlabel),
661                      bl_idx_to_fldname(fld)); num_args++;
662             */
663             XtSetArg(args[num_args], nhStr(XtNlabel), ""); num_args++;
664             X11_status_labels[fld] = XtCreateManagedWidget(labelname,
665                                                            labelWidgetClass, w,
666                                                            args, num_args);
667         }
668      }
669
670     for (i = 0; i < 32; i++) {
671         char condname[BUFSZ];
672         int prevfld;
673
674         Sprintf(condname, "cond_%i", i);
675         num_args = 0;
676
677         prevfld = X11_fieldorder[0][0];
678         XtSetArg(args[num_args], nhStr(XtNfromVert),
679                  X11_status_labels[prevfld]); num_args++;
680
681         XtSetArg(args[num_args], nhStr(XtNfromHoriz),
682                  (i == 0) ? X11_status_labels[BL_CONDITION]
683                  : X11_cond_labels[i-1]); num_args++;
684
685         XtSetArg(args[num_args], nhStr(XtNhorizDistance), 0); num_args++;
686         XtSetArg(args[num_args], nhStr(XtNvertDistance), 0); num_args++;
687         XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++;
688         XtSetArg(args[num_args], nhStr(XtNbottomMargin), 0); num_args++;
689         XtSetArg(args[num_args], nhStr(XtNleftMargin), 0); num_args++;
690         XtSetArg(args[num_args], nhStr(XtNrightMargin), 0); num_args++;
691         XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++;
692         XtSetArg(args[num_args], nhStr(XtNborderWidth), 0); num_args++;
693         XtSetArg(args[num_args], nhStr(XtNlabel), ""); num_args++;
694         X11_cond_labels[i] = XtCreateManagedWidget(condname,
695                                                    labelWidgetClass, w,
696                                                    args, num_args);
697     }
698
699     return w;
700 }
701
702 /*ARGSUSED*/
703 void
704 create_status_window_tty(wp, create_popup, parent)
705 struct xwindow *wp; /* window pointer */
706 boolean create_popup UNUSED;
707 Widget parent;
708 {
709     Arg args[10];
710     Cardinal num_args;
711
712     wp->type = NHW_STATUS;
713     X11_status_widget = wp->w = create_tty_status(parent, (Widget) 0);
714
715     num_args = 0;
716     XtSetArg(args[num_args], nhStr(XtNforeground), &X11_status_widget_fg); num_args++;
717     XtSetArg(args[num_args], nhStr(XtNbackground), &X11_status_widget_bg); num_args++;
718     XtGetValues(X11_status_widget, args, num_args);
719 }
720
721 void
722 destroy_status_window_tty(wp)
723 struct xwindow *wp;
724 {
725     /* If status_information is defined, then it a "text" status window. */
726     if (wp->status_information) {
727         if (wp->popup) {
728             nh_XtPopdown(wp->popup);
729             if (!wp->keep_window)
730                 XtDestroyWidget(wp->popup), wp->popup = (Widget) 0;
731         }
732         free((genericptr_t) wp->status_information);
733         wp->status_information = 0;
734     } else {
735     }
736     if (!wp->keep_window)
737         wp->type = NHW_NONE;
738 }
739
740 /*ARGSUSED*/
741 void
742 adjust_status_tty(wp, str)
743 struct xwindow *wp UNUSED;
744 const char *str UNUSED;
745 {
746     /* nothing */
747 }
748
749 void
750 create_status_window(wp, create_popup, parent)
751 struct xwindow *wp; /* window pointer */
752 boolean create_popup;
753 Widget parent;
754 {
755     xw_status_win = wp;
756     if (appResources.fancy_status)
757         create_status_window_fancy(wp, create_popup, parent);
758     else
759         create_status_window_tty(wp, create_popup, parent);
760 }
761
762 void
763 destroy_status_window(wp)
764 struct xwindow *wp;
765 {
766     if (appResources.fancy_status)
767         destroy_status_window_fancy(wp);
768     else
769         destroy_status_window_tty(wp);
770 }
771
772 void
773 adjust_status(wp, str)
774 struct xwindow *wp;
775 const char *str;
776 {
777     if (appResources.fancy_status)
778         adjust_status_fancy(wp, str);
779     else
780         adjust_status_tty(wp, str);
781 }
782
783 extern const char *hu_stat[];  /* from eat.c */
784 extern const char *enc_stat[]; /* from botl.c */
785
786 void
787 create_status_window_fancy(wp, create_popup, parent)
788 struct xwindow *wp; /* window pointer */
789 boolean create_popup;
790 Widget parent;
791 {
792 #if 0 /*JP*/
793     XFontStruct *fs;
794 #endif
795     Arg args[8];
796     Cardinal num_args;
797     Position top_margin, bottom_margin, left_margin, right_margin;
798 #ifdef XI18N
799     XFontSet fontset;
800     XFontSetExtents *extent;
801 #endif
802
803     wp->type = NHW_STATUS;
804
805     if (!create_popup) {
806         /*
807          * If we are not creating a popup, then we must be the "main" status
808          * window.
809          */
810         if (!parent)
811             panic("create_status_window_fancy: no parent for fancy status");
812         wp->status_information = 0;
813         wp->w = create_fancy_status(parent, (Widget) 0);
814         return;
815     }
816
817     wp->status_information =
818         (struct status_info_t *) alloc(sizeof(struct status_info_t));
819
820     init_text_buffer(&wp->status_information->text);
821
822     num_args = 0;
823     XtSetArg(args[num_args], XtNallowShellResize, False);
824     num_args++;
825     XtSetArg(args[num_args], XtNinput, False);
826     num_args++;
827
828     wp->popup = parent = XtCreatePopupShell(
829         "status_popup", topLevelShellWidgetClass, toplevel, args, num_args);
830     /*
831      * If we're here, then this is an auxiliary status window.  If we're
832      * cancelled via a delete window message, we should just pop down.
833      */
834
835     num_args = 0;
836     XtSetArg(args[num_args], nhStr(XtNdisplayCaret), False);
837     num_args++;
838     XtSetArg(args[num_args], nhStr(XtNscrollHorizontal),
839              XawtextScrollWhenNeeded);
840     num_args++;
841     XtSetArg(args[num_args], nhStr(XtNscrollVertical),
842              XawtextScrollWhenNeeded);
843     num_args++;
844
845 /*JP*/
846 #if defined(X11R6) && defined(XI18N)
847     XtSetArg(args[num_args], XtNinternational, True);
848     num_args++;
849 #endif
850     wp->w = XtCreateManagedWidget("status", /* name */
851                                   asciiTextWidgetClass,
852                                   parent,    /* parent widget */
853                                   args,      /* set some values */
854                                   num_args); /* number of values to set */
855
856     /*
857      * Adjust the height and width of the message window so that it
858      * is two lines high and COLNO of the widest characters wide.
859      */
860
861     /* Get the font and margin information. */
862     num_args = 0;
863 #ifndef XI18N
864     XtSetArg(args[num_args], XtNfont, &fs);
865 #else
866     XtSetArg(args[num_args], XtNfontSet, &fontset);
867 #endif
868     num_args++;
869     XtSetArg(args[num_args], nhStr(XtNtopMargin), &top_margin);
870     num_args++;
871     XtSetArg(args[num_args], nhStr(XtNbottomMargin), &bottom_margin);
872     num_args++;
873     XtSetArg(args[num_args], nhStr(XtNleftMargin), &left_margin);
874     num_args++;
875     XtSetArg(args[num_args], nhStr(XtNrightMargin), &right_margin);
876     num_args++;
877     XtGetValues(wp->w, args, num_args);
878
879 #ifndef XI18N
880     wp->pixel_height = 2 * nhFontHeight(wp->w) + top_margin + bottom_margin;
881     wp->pixel_width =
882         COLNO * fs->max_bounds.width + left_margin + right_margin;
883 #else
884     extent = XExtentsOfFontSet(fontset);
885     wp->pixel_height = 2 * extent->max_logical_extent.height + top_margin + bottom_margin;
886     wp->pixel_width  =
887         COLNO / 2 * extent->max_logical_extent.width + left_margin + right_margin;
888 #endif
889
890     /* Set the new width and height. */
891     num_args = 0;
892     XtSetArg(args[num_args], XtNwidth, wp->pixel_width);
893     num_args++;
894     XtSetArg(args[num_args], XtNheight, wp->pixel_height);
895     num_args++;
896     XtSetValues(wp->w, args, num_args);
897 }
898
899 void
900 destroy_status_window_fancy(wp)
901 struct xwindow *wp;
902 {
903     /* If status_information is defined, then it a "text" status window. */
904     if (wp->status_information) {
905         if (wp->popup) {
906             nh_XtPopdown(wp->popup);
907             if (!wp->keep_window)
908                 XtDestroyWidget(wp->popup), wp->popup = (Widget) 0;
909         }
910         free((genericptr_t) wp->status_information);
911         wp->status_information = 0;
912     } else {
913         destroy_fancy_status(wp);
914     }
915     if (!wp->keep_window)
916         wp->type = NHW_NONE;
917 }
918
919 /*
920  * This assumes several things:
921  *      + Status has only 2 lines
922  *      + That both lines are updated in succession in line order.
923  *      + We didn't set stringInPlace on the widget.
924  */
925 void
926 adjust_status_fancy(wp, str)
927 struct xwindow *wp;
928 const char *str;
929 {
930     Arg args[2];
931     Cardinal num_args;
932
933     if (!wp->status_information) {
934         update_fancy_status(wp);
935         return;
936     }
937
938     if (wp->cursy == 0) {
939         clear_text_buffer(&wp->status_information->text);
940         append_text_buffer(&wp->status_information->text, str, FALSE);
941         return;
942     }
943     append_text_buffer(&wp->status_information->text, str, FALSE);
944
945     /* Set new buffer as text. */
946     num_args = 0;
947     XtSetArg(args[num_args], XtNstring, wp->status_information->text.text);
948     num_args++;
949     XtSetValues(wp->w, args, num_args);
950 }
951
952 /* Fancy Status
953  * -------------------------------------------------------------*/
954 static int hilight_time = 1; /* number of turns to hilight a changed value */
955
956 struct X_status_value {
957     /* we have to cast away 'const' when assigning new names */
958     const char *name;   /* text name */
959     int type;           /* status type */
960     Widget w;           /* widget of name/value pair */
961     long last_value;    /* value displayed */
962     int turn_count;     /* last time the value changed */
963     boolean set;        /* if highlighted */
964     boolean after_init; /* don't highlight on first change (init) */
965 };
966
967 /* valid type values */
968 #define SV_VALUE 0 /* displays a label:value pair */
969 #define SV_LABEL 1 /* displays a changable label */
970 #define SV_NAME 2  /* displays an unchangeable name */
971
972 static void FDECL(hilight_label, (Widget));
973 static void FDECL(update_val, (struct X_status_value *, long));
974 static const char *FDECL(width_string, (int));
975 static void FDECL(create_widget, (Widget, struct X_status_value *, int));
976 static void FDECL(get_widths, (struct X_status_value *, int *, int *));
977 static void FDECL(set_widths, (struct X_status_value *, int, int));
978 static Widget FDECL(init_column, (const char *, Widget, Widget, Widget,
979                                   int *));
980 static void NDECL(fixup_cond_widths);
981 static Widget FDECL(init_info_form, (Widget, Widget, Widget));
982
983 /*
984  * Notes:
985  * + Alignment needs a different init value, because -1 is an alignment.
986  * + Armor Class is an schar, so 256 is out of range.
987  * + Blank value is 0 and should never change.
988  */
989 static struct X_status_value shown_stats[NUM_STATS] = {
990     { "", SV_NAME, (Widget) 0, -1, 0, FALSE, FALSE }, /* 0*/
991
992 #if 0 /*JP*/
993     { "Strength", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
994     { "Dexterity", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
995     { "Constitution", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
996     { "Intelligence", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
997     { "Wisdom", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /* 5*/
998     { "Charisma", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
999 #else /*JP*/
1000     { "\8b­\82³",   SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /* 0*/
1001     { "\91f\91\81\82³", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
1002     { "\91Ï\8bv\97Í", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
1003     { "\92m\97Í",   SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
1004     { "\8c«\82³",   SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
1005     { "\96£\97Í",   SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /* 5*/
1006 #endif
1007
1008     { "", SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* name */
1009     { "", SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* dlvl */
1010 #if 0 /*JP*/
1011     { "Gold", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
1012     { "Hit Points", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /*10*/
1013     { "Max HP", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
1014     { "Power", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
1015     { "Max Power", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
1016     { "Armor Class", SV_VALUE, (Widget) 0, 256, 0, FALSE, FALSE },
1017     { "Level", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /*15*/
1018     { "Experience", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
1019     { "Alignment", SV_VALUE, (Widget) 0, -2, 0, FALSE, FALSE },
1020     { "Time", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
1021     { "Score", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
1022 #else /*JP*/
1023     { "\8bà",             SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
1024     { "\91Ì\97Í",           SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
1025     { "\8dÅ\91å\91Ì\97Í",       SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /*10*/
1026     { "\96\82\97Í",           SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
1027     { "\8dÅ\91å\96\82\97Í",       SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
1028     { "\8aZ",             SV_VALUE, (Widget) 0,256, 0, FALSE, FALSE },
1029     { "\83\8c\83x\83\8b",         SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
1030     { "\8co\8c±",           SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /*15*/
1031     { "\91®\90«",           SV_VALUE, (Widget) 0, -2, 0, FALSE, FALSE },
1032     { "\8e\9e\8aÔ",           SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
1033     { "\83X\83R\83A",         SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
1034 #endif
1035
1036 #if 0 /*JP*/
1037     { "Petrifying", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*20*/
1038     { "Slimed", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1039     { "Strangled", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1040     { "Food Pois", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1041     { "Term Ill", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1042 #else
1043     { "\90Î\89»", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*20*/
1044     { "\83X\83\89\83C\83\80", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1045     { "\92\82\91§", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1046     { "\90H\93Å", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1047     { "\95a\8bC", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1048 #endif
1049
1050     { "", SV_NAME, (Widget) 0, -1, 0, FALSE, TRUE }, /*25*/     /* hunger */
1051     { "", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },             /*encumbr */
1052 #if 0 /*JP*/
1053     { "Levitating", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1054     { "Flying", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1055     { "Riding", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1056 #else
1057     { "\95\82\97V", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1058     { "\94ò\8ds", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1059     { "\8bR\8fæ", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1060 #endif
1061
1062 #if 0 /*JP*/
1063     { "Blind", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*30*/
1064     { "Deaf", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1065     { "Stunned", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1066     { "Confused", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1067     { "Hallucinating", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1068 #else
1069     { "\96Ó\96Ú", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*30*/
1070     { "\8e¨\98W", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1071     { "á¿\9dò", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1072     { "\8d¬\97\90", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1073     { "\8c\8ao", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE },
1074 #endif
1075 };
1076
1077 /*
1078  * Set all widget values to a null string.  This is used after all spacings
1079  * have been calculated so that when the window is popped up we don't get all
1080  * kinds of funny values being displayed.
1081  */
1082 void
1083 null_out_status()
1084 {
1085     int i;
1086     struct X_status_value *sv;
1087     Arg args[1];
1088
1089     for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) {
1090         switch (sv->type) {
1091         case SV_VALUE:
1092             set_value(sv->w, "");
1093             break;
1094
1095         case SV_LABEL:
1096         case SV_NAME:
1097             XtSetArg(args[0], XtNlabel, "");
1098             XtSetValues(sv->w, args, ONE);
1099             break;
1100
1101         default:
1102             impossible("null_out_status: unknown type %d\n", sv->type);
1103             break;
1104         }
1105     }
1106 }
1107
1108 /* This is almost an exact duplicate of hilight_value() */
1109 static void
1110 hilight_label(w)
1111 Widget w; /* label widget */
1112 {
1113     Arg args[2];
1114     Pixel fg, bg;
1115
1116     XtSetArg(args[0], XtNforeground, &fg);
1117     XtSetArg(args[1], XtNbackground, &bg);
1118     XtGetValues(w, args, TWO);
1119
1120     XtSetArg(args[0], XtNforeground, bg);
1121     XtSetArg(args[1], XtNbackground, fg);
1122     XtSetValues(w, args, TWO);
1123 }
1124
1125 static void
1126 update_val(attr_rec, new_value)
1127 struct X_status_value *attr_rec;
1128 long new_value;
1129 {
1130     char buf[BUFSZ];
1131     Arg args[4];
1132
1133     if (attr_rec->type == SV_LABEL) {
1134         if (attr_rec == &shown_stats[F_NAME]) {
1135             Strcpy(buf, plname);
1136             buf[0] = highc(buf[0]);
1137 #if 0 /*JP*/
1138             Strcat(buf, " the ");
1139 #else
1140             Strcat(buf, " ");
1141 #endif
1142             if (Upolyd) {
1143                 char mname[BUFSZ];
1144                 int k;
1145
1146                 Strcpy(mname, mons[u.umonnum].mname);
1147 #if 0 /*JP*//*\83L\83\83\83s\83^\83\89\83C\83Y\95s\97v*/
1148                 for (k = 0; mname[k] != '\0'; k++) {
1149                     if (k == 0 || mname[k - 1] == ' ')
1150                         mname[k] = highc(mname[k]);
1151                 }
1152 #endif
1153                 Strcat(buf, mname);
1154             } else
1155                 Strcat(buf, rank_of(u.ulevel, pl_character[0], flags.female));
1156
1157         } else if (attr_rec == &shown_stats[F_DLEVEL]) {
1158             if (!describe_level(buf)) {
1159                 Strcpy(buf, dungeons[u.uz.dnum].dname);
1160 /*JP
1161                 Sprintf(eos(buf), ", level %d", depth(&u.uz));
1162 */
1163                 Sprintf(eos(buf), " \92n\89º%d\8aK", depth(&u.uz));
1164             }
1165         } else {
1166             impossible("update_val: unknown label type \"%s\"",
1167                        attr_rec->name);
1168             return;
1169         }
1170
1171         if (strcmp(buf, attr_rec->name) == 0)
1172             return; /* same */
1173
1174         /* Set the label.  'name' field is const for most entries;
1175            we need to cast away that const for this assignment */
1176         Strcpy((char *) attr_rec->name, buf);
1177         XtSetArg(args[0], XtNlabel, buf);
1178         XtSetValues(attr_rec->w, args, ONE);
1179
1180     } else if (attr_rec->type == SV_NAME) {
1181         if (attr_rec->last_value == new_value)
1182             return; /* no change */
1183
1184         attr_rec->last_value = new_value;
1185
1186         /* special cases: hunger, encumbrance, sickness */
1187         if (attr_rec == &shown_stats[F_HUNGER]) {
1188             XtSetArg(args[0], XtNlabel, hu_stat[new_value]);
1189         } else if (attr_rec == &shown_stats[F_ENCUMBER]) {
1190             XtSetArg(args[0], XtNlabel, enc_stat[new_value]);
1191         } else if (new_value) {
1192             XtSetArg(args[0], XtNlabel, attr_rec->name);
1193         } else {
1194             XtSetArg(args[0], XtNlabel, "");
1195         }
1196         XtSetValues(attr_rec->w, args, ONE);
1197
1198     } else { /* a value pair */
1199         boolean force_update = FALSE;
1200
1201         /* special case: time can be enabled & disabled */
1202         if (attr_rec == &shown_stats[F_TIME]) {
1203             static boolean flagtime = TRUE;
1204
1205             if (flags.time && !flagtime) {
1206                 set_name(attr_rec->w, shown_stats[F_TIME].name);
1207                 force_update = TRUE;
1208                 flagtime = flags.time;
1209             } else if (!flags.time && flagtime) {
1210                 set_name(attr_rec->w, "");
1211                 set_value(attr_rec->w, "");
1212                 flagtime = flags.time;
1213             }
1214             if (!flagtime)
1215                 return;
1216         }
1217
1218         /* special case: exp can be enabled & disabled */
1219         else if (attr_rec == &shown_stats[F_EXP]) {
1220             static boolean flagexp = TRUE;
1221
1222             if (flags.showexp && !flagexp) {
1223                 set_name(attr_rec->w, shown_stats[F_EXP].name);
1224                 force_update = TRUE;
1225                 flagexp = flags.showexp;
1226             } else if (!flags.showexp && flagexp) {
1227                 set_name(attr_rec->w, "");
1228                 set_value(attr_rec->w, "");
1229                 flagexp = flags.showexp;
1230             }
1231             if (!flagexp)
1232                 return;
1233         }
1234
1235         /* special case: score can be enabled & disabled */
1236         else if (attr_rec == &shown_stats[F_SCORE]) {
1237             static boolean flagscore = TRUE;
1238 #ifdef SCORE_ON_BOTL
1239
1240             if (flags.showscore && !flagscore) {
1241                 set_name(attr_rec->w, shown_stats[F_SCORE].name);
1242                 force_update = TRUE;
1243                 flagscore = flags.showscore;
1244             } else if (!flags.showscore && flagscore) {
1245                 set_name(attr_rec->w, "");
1246                 set_value(attr_rec->w, "");
1247                 flagscore = flags.showscore;
1248             }
1249             if (!flagscore)
1250                 return;
1251 #else
1252             if (flagscore) {
1253                 set_name(attr_rec->w, "");
1254                 set_value(attr_rec->w, "");
1255                 flagscore = FALSE;
1256             }
1257             return;
1258 #endif
1259         }
1260
1261         /* special case: when polymorphed, show "HD", disable exp */
1262         else if (attr_rec == &shown_stats[F_LEVEL]) {
1263             static boolean lev_was_poly = FALSE;
1264
1265             if (Upolyd && !lev_was_poly) {
1266                 force_update = TRUE;
1267                 set_name(attr_rec->w, "HD");
1268                 lev_was_poly = TRUE;
1269             } else if (Upolyd && lev_was_poly) {
1270                 force_update = TRUE;
1271                 set_name(attr_rec->w, shown_stats[F_LEVEL].name);
1272                 lev_was_poly = FALSE;
1273             }
1274         } else if (attr_rec == &shown_stats[F_EXP]) {
1275             static boolean exp_was_poly = FALSE;
1276
1277             if (Upolyd && !exp_was_poly) {
1278                 force_update = TRUE;
1279                 set_name(attr_rec->w, "");
1280                 set_value(attr_rec->w, "");
1281                 exp_was_poly = TRUE;
1282             } else if (Upolyd && exp_was_poly) {
1283                 force_update = TRUE;
1284                 set_name(attr_rec->w, shown_stats[F_EXP].name);
1285                 exp_was_poly = FALSE;
1286             }
1287             if (Upolyd)
1288                 return; /* no display for exp when poly */
1289         }
1290
1291         if (attr_rec->last_value == new_value && !force_update) /* same */
1292             return;
1293
1294         attr_rec->last_value = new_value;
1295
1296         /* Special cases: strength, alignment and "clear". */
1297         if (attr_rec == &shown_stats[F_STR]) {
1298             if (new_value > 18) {
1299                 if (new_value > 118)
1300                     Sprintf(buf, "%ld", new_value - 100);
1301                 else if (new_value < 118)
1302                     Sprintf(buf, "18/%02ld", new_value - 18);
1303                 else
1304                     Strcpy(buf, "18/**");
1305             } else {
1306                 Sprintf(buf, "%ld", new_value);
1307             }
1308         } else if (attr_rec == &shown_stats[F_ALIGN]) {
1309 #if 0 /*JP*/
1310             Strcpy(buf,
1311                    (new_value == A_CHAOTIC)
1312                        ? "Chaotic"
1313                        : (new_value == A_NEUTRAL) ? "Neutral" : "Lawful");
1314 #else
1315             Strcpy(buf,
1316                    (new_value == A_CHAOTIC)
1317                    ? "\8d¬\93×"
1318                    : (new_value == A_NEUTRAL)
1319                    ? "\92\86\97§" : "\92\81\8f\98");
1320 #endif
1321         } else {
1322             Sprintf(buf, "%ld", new_value);
1323         }
1324         set_value(attr_rec->w, buf);
1325     }
1326
1327     /*
1328      * Now hilight the changed information.  Names, time and score don't
1329      * hilight.  If first time, don't hilight.  If already lit, don't do
1330      * it again.
1331      */
1332     if (attr_rec->type != SV_NAME && attr_rec != &shown_stats[F_TIME]) {
1333         if (attr_rec->after_init) {
1334             if (!attr_rec->set) {
1335                 if (attr_rec->type == SV_LABEL)
1336                     hilight_label(attr_rec->w);
1337                 else
1338                     hilight_value(attr_rec->w);
1339                 attr_rec->set = TRUE;
1340             }
1341             attr_rec->turn_count = 0;
1342         } else {
1343             attr_rec->after_init = TRUE;
1344         }
1345     }
1346 }
1347
1348 /*
1349  * Update the displayed status.  The current code in botl.c updates
1350  * two lines of information.  Both lines are always updated one after
1351  * the other.  So only do our update when we update the second line.
1352  *
1353  * Information on the first line:
1354  *      name, attributes, alignment, score
1355  *
1356  * Information on the second line:
1357  *      dlvl, gold, hp, power, ac, {level & exp or HD **}, time,
1358  *      status * (stone, slime, strngl, foodpois, termill,
1359  *                hunger, encumbrance, lev, fly, ride,
1360  *                blind, deaf, stun, conf, hallu)
1361  *
1362  *  [*] order of status fields is different on tty.
1363  * [**] HD is shown instead of level and exp if Upolyd.
1364  */
1365 static void
1366 update_fancy_status_field(i)
1367 int i;
1368 {
1369     struct X_status_value *sv = &shown_stats[i];
1370     long val;
1371
1372     switch (i) {
1373         case F_DUMMY:
1374             val = 0L;
1375             break;
1376         case F_STR:
1377             val = (long) ACURR(A_STR);
1378             break;
1379         case F_DEX:
1380             val = (long) ACURR(A_DEX);
1381             break;
1382         case F_CON:
1383             val = (long) ACURR(A_CON);
1384             break;
1385         case F_INT:
1386             val = (long) ACURR(A_INT);
1387             break;
1388         case F_WIS:
1389             val = (long) ACURR(A_WIS);
1390             break;
1391         case F_CHA:
1392             val = (long) ACURR(A_CHA);
1393             break;
1394         /*
1395          * Label stats.  With the exceptions of hunger, encumbrance, sick
1396          * these are either on or off.  Pleae leave the ternary operators
1397          * the way they are.  I want to specify 0 or 1, not a boolean.
1398          */
1399         case F_HUNGER:
1400             val = (long) u.uhs;
1401             break;
1402         case F_ENCUMBER:
1403             val = (long) near_capacity();
1404             break;
1405         case F_LEV:
1406             val = Levitation ? 1L : 0L;
1407             break;
1408         case F_FLY:
1409             val = Flying ? 1L : 0L;
1410             break;
1411         case F_RIDE:
1412             val = u.usteed ? 1L : 0L;
1413             break;
1414         /* fatal status conditions */
1415         case F_STONE:
1416             val = Stoned ? 1L : 0L;
1417             break;
1418         case F_SLIME:
1419             val = Slimed ? 1L : 0L;
1420             break;
1421         case F_STRNGL:
1422             val = Strangled ? 1L : 0L;
1423             break;
1424         case F_FOODPOIS:
1425             val = (Sick && (u.usick_type & SICK_VOMITABLE)) ? 1L : 0L;
1426             break;
1427         case F_TERMILL:
1428             val = (Sick && (u.usick_type & SICK_NONVOMITABLE)) ? 1L : 0L;
1429             break;
1430         /* non-fatal status conditions */
1431         case F_BLIND:
1432             val = Blind ? 1L : 0L;
1433             break;
1434         case F_DEAF:
1435             val = Deaf ? 1L : 0L;
1436             break;
1437         case F_STUN:
1438             val = Stunned ? 1L : 0L;
1439             break;
1440         case F_CONF:
1441             val = Confusion ? 1L : 0L;
1442             break;
1443         case F_HALLU:
1444             val = Hallucination ? 1L : 0L;
1445             break;
1446
1447         case F_NAME:
1448             val = (long) 0L;
1449             break; /* special */
1450         case F_DLEVEL:
1451             val = (long) 0L;
1452             break; /* special */
1453         case F_GOLD:
1454             val = money_cnt(invent);
1455             if (val < 0L)
1456                 val = 0L; /* ought to issue impossible() and discard gold */
1457             break;
1458         case F_HP:
1459             val = (long) (Upolyd ? (u.mh > 0 ? u.mh : 0)
1460                                  : (u.uhp > 0 ? u.uhp : 0));
1461             break;
1462         case F_MAXHP:
1463             val = (long) (Upolyd ? u.mhmax : u.uhpmax);
1464             break;
1465         case F_POWER:
1466             val = (long) u.uen;
1467             break;
1468         case F_MAXPOWER:
1469             val = (long) u.uenmax;
1470             break;
1471         case F_AC:
1472             val = (long) u.uac;
1473             break;
1474         case F_LEVEL:
1475             val = (long) (Upolyd ? mons[u.umonnum].mlevel : u.ulevel);
1476             break;
1477         case F_EXP:
1478             val = flags.showexp ? u.uexp : 0L;
1479             break;
1480         case F_ALIGN:
1481             val = (long) u.ualign.type;
1482             break;
1483         case F_TIME:
1484             val = flags.time ? (long) moves : 0L;
1485             break;
1486         case F_SCORE:
1487 #ifdef SCORE_ON_BOTL
1488             val = flags.showscore ? botl_score() : 0L;
1489 #else
1490             val = 0L;
1491 #endif
1492             break;
1493         default: {
1494             /*
1495              * There is a possible infinite loop that occurs with:
1496              *
1497              *  impossible->pline->flush_screen->bot->bot{1,2}->
1498              *  putstr->adjust_status->update_other->impossible
1499              *
1500              * Break out with this.
1501              */
1502             static boolean active = FALSE;
1503
1504             if (!active) {
1505                 active = TRUE;
1506                 impossible("update_other: unknown shown value");
1507                 active = FALSE;
1508             }
1509             val = 0L;
1510             break;
1511         } /* default */
1512     } /* switch */
1513     update_val(sv, val);
1514 }
1515
1516 /*ARGUSED*/
1517 static void
1518 update_fancy_status(wp)
1519 struct xwindow *wp UNUSED;
1520 {
1521     int i;
1522
1523     /*if (wp->cursy != 0)
1524       return;*/ /* do a complete update when line 0 is done */
1525
1526     for (i = 0; i < NUM_STATS; i++)
1527         update_fancy_status_field(i);
1528 }
1529
1530
1531 /*
1532  * Turn off hilighted status values after a certain amount of turns.
1533  */
1534 void
1535 check_turn_events()
1536 {
1537     int i;
1538     struct X_status_value *sv;
1539
1540     for (sv = shown_stats, i = 0; i < NUM_STATS; i++, sv++) {
1541         if (!sv->set)
1542             continue;
1543
1544         if (sv->turn_count++ >= hilight_time) {
1545             if (sv->type == SV_LABEL)
1546                 hilight_label(sv->w);
1547             else
1548                 hilight_value(sv->w);
1549             sv->set = FALSE;
1550         }
1551     }
1552 }
1553
1554 /* Initialize alternate status =============================================
1555  */
1556
1557 /* Return a string for the initial width. */
1558 static const char *
1559 width_string(sv_index)
1560 int sv_index;
1561 {
1562     switch (sv_index) {
1563     case F_DUMMY:
1564         return " ";
1565
1566     case F_STR:
1567         return "018/**";
1568     case F_DEX:
1569     case F_CON:
1570     case F_INT:
1571     case F_WIS:
1572     case F_CHA:
1573         return "088"; /* all but str never get bigger */
1574
1575     case F_HUNGER:
1576         return "Satiated";
1577     case F_ENCUMBER:
1578         return "Overloaded";
1579
1580     case F_LEV:
1581     case F_FLY:
1582     case F_RIDE:
1583     case F_STONE:
1584     case F_SLIME:
1585     case F_STRNGL:
1586     case F_FOODPOIS:
1587     case F_TERMILL:
1588     case F_BLIND:
1589     case F_DEAF:
1590     case F_STUN:
1591     case F_CONF:
1592     case F_HALLU:
1593         return shown_stats[sv_index].name;
1594
1595     case F_NAME:
1596     case F_DLEVEL:
1597         return "";
1598     case F_HP:
1599     case F_MAXHP:
1600         return "9999";
1601     case F_POWER:
1602     case F_MAXPOWER:
1603         return "9999";
1604     case F_AC:
1605         return "-127";
1606     case F_LEVEL:
1607         return "99";
1608     case F_GOLD:
1609         /* strongest hero can pick up roughly 30% of this much */
1610         return "999999"; /* same limit as tty */
1611     case F_EXP:
1612     case F_TIME:
1613     case F_SCORE:
1614         return "123456789"; /* a tenth digit will still fit legibly */
1615     case F_ALIGN:
1616         return "Neutral";
1617     }
1618     impossible("width_string: unknown index %d\n", sv_index);
1619     return "";
1620 }
1621
1622 static void
1623 create_widget(parent, sv, sv_index)
1624 Widget parent;
1625 struct X_status_value *sv;
1626 int sv_index;
1627 {
1628     Arg args[4];
1629     Cardinal num_args;
1630
1631     switch (sv->type) {
1632     case SV_VALUE:
1633         sv->w = create_value(parent, sv->name);
1634         set_value(sv->w, width_string(sv_index));
1635         break;
1636     case SV_LABEL:
1637         /* Labels get their own buffer. */
1638         sv->name = (char *) alloc(BUFSZ);
1639         /* we need to cast away 'const' when assigning a value */
1640         *(char *) (sv->name) = '\0';
1641
1642         num_args = 0;
1643         XtSetArg(args[num_args], XtNborderWidth, 0);
1644         num_args++;
1645         XtSetArg(args[num_args], XtNinternalHeight, 0);
1646         num_args++;
1647 #if defined(X11R6) && defined(XI18N)
1648         XtSetArg(args[num_args], XtNinternational, True);
1649         num_args++;
1650 #endif
1651         sv->w = XtCreateManagedWidget((sv_index == F_NAME)
1652                                          ? "name"
1653                                          : "dlevel",
1654                                       labelWidgetClass, parent,
1655                                       args, num_args);
1656         break;
1657     case SV_NAME:
1658         num_args = 0;
1659         XtSetArg(args[0], XtNlabel, width_string(sv_index)); num_args++;
1660         XtSetArg(args[num_args], XtNborderWidth, 0); num_args++;
1661         XtSetArg(args[num_args], XtNinternalHeight, 0); num_args++;
1662 #if defined(X11R6) && defined(XI18N)
1663         XtSetArg(args[num_args], XtNinternational, True); num_args++;
1664 #endif
1665         sv->w = XtCreateManagedWidget(sv->name, labelWidgetClass, parent,
1666                                       args, num_args);
1667         break;
1668     default:
1669         panic("create_widget: unknown type %d", sv->type);
1670     }
1671 }
1672
1673 /*
1674  * Get current width of value.  width2p is only valid for SV_VALUE types.
1675  */
1676 static void
1677 get_widths(sv, width1p, width2p)
1678 struct X_status_value *sv;
1679 int *width1p, *width2p;
1680 {
1681     Arg args[1];
1682     Dimension width;
1683
1684     switch (sv->type) {
1685     case SV_VALUE:
1686         *width1p = get_name_width(sv->w);
1687         *width2p = get_value_width(sv->w);
1688         break;
1689     case SV_LABEL:
1690     case SV_NAME:
1691         XtSetArg(args[0], XtNwidth, &width);
1692         XtGetValues(sv->w, args, ONE);
1693         *width1p = width;
1694         *width2p = 0;
1695         break;
1696     default:
1697         panic("get_widths: unknown type %d", sv->type);
1698     }
1699 }
1700
1701 static void
1702 set_widths(sv, width1, width2)
1703 struct X_status_value *sv;
1704 int width1, width2;
1705 {
1706     Arg args[1];
1707
1708     switch (sv->type) {
1709     case SV_VALUE:
1710         set_name_width(sv->w, width1);
1711         set_value_width(sv->w, width2);
1712         break;
1713     case SV_LABEL:
1714     case SV_NAME:
1715         XtSetArg(args[0], XtNwidth, (width1 + width2));
1716         XtSetValues(sv->w, args, ONE);
1717         break;
1718     default:
1719         panic("set_widths: unknown type %d", sv->type);
1720     }
1721 }
1722
1723 static Widget
1724 init_column(name, parent, top, left, col_indices)
1725 const char *name;
1726 Widget parent, top, left;
1727 int *col_indices;
1728 {
1729     Widget form;
1730     Arg args[4];
1731     Cardinal num_args;
1732     int max_width1, width1, max_width2, width2;
1733     int *ip;
1734     struct X_status_value *sv;
1735
1736     num_args = 0;
1737     if (top != (Widget) 0) {
1738         XtSetArg(args[num_args], nhStr(XtNfromVert), top);
1739         num_args++;
1740     }
1741     if (left != (Widget) 0) {
1742         XtSetArg(args[num_args], nhStr(XtNfromHoriz), left);
1743         num_args++;
1744     }
1745     XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0);
1746     num_args++;
1747     form = XtCreateManagedWidget(name, formWidgetClass, parent,
1748                                  args, num_args);
1749
1750     max_width1 = max_width2 = 0;
1751     for (ip = col_indices; *ip >= 0; ip++) {
1752         sv = &shown_stats[*ip];
1753         create_widget(form, sv, *ip); /* will set init width */
1754         if (ip != col_indices) {      /* not first */
1755             num_args = 0;
1756             XtSetArg(args[num_args], nhStr(XtNfromVert),
1757                      shown_stats[*(ip - 1)].w);
1758             num_args++;
1759             XtSetValues(sv->w, args, num_args);
1760         }
1761         get_widths(sv, &width1, &width2);
1762         if (width1 > max_width1)
1763             max_width1 = width1;
1764         if (width2 > max_width2)
1765             max_width2 = width2;
1766     }
1767     for (ip = col_indices; *ip >= 0; ip++) {
1768         set_widths(&shown_stats[*ip], max_width1, max_width2);
1769     }
1770
1771     /* There is room behind the end marker for the two widths. */
1772     *++ip = max_width1;
1773     *++ip = max_width2;
1774
1775     return form;
1776 }
1777
1778 /*
1779  * These are the orders of the displayed columns.  Change to suit.  The -1
1780  * indicates the end of the column.  The two numbers after that are used
1781  * to store widths that are calculated at run-time.
1782  */
1783 static int attrib_indices[] = { F_STR, F_DEX, F_CON, F_INT, F_WIS, F_CHA,
1784                                 -1, 0, 0 };
1785 /* including F_DUMMY makes the three status condition columns evenly
1786    spaced with regard to the adjacent characteristics (Str,Dex,&c) column;
1787    we lose track of the Widget pointer for them, each use clobbering the
1788    one before, leaving the one from leftover_indices[]; since they're never
1789    updated, that shouldn't matter */
1790 static int status_indices[3][9] = { { F_STONE, F_SLIME, F_STRNGL,
1791                                       F_FOODPOIS, F_TERMILL, F_DUMMY,
1792                                       -1, 0, 0 },
1793                                     { F_HUNGER, F_ENCUMBER,
1794                                       F_LEV, F_FLY, F_RIDE, F_DUMMY,
1795                                       -1, 0, 0 },
1796                                     { F_BLIND, F_DEAF, F_STUN,
1797                                       F_CONF, F_HALLU, F_DUMMY,
1798                                       -1, 0, 0 } };
1799 /* used to fill up the empty space to right of 3rd status condition column */
1800 static int leftover_indices[] = { F_DUMMY, -1, 0, 0 };
1801
1802 static int col1_indices[] = { F_HP,    F_POWER,    F_AC,    F_LEVEL, F_GOLD,
1803                               F_SCORE, -1, 0, 0 };
1804 static int col2_indices[] = { F_MAXHP, F_MAXPOWER, F_ALIGN, F_EXP,   F_TIME,
1805                               -1, 0, 0 };
1806 /*
1807  * Produce a form that looks like the following:
1808  *
1809  *                 name
1810  *                dlevel
1811  * col1_indices[0]      col2_indices[0]
1812  * col1_indices[1]      col2_indices[1]
1813  *    .             .
1814  *    .             .
1815  * col1_indices[n]      col2_indices[n]
1816  *
1817  * TODO:  increase the space between the two columns.
1818  */
1819 static Widget
1820 init_info_form(parent, top, left)
1821 Widget parent, top, left;
1822 {
1823     Widget form, col1;
1824     struct X_status_value *sv_name, *sv_dlevel;
1825     Arg args[6];
1826     Cardinal num_args;
1827     int total_width, *ip;
1828
1829     num_args = 0;
1830     if (top != (Widget) 0) {
1831         XtSetArg(args[num_args], nhStr(XtNfromVert), top);
1832         num_args++;
1833     }
1834     if (left != (Widget) 0) {
1835         XtSetArg(args[num_args], nhStr(XtNfromHoriz), left);
1836         num_args++;
1837     }
1838     XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0);
1839     num_args++;
1840     form = XtCreateManagedWidget("status_info", formWidgetClass, parent, args,
1841                                  num_args);
1842
1843     /* top of form */
1844     sv_name = &shown_stats[F_NAME];
1845     create_widget(form, sv_name, F_NAME);
1846
1847     /* second */
1848     sv_dlevel = &shown_stats[F_DLEVEL];
1849     create_widget(form, sv_dlevel, F_DLEVEL);
1850
1851     num_args = 0;
1852     XtSetArg(args[num_args], nhStr(XtNfromVert), sv_name->w);
1853     num_args++;
1854     XtSetValues(sv_dlevel->w, args, num_args);
1855
1856     /* two columns beneath */
1857     col1 = init_column("name_col1", form, sv_dlevel->w, (Widget) 0,
1858                        col1_indices);
1859     (void) init_column("name_col2", form, sv_dlevel->w, col1, col2_indices);
1860
1861     /* Add calculated widths. */
1862     for (ip = col1_indices; *ip >= 0; ip++)
1863         ; /* skip to end */
1864     total_width = *++ip;
1865     total_width += *++ip;
1866     for (ip = col2_indices; *ip >= 0; ip++)
1867         ; /* skip to end */
1868     total_width += *++ip;
1869     total_width += *++ip;
1870
1871     XtSetArg(args[0], XtNwidth, total_width);
1872     XtSetValues(sv_name->w, args, ONE);
1873     XtSetArg(args[0], XtNwidth, total_width);
1874     XtSetValues(sv_dlevel->w, args, ONE);
1875
1876     return form;
1877 }
1878
1879 /* give the three status condition columns the same width */
1880 static void
1881 fixup_cond_widths()
1882 {
1883     int pass, i, *ip, w1, w2;
1884
1885     w1 = w2 = 0;
1886     for (pass = 1; pass <= 2; ++pass) { /* two passes... */
1887         for (i = 0; i < 3; i++) { /* three columns */
1888             for (ip = status_indices[i]; *ip != -1; ++ip) { /* X fields */
1889                 /* pass 1: find -1;  pass 2: update field widths, find -1 */
1890                 if (pass == 2)
1891                     set_widths(&shown_stats[*ip], w1, w2);
1892             }
1893             /* found -1; the two slots beyond it contain column widths */
1894             if (pass == 1) { /* pass 1: collect maxima */
1895                 if (ip[1] > w1)
1896                     w1 = ip[1];
1897                 if (ip[2] > w2)
1898                     w2 = ip[2];
1899             } else { /* pass 2: update column widths with maxima */
1900                 ip[1] = w1;
1901                 ip[2] = w2;
1902             }
1903         }
1904         /* ascetics:  expand the maximum width to make cond columns wider */
1905         if (pass == 1) {
1906             w1 += 20;
1907             if (w2 > 0)
1908                 w2 += 20;
1909         }
1910     }
1911 }
1912
1913 /*
1914  * Create the layout for the fancy status.  Return a form widget that
1915  * contains everything.
1916  */
1917 static Widget
1918 create_fancy_status(parent, top)
1919 Widget parent, top;
1920 {
1921     Widget form; /* The form that surrounds everything. */
1922     Widget w;
1923     Arg args[8];
1924     Cardinal num_args;
1925     char buf[32];
1926     int i;
1927
1928     num_args = 0;
1929     if (top != (Widget) 0) {
1930         XtSetArg(args[num_args], nhStr(XtNfromVert), top);
1931         num_args++;
1932     }
1933     XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0);
1934     num_args++;
1935     XtSetArg(args[num_args], XtNborderWidth, 0);
1936     num_args++;
1937     XtSetArg(args[num_args], XtNorientation, XtorientHorizontal);
1938     num_args++;
1939     form = XtCreateManagedWidget("fancy_status", panedWidgetClass, parent,
1940                                  args, num_args);
1941
1942     w = init_info_form(form, (Widget) 0, (Widget) 0);
1943     w = init_column("status_attributes", form, (Widget) 0, w, attrib_indices);
1944     for (i = 0; i < 3; i++) {
1945         Sprintf(buf, "status_condition%d", i + 1);
1946         w = init_column(buf, form, (Widget) 0, w, status_indices[i]);
1947     }
1948     fixup_cond_widths(); /* make all 3 status_conditionN columns same width */
1949     w = init_column("status_leftover", form, (Widget) 0, w, leftover_indices);
1950     nhUse(w);
1951     return form;
1952 }
1953
1954 static void
1955 destroy_fancy_status(wp)
1956 struct xwindow *wp;
1957 {
1958     int i;
1959     struct X_status_value *sv;
1960
1961     if (!wp->keep_window)
1962         XtDestroyWidget(wp->w), wp->w = (Widget) 0;
1963
1964     for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++)
1965         if (sv->type == SV_LABEL) {
1966             free((genericptr_t) sv->name);
1967             sv->name = 0;
1968         }
1969 }
1970
1971 /*winstat.c*/