paulxstretch/deps/juce/examples/GUI/MenusDemo.h

524 lines
20 KiB
C
Raw Permalink Normal View History

/*
==============================================================================
This file is part of the JUCE examples.
Copyright (c) 2020 - Raw Material Software Limited
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES,
WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR
PURPOSE, ARE DISCLAIMED.
==============================================================================
*/
/*******************************************************************************
The block below describes the properties of this PIP. A PIP is a short snippet
of code that can be read by the Projucer and used to generate a JUCE project.
BEGIN_JUCE_PIP_METADATA
name: MenusDemo
version: 1.0.0
vendor: JUCE
website: http://juce.com
description: Showcases menu features.
dependencies: juce_core, juce_data_structures, juce_events, juce_graphics,
juce_gui_basics, juce_gui_extra
exporters: xcode_mac, vs2019, linux_make, androidstudio, xcode_iphone
moduleFlags: JUCE_STRICT_REFCOUNTEDPOINTER=1
type: Component
mainClass: MenusDemo
useLocalCopy: 1
END_JUCE_PIP_METADATA
*******************************************************************************/
#pragma once
#include "../Assets/DemoUtilities.h"
//==============================================================================
/**
This struct contains a header component that will be used when the burger menu
is enabled. It contains an icon that can be used to show the side panel containing
the menu.
*/
struct BurgerMenuHeader : public Component
{
BurgerMenuHeader (SidePanel& sp)
: sidePanel (sp)
{
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.onClick = [this] { showOrHide(); };
addAndMakeVisible (burgerButton);
}
~BurgerMenuHeader() override
{
sidePanel.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 ((float) getHeight() * 0.5f, Font::plain));
titleLabel.setBounds (r);
}
void showOrHide()
{
sidePanel.showOrHide (! sidePanel.isPanelShowing());
}
SidePanel& sidePanel;
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 ApplicationCommandTarget,
public MenuBarModel
{
public:
//==============================================================================
/** A list of the commands that this demo responds to. */
enum CommandIDs
{
menuPositionInsideWindow = 1,
menuPositionGlobalMenuBar,
menuPositionBurgerMenu,
outerColourRed,
outerColourGreen,
outerColourBlue,
innerColourRed,
innerColourGreen,
innerColourBlue
};
//==============================================================================
/** Represents the possible menu positions. */
enum class MenuBarPosition
{
window,
global,
burger
};
//==============================================================================
MenusDemo()
{
menuBar.reset (new MenuBarComponent (this));
addAndMakeVisible (menuBar.get());
setApplicationCommandManagerToWatch (&commandManager);
commandManager.registerAllCommandsForTarget (this);
// this ensures that commands invoked on the DemoRunner application are correctly
// forwarded to this demo
commandManager.setFirstCommandTarget (this);
// this lets the command manager use keypresses that arrive in our window to send out commands
addKeyListener (commandManager.getKeyMappings());
addChildComponent (menuHeader);
addAndMakeVisible (outerCommandTarget);
addAndMakeVisible (sidePanel);
setWantsKeyboardFocus (true);
setSize (500, 500);
}
~MenusDemo() override
{
#if JUCE_MAC
MenuBarModel::setMacMainMenu (nullptr);
#endif
commandManager.setFirstCommandTarget (nullptr);
}
void resized() override
{
auto b = getLocalBounds();
if (menuBarPosition == MenuBarPosition::window)
{
menuBar->setBounds (b.removeFromTop (LookAndFeel::getDefaultLookAndFeel()
.getDefaultMenuBarHeight()));
}
else if (menuBarPosition == MenuBarPosition::burger)
{
menuHeader.setBounds (b.removeFromTop (40));
}
outerCommandTarget.setBounds (b);
}
//==============================================================================
StringArray getMenuBarNames() override
{
return { "Menu Position", "Outer Colour", "Inner Colour" };
}
PopupMenu getMenuForIndex (int menuIndex, const String& /*menuName*/) override
{
PopupMenu menu;
if (menuIndex == 0)
{
menu.addCommandItem (&commandManager, CommandIDs::menuPositionInsideWindow);
#if JUCE_MAC
menu.addCommandItem (&commandManager, CommandIDs::menuPositionGlobalMenuBar);
#endif
menu.addCommandItem (&commandManager, CommandIDs::menuPositionBurgerMenu);
}
else if (menuIndex == 1)
{
menu.addCommandItem (&commandManager, CommandIDs::outerColourRed);
menu.addCommandItem (&commandManager, CommandIDs::outerColourGreen);
menu.addCommandItem (&commandManager, CommandIDs::outerColourBlue);
}
else if (menuIndex == 2)
{
menu.addCommandItem (&commandManager, CommandIDs::innerColourRed);
menu.addCommandItem (&commandManager, CommandIDs::innerColourGreen);
menu.addCommandItem (&commandManager, CommandIDs::innerColourBlue);
}
return menu;
}
void menuItemSelected (int /*menuItemID*/, int /*topLevelMenuIndex*/) override {}
//==============================================================================
// The following methods implement the ApplicationCommandTarget interface, allowing
// this window to publish a set of actions it can perform, and which can be mapped
// onto menus, keypresses, etc.
ApplicationCommandTarget* getNextCommandTarget() override
{
return &outerCommandTarget;
}
void getAllCommands (Array<CommandID>& c) override
{
Array<CommandID> commands { CommandIDs::menuPositionInsideWindow,
CommandIDs::menuPositionGlobalMenuBar,
CommandIDs::menuPositionBurgerMenu };
c.addArray (commands);
}
void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result) override
{
switch (commandID)
{
case CommandIDs::menuPositionInsideWindow:
result.setInfo ("Inside Window", "Places the menu bar inside the application window", "Menu", 0);
result.setTicked (menuBarPosition == MenuBarPosition::window);
result.addDefaultKeypress ('w', ModifierKeys::shiftModifier);
break;
case CommandIDs::menuPositionGlobalMenuBar:
result.setInfo ("Global", "Uses a global menu bar", "Menu", 0);
result.setTicked (menuBarPosition == MenuBarPosition::global);
result.addDefaultKeypress ('g', ModifierKeys::shiftModifier);
break;
case CommandIDs::menuPositionBurgerMenu:
result.setInfo ("Burger Menu", "Uses a burger menu", "Menu", 0);
result.setTicked (menuBarPosition == MenuBarPosition::burger);
result.addDefaultKeypress ('b', ModifierKeys::shiftModifier);
break;
default:
break;
}
}
bool perform (const InvocationInfo& info) override
{
switch (info.commandID)
{
case CommandIDs::menuPositionInsideWindow:
setMenuBarPosition (MenuBarPosition::window);
break;
case CommandIDs::menuPositionGlobalMenuBar:
setMenuBarPosition (MenuBarPosition::global);
break;
case CommandIDs::menuPositionBurgerMenu:
setMenuBarPosition (MenuBarPosition::burger);
break;
default:
return false;
}
return true;
}
void setMenuBarPosition (MenuBarPosition newPosition)
{
if (menuBarPosition != newPosition)
{
menuBarPosition = newPosition;
if (menuBarPosition != MenuBarPosition::burger)
sidePanel.showOrHide (false);
#if JUCE_MAC
MenuBarModel::setMacMainMenu (menuBarPosition == MenuBarPosition::global ? this : nullptr);
#endif
menuBar->setVisible (menuBarPosition == MenuBarPosition::window);
burgerMenu.setModel (menuBarPosition == MenuBarPosition::burger ? this : nullptr);
menuHeader.setVisible (menuBarPosition == MenuBarPosition::burger);
sidePanel.setContent (menuBarPosition == MenuBarPosition::burger ? &burgerMenu : nullptr, false);
menuItemsChanged();
resized();
}
}
private:
#if JUCE_DEMO_RUNNER
ApplicationCommandManager& commandManager = getGlobalCommandManager();
#else
ApplicationCommandManager commandManager;
#endif
std::unique_ptr<MenuBarComponent> menuBar;
MenuBarPosition menuBarPosition = MenuBarPosition::window;
SidePanel sidePanel { "Menu", 300, false };
BurgerMenuComponent burgerMenu;
BurgerMenuHeader menuHeader { sidePanel };
//==============================================================================
/**
Command messages that aren't handled in the main component will be passed
to this class to respond to.
*/
class OuterCommandTarget : public Component,
public ApplicationCommandTarget
{
public:
OuterCommandTarget (ApplicationCommandManager& m)
: commandManager (m),
innerCommandTarget (commandManager)
{
commandManager.registerAllCommandsForTarget (this);
addAndMakeVisible (innerCommandTarget);
}
void resized() override
{
innerCommandTarget.setBounds (getLocalBounds().reduced (50));
}
void paint (Graphics& g) override
{
g.fillAll (currentColour);
}
//==============================================================================
ApplicationCommandTarget* getNextCommandTarget() override
{
return &innerCommandTarget;
}
void getAllCommands (Array<CommandID>& c) override
{
Array<CommandID> commands { CommandIDs::outerColourRed,
CommandIDs::outerColourGreen,
CommandIDs::outerColourBlue };
c.addArray (commands);
}
void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result) override
{
switch (commandID)
{
case CommandIDs::outerColourRed:
result.setInfo ("Red", "Sets the outer colour to red", "Outer", 0);
result.setTicked (currentColour == Colours::red);
result.addDefaultKeypress ('r', ModifierKeys::commandModifier);
break;
case CommandIDs::outerColourGreen:
result.setInfo ("Green", "Sets the outer colour to green", "Outer", 0);
result.setTicked (currentColour == Colours::green);
result.addDefaultKeypress ('g', ModifierKeys::commandModifier);
break;
case CommandIDs::outerColourBlue:
result.setInfo ("Blue", "Sets the outer colour to blue", "Outer", 0);
result.setTicked (currentColour == Colours::blue);
result.addDefaultKeypress ('b', ModifierKeys::commandModifier);
break;
default:
break;
}
}
bool perform (const InvocationInfo& info) override
{
switch (info.commandID)
{
case CommandIDs::outerColourRed:
currentColour = Colours::red;
break;
case CommandIDs::outerColourGreen:
currentColour = Colours::green;
break;
case CommandIDs::outerColourBlue:
currentColour = Colours::blue;
break;
default:
return false;
}
repaint();
return true;
}
private:
//==============================================================================
/**
Command messages that aren't handled in the OuterCommandTarget will be passed
to this class to respond to.
*/
struct InnerCommandTarget : public Component,
public ApplicationCommandTarget
{
InnerCommandTarget (ApplicationCommandManager& m)
: commandManager (m)
{
commandManager.registerAllCommandsForTarget (this);
}
void paint (Graphics& g) override
{
g.fillAll (currentColour);
}
//==============================================================================
ApplicationCommandTarget* getNextCommandTarget() override
{
// this will return the next parent component that is an ApplicationCommandTarget
return findFirstTargetParentComponent();
}
void getAllCommands (Array<CommandID>& c) override
{
Array<CommandID> commands { CommandIDs::innerColourRed,
CommandIDs::innerColourGreen,
CommandIDs::innerColourBlue };
c.addArray (commands);
}
void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result) override
{
switch (commandID)
{
case CommandIDs::innerColourRed:
result.setInfo ("Red", "Sets the inner colour to red", "Inner", 0);
result.setTicked (currentColour == Colours::red);
result.addDefaultKeypress ('r', ModifierKeys::commandModifier | ModifierKeys::shiftModifier);
break;
case CommandIDs::innerColourGreen:
result.setInfo ("Green", "Sets the inner colour to green", "Inner", 0);
result.setTicked (currentColour == Colours::green);
result.addDefaultKeypress ('g', ModifierKeys::commandModifier | ModifierKeys::shiftModifier);
break;
case CommandIDs::innerColourBlue:
result.setInfo ("Blue", "Sets the inner colour to blue", "Inner", 0);
result.setTicked (currentColour == Colours::blue);
result.addDefaultKeypress ('b', ModifierKeys::commandModifier | ModifierKeys::shiftModifier);
break;
default:
break;
}
}
bool perform (const InvocationInfo& info) override
{
switch (info.commandID)
{
case CommandIDs::innerColourRed:
currentColour = Colours::red;
break;
case CommandIDs::innerColourGreen:
currentColour = Colours::green;
break;
case CommandIDs::innerColourBlue:
currentColour = Colours::blue;
break;
default:
return false;
}
repaint();
return true;
}
ApplicationCommandManager& commandManager;
Colour currentColour { Colours::blue };
};
ApplicationCommandManager& commandManager;
InnerCommandTarget innerCommandTarget;
Colour currentColour { Colours::red };
};
OuterCommandTarget outerCommandTarget { commandManager };
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MenusDemo)
};