mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-17 00:44:19 +00:00
Add support for creating popup menus inside parent components
This commit is contained in:
parent
77a8b9eab5
commit
ac9973f185
4 changed files with 107 additions and 40 deletions
|
|
@ -1075,6 +1075,11 @@ void LookAndFeel_V2::drawMenuBarItem (Graphics& g, int width, int height,
|
|||
g.drawFittedText (itemText, 0, 0, width, height, Justification::centred, 1);
|
||||
}
|
||||
|
||||
Component* LookAndFeel_V2::getParentComponentForMenuOptions (const PopupMenu::Options& options)
|
||||
{
|
||||
return options.getParentComponent();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void LookAndFeel_V2::fillTextEditorBackground (Graphics& g, int /*width*/, int /*height*/, TextEditor& textEditor)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -173,6 +173,8 @@ public:
|
|||
bool isMouseOverItem, bool isMenuOpen, bool isMouseOverBar,
|
||||
MenuBarComponent&) override;
|
||||
|
||||
Component* getParentComponentForMenuOptions (const PopupMenu::Options& options) override;
|
||||
|
||||
//==============================================================================
|
||||
void drawComboBox (Graphics&, int width, int height, bool isButtonDown,
|
||||
int buttonX, int buttonY, int buttonW, int buttonH,
|
||||
|
|
|
|||
|
|
@ -198,6 +198,7 @@ public:
|
|||
options (opts),
|
||||
managerOfChosenCommand (manager),
|
||||
componentAttachedTo (options.targetComponent),
|
||||
parentComponent (nullptr),
|
||||
hasBeenOver (false),
|
||||
needsToScroll (false),
|
||||
dismissOnMouseUp (shouldDismissOnMouseUp),
|
||||
|
|
@ -218,6 +219,8 @@ public:
|
|||
setLookAndFeel (parent != nullptr ? &(parent->getLookAndFeel())
|
||||
: menu.lookAndFeel.get());
|
||||
|
||||
parentComponent = getLookAndFeel().getParentComponentForMenuOptions (options);
|
||||
|
||||
setOpaque (getLookAndFeel().findColour (PopupMenu::backgroundColourId).isOpaque()
|
||||
|| ! Desktop::canUseSemiTransparentWindows());
|
||||
|
||||
|
|
@ -235,18 +238,30 @@ public:
|
|||
|
||||
if (options.visibleItemID != 0)
|
||||
{
|
||||
const int y = options.targetArea.getY() - windowPos.getY();
|
||||
const Point<int> targetPosition =
|
||||
(parentComponent != nullptr ? parentComponent->getLocalPoint (nullptr, options.targetArea.getTopLeft())
|
||||
: options.targetArea.getTopLeft());
|
||||
|
||||
const int y = targetPosition.getY() - windowPos.getY();
|
||||
ensureItemIsVisible (options.visibleItemID,
|
||||
isPositiveAndBelow (y, windowPos.getHeight()) ? y : -1);
|
||||
}
|
||||
|
||||
resizeToBestWindowPos();
|
||||
addToDesktop (ComponentPeer::windowIsTemporary
|
||||
| ComponentPeer::windowIgnoresKeyPresses
|
||||
| getLookAndFeel().getMenuWindowFlags());
|
||||
|
||||
getActiveWindows().add (this);
|
||||
Desktop::getInstance().addGlobalMouseListener (this);
|
||||
if (parentComponent != nullptr)
|
||||
{
|
||||
parentComponent->addChildComponent (this);
|
||||
}
|
||||
else
|
||||
{
|
||||
addToDesktop (ComponentPeer::windowIsTemporary
|
||||
| ComponentPeer::windowIgnoresKeyPresses
|
||||
| getLookAndFeel().getMenuWindowFlags());
|
||||
|
||||
getActiveWindows().add (this);
|
||||
Desktop::getInstance().addGlobalMouseListener (this);
|
||||
}
|
||||
}
|
||||
|
||||
~MenuWindow()
|
||||
|
|
@ -268,10 +283,13 @@ public:
|
|||
|
||||
void paintOverChildren (Graphics& g) override
|
||||
{
|
||||
LookAndFeel& lf = getLookAndFeel();
|
||||
|
||||
if (parentComponent != nullptr)
|
||||
lf.drawResizableFrame (g, getWidth(), getHeight(), BorderSize<int> (PopupMenuSettings::borderSize));
|
||||
|
||||
if (canScroll())
|
||||
{
|
||||
LookAndFeel& lf = getLookAndFeel();
|
||||
|
||||
if (isTopScrollZoneActive())
|
||||
lf.drawPopupMenuUpDownArrow (g, getWidth(), PopupMenuSettings::scrollZone, true);
|
||||
|
||||
|
|
@ -551,27 +569,43 @@ public:
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
void calculateWindowPos (const Rectangle<int>& target, const bool alignToRectangle)
|
||||
Rectangle<int> getParentArea (Point<int> targetPoint)
|
||||
{
|
||||
const Rectangle<int> mon (Desktop::getInstance().getDisplays()
|
||||
.getDisplayContaining (target.getCentre())
|
||||
#if JUCE_MAC
|
||||
.userArea);
|
||||
#else
|
||||
.totalArea); // on windows, don't stop the menu overlapping the taskbar
|
||||
#endif
|
||||
Rectangle<int> parentArea (Desktop::getInstance().getDisplays()
|
||||
.getDisplayContaining (targetPoint)
|
||||
#if JUCE_MAC
|
||||
.userArea);
|
||||
#else
|
||||
.totalArea); // on windows, don't stop the menu overlapping the taskbar
|
||||
#endif
|
||||
|
||||
const int maxMenuHeight = mon.getHeight() - 24;
|
||||
if (parentComponent == nullptr)
|
||||
return parentArea;
|
||||
|
||||
return parentComponent->getLocalArea (nullptr,
|
||||
parentComponent->getScreenBounds()
|
||||
.reduced (PopupMenuSettings::borderSize)
|
||||
.getIntersection (parentArea));
|
||||
}
|
||||
|
||||
void calculateWindowPos (Rectangle<int> target, const bool alignToRectangle)
|
||||
{
|
||||
const Rectangle<int> parentArea = getParentArea (target.getCentre());
|
||||
|
||||
if (parentComponent != nullptr)
|
||||
target = parentComponent->getLocalArea (nullptr, target).getIntersection (parentArea);
|
||||
|
||||
const int maxMenuHeight = parentArea.getHeight() - 24;
|
||||
|
||||
int x, y, widthToUse, heightToUse;
|
||||
layoutMenuItems (mon.getWidth() - 24, maxMenuHeight, widthToUse, heightToUse);
|
||||
layoutMenuItems (parentArea.getWidth() - 24, maxMenuHeight, widthToUse, heightToUse);
|
||||
|
||||
if (alignToRectangle)
|
||||
{
|
||||
x = target.getX();
|
||||
|
||||
const int spaceUnder = mon.getHeight() - (target.getBottom() - mon.getY());
|
||||
const int spaceOver = target.getY() - mon.getY();
|
||||
const int spaceUnder = parentArea.getHeight() - (target.getBottom() - parentArea.getY());
|
||||
const int spaceOver = target.getY() - parentArea.getY();
|
||||
|
||||
if (heightToUse < spaceUnder - 30 || spaceUnder >= spaceOver)
|
||||
y = target.getBottom();
|
||||
|
|
@ -580,7 +614,7 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
bool tendTowardsRight = target.getCentreX() < mon.getCentreX();
|
||||
bool tendTowardsRight = target.getCentreX() < parentArea.getCentreX();
|
||||
|
||||
if (parent != nullptr)
|
||||
{
|
||||
|
|
@ -589,19 +623,19 @@ public:
|
|||
const bool parentGoingRight = (parent->getX() + parent->getWidth() / 2
|
||||
> parent->parent->getX() + parent->parent->getWidth() / 2);
|
||||
|
||||
if (parentGoingRight && target.getRight() + widthToUse < mon.getRight() - 4)
|
||||
if (parentGoingRight && target.getRight() + widthToUse < parentArea.getRight() - 4)
|
||||
tendTowardsRight = true;
|
||||
else if ((! parentGoingRight) && target.getX() > widthToUse + 4)
|
||||
tendTowardsRight = false;
|
||||
}
|
||||
else if (target.getRight() + widthToUse < mon.getRight() - 32)
|
||||
else if (target.getRight() + widthToUse < parentArea.getRight() - 32)
|
||||
{
|
||||
tendTowardsRight = true;
|
||||
}
|
||||
}
|
||||
|
||||
const int biggestSpace = jmax (mon.getRight() - target.getRight(),
|
||||
target.getX() - mon.getX()) - 32;
|
||||
const int biggestSpace = jmax (parentArea.getRight() - target.getRight(),
|
||||
target.getX() - parentArea.getX()) - 32;
|
||||
|
||||
if (biggestSpace < widthToUse)
|
||||
{
|
||||
|
|
@ -610,21 +644,21 @@ public:
|
|||
if (numColumns > 1)
|
||||
layoutMenuItems (biggestSpace - 4, maxMenuHeight, widthToUse, heightToUse);
|
||||
|
||||
tendTowardsRight = (mon.getRight() - target.getRight()) >= (target.getX() - mon.getX());
|
||||
tendTowardsRight = (parentArea.getRight() - target.getRight()) >= (target.getX() - parentArea.getX());
|
||||
}
|
||||
|
||||
if (tendTowardsRight)
|
||||
x = jmin (mon.getRight() - widthToUse - 4, target.getRight());
|
||||
x = jmin (parentArea.getRight() - widthToUse - 4, target.getRight());
|
||||
else
|
||||
x = jmax (mon.getX() + 4, target.getX() - widthToUse);
|
||||
x = jmax (parentArea.getX() + 4, target.getX() - widthToUse);
|
||||
|
||||
y = target.getY();
|
||||
if (target.getCentreY() > mon.getCentreY())
|
||||
y = jmax (mon.getY(), target.getBottom() - heightToUse);
|
||||
if (target.getCentreY() > parentArea.getCentreY())
|
||||
y = jmax (parentArea.getY(), target.getBottom() - heightToUse);
|
||||
}
|
||||
|
||||
x = jmax (mon.getX() + 1, jmin (mon.getRight() - (widthToUse + 6), x));
|
||||
y = jmax (mon.getY() + 1, jmin (mon.getBottom() - (heightToUse + 6), y));
|
||||
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);
|
||||
|
||||
|
|
@ -695,9 +729,12 @@ public:
|
|||
childNum += numChildren;
|
||||
}
|
||||
|
||||
if (totalW < options.minWidth)
|
||||
// width must never be larger than the screen
|
||||
const int minWidth = jmin (maxMenuW, options.minWidth);
|
||||
|
||||
if (totalW < minWidth)
|
||||
{
|
||||
totalW = options.minWidth;
|
||||
totalW = minWidth;
|
||||
|
||||
for (int col = 0; col < numColumns; ++col)
|
||||
columnWidths.set (0, totalW / numColumns);
|
||||
|
|
@ -727,16 +764,15 @@ public:
|
|||
windowPos.getHeight() - (PopupMenuSettings::scrollZone + m->getHeight())),
|
||||
currentY);
|
||||
|
||||
const Rectangle<int> mon (Desktop::getInstance().getDisplays()
|
||||
.getDisplayContaining (windowPos.getPosition()).userArea);
|
||||
const Rectangle<int> parantArea = getParentArea (windowPos.getPosition());
|
||||
|
||||
int deltaY = wantedY - currentY;
|
||||
|
||||
windowPos.setSize (jmin (windowPos.getWidth(), mon.getWidth()),
|
||||
jmin (windowPos.getHeight(), mon.getHeight()));
|
||||
windowPos.setSize (jmin (windowPos.getWidth(), parantArea.getWidth()),
|
||||
jmin (windowPos.getHeight(), parantArea.getHeight()));
|
||||
|
||||
const int newY = jlimit (mon.getY(),
|
||||
mon.getBottom() - windowPos.getHeight(),
|
||||
const int newY = jlimit (parantArea.getY(),
|
||||
parantArea.getBottom() - windowPos.getHeight(),
|
||||
windowPos.getY() + deltaY);
|
||||
|
||||
deltaY -= newY - windowPos.getY();
|
||||
|
|
@ -912,6 +948,7 @@ public:
|
|||
OwnedArray<ItemComponent> items;
|
||||
ApplicationCommandManager** managerOfChosenCommand;
|
||||
WeakReference<Component> componentAttachedTo;
|
||||
Component* parentComponent;
|
||||
Rectangle<int> windowPos;
|
||||
bool hasBeenOver, needsToScroll;
|
||||
bool dismissOnMouseUp, hideOnExit, disableMouseMoves, hasAnyJuceCompHadFocus;
|
||||
|
|
@ -1428,6 +1465,7 @@ void PopupMenu::addSectionHeader (const String& title)
|
|||
//==============================================================================
|
||||
PopupMenu::Options::Options()
|
||||
: targetComponent (nullptr),
|
||||
parentComponent (nullptr),
|
||||
visibleItemID (0),
|
||||
minWidth (0),
|
||||
maxColumns (0),
|
||||
|
|
@ -1482,6 +1520,13 @@ PopupMenu::Options PopupMenu::Options::withItemThatMustBeVisible (int idOfItemTo
|
|||
return o;
|
||||
}
|
||||
|
||||
PopupMenu::Options PopupMenu::Options::withParentComponent (Component* parent) const noexcept
|
||||
{
|
||||
Options o (*this);
|
||||
o.parentComponent = parent;
|
||||
return o;
|
||||
}
|
||||
|
||||
Component* PopupMenu::createWindow (const Options& options,
|
||||
ApplicationCommandManager** managerOfChosenCommand) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -380,18 +380,31 @@ public:
|
|||
public:
|
||||
Options();
|
||||
|
||||
//==============================================================================
|
||||
Options withTargetComponent (Component* targetComponent) const noexcept;
|
||||
Options withTargetScreenArea (const Rectangle<int>& targetArea) const noexcept;
|
||||
Options withMinimumWidth (int minWidth) const noexcept;
|
||||
Options withMaximumNumColumns (int maxNumColumns) const noexcept;
|
||||
Options withStandardItemHeight (int standardHeight) const noexcept;
|
||||
Options withItemThatMustBeVisible (int idOfItemToBeVisible) const noexcept;
|
||||
Options withParentComponent (Component* parentComponent) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
Component* getParentComponent() const noexcept { return parentComponent; }
|
||||
Component* getTargetComponent() const noexcept { return targetComponent; }
|
||||
Rectangle<int> getTargetScreenArea() const noexcept { return targetArea; }
|
||||
int getMinimumWidth() const noexcept { return minWidth; }
|
||||
int getMaximumNumColumns() const noexcept { return maxColumns; }
|
||||
int getStandardItemHeight() const noexcept { return standardHeight; }
|
||||
int getItemThatMustBeVisible() const noexcept { return visibleItemID; }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
friend class PopupMenu;
|
||||
friend class PopupMenu::Window;
|
||||
Rectangle<int> targetArea;
|
||||
Component* targetComponent;
|
||||
Component* parentComponent;
|
||||
int visibleItemID, minWidth, maxColumns, standardHeight;
|
||||
};
|
||||
|
||||
|
|
@ -668,6 +681,8 @@ public:
|
|||
bool isMenuOpen,
|
||||
bool isMouseOverBar,
|
||||
MenuBarComponent&) = 0;
|
||||
|
||||
virtual Component* getParentComponentForMenuOptions (const PopupMenu::Options& options) = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue