From c5fe5d4fafdf960eb4a3503e47e1a763720317d1 Mon Sep 17 00:00:00 2001 From: Michael Alexsander Date: Mon, 27 Oct 2025 11:54:44 -0300 Subject: [PATCH] Fix `PopupMenu` losing item highlight when hovering submenus --- scene/gui/popup_menu.cpp | 27 +++++++++++++++++++++++---- scene/gui/popup_menu.h | 2 ++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 38c35278c05..14fd53df99e 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -709,6 +709,9 @@ void PopupMenu::_input_from_window_internal(const Ref &p_event) { if (!minimum_lifetime_timer->is_stopped()) { // The mouse left the safe area, but came back again, so cancel the auto-closing. minimum_lifetime_timer->stop(); + if (PopupMenu *parent_pum = Object::cast_to(get_parent())) { + parent_pum->_hover_active_submenu_item(); + } } if (mouse_over == -1 && !item_clickable_area.has_point(m->get_position())) { @@ -765,9 +768,12 @@ void PopupMenu::_mouse_over_update(const Point2 &p_over) { int id = (over < 0 || items[over].separator || items[over].disabled) ? -1 : (items[over].id >= 0 ? items[over].id : over); if (id < 0) { - mouse_over = -1; - queue_accessibility_update(); - control->queue_redraw(); + // Only remove the hover if there's no open submenu, or the mouse is in an item that can't be hovered. + if (over >= 0 || !(mouse_over >= 0 && items[mouse_over].submenu && items[mouse_over].submenu->is_visible())) { + mouse_over = -1; + queue_accessibility_update(); + control->queue_redraw(); + } return; } @@ -1083,6 +1089,19 @@ Rect2i PopupMenu::_popup_adjust_rect() const { return current; } +void PopupMenu::_hover_active_submenu_item() { + for (int i = 0; i < items.size(); i++) { + if (items[i].submenu && items[i].submenu->is_visible()) { + if (mouse_over != i) { + mouse_over = i; + queue_accessibility_update(); + control->queue_redraw(); + } + return; + } + } +} + void PopupMenu::add_child_notify(Node *p_child) { Window::add_child_notify(p_child); @@ -1271,7 +1290,7 @@ void PopupMenu::_notification(int p_what) { } break; case NOTIFICATION_WM_MOUSE_EXIT: { - if (mouse_over >= 0 && (!items[mouse_over].submenu || submenu_over != -1)) { + if (mouse_over >= 0 && (!items[mouse_over].submenu || !items[mouse_over].submenu->is_visible())) { mouse_over = -1; queue_accessibility_update(); control->queue_redraw(); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index 20b0e8a1879..1bfa7af4ddc 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -228,6 +228,8 @@ class PopupMenu : public Popup { String _atr(int p_idx, const String &p_text) const; protected: + void _hover_active_submenu_item(); + virtual void _pre_popup() override; virtual Rect2i _popup_adjust_rect() const override;