|
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2022 - Raw Material Software Limited
-
- JUCE is an open source library subject to commercial or open-source
- licensing.
-
- By using JUCE, you agree to the terms of both the JUCE 7 End-User License
- Agreement and JUCE Privacy Policy.
-
- End User License Agreement: www.juce.com/juce-7-licence
- Privacy Policy: www.juce.com/juce-privacy-policy
-
- Or: You may also use this code under the terms of the GPL v3 (see
- www.gnu.org/licenses).
-
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
-
- ==============================================================================
- */
-
- namespace juce::detail
- {
-
- constexpr char colourPropertyPrefix[] = "jcclr_";
-
- //==============================================================================
- struct ComponentHelpers
- {
- using SH = ScalingHelpers;
-
- #if JUCE_MODAL_LOOPS_PERMITTED
- static void* runModalLoopCallback (void* userData)
- {
- return (void*) (pointer_sized_int) static_cast<Component*> (userData)->runModalLoop();
- }
- #endif
-
- static Identifier getColourPropertyID (int colourID)
- {
- char buffer[32];
- auto* end = buffer + numElementsInArray (buffer) - 1;
- auto* t = end;
- *t = 0;
-
- for (auto v = (uint32) colourID;;)
- {
- *--t = "0123456789abcdef" [v & 15];
- v >>= 4;
-
- if (v == 0)
- break;
- }
-
- for (int i = (int) sizeof (colourPropertyPrefix) - 1; --i >= 0;)
- *--t = colourPropertyPrefix[i];
-
- return t;
- }
-
- //==============================================================================
- static bool hitTest (Component& comp, Point<float> localPoint)
- {
- const auto intPoint = localPoint.roundToInt();
- return Rectangle<int> { comp.getWidth(), comp.getHeight() }.contains (intPoint)
- && comp.hitTest (intPoint.x, intPoint.y);
- }
-
- // converts an unscaled position within a peer to the local position within that peer's component
- template <typename PointOrRect>
- static PointOrRect rawPeerPositionToLocal (const Component& comp, PointOrRect pos) noexcept
- {
- if (comp.isTransformed())
- pos = pos.transformedBy (comp.getTransform().inverted());
-
- return SH::unscaledScreenPosToScaled (comp, pos);
- }
-
- // converts a position within a peer's component to the unscaled position within the peer
- template <typename PointOrRect>
- static PointOrRect localPositionToRawPeerPos (const Component& comp, PointOrRect pos) noexcept
- {
- if (comp.isTransformed())
- pos = pos.transformedBy (comp.getTransform());
-
- return SH::scaledScreenPosToUnscaled (comp, pos);
- }
-
- template <typename PointOrRect>
- static PointOrRect convertFromParentSpace (const Component& comp, const PointOrRect pointInParentSpace)
- {
- const auto transformed = comp.affineTransform != nullptr ? pointInParentSpace.transformedBy (comp.affineTransform->inverted())
- : pointInParentSpace;
-
- if (comp.isOnDesktop())
- {
- if (auto* peer = comp.getPeer())
- return SH::unscaledScreenPosToScaled (comp, peer->globalToLocal (SH::scaledScreenPosToUnscaled (transformed)));
-
- jassertfalse;
- return transformed;
- }
-
- if (comp.getParentComponent() == nullptr)
- return SH::subtractPosition (SH::unscaledScreenPosToScaled (comp, SH::scaledScreenPosToUnscaled (transformed)), comp);
-
- return SH::subtractPosition (transformed, comp);
- }
-
- template <typename PointOrRect>
- static PointOrRect convertToParentSpace (const Component& comp, const PointOrRect pointInLocalSpace)
- {
- const auto preTransform = [&]
- {
- if (comp.isOnDesktop())
- {
- if (auto* peer = comp.getPeer())
- return SH::unscaledScreenPosToScaled (peer->localToGlobal (SH::scaledScreenPosToUnscaled (comp, pointInLocalSpace)));
-
- jassertfalse;
- return pointInLocalSpace;
- }
-
- if (comp.getParentComponent() == nullptr)
- return SH::unscaledScreenPosToScaled (SH::scaledScreenPosToUnscaled (comp, SH::addPosition (pointInLocalSpace, comp)));
-
- return SH::addPosition (pointInLocalSpace, comp);
- }();
-
- return comp.affineTransform != nullptr ? preTransform.transformedBy (*comp.affineTransform)
- : preTransform;
- }
-
- template <typename PointOrRect>
- static PointOrRect convertFromDistantParentSpace (const Component* parent, const Component& target, PointOrRect coordInParent)
- {
- auto* directParent = target.getParentComponent();
- jassert (directParent != nullptr);
-
- if (directParent == parent)
- return convertFromParentSpace (target, coordInParent);
-
- JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6011)
- return convertFromParentSpace (target, convertFromDistantParentSpace (parent, *directParent, coordInParent));
- JUCE_END_IGNORE_WARNINGS_MSVC
- }
-
- template <typename PointOrRect>
- static PointOrRect convertCoordinate (const Component* target, const Component* source, PointOrRect p)
- {
- while (source != nullptr)
- {
- if (source == target)
- return p;
-
- JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6011)
-
- if (source->isParentOf (target))
- return convertFromDistantParentSpace (source, *target, p);
-
- JUCE_END_IGNORE_WARNINGS_MSVC
-
- p = convertToParentSpace (*source, p);
- source = source->getParentComponent();
- }
-
- jassert (source == nullptr);
- if (target == nullptr)
- return p;
-
- auto* topLevelComp = target->getTopLevelComponent();
-
- p = convertFromParentSpace (*topLevelComp, p);
-
- if (topLevelComp == target)
- return p;
-
- return convertFromDistantParentSpace (topLevelComp, *target, p);
- }
-
- static bool clipObscuredRegions (const Component& comp, Graphics& g,
- const Rectangle<int> clipRect, Point<int> delta)
- {
- bool wasClipped = false;
-
- for (int i = comp.childComponentList.size(); --i >= 0;)
- {
- auto& child = *comp.childComponentList.getUnchecked(i);
-
- if (child.isVisible() && ! child.isTransformed())
- {
- auto newClip = clipRect.getIntersection (child.boundsRelativeToParent);
-
- if (! newClip.isEmpty())
- {
- if (child.isOpaque() && child.componentTransparency == 0)
- {
- g.excludeClipRegion (newClip + delta);
- wasClipped = true;
- }
- else
- {
- auto childPos = child.getPosition();
-
- if (clipObscuredRegions (child, g, newClip - childPos, childPos + delta))
- wasClipped = true;
- }
- }
- }
- }
-
- return wasClipped;
- }
-
- static Rectangle<int> getParentOrMainMonitorBounds (const Component& comp)
- {
- if (auto* p = comp.getParentComponent())
- return p->getLocalBounds();
-
- return Desktop::getInstance().getDisplays().getPrimaryDisplay()->userArea;
- }
-
- static void releaseAllCachedImageResources (Component& c)
- {
- if (auto* cached = c.getCachedComponentImage())
- cached->releaseResources();
-
- for (auto* child : c.childComponentList)
- 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, SH::screenPosToLocalPos (*c, ms.getScreenPosition()), Time::getCurrentTime());
- }
- };
-
- } // namespace juce::detail
|