//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #ifndef MESSAGEMAP_H #define MESSAGEMAP_H #ifdef _WIN32 #pragma once #endif #include "../tier1/utlvector.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 ////////////// //----------------------------------------------------------------------------- // 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 }; #ifdef WIN32 class __virtual_inheritance Panel; #else class Panel; #endif 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 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 &list); 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