' C:\Users\Public\Documents\IWBasic\MyProgs\TreeView Dir\TreeView_Dir.iwb
'  Compile as Windows.EXE

$MAIN
AUTODEFINE "off"

CONST C_Red   = 0x0000FF
CONST C_Cyan  = 0xFFFF00
CONST C_Black = 0x000000

DECLARE IMPORT,SHBrowseForFolder(param1:UINT),INT
DECLARE IMPORT,SHGetPathFromIDList(param1:UINT, param2:UINT),INT
DECLARE IMPORT,CoTaskMemFree(param1:INT),INT
DECLARE IMPORT,RtlZeroMemory(dat:UINT,length:INT),INT
DECLARE IMPORT,SendMessageA(hWnd:UINT, message:UINT, wParam:INT, lparam:UINT),UINT

TYPE BROWSEINFO
	DEF hOwner:UINT
	DEF pidlRoot:UINT
	DEF pszDisplayName:POINTER
	DEF lpszTitle:POINTER
	DEF ulFlags:UINT
	DEF lpfn:UINT
	DEF lParam:UINT
	DEF iImage:UINT
ENDTYPE

CONST WM_USER = 0x400
CONST BFFM_SETSELECTION = WM_USER + 102
CONST BFFM_INITIALIZED = 1
CONST BFFM_VALIDATEFAILED = 3
CONST BIF_RETURNFSANCESTORS = 8
CONST BIF_RETURNONLYFSDIRS = 1
CONST BIF_NEWDIALOGSTYLE = 0x40
CONST BIF_DONTGOBELOWDOMAIN = 2

CONST TView = 100
CONST Max_Path = 260

CONST TV_FIRST = 0x1100
CONST TVS_CHECKBOXES = 0x100
CONST TVM_SETBKCOLOR = (TV_FIRST + 29)
CONST TVM_SETLINECOLOR = (TV_FIRST + 40)
CONST TVM_SETTEXTCOLOR = (TV_FIRST + 30)

CONST w1_m1 = 100
CONST w1_m2 = w1_m1 + 1

DEF w1, tv:WINDOW
DEF run, cd, i, j, k:INT
DEF handle[30]:UINT
DEF dSize[30], fSize[30]:UINT64
DEF spath[Max_Path], bpath[Max_Path]:ISTRING

TYPE filetime
	DEF dwLowDateTime:INT
	DEF dwHighDateTime:INT
ENDTYPE

TYPE WIN32_FIND_DATA,4
	DEF dwFileAttributes:INT
	DEF ftCreationTime:FILETIME
	DEF ftLastAccessTime:FILETIME
	DEF ftLastWriteTime:FILETIME
	DEF nFileSizeHigh:UINT
	DEF nFileSizeLow:UINT
	DEF dwReserved0:INT
	DEF dwReserved1:INT
	DEF cFileName[Max_Path]:ISTRING
	DEF cAlternate[14]:ISTRING
ENDTYPE

OPENWINDOW w1,0,0,940,780,0,0,"Treeview Directory Sizes",&winproc
BEGINMENU w1
	MENUTITLE "&Menu"
	MENUITEM "&Browse",0,w1_m1
	MENUITEM "&Exit",0,w1_m2
ENDMENU

CONTROL w1,@TREEVIEW,"Directories",5,5,925,725,@TVSHasButtons|@TVSHasLines|@TVSLinesAtRoot|@Border,TView
SetFont w1,"Courier New",10,400,0,TView
tvDeleteAllItems(w1,TView)

SENDMESSAGE w1,TVM_SETBKCOLOR,0,C_Black,TView
SENDMESSAGE w1,TVM_SETLINECOLOR,0,C_Red,TView
SENDMESSAGE w1,TVM_SETTEXTCOLOR,0,C_Cyan,TView

bpath = GetStartPath
IF FolderRequest(0,"Select Starting Folder", spath, bpath, 0x441) = TRUE
	bpath = spath
	cd = 1
	FOR i = 0 TO 29
		handle[i] = 0
		dSize[i] = 0
		fSize[i] = 0
	NEXT i
	GetFiles(spath)
	run = 1
	WAITUNTIL run = 0
ENDIF
CLOSECONSOLE
END

SUB winproc
SELECT  @CLASS
	CASE @IDCLOSEWINDOW
	CASE& @IDDESTROY
		CLOSEWINDOW w1
		run = 0
	CASE @IDCREATE
		CENTERWINDOW w1
	CASE @IDMENUPICK
		SELECT @MENUNUM
			CASE w1_m1: ' browse
				IF FolderRequest(0,"Select Starting Folder", spath, bpath, 0x441) = TRUE
					bpath = spath
					cd = 1
					FOR i = 0 TO 29
						handle[i] = 0
						dSize[i] = 0
						fSize[i] = 0
					NEXT i
					GetFiles(spath)
				ENDIF
			CASE w1_m2: ' exit
				run = 0
		ENDSELECT
ENDSELECT
RETURN 0
ENDSUB

SUB FolderRequest(hWnd:UINT, title:POINTER, dir:POINTER, initial:POINTER, flags:UINT),INT
DEF r = FALSE:INT
DEF buffer[261]:ISTRING
DEF item_list:UINT
BROWSEINFO bi
RtlZeroMemory(&bi, LEN(bi))
bi.hOwner = hWnd
bi.lpszTitle = title
bi.ulFlags = flags
IF flags = 0 THEN bi.ulFlags = BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_DONTGOBELOWDOMAIN
bi.lpfn = &BrowseFolderCallback
bi.lParam = initial
item_list = SHBrowseForFolder(&bi)
IF item_list
	IF SHGetPathFromIDList(item_list, &buffer)
		IF MID$(buffer,LEN(buffer),1) <> "\\"
			#<STRING>dir = buffer + "\\"
		ELSE
			#<STRING>dir = buffer
		ENDIF
		r = TRUE
	ENDIF
	CoTaskMemFree(item_list)
ENDIF
RETURN r
ENDSUB

SUB BrowseFolderCallback(hWnd:UINT, uMsg:UINT, lParam:UINT, lpData:UINT),INT
SELECT uMsg
	CASE BFFM_INITIALIZED
		SendMessageA( hWnd, BFFM_SETSELECTION, TRUE, lpData )
	CASE BFFM_VALIDATEFAILED
		RETURN 1
ENDSELECT
RETURN 0
ENDSUB

SUB GetFiles(path:STRING)
DEF dir:INT
DEF filename = "", size$:STRING
DEF size = 0:UINT64

handle[cd] = tvInsertItem(w1,TView,path,handle[cd-1])
dir = FINDOPEN(path + "*.*")
IF (dir)
	WHILE (dir)
		filename = *<WIN32_FIND_DATA>dir.cFileName
		IF (*<WIN32_FIND_DATA>dir.dwFileAttributes & @FILE_DIRECTORY)
			IF (filename = ".") OR (filename = "..")
				filename = "0"
			ELSE
				cd++
				dSize[cd] = 0
				fSize[cd] = 0
				GetFiles(path + filename + "\\")
			ENDIF
		ELSE
			size = *<WIN32_FIND_DATA>dir.nFileSizeLow | (*<WIN32_FIND_DATA>dir.nFileSizeHigh << 32)
			dSize[cd] += size
			fSize[cd] += size
		ENDIF
		filename = FINDNEXT(dir)
		IF (*<WIN32_FIND_DATA>dir.cFileName[0] = "")
			FINDCLOSE(dir)
			dir = 0
		ENDIF
	ENDWHILE
	size$ = "(" + LTRIM$(USING("%q###,###,###,###,###",dSize[cd])) + ") - "
	IF fSize[cd] <> dSize[cd] THEN size$ += "(" + LTRIM$(USING("%q###,###,###,###,###",fSize[cd])) + ") - "
	IF cd > 1
		size$ += MID$(path,LEN(spath)+1)
	ELSE
		size$ += spath
	ENDIF
	size$ = MID$(size$,1,LEN(size$)-1)
	tvSetItemText(w1, TView, handle[cd], size$)
	cd--
	fSize[cd,1] += fSize[cd+1,1]
ENDIF
RETURN
ENDSUB