From: Pasi Kallinen Date: Tue, 17 Mar 2015 20:50:11 +0000 (+0200) Subject: Add menucolors X-Git-Tag: NetHack-3.6.0_RC01~492^2~11 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c8e781c4181ccbf1eec8bf3722a31b9f528b96c2;p=nethack Add menucolors -Add a boolean option menucolors to toggle menu color -Add MENUCOLOR -config file option TODO: -Better support for win32 -Support more windowports -Update Guidebook -Allow changing menucolor lines in-game --- diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 46b87d58f..5fa64755d 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -1132,6 +1132,7 @@ smartphone: added "Type Cmd" command that allows to type arbitrary commands smartphone: added Q(quiver) command to "Attack" layout smartphone: fixed F command to prompt for direction unix,vms: altmeta option to handle terminals which send "ESC c" for Alt+c +tty,win32gui,win32tty: add menucolors NetHack Community Patches (or Variation) Included diff --git a/include/color.h b/include/color.h index ab6fe0462..f7bec4a08 100644 --- a/include/color.h +++ b/include/color.h @@ -7,6 +7,10 @@ #ifndef COLOR_H #define COLOR_H +#ifdef MENU_COLOR_REGEX +#include +#endif + /* * The color scheme used is tailored for an IBM PC. It consists of the * standard 8 colors, folowed by their bright counterparts. There are @@ -51,4 +55,18 @@ #define DRAGON_SILVER CLR_BRIGHT_CYAN #define HI_ZAP CLR_BRIGHT_BLUE +struct menucoloring { +# ifdef MENU_COLOR_REGEX +# ifdef MENU_COLOR_REGEX_POSIX + regex_t match; +# else + struct re_pattern_buffer match; +# endif +# else + char *match; +# endif + int color, attr; + struct menucoloring *next; +}; + #endif /* COLOR_H */ diff --git a/include/config.h b/include/config.h index d8c96af14..c5e53abf6 100644 --- a/include/config.h +++ b/include/config.h @@ -437,6 +437,14 @@ typedef unsigned char uchar; * bugs left here. */ +/* Menucolors */ +# define MENU_COLOR_REGEX /* use GNU regex */ +/*# define MENU_COLOR_REGEX_POSIX*/ /* use POSIX regex */ +/* if neither is defined, uses pmatch() + * pmatch() provides basic globbing: '*' and '?' wildcards. + */ + + #define STATUS_VIA_WINDOWPORT /* re-work of the status line updating process */ #define STATUS_HILITES /* support hilites of status fields */ /* #define WINCHAIN*/ /* stacked window systems */ diff --git a/include/extern.h b/include/extern.h index 4e2780c6b..28680c5fa 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1583,6 +1583,9 @@ E void FDECL(parsesymbols, (char *)); E struct symparse *FDECL(match_sym, (char *)); E void NDECL(set_playmode); E int FDECL(sym_val, (char *)); +E boolean FDECL(add_menu_coloring, (char *)); +E boolean FDECL(get_menu_coloring, (char *, int *, int *)); +E void NDECL(free_menu_coloring); /* ### pager.c ### */ diff --git a/include/flag.h b/include/flag.h index 9eb7a68c6..072fb4a30 100644 --- a/include/flag.h +++ b/include/flag.h @@ -201,6 +201,7 @@ struct instance_flags { boolean rlecomp; /* run-length comp of levels when writing savefile */ uchar num_pad_mode; boolean echo; /* 1 to echo characters */ + boolean use_menu_color; /* use color in menus; only if wc_color */ #if 0 boolean DECgraphics; /* use DEC VT-xxx extended character set */ boolean IBMgraphics; /* use IBM extended character set */ diff --git a/src/decl.c b/src/decl.c index 6529336b2..d9429dbcf 100644 --- a/src/decl.c +++ b/src/decl.c @@ -219,6 +219,8 @@ NEARDATA struct c_color_names c_color_names = { "white" }; +struct menucoloring *menu_colorings = NULL; + const char *c_obj_colors[] = { "black", /* CLR_BLACK */ "red", /* CLR_RED */ diff --git a/src/files.c b/src/files.c index 179cd3437..f3b9eb610 100644 --- a/src/files.c +++ b/src/files.c @@ -2290,6 +2290,8 @@ int src; } else if (match_varname(buf, "BOULDER", 3)) { (void) get_uchars(fp, buf, bufp, &iflags.bouldersym, TRUE, 1, "BOULDER"); + } else if (match_varname(buf, "MENUCOLOR", 9)) { + (void) add_menu_coloring(bufp); } else if (match_varname(buf, "WARNINGS", 5)) { (void) get_uchars(fp, buf, bufp, translate, FALSE, WARNCOUNT, "WARNINGS"); diff --git a/src/options.c b/src/options.c index 742958fc3..54e0471e8 100644 --- a/src/options.c +++ b/src/options.c @@ -141,6 +141,7 @@ static struct Bool_Opt {"mail", (boolean *)0, TRUE, SET_IN_FILE}, #endif {"mention_walls", &iflags.mention_walls, FALSE, SET_IN_GAME}, + {"menucolors", &iflags.use_menu_color, FALSE, SET_IN_GAME}, /* for menu debugging only*/ {"menu_tab_sep", &iflags.menu_tab_sep, FALSE, SET_IN_GAME}, {"menu_objsyms", &iflags.menu_head_objsym, FALSE, SET_IN_GAME}, @@ -1090,6 +1091,174 @@ STATIC_VAR const struct paranoia_opts { { ~0, "all", 3, 0, 0, 0 }, /* ditto */ }; + +extern struct menucoloring *menu_colorings; + +static const struct { + const char *name; + const int color; +} colornames[] = { + {"black", CLR_BLACK}, + {"red", CLR_RED}, + {"green", CLR_GREEN}, + {"brown", CLR_BROWN}, + {"blue", CLR_BLUE}, + {"magenta", CLR_MAGENTA}, + {"cyan", CLR_CYAN}, + {"gray", CLR_GRAY}, + {"grey", CLR_GRAY}, + {"orange", CLR_ORANGE}, + {"lightgreen", CLR_BRIGHT_GREEN}, + {"yellow", CLR_YELLOW}, + {"lightblue", CLR_BRIGHT_BLUE}, + {"lightmagenta", CLR_BRIGHT_MAGENTA}, + {"lightcyan", CLR_BRIGHT_CYAN}, + {"white", CLR_WHITE} +}; + +static const struct { + const char *name; + const int attr; +} attrnames[] = { + {"none", ATR_NONE}, + {"bold", ATR_BOLD}, + {"dim", ATR_DIM}, + {"underline", ATR_ULINE}, + {"blink", ATR_BLINK}, + {"inverse", ATR_INVERSE} +}; + +/* parse '"regex_string"=color&attr' and add it to menucoloring */ +boolean +add_menu_coloring(str) +char *str; +{ + int i, c = NO_COLOR, a = ATR_NONE; + struct menucoloring *tmp; + char *tmps, *cs = strchr(str, '='); +#ifdef MENU_COLOR_REGEX_POSIX + int errnum; + char errbuf[80]; +#endif + const char *err = (char *)0; + + if (!cs || !str) return FALSE; + + tmps = cs; + tmps++; + while (*tmps && isspace(*tmps)) tmps++; + + for (i = 0; i < SIZE(colornames); i++) + if (strstri(tmps, colornames[i].name) == tmps) { + c = colornames[i].color; + break; + } + if ((i == SIZE(colornames)) && (*tmps >= '0' && *tmps <='9')) + c = atoi(tmps); + + if (c > 15) return FALSE; + + tmps = strchr(str, '&'); + if (tmps) { + tmps++; + while (*tmps && isspace(*tmps)) tmps++; + for (i = 0; i < SIZE(attrnames); i++) + if (strstri(tmps, attrnames[i].name) == tmps) { + a = attrnames[i].attr; + break; + } + if ((i == SIZE(attrnames)) && (*tmps >= '0' && *tmps <='9')) + a = atoi(tmps); + } + + *cs = '\0'; + tmps = str; + if ((*tmps == '"') || (*tmps == '\'')) { + cs--; + while (isspace(*cs)) cs--; + if (*cs == *tmps) { + *cs = '\0'; + tmps++; + } + } + + tmp = (struct menucoloring *)alloc(sizeof(struct menucoloring)); +#ifdef MENU_COLOR_REGEX +#ifdef MENU_COLOR_REGEX_POSIX + errnum = regcomp(&tmp->match, tmps, REG_EXTENDED | REG_NOSUB); + if (errnum != 0) + { + regerror(errnum, &tmp->match, errbuf, sizeof(errbuf)); + err = errbuf; + } +#else + tmp->match.translate = 0; + tmp->match.fastmap = 0; + tmp->match.buffer = 0; + tmp->match.allocated = 0; + tmp->match.regs_allocated = REGS_FIXED; + err = re_compile_pattern(tmps, strlen(tmps), &tmp->match); +#endif +#else + tmp->match = (char *)alloc(strlen(tmps)+1); + (void) memcpy((genericptr_t)tmp->match, (genericptr_t)tmps, strlen(tmps)+1); +#endif + if (err) { + raw_printf("\nMenucolor regex error: %s\n", err); + wait_synch(); + free(tmp); + return FALSE; + } else { + tmp->next = menu_colorings; + tmp->color = c; + tmp->attr = a; + menu_colorings = tmp; + return TRUE; + } +} + +boolean +get_menu_coloring(str, color, attr) +char *str; +int *color, *attr; +{ + struct menucoloring *tmpmc; + if (iflags.use_menu_color) + for (tmpmc = menu_colorings; tmpmc; tmpmc = tmpmc->next) +#ifdef MENU_COLOR_REGEX +# ifdef MENU_COLOR_REGEX_POSIX + if (regexec(&tmpmc->match, str, 0, NULL, 0) == 0) { +# else + if (re_search(&tmpmc->match, str, strlen(str), 0, 9999, 0) >= 0) { +# endif +#else + if (pmatch(tmpmc->match, str)) { +#endif + *color = tmpmc->color; + *attr = tmpmc->attr; + return TRUE; + } + return FALSE; +} + +void +free_menu_coloring() +{ + struct menucoloring *tmp = menu_colorings; + + while (tmp) { + struct menucoloring *tmp2 = tmp->next; +#ifdef MENU_COLOR_REGEX + (void) regfree(&tmp->match); +#else + free(tmp->match); +#endif + free(tmp); + tmp = tmp2; + } +} + + void parseoptions(opts, tinitial, tfrom_file) register char *opts; @@ -1431,6 +1600,16 @@ boolean tinitial, tfrom_file; return; } + /* menucolor:"regex_string"=color */ + fullname = "menucolor"; + if (match_optname(opts, fullname, 9, TRUE)) { + if (negated) bad_negation(fullname, FALSE); + else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) + if (!add_menu_coloring(op)) + badoption(opts); + return; + } + fullname = "msghistory"; if (match_optname(opts, fullname, 3, TRUE)) { if (duplicate) complain_about_duplicate(opts,1); diff --git a/src/save.c b/src/save.c index 4a4363e9e..094f54042 100644 --- a/src/save.c +++ b/src/save.c @@ -1296,6 +1296,7 @@ void freedynamicdata() { unload_qtlist(); + free_menu_coloring(); free_invbuf(); /* let_to_name (invent.c) */ free_youbuf(); /* You_buf,&c (pline.c) */ tmp_at(DISP_FREEMEM, 0); /* temporary display effects */ diff --git a/sys/share/NetHack.cnf b/sys/share/NetHack.cnf index 29d8ce910..2b16dfcc7 100644 --- a/sys/share/NetHack.cnf +++ b/sys/share/NetHack.cnf @@ -121,3 +121,14 @@ OPTIONS=time,noshowexp,number_pad:2,lit_corridor # DEC Rainbows will hang if rawio is set, so they should instead use: #OPTIONS=BIOS,DECgraphics +# Colored menus. +#OPTIONS=menucolors +# Syntax is: MENUCOLOR="string_to_match"=color&attribute +# Colors: black, red, green, brown, blue, magenta, cyan, gray, orange, +# lightgreen, yellow, lightblue, lightmagenta, lightcyan, white. +# Attributes: none, bold, dim, underline, blink, inverse. +#MENUCOLOR=" blessed "=green +#MENUCOLOR=" holy "=green +#MENUCOLOR=" cursed "=red +#MENUCOLOR=" unholy "=red +#MENUCOLOR=" cursed .* (being worn)"=orange&underline diff --git a/util/makedefs.c b/util/makedefs.c index 8555178e1..7bb689bef 100644 --- a/util/makedefs.c +++ b/util/makedefs.c @@ -1294,6 +1294,11 @@ static const char *build_opts[] = { #ifdef NEWS "news file", #endif +#ifdef MENU_COLOR_REGEX + "menu colors via regular expressions", +#else + "menu colors via pmatch", +#endif #ifdef OVERLAY # ifdef MOVERLAY "MOVE overlays", diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 8c8f5294c..0aaf9e92d 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -1462,6 +1462,8 @@ struct WinDesc *cw; for (page_lines = 0, curr = page_start; curr != page_end; page_lines++, curr = curr->next) { + int color = NO_COLOR, attr = ATR_NONE; + boolean menucolr = FALSE; if (curr->selector) *rp++ = curr->selector; @@ -1477,6 +1479,11 @@ struct WinDesc *cw; * actually output the character. We're faster doing * this. */ + if (iflags.use_menu_color && + (menucolr = get_menu_coloring(curr->str, &color,&attr))) { + term_start_attr(attr); + if (color != NO_COLOR) term_start_color(color); + } else term_start_attr(curr->attr); for (n = 0, cp = curr->str; #ifndef WIN32CON @@ -1494,6 +1501,10 @@ struct WinDesc *cw; (void) putchar('#'); /* count selected */ } else (void) putchar(*cp); + if (iflags.use_menu_color && menucolr) { + if (color != NO_COLOR) term_end_color(); + term_end_attr(attr); + } else term_end_attr(curr->attr); } } else { diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index bd3c60a17..d07af75c5 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -45,7 +45,6 @@ static void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut); #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) static void nhglyph2charcolor(short glyph, uchar* ch, int* color); #endif -static COLORREF nhcolor_to_RGB(int c); HWND mswin_init_map_window () { static int run_once = 0; diff --git a/win/win32/mhmap.h b/win/win32/mhmap.h index 54a614730..e33f64ec3 100644 --- a/win/win32/mhmap.h +++ b/win/win32/mhmap.h @@ -12,6 +12,7 @@ #include "global.h" +COLORREF nhcolor_to_RGB (int c); HWND mswin_init_map_window (void); void mswin_map_stretch(HWND hWnd, LPSIZE lpsz, BOOL redraw); int mswin_map_mode(HWND hWnd, int mode); diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c index e39470dc1..6f32931e3 100644 --- a/win/win32/mhmenu.c +++ b/win/win32/mhmenu.c @@ -917,6 +917,9 @@ BOOL onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) int column; int spacing = 0; + int color = NO_COLOR, attr; + boolean menucolr = FALSE; + lpdis = (LPDRAWITEMSTRUCT) lParam; /* If there are no list box items, skip this message. */ @@ -967,6 +970,13 @@ BOOL onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) buf[0] = item->accelerator; buf[1] = '\x0'; + if (iflags.use_menu_color && + (menucolr = get_menu_coloring(item->str, &color,&attr))) { + /* TODO: use attr too */ + if (color != NO_COLOR) + SetTextColor(lpdis->hDC, nhcolor_to_RGB(color)); + } + SetRect( &drawRect, x, lpdis->rcItem.top, lpdis->rcItem.right, lpdis->rcItem.bottom ); DrawText(lpdis->hDC, NH_A2W(buf, wbuf, 2), 1, &drawRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX); }