#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 *emitter; Vector params; Vector static_data; template void connect(T *obj, void (*func)(T*, Signal *)); template void disconnect(T *obj, void (*func)(T*, Signal *)); template 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(Object *p_emitter); void emit(Object *p_emitter, const Variant &p1); void emit(Object *p_emitter, const Variant &p1, const Variant &p2); void emit(Object *p_emitter, const Variant &p1, const Variant &p2, const Variant &p3); void emit(Object *p_emitter, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4); void emit(Object *p_emitter, 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 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 entries; }; template void Signal::connect(T *obj, void (*func)(T*, Signal *)) { ClassSignalEntrySpec *ce = new ClassSignalEntrySpec(); ce->obj = obj; ce->func = func; entries.push_back(ce); } template void Signal::disconnect(T *obj, void (*func)(T*, Signal *)) { ClassSignalEntrySpec 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(e); if (se->get_obj_ptr() == obj_ptr && se->get_func_ptr() == func_ptr) { entries.remove_keep_order(i); return; } } } } template bool Signal::is_connected(T *obj, void (*func)(T*, Signal *)) { ClassSignalEntrySpec 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(e); if (se->get_obj_ptr() == obj_ptr && se->get_func_ptr() == func_ptr) { return true; } } } return false; } #endif