/*
 * ===========================
 * VDK Visual Develeopment Kit
 * Version 0.4
 * October 1998
 * ===========================
 *
 * Copyright (C) 1998, Mario Motta
 * Developed by Mario Motta <mmotta@guest.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 */
#ifndef EVLISTHANDLE_H
#define EVLISTHANDLE_H
#include <vdk/vdkobj.h>
// #include <vdk/vdkstring.h>
#include <cstring>
#include <vdk/value_sem_list.h>
#include <gdk/gdktypes.h>
#define VDK_EVENT_NAME_LENGHT 63
/*
==============================================
         EVENT LIST ROUTINES
==============================================
*/
template <class T>
class _VDK_Event_Unit {
  
 public:
  typedef bool (T::*PMF)(VDKObject* sender, GdkEvent* event);
  VDKObject* Pm;
  //  VDKString event; /* Event name ala Gtk+ */
  char event[VDK_EVENT_NAME_LENGHT+1];
  PMF    Pmf;  /* <class T> member function offset */
  gint slot;  /* gtk+ slot returned by gtk_signal_connect() */
  bool connected;
  GtkObject* gtkobj; /* gtk object */
  /*
  _VDK_Event_Unit(VDKObject* Pm, char* event,
		   PMF Pmf):
    Pm(Pm),event(event),Pmf(Pmf), slot(-1),connected(true) {}
  */
  _VDK_Event_Unit(VDKObject* Pm, char* ev,
		   PMF Pmf):
    Pm(Pm),Pmf(Pmf), slot(-1),connected(true) 
    { 
      std::strncpy(event,ev,VDK_EVENT_NAME_LENGHT); 
      // for safe
      event[VDK_EVENT_NAME_LENGHT] ='\0';
    }
  /*
  bool operator ==(_VDK_Event_Unit& su)
    { return (event == su.event) && (Pm == su.Pm); }
  */
  bool operator ==(_VDK_Event_Unit& su)
    { return ((!std::strcmp(event,su.event)) && (Pm == su.Pm)); }
};



#define DECLARE_EVENT_LIST(_owner_class) \
\
private:\
typedef _VDK_Event_Unit<_owner_class> _EventUnit;\
typedef VDKValueList< _EventUnit >  _EventCallbackList;\
typedef VDKValueListIterator< _EventUnit >  _EventCallbackListIterator;\
_EventCallbackList _event_cbList;\
public:\
/*virtual bool FindEventAtClassLevel(VDKObject* Pm, VDKString& event);*/\
virtual bool FindEventAtClassLevel(VDKObject* Pm, char* event);\
/*virtual bool FindEventAtParentLevel(VDKObject* Pm, VDKString& event);*/\
virtual bool FindEventAtParentLevel(VDKObject* Pm, char* event);\
virtual int  VDKEventUnitResponse(GtkWidget* , char* , GdkEvent* , void*);\
\
\
\
int EventConnect(VDKObject* object, char* event,\
  bool (_owner_class::*Pmf)(VDKObject* sender, GdkEvent*), bool after = false);\
int EventConnect(char* event,\
  bool (_owner_class::*Pmf)(VDKObject* sender, GdkEvent*), bool after = false)\
{\
return EventConnect(this, event, Pmf,after);\
}\
\
\
bool EventDisconnect(int slot);

/*
 */

#define DEFINE_EVENT_LIST(_owner_class, _ancestor_class)\
\
\
/*bool _owner_class::FindEventAtClassLevel(VDKObject* Pm, VDKString& event)*/\
bool _owner_class::FindEventAtClassLevel(VDKObject* Pm, char* event)\
{\
_EventUnit su(Pm,event, (bool (_owner_class::*)(VDKObject*, GdkEvent*)) NULL);\
if(_event_cbList.find(su))\
 return true;\
else\
  return _ancestor_class::FindEventAtClassLevel(Pm,event);\
}\
\
\
/*bool _owner_class::FindEventAtParentLevel(VDKObject* Pm, VDKString& event)*/\
bool _owner_class::FindEventAtParentLevel(VDKObject* Pm, char* event)\
{\
VDKObject* parent;\
for(parent = Parent(); parent; parent = parent->Parent())\
    if(parent->FindEventAtClassLevel(Pm,event))\
      return true;\
return false;\
}\
\
\
\
int _owner_class::EventConnect(VDKObject* obj, char* event,\
  bool (_owner_class::*Pmf)(VDKObject* sender, GdkEvent*), bool after)\
{\
bool found = false;\
VDKObjectEventUnit* su = new VDKObjectEventUnit(this,obj,event);\
euList.add(su);\
_EventUnit sigUnit(obj,event,Pmf);\
found = obj->FindEventAtClassLevel(sigUnit.Pm,sigUnit.event) || \
      obj->FindEventAtParentLevel(sigUnit.Pm,sigUnit.event);\
if(!found)\
  sigUnit.slot = after ? gtk_signal_connect_after(GTK_OBJECT(obj->ConnectingWidget()),event,\
		     GTK_SIGNAL_FUNC(VDKObject::VDKEventUnitPipe),\
		     reinterpret_cast<gpointer>(su) ):\
		     gtk_signal_connect(GTK_OBJECT(obj->ConnectingWidget()),event,\
		     GTK_SIGNAL_FUNC(VDKObject::VDKEventUnitPipe),\
		     reinterpret_cast<gpointer>(su) );\
else\
 sigUnit.slot = (_event_cbList.size()+1)*-1;\
sigUnit.gtkobj = obj->ConnectingWidget() != NULL ? \
    GTK_OBJECT(obj->ConnectingWidget()) : NULL;\
_event_cbList.add(sigUnit);\
return sigUnit.slot;\
}\
\
\
\
bool _owner_class::EventDisconnect(int slot)\
{\
int t = 0;\
_EventCallbackListIterator li(_event_cbList);\
for(;li;li++,t++)\
{\
_EventUnit su = li.current();\
if(su.slot == slot)\
  {\
  if(su.slot > 0)\
    gtk_signal_disconnect(su.gtkobj,su.slot);\
  _event_cbList.unlink(t);\
  return true;\
  }\
}\
return false;\
}\
\
\
int _owner_class::VDKEventUnitResponse(GtkWidget* mobj,\
					char* event,\
                                        GdkEvent* evType,\
                                        void* obj)\
{\
bool treated = false;\
VDKObject* vdkobj = reinterpret_cast<VDKObject*>(obj);\
_EventCallbackListIterator li(_event_cbList);\
for(;li;li++)\
{\
_EventUnit su = li.current();\
if ( (su.Pm == vdkobj) &&\
     (!std::strcmp(su.event,event) && su.connected))\
   {\
	bool(_owner_class::*response)(VDKObject* sender, GdkEvent* )= \
                              su.Pmf;\
	if(((*this).*response)(vdkobj, evType) == true)\
            treated = true;\
   }\
}\
if(treated)\
   return 1;\
else\
   return _ancestor_class::VDKEventUnitResponse(mobj,event,evType,obj);\
}

#endif

