]> granicus.if.org Git - nethack/commitdiff
*** empty log message ***
authorjwalz <jwalz>
Sat, 5 Jan 2002 21:06:03 +0000 (21:06 +0000)
committerjwalz <jwalz>
Sat, 5 Jan 2002 21:06:03 +0000 (21:06 +0000)
win/X11/winstat.c [new file with mode: 0644]

diff --git a/win/X11/winstat.c b/win/X11/winstat.c
new file mode 100644 (file)
index 0000000..50a63e4
--- /dev/null
@@ -0,0 +1,991 @@
+/*     SCCS Id: @(#)winstat.c  3.3     96/04/05        */
+/* Copyright (c) Dean Luick, 1992                                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * Status window routines.  This file supports both the "traditional"
+ * tty status display and a "fancy" status display.  A tty status is
+ * made if a popup window is requested, otherewise a fancy status is
+ * made.  This code assumes that only one fancy status will ever be made.
+ * Currently, only one status window (of any type) is _ever_ made.
+ */
+
+#ifndef SYSV
+#define PRESERVE_NO_SYSV       /* X11 include files may define SYSV */
+#endif
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Cardinals.h>
+#include <X11/Xaw/Form.h>
+#include <X11/Xaw/Paned.h>
+#include <X11/Xaw/Label.h>
+#include <X11/Xatom.h>
+
+#ifdef PRESERVE_NO_SYSV
+# ifdef SYSV
+#  undef SYSV
+# endif
+# undef PRESERVE_NO_SYSV
+#endif
+
+#include "hack.h"
+#include "winX.h"
+
+extern const char *hu_stat[]; /* from eat.c */
+extern const char *enc_stat[]; /* from botl.c */
+
+static void FDECL(update_fancy_status, (struct xwindow *));
+static Widget FDECL(create_fancy_status, (Widget,Widget));
+static void FDECL(destroy_fancy_status, (struct xwindow *));
+
+void
+create_status_window(wp, create_popup, parent)
+    struct xwindow *wp;                        /* window pointer */
+    boolean create_popup;
+    Widget parent;
+{
+    XFontStruct *fs;
+    Arg args[8];
+    Cardinal num_args;
+    Position top_margin, bottom_margin, left_margin, right_margin;
+
+    wp->type = NHW_STATUS;
+
+    if (!create_popup) {
+       /*
+        * If we are not creating a popup, then we must be the "main" status
+        * window.
+        */
+       if (!parent)
+           panic("create_status_window: no parent for fancy status");
+       wp->status_information = 0;
+       wp->w = create_fancy_status(parent, (Widget) 0);
+       return;
+    }
+
+    wp->status_information =
+               (struct status_info_t *) alloc(sizeof(struct status_info_t));
+
+    init_text_buffer(&wp->status_information->text);
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNallowShellResize, False); num_args++;
+    XtSetArg(args[num_args], XtNinput, False);            num_args++;
+
+    wp->popup = parent = XtCreatePopupShell("status_popup",
+                                       topLevelShellWidgetClass,
+                                       toplevel, args, num_args);
+    /*
+     * If we're here, then this is an auxiliary status window.  If we're
+     * cancelled via a delete window message, we should just pop down.
+     */
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNdisplayCaret, False); num_args++;
+    XtSetArg(args[num_args], XtNscrollHorizontal,
+                                   XawtextScrollWhenNeeded);   num_args++;
+    XtSetArg(args[num_args], XtNscrollVertical,
+                                   XawtextScrollWhenNeeded);   num_args++;
+
+    wp->w = XtCreateManagedWidget(
+               "status",               /* name */
+               asciiTextWidgetClass,
+               parent,                 /* parent widget */
+               args,                   /* set some values */
+               num_args);              /* number of values to set */
+
+    /*
+     * Adjust the height and width of the message window so that it
+     * is two lines high and COLNO of the widest characters wide.
+     */
+
+    /* Get the font and margin information. */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNfont,        &fs);            num_args++;
+    XtSetArg(args[num_args], XtNtopMargin,    &top_margin);    num_args++;
+    XtSetArg(args[num_args], XtNbottomMargin, &bottom_margin); num_args++;
+    XtSetArg(args[num_args], XtNleftMargin,   &left_margin);   num_args++;
+    XtSetArg(args[num_args], XtNrightMargin,  &right_margin);  num_args++;
+    XtGetValues(wp->w, args, num_args);
+
+    wp->pixel_height = 2 * nhFontHeight(wp->w) + top_margin + bottom_margin;
+    wp->pixel_width  = COLNO * fs->max_bounds.width +
+                                               left_margin + right_margin;
+
+    /* Set the new width and height. */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNwidth,  wp->pixel_width);  num_args++;
+    XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++;
+    XtSetValues(wp->w, args, num_args);
+}
+
+void
+destroy_status_window(wp)
+    struct xwindow *wp;
+{
+    /* If status_information is defined, then it a "text" status window. */
+    if (wp->status_information) {
+       if (wp->popup) {
+           nh_XtPopdown(wp->popup);
+           if (!wp->keep_window)
+               XtDestroyWidget(wp->popup),  wp->popup = (Widget)0;
+       }
+       free((genericptr_t)wp->status_information);
+       wp->status_information = 0;
+    } else {
+       destroy_fancy_status(wp);
+    }
+    if (!wp->keep_window)
+       wp->type = NHW_NONE;
+}
+
+
+/*
+ * This assumes several things:
+ *     + Status has only 2 lines
+ *     + That both lines are updated in succession in line order.
+ *     + We didn't set stringInPlace on the widget.
+ */
+void
+adjust_status(wp, str)
+    struct xwindow *wp;
+    const char *str;
+{
+    Arg args[2];
+    Cardinal num_args;
+
+    if (!wp->status_information) {
+       update_fancy_status(wp);
+       return;
+    }
+
+    if (wp->cursy == 0) {
+       clear_text_buffer(&wp->status_information->text);
+       append_text_buffer(&wp->status_information->text, str, FALSE);
+       return;
+    }
+    append_text_buffer(&wp->status_information->text, str, FALSE);
+
+    /* Set new buffer as text. */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNstring, wp->status_information->text.text);
+                                                                   num_args++;
+    XtSetValues(wp->w, args, num_args);
+}
+
+
+/* Fancy Status -------------------------------------------------------------*/
+static int hilight_time = 1;   /* number of turns to hilight a changed value */
+
+struct X_status_value {
+    char    *name;             /* text name */
+    int     type;              /* status type */
+    Widget  w;                 /* widget of name/value pair */
+    long    last_value;                /* value displayed */
+    int            turn_count;         /* last time the value changed */
+    boolean set;               /* if hilighed */
+    boolean after_init;                /* don't hilight on first change (init) */
+};
+
+/* valid type values */
+#define SV_VALUE 0     /* displays a label:value pair */
+#define SV_LABEL 1     /* displays a changable label */
+#define SV_NAME  2     /* displays an unchangeable name */
+
+static void FDECL(hilight_label, (Widget));
+static void FDECL(update_val, (struct X_status_value *,long));
+static const char *FDECL(width_string, (int));
+static void FDECL(create_widget, (Widget,struct X_status_value *,int));
+static void FDECL(get_widths, (struct X_status_value *,int *,int *));
+static void FDECL(set_widths, (struct X_status_value *,int,int));
+static Widget FDECL(init_column, (char *,Widget,Widget,Widget,int *));
+static Widget FDECL(init_info_form, (Widget,Widget,Widget));
+
+/*
+ * Form entry storage indices.
+ */
+#define F_STR      0
+#define F_DEX      1
+#define F_CON      2
+#define F_INT      3
+#define F_WIS      4
+#define F_CHA      5
+
+#define F_NAME      6
+#define F_DLEVEL    7
+#define F_GOLD      8
+#define F_HP        9
+#define F_MAXHP           10
+#define F_POWER    11
+#define F_MAXPOWER 12
+#define F_AC      13
+#define F_LEVEL    14
+#define F_EXP      15
+#define F_ALIGN           16
+#define F_TIME     17
+#define F_SCORE           18
+
+#define F_HUNGER   19
+#define F_CONFUSED 20
+#define F_SICK    21
+#define F_BLIND           22
+#define F_STUNNED  23
+#define F_HALLU    24
+#define F_ENCUMBER 25
+
+#define NUM_STATS  26
+
+/*
+ * Notes:
+ * + Alignment needs a different init value, because -1 is an alignment.
+ * + Armor Class is an schar, so 256 is out of range.
+ * + Blank value is 0 and should never change.
+ */
+static struct X_status_value shown_stats[NUM_STATS] = {
+    { "Strength",      SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /* 0*/
+    { "Dexterity",     SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Constitution",  SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Intelligence",  SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Wisdom",                SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Charisma",      SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /* 5*/
+
+    { "",              SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* name */
+    { "",              SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* dlvl */
+    { "Gold",          SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Hit Points",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Max HP",                SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /*10*/
+    { "Power",         SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Max Power",     SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Armor Class",   SV_VALUE, (Widget) 0,256, 0, FALSE, FALSE },
+    { "Level",         SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Experience",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /*15*/
+    { "Alignment",     SV_VALUE, (Widget) 0, -2, 0, FALSE, FALSE },
+    { "Time",          SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+    { "Score",         SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
+
+    { "",              SV_NAME,  (Widget) 0, -1, 0, FALSE, TRUE }, /* hunger*/
+    { "Confused",      SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE },     /*20*/
+    { "",              SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE }, /* sick */
+    { "Blind",         SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE },
+    { "Stunned",       SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE },
+    { "Hallucinating", SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE },
+    { "",              SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE }, /*encumbr*/
+};
+
+
+/*
+ * Set all widget values to a null string.  This is used after all spacings
+ * have been calculated so that when the window is popped up we don't get all
+ * kinds of funny values being displayed.
+ */
+void
+null_out_status()
+{
+    int i;
+    struct X_status_value *sv;
+    Arg args[1];
+
+    for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) {
+       switch (sv->type) {
+           case SV_VALUE:
+               set_value(sv->w, "");
+               break;
+
+           case SV_LABEL:
+           case SV_NAME:
+               XtSetArg(args[0], XtNlabel, "");
+               XtSetValues(sv->w, args, ONE);
+               break;
+
+           default:
+               impossible("null_out_status: unknown type %d\n", sv->type);
+               break;
+       }
+    }
+}
+
+/* This is almost an exact duplicate of hilight_value() */
+static void
+hilight_label(w)
+    Widget w;  /* label widget */
+{
+    Arg args[2];
+    Pixel fg, bg;
+
+    XtSetArg(args[0], XtNforeground, &fg);
+    XtSetArg(args[1], XtNbackground, &bg);
+    XtGetValues(w, args, TWO);
+
+    XtSetArg(args[0], XtNforeground, bg);
+    XtSetArg(args[1], XtNbackground, fg);
+    XtSetValues(w, args, TWO);
+}
+
+
+static void
+update_val(attr_rec, new_value)
+    struct X_status_value *attr_rec;
+    long new_value;
+{
+    char buf[BUFSZ];
+    Arg args[4];
+
+    if (attr_rec->type == SV_LABEL) {
+
+       if (attr_rec == &shown_stats[F_NAME]) {
+
+           Strcpy(buf, plname);
+           if ('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A'-'a';
+           Strcat(buf, " the ");
+           if (u.mtimedone) {
+               char mname[BUFSZ];
+               int k = 0;
+
+               Strcpy(mname, mons[u.umonnum].mname);
+               while(mname[k] != 0) {
+                   if ((k == 0 || (k > 0 && mname[k-1] == ' ')) &&
+                                       'a' <= mname[k] && mname[k] <= 'z')
+                           mname[k] += 'A' - 'a';
+                   k++;
+               }
+               Strcat(buf, mname);
+           } else
+               Strcat(buf, rank_of(u.ulevel, pl_character[0], flags.female));
+
+       } else if (attr_rec == &shown_stats[F_DLEVEL]) {
+           if (!describe_level(buf)) {
+               Strcpy(buf, dungeons[u.uz.dnum].dname);
+               Sprintf(eos(buf), ", level %d", depth(&u.uz));
+           }
+       } else {
+           impossible("update_val: unknown label type \"%s\"",
+                                                       attr_rec->name);
+           return;
+       }
+
+       if (strcmp(buf, attr_rec->name) == 0) return;   /* same */
+
+       /* Set the label. */
+       Strcpy(attr_rec->name, buf);
+       XtSetArg(args[0], XtNlabel, buf);
+       XtSetValues(attr_rec->w, args, ONE);
+
+    } else if (attr_rec->type == SV_NAME) {
+
+       if (attr_rec->last_value == new_value) return;  /* no change */
+
+       attr_rec->last_value = new_value;
+
+       /* special cases: hunger, encumbrance, sickness */
+       if (attr_rec == &shown_stats[F_HUNGER]) {
+           XtSetArg(args[0], XtNlabel, hu_stat[new_value]);
+       } else if (attr_rec == &shown_stats[F_ENCUMBER]) {
+           XtSetArg(args[0], XtNlabel, enc_stat[new_value]);
+       } else if (attr_rec == &shown_stats[F_SICK]) {
+           buf[0] = 0;
+           if (Sick) {
+               if (u.usick_type & SICK_VOMITABLE)
+                   Strcat(buf, "FoodPois");
+               if (u.usick_type & SICK_NONVOMITABLE) {
+                   if (u.usick_type & SICK_VOMITABLE)
+                       Strcat(buf, " ");
+                   Strcat(buf, "Ill");
+               }
+           }
+           XtSetArg(args[0], XtNlabel, buf);
+       } else if (new_value) {
+           XtSetArg(args[0], XtNlabel, attr_rec->name);
+       } else {
+           XtSetArg(args[0], XtNlabel, "");
+       }
+       XtSetValues(attr_rec->w, args, ONE);
+
+    } else {   /* a value pair */
+       boolean force_update = FALSE;
+
+       /* special case: time can be enabled & disabled */
+       if (attr_rec == &shown_stats[F_TIME]) {
+           static boolean flagtime = TRUE;
+
+           if(flags.time && !flagtime) {
+               set_name(attr_rec->w, shown_stats[F_TIME].name);
+               force_update = TRUE;
+               flagtime = flags.time;
+           } else if(!flags.time && flagtime) {
+               set_name(attr_rec->w, "");
+               set_value(attr_rec->w, "");
+               flagtime = flags.time;
+           }
+           if(!flagtime) return;
+       }
+
+       /* special case: exp can be enabled & disabled */
+       else if (attr_rec == &shown_stats[F_EXP]) {
+           static boolean flagexp = TRUE;
+#ifdef EXP_ON_BOTL
+
+           if (flags.showexp && !flagexp) {
+               set_name(attr_rec->w, shown_stats[F_EXP].name);
+               force_update = TRUE;
+               flagexp = flags.showexp;
+           } else if(!flags.showexp && flagexp) {
+               set_name(attr_rec->w, "");
+               set_value(attr_rec->w, "");
+               flagexp = flags.showexp;
+           }
+           if (!flagexp) return;
+#else
+           if (flagexp) {
+               set_name(attr_rec->w, "");
+               set_value(attr_rec->w, "");
+               flagexp = FALSE;
+           }
+           return;     /* don't show it at all */
+#endif
+       }
+
+       /* special case: score can be enabled & disabled */
+       else if (attr_rec == &shown_stats[F_SCORE]) {
+           static boolean flagscore = TRUE;
+#ifdef SCORE_ON_BOTL
+
+           if(flags.showscore && !flagscore) {
+               set_name(attr_rec->w, shown_stats[F_SCORE].name);
+               force_update = TRUE;
+               flagscore = flags.showscore;
+           } else if(!flags.showscore && flagscore) {
+               set_name(attr_rec->w, "");
+               set_value(attr_rec->w, "");
+               flagscore = flags.showscore;
+           }
+           if(!flagscore) return;
+#else
+           if (flagscore) {
+               set_name(attr_rec->w, "");
+               set_value(attr_rec->w, "");
+               flagscore = FALSE;
+           }
+           return;
+#endif
+       }
+
+       /* special case: when polymorphed, show "HD", disable exp */
+       else if (attr_rec == &shown_stats[F_LEVEL]) {
+           static boolean lev_was_poly = FALSE;
+
+           if (u.mtimedone && !lev_was_poly) {
+               force_update = TRUE;
+               set_name(attr_rec->w, "HD");
+               lev_was_poly = TRUE;
+           } else if (!u.mtimedone && lev_was_poly) {
+               force_update = TRUE;
+               set_name(attr_rec->w, shown_stats[F_LEVEL].name);
+               lev_was_poly = FALSE;
+           }
+       } else if (attr_rec == &shown_stats[F_EXP]) {
+           static boolean exp_was_poly = FALSE;
+
+           if (u.mtimedone && !exp_was_poly) {
+               force_update = TRUE;
+               set_name(attr_rec->w, "");
+               set_value(attr_rec->w, "");
+               exp_was_poly = TRUE;
+           } else if (!u.mtimedone && exp_was_poly) {
+               force_update = TRUE;
+               set_name(attr_rec->w, shown_stats[F_EXP].name);
+               exp_was_poly = FALSE;
+           }
+           if (u.mtimedone) return;    /* no display for exp when poly */
+       }
+
+       if (attr_rec->last_value == new_value && !force_update) /* same */
+           return;
+
+       attr_rec->last_value = new_value;
+
+       /* Special cases: strength, alignment and "clear". */
+       if (attr_rec == &shown_stats[F_STR]) {
+           if(new_value > 18) {
+               if (new_value > 118)
+                   Sprintf(buf,"%ld", new_value-100);
+               else if(new_value < 118)
+                   Sprintf(buf, "18/%02ld", new_value-18);
+               else
+                   Strcpy(buf, "18/**");
+           } else {
+               Sprintf(buf, "%ld", new_value);
+           }
+       } else if (attr_rec == &shown_stats[F_ALIGN]) {
+
+           Strcpy(buf, (new_value == A_CHAOTIC) ? "Chaotic" :
+                       (new_value == A_NEUTRAL) ? "Neutral" :
+                                                  "Lawful"  );
+       } else {
+           Sprintf(buf, "%ld", new_value);
+       }
+       set_value(attr_rec->w, buf);
+    }
+
+    /*
+     * Now hilight the changed information.  Names, time and score don't
+     * hilight.  If first time, don't hilight.  If already lit, don't do
+     * it again.
+     */
+    if (attr_rec->type != SV_NAME && attr_rec != &shown_stats[F_TIME]) {
+       if (attr_rec->after_init) {
+           if(!attr_rec->set) {
+               if (attr_rec->type == SV_LABEL)
+                   hilight_label(attr_rec->w);
+               else
+                   hilight_value(attr_rec->w);
+               attr_rec->set = TRUE;
+           }
+           attr_rec->turn_count = 0;
+       } else {
+           attr_rec->after_init = TRUE;
+       }
+    }
+}
+
+/*
+ * Update the displayed status.  The current code in botl.c updates
+ * two lines of information.  Both lines are always updated one after
+ * the other.  So only do our update when we update the second line.
+ *
+ * Information on the first line:
+ *     name, attributes, alignment, score
+ *
+ * Information on the second line:
+ *     dlvl, gold, hp, power, ac, {level & exp or HD **}
+ *     status (hunger, conf, halu, stun, sick, blind), time, encumbrance
+ *
+ * [**] HD is shown instead of level and exp if mtimedone is non-zero.
+ */
+static void
+update_fancy_status(wp)
+    struct xwindow *wp;
+{
+    struct X_status_value *sv;
+    long val;
+    int i;
+
+    if (wp->cursy != 0) return;        /* do a complete update when line 0 is done */
+
+    for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) {
+       switch (i) {
+           case F_STR:         val = (long) ACURR(A_STR); break;
+           case F_DEX:         val = (long) ACURR(A_DEX); break;
+           case F_CON:         val = (long) ACURR(A_CON); break;
+           case F_INT:         val = (long) ACURR(A_INT); break;
+           case F_WIS:         val = (long) ACURR(A_WIS); break;
+           case F_CHA:         val = (long) ACURR(A_CHA); break;
+           /*
+            * Label stats.  With the exceptions of hunger, encumbrance, sick
+            * these are either on or off.  Pleae leave the ternary operators
+            * the way they are.  I want to specify 0 or 1, not a boolean.
+            */
+           case F_HUNGER:      val = (long) u.uhs;                     break;
+           case F_CONFUSED:    val = (long) Confusion     ? 1L : 0L;   break;
+           case F_SICK:        val = (long) Sick ? (long)u.usick_type
+                                                               : 0L;   break;
+           case F_BLIND:       val = (long) Blind         ? 1L : 0L;   break;
+           case F_STUNNED:     val = (long) Stunned       ? 1L : 0L;   break;
+           case F_HALLU:       val = (long) Hallucination ? 1L : 0L;   break;
+           case F_ENCUMBER:    val = (long) near_capacity();           break;
+
+           case F_NAME:        val = (long) 0L; break; /* special */
+           case F_DLEVEL:      val = (long) 0L; break; /* special */
+#ifndef GOLDOBJ
+           case F_GOLD:        val = (long) u.ugold; break;
+#else
+           case F_GOLD:        val = money_cnt(invent); break;
+#endif
+           case F_HP:          val = (long) (u.mtimedone ?
+                                             (u.mh  > 0 ? u.mh  : 0):
+                                             (u.uhp > 0 ? u.uhp : 0)); break;
+           case F_MAXHP:       val = (long) (u.mtimedone ? u.mhmax :
+                                                           u.uhpmax);  break;
+           case F_POWER:       val = (long) u.uen;     break;
+           case F_MAXPOWER:    val = (long) u.uenmax;  break;
+           case F_AC:          val = (long) u.uac;     break;
+           case F_LEVEL:       val = (long) (u.mtimedone ?
+                                               mons[u.umonnum].mlevel :
+                                               u.ulevel);              break;
+#ifdef EXP_ON_BOTL
+           case F_EXP:         val = flags.showexp ? u.uexp : 0L; break;
+#else
+           case F_EXP:         val = 0L; break;
+#endif
+           case F_ALIGN:       val = (long) u.ualign.type; break;
+           case F_TIME:        val = flags.time ? (long) moves : 0L;   break;
+#ifdef SCORE_ON_BOTL
+           case F_SCORE:       val = flags.showscore ? botl_score():0L; break;
+#else
+           case F_SCORE:       val = 0L; break;
+#endif
+           default:
+           {
+               /*
+                * There is a possible infinite loop that occurs with:
+                *
+                *      impossible->pline->flush_screen->bot->bot{1,2}->
+                *      putstr->adjust_status->update_other->impossible
+                *
+                * Break out with this.
+                */
+               static boolean active = FALSE;
+               if (!active) {
+                   active = TRUE;
+                   impossible("update_other: unknown shown value");
+                   active = FALSE;
+               }
+               val = 0;
+               break;
+           }
+       }
+       update_val(sv, val);
+    }
+}
+
+/*
+ * Turn off hilighted status values after a certain amount of turns.
+ */
+void
+check_turn_events()
+{
+    int i;
+    struct X_status_value *sv;
+
+    for (sv = shown_stats, i = 0; i < NUM_STATS; i++, sv++) {
+       if (!sv->set) continue;
+
+       if (sv->turn_count++ >= hilight_time) {
+           if (sv->type == SV_LABEL)
+               hilight_label(sv->w);
+           else
+               hilight_value(sv->w);
+           sv->set = FALSE;
+       }
+    }
+}
+
+/* Initialize alternate status ============================================= */
+
+/* Return a string for the initial width. */
+static const char *
+width_string(sv_index)
+    int sv_index;
+{
+    switch (sv_index) {
+       case F_STR:     return "018/**";
+       case F_DEX:
+       case F_CON:
+       case F_INT:
+       case F_WIS:
+       case F_CHA:     return "088";   /* all but str never get bigger */
+
+       case F_HUNGER:  return shown_stats[F_HUNGER].name;
+       case F_CONFUSED:return shown_stats[F_CONFUSED].name;
+       case F_SICK:    return shown_stats[F_SICK].name;
+       case F_BLIND:   return shown_stats[F_BLIND].name;
+       case F_STUNNED: return shown_stats[F_STUNNED].name;
+       case F_HALLU:   return shown_stats[F_HALLU].name;
+       case F_ENCUMBER:return shown_stats[F_ENCUMBER].name;
+
+       case F_NAME:
+       case F_DLEVEL:  return "";
+       case F_HP:
+       case F_MAXHP:   return "9999";
+       case F_POWER:
+       case F_MAXPOWER:return "999";
+       case F_AC:      return "-99";
+       case F_LEVEL:   return "99";
+       case F_GOLD:
+       case F_EXP:     return "4294967295";    /* max ulong */
+       case F_ALIGN:   return "Neutral";
+       case F_TIME:    return "4294967295";    /* max ulong */
+       case F_SCORE:   return "4294967295";    /* max ulong */
+    }
+    impossible("width_string: unknown index %d\n", sv_index);
+    return "";
+}
+
+static void
+create_widget(parent, sv, sv_index)
+    Widget parent;
+    struct X_status_value *sv;
+    int sv_index;
+{
+    Arg args[4];
+    Cardinal num_args;
+
+    switch (sv->type) {
+       case SV_VALUE:
+           sv->w = create_value(parent, sv->name);
+           set_value(sv->w, width_string(sv_index));
+           break;
+       case SV_LABEL:
+           /* Labels get their own buffer. */
+           sv->name = (char *) alloc(BUFSZ);
+           sv->name[0] = '\0';
+
+           num_args = 0;
+           XtSetArg(args[num_args], XtNborderWidth, 0);        num_args++;
+           XtSetArg(args[num_args], XtNinternalHeight, 0);     num_args++;
+           sv->w = XtCreateManagedWidget(
+                               sv_index == F_NAME ? "name" : "dlevel",
+                               labelWidgetClass,
+                               parent,
+                               args, num_args);
+           break;
+       case SV_NAME:
+           num_args = 0;
+           XtSetArg(args[num_args], XtNborderWidth, 0);        num_args++;
+           XtSetArg(args[num_args], XtNinternalHeight, 0);     num_args++;
+           sv->w = XtCreateManagedWidget(sv->name,
+                                       labelWidgetClass,
+                                       parent,
+                                       args, num_args);
+           break;
+       default:
+           panic("create_widget: unknown type %d", sv->type);
+    }
+}
+
+/*
+ * Get current width of value.  width2p is only valid for SV_LABEL types.
+ */
+static void
+get_widths(sv, width1p, width2p)
+    struct X_status_value *sv;
+    int *width1p, *width2p;
+{
+    Arg args[1];
+    Dimension width;
+
+    switch (sv->type) {
+       case SV_VALUE:
+           *width1p = get_name_width(sv->w);
+           *width2p = get_value_width(sv->w);
+           break;
+       case SV_LABEL:
+       case SV_NAME:
+           XtSetArg(args[0], XtNwidth, &width);
+           XtGetValues(sv->w, args, ONE);
+           *width1p = width;
+           *width2p = 0;
+           break;
+       default:
+           panic("get_widths: unknown type %d", sv->type);
+    }
+}
+
+static void
+set_widths(sv, width1, width2)
+    struct X_status_value *sv;
+    int width1, width2;
+{
+    Arg args[1];
+
+    switch (sv->type) {
+       case SV_VALUE:
+           set_name_width(sv->w, width1);
+           set_value_width(sv->w, width2);
+           break;
+       case SV_LABEL:
+       case SV_NAME:
+           XtSetArg(args[0], XtNwidth, (width1+width2));
+           XtSetValues(sv->w, args, ONE);
+           break;
+       default:
+           panic("set_widths: unknown type %d", sv->type);
+    }
+}
+
+static Widget
+init_column(name, parent, top, left, col_indices)
+    char *name;
+    Widget parent, top, left;
+    int *col_indices;
+{
+    Widget form;
+    Arg args[4];
+    Cardinal num_args;
+    int max_width1, width1, max_width2, width2;
+    int *ip;
+    struct X_status_value *sv;
+
+    num_args = 0;
+    if (top != (Widget) 0) {
+       XtSetArg(args[num_args], XtNfromVert, top);             num_args++;
+    }
+    if (left != (Widget) 0) {
+       XtSetArg(args[num_args], XtNfromHoriz, left);   num_args++;
+    }
+    XtSetArg(args[num_args], XtNdefaultDistance, 0);   num_args++;
+    form = XtCreateManagedWidget(name,
+                               formWidgetClass,
+                               parent, args, num_args);
+
+    max_width1 = max_width2 = 0;
+    for (ip = col_indices; *ip >= 0; ip++) {
+       sv = &shown_stats[*ip];
+       create_widget(form, sv, *ip);   /* will set init width */
+       if (ip != col_indices) {        /* not first */
+           num_args = 0;
+           XtSetArg(args[num_args], XtNfromVert, shown_stats[*(ip-1)].w);
+                                                               num_args++;
+           XtSetValues(sv->w, args, num_args);
+       }
+       get_widths(sv, &width1, &width2);
+       if (width1 > max_width1) max_width1 = width1;
+       if (width2 > max_width2) max_width2 = width2;
+    }
+    for (ip = col_indices; *ip >= 0 ; ip++) {
+       set_widths(&shown_stats[*ip], max_width1, max_width2);
+    }
+
+    /* There is room behind the end marker for the two widths. */
+    *++ip = max_width1;
+    *++ip = max_width2;
+
+    return form;
+}
+
+/*
+ * These are the orders of the displayed columns.  Change to suit.  The -1
+ * indicates the end of the column.  The two numbers after that are used
+ * to store widths that are calculated at run-time.
+ */
+static int attrib_indices[] = { F_STR,F_DEX,F_CON,F_INT,F_WIS,F_CHA, -1,0,0 };
+static int status_indices[] = { F_HUNGER, F_CONFUSED, F_SICK, F_BLIND,
+                               F_STUNNED, F_HALLU, F_ENCUMBER, -1,0,0 };
+
+static int col2_indices[] = { F_MAXHP,    F_ALIGN, F_TIME, F_EXP,
+                             F_MAXPOWER, -1,0,0 };
+static int col1_indices[] = { F_HP,       F_AC,    F_GOLD, F_LEVEL,
+                             F_POWER,    F_SCORE, -1,0,0 };
+
+
+/*
+ * Produce a form that looks like the following:
+ *
+ *                name
+ *               dlevel
+ * col1_indices[0]     col2_indices[0]
+ * col1_indices[1]     col2_indices[1]
+ *    .                    .
+ *    .                    .
+ * col1_indices[n]     col2_indices[n]
+ */
+static Widget
+init_info_form(parent, top, left)
+    Widget parent, top, left;
+{
+    Widget form, col1;
+    struct X_status_value *sv_name, *sv_dlevel;
+    Arg args[6];
+    Cardinal num_args;
+    int total_width, *ip;
+
+    num_args = 0;
+    if (top != (Widget) 0) {
+       XtSetArg(args[num_args], XtNfromVert, top);     num_args++;
+    }
+    if (left != (Widget) 0) {
+       XtSetArg(args[num_args], XtNfromHoriz, left);   num_args++;
+    }
+    XtSetArg(args[num_args], XtNdefaultDistance, 0);   num_args++;
+    form = XtCreateManagedWidget("status_info",
+                               formWidgetClass,
+                               parent,
+                               args, num_args);
+
+    /* top of form */
+    sv_name = &shown_stats[F_NAME];
+    create_widget(form, sv_name, F_NAME);
+
+    /* second */
+    sv_dlevel = &shown_stats[F_DLEVEL];
+    create_widget(form, sv_dlevel, F_DLEVEL);
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNfromVert, sv_name->w); num_args++;
+    XtSetValues(sv_dlevel->w, args, num_args);
+
+    /* two columns beneath */
+    col1 = init_column("name_col1", form, sv_dlevel->w,
+                                               (Widget) 0, col1_indices);
+    (void) init_column("name_col2", form, sv_dlevel->w,
+                                                     col1, col2_indices);
+
+    /* Add calculated widths. */
+    for (ip = col1_indices; *ip >= 0; ip++)
+       ;       /* skip to end */
+    total_width = *++ip;
+    total_width += *++ip;
+    for (ip = col2_indices; *ip >= 0; ip++)
+       ;       /* skip to end */
+    total_width += *++ip;
+    total_width += *++ip;
+
+    XtSetArg(args[0], XtNwidth, total_width);
+    XtSetValues(sv_name->w,   args, ONE);
+    XtSetArg(args[0], XtNwidth, total_width);
+    XtSetValues(sv_dlevel->w, args, ONE);
+
+    return form;
+}
+
+/*
+ * Create the layout for the fancy status.  Return a form widget that
+ * contains everything.
+ */
+static Widget
+create_fancy_status(parent, top)
+    Widget parent, top;
+{
+    Widget form;       /* The form that surrounds everything. */
+    Widget w;
+    Arg args[8];
+    Cardinal num_args;
+
+    num_args = 0;
+    if (top != (Widget) 0) {
+       XtSetArg(args[num_args], XtNfromVert, top);     num_args++;
+    }
+    XtSetArg(args[num_args], XtNdefaultDistance, 0);   num_args++;
+    XtSetArg(args[num_args], XtNborderWidth, 0);       num_args++;
+    XtSetArg(args[num_args], XtNorientation, XtorientHorizontal); num_args++;
+    form = XtCreateManagedWidget("fancy_status",
+                               panedWidgetClass,
+                               parent,
+                               args, num_args);
+
+    w = init_info_form(form, (Widget) 0, (Widget) 0);
+    w =    init_column("status_attributes",form, (Widget) 0, w, attrib_indices);
+    (void) init_column("status_condition", form, (Widget) 0, w, status_indices);
+    return form;
+}
+
+static void
+destroy_fancy_status(wp)
+struct xwindow *wp;
+{
+    int i;
+    struct X_status_value *sv;
+
+    if (!wp->keep_window)
+       XtDestroyWidget(wp->w),  wp->w = (Widget)0;
+
+    for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++)
+       if (sv->type == SV_LABEL) {
+           free((genericptr_t)sv->name);
+           sv->name = 0;
+       }
+}
+
+/*winstat.c*/