diff --git a/modules/juce_gui_basics/menus/juce_PopupMenu.cpp b/modules/juce_gui_basics/menus/juce_PopupMenu.cpp index ca010c074c..6c96c875a0 100644 --- a/modules/juce_gui_basics/menus/juce_PopupMenu.cpp +++ b/modules/juce_gui_basics/menus/juce_PopupMenu.cpp @@ -626,13 +626,16 @@ public: { x = target.getX(); - auto spaceUnder = parentArea.getHeight() - (target.getBottom() - parentArea.getY()); + auto spaceUnder = parentArea.getBottom() - target.getBottom(); auto spaceOver = target.getY() - parentArea.getY(); + auto bufferHeight = 30; - if (heightToUse < spaceUnder - 30 || spaceUnder >= spaceOver) - y = target.getBottom(); + if (options.getPreferredPopupDirection() == Options::PopupDirection::upwards) + y = (heightToUse < spaceOver - bufferHeight || spaceOver >= spaceUnder) ? target.getY() - heightToUse + : target.getBottom(); else - y = target.getY() - heightToUse; + y = (heightToUse < spaceUnder - bufferHeight || spaceUnder >= spaceOver) ? target.getBottom() + : target.getY() - heightToUse; } else { @@ -669,20 +672,17 @@ public: tendTowardsRight = (parentArea.getRight() - target.getRight()) >= (target.getX() - parentArea.getX()); } - if (tendTowardsRight) - x = jmin (parentArea.getRight() - widthToUse - 4, target.getRight()); - else - x = jmax (parentArea.getX() + 4, target.getX() - widthToUse); + x = tendTowardsRight ? jmin (parentArea.getRight() - widthToUse - 4, target.getRight()) + : jmax (parentArea.getX() + 4, target.getX() - widthToUse); if (getLookAndFeel().getPopupMenuBorderSize() == 0) // workaround for dismissing the window on mouse up when border size is 0 x += tendTowardsRight ? 1 : -1; - y = target.getY(); - if (target.getCentreY() > parentArea.getCentreY()) - y = jmax (parentArea.getY(), target.getBottom() - heightToUse); + y = target.getCentreY() > parentArea.getCentreY() ? jmax (parentArea.getY(), target.getBottom() - heightToUse) + : target.getY(); } - x = jmax (parentArea.getX() + 1, jmin (parentArea.getRight() - (widthToUse + 6), x)); + x = jmax (parentArea.getX() + 1, jmin (parentArea.getRight() - (widthToUse + 6), x)); y = jmax (parentArea.getY() + 1, jmin (parentArea.getBottom() - (heightToUse + 6), y)); windowPos.setBounds (x, y, widthToUse, heightToUse); @@ -1580,6 +1580,13 @@ PopupMenu::Options PopupMenu::Options::withParentComponent (Component* parent) c return o; } +PopupMenu::Options PopupMenu::Options::withPreferredPopupDirection (PopupDirection direction) const noexcept +{ + Options o (*this); + o.preferredPopupDirection = direction; + return o; +} + Component* PopupMenu::createWindow (const Options& options, ApplicationCommandManager** managerOfChosenCommand) const { diff --git a/modules/juce_gui_basics/menus/juce_PopupMenu.h b/modules/juce_gui_basics/menus/juce_PopupMenu.h index 7e1565e299..2c149c9fd2 100644 --- a/modules/juce_gui_basics/menus/juce_PopupMenu.h +++ b/modules/juce_gui_basics/menus/juce_PopupMenu.h @@ -390,6 +390,12 @@ public: Options (const Options&) = default; Options& operator= (const Options&) = default; + enum class PopupDirection + { + upwards, + downwards + }; + //============================================================================== Options withTargetComponent (Component* targetComponent) const noexcept; Options withTargetScreenArea (Rectangle targetArea) const noexcept; @@ -399,16 +405,18 @@ public: Options withStandardItemHeight (int standardHeight) const noexcept; Options withItemThatMustBeVisible (int idOfItemToBeVisible) const noexcept; Options withParentComponent (Component* parentComponent) const noexcept; + Options withPreferredPopupDirection (PopupDirection direction) const noexcept; //============================================================================== - Component* getParentComponent() const noexcept { return parentComponent; } - Component* getTargetComponent() const noexcept { return targetComponent; } - Rectangle getTargetScreenArea() const noexcept { return targetArea; } - int getMinimumWidth() const noexcept { return minWidth; } - int getMaximumNumColumns() const noexcept { return maxColumns; } - int getMinimumNumColumns() const noexcept { return minColumns; } - int getStandardItemHeight() const noexcept { return standardHeight; } - int getItemThatMustBeVisible() const noexcept { return visibleItemID; } + Component* getParentComponent() const noexcept { return parentComponent; } + Component* getTargetComponent() const noexcept { return targetComponent; } + Rectangle getTargetScreenArea() const noexcept { return targetArea; } + int getMinimumWidth() const noexcept { return minWidth; } + int getMaximumNumColumns() const noexcept { return maxColumns; } + int getMinimumNumColumns() const noexcept { return minColumns; } + int getStandardItemHeight() const noexcept { return standardHeight; } + int getItemThatMustBeVisible() const noexcept { return visibleItemID; } + PopupDirection getPreferredPopupDirection() const noexcept { return preferredPopupDirection; } private: //============================================================================== @@ -416,6 +424,7 @@ public: Component* targetComponent = nullptr; Component* parentComponent = nullptr; int visibleItemID = 0, minWidth = 0, minColumns = 1, maxColumns = 0, standardHeight = 0; + PopupDirection preferredPopupDirection = PopupDirection::downwards; }; //==============================================================================