Browse Source

Added a minimum number of columns option to the PopupMenu, and did a bit of internal modernising on the class's internals

tags/2021-05-28
jules 8 years ago
parent
commit
9e356135a1
2 changed files with 71 additions and 85 deletions
  1. +47
    -61
      modules/juce_gui_basics/menus/juce_PopupMenu.cpp
  2. +24
    -24
      modules/juce_gui_basics/menus/juce_PopupMenu.h

+ 47
- 61
modules/juce_gui_basics/menus/juce_PopupMenu.cpp View File

@@ -74,9 +74,7 @@ struct HeaderItemComponent : public PopupMenu::CustomComponent
struct ItemComponent : public Component
{
ItemComponent (const PopupMenu::Item& i, int standardItemHeight, MenuWindow& parent)
: item (i),
customComp (i.customComponent),
isHighlighted (false)
: item (i), customComp (i.customComponent)
{
if (item.isSectionHeader)
customComp = new HeaderItemComponent (item.text);
@@ -152,7 +150,7 @@ struct ItemComponent : public Component
private:
// NB: we use a copy of the one from the item info in case we're using our own section comp
ReferenceCountedObjectPtr<CustomComponent> customComp;
bool isHighlighted;
bool isHighlighted = false;
void updateShortcutKeyDescription()
{
@@ -200,7 +198,7 @@ public:
parent (parentWindow),
options (opts),
managerOfChosenCommand (manager),
componentAttachedTo (options.targetComponent),
componentAttachedTo (options.getTargetComponent()),
dismissOnMouseUp (shouldDismissOnMouseUp),
windowCreationTime (Time::getMillisecondCounter()),
lastFocusedTime (windowCreationTime),
@@ -230,23 +228,22 @@ public:
auto item = menu.items.getUnchecked (i);
if (i < menu.items.size() - 1 || ! item->isSeparator)
items.add (new ItemComponent (*item, options.standardHeight, *this));
items.add (new ItemComponent (*item, options.getStandardItemHeight(), *this));
}
Rectangle<int> targetArea = options.targetArea / scaleFactor;
auto targetArea = options.getTargetScreenArea() / scaleFactor;
calculateWindowPos (targetArea, alignToRectangle);
setTopLeftPosition (windowPos.getPosition());
updateYPositions();
if (options.visibleItemID != 0)
if (auto visibleID = options.getItemThatMustBeVisible())
{
auto targetPosition = parentComponent != nullptr ? parentComponent->getLocalPoint (nullptr, targetArea.getTopLeft())
: targetArea.getTopLeft();
auto y = targetPosition.getY() - windowPos.getY();
ensureItemIsVisible (options.visibleItemID,
isPositiveAndBelow (y, windowPos.getHeight()) ? y : -1);
ensureItemIsVisible (visibleID, isPositiveAndBelow (y, windowPos.getHeight()) ? y : -1);
}
resizeToBestWindowPos();
@@ -492,7 +489,7 @@ public:
if (! isVisible())
return false;
if (componentAttachedTo != options.targetComponent)
if (componentAttachedTo != options.getTargetComponent())
{
dismissMenu (nullptr);
return false;
@@ -629,8 +626,8 @@ public:
{
x = target.getX();
const int spaceUnder = parentArea.getHeight() - (target.getBottom() - parentArea.getY());
const int spaceOver = target.getY() - parentArea.getY();
auto spaceUnder = parentArea.getHeight() - (target.getBottom() - parentArea.getY());
auto spaceOver = target.getY() - parentArea.getY();
if (heightToUse < spaceUnder - 30 || spaceUnder >= spaceOver)
y = target.getBottom();
@@ -697,15 +694,14 @@ public:
void layoutMenuItems (const int maxMenuW, const int maxMenuH, int& width, int& height)
{
numColumns = 0;
numColumns = options.getMinimumNumColumns();
contentHeight = 0;
int totalW;
const int maximumNumColumns = options.maxColumns > 0 ? options.maxColumns : 7;
auto maximumNumColumns = options.getMaximumNumColumns() > 0 ? options.getMaximumNumColumns() : 7;
do
for (;;)
{
++numColumns;
totalW = workOutBestSize (maxMenuW);
if (totalW > maxMenuW)
@@ -715,12 +711,15 @@ public:
break;
}
if (totalW > maxMenuW / 2 || contentHeight < maxMenuH)
if (totalW > maxMenuW / 2
|| contentHeight < maxMenuH
|| numColumns >= maximumNumColumns)
break;
} while (numColumns < maximumNumColumns);
++numColumns;
}
const int actualH = jmin (contentHeight, maxMenuH);
auto actualH = jmin (contentHeight, maxMenuH);
needsToScroll = contentHeight > actualH;
@@ -736,7 +735,7 @@ public:
for (int col = 0; col < numColumns; ++col)
{
int colW = options.standardHeight, colH = 0;
int colW = options.getStandardItemHeight(), colH = 0;
const int numChildren = jmin (items.size() - childNum,
(items.size() + numColumns - 1) / numColumns);
@@ -757,7 +756,7 @@ public:
}
// width must never be larger than the screen
const int minWidth = jmin (maxMenuW, options.minWidth);
auto minWidth = jmin (maxMenuW, options.getMinimumWidth());
if (totalW < minWidth)
{
@@ -1321,13 +1320,6 @@ void PopupMenu::clear()
//==============================================================================
PopupMenu::Item::Item() noexcept
: itemID (0),
commandManager (nullptr),
colour (0x00000000),
isEnabled (true),
isTicked (false),
isSeparator (false),
isSectionHeader (false)
{
}
@@ -1526,12 +1518,6 @@ void PopupMenu::addSectionHeader (const String& title)
//==============================================================================
PopupMenu::Options::Options()
: targetComponent (nullptr),
parentComponent (nullptr),
visibleItemID (0),
minWidth (0),
maxColumns (0),
standardHeight (0)
{
targetArea.setPosition (Desktop::getMousePosition());
}
@@ -1547,7 +1533,7 @@ PopupMenu::Options PopupMenu::Options::withTargetComponent (Component* comp) con
return o;
}
PopupMenu::Options PopupMenu::Options::withTargetScreenArea (const Rectangle<int>& area) const noexcept
PopupMenu::Options PopupMenu::Options::withTargetScreenArea (Rectangle<int> area) const noexcept
{
Options o (*this);
o.targetArea = area;
@@ -1561,6 +1547,13 @@ PopupMenu::Options PopupMenu::Options::withMinimumWidth (int w) const noexcept
return o;
}
PopupMenu::Options PopupMenu::Options::withMinimumNumColumns (int cols) const noexcept
{
Options o (*this);
o.minColumns = cols;
return o;
}
PopupMenu::Options PopupMenu::Options::withMaximumNumColumns (int cols) const noexcept
{
Options o (*this);
@@ -1592,13 +1585,11 @@ PopupMenu::Options PopupMenu::Options::withParentComponent (Component* parent) c
Component* PopupMenu::createWindow (const Options& options,
ApplicationCommandManager** managerOfChosenCommand) const
{
if (items.size() > 0)
return new HelperClasses::MenuWindow (*this, nullptr, options,
! options.targetArea.isEmpty(),
ModifierKeys::getCurrentModifiers().isAnyMouseButtonDown(),
managerOfChosenCommand);
return nullptr;
return items.isEmpty() ? nullptr
: new HelperClasses::MenuWindow (*this, nullptr, options,
! options.getTargetScreenArea().isEmpty(),
ModifierKeys::getCurrentModifiers().isAnyMouseButtonDown(),
managerOfChosenCommand);
}
//==============================================================================
@@ -1690,9 +1681,8 @@ void PopupMenu::showMenuAsync (const Options& options, ModalComponentManager::Ca
//==============================================================================
#if JUCE_MODAL_LOOPS_PERMITTED
int PopupMenu::show (const int itemIDThatMustBeVisible,
const int minimumWidth, const int maximumNumColumns,
const int standardItemHeight,
int PopupMenu::show (int itemIDThatMustBeVisible, int minimumWidth,
int maximumNumColumns, int standardItemHeight,
ModalComponentManager::Callback* callback)
{
return showWithOptionalCallback (Options().withItemThatMustBeVisible (itemIDThatMustBeVisible)
@@ -1702,10 +1692,9 @@ int PopupMenu::show (const int itemIDThatMustBeVisible,
callback, true);
}
int PopupMenu::showAt (const Rectangle<int>& screenAreaToAttachTo,
const int itemIDThatMustBeVisible,
const int minimumWidth, const int maximumNumColumns,
const int standardItemHeight,
int PopupMenu::showAt (Rectangle<int> screenAreaToAttachTo,
int itemIDThatMustBeVisible, int minimumWidth,
int maximumNumColumns, int standardItemHeight,
ModalComponentManager::Callback* callback)
{
return showWithOptionalCallback (Options().withTargetScreenArea (screenAreaToAttachTo)
@@ -1717,15 +1706,14 @@ int PopupMenu::showAt (const Rectangle<int>& screenAreaToAttachTo,
}
int PopupMenu::showAt (Component* componentToAttachTo,
const int itemIDThatMustBeVisible,
const int minimumWidth, const int maximumNumColumns,
const int standardItemHeight,
int itemIDThatMustBeVisible, int minimumWidth,
int maximumNumColumns, int standardItemHeight,
ModalComponentManager::Callback* callback)
{
Options options (Options().withItemThatMustBeVisible (itemIDThatMustBeVisible)
.withMinimumWidth (minimumWidth)
.withMaximumNumColumns (maximumNumColumns)
.withStandardItemHeight (standardItemHeight));
auto options = Options().withItemThatMustBeVisible (itemIDThatMustBeVisible)
.withMinimumWidth (minimumWidth)
.withMaximumNumColumns (maximumNumColumns)
.withStandardItemHeight (standardItemHeight);
if (componentToAttachTo != nullptr)
options = options.withTargetComponent (componentToAttachTo);
@@ -1793,8 +1781,7 @@ void PopupMenu::setLookAndFeel (LookAndFeel* const newLookAndFeel)
//==============================================================================
PopupMenu::CustomComponent::CustomComponent (bool autoTrigger)
: isHighlighted (false),
triggeredAutomatically (autoTrigger)
: triggeredAutomatically (autoTrigger)
{
}
@@ -1835,9 +1822,8 @@ PopupMenu::CustomCallback::CustomCallback() {}
PopupMenu::CustomCallback::~CustomCallback() {}
//==============================================================================
PopupMenu::MenuItemIterator::MenuItemIterator (const PopupMenu& m, bool searchR) : searchRecursively (searchR)
PopupMenu::MenuItemIterator::MenuItemIterator (const PopupMenu& m, bool recurse) : searchRecursively (recurse)
{
currentItem = nullptr;
index.add (0);
menus.add (&m);
}


+ 24
- 24
modules/juce_gui_basics/menus/juce_PopupMenu.h View File

@@ -89,19 +89,19 @@ public:
PopupMenu();
/** Creates a copy of another menu. */
PopupMenu (const PopupMenu& other);
PopupMenu (const PopupMenu&);
/** Destructor. */
~PopupMenu();
/** Copies this menu from another one. */
PopupMenu& operator= (const PopupMenu& other);
PopupMenu& operator= (const PopupMenu&);
/** Move constructor */
PopupMenu (PopupMenu&& other) noexcept;
PopupMenu (PopupMenu&&) noexcept;
/** Move assignment operator */
PopupMenu& operator= (PopupMenu&& other) noexcept;
PopupMenu& operator= (PopupMenu&&) noexcept;
//==============================================================================
/** Resets the menu, removing all its items. */
@@ -125,8 +125,8 @@ public:
/** The menu item's name. */
String text;
/** The menu item's ID. This can not be 0 if you want the item to be triggerable! */
int itemID;
/** The menu item's ID. This must not be 0 if you want the item to be triggerable! */
int itemID = 0;
/** A sub-menu, or nullptr if there isn't one. */
ScopedPointer<PopupMenu> subMenu;
@@ -141,7 +141,7 @@ public:
ReferenceCountedObjectPtr<CustomCallback> customCallback;
/** A command manager to use to automatically invoke the command, or nullptr if none is specified. */
ApplicationCommandManager* commandManager;
ApplicationCommandManager* commandManager = nullptr;
/** An optional string describing the shortcut key for this item.
This is only used for displaying at the right-hand edge of a menu item - the
@@ -157,16 +157,16 @@ public:
Colour colour;
/** True if this menu item is enabled. */
bool isEnabled;
bool isEnabled = true;
/** True if this menu item should have a tick mark next to it. */
bool isTicked;
bool isTicked = false;
/** True if this menu item is a separator line. */
bool isSeparator;
bool isSeparator = false;
/** True if this menu item is a section header. */
bool isSectionHeader;
bool isSectionHeader = false;
};
/** Adds an item to the menu.
@@ -247,8 +247,6 @@ public:
const String& displayName = String(),
Drawable* iconToUse = nullptr);
/** Appends a text item with a special colour.
This is the same as addItem(), but specifies a colour to use for the
@@ -389,11 +387,14 @@ public:
{
public:
Options();
Options (const Options&) = default;
Options& operator= (const Options&) = default;
//==============================================================================
Options withTargetComponent (Component* targetComponent) const noexcept;
Options withTargetScreenArea (const Rectangle<int>& targetArea) const noexcept;
Options withTargetScreenArea (Rectangle<int> targetArea) const noexcept;
Options withMinimumWidth (int minWidth) const noexcept;
Options withMinimumNumColumns (int minNumColumns) const noexcept;
Options withMaximumNumColumns (int maxNumColumns) const noexcept;
Options withStandardItemHeight (int standardHeight) const noexcept;
Options withItemThatMustBeVisible (int idOfItemToBeVisible) const noexcept;
@@ -405,17 +406,16 @@ public:
Rectangle<int> 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; }
private:
//==============================================================================
friend class PopupMenu;
friend class PopupMenu::Window;
Rectangle<int> targetArea;
Component* targetComponent;
Component* parentComponent;
int visibleItemID, minWidth, maxColumns, standardHeight;
Component* targetComponent = nullptr;
Component* parentComponent = nullptr;
int visibleItemID = 0, minWidth = 0, minColumns = 1, maxColumns = 0, standardHeight = 0;
};
//==============================================================================
@@ -473,7 +473,7 @@ public:
@see show()
*/
int showAt (const Rectangle<int>& screenAreaToAttachTo,
int showAt (Rectangle<int> screenAreaToAttachTo,
int itemIDThatMustBeVisible = 0,
int minimumWidth = 0,
int maximumNumColumns = 0,
@@ -585,9 +585,9 @@ public:
//==============================================================================
bool searchRecursively;
Array <int> index;
Array <const PopupMenu*> menus;
PopupMenu::Item *currentItem;
Array<int> index;
Array<const PopupMenu*> menus;
PopupMenu::Item* currentItem = nullptr;
MenuItemIterator& operator= (const MenuItemIterator&);
JUCE_LEAK_DETECTOR (MenuItemIterator)
@@ -638,7 +638,7 @@ public:
private:
//==============================================================================
bool isHighlighted, triggeredAutomatically;
bool isHighlighted = false, triggeredAutomatically;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomComponent)
};


Loading…
Cancel
Save