/////////////////////////////////////////////////////////////////////// // 1/21/2004 // these classes give a similar interface as the one in the Qt library // An example of how to use the classes is shown below /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // example /////////////////////////////////////////////////////////////////////// #if 0 #include #include "callback.h" class C1 { public: int function (int test) { int rt; char buffer[256]; sprintf (buffer, "%d", test); rt = callback1 (test); rt += callback2 (test, buffer); rt += callback3 (test, buffer, &rt); return rt; } SIGNAL1 (int, callback1, int); SIGNAL2 (int, callback2, int, char *); SIGNAL3 (int, callback3, int, char *, int *); }; class C2 { public: int call1 (int t) { printf ("c2::callback (%d)\n", t); return 0; } int call2 (int t, char *str) { printf ("c2::callback (%d, %s)\n", t, str); return 0; } int call3 (int t, char *str, int *rt) { printf ("c2::callback (%d, %s, %d)\n", t, str, *rt); return 0; } }; int main (int argc, char *argv[]) { C1 c1; C2 c2; int rt; int id1; int id2; int id3; connect1 (&id1, int, &c1, callback, int, C2, &c2, call); connect2 (&id2, int, &c1, callback1, int, char *, C2, &c2, call); connect3 (&id3, int, &c1, callback1, int, char *, int *, C2, &c2, call); rt = c1.function (12345678); printf ("c1.function returns %d\n", rt); } #endif /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // classes /////////////////////////////////////////////////////////////////////// #ifndef CALLBACK_H #define CALLBACK_H #ifndef OK #define OK 0 #endif #ifndef OK #define ERROR -1 #endif typedef int CallbackId; // RT - return type // C1 - variable of source class // signal - source function // T1 - type of first parameter // CT2 - type of destination class // C2 - variable of destination class // slot - destination function #define DISCONNECT0(C1,signal,ID) (*C1).disconnect_##signal (ID) #define CONNECT0(ID,RT,C1,signal,CT2,C2,slot) \ { \ Callback0b *cb; \ cb = new Callback0b (C2, &CT2::slot); \ *ID = (*C1).connect_##signal (cb); \ } // RT - return type // C1 - variable of source class // signal - source function // T1 - type of first parameter // CT2 - type of destination class // C2 - variable of destination class // slot - destination function #define DISCONNECT1(C1,signal,T1,ID) (*C1).disconnect_##signal##T1 (ID) #define CONNECT1(ID,RT,C1,signal,T1,CT2,C2,slot) \ { \ Callback1b *cb; \ cb = new Callback1b (C2, &CT2::slot); \ *ID = (*C1).connect_##signal (cb); \ } // RT - return type // C1 - variable of source class // signal - source function // T1 - type of first parameter // T2 - type of second parameter // CT2 - type of destination class // C2 - variable of destination class // slot - destination function #define DISCONNECT2(C1,signal,T1,T2,ID) (*C1).disconnect_##signal##T1##T2 (ID) #define CONNECT2(ID, RT,C1,signal,T1,T2,CT2,C2,slot) \ { \ Callback2b *cb; \ cb = new Callback2b (C2, &CT2::slot); \ *ID =(*C1).connect_##signal (cb); \ } // RT - return type // C1 - variable of source class // signal - source function // T1 - type of first parameter // T2 - type of second parameter // T3 - type of third parameter // CT2 - type of destination class // C2 - variable of destination class // slot - destination function #define DISCONNECT3(C1,signal,T1,T2,T3,ID) \ (*C1).disconnect_##signal##T1##T2##T3 (ID) #define CONNECT3(ID,RT,C1,signal,T1,T2,T3,CT2,C2,slot) \ { \ Callback3b *cb; \ cb = new Callback3b (C2, &CT2::slot); \ *ID = (*C1).connect_##signal (cb); \ } // RT - return type // C1 - variable of source class // signal - source function // T1 - type of first parameter // T2 - type of second parameter // T3 - type of third parameter // T4 - type of fourth parameter // CT2 - type of destination class // C2 - variable of destination class // slot - destination function #define DISCONNECT4(C1,signal,T1,T2,T3,T4,ID) \ (*C1).disconnect_##signal##T1##T2##T3##T4 (ID) #define CONNECT4(ID,RT,C1,signal,T1,T2,T3,T4,CT2,C2,slot) \ { \ Callback4b *cb; \ cb = new Callback4b (C2, &CT2::slot); \ *ID = (*C1).connect_##signal (cb); \ } #define SIGNAL0(RT,f) \ private: \ Callback0a callback_##f; \ public: \ int disconnect_##f (CallbackId id) \ { \ callback_##f.remove (id); \ return OK; \ } \ int connect_##f (class CallbackFunc0 *p) \ { \ return callback_##f.setFunc (p); \ } \ RT f () \ { \ return _##f (); \ } \ virtual RT _##f () \ { \ return callback_##f.callback (); \ } #define SIGNAL1(RT,f,p1) \ private: \ Callback1a callback_##f##_##p1; \ public: \ int disconnect_##f##p1 (CallbackId id) \ { \ callback_##f##_##p1.remove (id); \ return OK; \ } \ int connect_##f (class CallbackFunc1 *p) \ { \ return callback_##f##_##p1.setFunc (p); \ } \ RT f (p1 p) \ { \ return _##f (p); \ } \ virtual RT _##f (p1 p) \ { \ return callback_##f##_##p1.callback (p); \ } #define SIGNAL2(rt,f,p1,p2) \ private: \ Callback2a callback_##f##_##p1##_##p2; \ public: \ int disconnect_##f##p1##p2 (CallbackId id) \ { \ callback_##f##_##p1##_##p2.remove (id); \ return OK; \ } \ int connect_##f (class CallbackFunc2 *p) \ { \ return callback_##f##_##p1##_##p2.setFunc (p); \ } \ rt f (p1 i1, p2 i2) \ { \ return _##f (i1, i2); \ } \ virtual rt _##f (p1 i1, p2 i2) \ { \ return callback_##f##_##p1##_##p2.callback (i1, i2); \ } #define SIGNAL3(rt,f,p1,p2,p3) \ private: \ Callback3a callback_##f##_##p1##_##p2##_##p3; \ public: \ int disconnect_##f##p1##p2##p3 (CallbackId id) \ { \ callback_##f##_##p1##_##p2##_##p3.remove (id); \ return OK; \ } \ int connect_##f (class CallbackFunc3 *p) \ { \ return callback_##f##_##p1##_##p2##_##p3.setFunc (p); \ } \ rt f (p1 i1, p2 i2, p3 i3) \ { \ return _##f (i1, i2, i3); \ } \ virtual rt _##f (p1 i1, p2 i2, p3 i3) \ { \ return callback_##f##_##p1##_##p2##_##p3.callback (i1, i2, i3); \ } #define SIGNAL4(rt,f,p1,p2,p3,p4) \ private: \ Callback4a callback_##f##_##p1##_##p2##_##p3##_##p4; \ public: \ int disconnect_##f##p1##p2##p3##p4 (CallbackId id) \ { \ callback_##f##_##p1##_##p2##_##p3##_##p4.remove (id); \ return OK; \ } \ int connect_##f (class CallbackFunc4 *p) \ { \ return callback_##f##_##p1##_##p2##_##p3##_##p4.setFunc (p); \ } \ rt f (p1 i1, p2 i2, p3 i3, p4 i4) \ { \ return _##f (i1, i2, i3, i4); \ } \ virtual rt _##f (p1 i1, p2 i2, p3 i3, p4 i4) \ { \ return callback_##f##_##p1##_##p2##_##p3##_##p4.callback (i1, i2, i3, i4); \ } /////////////////////////////////////////////////////////////////////// // this class should be used in signalling class with no parameters /////////////////////////////////////////////////////////////////////// template class CallbackFunc0 { public: class CallbackFunc0 *next; class CallbackFunc0 *prev; int id; virtual RT func () = 0; }; template class Callback0a { private: CallbackFunc0 *func; int id; public: Callback0a () { func = NULL; id = 1; } ~Callback0a () { CallbackFunc0 *p; CallbackFunc0 *pNext; for (p = func; p != NULL; p = pNext) { pNext = p->next; delete p; } } int setFunc (CallbackFunc0 *f) { CallbackFunc0 *p; f->id = id++; if (func == NULL) { f->next = NULL; f->prev = NULL; func = f; } else { for (p = func; p->next != NULL; p = p->next) { continue; } f->prev = p; f->next = NULL; p->next = f; } return f->id; } int remove(CallbackId id) { CallbackFunc0 *p; for (p = func; p != NULL; p = p->next) { if (p->id == id) { if (p->prev != NULL) { p->prev->next = p->next; } else { func = p->next; } if (p->next != NULL) { p->next->prev = p->prev; } return 0; } } return -1; } RT callback() { CallbackFunc0 *p; RT rt (-1); if (func == NULL) return rt; rt = 0; for (p = func; p != NULL; p = p->next) { rt |= p->func (); } return rt; } }; // this class should be used in the main program template class Callback0b : public CallbackFunc0 { typedef RT (C:: *SlotFunc)(); private: C *c; SlotFunc slot; public: Callback0b (C *cc, SlotFunc s) { c = cc; slot = s; } RT func () { return (c->*slot) (); } }; /////////////////////////////////////////////////////////////////////// // this class should be used in signalling class with one parameter /////////////////////////////////////////////////////////////////////// template class CallbackFunc1 { public: class CallbackFunc1 *next; class CallbackFunc1 *prev; int id; virtual RT func (P1 t) = 0; }; template class Callback1a { private: CallbackFunc1 *func; int id; public: Callback1a () { func = NULL; id = 1; } ~Callback1a () { CallbackFunc1 *p; CallbackFunc1 *pNext; for (p = func; p != NULL; p = pNext) { pNext = p->next; delete p; } } int setFunc (CallbackFunc1 *f) { CallbackFunc1 *p; f->id = id++; if (func == NULL) { f->next = NULL; f->prev = NULL; func = f; } else { for (p = func; p->next != NULL; p = p->next) { continue; } f->prev = p; f->next = NULL; p->next = f; } return f->id; } int remove(CallbackId id) { CallbackFunc1 *p; for (p = func; p != NULL; p = p->next) { if (p->id == id) { if (p->prev != NULL) { p->prev->next = p->next; } else { func = p->next; } if (p->next != NULL) { p->next->prev = p->prev; } return 0; } } return -1; } RT callback(P1 i1) { CallbackFunc1 *p; RT rt (-1); if (func == NULL) return rt; rt = 0; for (p = func; p != NULL; p = p->next) { rt |= p->func (i1); } return rt; } }; // this class should be used in the main program template class Callback1b : public CallbackFunc1 { typedef RT (C:: *SlotFunc)(P1); private: C *c; SlotFunc slot; public: Callback1b (C *cc, SlotFunc s) { c = cc; slot = s; } RT func (P1 t) { return (c->*slot) (t); } }; /////////////////////////////////////////////////////////////////////// // this class should be used in signalling class with two parameters /////////////////////////////////////////////////////////////////////// template class CallbackFunc2 { public: class CallbackFunc2 *next; class CallbackFunc2 *prev; int id; virtual RT func (P1 i1, P2 i2) = 0; }; template class Callback2a { private: CallbackFunc2 *func; int id; public: Callback2a () { func = NULL; id = 1; } ~Callback2a () { CallbackFunc2 *p; CallbackFunc2 *pNext; for (p = func; p != NULL; p = pNext) { pNext = p->next; delete p; } } int setFunc (CallbackFunc2 *f) { CallbackFunc2 *p; f->id = id++; if (func == NULL) { f->next = NULL; f->prev = NULL; func = f; } else { for (p = func; p->next != NULL; p = p->next) { continue; } f->prev = p; f->next = NULL; p->next = f; } return f->id; } int remove(CallbackId id) { CallbackFunc2 *p; for (p = func; p != NULL; p = p->next) { if (p->id == id) { if (p->prev != NULL) { p->prev->next = p->next; } else { func = p->next; } if (p->next != NULL) { p->next->prev = p->prev; } return 0; } } return -1; } RT callback(P1 i1, P2 i2) { CallbackFunc2 *p; RT rt (-1); if (func == NULL) return rt; rt = 0; for (p = func; p != NULL; p = p->next) { rt |= p->func (i1, i2); } return rt; } }; // this class should be used in the main program template class Callback2b : public CallbackFunc2 { typedef RT (C:: *SlotFunc)(P1, P2); private: C *c; SlotFunc slot; public: Callback2b (C *cc, SlotFunc s) { c = cc; slot = s; } RT func (P1 p1, P2 p2) { return (c->*slot) (p1, p2); } }; /////////////////////////////////////////////////////////////////////// // this class should be used in signalling class with three parameters /////////////////////////////////////////////////////////////////////// template class CallbackFunc3 { public: class CallbackFunc3 *next; class CallbackFunc3 *prev; int id; virtual RT func (P1 i1, P2 i2, P3 i3) = 0; }; template class Callback3a { private: CallbackFunc3 *func; int id; public: Callback3a () { func = NULL; id = 1; } ~Callback3a () { CallbackFunc3 *p; CallbackFunc3 *pNext; for (p = func; p != NULL; p = pNext) { pNext = p->next; delete p; } } int setFunc (CallbackFunc3 *f) { CallbackFunc3 *p; f->id = id++; if (func == NULL) { f->next = NULL; f->prev = NULL; func = f; } else { for (p = func; p->next != NULL; p = p->next) { continue; } f->prev = p; f->next = NULL; p->next = f; } return f->id; } int remove(CallbackId id) { CallbackFunc3 *p; for (p = func; p != NULL; p = p->next) { if (p->id == id) { if (p->prev != NULL) { p->prev->next = p->next; } else { func = p->next; } if (p->next != NULL) { p->next->prev = p->prev; } return 0; } } return -1; } RT callback(P1 i1, P2 i2, P3 i3) { CallbackFunc3 *p; RT rt (-1); if (func == NULL) return rt; rt = 0; for (p = func; p != NULL; p = p->next) { rt |= p->func (i1, i2, i3); } return rt; } }; // this class should be used in the main program template class Callback3b : public CallbackFunc3 { typedef RT (C:: *SlotFunc)(P1, P2, P3); private: C *c; SlotFunc slot; public: Callback3b (C *cc, SlotFunc s) { c = cc; slot = s; } RT func (P1 p1, P2 p2, P3 p3) { return (c->*slot) (p1, p2, p3); } }; /////////////////////////////////////////////////////////////////////// // this class should be used in signalling class with four parameters /////////////////////////////////////////////////////////////////////// template class CallbackFunc4 { public: class CallbackFunc4 *next; class CallbackFunc4 *prev; int id; virtual RT func (P1 i1, P2 i2, P3 i3, P4 i4) = 0; }; template class Callback4a { private: CallbackFunc4 *func; int id; public: Callback4a () { func = NULL; id = 1; } ~Callback4a () { CallbackFunc4 *p; CallbackFunc4 *pNext; for (p = func; p != NULL; p = pNext) { pNext = p->next; delete p; } } int setFunc (CallbackFunc4 *f) { CallbackFunc4 *p; f->id = id++; if (func == NULL) { f->next = NULL; f->prev = NULL; func = f; } else { for (p = func; p->next != NULL; p = p->next) { continue; } f->prev = p; f->next = NULL; p->next = f; } return f->id; } int remove(CallbackId id) { CallbackFunc4 *p; for (p = func; p != NULL; p = p->next) { if (p->id == id) { if (p->prev != NULL) { p->prev->next = p->next; } else { func = p->next; } if (p->next != NULL) { p->next->prev = p->prev; } return 0; } } return -1; } RT callback(P1 i1, P2 i2, P3 i3, P4 i4) { CallbackFunc4 *p; RT rt (-1); if (func == NULL) return rt; rt = 0; for (p = func; p != NULL; p = p->next) { rt |= p->func (i1, i2, i3, i4); } return rt; } }; // this class should be used in the main program template class Callback4b : public CallbackFunc4 { typedef RT (C:: *SlotFunc)(P1, P2, P3, P4); private: C *c; SlotFunc slot; public: Callback4b (C *cc, SlotFunc s) { c = cc; slot = s; } RT func (P1 p1, P2 p2, P3 p3, P4 p4) { return (c->*slot) (p1, p2, p3, p4); } }; #endif