Browse Source

Added some PopupMenu::addItem overloads which let you attach a lambda callback to be invoked for a menu item.

tags/2021-05-28
jules 6 years ago
parent
commit
0367d5c3a9
7 changed files with 214 additions and 138 deletions
  1. +1
    -1
      modules/juce_core/maths/juce_NormalisableRange.h
  2. +13
    -1
      modules/juce_events/messages/juce_MessageManager.cpp
  3. +1
    -15
      modules/juce_events/messages/juce_MessageManager.h
  4. +137
    -73
      modules/juce_gui_basics/menus/juce_PopupMenu.cpp
  5. +41
    -27
      modules/juce_gui_basics/menus/juce_PopupMenu.h
  6. +1
    -1
      modules/juce_gui_basics/widgets/juce_Toolbar.cpp
  7. +20
    -20
      modules/juce_gui_extra/misc/juce_KeyMappingEditorComponent.cpp

+ 1
- 1
modules/juce_core/maths/juce_NormalisableRange.h View File

@@ -195,7 +195,7 @@ public:
} }
/** Takes a non-normalised value and snaps it based on either the interval property of /** Takes a non-normalised value and snaps it based on either the interval property of
this NormalisedRange or the lambda function supplied to the constructor.
this NormalisableRange or the lambda function supplied to the constructor.
*/ */
ValueType snapToLegalValue (ValueType v) const noexcept ValueType snapToLegalValue (ValueType v) const noexcept
{ {


+ 13
- 1
modules/juce_events/messages/juce_MessageManager.cpp View File

@@ -164,7 +164,7 @@ private:
JUCE_DECLARE_NON_COPYABLE (AsyncFunctionCallback) JUCE_DECLARE_NON_COPYABLE (AsyncFunctionCallback)
}; };
void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* const func, void* const parameter)
void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* func, void* parameter)
{ {
if (isThisTheMessageThread()) if (isThisTheMessageThread())
return func (parameter); return func (parameter);
@@ -184,6 +184,18 @@ void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* cons
return nullptr; return nullptr;
} }
void MessageManager::callAsync (std::function<void()> fn)
{
struct AsyncCallInvoker : public MessageBase
{
AsyncCallInvoker (std::function<void()> f) : callback (std::move (f)) { post(); }
void messageCallback() override { callback(); }
std::function<void()> callback;
};
new AsyncCallInvoker (std::move (fn));
}
//============================================================================== //==============================================================================
void MessageManager::deliverBroadcastMessage (const String& value) void MessageManager::deliverBroadcastMessage (const String& value)
{ {


+ 1
- 15
modules/juce_events/messages/juce_MessageManager.h View File

@@ -95,11 +95,7 @@ public:
//============================================================================== //==============================================================================
/** Asynchronously invokes a function or C++11 lambda on the message thread. */ /** Asynchronously invokes a function or C++11 lambda on the message thread. */
template <typename FunctionType>
static void callAsync (FunctionType&& functionToCall)
{
new AsyncCallInvoker<FunctionType> (std::forward<FunctionType> (functionToCall));
}
static void callAsync (std::function<void()> functionToCall);
/** Calls a function using the message-thread. /** Calls a function using the message-thread.
@@ -340,16 +336,6 @@ private:
static void doPlatformSpecificShutdown(); static void doPlatformSpecificShutdown();
static bool dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages); static bool dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages);
template <typename FunctionType>
struct AsyncCallInvoker : public MessageBase
{
AsyncCallInvoker (FunctionType&& f) : callback (std::forward<FunctionType> (f)) { post(); }
void messageCallback() override { callback(); }
FunctionType callback;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AsyncCallInvoker)
};
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MessageManager) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MessageManager)
}; };


+ 137
- 73
modules/juce_gui_basics/menus/juce_PopupMenu.cpp View File

@@ -223,12 +223,12 @@ struct MenuWindow : public Component
setOpaque (lf.findColour (PopupMenu::backgroundColourId).isOpaque() setOpaque (lf.findColour (PopupMenu::backgroundColourId).isOpaque()
|| ! Desktop::canUseSemiTransparentWindows()); || ! Desktop::canUseSemiTransparentWindows());
for (int i = 0; i < menu.items.size(); ++i)
for (size_t i = 0; i < menu.items.size(); ++i)
{ {
auto item = menu.items.getUnchecked (i);
auto& item = menu.items[i];
if (i < menu.items.size() - 1 || ! item->isSeparator)
items.add (new ItemComponent (*item, options.getStandardItemHeight(), *this));
if (i + 1 < menu.items.size() || ! item.isSeparator)
items.add (new ItemComponent (item, options.getStandardItemHeight(), *this));
} }
auto targetArea = options.getTargetScreenArea() / scaleFactor; auto targetArea = options.getTargetScreenArea() / scaleFactor;
@@ -323,10 +323,15 @@ struct MenuWindow : public Component
*managerOfChosenCommand = item->commandManager; *managerOfChosenCommand = item->commandManager;
} }
exitModalState (getResultItemID (item));
auto resultID = getResultItemID (item);
if (makeInvisible && (deletionChecker != nullptr))
exitModalState (resultID);
if (makeInvisible && deletionChecker != nullptr)
setVisible (false); setVisible (false);
if (resultID != 0 && item != nullptr && item->action != nullptr)
MessageManager::callAsync (item->action);
} }
} }
@@ -1262,42 +1267,36 @@ PopupMenu::PopupMenu()
} }
PopupMenu::PopupMenu (const PopupMenu& other) PopupMenu::PopupMenu (const PopupMenu& other)
: lookAndFeel (other.lookAndFeel)
: items (other.items),
lookAndFeel (other.lookAndFeel)
{ {
items.addCopiesOf (other.items);
} }
PopupMenu& PopupMenu::operator= (const PopupMenu& other) PopupMenu& PopupMenu::operator= (const PopupMenu& other)
{ {
if (this != &other) if (this != &other)
{ {
items = other.items;
lookAndFeel = other.lookAndFeel; lookAndFeel = other.lookAndFeel;
clear();
items.addCopiesOf (other.items);
} }
return *this; return *this;
} }
PopupMenu::PopupMenu (PopupMenu&& other) noexcept PopupMenu::PopupMenu (PopupMenu&& other) noexcept
: lookAndFeel (other.lookAndFeel)
: items (std::move (other.items)),
lookAndFeel (std::move (other.lookAndFeel))
{ {
items.swapWith (other.items);
} }
PopupMenu& PopupMenu::operator= (PopupMenu&& other) noexcept PopupMenu& PopupMenu::operator= (PopupMenu&& other) noexcept
{ {
jassert (this != &other); // hopefully the compiler should make this situation impossible!
items.swapWith (other.items);
items = std::move (other.items);
lookAndFeel = other.lookAndFeel; lookAndFeel = other.lookAndFeel;
return *this; return *this;
} }
PopupMenu::~PopupMenu()
{
}
PopupMenu::~PopupMenu() = default;
void PopupMenu::clear() void PopupMenu::clear()
{ {
@@ -1305,13 +1304,54 @@ void PopupMenu::clear()
} }
//============================================================================== //==============================================================================
PopupMenu::Item::Item() noexcept
PopupMenu::Item::Item() = default;
#if JUCE_MSVC && _MSC_VER < 1900 // tedious VC2013 workaround
PopupMenu::Item::Item (Item&& other)
: text (std::move (other.text)),
itemID (other.itemID),
action (std::move (other.action)),
subMenu (std::move (other.subMenu)),
image (std::move (other.image)),
customComponent (std::move (other.customComponent)),
customCallback (std::move (other.customCallback)),
commandManager (other.commandManager),
shortcutKeyDescription (std::move (other.shortcutKeyDescription)),
colour (other.colour),
isEnabled (other.isEnabled),
isTicked (other.isTicked),
isSeparator (other.isSeparator),
isSectionHeader (other.isSectionHeader)
{ {
} }
PopupMenu::Item& PopupMenu::Item::operator= (Item&& other)
{
text = std::move (other.text);
itemID = other.itemID;
action = std::move (other.action);
subMenu = std::move (other.subMenu);
image = std::move (other.image);
customComponent = std::move (other.customComponent);
customCallback = std::move (other.customCallback);
commandManager = other.commandManager;
shortcutKeyDescription = std::move (other.shortcutKeyDescription);
colour = other.colour;
isEnabled = other.isEnabled;
isTicked = other.isTicked;
isSeparator = other.isSeparator;
isSectionHeader = other.isSectionHeader;
return *this;
}
#else
PopupMenu::Item::Item (Item&&) = default;
PopupMenu::Item& PopupMenu::Item::operator= (Item&&) = default;
#endif
PopupMenu::Item::Item (const Item& other) PopupMenu::Item::Item (const Item& other)
: text (other.text), : text (other.text),
itemID (other.itemID), itemID (other.itemID),
action (other.action),
subMenu (createCopyIfNotNull (other.subMenu.get())), subMenu (createCopyIfNotNull (other.subMenu.get())),
image (other.image != nullptr ? other.image->createCopy() : nullptr), image (other.image != nullptr ? other.image->createCopy() : nullptr),
customComponent (other.customComponent), customComponent (other.customComponent),
@@ -1330,6 +1370,7 @@ PopupMenu::Item& PopupMenu::Item::operator= (const Item& other)
{ {
text = other.text; text = other.text;
itemID = other.itemID; itemID = other.itemID;
action = other.action;
subMenu.reset (createCopyIfNotNull (other.subMenu.get())); subMenu.reset (createCopyIfNotNull (other.subMenu.get()));
image = other.image != nullptr ? other.image->createCopy() : std::unique_ptr<Drawable>(); image = other.image != nullptr ? other.image->createCopy() : std::unique_ptr<Drawable>();
customComponent = other.customComponent; customComponent = other.customComponent;
@@ -1344,7 +1385,7 @@ PopupMenu::Item& PopupMenu::Item::operator= (const Item& other)
return *this; return *this;
} }
void PopupMenu::addItem (const Item& newItem)
void PopupMenu::addItem (Item newItem)
{ {
// An ID of 0 is used as a return value to indicate that the user // An ID of 0 is used as a return value to indicate that the user
// didn't pick anything, so you shouldn't use it as the ID for an item.. // didn't pick anything, so you shouldn't use it as the ID for an item..
@@ -1352,17 +1393,33 @@ void PopupMenu::addItem (const Item& newItem)
|| newItem.isSeparator || newItem.isSectionHeader || newItem.isSeparator || newItem.isSectionHeader
|| newItem.subMenu != nullptr); || newItem.subMenu != nullptr);
items.add (new Item (newItem));
items.push_back (std::move (newItem));
}
void PopupMenu::addItem (String itemText, std::function<void()> action)
{
addItem (std::move (itemText), true, false, std::move (action));
} }
void PopupMenu::addItem (int itemResultID, const String& itemText, bool isActive, bool isTicked)
void PopupMenu::addItem (String itemText, bool isActive, bool isTicked, std::function<void()> action)
{ {
Item i; Item i;
i.text = itemText;
i.text = std::move (itemText);
i.action = std::move (action);
i.itemID = -1;
i.isEnabled = isActive;
i.isTicked = isTicked;
addItem (std::move (i));
}
void PopupMenu::addItem (int itemResultID, String itemText, bool isActive, bool isTicked)
{
Item i;
i.text = std::move (itemText);
i.itemID = itemResultID; i.itemID = itemResultID;
i.isEnabled = isActive; i.isEnabled = isActive;
i.isTicked = isTicked; i.isTicked = isTicked;
addItem (i);
addItem (std::move (i));
} }
static std::unique_ptr<Drawable> createDrawableFromImage (const Image& im) static std::unique_ptr<Drawable> createDrawableFromImage (const Image& im)
@@ -1377,26 +1434,26 @@ static std::unique_ptr<Drawable> createDrawableFromImage (const Image& im)
return {}; return {};
} }
void PopupMenu::addItem (int itemResultID, const String& itemText, bool isActive, bool isTicked, const Image& iconToUse)
void PopupMenu::addItem (int itemResultID, String itemText, bool isActive, bool isTicked, const Image& iconToUse)
{ {
addItem (itemResultID, itemText, isActive, isTicked, createDrawableFromImage (iconToUse));
addItem (itemResultID, std::move (itemText), isActive, isTicked, createDrawableFromImage (iconToUse));
} }
void PopupMenu::addItem (int itemResultID, const String& itemText, bool isActive,
void PopupMenu::addItem (int itemResultID, String itemText, bool isActive,
bool isTicked, std::unique_ptr<Drawable> iconToUse) bool isTicked, std::unique_ptr<Drawable> iconToUse)
{ {
Item i; Item i;
i.text = itemText;
i.text = std::move (itemText);
i.itemID = itemResultID; i.itemID = itemResultID;
i.isEnabled = isActive; i.isEnabled = isActive;
i.isTicked = isTicked; i.isTicked = isTicked;
i.image = std::move (iconToUse); i.image = std::move (iconToUse);
addItem (i);
addItem (std::move (i));
} }
void PopupMenu::addCommandItem (ApplicationCommandManager* commandManager, void PopupMenu::addCommandItem (ApplicationCommandManager* commandManager,
const CommandID commandID, const CommandID commandID,
const String& displayName,
String displayName,
std::unique_ptr<Drawable> iconToUse) std::unique_ptr<Drawable> iconToUse)
{ {
jassert (commandManager != nullptr && commandID != 0); jassert (commandManager != nullptr && commandID != 0);
@@ -1407,40 +1464,40 @@ void PopupMenu::addCommandItem (ApplicationCommandManager* commandManager,
auto* target = commandManager->getTargetForCommand (commandID, info); auto* target = commandManager->getTargetForCommand (commandID, info);
Item i; Item i;
i.text = displayName.isNotEmpty() ? displayName : info.shortName;
i.text = displayName.isNotEmpty() ? std::move (displayName) : info.shortName;
i.itemID = (int) commandID; i.itemID = (int) commandID;
i.commandManager = commandManager; i.commandManager = commandManager;
i.isEnabled = target != nullptr && (info.flags & ApplicationCommandInfo::isDisabled) == 0; i.isEnabled = target != nullptr && (info.flags & ApplicationCommandInfo::isDisabled) == 0;
i.isTicked = (info.flags & ApplicationCommandInfo::isTicked) != 0; i.isTicked = (info.flags & ApplicationCommandInfo::isTicked) != 0;
i.image = std::move (iconToUse); i.image = std::move (iconToUse);
addItem (i);
addItem (std::move (i));
} }
} }
void PopupMenu::addColouredItem (int itemResultID, const String& itemText, Colour itemTextColour,
void PopupMenu::addColouredItem (int itemResultID, String itemText, Colour itemTextColour,
bool isActive, bool isTicked, std::unique_ptr<Drawable> iconToUse) bool isActive, bool isTicked, std::unique_ptr<Drawable> iconToUse)
{ {
Item i; Item i;
i.text = itemText;
i.text = std::move (itemText);
i.itemID = itemResultID; i.itemID = itemResultID;
i.colour = itemTextColour; i.colour = itemTextColour;
i.isEnabled = isActive; i.isEnabled = isActive;
i.isTicked = isTicked; i.isTicked = isTicked;
i.image = std::move (iconToUse); i.image = std::move (iconToUse);
addItem (i);
addItem (std::move (i));
} }
void PopupMenu::addColouredItem (int itemResultID, const String& itemText, Colour itemTextColour,
void PopupMenu::addColouredItem (int itemResultID, String itemText, Colour itemTextColour,
bool isActive, bool isTicked, const Image& iconToUse) bool isActive, bool isTicked, const Image& iconToUse)
{ {
Item i; Item i;
i.text = itemText;
i.text = std::move (itemText);
i.itemID = itemResultID; i.itemID = itemResultID;
i.colour = itemTextColour; i.colour = itemTextColour;
i.isEnabled = isActive; i.isEnabled = isActive;
i.isTicked = isTicked; i.isTicked = isTicked;
i.image = createDrawableFromImage (iconToUse); i.image = createDrawableFromImage (iconToUse);
addItem (i);
addItem (std::move (i));
} }
void PopupMenu::addCustomItem (int itemResultID, CustomComponent* cc, const PopupMenu* subMenu) void PopupMenu::addCustomItem (int itemResultID, CustomComponent* cc, const PopupMenu* subMenu)
@@ -1449,7 +1506,7 @@ void PopupMenu::addCustomItem (int itemResultID, CustomComponent* cc, const Popu
i.itemID = itemResultID; i.itemID = itemResultID;
i.customComponent = cc; i.customComponent = cc;
i.subMenu.reset (createCopyIfNotNull (subMenu)); i.subMenu.reset (createCopyIfNotNull (subMenu));
addItem (i);
addItem (std::move (i));
} }
void PopupMenu::addCustomItem (int itemResultID, Component* customComponent, int idealWidth, int idealHeight, void PopupMenu::addCustomItem (int itemResultID, Component* customComponent, int idealWidth, int idealHeight,
@@ -1461,46 +1518,47 @@ void PopupMenu::addCustomItem (int itemResultID, Component* customComponent, int
subMenu); subMenu);
} }
void PopupMenu::addSubMenu (const String& subMenuName, const PopupMenu& subMenu, bool isActive)
void PopupMenu::addSubMenu (String subMenuName, PopupMenu subMenu, bool isActive)
{ {
addSubMenu (subMenuName, subMenu, isActive, nullptr, false, 0);
addSubMenu (std::move (subMenuName), std::move (subMenu), isActive, nullptr, false, 0);
} }
void PopupMenu::addSubMenu (const String& subMenuName, const PopupMenu& subMenu, bool isActive,
void PopupMenu::addSubMenu (String subMenuName, PopupMenu subMenu, bool isActive,
const Image& iconToUse, bool isTicked, int itemResultID) const Image& iconToUse, bool isTicked, int itemResultID)
{ {
addSubMenu (subMenuName, subMenu, isActive, createDrawableFromImage (iconToUse), isTicked, itemResultID);
addSubMenu (std::move (subMenuName), std::move (subMenu), isActive,
createDrawableFromImage (iconToUse), isTicked, itemResultID);
} }
void PopupMenu::addSubMenu (const String& subMenuName, const PopupMenu& subMenu, bool isActive,
void PopupMenu::addSubMenu (String subMenuName, PopupMenu subMenu, bool isActive,
std::unique_ptr<Drawable> iconToUse, bool isTicked, int itemResultID) std::unique_ptr<Drawable> iconToUse, bool isTicked, int itemResultID)
{ {
Item i; Item i;
i.text = subMenuName;
i.text = std::move (subMenuName);
i.itemID = itemResultID; i.itemID = itemResultID;
i.subMenu.reset (new PopupMenu (subMenu));
i.isEnabled = isActive && (itemResultID != 0 || subMenu.getNumItems() > 0); i.isEnabled = isActive && (itemResultID != 0 || subMenu.getNumItems() > 0);
i.subMenu.reset (new PopupMenu (std::move (subMenu)));
i.isTicked = isTicked; i.isTicked = isTicked;
i.image = std::move (iconToUse); i.image = std::move (iconToUse);
addItem (i);
addItem (std::move (i));
} }
void PopupMenu::addSeparator() void PopupMenu::addSeparator()
{ {
if (items.size() > 0 && ! items.getLast()->isSeparator)
if (items.size() > 0 && ! items.back().isSeparator)
{ {
Item i; Item i;
i.isSeparator = true; i.isSeparator = true;
addItem (i);
addItem (std::move (i));
} }
} }
void PopupMenu::addSectionHeader (const String& title)
void PopupMenu::addSectionHeader (String title)
{ {
Item i; Item i;
i.text = title;
i.text = std::move (title);
i.isSectionHeader = true; i.isSectionHeader = true;
addItem (i);
addItem (std::move (i));
} }
//============================================================================== //==============================================================================
@@ -1579,11 +1637,11 @@ PopupMenu::Options PopupMenu::Options::withPreferredPopupDirection (PopupDirecti
Component* PopupMenu::createWindow (const Options& options, Component* PopupMenu::createWindow (const Options& options,
ApplicationCommandManager** managerOfChosenCommand) const ApplicationCommandManager** managerOfChosenCommand) const
{ {
return items.isEmpty() ? nullptr
: new HelperClasses::MenuWindow (*this, nullptr, options,
! options.getTargetScreenArea().isEmpty(),
ModifierKeys::currentModifiers.isAnyMouseButtonDown(),
managerOfChosenCommand);
return items.empty() ? nullptr
: new HelperClasses::MenuWindow (*this, nullptr, options,
! options.getTargetScreenArea().isEmpty(),
ModifierKeys::currentModifiers.isAnyMouseButtonDown(),
managerOfChosenCommand);
} }
//============================================================================== //==============================================================================
@@ -1627,8 +1685,9 @@ struct PopupMenuCompletionCallback : public ModalComponentManager::Callback
JUCE_DECLARE_NON_COPYABLE (PopupMenuCompletionCallback) JUCE_DECLARE_NON_COPYABLE (PopupMenuCompletionCallback)
}; };
int PopupMenu::showWithOptionalCallback (const Options& options, ModalComponentManager::Callback* const userCallback,
const bool canBeModal)
int PopupMenu::showWithOptionalCallback (const Options& options,
ModalComponentManager::Callback* userCallback,
bool canBeModal)
{ {
std::unique_ptr<ModalComponentManager::Callback> userCallbackDeleter (userCallback); std::unique_ptr<ModalComponentManager::Callback> userCallbackDeleter (userCallback);
std::unique_ptr<PopupMenuCompletionCallback> callback (new PopupMenuCompletionCallback()); std::unique_ptr<PopupMenuCompletionCallback> callback (new PopupMenuCompletionCallback());
@@ -1664,6 +1723,11 @@ int PopupMenu::showMenu (const Options& options)
} }
#endif #endif
void PopupMenu::showMenuAsync (const Options& options)
{
showWithOptionalCallback (options, nullptr, false);
}
void PopupMenu::showMenuAsync (const Options& options, ModalComponentManager::Callback* userCallback) void PopupMenu::showMenuAsync (const Options& options, ModalComponentManager::Callback* userCallback)
{ {
#if ! JUCE_MODAL_LOOPS_PERMITTED #if ! JUCE_MODAL_LOOPS_PERMITTED
@@ -1743,8 +1807,8 @@ int PopupMenu::getNumItems() const noexcept
{ {
int num = 0; int num = 0;
for (auto* mi : items)
if (! mi->isSeparator)
for (auto& mi : items)
if (! mi.isSeparator)
++num; ++num;
return num; return num;
@@ -1752,9 +1816,9 @@ int PopupMenu::getNumItems() const noexcept
bool PopupMenu::containsCommandItem (const int commandID) const bool PopupMenu::containsCommandItem (const int commandID) const
{ {
for (auto* mi : items)
if ((mi->itemID == commandID && mi->commandManager != nullptr)
|| (mi->subMenu != nullptr && mi->subMenu->containsCommandItem (commandID)))
for (auto& mi : items)
if ((mi.itemID == commandID && mi.commandManager != nullptr)
|| (mi.subMenu != nullptr && mi.subMenu->containsCommandItem (commandID)))
return true; return true;
return false; return false;
@@ -1762,14 +1826,14 @@ bool PopupMenu::containsCommandItem (const int commandID) const
bool PopupMenu::containsAnyActiveItems() const noexcept bool PopupMenu::containsAnyActiveItems() const noexcept
{ {
for (auto* mi : items)
for (auto& mi : items)
{ {
if (mi->subMenu != nullptr)
if (mi.subMenu != nullptr)
{ {
if (mi->subMenu->containsAnyActiveItems())
if (mi.subMenu->containsAnyActiveItems())
return true; return true;
} }
else if (mi->isEnabled)
else if (mi.isEnabled)
{ {
return true; return true;
} }
@@ -1832,14 +1896,14 @@ PopupMenu::MenuItemIterator::MenuItemIterator (const PopupMenu& m, bool recurse)
menus.add (&m); menus.add (&m);
} }
PopupMenu::MenuItemIterator::~MenuItemIterator() {}
PopupMenu::MenuItemIterator::~MenuItemIterator() = default;
bool PopupMenu::MenuItemIterator::next() bool PopupMenu::MenuItemIterator::next()
{ {
if (index.size() == 0 || menus.getLast()->items.size() == 0) if (index.size() == 0 || menus.getLast()->items.size() == 0)
return false; return false;
currentItem = menus.getLast()->items.getUnchecked (index.getLast());
currentItem = const_cast<PopupMenu::Item*> (&(menus.getLast()->items[(size_t) index.getLast()]));
if (searchRecursively && currentItem->subMenu != nullptr) if (searchRecursively && currentItem->subMenu != nullptr)
{ {
@@ -1851,7 +1915,7 @@ bool PopupMenu::MenuItemIterator::next()
index.setUnchecked (index.size() - 1, index.getLast() + 1); index.setUnchecked (index.size() - 1, index.getLast() + 1);
} }
while (index.size() > 0 && index.getLast() >= menus.getLast()->items.size())
while (index.size() > 0 && index.getLast() >= (int) menus.getLast()->items.size())
{ {
index.removeLast(); index.removeLast();
menus.removeLast(); menus.removeLast();
@@ -1863,7 +1927,7 @@ bool PopupMenu::MenuItemIterator::next()
return true; return true;
} }
PopupMenu::Item& PopupMenu::MenuItemIterator::getItem() const noexcept
PopupMenu::Item& PopupMenu::MenuItemIterator::getItem() const
{ {
jassert (currentItem != nullptr); jassert (currentItem != nullptr);
return *(currentItem); return *(currentItem);


+ 41
- 27
modules/juce_gui_basics/menus/juce_PopupMenu.h View File

@@ -79,13 +79,7 @@ namespace juce
*/ */
class JUCE_API PopupMenu class JUCE_API PopupMenu
{ {
private:
class Window;
public: public:
class CustomComponent;
class CustomCallback;
//============================================================================== //==============================================================================
/** Creates an empty popup menu. */ /** Creates an empty popup menu. */
PopupMenu(); PopupMenu();
@@ -105,6 +99,10 @@ public:
/** Move assignment operator */ /** Move assignment operator */
PopupMenu& operator= (PopupMenu&&) noexcept; PopupMenu& operator= (PopupMenu&&) noexcept;
//==============================================================================
class CustomComponent;
class CustomCallback;
//============================================================================== //==============================================================================
/** Resets the menu, removing all its items. */ /** Resets the menu, removing all its items. */
void clear(); void clear();
@@ -116,13 +114,12 @@ public:
You'll need to set some fields after creating an Item before you You'll need to set some fields after creating an Item before you
can add it to a PopupMenu can add it to a PopupMenu
*/ */
Item() noexcept;
Item();
/** Creates a copy of an item. */
Item (const Item&); Item (const Item&);
/** Creates a copy of an item. */
Item& operator= (const Item&); Item& operator= (const Item&);
Item (Item&&);
Item& operator= (Item&&);
/** The menu item's name. */ /** The menu item's name. */
String text; String text;
@@ -130,6 +127,9 @@ public:
/** The menu item's ID. This must not be 0 if you want the item to be triggerable! */ /** The menu item's ID. This must not be 0 if you want the item to be triggerable! */
int itemID = 0; int itemID = 0;
/** An optional function which should be invoked when this menu item is triggered. */
std::function<void()> action;
/** A sub-menu, or nullptr if there isn't one. */ /** A sub-menu, or nullptr if there isn't one. */
std::unique_ptr<PopupMenu> subMenu; std::unique_ptr<PopupMenu> subMenu;
@@ -175,7 +175,17 @@ public:
You can call this method for full control over the item that is added, or use the other You can call this method for full control over the item that is added, or use the other
addItem helper methods if you want to pass arguments rather than creating an Item object. addItem helper methods if you want to pass arguments rather than creating an Item object.
*/ */
void addItem (const Item& newItem);
void addItem (Item newItem);
/** Adds an item to the menu with an action callback. */
void addItem (String itemText,
std::function<void()> action);
/** Adds an item to the menu with an action callback. */
void addItem (String itemText,
bool isEnabled,
bool isTicked,
std::function<void()> action);
/** Appends a new text item for this menu to show. /** Appends a new text item for this menu to show.
@@ -190,7 +200,7 @@ public:
@see addSeparator, addColouredItem, addCustomItem, addSubMenu @see addSeparator, addColouredItem, addCustomItem, addSubMenu
*/ */
void addItem (int itemResultID, void addItem (int itemResultID,
const String& itemText,
String itemText,
bool isEnabled = true, bool isEnabled = true,
bool isTicked = false); bool isTicked = false);
@@ -208,7 +218,7 @@ public:
@see addSeparator, addColouredItem, addCustomItem, addSubMenu @see addSeparator, addColouredItem, addCustomItem, addSubMenu
*/ */
void addItem (int itemResultID, void addItem (int itemResultID,
const String& itemText,
String itemText,
bool isEnabled, bool isEnabled,
bool isTicked, bool isTicked,
const Image& iconToUse); const Image& iconToUse);
@@ -228,7 +238,7 @@ public:
@see addSeparator, addColouredItem, addCustomItem, addSubMenu @see addSeparator, addColouredItem, addCustomItem, addSubMenu
*/ */
void addItem (int itemResultID, void addItem (int itemResultID,
const String& itemText,
String itemText,
bool isEnabled, bool isEnabled,
bool isTicked, bool isTicked,
std::unique_ptr<Drawable> iconToUse); std::unique_ptr<Drawable> iconToUse);
@@ -246,7 +256,7 @@ public:
*/ */
void addCommandItem (ApplicationCommandManager* commandManager, void addCommandItem (ApplicationCommandManager* commandManager,
CommandID commandID, CommandID commandID,
const String& displayName = String(),
String displayName = {},
std::unique_ptr<Drawable> iconToUse = {}); std::unique_ptr<Drawable> iconToUse = {});
/** Appends a text item with a special colour. /** Appends a text item with a special colour.
@@ -256,11 +266,11 @@ public:
current look-and-feel. See addItem() for a description of the parameters. current look-and-feel. See addItem() for a description of the parameters.
*/ */
void addColouredItem (int itemResultID, void addColouredItem (int itemResultID,
const String& itemText,
String itemText,
Colour itemTextColour, Colour itemTextColour,
bool isEnabled = true, bool isEnabled = true,
bool isTicked = false, bool isTicked = false,
const Image& iconToUse = Image());
const Image& iconToUse = {});
/** Appends a text item with a special colour. /** Appends a text item with a special colour.
@@ -269,7 +279,7 @@ public:
current look-and-feel. See addItem() for a description of the parameters. current look-and-feel. See addItem() for a description of the parameters.
*/ */
void addColouredItem (int itemResultID, void addColouredItem (int itemResultID,
const String& itemText,
String itemText,
Colour itemTextColour, Colour itemTextColour,
bool isEnabled, bool isEnabled,
bool isTicked, bool isTicked,
@@ -314,8 +324,8 @@ public:
If the itemResultID argument is non-zero, then the sub-menu item itself can be If the itemResultID argument is non-zero, then the sub-menu item itself can be
clicked to trigger it as a command. clicked to trigger it as a command.
*/ */
void addSubMenu (const String& subMenuName,
const PopupMenu& subMenu,
void addSubMenu (String subMenuName,
PopupMenu subMenu,
bool isEnabled = true); bool isEnabled = true);
/** Appends a sub-menu with an icon. /** Appends a sub-menu with an icon.
@@ -324,8 +334,8 @@ public:
If the itemResultID argument is non-zero, then the sub-menu item itself can be If the itemResultID argument is non-zero, then the sub-menu item itself can be
clicked to trigger it as a command. clicked to trigger it as a command.
*/ */
void addSubMenu (const String& subMenuName,
const PopupMenu& subMenu,
void addSubMenu (String subMenuName,
PopupMenu subMenu,
bool isEnabled, bool isEnabled,
const Image& iconToUse, const Image& iconToUse,
bool isTicked = false, bool isTicked = false,
@@ -341,8 +351,8 @@ public:
the item. The menu will take ownership of this drawable object and will delete it the item. The menu will take ownership of this drawable object and will delete it
later when no longer needed later when no longer needed
*/ */
void addSubMenu (const String& subMenuName,
const PopupMenu& subMenu,
void addSubMenu (String subMenuName,
PopupMenu subMenu,
bool isEnabled, bool isEnabled,
std::unique_ptr<Drawable> iconToUse, std::unique_ptr<Drawable> iconToUse,
bool isTicked = false, bool isTicked = false,
@@ -360,7 +370,7 @@ public:
This is a bold-font items which can be used as a header to separate the items This is a bold-font items which can be used as a header to separate the items
into named groups. into named groups.
*/ */
void addSectionHeader (const String& title);
void addSectionHeader (String title);
/** Returns the number of items that the menu currently contains. /** Returns the number of items that the menu currently contains.
(This doesn't count separators). (This doesn't count separators).
@@ -509,6 +519,9 @@ public:
int showMenu (const Options& options); int showMenu (const Options& options);
#endif #endif
/** Runs the menu asynchronously. */
void showMenuAsync (const Options& options);
/** Runs the menu asynchronously, with a user-provided callback that will receive the result. */ /** Runs the menu asynchronously, with a user-provided callback that will receive the result. */
void showMenuAsync (const Options& options, void showMenuAsync (const Options& options,
ModalComponentManager::Callback* callback); ModalComponentManager::Callback* callback);
@@ -594,7 +607,7 @@ public:
/** Returns a reference to the description of the current item. /** Returns a reference to the description of the current item.
It is only valid to call this after next() has returned true! It is only valid to call this after next() has returned true!
*/ */
Item& getItem() const noexcept;
Item& getItem() const;
private: private:
//============================================================================== //==============================================================================
@@ -749,10 +762,11 @@ public:
private: private:
//============================================================================== //==============================================================================
JUCE_PUBLIC_IN_DLL_BUILD (struct HelperClasses) JUCE_PUBLIC_IN_DLL_BUILD (struct HelperClasses)
class Window;
friend struct HelperClasses; friend struct HelperClasses;
friend class MenuBarComponent; friend class MenuBarComponent;
OwnedArray<Item> items;
std::vector<Item> items;
WeakReference<LookAndFeel> lookAndFeel; WeakReference<LookAndFeel> lookAndFeel;
Component* createWindow (const Options&, ApplicationCommandManager**) const; Component* createWindow (const Options&, ApplicationCommandManager**) const;


+ 1
- 1
modules/juce_gui_basics/widgets/juce_Toolbar.cpp View File

@@ -543,7 +543,7 @@ void Toolbar::showMissingItems()
{ {
PopupMenu m; PopupMenu m;
m.addCustomItem (1, new MissingItemsComponent (*this, getThickness())); m.addCustomItem (1, new MissingItemsComponent (*this, getThickness()));
m.showMenuAsync (PopupMenu::Options().withTargetComponent (missingItemsButton.get()), [] (int) {});
m.showMenuAsync (PopupMenu::Options().withTargetComponent (missingItemsButton.get()));
} }
} }


+ 20
- 20
modules/juce_gui_extra/misc/juce_KeyMappingEditorComponent.cpp View File

@@ -30,8 +30,8 @@ namespace juce
class KeyMappingEditorComponent::ChangeKeyButton : public Button class KeyMappingEditorComponent::ChangeKeyButton : public Button
{ {
public: public:
ChangeKeyButton (KeyMappingEditorComponent& kec, const CommandID command,
const String& keyName, const int keyIndex)
ChangeKeyButton (KeyMappingEditorComponent& kec, CommandID command,
const String& keyName, int keyIndex)
: Button (keyName), : Button (keyName),
owner (kec), owner (kec),
commandID (command), commandID (command),
@@ -50,31 +50,31 @@ public:
keyNum >= 0 ? getName() : String()); keyNum >= 0 ? getName() : String());
} }
static void menuCallback (int result, ChangeKeyButton* button)
{
if (button != nullptr)
{
switch (result)
{
case 1: button->assignNewKey(); break;
case 2: button->owner.getMappings().removeKeyPress (button->commandID, button->keyNum); break;
default: break;
}
}
}
void clicked() override void clicked() override
{ {
if (keyNum >= 0) if (keyNum >= 0)
{ {
// existing key clicked..
Component::SafePointer<ChangeKeyButton> button (this);
PopupMenu m; PopupMenu m;
m.addItem (1, TRANS("Change this key-mapping"));
m.addItem (TRANS("Change this key-mapping"),
[button]
{
if (button != nullptr)
button.getComponent()->assignNewKey();
});
m.addSeparator(); m.addSeparator();
m.addItem (2, TRANS("Remove this key-mapping"));
m.showMenuAsync (PopupMenu::Options(),
ModalCallbackFunction::forComponent (menuCallback, this));
m.addItem (TRANS("Remove this key-mapping"),
[button]
{
if (button != nullptr)
button->owner.getMappings().removeKeyPress (button->commandID,
button->keyNum);
});
m.showMenuAsync (PopupMenu::Options().withTargetComponent (this));
} }
else else
{ {


Loading…
Cancel
Save