| @@ -470,6 +470,24 @@ struct Component::ComponentHelpers | |||||
| for (auto* child : c.childComponentList) | for (auto* child : c.childComponentList) | ||||
| releaseAllCachedImageResources (*child); | releaseAllCachedImageResources (*child); | ||||
| } | } | ||||
| //============================================================================== | |||||
| static bool modalWouldBlockComponent (const Component& maybeBlocked, Component* modal) | |||||
| { | |||||
| return modal != nullptr | |||||
| && modal != &maybeBlocked | |||||
| && ! modal->isParentOf (&maybeBlocked) | |||||
| && ! modal->canModalEventBeSentToComponent (&maybeBlocked); | |||||
| } | |||||
| template <typename Function> | |||||
| static void sendMouseEventToComponentsThatAreBlockedByModal (Component& modal, Function&& function) | |||||
| { | |||||
| for (auto& ms : Desktop::getInstance().getMouseSources()) | |||||
| if (auto* c = ms.getComponentUnderMouse()) | |||||
| if (modalWouldBlockComponent (*c, &modal)) | |||||
| (c->*function) (ms, ms.getScreenPosition(), Time::getCurrentTime()); | |||||
| } | |||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -1720,6 +1738,11 @@ void Component::enterModalState (bool shouldTakeKeyboardFocus, | |||||
| if (! isCurrentlyModal (false)) | if (! isCurrentlyModal (false)) | ||||
| { | { | ||||
| // While this component is in modal state it may block other components from receiving | |||||
| // mouseExit events. To keep mouseEnter and mouseExit calls balanced on these components, | |||||
| // we must manually force the mouse to "leave" blocked components. | |||||
| ComponentHelpers::sendMouseEventToComponentsThatAreBlockedByModal (*this, &Component::internalMouseExit); | |||||
| auto& mcm = *ModalComponentManager::getInstance(); | auto& mcm = *ModalComponentManager::getInstance(); | ||||
| mcm.startModal (this, deleteWhenDismissed); | mcm.startModal (this, deleteWhenDismissed); | ||||
| mcm.attachCallback (this, callback); | mcm.attachCallback (this, callback); | ||||
| @@ -1746,10 +1769,10 @@ void Component::exitModalState (int returnValue) | |||||
| mcm.endModal (this, returnValue); | mcm.endModal (this, returnValue); | ||||
| mcm.bringModalComponentsToFront(); | mcm.bringModalComponentsToFront(); | ||||
| // If any of the mouse sources are over another Component when we exit the modal state then send a mouse enter event | |||||
| for (auto& ms : Desktop::getInstance().getMouseSources()) | |||||
| if (auto* c = ms.getComponentUnderMouse()) | |||||
| c->internalMouseEnter (ms, ms.getScreenPosition(), Time::getCurrentTime()); | |||||
| // While this component is in modal state it may block other components from receiving | |||||
| // mouseEnter events. To keep mouseEnter and mouseExit calls balanced on these components, | |||||
| // we must manually force the mouse to "enter" blocked components. | |||||
| ComponentHelpers::sendMouseEventToComponentsThatAreBlockedByModal (*this, &Component::internalMouseEnter); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -1772,10 +1795,7 @@ bool Component::isCurrentlyModal (bool onlyConsiderForemostModalComponent) const | |||||
| bool Component::isCurrentlyBlockedByAnotherModalComponent() const | bool Component::isCurrentlyBlockedByAnotherModalComponent() const | ||||
| { | { | ||||
| auto* mc = getCurrentlyModalComponent(); | |||||
| return ! (mc == nullptr || mc == this || mc->isParentOf (this) | |||||
| || mc->canModalEventBeSentToComponent (this)); | |||||
| return ComponentHelpers::modalWouldBlockComponent (*this, getCurrentlyModalComponent()); | |||||
| } | } | ||||
| int JUCE_CALLTYPE Component::getNumCurrentlyModalComponents() noexcept | int JUCE_CALLTYPE Component::getNumCurrentlyModalComponents() noexcept | ||||