This is an old revision of the document!
The VanillaJuceAudioProcessorEditor class defined in PluginEditor.h
is very simple, and little changed from what was automatically generated by the Projucer:
class VanillaJuceAudioProcessorEditor : public AudioProcessorEditor , public ChangeListener { public: VanillaJuceAudioProcessorEditor (VanillaJuceAudioProcessor&); ~VanillaJuceAudioProcessorEditor(); void paint (Graphics&) override; void resized() override; virtual void changeListenerCallback(ChangeBroadcaster* source); private: VanillaJuceAudioProcessor& processor; GuiTabs guiTabs; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VanillaJuceAudioProcessorEditor) };
The editor GUI is entirely built from JUCE Component-class objects. It consists of a single GuiTabs object (the guiTabs member variable above), which itself owns and contains all the other Components. As you'll see below, all of my Gui… classes take a SynthSound* pointer as a constructor argument, and implement a void notify() member function which gets called whenever any parameter is changed. Here is the entire PluginEditor.cpp
file (except for the #include
lines at the top):
VanillaJuceAudioProcessorEditor::VanillaJuceAudioProcessorEditor (VanillaJuceAudioProcessor& p) : AudioProcessorEditor (&p) , processor (p) , guiTabs(p.getSound()) { setSize (600, 400); addAndMakeVisible(&guiTabs); p.addChangeListener(this); } VanillaJuceAudioProcessorEditor::~VanillaJuceAudioProcessorEditor() { processor.removeChangeListener(this); } void VanillaJuceAudioProcessorEditor::paint (Graphics& g) { ignoreUnused(g); } void VanillaJuceAudioProcessorEditor::resized() { guiTabs.setBounds(0, 0, proportionOfWidth(1.0000f), proportionOfHeight(1.0000f)); } void VanillaJuceAudioProcessorEditor::changeListenerCallback(ChangeBroadcaster* source) { ignoreUnused(source); guiTabs.notify(); }
The constructor calls the processor's getSound() function to get a pointer to the one shared SynthSound object, which it passes to the constructor for guiTabs. It also sets the GUI window size, calls juce::Component::addAndMakeVisible() to add the tabs object as a child Component of the editor, and registers the editor as a change-listener to the processor. The destructor unregisters it.
The resized() function sets the bounds of the guiTabs object so it completely fills the editor window. As a consequence, the paint() function has nothing to do, because the tabs object will render the entire window contents.
The editor inherits from juce::ChangeListener, hence it implements changeListenerCallback(), which simply calls guiTabs.notify() (which will propagate the change notification to all of its child GUI components.)
The GuiTabs class is a container for a juce::TabbedComponent object, and three “tab” Components which are added to it:
class GuiTabs : public Component { public: GuiTabs (SynthSound* pSynthSound); ~GuiTabs(); void paint (Graphics& g) override; void resized() override; void notify(); private: ScopedPointer<TabbedComponent> tabbedComponent; GuiMainTab* pMainTab; GuiOscTab* pOscTab; GuiEgTab* pAmpEgTab; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GuiTabs) }; GuiTabs::GuiTabs (SynthSound* pSynthSound) { addAndMakeVisible (tabbedComponent = new TabbedComponent (TabbedButtonBar::TabsAtTop)); tabbedComponent->setTabBarDepth (32); tabbedComponent->addTab(TRANS("Main"), Colours::lightgrey, pMainTab = new GuiMainTab(pSynthSound), true); tabbedComponent->addTab (TRANS("Osc"), Colours::lightgrey, pOscTab = new GuiOscTab(pSynthSound), true); tabbedComponent->addTab(TRANS("AmpEG"), Colours::lightgrey, pAmpEgTab = new GuiEgTab(pSynthSound), true); tabbedComponent->setCurrentTabIndex(0); } GuiTabs::~GuiTabs() { // tabbedComponent will take care of deleting our tab objects tabbedComponent = nullptr; } //============================================================================== void GuiTabs::paint (Graphics& g) { g.fillAll (Colour (0xff323e44)); } void GuiTabs::resized() { tabbedComponent->setBounds (0, 0, proportionOfWidth (1.0000f), proportionOfHeight (1.0000f)); } void GuiTabs::notify() { pMainTab->notify(); pOscTab->notify(); pAmpEgTab->notify(); }
The constructor creates the tabbedComponent object and calls addAndMakeVisible() on it, sets the depth of the tabs bar to 32 pixels, creates the three tab objects and calls tabbedComponent→addTab, and sets the first (zeroth) tab to be the initially-selected one.