diff --git a/changelog_entries/submenu-positioning.md b/changelog_entries/submenu-positioning.md new file mode 100644 index 00000000000..a3d804f44d9 --- /dev/null +++ b/changelog_entries/submenu-positioning.md @@ -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 diff --git a/src/gui/dialogs/drop_down_menu.cpp b/src/gui/dialogs/drop_down_menu.cpp index 25527fbf145..2518f45ae46 100644 --- a/src/gui/dialogs/drop_down_menu.cpp +++ b/src/gui/dialogs/drop_down_menu.cpp @@ -85,6 +85,7 @@ drop_down_menu::drop_down_menu(styled_widget* parent, const std::vector& , 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("list", true).get_selected_row(); + const listbox& list = find_widget("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 diff --git a/src/gui/dialogs/drop_down_menu.hpp b/src/gui/dialogs/drop_down_menu.hpp index cd870710d27..5d28a325b4e 100644 --- a/src/gui/dialogs/drop_down_menu.hpp +++ b/src/gui/dialogs/drop_down_menu.hpp @@ -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_; diff --git a/src/hotkey/command_executor.cpp b/src/hotkey/command_executor.cpp index 8c6a032af00..1fd53af82ef 100644 --- a/src/hotkey/command_executor.cpp +++ b/src/hotkey/command_executor.cpp @@ -417,11 +417,19 @@ void command_executor::show_menu(const std::vector& 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& 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);