From a587ccaa266782973296db54b9355cafa8d820ef Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 28 Apr 2025 18:12:02 -0700 Subject: [PATCH] merge new use_menu_glyphs option with menu_objsyms The two options are very similar but probably mutually exclusive except when using look-here and look-into-container (both via ':') with the default setting for 'sortloot', or with inventory when 'sortpack' has been toggled off. This removes 'use_menu_glyphs' and changes 'menu_objsyms' from a boolean to a compound taking six possible values: | 0: no object symbols in menus, | 1: append object class symbol to object header lines (same as old |menu_objsyms boolean), | 2: include object symbol in menu entry lines for objects (same as |recently added use_menu_glyphs), | 3: both 1 and 2, | 4: display as #2 but only if the menu lacks class header lines, | 5: if header lines are present, display as #1; if headers are not |present, then display as #4 (which will implicitly be #2). Default is #4. Effectively replaces the options portion of pull request #1406 and retains the functionality, but not as default for normal menus. Guidebook.tex is only partially updated. Someone else will need to finish that. --- dat/opthelp | 12 +++- doc/Guidebook.mn | 37 ++++++++-- doc/Guidebook.tex | 36 +++++++++- include/flag.h | 14 ++-- include/optlist.h | 9 +-- src/options.c | 155 ++++++++++++++++++++++++++++++++++++++++++ win/curses/cursdial.c | 22 +++++- win/tty/wintty.c | 29 +++++--- 8 files changed, 281 insertions(+), 33 deletions(-) diff --git a/dat/opthelp b/dat/opthelp index 330dd963a..16106b16c 100644 --- a/dat/opthelp +++ b/dat/opthelp @@ -40,7 +40,6 @@ mail enable the mail daemon [True] mention_decor give feedback when walking across stairs, altars, [False] fountains, and such even when not obscured by objects mention_walls give feedback when walking against a wall [False] -menu_objsyms show object symbols in menus if it is selectable [False] menu_overlay overlay menus on the screen and align to right [True] menucolors enable MENUCOLOR pattern matching to highlight [False] lines in object menus like inventory; might highlight with @@ -80,7 +79,6 @@ travel enables travelling via mouse click if supported; [True] attempting to move the hero; does not affect travel via '_' use_darkgray use bold black instead of blue for black glyphs. [True] use_inverse display detected monsters in highlighted manner [False] -use_menu_glyphs show object glyphs in menu items (tty, curses) [True] verbose print more commentary during the game [True] whatis_menu show menu when getting a map location [False] whatis_moveskip skip same glyphs when getting a map location [False] @@ -191,6 +189,16 @@ menustyle user interface for selection of multiple objects: [Full] only the first letter ('T','C','F','P') matters (With Traditional, many actions allow pseudo-class 'm' to request a menu for choosing items: one-shot Combination.) +menu_objsyms whether to include object class symbols in menus: [5] + 0 - none -- don't add object symbols to menus; + 1 - headers -- append object class symbol to menu header lines; + 2 - entries -- show object glyphs (same as class symbol + for ASCII interfaces) on each menu entry line; + 3 - both -- 1 and 2 combined; + 4 - conditional -- as 2 but only if no headers are present; + 5 - one-or-other -- 1 and 4 combined; + choices 0 and 1 should work with any interface; 2 through 5 + are supported by tty and curses msg_window behavior of ^P message recall for tty interface: [s] single -- one message at a time full -- full window with all saved top line messages diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index fb2f21156..7d3530359 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -4169,8 +4169,38 @@ Default \(oq|\(cq. Key to go to the next menu page. Default \(oq>\(cq. .lp menu_objsyms -Show object symbols in menu headings in menus where -the object symbols act as menu accelerators (default off). +." [originally menu_objsyms was a boolean] +." Show object symbols in menu headings in menus where +." the object symbols act as menu accelerators (default off). +Inventory and other object menus are normally separated by object class +(weapons, armor, and so forth), with a menu header line at the beginning +of each group. +You can have menus add the display symbol for the class of objects for +each header line. +You can also add the display symbol for the individual item in each menu +entry. +For a tiles map, that would be a small rendition of an object's tile. +For a text map, it is the same character as is used for the object's +class, which would be most useful when there are no headers separating +objects among classes. +Possible values are +.PS "5\ -\ One-or-other" +.PL "0\ -\ None" +no symbols for either header lines or menu entries; +.PL "1\ -\ Headers" +show symbols on header lines but not entries; +.PL "2\ -\ Entries" +show symbols on menu entry lines but not headers; +.PL "3\ -\ Both" +show symbols on headers and entries; +.PL "4\ -\ Conditional" +only show symbols for entries if there are no headers; +.PL "5\ -\ One-or-other" +show symbols on headers, or on entries if no headers. +.PE +Supported by tty and curses. +When setting the value, it can be specified by digit or keyword. +The default value is \f(CRConditional\fP (4). .lp menu_overlay Do not clear the screen before drawing menus, and align menus to the right edge of the screen. Only for the tty port. @@ -4988,9 +5018,6 @@ to be \fIFalse\fP. Use bold black instead of blue for black glyphs (TTY only). .lp use_inverse If NetHack can, it should display inverse when the game specifies it. -.lp use_menu_glyphs -If NetHack can, it should display glyphs next to objects in the -inventory. .lp vary_msgcount If NetHack can, it should display this number of messages at a time in the message window. diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 14cea949b..6d7f1d38c 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -4576,8 +4576,40 @@ Key to go to the next menu page. Implemented by the Amiga, Gem and tty ports. Default `\verb+>+'. \item[\ib{menu\verb+_+objsyms}] -Show object symbols in menu headings in menus where -the object symbols act as menu accelerators (default off). +% [originally menu_objsyms was a boolean] +% Show object symbols in menu headings in menus where +% the object symbols act as menu accelerators (default off). +Inventory and other object menus are normally separated by object class +(weapons, armor, and so forth), with a menu header line at the beginning +of each group. +You can have menus add the display symbol for the class of objects for +each header line. +You can also add the display symbol for the individual item in each menu +entry. +For a tiles map, that would be a small rendition of an object's tile. +For a text map, it is the same character as is used for the object's +class, which would be most useful when there are no headers separating +objects among classes. +% FIXME! -- three column table may be simpler than mashing first two together +% Possible values are +% .PS "5\ -\ One-or-other" +% .PL "0\ -\ None" +% no symbols for either header lines or menu entries; +% .PL "1\ -\ Headers" +% show symbols on header lines but not entries; +% .PL "2\ -\ Entries" +% show symbols on menu entry lines but not headers; +% .PL "3\ -\ Both" +% show symbols on headers and entries; +% .PL "4\ -\ Conditional" +% only show symbols for entries if there are no headers; +% .PL "5\ -\ One-or-other" +% show symbols on headers, or on entries if no headers. +% .PE + +Supported by tty and curses. +When setting the value, it can be specified by digit or keyword. +The default value is {\tt Conditional} (4). \item[\ib{menu\verb+_+overlay}] Do not clear the screen before drawing menus, and align menus to the right edge of the screen. Only for the tty port. diff --git a/include/flag.h b/include/flag.h index 798d923c9..d586f3c5f 100644 --- a/include/flag.h +++ b/include/flag.h @@ -264,6 +264,8 @@ struct instance_flags { int getloc_filter; /* GFILTER_foo */ int in_lava_effects; /* hack for Boots_off() */ int last_msg; /* indicator of last message player saw */ + int menuobjsyms; /* value of 'menu_objsyms' option; + * ought to be in flags rather than iflags */ int override_ID; /* true to force full identification of objects */ int parse_config_file_src; /* hack for parse_config_line() */ int purge_monsters; /* # of dead monsters still on fmon list */ @@ -300,13 +302,13 @@ struct instance_flags { */ unsigned msg_history; /* hint: # of top lines to save */ int getpos_coords; /* show coordinates when getting cursor position */ - int menuinvertmode; /* 0 = invert toggles every item; - 1 = invert skips 'all items' item */ + int menuinvertmode; /* 0 = invert toggles every item; + * 1 = invert skips 'all items' item */ color_attr menu_headings; /* CLR_ and ATR_ for menu headings */ uint32_t colorcount; /* store how many colors terminal is capable of */ boolean use_truecolor; /* force use of truecolor */ #ifdef ALTMETA - boolean altmeta; /* Alt-c sends ESC c rather than M-c */ + boolean altmeta; /* Alt+c sends ESC c rather than M-c */ #endif boolean autodescribe; /* autodescribe mode in getpos() */ boolean cbreak; /* in cbreak mode, rogue format */ @@ -315,7 +317,8 @@ struct instance_flags { boolean echo; /* 1 to echo characters */ boolean force_invmenu; /* always menu when handling inventory */ boolean hilite_pile; /* mark piles of objects with a hilite */ - boolean menu_head_objsym; /* Show obj symbol in menu headings */ + boolean menu_head_objsym; /* Show obj symbol in menu headings; controlled + * by 'menuobjsyms' */ boolean menu_overlay; /* Draw menus over the map */ boolean menu_requested; /* Flag for overloaded use of 'm' prefix * on some non-move commands */ @@ -334,7 +337,8 @@ struct instance_flags { boolean tux_penalty; /* True iff hero is a monk and wearing a suit */ boolean use_background_glyph; /* use background glyph when appropriate */ boolean use_menu_color; /* use color in menus; only if wc_color */ - boolean use_menu_glyphs; /* use object glyphs in menus, if the port supports it */ + boolean use_menu_glyphs; /* use object glyphs in menus, if the port + * supports it; controlled by 'menuobjsyms' */ #ifdef STATUS_HILITES long hilite_delta; /* number of moves to leave a temp hilite lit */ long unhilite_deadline; /* time when oldest temp hilite should be unlit */ diff --git a/include/optlist.h b/include/optlist.h index 9d2db23c1..b0bc715f3 100644 --- a/include/optlist.h +++ b/include/optlist.h @@ -442,9 +442,9 @@ static int optfn_##a(int, int, boolean, char *, char *); No, Yes, No, No, NoAlias, "jump to the last page in a menu") NHOPTC(menu_next_page, Advanced, 4, opt_in, set_in_config, No, Yes, No, No, NoAlias, "go to the next menu page") - NHOPTB(menu_objsyms, Advanced, 0, opt_in, set_in_game, - Off, Yes, No, No, NoAlias, &iflags.menu_head_objsym, - Term_False, "show object symbols in menus") + NHOPTC(menu_objsyms, Advanced, 12, opt_in, set_in_game, + Yes, Yes, No, Yes, "use_menu_glyphs", + "show object symbols in menus") #ifdef TTY_GRAPHICS NHOPTB(menu_overlay, Advanced, 0, opt_in, set_in_game, On, Yes, No, No, NoAlias, &iflags.menu_overlay, Term_False, @@ -789,9 +789,6 @@ static int optfn_##a(int, int, boolean, char *, char *); NHOPTB(use_inverse, Advanced, 0, opt_out, set_in_game, On, Yes, No, No, NoAlias, &iflags.wc_inverse, Term_False, "display detected monsters in inverse") - NHOPTB(use_menu_glyphs, Advanced, 0, opt_out, set_in_game, - On, Yes, No, No, NoAlias, &iflags.use_menu_glyphs, - Term_False, "show object glyphs in menu items") NHOPTB(use_truecolor, Advanced, 0, opt_in, set_in_config, Off, Yes, No, No, "use_truecolour", &iflags.use_truecolor, Term_False, diff --git a/src/options.c b/src/options.c index 22963b343..704351790 100644 --- a/src/options.c +++ b/src/options.c @@ -257,6 +257,46 @@ static NEARDATA const char *perminv_modes[][3] = { /*8*/ { "in-use", "inuse-only", "subset: items currently in use" }, }; +struct objsymopt { + int num; + const char *nam; + const char *descr; +}; + +/* + * menuobjsyms: + * Inventory display for the various values of menuobjsyms. + * 4' and 5' represent !sortpack which lacks headers; they + * produce the same result. + * + * 0: 1: + * Weapons Weapons (')') + * a - 15 darts a - 15 darts + * Armor Armor ('[') + * b - Hawaiian shirt b - Hawaiian shirt + * 2: 3: + * Weapons Weapons (')') + * a ) 15 darts a ) 15 darts + * Armor Armor ('[') + * b [ Hawaiian shirt b [ Hawaiian shirt + * 4: 5: + * Weapons Weapons (')') + * a - 15 darts a - 15 darts + * Armor Armor ('[') + * b - Hawaiian shirt b - Hawaiian shirt + * 4': 5': + * a ) 15 darts a ) 15 darts + * b [ Hawaiian shirt b [ Hawaiian shirt + */ +static const struct objsymopt objsymvals[] = { + { 0, "none", "don't show object symbols in menus" }, + { 1, "headers", "show object symbols in menu header lines" }, + { 2, "entries", "show object symbols in individual menu entries" }, + { 3, "both", "show object symbols in headers and menu entries" }, + { 4, "conditional", "show objsyms in entries if no headers are shown" }, + { 5, "one-or-other", "show objsyms in header, in entries if no header" }, +}; + /* * Default menu manipulation command accelerators. These may _not_ be: * @@ -323,6 +363,7 @@ staticfn void rejectoption(const char *); staticfn char *string_for_opt(char *, boolean); staticfn char *string_for_env_opt(const char *, char *, boolean); staticfn void bad_negation(const char *, boolean); +staticfn void set_menuobjsyms_flags(int); staticfn int change_inv_order(char *); staticfn boolean warning_opts(char *, const char *); staticfn int feature_alert_opts(char *, const char *); @@ -368,6 +409,7 @@ staticfn int handler_align_misc(int); staticfn int handler_autounlock(int); staticfn int handler_disclose(void); staticfn int handler_menu_headings(void); +staticfn int handler_menu_objsyms(void); staticfn int handler_menustyle(void); staticfn int handler_msg_window(void); staticfn int handler_number_pad(void); @@ -2187,6 +2229,71 @@ optfn_menu_headings( return optn_ok; } +staticfn int +optfn_menu_objsyms( + int optidx, int req, + boolean negated, + char *opts, char *op) +{ + if (req == do_init) { + /* set iflags.menu_objsyms to 4, "conditional"; also sets + iflags.menu_head_objsym to False and + iflags.use_menu_glyphs True */ + set_menuobjsyms_flags(4); + return optn_ok; + } + if (req == do_set) { + unsigned k, l; + int i, osyms; + + if (negated) { + /* allow '!menu_objsyms' (and '!use_menu_glyphs') as + 'menu_objsyms:none' (0) */ + osyms = 0; + } else if (op == empty_optstr) { + /* treat boolean 'menu_objsyms' as 'menu_objsyms:headers' (1) + accept obsolete boolean 'use_menu_glyphs' as a synonym + for 'menu_objsyms:entries' (2) */ + osyms = !strncmp(opts, "use_menu_glyphs", 15) ? 2 : 1; + } else if (digit(*op)) { + i = atoi(op); + if (i >= SIZE(objsymvals)) { + config_error_add("Illegal %s parameter '%s'", + allopt[optidx].name, op); + return optn_err; + } + osyms = i; + } else { + /* stilted "one-or-other" is used to compress the menu width */ + static const char alt5[] = "one-or-the-other"; + unsigned l5 = (unsigned) (sizeof alt5 - sizeof ""); + + osyms = 0; + k = (unsigned) strlen(op); + for (i = 0; i < SIZE(objsymvals); ++i) { + l = (unsigned) strlen(objsymvals[i].nam); + if (k >= 4) + l = k; + if (!strncmpi(objsymvals[i].nam, op, l) + || (i == 5 && !strncmpi(alt5, op, l5))) { + osyms = i; + break; + } + } + } + set_menuobjsyms_flags(osyms); + return optn_ok; + } + if (req == get_val || req == get_cnf_val) { + Sprintf(opts, "%s", objsymvals[iflags.menuobjsyms].nam); + return optn_ok; + } + if (req == do_handler) { + return handler_menu_objsyms(); + } + return optn_ok; +} + staticfn int optfn_menuinvertmode( int optidx, int req, @@ -5671,6 +5778,43 @@ handler_menu_headings(void) return optn_ok; } +staticfn int +handler_menu_objsyms(void) +{ + winid tmpwin; + anything any; + char buf[BUFSZ]; + menu_item *picklist = (menu_item *) 0; + const char sep = iflags.menu_tab_sep ? '\t' : ' '; + int i, j, n, clr = NO_COLOR; + + tmpwin = create_nhwindow(NHW_MENU); + start_menu(tmpwin, MENU_BEHAVE_STANDARD); + any = cg.zeroany; + for (i = 0; i < SIZE(objsymvals); ++i) { + Snprintf(buf, sizeof buf, "%-12.12s%c%.60s", + objsymvals[i].nam, sep, objsymvals[i].descr); + any.a_int = i + 1; + j = objsymvals[i].num; + add_menu(tmpwin, &nul_glyphinfo, &any, '0' + i, *buf, + ATR_NONE, clr, buf, + (j == iflags.menuobjsyms) ? MENU_ITEMFLAGS_SELECTED + : MENU_ITEMFLAGS_NONE); + } + end_menu(tmpwin, "Set object symbols in menus to what?"); + n = select_menu(tmpwin, PICK_ONE, &picklist); + if (n > 0) { + i = picklist[0].item.a_int - 1; + /* if there are two picks, use the one that wasn't pre-selected */ + if (n > 1 && i == iflags.menuobjsyms) + i = picklist[1].item.a_int - 1; + set_menuobjsyms_flags(i); + free((genericptr_t) picklist); + } + destroy_nhwindow(tmpwin); + return optn_ok; +} + staticfn int handler_msg_window(void) { @@ -7033,6 +7177,7 @@ initoptions_init(void) flags.pile_limit = PILE_LIMIT_DFLT; /* 5 */ flags.runmode = RUN_LEAP; iflags.msg_history = 20; + /* msg_window has conflicting defaults for multi-interface binary */ #ifdef TTY_GRAPHICS iflags.prevmsg_window = 's'; @@ -7310,6 +7455,16 @@ initoptions_finish(void) ******************************************* */ +/* iflags.menuobjsyms also controls iflags.menu_head_objsym, and + iflags.use_menu_glyphs; they affect execution but are no longer options */ +staticfn void +set_menuobjsyms_flags(int newobjsyms) +{ + iflags.menuobjsyms = newobjsyms; + iflags.menu_head_objsym = ((newobjsyms & 1) != 0) ? TRUE : FALSE; + iflags.use_menu_glyphs = ((newobjsyms & (2 | 4)) != 0) ? TRUE : FALSE; +} + /* * Change the inventory order, using the given string as the new order. * Missing characters in the new order are filled in at the end from diff --git a/win/curses/cursdial.c b/win/curses/cursdial.c index 93157cd37..85803a5a8 100644 --- a/win/curses/cursdial.c +++ b/win/curses/cursdial.c @@ -60,6 +60,7 @@ typedef struct nhm { unsigned long mbehavior; /* menu flags */ boolean reuse_accels; /* Non-unique accelerators per page */ boolean bottom_heavy; /* display multi-page menu starting at end */ + boolean show_obj_syms; /* handle iflags.menuobjsyms */ struct nhm *prev_menu; /* Pointer to previous menu */ struct nhm *next_menu; /* Pointer to next menu */ } nhmenu; @@ -552,6 +553,7 @@ curses_create_nhmenu(winid wid, unsigned long mbehavior) new_menu->mbehavior = mbehavior; new_menu->reuse_accels = FALSE; new_menu->bottom_heavy = FALSE; + new_menu->show_obj_syms = FALSE; return; } @@ -565,6 +567,7 @@ curses_create_nhmenu(winid wid, unsigned long mbehavior) new_menu->mbehavior = mbehavior; new_menu->reuse_accels = FALSE; new_menu->bottom_heavy = FALSE; + new_menu->show_obj_syms = FALSE; new_menu->next_menu = NULL; if (nhmenus == NULL) { /* no menus in memory yet */ @@ -1029,6 +1032,18 @@ menu_win_size(nhmenu *menu) int maxentrywidth = 0; int maxheaderwidth = menu->prompt ? (int) strlen(menu->prompt) : 0; nhmenu_item *menu_item_ptr, *last_item_ptr = NULL; + boolean only_if_no_headers = (iflags.menuobjsyms & 4) != 0; + + /* check entire menu rather than one page at a time */ + menu->show_obj_syms = iflags.use_menu_glyphs; + if (only_if_no_headers) { + for (menu_item_ptr = menu->entries; menu_item_ptr != NULL; + menu_item_ptr = menu_item_ptr->next_item) + if (menu_item_ptr->identifier.a_void == 0) { + menu->show_obj_syms = FALSE; + break; + } + } #if 0 /* maxwidth is set below, so the value calculated here isn't used */ if (program_state.gameover) { @@ -1061,7 +1076,7 @@ menu_win_size(nhmenu *menu) /* Add space for accelerator (selector letter) */ curentrywidth += 4; if (menu_item_ptr->glyphinfo.glyph != NO_GLYPH - && iflags.use_menu_glyphs) + && menu->show_obj_syms) curentrywidth += 2; } if (curentrywidth > maxentrywidth) { @@ -1282,10 +1297,11 @@ menu_display_page( start_col += 4; } if (menu_item_ptr->glyphinfo.glyph != NO_GLYPH - && iflags.use_menu_glyphs) { + && menu->show_obj_syms) { color = menu_item_ptr->glyphinfo.gm.sym.color; curses_toggle_color_attr(win, color, NONE, ON); - mvwaddch(win, menu_item_ptr->line_num + 1, start_col, menu_item_ptr->glyphinfo.ttychar); + mvwaddch(win, menu_item_ptr->line_num + 1, start_col, + menu_item_ptr->glyphinfo.ttychar); curses_toggle_color_attr(win, color, NONE, OFF); mvwaddch(win, menu_item_ptr->line_num + 1, start_col + 1, ' '); entry_cols -= 2; diff --git a/win/tty/wintty.c b/win/tty/wintty.c index d042e6c9d..4c7a107dc 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -1330,7 +1330,8 @@ process_menu_window(winid window, struct WinDesc *cw) tty_menu_item *page_start, *page_end, *curr; long count; int n, attr_n, curr_page, page_lines, resp_len, previous_page_lines; - boolean finished, counting, reset_count; + boolean finished, counting, reset_count, show_obj_syms, + only_if_no_headers = (iflags.menuobjsyms & 4) != 0; char *cp, *rp, resp[QBUFSZ], gacc[QBUFSZ], *msave, *morestr, really_morc; #define MENU_EXPLICIT_CHOICE 0x7f /* pseudo menu manipulation char */ @@ -1378,6 +1379,15 @@ process_menu_window(winid window, struct WinDesc *cw) } resp_len = 0; /* lint suppression */ + show_obj_syms = iflags.use_menu_glyphs; + if (only_if_no_headers) { + for (curr = cw->mlist; curr; curr = curr->next) + if (curr->identifier.a_void == 0) { + show_obj_syms = FALSE; + break; + } + } + /* loop until finished */ while (!finished) { HUPSKIP(); @@ -1432,7 +1442,7 @@ process_menu_window(winid window, struct WinDesc *cw) if (curr->str[0] && curr->str[1] == ' ' && curr->str[2] && strchr("-+#", curr->str[2]) && curr->str[3] == ' ') - /* [0]=letter, [1]==space, [2]=[-+#], [3]=space */ + /* [0]=letter, [1]=space, [2]=[-+#], [3]=space */ attr_n = 4; /* [4:N]=entry description */ /* @@ -1454,15 +1464,14 @@ process_menu_window(winid window, struct WinDesc *cw) if (n == attr_n && (color != NO_COLOR || attr != ATR_NONE)) toggle_menu_attr(TRUE, color, attr); - if (n == 2 - && curr->identifier.a_void != 0 + if (n == 2 && curr->identifier.a_void != 0 && curr->selected) { - if (curr->count == -1L) - (void) putchar('+'); /* all selected */ - else - (void) putchar('#'); /* count selected */ - } else if (iflags.use_menu_glyphs && n == 2 - && curr->identifier.a_void != 0 + char c = (curr->count == -1L) ? '*' : '#'; + + /* all selected: '*' vs count selected: '#' */ + (void) putchar(c); + } else if (n == 2 && curr->identifier.a_void != 0 + && show_obj_syms && curr->glyphinfo.glyph != NO_GLYPH) { int gcolor = curr->glyphinfo.gm.sym.color;