diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/xbox/vxconsole/exclude_paths.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'utils/xbox/vxconsole/exclude_paths.cpp')
| -rw-r--r-- | utils/xbox/vxconsole/exclude_paths.cpp | 1134 |
1 files changed, 1134 insertions, 0 deletions
diff --git a/utils/xbox/vxconsole/exclude_paths.cpp b/utils/xbox/vxconsole/exclude_paths.cpp new file mode 100644 index 0000000..668a835 --- /dev/null +++ b/utils/xbox/vxconsole/exclude_paths.cpp @@ -0,0 +1,1134 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// EXCLUDE_PATHS.CPP +// +// DVD Exclude paths. +//=====================================================================================// +#include "vxconsole.h" + +#define UM_CHECKSTATECHANGE (WM_USER + 100) +#define UM_FIRSTTIMEPOPULATE (WM_USER + 101) + +#define MAX_TREE_DEPTH 32 +#define ROOT_NAME "Xbox:\\" +#define EXCLUDEPATHS_FILE "xbox_exclude_paths.txt" + +// known shipping 360 gamedirs +struct GameName_t +{ + const char *pName; + bool bIsModPath; +}; + +struct GamePath_t +{ + CUtlString pathName; + bool bIsModPath; +}; + +GameName_t g_GameNames[] = +{ + { "bin", false }, + { "platform", false }, + { "tf", true }, + { "portal", true }, + { "hl2", true }, + { "episodic", true }, + { "ep2", true } +}; + +CUtlVector< CUtlString > g_ExcludePaths; +BOOL g_bLinkGameDirs; + +inline bool PathLessThan( GamePath_t const &lhs, GamePath_t const &rhs ) +{ + if ( lhs.bIsModPath != rhs.bIsModPath ) + { + // sort mod paths to the bottom + return ( lhs.bIsModPath == false ); + } + + return ( stricmp( lhs.pathName.String(), rhs.pathName.String() ) < 0 ); +} +CUtlRBTree< GamePath_t > g_PathTable( 0, 0, PathLessThan ); + +//----------------------------------------------------------------------------- +// Add string to TreeView at specified level. Assumes an inorder insert. +// A node (at specified depth) must be inserted before it's children. +//----------------------------------------------------------------------------- +static HTREEITEM AddItemToTree( HWND hWndTree, LPSTR lpszItem, int nLevel, bool bIsModPath ) +{ + TVITEM tvi = { 0 }; + TVINSERTSTRUCT tvins = { 0 }; + static HTREEITEM s_hPrevItems[MAX_TREE_DEPTH]; + + if ( nLevel < 0 || nLevel >= MAX_TREE_DEPTH ) + { + Assert( 0 ); + return NULL; + } + + HTREEITEM hParent; + HTREEITEM hPrev; + if ( !nLevel ) + { + // one root item only, reset + for ( int i = 0; i < ARRAYSIZE( s_hPrevItems ); i++ ) + { + s_hPrevItems[i] = NULL; + } + hParent = TVI_ROOT; + hPrev = (HTREEITEM)TVI_FIRST; + } + else + { + hParent = s_hPrevItems[nLevel-1]; + hPrev = s_hPrevItems[nLevel]; + if ( !hParent ) + { + // parent should have been setup + Assert( 0 ); + return NULL; + } + if ( !hPrev ) + { + hPrev = TVI_FIRST; + } + } + + tvi.mask = TVIF_TEXT | TVIF_PARAM; + tvi.pszText = lpszItem; + tvi.cchTextMax = sizeof(tvi.pszText)/sizeof(tvi.pszText[0]); + tvi.lParam = (LPARAM)MAKELONG( nLevel, bIsModPath ); + + tvins.item = tvi; + tvins.hParent = hParent; + tvins.hInsertAfter = hPrev; + + // Add the item to the tree-view control. + hPrev = TreeView_InsertItem( hWndTree, &tvins ); + s_hPrevItems[nLevel] = hPrev; + + if ( nLevel > 0 ) + { + // set a back link to its parent + tvi.mask = TVIF_HANDLE; + tvi.hItem = TreeView_GetParent( hWndTree, hPrev ); + TreeView_SetItem( hWndTree, &tvi ); + } + + return hPrev; +} + +//----------------------------------------------------------------------------- +// Purpose: Get list of files from current path that match pattern +//----------------------------------------------------------------------------- +static int GetFileList( const char* pDirPath, const char* pPattern, CUtlVector< CUtlString > &fileList ) +{ + char sourcePath[MAX_PATH]; + char fullPath[MAX_PATH]; + bool bFindDirs; + + fileList.Purge(); + + strcpy( sourcePath, pDirPath ); + int len = (int)strlen( sourcePath ); + if ( !len ) + { + strcpy( sourcePath, ".\\" ); + } + else if ( sourcePath[len-1] != '\\' ) + { + sourcePath[len] = '\\'; + sourcePath[len+1] = '\0'; + } + + strcpy( fullPath, sourcePath ); + if ( pPattern[0] == '\\' && pPattern[1] == '\0' ) + { + // find directories only + bFindDirs = true; + strcat( fullPath, "*" ); + } + else + { + // find files, use provided pattern + bFindDirs = false; + strcat( fullPath, pPattern ); + } + + struct _finddata_t findData; + intptr_t h = _findfirst( fullPath, &findData ); + if ( h == -1 ) + { + return 0; + } + + do + { + // dos attribute complexities i.e. _A_NORMAL is 0 + if ( bFindDirs ) + { + // skip non dirs + if ( !( findData.attrib & _A_SUBDIR ) ) + continue; + } + else + { + // skip dirs + if ( findData.attrib & _A_SUBDIR ) + continue; + } + + if ( !stricmp( findData.name, "." ) ) + continue; + + if ( !stricmp( findData.name, ".." ) ) + continue; + + char fileName[MAX_PATH]; + strcpy( fileName, sourcePath ); + strcat( fileName, findData.name ); + + int j = fileList.AddToTail(); + fileList[j].Set( fileName ); + } + while ( !_findnext( h, &findData ) ); + + _findclose( h ); + + return fileList.Count(); +} + +//----------------------------------------------------------------------------- +// Purpose: Recursively determine directory tree +//----------------------------------------------------------------------------- +static void RecurseFileTree_r( const char *pBasePath, const char *pDirPath, int depth, CUtlVector< CUtlString > &dirList, bool bIsModPath ) +{ + if ( depth >= 2 ) + { + // too much unecessary detail + return; + } + + // ignore path roots, only interested in subdirs + const char *pSubName = pDirPath + strlen( pBasePath ); + if ( pSubName[0] ) + { + GamePath_t gamePath; + gamePath.pathName = pSubName; + gamePath.bIsModPath = bIsModPath; + + int iIndex = g_PathTable.Find( gamePath ); + if ( iIndex == g_PathTable.InvalidIndex() ) + { + g_PathTable.Insert( gamePath ); + } + } + + // recurse from source directory, get directories only + CUtlVector< CUtlString > fileList; + int dirCount = GetFileList( pDirPath, "\\", fileList ); + if ( !dirCount ) + { + // add directory name to search tree + int j = dirList.AddToTail(); + dirList[j].Set( pDirPath ); + return; + } + + for ( int i=0; i<dirCount; i++ ) + { + // form new path name, recurse into + RecurseFileTree_r( pBasePath, fileList[i].String(), depth+1, dirList, bIsModPath ); + } + + int j = dirList.AddToTail(); + dirList[j].Set( pDirPath ); +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_SetCheckState_r +// +// Propogate the check state to all children +//----------------------------------------------------------------------------- +void ExcludePathsDlg_SetCheckState_r( HWND hWndTree, HTREEITEM hTree, int depth, int checkState ) +{ + if ( !hTree ) + { + return; + } + + TreeView_SetCheckState( hWndTree, hTree, ( checkState == 1 ) ); + + TVITEM tvi = { 0 }; + tvi.mask = TVIF_HANDLE | TVIF_CHILDREN; + tvi.hItem = hTree; + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + if ( tvi.cChildren ) + { + HTREEITEM hChild = TreeView_GetChild( hWndTree, hTree ); + if ( hChild ) + { + ExcludePathsDlg_SetCheckState_r( hWndTree, hChild, depth+1, checkState ); + } + } + } + else + { + return; + } + + if ( !depth ) + { + // only iterate siblings of the parent's child + return; + } + + HTREEITEM hSibling = hTree; + while ( 1 ) + { + hSibling = TreeView_GetNextSibling( hWndTree, hSibling ); + if ( !hSibling ) + { + return; + } + + TreeView_SetCheckState( hWndTree, hSibling, ( checkState == 1 ) ); + + tvi.hItem = hSibling; + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + if ( tvi.cChildren ) + { + HTREEITEM hChild = TreeView_GetChild( hWndTree, hSibling ); + if ( hChild ) + { + ExcludePathsDlg_SetCheckState_r( hWndTree, hChild, depth+1, checkState ); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_SetCheckStateLinked_r +// +// Propogate the check state to all "mod path" children that match the specified name. +// A NULL name matches all. +//----------------------------------------------------------------------------- +void ExcludePathsDlg_SetCheckStateLinked_r( HWND hWndTree, HTREEITEM hTree, int depth, int checkState, const char *pName ) +{ + if ( !hTree ) + { + return; + } + + char szNodeName[MAX_PATH]; + TVITEM tvi = { 0 }; + tvi.mask = TVIF_HANDLE | TVIF_CHILDREN | TVIF_TEXT | TVIF_PARAM; + tvi.hItem = hTree; + tvi.pszText = szNodeName; + tvi.cchTextMax = sizeof( szNodeName ); + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + bool bIsModPath = HIWORD( tvi.lParam ) != 0; + if ( bIsModPath && ( !pName || !V_stricmp( szNodeName, pName ) ) ) + { + TreeView_SetCheckState( hWndTree, hTree, ( checkState == 1 ) ); + } + + if ( tvi.cChildren ) + { + HTREEITEM hChild = TreeView_GetChild( hWndTree, hTree ); + if ( hChild ) + { + ExcludePathsDlg_SetCheckStateLinked_r( hWndTree, hChild, depth+1, checkState, pName ); + } + } + } + else + { + return; + } + + if ( !depth ) + { + // only iterate siblings of the parent's child + return; + } + + HTREEITEM hSibling = hTree; + while ( 1 ) + { + hSibling = TreeView_GetNextSibling( hWndTree, hSibling ); + if ( !hSibling ) + { + return; + } + + tvi.hItem = hSibling; + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + bool bIsModPath = HIWORD( tvi.lParam ) != 0; + if ( bIsModPath && ( !pName || !V_stricmp( szNodeName, pName ) ) ) + { + TreeView_SetCheckState( hWndTree, hSibling, ( checkState == 1 ) ); + } + + if ( tvi.cChildren ) + { + HTREEITEM hChild = TreeView_GetChild( hWndTree, hSibling ); + if ( hChild ) + { + ExcludePathsDlg_SetCheckStateLinked_r( hWndTree, hChild, depth+1, checkState, pName ); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_GetCheckState_r +// +// Caller invokes at node. Returns with state set. +// State 0: unchecked, 1: checked, -1:unknown. +// Returns true if All children match, false otherwise. +//----------------------------------------------------------------------------- +bool ExcludePathsDlg_GetCheckState_r( HWND hWndTree, HTREEITEM hTree, int depth, int *pCheckState ) +{ + int checkState; + + checkState = TreeView_GetCheckState( hWndTree, hTree ); + if ( *pCheckState == -1 ) + { + *pCheckState = checkState; + } + else if ( *pCheckState != checkState ) + { + // disparate state, no need to recurse + return false; + } + + TVITEM tvi = { 0 }; + tvi.mask = TVIF_HANDLE | TVIF_CHILDREN; + tvi.hItem = hTree; + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + if ( tvi.cChildren ) + { + HTREEITEM hChild = TreeView_GetChild( hWndTree, hTree ); + if ( hChild ) + { + if ( !ExcludePathsDlg_GetCheckState_r( hWndTree, hChild, depth+1, pCheckState ) ) + { + return false; + } + } + } + } + else + { + return false; + } + + if ( !depth ) + { + // only iterate siblings of the parent's child + return true; + } + + HTREEITEM hSibling = hTree; + while ( 1 ) + { + hSibling = TreeView_GetNextSibling( hWndTree, hSibling ); + if ( !hSibling ) + { + break; + } + + checkState = TreeView_GetCheckState( hWndTree, hSibling ); + if ( *pCheckState != checkState ) + { + // disparate state, no need to recurse + return false; + } + + tvi.hItem = hSibling; + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + if ( tvi.cChildren ) + { + HTREEITEM hChild = TreeView_GetChild( hWndTree, hSibling ); + if ( hChild ) + { + if ( !ExcludePathsDlg_GetCheckState_r( hWndTree, hChild, depth+1, pCheckState ) ) + { + return false; + } + } + } + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_Expand_r +// +// MaxDepth >= 0, Expand/Collapse up to specified depth. +//----------------------------------------------------------------------------- +void ExcludePathsDlg_Expand_r( HWND hWndTree, HTREEITEM hTree, int depth, int maxDepth, bool bExpand ) +{ + if ( !hTree ) + { + return; + } + + if ( maxDepth >= 0 && depth >= maxDepth ) + { + return; + } + + int flags; + if ( bExpand ) + flags = TVE_EXPAND; + else + flags = TVE_COLLAPSE; + + TVITEM tvi = { 0 }; + tvi.mask = TVIF_HANDLE | TVIF_CHILDREN; + tvi.hItem = hTree; + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + if ( tvi.cChildren ) + { + TreeView_Expand( hWndTree, hTree, flags ); + HTREEITEM hChild = TreeView_GetChild( hWndTree, hTree ); + if ( hChild ) + { + ExcludePathsDlg_Expand_r( hWndTree, hChild, depth+1, maxDepth, bExpand ); + } + } + } + else + { + return; + } + + if ( !depth ) + { + // only iterate siblings of the parent's child + return; + } + + HTREEITEM hSibling = hTree; + while ( 1 ) + { + hSibling = TreeView_GetNextSibling( hWndTree, hSibling ); + if ( !hSibling ) + { + return; + } + + tvi.hItem = hSibling; + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + if ( tvi.cChildren ) + { + TreeView_Expand( hWndTree, hSibling, flags ); + HTREEITEM hChild = TreeView_GetChild( hWndTree, hSibling ); + if ( hChild ) + { + ExcludePathsDlg_Expand_r( hWndTree, hChild, depth+1, maxDepth, bExpand ); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_ExpandToShowState_r +// +//----------------------------------------------------------------------------- +void ExcludePathsDlg_ExpandToShowState_r( HWND hWndTree, HTREEITEM hTree, int depth ) +{ + if ( !hTree ) + { + return; + } + + TVITEM tvi = { 0 }; + tvi.mask = TVIF_HANDLE | TVIF_CHILDREN; + tvi.hItem = hTree; + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + int checkState = -1; + bool bStateIsSame = ExcludePathsDlg_GetCheckState_r( hWndTree, hTree, 0, &checkState ); + + if ( tvi.cChildren && !bStateIsSame ) + { + TreeView_Expand( hWndTree, hTree, TVE_EXPAND ); + HTREEITEM hChild = TreeView_GetChild( hWndTree, hTree ); + if ( hChild ) + { + ExcludePathsDlg_ExpandToShowState_r( hWndTree, hChild, depth+1 ); + } + } + } + else + { + return; + } + + if ( !depth ) + { + // only iterate siblings of the parent's child + return; + } + + HTREEITEM hSibling = hTree; + while ( 1 ) + { + hSibling = TreeView_GetNextSibling( hWndTree, hSibling ); + if ( !hSibling ) + { + return; + } + + tvi.hItem = hSibling; + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + int checkState = -1; + bool bStateIsSame = ExcludePathsDlg_GetCheckState_r( hWndTree, hSibling, 0, &checkState ); + + if ( tvi.cChildren && !bStateIsSame ) + { + TreeView_Expand( hWndTree, hSibling, TVE_EXPAND ); + HTREEITEM hChild = TreeView_GetChild( hWndTree, hSibling ); + if ( hChild ) + { + ExcludePathsDlg_ExpandToShowState_r( hWndTree, hChild, depth+1 ); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_Find_r +// +//----------------------------------------------------------------------------- +HTREEITEM ExcludePathsDlg_Find_r( HWND hWndTree, HTREEITEM hTree, int depth, const char *pBasePath, const char *pFindPath ) +{ + TVITEM tvi = { 0 }; + char szName[MAX_PATH]; + tvi.mask = TVIF_HANDLE | TVIF_CHILDREN | TVIF_TEXT; + tvi.hItem = hTree; + tvi.pszText = szName; + tvi.cchTextMax = sizeof( szName ); + if ( !TreeView_GetItem( hWndTree, &tvi ) ) + { + return NULL; + } + + char szPath[MAX_PATH]; + V_ComposeFileName( pBasePath, szName, szPath, sizeof( szPath ) ); + if ( !stricmp( szPath, pFindPath ) ) + { + return hTree; + } + + if ( tvi.cChildren ) + { + HTREEITEM hChild = TreeView_GetChild( hWndTree, hTree ); + if ( hChild ) + { + HTREEITEM hFindTree = ExcludePathsDlg_Find_r( hWndTree, hChild, depth+1, szPath, pFindPath ); + if ( hFindTree ) + { + return hFindTree; + } + } + } + + if ( !depth ) + { + // only iterate siblings of the parent's child + return NULL; + } + + // iterate siblings + HTREEITEM hSibling = hTree; + while ( 1 ) + { + hSibling = TreeView_GetNextSibling( hWndTree, hSibling ); + if ( !hSibling ) + { + break; + } + + tvi.hItem = hSibling; + if ( !TreeView_GetItem( hWndTree, &tvi ) ) + { + break; + } + + V_ComposeFileName( pBasePath, szName, szPath, sizeof( szPath ) ); + if ( !stricmp( szPath, pFindPath ) ) + { + return hSibling; + } + + if ( tvi.cChildren ) + { + HTREEITEM hChild = TreeView_GetChild( hWndTree, hSibling ); + if ( hChild ) + { + HTREEITEM hFindTree = ExcludePathsDlg_Find_r( hWndTree, hChild, depth+1, szPath, pFindPath ); + if ( hFindTree ) + { + return hFindTree; + } + } + } + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_BuildExcludeList_r +// +// An exclude path represents the path head, and thus does not need to iterate its children +// if they are deemed to the same exclusion state. +//----------------------------------------------------------------------------- +void ExcludePathsDlg_BuildExcludeList_r( HWND hWndTree, HTREEITEM hTree, int depth, const char *pPath ) +{ + int checkState = -1; + bool bStateIsSame = ExcludePathsDlg_GetCheckState_r( hWndTree, hTree, 0, &checkState ); + if ( checkState == -1 ) + { + return; + } + + TVITEM tvi = { 0 }; + char szName[MAX_PATH]; + tvi.mask = TVIF_HANDLE | TVIF_CHILDREN | TVIF_TEXT; + tvi.hItem = hTree; + tvi.pszText = szName; + tvi.cchTextMax = sizeof( szName ); + if ( !TreeView_GetItem( hWndTree, &tvi ) ) + { + return; + } + + char szPath[MAX_PATH]; + V_ComposeFileName( pPath, szName, szPath, sizeof( szPath ) ); + + if ( checkState == 1 && ( bStateIsSame || !tvi.cChildren ) ) + { + // add to exclude list + g_ExcludePaths.AddToTail( szPath ); + } + + if ( !bStateIsSame && tvi.cChildren ) + { + // mixed states, must recurse to resolve + HTREEITEM hChild = TreeView_GetChild( hWndTree, hTree ); + if ( hChild ) + { + ExcludePathsDlg_BuildExcludeList_r( hWndTree, hChild, depth+1, szPath ); + } + } + + if ( !depth ) + { + // only iterate siblings of the parent's child + return; + } + + // iterate siblings + HTREEITEM hSibling = hTree; + while ( 1 ) + { + hSibling = TreeView_GetNextSibling( hWndTree, hSibling ); + if ( !hSibling ) + { + break; + } + + checkState = -1; + bStateIsSame = ExcludePathsDlg_GetCheckState_r( hWndTree, hSibling, 0, &checkState ); + if ( checkState == -1 ) + { + break; + } + + tvi.hItem = hSibling; + if ( !TreeView_GetItem( hWndTree, &tvi ) ) + { + break; + } + + V_ComposeFileName( pPath, szName, szPath, sizeof( szPath ) ); + + if ( checkState == 1 && ( bStateIsSame || !tvi.cChildren ) ) + { + // add to exclude list + g_ExcludePaths.AddToTail( szPath ); + } + + if ( !bStateIsSame && tvi.cChildren ) + { + HTREEITEM hChild = TreeView_GetChild( hWndTree, hSibling ); + if ( hChild ) + { + ExcludePathsDlg_BuildExcludeList_r( hWndTree, hChild, depth+1, szPath ); + } + } + } +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_SaveChanges +// +//----------------------------------------------------------------------------- +void ExcludePathsDlg_SaveChanges( HWND hWnd ) +{ + g_ExcludePaths.Purge(); + HWND hWndTree = GetDlgItem( hWnd, IDC_PATHS_TREE ); + ExcludePathsDlg_BuildExcludeList_r( hWndTree, TreeView_GetRoot( hWndTree ), 0, "" ); + + char szPath[MAX_PATH]; + V_ComposeFileName( g_localPath, EXCLUDEPATHS_FILE, szPath, sizeof( szPath ) ); + + if ( !g_ExcludePaths.Count() ) + { + // no exclude paths + unlink( szPath ); + } + else + { + FILE *fp = fopen( szPath, "wt" ); + if ( !fp ) + { + Sys_MessageBox( "Error", "Could not open '%s' for writing\n", szPath ); + return; + } + + fprintf( fp, "// Auto-Generated by VXConsole - DO NOT MODIFY!\n" ); + for ( int i = 0; i < g_ExcludePaths.Count(); i++ ) + { + // strip expected root path + const char *pPath = g_ExcludePaths[i].String(); + pPath += strlen( ROOT_NAME ); + if ( !pPath[0] ) + { + // special code for root + fprintf( fp, "*\n" ); + break; + } + fprintf( fp, "\"\\%s\"\n", pPath ); + } + fclose( fp ); + } +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_Populate +// +// Generate a path table. +//----------------------------------------------------------------------------- +void ExcludePathsDlg_Populate( HWND hWnd, bool bRefresh ) +{ + struct GamePath_t + { + CUtlString pathName; + bool bIsModPath; + }; + + CUtlVector< GamePath_t > gamePaths; + + // can skip the time consuming directory scan, unless forced + if ( bRefresh || !g_PathTable.Count() ) + { + g_PathTable.Purge(); + + for ( int i = 0; i < ARRAYSIZE( g_GameNames ); i++ ) + { + char szTargetPath[MAX_PATH]; + V_strncpy( szTargetPath, g_localPath, sizeof( szTargetPath ) ); + V_AppendSlash( szTargetPath, sizeof( szTargetPath ) ); + V_strncat( szTargetPath, g_GameNames[i].pName, sizeof( szTargetPath ) ); + + GamePath_t gamePath; + gamePath.pathName = szTargetPath; + gamePath.bIsModPath = g_GameNames[i].bIsModPath; + gamePaths.AddToTail( gamePath ); + } + + // iterate all game paths + for ( int i = 0; i < gamePaths.Count(); i++ ) + { + CUtlVector< CUtlString > dirList; + RecurseFileTree_r( g_localPath, gamePaths[i].pathName.String(), 0, dirList, gamePaths[i].bIsModPath ); + } + } + + // reset the tree + HWND hWndTree = GetDlgItem( hWnd, IDC_PATHS_TREE ); + TreeView_DeleteAllItems( hWndTree ); + + // reset and add root + // only the root is at depth 0 + AddItemToTree( hWndTree, ROOT_NAME, 0, false ); + + // build the tree view + for ( int iIndex = g_PathTable.FirstInorder(); iIndex != g_PathTable.InvalidIndex(); iIndex = g_PathTable.NextInorder( iIndex ) ) + { + // due to sorting, number of slashes is depth + const char *pString = g_PathTable[iIndex].pathName.String(); + int depth = 0; + for ( int j = 0; j < (int)strlen( pString ); j++ ) + { + if ( pString[j] == '\\' ) + { + depth++; + } + } + if ( !depth ) + { + depth = 1; + } + + char szPath[MAX_PATH]; + V_FileBase( pString, szPath, sizeof( szPath ) ); + AddItemToTree( hWndTree, szPath, depth, g_PathTable[iIndex].bIsModPath ); + } + + HTREEITEM hTreeRoot = TreeView_GetRoot( hWndTree ); + for ( int i = 0; i < g_ExcludePaths.Count(); i++ ) + { + HTREEITEM hTree = ExcludePathsDlg_Find_r( hWndTree, hTreeRoot, 0, "", g_ExcludePaths[i].String() ); + if ( hTree ) + { + ExcludePathsDlg_SetCheckState_r( hWndTree, hTree, 0, true ); + } + } + + // expand the root node to show state + ExcludePathsDlg_ExpandToShowState_r( hWndTree, hTreeRoot, 0 ); +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_Setup +// +//----------------------------------------------------------------------------- +void ExcludePathsDlg_Setup( HWND hWnd ) +{ + TreeView_SetBkColor( GetDlgItem( hWnd, IDC_PATHS_TREE ), g_backgroundColor ); + + CheckDlgButton( hWnd, IDC_PATHS_LINKGAMEDIRS, g_bLinkGameDirs ? BST_CHECKED : BST_UNCHECKED ); + + // read the exisiting exclude paths + g_ExcludePaths.Purge(); + char szFilename[MAX_PATH]; + V_ComposeFileName( g_localPath, EXCLUDEPATHS_FILE, szFilename, sizeof( szFilename ) ); + if ( Sys_Exists( szFilename ) ) + { + Sys_LoadScriptFile( szFilename ); + while ( 1 ) + { + char *pToken = Sys_GetToken( true ); + if ( !pToken || !pToken[0] ) + { + break; + } + Sys_StripQuotesFromToken( pToken ); + if ( !stricmp( pToken, "*" ) ) + { + pToken = ""; + } + else if ( pToken[0] == '\\' ) + { + pToken++; + } + + char szPath[MAX_PATH]; + V_ComposeFileName( ROOT_NAME, pToken, szPath, sizeof( szPath ) ); + V_FixSlashes( szPath ); + + g_ExcludePaths.AddToTail( szPath ); + } + } +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_Proc +// +//----------------------------------------------------------------------------- +BOOL CALLBACK ExcludePathsDlg_Proc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + HWND hWndTree; + LPNMHDR lpnmh; + HTREEITEM hTree; + HTREEITEM hTreeRoot; + int checkState; + static bool s_bAllowPopulate = 0; + + switch ( message ) + { + case WM_INITDIALOG: + ExcludePathsDlg_Setup( hWnd ); + s_bAllowPopulate = true; + return TRUE; + + case WM_NOTIFY: + lpnmh = (LPNMHDR)lParam; + if ( ( lpnmh->code == NM_CLICK ) && ( lpnmh->idFrom == IDC_PATHS_TREE ) ) + { + TVHITTESTINFO ht = {0}; + DWORD dwpos = GetMessagePos(); + ht.pt.x = GET_X_LPARAM( dwpos ); + ht.pt.y = GET_Y_LPARAM( dwpos ); + MapWindowPoints( HWND_DESKTOP, lpnmh->hwndFrom, &ht.pt, 1 ); + TreeView_HitTest( lpnmh->hwndFrom, &ht ); + if ( ht.flags & TVHT_ONITEMSTATEICON ) + { + PostMessage( hWnd, UM_CHECKSTATECHANGE, 0, (LPARAM)ht.hItem ); + } + } + break; + + case UM_CHECKSTATECHANGE: + hWndTree = GetDlgItem( hWnd, IDC_PATHS_TREE ); + hTreeRoot = TreeView_GetRoot( hWndTree ); + hTree = (HTREEITEM)lParam; + checkState = TreeView_GetCheckState( hWndTree, hTree ); + if ( checkState != -1 ) + { + TVITEM tvi = { 0 }; + char szName[MAX_PATH]; + tvi.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_TEXT; + tvi.hItem = hTree; + tvi.pszText = szName; + tvi.cchTextMax = sizeof( szName ); + if ( !TreeView_GetItem( hWndTree, &tvi ) ) + { + break; + } + int nDepth = LOWORD( tvi.lParam ); + bool bIsModPath = HIWORD( tvi.lParam ) != 0; + + if ( g_bLinkGameDirs && bIsModPath ) + { + // a mod path root is at depth 1 + // a child of a mod path (depth > 1), will match all other children in mod paths + // a mod path (depth = 1) will match all other modpaths + ExcludePathsDlg_SetCheckStateLinked_r( hWndTree, hTreeRoot, 0, checkState, nDepth == 1 ? NULL : szName ); + } + else + { + ExcludePathsDlg_SetCheckState_r( hWndTree, hTree, 0, checkState ); + } + } + break; + + case WM_PAINT: + if ( s_bAllowPopulate ) + { + // unfortunate, but tree view needs to paint first before its state can be set + // related to checkbox style which doesn't manifest until after WM_INITDIALOG + // stall the initial population until after the first paint + s_bAllowPopulate = false; + PostMessage( hWnd, UM_FIRSTTIMEPOPULATE, 0, 0 ); + } + break; + + case UM_FIRSTTIMEPOPULATE: + ExcludePathsDlg_Populate( hWnd, false ); + break; + + case WM_COMMAND: + switch ( LOWORD( wParam ) ) + { + case IDC_OK: + ExcludePathsDlg_SaveChanges( hWnd ); + EndDialog( hWnd, wParam ); + return TRUE; + + case IDC_PATHS_RESCAN: + ExcludePathsDlg_Populate( hWnd, true ); + return TRUE; + + case IDC_PATHS_EXPAND: + // expand from root + hWndTree = GetDlgItem( hWnd, IDC_PATHS_TREE ); + ExcludePathsDlg_Expand_r( hWndTree, TreeView_GetRoot( hWndTree ), 0, -1, true ); + return TRUE; + + case IDC_PATHS_COLLAPSE: + // collapse from root + hWndTree = GetDlgItem( hWnd, IDC_PATHS_TREE ); + ExcludePathsDlg_Expand_r( hWndTree, TreeView_GetRoot( hWndTree ), 0, -1, false ); + return TRUE; + + case IDC_PATHS_LINKGAMEDIRS: + g_bLinkGameDirs = IsDlgButtonChecked( hWnd, IDC_PATHS_LINKGAMEDIRS ); + return TRUE; + + case IDCANCEL: + case IDC_CANCEL: + EndDialog( hWnd, wParam ); + return TRUE; + } + break; + } + return FALSE; +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_LoadConfig +// +//----------------------------------------------------------------------------- +void ExcludePathsDlg_LoadConfig() +{ + // get our config + Sys_GetRegistryInteger( "ExcludePaths_LinkGameDirs", true, g_bLinkGameDirs ); +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_SaveConfig +// +//----------------------------------------------------------------------------- +void ExcludePathsDlg_SaveConfig() +{ + Sys_SetRegistryInteger( "ExcludePaths_LinkGameDirs", g_bLinkGameDirs ); +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_Init +// +//----------------------------------------------------------------------------- +bool ExcludePathsDlg_Init() +{ + return true; +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_Open +// +//----------------------------------------------------------------------------- +void ExcludePathsDlg_Open() +{ + ExcludePathsDlg_LoadConfig(); + + int result = DialogBox( g_hInstance, MAKEINTRESOURCE( IDD_EXCLUDEPATHS ), g_hDlgMain, ( DLGPROC )ExcludePathsDlg_Proc ); + if ( LOWORD( result ) != IDC_OK ) + return; + + ExcludePathsDlg_SaveConfig(); +} |