Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1936 lines
59 KiB

  1. //====== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "filesystem.h"
  7. #include "matsys_controls/baseassetpicker.h"
  8. #include "tier1/keyvalues.h"
  9. #include "tier1/utlntree.h"
  10. #include "tier1/utlrbtree.h"
  11. #include "vgui_controls/ListPanel.h"
  12. #include "vgui_controls/TextEntry.h"
  13. #include "vgui_controls/ComboBox.h"
  14. #include "vgui_controls/Button.h"
  15. #include "vgui_controls/Splitter.h"
  16. #include "vgui_controls/TreeView.h"
  17. #include "vgui_controls/ImageList.h"
  18. #include "vgui_controls/CheckButton.h"
  19. #include "vgui/ISurface.h"
  20. #include "vgui/IInput.h"
  21. #include "vgui/IVGui.h"
  22. #include "vgui/Cursor.h"
  23. #include "tier2/fileutils.h"
  24. // NOTE: This has to be the last file included!
  25. #include "tier0/memdbgon.h"
  26. using namespace vgui;
  27. #define ASSET_LIST_DIRECTORY_INITIAL_SEARCH_TIME 0.25f
  28. #define ASSET_LIST_DIRECTORY_SEARCH_TIME 0.025f
  29. //-----------------------------------------------------------------------------
  30. // sorting function, should return true if node1 should be displayed before node2
  31. //-----------------------------------------------------------------------------
  32. bool AssetTreeViewSortFunc( KeyValues *node1, KeyValues *node2 )
  33. {
  34. const char *pDir1 = node1->GetString( "text", NULL );
  35. const char *pDir2 = node2->GetString( "text", NULL );
  36. return Q_stricmp( pDir1, pDir2 ) < 0;
  37. }
  38. //-----------------------------------------------------------------------------
  39. //
  40. // Tree view for assets
  41. //
  42. //-----------------------------------------------------------------------------
  43. class CAssetTreeView : public vgui::TreeView
  44. {
  45. DECLARE_CLASS_SIMPLE( CAssetTreeView, vgui::TreeView );
  46. public:
  47. CAssetTreeView( vgui::Panel *parent, const char *name, const char *pRootFolderName, const char *pRootDir );
  48. // Inherited from base classes
  49. virtual void GenerateChildrenOfNode( int itemIndex );
  50. virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
  51. // Opens and selects the root folder
  52. void OpenRoot();
  53. // Purpose: Refreshes the active file list
  54. void RefreshFileList();
  55. // Adds a subdirectory
  56. DirHandle_t GetRootDirectory( );
  57. DirHandle_t AddSubDirectory( DirHandle_t hParent, const char *pDirName );
  58. void ClearDirectories();
  59. // Selects a folder
  60. void SelectFolder( const char *pSubDir, const char *pPath );
  61. private:
  62. // Allocates the root node
  63. void AllocateRootNode( );
  64. // Purpose: Refreshes the active file list
  65. DirHandle_t RefreshTreeViewItem( int nItemIndex );
  66. // Sets an item to be colored as if its a menu
  67. void SetItemColorForDirectories( int nItemID );
  68. // Add a directory into the treeview
  69. void AddDirectoryToTreeView( int nParentItemIndex, const char *pFullParentPath, DirHandle_t hPath );
  70. // Selects an item in the tree
  71. bool SelectFolder_R( int nItemID, const char *pPath );
  72. CUtlString m_RootFolderName;
  73. CUtlString m_RootDirectory;
  74. vgui::ImageList m_Images;
  75. CUtlNTree< CUtlString, DirHandle_t > m_DirectoryStructure;
  76. };
  77. //-----------------------------------------------------------------------------
  78. // Constructor
  79. //-----------------------------------------------------------------------------
  80. CAssetTreeView::CAssetTreeView( Panel *pParent, const char *pName, const char *pRootFolderName, const char *pRootDir ) : BaseClass(pParent, pName), m_Images( false )
  81. {
  82. SetSortFunc( AssetTreeViewSortFunc );
  83. m_RootFolderName = pRootFolderName;
  84. m_RootDirectory = pRootDir;
  85. AllocateRootNode();
  86. // build our list of images
  87. m_Images.AddImage( scheme()->GetImage( "resource/icon_folder", false ) );
  88. SetImageList( &m_Images, false );
  89. SETUP_PANEL( this );
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Purpose: Refreshes the active file list
  93. //-----------------------------------------------------------------------------
  94. void CAssetTreeView::OpenRoot()
  95. {
  96. RemoveAll();
  97. // add the base node
  98. const char *pRootDir = m_DirectoryStructure[ m_DirectoryStructure.Root() ];
  99. KeyValues *pkv = new KeyValues( "root" );
  100. pkv->SetString( "text", m_RootFolderName.Get() );
  101. pkv->SetInt( "root", 1 );
  102. pkv->SetInt( "expand", 1 );
  103. pkv->SetInt( "dirHandle", m_DirectoryStructure.Root() );
  104. pkv->SetString( "path", pRootDir );
  105. int iRoot = AddItem( pkv, GetRootItemIndex() );
  106. pkv->deleteThis();
  107. ExpandItem( iRoot, true );
  108. }
  109. //-----------------------------------------------------------------------------
  110. // Allocates the root node
  111. //-----------------------------------------------------------------------------
  112. void CAssetTreeView::AllocateRootNode( )
  113. {
  114. DirHandle_t hRoot = m_DirectoryStructure.Alloc();
  115. m_DirectoryStructure.SetRoot( hRoot );
  116. m_DirectoryStructure[hRoot] = m_RootDirectory;
  117. }
  118. //-----------------------------------------------------------------------------
  119. // Adds a subdirectory (maintains sorted order)
  120. //-----------------------------------------------------------------------------
  121. DirHandle_t CAssetTreeView::GetRootDirectory( )
  122. {
  123. return m_DirectoryStructure.Root();
  124. }
  125. DirHandle_t CAssetTreeView::AddSubDirectory( DirHandle_t hParent, const char *pDirName )
  126. {
  127. DirHandle_t hSubdir = m_DirectoryStructure.Alloc();
  128. m_DirectoryStructure[hSubdir] = pDirName;
  129. Q_strlower( m_DirectoryStructure[hSubdir].Get() );
  130. DirHandle_t hChild = m_DirectoryStructure.FirstChild( hParent );
  131. m_DirectoryStructure.LinkChildBefore( hParent, hChild, hSubdir );
  132. return hSubdir;
  133. }
  134. void CAssetTreeView::ClearDirectories()
  135. {
  136. m_DirectoryStructure.RemoveAll();
  137. AllocateRootNode();
  138. }
  139. //-----------------------------------------------------------------------------
  140. // Sets an item to be colored as if its a menu
  141. //-----------------------------------------------------------------------------
  142. void CAssetTreeView::SetItemColorForDirectories( int nItemID )
  143. {
  144. // mark directories in orange
  145. SetItemFgColor( nItemID, Color(224, 192, 0, 255) );
  146. }
  147. //-----------------------------------------------------------------------------
  148. // Add a directory into the treeview
  149. //-----------------------------------------------------------------------------
  150. void CAssetTreeView::AddDirectoryToTreeView( int nParentItemIndex, const char *pFullParentPath, DirHandle_t hPath )
  151. {
  152. const char *pDirName = m_DirectoryStructure[hPath].Get();
  153. KeyValues *kv = new KeyValues( "node", "text", pDirName );
  154. char pFullPath[MAX_PATH];
  155. Q_snprintf( pFullPath, sizeof( pFullPath ), "%s/%s", pFullParentPath, pDirName );
  156. Q_FixSlashes( pFullPath );
  157. Q_strlower( pFullPath );
  158. bool bHasSubdirectories = m_DirectoryStructure.FirstChild( hPath ) != m_DirectoryStructure.InvalidIndex();
  159. kv->SetString( "path", pFullPath );
  160. kv->SetInt( "expand", bHasSubdirectories );
  161. kv->SetInt( "image", 0 );
  162. kv->SetInt( "dirHandle", hPath );
  163. int nItemID = AddItem( kv, nParentItemIndex );
  164. kv->deleteThis();
  165. // mark directories in orange
  166. SetItemColorForDirectories( nItemID );
  167. }
  168. //-----------------------------------------------------------------------------
  169. // override to incremental request and show p4 directories
  170. //-----------------------------------------------------------------------------
  171. void CAssetTreeView::GenerateChildrenOfNode( int nItemIndex )
  172. {
  173. KeyValues *pkv = GetItemData( nItemIndex );
  174. const char *pFullParentPath = pkv->GetString( "path", NULL );
  175. if ( !pFullParentPath )
  176. return;
  177. DirHandle_t hPath = (DirHandle_t)pkv->GetInt( "dirHandle", m_DirectoryStructure.InvalidIndex() );
  178. if ( hPath == m_DirectoryStructure.InvalidIndex() )
  179. return;
  180. DirHandle_t hChild = m_DirectoryStructure.FirstChild( hPath );
  181. while ( hChild != m_DirectoryStructure.InvalidIndex() )
  182. {
  183. AddDirectoryToTreeView( nItemIndex, pFullParentPath, hChild );
  184. hChild = m_DirectoryStructure.NextSibling( hChild );
  185. }
  186. }
  187. //-----------------------------------------------------------------------------
  188. // Purpose: Refreshes the active file list
  189. //-----------------------------------------------------------------------------
  190. DirHandle_t CAssetTreeView::RefreshTreeViewItem( int nItemIndex )
  191. {
  192. if ( nItemIndex < 0 )
  193. return m_DirectoryStructure.InvalidIndex();
  194. // Make sure the expand icons are set correctly
  195. KeyValues *pkv = GetItemData( nItemIndex );
  196. DirHandle_t hPath = (DirHandle_t)pkv->GetInt( "dirHandle", m_DirectoryStructure.InvalidIndex() );
  197. const char *pFullParentPath = pkv->GetString( "path", NULL );
  198. bool bHasSubdirectories = m_DirectoryStructure.FirstChild( hPath ) != m_DirectoryStructure.InvalidIndex();
  199. if ( bHasSubdirectories != ( pkv->GetInt( "expand" ) != 0 ) )
  200. {
  201. pkv->SetInt( "expand", bHasSubdirectories );
  202. ModifyItem( nItemIndex, pkv );
  203. }
  204. bool bIsExpanded = IsItemExpanded( nItemIndex );
  205. if ( !bIsExpanded )
  206. return hPath;
  207. // Check all children + build a list of children we've already got
  208. int nChildCount = GetNumChildren( nItemIndex );
  209. DirHandle_t *pFoundHandles = (DirHandle_t*)stackalloc( nChildCount * sizeof(DirHandle_t) );
  210. memset( pFoundHandles, 0xFF, nChildCount * sizeof(DirHandle_t) );
  211. for ( int i = 0; i < nChildCount; ++i )
  212. {
  213. int nChildItemIndex = GetChild( nItemIndex, i );
  214. pFoundHandles[i] = RefreshTreeViewItem( nChildItemIndex );
  215. }
  216. // Check directory structure to see if other directories were added
  217. DirHandle_t hChild = m_DirectoryStructure.FirstChild( hPath );
  218. for ( ; hChild != m_DirectoryStructure.InvalidIndex(); hChild = m_DirectoryStructure.NextSibling( hChild ) )
  219. {
  220. // Search for existence of this child already
  221. bool bFound = false;
  222. for ( int j = 0; j < nChildCount; ++j )
  223. {
  224. if ( pFoundHandles[j] == hChild )
  225. {
  226. pFoundHandles[j] = pFoundHandles[nChildCount-1];
  227. --nChildCount;
  228. bFound = true;
  229. break;
  230. }
  231. }
  232. if ( bFound )
  233. continue;
  234. // Child is new, add it
  235. AddDirectoryToTreeView( nItemIndex, pFullParentPath, hChild );
  236. }
  237. return hPath;
  238. }
  239. void CAssetTreeView::RefreshFileList()
  240. {
  241. // Make sure the expand icons are set correctly
  242. RefreshTreeViewItem( GetRootItemIndex() );
  243. InvalidateLayout();
  244. }
  245. //-----------------------------------------------------------------------------
  246. // Selects a folder
  247. //-----------------------------------------------------------------------------
  248. bool CAssetTreeView::SelectFolder_R( int nItemID, const char *pPath )
  249. {
  250. if ( nItemID < 0 )
  251. return false;
  252. KeyValues *kv = GetItemData( nItemID );
  253. const char *pTestPath = kv->GetString( "path" );
  254. if ( !Q_stricmp( pTestPath, pPath ) )
  255. {
  256. AddSelectedItem( nItemID, true, false, true );
  257. return true;
  258. }
  259. // Substring match..
  260. CUtlString str = pTestPath;
  261. str += '\\';
  262. if ( Q_strnicmp( str, pPath, str.Length() ) )
  263. return false;
  264. ExpandItem( nItemID, true );
  265. int nChildCount = GetNumChildren( nItemID );
  266. for ( int i = 0; i < nChildCount; ++i )
  267. {
  268. int nChildItemID = GetChild( nItemID, i );
  269. if ( SelectFolder_R( nChildItemID, pPath ) )
  270. return true;
  271. }
  272. return false;
  273. }
  274. void CAssetTreeView::SelectFolder( const char *pSubDir, const char *pPath )
  275. {
  276. char pTemp[MAX_PATH];
  277. Q_snprintf( pTemp, sizeof(pTemp), "%s\\%s", pSubDir, pPath );
  278. Q_StripTrailingSlash( pTemp );
  279. int nItem = GetRootItemIndex();
  280. SelectFolder_R( nItem, pTemp );
  281. }
  282. //-----------------------------------------------------------------------------
  283. // setup a smaller font
  284. //-----------------------------------------------------------------------------
  285. void CAssetTreeView::ApplySchemeSettings( IScheme *pScheme )
  286. {
  287. BaseClass::ApplySchemeSettings( pScheme );
  288. SetFont( pScheme->GetFont("DefaultSmall") );
  289. SetFgColor( Color(216, 222, 211, 255) );
  290. }
  291. //-----------------------------------------------------------------------------
  292. //
  293. // Cache of asset data so we don't need to rebuild all the time
  294. //
  295. //-----------------------------------------------------------------------------
  296. DECLARE_POINTER_HANDLE( AssetList_t );
  297. #define ASSET_LIST_INVALID ((AssetList_t)(0xFFFF))
  298. class CAssetCache
  299. {
  300. public:
  301. CAssetCache();
  302. // Mod iteration
  303. int ModCount() const;
  304. const CacheModInfo_t& ModInfo( int nIndex ) const;
  305. // Building the mod list
  306. void BuildModList( const char *pSearchPath );
  307. AssetList_t FindAssetList( const char *pAssetType, const char *pSubDir, int nExtCount, const char **ppExt );
  308. bool BeginAssetScan( AssetList_t hList, bool bForceRescan = false ); // return true if finished
  309. CAssetTreeView* GetFileTree( AssetList_t hList );
  310. int GetAssetCount( AssetList_t hList ) const;
  311. const CachedAssetInfo_t& GetAsset( AssetList_t hList, int nIndex ) const;
  312. void AddAsset( AssetList_t hList, const CachedAssetInfo_t& info );
  313. bool ContinueSearchForAssets( AssetList_t hList, float flDuration ); // return true if finished
  314. void SetUsedAssetList( CUtlVector< AssetUsageInfo_t > &usedAssets );
  315. private:
  316. struct DirToCheck_t
  317. {
  318. CUtlString m_DirName;
  319. DirHandle_t m_hDirHandle;
  320. };
  321. struct CachedAssetList_t
  322. {
  323. CachedAssetList_t() {}
  324. CachedAssetList_t( const char *pSearchSubDir, int nExtCount, const char **ppSearchExt ) :
  325. m_pSubDir( pSearchSubDir, Q_strlen( pSearchSubDir ) + 1 )
  326. {
  327. m_Ext.AddMultipleToTail( nExtCount, ppSearchExt );
  328. }
  329. CachedAssetList_t( const CachedAssetList_t& )
  330. {
  331. // Only used during insertion; do nothing
  332. }
  333. CUtlVector< CachedAssetInfo_t > m_AssetList;
  334. CAssetTreeView *m_pFileTree;
  335. CUtlString m_pSubDir;
  336. CUtlVector< const char * > m_Ext;
  337. CUtlLinkedList< DirToCheck_t > m_DirectoriesToCheck;
  338. FileFindHandle_t m_hFind;
  339. bool m_bAssetScanComplete;
  340. };
  341. private:
  342. bool AddFilesInDirectory( CachedAssetList_t& list, const char *pStartingFile, const char *pFilePath, DirHandle_t hDirHandle, float flStartTime, float flDuration );
  343. bool DoesExtensionMatch( CachedAssetList_t& list, const char *pFileName );
  344. void AddAssetToList( CachedAssetList_t& list, const char *pAssetName, int nModIndex, int nTimesUsed );
  345. private:
  346. int GetAssetUsageCount( const char *assetName );
  347. // List of known mods
  348. CUtlVector< CacheModInfo_t > m_ModList;
  349. // List of assets in use in the current context (such as the Hammer map), provided by the invoker of the asset picker
  350. CUtlVector< AssetUsageInfo_t > m_usedAssets;
  351. // List of cached assets
  352. CUtlRBTree< CachedAssetList_t > m_CachedAssets;
  353. // Search path
  354. const char *m_pAssetSearchPath;
  355. // Have we built the mod list?
  356. bool m_bBuiltModList;
  357. static bool CachedAssetLessFunc( const CachedAssetList_t& src1, const CachedAssetList_t& src2 );
  358. };
  359. //-----------------------------------------------------------------------------
  360. // Static instance of the asset cache
  361. //-----------------------------------------------------------------------------
  362. static CAssetCache s_AssetCache;
  363. //-----------------------------------------------------------------------------
  364. // Map sort func
  365. //-----------------------------------------------------------------------------
  366. bool CAssetCache::CachedAssetLessFunc( const CAssetCache::CachedAssetList_t& src1, const CAssetCache::CachedAssetList_t& src2 )
  367. {
  368. int nRetVal = Q_stricmp( src1.m_pSubDir, src2.m_pSubDir ) > 0;
  369. if ( nRetVal != 0 )
  370. return nRetVal > 0;
  371. int nCount = src1.m_Ext.Count();
  372. int nDiff = nCount - src2.m_Ext.Count();
  373. if ( nDiff != 0 )
  374. return nDiff > 0;
  375. for ( int i = 0; i < nCount; ++i )
  376. {
  377. nRetVal = Q_stricmp( src1.m_Ext[i], src2.m_Ext[i] );
  378. if ( nRetVal != 0 )
  379. return nRetVal > 0;
  380. }
  381. return false;
  382. }
  383. //-----------------------------------------------------------------------------
  384. // Constructor
  385. //-----------------------------------------------------------------------------
  386. CAssetCache::CAssetCache() : m_CachedAssets( 0, 0, CachedAssetLessFunc )
  387. {
  388. m_bBuiltModList = false;
  389. }
  390. //-----------------------------------------------------------------------------
  391. // Mod iteration
  392. //-----------------------------------------------------------------------------
  393. int CAssetCache::ModCount() const
  394. {
  395. return m_ModList.Count();
  396. }
  397. const CacheModInfo_t& CAssetCache::ModInfo( int nIndex ) const
  398. {
  399. return m_ModList[nIndex];
  400. }
  401. //-----------------------------------------------------------------------------
  402. // Building the mod list
  403. //-----------------------------------------------------------------------------
  404. void CAssetCache::BuildModList( const char *pSearchPathName )
  405. {
  406. if ( m_bBuiltModList )
  407. return;
  408. m_pAssetSearchPath = pSearchPathName;
  409. m_bBuiltModList = true;
  410. m_ModList.RemoveAll();
  411. // Add all mods
  412. int nLen = g_pFullFileSystem->GetSearchPath( m_pAssetSearchPath, false, NULL, 0 );
  413. char *pSearchPath = (char*)stackalloc( nLen * sizeof(char) );
  414. g_pFullFileSystem->GetSearchPath( m_pAssetSearchPath, false, pSearchPath, nLen );
  415. char *pPath = pSearchPath;
  416. while( pPath )
  417. {
  418. char *pSemiColon = strchr( pPath, ';' );
  419. if ( pSemiColon )
  420. {
  421. *pSemiColon = 0;
  422. }
  423. Q_StripTrailingSlash( pPath );
  424. Q_FixSlashes( pPath );
  425. char pModName[ MAX_PATH ];
  426. Q_FileBase( pPath, pModName, sizeof( pModName ) );
  427. // Always start in an asset-specific directory
  428. // char pAssetPath[MAX_PATH];
  429. // Q_snprintf( pAssetPath, MAX_PATH, "%s\\%s", pPath, m_pAssetSubDir );
  430. // Q_FixSlashes( pPath );
  431. int i = m_ModList.AddToTail( );
  432. m_ModList[i].m_ModName.Set( pModName );
  433. m_ModList[i].m_Path.Set( pPath );
  434. pPath = pSemiColon ? pSemiColon + 1 : NULL;
  435. }
  436. }
  437. //-----------------------------------------------------------------------------
  438. // Returns true if we should add the asset. Fills in timesUsed with the # of
  439. // times this asset is used.
  440. //-----------------------------------------------------------------------------
  441. int CAssetCache::GetAssetUsageCount( const char *assetName )
  442. {
  443. if ( !m_usedAssets.Count() )
  444. return 0;
  445. for ( int i = 0; i < m_usedAssets.Count(); i++ )
  446. {
  447. // FIXME: deal with stripped path
  448. if ( Q_stristr( m_usedAssets[i].m_assetName.Get(), assetName ) )
  449. {
  450. return m_usedAssets[i].m_nTimesUsed;
  451. }
  452. }
  453. return 0;
  454. }
  455. //-----------------------------------------------------------------------------
  456. // Adds an asset to the list of assets of this type
  457. //-----------------------------------------------------------------------------
  458. void CAssetCache::AddAssetToList( CachedAssetList_t& list, const char *pAssetName, int nModIndex, int nTimesUsed )
  459. {
  460. int i = list.m_AssetList.AddToTail( );
  461. CachedAssetInfo_t& info = list.m_AssetList[i];
  462. info.m_AssetName.Set( pAssetName );
  463. info.m_nModIndex = nModIndex;
  464. info.m_nTimesUsed = nTimesUsed;
  465. }
  466. //-----------------------------------------------------------------------------
  467. // Extension matches?
  468. //-----------------------------------------------------------------------------
  469. bool CAssetCache::DoesExtensionMatch( CachedAssetList_t& info, const char *pFileName )
  470. {
  471. char pChildExt[MAX_PATH];
  472. // We want to ignore any compiled assest for other platforms, like .360. or .ps3. etc.
  473. if ( Q_stristr( pFileName, ".360." ) != NULL ||
  474. Q_stristr( pFileName, ".ps3." ) != NULL )
  475. {
  476. return false;
  477. }
  478. Q_ExtractFileExtension( pFileName, pChildExt, sizeof(pChildExt) );
  479. // Check the extension matches
  480. int nCount = info.m_Ext.Count();
  481. for ( int i = 0; i < nCount; ++i )
  482. {
  483. if ( !Q_stricmp( info.m_Ext[i], pChildExt ) )
  484. return true;
  485. }
  486. return false;
  487. }
  488. //-----------------------------------------------------------------------------
  489. // Recursively add all files matching the wildcard under this directory
  490. //-----------------------------------------------------------------------------
  491. bool CAssetCache::AddFilesInDirectory( CachedAssetList_t& list, const char *pStartingFile, const char *pFilePath, DirHandle_t hCurrentDir, float flStartTime, float flDuration )
  492. {
  493. // Indicates no files found
  494. if ( list.m_hFind == FILESYSTEM_INVALID_FIND_HANDLE )
  495. return true;
  496. // generate children
  497. // add all the items
  498. int nModCount = m_ModList.Count();
  499. int nSubDirLen = list.m_pSubDir ? Q_strlen(list.m_pSubDir) : 0;
  500. const char *pszFileName = pStartingFile;
  501. while ( pszFileName )
  502. {
  503. char pRelativeChildPath[MAX_PATH];
  504. Q_snprintf( pRelativeChildPath, MAX_PATH, "%s\\%s", pFilePath, pszFileName );
  505. if ( g_pFullFileSystem->FindIsDirectory( list.m_hFind ) )
  506. {
  507. // If .svn is in the name, don't add this directory!!
  508. if ( strstr (pszFileName, ".svn") )
  509. {
  510. pszFileName = g_pFullFileSystem->FindNext( list.m_hFind );
  511. continue;
  512. }
  513. if ( Q_strnicmp( pszFileName, ".", 2 ) && Q_strnicmp( pszFileName, "..", 3 ) )
  514. {
  515. DirHandle_t hDirHandle = list.m_pFileTree->AddSubDirectory( hCurrentDir, pszFileName );
  516. int i = list.m_DirectoriesToCheck.AddToTail();
  517. list.m_DirectoriesToCheck[i].m_DirName = pRelativeChildPath;
  518. list.m_DirectoriesToCheck[i].m_hDirHandle = hDirHandle;
  519. }
  520. }
  521. else
  522. {
  523. // Check the extension matches
  524. if ( DoesExtensionMatch( list, pszFileName ) )
  525. {
  526. char pFullAssetPath[MAX_PATH];
  527. g_pFullFileSystem->RelativePathToFullPath( pRelativeChildPath, m_pAssetSearchPath, pFullAssetPath, sizeof(pFullAssetPath) );
  528. int nModIndex = -1;
  529. for ( int i = 0; i < nModCount; ++i )
  530. {
  531. if ( !Q_strnicmp( pFullAssetPath, m_ModList[i].m_Path, m_ModList[i].m_Path.Length() ) )
  532. {
  533. nModIndex = i;
  534. break;
  535. }
  536. }
  537. if ( nModIndex >= 0 )
  538. {
  539. // Strip 'subdir/' prefix
  540. char *pAssetName = pRelativeChildPath;
  541. if ( list.m_pSubDir )
  542. {
  543. if ( !Q_strnicmp( list.m_pSubDir, pAssetName, nSubDirLen ) )
  544. {
  545. if ( pAssetName[nSubDirLen] == '\\' )
  546. {
  547. pAssetName += nSubDirLen + 1;
  548. }
  549. }
  550. }
  551. strlwr( pAssetName );
  552. int nTimesUsed = GetAssetUsageCount( pAssetName );
  553. AddAssetToList( list, pAssetName, nModIndex, nTimesUsed );
  554. }
  555. }
  556. }
  557. // Don't let the search go for too long at a time
  558. if ( Plat_FloatTime() - flStartTime >= flDuration )
  559. return false;
  560. pszFileName = g_pFullFileSystem->FindNext( list.m_hFind );
  561. }
  562. return true;
  563. }
  564. //-----------------------------------------------------------------------------
  565. // Recursively add all files matching the wildcard under this directory
  566. //-----------------------------------------------------------------------------
  567. bool CAssetCache::ContinueSearchForAssets( AssetList_t hList, float flDuration )
  568. {
  569. CachedAssetList_t& list = m_CachedAssets[ (intp)hList ];
  570. float flStartTime = Plat_FloatTime();
  571. while ( list.m_DirectoriesToCheck.Count() )
  572. {
  573. const char *pFilePath = list.m_DirectoriesToCheck[ list.m_DirectoriesToCheck.Head() ].m_DirName;
  574. DirHandle_t hCurrentDir = list.m_DirectoriesToCheck[ list.m_DirectoriesToCheck.Head() ].m_hDirHandle;
  575. const char *pStartingFile;
  576. if ( list.m_hFind == FILESYSTEM_INVALID_FIND_HANDLE )
  577. {
  578. char pSearchString[MAX_PATH];
  579. Q_snprintf( pSearchString, MAX_PATH, "%s\\*", pFilePath );
  580. // get the list of files
  581. pStartingFile = g_pFullFileSystem->FindFirstEx( pSearchString, m_pAssetSearchPath, &list.m_hFind );
  582. }
  583. else
  584. {
  585. pStartingFile = g_pFullFileSystem->FindNext( list.m_hFind );
  586. }
  587. if ( !AddFilesInDirectory( list, pStartingFile, pFilePath, hCurrentDir, flStartTime, flDuration ) )
  588. return false;
  589. g_pFullFileSystem->FindClose( list.m_hFind );
  590. list.m_hFind = FILESYSTEM_INVALID_FIND_HANDLE;
  591. list.m_DirectoriesToCheck.Remove( list.m_DirectoriesToCheck.Head() );
  592. }
  593. list.m_bAssetScanComplete = true;
  594. return true;
  595. }
  596. //-----------------------------------------------------------------------------
  597. // Asset cache iteration
  598. //-----------------------------------------------------------------------------
  599. bool CAssetCache::BeginAssetScan( AssetList_t hList, bool bForceRescan )
  600. {
  601. CachedAssetList_t& list = m_CachedAssets[ (intp)hList ];
  602. if ( bForceRescan )
  603. {
  604. list.m_bAssetScanComplete = false;
  605. if ( list.m_hFind != FILESYSTEM_INVALID_FIND_HANDLE )
  606. {
  607. g_pFullFileSystem->FindClose( list.m_hFind );
  608. list.m_hFind = FILESYSTEM_INVALID_FIND_HANDLE;
  609. }
  610. list.m_DirectoriesToCheck.RemoveAll();
  611. }
  612. if ( list.m_bAssetScanComplete )
  613. return true;
  614. // This case occurs if we stopped the picker previously while in the middle of a scan
  615. if ( list.m_hFind != FILESYSTEM_INVALID_FIND_HANDLE )
  616. return false;
  617. list.m_AssetList.RemoveAll();
  618. list.m_pFileTree->ClearDirectories();
  619. // Add all files, determine which mod they are in.
  620. int i = list.m_DirectoriesToCheck.AddToTail();
  621. list.m_DirectoriesToCheck[i].m_DirName = list.m_pSubDir;
  622. list.m_DirectoriesToCheck[i].m_hDirHandle = list.m_pFileTree->GetRootDirectory();
  623. return false;
  624. }
  625. //-----------------------------------------------------------------------------
  626. //-----------------------------------------------------------------------------
  627. void CAssetCache::SetUsedAssetList( CUtlVector<AssetUsageInfo_t> &usedAssets )
  628. {
  629. m_usedAssets.RemoveAll();
  630. m_usedAssets.AddVectorToTail( usedAssets );
  631. for ( int cache = m_CachedAssets.FirstInorder(); cache != m_CachedAssets.InvalidIndex(); cache = m_CachedAssets.NextInorder( cache ) )
  632. {
  633. for ( int i = 0; i < m_CachedAssets.Element( cache ).m_AssetList.Count(); i++ )
  634. {
  635. m_CachedAssets.Element( cache ).m_AssetList.Element( i ).m_nTimesUsed = GetAssetUsageCount( m_CachedAssets.Element( cache ).m_AssetList.Element( i ).m_AssetName.Get() );
  636. }
  637. }
  638. }
  639. //-----------------------------------------------------------------------------
  640. // Asset cache iteration
  641. //-----------------------------------------------------------------------------
  642. AssetList_t CAssetCache::FindAssetList( const char *pAssetType, const char *pSubDir, int nExtCount, const char **ppExt )
  643. {
  644. CachedAssetList_t search( pSubDir, nExtCount, ppExt );
  645. int nIndex = m_CachedAssets.Find( search );
  646. if ( nIndex == m_CachedAssets.InvalidIndex() )
  647. {
  648. nIndex = m_CachedAssets.Insert( search );
  649. CachedAssetList_t &list = m_CachedAssets[nIndex];
  650. list.m_pSubDir = pSubDir;
  651. list.m_Ext.AddMultipleToTail( nExtCount, ppExt );
  652. list.m_hFind = FILESYSTEM_INVALID_FIND_HANDLE;
  653. list.m_bAssetScanComplete = false;
  654. list.m_pFileTree = new CAssetTreeView( NULL, "FolderFilter", pAssetType, pSubDir );
  655. }
  656. return (AssetList_t)(intp)nIndex;
  657. }
  658. CAssetTreeView* CAssetCache::GetFileTree( AssetList_t hList )
  659. {
  660. if ( hList == ASSET_LIST_INVALID )
  661. return NULL;
  662. return m_CachedAssets[ (intp)hList ].m_pFileTree;
  663. }
  664. int CAssetCache::GetAssetCount( AssetList_t hList ) const
  665. {
  666. if ( hList == ASSET_LIST_INVALID )
  667. return 0;
  668. return m_CachedAssets[ (intp)hList ].m_AssetList.Count();
  669. }
  670. const CachedAssetInfo_t& CAssetCache::GetAsset( AssetList_t hList, int nIndex ) const
  671. {
  672. Assert( nIndex < GetAssetCount(hList) );
  673. return m_CachedAssets[ (intp)hList ].m_AssetList[ nIndex ];
  674. }
  675. //-----------------------------------------------------------------------------
  676. //
  677. // Base asset Picker
  678. //
  679. //-----------------------------------------------------------------------------
  680. //-----------------------------------------------------------------------------
  681. // Sort by asset name
  682. //-----------------------------------------------------------------------------
  683. static int __cdecl AssetBrowserSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
  684. {
  685. bool bRoot1 = item1.kv->GetInt("root") != 0;
  686. bool bRoot2 = item2.kv->GetInt("root") != 0;
  687. if ( bRoot1 != bRoot2 )
  688. return bRoot1 ? -1 : 1;
  689. const char *pString1 = item1.kv->GetString("asset");
  690. const char *pString2 = item2.kv->GetString("asset");
  691. return Q_stricmp( pString1, pString2 );
  692. }
  693. static int __cdecl AssetBrowserModSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
  694. {
  695. int nMod1 = item1.kv->GetInt("modIndex", -1);
  696. int nMod2 = item2.kv->GetInt("modIndex", -1);
  697. if ( nMod1 != nMod2 )
  698. return nMod1 - nMod2;
  699. return AssetBrowserSortFunc( pPanel, item1, item2 );
  700. }
  701. static int __cdecl AssetBrowserTimesUsedSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
  702. {
  703. int nMod1 = item1.kv->GetInt("timesused", -1);
  704. int nMod2 = item2.kv->GetInt("timesused", -1);
  705. if ( nMod1 != nMod2 )
  706. return nMod1 - nMod2;
  707. return AssetBrowserSortFunc( pPanel, item1, item2 );
  708. }
  709. //-----------------------------------------------------------------------------
  710. // Purpose: Constructor
  711. //-----------------------------------------------------------------------------
  712. CBaseAssetPicker::CBaseAssetPicker( vgui::Panel *pParent, const char *pAssetType,
  713. const char *pExt, const char *pSubDir, const char *pTextType, const char *pAssetSearchPath ) :
  714. BaseClass( pParent, "AssetPicker" )
  715. {
  716. m_bBuiltAssetList = false;
  717. m_pAssetType = pAssetType;
  718. m_pAssetTextType = pTextType;
  719. m_pAssetExt = pExt;
  720. m_pAssetSubDir = pSubDir;
  721. m_pAssetSearchPath = pAssetSearchPath;
  722. m_bFinishedAssetListScan = false;
  723. m_bFirstAssetScan = false;
  724. m_nMatchingAssets = 0;
  725. m_bSubDirCheck = true;
  726. m_bOnlyUsedAssetsCheck = false;
  727. m_hAssetList = ASSET_LIST_INVALID;
  728. m_pInsertHelper = new KeyValues( "node" );
  729. }
  730. //-----------------------------------------------------------------------------
  731. // Purpose: Destructor
  732. //-----------------------------------------------------------------------------
  733. CBaseAssetPicker::~CBaseAssetPicker()
  734. {
  735. SaveUserConfig();
  736. // Detach!
  737. m_pFileTree->RemoveActionSignalTarget( this );
  738. m_pFileTree->SetParent( (Panel*)NULL );
  739. m_pFileTree = NULL;
  740. if ( m_pInsertHelper )
  741. {
  742. m_pInsertHelper->deleteThis();
  743. }
  744. }
  745. //-----------------------------------------------------------------------------
  746. // Creates standard controls
  747. //-----------------------------------------------------------------------------
  748. void CBaseAssetPicker::CreateStandardControls( vgui::Panel *pParent, bool bAllowMultiselect )
  749. {
  750. int nExtCount = 1 + m_ExtraAssetExt.Count();
  751. const char **ppExt = (const char **)stackalloc( nExtCount * sizeof(const char *) );
  752. ppExt[0] = m_pAssetExt;
  753. if ( nExtCount > 1 )
  754. {
  755. memcpy( ppExt + 1, m_ExtraAssetExt.Base(), nExtCount - 1 );
  756. }
  757. m_hAssetList = s_AssetCache.FindAssetList( m_pAssetType, m_pAssetSubDir, nExtCount, ppExt );
  758. m_pAssetSplitter = new vgui::Splitter( pParent, "AssetSplitter", SPLITTER_MODE_HORIZONTAL, 1 );
  759. m_pAssetSplitter->SetAutoResize( PIN_TOPLEFT, AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 );
  760. vgui::Panel *pSplitterTopSide = m_pAssetSplitter->GetChild( 0 );
  761. vgui::Panel *pSplitterBottomSide = m_pAssetSplitter->GetChild( 1 );
  762. // Combo box for mods
  763. m_pModSelector = new ComboBox( pSplitterTopSide, "ModFilter", 5, false );
  764. m_pModSelector->AddActionSignalTarget( this );
  765. // Rescan button
  766. m_pRescanButton = new Button( pSplitterTopSide, "RescanButton", "Rescan", this, "AssetRescan" );
  767. m_pRescanButton->SetWide(75);
  768. // file browser tree controls
  769. m_pFileTree = s_AssetCache.GetFileTree( m_hAssetList );
  770. m_pFileTree->SetParent( pSplitterTopSide );
  771. m_pFileTree->AddActionSignalTarget( this );
  772. m_pSubDirCheck = new CheckButton( pSplitterTopSide, "SubDirCheck", "Check subfolders for files?" );
  773. m_pSubDirCheck->SetSelected( true );
  774. m_pSubDirCheck->SetEnabled( false );
  775. m_pSubDirCheck->SetVisible( false );
  776. m_pSubDirCheck->AddActionSignalTarget( this );
  777. char pTemp[512];
  778. Q_snprintf( pTemp, sizeof(pTemp), "No .%s files", m_pAssetExt );
  779. m_pAssetBrowser = new vgui::ListPanel( pSplitterBottomSide, "AssetBrowser" );
  780. m_pAssetBrowser->AddColumnHeader( 0, "mod", "Mod", 52, 0 );
  781. m_pAssetBrowser->AddColumnHeader( 1, "asset", m_pAssetType, 128, ListPanel::COLUMN_RESIZEWITHWINDOW );
  782. m_pAssetBrowser->AddColumnHeader( 2, "timesused", "Times Used", 128, ListPanel::COLUMN_RESIZEWITHWINDOW );
  783. m_pAssetBrowser->SetSelectIndividualCells( false );
  784. m_pAssetBrowser->SetMultiselectEnabled( bAllowMultiselect );
  785. m_pAssetBrowser->SetEmptyListText( pTemp );
  786. m_pAssetBrowser->SetDragEnabled( true );
  787. m_pAssetBrowser->AddActionSignalTarget( this );
  788. m_pAssetBrowser->SetSortFunc( 0, AssetBrowserModSortFunc );
  789. m_pAssetBrowser->SetSortFunc( 1, AssetBrowserSortFunc );
  790. m_pAssetBrowser->SetSortFunc( 2, AssetBrowserTimesUsedSortFunc );
  791. m_pAssetBrowser->SetSortColumn( 1 );
  792. vgui::Panel *pSplitterBottomLeftSide = m_pAssetSplitter->GetChild( 1 );
  793. // filter selection
  794. m_pFilter = new TextEntry( pSplitterBottomLeftSide, "FilterList" );
  795. m_pFilter->AddActionSignalTarget( this );
  796. m_pOnlyUsedCheck = new CheckButton( pSplitterBottomLeftSide, "OnlyUsedCheck", "Show used assets only" );
  797. m_pOnlyUsedCheck->SetSelected( m_bOnlyUsedAssetsCheck );
  798. m_pOnlyUsedCheck->AddActionSignalTarget( this );
  799. // full path
  800. m_pFullPath = new TextEntry( pSplitterBottomLeftSide, "FullPath" );
  801. m_pFullPath->SetEnabled( false );
  802. m_pFullPath->SetEditable( false );
  803. // Rescan button
  804. m_pFindAssetButton = new Button( pSplitterBottomLeftSide, "FindButton", "Find Asset", this, "FindAsset" );
  805. //m_pFindAssetButton->SetWide(75);
  806. m_nCurrentModFilter = -1;
  807. }
  808. void CBaseAssetPicker::AutoLayoutStandardControls( )
  809. {
  810. vgui::Panel *pSplitterTopLeftSide = m_pAssetSplitter->GetChild( 0 );
  811. CBoxSizer* pTopLeftSplitterLayout = new CBoxSizer(ESLD_VERTICAL);
  812. {
  813. CBoxSizer* pRow = new CBoxSizer(ESLD_HORIZONTAL);
  814. pRow->AddPanel( new Label(pSplitterTopLeftSide,"ModFilterLabel","Mod Filter"), SizerAddArgs_t() );
  815. pRow->AddPanel( m_pModSelector, SizerAddArgs_t().Expand( 1.0f ) );
  816. pRow->AddPanel( m_pRescanButton, SizerAddArgs_t() );
  817. pTopLeftSplitterLayout->AddSizer( pRow, SizerAddArgs_t() );
  818. }
  819. m_pSubDirCheck->SetEnabled( true );
  820. m_pSubDirCheck->SetVisible( true );
  821. pTopLeftSplitterLayout->AddPanel( m_pSubDirCheck, SizerAddArgs_t() );
  822. pTopLeftSplitterLayout->AddPanel( m_pFileTree, SizerAddArgs_t().Expand( 1.0f ) );
  823. pSplitterTopLeftSide->SetSizer(pTopLeftSplitterLayout);
  824. vgui::Panel *pSplitterBottomLeftSide = m_pAssetSplitter->GetChild( 1 );
  825. CBoxSizer* pBottomLeftSplitterLayout = new CBoxSizer(ESLD_VERTICAL);
  826. pBottomLeftSplitterLayout->AddPanel( m_pAssetBrowser, SizerAddArgs_t().Expand( 1.0f ) );
  827. {
  828. CBoxSizer* pRow = new CBoxSizer(ESLD_HORIZONTAL);
  829. pRow->AddPanel( new Label(pSplitterBottomLeftSide,"FullPathLabel","Full Path"), SizerAddArgs_t() );
  830. pRow->AddPanel( m_pFullPath, SizerAddArgs_t().Expand( 1.0f ) );
  831. pRow->AddPanel( m_pFindAssetButton, SizerAddArgs_t().Expand( 1.0f ) );
  832. pBottomLeftSplitterLayout->AddSizer( pRow, SizerAddArgs_t() );
  833. }
  834. {
  835. CBoxSizer* pRow = new CBoxSizer(ESLD_HORIZONTAL);
  836. pRow->AddPanel( new Label(pSplitterBottomLeftSide,"FilterLabel","Filter"), SizerAddArgs_t() );
  837. pRow->AddPanel( m_pFilter, SizerAddArgs_t().Expand( 1.0f ) );
  838. pBottomLeftSplitterLayout->AddSizer( pRow, SizerAddArgs_t() );
  839. }
  840. {
  841. CBoxSizer* pRow = new CBoxSizer( ESLD_HORIZONTAL );
  842. pRow->AddPanel( m_pOnlyUsedCheck, SizerAddArgs_t().Expand( 1.0f ) );
  843. pRow->AddPanel( new Label( pSplitterBottomLeftSide, "OnlyUsedLabel", "Show used assets only" ), SizerAddArgs_t() );
  844. pBottomLeftSplitterLayout->AddSizer( pRow, SizerAddArgs_t() );
  845. }
  846. pSplitterBottomLeftSide->SetSizer(pBottomLeftSplitterLayout);
  847. }
  848. //-----------------------------------------------------------------------------
  849. // Reads user config settings
  850. //-----------------------------------------------------------------------------
  851. void CBaseAssetPicker::ApplyUserConfigSettings( KeyValues *pUserConfig )
  852. {
  853. BaseClass::ApplyUserConfigSettings( pUserConfig );
  854. // Populates the mod list names
  855. RefreshAssetList();
  856. const char *pFilter = pUserConfig->GetString( "filter", "" );
  857. m_FolderFilter = pUserConfig->GetString( "folderfilter", "" );
  858. const char *pMod = pUserConfig->GetString( "mod", "" );
  859. SetFilter( pFilter );
  860. m_nCurrentModFilter = -1;
  861. if ( pMod && pMod[0] )
  862. {
  863. int nCount = s_AssetCache.ModCount();
  864. for ( int i = 0; i < nCount; ++i )
  865. {
  866. const CacheModInfo_t& modInfo = s_AssetCache.ModInfo( i );
  867. if ( Q_stricmp( pMod, modInfo.m_ModName ) )
  868. continue;
  869. int nItemCount = m_pModSelector->GetItemCount();
  870. for ( int j = 0; j < nItemCount; ++j )
  871. {
  872. int nItemID = m_pModSelector->GetItemIDFromRow( j );
  873. KeyValues *kv = m_pModSelector->GetItemUserData( nItemID );
  874. int nModIndex = kv->GetInt( "mod" );
  875. if ( nModIndex == i )
  876. {
  877. m_nCurrentModFilter = i;
  878. m_pModSelector->ActivateItem( nItemID );
  879. break;
  880. }
  881. }
  882. break;
  883. }
  884. }
  885. }
  886. //-----------------------------------------------------------------------------
  887. // Purpose: returns user config settings for this control
  888. //-----------------------------------------------------------------------------
  889. void CBaseAssetPicker::GetUserConfigSettings( KeyValues *pUserConfig )
  890. {
  891. BaseClass::GetUserConfigSettings( pUserConfig );
  892. pUserConfig->SetString( "filter", m_Filter );
  893. pUserConfig->SetString( "folderfilter", m_FolderFilter );
  894. pUserConfig->SetString( "mod", ( m_nCurrentModFilter >= 0 ) ?
  895. s_AssetCache.ModInfo( m_nCurrentModFilter ).m_ModName : "" );
  896. }
  897. //-----------------------------------------------------------------------------
  898. // Purpose: optimization, return true if this control has any user config settings
  899. //-----------------------------------------------------------------------------
  900. bool CBaseAssetPicker::HasUserConfigSettings()
  901. {
  902. return true;
  903. }
  904. //-----------------------------------------------------------------------------
  905. // Allows the picker to browse multiple asset types
  906. //-----------------------------------------------------------------------------
  907. void CBaseAssetPicker::AddExtension( const char *pExtension )
  908. {
  909. m_ExtraAssetExt.AddToTail( pExtension );
  910. }
  911. //-----------------------------------------------------------------------------
  912. // Is multiselect enabled?
  913. //-----------------------------------------------------------------------------
  914. bool CBaseAssetPicker::IsMultiselectEnabled() const
  915. {
  916. return m_pAssetBrowser->IsMultiselectEnabled();
  917. }
  918. void CBaseAssetPicker::SetAllowMultiselect( bool bAllowMultiselect )
  919. {
  920. m_pAssetBrowser->SetMultiselectEnabled( bAllowMultiselect );
  921. }
  922. //-----------------------------------------------------------------------------
  923. // Sets the initial selected asset
  924. //-----------------------------------------------------------------------------
  925. void CBaseAssetPicker::SetInitialSelection( const char *pAssetName )
  926. {
  927. SetSelection( pAssetName, true );
  928. }
  929. void CBaseAssetPicker::SetSelection( const char *pAssetName, bool bInitialSelection )
  930. {
  931. if( bInitialSelection )
  932. {
  933. // This makes it so the background list filling code will automatically select this asset when it gets to it.
  934. m_SelectedAsset = pAssetName;
  935. }
  936. if ( pAssetName )
  937. {
  938. // Sometimes we've already refreshed our list with a bunch of cached resources and the item is already in the list,
  939. // so in that case just select it here.
  940. int i = m_pAssetBrowser->GetItem( pAssetName );
  941. if ( i != -1 )
  942. {
  943. m_pAssetBrowser->SetSelectedCell( i, 0 );
  944. m_pAssetBrowser->ScrollToItem( i );
  945. }
  946. }
  947. }
  948. //-----------------------------------------------------------------------------
  949. // Set/get the filter
  950. //-----------------------------------------------------------------------------
  951. void CBaseAssetPicker::SetFilter( const char *pFilter )
  952. {
  953. m_Filter = pFilter;
  954. m_pFilter->SetText( pFilter );
  955. }
  956. const char *CBaseAssetPicker::GetFilter()
  957. {
  958. return m_Filter;
  959. }
  960. //-----------------------------------------------------------------------------
  961. // Purpose: called to open
  962. //-----------------------------------------------------------------------------
  963. void CBaseAssetPicker::Activate()
  964. {
  965. RefreshAssetList();
  966. RequestFilterFocus();
  967. // Keep scanning...
  968. if ( !m_bFinishedAssetListScan )
  969. {
  970. vgui::ivgui()->AddTickSignal( GetVPanel(), 10 );
  971. }
  972. }
  973. //-----------------------------------------------------------------------------
  974. // Purpose:
  975. //-----------------------------------------------------------------------------
  976. void CBaseAssetPicker::OnKeyCodeTyped( KeyCode code )
  977. {
  978. if (( code == KEY_UP ) || ( code == KEY_DOWN ) || ( code == KEY_PAGEUP ) || ( code == KEY_PAGEDOWN ))
  979. {
  980. KeyValues *pMsg = new KeyValues("KeyCodeTyped", "code", code);
  981. vgui::ipanel()->SendMessage( m_pAssetBrowser->GetVPanel(), pMsg, GetVPanel());
  982. pMsg->deleteThis();
  983. }
  984. else
  985. {
  986. BaseClass::OnKeyCodeTyped( code );
  987. }
  988. }
  989. const CachedAssetInfo_t& CBaseAssetPicker::GetCachedAsset( int nAssetIndex )
  990. {
  991. return s_AssetCache.GetAsset( m_hAssetList, nAssetIndex );
  992. }
  993. //-----------------------------------------------------------------------------
  994. // Is a particular asset visible?
  995. //-----------------------------------------------------------------------------
  996. bool CBaseAssetPicker::IsAssetVisible( int nAssetIndex )
  997. {
  998. const CachedAssetInfo_t& info = GetCachedAsset( nAssetIndex );
  999. // Filter based on active mod
  1000. int nModIndex = info.m_nModIndex;
  1001. if ( ( m_nCurrentModFilter >= 0 ) && ( m_nCurrentModFilter != nModIndex ) )
  1002. return false;
  1003. // Filter based on name
  1004. const char *pAssetName = info.m_AssetName;
  1005. if ( !Q_strcmp( pAssetName, m_SelectedAsset ) )
  1006. return true;
  1007. if ( m_Filter.Length() && !Q_stristr( pAssetName, m_Filter.Get() ) )
  1008. return false;
  1009. // Filter based on folder
  1010. if ( m_FolderFilter.Length() && Q_strnicmp( pAssetName, m_FolderFilter.Get(), m_FolderFilter.Length() ) )
  1011. return false;
  1012. // Filter based on subdirectory check
  1013. if ( !m_bSubDirCheck && strchr( pAssetName + m_FolderFilter.Length(), '\\' ) )
  1014. return false;
  1015. // Skip this asset if it's never used and we are only looking at used assets.
  1016. if ( m_bOnlyUsedAssetsCheck && !info.m_nTimesUsed )
  1017. return false;
  1018. return true;
  1019. }
  1020. //-----------------------------------------------------------------------------
  1021. //-----------------------------------------------------------------------------
  1022. void CBaseAssetPicker::SetUsedAssetList( CUtlVector<AssetUsageInfo_t> &usedAssets )
  1023. {
  1024. s_AssetCache.SetUsedAssetList( usedAssets );
  1025. bool bEnabled = ( usedAssets.Count() > 0 );
  1026. m_pOnlyUsedCheck->SetEnabled( bEnabled );
  1027. if ( !bEnabled )
  1028. {
  1029. m_pOnlyUsedCheck->SetSelected( false );
  1030. m_bOnlyUsedAssetsCheck = false;
  1031. }
  1032. m_pFindAssetButton->SetEnabled( bEnabled );
  1033. }
  1034. //-----------------------------------------------------------------------------
  1035. // Adds an asset from the cache to the list
  1036. //-----------------------------------------------------------------------------
  1037. void CBaseAssetPicker::AddAssetToList( int nAssetIndex )
  1038. {
  1039. const CachedAssetInfo_t& info = GetCachedAsset( nAssetIndex );
  1040. bool bInRootDir = !strchr( info.m_AssetName, '\\' ) && !strchr( info.m_AssetName, '/' );
  1041. Assert( m_pInsertHelper );
  1042. KeyValues *kv = m_pInsertHelper;
  1043. kv->SetName( info.m_AssetName );
  1044. kv->SetString( "asset", info.m_AssetName );
  1045. kv->SetString( "mod", s_AssetCache.ModInfo( info.m_nModIndex ).m_ModName );
  1046. kv->SetInt( "modIndex", info.m_nModIndex );
  1047. kv->SetInt( "root", bInRootDir );
  1048. kv->SetInt( "assetIndex", nAssetIndex );
  1049. // NOTE: properties which may change between browser invocations also need
  1050. // to be updated in RefreshAssetList!
  1051. kv->SetInt( "timesused", info.m_nTimesUsed );
  1052. int nItemID = m_pAssetBrowser->AddItem( kv, 0, false, false );
  1053. if ( m_pAssetBrowser->GetSelectedItemsCount() == 0 && !Q_strcmp( m_SelectedAsset, info.m_AssetName ) )
  1054. {
  1055. m_pAssetBrowser->SetSelectedCell( nItemID, 0 );
  1056. }
  1057. KeyValues *pDrag = new KeyValues( "drag", "text", info.m_AssetName );
  1058. if ( m_pAssetTextType )
  1059. {
  1060. pDrag->SetString( "texttype", m_pAssetTextType );
  1061. }
  1062. m_pAssetBrowser->SetItemDragData( nItemID, pDrag );
  1063. int i = m_AssetList.AddToTail( );
  1064. m_AssetList[i].m_nAssetIndex = nAssetIndex;
  1065. m_AssetList[i].m_nItemId = nItemID;
  1066. bool bIsVisible = IsAssetVisible( i );
  1067. m_pAssetBrowser->SetItemVisible( nItemID, bIsVisible );
  1068. if ( bIsVisible )
  1069. {
  1070. ++m_nMatchingAssets;
  1071. }
  1072. }
  1073. int CBaseAssetPicker::GetCachedAssetCount()
  1074. {
  1075. return s_AssetCache.GetAssetCount( m_hAssetList );
  1076. }
  1077. // overriden functionality
  1078. bool CBaseAssetPicker::IncrementalCacheAssets( float flTimeAllowed )
  1079. {
  1080. bool bFinished = s_AssetCache.ContinueSearchForAssets( m_hAssetList, flTimeAllowed );
  1081. if ( m_bFirstAssetScan )
  1082. {
  1083. m_pFileTree->OpenRoot();
  1084. }
  1085. return bFinished;
  1086. }
  1087. // common functionality
  1088. bool CBaseAssetPicker::DoIncrementalCache( )
  1089. {
  1090. float flTimeAllowed = m_bFirstAssetScan ? ASSET_LIST_DIRECTORY_INITIAL_SEARCH_TIME : ASSET_LIST_DIRECTORY_SEARCH_TIME;
  1091. bool bFinished = IncrementalCacheAssets( flTimeAllowed );
  1092. m_bFirstAssetScan = false;
  1093. return bFinished;
  1094. }
  1095. //-----------------------------------------------------------------------------
  1096. // Continues to build the asset list
  1097. //-----------------------------------------------------------------------------
  1098. void CBaseAssetPicker::OnTick()
  1099. {
  1100. BaseClass::OnTick();
  1101. int nPreAssetCount = GetCachedAssetCount( );
  1102. bool bFinished = DoIncrementalCache( );
  1103. int nPostAssetCount = GetCachedAssetCount( );
  1104. for ( int i = nPreAssetCount; i < nPostAssetCount; ++i )
  1105. {
  1106. AddAssetToList( i );
  1107. }
  1108. if ( bFinished )
  1109. {
  1110. vgui::ivgui()->RemoveTickSignal( GetVPanel() );
  1111. m_bFinishedAssetListScan = true;
  1112. // Copy the current folder filter.. this is necessary
  1113. // to finally select the folder loaded from the user config settings
  1114. // in the free view (since it's finally populated at this point)
  1115. // NOTE: if a user has changed the folder filter between startup
  1116. // and this point, this should still work since m_FolderFilter should be updated
  1117. m_pFileTree->SelectFolder( m_pAssetSubDir, m_FolderFilter );
  1118. RefreshAssetList( );
  1119. return;
  1120. }
  1121. UpdateAssetColumnHeader();
  1122. }
  1123. bool CBaseAssetPicker::BeginCacheAssets( bool bForceRecache )
  1124. {
  1125. return s_AssetCache.BeginAssetScan( m_hAssetList, bForceRecache );
  1126. }
  1127. //-----------------------------------------------------------------------------
  1128. // Builds the Bsp name list
  1129. //-----------------------------------------------------------------------------
  1130. void CBaseAssetPicker::BuildAssetNameList( )
  1131. {
  1132. if ( m_bBuiltAssetList )
  1133. return;
  1134. m_bBuiltAssetList = true;
  1135. m_nMatchingAssets = 0;
  1136. m_nCurrentModFilter = -1;
  1137. // Build the list of known mods if we haven't
  1138. s_AssetCache.BuildModList( m_pAssetSearchPath );
  1139. m_pModSelector->RemoveAll();
  1140. m_pModSelector->AddItem( "All Mods", new KeyValues( "Mod", "mod", -1 ) );
  1141. int nModCount = s_AssetCache.ModCount();
  1142. for ( int i = 0; i < nModCount; ++i )
  1143. {
  1144. const char *pModName = s_AssetCache.ModInfo( i ).m_ModName;
  1145. m_pModSelector->AddItem( pModName, new KeyValues( "Mod", "mod", i ) );
  1146. }
  1147. m_pModSelector->ActivateItemByRow( 0 );
  1148. // If we've already read in
  1149. if ( !BeginCacheAssets(false) )
  1150. {
  1151. m_bFirstAssetScan = true;
  1152. m_bFinishedAssetListScan = false;
  1153. vgui::ivgui()->AddTickSignal( GetVPanel(), 10 );
  1154. }
  1155. else
  1156. {
  1157. m_bFirstAssetScan = false;
  1158. m_bFinishedAssetListScan = true;
  1159. }
  1160. int nAssetCount = GetCachedAssetCount();
  1161. for ( int i = 0; i < nAssetCount; ++i )
  1162. {
  1163. AddAssetToList( i );
  1164. }
  1165. }
  1166. //-----------------------------------------------------------------------------
  1167. // Rescan assets
  1168. //-----------------------------------------------------------------------------
  1169. void CBaseAssetPicker::RescanAssets()
  1170. {
  1171. m_pAssetBrowser->RemoveAll();
  1172. m_AssetList.RemoveAll();
  1173. BeginCacheAssets( true );
  1174. m_bFirstAssetScan = true;
  1175. m_nMatchingAssets = 0;
  1176. if ( m_bFinishedAssetListScan )
  1177. {
  1178. m_bFinishedAssetListScan = false;
  1179. vgui::ivgui()->AddTickSignal( GetVPanel(), 10 );
  1180. }
  1181. }
  1182. //-----------------------------------------------------------------------------
  1183. // Returns the mod path to the item index
  1184. //-----------------------------------------------------------------------------
  1185. const char *CBaseAssetPicker::GetModPath( int nModIndex )
  1186. {
  1187. return s_AssetCache.ModInfo( nModIndex ).m_Path.Get();
  1188. }
  1189. //-----------------------------------------------------------------------------
  1190. // Command handler
  1191. //-----------------------------------------------------------------------------
  1192. void CBaseAssetPicker::OnCommand( const char *pCommand )
  1193. {
  1194. if ( !Q_stricmp( pCommand, "AssetRescan" ) )
  1195. {
  1196. RescanAssets();
  1197. return;
  1198. }
  1199. if ( !Q_stricmp( pCommand, "FindAsset" ) )
  1200. {
  1201. KeyValues *pKeyValues = new KeyValues( "AssetPickerFind" );
  1202. int nLength = m_pFullPath->GetTextLength();
  1203. char *pPath = (char *)stackalloc( ( nLength + 1 ) * sizeof( char ) );
  1204. if ( nLength > 0 )
  1205. {
  1206. m_pFullPath->GetText( pPath, nLength + 1 );
  1207. }
  1208. else
  1209. {
  1210. pPath[0] = '\0';
  1211. }
  1212. pKeyValues->SetString( "asset", pPath );
  1213. PostActionSignal( pKeyValues );
  1214. }
  1215. BaseClass::OnCommand( pCommand );
  1216. }
  1217. //-----------------------------------------------------------------------------
  1218. // Update column headers
  1219. //-----------------------------------------------------------------------------
  1220. void CBaseAssetPicker::UpdateAssetColumnHeader( )
  1221. {
  1222. char pColumnTitle[512];
  1223. Q_snprintf( pColumnTitle, sizeof(pColumnTitle), "%s (%d/%d)%s",
  1224. m_pAssetType, m_nMatchingAssets, m_AssetList.Count(), m_bFinishedAssetListScan ? "" : " ..." );
  1225. m_pAssetBrowser->SetColumnHeaderText( 1, pColumnTitle );
  1226. }
  1227. //-----------------------------------------------------------------------------
  1228. // Request focus of the filter box
  1229. //-----------------------------------------------------------------------------
  1230. void CBaseAssetPicker::RequestFilterFocus()
  1231. {
  1232. if ( m_Filter.Length() )
  1233. {
  1234. m_pFilter->SelectAllOnFirstFocus( true );
  1235. }
  1236. m_pFilter->RequestFocus();
  1237. }
  1238. //-----------------------------------------------------------------------------
  1239. // Purpose: refreshes the asset list
  1240. //-----------------------------------------------------------------------------
  1241. void CBaseAssetPicker::RefreshAssetList( )
  1242. {
  1243. BuildAssetNameList();
  1244. // Check the filter matches
  1245. int nCount = m_AssetList.Count();
  1246. m_nMatchingAssets = 0;
  1247. for ( int i = 0; i < nCount; ++i )
  1248. {
  1249. // Filter based on active mod
  1250. bool bIsVisible = IsAssetVisible( i );
  1251. // Update any fields that can change between invocations of the browser
  1252. const CachedAssetInfo_t &info = GetCachedAsset( i );
  1253. ListPanelItem *pItem = m_pAssetBrowser->GetItemData( m_AssetList[i].m_nItemId );
  1254. int oldTimesUsed = pItem->kv->GetInt( "timesused" );
  1255. if ( oldTimesUsed != info.m_nTimesUsed )
  1256. {
  1257. pItem->kv->SetInt( "timesused", info.m_nTimesUsed );
  1258. m_pAssetBrowser->ApplyItemChanges( m_AssetList[i].m_nItemId );
  1259. }
  1260. m_pAssetBrowser->SetItemVisible( m_AssetList[i].m_nItemId, bIsVisible );
  1261. if ( bIsVisible )
  1262. {
  1263. ++m_nMatchingAssets;
  1264. }
  1265. }
  1266. UpdateAssetColumnHeader();
  1267. m_pAssetBrowser->SortList();
  1268. if ( ( m_pAssetBrowser->GetSelectedItemsCount() == 0 ) && ( m_pAssetBrowser->GetItemCount() > 0 ) )
  1269. {
  1270. // Invoke a callback if the next selection will be a 'default' selection
  1271. OnNextSelectionIsDefault();
  1272. int nItemID = m_pAssetBrowser->GetItemIDFromRow( 0 );
  1273. m_pAssetBrowser->SetSelectedCell( nItemID, 0 );
  1274. }
  1275. m_pFileTree->RefreshFileList();
  1276. OnAssetListChanged();
  1277. }
  1278. //-----------------------------------------------------------------------------
  1279. // Purpose: refreshes dialog on file folder changing
  1280. //-----------------------------------------------------------------------------
  1281. void CBaseAssetPicker::OnFileSelected()
  1282. {
  1283. // update list
  1284. const char *pFolderFilter = "";
  1285. int iItem = m_pFileTree->GetFirstSelectedItem();
  1286. if ( iItem >= 0 )
  1287. {
  1288. KeyValues *pkv = m_pFileTree->GetItemData( iItem );
  1289. pFolderFilter = pkv->GetString( "path" );
  1290. // The first keys are always the subdir
  1291. pFolderFilter += Q_strlen( m_pAssetSubDir );
  1292. if ( *pFolderFilter )
  1293. {
  1294. ++pFolderFilter;
  1295. }
  1296. }
  1297. if ( Q_stricmp( pFolderFilter, m_FolderFilter.Get() ) )
  1298. {
  1299. int nLen = Q_strlen( pFolderFilter );
  1300. m_FolderFilter = pFolderFilter;
  1301. if ( nLen > 0 )
  1302. {
  1303. m_FolderFilter += '\\';
  1304. }
  1305. RefreshAssetList();
  1306. }
  1307. }
  1308. //-----------------------------------------------------------------------------
  1309. // Purpose: refreshes dialog on text changing
  1310. //-----------------------------------------------------------------------------
  1311. void CBaseAssetPicker::OnTextChanged( KeyValues *pKeyValues )
  1312. {
  1313. vgui::Panel *pSource = (vgui::Panel*)pKeyValues->GetPtr( "panel" );
  1314. if ( pSource == m_pFilter )
  1315. {
  1316. int nLength = m_pFilter->GetTextLength();
  1317. char *pNewFilter = (char*)stackalloc( (nLength+1) * sizeof(char) );
  1318. if ( nLength > 0 )
  1319. {
  1320. m_pFilter->GetText( pNewFilter, nLength+1 );
  1321. }
  1322. else
  1323. {
  1324. pNewFilter[0] = 0;
  1325. }
  1326. if ( Q_stricmp( pNewFilter, m_Filter.Get() ) )
  1327. {
  1328. m_Filter.SetLength( nLength );
  1329. m_Filter = pNewFilter;
  1330. RefreshAssetList();
  1331. }
  1332. return;
  1333. }
  1334. if ( pSource == m_pModSelector )
  1335. {
  1336. KeyValues *pKeyValues = m_pModSelector->GetActiveItemUserData();
  1337. if ( pKeyValues )
  1338. {
  1339. m_nCurrentModFilter = pKeyValues->GetInt( "mod", -1 );
  1340. RefreshAssetList();
  1341. }
  1342. return;
  1343. }
  1344. }
  1345. CUtlString CBaseAssetPicker::GetSelectedAssetFullPath( int nIndex )
  1346. {
  1347. const char *pSelectedAsset = GetSelectedAsset( nIndex - 1 );
  1348. int nModIndex = GetSelectedAssetModIndex();
  1349. char pBuf[MAX_PATH];
  1350. Q_snprintf( pBuf, sizeof(pBuf), "%s\\%s\\%s",
  1351. s_AssetCache.ModInfo( nModIndex ).m_Path.Get(), m_pAssetSubDir, pSelectedAsset );
  1352. Q_FixSlashes( pBuf );
  1353. return CUtlString(pBuf);
  1354. }
  1355. //-----------------------------------------------------------------------------
  1356. // Purpose: Updates preview when an item is selected
  1357. //-----------------------------------------------------------------------------
  1358. void CBaseAssetPicker::OnItemSelected( KeyValues *kv )
  1359. {
  1360. Panel *pPanel = (Panel *)kv->GetPtr( "panel", NULL );
  1361. if ( pPanel == m_pAssetBrowser )
  1362. {
  1363. int nCount = GetSelectedAssetCount();
  1364. Assert( nCount > 0 );
  1365. const char *pSelectedAsset = GetSelectedAsset( nCount - 1 );
  1366. m_pFullPath->SetText( GetSelectedAssetFullPath( nCount - 1 ) );
  1367. surface()->SetCursor( dc_waitarrow );
  1368. OnSelectedAssetPicked( pSelectedAsset );
  1369. return;
  1370. }
  1371. }
  1372. void CBaseAssetPicker::OnItemDeselected( KeyValues *kv )
  1373. {
  1374. Panel *pPanel = (Panel *)kv->GetPtr( "panel", NULL );
  1375. if ( pPanel == m_pAssetBrowser )
  1376. {
  1377. OnSelectedAssetPicked( "" );
  1378. return;
  1379. }
  1380. }
  1381. void CBaseAssetPicker::OnCheckButtonChecked( KeyValues *kv )
  1382. {
  1383. vgui::Panel *pSource = (vgui::Panel*)kv->GetPtr( "panel" );
  1384. if ( pSource == m_pSubDirCheck )
  1385. {
  1386. m_bSubDirCheck = m_pSubDirCheck->IsSelected();
  1387. RefreshAssetList();
  1388. }
  1389. else if ( pSource == m_pOnlyUsedCheck )
  1390. {
  1391. m_bOnlyUsedAssetsCheck = m_pOnlyUsedCheck->IsSelected();
  1392. RefreshAssetList();
  1393. }
  1394. }
  1395. //-----------------------------------------------------------------------------
  1396. // Returns the selceted asset count
  1397. //-----------------------------------------------------------------------------
  1398. int CBaseAssetPicker::GetSelectedAssetCount()
  1399. {
  1400. return m_pAssetBrowser->GetSelectedItemsCount();
  1401. }
  1402. //-----------------------------------------------------------------------------
  1403. // Returns the selceted asset name
  1404. //-----------------------------------------------------------------------------
  1405. const char *CBaseAssetPicker::GetSelectedAsset( int nSelectionIndex )
  1406. {
  1407. int nSelectedAssetCount = m_pAssetBrowser->GetSelectedItemsCount();
  1408. if ( nSelectionIndex < 0 )
  1409. {
  1410. nSelectionIndex = nSelectedAssetCount - 1;
  1411. }
  1412. if ( nSelectedAssetCount <= nSelectionIndex || nSelectionIndex < 0 )
  1413. return NULL;
  1414. int nIndex = m_pAssetBrowser->GetSelectedItem( nSelectionIndex );
  1415. KeyValues *pItemKeyValues = m_pAssetBrowser->GetItem( nIndex );
  1416. return pItemKeyValues->GetString( "asset" );
  1417. }
  1418. //-----------------------------------------------------------------------------
  1419. // Returns the selected asset index (in the list of all cached assets)
  1420. //-----------------------------------------------------------------------------
  1421. int CBaseAssetPicker::GetSelectedAssetIndex( int nSelectionIndex )
  1422. {
  1423. int nSelectedAssetCount = m_pAssetBrowser->GetSelectedItemsCount();
  1424. if ( nSelectionIndex < 0 )
  1425. {
  1426. nSelectionIndex = nSelectedAssetCount - 1;
  1427. }
  1428. if ( nSelectedAssetCount <= nSelectionIndex || nSelectionIndex < 0 )
  1429. return -1;
  1430. int nIndex = m_pAssetBrowser->GetSelectedItem( nSelectionIndex );
  1431. KeyValues *pItemKeyValues = m_pAssetBrowser->GetItem( nIndex );
  1432. return pItemKeyValues->GetInt( "assetIndex" );
  1433. }
  1434. //-----------------------------------------------------------------------------
  1435. // Returns the total filtered asset count
  1436. //-----------------------------------------------------------------------------
  1437. int CBaseAssetPicker::GetAssetCount()
  1438. {
  1439. return m_AssetList.Count();
  1440. }
  1441. //-----------------------------------------------------------------------------
  1442. // Returns the specified asset name
  1443. //-----------------------------------------------------------------------------
  1444. const char *CBaseAssetPicker::GetAssetName( int nAssetIndex )
  1445. {
  1446. int cacheIndex = m_AssetList[nAssetIndex].m_nAssetIndex;
  1447. const CachedAssetInfo_t& assetInfo = s_AssetCache.GetAsset( m_hAssetList, cacheIndex );
  1448. return assetInfo.m_AssetName;
  1449. }
  1450. //-----------------------------------------------------------------------------
  1451. // Returns the selceted asset mod index
  1452. //-----------------------------------------------------------------------------
  1453. int CBaseAssetPicker::GetSelectedAssetModIndex( )
  1454. {
  1455. if ( m_pAssetBrowser->GetSelectedItemsCount() == 0 )
  1456. return NULL;
  1457. int nIndex = m_pAssetBrowser->GetSelectedItem( 0 );
  1458. KeyValues *pItemKeyValues = m_pAssetBrowser->GetItem( nIndex );
  1459. return pItemKeyValues->GetInt( "modIndex" );
  1460. }
  1461. int CBaseAssetPicker::ModCount() const
  1462. {
  1463. return s_AssetCache.ModCount();
  1464. }
  1465. const CacheModInfo_t& CBaseAssetPicker::ModInfo( int nIndex ) const
  1466. {
  1467. return s_AssetCache.ModInfo( nIndex );
  1468. }
  1469. void CBaseAssetPicker::CloseModal()
  1470. {
  1471. // Stop refreshing if close before finished loading
  1472. vgui::ivgui()->RemoveTickSignal( GetVPanel() );
  1473. }
  1474. //-----------------------------------------------------------------------------
  1475. //
  1476. // Purpose: Modal picker frame
  1477. //
  1478. //-----------------------------------------------------------------------------
  1479. CBaseAssetPickerFrame::CBaseAssetPickerFrame( vgui::Panel *pParent ) :
  1480. BaseClass( pParent, "AssetPickerFrame" )
  1481. {
  1482. m_pContextKeyValues = NULL;
  1483. SetDeleteSelfOnClose( true );
  1484. m_pOpenButton = new Button( this, "OpenButton", "#FileOpenDialog_Open", this, "Open" );
  1485. m_pCancelButton = new Button( this, "CancelButton", "#FileOpenDialog_Cancel", this, "Cancel" );
  1486. SetBlockDragChaining( true );
  1487. }
  1488. CBaseAssetPickerFrame::~CBaseAssetPickerFrame()
  1489. {
  1490. CleanUpMessage();
  1491. }
  1492. //-----------------------------------------------------------------------------
  1493. // Allows the derived class to create the picker
  1494. //-----------------------------------------------------------------------------
  1495. void CBaseAssetPickerFrame::SetAssetPicker( CBaseAssetPicker* pPicker )
  1496. {
  1497. m_pPicker = pPicker;
  1498. m_pPicker->AddActionSignalTarget( this );
  1499. }
  1500. //-----------------------------------------------------------------------------
  1501. // Deletes the message
  1502. //-----------------------------------------------------------------------------
  1503. void CBaseAssetPickerFrame::CleanUpMessage()
  1504. {
  1505. if ( m_pContextKeyValues )
  1506. {
  1507. m_pContextKeyValues->deleteThis();
  1508. m_pContextKeyValues = NULL;
  1509. }
  1510. }
  1511. //-----------------------------------------------------------------------------
  1512. // Sets the initial selected asset
  1513. //-----------------------------------------------------------------------------
  1514. void CBaseAssetPickerFrame::SetInitialSelection( const char *pAssetName )
  1515. {
  1516. m_pPicker->SetInitialSelection( pAssetName );
  1517. }
  1518. //-----------------------------------------------------------------------------
  1519. // Set/get the filter
  1520. //-----------------------------------------------------------------------------
  1521. void CBaseAssetPickerFrame::SetFilter( const char *pFilter )
  1522. {
  1523. m_pPicker->SetFilter( pFilter );
  1524. }
  1525. const char *CBaseAssetPickerFrame::GetFilter()
  1526. {
  1527. return m_pPicker->GetFilter( );
  1528. }
  1529. //-----------------------------------------------------------------------------
  1530. // Purpose: Activate the dialog
  1531. //-----------------------------------------------------------------------------
  1532. void CBaseAssetPickerFrame::DoModal( KeyValues *pKeyValues )
  1533. {
  1534. BaseClass::DoModal();
  1535. CleanUpMessage();
  1536. if ( m_pContextKeyValues )
  1537. {
  1538. m_pContextKeyValues->deleteThis();
  1539. }
  1540. m_pContextKeyValues = pKeyValues;
  1541. m_pPicker->Activate();
  1542. }
  1543. //-----------------------------------------------------------------------------
  1544. // Posts a message (passing the key values)
  1545. //-----------------------------------------------------------------------------
  1546. void CBaseAssetPickerFrame::PostMessageAndClose( KeyValues *pKeyValues )
  1547. {
  1548. if ( m_pContextKeyValues )
  1549. {
  1550. pKeyValues->AddSubKey( m_pContextKeyValues );
  1551. m_pContextKeyValues = NULL;
  1552. }
  1553. CloseModal();
  1554. PostActionSignal( pKeyValues );
  1555. }
  1556. //-----------------------------------------------------------------------------
  1557. // On command
  1558. //-----------------------------------------------------------------------------
  1559. void CBaseAssetPickerFrame::OnCommand( const char *pCommand )
  1560. {
  1561. if ( !Q_stricmp( pCommand, "Open" ) )
  1562. {
  1563. KeyValues *pActionKeys = new KeyValues( "AssetSelected" );
  1564. if ( !m_pPicker->IsMultiselectEnabled() )
  1565. {
  1566. const char *pAssetName = m_pPicker->GetSelectedAsset( );
  1567. pActionKeys->SetString( "asset", pAssetName );
  1568. }
  1569. else
  1570. {
  1571. char pBuf[512];
  1572. KeyValues *pAssetKeys = pActionKeys->FindKey( "assets", true );
  1573. int nCount = m_pPicker->GetSelectedAssetCount();
  1574. for ( int i = 0; i < nCount; ++i )
  1575. {
  1576. Q_snprintf( pBuf, sizeof(pBuf), "asset%d", i );
  1577. pAssetKeys->SetString( pBuf, m_pPicker->GetSelectedAsset( i ) );
  1578. }
  1579. }
  1580. m_pPicker->CustomizeSelectionMessage( pActionKeys );
  1581. PostMessageAndClose( pActionKeys );
  1582. return;
  1583. }
  1584. if ( !Q_stricmp( pCommand, "Cancel" ) )
  1585. {
  1586. CloseModal();
  1587. return;
  1588. }
  1589. BaseClass::OnCommand( pCommand );
  1590. }
  1591. void CBaseAssetPickerFrame::CloseModal()
  1592. {
  1593. GetAssetPicker()->CloseModal();
  1594. BaseClass::CloseModal();
  1595. }
  1596. void CBaseAssetPickerFrame::SetAllowMultiselect( bool bAllowMultiselect )
  1597. {
  1598. GetAssetPicker()->SetAllowMultiselect( bAllowMultiselect );
  1599. }