From d1dade164ef220a011bf89fa445a8b0012bf38df Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 29 Mar 2019 04:21:18 -0700 Subject: [PATCH] tty statuslines:3 Implement the 'statuslines' option for tty. 2 and 3 line status are similar to curses. Tty's version doesn't include insertion of extra spaces for enhanced readability, or ignoring 'showexp' when space is needed for other fields, or right justifying 'score' and suppressing it when there isn't room for the entire number. It continues to have abbreviated condition and encumbrance descriptions that curses lacks which get used when the normal ones take up too much space. 'statuslines' can be set with 'O' so it is feasible to switch back and forth between 2 and 3 lines on the fly. But only if the display is at least 25 lines (actually ROWNO+4) or else CLIPPING is enabled at build time. This fixes the bug where after resorting to abbreviated condition values it sometimes (always?) wouldn't switch back after more room became available. Abbreviated encumbrance values had problems too (lack of leading space and not changing value if encumbrance changed to anything other than unencumbered) and this fixes that as well. --- doc/Guidebook.mn | 4 +- doc/Guidebook.tex | 2 +- doc/fixes36.2 | 4 +- include/wintty.h | 6 +- src/options.c | 24 +- win/tty/termcap.c | 37 ++- win/tty/wintty.c | 666 +++++++++++++++++++++++++--------------------- 7 files changed, 413 insertions(+), 330 deletions(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 051f61299..956ba2aa1 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -1,4 +1,4 @@ -.\" $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.301 $ $NHDT-Date: 1553480404 2019/03/25 02:20:04 $ +.\" $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.302 $ $NHDT-Date: 1553858473 2019/03/29 11:21:13 $ .\" .\" This is an excerpt from the 'roff' man page from the 'groff' package. .\" NetHack's Guidebook.mn currently does *not* adhere to these guidelines. @@ -3657,7 +3657,7 @@ up (default yes). .lp statuslines Number of lines for traditional below-the-map status display. Acceptable values are 2 and 3 (default is 2). -Curses interface only. +Curses and tty interfaces only. .lp "term_cols\ \ \fIand\fP" .lp term_rows Curses interface only. diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index fa1a9872a..151bed238 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -4057,7 +4057,7 @@ it starts up (default yes). \item[\ib{statuslines}] Number of lines for traditional below-the-map status display. Acceptable values are 2 and 3 (default is 2). -Curses interface only. +Curses and tty interfaces only. %.lp \item[\ib{term\verb+_+cols}\ \ {\it and}]" %.lp diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 66de6f54d..72cb9856f 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.286 $ $NHDT-Date: 1553787633 2019/03/28 15:40:33 $ +$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.287 $ $NHDT-Date: 1553858472 2019/03/29 11:21:12 $ This fixes36.2 file is here to capture information about updates in the 3.6.x lineage following the release of 3.6.1 in April 2018. Please note, however, @@ -653,6 +653,8 @@ curses: status display substantially revamped for both horizontal (via 'align_status:bottom' or 'top') and vertical (via 'align_status:left' or 'right'); 3-line horizontal layout (via 'statuslines:3') added curses: support msg_window:full; default is still msg_window:reversed +tty: support statuslines:3 and dynamically switching between 2 and 3 with 'O' + (requires a display with at least 25 lines or that CLIPPING be enabled) NetHack Community Patches (or Variation) Included diff --git a/include/wintty.h b/include/wintty.h index f7e5b0611..1a609de2a 100644 --- a/include/wintty.h +++ b/include/wintty.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 wintty.h $NHDT-Date: 1549327485 2019/02/05 00:44:45 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.32 $ */ +/* NetHack 3.6 wintty.h $NHDT-Date: 1553858470 2019/03/29 11:21:10 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.33 $ */ /* Copyright (c) David Cohrs, 1991,1992 */ /* NetHack may be freely redistributed. See license for details. */ @@ -79,7 +79,7 @@ struct tty_status_fields { boolean valid; boolean dirty; boolean redraw; - boolean last_on_row; + boolean _not_used; /* was 'last_in_row' */ }; #endif @@ -151,6 +151,7 @@ E void NDECL(cl_eos); * a color or whatever. wintty.c should concern itself with WHERE to put * stuff in a window. */ +E int FDECL(term_attr_fixup, (int)); E void FDECL(term_start_attr, (int attr)); E void FDECL(term_end_attr, (int attr)); E void NDECL(term_start_raw_bold); @@ -182,6 +183,7 @@ E void FDECL(win_tty_init, (int)); /* external declarations */ E void FDECL(tty_init_nhwindows, (int *, char **)); +E void FDECL(tty_preference_update, (const char *)); E void NDECL(tty_player_selection); E void NDECL(tty_askname); E void NDECL(tty_get_nh_event); diff --git a/src/options.c b/src/options.c index f90cef3bd..c4471cf61 100644 --- a/src/options.c +++ b/src/options.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 options.c $NHDT-Date: 1553480404 2019/03/25 02:20:04 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.360 $ */ +/* NetHack 3.6 options.c $NHDT-Date: 1553858470 2019/03/29 11:21:10 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.361 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2008. */ /* NetHack may be freely redistributed. See license for details. */ @@ -385,20 +385,23 @@ static struct Comp_Opt { #ifdef MSDOS { "soundcard", "type of sound card to use", 20, SET_IN_FILE }, #endif -#ifdef STATUS_HILITES { "statushilites", +#ifdef STATUS_HILITES "0=no status highlighting, N=show highlights for N turns", - 20, SET_IN_GAME }, + 20, SET_IN_GAME #else - { "statushilites", "highlight control", 20, SET_IN_FILE }, + "highlight control", 20, SET_IN_FILE #endif -#ifdef CURSES_GRAPHICS + }, { "statuslines", +#ifdef CURSES_GRAPHICS "2 or 3 lines for horizonal (bottom or top) status display", - 20, SET_IN_GAME }, /*WC2*/ + 20, SET_IN_GAME #else - { "statuslines", "2 or 3 lines for status display", 20, SET_IN_FILE }, + "2 or 3 lines for status display", + 20, SET_IN_FILE #endif + }, /*WC2*/ { "symset", "load a set of display symbols from the symbols file", 70, SET_IN_GAME }, { "roguesymset", @@ -3703,6 +3706,7 @@ boolean tinitial, tfrom_file; } return retval; } +#endif /* CURSES_GRAPHICS */ /* WINCAP2 * statuslines:n */ @@ -3728,7 +3732,6 @@ boolean tinitial, tfrom_file; } return retval; } -#endif /* CURSES_GRAPHICS */ /* menustyle:traditional or combination or full or partial */ fullname = "menustyle"; @@ -5739,8 +5742,9 @@ char *buf; iflags.hilite_delta, iflags.hilite_delta); #endif } else if (!strcmp(optname,"statuslines")) { - Strcpy(buf, (WINDOWPORT("curses") - && iflags.wc2_statuslines < 3) ? "2" : "3"); + if (wc2_supported(optname)) + Strcpy(buf, (iflags.wc2_statuslines < 3) ? "2" : "3"); + /* else default to "unknown" */ } else if (!strcmp(optname, "suppress_alert")) { if (flags.suppress_alert == 0L) Strcpy(buf, none); diff --git a/win/tty/termcap.c b/win/tty/termcap.c index c373df04c..ead39d228 100644 --- a/win/tty/termcap.c +++ b/win/tty/termcap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 termcap.c $NHDT-Date: 1456907853 2016/03/02 08:37:33 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.24 $ */ +/* NetHack 3.6 termcap.c $NHDT-Date: 1553858473 2019/03/29 11:21:13 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.29 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1206,12 +1206,37 @@ int n; return nulstr; } +/* suppress nonfunctional highlights so render_status() might be able to + optimize more; keep this in sync with s_atr2str() */ +int +term_attr_fixup(msk) +int msk; +{ + /* underline is converted to bold if its start sequence isn't available */ + if ((msk & (1 << ATR_ULINE)) && !nh_US) { + msk |= (1 << ATR_BOLD); + msk &= ~(1 << ATR_ULINE); + } + /* blink is converted to bold unconditionally [why?] */ + if (msk & (1 << ATR_BLINK)) { + msk |= (1 << ATR_BOLD); + msk &= ~(1 << ATR_BLINK); + } + /* dim is ignored */ + if (msk & (1 << ATR_DIM)) + msk &= ~(1 << ATR_DIM); + return msk; +} + void term_start_attr(attr) int attr; { if (attr) { - xputs(s_atr2str(attr)); + const char *astr = s_atr2str(attr); + + if (*astr) + xputs(s_atr2str(attr)); } } @@ -1220,7 +1245,10 @@ term_end_attr(attr) int attr; { if (attr) { - xputs(e_atr2str(attr)); + const char *astr = e_atr2str(attr); + + if (*astr) + xputs(e_atr2str(attr)); } } @@ -1248,7 +1276,8 @@ void term_start_color(color) int color; { - xputs(hilites[color]); + if (color < CLR_MAX) + xputs(hilites[color]); } /* not to be confused with has_colors() in unixtty.c */ diff --git a/win/tty/wintty.c b/win/tty/wintty.c index b7ad2bf5b..fe06b8180 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 wintty.c $NHDT-Date: 1553716531 2019/03/27 19:55:31 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.198 $ */ +/* NetHack 3.6 wintty.c $NHDT-Date: 1553858474 2019/03/29 11:21:14 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.199 $ */ /* Copyright (c) David Cohrs, 1991 */ /* NetHack may be freely redistributed. See license for details. */ @@ -96,7 +96,7 @@ struct window_procs tty_procs = { | WC2_HILITE_STATUS | WC2_HITPOINTBAR | WC2_FLUSH_STATUS | WC2_RESET_STATUS #endif - | WC2_DARKGRAY | WC2_SUPPRESS_HIST), + | WC2_DARKGRAY | WC2_SUPPRESS_HIST | WC2_STATUSLINES), tty_init_nhwindows, tty_player_selection, tty_askname, tty_get_nh_event, tty_exit_nhwindows, tty_suspend_nhwindows, tty_resume_nhwindows, tty_create_nhwindow, tty_clear_nhwindow, tty_display_nhwindow, @@ -123,11 +123,7 @@ struct window_procs tty_procs = { /* other defs that really should go away (they're tty specific) */ tty_start_screen, tty_end_screen, genl_outrip, -#if defined(WIN32) - nttty_preference_update, -#else - genl_preference_update, -#endif + tty_preference_update, tty_getmsghistory, tty_putmsghistory, tty_status_init, genl_status_finish, tty_status_enablefield, @@ -179,8 +175,10 @@ static const char to_continue[] = "to continue"; #else STATIC_DCL void NDECL(getret); #endif -STATIC_DCL void FDECL(erase_menu_or_text, - (winid, struct WinDesc *, BOOLEAN_P)); +STATIC_DCL void FDECL(bail, (const char *)); /* __attribute__((noreturn)) */ +STATIC_DCL void NDECL(new_status_window); +STATIC_DCL void FDECL(erase_menu_or_text, (winid, struct WinDesc *, + BOOLEAN_P)); STATIC_DCL void FDECL(free_window_info, (struct WinDesc *, BOOLEAN_P)); STATIC_DCL void FDECL(dmore, (struct WinDesc *, const char *)); STATIC_DCL void FDECL(set_item_state, (winid, int, tty_menu_item *)); @@ -198,23 +196,20 @@ STATIC_DCL void FDECL(process_text_window, (winid, struct WinDesc *)); STATIC_DCL tty_menu_item *FDECL(reverse, (tty_menu_item *)); STATIC_DCL const char *FDECL(compress_str, (const char *)); STATIC_DCL void FDECL(tty_putsym, (winid, int, int, CHAR_P)); -STATIC_DCL void FDECL(bail, (const char *)); /* __attribute__((noreturn)) */ STATIC_DCL void FDECL(setup_rolemenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_racemenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_gendmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_algnmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL boolean NDECL(reset_role_filtering); #ifdef STATUS_HILITES -STATIC_DCL boolean FDECL(check_fields, (BOOLEAN_P, int *, int *)); +STATIC_DCL boolean FDECL(check_fields, (BOOLEAN_P, int *)); STATIC_DCL void NDECL(render_status); -STATIC_DCL void FDECL(tty_putstatusfield, (struct tty_status_fields *, - const char *, int, int)); +STATIC_DCL void FDECL(tty_putstatusfield, (const char *, int, int)); STATIC_DCL boolean NDECL(check_windowdata); STATIC_DCL int NDECL(condition_size); STATIC_DCL int FDECL(make_things_fit, (BOOLEAN_P)); STATIC_DCL void FDECL(shrink_enc, (int)); STATIC_DCL void FDECL(shrink_dlvl, (int)); -STATIC_DCL void NDECL(do_setlast); #endif /* @@ -322,19 +317,8 @@ int sig_unused UNUSED; cw = wins[WIN_MESSAGE]; cw->curx = cw->cury = 0; - tty_destroy_nhwindow(WIN_STATUS); - WIN_STATUS = tty_create_nhwindow(NHW_STATUS); - + new_status_window(); if (u.ux) { -#ifdef CLIPPING - if (CO < COLNO || LI < ROWNO + 3) { - setclipped(); - tty_cliparound(u.ux, u.uy); - } else { - clipping = FALSE; - clipx = clipy = 0; - } -#endif i = ttyDisplay->toplin; ttyDisplay->toplin = 0; docrt(); @@ -359,6 +343,41 @@ int sig_unused UNUSED; } #endif +/* destroy and recreate status window; extracted from winch_handler() + and augmented for use by tty_preference_update() */ +STATIC_OVL void +new_status_window() +{ + if (WIN_STATUS != WIN_ERR) { + /* if it's shrinking, clear it before destroying so that + dropped portion won't show anything that's now becoming stale */ + if (wins[WIN_STATUS]->maxrow > iflags.wc2_statuslines) + tty_clear_nhwindow(WIN_STATUS); + + tty_destroy_nhwindow(WIN_STATUS), WIN_STATUS = WIN_ERR; + } + /* frees some status tracking data */ + genl_status_finish(); + /* creates status window and allocates tracking data */ + tty_status_init(); + tty_clear_nhwindow(WIN_STATUS); /* does some init, sets context.botlx */ +#ifdef STATUS_HILITES + status_initialize(REASSESS_ONLY); +#endif + +#ifdef CLIPPING + if (u.ux) { + if (LI < 1 + ROWNO + iflags.wc2_statuslines) { + setclipped(); + tty_cliparound(u.ux, u.uy); + } else { + clipping = FALSE; + clipx = clipy = 0; + } + } +#endif +} + /*ARGSUSED*/ void tty_init_nhwindows(argcp, argv) @@ -367,14 +386,17 @@ char **argv UNUSED; { int wid, hgt, i; -/* - * Remember tty modes, to be restored on exit. - * - * gettty() must be called before tty_startup() - * due to ordering of LI/CO settings - * tty_startup() must be called before initoptions() - * due to ordering of graphics settings - */ + /* options aren't processed yet so wc2_statuslines might be 0; + make sure that it has a reasonable value during tty setup */ + iflags.wc2_statuslines = (iflags.wc2_statuslines < 3) ? 2 : 3; + /* + * Remember tty modes, to be restored on exit. + * + * gettty() must be called before tty_startup() + * due to ordering of LI/CO settings + * tty_startup() must be called before initoptions() + * due to ordering of graphics settings + */ #if defined(UNIX) || defined(VMS) setbuf(stdout, obuf); #endif @@ -414,6 +436,31 @@ char **argv UNUSED; tty_putstr(BASE_WINDOW, 0, copyright_banner_line(i)); tty_putstr(BASE_WINDOW, 0, ""); tty_display_nhwindow(BASE_WINDOW, FALSE); + + /* 'statuslines' defaults to SET_IN_FILE, allowed but invisible; + make it dynamically settable if feasible, otherwise visible */ + if (tty_procs.wincap2 & WC2_STATUSLINES) + set_wc2_option_mod_status(WC2_STATUSLINES, +#ifndef CLIPPING + (LI < 1 + ROWNO + 2) ? DISP_IN_GAME : +#endif + SET_IN_GAME); +} + +void +tty_preference_update(pref) +const char *pref; +{ + if (!strcmp(pref, "statuslines") && iflags.window_inited) { + new_status_window(); + } + +#if defined(WIN32) + nttty_preference_update(pref); +#else + genl_preference_update(pref); +#endif + return; } /* try to reduce clutter in the code below... */ @@ -1367,7 +1414,7 @@ tty_create_nhwindow(type) int type; { struct WinDesc *newwin; - int i; + int i, rowoffset; int newid; if (maxwin == MAXWIN) @@ -1402,15 +1449,22 @@ int type; newwin->maxcol = newwin->cols = 0; break; case NHW_STATUS: - /* status window, 2 lines long, full width, bottom of screen */ + /* status window, 2 or 3 lines long, full width, bottom of screen */ + if (iflags.wc2_statuslines < 2 +#ifndef CLIPPING + || (LI < 1 + ROWNO + 3) +#endif + || iflags.wc2_statuslines > 3) + iflags.wc2_statuslines = 2; newwin->offx = 0; + rowoffset = ttyDisplay->rows - iflags.wc2_statuslines; #if defined(USE_TILES) && defined(MSDOS) if (iflags.grmode) { - newwin->offy = ttyDisplay->rows - 2; + newwin->offy = rowoffset; } else #endif - newwin->offy = min((int) ttyDisplay->rows - 2, ROWNO + 1); - newwin->rows = newwin->maxrow = 2; + newwin->offy = min(rowoffset, ROWNO + 1); + newwin->rows = newwin->maxrow = iflags.wc2_statuslines; newwin->cols = newwin->maxcol = ttyDisplay->cols; break; case NHW_MAP: @@ -1424,9 +1478,8 @@ int type; break; case NHW_MENU: case NHW_TEXT: - /* inventory/menu window, variable length, full width, top of screen - */ - /* help window, the same, different semantics for display, etc */ + /* inventory/menu window, variable length, full width, top of screen; + help window, the same, different semantics for display, etc */ newwin->offx = newwin->offy = 0; newwin->rows = 0; newwin->cols = ttyDisplay->cols; @@ -1449,18 +1502,15 @@ int type; } if (newwin->maxrow) { - newwin->data = - (char **) alloc(sizeof(char *) * (unsigned) newwin->maxrow); - newwin->datlen = - (short *) alloc(sizeof(short) * (unsigned) newwin->maxrow); - if (newwin->maxcol) { - /* WIN_STATUS */ - for (i = 0; i < newwin->maxrow; i++) { + newwin->data = (char **) alloc( + (unsigned) (newwin->maxrow * sizeof (char *))); + newwin->datlen = (short *) alloc( + (unsigned) (newwin->maxrow * sizeof (short))); + for (i = 0; i < newwin->maxrow; i++) { + if (newwin->maxcol) { /* WIN_STATUS */ newwin->data[i] = (char *) alloc((unsigned) newwin->maxcol); newwin->datlen[i] = (short) newwin->maxcol; - } - } else { - for (i = 0; i < newwin->maxrow; i++) { + } else { newwin->data[i] = (char *) 0; newwin->datlen[i] = 0; } @@ -1547,6 +1597,7 @@ void tty_clear_nhwindow(window) winid window; { + int i, j, m, n; register struct WinDesc *cw = 0; HUPSKIP(); @@ -1567,10 +1618,18 @@ winid window; } break; case NHW_STATUS: - tty_curs(window, 1, 0); - cl_end(); - tty_curs(window, 1, 1); - cl_end(); + m = cw->maxrow; + n = cw->cols; + for (i = 0; i < m; ++i) { + tty_curs(window, 1, i); + cl_end(); + + for (j = 0; j < n - 1; ++j) + cw->data[i][j] = ' '; + cw->data[i][n - 1] = '\0'; + /*finalx[i][NOW] = finalx[i][BEFORE] = 0;*/ + } + context.botlx = 1; break; case NHW_MAP: /* cheap -- clear the whole thing and tell nethack to redraw botl */ @@ -1578,6 +1637,8 @@ winid window; /*FALLTHRU*/ case NHW_BASE: clear_screen(); + /*for (i = 0; i < cw->maxrow; ++i) */ + /* finalx[i][NOW] = finalx[i][BEFORE] = 0;*/ break; case NHW_MENU: case NHW_TEXT: @@ -2612,7 +2673,7 @@ const char *str; case NHW_STATUS: ob = &cw->data[cw->cury][j = cw->curx]; if (context.botlx) - *ob = 0; + *ob = '\0'; if (!cw->cury && (int) strlen(str) >= CO) { /* the characters before "St:" are unnecessary */ nb = index(str, ':'); @@ -2637,7 +2698,7 @@ const char *str; (void) strncpy(&cw->data[cw->cury][j], str, cw->cols - j - 1); cw->data[cw->cury][cw->cols - 1] = '\0'; /* null terminate */ - cw->cury = (cw->cury + 1) % 2; + cw->cury = (cw->cury + 1) % cw->maxrow; cw->curx = 0; break; #endif /* STATUS_HILITES */ @@ -2950,7 +3011,7 @@ const char *prompt; /* prompt to for menu */ free((genericptr_t) cw->plist); cw->plist_size = cw->npages + 1; cw->plist = (tty_menu_item **) alloc(cw->plist_size - * sizeof(tty_menu_item *)); + * sizeof (tty_menu_item *)); } cw->cols = 0; /* cols is set when the win is initialized... (why?) */ @@ -3247,7 +3308,7 @@ setclipped() clipping = TRUE; clipx = clipy = 0; clipxmax = CO; - clipymax = LI - 3; + clipymax = LI - 1 - iflags.wc2_statuslines; } void @@ -3269,10 +3330,10 @@ int x, y; } if (y < clipy + 2) { clipy = max(0, y - (clipymax - clipy) / 2); - clipymax = clipy + (LI - 3); + clipymax = clipy + (LI - 1 - iflags.wc2_statuslines); } else if (y > clipymax - 2) { clipymax = min(ROWNO, clipymax + (clipymax - clipy) / 2); - clipy = clipymax - (LI - 3); + clipy = clipymax - (LI - 1 - iflags.wc2_statuslines); } if (clipx != oldx || clipy != oldy) { if (on_level(&u.uz0, &u.uz) && !restoring) @@ -3582,14 +3643,6 @@ extern char *status_vals[MAXBLSTATS]; extern boolean status_activefields[MAXBLSTATS]; extern winid WIN_STATUS; -const char *fieldnames[] = { - "title", "strength", "dexterity", "constitution", "intelligence", - "wisdom", "charisma", "alignment", "score", "carrying-capacity", - "gold", "power", "power-max", "experience-level", "armor-class", - "HD", "time", "hunger", "hitpoints", "hitpoints-max", - "dungeon-level", "experience", "condition", -}; - #ifdef STATUS_HILITES #ifdef TEXTCOLOR STATIC_DCL int FDECL(condcolor, (long, unsigned long *)); @@ -3597,10 +3650,7 @@ STATIC_DCL int FDECL(condcolor, (long, unsigned long *)); STATIC_DCL int FDECL(condattr, (long, unsigned long *)); static unsigned long *tty_colormasks; static long tty_condition_bits; -int cond_disp_width[2]; /* 2: current and previous */ -static struct tty_status_fields - tty_status[2][MAXBLSTATS]; /* 2: first index is for current - and previous */ +static struct tty_status_fields tty_status[2][MAXBLSTATS]; /* 2: NOW,BEFORE */ static int hpbar_percent, hpbar_color; static struct condition_t { long mask; @@ -3626,21 +3676,35 @@ static const char *encvals[3][6] = { { "", "Burden", "Stress", "Strain", "Overtax", "Overload" }, { "", "Brd", "Strs", "Strn", "Ovtx", "Ovld" } }; +#define blPAD BL_FLUSH #define MAX_PER_ROW 15 -static enum statusfields fieldorder[2][MAX_PER_ROW] = { /* 2: 2 status lines */ +/* 2 or 3 status lines */ +static const enum statusfields + twolineorder[3][MAX_PER_ROW] = { { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, - BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, - BL_FLUSH }, + BL_SCORE, BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD }, { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, - BL_CAP, BL_CONDITION, BL_FLUSH } + BL_CAP, BL_CONDITION, BL_FLUSH }, + /* third row of array isn't used for twolineorder */ + { BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, + blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD } +}, + /* Align moved from 1 to 2, Leveldesc+Time+Condition moved from 2 to 3 */ + threelineorder[3][MAX_PER_ROW] = { + { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, + BL_SCORE, BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD }, + { BL_ALIGN, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, + BL_AC, BL_XP, BL_EXP, BL_HD, BL_HUNGER, + BL_CAP, BL_FLUSH, blPAD, blPAD }, + { BL_LEVELDESC, BL_TIME, BL_CONDITION, BL_FLUSH, blPAD, blPAD, + blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD } }; +static const enum statusfields (*fieldorder)[3][MAX_PER_ROW]; -static int last_on_row[2]; /* [rows] */ -static int finalx[2][2]; /* [rows][NOW or BEFORE] */ -static boolean setlast = FALSE; +static int finalx[3][2]; /* [rows][NOW or BEFORE] */ static boolean windowdata_init = FALSE; -static int cond_shrinklvl = 0, cond_width_at_shrink = 0; +static int cond_shrinklvl = 0; static int enclev = 0, enc_shrinklvl = 0; /* static int dl_shrinklvl = 0; */ static boolean truncation_expected = FALSE; @@ -3673,18 +3737,19 @@ void tty_status_init() { #ifdef STATUS_HILITES - int i; + int i, num_rows; + + num_rows = (iflags.wc2_statuslines < 3) ? 2 : 3; + fieldorder = (num_rows != 3) ? &twolineorder : &threelineorder; for (i = 0; i < MAXBLSTATS; ++i) { tty_status[NOW][i].idx = BL_FLUSH; tty_status[NOW][i].color = NO_COLOR; /* no color */ tty_status[NOW][i].attr = ATR_NONE; - tty_status[NOW][i].x = 0; - tty_status[NOW][i].y = 0; + tty_status[NOW][i].x = tty_status[NOW][i].y = 0; tty_status[NOW][i].valid = FALSE; tty_status[NOW][i].dirty = FALSE; tty_status[NOW][i].redraw = FALSE; - tty_status[NOW][i].last_on_row = FALSE; tty_status[BEFORE][i] = tty_status[NOW][i]; } tty_condition_bits = 0L; @@ -3703,10 +3768,6 @@ const char *fmt; boolean enable; { genl_status_enablefield(fieldidx, nm, fmt, enable); -#ifdef STATUS_HILITES - /* force re-evaluation of last field on the row */ - setlast = FALSE; -#endif } #ifdef STATUS_HILITES @@ -3774,10 +3835,11 @@ int fldidx, chg UNUSED, percent, color; genericptr_t ptr; unsigned long *colormasks; { - int i; + int i, attrmask; long *condptr = (long *) ptr; char *text = (char *) ptr; - char *fval, *lastchar, *p; + char goldbuf[40], *fval, *lastchar, *p; + const char *fmt; boolean reset_state = NO_RESET; if ((fldidx < BL_RESET) || (fldidx >= MAXBLSTATS)) @@ -3786,13 +3848,6 @@ unsigned long *colormasks; if ((fldidx >= 0 && fldidx < MAXBLSTATS) && !status_activefields[fldidx]) return; - if (!setlast) - do_setlast(); - -#ifndef TEXTCOLOR - color = (color & ~0x00FF) | NO_COLOR; -#endif - switch (fldidx) { case BL_RESET: reset_state = FORCE_RESET; @@ -3809,13 +3864,28 @@ unsigned long *colormasks; tty_status[NOW][fldidx].dirty = TRUE; truncation_expected = FALSE; break; + case BL_GOLD: + text = decode_mixed(goldbuf, text); + /*FALLTHRU*/ default: + attrmask = (color >> 8) & 0x00FF; +#ifndef TEXTCOLOR + color = NO_COLOR; +#endif + fmt = status_fieldfmt[fldidx]; + if (!fmt) + fmt = "%s"; + /* should be checking for first enabled field here rather than + just first field, but 'fieldorder' doesn't start any rows + with fields which can be disabled so [any_row][0] suffices */ + if (*fmt == ' ' && (fldidx == (*fieldorder)[0][0] + || fldidx == (*fieldorder)[1][0] + || fldidx == (*fieldorder)[2][0])) + ++fmt; /* skip leading space for first field on line */ + Sprintf(status_vals[fldidx], fmt, text); tty_status[NOW][fldidx].idx = fldidx; - Sprintf(status_vals[fldidx], - status_fieldfmt[fldidx] ? status_fieldfmt[fldidx] : "%s", - text); tty_status[NOW][fldidx].color = (color & 0x00FF); - tty_status[NOW][fldidx].attr = ((color >> 8) & 0x00FF); + tty_status[NOW][fldidx].attr = term_attr_fixup(attrmask); tty_status[NOW][fldidx].lth = strlen(status_vals[fldidx]); tty_status[NOW][fldidx].valid = TRUE; tty_status[NOW][fldidx].dirty = TRUE; @@ -3867,11 +3937,14 @@ unsigned long *colormasks; break; case BL_CAP: fval = status_vals[fldidx]; - if (fval) { + enclev = 0; + if (*fval) { + /* TODO: replace this with a callback to the core to + retrieve the cap index directly */ if (*fval == ' ') fval++; - for (i = 0; i < SIZE(encvals); ++i) { - if (!strcmp(encvals[enc_shrinklvl][i], fval)) { + for (i = 0; i < SIZE(encvals[0]); ++i) { + if (!strcmp(encvals[0][i], fval)) { enclev = i; break; /* for */ } @@ -3883,40 +3956,26 @@ unsigned long *colormasks; return; } -void -do_setlast() -{ - int i, row, fld; - - setlast = TRUE; - for (row = 0; row < 2; ++row) - for (i = MAX_PER_ROW - 1; i > 0; --i) { - fld = fieldorder[row][i]; - - if (fld == BL_FLUSH || !status_activefields[fld]) - continue; - - last_on_row[row] = fld; - break; - } -} - STATIC_OVL int make_things_fit(force_update) boolean force_update; { - int trycnt, fitting = 0, condsz = 0, requirement = 0; - int rowsz[2], otheroptions = 0; - boolean check = FALSE; + int trycnt, fitting = 0, condsz, requirement; + int rowsz[3], num_rows, condrow, otheroptions = 0; + num_rows = (iflags.wc2_statuslines < 3) ? 2 : 3; + condrow = num_rows - 1; + cond_shrinklvl = 0; condsz = condition_size(); for (trycnt = 0; trycnt < 6 && !fitting; ++trycnt) { - check = check_fields(force_update, &rowsz[0], &rowsz[1]); - if (!check) + /* FIXME: this remeasures each line every time even though it + is only attempting to shrink one of them and the other one + (or two) remains the same */ + if (!check_fields(force_update, rowsz)) return 0; - requirement = rowsz[1]; - if (requirement < wins[WIN_STATUS]->cols - 1) { + requirement = rowsz[condrow] - 1; + if (requirement <= wins[WIN_STATUS]->cols - 1) { fitting = requirement; break; /* we're good */ } @@ -3924,7 +3983,6 @@ boolean force_update; if (cond_shrinklvl < trycnt + 1) { cond_shrinklvl = trycnt + 1; condsz = condition_size(); - cond_width_at_shrink = cond_disp_width[NOW]; } continue; } @@ -3932,9 +3990,11 @@ boolean force_update; /* We've exhausted the condition identifiers shrinkage, * so let's try something other things... */ - if (otheroptions == 0 || otheroptions == 1) { - /* try shrinking the encumbrance word */ - shrink_enc(otheroptions + 1); + if (otheroptions < 2) { + /* try shrinking the encumbrance word, but + only when it's on the same line as conditions */ + if (num_rows == 2) + shrink_enc(otheroptions + 1); otheroptions++; } else if (otheroptions == 2) { shrink_dlvl(1); @@ -3956,23 +4016,23 @@ boolean force_update; * This is now done at an individual field case-by-case level. */ boolean -check_fields(forcefields, topsz, bottomsz) +check_fields(forcefields, sz) boolean forcefields; -int *topsz, *bottomsz; +int sz[3]; { - int c, i, row, col, trackx, idx; - boolean valid = TRUE, matchprev = FALSE, update_right, disregard = FALSE; + int c, i, row, col, num_rows, idx; + boolean valid = TRUE, matchprev, update_right; if (!windowdata_init && !check_windowdata()) return FALSE; - for (row = 0; row < 2; ++row) { + num_rows = (iflags.wc2_statuslines < 3) ? 2 : 3; + + for (row = 0; row < num_rows; ++row) { + sz[row] = 0; col = 1; - trackx = 1; update_right = FALSE; - idx = -1; - for (i = 0; fieldorder[row][i] != BL_FLUSH; ++i) { - idx = fieldorder[row][i]; + for (i = 0; (idx = (*fieldorder)[row][i]) != BL_FLUSH; ++i) { if (!status_activefields[idx]) continue; if (!tty_status[NOW][idx].valid) @@ -3983,109 +4043,98 @@ int *topsz, *bottomsz; /* On a change to the field length, everything further to the right must be updated as well */ - if (tty_status[NOW][idx].lth != tty_status[BEFORE][idx].lth) + if (tty_status[NOW][idx].lth != tty_status[BEFORE][idx].lth + || (idx == BL_CONDITION + && tty_status[NOW][idx].x != tty_status[BEFORE][idx].x)) update_right = TRUE; - if (idx == last_on_row[row]) - tty_status[NOW][idx].last_on_row = TRUE; - - if (!update_right && !forcefields) { + matchprev = FALSE; /* assume failure */ + if (valid && !update_right && !forcefields) { /* - * Check values against those already on the dislay. + * Check values against those already on the display. * - Is the additional processing time for this worth it? */ - if (do_field_opt) { - matchprev = FALSE; - disregard = (tty_status[NOW][idx].lth == 0); - if (do_field_opt && !disregard - && tty_status[NOW][idx].dirty) { + if (do_field_opt + && (tty_status[NOW][idx].color + == tty_status[BEFORE][idx].color) + && (tty_status[NOW][idx].attr + == tty_status[BEFORE][idx].attr)) { + matchprev = TRUE; /* assume success */ + if (tty_status[NOW][idx].dirty) { /* compare values */ - const char *ob, *nb; /* old byte, new byte */ + const char *ob, *nb; /* old byte, new byte */ + struct WinDesc *cw = wins[WIN_STATUS]; c = col - 1; - ob = &wins[WIN_STATUS]->data[row][c]; + ob = &cw->data[row][c]; nb = status_vals[idx]; - while (*nb && c < wins[WIN_STATUS]->cols) { + while (*nb && c < cw->cols) { if (*nb != *ob) break; nb++; ob++; c++; } - if (!*nb && c > col - 1) - matchprev = TRUE; + /* if we're not at the end of new string, no match; + we don't need to worry about whether there might + be leftover old string; that could only happen + if they have different lengths, in which case + 'update_right' will be set and we won't get here */ + if (*nb) + matchprev = FALSE; +#if 0 + if (*nb || (*ob && *ob != ' ' + && (*ob != '/' || idx != BL_XP) + && (*ob != '(' || (idx != BL_HP + && idx != BL_ENE)))) + matchprev = FALSE; +#endif } - } else { - matchprev = FALSE; } } - /* - * With STATUS_HILITES, it is possible that the color - * needs to change even if the text is the same, so - * we flag that here by setting .redraw. - * Then, render_status() will see that flag setting - * and ensure that the tty cell content is updated. - * After the field has been updated, render_status() - * will also clear .redraw and .dirty. - */ if (forcefields || update_right - || (!matchprev && tty_status[NOW][idx].dirty && !disregard) - || tty_status[NOW][idx].color != tty_status[BEFORE][idx].color - || tty_status[NOW][idx].attr != tty_status[BEFORE][idx].attr) + || (tty_status[NOW][idx].dirty && !matchprev)) tty_status[NOW][idx].redraw = TRUE; + col += tty_status[NOW][idx].lth; } - if (idx != -1) { - if (row && bottomsz) - *bottomsz = col + tty_status[NOW][idx].lth; - else if (topsz) - *topsz = col + tty_status[NOW][idx].lth; - } + sz[row] = col; } return valid; } /* * This is what places a field on the tty display. - * If val isn't null, it will be used rather than - * fld (it takes precedence). */ STATIC_OVL void -tty_putstatusfield(fld, val, x, y) -struct tty_status_fields *fld; -const char *val; +tty_putstatusfield(text, x, y) +const char *text; int x, y; { - int i, n, ncols, lth = 0; + int i, n, ncols, nrows, lth = 0; struct WinDesc *cw = 0; - const char *text = (char *)0; - if ((cw = wins[NHW_STATUS]) == (struct WinDesc *) 0) - panic("Invalid WinDesc\n"); + if (WIN_STATUS == WIN_ERR + || (cw = wins[WIN_STATUS]) == (struct WinDesc *) 0) + panic("tty_putstatusfield: Invalid WinDesc\n"); ncols = cw->cols; - if (val) { - text = val; - lth = strlen(text); - } else if (fld) { - text = status_vals[fld->idx]; - lth = fld->lth; - } - if (!text) - return; + nrows = cw->maxrow; + lth = (int) strlen(text); print_vt_code2(AVTC_SELECT_WINDOW, NHW_STATUS); - if (x < ncols && y < 2) { - tty_curs(NHW_STATUS, x, y); + if (x < ncols && y < nrows) { + if (x != cw->curx || y != cw->cury) + tty_curs(NHW_STATUS, x, y); for (i = 0; i < lth; ++i) { n = i + x; if (n < ncols && *text) { (void) putchar(*text); ttyDisplay->curx++; cw->curx++; - cw->data[y][n-1] = *text; + cw->data[y][n - 1] = *text; text++; } } @@ -4096,23 +4145,23 @@ int x, y; } } +/* caller must set cond_shrinklvl (0..2) before calling us */ STATIC_OVL int condition_size() { - long mask = 0L; - int c, x; - - x = 0; - for (c = 0; c < SIZE(conditions); ++c) { - mask = conditions[c].mask; - if ((tty_condition_bits & mask) == mask) { - x++; /* for spacer */ - x += (int) strlen(conditions[c].text[cond_shrinklvl]); + long mask; + int c, lth; + + lth = 0; + if (tty_condition_bits) { + for (c = 0; c < SIZE(conditions); ++c) { + mask = conditions[c].mask; + if ((tty_condition_bits & mask) == mask) + lth += 1 + (int) strlen(conditions[c].text[cond_shrinklvl]); } } - tty_status[NOW][BL_CONDITION].lth = x; - cond_disp_width[NOW] = x; - return x; + tty_status[NOW][BL_CONDITION].lth = lth; + return lth; } STATIC_OVL void @@ -4120,9 +4169,9 @@ shrink_enc(lvl) int lvl; { /* shrink or restore the encumbrance word */ - if (lvl == 0 || lvl <= 2) { + if (lvl <= 2) { enc_shrinklvl = lvl; - Strcpy(status_vals[BL_CAP], encvals[lvl][enclev]); + Sprintf(status_vals[BL_CAP], " %s", encvals[lvl][enclev]); } tty_status[NOW][BL_CAP].lth = strlen(status_vals[BL_CAP]); } @@ -4154,14 +4203,7 @@ check_windowdata(VOID_ARGS) paniclog("check_windowdata", " null status window."); return FALSE; } else if (!windowdata_init) { - int i, n = wins[WIN_STATUS]->cols; - - for (i = 0; i < wins[WIN_STATUS]->cols; ++i) { - wins[WIN_STATUS]->data[0][i] = ' '; - wins[WIN_STATUS]->data[1][i] = ' '; - } - wins[WIN_STATUS]->data[0][n - 1] = '\0'; /* null terminate */ - wins[WIN_STATUS]->data[1][n - 1] = '\0'; /* null terminate */ + tty_clear_nhwindow(WIN_STATUS); /* also sets cw->data[] to spaces */ windowdata_init = TRUE; } return TRUE; @@ -4263,10 +4305,10 @@ unsigned long *bmarray; STATIC_OVL void render_status(VOID_ARGS) { - long mask = 0L; - int i, c, row, attrmask = 0; + long mask, bits; + int i, x, y, idx, c, row, tlth, num_rows, coloridx = 0, attrmask = 0; + char *text; struct WinDesc *cw = 0; - struct tty_status_fields *nullfield = (struct tty_status_fields *) 0; if (WIN_STATUS == WIN_ERR || (cw = wins[WIN_STATUS]) == (struct WinDesc *) 0) { @@ -4274,22 +4316,19 @@ render_status(VOID_ARGS) return; } - for (row = 0; row < 2; ++row) { + num_rows = (iflags.wc2_statuslines < 3) ? 2 : 3; + for (row = 0; row < num_rows; ++row) { HUPSKIP(); - curs(WIN_STATUS, 1, row); - for (i = 0; fieldorder[row][i] != BL_FLUSH; ++i) { - int idx = fieldorder[row][i]; - + y = row; + tty_curs(WIN_STATUS, 1, y); + for (i = 0; (idx = (*fieldorder)[row][i]) != BL_FLUSH; ++i) { if (!status_activefields[idx]) continue; + x = tty_status[NOW][idx].x; + text = status_vals[idx]; + tlth = (int) tty_status[NOW][idx].lth; - if ((tty_status[NOW][idx].lth || idx == BL_CONDITION) - && (tty_status[NOW][idx].redraw || !do_field_opt)) { - int coloridx = tty_status[NOW][idx].color; - int attridx = tty_status[NOW][idx].attr; - int x = tty_status[NOW][idx].x; - int y = row; - char *text = status_vals[idx]; + if (tty_status[NOW][idx].redraw || !do_field_opt) { boolean hitpointbar = (idx == BL_TITLE && iflags.wc2_hitpointbar); @@ -4299,68 +4338,77 @@ render_status(VOID_ARGS) * | Condition Codes | * +-----------------+ */ + if (!tty_condition_bits) + continue; + if (num_rows == 3) { + int k; + char *dat = &cw->data[y][0]; + + /* line up with hunger (or where it would have + been when currently omitted); if there isn't + enough room for that, right justify; or place + as-is if not even enough room for /that/; we + expect hunger to be on preceding row, in which + case its current data has been moved to [BEFORE] */ + if (tty_status[BEFORE][BL_HUNGER].y < row + && x < tty_status[BEFORE][BL_HUNGER].x + && (tty_status[BEFORE][BL_HUNGER].x + tlth + < cw->cols - 1)) + k = tty_status[BEFORE][BL_HUNGER].x; + else if (x + tlth < cw->cols - 1) + k = cw->cols - tlth; + else + k = x; + while (x < k) { + if (dat[x - 1] != ' ') + tty_putstatusfield(" ", x, y); + ++x; + } + tty_status[NOW][BL_CONDITION].x = x; + tty_curs(WIN_STATUS, x, y); + } + bits = tty_condition_bits; for (c = 0; c < SIZE(conditions); ++c) { mask = conditions[c].mask; - if ((tty_condition_bits & mask) == mask) { + if (bits & mask) { const char *condtext; - tty_putstatusfield(nullfield, " ", x++, y); + tty_putstatusfield(" ", x++, y); if (iflags.hilite_delta) { attrmask = condattr(mask, tty_colormasks); Begin_Attr(attrmask); coloridx = condcolor(mask, tty_colormasks); - if (coloridx != NO_COLOR - && coloridx != CLR_MAX) + if (coloridx != NO_COLOR) term_start_color(coloridx); } - if (x >= cw->cols && !truncation_expected) + condtext = conditions[c].text[cond_shrinklvl]; + if (x >= cw->cols && !truncation_expected) { impossible( "Unexpected condition placement overflow"); - condtext = conditions[c].text[cond_shrinklvl]; - tty_putstatusfield(nullfield, condtext, x, y); + condtext = ""; + } + tty_putstatusfield(condtext, x, y); x += (int) strlen(condtext); if (iflags.hilite_delta) { - if (coloridx != NO_COLOR - && coloridx != CLR_MAX) + if (coloridx != NO_COLOR) term_end_color(); End_Attr(attrmask); } + if (!(bits &= ~mask)) + break; } } - if (x >= cw->cols) { + /* 'x' is 1-based and 'cols' and 'data' are 0-based, + so x==cols means we just stored in data[N-2] and + are now positioned at data[N-1], the terminator; + that's ok as long as we don't write there */ + if (x > cw->cols) { static unsigned once_only = 0; if (!truncation_expected && !once_only++) - paniclog( - "render_status()", " unexpected truncation."); - x = cw->cols - 1; - } - tty_curs(WIN_STATUS, x, y); - cl_end(); - } else if (idx == BL_GOLD) { - char buf[BUFSZ]; - /* - * +-----------+ - * | Gold | - * +-----------+ - */ - if (iflags.hilite_delta) { - if (*text == ' ') { - tty_putstatusfield(nullfield, " ", x++, y); - text++; - } - /* multiple attributes can be in effect concurrently */ - Begin_Attr(attridx); - if (coloridx != NO_COLOR && coloridx != CLR_MAX) - term_start_color(coloridx); - } - /* decode_mixed() due to GOLD glyph */ - tty_putstatusfield(nullfield, - decode_mixed(buf, text), x, y); - if (iflags.hilite_delta) { - if (coloridx != NO_COLOR && coloridx != CLR_MAX) - term_end_color(); - End_Attr(attridx); + paniclog("render_status()", + " unexpected truncation."); + x = cw->cols; } } else if (hitpointbar) { /* @@ -4381,6 +4429,7 @@ render_status(VOID_ARGS) } else Strcpy(bar, text); bar_len = (int) strlen(bar); /* always 30 */ + tlth = bar_len + 2; /* when at full HP, the whole title will be highlighted; when injured or dead, there will be a second portion which is not highlighted */ @@ -4395,12 +4444,12 @@ render_status(VOID_ARGS) savedch = *bar2; *bar2 = '\0'; } - tty_putstatusfield(nullfield, "[", x++, y); + tty_putstatusfield("[", x++, y); if (*bar) { /* always True, unless twoparts+dead (0 HP) */ term_start_attr(ATR_INVERSE); if (iflags.hilite_delta && hpbar_color != NO_COLOR) term_start_color(hpbar_color); - tty_putstatusfield(nullfield, bar, x, y); + tty_putstatusfield(bar, x, y); x += (int) strlen(bar); if (iflags.hilite_delta && hpbar_color != NO_COLOR) term_end_color(); @@ -4408,11 +4457,10 @@ render_status(VOID_ARGS) } if (twoparts) { /* no highlighting for second part */ *bar2 = savedch; - tty_putstatusfield(nullfield, bar2, x, y); + tty_putstatusfield(bar2, x, y); x += (int) strlen(bar2); - /*tty_curs(WIN_STATUS, x, y);*/ } - tty_putstatusfield(nullfield, "]", x++, y); + tty_putstatusfield("]", x++, y); } else { /* * +-----------------------------+ @@ -4421,43 +4469,47 @@ render_status(VOID_ARGS) * +-----------------------------+ */ if (iflags.hilite_delta) { - if (*text == ' ') { - tty_putstatusfield(nullfield, " ", x++, y); + while (*text == ' ') { + tty_putstatusfield(" ", x++, y); + text++; + } + if (*text == '/' && idx == BL_EXP) { + tty_putstatusfield("/", x++, y); text++; } - /* multiple attributes can be in effect concurrently */ - Begin_Attr(attridx); - if (coloridx != NO_COLOR && coloridx != CLR_MAX) + attrmask = tty_status[NOW][idx].attr; + Begin_Attr(attrmask); + coloridx = tty_status[NOW][idx].color; + if (coloridx != NO_COLOR) term_start_color(coloridx); } - tty_putstatusfield(&tty_status[NOW][idx], text, x, y); + tty_putstatusfield(text, x, y); + x += (int) strlen(text); if (iflags.hilite_delta) { - if (coloridx != NO_COLOR && coloridx != CLR_MAX) + if (coloridx != NO_COLOR) term_end_color(); - End_Attr(attridx); + End_Attr(attrmask); } } - if (tty_status[NOW][idx].last_on_row) { - int padright = 0; - - x = tty_status[NOW][idx].x + tty_status[NOW][idx].lth; - finalx[row][NOW] = x - 1; - if (finalx[row][NOW] < finalx[row][BEFORE]) - padright = finalx[row][BEFORE] - finalx[row][NOW]; - while (padright-- > 0) - tty_putstatusfield(nullfield, " ", x++, y); - } + } else { + /* not rendered => same text as before */ + x += tlth; } + finalx[row][NOW] = x - 1; /* reset .redraw, .dirty, .padright now that they're rendered */ tty_status[NOW][idx].dirty = FALSE; tty_status[NOW][idx].redraw = FALSE; - tty_status[NOW][idx].last_on_row = FALSE; - /* * For comparison of current and previous: * - Copy the entire tty_status struct. */ - tty_status[BEFORE][idx] = tty_status[NOW][idx]; + tty_status[BEFORE][idx] = tty_status[NOW][idx]; + } + x = finalx[row][NOW]; + if ((x < finalx[row][BEFORE] || !finalx[row][BEFORE]) + && x + 1 < cw->cols) { + tty_curs(WIN_STATUS, x + 1, y); + cl_end(); } /* * For comparison of current and previous: @@ -4465,12 +4517,6 @@ render_status(VOID_ARGS) */ finalx[row][BEFORE] = finalx[row][NOW]; } - if (cond_disp_width[NOW] < cond_width_at_shrink) { - cond_shrinklvl = 0; /* reset */ - cond_width_at_shrink = condition_size(); - shrink_enc(0); - shrink_dlvl(0); - } return; } -- 2.40.0