/* PIP - Platform Independent Primitives Object, base class of some PIP classes, provide EVENT -> EVENT_HANDLER mechanism Copyright (C) 2013 Ivan Pelipenko peri4ko@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PIOBJECT_H #define PIOBJECT_H #include "pistring.h" /// declare event handler \"event\" inside class \"obj\" with name \"name\", ret name() #define EVENT_HANDLER0(obj, ret, name) static ret __stat_eh_##name##__(void * o) {return ((obj*)o)->name();} ret name() #define EVENT_HANDLER1(obj, ret, name, a0, n0) static ret __stat_eh_##name##__(void * o, a0 n0) {return ((obj*)o)->name(n0);} ret name(a0 n0) #define EVENT_HANDLER2(obj, ret, name, a0, n0, a1, n1) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1) {return ((obj*)o)->name(n0, n1);} ret name(a0 n0, a1 n1) #define EVENT_HANDLER3(obj, ret, name, a0, n0, a1, n1, a2, n2) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1, a2 n2) {return ((obj*)o)->name(n0, n1, n2);} ret name(a0 n0, a1 n1, a2 n2) #define EVENT_HANDLER4(obj, ret, name, a0, n0, a1, n1, a2, n2, a3, n3) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1, a2 n2, a3 n3) {return ((obj*)o)->name(n0, n1, n2, n3);} ret name(a0 n0, a1 n1, a2 n2, a3 n3) #define EVENT_HANDLER EVENT_HANDLER0 /// declare virtual event handler \"event\" inside class \"obj\" with name \"name\", virtual ret name() #define EVENT_VHANDLER0(obj, ret, name) static ret __stat_eh_##name##__(void * o) {return ((obj*)o)->name();} virtual ret name() #define EVENT_VHANDLER1(obj, ret, name, a0, n0) static ret __stat_eh_##name##__(void * o, a0 n0) {return ((obj*)o)->name(n0);} virtual ret name(a0 n0) #define EVENT_VHANDLER2(obj, ret, name, a0, n0, a1, n1) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1) {return ((obj*)o)->name(n0, n1);} virtual ret name(a0 n0, a1 n1) #define EVENT_VHANDLER3(obj, ret, name, a0, n0, a1, n1, a2, n2) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1, a2 n2) {return ((obj*)o)->name(n0, n1, n2);} virtual ret name(a0 n0, a1 n1, a2 n2) #define EVENT_VHANDLER4(obj, ret, name, a0, n0, a1, n1, a2, n2, a3, n3) static ret __stat_eh_##name##__(void * o, a0 n0, a1 n1, a2 n2, a3 n3) {return ((obj*)o)->name(n0, n1, n2, n3);} virtual ret name(a0 n0, a1 n1, a2 n2, a3 n3) #define EVENT_VHANDLER EVENT_VHANDLER0 /// declare event \"event\" inside class \"obj\" with name \"name\", void name(); #define EVENT0(obj, name) EVENT_HANDLER0(obj, void, name) {PIObject::raiseEvent(this, #name);} #define EVENT1(obj, name, a0, n0) EVENT_HANDLER1(obj, void, name, a0, n0) {PIObject::raiseEvent(this, #name, n0);} #define EVENT2(obj, name, a0, n0, a1, n1) EVENT_HANDLER2(obj, void, name, a0, n0, a1, n1) {PIObject::raiseEvent(this, #name, n0, n1);} #define EVENT3(obj, name, a0, n0, a1, n1, a2, n2) EVENT_HANDLER3(obj, void, name, a0, n0, a1, n1, a2, n2) {PIObject::raiseEvent(this, #name, n0, n1, n2);} #define EVENT4(obj, name, a0, n0, a1, n1, a2, n2, a3, n3) EVENT_HANDLER4(obj, void, name, a0, n0, a1, n1, a2, n2, a3, n3) {PIObject::raiseEvent(this, #name, n0, n1, n2, n3);} #define EVENT EVENT0 /// raise event \"event\" from object \"src\" #define RAISE_EVENT0(src, event) (src)->event(); #define RAISE_EVENT1(src, event, v0) (src)->event(v0); #define RAISE_EVENT2(src, event, v0, v1) (src)->event(v0, v1); #define RAISE_EVENT3(src, event, v0, v1, v2) (src)->event(v0, v1, v2); #define RAISE_EVENT4(src, event, v0, v1, v2, v3) (src)->event(v0, v1, v2, v3); #define RAISE_EVENT RAISE_EVENT0 /// connect event \"event\" from object \"src\" to event handler \"handler\" from object \"dst\" with check of event and handler exists #define CONNECT0(ret, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*))(&(dst)->__stat_eh_##handler##__), (void*)(void(*)(void*))(&(src)->__stat_eh_##event##__)); #define CONNECT1(ret, a0, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*, a0))(&(dst)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0))(&(src)->__stat_eh_##event##__)); #define CONNECT2(ret, a0, a1, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*, a0, a1))(&(dst)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1))(&(src)->__stat_eh_##event##__)); #define CONNECT3(ret, a0, a1, a2, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*, a0, a1, a2))(&(dst)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1, a2))(&(src)->__stat_eh_##event##__)); #define CONNECT4(ret, a0, a1, a2, a3, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dst)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1, a2, a3))(&(src)->__stat_eh_##event##__)); #define CONNECT CONNECT0 /// connect event \"event\" from object \"src\" to event handler \"handler\" from object \"dst\" without check of event exists #define WEAK_CONNECT0(ret, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*))(&(dst)->__stat_eh_##handler##__)); #define WEAK_CONNECT1(ret, a0, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*, a0))(&(dst)->__stat_eh_##handler##__)); #define WEAK_CONNECT2(ret, a0, a1, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*, a0, a1))(&(dst)->__stat_eh_##handler##__)); #define WEAK_CONNECT3(ret, a0, a1, a2, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*, a0, a1, a2))(&(dst)->__stat_eh_##handler##__)); #define WEAK_CONNECT4(ret, a0, a1, a2, a3, src, event, dst, handler) PIObject::piConnect(src, #event, dst, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dst)->__stat_eh_##handler##__)); #define WEAK_CONNECT WEAK_CONNECT0 /// piDisconnect event \"event\" from object \"src\" from event handler \"handler\" from object \"dst\" #define DISCONNECT0(ret, src, event, dst, handler) PIObject::piDisconnect(src, #event, dst, (void*)(ret(*)(void*))(&(dst)->__stat_eh_##handler##__)); #define DISCONNECT1(ret, a0, src, event, dst, handler) PIObject::piDisconnect(src, #event, dst, (void*)(ret(*)(void*, a0))(&(dst)->__stat_eh_##handler##__)); #define DISCONNECT2(ret, a0, a1, src, event, dst, handler) PIObject::piDisconnect(src, #event, dst, (void*)(ret(*)(void*, a0, a1))(&(dst)->__stat_eh_##handler##__)); #define DISCONNECT3(ret, a0, a1, a2, src, event, dst, handler) PIObject::piDisconnect(src, #event, dst, (void*)(ret(*)(void*, a0, a1, a2))(&(dst)->__stat_eh_##handler##__)); #define DISCONNECT4(ret, a0, a1, a2, a3, src, event, dst, handler) PIObject::piDisconnect(src, #event, dst, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dst)->__stat_eh_##handler##__)); #define DISCONNECT DISCONNECT0 class PIObject { friend class PIObjectManager; public: PIObject(const PIString & name = PIString()) {piMonitor.objects++; setName(name); objects << this;} ~PIObject() {piMonitor.objects--; objects.removeAll(this);} const PIString & name() const {return name_;} void setName(const PIString & name) {name_ = name;} /* PIStringList events(); PIStringList eventHandlers(); /// Events void addEvent(const PIString & name) { signals_.insert(NamedFunction(0, name, PIStringList()), name); } template void addEvent(const PIString & name) { signals_.insert(NamedFunction(0, name, PIStringList(typeid(T0).name())), name); } template void addEvent(const PIString & name) { signals_.insert(NamedFunction(0, name, PIStringList(typeid(T0).name(), typeid(T1).name())), name); } template void addEvent(const PIString & name) { signals_.insert(NamedFunction(0, name, PIStringList(typeid(T0).name(), typeid(T1).name(), typeid(T2).name())), name); } template void addEvent(const PIString & name) { signals_.insert(NamedFunction(0, name, PIStringList(typeid(T0).name(), typeid(T1).name(), typeid(T2).name(), typeid(T3).name())), name); } /// Event handlers void addEventHandler(const PIString & name, void * func) { slots_.insert(NamedFunction(func, name, PIStringList()), name); } template void addEventHandler(const PIString & name, void * func) { slots_.insert(NamedFunction(func, name, PIStringList(typeid(T0).name())), name); } template void addEventHandler(const PIString & name, void * func) { slots_.insert(NamedFunction(func, name, PIStringList(typeid(T0).name(), typeid(T1).name())), name); } template void addEventHandler(const PIString & name, void * func) { slots_.insert(NamedFunction(func, name, PIStringList(typeid(T0).name(), typeid(T1).name(), typeid(T2).name())), name); } template void addEventHandler(const PIString & name, void * func) { slots_.insert(NamedFunction(func, name, PIStringList(typeid(T0).name(), typeid(T1).name(), typeid(T2).name(), typeid(T3).name())), name); } */ /// Direct connect static void piConnect(PIObject * src, const PIString & sig, void * dest, void * ev_h) {src->connections << Connection(ev_h, 0, sig, dest);} static void piConnect(PIObject * src, const PIString & sig, void * dest, void * ev_h, void * e_h) {src->connections << Connection(ev_h, e_h, sig, dest);} static void piDisconnect(PIObject * src, const PIString & sig, void * dest, void * ev_h) { for (int i = 0; i < src->connections.size_s(); ++i) { Connection & cc(src->connections[i]); if (cc.event == sig && cc.dest == dest && cc.slot == ev_h) { src->connections.remove(i); i--; } } } //static void piConnect(PIObject & src, const PIString & sig, PIObject * dest, void * ev_h) {src.connections << Connection(ev_h, sig, dest);} //static void piConnect(PIObject * src, const PIString & sig, PIObject & dest, void * ev_h) {src->connections << Connection(ev_h, sig, &dest);} //static void piConnect(PIObject & src, const PIString & sig, PIObject & dest, void * ev_h) {src.connections << Connection(ev_h, sig, &dest);} /*/// Connect through manager static bool piConnect(const PIString & srcObject, const PIString & event, const PIString & destObject, const PIString & handler, bool force = false) { PIObject * src = findByName(srcObject); if (src == 0) { cout << "PIObject::piConnect: can`t find PIObject with \"" << srcObject << "\" name!" << endl; return false; } PIObject * dest = findByName(destObject); if (dest == 0) { cout << "PIObject::piConnect: can`t find PIObject with \"" << destObject << "\" name!" << endl; return false; } return PIObject::piConnect(src, event, dest, handler, force); }*/ /// Raise events static void raiseEvent(PIObject * sender, const PIString & event) { for (int j = 0; j < sender->connections.size_s(); ++j) { Connection & i(sender->connections[j]); if (i.event != event) continue; ((void(*)(void * ))i.slot)(i.dest); } } template static void raiseEvent(PIObject * sender, const PIString & event, const T0 & v0 = T0()) { for (int j = 0; j < sender->connections.size_s(); ++j) { Connection & i(sender->connections[j]); if (i.event != event) continue; ((void(*)(void * , T0))i.slot)(i.dest, v0); } } template static void raiseEvent(PIObject * sender, const PIString & event, const T0 & v0 = T0(), const T1 & v1 = T1()) { for (int j = 0; j < sender->connections.size_s(); ++j) { Connection & i(sender->connections[j]); if (i.event != event) continue; ((void(*)(void * , T0, T1))i.slot)(i.dest, v0, v1); } } template static void raiseEvent(PIObject * sender, const PIString & event, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2()) { for (int j = 0; j < sender->connections.size_s(); ++j) { Connection & i(sender->connections[j]); if (i.event != event) continue; ((void(*)(void * , T0, T1, T2))i.slot)(i.dest, v0, v1, v2); } } template static void raiseEvent(PIObject * sender, const PIString & event, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2(), const T3 & v3 = T3()) { for (int j = 0; j < sender->connections.size_s(); ++j) { Connection & i(sender->connections[j]); if (i.event != event) continue; ((void(*)(void * , T0, T1, T2, T3))i.slot)(i.dest, v0, v1, v2, v3); } } /* /// Raise events (static) static void raiseEvent(PIObject * destObject, const PIString & name) { destObject->raiseEvent(name); } template static void raiseEvent(PIObject * destObject, const PIString & name, const T0 & v0 = T0()) { destObject->raiseEvent(name, v0); } template static void raiseEvent(PIObject * destObject, const PIString & name, const T0 & v0 = T0(), const T1 & v1 = T1()) { destObject->raiseEvent(name, v0, v1); } template static void raiseEvent(PIObject * destObject, const PIString & name, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2()) { destObject->raiseEvent(name, v0, v1, v2); } template static void raiseEvent(PIObject * destObject, const PIString & name, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2(), const T3 & v3 = T3()) { destObject->raiseEvent(name, v0, v1, v2, v3); } */ /// Raise events through manager static void raiseEvent(const PIString & destObject, const PIString & name) { PIObject * dest = findByName(destObject); if (dest == 0) { cout << "PIObject::piConnect: can`t find PIObject with \"" << destObject << "\" name!" << endl; return; } raiseEvent(dest, name); } template static void raiseEvent(const PIString & destObject, const PIString & name, const T0 & v0 = T0()) { PIObject * dest = findByName(destObject); if (dest == 0) { cout << "PIObject::piConnect: can`t find PIObject with \"" << destObject << "\" name!" << endl; return; } raiseEvent(dest, name, v0); } template static void raiseEvent(const PIString & destObject, const PIString & name, const T0 & v0 = T0(), const T1 & v1 = T1()) { PIObject * dest = findByName(destObject); if (dest == 0) { cout << "PIObject::piConnect: can`t find PIObject with \"" << destObject << "\" name!" << endl; return; } raiseEvent(dest, name, v0, v1); } template static void raiseEvent(const PIString & destObject, const PIString & name, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2()) { PIObject * dest = findByName(destObject); if (dest == 0) { cout << "PIObject::piConnect: can`t find PIObject with \"" << destObject << "\" name!" << endl; return; } raiseEvent(name, dest, v0, v1, v2); } template static void raiseEvent(const PIString & destObject, const PIString & name, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2(), const T3 & v3 = T3()) { PIObject * dest = findByName(destObject); if (dest == 0) { cout << "PIObject::piConnect: can`t find PIObject with \"" << destObject << "\" name!" << endl; return; } raiseEvent(name,dest , v0, v1, v2, v3); } protected: PIString name_; private: struct Connection { Connection(void * sl = 0, void * si = 0, const PIString & e = PIString(), void * o = 0) {slot = sl; signal = si; event = e; dest = o;} void * slot; void * signal; PIString event; void * dest; }; PIVector connections; static PIVector objects; static PIObject * findByName(const PIString & name) { piForeach (PIObject * i, PIObject::objects) { if (i->name_ != name) continue; return i; } return 0; }; }; #endif // PIOBJECT_H