From edfa87801cce850aadd3f34c3bdde2ba8d69cfe9 Mon Sep 17 00:00:00 2001 From: reuk Date: Mon, 18 Aug 2025 18:10:36 +0100 Subject: [PATCH] PopupMenu: Extract implementation of ensureItemComponentIsVisible into static function This makes it a bit easier to see exactly which PopupMenu state is used during the calculation, and enforces that no menu state is modified during the call. --- .../juce_gui_basics/menus/juce_PopupMenu.cpp | 42 ++++++++++++++----- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/modules/juce_gui_basics/menus/juce_PopupMenu.cpp b/modules/juce_gui_basics/menus/juce_PopupMenu.cpp index 264eb86fd5..4a4597e362 100644 --- a/modules/juce_gui_basics/menus/juce_PopupMenu.cpp +++ b/modules/juce_gui_basics/menus/juce_PopupMenu.cpp @@ -431,15 +431,15 @@ struct MenuWindow final : public Component if (iter != items.end()) { - const auto targetPosition = [&] + const auto targetPosition = std::invoke ([&] { if (auto* pc = options.getParentComponent()) return pc->getLocalPoint (nullptr, targetArea.getTopLeft()); return targetArea.getTopLeft(); - }(); + }); - auto y = targetPosition.getY() - windowPos.getY(); + const auto y = targetPosition.getY() - windowPos.getY(); ensureItemComponentIsVisible (**iter, isPositiveAndBelow (y, windowPos.getHeight()) ? y : -1); } } @@ -1093,20 +1093,40 @@ struct MenuWindow final : public Component void ensureItemComponentIsVisible (const ItemComponent& itemComp, int wantedY) { - if (windowPos.getHeight() <= PopupMenuSettings::scrollZone * 4 - || (wantedY <= 0 && 0 <= itemComp.getY() && itemComp.getBottom() <= windowPos.getHeight())) + const auto parentArea = getParentArea (windowPos.getPosition(), options.getParentComponent()) / scaleFactor; + + if (const auto posAndOffset = computeInitialPosAndOffset (windowPos, parentArea, itemComp.getBounds(), childYOffset, wantedY)) { - return; + std::tie (windowPos, childYOffset) = std::tie (posAndOffset->windowPos, posAndOffset->childYOffset); + updateYPositions(); + } + } + + struct PosAndOffset + { + Rectangle windowPos; + int childYOffset = 0; + }; + + static std::optional computeInitialPosAndOffset (Rectangle windowPos, + const Rectangle& parentArea, + const Rectangle& itemCompBounds, + int childYOffset, + int wantedY) + { + if (windowPos.getHeight() <= PopupMenuSettings::scrollZone * 4 + || (wantedY <= 0 && 0 <= itemCompBounds.getY() && itemCompBounds.getBottom() <= windowPos.getHeight())) + { + return {}; } if (wantedY < 0) wantedY = jlimit (PopupMenuSettings::scrollZone, jmax (PopupMenuSettings::scrollZone, - windowPos.getHeight() - (PopupMenuSettings::scrollZone + itemComp.getHeight())), - itemComp.getY()); + windowPos.getHeight() - (PopupMenuSettings::scrollZone + itemCompBounds.getHeight())), + itemCompBounds.getY()); - const auto parentArea = getParentArea (windowPos.getPosition(), options.getParentComponent()) / scaleFactor; - const auto deltaY = windowPos.getY() + wantedY - itemComp.getY(); + const auto deltaY = windowPos.getY() + wantedY - itemCompBounds.getY(); windowPos.setSize (jmin (windowPos.getWidth(), parentArea.getWidth()), jmin (windowPos.getHeight(), parentArea.getHeight())); @@ -1118,7 +1138,7 @@ struct MenuWindow final : public Component childYOffset -= (deltaY - newY); windowPos.setPosition (windowPos.getX(), newY); - updateYPositions(); + return PosAndOffset { windowPos, childYOffset }; } void resizeToBestWindowPos()