summaryrefslogtreecommitdiff
path: root/vgui2/dme_controls/dmepanel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'vgui2/dme_controls/dmepanel.cpp')
-rw-r--r--vgui2/dme_controls/dmepanel.cpp656
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;
+}
+