This allows the LookAndFeel of submenus to query the target component used for the top-level menu. getTargetComponent() isn't suitable for this because the target component is set to null for submenus, and this behaviour can't be changed without potentially breaking code that relies on the current behaviour.develop
| @@ -1195,22 +1195,19 @@ struct MenuWindow final : public Component | |||||
| { | { | ||||
| activeSubMenu.reset(); | activeSubMenu.reset(); | ||||
| if (childComp != nullptr | |||||
| && hasActiveSubMenu (childComp->item)) | |||||
| { | |||||
| activeSubMenu.reset (new HelperClasses::MenuWindow (*(childComp->item.subMenu), this, | |||||
| options.withTargetScreenArea (childComp->getScreenBounds()) | |||||
| .withMinimumWidth (0) | |||||
| .withTargetComponent (nullptr), | |||||
| false, dismissOnMouseUp, managerOfChosenCommand, scaleFactor)); | |||||
| activeSubMenu->setVisible (true); // (must be called before enterModalState on Windows to avoid DropShadower confusion) | |||||
| activeSubMenu->enterModalState (false); | |||||
| activeSubMenu->toFront (false); | |||||
| return true; | |||||
| } | |||||
| if (childComp == nullptr || ! hasActiveSubMenu (childComp->item)) | |||||
| return false; | |||||
| return false; | |||||
| activeSubMenu.reset (new HelperClasses::MenuWindow (*(childComp->item.subMenu), this, | |||||
| options.forSubmenu() | |||||
| .withTargetScreenArea (childComp->getScreenBounds()) | |||||
| .withMinimumWidth (0), | |||||
| false, dismissOnMouseUp, managerOfChosenCommand, scaleFactor)); | |||||
| activeSubMenu->setVisible (true); // (must be called before enterModalState on Windows to avoid DropShadower confusion) | |||||
| activeSubMenu->enterModalState (false); | |||||
| activeSubMenu->toFront (false); | |||||
| return true; | |||||
| } | } | ||||
| void triggerCurrentlyHighlightedItem() | void triggerCurrentlyHighlightedItem() | ||||
| @@ -1975,7 +1972,7 @@ static PopupMenu::Options with (PopupMenu::Options options, Member&& member, Ite | |||||
| PopupMenu::Options PopupMenu::Options::withTargetComponent (Component* comp) const | PopupMenu::Options PopupMenu::Options::withTargetComponent (Component* comp) const | ||||
| { | { | ||||
| auto o = with (*this, &Options::targetComponent, comp); | |||||
| auto o = with (with (*this, &Options::targetComponent, comp), &Options::topLevelTarget, comp); | |||||
| if (comp != nullptr) | if (comp != nullptr) | ||||
| o.targetArea = comp->getScreenBounds(); | o.targetArea = comp->getScreenBounds(); | ||||
| @@ -2045,6 +2042,11 @@ PopupMenu::Options PopupMenu::Options::withInitiallySelectedItem (int idOfItemTo | |||||
| return with (*this, &Options::initiallySelectedItemId, idOfItemToBeSelected); | return with (*this, &Options::initiallySelectedItemId, idOfItemToBeSelected); | ||||
| } | } | ||||
| PopupMenu::Options PopupMenu::Options::forSubmenu() const | |||||
| { | |||||
| return with (*this, &Options::targetComponent, nullptr); | |||||
| } | |||||
| Component* PopupMenu::createWindow (const Options& options, | Component* PopupMenu::createWindow (const Options& options, | ||||
| ApplicationCommandManager** managerOfChosenCommand) const | ApplicationCommandManager** managerOfChosenCommand) const | ||||
| { | { | ||||
| @@ -562,6 +562,13 @@ public: | |||||
| */ | */ | ||||
| [[nodiscard]] Options withInitiallySelectedItem (int idOfItemToBeSelected) const; | [[nodiscard]] Options withInitiallySelectedItem (int idOfItemToBeSelected) const; | ||||
| /** Returns a copy of these options with the target component set to null. The value of the | |||||
| top-level target component will not be changed. | |||||
| @see getTargetComponent(), getTopLevelTargetComponent() | |||||
| */ | |||||
| [[nodiscard]] Options forSubmenu() const; | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Gets the parent component. This may be nullptr if the Component has been deleted. | /** Gets the parent component. This may be nullptr if the Component has been deleted. | ||||
| @@ -575,6 +582,14 @@ public: | |||||
| */ | */ | ||||
| Component* getTargetComponent() const noexcept { return targetComponent; } | Component* getTargetComponent() const noexcept { return targetComponent; } | ||||
| /** Gets the target component that was set for the top-level menu. | |||||
| When querying the options of a submenu, getTargetComponent() will always return | |||||
| nullptr, while getTopLevelTargetComponent() will return the target passed to | |||||
| withTargetComponent() when creating the top-level menu. | |||||
| */ | |||||
| Component* getTopLevelTargetComponent() const noexcept { return topLevelTarget; } | |||||
| /** Returns true if the menu was watching a component, and that component has been deleted, and false otherwise. | /** Returns true if the menu was watching a component, and that component has been deleted, and false otherwise. | ||||
| @see withDeletionCheck | @see withDeletionCheck | ||||
| @@ -632,7 +647,7 @@ public: | |||||
| private: | private: | ||||
| //============================================================================== | //============================================================================== | ||||
| Rectangle<int> targetArea; | Rectangle<int> targetArea; | ||||
| WeakReference<Component> targetComponent, parentComponent, componentToWatchForDeletion; | |||||
| WeakReference<Component> targetComponent, parentComponent, componentToWatchForDeletion, topLevelTarget; | |||||
| int visibleItemID = 0, minWidth = 0, minColumns = 1, maxColumns = 0, standardHeight = 0, initiallySelectedItemId = 0; | int visibleItemID = 0, minWidth = 0, minColumns = 1, maxColumns = 0, standardHeight = 0, initiallySelectedItemId = 0; | ||||
| bool isWatchingForDeletion = false; | bool isWatchingForDeletion = false; | ||||
| PopupDirection preferredPopupDirection = PopupDirection::downwards; | PopupDirection preferredPopupDirection = PopupDirection::downwards; | ||||