Here is a means of replacing the buttonClicked() Button::Listener api with std::function<>. Thanks to @basteln for the template concepts in his varx addition.
First, a means of making sure only Buttons are passed to the template
#include <type_traits>
#include <functional>
#include <utility>
namespace Is_A {
template<typename T>
using IsButton = typename std::enable_if<std::is_base_of<juce::Button, T>::value>::type;
}
//a Generic declaration we can specialize just for Buttons
template<typename T, typename Enable = void> class LambdaComponent;
now the template similar to bastelnâs varx template to make juce components have React extensions
template<typename ButtonType>
class LambdaComponent<ButtonType, Is_A::IsButton<ButtonType>> : public ButtonType
{
public:
std::function<void(Button* b)> buttonClickedHandler; //this is the buttonClicked lambda
std::function<void(Button* b)> buttonStateChangedHandler; //this is the stateChanged lambda
template<typename... Args>
LambdaComponent(Args&&... args)
: ButtonType(std::forward<Args>(args)...), //this creates the button
listener(this, buttonClickedHandler, buttonStateChangedHandler ) //this creates the listener
{
this->addListener(&listener); //this links them
}
private:
class Listener : public ButtonType::Listener
{
public:
Listener(Button* targ,
std::function<void(Button* b)>& clickHandler,
std::function<void(Button* b)>& stateHandler)
: target(targ), buttonClickedHandler( clickHandler), buttonStateChangedHandler( stateHandler )
{}
~Listener()
{
if( target != nullptr ) target->removeListener(this); //this unlinks them
}
void buttonClicked(juce::Button *b) override
{ if( buttonClickedHandler ) { buttonClickedHandler(b); } }
void buttonStateChanged(juce::Button *b) override
{ if( buttonStateChangedHandler ) { buttonStateChangedHandler(b); } }
private:
Button* target{nullptr};
std::function<void(Button* b)>& buttonClickedHandler;
std::function<void(Button* b)>& buttonStateChangedHandler;
};
Listener listener;
};
usage example:
LambdaComponent<TextButton> textButton;
textButton.buttonClickedHandler = [this](Button*) { DBG( "you clicked the button " + this->textButton.getName() ); };
much easier than the whole ; Button::Listener::buttonClicked(Button* b) derived class, button.addListener(this); if( b == &button )⊠system currently in use!