You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
437 lines
13 KiB
437 lines
13 KiB
//========= 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; |
|
} |
|
|
|
|
|
|