diff options
Diffstat (limited to 'vgui2/dme_controls/dmepanel.cpp')
| -rw-r--r-- | vgui2/dme_controls/dmepanel.cpp | 656 |
1 files changed, 656 insertions, 0 deletions
diff --git a/vgui2/dme_controls/dmepanel.cpp b/vgui2/dme_controls/dmepanel.cpp new file mode 100644 index 0000000..b653a1f --- /dev/null +++ b/vgui2/dme_controls/dmepanel.cpp @@ -0,0 +1,656 @@ +//========= Copyright 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; +} + |