From cdb4a9e8b372e9956e945d1729cc1adde23c5eb9 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 31 May 2019 10:11:45 -0700 Subject: [PATCH] fix github issue #193 - curses: menu search Fixes #193 Under curses interface, make characters which are both entry selectors and menu commands function as a selector. Needed to support using ':' to look inside a container when applying/looting it via menu, instead of performing a menu search operation. (There was another case like this but I can't remember what the circumstances are. The fix is general enough to cover it, whatever it is.) For menus which don't have ':' as a choice, make sure search prompt doesn't offer garbage default input when built with EDIT_GETLIN. Bug? If player has 'popup_dialog' option On, EDIT_GETLIN is ignored. Plain curses I/O doesn't seem to offer a way to implement it. --- win/curses/cursdial.c | 212 ++++++++++++++++++++++-------------------- win/curses/cursmain.c | 1 + 2 files changed, 113 insertions(+), 100 deletions(-) diff --git a/win/curses/cursdial.c b/win/curses/cursdial.c index 18eaec465..2f2f5fcce 100644 --- a/win/curses/cursdial.c +++ b/win/curses/cursdial.c @@ -97,7 +97,8 @@ static char menu_get_accel(boolean first); static void menu_determine_pages(nhmenu *menu); static boolean menu_is_multipage(nhmenu *menu, int width, int height); static void menu_win_size(nhmenu *menu); -static void menu_display_page(nhmenu *menu, WINDOW * win, int page_num); +static void menu_display_page(nhmenu *menu, WINDOW * win, int page_num, + char *); static int menu_get_selections(WINDOW * win, nhmenu *menu, int how); static void menu_select_deselect(WINDOW * win, nhmenu_item *item, menu_op operation); @@ -116,7 +117,7 @@ static nhmenu *nhmenus = NULL; /* NetHack menu array */ /* Get a line of text from the player, such as asking for a character name - or a wish */ + or a wish. Note: EDIT_GETLIN not supported for popup prompting. */ void curses_line_input_dialog(const char *prompt, char *answer, int buffer) @@ -133,8 +134,8 @@ curses_line_input_dialog(const char *prompt, char *answer, int buffer) re-activate them now that input is being requested */ curses_got_input(); - if (buffer >= (int) sizeof input) - buffer = (int) sizeof input - 1; + if (buffer > (int) sizeof input) + buffer = (int) sizeof input; maxwidth = term_cols - 2; if (iflags.window_inited) { @@ -1059,7 +1060,7 @@ menu_win_size(nhmenu *menu) /* Displays menu selections in the given window */ static void -menu_display_page(nhmenu *menu, WINDOW * win, int page_num) +menu_display_page(nhmenu *menu, WINDOW * win, int page_num, char *selectors) { nhmenu_item *menu_item_ptr; int count, curletter, entry_cols, start_col, num_lines; @@ -1068,6 +1069,10 @@ menu_display_page(nhmenu *menu, WINDOW * win, int page_num) int color = NO_COLOR, attr = A_NORMAL; boolean menu_color = FALSE; + /* letters assigned to entries on current page */ + if (selectors) + (void) memset((genericptr_t) selectors, 0, 256); + /* Cycle through entries until we are on the correct page */ menu_item_ptr = menu->entries; @@ -1117,6 +1122,9 @@ menu_display_page(nhmenu *menu, WINDOW * win, int page_num) } menu_item_ptr->accelerator = curletter; } + /* we have a selector letter; tell caller about it */ + if (selectors) + selectors[(unsigned) (curletter & 0xFF)]++; if (menu_item_ptr->selected) { curses_toggle_color_attr(win, HIGHLIGHT_COLOR, A_REVERSE, ON); @@ -1222,10 +1230,10 @@ menu_get_selections(WINDOW * win, nhmenu *menu, int how) int curpage = !menu->bottom_heavy ? 1 : menu->num_pages; int num_selected = 0; boolean dismiss = FALSE; - char search_key[BUFSZ]; + char search_key[BUFSZ], selectors[256]; nhmenu_item *menu_item_ptr = menu->entries; - menu_display_page(menu, win, curpage); + menu_display_page(menu, win, curpage, selectors); while (!dismiss) { curletter = getch(); @@ -1253,25 +1261,27 @@ menu_get_selections(WINDOW * win, nhmenu *menu, int how) } break; case PICK_ANY: - switch (curletter) { - case MENU_SELECT_PAGE: - (void) menu_operation(win, menu, SELECT, curpage); - break; - case MENU_SELECT_ALL: - curpage = menu_operation(win, menu, SELECT, 0); - break; - case MENU_UNSELECT_PAGE: - (void) menu_operation(win, menu, DESELECT, curpage); - break; - case MENU_UNSELECT_ALL: - curpage = menu_operation(win, menu, DESELECT, 0); - break; - case MENU_INVERT_PAGE: - (void) menu_operation(win, menu, INVERT, curpage); - break; - case MENU_INVERT_ALL: - curpage = menu_operation(win, menu, INVERT, 0); - break; + if (curletter <= 0 || curletter >= 256 || !selectors[curletter]) { + switch (curletter) { + case MENU_SELECT_PAGE: + (void) menu_operation(win, menu, SELECT, curpage); + break; + case MENU_SELECT_ALL: + curpage = menu_operation(win, menu, SELECT, 0); + break; + case MENU_UNSELECT_PAGE: + (void) menu_operation(win, menu, DESELECT, curpage); + break; + case MENU_UNSELECT_ALL: + curpage = menu_operation(win, menu, DESELECT, 0); + break; + case MENU_INVERT_PAGE: + (void) menu_operation(win, menu, INVERT, curpage); + break; + case MENU_INVERT_ALL: + curpage = menu_operation(win, menu, INVERT, 0); + break; + } } /*FALLTHRU*/ default: @@ -1286,86 +1296,88 @@ menu_get_selections(WINDOW * win, nhmenu *menu, int how) } } - switch (curletter) { - case KEY_ESC: - num_selected = -1; - dismiss = TRUE; - break; - case '\n': - case '\r': - dismiss = TRUE; - break; - case KEY_RIGHT: - case KEY_NPAGE: - case MENU_NEXT_PAGE: - case ' ': - if (curpage < menu->num_pages) { - curpage++; - menu_display_page(menu, win, curpage); - } else if (curletter == ' ') { + if (curletter <= 0 || curletter >= 256 || !selectors[curletter]) { + switch (curletter) { + case KEY_ESC: + num_selected = -1; dismiss = TRUE; break; - } - break; - case KEY_LEFT: - case KEY_PPAGE: - case MENU_PREVIOUS_PAGE: - if (curpage > 1) { - curpage--; - menu_display_page(menu, win, curpage); - } - break; - case KEY_END: - case MENU_LAST_PAGE: - if (curpage != menu->num_pages) { - curpage = menu->num_pages; - menu_display_page(menu, win, curpage); - } - break; - case KEY_HOME: - case MENU_FIRST_PAGE: - if (curpage != 1) { - curpage = 1; - menu_display_page(menu, win, curpage); - } - break; - case MENU_SEARCH: - curses_line_input_dialog("Search for:", search_key, BUFSZ); - - refresh(); - touchwin(win); - wrefresh(win); - - if (!*search_key) { + case '\n': + case '\r': + dismiss = TRUE; break; - } + case KEY_RIGHT: + case KEY_NPAGE: + case MENU_NEXT_PAGE: + case ' ': + if (curpage < menu->num_pages) { + curpage++; + menu_display_page(menu, win, curpage, selectors); + } else if (curletter == ' ') { + dismiss = TRUE; + break; + } + break; + case KEY_LEFT: + case KEY_PPAGE: + case MENU_PREVIOUS_PAGE: + if (curpage > 1) { + curpage--; + menu_display_page(menu, win, curpage, selectors); + } + break; + case KEY_END: + case MENU_LAST_PAGE: + if (curpage != menu->num_pages) { + curpage = menu->num_pages; + menu_display_page(menu, win, curpage, selectors); + } + break; + case KEY_HOME: + case MENU_FIRST_PAGE: + if (curpage != 1) { + curpage = 1; + menu_display_page(menu, win, curpage, selectors); + } + break; + case MENU_SEARCH: + search_key[0] = '\0'; + curses_line_input_dialog("Search for:", search_key, BUFSZ); - menu_item_ptr = menu->entries; + refresh(); + touchwin(win); + wrefresh(win); - while (menu_item_ptr != NULL) { - if (menu_item_ptr->identifier.a_void != NULL - && strstri(menu_item_ptr->str, search_key)) { - if (how == PICK_ONE) { - menu_clear_selections(menu); - menu_select_deselect(win, menu_item_ptr, SELECT); - num_selected = 1; - dismiss = TRUE; - break; - } else { - menu_select_deselect(win, menu_item_ptr, INVERT); + if (!*search_key) + break; + + menu_item_ptr = menu->entries; + + while (menu_item_ptr != NULL) { + if (menu_item_ptr->identifier.a_void != NULL + && strstri(menu_item_ptr->str, search_key)) { + if (how == PICK_ONE) { + menu_clear_selections(menu); + menu_select_deselect(win, menu_item_ptr, SELECT); + num_selected = 1; + dismiss = TRUE; + break; + } else { + menu_select_deselect(win, menu_item_ptr, INVERT); + } } - } - menu_item_ptr = menu_item_ptr->next_item; - } + menu_item_ptr = menu_item_ptr->next_item; + } - menu_item_ptr = menu->entries; - break; - default: - if (how == PICK_NONE) { - num_selected = 0; - dismiss = TRUE; + menu_item_ptr = menu->entries; break; + default: + if (how == PICK_NONE) { + num_selected = 0; + dismiss = TRUE; + break; + } } } @@ -1379,7 +1391,7 @@ menu_get_selections(WINDOW * win, nhmenu *menu, int how) && curletter == menu_item_ptr->group_accel)) { if (curpage != menu_item_ptr->page_num) { curpage = menu_item_ptr->page_num; - menu_display_page(menu, win, curpage); + menu_display_page(menu, win, curpage, selectors); } if (how == PICK_ONE) { @@ -1479,7 +1491,7 @@ menu_operation(WINDOW * win, nhmenu *menu, menu_op current_page = first_page; if (page_num == 0) { - menu_display_page(menu, win, current_page); + menu_display_page(menu, win, current_page, (char *) 0); } if (menu_item_ptr == NULL) { /* Page not found */ @@ -1494,7 +1506,7 @@ menu_operation(WINDOW * win, nhmenu *menu, menu_op } current_page = menu_item_ptr->page_num; - menu_display_page(menu, win, current_page); + menu_display_page(menu, win, current_page, (char *) 0); } if (menu_item_ptr->identifier.a_void != NULL) { diff --git a/win/curses/cursmain.c b/win/curses/cursmain.c index ada703de4..931de9569 100644 --- a/win/curses/cursmain.c +++ b/win/curses/cursmain.c @@ -202,6 +202,7 @@ curses_player_selection() void curses_askname() { + plname[0] = '\0'; curses_line_input_dialog("Who are you?", plname, PL_NSIZ); } -- 2.50.0