Browse Source

Added a BurgerMenu component which will display your menus and menu items in a "burger" menu

tags/2021-05-28
hogliux 8 years ago
parent
commit
e2a0759ab3
10 changed files with 561 additions and 34 deletions
  1. +135
    -31
      examples/Demo/Source/Demos/WidgetsDemo.cpp
  2. +5
    -0
      examples/Demo/Source/Main.cpp
  3. +13
    -0
      examples/Demo/Source/MainWindow.cpp
  4. +2
    -0
      examples/Demo/Source/MainWindow.h
  5. +1
    -0
      modules/juce_gui_basics/juce_gui_basics.cpp
  6. +1
    -0
      modules/juce_gui_basics/juce_gui_basics.h
  7. +3
    -2
      modules/juce_gui_basics/layout/juce_SidePanel.h
  8. +294
    -0
      modules/juce_gui_basics/menus/juce_BurgerMenuComponent.cpp
  9. +106
    -0
      modules/juce_gui_basics/menus/juce_BurgerMenuComponent.h
  10. +1
    -1
      modules/juce_gui_basics/menus/juce_PopupMenu.cpp

+ 135
- 31
examples/Demo/Source/Demos/WidgetsDemo.cpp View File

@@ -1275,6 +1275,72 @@ private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DragAndDropDemo)
};
//==============================================================================
struct BurgerMenuHeader : public Component,
private Button::Listener
{
BurgerMenuHeader()
{
static const unsigned char burgerMenuPathData[]
= { 110,109,0,0,128,64,0,0,32,65,108,0,0,224,65,0,0,32,65,98,254,212,232,65,0,0,32,65,0,0,240,65,252,
169,17,65,0,0,240,65,0,0,0,65,98,0,0,240,65,8,172,220,64,254,212,232,65,0,0,192,64,0,0,224,65,0,0,
192,64,108,0,0,128,64,0,0,192,64,98,16,88,57,64,0,0,192,64,0,0,0,64,8,172,220,64,0,0,0,64,0,0,0,65,
98,0,0,0,64,252,169,17,65,16,88,57,64,0,0,32,65,0,0,128,64,0,0,32,65,99,109,0,0,224,65,0,0,96,65,108,
0,0,128,64,0,0,96,65,98,16,88,57,64,0,0,96,65,0,0,0,64,4,86,110,65,0,0,0,64,0,0,128,65,98,0,0,0,64,
254,212,136,65,16,88,57,64,0,0,144,65,0,0,128,64,0,0,144,65,108,0,0,224,65,0,0,144,65,98,254,212,232,
65,0,0,144,65,0,0,240,65,254,212,136,65,0,0,240,65,0,0,128,65,98,0,0,240,65,4,86,110,65,254,212,232,
65,0,0,96,65,0,0,224,65,0,0,96,65,99,109,0,0,224,65,0,0,176,65,108,0,0,128,64,0,0,176,65,98,16,88,57,
64,0,0,176,65,0,0,0,64,2,43,183,65,0,0,0,64,0,0,192,65,98,0,0,0,64,254,212,200,65,16,88,57,64,0,0,208,
65,0,0,128,64,0,0,208,65,108,0,0,224,65,0,0,208,65,98,254,212,232,65,0,0,208,65,0,0,240,65,254,212,
200,65,0,0,240,65,0,0,192,65,98,0,0,240,65,2,43,183,65,254,212,232,65,0,0,176,65,0,0,224,65,0,0,176,
65,99,101,0,0 };
Path p;
p.loadPathFromData (burgerMenuPathData, sizeof (burgerMenuPathData));
burgerButton.setShape (p, true, true, false);
burgerButton.addListener (this);
addAndMakeVisible (burgerButton);
}
~BurgerMenuHeader()
{
MainAppWindow::getSharedSidePanel().showOrHide (false);
}
private:
void paint (Graphics& g) override
{
auto titleBarBackgroundColour = getLookAndFeel().findColour (ResizableWindow::backgroundColourId)
.darker();
g.setColour (titleBarBackgroundColour);
g.fillRect (getLocalBounds());
}
void resized() override
{
auto r = getLocalBounds();
burgerButton.setBounds (r.removeFromRight (40).withSizeKeepingCentre (20, 20));
titleLabel.setFont (Font (getHeight() * 0.5f, Font::plain));
titleLabel.setBounds (r);
}
void buttonClicked (Button*) override
{
auto& panel = MainAppWindow::getSharedSidePanel();
panel.showOrHide (! panel.isPanelShowing());
}
Label titleLabel { "titleLabel", "JUCE Demo" };
ShapeButton burgerButton { "burgerButton", Colours::lightgrey, Colours::lightgrey, Colours::white };
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BurgerMenuHeader)
};
//==============================================================================
class MenusDemo : public Component,
public MenuBarModel,
@@ -1282,6 +1348,15 @@ class MenusDemo : public Component,
private Button::Listener
{
public:
//==============================================================================
enum MenuBarPosition
{
window,
globalMenuBar,
burger
};
//==============================================================================
MenusDemo()
{
addAndMakeVisible (menuBar = new MenuBarComponent (this));
@@ -1290,12 +1365,15 @@ public:
popupButton.setTriggeredOnMouseDown (true);
popupButton.addListener (this);
addAndMakeVisible (popupButton);
addChildComponent (menuHeader);
setApplicationCommandManagerToWatch (&MainAppWindow::getApplicationCommandManager());
}
~MenusDemo()
{
MainAppWindow::getSharedSidePanel().setContent (nullptr, false);
#if JUCE_MAC
MenuBarModel::setMacMainMenu (nullptr);
#endif
@@ -1307,7 +1385,13 @@ public:
void resized() override
{
Rectangle<int> area (getLocalBounds());
menuBar->setBounds (area.removeFromTop (LookAndFeel::getDefaultLookAndFeel().getDefaultMenuBarHeight()));
{
auto menuBarArea = area.removeFromTop (40);
menuBar->setBounds (menuBarArea.withHeight (LookAndFeel::getDefaultLookAndFeel().getDefaultMenuBarHeight()));
menuHeader.setBounds (menuBarArea);
}
area.removeFromTop (20);
area = area.removeFromTop (33);
@@ -1317,7 +1401,7 @@ public:
//==============================================================================
StringArray getMenuBarNames() override
{
return { "Demo", "Look-and-feel", "Tabs", "Misc" };
return { "Demo", "Look-and-feel", "Menus", "Tabs", "Misc" };
}
PopupMenu getMenuForIndex (int menuIndex, const String& /*menuName*/) override
@@ -1350,10 +1434,6 @@ public:
menu.addSeparator();
menu.addCommandItem (commandManager, MainAppWindow::useNativeTitleBar);
#if JUCE_MAC
menu.addItem (6000, "Use Native Menu Bar");
#endif
#if ! JUCE_LINUX
menu.addCommandItem (commandManager, MainAppWindow::goToKioskMode);
#endif
@@ -1372,6 +1452,14 @@ public:
}
}
else if (menuIndex == 2)
{
menu.addItem (6000, "Inside Window", true, menuBarPosition == window);
#if JUCE_MAC
menu.addItem (6001, "Global Menu Bar", true, menuBarPosition == globalMenuBar);
#endif
menu.addItem (6002, "Burger Menu", true, menuBarPosition == burger);
}
else if (menuIndex == 3)
{
if (TabbedComponent* tabs = findParentComponentOfClass<TabbedComponent>())
{
@@ -1381,7 +1469,7 @@ public:
menu.addItem (3003, "Tabs on Right", true, tabs->getOrientation() == TabbedButtonBar::TabsAtRight);
}
}
else if (menuIndex == 3)
else if (menuIndex == 4)
{
return getDummyPopupMenu();
}
@@ -1394,20 +1482,28 @@ public:
// most of our menu items are invoked automatically as commands, but we can handle the
// other special cases here..
if (menuItemID == 6000)
if (menuItemID >= 6000 && menuItemID < 7000)
{
#if JUCE_MAC
if (MenuBarModel::getMacMainMenu() != nullptr)
{
MenuBarModel::setMacMainMenu (nullptr);
menuBar->setModel (this);
}
else
auto newPosition = static_cast<MenuBarPosition> (menuItemID - 6000);
if (newPosition != menuBarPosition)
{
menuBar->setModel (nullptr);
MenuBarModel::setMacMainMenu (this);
menuBarPosition = newPosition;
if (menuBarPosition != burger)
MainAppWindow::getSharedSidePanel().showOrHide (false);
#if JUCE_MAC
MenuBarModel::setMacMainMenu (menuBarPosition == globalMenuBar ? this : nullptr);
#endif
menuBar->setModel (menuBarPosition == window ? this : nullptr);
menuBar->setVisible (menuBarPosition == window);
burgerMenu.setModel (menuBarPosition == burger ? this : nullptr);
menuHeader.setVisible (menuBarPosition == burger);
MainAppWindow::getSharedSidePanel().setContent (menuBarPosition == burger ? &burgerMenu : nullptr, false);
menuItemsChanged();
}
#endif
}
else if (menuItemID >= 3000 && menuItemID <= 3003)
{
@@ -1431,6 +1527,9 @@ public:
private:
TextButton popupButton;
ScopedPointer<MenuBarComponent> menuBar;
BurgerMenuComponent burgerMenu;
BurgerMenuHeader menuHeader;
MenuBarPosition menuBarPosition = window;
PopupMenu getDummyPopupMenu()
{
@@ -1443,21 +1542,24 @@ private:
m.addCustomItem (5, new CustomMenuComponent());
m.addSeparator();
for (int i = 0; i < 8; ++i)
if (menuBarPosition != burger)
{
PopupMenu subMenu;
for (int s = 0; s < 8; ++s)
for (int i = 0; i < 8; ++i)
{
PopupMenu subSubMenu;
PopupMenu subMenu;
for (int item = 0; item < 8; ++item)
subSubMenu.addItem (1000 + (i * s * item), "Item " + String (item + 1));
for (int s = 0; s < 8; ++s)
{
PopupMenu subSubMenu;
subMenu.addSubMenu ("Sub-sub menu " + String (s + 1), subSubMenu);
}
for (int item = 0; item < 8; ++item)
subSubMenu.addItem (1000 + (i * s * item), "Item " + String (item + 1));
m.addSubMenu ("Sub menu " + String (i + 1), subMenu);
subMenu.addSubMenu ("Sub-sub menu " + String (s + 1), subSubMenu);
}
m.addSubMenu ("Sub menu " + String (i + 1), subMenu);
}
}
return m;
@@ -1508,9 +1610,11 @@ private:
void timerCallback() override
{
Random random;
blobPosition.setBounds ((float) random.nextInt (getWidth()),
(float) random.nextInt (getHeight()),
40.0f, 30.0f);
if (! getBounds().isEmpty())
blobPosition.setBounds ((float) random.nextInt (getWidth()),
(float) random.nextInt (getHeight()),
40.0f, 30.0f);
repaint();
}


+ 5
- 0
examples/Demo/Source/Main.cpp View File

@@ -54,6 +54,11 @@ public:
mainWindow.reset();
}
void backButtonPressed() override
{
MainAppWindow::getSharedSidePanel().showOrHide (false);
}
//==============================================================================
void systemRequestedQuit() override
{


+ 13
- 0
examples/Demo/Source/MainWindow.cpp View File

@@ -124,6 +124,8 @@ public:
demoList.getViewport()->setScrollOnDragEnabled (true);
addAndMakeVisible (demoList);
addAndMakeVisible (sidePanel);
sidePanel.setAlwaysOnTop (true);
}
~ContentComponent()
@@ -246,9 +248,15 @@ public:
return currentDemo != nullptr && currentDemo->getName().contains ("OpenGL 2D");
}
SidePanel& getSharedSidePanel()
{
return sidePanel;
}
private:
ListBox demoList;
ScopedPointer<Component> currentDemo;
SidePanel sidePanel {"Menu", 300, false};
LookAndFeel_V1 lookAndFeelV1;
LookAndFeel_V2 lookAndFeelV2;
@@ -745,6 +753,11 @@ int MainAppWindow::getActiveRenderingEngine() const
return 0;
}
SidePanel& MainAppWindow::getSharedSidePanel()
{
return getMainAppWindow()->contentComponent->getSharedSidePanel();
}
Path MainAppWindow::getJUCELogoPath()
{
return Drawable::parseSVGPath (


+ 2
- 0
examples/Demo/Source/MainWindow.h View File

@@ -48,6 +48,8 @@ public:
// (returns a shared AudioDeviceManager object that all the demos can use)
static AudioDeviceManager& getSharedAudioDeviceManager();
static SidePanel& getSharedSidePanel();
StringArray getRenderingEngines() const;
int getActiveRenderingEngine() const;
void setRenderingEngine (int index);


+ 1
- 0
modules/juce_gui_basics/juce_gui_basics.cpp View File

@@ -215,6 +215,7 @@ namespace juce
#include "lookandfeel/juce_LookAndFeel_V3.cpp"
#include "lookandfeel/juce_LookAndFeel_V4.cpp"
#include "menus/juce_MenuBarComponent.cpp"
#include "menus/juce_BurgerMenuComponent.cpp"
#include "menus/juce_MenuBarModel.cpp"
#include "menus/juce_PopupMenu.cpp"
#include "positioning/juce_MarkerList.cpp"


+ 1
- 0
modules/juce_gui_basics/juce_gui_basics.h View File

@@ -248,6 +248,7 @@ namespace juce
#include "widgets/juce_ToolbarItemComponent.h"
#include "widgets/juce_ToolbarItemFactory.h"
#include "widgets/juce_ToolbarItemPalette.h"
#include "menus/juce_BurgerMenuComponent.h"
#include "buttons/juce_ToolbarButton.h"
#include "misc/juce_DropShadower.h"
#include "misc/juce_JUCESplashScreen.h"


+ 3
- 2
modules/juce_gui_basics/layout/juce_SidePanel.h View File

@@ -58,7 +58,8 @@ public:
the caller must manage the lifetime of the component
*/
SidePanel (StringRef title, int width, bool positionOnLeft,
Component* contentComponent = nullptr, bool deleteComponentWhenNoLongerNeeded = true);
Component* contentComponent = nullptr,
bool deleteComponentWhenNoLongerNeeded = true);
/** Destructor */
~SidePanel();
@@ -156,7 +157,7 @@ private:
OptionalScopedPointer<Component> contentComponent;
Label titleLabel;
ShapeButton dismissButton {"dismissButton", Colours::lightgrey, Colours::lightgrey, Colours::white};
ShapeButton dismissButton { "dismissButton", Colours::lightgrey, Colours::lightgrey, Colours::white };
Rectangle<int> shadowArea;


+ 294
- 0
modules/juce_gui_basics/menus/juce_BurgerMenuComponent.cpp View File

@@ -0,0 +1,294 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
struct CustomMenuBarItemHolder : public Component
{
CustomMenuBarItemHolder (const ReferenceCountedObjectPtr<PopupMenu::CustomComponent>& customComponent)
{
setInterceptsMouseClicks (false, true);
update (customComponent);
}
void update (const ReferenceCountedObjectPtr<PopupMenu::CustomComponent>& newComponent)
{
jassert (newComponent != nullptr);
if (newComponent != custom)
{
if (custom != nullptr)
removeChildComponent (custom);
custom = newComponent;
addAndMakeVisible (custom);
resized();
}
}
void resized() override
{
custom->setBounds (getLocalBounds());
}
ReferenceCountedObjectPtr<PopupMenu::CustomComponent> custom;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomMenuBarItemHolder)
};
//==============================================================================
BurgerMenuComponent::BurgerMenuComponent (MenuBarModel* modelToUse)
{
auto& lf = getLookAndFeel();
listBox.setRowHeight (roundToInt (lf.getPopupMenuFont().getHeight() * 2.0f));
listBox.addMouseListener (this, true);
setModel (modelToUse);
addAndMakeVisible (listBox);
}
BurgerMenuComponent::~BurgerMenuComponent()
{
if (model != nullptr)
model->removeListener (this);
}
void BurgerMenuComponent::setModel (MenuBarModel* newModel)
{
if (newModel != model)
{
if (model != nullptr)
model->removeListener (this);
model = newModel;
if (model != nullptr)
model->addListener (this);
refresh();
listBox.updateContent();
}
}
MenuBarModel* BurgerMenuComponent::getModel() const noexcept
{
return model;
}
void BurgerMenuComponent::refresh()
{
lastRowClicked = inputSourceIndexOfLastClick = -1;
rows.clear();
if (model != nullptr)
{
auto menuBarNames = model->getMenuBarNames();
for (auto menuIdx = 0; menuIdx < menuBarNames.size(); ++menuIdx)
{
PopupMenu::Item menuItem;
menuItem.text = menuBarNames[menuIdx];
String ignore;
auto menu = model->getMenuForIndex (menuIdx, ignore);
rows.add (Row { true, menuIdx, menuItem });
addMenuBarItemsForMenu (menu, menuIdx);
}
}
}
void BurgerMenuComponent::addMenuBarItemsForMenu (PopupMenu& menu, int menuIdx)
{
for (PopupMenu::MenuItemIterator it (menu); it.next();)
{
auto& item = it.getItem();
if (item.isSeparator)
continue;
if (hasSubMenu (item))
addMenuBarItemsForMenu (*item.subMenu, menuIdx);
else
rows.add (Row {false, menuIdx, it.getItem()});
}
}
int BurgerMenuComponent::getNumRows()
{
return rows.size();
}
void BurgerMenuComponent::paint (Graphics& g)
{
getLookAndFeel().drawPopupMenuBackground (g, getWidth(), getHeight());
}
void BurgerMenuComponent::paintListBoxItem (int rowIndex, Graphics& g, int w, int h, bool highlight)
{
auto& lf = getLookAndFeel();
Rectangle<int> r (w, h);
auto row = (rowIndex < rows.size() ? rows.getReference (rowIndex)
: Row { true, 0, {} });
g.fillAll (findColour (PopupMenu::backgroundColourId));
if (row.isMenuHeader)
{
lf.drawPopupMenuSectionHeader (g, r.reduced (20, 0), row.item.text);
g.setColour (Colours::grey);
g.fillRect (r.withHeight (1));
}
else
{
auto& item = row.item;
auto* colour = item.colour != Colour() ? &item.colour : nullptr;
if (item.customComponent == nullptr)
lf.drawPopupMenuItem (g, r.reduced (20, 0),
item.isSeparator,
item.isEnabled,
highlight,
item.isTicked,
hasSubMenu (item),
item.text,
item.shortcutKeyDescription,
item.image,
colour);
}
}
bool BurgerMenuComponent::hasSubMenu (const PopupMenu::Item& item)
{
return item.subMenu != nullptr && (item.itemID == 0 || item.subMenu->getNumItems() > 0);
}
void BurgerMenuComponent::listBoxItemClicked (int rowIndex, const MouseEvent& e)
{
auto row = rowIndex < rows.size() ? rows.getReference (rowIndex)
: Row { true, 0, {} };
if (! row.isMenuHeader)
{
lastRowClicked = rowIndex;
inputSourceIndexOfLastClick = e.source.getIndex();
}
}
Component* BurgerMenuComponent::refreshComponentForRow (int rowIndex, bool isRowSelected, Component* existing)
{
auto row = rowIndex < rows.size() ? rows.getReference (rowIndex)
: Row { true, 0, {} };
auto hasCustomComponent = (row.item.customComponent != nullptr);
if (existing == nullptr && hasCustomComponent)
return new CustomMenuBarItemHolder (row.item.customComponent);
if (existing != nullptr)
{
auto* componentToUpdate = dynamic_cast<CustomMenuBarItemHolder*> (existing);
jassert (componentToUpdate != nullptr);
if (hasCustomComponent && componentToUpdate != nullptr)
{
row.item.customComponent->setHighlighted (isRowSelected);
componentToUpdate->update (row.item.customComponent);
}
else
{
delete existing;
existing = nullptr;
}
}
return existing;
}
void BurgerMenuComponent::resized()
{
listBox.setBounds (getLocalBounds());
}
void BurgerMenuComponent::menuBarItemsChanged (MenuBarModel* menuBarModel)
{
setModel (menuBarModel);
}
void BurgerMenuComponent::menuCommandInvoked (MenuBarModel*, const ApplicationCommandTarget::InvocationInfo&)
{
}
void BurgerMenuComponent::mouseUp (const MouseEvent& event)
{
auto rowIndex = listBox.getSelectedRow();
if (rowIndex == lastRowClicked && rowIndex < rows.size()
&& event.source.getIndex() == inputSourceIndexOfLastClick)
{
auto& row = rows.getReference (rowIndex);
if (! row.isMenuHeader)
{
listBox.selectRow (-1);
lastRowClicked = -1;
inputSourceIndexOfLastClick = -1;
topLevelIndexClicked = row.topLevelMenuIndex;
auto& item = row.item;
if (auto* managerOfChosenCommand = item.commandManager)
{
ApplicationCommandTarget::InvocationInfo info (item.itemID);
info.invocationMethod = ApplicationCommandTarget::InvocationInfo::fromMenu;
managerOfChosenCommand->invoke (info, true);
}
postCommandMessage (item.itemID);
}
}
}
void BurgerMenuComponent::handleCommandMessage (int commandID)
{
if (model != nullptr)
{
model->menuItemSelected (commandID, topLevelIndexClicked);
topLevelIndexClicked = -1;
refresh();
listBox.updateContent();
}
}
} // namespace juce

+ 106
- 0
modules/juce_gui_basics/menus/juce_BurgerMenuComponent.h View File

@@ -0,0 +1,106 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A component which lists all menu items and groups them into categories
by their respective parent menus. This kind of component is often used
for so-called "burger" menus in mobile apps.
@see MenuBarModel
*/
//==============================================================================
class BurgerMenuComponent : public Component,
private ListBoxModel,
private MenuBarModel::Listener
{
public:
//==============================================================================
/** Creates a burger menu component.
@param model the model object to use to control this burger menu. You can
set the parameter or pass nullptr into this if you like,
and set the model later using the setModel() method.
@see setModel
*/
BurgerMenuComponent (MenuBarModel* model = nullptr);
/** Destructor. */
~BurgerMenuComponent();
//==============================================================================
/** Changes the model object to use to control the burger menu.
This can be a nullptr, in which case the bar will be empty. This object will not be
owned by the BurgerMenuComponent so it is up to you to manage its lifetime.
Don't delete the object that is passed-in while it's still being used by this MenuBar.
Any submenus in your MenuBarModel will be recursively flattened and added to the
top-level burger menu section.
*/
void setModel (MenuBarModel* newModel);
/** Returns the current burger menu model being used. */
MenuBarModel* getModel() const noexcept;
private:
//==============================================================================
struct Row
{
bool isMenuHeader;
int topLevelMenuIndex;
PopupMenu::Item item;
};
void refresh();
void paint (Graphics&) override;
int getNumRows() override;
void paintListBoxItem (int, Graphics&, int, int, bool) override;
void listBoxItemClicked (int, const MouseEvent&) override;
Component* refreshComponentForRow (int, bool, Component*) override;
void resized() override;
void menuBarItemsChanged (MenuBarModel*) override;
void menuCommandInvoked (MenuBarModel*, const ApplicationCommandTarget::InvocationInfo&) override;
void mouseUp (const MouseEvent&) override;
void handleCommandMessage (int) override;
void addMenuBarItemsForMenu (PopupMenu&, int);
static bool hasSubMenu (const PopupMenu::Item&);
//==============================================================================
MenuBarModel* model = nullptr;
ListBox listBox {"BurgerMenuListBox", this};
Array<Row> rows;
int lastRowClicked = -1, inputSourceIndexOfLastClick = -1, topLevelIndexClicked = -1;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BurgerMenuComponent)
};
} // namespace juce

+ 1
- 1
modules/juce_gui_basics/menus/juce_PopupMenu.cpp View File

@@ -44,7 +44,7 @@ class MenuWindow;
static bool canBeTriggered (const PopupMenu::Item& item) noexcept { return item.isEnabled && item.itemID != 0 && ! item.isSectionHeader; }
static bool hasActiveSubMenu (const PopupMenu::Item& item) noexcept { return item.isEnabled && item.subMenu != nullptr && item.subMenu->items.size() > 0; }
static const Colour* getColour (const PopupMenu::Item& item) noexcept { return item.colour != Colour (0x00000000) ? &item.colour : nullptr; }
static const Colour* getColour (const PopupMenu::Item& item) noexcept { return item.colour != Colour() ? &item.colour : nullptr; }
static bool hasSubMenu (const PopupMenu::Item& item) noexcept { return item.subMenu != nullptr && (item.itemID == 0 || item.subMenu->getNumItems() > 0); }
//==============================================================================


Loading…
Cancel
Save