diff --git a/modules/juce_graphics/geometry/juce_Path.cpp b/modules/juce_graphics/geometry/juce_Path.cpp index 360140e2c9..97c1c8723e 100644 --- a/modules/juce_graphics/geometry/juce_Path.cpp +++ b/modules/juce_graphics/geometry/juce_Path.cpp @@ -61,15 +61,64 @@ const float Path::quadMarker = 100003.0f; const float Path::cubicMarker = 100004.0f; const float Path::closeSubPathMarker = 100005.0f; +//============================================================================== +Path::PathBounds::PathBounds() noexcept + : pathXMin (0), pathXMax (0), pathYMin (0), pathYMax (0) +{ +} + +Rectangle Path::PathBounds::getRectangle() const noexcept +{ + return Rectangle (pathXMin, pathYMin, pathXMax - pathXMin, pathYMax - pathYMin); +} + +void Path::PathBounds::reset() noexcept +{ + pathXMin = pathYMin = pathYMax = pathXMax = 0; +} + +void Path::PathBounds::reset (const float x, const float y) noexcept +{ + pathXMin = pathXMax = x; + pathYMin = pathYMax = y; +} + +void Path::PathBounds::extend (const float x, const float y) noexcept +{ + pathXMin = jmin (pathXMin, x); + pathXMax = jmax (pathXMax, x); + pathYMin = jmin (pathYMin, y); + pathYMax = jmax (pathYMax, y); +} + +void Path::PathBounds::extend (const float x1, const float y1, const float x2, const float y2) noexcept +{ + if (x1 < x2) + { + pathXMin = jmin (pathXMin, x1); + pathXMax = jmax (pathXMax, x2); + } + else + { + pathXMin = jmin (pathXMin, x2); + pathXMax = jmax (pathXMax, x1); + } + + if (y1 < y2) + { + pathYMin = jmin (pathYMin, y1); + pathYMax = jmax (pathYMax, y2); + } + else + { + pathYMin = jmin (pathYMin, y2); + pathYMax = jmax (pathYMax, y1); + } +} //============================================================================== Path::Path() - : numElements (0), - pathXMin (0), - pathXMax (0), - pathYMin (0), - pathYMax (0), - useNonZeroWinding (true) + : numElements (0), useNonZeroWinding (true) { } @@ -79,10 +128,7 @@ Path::~Path() Path::Path (const Path& other) : numElements (other.numElements), - pathXMin (other.pathXMin), - pathXMax (other.pathXMax), - pathYMin (other.pathYMin), - pathYMax (other.pathYMax), + bounds (other.bounds), useNonZeroWinding (other.useNonZeroWinding) { if (numElements > 0) @@ -99,10 +145,7 @@ Path& Path::operator= (const Path& other) data.ensureAllocatedSize ((int) other.numElements); numElements = other.numElements; - pathXMin = other.pathXMin; - pathXMax = other.pathXMax; - pathYMin = other.pathYMin; - pathYMax = other.pathYMax; + bounds = other.bounds; useNonZeroWinding = other.useNonZeroWinding; if (numElements > 0) @@ -116,10 +159,7 @@ Path& Path::operator= (const Path& other) Path::Path (Path&& other) noexcept : data (static_cast &&> (other.data)), numElements (other.numElements), - pathXMin (other.pathXMin), - pathXMax (other.pathXMax), - pathYMin (other.pathYMin), - pathYMax (other.pathYMax), + bounds (other.bounds), useNonZeroWinding (other.useNonZeroWinding) { } @@ -128,10 +168,7 @@ Path& Path::operator= (Path&& other) noexcept { data = static_cast &&> (other.data); numElements = other.numElements; - pathXMin = other.pathXMin; - pathXMax = other.pathXMax; - pathYMin = other.pathYMin; - pathYMax = other.pathYMax; + bounds = other.bounds; useNonZeroWinding = other.useNonZeroWinding; return *this; } @@ -157,20 +194,17 @@ bool Path::operator!= (const Path& other) const noexcept void Path::clear() noexcept { numElements = 0; - pathXMin = 0; - pathYMin = 0; - pathYMax = 0; - pathXMax = 0; + bounds.reset(); } void Path::swapWithPath (Path& other) noexcept { data.swapWith (other.data); std::swap (numElements, other.numElements); - std::swap (pathXMin, other.pathXMin); - std::swap (pathXMax, other.pathXMax); - std::swap (pathYMin, other.pathYMin); - std::swap (pathYMax, other.pathYMax); + std::swap (bounds.pathXMin, other.bounds.pathXMin); + std::swap (bounds.pathXMax, other.bounds.pathXMax); + std::swap (bounds.pathYMin, other.bounds.pathYMin); + std::swap (bounds.pathYMax, other.bounds.pathYMax); std::swap (useNonZeroWinding, other.useNonZeroWinding); } @@ -212,9 +246,7 @@ bool Path::isEmpty() const noexcept Rectangle Path::getBounds() const noexcept { - return Rectangle (pathXMin, pathYMin, - pathXMax - pathXMin, - pathYMax - pathYMin); + return bounds.getRectangle(); } Rectangle Path::getBoundsTransformed (const AffineTransform& transform) const noexcept @@ -228,17 +260,9 @@ void Path::startNewSubPath (const float x, const float y) JUCE_CHECK_COORDS_ARE_VALID (x, y); if (numElements == 0) - { - pathXMin = pathXMax = x; - pathYMin = pathYMax = y; - } + bounds.reset (x, y); else - { - pathXMin = jmin (pathXMin, x); - pathXMax = jmax (pathXMax, x); - pathYMin = jmin (pathYMin, y); - pathYMax = jmax (pathYMax, y); - } + bounds.extend (x, y); data.ensureAllocatedSize ((int) numElements + 3); @@ -265,10 +289,7 @@ void Path::lineTo (const float x, const float y) data.elements [numElements++] = x; data.elements [numElements++] = y; - pathXMin = jmin (pathXMin, x); - pathXMax = jmax (pathXMax, x); - pathYMin = jmin (pathYMin, y); - pathYMax = jmax (pathYMax, y); + bounds.extend (x, y); } void Path::lineTo (const Point& end) @@ -293,10 +314,7 @@ void Path::quadraticTo (const float x1, const float y1, data.elements [numElements++] = x2; data.elements [numElements++] = y2; - pathXMin = jmin (pathXMin, x1, x2); - pathXMax = jmax (pathXMax, x1, x2); - pathYMin = jmin (pathYMin, y1, y2); - pathYMax = jmax (pathYMax, y1, y2); + bounds.extend (x1, y1, x2, y2); } void Path::quadraticTo (const Point& controlPoint, @@ -327,10 +345,8 @@ void Path::cubicTo (const float x1, const float y1, data.elements [numElements++] = x3; data.elements [numElements++] = y3; - pathXMin = jmin (pathXMin, x1, x2, x3); - pathXMax = jmax (pathXMax, x1, x2, x3); - pathYMin = jmin (pathYMin, y1, y2, y3); - pathYMax = jmax (pathYMax, y1, y2, y3); + bounds.extend (x1, y1, x2, y2); + bounds.extend (x3, y3); } void Path::cubicTo (const Point& controlPoint1, @@ -388,17 +404,17 @@ void Path::addRectangle (const float x, const float y, if (numElements == 0) { - pathXMin = x1; - pathXMax = x2; - pathYMin = y1; - pathYMax = y2; + bounds.pathXMin = x1; + bounds.pathXMax = x2; + bounds.pathYMin = y1; + bounds.pathYMax = y2; } else { - pathXMin = jmin (pathXMin, x1); - pathXMax = jmax (pathXMax, x2); - pathYMin = jmin (pathYMin, y1); - pathYMax = jmax (pathYMax, y2); + bounds.pathXMin = jmin (bounds.pathXMin, x1); + bounds.pathXMax = jmax (bounds.pathXMax, x2); + bounds.pathYMin = jmin (bounds.pathYMin, y1); + bounds.pathYMax = jmax (bounds.pathYMax, y2); } data.elements [numElements++] = moveMarker; @@ -751,42 +767,30 @@ void Path::addBubble (float x, float y, void Path::addPath (const Path& other) { size_t i = 0; + const float* const d = other.data.elements; while (i < other.numElements) { - const float type = other.data.elements [i++]; + const float type = d[i++]; if (type == moveMarker) { - startNewSubPath (other.data.elements [i], - other.data.elements [i + 1]); - + startNewSubPath (d[i], d[i + 1]); i += 2; } else if (type == lineMarker) { - lineTo (other.data.elements [i], - other.data.elements [i + 1]); - + lineTo (d[i], d[i + 1]); i += 2; } else if (type == quadMarker) { - quadraticTo (other.data.elements [i], - other.data.elements [i + 1], - other.data.elements [i + 2], - other.data.elements [i + 3]); + quadraticTo (d[i], d[i + 1], d[i + 2], d[i + 3]); i += 4; } else if (type == cubicMarker) { - cubicTo (other.data.elements [i], - other.data.elements [i + 1], - other.data.elements [i + 2], - other.data.elements [i + 3], - other.data.elements [i + 4], - other.data.elements [i + 5]); - + cubicTo (d[i], d[i + 1], d[i + 2], d[i + 3], d[i + 4], d[i + 5]); i += 6; } else if (type == closeSubPathMarker) @@ -805,10 +809,11 @@ void Path::addPath (const Path& other, const AffineTransform& transformToApply) { size_t i = 0; + const float* const d = other.data.elements; while (i < other.numElements) { - const float type = other.data.elements [i++]; + const float type = d [i++]; if (type == closeSubPathMarker) { @@ -816,8 +821,8 @@ void Path::addPath (const Path& other, } else { - float x = other.data.elements [i++]; - float y = other.data.elements [i++]; + float x = d[i++]; + float y = d[i++]; transformToApply.transformPoint (x, y); if (type == moveMarker) @@ -830,18 +835,18 @@ void Path::addPath (const Path& other, } else if (type == quadMarker) { - float x2 = other.data.elements [i++]; - float y2 = other.data.elements [i++]; + float x2 = d [i++]; + float y2 = d [i++]; transformToApply.transformPoint (x2, y2); quadraticTo (x, y, x2, y2); } else if (type == cubicMarker) { - float x2 = other.data.elements [i++]; - float y2 = other.data.elements [i++]; - float x3 = other.data.elements [i++]; - float y3 = other.data.elements [i++]; + float x2 = d [i++]; + float y2 = d [i++]; + float x3 = d [i++]; + float y3 = d [i++]; transformToApply.transformPoints (x2, y2, x3, y3); cubicTo (x, y, x2, y2, x3, y3); @@ -858,70 +863,49 @@ void Path::addPath (const Path& other, //============================================================================== void Path::applyTransform (const AffineTransform& transform) noexcept { - size_t i = 0; - pathYMin = pathXMin = 0; - pathYMax = pathXMax = 0; - bool setMaxMin = false; + bounds.reset(); + bool firstPoint = true; + float* d = data.elements; + float* const end = d + numElements; - while (i < numElements) + while (d < end) { - const float type = data.elements [i++]; + const float type = *d++; if (type == moveMarker) { - transform.transformPoint (data.elements [i], data.elements [i + 1]); + transform.transformPoint (d[0], d[1]); - if (setMaxMin) + if (firstPoint) { - pathXMin = jmin (pathXMin, data.elements [i]); - pathXMax = jmax (pathXMax, data.elements [i]); - pathYMin = jmin (pathYMin, data.elements [i + 1]); - pathYMax = jmax (pathYMax, data.elements [i + 1]); + firstPoint = false; + bounds.reset (d[0], d[1]); } else { - pathXMin = pathXMax = data.elements [i]; - pathYMin = pathYMax = data.elements [i + 1]; - setMaxMin = true; + bounds.extend (d[0], d[1]); } - i += 2; + d += 2; } else if (type == lineMarker) { - transform.transformPoint (data.elements [i], data.elements [i + 1]); - - pathXMin = jmin (pathXMin, data.elements [i]); - pathXMax = jmax (pathXMax, data.elements [i]); - pathYMin = jmin (pathYMin, data.elements [i + 1]); - pathYMax = jmax (pathYMax, data.elements [i + 1]); - - i += 2; + transform.transformPoint (d[0], d[1]); + bounds.extend (d[0], d[1]); + d += 2; } else if (type == quadMarker) { - transform.transformPoints (data.elements [i], data.elements [i + 1], - data.elements [i + 2], data.elements [i + 3]); - - pathXMin = jmin (pathXMin, data.elements [i], data.elements [i + 2]); - pathXMax = jmax (pathXMax, data.elements [i], data.elements [i + 2]); - pathYMin = jmin (pathYMin, data.elements [i + 1], data.elements [i + 3]); - pathYMax = jmax (pathYMax, data.elements [i + 1], data.elements [i + 3]); - - i += 4; + transform.transformPoints (d[0], d[1], d[2], d[3]); + bounds.extend (d[0], d[1], d[2], d[3]); + d += 4; } else if (type == cubicMarker) { - transform.transformPoints (data.elements [i], data.elements [i + 1], - data.elements [i + 2], data.elements [i + 3], - data.elements [i + 4], data.elements [i + 5]); - - pathXMin = jmin (pathXMin, data.elements [i], data.elements [i + 2], data.elements [i + 4]); - pathXMax = jmax (pathXMax, data.elements [i], data.elements [i + 2], data.elements [i + 4]); - pathYMin = jmin (pathYMin, data.elements [i + 1], data.elements [i + 3], data.elements [i + 5]); - pathYMax = jmax (pathYMax, data.elements [i + 1], data.elements [i + 3], data.elements [i + 5]); - - i += 6; + transform.transformPoints (d[0], d[1], d[2], d[3], d[4], d[5]); + bounds.extend (d[0], d[1], d[2], d[3]); + bounds.extend (d[4], d[5]); + d += 6; } } } @@ -983,8 +967,8 @@ AffineTransform Path::getTransformToScaleToFit (const float x, const float y, //============================================================================== bool Path::contains (const float x, const float y, const float tolerance) const { - if (x <= pathXMin || x >= pathXMax - || y <= pathYMin || y >= pathYMax) + if (x <= bounds.pathXMin || x >= bounds.pathXMax + || y <= bounds.pathYMin || y >= bounds.pathYMax) return false; PathFlatteningIterator i (*this, AffineTransform::identity, tolerance); diff --git a/modules/juce_graphics/geometry/juce_Path.h b/modules/juce_graphics/geometry/juce_Path.h index 644dc99dce..1192eb8645 100644 --- a/modules/juce_graphics/geometry/juce_Path.h +++ b/modules/juce_graphics/geometry/juce_Path.h @@ -738,7 +738,20 @@ private: friend class Path::Iterator; ArrayAllocationBase data; size_t numElements; - float pathXMin, pathXMax, pathYMin, pathYMax; + + struct PathBounds + { + PathBounds() noexcept; + Rectangle getRectangle() const noexcept; + void reset() noexcept; + void reset (float, float) noexcept; + void extend (float, float) noexcept; + void extend (float, float, float, float) noexcept; + + float pathXMin, pathXMax, pathYMin, pathYMax; + }; + + PathBounds bounds; bool useNonZeroWinding; static const float lineMarker; diff --git a/modules/juce_gui_basics/components/juce_Component.cpp b/modules/juce_gui_basics/components/juce_Component.cpp index 577a69cde2..e860bb1bf8 100644 --- a/modules/juce_gui_basics/components/juce_Component.cpp +++ b/modules/juce_gui_basics/components/juce_Component.cpp @@ -23,7 +23,11 @@ ============================================================================== */ -#define CHECK_MESSAGE_MANAGER_IS_LOCKED jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); +#define CHECK_MESSAGE_MANAGER_IS_LOCKED \ + jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); + +#define CHECK_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN \ + jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager() || getPeer() == nullptr); Component* Component::currentlyFocusedComponent = nullptr; @@ -411,7 +415,7 @@ void Component::setName (const String& name) { // if component methods are being called from threads other than the message // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - CHECK_MESSAGE_MANAGER_IS_LOCKED + CHECK_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN if (componentName != name) { @@ -442,7 +446,7 @@ void Component::setVisible (bool shouldBeVisible) { // if component methods are being called from threads other than the message // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - CHECK_MESSAGE_MANAGER_IS_LOCKED + CHECK_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN const WeakReference safePointer (this); flags.visibleFlag = shouldBeVisible; @@ -788,7 +792,7 @@ void Component::toFront (const bool setAsForeground) { // if component methods are being called from threads other than the message // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - CHECK_MESSAGE_MANAGER_IS_LOCKED + CHECK_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN if (flags.hasHeavyweightPeerFlag) { @@ -965,6 +969,11 @@ int Component::getScreenY() const { return getScreenPosition().y; } Point Component::getScreenPosition() const { return localPointToGlobal (Point()); } Rectangle Component::getScreenBounds() const { return localAreaToGlobal (getLocalBounds()); } +Rectangle Component::getParentMonitorArea() const +{ + return Desktop::getInstance().getMonitorAreaContaining (getScreenBounds().getCentre()); +} + Point Component::getLocalPoint (const Component* source, const Point& point) const { return ComponentHelpers::convertCoordinate (this, source, point); @@ -1008,7 +1017,7 @@ void Component::setBounds (const int x, const int y, int w, int h) { // if component methods are being called from threads other than the message // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - CHECK_MESSAGE_MANAGER_IS_LOCKED + CHECK_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN if (w < 0) w = 0; if (h < 0) h = 0; @@ -1302,10 +1311,9 @@ bool Component::contains (const Point& point) if (ComponentHelpers::hitTest (*this, point)) { if (parentComponent != nullptr) - { return parentComponent->contains (ComponentHelpers::convertToParentSpace (*this, point)); - } - else if (flags.hasHeavyweightPeerFlag) + + if (flags.hasHeavyweightPeerFlag) { const ComponentPeer* const peer = getPeer(); @@ -1357,7 +1365,10 @@ void Component::addChildComponent (Component* const child, int zOrder) { // if component methods are being called from threads other than the message // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - CHECK_MESSAGE_MANAGER_IS_LOCKED + CHECK_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN + + jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager() || ! isShowing()); + if (child != nullptr && child->parentComponent != this) { @@ -1424,7 +1435,7 @@ Component* Component::removeChildComponent (const int index, bool sendParentEven { // if component methods are being called from threads other than the message // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - CHECK_MESSAGE_MANAGER_IS_LOCKED + CHECK_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN Component* const child = childComponentList [index]; @@ -1793,14 +1804,14 @@ void Component::internalRepaint (const Rectangle& area) void Component::internalRepaintUnchecked (const Rectangle& area, const bool isEntireComponent) { - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - CHECK_MESSAGE_MANAGER_IS_LOCKED - if (flags.visibleFlag) { if (flags.hasHeavyweightPeerFlag) { + // if component methods are being called from threads other than the message + // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. + CHECK_MESSAGE_MANAGER_IS_LOCKED + ComponentPeer* const peer = getPeer(); if (peer != nullptr) @@ -2380,7 +2391,6 @@ void Component::internalMouseUp (MouseInputSource& source, const Point& rel source.getLastMouseDownTime(), source.getNumberOfMultipleClicks(), source.hasMouseMovedSignificantlySincePressed()); - mouseUp (me); if (checker.shouldBailOut()) @@ -2417,7 +2427,6 @@ void Component::internalMouseDrag (MouseInputSource& source, const Point& r source.getLastMouseDownTime(), source.getNumberOfMultipleClicks(), source.hasMouseMovedSignificantlySincePressed()); - mouseDrag (me); if (checker.shouldBailOut()) @@ -2431,10 +2440,6 @@ void Component::internalMouseDrag (MouseInputSource& source, const Point& r void Component::internalMouseMove (MouseInputSource& source, const Point& relativePos, const Time& time) { Desktop& desktop = Desktop::getInstance(); - BailOutChecker checker (this); - - const MouseEvent me (source, relativePos, source.getCurrentModifiers(), - this, this, time, relativePos, time, 0, false); if (isCurrentlyBlockedByAnotherModalComponent()) { @@ -2443,6 +2448,10 @@ void Component::internalMouseMove (MouseInputSource& source, const Point& r } else { + BailOutChecker checker (this); + + const MouseEvent me (source, relativePos, source.getCurrentModifiers(), + this, this, time, relativePos, time, 0, false); mouseMove (me); if (checker.shouldBailOut()) @@ -2493,7 +2502,7 @@ void Component::sendFakeMouseMove() const mainMouse.triggerFakeMove(); } -void Component::beginDragAutoRepeat (const int interval) +void JUCE_CALLTYPE Component::beginDragAutoRepeat (const int interval) { Desktop::getInstance().beginDragAutoRepeat (interval); } @@ -2867,12 +2876,6 @@ Point Component::getMouseXYRelative() const return getLocalPoint (nullptr, Desktop::getMousePosition()); } -//============================================================================== -Rectangle Component::getParentMonitorArea() const -{ - return Desktop::getInstance().getMonitorAreaContaining (getScreenBounds().getCentre()); -} - //============================================================================== void Component::addKeyListener (KeyListener* const newListener) { @@ -2888,15 +2891,8 @@ void Component::removeKeyListener (KeyListener* const listenerToRemove) keyListeners->removeValue (listenerToRemove); } -bool Component::keyPressed (const KeyPress&) -{ - return false; -} - -bool Component::keyStateChanged (const bool /*isKeyDown*/) -{ - return false; -} +bool Component::keyPressed (const KeyPress&) { return false; } +bool Component::keyStateChanged (const bool /*isKeyDown*/) { return false; } void Component::modifierKeysChanged (const ModifierKeys& modifiers) { @@ -2907,7 +2903,6 @@ void Component::modifierKeysChanged (const ModifierKeys& modifiers) void Component::internalModifierKeysChanged() { sendFakeMouseMove(); - modifierKeysChanged (ModifierKeys::getCurrentModifiers()); } diff --git a/modules/juce_gui_basics/components/juce_Component.h b/modules/juce_gui_basics/components/juce_Component.h index 0abb222b63..517edde3a3 100644 --- a/modules/juce_gui_basics/components/juce_Component.h +++ b/modules/juce_gui_basics/components/juce_Component.h @@ -1612,7 +1612,7 @@ public: @see mouseDrag, Desktop::beginDragAutoRepeat */ - static void beginDragAutoRepeat (int millisecondsBetweenCallbacks); + static void JUCE_CALLTYPE beginDragAutoRepeat (int millisecondsBetweenCallbacks); /** Causes automatic repaints when the mouse enters or exits this component.