Hey Everyone,
Wow, thread really took off over night eh?
Thanks for all the advice, yah I had my terminology a bit mangled =P
So what I’m hearing above is that in principle I should be able to pass a pointer to the editor down through my component hierarchy from its constructor. Unfortunately, in my case, this just doesn’t work reliably.
To be more specific, in the editors constructor, I can pass a pointer to it to child components and they can use it fine in their constructor. But if the child components tried to send the same pointer to their child components, when those grand children components tried to use the pointer the plugin crashed.
Anyways I’ve managed to stabilize the app using an architecture I actually fell back on last time, it’s just been so long that I forgot the finer details and had to figure it out again the hard way. Can’t guarantee it won’t push your buttons either, but for now, it’s what’s letting me just get on with it.
I use an abstract class called LayoutComponent to handle passing the pointer down (and passing input back up):
LayoutComponent.h
// Conductor : Copyright ioFlow Studios 2021 //
#pragma once
// Forward declarations
class ConductorAudioProcessorEditor;
// Juce includes
#include <JuceHeader.h>
enum class eLayoutParentType
{
Editor,
Layout
};
class LayoutComponent : public juce::Component
{
public:
////////// ---------- Properties ---------- //////////
// anti juce torture mechanism
bool initEditor;
bool initParent;
ConductorAudioProcessorEditor* editor;
LayoutComponent* parent;
////////// ---------- Methods ---------- //////////
LayoutComponent();
~LayoutComponent() override;
void init(ConductorAudioProcessorEditor* argEditor, LayoutComponent* argParent);
virtual void initChildren() = 0;
virtual void input(String argComponentID, String argEventType, String argArgument) = 0;
virtual void paint (juce::Graphics&) = 0;
virtual void resized() = 0;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LayoutComponent)
};
layoutComponent.cpp
// Conductor : Copyright ioFlow Studios 2021 //
#include <JuceHeader.h>
#include "LayoutComponent.h"
// Forward declaration includes
#include "PluginEditor.h"
///////////////////
// //
// constructor //
// //
///////////////////
LayoutComponent::LayoutComponent()
{
initEditor = false;
initParent = false;
}
LayoutComponent::~LayoutComponent(){}
////////////
// //
// init //
// //
////////////
void LayoutComponent::init(ConductorAudioProcessorEditor* argEditor, LayoutComponent* argParent)
{
editor = argEditor;
initEditor = true;
parent = argParent;
initParent = true;
initChildren();
}
In my PluginEditors constructor I add the three top level LayoutComponents as per usual:
ConductorAudioProcessorEditor::ConductorAudioProcessorEditor (ConductorAudioProcessor& p)
: AudioProcessorEditor (&p), audioProcessor (p)
{
// add app layout components
addAndMakeVisible(header);
addAndMakeVisible(body);
addAndMakeVisible(footer);
They in turn add their child components in their constructor, but do NOTHING else.
Now my hierarchy is in place but completely inert and each component has an init method buried in it.
Back in the PluginEditor I use a timerCallback (which I needed anyway for tracking time from the daw) to only once trigger the init in the top level LayoutComponents AFTER the constructors have all done their thing. This cascades down through the hierarchy, now everyone has a pointer to PluginEditor and no one crashes 
/////////////////////
// //
// timerCallBack //
// //
/////////////////////
void ConductorAudioProcessorEditor::timerCallback()
{
// cascade editor references through the component hierarchy AFTER construction
if (!edInit)
{
debug("starting init cascade");
header.init(this, nullptr);
body.init(this, nullptr);
footer.init(this, nullptr);
edInit = true;
}
So it works, and I’m free and clear to do what I need to now, but I figured I’d post it all here for wiser C++ peoples than me to pick apart if it’s awful. If it’s not awful, maybe it might save someone else going through the grief I did getting it going.