Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ImGui keybindings screen not allowing the user to scroll the list upon opening #72871

Merged
65 changes: 65 additions & 0 deletions src/cata_imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "input.h"
#include "output.h"
#include "ui_manager.h"
#include "input_context.h"

static ImGuiKey cata_key_to_imgui( int cata_key );

Expand Down Expand Up @@ -461,6 +462,13 @@ class cataimgui::window_impl
}
};

class cataimgui::filter_box_impl
{
public:
char text[255]; // NOLINT(modernize-avoid-c-arrays)
katemonster33 marked this conversation as resolved.
Show resolved Hide resolved
ImGuiID id;
};

cataimgui::window::window( int window_flags )
{
p_impl = nullptr;
Expand Down Expand Up @@ -599,3 +607,60 @@ cataimgui::bounds cataimgui::window::get_bounds()
{
return { -1.f, -1.f, -1.f, -1.f };
}

void cataimgui::window::draw_filter( const input_context &ctxt, bool filtering_active )
{
if( !filter_impl ) {
filter_impl = std::make_unique<cataimgui::filter_box_impl>();
filter_impl->id = 0;
filter_impl->text[0] = '\0';
}

if( !filtering_active ) {
action_button( "FILTER", ctxt.get_button_text( "FILTER" ) );
ImGui::SameLine();
action_button( "RESET_FILTER", ctxt.get_button_text( "RESET_FILTER" ) );
ImGui::SameLine();
} else {
action_button( "QUIT", ctxt.get_button_text( "QUIT", _( "Cancel" ) ) );
ImGui::SameLine();
action_button( "TEXT.CONFIRM", ctxt.get_button_text( "TEXT.CONFIRM", _( "OK" ) ) );
ImGui::SameLine();
}
ImGui::BeginDisabled( filtering_active );
ImGui::InputText( "##FILTERBOX", filter_impl->text,
std::extent_v < decltype( filter_impl->text ) > );
katemonster33 marked this conversation as resolved.
Show resolved Hide resolved
ImGui::EndDisabled();
if( !filter_impl->id ) {
filter_impl->id = GImGui->LastItemData.ID;
}
}

std::string cataimgui::window::get_filter()
{
if( filter_impl ) {
return std::string( filter_impl->text );
katemonster33 marked this conversation as resolved.
Show resolved Hide resolved
} else {
return std::string();
}
}

void cataimgui::window::clear_filter()
{
if( filter_impl && filter_impl->id != 0 ) {
ImGuiInputTextState *input_state = ImGui::GetInputTextState( filter_impl->id );
if( input_state ) {
input_state->ClearText();
filter_impl->text[0] = '\0';
}
}
}

//void cataimgui::window::set_filter( const std::string &filter )
//{
// // doesnt currently work, relies on API only available in newer ImGUi, because I can't have nice things
// //ImGuiInputTextState* input_state = ImGui::GetInputTextState( p_impl->id );
// //if( input_state ) {
// // input_state->ReloadUserBufAndSelectAll();
// //}
//}
katemonster33 marked this conversation as resolved.
Show resolved Hide resolved
6 changes: 6 additions & 0 deletions src/cata_imgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ struct item_info_data;
struct point;
class ImVec2;
class Font;
class input_context;

namespace cataimgui
{
Expand Down Expand Up @@ -78,6 +79,7 @@ void imvec2_to_point( ImVec2 *src, point *dest );
class window
{
std::unique_ptr<class window_impl> p_impl;
std::unique_ptr<class filter_box_impl> filter_impl;
bounds cached_bounds;
protected:
explicit window( int window_flags = 0 );
Expand All @@ -102,6 +104,9 @@ class window
size_t get_text_height( const char *text );
size_t str_width_to_pixels( size_t len );
size_t str_height_to_pixels( size_t len );
std::string get_filter();
//void set_filter( const std::string &filter );
void clear_filter();
void mark_resized();

protected:
Expand All @@ -112,6 +117,7 @@ class window
std::string button_action;
virtual bounds get_bounds();
virtual void draw_controls() = 0;
void draw_filter( const input_context &ctxt, bool filtering_active );
};

#if !(defined(TILES) || defined(WIN32))
Expand Down
85 changes: 68 additions & 17 deletions src/input_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
#include "imgui/imgui.h"

enum class kb_menu_status {
remove, reset, add, add_global, execute, show
remove, reset, add, add_global, execute, show, filter
};

class keybindings_ui : public cataimgui::window
Expand All @@ -48,7 +48,6 @@
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/reseting/executing/showing keybindings
kb_menu_status status = kb_menu_status::show, last_status = kb_menu_status::execute;
Expand All @@ -61,7 +60,7 @@
std::string hotkeys;
int highlight_row_index = -1;
size_t scroll_offset = 0;
std::string filter_text;
//std::string filter_text;
keybindings_ui( bool permit_execute_action, input_context *parent );
void init();

Expand Down Expand Up @@ -321,6 +320,44 @@
return rval;
}


std::string input_context::get_button_text( const std::string &action_descriptor ) const
{
std::string action_name = get_action_name( action_descriptor );
if( action_name.empty() ) {
action_name = action_descriptor;
}
return get_button_text( action_descriptor, action_name );
}

std::string input_context::get_button_text( const std::string &action_descriptor,
const std::string &action_text ) const
{
if( action_descriptor == "ANY_INPUT" ) {
return ""; // what sort of crazy button would this be?
}

bool is_local = false;
const std::vector<input_event> &events = inp_mngr.get_input_for_action( action_descriptor,
category, &is_local );
if( events.empty() ) {
return action_text;
}

std::vector<input_event> inputs_to_show;
for( const input_event &event : events ) {
if( is_event_type_enabled( event.type ) ) {
inputs_to_show.push_back( event );
}
}

if( inputs_to_show.empty() ) {
return action_text;
} else {
return string_format( "[%s] %s", inputs_to_show[0].long_description(), action_text );
}
}

std::string input_context::get_desc(
const std::string &action_descriptor,
const std::string &text,
Expand Down Expand Up @@ -608,7 +645,6 @@
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 ) );
Expand Down Expand Up @@ -655,23 +691,24 @@
ImGui::SetCursorPosX( str_width_to_pixels( width ) - ( get_text_width(
button_text_no_color ) +
( ImGui::GetStyle().FramePadding.x * 2 ) + ImGui::GetStyle().ItemSpacing.x ) );
ImGui::BeginDisabled( status == kb_menu_status::filter );
action_button( buttons[legend_idx].first, button_text_no_color );
ImGui::EndDisabled();
}
for( ; legend_idx < legend.size(); legend_idx++ ) {
draw_colored_text( legend[legend_idx], c_white );
}
if( last_status != status && status == kb_menu_status::show ) {
if( last_status != status && status == kb_menu_status::filter ) {
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 );
draw_filter( *ctxt, status == kb_menu_status::filter );
ImGui::Separator();

if( last_status != status && status == kb_menu_status::show ) {
ImGui::SetNextWindowFocus();
}
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 );
Expand Down Expand Up @@ -1299,10 +1336,13 @@
ctxt.register_action( "ADD_LOCAL" );
ctxt.register_action( "ADD_GLOBAL" );
ctxt.register_action( "TEXT.CLEAR" );
ctxt.register_action( "TEXT.CONFIRM" );
ctxt.register_action( "PAGE_UP" );
ctxt.register_action( "PAGE_DOWN" );
ctxt.register_action( "END" );
ctxt.register_action( "HOME" );
ctxt.register_action( "FILTER" );
ctxt.register_action( "RESET_FILTER" );
ctxt.register_action( "TEXT.INPUT_FROM_FILE" );
if( permit_execute_action ) {
ctxt.register_action( "EXECUTE" );
Expand Down Expand Up @@ -1357,13 +1397,19 @@
}

kb_menu.filtered_registered_actions = filter_strings_by_phrase( org_registered_actions,
kb_menu.filter_text );
kb_menu.get_filter() );

// 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.status == kb_menu_status::filter ) {
if( action == "QUIT" ) {
kb_menu.clear_filter( );
kb_menu.status = kb_menu_status::show;
} else if( action == "TEXT.CONFIRM" ) {
kb_menu.status = kb_menu_status::show;
}
} else if( action == "ADD_LOCAL" ) {
if( !kb_menu.filtered_registered_actions.empty() ) {
kb_menu.status = kb_menu_status::add;
}
Expand All @@ -1388,22 +1434,27 @@
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" ) {

Check failure on line 1437 in src/input_context.cpp

View workflow job for this annotation

GitHub Actions / build (src)

repeated branch body in conditional chain [bugprone-branch-clone,-warnings-as-errors]
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.clear_filter();
kb_menu.filtered_registered_actions = filter_strings_by_phrase( org_registered_actions,
"" );
} else if( !kb_menu.get_is_open() ) {
break;
} else if( action == "FILTER" ) {
kb_menu.status = kb_menu_status::filter;
} else if( action == "RESET_FILTER" ) {
kb_menu.clear_filter();
} 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();
//kb_menu.set_filter( kb_menu.get_filter() + get_input_string_from_file() );
continue;
} 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 );
Expand Down
21 changes: 21 additions & 0 deletions src/input_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,27 @@ class input_context
unsigned int max_limit = 0,
const input_event_filter &evt_filter = allow_all_keys ) const;

/**
* Get a description for the action parameter along with a printable hotkey
* for the description in the format [%s] %s
*
* @param action_descriptor The action descriptor for which to return
* a description of the bound keys.
*/
std::string get_button_text( const std::string &action_descriptor ) const;

/**
* Get a description for the action parameter along with a printable hotkey
* for the description in the format [%s] %s
*
* @param action_descriptor The action descriptor for which to return
* a description of the bound keys.
*
* @param action_text The human readable description of the action.
*/
std::string get_button_text( const std::string &action_descriptor,
const std::string &action_text ) const;

/**
* Get a description based on `text`. If a bound key for `action_descriptor`
* satisfying `evt_filter` is contained in `text`, surround the key with
Expand Down
Loading