text: //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  //
  // Purpose: 
  //
  // $NoKeywords: $
  //=============================================================================//
  
  #ifndef MESSAGEMAP_H
  #define MESSAGEMAP_H
  
  #ifdef _WIN32
  #pragma once
  #endif
  
  //#include "tier1/utlvector.h"
  #include "dmxloader/dmxelement.h"
  
  // more flexible than default pointers to members code required for casting member function pointers
  #pragma pointers_to_members( full_generality, virtual_inheritance )
  
  namespace vgui
  {
  
  ////////////// MESSAGEMAP DEFINITIONS //////////////
  
  
  #ifndef ARRAYSIZE
  #define ARRAYSIZE(p)	(sizeof(p)/sizeof(p[0]))
  #endif
  
  
  //-----------------------------------------------------------------------------
  // Purpose: parameter data type enumeration
  //			used internal but the shortcut macros require this to be exposed
  //-----------------------------------------------------------------------------
  enum DataType_t
  {
  	DATATYPE_VOID,
  	DATATYPE_CONSTCHARPTR,
  	DATATYPE_INT,
  	DATATYPE_FLOAT,
  	DATATYPE_PTR,
  	DATATYPE_BOOL,
  	DATATYPE_KEYVALUES,
  	DATATYPE_CONSTWCHARPTR,
  	DATATYPE_UINT64,
  	DATATYPE_HANDLE,  // It's an int, really
  };
  
  class Panel;
  typedef unsigned int VPANEL;
  
  typedef void (Panel::*MessageFunc_t)(void);
  
  //-----------------------------------------------------------------------------
  // Purpose: Single item in a message map
  //			Contains the information to map a string message name with parameters
  //			to a function call
  //-----------------------------------------------------------------------------
  #pragma warning(disable:4121)
  struct MessageMapItem_t
  {
  	const char *name;
  	// VC6 aligns this to 16-bytes.  Since some of the code has been compiled with VC6,
  	// we need to enforce the alignment on later compilers to remain compatible.
  	ALIGN16 MessageFunc_t func;
  
  	int numParams;
  
  	DataType_t firstParamType;
  	const char *firstParamName;
  
  	DataType_t secondParamType;
  	const char *secondParamName;
  
  	int nameSymbol;
  	int firstParamSymbol;
  	int secondParamSymbol;
  };
  
  #define DECLARE_PANELMESSAGEMAP( className )												\
  	static void AddToMap( char const *scriptname, vgui::MessageFunc_t function, int paramCount, int p1type, const char *p1name, int p2type, const char *p2name ) 	\
  	{																					\
  		vgui::PanelMessageMap *map = vgui::FindOrAddPanelMessageMap( GetPanelClassName() );			\
  																						\
  		vgui::MessageMapItem_t entry;															\
  		entry.name = scriptname;														\
  		entry.func = function;															\
  		entry.numParams = paramCount;													\
  		entry.firstParamType = (vgui::DataType_t)p1type;								\
  		entry.firstParamName = p1name;													\
  		entry.secondParamType = (vgui::DataType_t)p2type;								\
  		entry.secondParamName = p2name;													\
  		entry.nameSymbol = 0;															\
  		entry.firstParamSymbol = 0;														\
  		entry.secondParamSymbol = 0;													\
  																						\
  		map->entries.AddToTail( entry );												\
  	}																					\
  																						\
  	static void ChainToMap( void )														\
  	{																					\
  		static bool chained = false;													\
  		if ( chained )																	\
  			return;																		\
  		chained = true;																	\
  		vgui::PanelMessageMap *map = vgui::FindOrAddPanelMessageMap( GetPanelClassName() );			\
  		map->pfnClassName = &GetPanelClassName;											\
  		if ( map && GetPanelBaseClassName() && GetPanelBaseClassName()[0] )				\
  		{																				\
  			map->baseMap = vgui::FindOrAddPanelMessageMap( GetPanelBaseClassName() );			\
  		}																				\
  	}																					\
  																						\
  	class className##_RegisterMap;															\
  	friend class className##_RegisterMap;													\
  	class className##_RegisterMap															\
  	{																					\
  	public:																				\
  		className##_RegisterMap()															\
  		{																				\
  			className::ChainToMap();													\
  		}																				\
  	};																					\
  	className##_RegisterMap m_RegisterClass;												\
  																						\
  	virtual vgui::PanelMessageMap *GetMessageMap()											\
  	{																					\
  		static vgui::PanelMessageMap *s_pMap = vgui::FindOrAddPanelMessageMap( GetPanelClassName() );	\
  		return s_pMap;																	\
  	}
  
  #if !defined( _XBOX )
  #define VGUI_USEKEYBINDINGMAPS	1
  #endif
  
  #if defined( VGUI_USEKEYBINDINGMAPS )
  
  #define DECLARE_CLASS_SIMPLE( className, baseClassName ) \
  	typedef baseClassName BaseClass; \
  	typedef className ThisClass;	\
  public:								\
  	DECLARE_PANELMESSAGEMAP( className ); \
  	DECLARE_PANELANIMATION( className ); \
  	DECLARE_KEYBINDINGMAP( className ); \
  	static char const *GetPanelClassName() { return #className; } \
  	static char const *GetPanelBaseClassName() { return #baseClassName; }
  
  #define DECLARE_CLASS_SIMPLE_NOBASE( className ) \
  	typedef className ThisClass;	\
  public:							\
  	DECLARE_PANELMESSAGEMAP( className ); \
  	DECLARE_PANELANIMATION( className ); \
  	DECLARE_KEYBINDINGMAP( className ); \
  	static char const *GetPanelClassName() { return #className; } \
  	static char const *GetPanelBaseClassName() { return NULL; }
  
  #else // no keybinding maps
  
  #define DECLARE_CLASS_SIMPLE( className, baseClassName ) \
  	typedef baseClassName BaseClass; \
  	typedef className ThisClass;	\
  public:								\
  	DECLARE_PANELMESSAGEMAP( className ); \
  	DECLARE_PANELANIMATION( className ); \
  	static char const *GetPanelClassName() { return #className; } \
  	static char const *GetPanelBaseClassName() { return #baseClassName; }
  
  #define DECLARE_CLASS_SIMPLE_NOBASE( className ) \
  	typedef className ThisClass;	\
  public:							\
  	DECLARE_PANELMESSAGEMAP( className ); \
  	DECLARE_PANELANIMATION( className ); \
  	static char const *GetPanelClassName() { return #className; } \
  	static char const *GetPanelBaseClassName() { return NULL; }
  
  #endif // !VGUI_USEKEYBINDINGMAPS
  
  #define _MessageFuncCommon( name, scriptname, paramCount, p1type, p1name, p2type, p2name )	\
  	class PanelMessageFunc_##name; \
  	friend class PanelMessageFunc_##name; \
  	class PanelMessageFunc_##name \
  	{ \
  	public: \
  		static void InitVar() \
  		{ \
  			static bool bAdded = false; \
  			if ( !bAdded ) \
  			{ \
  				bAdded = true; \
  				AddToMap( scriptname, (vgui::MessageFunc_t)&ThisClass::name, paramCount, p1type, p1name, p2type, p2name ); \
  			} \
  		}												\
  		PanelMessageFunc_##name()						\
  		{												\
  			PanelMessageFunc_##name::InitVar();			\
  		}												\
  	};													\
  	PanelMessageFunc_##name m_##name##_register;		\
  
  // Use this macro to define a message mapped function
  // must end with a semicolon ';', or with a function
  // no parameter
  #define MESSAGE_FUNC( name, scriptname )			_MessageFuncCommon( name, scriptname, 0, 0, 0, 0, 0 );	virtual void name( void )
  
  // one parameter
  #define MESSAGE_FUNC_INT( name, scriptname, p1 )	_MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_INT, #p1, 0, 0 );	virtual void name( int p1 )
  #define MESSAGE_FUNC_UINT64( name, scriptname, p1 )	_MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_UINT64, #p1, 0, 0 );	virtual void name( uint64 p1 )
  #define MESSAGE_FUNC_PTR( name, scriptname, p1 )	_MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_PTR, #p1, 0, 0 );	virtual void name( vgui::Panel *p1 )
  #define MESSAGE_FUNC_HANDLE( name, scriptname, p1 )	_MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_HANDLE, #p1, 0, 0 );	virtual void name( vgui::VPANEL p1 )
  #define MESSAGE_FUNC_ENUM( name, scriptname, t1, p1 )	_MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_INT, #p1, 0, 0 );	virtual void name( t1 p1 )
  #define MESSAGE_FUNC_FLOAT( name, scriptname, p1 )	_MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_FLOAT, #p1, 0, 0 );	virtual void name( float p1 )
  #define MESSAGE_FUNC_CHARPTR( name, scriptname, p1 )	_MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_CONSTCHARPTR, #p1, 0, 0 );	virtual void name( const char *p1 )
  #define MESSAGE_FUNC_WCHARPTR( name, scriptname, p1 )	_MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_CONSTWCHARPTR, #p1, 0, 0 ); virtual void name( const wchar_t *p1 )
  
  // two parameters
  #define MESSAGE_FUNC_INT_INT( name, scriptname, p1, p2 )	_MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_INT, #p1, vgui::DATATYPE_INT, #p2 );	virtual void name( int p1, int p2 )
  #define MESSAGE_FUNC_PTR_INT( name, scriptname, p1, p2 )	_MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_PTR, #p1, vgui::DATATYPE_INT, #p2 );	virtual void name( vgui::Panel *p1, int p2 )
  #define MESSAGE_FUNC_HANDLE_INT( name, scriptname, p1, p2 )	_MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_HANDLE, #p1, vgui::DATATYPE_INT, #p2 );	virtual void name( vgui::VPANEL p1, int p2 )
  #define MESSAGE_FUNC_ENUM_ENUM( name, scriptname, t1, p1, t2, p2 )	_MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_INT, #p1, vgui::DATATYPE_INT, #p2 );	virtual void name( t1 p1, t2 p2 )
  #define MESSAGE_FUNC_INT_CHARPTR( name, scriptname, p1, p2 )	_MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_INT, #p1, vgui::DATATYPE_CONSTCHARPTR, #p2 );	virtual void name( int p1, const char *p2 )
  #define MESSAGE_FUNC_PTR_CHARPTR( name, scriptname, p1, p2 )	_MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_PTR, #p1, vgui::DATATYPE_CONSTCHARPTR, #p2 );	virtual void name( vgui::Panel *p1, const char *p2 )
  #define MESSAGE_FUNC_HANDLE_CHARPTR( name, scriptname, p1, p2 )	_MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_HANDLE, #p1, vgui::DATATYPE_CONSTCHARPTR, #p2 );	virtual void name( vgui::VPANEL p1, const char *p2 )
  #define MESSAGE_FUNC_PTR_WCHARPTR( name, scriptname, p1, p2 )	_MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_PTR, #p1, vgui::DATATYPE_CONSTWCHARPTR, #p2 );	virtual void name( vgui::Panel *p1, const wchar_t *p2 )
  #define MESSAGE_FUNC_HANDLE_WCHARPTR( name, scriptname, p1, p2 )	_MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_HANDLE, #p1, vgui::DATATYPE_CONSTWCHARPTR, #p2 );	virtual void name( vgui::VPANEL p1, const wchar_t *p2 )
  #define MESSAGE_FUNC_CHARPTR_CHARPTR( name, scriptname, p1, p2 )	_MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_CONSTCHARPTR, #p1, vgui::DATATYPE_CONSTCHARPTR, #p2 );	virtual void name( const char *p1, const char *p2 )
  
  // unlimited parameters (passed in the whole KeyValues)
  #define MESSAGE_FUNC_PARAMS( name, scriptname, p1 )	_MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_KEYVALUES, NULL, 0, 0 );	virtual void name( KeyValues *p1 )
  
  // no-virtual function version
  #define MESSAGE_FUNC_NV( name, scriptname )			_MessageFuncCommon( name, scriptname, 0, 0, 0, 0, 0 );	void name( void )
  #define MESSAGE_FUNC_NV_INT( name, scriptname, p1 )	_MessageFuncCommon( name, scriptname, 1, vgui::DATATYPE_INT, #p1, 0, 0 );	void name( int p1 )
  #define MESSAGE_FUNC_NV_INT_INT( name, scriptname, p1, p2 )	_MessageFuncCommon( name, scriptname, 2, vgui::DATATYPE_INT, #p1, vgui::DATATYPE_INT, #p2 );	void name( int p1, int p2 )
  
  
  // mapping, one per class
  struct PanelMessageMap
  {
  	PanelMessageMap()
  	{
  		baseMap = NULL;
  		pfnClassName = NULL;
  		processed = false;
  	}
  
  	CUtlVector< MessageMapItem_t > entries;
  	bool processed;
  	PanelMessageMap *baseMap;
  	char const *(*pfnClassName)( void );
  };
  
  PanelMessageMap *FindPanelMessageMap( char const *className );
  PanelMessageMap *FindOrAddPanelMessageMap( char const *className );
  
  
  
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  // 
  // OBSELETE MAPPING FUNCTIONS, USE ABOVE
  //
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  
  // no parameters
  #define MAP_MESSAGE( type, name, func )						{ name, (vgui::MessageFunc_t)(&type::func), 0 }
  
  // implicit single parameter (params is the data store)
  #define MAP_MESSAGE_PARAMS( type, name, func )				{ name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_KEYVALUES, NULL }
  
  // single parameter
  #define MAP_MESSAGE_PTR( type, name, func, param1 )			{ name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_PTR, param1 }
  #define MAP_MESSAGE_INT( type, name, func, param1 )			{ name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_INT, param1 }
  #define MAP_MESSAGE_BOOL( type, name, func, param1 )		{ name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_BOOL, param1 }
  #define MAP_MESSAGE_FLOAT( type, name, func, param1 )		{ name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_FLOAT, param1 }
  #define MAP_MESSAGE_PTR( type, name, func, param1 )			{ name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_PTR, param1 }
  #define MAP_MESSAGE_CONSTCHARPTR( type, name, func, param1) { name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_CONSTCHARPTR, param1 }
  #define MAP_MESSAGE_CONSTWCHARPTR( type, name, func, param1) { name, (vgui::MessageFunc_t)(&type::func), 1, vgui::DATATYPE_CONSTWCHARPTR, param1 }
  
  // two parameters
  #define MAP_MESSAGE_INT_INT( type, name, func, param1, param2 ) { name, (vgui::MessageFunc_t)&type::func, 2, vgui::DATATYPE_INT, param1, vgui::DATATYPE_INT, param2 }
  #define MAP_MESSAGE_PTR_INT( type, name, func, param1, param2 ) { name, (vgui::MessageFunc_t)&type::func, 2, vgui::DATATYPE_PTR, param1, vgui::DATATYPE_INT, param2 }
  #define MAP_MESSAGE_INT_CONSTCHARPTR( type, name, func, param1, param2 ) { name, (vgui::MessageFunc_t)&type::func, 2, vgui::DATATYPE_INT, param1, vgui::DATATYPE_CONSTCHARPTR, param2 }
  #define MAP_MESSAGE_PTR_CONSTCHARPTR( type, name, func, param1, param2 ) { name, (vgui::MessageFunc_t)&type::func, 2, vgui::DATATYPE_PTR, param1, vgui::DATATYPE_CONSTCHARPTR, param2 }
  #define MAP_MESSAGE_PTR_CONSTWCHARPTR( type, name, func, param1, param2 ) { name, (vgui::MessageFunc_t)&type::func, 2, vgui::DATATYPE_PTR, param1, vgui::DATATYPE_CONSTWCHARPTR, param2 }
  #define MAP_MESSAGE_CONSTCHARPTR_CONSTCHARPTR( type, name, func, param1, param2 ) { name, (vgui::MessageFunc_t)&type::func, 2, vgui::DATATYPE_CONSTCHARPTR, param1, vgui::DATATYPE_CONSTCHARPTR, param2 }
  
  // if more parameters are needed, just use MAP_MESSAGE_PARAMS() and pass the keyvalue set into the function
  
  
  //-----------------------------------------------------------------------------
  // Purpose: stores the list of objects in the hierarchy
  //			used to iterate through an object's message maps
  //-----------------------------------------------------------------------------
  struct PanelMap_t
  {
  	MessageMapItem_t *dataDesc;
  	int dataNumFields;
  	const char *dataClassName;
  	PanelMap_t *baseMap;
  	int processed;
  };
  
  // for use in class declarations
  // declares the static variables and functions needed for the data description iteration
  #define DECLARE_PANELMAP() \
  	static vgui::PanelMap_t m_PanelMap; \
  	static vgui::MessageMapItem_t m_MessageMap[]; \
  	virtual vgui::PanelMap_t *GetPanelMap( void );
  
  // could embed typeid() into here as well?
  #define IMPLEMENT_PANELMAP( derivedClass, baseClass ) \
  	vgui::PanelMap_t derivedClass::m_PanelMap = { derivedClass::m_MessageMap, ARRAYSIZE(derivedClass::m_MessageMap), #derivedClass, &baseClass::m_PanelMap }; \
  	vgui::PanelMap_t *derivedClass::GetPanelMap( void ) { return &m_PanelMap; }
  
  typedef vgui::Panel *( *PANELCREATEFUNC )( void );
  
  //-----------------------------------------------------------------------------
  // Purpose: Used by DECLARE_BUILD_FACTORY macro to create a linked list of
  //  instancing functions
  //-----------------------------------------------------------------------------
  class CBuildFactoryHelper
  {
  public:
  	// Static list of helpers
  	static CBuildFactoryHelper *m_sHelpers;
  
  public:
  	// Construction
  	CBuildFactoryHelper( char const *className, PANELCREATEFUNC func );
  
  	// Accessors
  	CBuildFactoryHelper *GetNext( void );
  
  	char const	*GetClassName() const;
  
  	vgui::Panel *CreatePanel();
  
  	static vgui::Panel *InstancePanel( char const *className );
  	static void GetFactoryNames( CUtlVector< char const * >& list );
  
  	static CDmxElement *CreatePanelDmxElement( vgui::Panel *pPanel );
  	static Panel* UnserializeDmxElementPanel( CDmxElement *pElement );
  
  	// DMX serializer fxns
  	static bool Serialize( CUtlBuffer &buf, vgui::Panel *pPanel );
  	static bool Unserialize( Panel **ppPanel, CUtlBuffer &buf, const char *pFileName = NULL );
  
  
  private:
  
  	static bool HasFactory( char const *className );
  
  	// Next factory in list
  	CBuildFactoryHelper	*m_pNext;
  
  	int					m_Type;
  	PANELCREATEFUNC		m_CreateFunc;
  	char const			*m_pClassName;
  };
  
  // This is the macro which implements creation of each type of panel
  // It creates a function which instances an object of the specified type
  // It them hooks that function up to the helper list so that the CHud objects can create
  //  the elements by name, with no header file dependency, etc.
  #define DECLARE_BUILD_FACTORY( className )										\
  	static vgui::Panel *Create_##className( void )							\
  		{																		\
  			return new className( NULL, NULL );									\
  		};																		\
  		static vgui::CBuildFactoryHelper g_##className##_Helper( #className, Create_##className );\
  	className *g_##className##LinkerHack = NULL;
  
  #define DECLARE_BUILD_FACTORY_DEFAULT_TEXT( className, defaultText )			\
  	static vgui::Panel *Create_##className( void )							\
  		{																		\
  			return new className( NULL, NULL, #defaultText );					\
  		};																		\
  	static vgui::CBuildFactoryHelper g_##className##_Helper( #className, Create_##className );\
  	className *g_##className##LinkerHack = NULL;
  
  // This one allows passing in a special function with calls new panel( xxx ) with arbitrary default parameters
  #define DECLARE_BUILD_FACTORY_CUSTOM( className, createFunc )					\
  	static vgui::CBuildFactoryHelper g_##className##_Helper( #className, createFunc );\
  	className *g_##className##LinkerHack = NULL;
  
  #define DECLARE_BUILD_FACTORY_CUSTOM_ALIAS( className, factoryName, createFunc )					\
  	static vgui::CBuildFactoryHelper g_##factoryName##_Helper( #factoryName, createFunc );\
  	className *g_##factoryName##LinkerHack = NULL;
  
  } // namespace vgui
  
  
  #endif // MESSAGEMAP_H
  