diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 8e0d72f85..8ebe6bb2d 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -126,6 +126,7 @@ msdos: Add -DSTATUES_LOOK_LIKE_MONSTERS to Makefile1.cross so the VESA mode tty: role and race selection menus weren't filtering out potential choices which got excluded by OPTIONS=align:!lawful or !neutral or !chaotic windows: update for new status condition fields +X11: substantial overhaul of status display, both 'fancy' and 'tty-style' General New Features diff --git a/include/winX.h b/include/winX.h index 56aafedd1..fe7f63b56 100644 --- a/include/winX.h +++ b/include/winX.h @@ -115,10 +115,18 @@ struct mesg_info_t { }; /* - * Information specific to a "text" status window. + * Information specific to "fancy", "text", or "tty-style" status window. + * (Tty-style supports status highlighting and effectively makes "text" + * obsolete.) */ struct status_info_t { struct text_buffer text; /* Just a text buffer. */ + Pixel fg, bg; /* foreground and background */ + XFontStruct *fs; /* Status window font structure. */ + Dimension spacew; /* width of one space */ + Position x, y[3]; /* x coord (not used), y for up to three lines */ + Dimension wd, ht; /* width (not used), height (same for all lines) */ + Dimension brd, in_wd; /* border width, internal width */ }; /* @@ -285,11 +293,12 @@ E void (*input_func)(); extern struct window_procs X11_procs; /* Check for an invalid window id. */ -#define check_winid(window) \ - if ((window) < 0 || (window) >= MAX_WINDOWS) { \ - panic("illegal windid [%d] in %s at line %d", window, __FILE__, \ - __LINE__); \ - } +#define check_winid(window) \ + do { \ + if ((window) < 0 || (window) >= MAX_WINDOWS) \ + panic("illegal windid [%d] in %s at line %d", \ + window, __FILE__, __LINE__); \ + } while (0) /* ### dialogs.c ### */ E Widget @@ -442,8 +451,10 @@ E void FDECL(X11_number_pad, (int)); E void NDECL(X11_delay_output); E void NDECL(X11_status_init); E void NDECL(X11_status_finish); -E void FDECL(X11_status_enablefield, (int, const char *, const char *, BOOLEAN_P)); -E void FDECL(X11_status_update, (int, genericptr_t, int, int, int, unsigned long *)); +E void FDECL(X11_status_enablefield, (int, const char *, const char *, + BOOLEAN_P)); +E void FDECL(X11_status_update, (int, genericptr_t, int, int, int, + unsigned long *)); /* other defs that really should go away (they're tty specific) */ E void NDECL(X11_start_screen); diff --git a/win/X11/winX.c b/win/X11/winX.c index c7afa415f..e2fff7c7b 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -98,13 +98,15 @@ static XtSignalId X11_sig_id; /* Interface definition, for windows.c */ struct window_procs X11_procs = { "X11", - (WC_COLOR | WC_HILITE_PET | WC_ASCII_MAP | WC_TILED_MAP - | WC_PLAYER_SELECTION | WC_PERM_INVENT | WC_MOUSE_SUPPORT), -#if defined(STATUS_HILITES) - WC2_FLUSH_STATUS | WC2_RESET_STATUS | WC2_HILITE_STATUS | + ( WC_COLOR | WC_HILITE_PET | WC_ASCII_MAP | WC_TILED_MAP + | WC_PLAYER_SELECTION | WC_PERM_INVENT | WC_MOUSE_SUPPORT ), + /* status requires VIA_WINDOWPORT(); WC2_FLUSH_STATUS ensures that */ + ( WC2_FLUSH_STATUS +#ifdef STATUS_HILITES + | WC2_RESET_STATUS | WC2_HILITE_STATUS #endif - 0L, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ + | 0L ), + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ X11_init_nhwindows, X11_player_selection, X11_askname, X11_get_nh_event, X11_exit_nhwindows, X11_suspend_nhwindows, X11_resume_nhwindows, X11_create_nhwindow, @@ -300,6 +302,9 @@ struct xwindow *wp; XtNbright_cyan, XtNwhite, }; + static const char *wintypenames[NHW_TEXT] = { + "message", "status", "map", "menu", "text" + }; Display *dpy; Colormap screen_colormap; XrmDatabase rDB; @@ -307,13 +312,8 @@ struct xwindow *wp; Status rc; int color; char *ret_type[32]; - char clr_name[BUFSZ]; - char clrclass[BUFSZ]; - const char *wintypenames[NHW_TEXT] = { - "message", "status", "map", "menu", "text" - }; + char wtn_up[20], clr_name[BUFSZ], clrclass[BUFSZ]; const char *wtn; - char wtn_up[BUFSZ]; if (wp->nh_colors_inited || !wp->type) return; @@ -1414,7 +1414,8 @@ static XtActionsRec actions[] = { static XtResource resources[] = { { nhStr("slow"), nhStr("Slow"), XtRBoolean, sizeof(Boolean), XtOffset(AppResources *, slow), XtRString, nhStr("True") }, - { nhStr("fancy_status"), nhStr("Fancy_status"), XtRBoolean, sizeof(Boolean), + { nhStr("fancy_status"), nhStr("Fancy_status"), + XtRBoolean, sizeof(Boolean), XtOffset(AppResources *, fancy_status), XtRString, nhStr("True") }, { nhStr("autofocus"), nhStr("AutoFocus"), XtRBoolean, sizeof(Boolean), XtOffset(AppResources *, autofocus), XtRString, nhStr("False") }, @@ -1469,10 +1470,10 @@ XErrorEvent *error; { char buf[BUFSZ]; XGetErrorText(display, error->error_code, buf, BUFSZ); - fprintf(stderr, "X Error: code %i (%s), request %i, minor %i, serial %lu\n", + fprintf(stderr, + "X Error: code %i (%s), request %i, minor %i, serial %lu\n", error->error_code, buf, - error->request_code, error->minor_code, - error->serial); + error->request_code, error->minor_code, error->serial); panic("X Error"); return 0; } @@ -2289,8 +2290,8 @@ static int input_event(exit_condition) int exit_condition; { - if (appResources.fancy_status && WIN_STATUS != WIN_ERR) /* hilighting on the fancy status window */ - check_turn_events(); + if (appResources.fancy_status && WIN_STATUS != WIN_ERR) + check_turn_events(); /* hilighting on the fancy status window */ if (WIN_MAP != WIN_ERR) /* make sure cursor is not clipped */ check_cursor_visibility(&window_list[WIN_MAP]); if (WIN_MESSAGE != WIN_ERR) /* reset pause line */ diff --git a/win/X11/winstat.c b/win/X11/winstat.c index 9dc5ac09c..965d3859c 100644 --- a/win/X11/winstat.c +++ b/win/X11/winstat.c @@ -15,16 +15,16 @@ #endif #include -#include +#include /* for XtResizeWidget() and XtConfigureWidget() */ #include #include #include -#include +#include /* just for ONE, TWO */ #include #include #include #include -#include +/*#include */ #ifdef PRESERVE_NO_SYSV #ifdef SYSV @@ -48,43 +48,63 @@ #define F_WIS 5 #define F_CHA 6 -#define F_NAME 7 -#define F_DLEVEL 8 +#define F_NAME 7 /* title: "Name the Rank" where rank is role-specific */ +#define F_DLEVEL 8 /* location: dungeon branch and level */ #define F_GOLD 9 #define F_HP 10 #define F_MAXHP 11 #define F_POWER 12 #define F_MAXPOWER 13 #define F_AC 14 -#define F_LEVEL 15 -#define F_EXP 16 +#define F_XP_LEVL 15 +/*#define F_HD F_XP_LEVL*/ +#define F_EXP_PTS 16 #define F_ALIGN 17 #define F_TIME 18 #define F_SCORE 19 -/* status conditions grouped by columns; tty orders these differently */ -#define F_STONE 20 -#define F_SLIME 21 -#define F_STRNGL 22 -#define F_FOODPOIS 23 -#define F_TERMILL 24 +/* status conditions grouped by columns; tty orders these differently; + hunger/encumbrance/movement used to be in the middle with fatal + conditions on the left but those columns have been swapped and + renumbered to match new order (forcing shown_stat[] to be reordered) */ +#define F_HUNGER 20 +#define F_ENCUMBER 21 +#define F_TRAPPED 22 +#define F_LEV 23 +#define F_FLY 24 +#define F_RIDE 25 -#define F_HUNGER 25 -#define F_ENCUMBER 26 -#define F_LEV 27 -#define F_FLY 28 -#define F_RIDE 29 +#define F_GRABBED 26 +#define F_STONE 27 +#define F_SLIME 28 +#define F_STRNGL 29 +#define F_FOODPOIS 30 +#define F_TERMILL 31 +#define F_IN_LAVA 32 -#define F_BLIND 30 -#define F_DEAF 31 -#define F_STUN 32 -#define F_CONF 33 -#define F_HALLU 34 +#define F_HELD 33 +#define F_BLIND 34 +#define F_DEAF 35 +#define F_STUN 36 +#define F_CONF 37 +#define F_HALLU 38 -#define NUM_STATS 35 +#define NUM_STATS 39 -static void FDECL(update_fancy_status, (struct xwindow *)); +static int FDECL(condcolor, (long, unsigned long *)); +static int FDECL(condattr, (long, unsigned long *)); +static void FDECL(HiliteField, (Widget, int, int, int, XFontStruct **)); +static void FDECL(PrepStatusField, (int, Widget, const char *)); +static void FDECL(DisplayCond, (int, unsigned long *)); +static int FDECL(render_conditions, (int, int)); +#ifdef STATUS_HILITES +static void FDECL(tt_reset_color, (int, int, unsigned long *)); +#endif +static void NDECL(tt_status_fixup); +static Widget FDECL(create_tty_status_field, (int, int, Widget, Widget)); +static Widget FDECL(create_tty_status, (Widget, Widget)); static void FDECL(update_fancy_status_field, (int)); +static void FDECL(update_fancy_status, (BOOLEAN_P)); static Widget FDECL(create_fancy_status, (Widget, Widget)); static void FDECL(destroy_fancy_status, (struct xwindow *)); static void FDECL(create_status_window_fancy, (struct xwindow *, @@ -99,14 +119,21 @@ static void FDECL(adjust_status_tty, (struct xwindow *, const char *)); extern const char *status_fieldfmt[MAXBLSTATS]; extern char *status_vals[MAXBLSTATS]; extern boolean status_activefields[MAXBLSTATS]; -static long X11_condition_bits; -static int X11_status_colors[MAXBLSTATS]; -static int hpbar_percent, hpbar_color; +static unsigned long X11_condition_bits, old_condition_bits; +static int X11_status_colors[MAXBLSTATS], + old_field_colors[MAXBLSTATS], + old_cond_colors[32]; +static int hpbar_percent, hpbar_color; +/* Number of conditions displayed during this update and last update. + When the last update had more, the excess need to be erased. */ +static int next_cond_indx = 0, prev_cond_indx = 0; + +/* TODO: support statuslines:3 in addition to 2 for the tty-style status */ #define X11_NUM_STATUS_LINES 2 #define X11_NUM_STATUS_FIELD 15 -static enum statusfields X11_fieldorder[X11_NUM_STATUS_LINES][X11_NUM_STATUS_FIELD] = { +static enum statusfields X11_fieldorder[][X11_NUM_STATUS_FIELD] = { { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH }, @@ -115,15 +142,39 @@ static enum statusfields X11_fieldorder[X11_NUM_STATUS_LINES][X11_NUM_STATUS_FIE BL_CAP, BL_CONDITION, BL_FLUSH } }; +/* condition list for tty-style display, roughly in order of importance */ +static struct tt_condinfo { + unsigned long mask; + const char *text; +} tt_condorder[] = { + { BL_MASK_GRAB, "Grab!" }, + { BL_MASK_STONE, "Stone" }, + { BL_MASK_SLIME, "Slime" }, + { BL_MASK_STRNGL, "Strngl" }, + { BL_MASK_FOODPOIS, "FoodPois" }, + { BL_MASK_TERMILL, "TermIll" }, + { BL_MASK_INLAVA, "Lava" }, + { BL_MASK_HELD, "Held" }, + { BL_MASK_BLIND, "Blind" }, + { BL_MASK_DEAF, "Deaf" }, + { BL_MASK_STUN, "Stun" }, + { BL_MASK_CONF, "Conf" }, + { BL_MASK_HALLU, "Hallu" }, + { BL_MASK_TRAPPED, "Trap" }, + { BL_MASK_LEV, "Lev" }, + { BL_MASK_FLY, "Fly" }, + { BL_MASK_RIDE, "Ride" }, +}; + static Widget X11_status_widget; static Widget X11_status_labels[MAXBLSTATS]; static Widget X11_cond_labels[32]; /* Ugh */ +static XFontStruct *X11_status_font; +static Pixel X11_status_fg, X11_status_bg; struct xwindow *xw_status_win; -static Pixel X11_status_widget_fg, X11_status_widget_bg; - -int +static int condcolor(bm, bmarray) long bm; unsigned long *bmarray; @@ -138,7 +189,7 @@ unsigned long *bmarray; return NO_COLOR; } -int +static int condattr(bm, bmarray) long bm; unsigned long *bmarray; @@ -175,14 +226,15 @@ unsigned long *bmarray; void X11_status_init() { -#ifdef STATUS_HILITES int i; + /* no color and no attributes */ for (i = 0; i < MAXBLSTATS; ++i) - X11_status_colors[i] = NO_COLOR; /* no color */ - X11_condition_bits = 0L; + X11_status_colors[i] = old_field_colors[i] = NO_COLOR; + for (i = 0; i < SIZE(old_cond_colors); ++i) + old_cond_colors[i] = NO_COLOR; hpbar_percent = 0, hpbar_color = NO_COLOR; -#endif /* STATUS_HILITES */ + X11_condition_bits = old_condition_bits = 0L; /* let genl_status_init do most of the initialization */ genl_status_init(); } @@ -191,6 +243,7 @@ void X11_status_finish() { /* nothing */ + return; } void @@ -203,335 +256,561 @@ boolean enable; genl_status_enablefield(fieldidx, nm, fmt, enable); } - +#if 0 int cond_bm2idx(bm) unsigned long bm; { int i; + for (i = 0; i < 32; i++) if ((1 << i) == bm) return i; return -1; } +#endif -void -MaybeDisplayCond(bm, colormasks, text) -unsigned long bm; -unsigned long *colormasks; -const char *text; +/* highlight a tty-style status field (or condition) */ +static void +HiliteField(label, fld, cond, colrattr, font_p) +Widget label; +int fld, cond, colrattr; +XFontStruct **font_p; { - int idx = cond_bm2idx(bm); - Widget label; - Arg args[10]; +#ifdef STATUS_HILITES + static Pixel grayPxl, blackPxl, whitePxl; + Arg args[6]; Cardinal num_args; - Pixel fg = X11_status_widget_fg, bg = X11_status_widget_bg; - Dimension lbl_wid; - Dimension lbl_hei; - Dimension lbl_border_wid; - Dimension lbl_iwidth; - - if (idx < 0) - return; - - label = X11_cond_labels[idx]; - if ((X11_condition_bits & bm) != 0) { - int attrmask, coloridx; - XFontStruct *font; - Position lbl_x; - Position lbl_y; + XFontStruct *font = X11_status_font; + Pixel px, fg = X11_status_fg, bg = X11_status_bg; + struct xwindow *xw = xw_status_win; + int colr, attr; #ifdef TEXTCOLOR - coloridx = condcolor(bm, colormasks); -#else - coloridx = NO_COLOR; + if ((colrattr & 0x00ff) >= CLR_MAX) + /* for !TEXTCOLOR, the following line is unconditional */ #endif - attrmask = condattr(bm, colormasks); - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNfont), &font); num_args++; - XtSetArg(args[num_args], nhStr(XtNx), &lbl_x); num_args++; - XtSetArg(args[num_args], nhStr(XtNy), &lbl_y); num_args++; - XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++; - XtSetArg(args[num_args], nhStr(XtNheight), &lbl_hei); num_args++; - XtSetArg(args[num_args], nhStr(XtNinternalWidth), - &lbl_iwidth); num_args++; - XtSetArg(args[num_args], nhStr(XtNborderWidth), - &lbl_border_wid); num_args++; - XtGetValues(label, args, num_args); + colrattr = (colrattr & ~0x00ff) | NO_COLOR; + colr = colrattr & 0x00ff; /* guaranteed to be >= 0 and < CLR_MAX */ + attr = (colrattr >> 8) & 0x00ff; - if (text && *text) - lbl_wid = lbl_iwidth + font->max_bounds.width * strlen(text); - else - lbl_wid = 1; - - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNlabel), - (text && *text) ? text : ""); num_args++; - XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++; - - fg = (coloridx != NO_COLOR) - ? get_nhcolor(xw_status_win, coloridx).pixel - : X11_status_widget_fg; - if (attrmask & HL_INVERSE) { - Pixel tmppx = fg; - - fg = bg; - bg = tmppx; - } - - if (attrmask & HL_BOLD) { - load_boldfont(xw_status_win, label); - XtSetArg(args[num_args], nhStr(XtNfont), - xw_status_win->boldfs); num_args++; - } - - if (fg == bg) - fg = get_nhcolor(xw_status_win, CLR_GRAY).pixel; - - XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++; - XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++; - XtSetValues(label, args, num_args); - XtResizeWidget(label, lbl_wid, lbl_hei, lbl_border_wid); - } else { - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++; - XtSetArg(args[num_args], nhStr(XtNheight), &lbl_hei); num_args++; - XtSetArg(args[num_args], nhStr(XtNinternalWidth), - &lbl_iwidth); num_args++; - XtSetArg(args[num_args], nhStr(XtNborderWidth), - &lbl_border_wid); num_args++; - XtGetValues(label, args, num_args); - - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNlabel), ""); num_args++; - XtSetArg(args[num_args], nhStr(XtNwidth), 1); num_args++; - XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++; - XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++; - XtSetValues(label, args, num_args); - - XtResizeWidget(label, lbl_wid, lbl_hei, lbl_border_wid); + /* potentially used even for !TEXTCOLOR configuration */ + if (!grayPxl) {/* one-time init */ + grayPxl = get_nhcolor(xw, CLR_GRAY).pixel; + blackPxl = get_nhcolor(xw, CLR_BLACK).pixel; + whitePxl = get_nhcolor(xw, CLR_WHITE).pixel; } + /* [shouldn't be necessary; setting up gray will set up all colors] */ + if (colr != NO_COLOR && !xw->nh_colors[colr].pixel) + (void) get_nhcolor(xw, colr); + + /* handle highlighting if caller has specified that; set foreground, + background, and font even if not specified this time in case they + used modified values last time (which would stick if not reset) */ + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + if (colr != NO_COLOR) + fg = xw->nh_colors[colr].pixel; + if ((attr & HL_INVERSE) != 0) { + px = fg; + fg = bg; + bg = px; + } + /* foreground and background might both default to black, so we + need to force one to be different if/when they're the same + (actually, tt_status_fixup() takes care of that nowadays); + using gray to implement 'dim' only works for black and white + (or color+'inverse' when former background was black or white) */ + if (fg == bg + || ((attr & HL_DIM) != 0 && (fg == whitePxl || fg == blackPxl))) + fg = (fg != grayPxl) ? grayPxl + : (fg != blackPxl) ? blackPxl + : whitePxl; + XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++; + XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++; + if (attr & HL_BOLD) { + load_boldfont(xw_status_win, label); + if (xw_status_win->boldfs) + font = xw_status_win->boldfs; + } + XtSetArg(args[num_args], nhStr(XtNfont), font); num_args++; + XtSetValues(label, args, num_args); + + /* return possibly modified font to caller so that text width + measurement can use it */ + if (font_p) + *font_p = font; +#else /*!STATUS_HILITES*/ + nhUse(label); + nhUse(font_p); +#endif /*?STATUS_HILITES*/ + if (fld != BL_CONDITION) + old_field_colors[fld] = colrattr; + else + old_cond_colors[cond] = colrattr; } +/* set up a specific field other than 'condition'; its general location + was specified during widget creation but it might need adjusting */ +static void +PrepStatusField(fld, label, text) +int fld; +Widget label; +const char *text; +{ + Arg args[6]; + Cardinal num_args; + Dimension lbl_wid; + XFontStruct *font = X11_status_font; + int colrattr = X11_status_colors[fld]; + struct status_info_t *si = xw_status_win->Win_info.Status_info; -void + /* highlight if color and/or attribute(s) are different from last time */ + if (colrattr != old_field_colors[fld]) + HiliteField(label, fld, 0, colrattr, &font); + + num_args = 0; + (void) memset((genericptr_t) args, 0, sizeof args); + /* set up the current text to be displayed */ + if (text && *text) { + lbl_wid = 2 * si->in_wd + XTextWidth(font, text, (int) strlen(text)); + } else { + text = ""; + lbl_wid = 1; + } + XtSetArg(args[num_args], nhStr(XtNlabel), text); num_args++; + /*XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++;*/ + XtSetValues(label, args, num_args); + XtResizeWidget(label, lbl_wid, si->ht, si->brd); +} + +/* set up one status condition for tty-style status display */ +static void +DisplayCond(c_idx, colormasks) +int c_idx; /* index into tt_condorder[] */ +unsigned long *colormasks; +{ + Widget label; + Arg args[6]; + Cardinal num_args; + Dimension lbl_wid; + XFontStruct *font = X11_status_font; + int coloridx, attrmask, colrattr, idx; + unsigned long bm = tt_condorder[c_idx].mask; + const char *text = tt_condorder[c_idx].text; + struct status_info_t *si = xw_status_win->Win_info.Status_info; + + if ((X11_condition_bits & bm) == 0) + return; + + /* widgets have been created for every condition; we allocate them + from left to right rather than keeping their original assignments */ + idx = next_cond_indx; + label = X11_cond_labels[idx]; + + /* handle highlighting if caller requests it */ + coloridx = condcolor(bm, colormasks); + attrmask = condattr(bm, colormasks); + colrattr = (attrmask << 8) | coloridx; + if (colrattr != old_cond_colors[c_idx]) + HiliteField(label, BL_CONDITION, c_idx, colrattr, &font); + + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + /* set the condition text and its width; this widget might have + been displaying a different condition last time around */ + XtSetArg(args[num_args], nhStr(XtNlabel), text); num_args++; + /* measure width after maybe changing font [HiliteField()] */ + lbl_wid = 2 * si->in_wd + XTextWidth(font, text, (int) strlen(text)); + /*XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++;*/ + + /* make this condition widget be ready for display */ + XtSetValues(label, args, num_args); + XtResizeWidget(label, lbl_wid, si->ht, si->brd); + + ++next_cond_indx; +} + +/* display the tty-style status conditions; the number shown varies and + we might be showing more, same, or fewer than during previous status */ +static int +render_conditions(row, dx) +int row, dx; +{ + Widget label; + Arg args[6]; + Cardinal num_args; + Position lbl_x; + int i, gap = 5; + struct status_info_t *si = xw_status_win->Win_info.Status_info; + Dimension lbl_wid, brd_wid = si->brd; + + for (i = 0; i < next_cond_indx; i++) { + label = X11_cond_labels[i]; + + /* width of this widget was set in DisplayCond(); fetch it */ + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++; + XtGetValues(label, args, num_args); + + /* figure out where to draw this widget and place it there */ + lbl_x = (Position) (dx + 1 + gap); + + XtConfigureWidget(label, lbl_x, si->y[row], lbl_wid, si->ht, brd_wid); + + /* keep track of where the end of our text appears */ + dx = (int) lbl_x + (int) (lbl_wid + 2 * brd_wid) - 1; + } + + /* if we have fewer conditions shown now than last time, set the + excess ones to blank; unlike the set drawn above, these haven't + been prepared in advance by DisplayCond because they aren't + being displayed; they might have been highlighted last time so + we need to specify more than just an empty text string */ + if (next_cond_indx < prev_cond_indx) { + XFontStruct *font = X11_status_font; + Pixel fg = X11_status_fg, bg = X11_status_bg; + + lbl_x = dx + 1; + lbl_wid = 1 + 2 * brd_wid; + for (i = next_cond_indx; i < prev_cond_indx; ++i) { + label = X11_cond_labels[i]; + + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNlabel), ""); num_args++; + XtSetArg(args[num_args], nhStr(XtNfont), font); num_args++; + XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++; + XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++; + /*XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++;*/ + /*XtSetArg(args[num_args], nhStr(XtNx), lbl_x); num_args++;*/ + XtSetValues(label, args, num_args); + old_cond_colors[i] = NO_COLOR; /* fg, bg, font were just reset */ + XtConfigureWidget(label, lbl_x, si->y[row], lbl_wid, si->ht, 0); + /* don't advance 'dx' here */ + } + } + + return dx; +} + +#ifdef STATUS_HILITES +/* reset status_hilite for BL_RESET; if highlighting has been disabled or + this field is disabled, clear highlighting for this field or condition */ +static void +tt_reset_color(fld, cond, colormasks) +int fld, cond; +unsigned long *colormasks; +{ + Widget label; + int colrattr = NO_COLOR; + + if (fld != BL_CONDITION) { + if (iflags.hilite_delta != 0L && status_activefields[fld]) + colrattr = X11_status_colors[fld]; + cond = 0; + label = X11_status_labels[fld]; + } else { + unsigned long bm = tt_condorder[cond].mask; + + if (iflags.hilite_delta != 0L && (X11_condition_bits & bm) != 0) { + /* BL_RESET before first BL_CONDITION will have colormasks==Null + but condcolor() and condattr() can cope with that */ +#ifdef TEXTCOLOR + colrattr = condcolor(bm, colormasks); +#endif + colrattr |= (condattr(bm, colormasks) << 8); + } + label = X11_cond_labels[cond]; + } + HiliteField(label, fld, cond, colrattr, (XFontStruct **) 0); +} +#endif + +/* make sure foreground, background, and font have reasonable values, + then explicitly set them for all the status widgets; + also cache some geometry settings in (*xw_status_win).Status_info */ +static void +tt_status_fixup() +{ + Arg args[6]; + Cardinal num_args; + Widget w; + Position lbl_y; + int x, y, ci, fld; + XFontStruct *font = 0; + Pixel fg = 0, bg = 0; + struct status_info_t *si = xw_status_win->Win_info.Status_info; + + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNfont), &font); num_args++; + XtSetArg(args[num_args], nhStr(XtNforeground), &fg); num_args++; + XtSetArg(args[num_args], nhStr(XtNbackground), &bg); num_args++; + XtGetValues(X11_status_widget, args, num_args); + if (fg == bg) { + XColor black = get_nhcolor(xw_status_win, CLR_BLACK), + white = get_nhcolor(xw_status_win, CLR_WHITE); + + fg = (bg == white.pixel) ? black.pixel : white.pixel; + } + X11_status_fg = si->fg = fg, X11_status_bg = si->bg = bg; + + if (!font) { + w = X11_status_widget; + XtSetArg(args[0], nhStr(XtNfont), &font); + do { + XtGetValues(w, args, ONE); + } while (!font && (w = XtParent(w)) != 0); + + if (!font) { + /* trial and error time -- this is where we've actually + been obtaining the font even though we aren't setting + it for any of the field widgets (until for(y,x) below) */ + XtGetValues(X11_status_labels[0], args, ONE); + + if (!font) { /* this bit is untested... */ + /* write some text and hope Xaw sets up font for us */ + XtSetArg(args[0], nhStr(XtNlabel), "NetHack"); + XtSetValues(X11_status_labels[0], args, ONE); + (void) XFlush(XtDisplay(X11_status_labels[0])); + + XtSetArg(args[0], nhStr(XtNfont), &font); + XtGetValues(X11_status_labels[0], args, ONE); + + /* if still Null, XTextWidth() would crash so bail out */ + if (!font) + panic("X11 status can't determine font."); + } + } + } + X11_status_font = si->fs = font; + + /* amount of space to advance a widget's location by one space; + increase width a tiny bit beyond the actual space */ + si->spacew = XTextWidth(X11_status_font, " ", 1) + (Dimension) 1; + + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNfont), font); num_args++; + XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++; + XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++; + XtSetValues(X11_status_widget, args, num_args); + + for (y = 0; y < X11_NUM_STATUS_LINES; y++) { + for (x = 0; x < X11_NUM_STATUS_FIELD; x++) { + fld = X11_fieldorder[y][x]; /* next field to handle */ + if (fld <= BL_FLUSH) + continue; /* skip fieldorder[][] padding */ + + XtSetValues(X11_status_labels[fld], args, num_args); + old_field_colors[fld] = NO_COLOR; + + if (fld == BL_CONDITION) { + for (ci = 0; ci < SIZE(X11_cond_labels); ++ci) { /* 0..31 */ + XtSetValues(X11_cond_labels[ci], args, num_args); + old_cond_colors[ci] = NO_COLOR; + } + } + } + } + + /* cache the y coordinate of each row for XtConfigureWidget() */ + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + XtSetArg(args[0], nhStr(XtNy), &lbl_y); num_args++; + for (y = 0; y < X11_NUM_STATUS_LINES; y++) { + fld = X11_fieldorder[y][0]; + XtGetValues(X11_status_labels[fld], args, num_args); + si->y[y] = lbl_y; + } + + /* cache height, borderWidth, and internalWidth for XtResizeWidget() */ + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNheight), &si->ht); num_args++; + XtSetArg(args[num_args], nhStr(XtNborderWidth), &si->brd); num_args++; + XtSetArg(args[num_args], nhStr(XtNinternalWidth), &si->in_wd); num_args++; + XtGetValues(X11_status_labels[0], args, num_args); +} + +/* core requests updating one status field (or is indicating that it's time + to flush all updated fields); tty-style handling */ +static void X11_status_update_tty(fld, ptr, chg, percent, color, colormasks) int fld, chg UNUSED, percent, color; genericptr_t ptr; -unsigned long *colormasks; +unsigned long *colormasks; /* bitmask of highlights for conditions */ { - static boolean oncearound = FALSE; /* prevent premature partial display */ - long *condptr = (long *) ptr; - int coloridx = NO_COLOR; - const char *text = (char *) ptr; - char tmpbuf[BUFSZ]; - int attridx = 0; + static int xtra_space[MAXBLSTATS]; + static unsigned long *cond_colormasks = (unsigned long *) 0; - XFontStruct *font; - Arg args[10]; + Arg args[6]; Cardinal num_args; Position lbl_x; - Position lbl_y; - Dimension lbl_wid; - Dimension lbl_hei; - Dimension lbl_border_wid; - Dimension lbl_iwidth; + Dimension lbl_wid, brd_wid; Widget label; - Pixel fg = X11_status_widget_fg, bg = X11_status_widget_bg; -#ifndef TEXTCOLOR - color = NO_COLOR; -#endif + struct status_info_t *si; + char goldbuf[40]; + const char *fmt; + const char *text; + unsigned long *condptr; + int f, x, y, dx; - if (fld < BL_RESET || fld >= MAXBLSTATS) - return; - - if ((fld >= 0 && fld < MAXBLSTATS) && !status_activefields[fld]) - return; - - if (fld != BL_FLUSH && fld != BL_RESET) { - if (!status_activefields[fld]) - return; - switch (fld) { - case BL_CONDITION: - X11_condition_bits = *condptr; - oncearound = TRUE; - break; - default: - Sprintf(status_vals[fld], - (fld == BL_TITLE && iflags.wc2_hitpointbar) ? "%-30s" : - status_fieldfmt[fld] ? status_fieldfmt[fld] : "%s", - text); - X11_status_colors[fld] = color; - if (iflags.wc2_hitpointbar && fld == BL_HP) { - hpbar_percent = percent; - hpbar_color = color; - } - break; - } - if (fld == BL_CONDITION) { - MaybeDisplayCond(BL_MASK_STONE, colormasks, "Stone"); - MaybeDisplayCond(BL_MASK_SLIME, colormasks, "Slime"); - MaybeDisplayCond(BL_MASK_STRNGL, colormasks, "Strngl"); - MaybeDisplayCond(BL_MASK_FOODPOIS, colormasks, "FoodPois"); - MaybeDisplayCond(BL_MASK_TERMILL, colormasks, "TermIll"); - MaybeDisplayCond(BL_MASK_BLIND, colormasks, "Blind"); - MaybeDisplayCond(BL_MASK_DEAF, colormasks, "Deaf"); - MaybeDisplayCond(BL_MASK_STUN, colormasks, "Stun"); - MaybeDisplayCond(BL_MASK_CONF, colormasks, "Conf"); - MaybeDisplayCond(BL_MASK_HALLU, colormasks, "Hallu"); - MaybeDisplayCond(BL_MASK_LEV, colormasks, "Lev"); - MaybeDisplayCond(BL_MASK_FLY, colormasks, "Fly"); - MaybeDisplayCond(BL_MASK_RIDE, colormasks, "Ride"); - } else { - label = X11_status_labels[fld]; - text = status_vals[fld]; - if (fld == BL_GOLD) - text = decode_mixed(tmpbuf, text); -#ifdef TEXTCOLOR - coloridx = X11_status_colors[fld] & 0x00FF; -#endif - attridx = (X11_status_colors[fld] & 0xFF00) >> 8; - - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNfont), &font); num_args++; - XtSetArg(args[num_args], nhStr(XtNx), &lbl_x); num_args++; - XtSetArg(args[num_args], nhStr(XtNy), &lbl_y); num_args++; - XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++; - XtSetArg(args[num_args], nhStr(XtNheight), &lbl_hei); num_args++; - XtSetArg(args[num_args], nhStr(XtNinternalWidth), - &lbl_iwidth); num_args++; - XtSetArg(args[num_args], nhStr(XtNborderWidth), - &lbl_border_wid); num_args++; - XtGetValues(label, args, num_args); - - /*raw_printf("font: %i-%i", - font->min_bounds.width, font->max_bounds.width);*/ - - if (text && *text) - lbl_wid = lbl_iwidth + font->max_bounds.width * strlen(text); - else - lbl_wid = 1; - - /*raw_printf("1:lbl_wid=%i('%s')", lbl_wid, text);*/ - - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNlabel), - (text && *text) ? text : ""); num_args++; - XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++; - - fg = (coloridx != NO_COLOR) - ? get_nhcolor(xw_status_win, coloridx).pixel - : X11_status_widget_fg; - if (attridx & HL_INVERSE) { - Pixel tmppx = fg; - - fg = bg; - bg = tmppx; - } - - if (attridx & HL_BOLD) { - load_boldfont(xw_status_win, label); - XtSetArg(args[num_args], nhStr(XtNfont), - xw_status_win->boldfs); num_args++; - } - - if (fg == bg) - fg = get_nhcolor(xw_status_win, CLR_GRAY).pixel; - - XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++; - XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++; - XtSetValues(label, args, num_args); - XtResizeWidget(label, lbl_wid, lbl_hei, lbl_border_wid); - } - } else { - int x, y; + if (X11_status_fg == X11_status_bg || !X11_status_font) + tt_status_fixup(); + if (fld == BL_RESET) { +#ifdef STATUS_HILITES for (y = 0; y < X11_NUM_STATUS_LINES; y++) { - Cardinal dx = 0; - for (x = 0; x < X11_NUM_STATUS_FIELD; x++) { - int f = X11_fieldorder[y][x]; - + f = X11_fieldorder[y][x]; if (f <= BL_FLUSH) - continue; - if (!status_activefields[f]) - continue; + continue; /* skip padding in the fieldorder[][] layout */ + if (f != BL_CONDITION) { + tt_reset_color(f, 0, (unsigned long *) 0); + } else { + int c_i; - if (f == BL_CONDITION) { - int i; - - for (i = 0; i < 32; i++) { - label = X11_cond_labels[i]; - - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNx), - &lbl_x); num_args++; - XtSetArg(args[num_args], nhStr(XtNy), - &lbl_y); num_args++; - XtSetArg(args[num_args], nhStr(XtNwidth), - &lbl_wid); num_args++; - XtSetArg(args[num_args], nhStr(XtNheight), - &lbl_hei); num_args++; - XtSetArg(args[num_args], nhStr(XtNborderWidth), - &lbl_border_wid); num_args++; - XtGetValues(label, args, num_args); - - lbl_x = dx; - - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNx), - lbl_x); num_args++; - XtSetValues(label, args, num_args); - XtConfigureWidget(label, lbl_x, lbl_y, - lbl_wid, lbl_hei, lbl_border_wid); - - if (lbl_wid > 1) - dx += lbl_wid; - } - continue; + for (c_i = 0; c_i < SIZE(tt_condorder); ++c_i) + tt_reset_color(f, c_i, cond_colormasks); } - label = X11_status_labels[f]; - - text = status_vals[f]; - if (f == BL_GOLD) - text = decode_mixed(tmpbuf, text); - - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNx), &lbl_x); num_args++; - XtSetArg(args[num_args], nhStr(XtNy), &lbl_y); num_args++; - XtSetArg(args[num_args], nhStr(XtNwidth), - &lbl_wid); num_args++; - XtSetArg(args[num_args], nhStr(XtNheight), - &lbl_hei); num_args++; - XtSetArg(args[num_args], nhStr(XtNborderWidth), - &lbl_border_wid); num_args++; - XtGetValues(label, args, num_args); - - lbl_x = dx; - /*raw_printf("2:lbl_wid=%i('%s')", lbl_wid, text);*/ - - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNx), lbl_x); num_args++; - XtSetArg(args[num_args], nhStr(XtNlabel), text); num_args++; - XtSetValues(label, args, num_args); - XtConfigureWidget(label, lbl_x, lbl_y, - lbl_wid, lbl_hei, lbl_border_wid); - - dx += lbl_wid; } } +#endif + fld = BL_FLUSH; } + + if (fld == BL_CONDITION) { + condptr = (unsigned long *) ptr; + X11_condition_bits = *condptr; + cond_colormasks = colormasks; /* expected to be non-Null */ + + prev_cond_indx = next_cond_indx; + next_cond_indx = 0; + /* if any conditions are active, set up their widgets */ + if (X11_condition_bits) + for (f = 0; f < SIZE(tt_condorder); ++f) + DisplayCond(f, cond_colormasks); + return; + + } else if (fld != BL_FLUSH) { + /* set up a specific field other than 'condition' */ + text = (char *) ptr; + if (fld == BL_GOLD) + text = decode_mixed(goldbuf, text); + xtra_space[fld] = 0; + if (status_activefields[fld]) { + fmt = (fld == BL_TITLE && iflags.wc2_hitpointbar) ? "%-30s" + : status_fieldfmt[fld] ? status_fieldfmt[fld] : "%s"; + if (*fmt == ' ') { + ++xtra_space[fld]; + ++fmt; + } + Sprintf(status_vals[fld], fmt, text); + } else { + /* don't expect this since core won't call status_update() + for a field which isn't active */ + *status_vals[fld] = '\0'; + } +#ifndef TEXTCOLOR + /* even without color, attribute(s) bits still apply */ + color = (color & ~0x00ff) | NO_COLOR; +#endif +#ifdef STATUS_HILITES + if (!iflags.hilite_delta) + color = NO_COLOR; +#endif + X11_status_colors[fld] = color; + if (iflags.wc2_hitpointbar && fld == BL_HP) { + hpbar_percent = percent; + hpbar_color = color; + } + + label = X11_status_labels[fld]; + text = status_vals[fld]; + PrepStatusField(fld, label, text); + return; + } + + /* + * BL_FLUSH: draw all the status fields. + */ + si = xw_status_win->Win_info.Status_info; /* for cached geometry */ + + for (y = 0; y < X11_NUM_STATUS_LINES; y++) { /* row */ + dx = 0; /* no pixels written to this row yet */ + + for (x = 0; x < X11_NUM_STATUS_FIELD; x++) { /* 'column' */ + f = X11_fieldorder[y][x]; + if (f <= BL_FLUSH) + continue; /* skip padding in the fieldorder[][] layout */ + + if (f == BL_CONDITION) { + if (next_cond_indx > 0 || prev_cond_indx > 0) + dx = render_conditions(y, dx); + continue; + } + + label = X11_status_labels[f]; + text = status_vals[f]; + + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++; + XtGetValues(label, args, num_args); + brd_wid = si->brd; + + /* for a field which shouldn't be shown, we can't just skip + it because we might need to remove its previous content + if it has just been toggled off */ + if (!status_activefields[f]) { + if (lbl_wid <= 1) + continue; + text = ""; + lbl_wid = (Dimension) 1; + brd_wid = (Dimension) 0; + } else if (xtra_space[f]) { + /* if this field was to be formatted with a leading space + to separate it from the preceding field, we suppressed + that space during formatting; insert separation between + fields here; this prevents inverse video highlighting + from inverting the separating space along with the text */ + dx += xtra_space[f] * si->spacew; + } + + /* where to display the current widget */ + lbl_x = (Position) (dx + 1); + + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNlabel), text); num_args++; + /*XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++;*/ + /*XtSetArg(args[num_args], nhStr(XtNx), lbl_x); num_args++;*/ + XtSetValues(label, args, num_args); + XtConfigureWidget(label, lbl_x, si->y[y], + lbl_wid, si->ht, brd_wid); + + /* track the right-most pixel written so far */ + dx = (int) lbl_x + (int) (lbl_wid + 2 * brd_wid) - 1; + } /* [x] fields/columns in current row */ + } /* [y] rows */ + + /* this probably doesn't buy us anything but it isn't a sure thing + that nethack will immediately ask for input (triggering auto-flush) */ + (void) XFlush(XtDisplay(X11_status_labels[0])); } /*ARGSUSED*/ -void +static void X11_status_update_fancy(fld, ptr, chg, percent, color, colormasks) int fld, chg UNUSED, percent UNUSED, color UNUSED; genericptr_t ptr; unsigned long *colormasks UNUSED; { - static const struct { + static const struct bl_to_ff { int bl, ff; } bl_to_fancyfield[] = { { BL_TITLE, F_NAME }, @@ -547,30 +826,33 @@ unsigned long *colormasks UNUSED; { BL_GOLD, F_GOLD }, { BL_ENE, F_POWER }, { BL_ENEMAX, F_MAXPOWER }, - { BL_XP, F_LEVEL }, + { BL_XP, F_XP_LEVL }, /* shares with BL_HD, depending upon Upolyd */ { BL_AC, F_AC }, - /*{ BL_HD, F_ },*/ { BL_TIME, F_TIME }, { BL_HUNGER, F_HUNGER }, { BL_HP, F_HP }, { BL_HPMAX, F_MAXHP }, { BL_LEVELDESC, F_DLEVEL }, - { BL_EXP, F_EXP } + { BL_EXP, F_EXP_PTS } }; - static const struct { + static const struct mask_to_ff { unsigned long mask; int ff; } mask_to_fancyfield[] = { + { BL_MASK_GRAB, F_GRABBED }, { BL_MASK_STONE, F_STONE }, { BL_MASK_SLIME, F_SLIME }, { BL_MASK_STRNGL, F_STRNGL }, { BL_MASK_FOODPOIS, F_FOODPOIS }, { BL_MASK_TERMILL, F_TERMILL }, + { BL_MASK_INLAVA, F_IN_LAVA }, + { BL_MASK_HELD, F_HELD }, { BL_MASK_BLIND, F_BLIND }, { BL_MASK_DEAF, F_DEAF }, { BL_MASK_STUN, F_STUN }, { BL_MASK_CONF, F_CONF }, { BL_MASK_HALLU, F_HALLU }, + { BL_MASK_TRAPPED, F_TRAPPED }, { BL_MASK_LEV, F_LEV }, { BL_MASK_FLY, F_FLY }, { BL_MASK_RIDE, F_RIDE } @@ -579,23 +861,29 @@ unsigned long *colormasks UNUSED; if (fld == BL_RESET || fld == BL_FLUSH) { if (WIN_STATUS != WIN_ERR) { - struct xwindow *wp = &window_list[WIN_STATUS]; - - update_fancy_status(wp); + update_fancy_status(FALSE); } return; } if (fld == BL_CONDITION) { - unsigned long mask = (unsigned long) ptr; + unsigned long changed_bits, *condptr = (unsigned long *) ptr; - for (i = 0; i < SIZE(mask_to_fancyfield); i++) - if (mask_to_fancyfield[i].mask == mask) - update_fancy_status_field(mask_to_fancyfield[i].ff); + X11_condition_bits = *condptr; + /* process the bits that are different from last time */ + changed_bits = (X11_condition_bits ^ old_condition_bits); + if (changed_bits) { + for (i = 0; i < SIZE(mask_to_fancyfield); i++) + if ((changed_bits & mask_to_fancyfield[i].mask) != 0L) + update_fancy_status_field(mask_to_fancyfield[i].ff); + old_condition_bits = X11_condition_bits; + } } else { for (i = 0; i < SIZE(bl_to_fancyfield); i++) - if (bl_to_fancyfield[i].bl == fld) + if (bl_to_fancyfield[i].bl == fld) { update_fancy_status_field(bl_to_fancyfield[i].ff); + break; + } } } @@ -605,26 +893,72 @@ int fld, chg UNUSED, percent UNUSED, color; genericptr_t ptr; unsigned long *colormasks; { + if (fld < BL_RESET || fld >= MAXBLSTATS) + panic("X11_status_update(%d) -- invalid field", fld); + if (appResources.fancy_status) X11_status_update_fancy(fld, ptr, chg, percent, color, colormasks); else X11_status_update_tty(fld, ptr, chg, percent, color, colormasks); } -Widget +/* create a widget for a particular status field or potential condition */ +static Widget +create_tty_status_field(fld, condindx, above, left) +int fld, condindx; +Widget above, left; +{ + Arg args[16]; + Cardinal num_args; + char labelname[40]; + int gap = condindx ? 5 : 0; + + if (!condindx) + Sprintf(labelname, "label_%s", bl_idx_to_fldname(fld)); + else + Sprintf(labelname, "cond_%02d", condindx); + + /* set up widget attributes which (mostly) aren't going to be changing */ + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + if (above) + XtSetArg(args[num_args], nhStr(XtNfromVert), above); num_args++; + if (left) + XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); num_args++; + + XtSetArg(args[num_args], nhStr(XtNhorizDistance), gap); num_args++; + XtSetArg(args[num_args], nhStr(XtNvertDistance), 0); num_args++; + + XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++; + XtSetArg(args[num_args], nhStr(XtNbottomMargin), 0); num_args++; + XtSetArg(args[num_args], nhStr(XtNleftMargin), 0); num_args++; + XtSetArg(args[num_args], nhStr(XtNrightMargin), 0); num_args++; + XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++; + /* internalWidth: default is 4; cut that it half and adjust regular + width to have it on both left and right instead of just on the left */ + XtSetArg(args[num_args], nhStr(XtNinternalWidth), 2); num_args++; + XtSetArg(args[num_args], nhStr(XtNborderWidth), 0); num_args++; + XtSetArg(args[num_args], nhStr(XtNlabel), ""); num_args++; + return XtCreateManagedWidget(labelname, labelWidgetClass, + X11_status_widget, args, num_args); +} + +/* create an overall status widget (X11_status_widget) and also + separate widgets for all status fields and potential conditions */ +static Widget create_tty_status(parent, top) Widget parent, top; { - Widget form; /* The form that surrounds everything. */ - Widget w; - Arg args[16]; + Widget form; /* viewport that holds the form that surrounds everything */ + Widget w, over_w, prev_w; + Arg args[6]; Cardinal num_args; - int i, x, y; + int x, y, i, fld; + (void) memset((genericptr_t) args, 0, sizeof args); num_args = 0; - if (top != (Widget) 0) { + if (top) XtSetArg(args[num_args], nhStr(XtNfromVert), top); num_args++; - } XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0); num_args++; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; XtSetArg(args[num_args], XtNwidth, 400); num_args++; @@ -632,83 +966,37 @@ Widget parent, top; form = XtCreateManagedWidget("status_viewport", viewportWidgetClass, parent, args, num_args); + (void) memset((genericptr_t) args, 0, sizeof args); num_args = 0; XtSetArg(args[num_args], XtNwidth, 400); num_args++; XtSetArg(args[num_args], XtNheight, 100); num_args++; - w = XtCreateManagedWidget("status_form", formWidgetClass, - form, args, num_args); + X11_status_widget = XtCreateManagedWidget("status_form", formWidgetClass, + form, args, num_args); + for (y = 0; y < X11_NUM_STATUS_LINES; y++) { + fld = (y > 0) ? X11_fieldorder[y - 1][0] : 0; /* temp, for over_w */ + /* for row(s) beyond the first, pick a widget in the previous + row to put this one underneath (in 'y' terms; 'x' is fluid) */ + over_w = (y > 0) ? X11_status_labels[fld] : (Widget) 0; + /* widget on current row to put the next one to the right of ('x') */ + prev_w = (Widget) 0; for (x = 0; x < X11_NUM_STATUS_FIELD; x++) { - int fld = X11_fieldorder[y][x]; - char labelname[BUFSZ]; - int prevfld; - + fld = X11_fieldorder[y][x]; /* next field to handle */ if (fld <= BL_FLUSH) - continue; - Sprintf(labelname, "label_%s", bl_idx_to_fldname(fld)); - num_args = 0; - if (y > 0) { - prevfld = X11_fieldorder[y-1][0]; - XtSetArg(args[num_args], nhStr(XtNfromVert), - X11_status_labels[prevfld]); num_args++; - } - if (x > 0) { - prevfld = X11_fieldorder[y][x-1]; - XtSetArg(args[num_args], nhStr(XtNfromHoriz), - X11_status_labels[prevfld]); num_args++; - } + continue; /* skip fieldorder[][] padding */ - XtSetArg(args[num_args], nhStr(XtNhorizDistance), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNvertDistance), 0); num_args++; + w = create_tty_status_field(fld, 0, over_w, prev_w); + X11_status_labels[fld] = prev_w = w; - XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNbottomMargin), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNleftMargin), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNrightMargin), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNjustify), - XtJustifyLeft); num_args++; - XtSetArg(args[num_args], nhStr(XtNborderWidth), 0); num_args++; - /* - XtSetArg(args[num_args], nhStr(XtNlabel), - bl_idx_to_fldname(fld)); num_args++; - */ - XtSetArg(args[num_args], nhStr(XtNlabel), ""); num_args++; - X11_status_labels[fld] = XtCreateManagedWidget(labelname, - labelWidgetClass, w, - args, num_args); + if (fld == BL_CONDITION) { + for (i = 1; i <= SIZE(X11_cond_labels); ++i) { /* 1..32 */ + w = create_tty_status_field(fld, i, over_w, prev_w); + X11_cond_labels[i - 1] = prev_w = w; + } + } } - } - - for (i = 0; i < 32; i++) { - char condname[BUFSZ]; - int prevfld; - - Sprintf(condname, "cond_%i", i); - num_args = 0; - - prevfld = X11_fieldorder[0][0]; - XtSetArg(args[num_args], nhStr(XtNfromVert), - X11_status_labels[prevfld]); num_args++; - - XtSetArg(args[num_args], nhStr(XtNfromHoriz), - (i == 0) ? X11_status_labels[BL_CONDITION] - : X11_cond_labels[i-1]); num_args++; - - XtSetArg(args[num_args], nhStr(XtNhorizDistance), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNvertDistance), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNbottomMargin), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNleftMargin), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNrightMargin), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++; - XtSetArg(args[num_args], nhStr(XtNborderWidth), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNlabel), ""); num_args++; - X11_cond_labels[i] = XtCreateManagedWidget(condname, - labelWidgetClass, w, - args, num_args); } - - return w; + return X11_status_widget; } /*ARGSUSED*/ @@ -718,18 +1006,8 @@ struct xwindow *wp; /* window pointer */ boolean create_popup UNUSED; Widget parent; { - Arg args[10]; - Cardinal num_args; - wp->type = NHW_STATUS; - X11_status_widget = wp->w = create_tty_status(parent, (Widget) 0); - - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNforeground), - &X11_status_widget_fg); num_args++; - XtSetArg(args[num_args], nhStr(XtNbackground), - &X11_status_widget_bg); num_args++; - XtGetValues(X11_status_widget, args, num_args); + wp->w = create_tty_status(parent, (Widget) 0); } void @@ -759,6 +1037,7 @@ struct xwindow *wp UNUSED; const char *str UNUSED; { /* nothing */ + return; } void @@ -767,11 +1046,18 @@ struct xwindow *wp; /* window pointer */ boolean create_popup; Widget parent; { + struct status_info_t *si = (struct status_info_t *) alloc(sizeof *si); + xw_status_win = wp; - if (appResources.fancy_status) - create_status_window_fancy(wp, create_popup, parent); - else + if (wp->Win_info.Status_info) + free((genericptr_t) wp->Win_info.Status_info); + wp->Win_info.Status_info = si; + (void) memset((genericptr_t) si, 0, sizeof *si); + + if (!appResources.fancy_status) create_status_window_tty(wp, create_popup, parent); + else + create_status_window_fancy(wp, create_popup, parent); } void @@ -795,9 +1081,6 @@ const char *str; adjust_status_tty(wp, str); } -extern const char *hu_stat[]; /* from eat.c */ -extern const char *enc_stat[]; /* from botl.c */ - void create_status_window_fancy(wp, create_popup, parent) struct xwindow *wp; /* window pointer */ @@ -865,7 +1148,8 @@ Widget parent; XtSetArg(args[num_args], nhStr(XtNbottomMargin), &bottom_margin); num_args++; XtSetArg(args[num_args], nhStr(XtNleftMargin), &left_margin); num_args++; - XtSetArg(args[num_args], nhStr(XtNrightMargin), &right_margin); num_args++; + XtSetArg(args[num_args], nhStr(XtNrightMargin), + &right_margin); num_args++; XtGetValues(wp->w, args, num_args); wp->pixel_height = 2 * nhFontHeight(wp->w) + top_margin + bottom_margin; @@ -914,7 +1198,7 @@ const char *str; Cardinal num_args; if (!wp->status_information) { - update_fancy_status(wp); + update_fancy_status(TRUE); return; } @@ -932,8 +1216,7 @@ const char *str; XtSetValues(wp->w, args, num_args); } -/* Fancy Status - * -------------------------------------------------------------*/ +/* Fancy ================================================================== */ static int hilight_time = 1; /* number of turns to hilight a changed value */ struct X_status_value { @@ -950,7 +1233,7 @@ struct X_status_value { /* 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 */ +#define SV_NAME 2 /* displays an unchangeable name */ static void FDECL(hilight_label, (Widget)); static void FDECL(update_val, (struct X_status_value *, long)); @@ -959,7 +1242,7 @@ static void FDECL(create_widget, (Widget, struct X_status_value *, int)); static void FDECL(get_widths, (struct X_status_value *, int *, int *)); static void FDECL(set_widths, (struct X_status_value *, int, int)); static Widget FDECL(init_column, (const char *, Widget, Widget, Widget, - int *)); + int *, int)); static void NDECL(fixup_cond_widths); static Widget FDECL(init_info_form, (Widget, Widget, Widget)); @@ -968,50 +1251,60 @@ static Widget FDECL(init_info_form, (Widget, Widget, Widget)); * + Alignment needs a different init value, because -1 is an alignment. * + Armor Class is an schar, so 256 is out of range. * + Blank value is 0 and should never change. + * + * - These must be in the same order as the F_foo numbers. */ static struct X_status_value shown_stats[NUM_STATS] = { - { "", SV_NAME, (Widget) 0, -1, 0, FALSE, FALSE }, /* 0*/ + { "", SV_NAME, (Widget) 0, -1, 0, FALSE, FALSE }, /* 0, F_DUMMY */ - { "Strength", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, + { "Strength", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /* 1*/ { "Dexterity", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Constitution", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Intelligence", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Wisdom", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /* 5*/ { "Charisma", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, - { "", SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* name */ - { "", SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* dlvl */ + { "", SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* 7, F_NAME */ + { "", SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* F_DLEVEL */ { "Gold", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Hit Points", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /*10*/ { "Max HP", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Power", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Max Power", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Armor Class", SV_VALUE, (Widget) 0, 256, 0, FALSE, FALSE }, - { "Level", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /*15*/ - { "Experience", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, + { "Xp Level", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /*15*/ + /*{ "Hit Dice", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },==15*/ + { "Exp Points", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Alignment", SV_VALUE, (Widget) 0, -2, 0, FALSE, FALSE }, { "Time", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Score", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, - { "Petrifying", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*20*/ - { "Slimed", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, - { "Strangled", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, - { "Food Pois", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, - { "Term Ill", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, - - { "", SV_NAME, (Widget) 0, -1, 0, FALSE, TRUE }, /*25*/ /* hunger */ - { "", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*encumbr */ + { "", SV_NAME, (Widget) 0, -1, 0, FALSE, TRUE }, /*20, F_HUNGER */ + { "", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /* F_ENCUMBER */ + { "Trapped", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, { "Levitating", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, { "Flying", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, - { "Riding", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, + { "Riding", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*25, F_RIDE */ - { "Blind", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*30*/ - { "Deaf", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, + { "Grabbed!", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*26, F_GRAB */ + { "Petrifying", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /* F_STONE */ + { "Slimed", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, + { "Strangled", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, + { "Food Pois", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*30*/ + { "Term Ill", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, + { "Sinking", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /* 32, F_IN_LAVA */ + + { "Held", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*33*/ + { "Blind", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, + { "Deaf", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*35*/ { "Stunned", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, { "Confused", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, - { "Hallucinating", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, + { "Hallucinating", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*38*/ }; +extern const char *hu_stat[]; /* from eat.c */ +extern const char *enc_stat[]; /* from botl.c */ + /* * Set all widget values to a null string. This is used after all spacings * have been calculated so that when the window is popped up we don't get all @@ -1043,13 +1336,18 @@ null_out_status() } } -/* This is almost an exact duplicate of hilight_value() */ +/* this is almost an exact duplicate of hilight_value() */ static void hilight_label(w) Widget w; /* label widget */ { Arg args[2]; Pixel fg, bg; + /* + * This predates STATUS_HILITES. + * It is used to show any changed item in inverse and gets + * reset on the next turn. + */ XtSetArg(args[0], XtNforeground, &fg); XtSetArg(args[1], XtNbackground, &bg); @@ -1065,6 +1363,8 @@ update_val(attr_rec, new_value) struct X_status_value *attr_rec; long new_value; { + static boolean Exp_shown = TRUE, time_shown = TRUE, score_shown = TRUE, + Xp_was_HD = FALSE; char buf[BUFSZ]; Arg args[4]; @@ -1113,7 +1413,7 @@ long new_value; attr_rec->last_value = new_value; - /* special cases: hunger, encumbrance, sickness */ + /* special cases: hunger and encumbrance */ if (attr_rec == &shown_stats[F_HUNGER]) { XtSetArg(args[0], XtNlabel, hu_stat[new_value]); } else if (attr_rec == &shown_stats[F_ENCUMBER]) { @@ -1130,90 +1430,66 @@ long new_value; /* special case: time can be enabled & disabled */ if (attr_rec == &shown_stats[F_TIME]) { - static boolean flagtime = TRUE; - - if (flags.time && !flagtime) { + if (flags.time && !time_shown) { set_name(attr_rec->w, shown_stats[F_TIME].name); force_update = TRUE; - flagtime = flags.time; - } else if (!flags.time && flagtime) { + time_shown = TRUE; + } else if (!flags.time && time_shown) { set_name(attr_rec->w, ""); set_value(attr_rec->w, ""); - flagtime = flags.time; + time_shown = FALSE; } - if (!flagtime) + if (!time_shown) return; - /* special case: exp can be enabled & disabled */ - } else if (attr_rec == &shown_stats[F_EXP]) { - static boolean flagexp = TRUE; + /* special case: experience points can be enabled & disabled */ + } else if (attr_rec == &shown_stats[F_EXP_PTS]) { + boolean showexp = flags.showexp && !Upolyd; - if (flags.showexp && !flagexp) { - set_name(attr_rec->w, shown_stats[F_EXP].name); + if (showexp && !Exp_shown) { + set_name(attr_rec->w, shown_stats[F_EXP_PTS].name); force_update = TRUE; - flagexp = flags.showexp; - } else if (!flags.showexp && flagexp) { + Exp_shown = TRUE; + } else if (!showexp && Exp_shown) { set_name(attr_rec->w, ""); set_value(attr_rec->w, ""); - flagexp = flags.showexp; + Exp_shown = FALSE; } - if (!flagexp) + if (!Exp_shown) return; - } - /* special case: score can be enabled & disabled */ - else if (attr_rec == &shown_stats[F_SCORE]) { - static boolean flagscore = TRUE; + /* special case: when available, score can be enabled & disabled */ + } else if (attr_rec == &shown_stats[F_SCORE]) { #ifdef SCORE_ON_BOTL - - if (flags.showscore && !flagscore) { + if (flags.showscore && !score_shown) { 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; + score_shown = TRUE; + } else #endif - - /* special case: when polymorphed, show "HD", disable exp */ - } else if (attr_rec == &shown_stats[F_LEVEL]) { - static boolean lev_was_poly = FALSE; - - if (Upolyd && !lev_was_poly) { - force_update = TRUE; - set_name(attr_rec->w, "HD"); - lev_was_poly = TRUE; - } else if (Upolyd && 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 (Upolyd && !exp_was_poly) { - force_update = TRUE; + if (!flags.showscore && score_shown) { set_name(attr_rec->w, ""); set_value(attr_rec->w, ""); - exp_was_poly = TRUE; - } else if (Upolyd && exp_was_poly) { - force_update = TRUE; - set_name(attr_rec->w, shown_stats[F_EXP].name); - exp_was_poly = FALSE; + score_shown = FALSE; } - if (Upolyd) - return; /* no display for exp when poly */ + if (!score_shown) + return; + + /* special case: when polymorphed, show "Hit Dice" and disable Exp */ + } else if (attr_rec == &shown_stats[F_XP_LEVL]) { + if (Upolyd && !Xp_was_HD) { + force_update = TRUE; + set_name(attr_rec->w, "Hit Dice"); + Xp_was_HD = TRUE; + } else if (!Upolyd && Xp_was_HD) { + force_update = TRUE; + set_name(attr_rec->w, shown_stats[F_XP_LEVL].name); + Xp_was_HD = FALSE; + } + /* core won't call status_update() for Exp when it hasn't changed + so do so ourselves (to get Exp_shown flag to match display) */ + if (force_update) + update_fancy_status_field(F_EXP_PTS); } if (attr_rec->last_value == new_value && !force_update) /* same */ @@ -1221,23 +1497,34 @@ long new_value; 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); + /* Special cases: strength and other characteristics, alignment + and "clear". */ + if (attr_rec >= &shown_stats[F_STR] + && attr_rec <= &shown_stats[F_CHA]) { + static const char fmt1[] = "%ld%s", fmt2[] = "%2ld%s"; + struct xwindow *wp; + const char *fmt = fmt1, *padding = ""; + + /* for full-fledged fancy status, force two digits for all + six characteristics, followed by three spaces of padding + to match "/xx" exceptional strength */ + wp = (WIN_STATUS != WIN_ERR) ? &window_list[WIN_STATUS] : 0; + if (wp && !wp->status_information) + fmt = fmt2, padding = " "; + + if (new_value > 18L && attr_rec == &shown_stats[F_STR]) { + if (new_value > 118L) /* 19..25 encoded as 119..125 */ + Sprintf(buf, fmt, new_value - 100L, padding); + else if (new_value < 118L) /* 18/01..18/99 as 19..117*/ + Sprintf(buf, "18/%02ld", new_value - 18L); else - Strcpy(buf, "18/**"); - } else { - Sprintf(buf, "%ld", new_value); + Strcpy(buf, "18/**"); /* 18/100 encoded as 118 */ + } else { /* non-strength or less than 18/01 strength (3..18) */ + Sprintf(buf, fmt, new_value, padding); /* 3..25 */ } } else if (attr_rec == &shown_stats[F_ALIGN]) { - Strcpy(buf, - (new_value == A_CHAOTIC) - ? "Chaotic" - : (new_value == A_NEUTRAL) ? "Neutral" : "Lawful"); + Strcpy(buf, (new_value == A_CHAOTIC) ? "Chaotic" + : (new_value == A_NEUTRAL) ? "Neutral" : "Lawful"); } else { Sprintf(buf, "%ld", new_value); } @@ -1271,7 +1558,7 @@ long new_value; * the other. So only do our update when we update the second line. * * Information on the first line: - * name, attributes, alignment, score + * name, characteristics, alignment, score * * Information on the second line: * dlvl, gold, hp, power, ac, {level & exp or HD **}, time, @@ -1287,7 +1574,8 @@ update_fancy_status_field(i) int i; { struct X_status_value *sv = &shown_stats[i]; - long val; + unsigned long condmask = 0L; + long val = 0L; switch (i) { case F_DUMMY: @@ -1312,7 +1600,7 @@ int i; val = (long) ACURR(A_CHA); break; /* - * Label stats. With the exceptions of hunger, encumbrance, sick + * Label stats. With the exceptions of hunger and encumbrance * these are either on or off. Pleae leave the ternary operators * the way they are. I want to specify 0 or 1, not a boolean. */ @@ -1322,54 +1610,66 @@ int i; case F_ENCUMBER: val = (long) near_capacity(); break; + + case F_TRAPPED: + condmask = BL_MASK_TRAPPED; + break; case F_LEV: - val = Levitation ? 1L : 0L; + condmask = BL_MASK_LEV; break; case F_FLY: - val = Flying ? 1L : 0L; + condmask = BL_MASK_FLY; break; case F_RIDE: - val = u.usteed ? 1L : 0L; + condmask = BL_MASK_RIDE; break; /* fatal status conditions */ + case F_GRABBED: + condmask = BL_MASK_GRAB; + break; case F_STONE: - val = Stoned ? 1L : 0L; + condmask = BL_MASK_STONE; break; case F_SLIME: - val = Slimed ? 1L : 0L; + condmask = BL_MASK_SLIME; break; case F_STRNGL: - val = Strangled ? 1L : 0L; + condmask = BL_MASK_STRNGL; break; case F_FOODPOIS: - val = (Sick && (u.usick_type & SICK_VOMITABLE)) ? 1L : 0L; + condmask = BL_MASK_FOODPOIS; break; case F_TERMILL: - val = (Sick && (u.usick_type & SICK_NONVOMITABLE)) ? 1L : 0L; + condmask = BL_MASK_TERMILL; + break; + case F_IN_LAVA: + condmask = BL_MASK_INLAVA; break; /* non-fatal status conditions */ + case F_HELD: + condmask = BL_MASK_HELD; + break; case F_BLIND: - val = Blind ? 1L : 0L; + condmask = BL_MASK_BLIND; break; case F_DEAF: - val = Deaf ? 1L : 0L; + condmask = BL_MASK_DEAF; break; case F_STUN: - val = Stunned ? 1L : 0L; + condmask = BL_MASK_STUN; break; case F_CONF: - val = Confusion ? 1L : 0L; + condmask = BL_MASK_CONF; break; case F_HALLU: - val = Hallucination ? 1L : 0L; + condmask = BL_MASK_HALLU; break; case F_NAME: - val = (long) 0L; - break; /* special */ case F_DLEVEL: val = (long) 0L; break; /* special */ + case F_GOLD: val = money_cnt(g.invent); if (val < 0L) @@ -1391,10 +1691,10 @@ int i; case F_AC: val = (long) u.uac; break; - case F_LEVEL: + case F_XP_LEVL: val = (long) (Upolyd ? mons[u.umonnum].mlevel : u.ulevel); break; - case F_EXP: + case F_EXP_PTS: val = flags.showexp ? u.uexp : 0L; break; case F_ALIGN: @@ -1430,24 +1730,42 @@ int i; break; } /* default */ } /* switch */ + + if (condmask) + val = ((X11_condition_bits & condmask) != 0L); update_val(sv, val); } -/*ARGUSED*/ +/* fully update status after bl_flush or window resize */ static void -update_fancy_status(wp) -struct xwindow *wp UNUSED; +update_fancy_status(force_update) +boolean force_update; { + static boolean old_showtime, old_showexp, old_showscore; + static int old_upolyd = -1; /* -1: force first time update */ int i; - /*if (wp->cursy != 0) - return;*/ /* do a complete update when line 0 is done */ + if (force_update + || Upolyd != old_upolyd /* Xp vs HD */ + || flags.time != old_showtime + || flags.showexp != old_showexp + || flags.showscore != old_showscore) { + /* update everything; usually only need this on the very first + time, then later if the window gets resized or if poly/unpoly + triggers Xp <-> HD switch or if an optional field gets + toggled off since there won't be a status_update() call for + the no longer displayed field; we're a bit more conservative + than that and do this when toggling on as well as off */ + for (i = 0; i < NUM_STATS; i++) + update_fancy_status_field(i); - for (i = 0; i < NUM_STATS; i++) - update_fancy_status_field(i); + old_upolyd = Upolyd; + old_showtime = flags.time; + old_showexp = flags.showexp; + old_showscore = flags.showscore; + } } - /* * Turn off hilighted status values after a certain amount of turns. */ @@ -1462,6 +1780,7 @@ check_turn_events() continue; if (sv->turn_count++ >= hilight_time) { + /* unhighlights by toggling a highlit item back off again */ if (sv->type == SV_LABEL) hilight_label(sv->w); else @@ -1471,10 +1790,9 @@ check_turn_events() } } -/* Initialize alternate status ============================================= - */ +/* Initialize alternate status ============================================ */ -/* Return a string for the initial width. */ +/* Return a string for the initial width, so use longest possible value. */ static const char * width_string(sv_index) int sv_index; @@ -1500,11 +1818,15 @@ int sv_index; case F_LEV: case F_FLY: case F_RIDE: + case F_TRAPPED: + case F_GRABBED: case F_STONE: case F_SLIME: case F_STRNGL: case F_FOODPOIS: case F_TERMILL: + case F_IN_LAVA: + case F_HELD: case F_BLIND: case F_DEAF: case F_STUN: @@ -1514,7 +1836,8 @@ int sv_index; case F_NAME: case F_DLEVEL: - return ""; + return ""; /* longest possible value not needed for these */ + case F_HP: case F_MAXHP: return "9999"; @@ -1523,12 +1846,12 @@ int sv_index; return "9999"; case F_AC: return "-127"; - case F_LEVEL: + case F_XP_LEVL: return "99"; case F_GOLD: /* strongest hero can pick up roughly 30% of this much */ return "999999"; /* same limit as tty */ - case F_EXP: + case F_EXP_PTS: case F_TIME: case F_SCORE: return "123456789"; /* a tenth digit will still fit legibly */ @@ -1632,10 +1955,10 @@ int width1, width2; } static Widget -init_column(name, parent, top, left, col_indices) +init_column(name, parent, top, left, col_indices, xtrawidth) const char *name; Widget parent, top, left; -int *col_indices; +int *col_indices, xtrawidth; { Widget form; Arg args[4]; @@ -1651,7 +1974,8 @@ int *col_indices; if (left != (Widget) 0) { XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); num_args++; } - XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0); num_args++; + /* this was 0 but that resulted in the text being crammed together */ + XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 2); num_args++; form = XtCreateManagedWidget(name, formWidgetClass, parent, args, num_args); @@ -1671,6 +1995,10 @@ int *col_indices; if (width2 > max_width2) max_width2 = width2; } + + /* insert some extra spacing between columns */ + max_width1 += xtrawidth; + for (ip = col_indices; *ip >= 0; ip++) { set_widths(&shown_stats[*ip], max_width1, max_width2); } @@ -1686,48 +2014,74 @@ int *col_indices; * These are the orders of the displayed columns. Change to suit. The -1 * indicates the end of the column. The two numbers after that are used * to store widths that are calculated at run-time. + * + * 3.7: changed so that all 6 columns have 8 rows, but a few entries + * are left blank <>. Exp-points, Score, and Time are optional depending + * on run-time settings; Xp-level is replaced by Hit-Dice (and Exp-points + * suppressed) when the hero is polymorphed. Title and Dungeon-Level span + * two columns and might expand to more if 'hitpointbar' is implemented. + * + Title ("Plname the Rank") <> <> <> <> + Dungeon-Branch-and-Level <> Hunger Grabbed Held + Hit-points Max-HP Strength Encumbrance Petrifying Blind + Power-points Max-Power Dexterity Trapped Slimed Deaf + Armor-class Alignment Constitution Levitation Strangled Stunned + Xp-level [Exp-points] Intelligence Flying Food-Pois Confused + Gold [Score] Wisdom Riding Term-Ill Hallucinatg + <> [Time] Charisma <> Sinking <> + * + * A seventh column is going to be needed to fit in more conditions. + * + * Possible enhancement: if Exp-points and Score are both disabled, move + * Gold to the Exp-points slot. */ -static int attrib_indices[] = { F_STR, F_DEX, F_CON, F_INT, F_WIS, F_CHA, - -1, 0, 0 }; + /* including F_DUMMY makes the three status condition columns evenly spaced with regard to the adjacent characteristics (Str,Dex,&c) column; - we lose track of the Widget pointer for them, each use clobbering the + we lose track of the Widget pointer for F_DUMMY, each use clobbering the one before, leaving the one from leftover_indices[]; since they're never updated, that shouldn't matter */ -static int status_indices[3][9] = { { F_STONE, F_SLIME, F_STRNGL, - F_FOODPOIS, F_TERMILL, F_DUMMY, - -1, 0, 0 }, - { F_HUNGER, F_ENCUMBER, - F_LEV, F_FLY, F_RIDE, F_DUMMY, - -1, 0, 0 }, - { F_BLIND, F_DEAF, F_STUN, - F_CONF, F_HALLU, F_DUMMY, - -1, 0, 0 } }; +static int status_indices[3][11] = { + { F_DUMMY, F_HUNGER, F_ENCUMBER, F_TRAPPED, + F_LEV, F_FLY, F_RIDE, F_DUMMY, -1, 0, 0 }, + { F_DUMMY, F_GRABBED, F_STONE, F_SLIME, F_STRNGL, + F_FOODPOIS, F_TERMILL, F_IN_LAVA, -1, 0, 0 }, + { F_DUMMY, F_HELD, F_BLIND, F_DEAF, F_STUN, + F_CONF, F_HALLU, F_DUMMY, -1, 0, 0 }, +}; /* used to fill up the empty space to right of 3rd status condition column */ static int leftover_indices[] = { F_DUMMY, -1, 0, 0 }; +/* -2: top two rows of these columns are reserved for title and location */ +static int col1_indices[11 - 2] = { + F_HP, F_POWER, F_AC, F_XP_LEVL, F_GOLD, F_DUMMY, -1, 0, 0 +}; +static int col2_indices[11 - 2] = { + F_MAXHP, F_MAXPOWER, F_ALIGN, F_EXP_PTS, F_SCORE, F_TIME, -1, 0, 0 +}; +static int characteristics_indices[11 - 2] = { + F_STR, F_DEX, F_CON, F_INT, F_WIS, F_CHA, -1, 0, 0 +}; -static int col1_indices[] = { F_HP, F_POWER, F_AC, F_LEVEL, F_GOLD, - F_SCORE, -1, 0, 0 }; -static int col2_indices[] = { F_MAXHP, F_MAXPOWER, F_ALIGN, F_EXP, F_TIME, - -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] + * title + * location + * col1_indices[0] col2_indices[0] col3_indices[0] + * col1_indices[1] col2_indices[1] col3_indices[1] + * ... ... ... + * col1_indices[5] col2_indices[5] col3_indices[5] * - * TODO: increase the space between the two columns. + * The status conditions are managed separately and appear to the right + * of this form. + * + * TODO: widen title field and implement hitpoint bar on it. */ static Widget init_info_form(parent, top, left) Widget parent, top, left; { - Widget form, col1; + Widget form, col1, col2; struct X_status_value *sv_name, *sv_dlevel; Arg args[6]; Cardinal num_args; @@ -1740,26 +2094,29 @@ Widget parent, top, left; if (left != (Widget) 0) { XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); num_args++; } - XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0); num_args++; + XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 2); num_args++; form = XtCreateManagedWidget("status_info", formWidgetClass, parent, args, num_args); - /* top of form */ - sv_name = &shown_stats[F_NAME]; + /* top line/row of form */ + sv_name = &shown_stats[F_NAME]; /* title */ create_widget(form, sv_name, F_NAME); - /* second */ - sv_dlevel = &shown_stats[F_DLEVEL]; + /* second line/row */ + sv_dlevel = &shown_stats[F_DLEVEL]; /* location */ create_widget(form, sv_dlevel, F_DLEVEL); num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), sv_name->w); num_args++; XtSetValues(sv_dlevel->w, args, num_args); - /* two columns beneath */ + /* there are 3 columns beneath but top 2 rows are centered over first 2 */ col1 = init_column("name_col1", form, sv_dlevel->w, (Widget) 0, - col1_indices); - (void) init_column("name_col2", form, sv_dlevel->w, col1, col2_indices); + col1_indices, 0); + col2 = init_column("name_col2", form, sv_dlevel->w, col1, + col2_indices, 5); + (void) init_column("status_characteristics", form, sv_dlevel->w, col2, + characteristics_indices, 15); /* Add calculated widths. */ for (ip = col1_indices; *ip >= 0; ip++) @@ -1806,9 +2163,9 @@ fixup_cond_widths() } /* ascetics: expand the maximum width to make cond columns wider */ if (pass == 1) { - w1 += 20; + w1 += 15; if (w2 > 0) - w2 += 20; + w2 += 15; } } } @@ -1832,20 +2189,24 @@ Widget parent, top; if (top != (Widget) 0) { XtSetArg(args[num_args], nhStr(XtNfromVert), top); num_args++; } - XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0); num_args++; + XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 2); num_args++; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; XtSetArg(args[num_args], XtNorientation, XtorientHorizontal); num_args++; form = XtCreateManagedWidget("fancy_status", panedWidgetClass, parent, args, num_args); w = init_info_form(form, (Widget) 0, (Widget) 0); - w = init_column("status_attributes", form, (Widget) 0, w, attrib_indices); +#if 0 /* moved to init_info_form() */ + w = init_column("status_characteristics", form, (Widget) 0, w, + characteristics_indices, 15); +#endif for (i = 0; i < 3; i++) { Sprintf(buf, "status_condition%d", i + 1); - w = init_column(buf, form, (Widget) 0, w, status_indices[i]); + w = init_column(buf, form, (Widget) 0, w, status_indices[i], 0); } fixup_cond_widths(); /* make all 3 status_conditionN columns same width */ - w = init_column("status_leftover", form, (Widget) 0, w, leftover_indices); + w = init_column("status_leftover", form, (Widget) 0, w, + leftover_indices, 0); nhUse(w); return form; }