Tutorial

Declare a Signal:

Declaring a signal is really simple, just include the esignal file:

#include <esignal/Signal.hpp>

You can now declare your signals. We have basicly declare some basic signal type:

  • void
  • bool
  • std::string / std::u32string
  • int8_t / int16_t / int32_t / int64_t
  • uint8_t / uint16_t / uint32_t / uint64_t
  • float / double
  • vec2 / bvec2 / ivec2 / uivec2
  • vec3 / bvec3 / ivec3 / uivec3
  • etk::Color<unsigned char,4>
  • etk::Color<unsigned char,3>
  • etk::Color<float,4>
  • etk::Color<float,3>

To declare a signal with 'void' type:

esignal::Signal<> signalVoid;

To declare a signal with 'int32_t' type:

esignal::Signal<int32_t> signalInt;

To declare a signal with 'string' type:

esignal::Signal<std::string> signalString;

Connecting on a signal

We have some way to connect on a signals depending on where we do the connection.

Connection and basic emition

Declare the signal:

esignal::Signal<int32_t> signalValue;

Declare a generic fuction:

void localCallBack(int32_t _val) {
TEST_PRINT("Callback Local the value is : " << _val);
}

Connect a generic function:

esignal::Connection con1 = signalValue.connect(&localCallBack);

Or simply connect a lambda function:

esignal::Connection con2 = signalValue.connect(
[](int32_t _val) {
TEST_PRINT("Callback 1 the value is : " << _val);
});

And now, we can emit a simple signal:

signalValue.emit(1001001);

You can see that all connection return a esignal::Connection value. This is an handle that can not be copiable, but only movable, While this handle is alive, the connection is allive too. The to remove a connection, we only need to remive the handle or call the esignal::Connection::disconnect fucntion.

To disconnect a signal, it is very simple:

con1.disconnect();

This Will generate this simple sample code:

void localCallBack(int32_t _val) {
TEST_PRINT("Callback Local the value is : " << _val);
}
void basicConnection() {
// Create the signal
esignal::Signal<int32_t> signalValue;
// Connect the signal function
esignal::Connection con1 = signalValue.connect(&localCallBack);
// Connect the signal Lambda
esignal::Connection con2 = signalValue.connect(
[](int32_t _val) {
TEST_PRINT("Callback 1 the value is : " << _val);
});
// Emit the signal
signalValue.emit(1001001);
// Disconnect the connection n°1
con1.disconnect();
// Second emit to check disconnection
signalValue.emit(2002002);
}

Connection on class member function

Declare class fuction:

class TmpClass {
public:
void localCallBack(const int32_t& _val) {
TEST_PRINT("Callback Local the value is : " << _val);
}
void localCallBackSecond(const int32_t& _val, const std::string& _otherValue) {
TEST_PRINT("Callback 2 Local the value is : " << _val << " with perso: '" << _otherValue << "'");
}
};

For direct connection, you need to have a 'const ref' on the parameter (internal helper design) to bind on the signal

Now you can nonnect the functions:

esignal::Connection con1 = signalValue.connect(&myClass, &TmpClass::localCallBack);
esignal::Connection con2 = signalValue.connect(&myClass, &TmpClass::localCallBackSecond, "Hello, HowAreYou");

This Will generate this simple sample code:

class TmpClass {
public:
void localCallBack(const int32_t& _val) {
TEST_PRINT("Callback Local the value is : " << _val);
}
void localCallBackSecond(const int32_t& _val, const std::string& _otherValue) {
TEST_PRINT("Callback 2 Local the value is : " << _val << " with perso: '" << _otherValue << "'");
}
};
void classConnection() {
// Create the signal
esignal::Signal<int32_t> signalValue;
// Declare the class
TmpClass myClass;
// Connect signals
esignal::Connection con1 = signalValue.connect(&myClass, &TmpClass::localCallBack);
esignal::Connection con2 = signalValue.connect(&myClass, &TmpClass::localCallBackSecond, "Hello, HowAreYou");
// Emit sample signals
signalValue.emit(4004004);
}

Connection on ememory::SharedPtr<class> member function

ememory::SharedPtr have intrinsec knowledge of alive pointer, then, if you do not need to remove connection while the ememory::SharedPtr is alive, just connect it like:

void sharedConnection() {
// Create the signal
esignal::Signal<int32_t> signalValue;
// Declare the class
ememory::SharedPtr<TmpClass> myClassShared = ememory::makeShared<TmpClass>();
// Connect signals
signalValue.connect(myClassShared, &TmpClass::localCallBack);
// Emit sample signals
signalValue.emit(7007007);
}

Create new Signal

If the signal is not in the list: Declare a Signal: , you need to declare it yourself. This is due to optimise the compilation time, in C++ when we inserte many template with all the implementation, the compilation time increase, the we decide to optimise the build time.

Create a new custum signal:

esignal::Signal<int32_t, std::string> signalCustum;

Connect on the Signal:

esignal::Connection con2 = signalCustum.connect(
[](int32_t _val, std::string _val2) {
TEST_PRINT("lambda callback: " << _val << " vel2=" << _val2);
});

Emit a Signal:

signalCustum.emit(1001001, "plop");

This might work good, but at this point the compilation is OK, but not the linking ==> we need to declare the implementation of the signal:

#include <esignal/details/Signal.hxx>
ESIGNAL_DECLARE_SIGNAL(int32_t, std::string);

This Will generate this simple sample code:

void newSignal() {
// Declare new signal
esignal::Signal<int32_t, std::string> signalCustum;
// Connect a lambda
esignal::Connection con2 = signalCustum.connect(
[](int32_t _val, std::string _val2) {
TEST_PRINT("lambda callback: " << _val << " vel2=" << _val2);
});
// Example emit
signalCustum.emit(1001001, "plop");
}
// do it in a single C++: Implementation of signal
#include <esignal/details/Signal.hxx>
ESIGNAL_DECLARE_SIGNAL(int32_t, std::string);