diff options
Diffstat (limited to 'game/client/panelmetaclassmgr.cpp')
| -rw-r--r-- | game/client/panelmetaclassmgr.cpp | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/game/client/panelmetaclassmgr.cpp b/game/client/panelmetaclassmgr.cpp new file mode 100644 index 0000000..6f0b50d --- /dev/null +++ b/game/client/panelmetaclassmgr.cpp @@ -0,0 +1,437 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A panel "metaclass" is a name given to a particular type of +// panel with particular instance data. Such panels tend to be dynamically +// added and removed from their parent panels. +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "panelmetaclassmgr.h" +#include <KeyValues.h> +#include <vgui_controls/Panel.h> +#include "utldict.h" +#include "filesystem.h" +#include <KeyValues.h> + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Helper KeyValue parsing methods +//----------------------------------------------------------------------------- +bool ParseRGBA( KeyValues *pValues, const char* pFieldName, int& r, int& g, int& b, int& a ) +{ + r = g = b = a = 255; + const char *pColorString = pValues->GetString( pFieldName, "255 255 255 255" ); + if ( !pColorString || !pColorString[ 0 ] ) + return false; + + // Try and scan them in + int scanned; + scanned = sscanf( pColorString, "%i %i %i %i", &r, &g, &b, &a ); + if ( scanned != 4 ) + { + Warning( "Couldn't scan four color values from %s\n", pColorString ); + return false; + } + + return true; +} + +bool ParseRGBA( KeyValues* pValues, const char* pFieldName, Color& c ) +{ + int r, g, b, a; + if (!ParseRGBA( pValues, pFieldName, r, g, b, a )) + return false; + + c.SetColor( r, g, b, a ); + return true; +} + +//----------------------------------------------------------------------------- +// FIXME: Why do we have vgui::KeyValues too!?!??! Bleah +/*----------------------------------------------------------------------------- +bool ParseRGBA( KeyValues *pValues, const char* pFieldName, int& r, int& g, int& b, int& a ) +{ + r = g = b = a = 255; + const char *pColorString = pValues->GetString( pFieldName, "255 255 255 255" ); + if ( !pColorString || !pColorString[ 0 ] ) + return false; + + // Try and scan them in + int scanned; + scanned = sscanf( pColorString, "%i %i %i %i", &r, &g, &b, &a ); + if ( scanned != 4 ) + { + Warning( "Couldn't scan four color values from %s\n", pColorString ); + return false; + } + + return true; +} + +bool ParseRGBA( KeyValues* pValues, const char* pFieldName, Color& c ) +{ + int r, g, b, a; + if (!ParseRGBA( pValues, pFieldName, r, g, b, a )) + return false; + + c.SetColor( r, g, b, a ); + return true; +} */ + + +bool ParseCoord( KeyValues *pValues, const char* pFieldName, int& x, int& y ) +{ + x = y = 0; + const char *pCoordString = pValues->GetString( pFieldName, "0 0" ); + if ( !pCoordString || !pCoordString[ 0 ] ) + return false; + + // Try and scan them in + int scanned; + scanned = sscanf( pCoordString, "%i %i", &x, &y ); + if ( scanned != 2 ) + { + Warning( "Couldn't scan 2d coordinate values from %s\n", pCoordString ); + return false; + } + + // coords are within 640x480 screen space + x = ( x * ( ( float )ScreenWidth() / 640.0 ) ); + y = ( y * ( ( float )ScreenHeight() / 480.0 ) ); + + return true; +} + +bool ParseRect( KeyValues *pValues, const char* pFieldName, int& x, int& y, int& w, int& h ) +{ + x = y = w = h = 0; + const char *pRectString = pValues->GetString( pFieldName, "0 0 0 0" ); + if ( !pRectString || !pRectString[ 0 ] ) + return false; + + // Try and scan them in + int scanned; + scanned = sscanf( pRectString, "%i %i %i %i", &x, &y, &w, &h ); + if ( scanned != 4 ) + { + Warning( "Couldn't scan rectangle values from %s\n", pRectString ); + return false; + } + + // coords are within 640x480 screen space + x = ( x * ( ( float )ScreenWidth() / 640.0 ) ); + y = ( y * ( ( float )ScreenHeight() / 480.0 ) ); + w = ( w * ( ( float )ScreenWidth() / 640.0 ) ); + h = ( h * ( ( float )ScreenHeight() / 480.0 ) ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Helper class to make meta class panels (for use in entities, so they autocleanup) +//----------------------------------------------------------------------------- +CPanelWrapper::CPanelWrapper() : m_pPanel(NULL) +{ +} + +CPanelWrapper::~CPanelWrapper() +{ + Deactivate(); +} + +void CPanelWrapper::Activate( char const* pMetaClassName, vgui::Panel *pParent, int sortorder, void *pVoidInitData ) +{ + if ( m_pPanel ) + { + Deactivate(); + } + + m_pPanel = PanelMetaClassMgr()->CreatePanelMetaClass( pMetaClassName, sortorder, pVoidInitData, pParent ); +} + +void CPanelWrapper::Deactivate( void ) +{ + if ( m_pPanel ) + { + PanelMetaClassMgr()->DestroyPanelMetaClass( m_pPanel ); + m_pPanel = NULL; + } +} + +vgui::Panel *CPanelWrapper::GetPanel( ) +{ + return m_pPanel; +} + + +//----------------------------------------------------------------------------- +// Purpose: Singleton class responsible for managing metaclass panels +//----------------------------------------------------------------------------- +class CPanelMetaClassMgrImp : public IPanelMetaClassMgr +{ +public: + // constructor, destructor + CPanelMetaClassMgrImp(); + virtual ~CPanelMetaClassMgrImp(); + + // Members of IPanelMetaClassMgr + virtual void LoadMetaClassDefinitionFile( const char* pLevelName ); + virtual void InstallPanelType( const char* pPanelName, IPanelFactory* pFactory ); + virtual vgui::Panel *CreatePanelMetaClass( const char* pMetaClassName, + int sortorder, void *pInitData, vgui::Panel *pParent, const char *pChainName ); + virtual void DestroyPanelMetaClass( vgui::Panel *pPanel ); + +private: + struct MetaClassDict_t + { + unsigned short m_KeyValueIndex; + unsigned short m_TypeIndex; + KeyValues* m_pKeyValues; + }; + + // various parsing helper methods + bool ParseSingleMetaClass( const char* pFileName, const char* pInstanceName, + KeyValues* pMetaClass, int keyValueIndex ); + bool ParseMetaClassList( const char* pFileName, KeyValues* pKeyValues, int keyValueIndex ); + + // No copy constructor + CPanelMetaClassMgrImp( const CPanelMetaClassMgrImp & ); + + // List of panel types... + CUtlDict< IPanelFactory*, unsigned short > m_PanelTypeDict; + + // List of metaclass types + CUtlDict< MetaClassDict_t, unsigned short > m_MetaClassDict; + + // Create key value accesor + CUtlDict< KeyValues*, unsigned short > m_MetaClassKeyValues; +}; + + +//----------------------------------------------------------------------------- +// Returns the singleton panel metaclass mgr interface +//----------------------------------------------------------------------------- +IPanelMetaClassMgr* PanelMetaClassMgr() +{ + // NOTE: the CPanelFactory implementation requires the local static here + // even though it means an extra check every time PanelMetaClassMgr is accessed + static CPanelMetaClassMgrImp s_MetaClassMgrImp; + return &s_MetaClassMgrImp; +} + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +CPanelMetaClassMgrImp::CPanelMetaClassMgrImp() : m_PanelTypeDict( true, 0, 32 ) +{ +} + +CPanelMetaClassMgrImp::~CPanelMetaClassMgrImp() +{ +} + + +//----------------------------------------------------------------------------- +// Call this to install a new panel type +//----------------------------------------------------------------------------- +void CPanelMetaClassMgrImp::InstallPanelType( const char* pPanelName, IPanelFactory* pFactory ) +{ + Assert( pPanelName && pFactory ); + + // convert to lowercase + int len = Q_strlen(pPanelName) + 1; + char* pTemp = (char*)stackalloc( len ); + Q_strncpy( pTemp, pPanelName, len ); + Q_strnlwr( pTemp, len ); + + m_PanelTypeDict.Insert( pTemp, pFactory ); + + stackfree( pTemp ); +} + + +//----------------------------------------------------------------------------- +// Parse a single metaclass +//----------------------------------------------------------------------------- +bool CPanelMetaClassMgrImp::ParseSingleMetaClass( const char* pFileName, + const char* pMetaClassName, KeyValues* pMetaClassValues, int keyValueIndex ) +{ + // Complain about duplicately defined metaclass names... + if ( m_MetaClassDict.Find( pMetaClassName ) != m_MetaClassDict.InvalidIndex() ) + { + Warning( "Meta class %s duplicately defined (file %s)\n", pMetaClassName, pFileName ); + return false; + } + + // find the type... + const char* pPanelType = pMetaClassValues->GetString( "type" ); + if (!pPanelType || !pPanelType[0]) + { + Warning( "Unable to find type of meta class %s in file %s\n", pMetaClassName, pFileName ); + return false; + } + + unsigned short i = m_PanelTypeDict.Find( pPanelType ); + if (i == m_PanelTypeDict.InvalidIndex()) + { + Warning( "Type %s of meta class %s undefined!\n", pPanelType, pMetaClassName ); + stackfree(pLwrMetaClass); + return false; + } + + // Add it to the metaclass dictionary + MetaClassDict_t element; + element.m_TypeIndex = i; + element.m_KeyValueIndex = keyValueIndex; + element.m_pKeyValues = pMetaClassValues; + m_MetaClassDict.Insert( pMetaClassName, element ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Parse the metaclass list +//----------------------------------------------------------------------------- +bool CPanelMetaClassMgrImp::ParseMetaClassList( const char* pFileName, + KeyValues* pKeyValues, int keyValueIdx ) +{ + // Iterate over all metaclasses... + KeyValues* pIter = pKeyValues->GetFirstSubKey(); + while( pIter ) + { + if (!ParseSingleMetaClass( pFileName, pIter->GetName(), pIter, keyValueIdx )) + { + // return false; + Warning( "MetaClass missing for %s\n", pIter->GetName() ); + } + pIter = pIter->GetNextKey(); + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Loads up a file containing metaclass definitions +//----------------------------------------------------------------------------- +void CPanelMetaClassMgrImp::LoadMetaClassDefinitionFile( const char *pFileName ) +{ + MEM_ALLOC_CREDIT(); + + // Blat out previous metaclass definitions read in from this file... + int i = m_MetaClassKeyValues.Find( pFileName ); + if (i != m_MetaClassKeyValues.InvalidIndex() ) + { + // Blow away the previous keyvalues from that file + unsigned short j = m_MetaClassDict.First(); + while ( j != m_MetaClassDict.InvalidIndex() ) + { + unsigned short next = m_MetaClassDict.Next(j); + if ( m_MetaClassDict[j].m_KeyValueIndex == i) + { + m_MetaClassDict.RemoveAt(j); + } + + j = next; + } + + m_MetaClassKeyValues[i]->deleteThis(); + m_MetaClassKeyValues.RemoveAt(i); + } + + // Create a new keyvalues entry + KeyValues* pKeyValues = new KeyValues(pFileName); + int idx = m_MetaClassKeyValues.Insert( pFileName, pKeyValues ); + + // Read in all metaclass definitions... + + // Load the file + if ( !pKeyValues->LoadFromFile( filesystem, pFileName ) ) + { + Warning( "Couldn't find metaclass definition file %s\n", pFileName ); + pKeyValues->deleteThis(); + m_MetaClassKeyValues.RemoveAt(idx); + return; + } + else + { + // Go ahead and parse the data now + if ( !ParseMetaClassList( pFileName, pKeyValues, idx ) ) + { + Warning( "Detected one or more errors parsing %s\n", pFileName ); + } + } +} + + +//----------------------------------------------------------------------------- +// Performs key value chaining +//----------------------------------------------------------------------------- +static void KeyValueChainRecursive( KeyValues* pKeyValues, const char *pSectionName ) +{ + KeyValues* pSection = pKeyValues->FindKey( pSectionName ); + + if (pSection) + { + pKeyValues->ChainKeyValue( pSection ); + } + + KeyValues* pIter = pKeyValues->GetFirstSubKey(); + while (pIter) + { + // Don't both setting up links on a keyvalue that has no children + if (pIter->GetFirstSubKey()) + KeyValueChainRecursive( pIter, pSectionName ); + + pIter = pIter->GetNextKey(); + } +} + + +//----------------------------------------------------------------------------- +// Create, destroy panel... +//----------------------------------------------------------------------------- +vgui::Panel *CPanelMetaClassMgrImp::CreatePanelMetaClass( const char* pMetaClassName, + int sortorder, void *pInitData, vgui::Panel *pParent, const char *pChainName ) +{ + // Search for the metaclass name + int i = m_MetaClassDict.Find( pMetaClassName ); + if (i == m_MetaClassDict.InvalidIndex()) + return NULL; + + // Now that we've got the metaclass, we can figure out what kind of + // panel to instantiate... + MetaClassDict_t &metaClass = m_MetaClassDict[i]; + IPanelFactory* pFactory = m_PanelTypeDict[metaClass.m_TypeIndex]; + + // Set up the key values for use in initialization + if (pChainName) + { + KeyValueChainRecursive( metaClass.m_pKeyValues, pChainName ); + } + + // Create and initialize the panel + vgui::Panel *pPanel = pFactory->Create( pMetaClassName, metaClass.m_pKeyValues, pInitData, pParent ); + if ( pPanel ) + { + pPanel->SetZPos( sortorder ); + } + + return pPanel; +} + +void CPanelMetaClassMgrImp::DestroyPanelMetaClass( vgui::Panel *pPanel ) +{ +// if ( pPanel ) +// pPanel->MarkForDeletion(); + delete pPanel; +} + + |