Hi,
I’m trying to use setMacMainMenu with multiple DocumentWindows and I am running into all sorts of difficulty. For one, I’m not sure if I should be creating a single MenuBarModel, or one for each window. Secondly, in the latter case, it becomes very difficult to manage because calling setMacMainMenu(0) wipes out the menu for all windows. However, I don’t see how to make one MenuBarModel with all of its commands apply to each window.
In a semi-related issue, how does one ensure that a window responds to commands as soon as it is created. I’ve tried all sorts of things with grabKeyboardFocus, and the only thing that works for me is to start a timer that continually focuses the window until it is successful. Otherwise the user has to click inside the window first to get shortcuts to work. Simply calling grabKeyboardFocus in the constructor doesn’t work, of course, since the window is not visble yet, but nor does calling the method in something like repaint or resize.
Here’s the code (adapted from the hello world, using a single file and taking out MainComponent.cpp/h). You can use File->New to create a new window. See the HelloWorldWindow constructor and closeButtonPressed for the setMacMainMenu code.
#include "../JuceLibraryCode/JuceHeader.h"
juce::ApplicationCommandManager* acm = 0;
void makeNewWindow(void);
class MainComponent : public Component, public ButtonListener,
public ApplicationCommandTarget, public MenuBarModel
{
Label* helloWorldLabel;
TextButton* quitButton;
Path internalPath1;
public:
int MyIndex;
//Hello world stuff...
MainComponent() : helloWorldLabel (0), quitButton (0)
{
static int counter = 0;
MyIndex = ++counter;
addAndMakeVisible (helloWorldLabel = new Label (String::empty,
T("Hello World!")));
helloWorldLabel->setFont (Font (40.0000f, Font::bold));
helloWorldLabel->setJustificationType (Justification::centred);
helloWorldLabel->setEditable (false, false, false);
helloWorldLabel->setColour (Label::textColourId, Colours::black);
helloWorldLabel->setColour (TextEditor::textColourId, Colours::black);
helloWorldLabel->setColour (TextEditor::backgroundColourId, Colour (0x0));
addAndMakeVisible (quitButton = new TextButton (String::empty));
quitButton->setButtonText (T("Quit"));
quitButton->addListener (this);
addKeyListener(acm->getKeyMappings());
setSize (600, 300);
}
~MainComponent()
{
deleteAndZero (helloWorldLabel);
deleteAndZero (quitButton);
}
void paint (Graphics& g)
{
g.fillAll (Colour (0xffc1d0ff));
g.setColour (Colours::white);
g.fillPath (internalPath1);
g.setColour (Colour (0xff6f6f6f));
g.strokePath (internalPath1, PathStrokeType (5.2000f));
}
void resized()
{
helloWorldLabel->setBounds (152, 80, 296, 48);
quitButton->setBounds (getWidth() - 176, getHeight() - 60, 120, 32);
internalPath1.clear();
internalPath1.startNewSubPath (136.0f, 80.0f);
internalPath1.quadraticTo (176.0f, 24.0f, 328.0f, 32.0f);
internalPath1.quadraticTo (472.0f, 40.0f, 472.0f, 104.0f);
internalPath1.quadraticTo (472.0f, 192.0f, 232.0f, 176.0f);
internalPath1.lineTo (184.0f, 216.0f);
internalPath1.lineTo (200.0f, 168.0f);
internalPath1.quadraticTo (96.0f, 136.0f, 136.0f, 80.0f);
internalPath1.closeSubPath();
}
void buttonClicked (Button* buttonThatWasClicked)
{
if (buttonThatWasClicked == quitButton)
JUCEApplication::quit();
}
//Command stuff...
juce::ApplicationCommandTarget* getNextCommandTarget(void)
{
return findFirstTargetParentComponent();
}
void getAllCommands(juce::Array<juce::CommandID>& Commands)
{
Commands.add(0x1000);
Commands.add(0x2000);
Commands.add(0x3000);
Commands.add(0x4000);
}
juce::String getCommandNameFromID(const juce::CommandID ID)
{
std::cout << "getCommandNameFromID" << std::endl;
if(ID == 0x1000) return "New";
else if(ID == 0x2000) return "Open";
else if(ID == 0x3000) return "Copy";
else if(ID == 0x4000) return "Paste";
else return "Unknown";
}
void getShortcuts(const juce::CommandID ID,
juce::ApplicationCommandInfo& Info)
{
std::cout << "getShortcuts: " << ID << std::endl;
}
void getCommandInfo(juce::CommandID ID,
juce::ApplicationCommandInfo& Info)
{
if(ID == 0x1000) Info.shortName = "New";
else if(ID == 0x2000) Info.shortName = "Open";
else if(ID == 0x3000) Info.shortName = "Copy";
else if(ID == 0x4000) Info.shortName = "Paste";
if(ID == 0x1000)
Info.addDefaultKeypress('n', juce::ModifierKeys::commandModifier);
else if(ID == 0x2000)
Info.addDefaultKeypress('o', juce::ModifierKeys::commandModifier);
else if(ID == 0x3000)
Info.addDefaultKeypress('c', juce::ModifierKeys::commandModifier);
else if(ID == 0x4000)
Info.addDefaultKeypress('v', juce::ModifierKeys::commandModifier);
Info.setActive(true);
Info.setTicked(false);
std::cout << "getCommandInfo" << std::endl;
}
bool perform(const juce::ApplicationCommandTarget::InvocationInfo& Info)
{
if(Info.commandID == 0x1000)
makeNewWindow();
return true;
}
//Menu stuff...
const juce::StringArray getMenuBarNames(void)
{
if(MyIndex == 1)
{
const char* TopLevelMenus[3] = {"FileA", "EditA", 0};
return juce::StringArray(TopLevelMenus);
}
else
{
const char* TopLevelMenus[3] = {"FileB", "EditB", 0};
return juce::StringArray(TopLevelMenus);
}
}
const juce::PopupMenu getMenuForIndex(int Index, const juce::String& Name)
{
juce::PopupMenu Menu;
if(Name == "File")
{
Menu.addCommandItem(acm, 0x1000);
Menu.addCommandItem(acm, 0x2000);
}
else if(Name == "Edit")
{
Menu.addCommandItem(acm, 0x3000);
Menu.addCommandItem(acm, 0x4000);
}
return Menu;
}
void menuItemSelected(int ID, int TopLevelMenuIndex) {}
};
struct HelloWorldWindow : public DocumentWindow
{
HelloWorldWindow() : DocumentWindow (T("Menu Test"), Colours::lightgrey,
DocumentWindow::allButtons, true)
{
MainComponent* const contentComponent = new MainComponent();
acm->registerAllCommandsForTarget(contentComponent);
acm->registerAllCommandsForTarget(JUCEApplication::getInstance());
setContentComponent (contentComponent, true, true);
setBounds(contentComponent->MyIndex * 50, contentComponent->MyIndex * 50,
getWidth(), getHeight());
setVisible(true);
MenuBarModel::setMacMainMenu(contentComponent);
//setMenuBar(contentComponent);
contentComponent->setApplicationCommandManagerToWatch(acm);
}
void closeButtonPressed()
{
/*
//Scenario 1: After window is closed, click the main menu crashes the app.
delete this;
//*/
//*
//Scenario 2: After window closes, main menu disappers
MenuBarModel::setMacMainMenu(0);
delete this;
//*/
//*
//*/
//JUCEApplication::quit();
}
};
void makeNewWindow(void)
{
new HelloWorldWindow;
}
class JUCEHelloWorldApplication : public JUCEApplication
{
public:
void initialise (const String& commandLine)
{
acm = new juce::ApplicationCommandManager;
new HelloWorldWindow;
}
JUCEHelloWorldApplication() {}
void shutdown(){}
const String getApplicationName() {return "Menu Test";}
const String getApplicationVersion(){return "1.0";}
bool moreThanOneInstanceAllowed(){return true;}
void anotherInstanceStarted (const String& commandLine){}
};
START_JUCE_APPLICATION (JUCEHelloWorldApplication)
Thanks!
Andrew
