|
|
//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#include "dme_controls/dmepanel.h"
#include "tier1/keyvalues.h"
#include "dme_controls/dmecontrols.h"
#include "vgui_controls/combobox.h"
#include "datamodel/dmelement.h"
#include "dme_controls/dmecontrols_utils.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
//-----------------------------------------------------------------------------
// All DmePanels used by the system must be listed here to link them in
//-----------------------------------------------------------------------------
USING_DMEPANEL_FACTORY( CDmeElementPanel, DmElement ); USING_DMEPANEL_FACTORY( CDmeSourceSkinPanel, DmeSourceSkin ); USING_DMEPANEL_FACTORY( CAssetBuilder, DmeMakefile ); USING_DMEPANEL_FACTORY( CDmeSourceDCCFilePanel, DmeSourceDCCFile ); USING_DMEPANEL_FACTORY( CDmeDagRenderPanel, DmeDag ); USING_DMEPANEL_FACTORY( CDmeDagRenderPanel, DmeSourceAnimation ); USING_DMEPANEL_FACTORY( CDmeDagRenderPanel, DmeSourceSkin ); USING_DMEPANEL_FACTORY( CDmeDagRenderPanel, DmeDCCMakefile ); USING_DMEPANEL_FACTORY( CDmeDagEditPanel, DmeDag ); USING_DMEPANEL_FACTORY( CDmeDagEditPanel, DmeSourceAnimation ); USING_DMEPANEL_FACTORY( CDmeDagEditPanel, DmeSourceSkin ); USING_DMEPANEL_FACTORY( CDmeDagEditPanel, DmeDCCMakefile ); USING_DMEPANEL_FACTORY( CDmeMDLPanel, DmeMDLMakefile );
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
CDmePanel::CDmePanel( vgui::Panel *pParent, const char *pPanelName, bool bComboBoxVisible ) : BaseClass( pParent, pPanelName ) { m_pEditorNames = new vgui::ComboBox( this, "EditorDisplayNames", 6, false ); if ( bComboBoxVisible ) { m_pEditorNames->AddActionSignalTarget( this ); } else { m_pEditorNames->SetVisible( false ); } m_pDmeEditorPanel = NULL; m_hElement = NULL;
SetDropEnabled( true ); }
CDmePanel::~CDmePanel() { DeleteCachedPanels(); }
//-----------------------------------------------------------------------------
// Scheme
//-----------------------------------------------------------------------------
void CDmePanel::ApplySchemeSettings( vgui::IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); m_pEditorNames->SetFont( pScheme->GetFont( "DefaultVerySmall" ) ); }
//-----------------------------------------------------------------------------
// Layout
//-----------------------------------------------------------------------------
void CDmePanel::PerformLayout() { BaseClass::PerformLayout();
int w, h; GetSize( w, h ); if ( m_pEditorNames->IsVisible() ) { m_pEditorNames->SetBounds( 1, 1, w-2, 20 ); if ( m_pDmeEditorPanel ) { m_pDmeEditorPanel->SetBounds( 0, 24, w, h-24 ); } } else { if ( m_pDmeEditorPanel ) { m_pDmeEditorPanel->SetBounds( 0, 0, w, h ); } } }
//-----------------------------------------------------------------------------
// Drag/drop
//-----------------------------------------------------------------------------
bool CDmePanel::IsDroppable( CUtlVector< KeyValues * >& msglist ) { if ( msglist.Count() != 1 ) return false;
KeyValues *data = msglist[ 0 ]; CDmElement *ptr = GetElementKeyValue<CDmElement>( data, "dmeelement" ); if ( !ptr ) return false;
if ( ptr == m_hElement.Get() ) return false;
return true; }
void CDmePanel::OnPanelDropped( CUtlVector< KeyValues * >& msglist ) { if ( msglist.Count() != 1 ) return;
KeyValues *data = msglist[ 0 ]; CDmElement *ptr = GetElementKeyValue<CDmElement>( data, "dmeelement" ); if ( !ptr ) return;
// Already browsing
if ( ptr == m_hElement.Get() ) return;
SetDmeElement( ptr ); }
//-----------------------------------------------------------------------------
// Sets the default editor type
//-----------------------------------------------------------------------------
void CDmePanel::SetDefaultEditorType( const char *pEditorType ) { m_DefaultEditorType = pEditorType; }
//-----------------------------------------------------------------------------
// Populate editor name combo box
//-----------------------------------------------------------------------------
void CDmePanel::PopulateEditorNames( const char *pPanelName ) { m_pEditorNames->RemoveAll(); m_pEditorNames->SetText( "" ); if ( !m_pEditorNames->IsVisible() ) { SetEditor( pPanelName ); return; }
if ( !m_hElement.Get() ) { OnTextChanged(); return; }
const char *pPreferredEditor = NULL; if ( m_LastUsedEditorType.Defined( m_hElement->GetTypeString() ) ) { pPreferredEditor = m_LastUsedEditorType[ m_hElement->GetTypeString() ].Get(); } else { pPreferredEditor = m_DefaultEditorType; }
int nBestInheritanceDepth = -1; int nActiveItemID = -1; bool bFoundPanelName = false; DmeFactoryHandle_t h = DmePanelFirstFactory( m_hElement.Get() ); for ( ; h != DMEFACTORY_HANDLE_INVALID; h = DmePanelNextFactory( h, m_hElement.Get() ) ) { const char *pDisplayName = DmePanelFactoryDisplayName( h ); const char *pEditorName = DmePanelFactoryName( h ); KeyValues *pKeyValues = new KeyValues( "entry", "editorName", pEditorName );
int nItemID = m_pEditorNames->AddItem( pDisplayName, pKeyValues );
if ( pPanelName && !Q_stricmp( pPanelName, pEditorName ) ) { nBestInheritanceDepth = 0; nActiveItemID = nItemID; bFoundPanelName = true; continue; }
if ( pPreferredEditor && !bFoundPanelName && !Q_stricmp( pPreferredEditor, pEditorName ) ) { nBestInheritanceDepth = 0; nActiveItemID = nItemID; continue; }
// Don't select this as the default if it's not a default factory
if ( !DmePanelFactoryIsDefault(h) ) continue;
// Choose this factory if it's more derived than the previous best
const char *pElementType = DmePanelFactoryElementType( h ); int nInheritanceDepth = m_hElement->GetInheritanceDepth( pElementType ); Assert( nInheritanceDepth >= 0 ); if ( nBestInheritanceDepth >= 0 && ( nInheritanceDepth >= nBestInheritanceDepth ) ) continue;
nBestInheritanceDepth = nInheritanceDepth; nActiveItemID = nItemID; }
if ( m_pEditorNames->GetItemCount() == 0 ) { // ItemCount == 0;
m_pEditorNames->SetText( "" ); m_CurrentEditorName = NULL; OnTextChanged(); return; }
if ( nActiveItemID >= 0 ) { m_pEditorNames->ActivateItem( nActiveItemID ); } else { m_pEditorNames->ActivateItemByRow( 0 ); } }
//-----------------------------------------------------------------------------
// Called when the dme element was changed
//-----------------------------------------------------------------------------
void CDmePanel::OnDmeElementChanged() { PostActionSignal( new KeyValues( "DmeElementChanged" ) ); }
//-----------------------------------------------------------------------------
// Context menu support
//-----------------------------------------------------------------------------
void CDmePanel::OnOpenContextMenu( KeyValues *params ) { // Forward the context menu message to the DME panel
KeyValues *pMsg = params->MakeCopy(); if ( m_pDmeEditorPanel ) { PostMessage( m_pDmeEditorPanel->GetVPanel(), pMsg ); } }
//-----------------------------------------------------------------------------
// Copy/paste support
//-----------------------------------------------------------------------------
void CDmePanel::PostMessageToDmePanel( const char *pMessage ) { if ( m_pDmeEditorPanel ) { PostMessage( m_pDmeEditorPanel->GetVPanel(), new KeyValues( pMessage ) ); } }
void CDmePanel::OnCut() { PostMessageToDmePanel( "OnCut" ); }
void CDmePanel::OnCopy() { PostMessageToDmePanel( "OnCopy" ); }
void CDmePanel::OnPaste() { PostMessageToDmePanel( "OnPaste" ); }
void CDmePanel::OnPasteInsert() { PostMessageToDmePanel( "OnPasteInsert" ); }
void CDmePanel::OnPasteReference() { PostMessageToDmePanel( "OnPasteReference" ); }
void CDmePanel::OnEditDelete() { PostMessageToDmePanel( "OnEditDelete" ); }
//-----------------------------------------------------------------------------
// Called when a child of the dme panel switches the thing it's looking at
//-----------------------------------------------------------------------------
void CDmePanel::OnViewedElementChanged( KeyValues *kv ) { // This is kind of tricky. It's called by the element properties tree
// when doing the back/forward searching. Just calling the normal SetDmeElement
// doesn't work because it reorders the history. What we want is to
// populate the combo box without causing the OnTextChanged message to get sent.
// FIXME: Perhaps it would be better to extract the back/forward/search
// out of the element properties tree and put it into the dme panel?
CDmElement *pElement = GetElementKeyValue<CDmElement>( kv, "dmeelement" ); if ( pElement == m_hElement ) return;
// If the current editor isn't supported by this new element, then just reset. Too bad.
bool bFound = false; if ( m_CurrentEditorName.Length() && pElement ) { DmeFactoryHandle_t h = DmePanelFirstFactory( pElement ); for ( ; h != DMEFACTORY_HANDLE_INVALID; h = DmePanelNextFactory( h, pElement ) ) { const char *pEditorName = DmePanelFactoryName( h ); if ( !Q_stricmp( m_CurrentEditorName, pEditorName ) ) { bFound = true; break; } } }
if ( !bFound ) { SetDmeElement( pElement ); return; }
// Remove obsolete items
int nCount = m_pEditorNames->GetItemCount(); while ( --nCount >= 0 ) { int nItemID = m_pEditorNames->GetItemIDFromRow( nCount ); KeyValues *kv = m_pEditorNames->GetItemUserData( nItemID ); if ( Q_stricmp( m_CurrentEditorName, kv->GetString( "editorName" ) ) ) { m_pEditorNames->DeleteItem( nItemID ); } }
// Just want to populate the combo box with new items
DmeFactoryHandle_t h = DmePanelFirstFactory( pElement ); for ( ; h != DMEFACTORY_HANDLE_INVALID; h = DmePanelNextFactory( h, pElement ) ) { const char *pEditorName = DmePanelFactoryName( h ); if ( Q_stricmp( pEditorName, m_CurrentEditorName ) ) { const char *pDisplayName = DmePanelFactoryDisplayName( h ); KeyValues *pKeyValues = new KeyValues( "entry", "editorName", pEditorName ); m_pEditorNames->AddItem( pDisplayName, pKeyValues ); } }
m_hElement = pElement; }
//-----------------------------------------------------------------------------
// Delete cached panels
//-----------------------------------------------------------------------------
void CDmePanel::DeleteCachedPanels() { int nCount = m_EditorPanelCache.GetNumStrings(); for ( int i = 0; i < nCount; ++i ) { int nEditorCount = m_EditorPanelCache[ i ].Count(); for ( int j = 0; j < nEditorCount; ++j ) { m_EditorPanelCache[ i ][ j ].m_pEditorPanel->MarkForDeletion(); } } m_EditorPanelCache.Clear(); }
//-----------------------------------------------------------------------------
// Refreshes the current panel owing to external change
// Values only means no topological change
//-----------------------------------------------------------------------------
void CDmePanel::Refresh( bool bValuesOnly ) { if ( m_pDmeEditorPanel ) { KeyValues *pKeyValues = new KeyValues( "ElementChangedExternally", "valuesOnly", bValuesOnly ); PostMessage( m_pDmeEditorPanel, pKeyValues ); } }
//-----------------------------------------------------------------------------
// Deactivates the current editor
//-----------------------------------------------------------------------------
void CDmePanel::DeactivateCurrentEditor() { if ( m_pDmeEditorPanel ) { m_pDmeEditorPanel->SetParent( (vgui::Panel*)NULL ); m_pDmeEditorPanel = NULL; m_CurrentEditorName = NULL; } }
//-----------------------------------------------------------------------------
// Switch to a new editor
//-----------------------------------------------------------------------------
void CDmePanel::SetEditor( const char *pEditorName ) { if ( pEditorName && !Q_stricmp( m_CurrentEditorName, pEditorName ) ) return;
DeactivateCurrentEditor();
if ( !m_hElement.Get() || !pEditorName ) return;
if ( m_EditorPanelCache.Defined( pEditorName ) ) { CUtlVector< EditorPanelMap_t > &entries = m_EditorPanelCache[ pEditorName ]; int nCount = entries.Count(); for ( int i = 0; i < nCount; ++i ) { EditorPanelMap_t &entry = entries[i]; if ( !m_hElement->IsA( entry.m_pFactory->m_pElementType ) ) continue;
m_pDmeEditorPanel = entry.m_pEditorPanel; m_pDmeEditorPanel->SetParent( this ); entry.m_pFactory->SetDmeElement( m_pDmeEditorPanel, m_hElement ); break; } } if ( !m_pDmeEditorPanel ) { EditorPanelMap_t entry; if ( CreateDmePanel( this, "DmePanelEditor", m_hElement, pEditorName, &entry ) ) { m_EditorPanelCache[ pEditorName ].AddToTail( entry ); m_pDmeEditorPanel = entry.m_pEditorPanel; } }
if ( m_pDmeEditorPanel ) { // Store the last selected type of editor
m_LastUsedEditorType[ m_hElement->GetTypeString() ] = pEditorName; m_CurrentEditorName = pEditorName; m_pDmeEditorPanel->AddActionSignalTarget( this ); } InvalidateLayout(); }
//-----------------------------------------------------------------------------
// Called when a new element in the combo box has been selected
//-----------------------------------------------------------------------------
void CDmePanel::OnTextChanged() { KeyValues *kv = m_pEditorNames->GetActiveItemUserData(); const char *pEditorName = kv ? kv->GetString( "editorName", NULL ) : NULL; SetEditor( pEditorName ); }
//-----------------------------------------------------------------------------
// Setting a new element
//-----------------------------------------------------------------------------
void CDmePanel::SetDmeElement( CDmElement *pDmeElement, bool bForce, const char *pPanelName ) { if ( ( m_hElement == pDmeElement ) && !bForce ) { if ( !pPanelName || !Q_stricmp( pPanelName, m_CurrentEditorName.Get() ) ) return; }
m_hElement = pDmeElement; m_CurrentEditorName = NULL;
// Populate the editor type list
PopulateEditorNames( pPanelName ); }
//-----------------------------------------------------------------------------
// Statics for the panel factory
//-----------------------------------------------------------------------------
CBaseDmePanelFactory* CBaseDmePanelFactory::s_pFirstDmePanelFactory;
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
CBaseDmePanelFactory::CBaseDmePanelFactory( const char *pElementType, const char *pEditorName, const char *pEditorDisplayName, bool bIsDefault, bool bIsOverride ) { // Prior to linking this in, look to see if this has been overridden
CBaseDmePanelFactory *pPrevFactory = NULL; for( CBaseDmePanelFactory* pFactory = s_pFirstDmePanelFactory; pFactory; pPrevFactory = pFactory, pFactory = pFactory->m_pNext ) { if ( !Q_stricmp( pFactory->m_pElementType, pElementType ) && !Q_stricmp( pFactory->m_pEditorDisplayName, pEditorDisplayName ) ) { // Collision found! If this is not an override, then we've been overridden
if ( !bIsOverride ) { AssertMsg( pFactory->m_bIsOverride, ( "Two DmePanel factories have the same name (\"%s\") + type (\"%s\")!\n", pElementType, pEditorName ) ); return; }
// If this *is* an override, replace the previous version
AssertMsg( !pFactory->m_bIsOverride, ( "Two DmePanel factories have the same name (\"%s\") + type (\"%s\")!\n", pElementType, pEditorName ) ); if ( pPrevFactory ) { pPrevFactory->m_pNext = pFactory->m_pNext; } else { s_pFirstDmePanelFactory = pFactory->m_pNext; } break; } }
m_pNext = s_pFirstDmePanelFactory; s_pFirstDmePanelFactory = this;
m_pElementType = pElementType; m_pEditorName = pEditorName; m_pEditorDisplayName = pEditorDisplayName; m_bIsDefault = bIsDefault; m_bIsOverride = bIsOverride; }
//-----------------------------------------------------------------------------
// Dme Panel factory iteration methods
//-----------------------------------------------------------------------------
DmeFactoryHandle_t DmePanelFirstFactory( CDmElement *pElement ) { CBaseDmePanelFactory *pFactory = CBaseDmePanelFactory::s_pFirstDmePanelFactory; for ( ; pFactory; pFactory = pFactory->m_pNext ) { if ( !pElement || pElement->IsA( pFactory->m_pElementType ) ) return (DmeFactoryHandle_t)pFactory; }
return DMEFACTORY_HANDLE_INVALID; }
DmeFactoryHandle_t DmePanelNextFactory( DmeFactoryHandle_t h, CDmElement *pElement ) { CBaseDmePanelFactory *pFactory = (CBaseDmePanelFactory*)h; if ( !pFactory ) return DMEFACTORY_HANDLE_INVALID;
for ( pFactory = pFactory->m_pNext; pFactory; pFactory = pFactory->m_pNext ) { if ( !pElement || pElement->IsA( pFactory->m_pElementType ) ) return (DmeFactoryHandle_t)pFactory; }
return DMEFACTORY_HANDLE_INVALID; }
//-----------------------------------------------------------------------------
// Dme Panel factory info methods
//-----------------------------------------------------------------------------
const char *DmePanelFactoryName( DmeFactoryHandle_t h ) { CBaseDmePanelFactory *pFactory = (CBaseDmePanelFactory*)h; return pFactory ? pFactory->m_pEditorName : NULL; }
const char *DmePanelFactoryDisplayName( DmeFactoryHandle_t h ) { CBaseDmePanelFactory *pFactory = (CBaseDmePanelFactory*)h; return pFactory ? pFactory->m_pEditorDisplayName : NULL; }
const char *DmePanelFactoryElementType( DmeFactoryHandle_t h ) { CBaseDmePanelFactory *pFactory = (CBaseDmePanelFactory*)h; return pFactory ? pFactory->m_pElementType : NULL; }
bool DmePanelFactoryIsDefault( DmeFactoryHandle_t h ) { CBaseDmePanelFactory *pFactory = (CBaseDmePanelFactory*)h; return pFactory ? pFactory->m_bIsDefault : false; }
//-----------------------------------------------------------------------------
// Dme Panel factory methods
//-----------------------------------------------------------------------------
bool CDmePanel::CreateDmePanel( vgui::Panel *pParent, const char *pPanelName, CDmElement *pElement, const char *pEditorName, EditorPanelMap_t *pMap ) { int nBestInheritanceDepth = -1; CBaseDmePanelFactory *pBestFactory = NULL; CBaseDmePanelFactory *pFactory = CBaseDmePanelFactory::s_pFirstDmePanelFactory; for ( ; pFactory; pFactory = pFactory->m_pNext ) { if ( !pElement->IsA( pFactory->m_pElementType ) ) continue; if ( pEditorName ) { if ( !Q_stricmp( pEditorName, pFactory->m_pEditorName ) ) { pBestFactory = pFactory; break; } continue; }
// No editor name specified? Only use default factories
if ( !pFactory->m_bIsDefault ) continue;
// Choose this factory if it's more derived than the previous best
int nInheritanceDepth = pElement->GetInheritanceDepth( pFactory->m_pElementType ); Assert( nInheritanceDepth >= 0 ); if ( nBestInheritanceDepth >= 0 && ( nInheritanceDepth > nBestInheritanceDepth ) ) continue;
nBestInheritanceDepth = nInheritanceDepth; pBestFactory = pFactory; }
if ( pBestFactory ) { pMap->m_pFactory = pBestFactory; pMap->m_pEditorPanel = pBestFactory->CreateDmePanel( pParent, pPanelName, pElement ); return true; } return false; }
|