diff --git a/modules/juce_gui_basics/components/juce_Component.cpp b/modules/juce_gui_basics/components/juce_Component.cpp index 7eb1d58918..0225e714b7 100644 --- a/modules/juce_gui_basics/components/juce_Component.cpp +++ b/modules/juce_gui_basics/components/juce_Component.cpp @@ -39,6 +39,51 @@ static Component* findFirstEnabledAncestor (Component* in) Component* Component::currentlyFocusedComponent = nullptr; +//============================================================================== +class HierarchyChecker +{ +public: + HierarchyChecker (Component* comp, const MouseEvent& originalEvent) + : me (originalEvent) + { + for (; comp != nullptr; comp = comp->getParentComponent()) + hierarchy.emplace_back (comp); + } + + Component* nearestNonNullParent() const + { + for (auto& comp : hierarchy) + if (comp != nullptr) + return comp; + + return nullptr; + } + + bool shouldBailOut() const + { + return nearestNonNullParent() == nullptr; + } + + MouseEvent eventWithNearestParent() const + { + auto* comp = nearestNonNullParent(); + return { me.source, + me.position.toFloat(), + me.mods, + me.pressure, me.orientation, me.rotation, + me.tiltX, me.tiltY, + comp, comp, + me.eventTime, + me.mouseDownPosition.toFloat(), + me.mouseDownTime, + me.getNumberOfClicks(), + me.mouseWasDraggedSinceMouseDown() }; + } + +private: + std::vector> hierarchy; + const MouseEvent me; +}; //============================================================================== class Component::MouseListenerList @@ -75,51 +120,14 @@ public: } } - // g++ 4.8 cannot deduce the parameter pack inside the function pointer when it has more than one element - #if defined(__GNUC__) && __GNUC__ < 5 && ! defined(__clang__) - template - static void sendMouseEvent (Component& comp, Component::BailOutChecker& checker, - void (MouseListener::*eventMethod) (const MouseEvent&), - Params... params) - { - sendMouseEvent (comp, checker, eventMethod, params...); - } - - template - static void sendMouseEvent (Component& comp, Component::BailOutChecker& checker, - void (MouseListener::*eventMethod) (const MouseEvent&, const MouseWheelDetails&), - Params... params) - { - sendMouseEvent (comp, checker, eventMethod, params...); - } - - template - static void sendMouseEvent (Component& comp, Component::BailOutChecker& checker, - void (MouseListener::*eventMethod) (const MouseEvent&, float), - Params... params) - { - sendMouseEvent (comp, checker, eventMethod, params...); - } - template - static void sendMouseEvent (Component& comp, Component::BailOutChecker& checker, - EventMethod eventMethod, - Params... params) - #else - template - static void sendMouseEvent (Component& comp, Component::BailOutChecker& checker, - void (MouseListener::*eventMethod) (Params...), - Params... params) - #endif + static void sendMouseEvent (HierarchyChecker& checker, EventMethod&& eventMethod, Params&&... params) { - if (checker.shouldBailOut()) - return; - - if (auto* list = comp.mouseListeners.get()) + if (auto* list = checker.nearestNonNullParent()->mouseListeners.get()) { for (int i = list->listeners.size(); --i >= 0;) { - (list->listeners.getUnchecked(i)->*eventMethod) (params...); + (list->listeners.getUnchecked (i)->*eventMethod) (checker.eventWithNearestParent(), params...); if (checker.shouldBailOut()) return; @@ -128,19 +136,22 @@ public: } } - for (Component* p = comp.parentComponent; p != nullptr; p = p->parentComponent) + for (Component* p = checker.nearestNonNullParent()->parentComponent; p != nullptr; p = p->parentComponent) { if (auto* list = p->mouseListeners.get()) { if (list->numDeepMouseListeners > 0) { - BailOutChecker2 checker2 (checker, p); + const auto shouldBailOut = [&checker, safePointer = WeakReference { p }] + { + return checker.shouldBailOut() || safePointer == nullptr; + }; for (int i = list->numDeepMouseListeners; --i >= 0;) { - (list->listeners.getUnchecked(i)->*eventMethod) (params...); + (list->listeners.getUnchecked(i)->*eventMethod) (checker.eventWithNearestParent(), params...); - if (checker2.shouldBailOut()) + if (shouldBailOut()) return; i = jmin (i, list->numDeepMouseListeners); @@ -154,25 +165,6 @@ private: Array listeners; int numDeepMouseListeners = 0; - struct BailOutChecker2 - { - BailOutChecker2 (Component::BailOutChecker& boc, Component* comp) - : checker (boc), safePointer (comp) - { - } - - bool shouldBailOut() const noexcept - { - return checker.shouldBailOut() || safePointer == nullptr; - } - - private: - Component::BailOutChecker& checker; - const WeakReference safePointer; - - JUCE_DECLARE_NON_COPYABLE (BailOutChecker2) - }; - JUCE_DECLARE_NON_COPYABLE (MouseListenerList) }; @@ -2422,8 +2414,6 @@ void Component::internalMouseEnter (MouseInputSource source, Point relati if (flags.repaintOnMouseActivityFlag) repaint(); - BailOutChecker checker (this); - const auto me = makeMouseEvent (source, PointerState().withPosition (relativePos), source.getCurrentModifiers(), @@ -2434,6 +2424,8 @@ void Component::internalMouseEnter (MouseInputSource source, Point relati time, 0, false); + + HierarchyChecker checker (this, me); mouseEnter (me); flags.cachedMouseInsideComponent = true; @@ -2442,8 +2434,7 @@ void Component::internalMouseEnter (MouseInputSource source, Point relati return; Desktop::getInstance().getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseEnter (me); }); - - MouseListenerList::template sendMouseEvent (*this, checker, &MouseListener::mouseEnter, me); + MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseEnter); } void Component::internalMouseExit (MouseInputSource source, Point relativePos, Time time) @@ -2460,8 +2451,6 @@ void Component::internalMouseExit (MouseInputSource source, Point relativ flags.cachedMouseInsideComponent = false; - BailOutChecker checker (this); - const auto me = makeMouseEvent (source, PointerState().withPosition (relativePos), source.getCurrentModifiers(), @@ -2473,20 +2462,32 @@ void Component::internalMouseExit (MouseInputSource source, Point relativ 0, false); + HierarchyChecker checker (this, me); mouseExit (me); if (checker.shouldBailOut()) return; Desktop::getInstance().getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseExit (me); }); - - MouseListenerList::template sendMouseEvent (*this, checker, &MouseListener::mouseExit, me); + MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseExit); } void Component::internalMouseDown (MouseInputSource source, const PointerState& relativePointerState, Time time) { auto& desktop = Desktop::getInstance(); - BailOutChecker checker (this); + + const auto me = makeMouseEvent (source, + relativePointerState, + source.getCurrentModifiers(), + this, + this, + time, + relativePointerState.position, + time, + source.getNumberOfMultipleClicks(), + false); + + HierarchyChecker checker (this, me); if (isCurrentlyBlockedByAnotherModalComponent()) { @@ -2501,18 +2502,7 @@ void Component::internalMouseDown (MouseInputSource source, const PointerState& if (isCurrentlyBlockedByAnotherModalComponent()) { // allow blocked mouse-events to go to global listeners.. - const auto me = makeMouseEvent (source, - relativePointerState, - source.getCurrentModifiers(), - this, - this, - time, - relativePointerState.position, - time, - source.getNumberOfMultipleClicks(), - false); - - desktop.getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseDown (me); }); + desktop.getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseDown (checker.eventWithNearestParent()); }); return; } } @@ -2541,24 +2531,14 @@ void Component::internalMouseDown (MouseInputSource source, const PointerState& if (flags.repaintOnMouseActivityFlag) repaint(); - const auto me = makeMouseEvent (source, - relativePointerState, - source.getCurrentModifiers(), - this, - this, - time, - relativePointerState.position, - time, - source.getNumberOfMultipleClicks(), - false); mouseDown (me); if (checker.shouldBailOut()) return; - desktop.getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseDown (me); }); + desktop.getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseDown (checker.eventWithNearestParent()); }); - MouseListenerList::template sendMouseEvent (*this, checker, &MouseListener::mouseDown, me); + MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseDown); } void Component::internalMouseUp (MouseInputSource source, const PointerState& relativePointerState, Time time, const ModifierKeys oldModifiers) @@ -2566,11 +2546,6 @@ void Component::internalMouseUp (MouseInputSource source, const PointerState& re if (flags.mouseDownWasBlocked && isCurrentlyBlockedByAnotherModalComponent()) return; - BailOutChecker checker (this); - - if (flags.repaintOnMouseActivityFlag) - repaint(); - const auto me = makeMouseEvent (source, relativePointerState, oldModifiers, @@ -2581,15 +2556,21 @@ void Component::internalMouseUp (MouseInputSource source, const PointerState& re source.getLastMouseDownTime(), source.getNumberOfMultipleClicks(), source.isLongPressOrDrag()); + + HierarchyChecker checker (this, me); + + if (flags.repaintOnMouseActivityFlag) + repaint(); + mouseUp (me); if (checker.shouldBailOut()) return; auto& desktop = Desktop::getInstance(); - desktop.getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseUp (me); }); + desktop.getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseUp (checker.eventWithNearestParent()); }); - MouseListenerList::template sendMouseEvent (*this, checker, &MouseListener::mouseUp, me); + MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseUp); if (checker.shouldBailOut()) return; @@ -2597,13 +2578,13 @@ void Component::internalMouseUp (MouseInputSource source, const PointerState& re // check for double-click if (me.getNumberOfClicks() >= 2) { - mouseDoubleClick (me); + mouseDoubleClick (checker.eventWithNearestParent()); if (checker.shouldBailOut()) return; - desktop.mouseListeners.callChecked (checker, [&] (MouseListener& l) { l.mouseDoubleClick (me); }); - MouseListenerList::template sendMouseEvent (*this, checker, &MouseListener::mouseDoubleClick, me); + desktop.mouseListeners.callChecked (checker, [&] (MouseListener& l) { l.mouseDoubleClick (checker.eventWithNearestParent()); }); + MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseDoubleClick); } } @@ -2611,8 +2592,6 @@ void Component::internalMouseDrag (MouseInputSource source, const PointerState& { if (! isCurrentlyBlockedByAnotherModalComponent()) { - BailOutChecker checker (this); - const auto me = makeMouseEvent (source, relativePointerState, source.getCurrentModifiers(), @@ -2623,14 +2602,16 @@ void Component::internalMouseDrag (MouseInputSource source, const PointerState& source.getLastMouseDownTime(), source.getNumberOfMultipleClicks(), source.isLongPressOrDrag()); + + HierarchyChecker checker (this, me); + mouseDrag (me); if (checker.shouldBailOut()) return; - Desktop::getInstance().getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseDrag (me); }); - - MouseListenerList::template sendMouseEvent (*this, checker, &MouseListener::mouseDrag, me); + Desktop::getInstance().getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseDrag (checker.eventWithNearestParent()); }); + MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseDrag); } } @@ -2645,8 +2626,6 @@ void Component::internalMouseMove (MouseInputSource source, Point relativ } else { - BailOutChecker checker (this); - const auto me = makeMouseEvent (source, PointerState().withPosition (relativePos), source.getCurrentModifiers(), @@ -2657,14 +2636,16 @@ void Component::internalMouseMove (MouseInputSource source, Point relativ time, 0, false); + + HierarchyChecker checker (this, me); + mouseMove (me); if (checker.shouldBailOut()) return; - desktop.getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseMove (me); }); - - MouseListenerList::template sendMouseEvent (*this, checker, &MouseListener::mouseMove, me); + desktop.getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseMove (checker.eventWithNearestParent()); }); + MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseMove); } } @@ -2672,7 +2653,6 @@ void Component::internalMouseWheel (MouseInputSource source, Point relati Time time, const MouseWheelDetails& wheel) { auto& desktop = Desktop::getInstance(); - BailOutChecker checker (this); const auto me = makeMouseEvent (source, PointerState().withPosition (relativePos), @@ -2685,6 +2665,8 @@ void Component::internalMouseWheel (MouseInputSource source, Point relati 0, false); + HierarchyChecker checker (this, me); + if (isCurrentlyBlockedByAnotherModalComponent()) { // allow blocked mouse-events to go to global listeners.. @@ -2697,10 +2679,10 @@ void Component::internalMouseWheel (MouseInputSource source, Point relati if (checker.shouldBailOut()) return; - desktop.mouseListeners.callChecked (checker, [&] (MouseListener& l) { l.mouseWheelMove (me, wheel); }); + desktop.mouseListeners.callChecked (checker, [&] (MouseListener& l) { l.mouseWheelMove (checker.eventWithNearestParent(), wheel); }); if (! checker.shouldBailOut()) - MouseListenerList::template sendMouseEvent (*this, checker, &MouseListener::mouseWheelMove, me, wheel); + MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseWheelMove, wheel); } } @@ -2708,7 +2690,6 @@ void Component::internalMagnifyGesture (MouseInputSource source, Point re Time time, float amount) { auto& desktop = Desktop::getInstance(); - BailOutChecker checker (this); const auto me = makeMouseEvent (source, PointerState().withPosition (relativePos), @@ -2721,6 +2702,8 @@ void Component::internalMagnifyGesture (MouseInputSource source, Point re 0, false); + HierarchyChecker checker (this, me); + if (isCurrentlyBlockedByAnotherModalComponent()) { // allow blocked mouse-events to go to global listeners.. @@ -2733,10 +2716,10 @@ void Component::internalMagnifyGesture (MouseInputSource source, Point re if (checker.shouldBailOut()) return; - desktop.mouseListeners.callChecked (checker, [&] (MouseListener& l) { l.mouseMagnify (me, amount); }); + desktop.mouseListeners.callChecked (checker, [&] (MouseListener& l) { l.mouseMagnify (checker.eventWithNearestParent(), amount); }); if (! checker.shouldBailOut()) - MouseListenerList::template sendMouseEvent (*this, checker, &MouseListener::mouseMagnify, me, amount); + MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseMagnify, amount); } }