Not really sure whether I'm helping anyone here, as this is all excellent code that speaks for itself.
But it helps me to write it out, so hopefully it isn't annoying.
I'm going to keep tweaking these posts butuntil I'm happy with them.
π
If you look in main.cpp, in the constructor for JuceDemoApplication ...
class JuceDemoApplication : public JUCEApplication
{
public:
JuceDemoApplication() {}
//==============================================================================
void initialise (const String& commandLine) override
{
:
// Do your application's initialisation code here..
mainWindow = new MainAppWindow();
}
so, ... onto MainAppWindow ...
MainAppWindow::MainAppWindow()
: DocumentWindow (JUCEApplication::getInstance()->getApplicationName(),
Colours::lightgrey,
DocumentWindow::allButtons)
{
:
contentComponent = new ContentComponent();
:
}
... and now ContentComponent ...
class ContentComponent : public Component,
public ListBoxModel,
public ApplicationCommandTarget
{
public:
ContentComponent()
{
:
addAndMakeVisible (demoList);
:
demoList.selectRow (0);
}
void resized() override
{
Rectangle<int> r (getLocalBounds());
if (r.getWidth() > 600)
{
demoList.setBounds (r.removeFromLeft (210));
demoList.setRowHeight (20);
}
else
{
demoList.setBounds (r.removeFromLeft (130));
demoList.setRowHeight (30);
}
if (currentDemo != nullptr)
currentDemo->setBounds (r);
}
So, we get a main-window containing a content component.
This content component draws a list of demos on the left and the active demo on the right, and contains the logic for navigating the demo list -- you can hit a number 0 thru 9, use up&down arrows (both of these methods are classed as keyboard commands), or just click on the demo you want.
You can see that every time it gets resized, it splits its rectangle into DemoList (left) and space for the actual demo (right). If you click through removeFromLeft you can see that it cuts a strip from the left of the rectangle, reducing the original rectangle in-place and returning the strip.
The paintListBoxItem override speaks for itself. ContentComponent inherits from ListBoxModel, which triggers this function, and it's easy to see how a particular item gets drawn.
Now I'm looking into commands, seeing as that seems to be a large proportion of the code in MainWindow.cpp.
class MainAppWindow : public DocumentWindow,
private AsyncUpdater
{
public:
:
// (return the command manager object used to dispatch command events)
static ApplicationCommandManager& getApplicationCommandManager();
enum CommandIDs
{
showPreviousDemo = 0x2100,
showNextDemo = 0x2101,
welcome = 0x2000
:
};
That method is encapsulating a ...
static ScopedPointer<ApplicationCommandManager> applicationCommandManager;
and clicking through ApplicationCommandManager takes you to a complete documentation of commands. The idea is that you define your commands at the application level, so your app only has one command manager object. Often there are several different ways to activate a particular command: click, keyboard shortcut, menu, pop-up menu, icon, etc, so when you're designing a component you can choose which command(s) it responds to.
That's why these IDs are getting defined in the main window. Nothing to do with the main window per se, just that an app has only one main window, and we want just one command manager, so it makes some sense to stick them here.
Find all occurrences of "showPreviousDemo" in the workspace (double-click to select, right click -> "find selected text in workspace"), and you can see how it all fits together. You can see that this command gets assigned a hotkey, and when it is detected it calls moveDemoPages (-1); which cycles to the previous demo.
One thing I don't quite get is this:
class ContentComponent : public Component,
public ListBoxModel,
public ApplicationCommandTarget
{
private:
//==============================================================================
// 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.
:
void getAllCommands (Array<CommandID>& commands) override
{
// this returns the set of all commands that this target can perform..
const CommandID ids[] = { MainAppWindow::showPreviousDemo,
MainAppWindow::showNextDemo,
MainAppWindow::welcome,
Although the comment says that we let the window publish a set of commands it will listen out for, it seems to be our contentComponent that is feeding the command manager with every command that will exist in this app.
i.e. it is actually the ContentComponent not the MainAppWindow that inherits from ApplicationCommandTarget, and hence gets to choose which commands to listen out for and what to do when one of them triggers.
So I'm not really sure why the CommandIDs exist within MainAppWindow, not ContentComponent.
NOTE: this one is still in progress, I've nearly figured it out now... Going to rewrite later today