diff --git a/BREAKING-CHANGES.txt b/BREAKING-CHANGES.txt index 4c45f81de4..f86caaae60 100644 --- a/BREAKING-CHANGES.txt +++ b/BREAKING-CHANGES.txt @@ -4,6 +4,28 @@ JUCE breaking changes Develop Branch ============== +Change +------ +PopupMenus now scale according to the AffineTransform and scaling factor of their target components + +Possible Issues +--------------- +Developers who have manually scaled their PopupMenus to fit the scaling factor of the parent UI will now have the scaling applied two times in a row. + +Workaround +---------- +1. Do not apply your own manual scaling to make your popups match the UI scaling + +or + +2. Override the Look&Feel method PopupMenu::LookAndFeelMethods::shouldPopupMenuScaleWithTargetComponent and return false. + See https://github.com/WeAreROLI/JUCE/blob/c288c94c2914af20f36c03ca9c5401fcb555e4e9/modules/juce_gui_basics/menus/juce_PopupMenu.h#725 + +Rationale +--------- +Previously, PopupMenus would not scale if the GUI of the target component (or any of it’s parents) were scaled. The only way to scale PopupMenus was via the global scaling factor. This had several drawbacks as the global scaling factor would scale everything. This was especially problematic in plug-in editors. + + Change ------ Removed the setSecurityFlags() method from the Windows implementation of WebInputStream as it disabled HTTPS security features diff --git a/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp b/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp index 678629d7ec..9edee80c94 100644 --- a/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp +++ b/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp @@ -1104,6 +1104,8 @@ Component* LookAndFeel_V2::getParentComponentForMenuOptions (const PopupMenu::Op void LookAndFeel_V2::preparePopupMenuWindow (Component&) {} +bool LookAndFeel_V2::shouldPopupMenuScaleWithTargetComponent (const PopupMenu::Options&) { return true; } + //============================================================================== void LookAndFeel_V2::fillTextEditorBackground (Graphics& g, int /*width*/, int /*height*/, TextEditor& textEditor) { diff --git a/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h b/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h index 2b84d819b2..302edef3e2 100644 --- a/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h +++ b/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h @@ -180,6 +180,8 @@ public: Component* getParentComponentForMenuOptions (const PopupMenu::Options& options) override; + bool shouldPopupMenuScaleWithTargetComponent (const PopupMenu::Options& options) override; + //============================================================================== void drawComboBox (Graphics&, int width, int height, bool isButtonDown, int buttonX, int buttonY, int buttonW, int buttonH, diff --git a/modules/juce_gui_basics/menus/juce_PopupMenu.cpp b/modules/juce_gui_basics/menus/juce_PopupMenu.cpp index 4e3082ea32..291f4b7be7 100644 --- a/modules/juce_gui_basics/menus/juce_PopupMenu.cpp +++ b/modules/juce_gui_basics/menus/juce_PopupMenu.cpp @@ -202,7 +202,8 @@ public: dismissOnMouseUp (shouldDismissOnMouseUp), windowCreationTime (Time::getMillisecondCounter()), lastFocusedTime (windowCreationTime), - timeEnteredCurrentChildComp (windowCreationTime) + timeEnteredCurrentChildComp (windowCreationTime), + scaleFactor (1.0f) { setWantsKeyboardFocus (false); setMouseClickGrabsKeyboardFocus (false); @@ -215,6 +216,9 @@ public: parentComponent = lf.getParentComponentForMenuOptions (options); + if (parentComponent == nullptr && lf.shouldPopupMenuScaleWithTargetComponent (options)) + scaleFactor = getApproximateScaleFactorForTargetComponent (options.getTargetComponent()); + setOpaque (lf.findColour (PopupMenu::backgroundColourId).isOpaque() || ! Desktop::canUseSemiTransparentWindows()); @@ -226,14 +230,16 @@ public: items.add (new ItemComponent (*item, options.standardHeight, *this)); } - calculateWindowPos (options.targetArea, alignToRectangle); + Rectangle targetArea = options.targetArea / scaleFactor; + + calculateWindowPos (targetArea, alignToRectangle); setTopLeftPosition (windowPos.getPosition()); updateYPositions(); if (options.visibleItemID != 0) { - auto targetPosition = parentComponent != nullptr ? parentComponent->getLocalPoint (nullptr, options.targetArea.getTopLeft()) - : options.targetArea.getTopLeft(); + auto targetPosition = parentComponent != nullptr ? parentComponent->getLocalPoint (nullptr, targetArea.getTopLeft()) + : targetArea.getTopLeft(); auto y = targetPosition.getY() - windowPos.getY(); ensureItemIsVisible (options.visibleItemID, @@ -356,6 +362,8 @@ public: } } + float getDesktopScaleFactor() const override { return scaleFactor * Desktop::getInstance().getGlobalScaleFactor(); } + //============================================================================== bool keyPressed (const KeyPress& key) override { @@ -946,6 +954,22 @@ public: bool isTopScrollZoneActive() const noexcept { return canScroll() && childYOffset > 0; } bool isBottomScrollZoneActive() const noexcept { return canScroll() && childYOffset < contentHeight - windowPos.getHeight(); } + //============================================================================== + static float getApproximateScaleFactorForTargetComponent (Component* targetComponent) + { + AffineTransform transform; + + for (auto* target = targetComponent; target != nullptr; target = target->getParentComponent()) + { + transform = transform.followedBy (target->getTransform()); + + if (target->isOnDesktop()) + transform = transform.scaled (target->getDesktopScaleFactor()); + } + + return (transform.getScaleFactor() / Desktop::getInstance().getGlobalScaleFactor()); + } + //============================================================================== MenuWindow* parent; const Options options; @@ -962,6 +986,7 @@ public: Array columnWidths; uint32 windowCreationTime, lastFocusedTime, timeEnteredCurrentChildComp; OwnedArray mouseSourceStates; + float scaleFactor; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MenuWindow) }; diff --git a/modules/juce_gui_basics/menus/juce_PopupMenu.h b/modules/juce_gui_basics/menus/juce_PopupMenu.h index d119a14993..14d36b8fc1 100644 --- a/modules/juce_gui_basics/menus/juce_PopupMenu.h +++ b/modules/juce_gui_basics/menus/juce_PopupMenu.h @@ -719,6 +719,10 @@ public: virtual Component* getParentComponentForMenuOptions (const PopupMenu::Options& options) = 0; virtual void preparePopupMenuWindow (Component& newWindow) = 0; + + /** Return true if you want your popup menus to scale with the target component's AffineTransform + or scale factor */ + virtual bool shouldPopupMenuScaleWithTargetComponent (const PopupMenu::Options& options) = 0; }; private: