diff --git a/src/input.h b/src/input.h index 2e301faa476fe..d658cbf9a6367 100644 --- a/src/input.h +++ b/src/input.h @@ -10,6 +10,7 @@ #include "translation.h" class cata_path; +class keybindings_ui; // Curses key constants constexpr int KEY_ESCAPE = 27; @@ -199,6 +200,7 @@ constexpr int JOY_LEFTDOWN = 256 + 8; */ class input_manager { + friend class keybindings_ui; public: // TODO: rewrite this to have several alternative input events for the same action diff --git a/src/input_context.cpp b/src/input_context.cpp index 885a901f34a2a..56bd53e37b572 100644 --- a/src/input_context.cpp +++ b/src/input_context.cpp @@ -31,6 +31,49 @@ #include "string_input_popup.h" #include "translations.h" #include "ui_manager.h" +#if !defined(__ANDROID__) +#include "cata_imgui.h" +#include "imgui/imgui.h" + +enum class kb_menu_status { + remove, add, add_global, execute, show +}; + +class keybindings_ui : public cataimgui::window +{ + // colors of the keybindings + const nc_color global_key = c_light_gray; + const nc_color h_global_key = h_light_gray; + const nc_color local_key = c_light_green; + const nc_color h_local_key = h_light_green; + const nc_color unbound_key = c_light_red; + const nc_color h_unbound_key = h_light_red; + input_context *ctxt; + char filter_text_impl[255]; // NOLINT(modernize-avoid-c-arrays) + public: + // current status: adding/removing/executing/showing keybindings + kb_menu_status status = kb_menu_status::show, last_status = kb_menu_status::execute; + + // keybindings help + std::vector legend; + std::vector> buttons; + int width = 0; + std::vector filtered_registered_actions; + std::string hotkeys; + int highlight_row_index = -1; + size_t scroll_offset = 0; + std::string filter_text; + keybindings_ui( bool permit_execute_action, input_context *parent ); + void init(); + + protected: + cataimgui::bounds get_bounds() override; + void draw_controls() override; + void on_resized() override { + init(); + }; +}; +#endif static const std::string default_context_id( "default" ); @@ -520,7 +563,157 @@ static const std::map fallback_keys = { { fallback_action::execute, '.' }, }; -action_id input_context::display_menu( const bool permit_execute_action ) +#if !defined(__ANDROID__) +keybindings_ui::keybindings_ui( bool permit_execute_action, + input_context *parent ) : cataimgui::window( "KEYBINDINGS", ImGuiWindowFlags_NoNav ) +{ + filter_text_impl[0] = '\0'; + this->ctxt = parent; + + legend.push_back( colorize( _( "Unbound keys" ), unbound_key ) ); + legend.push_back( colorize( _( "Keybinding active only on this screen" ), local_key ) ); + legend.push_back( colorize( _( "Keybinding active globally" ), global_key ) ); + legend.push_back( colorize( _( "* User created" ), global_key ) ); + if( permit_execute_action ) { + legend.push_back( string_format( + _( "Press %c to execute action\n" ), + fallback_keys.at( fallback_action::execute ) ) ); + } + buttons.assign( { + { + "REMOVE", string_format( _( "[%c] Remove keybinding" ), + fallback_keys.at( fallback_action::remove ) ) + }, + { + "ADD_LOCAL", string_format( _( "[%c] Add local keybinding" ), + fallback_keys.at( fallback_action::add_local ) ) + }, + { + "ADD_GLOBAL", string_format( _( "[%c] Add global keybinding" ), + fallback_keys.at( fallback_action::add_global ) ) + } } ); +} + +cataimgui::bounds keybindings_ui::get_bounds() +{ + return { -1.f, -1.f, float( str_width_to_pixels( width ) ), float( str_height_to_pixels( TERMY ) ) }; +} + +void keybindings_ui::draw_controls() +{ + scroll_offset = SIZE_MAX; + size_t legend_idx = 0; + for( ; legend_idx < 3; legend_idx++ ) { + draw_colored_text( legend[legend_idx], c_white ); + ImGui::SameLine(); + std::string button_text_no_color = remove_color_tags( buttons[legend_idx].second ); + ImGui::SetCursorPosX( str_width_to_pixels( width ) - ( get_text_width( + button_text_no_color ) + + ( ImGui::GetStyle().FramePadding.x * 2 ) + ImGui::GetStyle().ItemSpacing.x ) ); + action_button( buttons[legend_idx].first, button_text_no_color ); + } + for( ; legend_idx < legend.size(); legend_idx++ ) { + draw_colored_text( legend[legend_idx], c_white ); + } + if( last_status != status && status == kb_menu_status::show ) { + ImGui::SetKeyboardFocusHere( 0 ); + } + strncpy( filter_text_impl, filter_text.c_str(), filter_text.length() ); + ImGui::InputText( "##NOLABEL", filter_text_impl, std::extent_v< decltype( filter_text_impl )>, + status == kb_menu_status::show ? ImGuiInputTextFlags_None : ImGuiInputTextFlags_ReadOnly ); + filter_text.assign( filter_text_impl ); + ImGui::Separator(); + if( ImGui::BeginTable( "KB_KEYS", 2, ImGuiTableFlags_ScrollY ) ) { + if( last_status != status && status != kb_menu_status::show ) { + ImGui::SetKeyboardFocusHere( 0 ); + } + ImGui::TableSetupColumn( "Action Name", + ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_NoSort ); + float keys_col_width = str_width_to_pixels( width ) - str_width_to_pixels( TERMX >= 100 ? 62 : 52 ); + ImGui::TableSetupColumn( "Assigned Key(s)", + ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoSort, keys_col_width ); + //ImGui::TableHeadersRow(); + for( size_t i = 0; i < filtered_registered_actions.size(); i++ ) { + const std::string &action_id = filtered_registered_actions[i]; + + bool overwrite_default; + const action_attributes &attributes = inp_mngr.get_action_attributes( action_id, ctxt->category, + &overwrite_default ); + bool basic_overwrite_default; + const action_attributes &basic_attributes = inp_mngr.get_action_attributes( action_id, + ctxt->category, &basic_overwrite_default, true ); + + ImGui::TableNextColumn(); + ImGui::Text( " " ); + ImGui::SameLine( 0, 0 ); + char invlet = ' '; + //if( i < hotkeys.size() ) { + // invlet = hotkeys[i]; + if( ImGui::IsItemVisible() ) { + if( scroll_offset == SIZE_MAX ) { + scroll_offset = i; + } + if( i >= scroll_offset && ( i - scroll_offset ) < hotkeys.size() ) { + invlet = hotkeys[i - scroll_offset]; + } + } + std::string key_text; + if( status == kb_menu_status::add_global && overwrite_default ) { + // We're trying to add a global, but this action has a local + // defined, so gray out the invlet. + key_text = colorize( string_format( "%c", invlet ), c_dark_gray ); + } else if( status == kb_menu_status::add || status == kb_menu_status::add_global || + status == kb_menu_status::remove ) { + key_text = colorize( string_format( "%c", invlet ), c_light_blue ); + } else if( status == kb_menu_status::execute ) { + key_text = colorize( string_format( "%c", invlet ), c_white ); + } else { + key_text = " "; + } + nc_color col; + if( attributes.input_events.empty() ) { + col = i == size_t( highlight_row_index ) ? h_unbound_key : unbound_key; + } else if( overwrite_default ) { + col = i == size_t( highlight_row_index ) ? h_local_key : local_key; + } else { + col = i == size_t( highlight_row_index ) ? h_global_key : global_key; + } + if( overwrite_default != basic_overwrite_default + || attributes.input_events != basic_attributes.input_events + ) { + key_text += "*"; + } else { + key_text += " "; + } + key_text += string_format( "%s:", ctxt->get_action_name( action_id ) ); + bool is_selected = false; + draw_colored_text( key_text, col, 0.0f, &is_selected ); + if( ( is_selected || ImGui::IsItemHovered() ) && invlet != ' ' ) { + highlight_row_index = i; + } + //ImGui::SameLine(); + //ImGui::SetCursorPosX(str_width_to_pixels(TERMX >= 100 ? 62 : 52)); + ImGui::TableNextColumn(); + ImGui::Text( "%s", ctxt->get_desc( action_id ).c_str() ); + } + ImGui::EndTable(); + } + last_status = status; + + // spopup.query_string() will call wnoutrefresh( w_help ) + //spopup.text(filter_phrase); + //spopup.query_string(false, true); + // Record cursor immediately after spopup drawing + //ui.record_term_cursor(); +} + +void keybindings_ui::init() +{ + width = TERMX >= 100 ? 100 : 80; +} +#endif + +action_id input_context::display_menu_legacy( const bool permit_execute_action ) { action_id action_to_execute = ACTION_NULL; @@ -597,7 +790,7 @@ action_id input_context::display_menu( const bool permit_execute_action ) // keybindings before the user changed anything. input_manager::t_action_contexts old_action_contexts( inp_mngr.action_contexts ); // current status: adding/removing/executing/showing keybindings - enum { s_remove, s_add, s_add_global, s_execute, s_show } status = s_show; + kb_menu_status status = kb_menu_status::show; // copy of registered_actions, but without the ANY_INPUT and COORDINATE, which should not be shown std::vector org_registered_actions( registered_actions ); org_registered_actions.erase( std::remove_if( org_registered_actions.begin(), @@ -675,13 +868,14 @@ action_id input_context::display_menu( const bool permit_execute_action ) invlet = ' '; } - if( status == s_add_global && overwrite_default ) { + if( status == kb_menu_status::add_global && overwrite_default ) { // We're trying to add a global, but this action has a local // defined, so gray out the invlet. mvwprintz( w_help, point( 2, i + 7 ), c_dark_gray, "%c ", invlet ); - } else if( status == s_add || status == s_add_global || status == s_remove ) { + } else if( status == kb_menu_status::add || status == kb_menu_status::add_global || + status == kb_menu_status::remove ) { mvwprintz( w_help, point( 2, i + 7 ), c_light_blue, "%c ", invlet ); - } else if( status == s_execute ) { + } else if( status == kb_menu_status::execute ) { mvwprintz( w_help, point( 2, i + 7 ), c_white, "%c ", invlet ); } else { mvwprintz( w_help, point( 2, i + 7 ), c_blue, " " ); @@ -714,7 +908,7 @@ action_id input_context::display_menu( const bool permit_execute_action ) while( true ) { ui_manager::redraw(); - if( status == s_show ) { + if( status == kb_menu_status::show ) { filter_phrase = spopup.query_string( false ); action = ctxt.input_to_action( ctxt.get_raw_input() ); } else { @@ -738,7 +932,7 @@ action_id input_context::display_menu( const bool permit_execute_action ) if( o_p ) { point p = o_p.value(); if( window_contains_point_relative( w_help, p ) ) { - if( p.y >= 7 && p.y < TERMY && status != s_show ) { + if( p.y >= 7 && p.y < TERMY && status != kb_menu_status::show ) { highlight_row_index = p.y - 7; } else if( p.y == 4 ) { if( p.x >= 17 && p.x <= 43 ) { @@ -754,13 +948,13 @@ action_id input_context::display_menu( const bool permit_execute_action ) if( action == "SELECT" ) { switch( highlighted_btn_index ) { case kb_btn_idx::remove: - status = s_remove; + status = kb_menu_status::remove; break; case kb_btn_idx::add_local: - status = s_add; + status = kb_menu_status::add; break; case kb_btn_idx::add_global: - status = s_add_global; + status = kb_menu_status::add_global; break; case kb_btn_idx::none: break; @@ -773,23 +967,23 @@ action_id input_context::display_menu( const bool permit_execute_action ) if( action == "ADD_LOCAL" || raw_input_char == fallback_keys.at( fallback_action::add_local ) ) { if( !filtered_registered_actions.empty() ) { - status = s_add; + status = kb_menu_status::add; } } else if( action == "ADD_GLOBAL" || raw_input_char == fallback_keys.at( fallback_action::add_global ) ) { if( !filtered_registered_actions.empty() ) { - status = s_add_global; + status = kb_menu_status::add_global; } } else if( action == "REMOVE" || raw_input_char == fallback_keys.at( fallback_action::remove ) ) { if( !filtered_registered_actions.empty() ) { - status = s_remove; + status = kb_menu_status::remove; } } else if( ( action == "EXECUTE" || raw_input_char == fallback_keys.at( fallback_action::execute ) ) && permit_execute_action ) { if( !filtered_registered_actions.empty() ) { - status = s_execute; + status = kb_menu_status::execute; } } else if( action == "DOWN" ) { if( !filtered_registered_actions.empty() @@ -822,15 +1016,15 @@ action_id input_context::display_menu( const bool permit_execute_action ) scroll_offset = filtered_registered_actions.size() - display_height; } } else if( action == "QUIT" ) { - if( status != s_show ) { - status = s_show; + if( status != kb_menu_status::show ) { + status = kb_menu_status::show; } else { break; } } else if( action == "HELP_KEYBINDINGS" ) { // update available hotkeys in case they've changed hotkeys = ctxt.get_available_single_char_hotkeys( display_help_hotkeys ); - } else if( !filtered_registered_actions.empty() && status != s_show ) { + } else if( !filtered_registered_actions.empty() && status != kb_menu_status::show ) { size_t hotkey_index = hotkeys.find_first_of( raw_input_char ); if( hotkey_index == std::string::npos ) { if( action == "SELECT" && highlight_row_index != -1 ) { @@ -854,7 +1048,7 @@ action_id input_context::display_menu( const bool permit_execute_action ) // We don't want to completely delete a global context entry. // Only attempt removal for a local context, or when there's // bindings for the default context. - if( status == s_remove && ( is_local || !is_empty ) ) { + if( status == kb_menu_status::remove && ( is_local || !is_empty ) ) { if( !get_option( "QUERY_KEYBIND_REMOVAL" ) || query_yn( is_local && is_empty ? _( "Reset to global bindings for %s?" ) : _( "Clear keys for %s?" ), name ) ) { @@ -867,10 +1061,10 @@ action_id input_context::display_menu( const bool permit_execute_action ) inp_mngr.remove_input_for_action( action_id, category_to_access ); changed = true; } - } else if( status == s_add_global && is_local ) { + } else if( status == kb_menu_status::add_global && is_local ) { // Disallow adding global actions to an action that already has a local defined. popup( _( "There are already local keybindings defined for this action, please remove them first." ) ); - } else if( status == s_add || status == s_add_global ) { + } else if( status == kb_menu_status::add || status == kb_menu_status::add_global ) { const input_event new_event = query_popup() .preferred_keyboard_mode( preferred_keyboard_mode ) .message( _( "New key for %s" ), name ) @@ -880,9 +1074,9 @@ action_id input_context::display_menu( const bool permit_execute_action ) if( action_uses_input( action_id, new_event ) // Allow adding keys already used globally to local bindings - && ( status == s_add_global || is_local ) ) { + && ( status == kb_menu_status::add_global || is_local ) ) { popup_getkey( _( "This key is already used for %s." ), name ); - status = s_show; + status = kb_menu_status::show; continue; } @@ -903,18 +1097,18 @@ action_id input_context::display_menu( const bool permit_execute_action ) // We might be adding a local or global action. std::string category_to_access = category; - if( status == s_add_global ) { + if( status == kb_menu_status::add_global ) { category_to_access = default_context_id; } inp_mngr.add_input_for_action( action_id, category_to_access, new_event ); changed = true; } - } else if( status == s_execute && permit_execute_action ) { + } else if( status == kb_menu_status::execute && permit_execute_action ) { action_to_execute = look_up_action( action_id ); break; } - status = s_show; + status = kb_menu_status::show; } } @@ -932,6 +1126,242 @@ action_id input_context::display_menu( const bool permit_execute_action ) return action_to_execute; } +#if !defined(__ANDROID__) +action_id input_context::display_menu_imgui( const bool permit_execute_action ) +{ + + action_id action_to_execute = ACTION_NULL; + + input_context ctxt( "HELP_KEYBINDINGS", keyboard_mode::keychar ); + // Keybinding menu actions + ctxt.register_action( "COORDINATE" ); + ctxt.register_action( "MOUSE_MOVE" ); + ctxt.register_action( "SELECT" ); + ctxt.register_action( "REMOVE" ); + ctxt.register_action( "ADD_LOCAL" ); + ctxt.register_action( "ADD_GLOBAL" ); + ctxt.register_action( "TEXT.CLEAR" ); + ctxt.register_action( "PAGE_UP" ); + ctxt.register_action( "PAGE_DOWN" ); + ctxt.register_action( "END" ); + ctxt.register_action( "HOME" ); + ctxt.register_action( "TEXT.INPUT_FROM_FILE" ); + if( permit_execute_action ) { + ctxt.register_action( "EXECUTE" ); + } + ctxt.register_action( "QUIT" ); + ctxt.register_action( "ANY_INPUT" ); + + if( category != "HELP_KEYBINDINGS" ) { + // avoiding inception! + ctxt.register_action( "HELP_KEYBINDINGS" ); + } +#if defined(WIN32) || defined(TILES) + ctxt.set_timeout( 50 ); +#endif + + // has the user changed something? + bool changed = false; + // keybindings before the user changed anything. + input_manager::t_action_contexts old_action_contexts( inp_mngr.action_contexts ); + // copy of registered_actions, but without the ANY_INPUT and COORDINATE, which should not be shown + std::vector org_registered_actions( registered_actions ); + org_registered_actions.erase( std::remove_if( org_registered_actions.begin(), + org_registered_actions.end(), + []( const std::string & a ) { + return a == ANY_INPUT || a == COORDINATE; + } ), org_registered_actions.end() ); + + std::string action; + keybindings_ui kb_menu( permit_execute_action, this ); + kb_menu.filtered_registered_actions = org_registered_actions; + kb_menu.hotkeys = ctxt.get_available_single_char_hotkeys( display_help_hotkeys ); + kb_menu.init(); + int raw_input_char = 0; + //const auto redraw = [&]( ui_adaptor & ui ) { + //}; + //ui.on_redraw( redraw ); + + while( true ) { + kb_menu.highlight_row_index = -1; + ui_manager::redraw(); + if( kb_menu.has_button_action() ) { + action = kb_menu.get_button_action(); + raw_input_char = 0; + } else { + action = ctxt.handle_input(); + raw_input_char = ctxt.get_raw_input().get_first_input(); + } + for( const std::pair &v : fallback_keys ) { + if( v.second == raw_input_char ) { + action.clear(); + } + } + + kb_menu.filtered_registered_actions = filter_strings_by_phrase( org_registered_actions, + kb_menu.filter_text ); + + // In addition to the modifiable hotkeys, we also check for hardcoded + // keys, e.g. '+', '-', '=', '.' in order to prevent the user from + // entering an unrecoverable state. + if( action == "ADD_LOCAL" + || raw_input_char == fallback_keys.at( fallback_action::add_local ) ) { + if( !kb_menu.filtered_registered_actions.empty() ) { + kb_menu.status = kb_menu_status::add; + } + } else if( action == "ADD_GLOBAL" + || raw_input_char == fallback_keys.at( fallback_action::add_global ) ) { + if( !kb_menu.filtered_registered_actions.empty() ) { + kb_menu.status = kb_menu_status::add_global; + } + } else if( action == "REMOVE" + || raw_input_char == fallback_keys.at( fallback_action::remove ) ) { + if( !kb_menu.filtered_registered_actions.empty() ) { + kb_menu.status = kb_menu_status::remove; + } + } else if( ( action == "EXECUTE" + || raw_input_char == fallback_keys.at( fallback_action::execute ) ) + && permit_execute_action ) { + if( !kb_menu.filtered_registered_actions.empty() ) { + kb_menu.status = kb_menu_status::execute; + } + } else if( action == "PAGE_UP" || action == "PAGE_DOWN" || action == "HOME" || action == "END" ) { + continue; // do nothing - on tiles version for some reason this counts as pressing various alphabet keys + } else if( action == "TEXT.CLEAR" ) { + kb_menu.filter_text.assign( "" ); + kb_menu.filtered_registered_actions = filter_strings_by_phrase( org_registered_actions, + "" ); + } else if( !kb_menu.get_is_open() ) { + break; + } else if( action == "QUIT" ) { + if( kb_menu.status != kb_menu_status::show ) { + kb_menu.status = kb_menu_status::show; + } else { + break; + } + } else if( action == "TEXT.INPUT_FROM_FILE" ) { + kb_menu.filter_text += get_input_string_from_file(); + } else if( action == "HELP_KEYBINDINGS" ) { + // update available hotkeys in case they've changed + kb_menu.hotkeys = ctxt.get_available_single_char_hotkeys( display_help_hotkeys ); + } else if( !kb_menu.filtered_registered_actions.empty() && + kb_menu.status != kb_menu_status::show ) { + size_t hotkey_index = kb_menu.hotkeys.find_first_of( raw_input_char ); + if( hotkey_index == std::string::npos ) { + if( action == "SELECT" && kb_menu.highlight_row_index != -1 ) { + hotkey_index = size_t( kb_menu.highlight_row_index ); + } else { + continue; + } + } + const size_t action_index = hotkey_index + kb_menu.scroll_offset; + if( action_index >= kb_menu.filtered_registered_actions.size() ) { + continue; + } + const std::string &action_id = kb_menu.filtered_registered_actions[action_index]; + + // Check if this entry is local or global. + bool is_local = false; + const action_attributes &actions = inp_mngr.get_action_attributes( action_id, category, &is_local ); + bool is_empty = actions.input_events.empty(); + const std::string name = get_action_name( action_id ); + + // We don't want to completely delete a global context entry. + // Only attempt removal for a local context, or when there's + // bindings for the default context. + if( kb_menu.status == kb_menu_status::remove && ( is_local || !is_empty ) ) { + if( !get_option( "QUERY_KEYBIND_REMOVAL" ) || query_yn( is_local && + is_empty ? _( "Reset to global bindings for %s?" ) : _( "Clear keys for %s?" ), name ) ) { + + // If it's global, reset the global actions. + std::string category_to_access = category; + if( !is_local ) { + category_to_access = default_context_id; + } + + inp_mngr.remove_input_for_action( action_id, category_to_access ); + changed = true; + } + } else if( kb_menu.status == kb_menu_status::add_global && is_local ) { + // Disallow adding global actions to an action that already has a local defined. + popup( _( "There are already local keybindings defined for this action, please remove them first." ) ); + } else if( kb_menu.status == kb_menu_status::add || + kb_menu.status == kb_menu_status::add_global ) { + const input_event new_event = query_popup() + .preferred_keyboard_mode( preferred_keyboard_mode ) + .message( _( "New key for %s" ), name ) + .allow_anykey( true ) + .query() + .evt; + + if( action_uses_input( action_id, new_event ) + // Allow adding keys already used globally to local bindings + && ( kb_menu.status == kb_menu_status::add_global || is_local ) ) { + popup_getkey( _( "This key is already used for %s." ), name ); + kb_menu.status = kb_menu_status::show; + continue; + } + + const std::string conflicts = get_conflicts( new_event, action_id ); + const bool has_conflicts = !conflicts.empty(); + bool resolve_conflicts = false; + + if( has_conflicts ) { + resolve_conflicts = query_yn( + _( "This key conflicts with %s. Remove this key from the conflicting command(s), and continue?" ), + conflicts.c_str() ); + } + + if( !has_conflicts || resolve_conflicts ) { + if( resolve_conflicts ) { + clear_conflicting_keybindings( new_event ); + } + + // We might be adding a local or global action. + std::string category_to_access = category; + if( kb_menu.status == kb_menu_status::add_global ) { + category_to_access = default_context_id; + } + + inp_mngr.add_input_for_action( action_id, category_to_access, new_event ); + changed = true; + } + } else if( kb_menu.status == kb_menu_status::execute && permit_execute_action ) { + action_to_execute = look_up_action( action_id ); + break; + } + kb_menu.status = kb_menu_status::show; + } + } + + if( changed && query_yn( _( "Save changes?" ) ) ) { + try { + inp_mngr.save(); + get_help().load(); + } catch( std::exception &err ) { + popup( _( "saving keybindings failed: %s" ), err.what() ); + } + } else if( changed ) { + inp_mngr.action_contexts.swap( old_action_contexts ); + } + + return action_to_execute; +} +#endif + +action_id input_context::display_menu( bool permit_execute_action ) +{ +#if defined(__ANDROID__) + return display_menu_legacy( permit_execute_action ); +#else + if( get_options().has_option( "USE_IMGUI" ) && get_option( "USE_IMGUI" ) ) { + return display_menu_imgui( permit_execute_action ); + } else { + return display_menu_legacy( permit_execute_action ); + } +#endif +} + input_event input_context::get_raw_input() { return next_action; diff --git a/src/input_context.h b/src/input_context.h index bb490b432aaf1..c83569ee0ac0a 100644 --- a/src/input_context.h +++ b/src/input_context.h @@ -18,6 +18,9 @@ #include "translation.h" class hotkey_queue; +#if !defined(__ANDROID__) +class keybindings_ui; +#endif namespace catacurses { class window; @@ -35,6 +38,9 @@ class window; */ class input_context { +#if !defined(__ANDROID__) + friend class keybindings_ui; +#endif public: #if defined(__ANDROID__) // Whatever's on top is our current input context. @@ -418,6 +424,11 @@ class input_context */ std::vector filter_strings_by_phrase( const std::vector &strings, std::string_view phrase ) const; + + action_id display_menu_legacy( bool permit_execute_action ); +#if !defined(__ANDROID__) + action_id display_menu_imgui( bool permit_execute_action ); +#endif }; class hotkey_queue