gui: Better positioning of submenus in the main UI (#8517)

This makes it possible to fetch the on-screen coordinates of a drop
down menu item as the menu is dismissed by clicking on it so the
caller can use these coordinates to make a more informed decision as
to where to spawn a submenu, improving the previous mechanism wherein
the submenu would have its top left corner set at the mouse's location
which would produce different results depending on where exactly in
the menu item's box the mouse was at the time the parent menu was
dismissed.
This commit is contained in:
Iris Morelle 2025-01-15 23:02:02 -03:00 committed by GitHub
parent 20c95a472c
commit 5a7bd7c51f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 29 additions and 3 deletions

View File

@ -0,0 +1,2 @@
### User interface
* Submenus are now positioned at the location of the menu item that spawned them, rather than the location of the mouse cursor at the time of click

View File

@ -85,6 +85,7 @@ drop_down_menu::drop_down_menu(styled_widget* parent, const std::vector<config>&
, items_(items.begin(), items.end())
, button_pos_(parent->get_rectangle())
, selected_item_(selected_item)
, selected_item_pos_(-1, -1)
, use_markup_(parent->get_use_markup())
, keep_open_(keep_open)
, mouse_down_happened_(false)
@ -241,7 +242,17 @@ void drop_down_menu::pre_show()
void drop_down_menu::post_show()
{
selected_item_ = find_widget<listbox>("list", true).get_selected_row();
const listbox& list = find_widget<listbox>("list", true);
selected_item_ = list.get_selected_row();
if(selected_item_ != -1) {
const grid* row_grid = list.get_row_grid(selected_item_);
if(row_grid) {
selected_item_pos_.x = row_grid->get_x();
selected_item_pos_.y = row_grid->get_y();
}
} else {
selected_item_pos_.x = selected_item_pos_.y = -1;
}
}
boost::dynamic_bitset<> drop_down_menu::get_toggle_states() const

View File

@ -44,6 +44,11 @@ public:
return selected_item_;
}
point selected_item_pos() const
{
return selected_item_pos_;
}
/** If a toggle button widget is present, returns the toggled state of each row's button. */
boost::dynamic_bitset<> get_toggle_states() const;
@ -86,6 +91,7 @@ private:
SDL_Rect button_pos_;
int selected_item_;
point selected_item_pos_;
bool use_markup_;

View File

@ -417,11 +417,19 @@ void command_executor::show_menu(const std::vector<config>& items_arg, int xloc,
get_menu_images(gui, items);
int res = -1;
point selection_pos;
{
SDL_Rect pos {xloc, yloc, 1, 1};
gui2::dialogs::drop_down_menu mmenu(pos, items, -1, true, false); // TODO: last value should be variable
if(mmenu.show()) {
res = mmenu.selected_item();
if(res >= 0) {
// Get selection coordinates for a potential submenu below
selection_pos = mmenu.selected_item_pos();
// Compensate for borders
selection_pos.x--;
selection_pos.y--;
}
}
} // This will kill the dialog.
if (res < 0 || std::size_t(res) >= items.size()) return;
@ -429,8 +437,7 @@ void command_executor::show_menu(const std::vector<config>& items_arg, int xloc,
std::string id = items[res]["id"];
const theme::menu* submenu = gui.get_theme().get_menu_item(id);
if (submenu) {
auto [x, y] = sdl::get_mouse_location();
this->show_menu(submenu->items(), x, y, submenu->is_context(), gui);
this->show_menu(submenu->items(), selection_pos.x, selection_pos.y, submenu->is_context(), gui);
} else {
hotkey::ui_command cmd = hotkey::ui_command(id, res);
do_execute_command(cmd);