diff options
| author | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
|---|---|---|
| committer | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
| commit | 39ed87570bdb2f86969d4be821c94b722dc71179 (patch) | |
| tree | abc53757f75f40c80278e87650ea92808274aa59 /mp/src/game/client/panelmetaclassmgr.cpp | |
| download | source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip | |
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/game/client/panelmetaclassmgr.cpp')
| -rw-r--r-- | mp/src/game/client/panelmetaclassmgr.cpp | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/mp/src/game/client/panelmetaclassmgr.cpp b/mp/src/game/client/panelmetaclassmgr.cpp new file mode 100644 index 00000000..1b2064cb --- /dev/null +++ b/mp/src/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;
+}
+
+
|