///////////////////////////////////////////////////////////////////////
// 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

    Source: geocities.com/capecanaveral/lab/8679/callback

               ( geocities.com/capecanaveral/lab/8679)                   ( geocities.com/capecanaveral/lab)                   ( geocities.com/capecanaveral)