diff --git a/modules/juce_gui_basics/components/juce_Component.cpp b/modules/juce_gui_basics/components/juce_Component.cpp index 93fdf1249c..1fc7fcb086 100644 --- a/modules/juce_gui_basics/components/juce_Component.cpp +++ b/modules/juce_gui_basics/components/juce_Component.cpp @@ -196,44 +196,64 @@ struct Component::ComponentHelpers static inline bool hitTest (Component& comp, Point localPoint) { return isPositiveAndBelow (localPoint.x, comp.getWidth()) - && isPositiveAndBelow (localPoint.y, comp.getHeight()) - && comp.hitTest (localPoint.x, localPoint.y); + && isPositiveAndBelow (localPoint.y, comp.getHeight()) + && comp.hitTest (localPoint.x, localPoint.y); } - static Point convertFromParentSpace (const Component& comp, Point pointInParentSpace) + template + static PointOrRect unscaledScreenPosToScaled (PointOrRect pos) noexcept { - if (comp.affineTransform == nullptr) - return pointInParentSpace - comp.getPosition(); + const float scale = Desktop::getInstance().masterScaleFactor; + return scale != 1.0f ? pos / scale : pos; + } - return pointInParentSpace.toFloat().transformedBy (comp.affineTransform->inverted()).toInt() - comp.getPosition(); + template + static PointOrRect scaledScreenPosToUnscaled (PointOrRect pos) noexcept + { + const float scale = Desktop::getInstance().masterScaleFactor; + return scale != 1.0f ? pos * scale : pos; } - static Rectangle convertFromParentSpace (const Component& comp, const Rectangle& areaInParentSpace) + // converts an unscaled position within a peer to the local position within that peer's component + template + static PointOrRect rawPeerPositionToLocal (const Component& comp, PointOrRect pos) noexcept { - if (comp.affineTransform == nullptr) - return areaInParentSpace - comp.getPosition(); + if (comp.isTransformed()) + pos = pos.transformedBy (comp.getTransform().inverted()); + + return unscaledScreenPosToScaled (pos); + } + + // converts a position within a peer's component to the unscaled position within the peer + template + static PointOrRect localPositionToRawPeerPos (const Component& comp, PointOrRect pos) noexcept + { + if (comp.isTransformed()) + pos = pos.transformedBy (comp.getTransform()); - return areaInParentSpace.toFloat().transformedBy (comp.affineTransform->inverted()).getSmallestIntegerContainer() - comp.getPosition(); + return scaledScreenPosToUnscaled (pos); } - static Point convertToParentSpace (const Component& comp, Point pointInLocalSpace) + template + static PointOrRect convertFromParentSpace (const Component& comp, PointOrRect pointInParentSpace) { if (comp.affineTransform == nullptr) - return pointInLocalSpace + comp.getPosition(); + return pointInParentSpace - comp.getPosition(); - return (pointInLocalSpace + comp.getPosition()).toFloat().transformedBy (*comp.affineTransform).toInt(); + return pointInParentSpace.transformedBy (comp.affineTransform->inverted()) - comp.getPosition(); } - static Rectangle convertToParentSpace (const Component& comp, const Rectangle& areaInLocalSpace) + template + static PointOrRect convertToParentSpace (const Component& comp, PointOrRect pointInLocalSpace) { if (comp.affineTransform == nullptr) - return areaInLocalSpace + comp.getPosition(); + return pointInLocalSpace + comp.getPosition(); - return (areaInLocalSpace + comp.getPosition()).transformedBy (*comp.affineTransform); + return (pointInLocalSpace + comp.getPosition()).transformedBy (*comp.affineTransform); } - template - static Type convertFromDistantParentSpace (const Component* parent, const Component& target, const Type& coordInParent) + template + static PointOrRect convertFromDistantParentSpace (const Component* parent, const Component& target, const PointOrRect& coordInParent) { const Component* const directParent = target.getParentComponent(); jassert (directParent != nullptr); @@ -244,8 +264,8 @@ struct Component::ComponentHelpers return convertFromParentSpace (target, convertFromDistantParentSpace (parent, *directParent, coordInParent)); } - template - static Type convertCoordinate (const Component* target, const Component* source, Type p) + template + static PointOrRect convertCoordinate (const Component* target, const Component* source, PointOrRect p) { while (source != nullptr) { @@ -255,19 +275,8 @@ struct Component::ComponentHelpers if (source->isParentOf (target)) return convertFromDistantParentSpace (source, *target, p); - if (source->isOnDesktop()) - { - if (source->isTransformed()) - p = p.transformedBy (source->getTransform()); - - p = source->getPeer()->localToGlobal (p); - source = nullptr; - } - else - { - p = convertToParentSpace (*source, p); - source = source->getParentComponent(); - } + p = convertToParentSpace (*source, p); + source = source->getParentComponent(); } jassert (source == nullptr); @@ -276,17 +285,7 @@ struct Component::ComponentHelpers const Component* const topLevelComp = target->getTopLevelComponent(); - if (topLevelComp->isOnDesktop()) - { - p = topLevelComp->getPeer()->globalToLocal (p); - - if (topLevelComp->isTransformed()) - p = p.transformedBy (topLevelComp->getTransform().inverted()); - } - else - { - p = convertFromParentSpace (*topLevelComp, p); - } + p = convertFromParentSpace (*topLevelComp, p); if (topLevelComp == target) return p; @@ -1218,11 +1217,6 @@ void Component::setBoundsToFit (int x, int y, int width, int height, } //============================================================================== -bool Component::isTransformed() const noexcept -{ - return affineTransform != nullptr; -} - void Component::setTransform (const AffineTransform& newTransform) { // If you pass in a transform with no inverse, the component will have no dimensions, @@ -1256,6 +1250,11 @@ void Component::setTransform (const AffineTransform& newTransform) } } +bool Component::isTransformed() const noexcept +{ + return affineTransform != nullptr; +} + AffineTransform Component::getTransform() const { return affineTransform != nullptr ? *affineTransform : AffineTransform::identity; @@ -1802,8 +1801,8 @@ void Component::internalRepaintUnchecked (const Rectangle& area, const bool CHECK_MESSAGE_MANAGER_IS_LOCKED if (ComponentPeer* const peer = getPeer()) - peer->repaint (affineTransform != nullptr ? area.transformedBy (*affineTransform) - : area); + peer->repaint (ComponentHelpers::scaledScreenPosToUnscaled (affineTransform != nullptr ? area.transformedBy (*affineTransform) + : area)); } else { diff --git a/modules/juce_gui_basics/components/juce_Desktop.cpp b/modules/juce_gui_basics/components/juce_Desktop.cpp index 9057514a35..d70702ca44 100644 --- a/modules/juce_gui_basics/components/juce_Desktop.cpp +++ b/modules/juce_gui_basics/components/juce_Desktop.cpp @@ -142,18 +142,6 @@ void Desktop::componentBroughtToFront (Component* const c) } } -//============================================================================== -void Desktop::addPeer (ComponentPeer* peer) -{ - peers.add (peer); -} - -void Desktop::removePeer (ComponentPeer* peer) -{ - peers.removeFirstMatchingValue (peer); - triggerFocusCallback(); -} - //============================================================================== Point Desktop::getMousePosition() { @@ -489,3 +477,13 @@ bool Desktop::isOrientationEnabled (const DisplayOrientation orientation) const return (allowedOrientations & orientation) != 0; } + +void Desktop::setGlobalScaleFactor (float newScaleFactor) noexcept +{ + if (masterScaleFactor != newScaleFactor) + { + masterScaleFactor = newScaleFactor; + + displays->refresh(); + } +} diff --git a/modules/juce_gui_basics/components/juce_Desktop.h b/modules/juce_gui_basics/components/juce_Desktop.h index e3e26b0a43..1870cbc76e 100644 --- a/modules/juce_gui_basics/components/juce_Desktop.h +++ b/modules/juce_gui_basics/components/juce_Desktop.h @@ -375,7 +375,18 @@ public: void findDisplays (float masterScale); }; - const Displays& getDisplays() const noexcept { return *displays; } + const Displays& getDisplays() const noexcept { return *displays; } + + //============================================================================== + /** Sets a global scale factor to be used for all desktop windows. + Setting this will also scale the monitor sizes that are returned by getDisplays(). + */ + void setGlobalScaleFactor (float newScaleFactor) noexcept; + + /** Returns the current global scale factor, as set by setGlobalScaleFactor(). + @see setGlobalScaleFactor + */ + float getGlobalScaleFactor() const noexcept { return masterScaleFactor; } //============================================================================== /** True if the OS supports semitransparent windows */ @@ -401,9 +412,6 @@ private: Array desktopComponents; Array peers; - void addPeer (ComponentPeer*); - void removePeer (ComponentPeer*); - ScopedPointer displays; Point lastFakeMouseMove; diff --git a/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.cpp b/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.cpp index fed399e363..745f8ee4fd 100644 --- a/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.cpp +++ b/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.cpp @@ -123,18 +123,8 @@ bool FileChooserDialogBox::show (int w, int h) bool FileChooserDialogBox::showAt (int x, int y, int w, int h) { - if (w <= 0) - { - Component* const previewComp = content->chooserComponent.getPreviewComponent(); - - if (previewComp != nullptr) - w = 400 + previewComp->getWidth(); - else - w = 600; - } - - if (h <= 0) - h = 500; + if (w <= 0) w = getDefaultWidth(); + if (h <= 0) h = 500; if (x < 0 || y < 0) centreWithSize (w, h); @@ -149,11 +139,15 @@ bool FileChooserDialogBox::showAt (int x, int y, int w, int h) void FileChooserDialogBox::centreWithDefaultSize (Component* componentToCentreAround) { - Component* const previewComp = content->chooserComponent.getPreviewComponent(); + centreAroundComponent (componentToCentreAround, getDefaultWidth(), 500); +} + +int FileChooserDialogBox::getDefaultWidth() const +{ + if (Component* const previewComp = content->chooserComponent.getPreviewComponent()) + return 400 + previewComp->getWidth(); - centreAroundComponent (componentToCentreAround, - previewComp != nullptr ? 400 + previewComp->getWidth() : 600, - 500); + return 600; } //============================================================================== diff --git a/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.h b/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.h index 738c3d4445..45c3ea46e2 100644 --- a/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.h +++ b/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.h @@ -146,6 +146,7 @@ private: void fileClicked (const File&, const MouseEvent&) override; void fileDoubleClicked (const File&) override; void browserRootChanged (const File&) override; + int getDefaultWidth() const; void okButtonPressed(); void createNewFolder(); diff --git a/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp b/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp index c1102ef6de..79ae338af6 100644 --- a/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp +++ b/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp @@ -57,12 +57,18 @@ public: return lastPeer; } + static Point screenPosToLocalPos (Component& comp, Point pos) + { + return comp.getLocalPoint (nullptr, Component::ComponentHelpers::unscaledScreenPosToScaled (pos)); + } + Component* findComponentAt (Point screenPos) { if (ComponentPeer* const peer = getPeer()) { Component& comp = peer->getComponent(); - const Point relativePos (comp.getLocalPoint (nullptr, screenPos)); + Point relativePos (Component::ComponentHelpers::convertFromParentSpace (comp, + Component::ComponentHelpers::unscaledScreenPosToScaled (screenPos))); // (the contains() call is needed to test for overlapping desktop windows) if (comp.contains (relativePos)) @@ -76,20 +82,21 @@ public: { // This needs to return the live position if possible, but it mustn't update the lastScreenPos // value, because that can cause continuity problems. - return unboundedMouseOffset + (isMouseDevice ? MouseInputSource::getCurrentRawMousePosition() - : lastScreenPos); + return Component::ComponentHelpers::unscaledScreenPosToScaled + (unboundedMouseOffset + (isMouseDevice ? MouseInputSource::getCurrentRawMousePosition() + : lastScreenPos)); } void setScreenPosition (Point p) { - MouseInputSource::setRawMousePosition (p); + MouseInputSource::setRawMousePosition (Component::ComponentHelpers::scaledScreenPosToUnscaled (p)); } //============================================================================== #if JUCE_DUMP_MOUSE_EVENTS #define JUCE_MOUSE_EVENT_DBG(desc) DBG ("Mouse " desc << " #" << source.getIndex() \ - << ": " << comp->getLocalPoint (nullptr, screenPos).toString() \ - << " - Comp: " << String::toHexString ((int) comp)); + << ": " << screenPosToLocalPos (comp, screenPos).toString() \ + << " - Comp: " << String::toHexString ((int) &comp)); #else #define JUCE_MOUSE_EVENT_DBG(desc) #endif @@ -97,49 +104,49 @@ public: void sendMouseEnter (Component& comp, Point screenPos, Time time) { JUCE_MOUSE_EVENT_DBG ("enter") - comp.internalMouseEnter (source, comp.getLocalPoint (nullptr, screenPos), time); + comp.internalMouseEnter (source, screenPosToLocalPos (comp, screenPos), time); } void sendMouseExit (Component& comp, Point screenPos, Time time) { JUCE_MOUSE_EVENT_DBG ("exit") - comp.internalMouseExit (source, comp.getLocalPoint (nullptr, screenPos), time); + comp.internalMouseExit (source, screenPosToLocalPos (comp, screenPos), time); } void sendMouseMove (Component& comp, Point screenPos, Time time) { JUCE_MOUSE_EVENT_DBG ("move") - comp.internalMouseMove (source, comp.getLocalPoint (nullptr, screenPos), time); + comp.internalMouseMove (source, screenPosToLocalPos (comp, screenPos), time); } void sendMouseDown (Component& comp, Point screenPos, Time time) { JUCE_MOUSE_EVENT_DBG ("down") - comp.internalMouseDown (source, comp.getLocalPoint (nullptr, screenPos), time); + comp.internalMouseDown (source, screenPosToLocalPos (comp, screenPos), time); } void sendMouseDrag (Component& comp, Point screenPos, Time time) { JUCE_MOUSE_EVENT_DBG ("drag") - comp.internalMouseDrag (source, comp.getLocalPoint (nullptr, screenPos), time); + comp.internalMouseDrag (source, screenPosToLocalPos (comp, screenPos), time); } void sendMouseUp (Component& comp, Point screenPos, Time time, const ModifierKeys oldMods) { JUCE_MOUSE_EVENT_DBG ("up") - comp.internalMouseUp (source, comp.getLocalPoint (nullptr, screenPos), time, oldMods); + comp.internalMouseUp (source, screenPosToLocalPos (comp, screenPos), time, oldMods); } void sendMouseWheel (Component& comp, Point screenPos, Time time, const MouseWheelDetails& wheel) { JUCE_MOUSE_EVENT_DBG ("wheel") - comp.internalMouseWheel (source, comp.getLocalPoint (nullptr, screenPos), time, wheel); + comp.internalMouseWheel (source, screenPosToLocalPos (comp, screenPos), time, wheel); } void sendMagnifyGesture (Component& comp, Point screenPos, Time time, const float amount) { JUCE_MOUSE_EVENT_DBG ("magnify") - comp.internalMagnifyGesture (source, comp.getLocalPoint (nullptr, screenPos), time, amount); + comp.internalMagnifyGesture (source, screenPosToLocalPos (comp, screenPos), time, amount); } //============================================================================== @@ -330,7 +337,7 @@ public: //============================================================================== Time getLastMouseDownTime() const noexcept { return mouseDowns[0].time; } - Point getLastMouseDownPosition() const noexcept { return mouseDowns[0].position; } + Point getLastMouseDownPosition() const noexcept { return Component::ComponentHelpers::unscaledScreenPosToScaled (mouseDowns[0].position); } int getNumberOfMultipleClicks() const noexcept { diff --git a/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp b/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp index 59f02f7e58..13d585e5a7 100644 --- a/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp +++ b/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp @@ -33,12 +33,14 @@ ComponentPeer::ComponentPeer (Component& comp, const int flags) uniqueID (lastUniqueID += 2), // increment by 2 so that this can never hit 0 isWindowMinimised (false) { - Desktop::getInstance().addPeer (this); + Desktop::getInstance().peers.add (this); } ComponentPeer::~ComponentPeer() { - Desktop::getInstance().removePeer (this); + Desktop& desktop = Desktop::getInstance(); + desktop.peers.removeFirstMatchingValue (this); + desktop.triggerFocusCallback(); } //============================================================================== @@ -74,7 +76,7 @@ bool ComponentPeer::isValidPeer (const ComponentPeer* const peer) noexcept void ComponentPeer::updateBounds() { - setBounds (component.getBoundsInParent(), false); + setBounds (Component::ComponentHelpers::scaledScreenPosToUnscaled (component.getBoundsInParent()), false); } //============================================================================== @@ -105,7 +107,14 @@ void ComponentPeer::handlePaint (LowLevelGraphicsContext& contextToPaintTo) ModifierKeys::updateCurrentModifiers(); Graphics g (&contextToPaintTo); - g.addTransform (component.getTransform()); + + if (component.isTransformed()) + g.addTransform (component.getTransform()); + + float masterScale = Desktop::getInstance().masterScaleFactor; + + if (masterScale != 1.0f) + g.addTransform (AffineTransform::scale (masterScale)); #if JUCE_ENABLE_REPAINT_DEBUGGING g.saveState(); @@ -284,12 +293,18 @@ void ComponentPeer::handleMovedOrResized() { const WeakReference deletionChecker (&component); - const Rectangle newBounds (getBounds().transformedBy (component.getTransform().inverted())); - const bool wasMoved = (component.getPosition() != newBounds.getPosition()); - const bool wasResized = (component.getWidth() != newBounds.getWidth() || component.getHeight() != newBounds.getHeight()); + Rectangle newBounds (getBounds()); + Rectangle oldBounds (component.getBounds()); + + oldBounds = Component::ComponentHelpers::localPositionToRawPeerPos (component, oldBounds); + + const bool wasMoved = (oldBounds.getPosition() != newBounds.getPosition()); + const bool wasResized = (oldBounds.getWidth() != newBounds.getWidth() || oldBounds.getHeight() != newBounds.getHeight()); if (wasMoved || wasResized) { + newBounds = Component::ComponentHelpers::rawPeerPositionToLocal (component, newBounds); + component.bounds = newBounds; if (wasResized)