From 2e9d0753c856104e3ad5289c08d9a1cdf8d63242 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 18 Mar 2024 13:24:21 -0700 Subject: [PATCH] enhance the windowcolors option When processing |OPTIONS=windowcolors:window-type foreground-color/background-color parse the color values and use their names rather than the player's raw options text. Affects the feedback from 'm O' and is essential for the next feature. Accept either "gray" or "grey" where colortable[] always uses "gray" (half a dozen or so instances), and accept dash or underscore where colortable[] always uses dash (many instances). Also, complain about 'window-type' if it isn't recognized as one of menu, message, status, or text. [For curses, the complaint gets written to stdout and is then immediately erased as it goes into full screen mode. That's a general problem, not specific to this option.] --- include/extern.h | 3 +- src/coloratt.c | 88 ++++++++++++++++++++++++++++++++++++++++++------ src/options.c | 40 +++++++++++++--------- 3 files changed, 104 insertions(+), 27 deletions(-) diff --git a/include/extern.h b/include/extern.h index 4733f1246..0e1a922e8 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 extern.h $NHDT-Date: 1710008870 2024/03/09 18:27:50 $ $NHDT-Branch: keni-regex $:$NHDT-Revision: 1.1397 $ */ +/* NetHack 3.7 extern.h $NHDT-Date: 1710792423 2024/03/18 20:07:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1398 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -317,6 +317,7 @@ extern void free_one_menu_coloring(int); extern void free_menu_coloring(void); extern int count_menucolors(void); extern int32 check_enhanced_colors(char *) NONNULLARG1; +extern const char *wc_color_name(int32) NONNULL; /* ### cmd.c ### */ diff --git a/src/coloratt.c b/src/coloratt.c index a50b7a0c2..7fb0237b5 100644 --- a/src/coloratt.c +++ b/src/coloratt.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 coloratt.c $NHDT-Date: 1709559438 2024/03/04 13:37:18 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1 $ */ +/* NetHack 3.7 coloratt.c $NHDT-Date: 1710792438 2024/03/18 20:07:18 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.2 $ */ /* Copyright (c) Pasi Kallinen, 2024 */ /* NetHack may be freely redistributed. See license for details. */ @@ -507,13 +507,16 @@ DISABLE_WARNING_FORMAT_NONLITERAL extern const char regex_id[]; /* from sys/share/regex.{c,cpp} */ -/* True: temporarily replace menu color entries with a fake set of menu - colors, { "light blue"=light_blue, "blue"=blue, "red"=red, &c }, that - illustrates most colors for use when the pick-a-color menu is rendered; - suppresses black and white because one of those will likely be invisible - due to matching the background; False: restore user-specified colorings */ +/* set up a menu for picking a color, one that shows each name in its color; + overrides player's MENUCOLORS with a set of "blue"=blue, "red"=red, and + so forth; suppresses color for black and white because one of those will + likely be invisible due to matching the background; the alternate set of + MENUCOLORS is kept around for potential re-use */ void -basic_menu_colors(boolean load_colors) +basic_menu_colors( + boolean load_colors) /* True: temporarily replace menu color entries with + * a fake set of menu colors which match their names; + * False: restore user-specified colorings */ { if (load_colors) { /* replace normal menu colors with a set specifically for colors */ @@ -537,7 +540,9 @@ basic_menu_colors(boolean load_colors) /* this orders the patterns last-in/first-out; that means that the "light " variations come before the basic - "" ones, which is exactly what we want */ + "" ones, which is exactly what we want (so that the + shorter basic names won't get false matches as substrings + of the longer ones) */ for (i = 0; i < SIZE(colornames); ++i) { if (!colornames[i].name) /* first alias entry has no name */ break; @@ -703,17 +708,78 @@ count_menucolors(void) int32 check_enhanced_colors(char *buf) { + char xtra = '\0'; /* used to catch trailing junk after "#rrggbb" */ + unsigned r, g, b; int32 retcolor = -1, color; if ((color = match_str2clr(buf, TRUE)) != CLR_MAX) { retcolor = color | NH_BASIC_COLOR; + } else if (sscanf(buf, "#%02x%02x%02x%c", &r, &g, &b, &xtra) >= 3) { + retcolor = !xtra ? (int32) ((r << 16) | (g << 8) | b) : -1; } else { - for (color = 0; color < SIZE(colortable); ++color) { - if (!strcmpi(buf, colortable[color].name)) - retcolor = colortable_to_int32(&colortable[color]); + /* altbuf: allow user's "grey" to match colortable[]'s "gray"; + * fuzzymatch(): ignore spaces, hyphens, and underscores so that + * space or underscore in user-supplied name will match hyphen + * [note: caller splits text at spaces so we won't see any here] + */ + char *altbuf = NULL, *grey = strstri(buf, "grey"); + ptrdiff_t greyoffset = grey ? (grey - buf) : -1; + + if (greyoffset >= 0) { + altbuf = dupstr(buf); + /* use direct copy because strsubst() is case-sensitive */ + /*(void) strncpy(&altbuf[greyoffset], "gray", 4);*/ + (void) memcpy(altbuf + greyoffset, "gray", 4); } + for (color = 0; color < SIZE(colortable); ++color) { + if (fuzzymatch(buf, colortable[color].name, " -_", TRUE) + || (altbuf && fuzzymatch(altbuf, colortable[color].name, + " -_", TRUE))) { + retcolor = colortable_to_int32(&colortable[color]); + break; + } + } + if (altbuf) + free(altbuf); } return retcolor; } +/* return the canonical name of a particular color */ +const char * +wc_color_name(int32 colorindx) +{ + static char hexcolor[sizeof "#rrggbb"]; /* includes room for '\0' */ + const char *result = "no-color"; + if (colorindx >= 0) { + int32 basicindx = colorindx & ~NH_BASIC_COLOR; + + /* if colorindx has NH_BASIC_COLOR bit set, basicindx won't, + so differing implies a basic color */ + if (basicindx != colorindx) { + assert(basicindx < 16); + result = colortable[basicindx].name; + } else { + int indx; + long r = (colorindx >> 16) & 0x0000ff, /* shift rrXXXX to rr */ + g = (colorindx >> 8) & 0x0000ff, /* shift XXggXX to gg */ + b = colorindx & 0x0000ff; /* mask XXXXbb to bb */ + + Snprintf(hexcolor, sizeof hexcolor, "#%02x%02x%02x", + (uint8) r, (uint8) g, (uint8) b); + result = hexcolor; + /* override hex value if this is a named color */ + for (indx = 16; indx < SIZE(colortable); ++indx) + if (colortable[indx].r == r + && colortable[indx].g == g + && colortable[indx].b == b) { + result = colortable[indx].name; + break; + } + } + } + return result; +} + +/*coloratt.c*/ diff --git a/src/options.c b/src/options.c index 427f2930e..6b4691e1e 100644 --- a/src/options.c +++ b/src/options.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 options.c $NHDT-Date: 1708737173 2024/02/24 01:12:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.709 $ */ +/* NetHack 3.7 options.c $NHDT-Date: 1710792444 2024/03/18 20:07:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.723 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2008. */ /* NetHack may be freely redistributed. See license for details. */ @@ -4677,8 +4677,10 @@ optfn_windowchain( int wcolors_opt[WC_COUNT]; staticfn int -optfn_windowcolors(int optidx, int req, boolean negated UNUSED, - char *opts, char *op) +optfn_windowcolors( + int optidx, int req, + boolean negated UNUSED, + char *opts, char *op) { if (req == do_init) { int wccount; @@ -4691,8 +4693,7 @@ optfn_windowcolors(int optidx, int req, boolean negated UNUSED, if (req == do_set) { /* WINCAP * setting window colors - * syntax: windowcolors=menu foregrnd/backgrnd text - * foregrnd/backgrnd + * syntax: windowcolors=menu foregrnd/backgrnd text foregrnd/backgrnd */ if ((op = string_for_opt(opts, FALSE)) != empty_optstr) { if (!wc_set_window_colors(op)) { @@ -4704,8 +4705,8 @@ optfn_windowcolors(int optidx, int req, boolean negated UNUSED, return optn_ok; } if (req == get_val || req == get_cnf_val) { - Sprintf( - opts, "%s/%s %s/%s %s/%s %s/%s", + /* FIXME: this constructed value is not correct for 'get_cnf_val' */ + Sprintf(opts, "%s/%s %s/%s %s/%s %s/%s", iflags.wcolors[wcolor_menu].fg ? iflags.wcolors[wcolor_menu].fg : defbrief, @@ -9649,13 +9650,12 @@ wc_set_window_colors(char *op) * menu white/black message green/yellow status white/blue text * white/black */ - int j; - char buf[BUFSZ]; - char *wn, *tfg, *tbg, *newop; static const char *const wnames[WC_COUNT] = { "menu", "message", "status", "text" }; - static const char *const shortnames[WC_COUNT] = { "mnu", "msg", "sts", "txt" }; + static const char *const shortnames[WC_COUNT] = { + "mnu", "msg", "sts", "txt" + }; static char **fgp[] = { &iflags.wcolors[wcolor_menu].fg, &iflags.wcolors[wcolor_message].fg, &iflags.wcolors[wcolor_status].fg, @@ -9664,6 +9664,10 @@ wc_set_window_colors(char *op) &iflags.wcolors[wcolor_message].bg, &iflags.wcolors[wcolor_status].bg, &iflags.wcolors[wcolor_text].bg }; + int j; + int32 clr; + char buf[BUFSZ]; + char *wn, *tfg, *tbg, *newop; Strcpy(buf, op); newop = mungspaces(buf); @@ -9718,22 +9722,28 @@ wc_set_window_colors(char *op) if (!strstri(tfg, " ")) { if (*fgp[j]) free((genericptr_t) *fgp[j]); - *fgp[j] = dupstr(tfg); + clr = check_enhanced_colors(tfg); + *fgp[j] = dupstr((clr >= 0) ? wc_color_name(clr) : tfg); } if (!strstri(tbg, " ")) { if (*bgp[j]) free((genericptr_t) *bgp[j]); - *bgp[j] = dupstr(tbg); + clr = check_enhanced_colors(tbg); + *bgp[j] = dupstr((clr >= 0) ? wc_color_name(clr) : tbg); } if (wcolors_opt[j] != 0) { config_error_add( - "windowcolors for %s windows specified multiple times", - wnames[j]); + "windowcolors for %s windows specified multiple times", + wnames[j]); } wcolors_opt[j]++; break; } } + if (j == WC_COUNT) { + config_error_add("windowcolors for unrecognized window type: %s", + wn); + } } return 1; }