|
|
@@ -198,6 +198,7 @@ public: |
|
|
options (opts),
|
|
|
options (opts),
|
|
|
managerOfChosenCommand (manager),
|
|
|
managerOfChosenCommand (manager),
|
|
|
componentAttachedTo (options.targetComponent),
|
|
|
componentAttachedTo (options.targetComponent),
|
|
|
|
|
|
parentComponent (nullptr),
|
|
|
hasBeenOver (false),
|
|
|
hasBeenOver (false),
|
|
|
needsToScroll (false),
|
|
|
needsToScroll (false),
|
|
|
dismissOnMouseUp (shouldDismissOnMouseUp),
|
|
|
dismissOnMouseUp (shouldDismissOnMouseUp),
|
|
|
@@ -218,6 +219,8 @@ public: |
|
|
setLookAndFeel (parent != nullptr ? &(parent->getLookAndFeel())
|
|
|
setLookAndFeel (parent != nullptr ? &(parent->getLookAndFeel())
|
|
|
: menu.lookAndFeel.get());
|
|
|
: menu.lookAndFeel.get());
|
|
|
|
|
|
|
|
|
|
|
|
parentComponent = getLookAndFeel().getParentComponentForMenuOptions (options);
|
|
|
|
|
|
|
|
|
setOpaque (getLookAndFeel().findColour (PopupMenu::backgroundColourId).isOpaque()
|
|
|
setOpaque (getLookAndFeel().findColour (PopupMenu::backgroundColourId).isOpaque()
|
|
|
|| ! Desktop::canUseSemiTransparentWindows());
|
|
|
|| ! Desktop::canUseSemiTransparentWindows());
|
|
|
|
|
|
|
|
|
@@ -235,18 +238,30 @@ public: |
|
|
|
|
|
|
|
|
if (options.visibleItemID != 0)
|
|
|
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,
|
|
|
ensureItemIsVisible (options.visibleItemID,
|
|
|
isPositiveAndBelow (y, windowPos.getHeight()) ? y : -1);
|
|
|
isPositiveAndBelow (y, windowPos.getHeight()) ? y : -1);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
resizeToBestWindowPos();
|
|
|
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()
|
|
|
~MenuWindow()
|
|
|
@@ -268,10 +283,13 @@ public: |
|
|
|
|
|
|
|
|
void paintOverChildren (Graphics& g) override
|
|
|
void paintOverChildren (Graphics& g) override
|
|
|
{
|
|
|
{
|
|
|
|
|
|
LookAndFeel& lf = getLookAndFeel();
|
|
|
|
|
|
|
|
|
|
|
|
if (parentComponent != nullptr)
|
|
|
|
|
|
lf.drawResizableFrame (g, getWidth(), getHeight(), BorderSize<int> (PopupMenuSettings::borderSize));
|
|
|
|
|
|
|
|
|
if (canScroll())
|
|
|
if (canScroll())
|
|
|
{
|
|
|
{
|
|
|
LookAndFeel& lf = getLookAndFeel();
|
|
|
|
|
|
|
|
|
|
|
|
if (isTopScrollZoneActive())
|
|
|
if (isTopScrollZoneActive())
|
|
|
lf.drawPopupMenuUpDownArrow (g, getWidth(), PopupMenuSettings::scrollZone, true);
|
|
|
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;
|
|
|
int x, y, widthToUse, heightToUse;
|
|
|
layoutMenuItems (mon.getWidth() - 24, maxMenuHeight, widthToUse, heightToUse);
|
|
|
|
|
|
|
|
|
layoutMenuItems (parentArea.getWidth() - 24, maxMenuHeight, widthToUse, heightToUse);
|
|
|
|
|
|
|
|
|
if (alignToRectangle)
|
|
|
if (alignToRectangle)
|
|
|
{
|
|
|
{
|
|
|
x = target.getX();
|
|
|
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)
|
|
|
if (heightToUse < spaceUnder - 30 || spaceUnder >= spaceOver)
|
|
|
y = target.getBottom();
|
|
|
y = target.getBottom();
|
|
|
@@ -580,7 +614,7 @@ public: |
|
|
}
|
|
|
}
|
|
|
else
|
|
|
else
|
|
|
{
|
|
|
{
|
|
|
bool tendTowardsRight = target.getCentreX() < mon.getCentreX();
|
|
|
|
|
|
|
|
|
bool tendTowardsRight = target.getCentreX() < parentArea.getCentreX();
|
|
|
|
|
|
|
|
|
if (parent != nullptr)
|
|
|
if (parent != nullptr)
|
|
|
{
|
|
|
{
|
|
|
@@ -589,19 +623,19 @@ public: |
|
|
const bool parentGoingRight = (parent->getX() + parent->getWidth() / 2
|
|
|
const bool parentGoingRight = (parent->getX() + parent->getWidth() / 2
|
|
|
> parent->parent->getX() + parent->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;
|
|
|
tendTowardsRight = true;
|
|
|
else if ((! parentGoingRight) && target.getX() > widthToUse + 4)
|
|
|
else if ((! parentGoingRight) && target.getX() > widthToUse + 4)
|
|
|
tendTowardsRight = false;
|
|
|
tendTowardsRight = false;
|
|
|
}
|
|
|
}
|
|
|
else if (target.getRight() + widthToUse < mon.getRight() - 32)
|
|
|
|
|
|
|
|
|
else if (target.getRight() + widthToUse < parentArea.getRight() - 32)
|
|
|
{
|
|
|
{
|
|
|
tendTowardsRight = true;
|
|
|
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)
|
|
|
if (biggestSpace < widthToUse)
|
|
|
{
|
|
|
{
|
|
|
@@ -610,21 +644,21 @@ public: |
|
|
if (numColumns > 1)
|
|
|
if (numColumns > 1)
|
|
|
layoutMenuItems (biggestSpace - 4, maxMenuHeight, widthToUse, heightToUse);
|
|
|
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)
|
|
|
if (tendTowardsRight)
|
|
|
x = jmin (mon.getRight() - widthToUse - 4, target.getRight());
|
|
|
|
|
|
|
|
|
x = jmin (parentArea.getRight() - widthToUse - 4, target.getRight());
|
|
|
else
|
|
|
else
|
|
|
x = jmax (mon.getX() + 4, target.getX() - widthToUse);
|
|
|
|
|
|
|
|
|
x = jmax (parentArea.getX() + 4, target.getX() - widthToUse);
|
|
|
|
|
|
|
|
|
y = target.getY();
|
|
|
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);
|
|
|
windowPos.setBounds (x, y, widthToUse, heightToUse);
|
|
|
|
|
|
|
|
|
@@ -695,9 +729,12 @@ public: |
|
|
childNum += numChildren;
|
|
|
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)
|
|
|
for (int col = 0; col < numColumns; ++col)
|
|
|
columnWidths.set (0, totalW / numColumns);
|
|
|
columnWidths.set (0, totalW / numColumns);
|
|
|
@@ -727,16 +764,15 @@ public: |
|
|
windowPos.getHeight() - (PopupMenuSettings::scrollZone + m->getHeight())),
|
|
|
windowPos.getHeight() - (PopupMenuSettings::scrollZone + m->getHeight())),
|
|
|
currentY);
|
|
|
currentY);
|
|
|
|
|
|
|
|
|
const Rectangle<int> mon (Desktop::getInstance().getDisplays()
|
|
|
|
|
|
.getDisplayContaining (windowPos.getPosition()).userArea);
|
|
|
|
|
|
|
|
|
const Rectangle<int> parantArea = getParentArea (windowPos.getPosition());
|
|
|
|
|
|
|
|
|
int deltaY = wantedY - currentY;
|
|
|
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);
|
|
|
windowPos.getY() + deltaY);
|
|
|
|
|
|
|
|
|
deltaY -= newY - windowPos.getY();
|
|
|
deltaY -= newY - windowPos.getY();
|
|
|
@@ -912,6 +948,7 @@ public: |
|
|
OwnedArray<ItemComponent> items;
|
|
|
OwnedArray<ItemComponent> items;
|
|
|
ApplicationCommandManager** managerOfChosenCommand;
|
|
|
ApplicationCommandManager** managerOfChosenCommand;
|
|
|
WeakReference<Component> componentAttachedTo;
|
|
|
WeakReference<Component> componentAttachedTo;
|
|
|
|
|
|
Component* parentComponent;
|
|
|
Rectangle<int> windowPos;
|
|
|
Rectangle<int> windowPos;
|
|
|
bool hasBeenOver, needsToScroll;
|
|
|
bool hasBeenOver, needsToScroll;
|
|
|
bool dismissOnMouseUp, hideOnExit, disableMouseMoves, hasAnyJuceCompHadFocus;
|
|
|
bool dismissOnMouseUp, hideOnExit, disableMouseMoves, hasAnyJuceCompHadFocus;
|
|
|
@@ -1428,6 +1465,7 @@ void PopupMenu::addSectionHeader (const String& title) |
|
|
//==============================================================================
|
|
|
//==============================================================================
|
|
|
PopupMenu::Options::Options()
|
|
|
PopupMenu::Options::Options()
|
|
|
: targetComponent (nullptr),
|
|
|
: targetComponent (nullptr),
|
|
|
|
|
|
parentComponent (nullptr),
|
|
|
visibleItemID (0),
|
|
|
visibleItemID (0),
|
|
|
minWidth (0),
|
|
|
minWidth (0),
|
|
|
maxColumns (0),
|
|
|
maxColumns (0),
|
|
|
@@ -1482,6 +1520,13 @@ PopupMenu::Options PopupMenu::Options::withItemThatMustBeVisible (int idOfItemTo |
|
|
return o;
|
|
|
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,
|
|
|
Component* PopupMenu::createWindow (const Options& options,
|
|
|
ApplicationCommandManager** managerOfChosenCommand) const
|
|
|
ApplicationCommandManager** managerOfChosenCommand) const
|
|
|
{
|
|
|
{
|
|
|
|