From c05ec5f9d0a69b5e7c4ccf38aeafe75dc1aff0c8 Mon Sep 17 00:00:00 2001 From: attila Date: Mon, 1 Aug 2022 19:02:10 +0200 Subject: [PATCH] MenuBarComponent: Fix incorrect deactivation of the menu bar Prior to this commit it was possible to get the menu bar deactivated by moving the mouse to an adjacent menu item and then back again. If the movement was quick enough the corresponding PopupMenu would be dismissed and created again before the dismissal's async command handler would run. The command handler would see that the dismissed menu's index and the currently activated index are equal and deactivate the menu bar. --- .../menus/juce_MenuBarComponent.cpp | 60 ++++++++++--------- .../menus/juce_MenuBarComponent.h | 3 +- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/modules/juce_gui_basics/menus/juce_MenuBarComponent.cpp b/modules/juce_gui_basics/menus/juce_MenuBarComponent.cpp index 99bec2c987..328b46f7c5 100644 --- a/modules/juce_gui_basics/menus/juce_MenuBarComponent.cpp +++ b/modules/juce_gui_basics/menus/juce_MenuBarComponent.cpp @@ -223,41 +223,47 @@ void MenuBarComponent::updateItemUnderMouse (Point p) void MenuBarComponent::showMenu (int index) { - if (index != currentPopupIndex) + if (index == currentPopupIndex) + return; + + const auto needToOpenNewSubMenu = isPositiveAndBelow (index, (int) itemComponents.size()); + + if (needToOpenNewSubMenu) + ++numActiveMenus; + + PopupMenu::dismissAllActiveMenus(); + menuBarItemsChanged (nullptr); + + setOpenItem (index); + setItemUnderMouse (index); + + if (needToOpenNewSubMenu) { - PopupMenu::dismissAllActiveMenus(); - menuBarItemsChanged (nullptr); + const auto& itemComponent = itemComponents[(size_t) index]; + auto m = model->getMenuForIndex (itemUnderMouse, itemComponent->getName()); - setOpenItem (index); - setItemUnderMouse (index); + if (m.lookAndFeel == nullptr) + m.setLookAndFeel (&getLookAndFeel()); - if (isPositiveAndBelow (index, (int) itemComponents.size())) + auto itemBounds = itemComponent->getBounds(); + + const auto callback = [ref = SafePointer (this), index] (int result) { - const auto& itemComponent = itemComponents[(size_t) index]; - auto m = model->getMenuForIndex (itemUnderMouse, itemComponent->getName()); + if (ref != nullptr) + ref->menuDismissed (index, result); + }; - if (m.lookAndFeel == nullptr) - m.setLookAndFeel (&getLookAndFeel()); - - auto itemBounds = itemComponent->getBounds(); - - const auto callback = [ref = SafePointer (this), index] (int result) - { - if (ref != nullptr) - ref->menuDismissed (index, result); - }; - - m.showMenuAsync (PopupMenu::Options().withTargetComponent (this) - .withTargetScreenArea (localAreaToGlobal (itemBounds)) - .withMinimumWidth (itemBounds.getWidth()), - callback); - } + m.showMenuAsync (PopupMenu::Options().withTargetComponent (this) + .withTargetScreenArea (localAreaToGlobal (itemBounds)) + .withMinimumWidth (itemBounds.getWidth()), + callback); } } void MenuBarComponent::menuDismissed (int topLevelIndex, int itemId) { - topLevelIndexClicked = topLevelIndex; + topLevelIndexDismissed = topLevelIndex; + --numActiveMenus; postCommandMessage (itemId); } @@ -265,11 +271,11 @@ void MenuBarComponent::handleCommandMessage (int commandId) { updateItemUnderMouse (getMouseXYRelative()); - if (currentPopupIndex == topLevelIndexClicked) + if (numActiveMenus == 0) setOpenItem (-1); if (commandId != 0 && model != nullptr) - model->menuItemSelected (commandId, topLevelIndexClicked); + model->menuItemSelected (commandId, topLevelIndexDismissed); } //============================================================================== diff --git a/modules/juce_gui_basics/menus/juce_MenuBarComponent.h b/modules/juce_gui_basics/menus/juce_MenuBarComponent.h index 602e7bf0a6..d17613168c 100644 --- a/modules/juce_gui_basics/menus/juce_MenuBarComponent.h +++ b/modules/juce_gui_basics/menus/juce_MenuBarComponent.h @@ -119,7 +119,8 @@ private: std::vector> itemComponents; Point lastMousePos; - int itemUnderMouse = -1, currentPopupIndex = -1, topLevelIndexClicked = 0; + int itemUnderMouse = -1, currentPopupIndex = -1, topLevelIndexDismissed = 0; + int numActiveMenus = 0; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MenuBarComponent) };