#include-once #include #include #include #include #include ; #MultiFoldersSelectorUDF# ====================================================================================================== ; Name ..........: Multi Folders Selector UDF ; Description ...: To select multiple folders in one window ; : Optionally, you can select the root folder that will serve for the folder selector ; Author ........: Nine ; Created .......: 2021-03-01 ; Modified ......: 2024-05-01 ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: Yes ; =============================================================================================================================== ; #Global# ====================================================================================================================== Global $hMFS_TVFolders ; Handle to the tree view of folders from the root Global $hMFS_ListFolders ; Handle to the list box of the selected folders Global $hMFS_ListFiles ; Handle to the list box showing folder content Global $aMFS_Folders ; Array of all folders appearing in the tree view Global $idMFS_Info ; Info about what the List Box area is showing Global $aMFS_PreSet ; Preset array of full path folders ; =============================================================================================================================== ; #FUNCTION# ==================================================================================================================== ; Name...........: _MFS_SelectRootFolder ; Description ...: Root folder selector ; Syntax.........: _MKHKS_Initialize() ; Parameters ....: none ; Return values .: String that represents the root folder or 0 with @error 1 if canceled ; Author ........: Nine ; Modified ......: ; Remarks .......: ; =============================================================================================================================== Func _MFS_SelectRootFolder() Local $aStack[20] = ["Root"], $iStack = 0 Local $hGUI = GUICreate("Root Selector", 500, 500) GUISetBkColor(0xD0D0D0) Local $idFolder = GUICtrlCreateLabel("Select Root Folder", 30, 20, 200, 20) GUICtrlSetFont(-1, 12) Local $idRootList = GUICtrlCreateList("", 30, 50, 440, 400) __MFS_FillRootList($idRootList, "Root", $aStack, $iStack) GUICtrlSetFont(-1, 9) Local $idSelect = GUICtrlCreateButton("Select", 100, 460, 80, 20) GUICtrlSetState(-1, $GUI_DISABLE) GUISetState() Local $sFolder While True Switch GUIGetMsg() Case $GUI_EVENT_CLOSE GUIDelete() Return SetError(1) Case $idRootList $sFolder = __MFS_FillRootList($idRootList, GUICtrlRead($idRootList), $aStack, $iStack) GUICtrlSetData($idFolder, $sFolder) GUICtrlSetState($idSelect, StringInStr(FileGetAttrib($sFolder), "D") ? $GUI_ENABLE : $GUI_DISABLE) Case $idSelect $sFolder = GUICtrlRead($idFolder) ExitLoop EndSwitch WEnd GUIDelete() Return $sFolder EndFunc ;==>_MFS_SelectRootFolder ; #FUNCTION# ==================================================================================================================== ; Name...........: _MFS_SelectMultipleFolders ; Description ...: Multiple Folders Selector ; Syntax.........: _MFS_SelectMultipleFolders($sRootFolder) ; Parameters ....: $sRootFolder : Folder that will serve to show tree view of all folder under ; : $aPreSet : Optional array (0-based) of folders to be pre-checked ; Return values .: Array of all selected folders or 0 if error and @error set to : ; : 1 - Folder does not exists ; : 2 - Not a folder ; : 3 - Cancelled ; Author ........: Nine ; Modified ......: ; Remarks .......: ; =============================================================================================================================== Func _MFS_SelectMultipleFolders($sRootFolder, $aPreSet = Null) If Not FileExists($sRootFolder) Then SetError(1) If Not StringInStr(FileGetAttrib($sRootFolder), "D") Then SetError(2) $aMFS_PreSet = __MFS_PreparePreChecked($aPreSet) Local $hGUI = GUICreate("Folders Selector", 750, 560) GUICtrlCreateLabel("Select folders by checking boxes" & @LF & "Click folder to see file content", 30, 8, 300, 35) GUICtrlSetFont(-1, 10) $hMFS_TVFolders = _GUICtrlTreeView_Create($hGUI, 30, 50, 320, 396, BitOR($TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, _ $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS, $TVS_CHECKBOXES), $WS_EX_CLIENTEDGE) $idMFS_Info = GUICtrlCreateLabel("Showing Folders Selection", 370, 25, 350, 20) GUICtrlSetFont(-1, 10) $hMFS_ListFolders = _GUICtrlListBox_Create($hGUI, "", 370, 50, 360, 421) $hMFS_ListFiles = _GUICtrlListBox_Create($hGUI, "", 370, 50, 360, 421) ControlHide($hGUI, "", $hMFS_ListFiles) Local $idDone = GUICtrlCreateButton("Done", 95, 470, 100, 25) Local $idShowSelect = GUICtrlCreateButton("Selection", 435, 470, 100, 25) GUISetState() __MFS_Create_Tree($sRootFolder) _WinAPI_RedrawWindow($hMFS_TVFolders) GUIRegisterMsg($WM_NOTIFY, __MFS_WM_NOTIFY) While True Switch GUIGetMsg() Case $GUI_EVENT_CLOSE GUIDelete() Return SetError(3) Case $idDone $aMFS_Folders = __MFS_ExtractListBox($hMFS_ListFolders) ExitLoop Case $idShowSelect __MFS_SetListBoxToSelection($hGUI, True) EndSwitch WEnd GUIDelete() GUIRegisterMsg($WM_NOTIFY, "") Return $aMFS_Folders EndFunc ;==>_MFS_SelectMultipleFolders ; #INTERNAL FUNCTIONS# ========================================================================================================== Func __MFS_WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam) Local $tNMHdr = DllStructCreate($tagNMHDR, $lParam) Local $hWndFrom = $tNMHdr.hWndFrom, $iCode = $tNMHdr.Code If $hWndFrom <> $hMFS_TVFolders Then Return $GUI_RUNDEFMSG Local $tNMTreeView, $tNMTVItemChange, $bCheckNew, $bCheckOld Switch $iCode Case $TVN_SELCHANGEDA, $TVN_SELCHANGEDW $tNMTreeView = DllStructCreate($tagNMTREEVIEW, $lParam) __MFS_SetListBoxToSelection($hWnd, False) __MFS_ShowFolderContent($tNMTreeView.NewhItem) Case $TVN_ITEMCHANGEDA, $TVN_ITEMCHANGEDW $tNMTVItemChange = DllStructCreate($tagNMTVITEMCHANGE, $lParam) $bCheckNew = BitAND($tNMTVItemChange.StateNew, 0x2000) ? True : False $bCheckOld = BitAND($tNMTVItemChange.StateOld, 0x2000) ? True : False If BitXOR($bCheckNew, $bCheckOld) Then __MFS_SetListBoxToSelection($hWnd, True) If $bCheckNew Then __MFS_ModifyList($tNMTVItemChange.hItem, True) Else __MFS_ModifyList($tNMTVItemChange.hItem, False) EndIf EndIf EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>__MFS_WM_NOTIFY Func __MFS_FillRootList($idList, $sFolder, ByRef $aStack, ByRef $iStack) Local Enum $ssfDRIVES = 17, $ssfNETWORK Local Const $SHCONTF_FOLDERS = 0x20 GUICtrlSetData($idList, "") If $sFolder = ".." Then $iStack -= 1 $sFolder = $aStack[$iStack] Else $iStack += 1 $aStack[$iStack] = $sFolder EndIf If $sFolder <> "Root" Then GUICtrlSetData($idList, "..|") Local $oShell, $oFolder, $oItems, $sData Switch $sFolder Case "Root" GUICtrlSetData($idList, "Drives|Network") Case "Drives" $oShell = ObjCreate("Shell.Application") $oFolder = $oShell.NameSpace($ssfDRIVES) $oItems = $oFolder.Items() For $oItem In $oItems If StringLen($oItem.path) > 3 Then ContinueLoop GUICtrlSetData($idList, $oItem.path & "|") Next Case "Network" $oShell = ObjCreate("Shell.Application") $oFolder = $oShell.NameSpace($ssfNETWORK) $oItems = $oFolder.Items() For $oItem In $oItems If StringLeft($oItem.path, 2) <> "\\" Then ContinueLoop GUICtrlSetData($idList, $oItem.path & "|") Next Case Else $oShell = ObjCreate("Shell.Application") $oFolder = $oShell.NameSpace($sFolder) $oItems = $oFolder.Items() $oItems.Filter($SHCONTF_FOLDERS, "*") For $oItem In $oItems If StringLeft($oItem.path, 1) = "$" Then ContinueLoop GUICtrlSetData($idList, $oItem.path & "|") Next EndSwitch Return $sFolder EndFunc ;==>__MFS_FillRootList Func __MFS_Create_Tree($sRoot) Local Const $CURSOR_WAIT = 15 GUISetCursor($CURSOR_WAIT, $GUI_CURSOR_OVERRIDE) If StringRight($sRoot, 1) <> "\" Then $sRoot &= "\" Local $aArray[1][2], $i = 0 $aMFS_Folders = $aArray $aMFS_Folders[0][0] = _GUICtrlTreeView_Add($hMFS_TVFolders, 0, $sRoot) $aMFS_Folders[0][1] = $sRoot __MFS_Recurse_Tree($i, $sRoot, $aMFS_Folders[0][0]) GUISetCursor() EndFunc ;==>__MFS_Create_Tree Func __MFS_Recurse_Tree(ByRef $iIndx, $sFolder, $hParent) Local $aList = _FileListToArray($sFolder, "*", $FLTA_FOLDERS) If @error Then Return Local $hSibling For $i = 1 To $aList[0] $iIndx += 1 ReDim $aMFS_Folders[$iIndx + 1][2] If $i = 1 Then $hSibling = _GUICtrlTreeView_AddChild($hMFS_TVFolders, $hParent, $aList[$i]) Else $hSibling = _GUICtrlTreeView_Add($hMFS_TVFolders, $hSibling, $aList[$i]) EndIf $aMFS_Folders[$iIndx][0] = $hSibling $aMFS_Folders[$iIndx][1] = $sFolder & $aList[$i] & "\" If IsArray($aMFS_PreSet) Then _ArraySearch($aMFS_PreSet, $aMFS_Folders[$iIndx][1]) If Not @error Then _GUICtrlTreeView_SetChecked($hMFS_TVFolders, $hSibling) _GUICtrlListBox_AddString($hMFS_ListFolders, $aMFS_Folders[$iIndx][1]) EndIf EndIf __MFS_Recurse_Tree($iIndx, $aMFS_Folders[$iIndx][1], $hSibling) Next EndFunc ;==>__MFS_Recurse_Tree Func __MFS_ModifyList($hItem, $bAdd) Local $iIndx = _ArraySearch($aMFS_Folders, $hItem, Default, Default, Default, Default, Default, 0) Local $sText = $aMFS_Folders[$iIndx][1] If $bAdd Then _GUICtrlListBox_AddString($hMFS_ListFolders, $sText) Else $iIndx = _GUICtrlListBox_FindString($hMFS_ListFolders, $sText, True) _GUICtrlListBox_DeleteString($hMFS_ListFolders, $iIndx) EndIf _GUICtrlListBox_UpdateHScroll($hMFS_ListFolders) EndFunc ;==>__MFS_ModifyList Func __MFS_ShowFolderContent($hItem) Local $iIndx = _ArraySearch($aMFS_Folders, $hItem, Default, Default, Default, Default, Default, 0) _GUICtrlListBox_ResetContent($hMFS_ListFiles) Local $sFolder = $aMFS_Folders[$iIndx][1] Local $aFile = _FileListToArray($sFolder, "*", $FLTA_FILES) If @error Then Return For $i = 1 To $aFile[0] If StringRegExp(FileGetAttrib($sFolder & $aFile[$i]), "H|S") Then ContinueLoop _GUICtrlListBox_AddString($hMFS_ListFiles, $aFile[$i]) Next _GUICtrlListBox_UpdateHScroll($hMFS_ListFiles) EndFunc ;==>__MFS_ShowFolderContent Func __MFS_ExtractListBox($hList) Local $iCount = _GUICtrlListBox_GetCount($hList) Local $aList[$iCount] For $i = 0 To $iCount - 1 $aList[$i] = _GUICtrlListBox_GetText($hList, $i) Next Return $aList EndFunc ;==>__MFS_ExtractListBox Func __MFS_SetListBoxToSelection($hGUI, $bSelect) Local Static $bShowingSelection = True If Not BitXOR($bSelect, $bShowingSelection) Then Return $bShowingSelection = Not $bShowingSelection If $bSelect Then ControlShow($hGUI, "", $hMFS_ListFolders) ControlHide($hGUI, "", $hMFS_ListFiles) GUICtrlSetData($idMFS_Info, "Showing Folders Selection") Else ControlHide($hGUI, "", $hMFS_ListFolders) ControlShow($hGUI, "", $hMFS_ListFiles) GUICtrlSetData($idMFS_Info, "Showing files in selected folder") EndIf EndFunc ;==>__MFS_SetListBoxToSelection Func __MFS_PreparePreChecked($aArray) If Not IsArray($aArray) Then Return Null For $i = 0 To UBound($aArray) - 1 If StringRight($aArray[$i], 1) <> "\" Then $aArray[$i] &= "\" Next Return $aArray EndFunc ;==>__MFS_PreparePreChecked ;================================================================================================================================