User-friendly options menu

Make the default options menu only show the most important
options, split into categories. The full, traditional menu
can be accessed by using the m-prefix.
This commit is contained in:
Pasi Kallinen
2022-08-03 14:07:17 +03:00
parent c7a467701f
commit f3591ea07d
6 changed files with 388 additions and 234 deletions

View File

@@ -2529,7 +2529,7 @@ struct ext_func_tab extcmdlist[] = {
{ 'o', "open", "open a door",
doopen, 0, NULL },
{ 'O', "options", "show option settings, possibly change them",
doset, IFBURIED | GENERALCMD, NULL },
doset, IFBURIED | GENERALCMD | CMD_M_PREFIX, NULL },
/* #overview used to need autocomplete and has retained that even
after being assigned to ^O [old wizard mode ^O is now #wizwhere] */
{ C('o'), "overview", "show a summary of the explored dungeon",

View File

@@ -64,7 +64,7 @@ enum opt {
#define NHOPT_PARSE
static struct allopt_t allopt_init[] = {
#include "optlist.h"
{(const char *) 0, 0, 0, 0, set_in_sysconf, BoolOpt,
{(const char *) 0, OptS_Advanced, 0, 0, 0, set_in_sysconf, BoolOpt,
No, No, No, No, 0, (boolean *) 0,
(int (*)(int, int, boolean, char *, char *)) 0,
(char *) 0, (const char *) 0, (const char *) 0, 0, 0, 0}
@@ -112,6 +112,11 @@ extern char ttycolors[CLR_MAX]; /* in sys/msdos/video.c */
static char empty_optstr[] = { '\0' };
boolean duplicate, using_alias;
static boolean give_opt_msg = TRUE;
static NEARDATA const char *OptS_type[OptS_Advanced+1] = {
"General", "Behavior", "Map", "Status", "Advanced"
};
static const char def_inv_order[MAXOCLASSES] = {
COIN_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS,
@@ -297,6 +302,7 @@ static void free_one_menu_coloring(int);
static int count_menucolors(void);
static boolean parse_role_opts(int, boolean, const char *,
char *, char **);
static int doset_simple(void);
static unsigned int longest_option_name(int, int);
static void doset_add_menu(winid, const char *, int, int);
static int handle_add_list_remove(const char *, int);
@@ -1360,7 +1366,8 @@ optfn_fruit(int optidx UNUSED, int req, boolean negated,
a new fruit; it can only be nonNull if no fruits have
been created since the previous name was put in place */
(void) fruitadd(g.pl_fruit, forig);
pline("Fruit is now \"%s\".", g.pl_fruit);
if (give_opt_msg)
pline("Fruit is now \"%s\".", g.pl_fruit);
}
/* If initial, then initoptions is allowed to do it instead
* of here (initoptions always has to do it even if there's
@@ -4552,8 +4559,9 @@ optfn_boolean(int optidx, int req, boolean negated, char *opts, char *op)
/* boolean value has been toggled but some option changes can
still be pending at this point (mainly for opt_need_redraw);
give the toggled message now regardless */
pline("'%s' option toggled %s.", allopt[optidx].name,
!negated ? "on" : "off");
if (give_opt_msg)
pline("'%s' option toggled %s.", allopt[optidx].name,
!negated ? "on" : "off");
return optn_ok;
}
@@ -4745,7 +4753,7 @@ handler_autounlock(int optidx)
}
destroy_nhwindow(tmpwin);
chngd = (flags.autounlock != oldflags);
if (chngd || Verbose(2, handler_autounlock)) {
if ((chngd || Verbose(2, handler_autounlock)) && give_opt_msg) {
optfn_autounlock(optidx, get_val, FALSE, buf, (char *) NULL);
pline("'%s' %s '%s'.", optname,
chngd ? "changed to" : "is still", buf);
@@ -7712,6 +7720,141 @@ longest_option_name(int startpass, int endpass)
return longest_name_len;
}
/* #options - the user friendly version */
static int
doset_simple(void)
{
static boolean made_fmtstr = FALSE;
char buf[BUFSZ];
winid tmpwin;
anything any;
menu_item *pick_list;
int i, pick_cnt, pick_idx;
enum OptSection section;
boolean *bool_p;
const char *name;
if (!made_fmtstr) {
Sprintf(fmtstr_doset, "%%s%%-%us [%%s]",
longest_option_name(set_gameview, set_in_game));
made_fmtstr = TRUE;
}
give_opt_msg = FALSE;
rerun:
tmpwin = create_nhwindow(NHW_MENU);
start_menu(tmpwin, MENU_BEHAVE_STANDARD);
for (section = OptS_General; section < OptS_Advanced; section++) {
any = cg.zeroany;
if (section != OptS_General)
add_menu(tmpwin, &nul_glyphinfo, &any, 0, 0, ATR_NONE,
0, "", MENU_ITEMFLAGS_NONE);
Sprintf(buf, " %-30s ", OptS_type[section]);
add_menu(tmpwin, &nul_glyphinfo, &any, 0, 0,
iflags.menu_headings, 0,
buf /*OptS_type[section]*/, MENU_ITEMFLAGS_NONE);
for (i = 0; (name = allopt[i].name) != 0; i++) {
if (allopt[i].section != section)
continue;
if ((is_wc_option(name) && !wc_supported(name))
|| (is_wc2_option(name) && !wc2_supported(name)))
continue;
any.a_int = i + 1;
switch (allopt[i].opttyp) {
case BoolOpt:
bool_p = allopt[i].addr;
Sprintf(buf, fmtstr_doset, "",
name, *bool_p ? "X" : " ");
break;
case CompOpt:
case OthrOpt:
{
const char *value = "unknown";
int reslt = optn_err;
char buf2[BUFSZ];
buf2[0] = '\0';
if (allopt[i].optfn)
reslt = (*allopt[i].optfn)(allopt[i].idx, get_val,
FALSE, buf2, empty_optstr);
if (reslt == optn_ok && buf2[0])
value = (const char *) buf2;
Sprintf(buf, fmtstr_doset, "", name, value);
}
break;
default:
Sprintf(buf, "ERROR");
break;
}
add_menu(tmpwin, &nul_glyphinfo, &any, 0, 0,
ATR_NONE, 0, buf, MENU_ITEMFLAGS_NONE);
}
}
end_menu(tmpwin, "Options");
g.opt_need_redraw = FALSE;
g.opt_need_glyph_reset = FALSE;
if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &pick_list)) > 0) {
for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
int k = pick_list[pick_idx].item.a_int - 1;
if (allopt[k].opttyp == BoolOpt) {
/* boolean option */
Sprintf(buf, "%s%s", *allopt[k].addr ? "!" : "",
allopt[k].name);
(void) parseoptions(buf, FALSE, FALSE);
} else {
/* compound option */
int reslt UNUSED;
if (allopt[k].has_handler && allopt[k].optfn) {
reslt = (*allopt[k].optfn)(allopt[k].idx, do_handler,
FALSE, empty_optstr,
empty_optstr);
} else {
char abuf[BUFSZ];
Sprintf(buf, "Set %s to what?", allopt[k].name);
abuf[0] = '\0';
getlin(buf, abuf);
if (abuf[0] == '\033')
continue;
Sprintf(buf, "%s:", allopt[k].name);
(void) strncat(eos(buf), abuf,
(sizeof buf - 1 - strlen(buf)));
/* pass the buck */
(void) parseoptions(buf, FALSE, FALSE);
}
}
if (wc_supported(allopt[k].name)
|| wc2_supported(allopt[k].name))
preference_update(allopt[k].name);
}
free((genericptr_t) pick_list), pick_list = (menu_item *) 0;
}
destroy_nhwindow(tmpwin);
if (g.opt_need_glyph_reset) {
reset_glyphmap(gm_optionchange);
}
if (g.opt_need_redraw) {
check_gold_symbol();
reglyph_darkroom();
(void) doredraw();
}
if (g.context.botl || g.context.botlx) {
bot();
}
if (pick_cnt > 0)
goto rerun;
give_opt_msg = TRUE;
return ECMD_OK;
}
/* the #options command */
int
doset(void) /* changing options via menu by Per Liboriussen */
@@ -7729,6 +7872,9 @@ doset(void) /* changing options via menu by Per Liboriussen */
gavehelp = FALSE, skiphelp = !iflags.cmdassist;
int clr = 0;
if (!iflags.menu_requested)
return doset_simple();
/* if we offer '?' as a choice and it is the only thing chosen,
we'll end up coming back here after showing the explanatory text */
rerun: