Added a signal class.

This commit is contained in:
Relintai 2022-02-04 08:53:57 +01:00
parent b613349a11
commit d42311356f
2 changed files with 281 additions and 0 deletions

107
core/signal.cpp Normal file
View File

@ -0,0 +1,107 @@
#include "signal.h"
void Signal::connect_static(void (*func)(Signal *)) {
StaticSignalEntry *se = new StaticSignalEntry();
se->func = func;
entries.push_back(se);
}
void Signal::disconnect_static(void (*func)(Signal *)) {
for (int i = 0; i < entries.size(); ++i) {
SignalEntry *e = entries[i];
if (e->type == SIGNAL_ENTRY_TYPE_STATIC) {
StaticSignalEntry *se = static_cast<StaticSignalEntry *>(e);
if (se->func == func) {
entries.remove_keep_order(i);
return;
}
}
}
}
bool Signal::is_connected_static(void (*func)(Signal *)) {
for (int i = 0; i < entries.size(); ++i) {
SignalEntry *e = entries[i];
if (e->type == SIGNAL_ENTRY_TYPE_STATIC) {
StaticSignalEntry *se = static_cast<StaticSignalEntry *>(e);
if (se->func == func) {
return true;
}
}
}
return false;
}
void Signal::emit() {
for (int i = 0; i < entries.size(); ++i) {
entries[i]->call(this);
}
}
void Signal::emit(const Variant &p1) {
params.push_back(p1);
for (int i = 0; i < entries.size(); ++i) {
entries[i]->call(this);
}
params.clear();
}
void Signal::emit(const Variant &p1, const Variant &p2) {
params.push_back(p1);
params.push_back(p2);
for (int i = 0; i < entries.size(); ++i) {
entries[i]->call(this);
}
params.clear();
}
void Signal::emit(const Variant &p1, const Variant &p2, const Variant &p3) {
params.push_back(p1);
params.push_back(p2);
params.push_back(p3);
for (int i = 0; i < entries.size(); ++i) {
entries[i]->call(this);
}
params.clear();
}
void Signal::emit(const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4) {
params.push_back(p1);
params.push_back(p2);
params.push_back(p3);
params.push_back(p4);
for (int i = 0; i < entries.size(); ++i) {
entries[i]->call(this);
}
params.clear();
}
void Signal::emit(const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4, const Variant &p5) {
params.push_back(p1);
params.push_back(p2);
params.push_back(p3);
params.push_back(p4);
params.push_back(p5);
for (int i = 0; i < entries.size(); ++i) {
entries[i]->call(this);
}
params.clear();
}
Signal::Signal() :
Object() {
}
Signal::~Signal() {
}

174
core/signal.h Normal file
View File

@ -0,0 +1,174 @@
#ifndef SIGNAL_H
#define SIGNAL_H
#include "core/containers/vector.h"
#include "core/string.h"
#include "core/variant.h"
#include "reference.h"
class Signal : public Object {
RCPP_OBJECT(Signal, Object);
public:
Object *owner;
Vector<Variant> params;
Vector<Variant> static_data;
template <class T>
void connect(T *obj, void (*func)(T*, Signal *));
template <class T>
void disconnect(T *obj, void (*func)(T*, Signal *));
template <class T>
bool is_connected(T *obj, void (*func)(T*, Signal *));
void connect_static(void (*func)(Signal *));
void disconnect_static(void (*func)(Signal *));
bool is_connected_static(void (*func)(Signal *));
void emit();
void emit(const Variant &p1);
void emit(const Variant &p1, const Variant &p2);
void emit(const Variant &p1, const Variant &p2, const Variant &p3);
void emit(const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4);
void emit(const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4, const Variant &p5);
Signal();
~Signal();
protected:
enum SignalEntryType {
SIGNAL_ENTRY_TYPE_NONE = 0,
SIGNAL_ENTRY_TYPE_STATIC = 1,
SIGNAL_ENTRY_TYPE_CLASS = 2,
};
struct SignalEntry {
SignalEntryType type;
virtual void call(Signal *s) {
}
SignalEntry() {
type = SIGNAL_ENTRY_TYPE_NONE;
}
};
struct StaticSignalEntry : public SignalEntry {
void (*func)(Signal *);
virtual void call(Signal *s) {
func(s);
}
StaticSignalEntry() {
type = SIGNAL_ENTRY_TYPE_STATIC;
func = nullptr;
}
};
struct ClassSignalEntry : public SignalEntry {
virtual void* get_obj_ptr() {
return nullptr;
}
virtual void* get_func_ptr() {
return nullptr;
}
ClassSignalEntry() {
type = SIGNAL_ENTRY_TYPE_CLASS;
}
};
template<typename T>
struct ClassSignalEntrySpec : public ClassSignalEntry {
union {
T* obj;
void* obj_ptr;
};
union {
void (*func)(T*, Signal *);
void* func_ptr;
};
virtual void call(Signal *s) {
func(obj, s);
}
void* get_obj_ptr() {
return obj_ptr;
}
void* get_func_ptr() {
return func_ptr;
}
ClassSignalEntrySpec() {
obj = nullptr;
func = nullptr;
}
};
protected:
Vector<SignalEntry *> entries;
};
template <typename T>
void Signal::connect(T *obj, void (*func)(T*, Signal *)) {
ClassSignalEntrySpec<T> *ce = new ClassSignalEntrySpec<T>();
ce->obj = obj;
ce->func = func;
entries.push_back(ce);
}
template <typename T>
void Signal::disconnect(T *obj, void (*func)(T*, Signal *)) {
ClassSignalEntrySpec<T> t;
t.obj = obj;
t.func = func;
void* obj_ptr = t.obj_ptr;
void* func_ptr = t.func_ptr;
for (int i = 0; i < entries.size(); ++i) {
SignalEntry *e = entries[i];
if (e->type == SIGNAL_ENTRY_TYPE_CLASS) {
ClassSignalEntry *se = static_cast<ClassSignalEntry *>(e);
if (se->get_obj_ptr() == obj_ptr && se->get_func_ptr() == func_ptr) {
entries.remove_keep_order(i);
return;
}
}
}
}
template <typename T>
bool Signal::is_connected(T *obj, void (*func)(T*, Signal *)) {
ClassSignalEntrySpec<T> t;
t.obj = obj;
t.func = func;
void* obj_ptr = t.obj_ptr;
void* func_ptr = t.func_ptr;
for (int i = 0; i < entries.size(); ++i) {
SignalEntry *e = entries[i];
if (e->type == SIGNAL_ENTRY_TYPE_CLASS) {
ClassSignalEntry *se = static_cast<ClassSignalEntry *>(e);
if (se->get_obj_ptr() == obj_ptr && se->get_func_ptr() == func_ptr) {
return true;
}
}
}
return false;
}
#endif