Skip to content

Commit

Permalink
Merge pull request CleverRaven#76033 from db48x/uilist-alternate-mous…
Browse files Browse the repository at this point in the history
…e-handling

Handle mouse input in a more sophisticated manner
  • Loading branch information
Maleclypse authored Sep 1, 2024
2 parents cce2520 + 6e95a9f commit 2b4fa4b
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 66 deletions.
4 changes: 2 additions & 2 deletions src/advanced_inv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2087,9 +2087,9 @@ void query_destination_callback::draw_squares( const uilist *menu )
ImGui::NewLine();
cata_assert( menu->entries.size() >= 9 );
int sel = 0;
if( menu->selected >= 0 && static_cast<size_t>( menu->selected ) < menu->entries.size() ) {
if( menu->hovered >= 0 && static_cast<size_t>( menu->hovered ) < menu->entries.size() ) {
sel = _adv_inv.screen_relative_location(
static_cast <aim_location>( menu->selected + 1 ) );
static_cast <aim_location>( menu->hovered + 1 ) );
}
for( int i = 1; i < 10; i++ ) {
aim_location loc = _adv_inv.screen_relative_location( static_cast <aim_location>( i ) );
Expand Down
2 changes: 1 addition & 1 deletion src/item_contents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ void pocket_favorite_callback::refresh( uilist *menu )
continue;
}

if( i == menu->selected ) {
if( i == menu->hovered ) {
selected_pocket = pocket;
pocket_num = std::get<1>( pocket_val ) + 1;
break;
Expand Down
6 changes: 3 additions & 3 deletions src/magic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2458,8 +2458,8 @@ class spellcasting_callback : public uilist_callback
ImGui::NewLine();
if( ImGui::BeginChild( "spell info", { desired_extra_space_right( ), 0 }, false,
ImGuiWindowFlags_AlwaysAutoResize ) ) {
if( menu->selected >= 0 && static_cast<size_t>( menu->selected ) < known_spells.size() ) {
display_spell_info( menu->selected );
if( menu->hovered >= 0 && static_cast<size_t>( menu->hovered ) < known_spells.size() ) {
display_spell_info( menu->hovered );
}
}
ImGui::EndChild();
Expand Down Expand Up @@ -2897,7 +2897,7 @@ int known_magic::select_spell( Character &guy )
}
reflesh_favorite( &spell_menu, known_spells_sorted );

spell_menu.query( true, -1, true );
spell_menu.query( true, 50, true );

casting_ignore = static_cast<spellcasting_callback *>( spell_menu.callback )->casting_ignore;

Expand Down
2 changes: 1 addition & 1 deletion src/magic_teleporter_list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ class teleporter_callback : public uilist_callback
}
void refresh( uilist *menu ) override {
ImGui::TableSetColumnIndex( 2 );
const int entnum = menu->selected;
const int entnum = menu->hovered;
if( entnum >= 0 && static_cast<size_t>( entnum ) < index_pairs.size() ) {
avatar &player_character = get_avatar();
int dist = rl_dist( player_character.global_omt_location(), index_pairs[entnum] );
Expand Down
115 changes: 65 additions & 50 deletions src/ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "ui_manager.h"
#include "cata_imgui.h"
#include "imgui/imgui.h"
#include "imgui/imgui_internal.h"

#if defined(__ANDROID__)
#include <jni.h>
Expand Down Expand Up @@ -90,45 +91,62 @@ void uilist_impl::draw_controls()
ImGui::TableSetupColumn( "secondary", ImGuiTableColumnFlags_WidthFixed,
parent.calculated_secondary_width );

// It would be natural to make the entries into buttons, or
// combos, or other pre-built ui elements. For now I am mostly
// going to copy the style of the original textual ui elements.
for( size_t i = 0; i < parent.fentries.size(); i++ ) {
auto entry = parent.entries[parent.fentries[i]];
ImGui::TableNextRow( ImGuiTableRowFlags_None, entry_height );
ImGui::TableSetColumnIndex( 0 );

ImVec2 rowMin = ImGui::GetCursorScreenPos();
ImVec2 rowMax = ImVec2( rowMin.x + parent.calculated_menu_size.x, rowMin.y + entry_height );
bool is_hovered = ImGui::IsMouseHoveringRect( rowMin, rowMax, false );
if( is_hovered ) {
ImGui::TableSetBgColor( ImGuiTableBgTarget_RowBg1,
ImColor( ImGui::GetStyle().Colors[ ImGuiCol_HeaderHovered ] ) );
parent.fselected = i;
}
bool is_selected = static_cast<int>( i ) == parent.fselected;
if( is_selected ) {
ImGui::SetItemDefaultFocus();
ImGui::SetScrollHereY();
ImGui::TableSetBgColor( ImGuiTableBgTarget_RowBg1,
ImColor( ImGui::GetStyle().Colors[ ImGuiCol_HeaderActive ] ) );
}

if( entry.hotkey.has_value() ) {
nc_color color = is_selected ? parent.hilight_color : parent.hotkey_color;
ImGuiListClipper clipper;
clipper.Begin( parent.fentries.size(), entry_height );
clipper.IncludeRangeByIndices( parent.fselected, parent.fselected + 1 );
while( clipper.Step() ) {
// It would be natural to make the entries into buttons, or
// combos, or other pre-built ui elements. For now I am mostly
// going to copy the style of the original textual ui elements.
for( int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++ ) {
auto entry = parent.entries[parent.fentries[i]];
bool is_selected = i == parent.fselected;
ImGui::PushID( i );
ImGui::TableNextRow( ImGuiTableRowFlags_None, entry_height );
ImGui::TableSetColumnIndex( 0 );

if( is_selected && parent.need_to_scroll ) {
// this is the selected row, and the user just changed the selection; scroll it into view
ImGui::SetScrollHereY();
parent.need_to_scroll = false;
}
ImGuiSelectableFlags flags = ImGuiSelectableFlags_SpanAllColumns |
ImGuiSelectableFlags_AllowItemOverlap;
if( !entry.enabled ) {
flags |= ImGuiSelectableFlags_Disabled;
}
if( ImGui::Selectable( "##s", is_selected, flags ) ) {
parent.fselected = i;
parent.selected = parent.hovered = parent.fentries[ parent.fselected ];
// We are going to return now that the user clicked on something, so scrolling seems
// unnecessary. However, the debug spawn item function reuses the same menu to let the
// user spawn multiple items and it’s weird if the correct item isn’t scrolled into view
// the next time around.
parent.need_to_scroll = true;
is_selected = parent.clicked = true;
}
bool mouse_moved = ImGui::GetCurrentContext()->HoveredId !=
ImGui::GetCurrentContext()->HoveredIdPreviousFrame;
if( ImGui::IsItemHovered( ImGuiHoveredFlags_NoNavOverride ) && mouse_moved ) {
// this row is hovered and the hover state just changed, show context for it
parent.hovered = parent.fentries[ i ];
}
ImGui::SameLine( 0, 0 );
cataimgui::draw_colored_text( entry.hotkey.value().short_description(),
color );
}
ImGui::TableSetColumnIndex( 1 );
nc_color color = ( is_selected ?
parent.hilight_color :
( entry.enabled || entry.force_color ?
entry.text_color :
parent.disabled_color ) );
cataimgui::draw_colored_text( entry.txt, color );
ImGui::TableSetColumnIndex( 2 );
if( !entry.ctxt.empty() ) {
is_selected ? parent.hilight_color : parent.hotkey_color );

ImGui::TableSetColumnIndex( 1 );
nc_color color = ( is_selected ?
parent.hilight_color :
( entry.enabled || entry.force_color ?
entry.text_color :
parent.disabled_color ) );
cataimgui::draw_colored_text( entry.txt, color );

ImGui::TableSetColumnIndex( 2 );
cataimgui::draw_colored_text( entry.ctxt, color );

ImGui::PopID();
}
}
ImGui::EndTable();
Expand All @@ -147,8 +165,8 @@ void uilist_impl::draw_controls()
std::string description;
if( !parent.footer_text.empty() ) {
description = parent.footer_text;
} else if( parent.selected >= 0 ) {
description = parent.entries[parent.selected].desc;
} else {
description = parent.entries[parent.hovered].desc;
}
cataimgui::draw_colored_text( description );
}
Expand Down Expand Up @@ -379,6 +397,7 @@ void uilist::init()
ret_evt = input_event(); // last input event
keymap.clear(); // keymap[input_event] == index, for entries[index]
selected = 0; // current highlight, for entries[index]
hovered = 0; // current mouse highlight, for entries[index]
entries.clear(); // uilist_entry(int returnval, bool enabled, int keycode, std::string text, ... TODO: submenu stuff)
started = false; // set to true when width and key calculations are done, and window is generated.
desc_enabled = false; // don't show option description by default
Expand Down Expand Up @@ -423,8 +442,6 @@ input_context uilist::create_main_input_context() const
ctxt.register_action( "PAGE_DOWN", to_translation( "Fast scroll down" ) );
ctxt.register_action( "HOME", to_translation( "Go to first entry" ) );
ctxt.register_action( "END", to_translation( "Go to last entry" ) );
ctxt.register_action( "SCROLL_UP" );
ctxt.register_action( "SCROLL_DOWN" );
if( allow_cancel ) {
ctxt.register_action( "UILIST.QUIT" );
}
Expand Down Expand Up @@ -701,8 +718,6 @@ int uilist::scroll_amount_from_action( const std::string &action )
return -1;
} else if( action == "PAGE_UP" ) {
return -scroll_rate;
} else if( action == "SCROLL_UP" ) {
return -3;
} else if( action == "HOME" ) {
return -fselected;
} else if( action == "END" ) {
Expand All @@ -711,8 +726,6 @@ int uilist::scroll_amount_from_action( const std::string &action )
return 1;
} else if( action == "PAGE_DOWN" ) {
return scroll_rate;
} else if( action == "SCROLL_DOWN" ) {
return +3;
} else {
return 0;
}
Expand Down Expand Up @@ -768,7 +781,7 @@ bool uilist::scrollby( const int scrollby )
}
}
if( static_cast<size_t>( fselected ) < fentries.size() ) {
selected = fentries [ fselected ];
selected = hovered = fentries [ fselected ];
if( callback != nullptr ) {
callback->select( this );
}
Expand Down Expand Up @@ -890,6 +903,7 @@ void uilist::query( bool loop, int timeout, bool allow_unfiltered_hotkeys )
recalc_start = false;

if( scrollby( scroll_amount_from_action( ret_act ) ) ) {
need_to_scroll = true;
recalc_start = true;
} else if( filtering && ret_act == "UILIST.FILTER" ) {
inputfilter();
Expand Down Expand Up @@ -925,14 +939,15 @@ void uilist::query( bool loop, int timeout, bool allow_unfiltered_hotkeys )
}
}
}
} else if( allow_confirm && !fentries.empty() && ( ret_act == "CONFIRM" || ret_act == "SELECT" ) ) {
} else if( allow_confirm && !fentries.empty() && ( clicked || ret_act == "CONFIRM" ) ) {
clicked = false;
if( entries[ selected ].enabled || allow_disabled ) {
ret = entries[selected].retval;
}
} else if( allow_cancel && ret_act == "UILIST.QUIT" ) {
ret = UILIST_CANCEL;
} else if( ret_act == "TIMEOUT" ) {
ret = UILIST_TIMEOUT;
ret = UILIST_WAIT_INPUT;
} else {
// including HELP_KEYBINDINGS, in case the caller wants to refresh their contents
bool unhandled = callback == nullptr || !callback->key( ctxt, event, selected, this );
Expand Down Expand Up @@ -1016,7 +1031,7 @@ void uilist::settext( const std::string &str )

void uilist::set_selected( int index )
{
selected = std::clamp( index, 0, static_cast<int>( entries.size() - 1 ) );
selected = hovered = std::clamp( index, 0, static_cast<int>( entries.size() - 1 ) );
}

void uilist::add_category( const std::string &key, const std::string &name )
Expand Down Expand Up @@ -1084,7 +1099,7 @@ void uimenu::finalize_addentries()

void uimenu::set_selected( int index )
{
menu.selected = index;
menu.selected = menu.hovered = index;
}

void uimenu::set_title( const std::string &title )
Expand Down
11 changes: 6 additions & 5 deletions src/ui.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ struct uilist_entry {
* }
* }
* void refresh( uilist *menu ) {
* if( menu->selected >= 0 && static_cast<size_t>( menu->selected ) < game_z.size() ) {
* ImGui::TextColored( c_red, "( %s )", game_z[menu->selected]->name() );
* if( menu->hovered >= 0 && static_cast<size_t>( menu->hovered ) < game_z.size() ) {
* ImGui::TextColored( c_red, "( %s )", game_z[menu->hovered]->name() );
* }
* }
* }
Expand Down Expand Up @@ -294,7 +294,7 @@ class uilist // NOLINT(cata-xy)
// initialize the window or reposition it after screen size change.
void reposition();
bool scrollby( int scrollby );
void query( bool loop = true, int timeout = -1, bool allow_unfiltered_hotkeys = false );
void query( bool loop = true, int timeout = 50, bool allow_unfiltered_hotkeys = false );
void filterlist();
// In add_entry/add_entry_desc/add_entry_col, int k only support letters
// (a-z, A-Z) and digits (0-9), MENU_AUTOASSIGN, and 0 or ' ' (disable
Expand Down Expand Up @@ -480,9 +480,9 @@ class uilist // NOLINT(cata-xy)
int vmax = 0;

bool started = false;

bool recalc_start = false;

bool clicked = false;
bool need_to_scroll = false;
std::vector<std::pair<std::string, std::string>> categories;
std::function<bool( const uilist_entry &, const std::string & )> category_filter;
int current_category = 0;
Expand All @@ -494,6 +494,7 @@ class uilist // NOLINT(cata-xy)
input_event ret_evt;
int ret = 0;
int selected = 0;
int hovered = 0;

void set_selected( int index );
};
Expand Down
8 changes: 4 additions & 4 deletions src/wish.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ class wish_mutate_callback: public uilist_callback

ImGui::TableSetColumnIndex( 2 );

if( menu->selected >= 0 && static_cast<size_t>( menu->selected ) < vTraits.size() ) {
const mutation_branch &mdata = vTraits[menu->selected].obj();
if( menu->hovered >= 0 && static_cast<size_t>( menu->hovered ) < vTraits.size() ) {
const mutation_branch &mdata = vTraits[menu->hovered].obj();

ImGui::TextUnformatted( mdata.valid ? _( "Valid" ) : _( "Nonvalid" ) );
ImGui::NewLine();
Expand Down Expand Up @@ -672,7 +672,7 @@ class wish_monster_callback: public uilist_callback
info_size.x = desired_extra_space_right( );
ImGui::TableSetColumnIndex( 2 );
if( ImGui::BeginChild( "monster info", info_size ) ) {
const int entnum = menu->selected;
const int entnum = menu->hovered;
const bool valid_entnum = entnum >= 0 && static_cast<size_t>( entnum ) < mtypes.size();
if( entnum != lastent ) {
lastent = entnum;
Expand Down Expand Up @@ -921,7 +921,7 @@ class wish_item_callback: public uilist_callback
info_size.x = desired_extra_space_right( );
ImGui::TableSetColumnIndex( 2 );
if( ImGui::BeginChild( "monster info", info_size ) ) {
const int entnum = menu->selected;
const int entnum = menu->hovered;
if( entnum >= 0 && static_cast<size_t>( entnum ) < standard_itype_ids.size() ) {
item tmp = wishitem_produce( *standard_itype_ids[entnum], flags, false );

Expand Down

0 comments on commit 2b4fa4b

Please sign in to comment.