//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= // // Purpose: // //============================================================================= #include "dme_controls/AssetBuilder.h" #include "dme_controls/DmePanel.h" #include "dme_controls/dmecontrols_utils.h" #include "tier1/keyvalues.h" #include "vgui_controls/ListPanel.h" #include "vgui_controls/MenuButton.h" #include "vgui_controls/TextEntry.h" #include "vgui_controls/MessageBox.h" #include "vgui_controls/ComboBox.h" #include "vgui_controls/FileOpenDialog.h" #include "vgui_controls/Splitter.h" #include "vgui_controls/FileOpenStateMachine.h" #include "vgui_controls/PropertySheet.h" #include "vgui_controls/PropertyPage.h" #include "vgui/ischeme.h" #include "vgui/ivgui.h" #include "vgui/isurface.h" #include "tier1/tier1.h" #include "movieobjects/dmemakefile.h" #include "matsys_controls/picker.h" #include "tier2/fileutils.h" #include "vgui/keycode.h" #include "filesystem.h" #include "movieobjects/idmemakefileutils.h" #include "tier3/tier3.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" using namespace vgui; #define ASSET_FILE_FORMAT "model" //----------------------------------------------------------------------------- // Compile status bar //----------------------------------------------------------------------------- class CCompileStatusBar : public vgui::EditablePanel { DECLARE_CLASS_SIMPLE( CCompileStatusBar, EditablePanel ); public: enum CompileStatus_t { NOT_COMPILING, CURRENTLY_COMPILING, COMPILATION_FAILED, COMPILATION_SUCCESSFUL }; CCompileStatusBar( vgui::Panel *pParent, const char *pPanelName ); virtual ~CCompileStatusBar(); virtual void PaintBackground(); void SetStatus( CompileStatus_t status, const char *pMessage ); private: vgui::Label *m_pStatus; CompileStatus_t m_Status; int m_CompilingId; }; //----------------------------------------------------------------------------- // Constructor, destructor //----------------------------------------------------------------------------- CCompileStatusBar::CCompileStatusBar( vgui::Panel *pParent, const char *pPanelName ) : BaseClass( pParent, pPanelName ) { m_pStatus = new vgui::Label( this, "StatusLabel", "" ); m_pStatus->SetAutoResize( PIN_TOPLEFT, AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 ); m_pStatus->SetContentAlignment( vgui::Label::a_center ); m_pStatus->SetTextColorState( vgui::Label::CS_BRIGHT ); SetStatus( NOT_COMPILING, "" ); SetPaintBackgroundEnabled( true ); m_CompilingId = vgui::surface()->DrawGetTextureId( "vgui/progressbar" ); if ( m_CompilingId == -1 ) // we didn't find it, so create a new one { m_CompilingId = vgui::surface()->CreateNewTextureID(); } vgui::surface()->DrawSetTextureFile( m_CompilingId, "vgui/progressbar", true, false ); } CCompileStatusBar::~CCompileStatusBar() { } //----------------------------------------------------------------------------- // Sets compile status //----------------------------------------------------------------------------- void CCompileStatusBar::SetStatus( CompileStatus_t status, const char *pMessage ) { m_Status = status; m_pStatus->SetText( pMessage ); } void CCompileStatusBar::PaintBackground() { int w, h; GetSize( w, h ); switch( m_Status ) { case NOT_COMPILING: break; case COMPILATION_FAILED: vgui::surface()->DrawSetColor( 255, 0, 0, 255 ); vgui::surface()->DrawFilledRect( 0, 0, w, h ); break; case COMPILATION_SUCCESSFUL: vgui::surface()->DrawSetColor( 0, 255, 0, 255 ); vgui::surface()->DrawFilledRect( 0, 0, w, h ); break; case CURRENTLY_COMPILING: { float du = Plat_FloatTime() / 5.0f; du -= (int)du; du = 1.0f - du; Vertex_t verts[4]; verts[0].Init( Vector2D( 0.0f, 0.0f ), Vector2D( du, 0.0f ) ); verts[1].Init( Vector2D( w, 0.0f ), Vector2D( 1.0f + du, 0.0f ) ); verts[2].Init( Vector2D( w, h ), Vector2D( 1.0f + du, 1.0f ) ); verts[3].Init( Vector2D( 0.0f, h ), Vector2D( du, 1.0f ) ); vgui::surface()->DrawSetColor( 255, 255, 255, 255 ); vgui::surface()->DrawSetTexture( m_CompilingId ); vgui::surface()->DrawTexturedPolygon( 4, verts ); } break; } } //----------------------------------------------------------------------------- // // Asset Builder // //----------------------------------------------------------------------------- IMPLEMENT_DMEPANEL_FACTORY( CAssetBuilder, DmeMakefile, "DmeMakeFileDefault", "MakeFile Editor", true ); //----------------------------------------------------------------------------- // Static data //----------------------------------------------------------------------------- static PickerList_t s_AssetTypes; static bool s_bAssetTypeListBuilt = false; //----------------------------------------------------------------------------- // Builds the list of asset types //----------------------------------------------------------------------------- void BuildAssetTypeList( ) { if ( s_bAssetTypeListBuilt ) return; s_bAssetTypeListBuilt = true; CDisableUndoScopeGuard guard; int hFactory = g_pDataModel->GetFirstFactory(); while ( g_pDataModel->IsValidFactory( hFactory ) ) { // Add all DmeElements that inherit from DmeMakefile const char *pFactoryName = g_pDataModel->GetFactoryName( hFactory ); CDmElement *pElement = GetElement< CDmElement >( g_pDataModel->CreateElement( pFactoryName, "temp", DMFILEID_INVALID ) ); CDmeMakefile *pMakeFile = CastElement( pElement ); if ( pMakeFile && pMakeFile->GetMakefileType() ) { int i = s_AssetTypes.AddToTail(); s_AssetTypes[i].m_pChoiceString = pMakeFile->GetMakefileType()->m_pHumanReadableName; s_AssetTypes[i].m_pChoiceValue = pFactoryName; } DestroyElement( pElement ); hFactory = g_pDataModel->GetNextFactory( hFactory ); } } //----------------------------------------------------------------------------- // Builds the list of asset types //----------------------------------------------------------------------------- static PickerList_t &BuildAssetSubTypeList( const char **ppSubTypes, PickerList_t &pickerList ) { if ( !ppSubTypes ) return s_AssetTypes; pickerList.RemoveAll(); CDisableUndoScopeGuard guard; int nCount = s_AssetTypes.Count(); for ( int i = 0; i < nCount; ++i ) { // Add all DmeElements that inherit from DmeMakefile CDmElement *pElement = GetElement< CDmElement >( g_pDataModel->CreateElement( s_AssetTypes[i].m_pChoiceValue, "temp", DMFILEID_INVALID ) ); CDmeMakefile *pMakeFile = CastElement< CDmeMakefile >( pElement ); for ( int j = 0; ppSubTypes[j]; ++j ) { if ( !pElement->IsA( ppSubTypes[j] ) ) continue; int k = pickerList.AddToTail(); pickerList[k].m_pChoiceString = pMakeFile->GetMakefileType()->m_pHumanReadableName; pickerList[k].m_pChoiceValue = s_AssetTypes[i].m_pChoiceValue; break; } DestroyElement( pElement ); } return pickerList; } //----------------------------------------------------------------------------- // Shows the overwrite existing file dialog //----------------------------------------------------------------------------- static void OverwriteFileDialog( vgui::Panel *pActionTarget, const char *pFileName, KeyValues *pOkCommand ) { if ( !g_pFullFileSystem->FileExists( pFileName ) ) { pActionTarget->PostMessage( pActionTarget->GetVPanel(), pOkCommand ); return; } char pBuf[1024]; Q_snprintf( pBuf, sizeof(pBuf), "File already exists. Overwrite it?\n\n\"%s\"\n", pFileName ); vgui::MessageBox *pMessageBox = new vgui::MessageBox( "Overwrite Existing File?", pBuf, pActionTarget ); pMessageBox->AddActionSignalTarget( pActionTarget ); pMessageBox->SetOKButtonVisible( true ); pMessageBox->SetOKButtonText( "Yes" ); pMessageBox->SetCancelButtonVisible( true ); pMessageBox->SetCancelButtonText( "No" ); pMessageBox->SetCloseButtonVisible( false ); pMessageBox->SetCommand( pOkCommand ); pMessageBox->DoModal(); } //----------------------------------------------------------------------------- // Utility to load a makefile //----------------------------------------------------------------------------- static CDmeMakefile *ReadMakefile( const char *pFileName, CDmElement **ppRoot = NULL ) { if ( ppRoot ) { *ppRoot = NULL; } CDmElement *pRoot; DmFileId_t fileid = g_pDataModel->RestoreFromFile( pFileName, NULL, NULL, &pRoot, CR_DELETE_OLD ); if ( fileid == DMFILEID_INVALID || !pRoot ) { Warning( "Unable to read makefile \"%s\"!\n", pFileName ); return NULL; } CDmeMakefile *pMakeFile = CastElement< CDmeMakefile >( pRoot ); if ( !pMakeFile ) { CDmElement *pElement = CastElement< CDmElement >( pRoot ); pMakeFile = pElement->GetValueElement< CDmeMakefile >( "makefile" ); if ( !pMakeFile ) { DmFileId_t fileId = pRoot->GetFileId(); DestroyElement( pRoot ); if ( fileId != DMFILEID_INVALID && g_pDataModel->GetFileName( fileId )[0] ) { g_pDataModel->RemoveFileId( fileId ); } return NULL; } } if ( ppRoot ) { *ppRoot = CastElement< CDmElement >( pRoot ); } return pMakeFile; } //----------------------------------------------------------------------------- // Sort by MDL name //----------------------------------------------------------------------------- static int __cdecl TypeSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 ) { const char *string1 = item1.kv->GetString("type"); const char *string2 = item2.kv->GetString("type"); int nRetVal = Q_stricmp( string1, string2 ); if ( nRetVal != 0 ) return nRetVal; string1 = item1.kv->GetString("file"); string2 = item2.kv->GetString("file"); nRetVal = Q_stricmp( string1, string2 ); if ( nRetVal != 0 ) return nRetVal; int nIndex1 = item1.kv->GetInt( "index" ); int nIndex2 = item2.kv->GetInt( "index" ); return nIndex1 - nIndex2; } static int __cdecl FileSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 ) { const char *string1 = item1.kv->GetString("file"); const char *string2 = item2.kv->GetString("file"); int nRetVal = Q_stricmp( string1, string2 ); if ( nRetVal != 0 ) return nRetVal; string1 = item1.kv->GetString("type"); string2 = item2.kv->GetString("type"); nRetVal = Q_stricmp( string1, string2 ); if ( nRetVal != 0 ) return nRetVal; int nIndex1 = item1.kv->GetInt( "index" ); int nIndex2 = item2.kv->GetInt( "index" ); return nIndex1 - nIndex2; } //----------------------------------------------------------------------------- // Purpose: Constructor, destructor //----------------------------------------------------------------------------- CAssetBuilder::CAssetBuilder( vgui::Panel *pParent, const char *pPanelName ) : BaseClass( pParent, pPanelName ) { m_hContextMenu = NULL; m_hRootMakefile = NULL; m_bIsCompiling = false; m_bDestroyMakefileOnClose = true; m_pInputOutputSheet = new vgui::PropertySheet( this, "InputOutputSheet" ); m_pInputOutputSheet->AddActionSignalTarget( this ); m_pInputPage = new PropertyPage( m_pInputOutputSheet, "InputPage" ); m_pOutputPage = new PropertyPage( m_pInputOutputSheet, "OutputPage" ); m_pCompilePage = new PropertyPage( m_pInputOutputSheet, "CompilePage" ); m_pOutputPreviewPage = new PropertyPage( m_pInputOutputSheet, "OutputPreviewPage" ); m_pPropertiesSplitter = new vgui::Splitter( m_pInputPage, "PropertiesSplitter", SPLITTER_MODE_VERTICAL, 1 ); vgui::Panel *pSplitterLeftSide = m_pPropertiesSplitter->GetChild( 0 ); vgui::Panel *pSplitterRightSide = m_pPropertiesSplitter->GetChild( 1 ); m_pDmePanel = new CDmePanel( pSplitterRightSide, "CompileOptions" ); m_pDmePanel->AddActionSignalTarget( this ); m_pOututPreviewPanel = new CDmePanel( m_pOutputPreviewPage, "OutputPreview", false ); m_pOututPreviewPanel->AddActionSignalTarget( this ); m_pSourcesList = new vgui::ListPanel( pSplitterLeftSide, "SourcesList" ); m_pSourcesList->AddColumnHeader( 0, "type", "type", 100, 0 ); m_pSourcesList->AddColumnHeader( 1, "file", "file", 52, 0 ); m_pSourcesList->AddActionSignalTarget( this ); m_pSourcesList->SetSortFunc( 0, TypeSortFunc ); m_pSourcesList->SetSortFunc( 1, FileSortFunc ); m_pSourcesList->SetSortColumn( 0 ); // m_pSourcesList->SetSelectIndividualCells( true ); m_pSourcesList->SetEmptyListText("No sources"); // m_pSourcesList->SetDragEnabled( true ); m_pOutputList = new vgui::ListPanel( m_pOutputPage, "OutputList" ); m_pOutputList->AddColumnHeader( 0, "type", "type", 100, 0 ); m_pOutputList->AddColumnHeader( 1, "file", "file", 52, 0 ); m_pOutputList->AddActionSignalTarget( this ); m_pOutputList->SetSortFunc( 0, TypeSortFunc ); m_pOutputList->SetSortFunc( 1, FileSortFunc ); m_pOutputList->SetSortColumn( 0 ); m_pOutputList->SetEmptyListText("No outputs"); m_pCompileOutput = new vgui::TextEntry( m_pCompilePage, "CompileOutput" ); m_pCompileOutput->SetMultiline( true ); m_pCompileOutput->SetVerticalScrollbar( true ); m_pCompile = new vgui::Button( this, "CompileButton", "Compile", this, "OnCompile" ); m_pPublish = new vgui::Button( this, "PublishButton", "Publish", this, "OnPublish" ); m_pAbortCompile = new vgui::Button( this, "AbortCompileButton", "AbortCompile", this, "OnAbortCompile" ); m_pCompileStatusBar = new CCompileStatusBar( this, "CompileStatus" ); m_pInputPage->LoadControlSettingsAndUserConfig( "resource/assetbuilderinputpage.res" ); m_pOutputPage->LoadControlSettingsAndUserConfig( "resource/assetbuilderoutputpage.res" ); m_pCompilePage->LoadControlSettingsAndUserConfig( "resource/assetbuildercompilepage.res" ); m_pOutputPreviewPage->LoadControlSettingsAndUserConfig( "resource/assetbuilderoutputpreviewpage.res" ); // Load layout settings; has to happen before pinning occurs in code LoadControlSettingsAndUserConfig( "resource/assetbuilder.res" ); // NOTE: Page adding happens *after* LoadControlSettingsAndUserConfig // because the layout of the sheet is correct at this point. m_pInputOutputSheet->AddPage( m_pInputPage, "Input" ); m_pInputOutputSheet->AddPage( m_pOutputPage, "Output" ); m_pInputOutputSheet->AddPage( m_pCompilePage, "Compile" ); m_pInputOutputSheet->AddPage( m_pOutputPreviewPage, "Preview" ); m_pCompile->SetEnabled( false ); m_pPublish->SetEnabled( false ); m_pAbortCompile->SetEnabled( false ); } CAssetBuilder::~CAssetBuilder() { if ( m_bDestroyMakefileOnClose ) { CleanupMakefile(); } CleanupContextMenu(); SaveUserConfig(); } //----------------------------------------------------------------------------- // Default behavior is to destroy the makefile when we close //----------------------------------------------------------------------------- void CAssetBuilder::DestroyMakefileOnClose( bool bEnable ) { m_bDestroyMakefileOnClose = bEnable; } //----------------------------------------------------------------------------- // Builds a unique list of file IDs //----------------------------------------------------------------------------- void CAssetBuilder::BuildFileIDList( CDmeMakefile *pMakeFile, CUtlVector &fileIds ) { if ( !pMakeFile ) return; // NOTE: Not hugely efficient. If the CDmeDependencyMakefile starts // getting large, we can optimize this DmFileId_t id = pMakeFile->GetFileId(); int nCount = fileIds.Count(); int i; for ( i = 0; i < nCount; ++i ) { if ( fileIds[i] == id ) break; } if ( i == nCount ) { fileIds.AddToTail( id ); } int nSourceCount = pMakeFile->GetSourceCount(); for ( int i = 0; i < nSourceCount; ++i ) { CDmeSource *pSource = pMakeFile->GetSource(i); BuildFileIDList( pSource->GetDependentMakefile(), fileIds ); } } //----------------------------------------------------------------------------- // Removes a makefile from memory //----------------------------------------------------------------------------- void CAssetBuilder::CleanupMakefile() { m_hMakefileStack.Clear(); m_pDmePanel->SetDmeElement( NULL ); m_pOututPreviewPanel->SetDmeElement( NULL ); if ( !m_hRootMakefile.Get() ) return; // First, build a list of unique file IDs CUtlVector fileIds; BuildFileIDList( m_hRootMakefile, fileIds ); CDisableUndoScopeGuard guard; m_hRootMakefile = NULL; int nCount = fileIds.Count(); for ( int i = 0; i < nCount; ++i ) { if ( fileIds[i] != DMFILEID_INVALID && g_pDataModel->GetFileName( fileIds[i] )[0] ) { g_pDataModel->RemoveFileId( fileIds[i] ); } } } //----------------------------------------------------------------------------- // Marks the file as dirty (or not) //----------------------------------------------------------------------------- void CAssetBuilder::SetDirty() { PostActionSignal( new KeyValues( "DmeElementChanged" ) ); } //----------------------------------------------------------------------------- // Returns the current makefile //----------------------------------------------------------------------------- CDmeMakefile *CAssetBuilder::GetMakeFile() { return m_hMakefile.Get(); } CDmeMakefile *CAssetBuilder::GetRootMakeFile() { return m_hRootMakefile.Get(); } //----------------------------------------------------------------------------- // Resets the lists; called when file name changes //----------------------------------------------------------------------------- void CAssetBuilder::Refresh() { RefreshSourceList(); RefreshOutputList(); } //----------------------------------------------------------------------------- // Resets the root makefile //----------------------------------------------------------------------------- void CAssetBuilder::SetRootMakefile( CDmeMakefile *pMakeFile ) { CleanupMakefile(); if ( pMakeFile ) { m_hRootMakefile = pMakeFile; m_hMakefileStack.Push( m_hRootMakefile ); } SetCurrentMakefile( pMakeFile ); } //----------------------------------------------------------------------------- // Resets the current makefile //----------------------------------------------------------------------------- void CAssetBuilder::SetCurrentMakefile( CDmeMakefile *pMakeFile ) { m_hMakefile = pMakeFile; m_pDmePanel->SetDmeElement( NULL ); m_pOututPreviewPanel->SetDmeElement( pMakeFile, true, "DmeMakeFileOutputPreview" ); RefreshSourceList(); RefreshOutputList(); // Lets the asset builder update the title bar PostActionSignal( new KeyValues( "UpdateFileName" ) ); } //----------------------------------------------------------------------------- // Hook into the DME panel framework //----------------------------------------------------------------------------- void CAssetBuilder::SetDmeElement( CDmeMakefile *pMakeFile ) { SetRootMakefile( pMakeFile ); } //----------------------------------------------------------------------------- // Refresh the source list //----------------------------------------------------------------------------- void CAssetBuilder::RefreshSourceList( ) { m_pSourcesList->RemoveAll(); if ( !m_hMakefile.Get() ) return; DmeMakefileType_t *pSourceTypes = m_hMakefile->GetSourceTypes(); for ( int i = 0; pSourceTypes[i].m_pTypeName; ++i ) { CUtlVector< CDmeHandle< CDmeSource > > sources; m_hMakefile->GetSources( pSourceTypes[i].m_pTypeName, sources ); int nCount = sources.Count(); for ( int j = 0; j < nCount; ++j ) { char pFullPath[MAX_PATH]; m_hMakefile->GetSourceFullPath( sources[j], pFullPath, sizeof(pFullPath) ); KeyValues *pItemKeys = new KeyValues( "node", "type", pSourceTypes[i].m_pHumanReadableName ); pItemKeys->SetString( "file", pFullPath ); pItemKeys->SetInt( "sourceTypeIndex", i ); pItemKeys->SetInt( "index", j ); // for sorting in the listpanel SetElementKeyValue( pItemKeys, "dmeSource", sources[j] ); m_pSourcesList->AddItem( pItemKeys, 0, false, false ); } } m_pSourcesList->SortList(); } //----------------------------------------------------------------------------- // Refreshes the output list //----------------------------------------------------------------------------- void CAssetBuilder::RefreshOutputList() { m_pOutputList->RemoveAll(); m_pCompile->SetEnabled( false ); m_pPublish->SetEnabled( false ); if ( !m_hMakefile.Get() ) return; CUtlVector outputs; m_hMakefile->GetOutputs( outputs ); int nCount = outputs.Count(); for ( int j = 0; j < nCount; ++j ) { KeyValues *pItemKeys = new KeyValues( "node", "type", "Output" ); pItemKeys->SetString( "file", outputs[j] ); pItemKeys->SetInt( "index", j ); m_pOutputList->AddItem( pItemKeys, 0, false, false ); } bool bEnabled = ( nCount > 0 ) && ( g_pDmeMakefileUtils != NULL ); m_pCompile->SetEnabled( bEnabled ); m_pPublish->SetEnabled( bEnabled ); m_pOutputList->SortList(); } //----------------------------------------------------------------------------- // Selects a particular source //----------------------------------------------------------------------------- void CAssetBuilder::SelectSource( CDmeSource *pSource ) { int nItemID = m_pSourcesList->FirstItem(); for ( ; nItemID != m_pSourcesList->InvalidItemID(); nItemID = m_pSourcesList->NextItem( nItemID ) ) { KeyValues *kv = m_pSourcesList->GetItem( nItemID ); if ( GetElementKeyValue< CDmeSource >( kv, "dmeSource" ) != pSource ) continue; m_pSourcesList->SetSingleSelectedItem( nItemID ); return; } } //----------------------------------------------------------------------------- // Called by the picker popped up in OnFileNew //----------------------------------------------------------------------------- void CAssetBuilder::OnPicked( KeyValues *kv ) { const char *pValue = kv->GetString( "choice" ); KeyValues *pContextKeys = kv->FindKey( "OnAddSource" ); if ( pContextKeys ) { OnSourceFileAdded( "", pValue ); return; } CDisableUndoScopeGuard guard; CDmeMakefile *pMakeFile = GetElement< CDmeMakefile >( g_pDataModel->CreateElement( pValue, "unnamed", DMFILEID_INVALID ) ); if ( !pMakeFile ) return; DmeMakefileType_t *pType = pMakeFile->GetMakefileType(); char pContext[MAX_PATH]; Q_snprintf( pContext, sizeof(pContext), "asset_builder_session_%s", pType->m_pTypeName ); char pStartingDir[MAX_PATH]; pMakeFile->GetDefaultDirectory( pType->m_pDefaultDirectoryID, pStartingDir, sizeof(pStartingDir) ); g_pFullFileSystem->CreateDirHierarchy( pStartingDir ); KeyValues *pDialogKeys = new KeyValues( "NewSourceFileSelected", "makefileType", pValue ); FileOpenDialog *pDialog = new FileOpenDialog( this, "Select Asset Builder File Name", false, pDialogKeys ); pDialog->SetStartDirectoryContext( pContext, pStartingDir ); pDialog->AddFilter( pType->m_pFileFilter, pType->m_pFileFilterString, true ); pDialog->AddActionSignalTarget( this ); pDialog->DoModal( false ); DestroyElement( pMakeFile ); } //----------------------------------------------------------------------------- // Creates a new source file, hooks it in //----------------------------------------------------------------------------- void CAssetBuilder::OnNewSourceFile( ) { KeyValues *pKeyValues = GetSelectedSourceKeyvalues(); CDmeSource *pSource = GetElementKeyValue< CDmeSource >( pKeyValues, "dmeSource" ); if ( !pSource ) return; BuildAssetTypeList(); PickerList_t typePickerList; PickerList_t &pickerList = BuildAssetSubTypeList( pSource->GetSourceMakefileTypes(), typePickerList ); // Create a list indicating which type of asset to create CPickerFrame *pPicker = new CPickerFrame( this, "Select Sub-Asset Type", "Asset Type", "assetType" ); pPicker->DoModal( pickerList ); } //----------------------------------------------------------------------------- // Called when the button to add a file is clicked //----------------------------------------------------------------------------- void CAssetBuilder::OnAddSource( ) { if ( !m_hMakefile.Get() ) return; PickerList_t sourceType; DmeMakefileType_t *pSourceTypes = m_hMakefile->GetSourceTypes(); for ( int i = 0; pSourceTypes[i].m_pTypeName; ++i ) { if ( pSourceTypes[i].m_bIsSingleton ) { if ( m_hMakefile->HasSourceOfType( pSourceTypes[i].m_pTypeName ) ) continue; } int j = sourceType.AddToTail( ); sourceType[j].m_pChoiceString = pSourceTypes[i].m_pHumanReadableName; sourceType[j].m_pChoiceValue = pSourceTypes[i].m_pTypeName; } if ( sourceType.Count() == 0 ) return; KeyValues *pContextKeys = new KeyValues( "OnAddSource" ); CPickerFrame *pPicker = new CPickerFrame( this, "Select Source Type", "Source Type", "sourceType" ); pPicker->DoModal( sourceType, pContextKeys ); } //----------------------------------------------------------------------------- // Returns the curerntly selected row //----------------------------------------------------------------------------- int CAssetBuilder::GetSelectedRow( ) { int nItemID = m_pSourcesList->GetSelectedItem( 0 ); return ( nItemID != -1 ) ? m_pSourcesList->GetItemCurrentRow( nItemID ) : -1; } //----------------------------------------------------------------------------- // Selects a particular row of the source list //----------------------------------------------------------------------------- void CAssetBuilder::SelectSourceListRow( int nRow ) { int nVisibleRowCount = m_pSourcesList->GetItemCount(); if ( nVisibleRowCount == 0 || nRow < 0 ) return; if ( nRow >= nVisibleRowCount ) { nRow = nVisibleRowCount - 1; } int nNewItemID = m_pSourcesList->GetItemIDFromRow( nRow ); m_pSourcesList->SetSingleSelectedItem( nNewItemID ); } //----------------------------------------------------------------------------- // Called when the button to remove a file is clicked //----------------------------------------------------------------------------- void CAssetBuilder::OnRemoveSource( ) { int nCount = m_pSourcesList->GetSelectedItemsCount(); if ( nCount == 0 || !m_hMakefile.Get() ) return; int nRow = GetSelectedRow(); Assert( nRow >= 0 ); // Update the selection to be reasonable after deletion CDisableUndoScopeGuard guard; for ( int i = 0; i < nCount; ++i ) { int nItemID = m_pSourcesList->GetSelectedItem( i ); KeyValues *pKeyValues = m_pSourcesList->GetItem( nItemID ); CDmeSource *pSource = GetElementKeyValue< CDmeSource >( pKeyValues, "dmeSource" ); if ( pSource ) { m_hMakefile->RemoveSource( pSource ); DestroyElement( pSource ); SetDirty( ); } } RefreshSourceList(); SelectSourceListRow( nRow ); } //----------------------------------------------------------------------------- // Called to make a particular source the currently selected source //----------------------------------------------------------------------------- void CAssetBuilder::OnZoomInSource() { // Called to zoom into the currently selected source CDmeSource *pSource = GetSelectedSource( ); if ( !pSource ) return; CDmeMakefile *pChild = m_hMakefile->FindDependentMakefile( pSource ); if ( pChild ) { CDmeHandle< CDmeMakefile > hChild; hChild = pChild; m_hMakefileStack.Push( hChild ); SetCurrentMakefile( pChild ); } } //----------------------------------------------------------------------------- // Called to zoom out of a particular source //----------------------------------------------------------------------------- void CAssetBuilder::OnZoomOutSource() { // Called to zoom into the currently selected source if ( m_hMakefileStack.Count() <= 1 ) return; CDmeMakefile *pOldParent = m_hMakefileStack.Top().Get(); m_hMakefileStack.Pop( ); CDmeMakefile *pParent = m_hMakefileStack.Top().Get(); if ( pParent ) { SetCurrentMakefile( pParent ); CDmeSource *pSource = pParent->FindAssociatedSource( pOldParent ); if ( pSource ) { SelectSource( pSource ); } } } //----------------------------------------------------------------------------- // Called when a key is typed //----------------------------------------------------------------------------- void CAssetBuilder::OnKeyCodeTyped( vgui::KeyCode code ) { if ( code == KEY_DELETE ) { OnRemoveSource(); return; } if ( code == KEY_ENTER ) { OnZoomInSource(); return; } BaseClass::OnKeyCodeTyped( code ); } //----------------------------------------------------------------------------- // Called when we're browsing for a source file and one was selected //----------------------------------------------------------------------------- void CAssetBuilder::OnSourceFileAdded( const char *pFileName, const char *pTypeName ) { CDmeSource *pSource = NULL; { CDisableUndoScopeGuard guard; pSource = m_hMakefile->AddSource( pTypeName, pFileName ); } SetDirty( ); RefreshSourceList( ); SelectSource( pSource ); } //----------------------------------------------------------------------------- // Called when the file open dialog for browsing source files selects something //----------------------------------------------------------------------------- void CAssetBuilder::OnNewSourceFileSelected( const char *pFileName, KeyValues *kv ) { int nCount = m_pSourcesList->GetSelectedItemsCount(); if ( nCount != 1 || !m_hMakefile.Get() ) return; int nItemID = m_pSourcesList->GetSelectedItem( 0 ); KeyValues *pKeyValues = m_pSourcesList->GetItem( nItemID ); CDmeSource *pSource = GetElementKeyValue< CDmeSource >( pKeyValues, "dmeSource" ); if ( !pSource ) return; const char *pMakeFileType = kv->GetString( "makefileType" ); { CDisableUndoScopeGuard guard; m_hMakefile->SetSourceFullPath( pSource, pFileName ); DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( pFileName ); CDmeMakefile *pSourceMakeFile = CreateElement< CDmeMakefile >( pMakeFileType, pFileName, fileid ); pSourceMakeFile->SetFileName( pFileName ); m_hMakefile->SetAssociation( pSource, pSourceMakeFile ); SetDirty( ); } pKeyValues->SetString( "file", pFileName ); m_pSourcesList->ApplyItemChanges( nItemID ); m_pSourcesList->SortList(); } //----------------------------------------------------------------------------- // Called when the file open dialog for browsing source files selects something //----------------------------------------------------------------------------- void CAssetBuilder::OnFileSelected( KeyValues *kv ) { const char *pFileName = kv->GetString( "fullpath", NULL ); if ( !pFileName ) return; KeyValues *pDialogKeys = kv->FindKey( "SelectSourceFile" ); if ( pDialogKeys ) { OnSourceFileNameChanged( pFileName ); return; } pDialogKeys = kv->FindKey( "NewSourceFileSelected" ); if ( pDialogKeys ) { if ( !g_pFullFileSystem->FileExists( pFileName ) ) { OnNewSourceFileSelected( pFileName, pDialogKeys ); } else { OnSourceFileNameChanged( pFileName ); } return; } } //----------------------------------------------------------------------------- // Shows the source file browser //----------------------------------------------------------------------------- void CAssetBuilder::ShowSourceFileBrowser( const char *pTitle, DmeMakefileType_t *pSourceType, KeyValues *pDialogKeys ) { char pContext[MAX_PATH]; Q_snprintf( pContext, sizeof(pContext), "asset_builder_session_%s", pSourceType->m_pTypeName ); char pStartingDir[MAX_PATH]; m_hMakefile->GetDefaultDirectory( pSourceType->m_pDefaultDirectoryID, pStartingDir, sizeof(pStartingDir) ); g_pFullFileSystem->CreateDirHierarchy( pStartingDir ); FileOpenDialog *pDialog = new FileOpenDialog( this, pTitle, true, pDialogKeys ); pDialog->SetStartDirectoryContext( pContext, pStartingDir ); pDialog->AddFilter( pSourceType->m_pFileFilter, pSourceType->m_pFileFilterString, true ); pDialog->AddActionSignalTarget( this ); pDialog->DoModal( false ); } //----------------------------------------------------------------------------- // Called when the button to browse for a source file is clicked //----------------------------------------------------------------------------- void CAssetBuilder::OnBrowseSourceFile( ) { KeyValues *pKeyValues = GetSelectedSourceKeyvalues(); if ( !pKeyValues ) return; int nSourceTypeIndex = pKeyValues->GetInt( "sourceTypeIndex", -1 ); KeyValues *pDialogKeys = new KeyValues( "SelectSourceFile" ); DmeMakefileType_t &sourceType = m_hMakefile->GetSourceTypes()[nSourceTypeIndex]; ShowSourceFileBrowser( "Select Source File", &sourceType, pDialogKeys ); } //----------------------------------------------------------------------------- // Command handler //----------------------------------------------------------------------------- void CAssetBuilder::OnCommand( const char *pCommand ) { if ( !Q_stricmp( pCommand, "OnCompile" ) ) { OnCompile(); return; } if ( !Q_stricmp( pCommand, "OnAbortCompile" ) ) { OnAbortCompile(); return; } if ( !Q_stricmp( pCommand, "OnPublish" ) ) { OnPublish(); return; } BaseClass::OnCommand( pCommand ); } //----------------------------------------------------------------------------- // Cleans up the context menu //----------------------------------------------------------------------------- void CAssetBuilder::CleanupContextMenu() { if ( m_hContextMenu.Get() ) { m_hContextMenu->MarkForDeletion(); m_hContextMenu = NULL; } } //----------------------------------------------------------------------------- // Called to open a context-sensitive menu for a particular menu item //----------------------------------------------------------------------------- void CAssetBuilder::OnOpenContextMenu( KeyValues *kv ) { CleanupContextMenu(); if ( !m_hMakefile.Get() ) return; Panel *pPanel = (Panel *)kv->GetPtr( "panel", NULL ); int nItemID = kv->GetInt( "itemID", -1 ); if ( pPanel != m_pSourcesList ) return; m_hContextMenu = new Menu( this, "ActionMenu" ); m_hContextMenu->AddMenuItem( "Add...", new KeyValues( "AddSource" ), this ); int nCount = m_pSourcesList->GetSelectedItemsCount(); if ( nCount > 0 ) { m_hContextMenu->AddMenuItem( "Remove", new KeyValues( "RemoveSource" ), this ); } bool bShowZoomIn = false; bool bShowZoomOut = m_hMakefileStack.Count() > 1; bool bShowLoadSourceFile = false; bool bHasValidSourceFile = false; if ( nCount == 1 && nItemID != -1 ) { KeyValues *kv = m_pSourcesList->GetItem( nItemID ); CDmeSource *pSource = GetElementKeyValue< CDmeSource >( kv, "dmeSource" ); if ( pSource ) { bHasValidSourceFile = pSource->GetRelativeFileName()[0] != 0; if ( m_hMakefile->FindDependentMakefile( pSource ) ) { bShowZoomIn = true; } else { bShowLoadSourceFile = bHasValidSourceFile; } } } if ( bShowZoomIn || bShowZoomOut ) { m_hContextMenu->AddSeparator(); if ( bShowZoomIn ) { m_hContextMenu->AddMenuItem( "Zoom In", new KeyValues( "ZoomInSource" ), this ); } if ( bShowZoomOut ) { m_hContextMenu->AddMenuItem( "Zoom Out", new KeyValues( "ZoomOutSource" ), this ); } } if ( nCount == 1 ) { m_hContextMenu->AddSeparator(); m_hContextMenu->AddMenuItem( "New Source File...", new KeyValues( "NewSourceFile" ), this ); m_hContextMenu->AddMenuItem( "Select Source File...", new KeyValues( "BrowseSourceFile" ), this ); if ( bShowLoadSourceFile ) { m_hContextMenu->AddMenuItem( "Load Source File", new KeyValues( "LoadSourceFile" ), this ); } if ( bHasValidSourceFile ) { m_hContextMenu->AddMenuItem( "Edit Source File", new KeyValues( "EditSourceFile" ), this ); } } Menu::PlaceContextMenu( this, m_hContextMenu.Get() ); } //----------------------------------------------------------------------------- // Called when a list panel's selection changes //----------------------------------------------------------------------------- void CAssetBuilder::OnSourceItemSelectionChanged( ) { int nCount = m_pSourcesList->GetSelectedItemsCount(); if ( nCount != 1 ) { m_pDmePanel->SetDmeElement( NULL ); return; } int nItemID = m_pSourcesList->GetSelectedItem( 0 ); KeyValues *pKeyValues = m_pSourcesList->GetItem( nItemID ); CDmeSource *pSource = GetElementKeyValue< CDmeSource >( pKeyValues, "dmeSource" ); m_pDmePanel->SetDmeElement( pSource ); } //----------------------------------------------------------------------------- // Called when a list panel's selection changes //----------------------------------------------------------------------------- void CAssetBuilder::OnItemSelected( KeyValues *kv ) { Panel *pPanel = (Panel *)kv->GetPtr( "panel", NULL ); if ( pPanel == m_pSourcesList ) { OnSourceItemSelectionChanged(); return; } } //----------------------------------------------------------------------------- // Called when a list panel's selection changes //----------------------------------------------------------------------------- void CAssetBuilder::OnItemDeselected( KeyValues *kv ) { Panel *pPanel = (Panel *)kv->GetPtr( "panel", NULL ); if ( pPanel == m_pSourcesList ) { OnSourceItemSelectionChanged(); return; } } //----------------------------------------------------------------------------- // Returns the selected source (if there's only 1 source selected) //----------------------------------------------------------------------------- CDmeSource *CAssetBuilder::GetSelectedSource( ) { int nCount = m_pSourcesList->GetSelectedItemsCount(); if ( nCount != 1 || !m_hMakefile.Get() ) return NULL; int nItemID = m_pSourcesList->GetSelectedItem( 0 ); KeyValues *pKeyValues = m_pSourcesList->GetItem( nItemID ); return GetElementKeyValue< CDmeSource >( pKeyValues, "dmeSource" ); } KeyValues *CAssetBuilder::GetSelectedSourceKeyvalues( ) { int nCount = m_pSourcesList->GetSelectedItemsCount(); if ( nCount != 1 || !m_hMakefile.Get() ) return NULL; int nItemID = m_pSourcesList->GetSelectedItem( 0 ); return m_pSourcesList->GetItem( nItemID ); } //----------------------------------------------------------------------------- // Called when the source file name changes //----------------------------------------------------------------------------- void CAssetBuilder::OnSourceFileNameChanged( const char *pFileName ) { int nCount = m_pSourcesList->GetSelectedItemsCount(); if ( nCount != 1 || !m_hMakefile.Get() ) return; int nItemID = m_pSourcesList->GetSelectedItem( 0 ); KeyValues *pKeyValues = m_pSourcesList->GetItem( nItemID ); CDmeSource *pSource = GetElementKeyValue< CDmeSource >( pKeyValues, "dmeSource" ); if ( !pSource ) return; { CDisableUndoScopeGuard guard; m_hMakefile->SetSourceFullPath( pSource, pFileName ); SetDirty( ); } pKeyValues->SetString( "file", pFileName ); m_pSourcesList->ApplyItemChanges( nItemID ); m_pSourcesList->SortList(); } //----------------------------------------------------------------------------- // Called during compilation //----------------------------------------------------------------------------- void CAssetBuilder::OnLoadSourceFile() { CDmeSource *pSource = GetSelectedSource( ); if ( !pSource ) return; char pFullPath[MAX_PATH]; m_hMakefile->GetSourceFullPath( pSource, pFullPath, sizeof(pFullPath) ); { CDisableUndoScopeGuard guard; CDmElement *pRoot; CDmeMakefile *pMakeFile = ReadMakefile( pFullPath, &pRoot ); if ( !pMakeFile ) return; // Successfully loaded a makefile. Set up the association. m_hMakefile->SetAssociation( pSource, pMakeFile ); // Refresh the dme panel... setting association could provoke changes m_pDmePanel->SetDmeElement( pSource, true ); } } //----------------------------------------------------------------------------- // Called to open an external editor for this source file //----------------------------------------------------------------------------- void CAssetBuilder::OnEditSourceFile() { CDmeSource *pSource = GetSelectedSource( ); if ( pSource ) { pSource->OpenEditor(); } } //----------------------------------------------------------------------------- // Finishes compilation //----------------------------------------------------------------------------- void CAssetBuilder::FinishCompilation( CompilationState_t state ) { // NOTE: compilation can cause the makefile to be completely // rebuilt if it's sitting in the output file. Therefore, // Detach the source preview panel from the source and refresh the // source list to get it to correctly reconnect to the new source elements m_pDmePanel->SetDmeElement( NULL ); int nRow = GetSelectedRow(); m_pOututPreviewPanel->SetDmeElement( m_hMakefile, true, "DmeMakeFileOutputPreview" ); m_bIsCompiling = false; // NOTE: Sort of side-effecty. These two things must be done after // m_pOututPreviewPanel->SetDmeElement, since that's what reloads the output element, // which is also what can cause a reload of the makefile RefreshSourceList(); SelectSourceListRow( nRow ); // Lets the asset builder update the title bar // (compilation could have changed the dirty state if the makefile is in the file) PostActionSignal( new KeyValues( "UpdateFileName" ) ); if ( state == COMPILATION_FAILED ) { char pBuf[256]; Q_snprintf( pBuf, sizeof(pBuf), "Compilation Error (return code %d)", g_pDmeMakefileUtils->GetExitCode() ); m_pCompileStatusBar->SetStatus( CCompileStatusBar::COMPILATION_FAILED, pBuf ); } else { m_pCompileStatusBar->SetStatus( CCompileStatusBar::COMPILATION_SUCCESSFUL, "Compile Successful!" ); } } //----------------------------------------------------------------------------- // Called during compilation //----------------------------------------------------------------------------- void CAssetBuilder::OnTick() { BaseClass::OnTick(); if ( m_bIsCompiling ) { int nLen = g_pDmeMakefileUtils->GetCompileOutputSize( ); char *pBuf = (char*)_alloca( nLen+1 ); CompilationState_t state = g_pDmeMakefileUtils->UpdateCompilation( pBuf, nLen ); if ( nLen > 0 ) { m_pCompileOutput->InsertString( pBuf ); } Assert( m_hMakefile.Get() ); if ( state != COMPILATION_NOT_COMPLETE ) { FinishCompilation( state ); } } if ( !m_bIsCompiling ) { m_pAbortCompile->SetEnabled( false ); vgui::ivgui()->RemoveTickSignal( GetVPanel() ); } } //----------------------------------------------------------------------------- // Abort compile asset //----------------------------------------------------------------------------- void CAssetBuilder::OnAbortCompile() { if ( m_bIsCompiling ) { g_pDmeMakefileUtils->AbortCurrentCompilation(); m_bIsCompiling = false; m_pAbortCompile->SetEnabled( false ); m_pCompileStatusBar->SetStatus( CCompileStatusBar::COMPILATION_FAILED, "Compile Aborted" ); } } //----------------------------------------------------------------------------- // Compile asset //----------------------------------------------------------------------------- void CAssetBuilder::OnCompile( ) { if ( !m_hMakefile.Get() ) return; OnAbortCompile(); m_pCompileOutput->SetText( "" ); g_pDmeMakefileUtils->PerformCompile( m_hMakefile, false ); m_bIsCompiling = true; m_pAbortCompile->SetEnabled( true ); m_pCompileStatusBar->SetStatus( CCompileStatusBar::CURRENTLY_COMPILING, "Compiling..." ); vgui::ivgui()->AddTickSignal( GetVPanel(), 10 ); } //----------------------------------------------------------------------------- // Compile, then publish //----------------------------------------------------------------------------- void CAssetBuilder::OnPublish( ) { if ( !m_hMakefile.Get() ) return; OnAbortCompile(); m_pCompileOutput->SetText( "" ); g_pDmeMakefileUtils->PerformCompile( m_hMakefile, false ); m_bIsCompiling = true; m_pAbortCompile->SetEnabled( true ); m_pCompileStatusBar->SetStatus( CCompileStatusBar::CURRENTLY_COMPILING, "Compiling..." ); vgui::ivgui()->AddTickSignal( GetVPanel(), 10 ); } //----------------------------------------------------------------------------- // Purpose: Constructor, destructor //----------------------------------------------------------------------------- CAssetBuilderFrame::CAssetBuilderFrame( vgui::Panel *pParent, const char *pTitle ) : BaseClass( pParent, "AssetBuilderFrame" ) { m_TitleString = pTitle; SetMenuButtonVisible( true ); SetImages( "resource/downarrow" ); m_pAssetBuilder = new CAssetBuilder( this, "AssetBuilder" ); m_pAssetBuilder->AddActionSignalTarget( this ); vgui::Menu *pMenu = new vgui::Menu( NULL, "FileMenu" ); pMenu->AddMenuItem( "new", "#AssetBuilder_FileNew", new KeyValues( "FileNew" ), this ); pMenu->AddMenuItem( "open", "#AssetBuilder_FileOpen", new KeyValues( "FileOpen" ), this ); pMenu->AddMenuItem( "save", "#AssetBuilder_FileSave", new KeyValues( "FileSave" ), this ); pMenu->AddMenuItem( "saveas", "#AssetBuilder_FileSaveAs", new KeyValues( "FileSaveAs" ), this ); SetSysMenu( pMenu ); m_pFileOpenStateMachine = new vgui::FileOpenStateMachine( this, this ); m_pFileOpenStateMachine->AddActionSignalTarget( this ); // Load layout settings; has to happen before pinning occurs in code LoadControlSettingsAndUserConfig( "resource/assetbuilderframe.res" ); UpdateFileName(); } CAssetBuilderFrame::~CAssetBuilderFrame() { } //----------------------------------------------------------------------------- // Inherited from IFileOpenStateMachineClient //----------------------------------------------------------------------------- void CAssetBuilderFrame::SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues ) { // Compute starting directory char pStartingDir[ MAX_PATH ]; GetModContentSubdirectory( "", pStartingDir, sizeof(pStartingDir) ); if ( bOpenFile ) { // Clear out the existing makefile if we're opening a file m_pAssetBuilder->SetRootMakefile( NULL ); pDialog->SetTitle( "Open Asset MakeFile", true ); } else { pDialog->SetTitle( "Save Asset MakeFile As", true ); } pDialog->SetStartDirectoryContext( "asset_browser_makefile", pStartingDir ); pDialog->AddFilter( "*.*", "All Files (*.*)", false ); pDialog->AddFilter( "*.dmx", "Asset MakeFiles (*.dmx)", true, "keyvalues2" ); } bool CAssetBuilderFrame::OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues ) { CDmElement *pRoot; CDmeMakefile *pMakeFile = ReadMakefile( pFileName, &pRoot ); if ( !pMakeFile ) return false; Reset( pMakeFile ); return true; } bool CAssetBuilderFrame::OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues ) { // Recompute relative paths for each source now that we know the file name // NOTE: This also updates the name of the fileID in the datamodel system CDmeMakefile *pMakefile = m_pAssetBuilder->GetMakeFile(); bool bOk; { CDisableUndoScopeGuard guard; bOk = pMakefile->SetFileName( pFileName ); } if ( !bOk ) { vgui::MessageBox *pError = new vgui::MessageBox( "#AssetBuilder_CannotRenameSourceFiles", "#AssetBuilder_CannotRenameSourceFilesText", this ); pError->DoModal(); return false; } CDmElement *pRoot = GetElement< CDmElement >( g_pDataModel->GetFileRoot( pMakefile->GetFileId() ) ); if ( !pRoot ) { pRoot = pMakefile; } bOk = g_pDataModel->SaveToFile( pFileName, NULL, g_pDataModel->GetDefaultEncoding( pFileFormat ), pFileFormat, pRoot ); m_pAssetBuilder->Refresh(); return bOk; } //----------------------------------------------------------------------------- // Updates the file name //----------------------------------------------------------------------------- void CAssetBuilderFrame::UpdateFileName( ) { CDmeMakefile *pMakeFile = m_pAssetBuilder->GetMakeFile(); if ( !pMakeFile ) { SetTitle( m_TitleString.Get(), true ); return; } DmeMakefileType_t *pMakefileType = pMakeFile->GetMakefileType(); DmFileId_t fileId = pMakeFile->GetFileId(); const char *pFileName = ( fileId != DMFILEID_INVALID ) ? g_pDataModel->GetFileName( fileId ) : ""; if ( !pFileName || !pFileName[0] ) { pFileName = ""; } char pBuf[2*MAX_PATH]; if ( m_TitleString.Get() ) { Q_snprintf( pBuf, sizeof(pBuf), "%s - %s - %s%s", m_TitleString.Get(), pMakefileType->m_pHumanReadableName, pFileName, pMakeFile->IsDirty() ? " *" : "" ); } else { Q_snprintf( pBuf, sizeof(pBuf), "%s - s%s", pMakefileType->m_pHumanReadableName, pFileName, pMakeFile->IsDirty() ? " *" : "" ); } SetTitle( pBuf, true ); } //----------------------------------------------------------------------------- // Marks the file as dirty (or not) //----------------------------------------------------------------------------- void CAssetBuilderFrame::SetDirty( bool bDirty ) { CDmeMakefile *pMakeFile = m_pAssetBuilder->GetMakeFile(); if ( pMakeFile && ( pMakeFile->IsDirty() != bDirty ) ) { pMakeFile->SetDirty( bDirty ); // Necessary because we draw a * if it's dirty before the name UpdateFileName(); } } //----------------------------------------------------------------------------- // Called when the asset builder changes something //----------------------------------------------------------------------------- void CAssetBuilderFrame::OnDmeElementChanged() { SetDirty( true ); } //----------------------------------------------------------------------------- // Resets the state //----------------------------------------------------------------------------- void CAssetBuilderFrame::Reset( CDmeMakefile *pMakeFile ) { // NOTE: Don't need to call SetDirty because we call UpdateFileName below m_pAssetBuilder->SetRootMakefile( pMakeFile ); UpdateFileName(); } //----------------------------------------------------------------------------- // Called when the file open dialog for selecting the new asset name is selected //----------------------------------------------------------------------------- void CAssetBuilderFrame::OnPerformFileNew( KeyValues *kv ) { const char *pMakefileType = kv->GetString( "makefileType" ); const char *pFileName = kv->GetString( "fileName" ); CDmeMakefile *pMakeFile; { DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( pFileName ); CDisableUndoScopeGuard guard; pMakeFile = CreateElement< CDmeMakefile >( pMakefileType, pFileName, fileid ); } if ( !pMakeFile ) return; pMakeFile->SetFileName( pFileName ); Reset( pMakeFile ); SetDirty( true ); } //----------------------------------------------------------------------------- // Called when the file open dialog for browsing source files selects something //----------------------------------------------------------------------------- void CAssetBuilderFrame::OnFileSelected( KeyValues *kv ) { const char *pFileName = kv->GetString( "fullpath", NULL ); if ( !pFileName ) return; KeyValues *pDialogKeys = kv->FindKey( "OnFileNew" ); if ( pDialogKeys ) { KeyValues *pOkCommand = new KeyValues( "PerformFileNew", "makefileType", pDialogKeys->GetString( "makefileType" ) ); pOkCommand->SetString( "fileName", pFileName ); OverwriteFileDialog( this, pFileName, pOkCommand ); return; } } //----------------------------------------------------------------------------- // Called by the picker popped up in OnFileNew //----------------------------------------------------------------------------- void CAssetBuilderFrame::OnPicked( KeyValues *kv ) { const char *pValue = kv->GetString( "choice" ); CDisableUndoScopeGuard guard; CDmeMakefile *pMakeFile = GetElement< CDmeMakefile >( g_pDataModel->CreateElement( pValue, "unnamed", DMFILEID_INVALID ) ); if ( !pMakeFile ) return; DmeMakefileType_t *pType = pMakeFile->GetMakefileType(); char pContext[MAX_PATH]; Q_snprintf( pContext, sizeof(pContext), "asset_builder_session_%s", pType->m_pTypeName ); char pStartingDir[MAX_PATH]; pMakeFile->GetDefaultDirectory( pType->m_pDefaultDirectoryID, pStartingDir, sizeof(pStartingDir) ); g_pFullFileSystem->CreateDirHierarchy( pStartingDir ); char pTitle[MAX_PATH]; Q_snprintf( pTitle, sizeof(pTitle), "Select %s File Name", pType->m_pHumanReadableName ); KeyValues *pDialogKeys = new KeyValues( "OnFileNew", "makefileType", pValue ); FileOpenDialog *pDialog = new FileOpenDialog( this, pTitle, false, pDialogKeys ); pDialog->SetStartDirectoryContext( pContext, pStartingDir ); pDialog->AddFilter( pType->m_pFileFilter, pType->m_pFileFilterString, true ); pDialog->AddActionSignalTarget( this ); pDialog->DoModal( false ); DestroyElement( pMakeFile ); } //----------------------------------------------------------------------------- // Called by the file open state machine when an operation has completed //----------------------------------------------------------------------------- void CAssetBuilderFrame::OnFileStateMachineFinished( KeyValues *pKeyValues ) { KeyValues *pNewFile = pKeyValues->FindKey( "FileNew" ); if ( pNewFile ) { if ( pKeyValues->GetInt( "wroteFile", 0 ) != 0 ) { SetDirty( false ); UpdateFileName(); } if ( pKeyValues->GetInt( "completionState", FileOpenStateMachine::IN_PROGRESS ) == FileOpenStateMachine::SUCCESSFUL ) { ShowNewAssetPicker(); } return; } KeyValues *pSaveFile = pKeyValues->FindKey( "FileSave" ); if ( pSaveFile ) { if ( pKeyValues->GetInt( "wroteFile", 0 ) != 0 ) { SetDirty( false ); UpdateFileName(); } return; } } //----------------------------------------------------------------------------- // Shows a picker for creating a new asset //----------------------------------------------------------------------------- void CAssetBuilderFrame::ShowNewAssetPicker( ) { BuildAssetTypeList(); // Create a list indicating which type of asset to create CPickerFrame *pPicker = new CPickerFrame( this, "Select Asset Type", "Asset Type", "assetType" ); pPicker->DoModal( s_AssetTypes ); } //----------------------------------------------------------------------------- // Creates a new file //----------------------------------------------------------------------------- void CAssetBuilderFrame::OnFileNew( ) { CDmeMakefile *pMakeFile = m_pAssetBuilder->GetMakeFile(); if ( pMakeFile && pMakeFile->IsDirty() ) { KeyValues *pContextKeyValues = new KeyValues( "FileNew" ); const char *pFileName = g_pDataModel->GetFileName( pMakeFile->GetFileId() ); m_pFileOpenStateMachine->SaveFile( pContextKeyValues, pFileName, ASSET_FILE_FORMAT, FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY ); return; } ShowNewAssetPicker(); } void CAssetBuilderFrame::OnFileOpen( ) { int nFlags = 0; const char *pFileName = NULL; CDmeMakefile *pMakeFile = m_pAssetBuilder->GetMakeFile(); if ( pMakeFile && pMakeFile->IsDirty() ) { nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY; pFileName = g_pDataModel->GetFileName( pMakeFile->GetFileId() ); } KeyValues *pContextKeyValues = new KeyValues( "FileOpen" ); m_pFileOpenStateMachine->OpenFile( ASSET_FILE_FORMAT, pContextKeyValues, pFileName, NULL, nFlags ); } void CAssetBuilderFrame::OnFileSave( ) { CDmeMakefile *pMakeFile = m_pAssetBuilder->GetMakeFile(); if ( !pMakeFile ) return; KeyValues *pContextKeyValues = new KeyValues( "FileSave" ); const char *pFileName = g_pDataModel->GetFileName( pMakeFile->GetFileId() ); m_pFileOpenStateMachine->SaveFile( pContextKeyValues, pFileName, ASSET_FILE_FORMAT, FOSM_SHOW_PERFORCE_DIALOGS ); } void CAssetBuilderFrame::OnFileSaveAs( ) { CDmeMakefile *pMakeFile = m_pAssetBuilder->GetMakeFile(); if ( !pMakeFile ) return; KeyValues *pContextKeyValues = new KeyValues( "FileSave" ); m_pFileOpenStateMachine->SaveFile( pContextKeyValues, NULL, ASSET_FILE_FORMAT, FOSM_SHOW_PERFORCE_DIALOGS ); }