[GUI] FileSelect alternative - Customize / Restrict to a specific folder (20.03.2018)

Post your working scripts, libraries and tools for AHK v1.1 and older
DigiDon
Posts: 178
Joined: 19 May 2014, 04:55
Contact:

[GUI] FileSelect alternative - Customize / Restrict to a specific folder (20.03.2018)

07 Feb 2018, 07:11

Hi,

For my project EverFastAccess I needed a dialog able to select multiple files and folders.
The standard folder select dialog thus wasn't a fit so I decided to create a more flexible and configurable file/folder select dialog.

I hope this will benefit many :)

AHK GUI alternative to the FileSelectFile / FileSelectFolder dialogs
  • Allows more parameters/customization
  • Allows to restrict navigation within a specific folder
  • Allows selection of both files and folders
Image
Image

UPDATES last 20.03.2018 - 19h UTC+1
Spoiler
I am quite surprised I could not find such a script. I'm especially quite surprised it seems not available by Windows as standard as well :roll:
I wanted to have a GUI (TreeView and/or ListView) that allows user to naviagate folders and select a file WITHIN the specified folder.

I didn't want to apply dirty tricks to the fileselect standard dialog so I thought a complete AHK Gui could be a good solution.
So based on the ListView Main Example https://www.autohotkey.com/docs/command ... m#Examples here is my try!

Don't hesitate to post improvements or say anything ;)

DOCUMENTATION (example at the end)

Code: Select all

; **********************************************************
; FileSelectSpecific Functions by DigiDon
; **********************************************************
; Use/modify as you wish
; Based on Main example from https://autohotkey.com/docs/commands/ListView.htm
; **********************************************************
; AHK GUI alternative to the FileSelectFile / FileSelectFolder dialogs
; Allows more parameters/customization
; Allows to restrict navigation within a specific folder
; Allows to select File(s) or/and Folder(s)
; Allows to filter file types in or out
; **********************************************************
; FileSelectSpecific(P_OwnerNum,P_Path,P_SelectFileOrFolder="File",P_Prompt="",P_ComplementText="",P_Multi="",P_DefaultView="Icon",P_FilterOK="",P_FilterNO="",P_Restrict=1,P_LVHeight="220",P_LVWidth="350")
;*****************************
;	PARAMETERS
;*****************************
;----- P_OwnerNum: Num/Name of the Gui Owner: it will be disabled the time a selection is made
;----- P_Path: Starting Folder 
;EMPTY: Start with all disks
;----- P_SelectFileOrFolder : Type of Selection to make
;"File" : User should select File(s)
;"Folder" : User should select Folder(s)
;"All" : User should select File(s) and/or Folder(s)
;----- P_Prompt : Text to display at the top of GUI
;----- P_ComplementText : Text to display at the bottom the GUI
;----- P_Multi : MultiSelection
;VALUE: Allowed / EMPTY: Forbidden
;----- P_DefaultView : Default View for the Tree List
;"Icon" / "Report"
;----- P_FilterOK : Comma-list of allowed extensions to be displayed and chosen
;ex "EXE,INI"
;----- P_FilterNO : Comma-list of forbidden extensions to be displayed and chosen
;ex "EXE,INI"
;----- P_Restrict : The user should not be able to navigate above the starting folder
;----- P_LVHeight : Height of ListView in Px
;----- P_LVWidth  : Width  of ListView in Px
;*****************************
;	RETURN VALUE
;*****************************
;----- FSHwnd: Hwnd of the GUI windows
;*****************************
; GLOBAL VALUE TO CHECK AFTER CALL
;*****************************
;----- glb_FSReturn: Contains the path of the selected file(s)
;NO SELECTION : EMPTY
;NO Multi Selection: Path of the selected File
;Multi Selection: Path of the folder "`n" Paths of the selected files (`n separated)
;*****************************
;			USAGE
;*****************************
;ANY SINGLE FILE ANYWHERE
FSHwnd:=FileSelectSpecific("","","File","Please Choose a file")
WinWait % "ahk_id " FSHwnd
WinWaitClose % "ahk_id " FSHwnd
if !glb_FSReturn
	msgbox No selection
else
	msgbox selection was %glb_FSReturn%
; ONE OR MORE NON-RTF FILES WITHIN C:
FSHwnd:=FileSelectSpecific("","C:","File","Please Choose file(s) in C: (no rtf)","",1,,,"rtf",1)
WinWait % "ahk_id " FSHwnd
WinWaitClose % "ahk_id " FSHwnd
if !glb_FSReturn
	msgbox No selection
else
	msgbox selection was %glb_FSReturn%
;*****************************
FUNCTIONS AND WORKING EXAMPLE

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
#SingleInstance, Force

; ONE OR MORE NON-RTF FILES WITHIN C:
WinWaitClose % "ahk_id " FileSelectSpecific("","C:","File","Please Choose file(s) in C: (no rtf)","",1,,,"rtf",1)
if !glb_FSReturn
	msgbox No selection
else
	msgbox selection was %glb_FSReturn%
	
;ANY SINGLE FILE ANYWHERE
WinWaitClose % "ahk_id " FileSelectSpecific("","","File","Please Choose a file")
if !glb_FSReturn
	msgbox No selection
else
	msgbox selection was %glb_FSReturn%
return

FileSelectSpecific(P_OwnerNum,P_Path,P_SelectFileOrFolder="File",P_Prompt="",P_ComplementText="",P_Multi="",P_DefaultView="Icon",P_FilterOK="",P_FilterNO="",P_Restrict=1,P_LVHeight="220",P_LVWidth="350") {
global
	
	;*****************************
	; MAKE SURE PREVIOUS OWNER IS RE-ENABLED AND EXISTING FS DESTROYED
	;*****************************
	if glb_FSOwnerNum
		try, Gui,%glb_FSOwnerNum%:-Disabled
	try Gui,FileSelectSpecific:Destroy
	;*****************************
	; CONTEXT MENU
	;*****************************
	try
	Menu, FSContextMenu, Add, SELECT, FSSelect
	Menu, FSContextMenu, Add, Create Folder, FSCreateFolder
	Menu, FSContextMenu, Add, Open Folder in Explorer, FSDisplayFolder
	Menu, FSContextMenu, Default, 1&

	;*****************************
	; GLOBAL VARS
	;*****************************
	glb_FSTitle=%A_ScriptName% - File Select Dialog
	
	glb_FSInit:=1
	glb_FSFolder:=P_Path
	glb_FSCurrent:=glb_FSFolder
	glb_FSFilterOK:=P_FilterOK
	glb_FSFilterNO:=P_FilterNO
	glb_FSRestrict:=P_Restrict

	glb_FSType:=P_SelectFileOrFolder
	glb_FSReturn:=""
	glb_FSOwnerNum:=P_OwnerNum
	
	
	if (P_SelectFileOrFolder="File" or P_SelectFileOrFolder="All")
		LoopType:="FD"
	else if (P_SelectFileOrFolder="Folder")
		LoopType:="D"
		
	glb_FSLoopType:=LoopType
	
	if P_Multi
		glb_FSNoMulti:=""
	else
		glb_FSNoMulti:="-Multi"
		
	; Check if the last character of the folder name is a backslash, which happens for root
	; directories such as C:\. If it is, remove it to prevent a double-backslash later on.
	StringRight, LastChar, glb_FSFolder, 1
	if LastChar = \
		StringTrimRight, glb_FSFolder, glb_FSFolder, 1  ; Remove the trailing backslash.
	glb_FSCurrent:=glb_FSFolder
		
	;*****************************
	; GUI CREATION
	;*****************************
	Gui, FileSelectSpecific:Default
	Gui, FileSelectSpecific: New
	Gui +HwndFSHwnd
	Gui +Resize +MinSize330x280
	
	;SET AND DISABLE OWNER
	if (glb_FSOwnerNum) {
		Gui +Owner%glb_FSOwnerNum%
		Gui, %glb_FSOwnerNum%:+Disabled
		}
	
	Gui +OwnDialogs  ; Forces user to dismiss the following dialog before using main window.

	; Create some buttons:
	Gui, Add, Button, xm w20 gFSSwitchView, % Chr(0x02630)
	Gui, Font, Bold
	Gui, Add, Button, x+5 yp gFSRefresh, % Chr(0x21BB)
	Gui, Add, Button, x+5 w30 gFSPrevious, % Chr(0x2190)
	; Gui, Font
	; Gui, Font, Bold
	Gui, Add, Button, x+5 yp gFSSelect, % "SELECT"
	Gui, Font
	Gui, Add, Edit, xm y+8 w%P_LVWidth% vFSNavBarv, % glb_FSCurrent
	Gui, Add, Text, xm y+8 w%P_LVWidth% vFSPromptv, % P_Prompt
	

	; Create the ListView and its columns:
	ListViewPos:= " w" P_LVWidth
	ListViewPos:= " h" P_LVHeight
	
	Gui, Add, ListView, xm y+10 %ListViewPos% vFSListView gFSListViewHandler %glb_FSNoMulti%, Name|In Folder|Size (KB)|Type
	LV_ModifyCol(3, "Integer")  ; For sorting, indicate that the Size column is an integer.
	
	if (P_DefaultView="Icon") {
		GuiControl, +Icon, FSListView    ; Switch to icon view.
		Glb_FSIconView:=1
	} else {
		GuiControl, +Report, FSListView  ; Switch back to details view.
		Glb_FSIconView:=0
	}
	
	Gui, Font, s10
	if P_ComplementText
		Gui, Add, Text, xm y+8 w%P_LVWidth% vFSComplementv, % P_ComplementText
	
	Gui, Font, Italic s9
	if !glb_FSNoMulti
		Gui, Add, Text, xm y+5 w%P_LVWidth% vFSMultiIndicv, % "Hold Ctrl or Shift for Multi-Selection"
	
	Gui, Font
	
	;*****************************
	; ICONS CREATION
	;*****************************
	; Calculate buffer size required for SHFILEINFO structure.
	FSIconArray:={}

	FSImageListID1 := IL_Create(10)
	FSImageListID2 := IL_Create(10, 10, true)  ; A list of large icons to go with the small ones.
	; Attach the ImageLists to the ListView so that it can later display the icons:
	LV_SetImageList(FSImageListID1)
	LV_SetImageList(FSImageListID2)

	; Gather a list of file names from the selected folder and append them to the ListView:
	;*****************************
	; SEARCH FILES AND SHOW GUI
	;*****************************
	GuiControl, -Redraw, FSListView  ; Improve performance by disabling redrawing during load.
	
	FSAddLoopFiles()
	FSRedrawCol()
	
	GuiControl, +Redraw, FSListView  ; Re-enable redrawing (it was disabled above).
	
	Gui, Show,,% glb_FSTitle
	glb_FSInit:=0
	
	return FSHwnd
}

FileSelectSpecificAdjust(P_Path="") {
	global
	if !P_Path
		P_Path:=glb_FSCurrent
	Gui FileSelectSpecific: Default
	GuiControl, -Redraw, FSListView
	LV_Delete()
	FSAddLoopFiles()
	GuiControl,,FSNavBarv, % glb_FSCurrent
	FSRedrawCol()
	GuiControl, +Redraw, FSListView
}

FSAddLoopFiles() {
global
	Gui FileSelectSpecific: Default
	
	FSsfi_size := A_PtrSize + 8 + (A_IsUnicode ? 680 : 340)
	VarSetCapacity(FSsfi, FSsfi_size,0)
	
	if !glb_FSCurrent {
		DriveGet, FSDriveList, list
		FSDriveLabels:={}
		
		Loop, parse, FSDriveList 
			{
			DriveGet, FSDriveLabel, Label, %A_Loopfield%:
			FSDriveLabels[A_Index]:=FSDriveLabel
		
			IconNumber:=FSSetIcon(A_Loopfield ":","",FSIconArray,FSImageListID1,FSImageListID2)
			
			LV_Add("Icon" . IconNumber, A_Loopfield ": " FSDriveLabels[A_Index], "", "", "")
			}
		return
	}

	Loop, Files, %glb_FSCurrent%\*, %glb_FSLoopType%
	{
		if A_LoopFileAttrib contains H,S  ; Skip any file that is either H (Hidden), or S (System). Note: No spaces in "H,S".
			continue  ; Skip this file and move on to the next one.
		
		; FileName := A_LoopFileFullPath  ; Must save it to a writable variable for use below.
		
		If glb_FSfilterOK
			If A_LoopFileExt not in ,%glb_FSfilterOK%
				continue
			
		If glb_FSFilterNO
			If A_LoopFileExt in %glb_FSFilterNO%
				continue
		
		IconNumber:=FSSetIcon(A_LoopFileFullPath,A_LoopFileExt,FSIconArray,FSImageListID1,FSImageListID2)

		; Create the new row in the ListView and assign it the icon number determined above:
		LV_Add("Icon" . IconNumber, A_LoopFileName, A_LoopFileDir, A_LoopFileSizeKB, A_LoopFileExt)
	}
}

FSSetIcon(P_Filepath,P_FileExt,ByRef P_IconArray,ByRef P_Imagelist1,ByRef P_ImageList2) {
global
	
	if P_FileExt in EXE,ICO,ANI,CUR
	{
		ExtID := P_FileExt  ; Special ID as a placeholder.
		IconNumber = 0  ; Flag it as not found so that these types can each have a unique icon.
	}
	else  ; Some other extension/file-type, so calculate its unique ID.
	{
		;TTRICK: if no ext it can be drive or directory or a file without ext. In this case we create a fake ext so they won't use the same icons and icons can be re-used
		if !P_FileExt
		{
			
			if Regexmatch(P_Filepath, ":$")
				P_FileExt:="DRIVE"
			else if InStr(FileExist(P_Filepath), "D")
				P_FileExt:="DIR"
			else if FileExist(P_Filepath)
				P_FileExt:="NOEXT"
		}
		ExtID = 0  ; Initialize to handle extensions that are shorter than others.
		Loop 7     ; Limit the extension to 7 characters so that it fits in a 64-bit value.
			{
			StringMid, ExtChar, P_FileExt, A_Index, 1
			if not ExtChar  ; No more characters.
				break
			; Derive a Unique ID by assigning a different bit position to each character:
			ExtID := ExtID | (Asc(ExtChar) << (8 * (A_Index - 1)))
			}
		; Check if this file extension already has an icon in the ImageLists. If it does,
		; several calls can be avoided and loading performance is greatly improved,
		; especially for a folder containing hundreds of files:
		IconNumber := P_IconArray[ExtID]
	}
	;can debug icons here
	; msgbox IconNumber %IconNumber% P_Filepath %P_Filepath% P_FileExt %P_FileExt%
	if not IconNumber  ; There is not yet any icon for this extension, so load it.
	{
		; Get the high-quality small-icon associated with this file extension:
		if not DllCall("Shell32\SHGetFileInfo" . (A_IsUnicode ? "W":"A"), "str", P_Filepath, "uint", 0, "ptr", &FSsfi, "uint", FSsfi_size, "uint", 0x101)  ; 0x101 is SHGFI_ICON+SHGFI_SMALLICON
			IconNumber = 9999999  ; Set it out of bounds to display a blank icon.
		else ; Icon successfully loaded.
		{
			; Extract the hIcon member from the structure:
			hIcon := NumGet(FSsfi, 0)
			; Add the HICON directly to the small-icon and large-icon lists.
			; Below uses +1 to convert the returned index from zero-based to one-based:
			IconNumber := DllCall("ImageList_ReplaceIcon", "ptr", P_Imagelist1, "int", -1, "ptr", hIcon) + 1
			DllCall("ImageList_ReplaceIcon", "ptr", P_ImageList2, "int", -1, "ptr", hIcon)
			; Now that it's been copied into the ImageLists, the original should be destroyed:
			DllCall("DestroyIcon", "ptr", hIcon)
			; Cache the icon to save memory and improve loading performance:
			P_IconArray[ExtID] := IconNumber
		}
	}
	return IconNumber
}


;*****************************
;FS GUI LABELS
;*****************************
FSCreateFolder:
	Gui FileSelectSpecific: Default
	InputBox, FolderName, , % "Enter Folder Name",,,120
	if (ErrorLevel or !FolderName)
		return
	FileCreateDir, % glb_FSCurrent "/" FolderName
	FileSelectSpecificAdjust(glb_FSCurrent)
return

FSDisplayFolder:
	Gui FileSelectSpecific: Default
	FSOpenFolderInExplorer(glb_FSCurrent)
return

FSSwitchView:
	Gui FileSelectSpecific: Default
	GuiControl, -Redraw, FSListView
	if not Glb_FSIconView
		GuiControl, +Icon, FSListView    ; Switch to icon view.
	else
		GuiControl, +Report, FSListView  ; Switch back to details view.
	Glb_FSIconView := not Glb_FSIconView             ; Invert in preparation for next time.
	FSRedrawCol()
	GuiControl, +Redraw, FSListView
return

FSRedrawCol() {
global
	Gui FileSelectSpecific: Default
	LV_ModifyCol()  ; Auto-size each column to fit its contents.
	LV_ModifyCol(2,0)  ; Hide FileDir Col
	LV_ModifyCol(3, 60) ; Make the Size column at little wider to reveal its header.
	LV_ModifyCol(4, "AutoHdr") ; Make the Size column at little wider to reveal its header.
}

FSListViewHandler:
	if A_GuiEvent = DoubleClick  ; There are many other possible values the script can check.
	{
		LV_GetText(FileName, A_EventInfo, 1) ; Get the text of the first field.
		LV_GetText(FileDir, A_EventInfo, 2)  ; Get the text of the second field.
		; LV_GetText(FileExt, A_EventInfo, 4)  ; Get the text of the fourth field.
		FilePath:=FileDir "\" FileName
		
		if !glb_FSCurrent
		{
			loop, parse, FileName, :
				if (A_Index=1) {
					FilePath := A_Loopfield ":"
					break
				}
		}
			
		if InStr(FileExist(FilePath), "D") {
			glb_FSCurrent:=FilePath
			FileSelectSpecificAdjust(glb_FSCurrent)
			return
		}
		
		else if (FileExist(FilePath) and (glb_FSType="File" or glb_FSType="All")) {
			if glb_FSNoMulti
				glb_FSReturn:=FilePath
			else
				glb_FSReturn:=FileDir "`n" FileName
			
			if (glb_FSOwnerNum)
				Gui, %glb_FSOwnerNum%:-Disabled
			Gui,FileSelectSpecific:Destroy
			return
		}
	}
return

FSPrevious:
	Gui FileSelectSpecific: Default
	if !glb_FSCurrent
		return
	if (glb_FSCurrent=glb_FSFolder and glb_FSRestrict) {
		tooltip You can not navigate above the folder `n%glb_FSFolder%
		SetTimer, RemoveToolTip, -3000
		return
	}
	if !InStr(FileExist(FSGetParentDir(glb_FSCurrent)), "D")
		glb_FSCurrent:=""
	else
		glb_FSCurrent:=FSGetParentDir(glb_FSCurrent)
		
	FileSelectSpecificAdjust(glb_FSCurrent)
return

FSRefresh:
	Gui FileSelectSpecific: Default
	FileSelectSpecificAdjust(glb_FSCurrent)
return

FSSelect:
	Gui FileSelectSpecific: Default
	RowNumber = 0
	RowOkayed = 0 
	if !LV_GetNext(RowNumber) {
		msgbox Please select an element first
		return
	}
		
	Loop
	{
		RowNumber := LV_GetNext(RowNumber)  ; Resume the search at the row after that found by the previous iteration.
		; msgbox RowNumber %RowNumber%
		if not RowNumber  ; The above returned zero, so there are no more selected rows.
			break
		LV_GetText(FileName, RowNumber, 1) ; Get the text of the first field.
		LV_GetText(FileDir, RowNumber, 2)  ; Get the text of the second field.
		FilePath:=FileDir "\" FileName
		
		if !glb_FSCurrent
		{
			loop, parse, FileName, :
				if (A_Index=1) {
					FilePath := A_Loopfield ":"
					FileName := A_Loopfield ":"
					break
				}
		}

		if !FileExist(FilePath)
			continue
		
		if (InStr(FileExist(FilePath), "D") and glb_FSType="File")
			continue
			
		if (!InStr(FileExist(FilePath), "D") and glb_FSType="Folder")
			continue
			
		RowOkayed++
		
		glb_FSMultiReturn.= "`n" FileName
		
	}
	
	if (RowOkayed=0) {
		msgbox sorry wrong selection
		return
	}
	
	if (RowOkayed=1 and glb_FSNoMulti)
		glb_FSReturn:=FilePath
	else
		glb_FSReturn:=FileDir . glb_FSMultiReturn

	if (glb_FSOwnerNum)
		Gui, %glb_FSOwnerNum%:-Disabled
		
	Gui,FileSelectSpecific:Destroy
return

;Context-sensitive hotkey to detect Enter on FS navigation bar
#If (FSHwnd and WinActive("ahk_id " FSHwnd))
Enter::
GuiControlGet, OutputVar, FileSelectSpecific:FocusV
; msgbox OutputVar %OutputVar%
if (OutputVar="FSNavBarv")
	Gosub, FSNavBar
Return
#If

;Enter on FS navigation bar
FSNavBar:
Gui, FileSelectSpecific:Default
GuiControlGet, FSNavBarv
StringRight, LastChar, FSNavBarv, 1
	if LastChar = \
		StringTrimRight, FSNavBarv, FSNavBarv, 1  ; Remove the trailing backslash.
if !InStr(FileExist(FSNavBarv), "D")
	return

if (glb_FSRestrict and !Instr(FSNavBarv,glb_FSFolder)) {
	tooltip You can not navigate above the folder `n%glb_FSFolder%
	SetTimer, RemoveToolTip, -3000
	return
	}
GuiControl,,FSNavBarv,% FSNavBarv

glb_FSCurrent:=FSNavBarv
FileSelectSpecificAdjust()
return

RemoveToolTip:
tooltip
return

;*****************************
;FS GUI SPECIAL LABELS
;*****************************
FileSelectSpecificGuiContextMenu:  ; Launched in response to a right-click or press of the Apps key.
Gui FileSelectSpecific: Default
	if A_GuiControl <> FSListView  ; This check is optional. It displays the menu only for clicks inside the ListView.
		return
	Menu, FSContextMenu, Show
return

FileSelectSpecificGuiClose:
	if glb_FSOwnerNum
		try, Gui,%glb_FSOwnerNum%:-Disabled
	Gui,Destroy
return

FileSelectSpecificGuiSize:  ; Readjust the controls in response to the user's resizing of the window.
	if A_EventInfo = 1  ; The window has been minimized.  No action needed.
		return
	;Do not trigger during init
	if glb_FSInit
		return
		
	GuiControl, -Redraw, FSListView

	GuiControlGet, FSComplementv
	GuiControlGet, FSMultiIndicv
	
	; Otherwise, the window has been resized or maximized. Resize the controls.
	
	GuiControlGet, FSListViewPos, Pos, FSListView
	
	GuiControl, MoveDraw, FSPromptv, % " W" . (A_GuiWidth-20)
	GuiControl, MoveDraw, FSNavBarv, % " W" . (A_GuiWidth-20)
	
	FSListGap=
	
	if (FSComplementv) {
		GuiControl, MoveDraw, FSComplementv, % "y" FSListViewPosY + FSListViewPosH + 10 " W" . (A_GuiWidth-20)
		FSListGap+=10
	}
	
	GuiControlGet, FSComplementPos, Pos, FSComplementv
	
	if (FSMultiIndicv) {
		GuiControl, MoveDraw, FSMultiIndicv, % "y" A_GuiHeight-20 " W" . (A_GuiWidth-20)
		FSListGap+=5
	}
	
	GuiControlGet, FSMultiIndicPos, Pos, FSMultiIndicv
	
	;Trick : Round() so that empty vars = 0
	FSListGap:=Round(FSComplementPosH) + Round(FSMultiIndicPosH) + 15
	
	GuiControl, MoveDraw, FSListView, % "W" . (A_GuiWidth - 20) . " H" . (A_GuiHeight - FSListViewPosY - Round(FSListGap))
	
	;Set timer to recreate listview if icon view
	if (Glb_FSIconView)
		SetTimer, FileSelectSpecificAdjust, -200
	
	GuiControl, +Redraw, FSListView  ; Re-enable redrawing (it was disabled above).
	
return
;*****************************


;*****************************
;SMALL FS FUNCTIONS
;*****************************
FSGetParentDir(Path) {
	return SubStr(Path, 1, InStr(SubStr(Path,1,-1), "\", 0, 0)-1)
}

FSOpenFolderInExplorer(P_Folder) {
global
	if !InStr(FileExist(P_Folder), "D")
		return 0
	Run % P_Folder
}
Last edited by DigiDon on 22 Jun 2018, 09:28, edited 60 times in total.
EverFastAccess : Take Notes on anything the Fast way: Attach notes, Set reminders & Speed up research in 1 gesture - AHK topic
AHK Dynamic Obfuscator L - Protect your AHK code by Obfuscation - AHK topic
QuickModules for Outlook : Sort Outlook emails very quickly to multiple folders - AHK topic
Coding takes lots of time and efforts. If I have helped you or if you enjoy one of my free projects, please consider a small donation :thumbup:
Sorry I am working hard at the moment at a new job and can't commit on delays of answers & updates
DigiDon
Posts: 178
Joined: 19 May 2014, 04:55
Contact:

Re: FileSelectFile style GUI you can restrict to a specific folder

07 Feb 2018, 12:12

UPDATE 07.02.2018 - 18h UTC+1
Function much improved !


-Have a better code structure
-Have nicer button and show "Select" button in a more adapted way
-Offer File filters
-Show folders only if select folders
-Propose folder creation (or not) via right clic
-Multi selection possible (returns the same as FileSelectFile)
-Examples improved

Would be great to improve documentation a bit though
EverFastAccess : Take Notes on anything the Fast way: Attach notes, Set reminders & Speed up research in 1 gesture - AHK topic
AHK Dynamic Obfuscator L - Protect your AHK code by Obfuscation - AHK topic
QuickModules for Outlook : Sort Outlook emails very quickly to multiple folders - AHK topic
Coding takes lots of time and efforts. If I have helped you or if you enjoy one of my free projects, please consider a small donation :thumbup:
Sorry I am working hard at the moment at a new job and can't commit on delays of answers & updates
burque505
Posts: 1731
Joined: 22 Jan 2017, 19:37

Re: FileSelectFile style GUI you can restrict to a specific folder

07 Feb 2018, 13:42

Nice script, @DigiDon. Would you take a look at my small additions? My changes are on lines 7-8 and 82-83. The reason I added them is because the button text as provided wasn't meaningful for me.
I'm trying to get a Chr(29) in the button (↔) but haven't gotten there yet.
Spoiler
EDIT: Got rid of Transform, used Chr(), running AHK_H v1.1.27.06. Using Unicode for switch view button.

Code: Select all

UpArrow := Chr(24)
SwitchLeft := Chr("0x0021DA")
SwitchRight := Chr("0x0021DB")
and

Code: Select all

	Gui, Add, Button, xm+10 w30 gFSPrevious, %UpArrow%
	Gui, Add, Button, x+5 w30 gFSSwitchView, %SwitchLeft% %SwitchRight%
buttons.png
buttons.png (1.44 KiB) Viewed 6799 times
Thanks again,
burque505
DigiDon
Posts: 178
Joined: 19 May 2014, 04:55
Contact:

Re: FileSelectFile style GUI you can restrict to a specific folder

07 Feb 2018, 15:57

Thanks burque505 for the sugestion ;)

But finding perfect unicode characters is hard.
The one you suggest makes me think of On top and Enlarge.

I prefer
Image

Code: Select all

Gui, Add, Button, xm+10 w20 gFSSwitchView, % Chr(0x02630)
	Gui, Font, Bold
	Gui, Add, Button, x+5 w30 gFSPrevious, % Chr(0x2190)
But I think I would prefer to have some nice image button with hover effect if possible, but I don't have the time to do it for now.
EverFastAccess : Take Notes on anything the Fast way: Attach notes, Set reminders & Speed up research in 1 gesture - AHK topic
AHK Dynamic Obfuscator L - Protect your AHK code by Obfuscation - AHK topic
QuickModules for Outlook : Sort Outlook emails very quickly to multiple folders - AHK topic
Coding takes lots of time and efforts. If I have helped you or if you enjoy one of my free projects, please consider a small donation :thumbup:
Sorry I am working hard at the moment at a new job and can't commit on delays of answers & updates
DigiDon
Posts: 178
Joined: 19 May 2014, 04:55
Contact:

Re: FileSelectFile style GUI you can restrict to a specific folder

08 Feb 2018, 05:46

UPDATES
08.02.2018 - 12h UTC+1
*DOCUMENTATION ADDED
*MultiSelection return value was corrected
*ABLE TO START OR NAVIGATE TO ALL DISKS
*ABLE TO RESTRICT OR NOT ABOVE NAVIGATION
*More concise usage : return Hwnd
*Refresh button
*Ability to create folder via right clic
*Ability to open the current folder in explorer via right clic
EverFastAccess : Take Notes on anything the Fast way: Attach notes, Set reminders & Speed up research in 1 gesture - AHK topic
AHK Dynamic Obfuscator L - Protect your AHK code by Obfuscation - AHK topic
QuickModules for Outlook : Sort Outlook emails very quickly to multiple folders - AHK topic
Coding takes lots of time and efforts. If I have helped you or if you enjoy one of my free projects, please consider a small donation :thumbup:
Sorry I am working hard at the moment at a new job and can't commit on delays of answers & updates
DigiDon
Posts: 178
Joined: 19 May 2014, 04:55
Contact:

Re: FileSelect GUI alternative - Customize / Restrict to a specific folder

08 Feb 2018, 10:53

UPDATE 08.02.2018 - 16h UTC+1
Bug fixed of troncated return value
New "All" param to select both files and folders
EverFastAccess : Take Notes on anything the Fast way: Attach notes, Set reminders & Speed up research in 1 gesture - AHK topic
AHK Dynamic Obfuscator L - Protect your AHK code by Obfuscation - AHK topic
QuickModules for Outlook : Sort Outlook emails very quickly to multiple folders - AHK topic
Coding takes lots of time and efforts. If I have helped you or if you enjoy one of my free projects, please consider a small donation :thumbup:
Sorry I am working hard at the moment at a new job and can't commit on delays of answers & updates
DigiDon
Posts: 178
Joined: 19 May 2014, 04:55
Contact:

Re: FileSelect GUI alternative - Customize / Restrict to a specific folder

13 Feb 2018, 09:21

MAJOR UPDATE ! ;)

13.02.2018 - 15h UTC+1
  • Navigation bar to show current folder and navigate directly via Enter
  • Much more dynamic sizing
  • Warning if user tries to go above restricted folder
  • Secondary text below listview
  • Size of GUI reduced and can be custom
  • Size of GUI has a minimum when resized
EverFastAccess : Take Notes on anything the Fast way: Attach notes, Set reminders & Speed up research in 1 gesture - AHK topic
AHK Dynamic Obfuscator L - Protect your AHK code by Obfuscation - AHK topic
QuickModules for Outlook : Sort Outlook emails very quickly to multiple folders - AHK topic
Coding takes lots of time and efforts. If I have helped you or if you enjoy one of my free projects, please consider a small donation :thumbup:
Sorry I am working hard at the moment at a new job and can't commit on delays of answers & updates
DigiDon
Posts: 178
Joined: 19 May 2014, 04:55
Contact:

Re: [GUI] FileSelect alternative - Customize / Restrict to a specific folder (14.02.2018)

14 Feb 2018, 16:55

14.02.2018 - 23h UTC+1
  • Correction: if multiselection and type folder: skip files
EverFastAccess : Take Notes on anything the Fast way: Attach notes, Set reminders & Speed up research in 1 gesture - AHK topic
AHK Dynamic Obfuscator L - Protect your AHK code by Obfuscation - AHK topic
QuickModules for Outlook : Sort Outlook emails very quickly to multiple folders - AHK topic
Coding takes lots of time and efforts. If I have helped you or if you enjoy one of my free projects, please consider a small donation :thumbup:
Sorry I am working hard at the moment at a new job and can't commit on delays of answers & updates
burque505
Posts: 1731
Joined: 22 Jan 2017, 19:37

Re: [GUI] FileSelect alternative - Customize / Restrict to a specific folder (14.02.2018)

14 Feb 2018, 17:47

Hi DigiDon, thanks for your continued work on this project. Just wanted to alert you to a couple of things.
I'm running Win7-64, AHK_L 1.1.127.07 and have tried it with AHK_H 1.1.127.06, both U64.

1) As downloaded, it won't start. At lines 337 and 435, instead of "SetTimer( "RemoveToolTip", -3000 )", I think it needs to be:

Code: Select all

SetTimer, RemoveToolTip, -3000
Replacing that and running it brings up this GUI, much different than the OP's images:
SelectFiles.GUI.2.14.18.PNG
SelectFiles.GUI.2.14.18.PNG (49.01 KiB) Viewed 6556 times
But upon entering a folder:
SelectFiles.2.14.18.PNG
SelectFiles.2.14.18.PNG (63.17 KiB) Viewed 6556 times
Regards,
burque505
DigiDon
Posts: 178
Joined: 19 May 2014, 04:55
Contact:

Re: [GUI] FileSelect alternative - Customize / Restrict to a specific folder (14.02.2018)

14 Feb 2018, 18:00

Hi burque505,

Thanks for notifying me! ;)

I already implemented it in a project and therefore am making modifications in it directly before trying to put them back on there.

Truth is I was surprized nobody complained of a problem :lol:

I'll take a proper look, will soon update.
Last edited by DigiDon on 14 Feb 2018, 18:19, edited 1 time in total.
EverFastAccess : Take Notes on anything the Fast way: Attach notes, Set reminders & Speed up research in 1 gesture - AHK topic
AHK Dynamic Obfuscator L - Protect your AHK code by Obfuscation - AHK topic
QuickModules for Outlook : Sort Outlook emails very quickly to multiple folders - AHK topic
Coding takes lots of time and efforts. If I have helped you or if you enjoy one of my free projects, please consider a small donation :thumbup:
Sorry I am working hard at the moment at a new job and can't commit on delays of answers & updates
DigiDon
Posts: 178
Joined: 19 May 2014, 04:55
Contact:

Re: [GUI] FileSelect alternative - Customize / Restrict to a specific folder (14.02.2018)

14 Feb 2018, 18:15

I've made some changes and it seems the single line WinWaitClose of the example does not work anymore because the Gui is hidden at first.
So the calling of the function has to be modified.

I'm on the same environement so it works but please confirm ;)
I've updated the OP.

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
#SingleInstance, Force

;ANY SINGLE FILE ANYWHERE
FSHwnd:=FileSelectSpecific("","","File","Please Choose a file")
WinWait % "ahk_id " FSHwnd
WinWaitClose % "ahk_id " FSHwnd
if !glb_FSReturn
	msgbox No selection
else
	msgbox selection was %glb_FSReturn%
; ONE OR MORE NON-RTF FILES WITHIN C:
FSHwnd:=FileSelectSpecific("","C:","File","Please Choose file(s) in C: (no rtf)","",1,,,"rtf",1)
WinWait % "ahk_id " FSHwnd
WinWaitClose % "ahk_id " FSHwnd
if !glb_FSReturn
	msgbox No selection
else
	msgbox selection was %glb_FSReturn%
return
EverFastAccess : Take Notes on anything the Fast way: Attach notes, Set reminders & Speed up research in 1 gesture - AHK topic
AHK Dynamic Obfuscator L - Protect your AHK code by Obfuscation - AHK topic
QuickModules for Outlook : Sort Outlook emails very quickly to multiple folders - AHK topic
Coding takes lots of time and efforts. If I have helped you or if you enjoy one of my free projects, please consider a small donation :thumbup:
Sorry I am working hard at the moment at a new job and can't commit on delays of answers & updates
burque505
Posts: 1731
Joined: 22 Jan 2017, 19:37

Re: [GUI] FileSelect alternative - Customize / Restrict to a specific folder (14.02.2018)

15 Feb 2018, 08:26

Hi, I'm still getting exactly the same behavior, except no SetTimer error.
Screenshots still the same as my last post.
Regards,
burque505
DigiDon
Posts: 178
Joined: 19 May 2014, 04:55
Contact:

Re: [GUI] FileSelect alternative - Customize / Restrict to a specific folder (14.02.2018)

15 Feb 2018, 08:36

Hi burque505,

I'm surprized.

I've tested again from the sample in this very topic and it's working fine.

Are you sure you put first the testing sample and then the function (outside autoexecute) ?
PS: just in case I switched the examples so that you choose a file in C: first.

Please try the complete example:

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
#SingleInstance, Force

; ONE OR MORE NON-RTF FILES WITHIN C:
FSHwnd:=FileSelectSpecific("","C:","File","Please Choose file(s) in C: (no rtf)","",1,,,"rtf",1)
WinWait % "ahk_id " FSHwnd
WinWaitClose % "ahk_id " FSHwnd
if !glb_FSReturn
	msgbox No selection
else
	msgbox selection was %glb_FSReturn%
	
;ANY SINGLE FILE ANYWHERE
FSHwnd:=FileSelectSpecific("","","File","Please Choose a file")
WinWait % "ahk_id " FSHwnd
WinWaitClose % "ahk_id " FSHwnd
if !glb_FSReturn
	msgbox No selection
else
	msgbox selection was %glb_FSReturn%
return

FileSelectSpecific(P_OwnerNum,P_Path,P_SelectFileOrFolder="File",P_Prompt="",P_ComplementText="",P_Multi="",P_DefaultView="Icon",P_FilterOK="",P_FilterNO="",P_Restrict=1,P_LVHeight="220",P_LVWidth="350") {
global
	
	;*****************************
	; MAKE SURE PREVIOUS OWNER IS RE-ENABLED AND EXISTING FS DESTROYED
	;*****************************
	if glb_FSOwnerNum
		try, Gui,%glb_FSOwnerNum%:-Disabled
	try Gui,FileSelectSpecific:Destroy
	;*****************************
	; CONTEXT MENU
	;*****************************
	try
	Menu, FSContextMenu, Add, SELECT, FSSelect
	Menu, FSContextMenu, Add, Create Folder, FSCreateFolder
	Menu, FSContextMenu, Add, Open Folder in Explorer, FSDisplayFolder
	Menu, FSContextMenu, Default, 1&

	;*****************************
	; GLOBAL VARS
	;*****************************
	glb_FSTitle=%A_ScriptName% - File Select Dialog
	
	glb_FSInit:=1
	glb_FSFolder:=P_Path
	glb_FSCurrent:=glb_FSFolder
	glb_FSFilterOK:=P_FilterOK
	glb_FSFilterNO:=P_FilterNO
	glb_FSRestrict:=P_Restrict

	glb_FSType:=P_SelectFileOrFolder
	glb_FSReturn:=""
	glb_FSOwnerNum:=P_OwnerNum
	
	
	if (P_SelectFileOrFolder="File" or P_SelectFileOrFolder="All")
		LoopType:="FD"
	else if (P_SelectFileOrFolder="Folder")
		LoopType:="D"
		
	glb_FSLoopType:=LoopType
	
	if P_Multi
		glb_FSNoMulti:=""
	else
		glb_FSNoMulti:="-Multi"
		
	; Check if the last character of the folder name is a backslash, which happens for root
	; directories such as C:\. If it is, remove it to prevent a double-backslash later on.
	StringRight, LastChar, glb_FSFolder, 1
	if LastChar = \
		StringTrimRight, glb_FSFolder, glb_FSFolder, 1  ; Remove the trailing backslash.
	glb_FSCurrent:=glb_FSFolder
		
	;*****************************
	; GUI CREATION
	;*****************************
	Gui, FileSelectSpecific:Default
	Gui, FileSelectSpecific: New
	Gui +HwndFSHwnd
	Gui +Resize +MinSize330x280
	
	;SET AND DISABLE OWNER
	if (glb_FSOwnerNum) {
		Gui +Owner%glb_FSOwnerNum%
		Gui, %glb_FSOwnerNum%:+Disabled
		}
	
	Gui +OwnDialogs  ; Forces user to dismiss the following dialog before using main window.

	; Create some buttons:
	Gui, Add, Button, xm w20 gFSSwitchView, % Chr(0x02630)
	Gui, Font, Bold
	Gui, Add, Button, x+5 yp gFSRefresh, % Chr(0x21BB)
	Gui, Add, Button, x+5 w30 gFSPrevious, % Chr(0x2190)
	; Gui, Font
	; Gui, Font, Bold
	Gui, Add, Button, x+5 yp gFSSelect, % "SELECT"
	Gui, Font
	Gui, Add, Edit, xm y+8 w%P_LVWidth% vFSNavBarv, % glb_FSCurrent
	Gui, Add, Text, xm y+8 w%P_LVWidth% vFSPromptv, % P_Prompt
	

	; Create the ListView and its columns:
	ListViewPos:= " w" P_LVWidth
	ListViewPos:= " h" P_LVHeight
	
	Gui, Add, ListView, xm y+10 %ListViewPos% vFSListView gFSListViewHandler %glb_FSNoMulti%, Name|In Folder|Size (KB)|Type
	LV_ModifyCol(3, "Integer")  ; For sorting, indicate that the Size column is an integer.
	
	if (P_DefaultView="Icon") {
		GuiControl, +Icon, FSListView    ; Switch to icon view.
		Glb_FSIconView:=1
	} else {
		GuiControl, +Report, FSListView  ; Switch back to details view.
		Glb_FSIconView:=0
	}
	
	Gui, Font, s10
	if P_ComplementText
		Gui, Add, Text, xm y+8 w%P_LVWidth% vFSComplementv, % P_ComplementText
	
	Gui, Font, Italic s9
	if !glb_FSNoMulti
		Gui, Add, Text, xm y+5 w%P_LVWidth% vFSMultiIndicv, % "Hold Ctrl or Shift for Multi-Selection"
	
	Gui, Font
	
	;*****************************
	; ICONS CREATION
	;*****************************
	; Calculate buffer size required for SHFILEINFO structure.
	FSIconArray:={}

	FSImageListID1 := IL_Create(10)
	FSImageListID2 := IL_Create(10, 10, true)  ; A list of large icons to go with the small ones.
	; Attach the ImageLists to the ListView so that it can later display the icons:
	LV_SetImageList(FSImageListID1)
	LV_SetImageList(FSImageListID2)

	; Gather a list of file names from the selected folder and append them to the ListView:
	
	;*****************************
	; LOOP AND SHOW (depends on viewtype)
	;*****************************
	if (P_DefaultView!="Icon") {
		GuiControl, -Redraw, FSListView  ; Improve performance by disabling redrawing during load.
		
		FSAddLoopFiles()
		FSRedrawCol()
		
		GuiControl, +Redraw, FSListView  ; Re-enable redrawing (it was disabled above).
		
		Gui, Show,,% glb_FSTitle
		; msgbox stop
	}
	else ;Trick for Icon view first time: If Icon view then we show/hide the first time to start the size label and readjust icons properly without flickering
		Gui, Show,Hide,% glb_FSTitle
	
	return FSHwnd
}

FileSelectSpecificAdjust(P_Path="") {
	global
	if !P_Path
		P_Path:=glb_FSCurrent
	Gui FileSelectSpecific: Default
	GuiControl, -Redraw, FSListView
	LV_Delete()
	FSAddLoopFiles()
	GuiControl,,FSNavBarv, % glb_FSCurrent
	FSRedrawCol()
	;Trick for Icon view first time
	GuiControl, +Redraw, FSListView
	if (Glb_FSIconView and glb_FSInit)
		Gui, Show,,% glb_FSTitle
	if glb_FSInit
		glb_FSInit=0
}

FSAddLoopFiles() {
global
	Gui FileSelectSpecific: Default
	
	FSsfi_size := A_PtrSize + 8 + (A_IsUnicode ? 680 : 340)
	VarSetCapacity(FSsfi, FSsfi_size,0)
	
	if !glb_FSCurrent {
		DriveGet, FSDriveList, list
		FSDriveLabels:={}
		
		Loop, parse, FSDriveList 
			{
			DriveGet, FSDriveLabel, Label, %A_Loopfield%:
			FSDriveLabels[A_Index]:=FSDriveLabel
		
			IconNumber:=FSSetIcon(A_Loopfield ":","",FSIconArray,FSImageListID1,FSImageListID2)
			
			LV_Add("Icon" . IconNumber, A_Loopfield ": " FSDriveLabels[A_Index], "", "", "")
			}
		return
	}

	Loop, Files, %glb_FSCurrent%\*, %glb_FSLoopType%
	{
		if A_LoopFileAttrib contains H,S  ; Skip any file that is either H (Hidden), or S (System). Note: No spaces in "H,S".
			continue  ; Skip this file and move on to the next one.
		
		; FileName := A_LoopFileFullPath  ; Must save it to a writable variable for use below.
		
		If glb_FSfilterOK
			If A_LoopFileExt not in ,%glb_FSfilterOK%
				continue
			
		If glb_FSFilterNO
			If A_LoopFileExt in %glb_FSFilterNO%
				continue
		
		IconNumber:=FSSetIcon(A_LoopFileFullPath,A_LoopFileExt,FSIconArray,FSImageListID1,FSImageListID2)

		; Create the new row in the ListView and assign it the icon number determined above:
		LV_Add("Icon" . IconNumber, A_LoopFileName, A_LoopFileDir, A_LoopFileSizeKB, A_LoopFileExt)
	}
}

FSSetIcon(P_Filepath,P_FileExt,ByRef P_IconArray,ByRef P_Imagelist1,ByRef P_ImageList2) {
global
	
	if P_FileExt in EXE,ICO,ANI,CUR
	{
		ExtID := P_FileExt  ; Special ID as a placeholder.
		IconNumber = 0  ; Flag it as not found so that these types can each have a unique icon.
	}
	else  ; Some other extension/file-type, so calculate its unique ID.
	{
		;TTRICK: if no ext it can be drive or directory or a file without ext. In this case we create a fake ext so they won't use the same icons and icons can be re-used
		if !P_FileExt
		{
			
			if Regexmatch(P_Filepath, ":$")
				P_FileExt:="DRIVE"
			else if InStr(FileExist(P_Filepath), "D")
				P_FileExt:="DIR"
			else if FileExist(P_Filepath)
				P_FileExt:="NOEXT"
		}
		ExtID = 0  ; Initialize to handle extensions that are shorter than others.
		Loop 7     ; Limit the extension to 7 characters so that it fits in a 64-bit value.
			{
			StringMid, ExtChar, P_FileExt, A_Index, 1
			if not ExtChar  ; No more characters.
				break
			; Derive a Unique ID by assigning a different bit position to each character:
			ExtID := ExtID | (Asc(ExtChar) << (8 * (A_Index - 1)))
			}
		; Check if this file extension already has an icon in the ImageLists. If it does,
		; several calls can be avoided and loading performance is greatly improved,
		; especially for a folder containing hundreds of files:
		IconNumber := P_IconArray[ExtID]
	}
	;can debug icons here
	; msgbox IconNumber %IconNumber% P_Filepath %P_Filepath% P_FileExt %P_FileExt%
	if not IconNumber  ; There is not yet any icon for this extension, so load it.
	{
		; Get the high-quality small-icon associated with this file extension:
		if not DllCall("Shell32\SHGetFileInfo" . (A_IsUnicode ? "W":"A"), "str", P_Filepath, "uint", 0, "ptr", &FSsfi, "uint", FSsfi_size, "uint", 0x101)  ; 0x101 is SHGFI_ICON+SHGFI_SMALLICON
			IconNumber = 9999999  ; Set it out of bounds to display a blank icon.
		else ; Icon successfully loaded.
		{
			; Extract the hIcon member from the structure:
			hIcon := NumGet(FSsfi, 0)
			; Add the HICON directly to the small-icon and large-icon lists.
			; Below uses +1 to convert the returned index from zero-based to one-based:
			IconNumber := DllCall("ImageList_ReplaceIcon", "ptr", P_Imagelist1, "int", -1, "ptr", hIcon) + 1
			DllCall("ImageList_ReplaceIcon", "ptr", P_ImageList2, "int", -1, "ptr", hIcon)
			; Now that it's been copied into the ImageLists, the original should be destroyed:
			DllCall("DestroyIcon", "ptr", hIcon)
			; Cache the icon to save memory and improve loading performance:
			P_IconArray[ExtID] := IconNumber
		}
	}
	return IconNumber
}


;*****************************
;FS GUI LABELS
;*****************************
FSCreateFolder:
	Gui FileSelectSpecific: Default
	InputBox, FolderName, , % "Enter Folder Name",,,120
	if (ErrorLevel or !FolderName)
		return
	FileCreateDir, % glb_FSCurrent "/" FolderName
	FileSelectSpecificAdjust(glb_FSCurrent)
return

FSDisplayFolder:
	Gui FileSelectSpecific: Default
	FSOpenFolderInExplorer(glb_FSCurrent)
return

FSSwitchView:
	Gui FileSelectSpecific: Default
	GuiControl, -Redraw, FSListView
	if not Glb_FSIconView
		GuiControl, +Icon, FSListView    ; Switch to icon view.
	else
		GuiControl, +Report, FSListView  ; Switch back to details view.
	Glb_FSIconView := not Glb_FSIconView             ; Invert in preparation for next time.
	FSRedrawCol()
	GuiControl, +Redraw, FSListView
return

FSRedrawCol() {
global
	Gui FileSelectSpecific: Default
	LV_ModifyCol()  ; Auto-size each column to fit its contents.
	LV_ModifyCol(2,0)  ; Hide FileDir Col
	LV_ModifyCol(3, 60) ; Make the Size column at little wider to reveal its header.
	LV_ModifyCol(4, "AutoHdr") ; Make the Size column at little wider to reveal its header.
}

FSListViewHandler:
	if A_GuiEvent = DoubleClick  ; There are many other possible values the script can check.
	{
		LV_GetText(FileName, A_EventInfo, 1) ; Get the text of the first field.
		LV_GetText(FileDir, A_EventInfo, 2)  ; Get the text of the second field.
		; LV_GetText(FileExt, A_EventInfo, 4)  ; Get the text of the fourth field.
		FilePath:=FileDir "\" FileName
		
		if !glb_FSCurrent
		{
			loop, parse, FileName, :
				if (A_Index=1) {
					FilePath := A_Loopfield ":"
					break
				}
		}
			
		if InStr(FileExist(FilePath), "D") {
			glb_FSCurrent:=FilePath
			FileSelectSpecificAdjust(glb_FSCurrent)
			return
		}
		
		else if (FileExist(FilePath) and (glb_FSType="File" or glb_FSType="All")) {
			if glb_FSNoMulti
				glb_FSReturn:=FilePath
			else
				glb_FSReturn:=FileDir "`n" FileName
			
			if (glb_FSOwnerNum)
				Gui, %glb_FSOwnerNum%:-Disabled
			Gui,FileSelectSpecific:Destroy
			return
		}
	}
return

FSPrevious:
	Gui FileSelectSpecific: Default
	if !glb_FSCurrent
		return
	if (glb_FSCurrent=glb_FSFolder and glb_FSRestrict) {
		tooltip You can not navigate above the folder `n%glb_FSFolder%
		SetTimer, RemoveToolTip, -3000
		return
	}
	if !InStr(FileExist(FSGetParentDir(glb_FSCurrent)), "D")
		glb_FSCurrent:=""
	else
		glb_FSCurrent:=FSGetParentDir(glb_FSCurrent)
		
	FileSelectSpecificAdjust(glb_FSCurrent)
return

FSRefresh:
	Gui FileSelectSpecific: Default
	FileSelectSpecificAdjust(glb_FSCurrent)
return

FSSelect:
	Gui FileSelectSpecific: Default
	RowNumber = 0
	RowOkayed = 0 
	if !LV_GetNext(RowNumber) {
		msgbox Please select an element first
		return
	}
		
	Loop
	{
		RowNumber := LV_GetNext(RowNumber)  ; Resume the search at the row after that found by the previous iteration.
		; msgbox RowNumber %RowNumber%
		if not RowNumber  ; The above returned zero, so there are no more selected rows.
			break
		LV_GetText(FileName, RowNumber, 1) ; Get the text of the first field.
		LV_GetText(FileDir, RowNumber, 2)  ; Get the text of the second field.
		FilePath:=FileDir "\" FileName
		
		if !glb_FSCurrent
		{
			loop, parse, FileName, :
				if (A_Index=1) {
					FilePath := A_Loopfield ":"
					FileName := A_Loopfield ":"
					break
				}
		}

		if !FileExist(FilePath)
			continue
		
		if (InStr(FileExist(FilePath), "D") and glb_FSType="File")
			continue
			
		if (!InStr(FileExist(FilePath), "D") and glb_FSType="Folder")
			continue
			
		RowOkayed++
		
		glb_FSMultiReturn.= "`n" FileName
		
	}
	
	if (RowOkayed=0) {
		msgbox sorry wrong selection
		return
	}
	
	if (RowOkayed=1 and glb_FSNoMulti)
		glb_FSReturn:=FilePath
	else
		glb_FSReturn:=FileDir . glb_FSMultiReturn

	if (glb_FSOwnerNum)
		Gui, %glb_FSOwnerNum%:-Disabled
		
	Gui,FileSelectSpecific:Destroy
return

;Context-sensitive hotkey to detect Enter on FS navigation bar
#If (FSHwnd and WinActive("ahk_id " FSHwnd))
Enter::
GuiControlGet, OutputVar, FileSelectSpecific:FocusV
; msgbox OutputVar %OutputVar%
if (OutputVar="FSNavBarv")
	Gosub, FSNavBar
Return
#If

;Enter on FS navigation bar
FSNavBar:
Gui, FileSelectSpecific:Default
GuiControlGet, FSNavBarv
StringRight, LastChar, FSNavBarv, 1
	if LastChar = \
		StringTrimRight, FSNavBarv, FSNavBarv, 1  ; Remove the trailing backslash.
if !InStr(FileExist(FSNavBarv), "D")
	return

if (glb_FSRestrict and !Instr(FSNavBarv,glb_FSFolder)) {
	tooltip You can not navigate above the folder `n%glb_FSFolder%
	SetTimer, RemoveToolTip, -3000
	return
	}
GuiControl,,FSNavBarv,% FSNavBarv

glb_FSCurrent:=FSNavBarv
FileSelectSpecificAdjust()
return

RemoveToolTip:
tooltip
return

;$OBFUSCATOR: $LABELS_CHANGE_DEFAULTS: -1
;*****************************
;FS GUI SPECIAL LABELS
;*****************************
FileSelectSpecificGuiContextMenu:  ; Launched in response to a right-click or press of the Apps key.
Gui FileSelectSpecific: Default
	if A_GuiControl <> FSListView  ; This check is optional. It displays the menu only for clicks inside the ListView.
		return
	Menu, FSContextMenu, Show
return

FileSelectSpecificGuiClose:
	if glb_FSOwnerNum
		try, Gui,%glb_FSOwnerNum%:-Disabled
	Gui,Destroy
return

FileSelectSpecificGuiSize:  ; Readjust the controls in response to the user's resizing of the window.
	if A_EventInfo = 1  ; The window has been minimized.  No action needed.
		return
		
	GuiControl, -Redraw, FSListView

	GuiControlGet, FSComplementv
	GuiControlGet, FSMultiIndicv
	
	; Otherwise, the window has been resized or maximized. Resize the controls.
	
	GuiControlGet, FSListViewPos, Pos, FSListView
	
	GuiControl, MoveDraw, FSPromptv, % " W" . (A_GuiWidth-20)
	GuiControl, MoveDraw, FSNavBarv, % " W" . (A_GuiWidth-20)
	
	if FSComplementv
	GuiControl, MoveDraw, FSComplementv, % "y" FSListViewPosY + FSListViewPosH + 10 " W" . (A_GuiWidth-20)
	
	GuiControlGet, FSComplementPos, Pos, FSComplementv
	
	if FSMultiIndicv
	GuiControl, MoveDraw, FSMultiIndicv, % "y" A_GuiHeight-20 " W" . (A_GuiWidth-20)
	
	GuiControlGet, FSMultiIndicPos, Pos, FSMultiIndicv
	
	;Trick : Round() so that empty vars = 0
	FSListGap:=Round(FSComplementPosH) + Round(FSMultiIndicPosH) + 15
	
	GuiControl, MoveDraw, FSListView, % "W" . (A_GuiWidth - 20) . " H" . (A_GuiHeight - FSListViewPosY - Round(FSListGap))
	
	;Set timer to recreate listview if icon view
	if (Glb_FSIconView and !glb_FSInit)
		SetTimer, FileSelectSpecificAdjust, -200
	else if (Glb_FSIconView and glb_FSInit)
		FileSelectSpecificAdjust()
	
	GuiControl, +Redraw, FSListView  ; Re-enable redrawing (it was disabled above).
	
return
;$OBFUSCATOR: $LABELS_RESTORE_DEFAULTS:
;*****************************


;*****************************
;SMALL FS FUNCTIONS
;*****************************
FSGetParentDir(Path) {
	return SubStr(Path, 1, InStr(SubStr(Path,1,-1), "\", 0, 0)-1)
}

FSOpenFolderInExplorer(P_Folder) {
global
	if !InStr(FileExist(P_Folder), "D")
		return 0
	Run % P_Folder
}
Last edited by DigiDon on 15 Feb 2018, 09:08, edited 2 times in total.
EverFastAccess : Take Notes on anything the Fast way: Attach notes, Set reminders & Speed up research in 1 gesture - AHK topic
AHK Dynamic Obfuscator L - Protect your AHK code by Obfuscation - AHK topic
QuickModules for Outlook : Sort Outlook emails very quickly to multiple folders - AHK topic
Coding takes lots of time and efforts. If I have helped you or if you enjoy one of my free projects, please consider a small donation :thumbup:
Sorry I am working hard at the moment at a new job and can't commit on delays of answers & updates
DigiDon
Posts: 178
Joined: 19 May 2014, 04:55
Contact:

Re: [GUI] FileSelect alternative - Customize / Restrict to a specific folder (14.02.2018)

15 Feb 2018, 08:45

Unrelated but I've noticed there is a small bug for the icons of the drives though, I'm working on it.

And even if there shouldn't be an error I'll try to make really sure the VarSetCapacity is fine.
Last edited by DigiDon on 15 Feb 2018, 09:40, edited 1 time in total.
EverFastAccess : Take Notes on anything the Fast way: Attach notes, Set reminders & Speed up research in 1 gesture - AHK topic
AHK Dynamic Obfuscator L - Protect your AHK code by Obfuscation - AHK topic
QuickModules for Outlook : Sort Outlook emails very quickly to multiple folders - AHK topic
Coding takes lots of time and efforts. If I have helped you or if you enjoy one of my free projects, please consider a small donation :thumbup:
Sorry I am working hard at the moment at a new job and can't commit on delays of answers & updates
DigiDon
Posts: 178
Joined: 19 May 2014, 04:55
Contact:

Re: [GUI] FileSelect alternative - Customize / Restrict to a specific folder (15.02.2018)

15 Feb 2018, 09:08

Minor corrections.
15.02.2018 - 15h UTC+1
  • Correction: Icons of drives, directories and files without ext are better dealt with
  • Included the full example to the fuction
  • Moved VarSetCapacity to protect the DllCall better
EverFastAccess : Take Notes on anything the Fast way: Attach notes, Set reminders & Speed up research in 1 gesture - AHK topic
AHK Dynamic Obfuscator L - Protect your AHK code by Obfuscation - AHK topic
QuickModules for Outlook : Sort Outlook emails very quickly to multiple folders - AHK topic
Coding takes lots of time and efforts. If I have helped you or if you enjoy one of my free projects, please consider a small donation :thumbup:
Sorry I am working hard at the moment at a new job and can't commit on delays of answers & updates
burque505
Posts: 1731
Joined: 22 Jan 2017, 19:37

Re: [GUI] FileSelect alternative - Customize / Restrict to a specific folder (15.02.2018)

15 Feb 2018, 13:41

@DigiDon, looks good! Thanks. I look forward to seeing this evolve, it will be very helpful. And your RichEdit work will be too.
Regards,
burque505
DigiDon
Posts: 178
Joined: 19 May 2014, 04:55
Contact:

Re: [GUI] FileSelect alternative - Customize / Restrict to a specific folder (15.02.2018)

15 Feb 2018, 14:07

OK great news ! I suppose it is better to put a full example rather than the function and separate doc.
I guess you ran the function code directly which caused the weird things.

Thanks, I hope it will be helpful indeed.

If you can please test a bit the two functions and tell me if you see flickering on the first one (try to specify sizes if you can).
Tell me if you notice something else.
EverFastAccess : Take Notes on anything the Fast way: Attach notes, Set reminders & Speed up research in 1 gesture - AHK topic
AHK Dynamic Obfuscator L - Protect your AHK code by Obfuscation - AHK topic
QuickModules for Outlook : Sort Outlook emails very quickly to multiple folders - AHK topic
Coding takes lots of time and efforts. If I have helped you or if you enjoy one of my free projects, please consider a small donation :thumbup:
Sorry I am working hard at the moment at a new job and can't commit on delays of answers & updates
DigiDon
Posts: 178
Joined: 19 May 2014, 04:55
Contact:

Re: [GUI] FileSelect alternative - Customize / Restrict to a specific folder (20.03.2018)

20 Mar 2018, 13:38

20.03.2018 - 19h UTC+1
  • Managed to avoid flickering in the first simplier version: therefore deleted the other version
  • Little better autosizing
EverFastAccess : Take Notes on anything the Fast way: Attach notes, Set reminders & Speed up research in 1 gesture - AHK topic
AHK Dynamic Obfuscator L - Protect your AHK code by Obfuscation - AHK topic
QuickModules for Outlook : Sort Outlook emails very quickly to multiple folders - AHK topic
Coding takes lots of time and efforts. If I have helped you or if you enjoy one of my free projects, please consider a small donation :thumbup:
Sorry I am working hard at the moment at a new job and can't commit on delays of answers & updates
aldrinjohnom
Posts: 77
Joined: 18 Apr 2018, 08:49

Re: [GUI] FileSelect alternative - Customize / Restrict to a specific folder (20.03.2018)

04 Nov 2019, 02:59

DigiDon wrote:
07 Feb 2018, 07:11
Hi,

For my project EverFastAccess I needed a dialog able to select multiple files and folders.
The standard folder select dialog thus wasn't a fit so I decided to create a more flexible and configurable file/folder select dialog.

I hope this will benefit many :)

AHK GUI alternative to the FileSelectFile / FileSelectFolder dialogs
  • Allows more parameters/customization
  • Allows to restrict navigation within a specific folder
  • Allows selection of both files and folders
Image
Image

UPDATES last 20.03.2018 - 19h UTC+1
Spoiler
I am quite surprised I could not find such a script. I'm especially quite surprised it seems not available by Windows as standard as well :roll:
I wanted to have a GUI (TreeView and/or ListView) that allows user to naviagate folders and select a file WITHIN the specified folder.

I didn't want to apply dirty tricks to the fileselect standard dialog so I thought a complete AHK Gui could be a good solution.
So based on the ListView Main Example https://www.autohotkey.com/docs/commands/ListView.htm#Examples here is my try!

Don't hesitate to post improvements or say anything ;)

DOCUMENTATION (example at the end)

Code: Select all

; **********************************************************
; FileSelectSpecific Functions by DigiDon
; **********************************************************
; Use/modify as you wish
; Based on Main example from https://autohotkey.com/docs/commands/ListView.htm
; **********************************************************
; AHK GUI alternative to the FileSelectFile / FileSelectFolder dialogs
; Allows more parameters/customization
; Allows to restrict navigation within a specific folder
; Allows to select File(s) or/and Folder(s)
; Allows to filter file types in or out
; **********************************************************
; FileSelectSpecific(P_OwnerNum,P_Path,P_SelectFileOrFolder="File",P_Prompt="",P_ComplementText="",P_Multi="",P_DefaultView="Icon",P_FilterOK="",P_FilterNO="",P_Restrict=1,P_LVHeight="220",P_LVWidth="350")
;*****************************
;	PARAMETERS
;*****************************
;----- P_OwnerNum: Num/Name of the Gui Owner: it will be disabled the time a selection is made
;----- P_Path: Starting Folder 
;EMPTY: Start with all disks
;----- P_SelectFileOrFolder : Type of Selection to make
;"File" : User should select File(s)
;"Folder" : User should select Folder(s)
;"All" : User should select File(s) and/or Folder(s)
;----- P_Prompt : Text to display at the top of GUI
;----- P_ComplementText : Text to display at the bottom the GUI
;----- P_Multi : MultiSelection
;VALUE: Allowed / EMPTY: Forbidden
;----- P_DefaultView : Default View for the Tree List
;"Icon" / "Report"
;----- P_FilterOK : Comma-list of allowed extensions to be displayed and chosen
;ex "EXE,INI"
;----- P_FilterNO : Comma-list of forbidden extensions to be displayed and chosen
;ex "EXE,INI"
;----- P_Restrict : The user should not be able to navigate above the starting folder
;----- P_LVHeight : Height of ListView in Px
;----- P_LVWidth  : Width  of ListView in Px
;*****************************
;	RETURN VALUE
;*****************************
;----- FSHwnd: Hwnd of the GUI windows
;*****************************
; GLOBAL VALUE TO CHECK AFTER CALL
;*****************************
;----- glb_FSReturn: Contains the path of the selected file(s)
;NO SELECTION : EMPTY
;NO Multi Selection: Path of the selected File
;Multi Selection: Path of the folder "`n" Paths of the selected files (`n separated)
;*****************************
;			USAGE
;*****************************
;ANY SINGLE FILE ANYWHERE
FSHwnd:=FileSelectSpecific("","","File","Please Choose a file")
WinWait % "ahk_id " FSHwnd
WinWaitClose % "ahk_id " FSHwnd
if !glb_FSReturn
	msgbox No selection
else
	msgbox selection was %glb_FSReturn%
; ONE OR MORE NON-RTF FILES WITHIN C:
FSHwnd:=FileSelectSpecific("","C:","File","Please Choose file(s) in C: (no rtf)","",1,,,"rtf",1)
WinWait % "ahk_id " FSHwnd
WinWaitClose % "ahk_id " FSHwnd
if !glb_FSReturn
	msgbox No selection
else
	msgbox selection was %glb_FSReturn%
;*****************************
FUNCTIONS AND WORKING EXAMPLE

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
#SingleInstance, Force

; ONE OR MORE NON-RTF FILES WITHIN C:
WinWaitClose % "ahk_id " FileSelectSpecific("","C:","File","Please Choose file(s) in C: (no rtf)","",1,,,"rtf",1)
if !glb_FSReturn
	msgbox No selection
else
	msgbox selection was %glb_FSReturn%
	
;ANY SINGLE FILE ANYWHERE
WinWaitClose % "ahk_id " FileSelectSpecific("","","File","Please Choose a file")
if !glb_FSReturn
	msgbox No selection
else
	msgbox selection was %glb_FSReturn%
return

FileSelectSpecific(P_OwnerNum,P_Path,P_SelectFileOrFolder="File",P_Prompt="",P_ComplementText="",P_Multi="",P_DefaultView="Icon",P_FilterOK="",P_FilterNO="",P_Restrict=1,P_LVHeight="220",P_LVWidth="350") {
global
	
	;*****************************
	; MAKE SURE PREVIOUS OWNER IS RE-ENABLED AND EXISTING FS DESTROYED
	;*****************************
	if glb_FSOwnerNum
		try, Gui,%glb_FSOwnerNum%:-Disabled
	try Gui,FileSelectSpecific:Destroy
	;*****************************
	; CONTEXT MENU
	;*****************************
	try
	Menu, FSContextMenu, Add, SELECT, FSSelect
	Menu, FSContextMenu, Add, Create Folder, FSCreateFolder
	Menu, FSContextMenu, Add, Open Folder in Explorer, FSDisplayFolder
	Menu, FSContextMenu, Default, 1&

	;*****************************
	; GLOBAL VARS
	;*****************************
	glb_FSTitle=%A_ScriptName% - File Select Dialog
	
	glb_FSInit:=1
	glb_FSFolder:=P_Path
	glb_FSCurrent:=glb_FSFolder
	glb_FSFilterOK:=P_FilterOK
	glb_FSFilterNO:=P_FilterNO
	glb_FSRestrict:=P_Restrict

	glb_FSType:=P_SelectFileOrFolder
	glb_FSReturn:=""
	glb_FSOwnerNum:=P_OwnerNum
	
	
	if (P_SelectFileOrFolder="File" or P_SelectFileOrFolder="All")
		LoopType:="FD"
	else if (P_SelectFileOrFolder="Folder")
		LoopType:="D"
		
	glb_FSLoopType:=LoopType
	
	if P_Multi
		glb_FSNoMulti:=""
	else
		glb_FSNoMulti:="-Multi"
		
	; Check if the last character of the folder name is a backslash, which happens for root
	; directories such as C:\. If it is, remove it to prevent a double-backslash later on.
	StringRight, LastChar, glb_FSFolder, 1
	if LastChar = \
		StringTrimRight, glb_FSFolder, glb_FSFolder, 1  ; Remove the trailing backslash.
	glb_FSCurrent:=glb_FSFolder
		
	;*****************************
	; GUI CREATION
	;*****************************
	Gui, FileSelectSpecific:Default
	Gui, FileSelectSpecific: New
	Gui +HwndFSHwnd
	Gui +Resize +MinSize330x280
	
	;SET AND DISABLE OWNER
	if (glb_FSOwnerNum) {
		Gui +Owner%glb_FSOwnerNum%
		Gui, %glb_FSOwnerNum%:+Disabled
		}
	
	Gui +OwnDialogs  ; Forces user to dismiss the following dialog before using main window.

	; Create some buttons:
	Gui, Add, Button, xm w20 gFSSwitchView, % Chr(0x02630)
	Gui, Font, Bold
	Gui, Add, Button, x+5 yp gFSRefresh, % Chr(0x21BB)
	Gui, Add, Button, x+5 w30 gFSPrevious, % Chr(0x2190)
	; Gui, Font
	; Gui, Font, Bold
	Gui, Add, Button, x+5 yp gFSSelect, % "SELECT"
	Gui, Font
	Gui, Add, Edit, xm y+8 w%P_LVWidth% vFSNavBarv, % glb_FSCurrent
	Gui, Add, Text, xm y+8 w%P_LVWidth% vFSPromptv, % P_Prompt
	

	; Create the ListView and its columns:
	ListViewPos:= " w" P_LVWidth
	ListViewPos:= " h" P_LVHeight
	
	Gui, Add, ListView, xm y+10 %ListViewPos% vFSListView gFSListViewHandler %glb_FSNoMulti%, Name|In Folder|Size (KB)|Type
	LV_ModifyCol(3, "Integer")  ; For sorting, indicate that the Size column is an integer.
	
	if (P_DefaultView="Icon") {
		GuiControl, +Icon, FSListView    ; Switch to icon view.
		Glb_FSIconView:=1
	} else {
		GuiControl, +Report, FSListView  ; Switch back to details view.
		Glb_FSIconView:=0
	}
	
	Gui, Font, s10
	if P_ComplementText
		Gui, Add, Text, xm y+8 w%P_LVWidth% vFSComplementv, % P_ComplementText
	
	Gui, Font, Italic s9
	if !glb_FSNoMulti
		Gui, Add, Text, xm y+5 w%P_LVWidth% vFSMultiIndicv, % "Hold Ctrl or Shift for Multi-Selection"
	
	Gui, Font
	
	;*****************************
	; ICONS CREATION
	;*****************************
	; Calculate buffer size required for SHFILEINFO structure.
	FSIconArray:={}

	FSImageListID1 := IL_Create(10)
	FSImageListID2 := IL_Create(10, 10, true)  ; A list of large icons to go with the small ones.
	; Attach the ImageLists to the ListView so that it can later display the icons:
	LV_SetImageList(FSImageListID1)
	LV_SetImageList(FSImageListID2)

	; Gather a list of file names from the selected folder and append them to the ListView:
	;*****************************
	; SEARCH FILES AND SHOW GUI
	;*****************************
	GuiControl, -Redraw, FSListView  ; Improve performance by disabling redrawing during load.
	
	FSAddLoopFiles()
	FSRedrawCol()
	
	GuiControl, +Redraw, FSListView  ; Re-enable redrawing (it was disabled above).
	
	Gui, Show,,% glb_FSTitle
	glb_FSInit:=0
	
	return FSHwnd
}

FileSelectSpecificAdjust(P_Path="") {
	global
	if !P_Path
		P_Path:=glb_FSCurrent
	Gui FileSelectSpecific: Default
	GuiControl, -Redraw, FSListView
	LV_Delete()
	FSAddLoopFiles()
	GuiControl,,FSNavBarv, % glb_FSCurrent
	FSRedrawCol()
	GuiControl, +Redraw, FSListView
}

FSAddLoopFiles() {
global
	Gui FileSelectSpecific: Default
	
	FSsfi_size := A_PtrSize + 8 + (A_IsUnicode ? 680 : 340)
	VarSetCapacity(FSsfi, FSsfi_size,0)
	
	if !glb_FSCurrent {
		DriveGet, FSDriveList, list
		FSDriveLabels:={}
		
		Loop, parse, FSDriveList 
			{
			DriveGet, FSDriveLabel, Label, %A_Loopfield%:
			FSDriveLabels[A_Index]:=FSDriveLabel
		
			IconNumber:=FSSetIcon(A_Loopfield ":","",FSIconArray,FSImageListID1,FSImageListID2)
			
			LV_Add("Icon" . IconNumber, A_Loopfield ": " FSDriveLabels[A_Index], "", "", "")
			}
		return
	}

	Loop, Files, %glb_FSCurrent%\*, %glb_FSLoopType%
	{
		if A_LoopFileAttrib contains H,S  ; Skip any file that is either H (Hidden), or S (System). Note: No spaces in "H,S".
			continue  ; Skip this file and move on to the next one.
		
		; FileName := A_LoopFileFullPath  ; Must save it to a writable variable for use below.
		
		If glb_FSfilterOK
			If A_LoopFileExt not in ,%glb_FSfilterOK%
				continue
			
		If glb_FSFilterNO
			If A_LoopFileExt in %glb_FSFilterNO%
				continue
		
		IconNumber:=FSSetIcon(A_LoopFileFullPath,A_LoopFileExt,FSIconArray,FSImageListID1,FSImageListID2)

		; Create the new row in the ListView and assign it the icon number determined above:
		LV_Add("Icon" . IconNumber, A_LoopFileName, A_LoopFileDir, A_LoopFileSizeKB, A_LoopFileExt)
	}
}

FSSetIcon(P_Filepath,P_FileExt,ByRef P_IconArray,ByRef P_Imagelist1,ByRef P_ImageList2) {
global
	
	if P_FileExt in EXE,ICO,ANI,CUR
	{
		ExtID := P_FileExt  ; Special ID as a placeholder.
		IconNumber = 0  ; Flag it as not found so that these types can each have a unique icon.
	}
	else  ; Some other extension/file-type, so calculate its unique ID.
	{
		;TTRICK: if no ext it can be drive or directory or a file without ext. In this case we create a fake ext so they won't use the same icons and icons can be re-used
		if !P_FileExt
		{
			
			if Regexmatch(P_Filepath, ":$")
				P_FileExt:="DRIVE"
			else if InStr(FileExist(P_Filepath), "D")
				P_FileExt:="DIR"
			else if FileExist(P_Filepath)
				P_FileExt:="NOEXT"
		}
		ExtID = 0  ; Initialize to handle extensions that are shorter than others.
		Loop 7     ; Limit the extension to 7 characters so that it fits in a 64-bit value.
			{
			StringMid, ExtChar, P_FileExt, A_Index, 1
			if not ExtChar  ; No more characters.
				break
			; Derive a Unique ID by assigning a different bit position to each character:
			ExtID := ExtID | (Asc(ExtChar) << (8 * (A_Index - 1)))
			}
		; Check if this file extension already has an icon in the ImageLists. If it does,
		; several calls can be avoided and loading performance is greatly improved,
		; especially for a folder containing hundreds of files:
		IconNumber := P_IconArray[ExtID]
	}
	;can debug icons here
	; msgbox IconNumber %IconNumber% P_Filepath %P_Filepath% P_FileExt %P_FileExt%
	if not IconNumber  ; There is not yet any icon for this extension, so load it.
	{
		; Get the high-quality small-icon associated with this file extension:
		if not DllCall("Shell32\SHGetFileInfo" . (A_IsUnicode ? "W":"A"), "str", P_Filepath, "uint", 0, "ptr", &FSsfi, "uint", FSsfi_size, "uint", 0x101)  ; 0x101 is SHGFI_ICON+SHGFI_SMALLICON
			IconNumber = 9999999  ; Set it out of bounds to display a blank icon.
		else ; Icon successfully loaded.
		{
			; Extract the hIcon member from the structure:
			hIcon := NumGet(FSsfi, 0)
			; Add the HICON directly to the small-icon and large-icon lists.
			; Below uses +1 to convert the returned index from zero-based to one-based:
			IconNumber := DllCall("ImageList_ReplaceIcon", "ptr", P_Imagelist1, "int", -1, "ptr", hIcon) + 1
			DllCall("ImageList_ReplaceIcon", "ptr", P_ImageList2, "int", -1, "ptr", hIcon)
			; Now that it's been copied into the ImageLists, the original should be destroyed:
			DllCall("DestroyIcon", "ptr", hIcon)
			; Cache the icon to save memory and improve loading performance:
			P_IconArray[ExtID] := IconNumber
		}
	}
	return IconNumber
}


;*****************************
;FS GUI LABELS
;*****************************
FSCreateFolder:
	Gui FileSelectSpecific: Default
	InputBox, FolderName, , % "Enter Folder Name",,,120
	if (ErrorLevel or !FolderName)
		return
	FileCreateDir, % glb_FSCurrent "/" FolderName
	FileSelectSpecificAdjust(glb_FSCurrent)
return

FSDisplayFolder:
	Gui FileSelectSpecific: Default
	FSOpenFolderInExplorer(glb_FSCurrent)
return

FSSwitchView:
	Gui FileSelectSpecific: Default
	GuiControl, -Redraw, FSListView
	if not Glb_FSIconView
		GuiControl, +Icon, FSListView    ; Switch to icon view.
	else
		GuiControl, +Report, FSListView  ; Switch back to details view.
	Glb_FSIconView := not Glb_FSIconView             ; Invert in preparation for next time.
	FSRedrawCol()
	GuiControl, +Redraw, FSListView
return

FSRedrawCol() {
global
	Gui FileSelectSpecific: Default
	LV_ModifyCol()  ; Auto-size each column to fit its contents.
	LV_ModifyCol(2,0)  ; Hide FileDir Col
	LV_ModifyCol(3, 60) ; Make the Size column at little wider to reveal its header.
	LV_ModifyCol(4, "AutoHdr") ; Make the Size column at little wider to reveal its header.
}

FSListViewHandler:
	if A_GuiEvent = DoubleClick  ; There are many other possible values the script can check.
	{
		LV_GetText(FileName, A_EventInfo, 1) ; Get the text of the first field.
		LV_GetText(FileDir, A_EventInfo, 2)  ; Get the text of the second field.
		; LV_GetText(FileExt, A_EventInfo, 4)  ; Get the text of the fourth field.
		FilePath:=FileDir "\" FileName
		
		if !glb_FSCurrent
		{
			loop, parse, FileName, :
				if (A_Index=1) {
					FilePath := A_Loopfield ":"
					break
				}
		}
			
		if InStr(FileExist(FilePath), "D") {
			glb_FSCurrent:=FilePath
			FileSelectSpecificAdjust(glb_FSCurrent)
			return
		}
		
		else if (FileExist(FilePath) and (glb_FSType="File" or glb_FSType="All")) {
			if glb_FSNoMulti
				glb_FSReturn:=FilePath
			else
				glb_FSReturn:=FileDir "`n" FileName
			
			if (glb_FSOwnerNum)
				Gui, %glb_FSOwnerNum%:-Disabled
			Gui,FileSelectSpecific:Destroy
			return
		}
	}
return

FSPrevious:
	Gui FileSelectSpecific: Default
	if !glb_FSCurrent
		return
	if (glb_FSCurrent=glb_FSFolder and glb_FSRestrict) {
		tooltip You can not navigate above the folder `n%glb_FSFolder%
		SetTimer, RemoveToolTip, -3000
		return
	}
	if !InStr(FileExist(FSGetParentDir(glb_FSCurrent)), "D")
		glb_FSCurrent:=""
	else
		glb_FSCurrent:=FSGetParentDir(glb_FSCurrent)
		
	FileSelectSpecificAdjust(glb_FSCurrent)
return

FSRefresh:
	Gui FileSelectSpecific: Default
	FileSelectSpecificAdjust(glb_FSCurrent)
return

FSSelect:
	Gui FileSelectSpecific: Default
	RowNumber = 0
	RowOkayed = 0 
	if !LV_GetNext(RowNumber) {
		msgbox Please select an element first
		return
	}
		
	Loop
	{
		RowNumber := LV_GetNext(RowNumber)  ; Resume the search at the row after that found by the previous iteration.
		; msgbox RowNumber %RowNumber%
		if not RowNumber  ; The above returned zero, so there are no more selected rows.
			break
		LV_GetText(FileName, RowNumber, 1) ; Get the text of the first field.
		LV_GetText(FileDir, RowNumber, 2)  ; Get the text of the second field.
		FilePath:=FileDir "\" FileName
		
		if !glb_FSCurrent
		{
			loop, parse, FileName, :
				if (A_Index=1) {
					FilePath := A_Loopfield ":"
					FileName := A_Loopfield ":"
					break
				}
		}

		if !FileExist(FilePath)
			continue
		
		if (InStr(FileExist(FilePath), "D") and glb_FSType="File")
			continue
			
		if (!InStr(FileExist(FilePath), "D") and glb_FSType="Folder")
			continue
			
		RowOkayed++
		
		glb_FSMultiReturn.= "`n" FileName
		
	}
	
	if (RowOkayed=0) {
		msgbox sorry wrong selection
		return
	}
	
	if (RowOkayed=1 and glb_FSNoMulti)
		glb_FSReturn:=FilePath
	else
		glb_FSReturn:=FileDir . glb_FSMultiReturn

	if (glb_FSOwnerNum)
		Gui, %glb_FSOwnerNum%:-Disabled
		
	Gui,FileSelectSpecific:Destroy
return

;Context-sensitive hotkey to detect Enter on FS navigation bar
#If (FSHwnd and WinActive("ahk_id " FSHwnd))
Enter::
GuiControlGet, OutputVar, FileSelectSpecific:FocusV
; msgbox OutputVar %OutputVar%
if (OutputVar="FSNavBarv")
	Gosub, FSNavBar
Return
#If

;Enter on FS navigation bar
FSNavBar:
Gui, FileSelectSpecific:Default
GuiControlGet, FSNavBarv
StringRight, LastChar, FSNavBarv, 1
	if LastChar = \
		StringTrimRight, FSNavBarv, FSNavBarv, 1  ; Remove the trailing backslash.
if !InStr(FileExist(FSNavBarv), "D")
	return

if (glb_FSRestrict and !Instr(FSNavBarv,glb_FSFolder)) {
	tooltip You can not navigate above the folder `n%glb_FSFolder%
	SetTimer, RemoveToolTip, -3000
	return
	}
GuiControl,,FSNavBarv,% FSNavBarv

glb_FSCurrent:=FSNavBarv
FileSelectSpecificAdjust()
return

RemoveToolTip:
tooltip
return

;*****************************
;FS GUI SPECIAL LABELS
;*****************************
FileSelectSpecificGuiContextMenu:  ; Launched in response to a right-click or press of the Apps key.
Gui FileSelectSpecific: Default
	if A_GuiControl <> FSListView  ; This check is optional. It displays the menu only for clicks inside the ListView.
		return
	Menu, FSContextMenu, Show
return

FileSelectSpecificGuiClose:
	if glb_FSOwnerNum
		try, Gui,%glb_FSOwnerNum%:-Disabled
	Gui,Destroy
return

FileSelectSpecificGuiSize:  ; Readjust the controls in response to the user's resizing of the window.
	if A_EventInfo = 1  ; The window has been minimized.  No action needed.
		return
	;Do not trigger during init
	if glb_FSInit
		return
		
	GuiControl, -Redraw, FSListView

	GuiControlGet, FSComplementv
	GuiControlGet, FSMultiIndicv
	
	; Otherwise, the window has been resized or maximized. Resize the controls.
	
	GuiControlGet, FSListViewPos, Pos, FSListView
	
	GuiControl, MoveDraw, FSPromptv, % " W" . (A_GuiWidth-20)
	GuiControl, MoveDraw, FSNavBarv, % " W" . (A_GuiWidth-20)
	
	FSListGap=
	
	if (FSComplementv) {
		GuiControl, MoveDraw, FSComplementv, % "y" FSListViewPosY + FSListViewPosH + 10 " W" . (A_GuiWidth-20)
		FSListGap+=10
	}
	
	GuiControlGet, FSComplementPos, Pos, FSComplementv
	
	if (FSMultiIndicv) {
		GuiControl, MoveDraw, FSMultiIndicv, % "y" A_GuiHeight-20 " W" . (A_GuiWidth-20)
		FSListGap+=5
	}
	
	GuiControlGet, FSMultiIndicPos, Pos, FSMultiIndicv
	
	;Trick : Round() so that empty vars = 0
	FSListGap:=Round(FSComplementPosH) + Round(FSMultiIndicPosH) + 15
	
	GuiControl, MoveDraw, FSListView, % "W" . (A_GuiWidth - 20) . " H" . (A_GuiHeight - FSListViewPosY - Round(FSListGap))
	
	;Set timer to recreate listview if icon view
	if (Glb_FSIconView)
		SetTimer, FileSelectSpecificAdjust, -200
	
	GuiControl, +Redraw, FSListView  ; Re-enable redrawing (it was disabled above).
	
return
;*****************************


;*****************************
;SMALL FS FUNCTIONS
;*****************************
FSGetParentDir(Path) {
	return SubStr(Path, 1, InStr(SubStr(Path,1,-1), "\", 0, 0)-1)
}

FSOpenFolderInExplorer(P_Folder) {
global
	if !InStr(FileExist(P_Folder), "D")
		return 0
	Run % P_Folder
}
Hello, I see that your function was set as global. Unfortunately, I find it quite messy if function operations are global... Can you make it as Local as Possible? or static maybe so that the function will not interfere with current variables,arrays,objects, etc at the global script? Nice script BTW, just that one thing issue though...
Developer of AJOM's DOTA2 MOD Master, Easiest way to MOD your DOTA2 without the use of internet :lol: . I created this program using Autohotkey thats why I love Autohotkey and the community!

GitHub:
https://github.com/Aldrin-John-Olaer-Manalansan

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 117 guests