--	-----------------------------------------------------------------------------------------------------------------------------
--	Supra v1.1 by Light @ 24.03.2006 18:52:55														www.orionflame.com
--	-----------------------------------------------------------------------------------------------------------------------------
--	Development History
--
--	v0.2 	expanding the nodes doesn't randomize the scroll
--			better sorting algorithm
--
--	v0.3 	better data handling
--
--	v0.4 	fast access to scripts & stdscripts folders
--			ability to search inside scripts
--			bold style for directory nodes
--
--	v0.5 	remembers dialog size correctly
--			docks faster
--
--	v0.6		searching inside scripts shows the number of found instances of the searched string
--			shows the number of scripts each directory have
--			auto macro creation
--			complete rewrite
--			filtering scripts
--			new interface

--	v0.7		ability to run scripts

--	v0.8		improved sorting algorithm
--			groups similar scripts based on version & prefix

--	v0.9		ability to save favourite folders

--	v1.0		improved sorting algorithm for version & prefix features
--			more streamlined saving of favourite folders
--			code cleanup & speed optimizations
--			max 9 compatible

--	v1.1		redesigned code for faster performance and clarity
(
	global Supra, toggleSupra, C4; local SupraRC
	
	rollout Supra "Supra v1.1 by Light" width:200 height:600
	(
		checkButton 		vSearch			"S"		 				width:16		height:16 	pos:[3,3]		tooltip:"Search"
		editText			search			""						width:72					pos:[17,3]
		checkButton 		vFilter			"F"		 				width:16		height:16 	pos:[92,3]	tooltip:"Filter"
		editText			filter				""						width:72					pos:[106,3]
		button 			showOptions 		""		 				width:16		height:16 	pos:[181,3]	tooltip:"Options"	images:#(bitmap 14 14 color:((colorMan.getColor #text) * 255), C4.getOptionsMask(), 1, 1, 1, 1, 1)
		imgTag			ghost									width:200	height:1		pos:[0,19]					bitmap:(bitmap 1 1 color:((colorMan.getColor #background) * 255))
		activeXControl	tvdirs			"MSComctlLib.TreeCtrl" 		width:200 	height:18 	pos:[0,22]
		activeXControl	tv 				"MSComctlLib.TreeCtrl" 		width:200 	height:561 	pos:[0,39]
		timer			timeX																		interval:50
		
		struct settings
		(
								--	Settings to be saved
								
			autoLoad,			--	Auto Load option
			autoFocus,			--	Auto Focus option
			dockState,			--	Dialog Dock State
			dialogPos,			--	Dialog Current Position
			dialogSize,			--	Dialog Current Size
			expand,				--	Expand Script Nodes
			expandPath,			--	Expand Path Section
			currentDirectory,		--	Index of the Current Directory
			dirs,					--	Array of Saved Directories
			
								--	Setting NOT to be saved
								
			searched = false,		--	Variable that holds if any search has been done currently
			filtered = false,		--	Variable that holds if any filtering has been done currently
			directoryCount,		--	Number of directories
			scriptCountInDirs,		--	Number of scripts in directories (except the main directory)
			theMax,				--	Variable that holds the number of directories the deepest script has been buried
			newFolder = #(),		--	Array that holds the most recently added directory node and its name
			dirPath,				--	Variable that holds the most recently added directory path
			scripts,				--	Array that holds all the scripts found in the current directory
			cacheArr,			--	Array that holds a slightly different copy of the scripts array
			searchStr = "",		--	Variable that holds the lastly used search string if the search is currently active, else holds an empty string ""
			filterStr = "",			--	Variable that holds the lastly used filter string if the filtering is currently active, else holds an empty string ""
			RMB = false,			--	Variable that holds the current state of the right mouse button click
			numVerPrefix = 0,		--	Number of treeview nodes that are used to prefix or version other scripts
			clr = color 240 0 40,	--	Color of the prefix, version and directories treeview nodes
			isOpen = false,		--	Variable that holds the current state of whether the dialog is open or not
			
			--	Check either search or filter is used (or both). If one or both of them is on, shows only the files that passes the search/filter
			fn searchFilter sourceA sourceB &count = (filterStr == "" or findString sourceA filterStr != undefined) and (searchStr == "" or (count = C4.searchString sourceB searchStr) != 0),
			
			--	Update the title of the tool with the number of scripts, when undocked
			fn updateTitle = if not Supra.dialogBar do Supra.title = "Supra v1.1 by Light : " + (tv.nodes.count - directoryCount - numVerPrefix) as string,
			
			fn dockDialog style save:true =
			(
				if style != #cui_floatable then
				(
					if dockState != style do
					(
						if not Supra.dialogBar do
						(
							for i in Supra.controls do i.pos.y -= 3
							cui.registerDialogBar Supra maxSize:[Supra.width, systemTools.getScreenHeight()] style:#(#cui_dock_vert)
						)
						dockState = style
						tv.size.y = (systemTools.getScreenHeight()) - 74 - (if findItem #(18, 21) tvdirs.size.y != 0 then 18 else 170)
						cui.dockDialogBar Supra style
					)
				)
				else
				(
					for i in Supra.controls do i.pos.y += 3
					cui.unRegisterDialogBar Supra
					Supra.width = dialogSize.x
					if save do dockState = #cui_floatable
					tv.size.y = dialogSize.y - tvdirs.size.y - 21
					dialogPos.y -= 3
					setDialogPos Supra dialogPos
				)
			),
			
			fn expandNodes =
			(
				if tv.nodes.count != 0 then
				(
					if not Supra.dialogBar do setDialogPos Supra [-1000,-1000]
					(for i = 1 to directoryCount collect tv.nodes[i]).expanded = not tv.nodes[1].expanded
					if tv.selectedItem != undefined then tv.selectedItem.ensureVisible() else tv.nodes[1].ensureVisible()
					local WM_HSCROLL = 276
					local SBLEFT = 6
					windows.sendMessage tv.hWnd WM_HSCROLL SBLEFT 0
					if not Supra.dialogBar do setDialogPos Supra dialogPos
					tv.nodes[1].expanded
				)
				else false
			),
			
			fn expandPaths pState =
			(
				tvdirs.enabled = false
				local sign = if pState then 1 else -1
				tvdirs.size.y += 152 * sign
				tv.pos.y += 152 * sign
				tvdirs.scroll = pState
				tvdirs.nodes.clear()
				local index = if pState then currentDirectory else 1
				if pState then for i in dirs[1] do C4.addNode tvdirs i else C4.addNode tvdirs dirs[1][currentDirectory]
				tvdirs.nodes[index].foreColor = clr
				tvdirs.enabled = true
				pState
			),
			
			fn getBaseName str remove:true =
			(
				local chars = "abcdefghijklmnopqrstuvwxyz"
				local sub = if remove then (if str[str.count] == "s" then 3 else 4) else 0
				local subtract = 0, found
				for i = str.count - sub to 1 by -1 while found == undefined where (found = findString chars str[i]) == undefined do subtract += 1
				substring str 1 (str.count - subtract - sub)
			),
			
			fn getCommonName a b char =
			(
				local arr = #(filterString a char, filterString b char)
				local str = "", done = false
				for i = 1 to arr[1].count while not done do (if arr[1][i] != undefined and arr[2][i] != undefined and stricmp arr[1][i] arr[2][i] == 0 then str += arr[1][i] + char else done = true)
				substring a 1 str.count
			),
			
			fn addNewNode nodeName arr =
			(
				if tv.nodes[arr[2]].children == 0 do
				(
					C4.addNode tv tv.nodes[arr[2]].text index:arr[2] color:clr
					tv.nodes[arr[2]].foreColor = clr
				)
				C4.addNode tv nodeName index:arr[2] color:clr
				arr[2]
			),
			
			fn addNewDir dirName dirPath =
			(
				if findItem dirs[2] dirPath == 0 then
				(
					if findItem #(18, 21) tvdirs.size.y != 0 do expandPaths true
					local str = ""; local nodeArr = for i in tvdirs.nodes where getBaseName i.text remove:false == "New Folder" do str += i.text
					local theNum = 1, found = 0
					while found != undefined do
					(
						found = findString str ("(" + theNum as string + ")")
						if found != undefined do theNum += 1
					)
					newFolder[1] = C4.addCount "New Folder" theNum "()" false
					local currentDir = dirs[1][currentDirectory]
					append dirs[1] newFolder[1]
					dirs[1] = C4.sort2 dirs[1]
					local index = findItem dirs[1] newFolder[1]
					insertItem dirPath dirs[2] index
					currentDirectory = findItem dirs[1] currentDir
					local arr = for i = index to tvdirs.nodes.count collect tvdirs.nodes[i].text
					for i = tvdirs.nodes.count to index by -1 do tvdirs.nodes.remove i
					newFolder[2] = (C4.addNode tvdirs newFolder[1]).index
					for i in arr do C4.addNode tvdirs i
					tvdirs.nodes[currentDirectory].foreColor = clr
					tvdirs.nodes[index].selected = true
					tvdirs.startLabelEdit()
				)
				else messageBox "Folder name or path already in the list" title:Supra.title
			),
			
			fn initializeScripts =
			(
				--	Collect all ms and mcr files inside the current directory (mcr should be scanned first because it comes before ms alphabetically)
				scripts = join (C4.getAllFiles dirs[2][currentDirectory] "*.mcr") (C4.getAllFiles dirs[2][currentDirectory] "*.ms")
				scripts = for i in scripts collect substring i (dirs[2][currentDirectory].count + 2) i.count		--	Remove the current directory from every file's path name
				local original = C4.copyArr scripts														--	Create a copy of the scripts array
				scripts = for i in scripts collect substring i 1 (i.count - (if i[i.count] == "s" then 3 else 4))		--	Remove file types from the script names in the scripts array
				scripts = for i in scripts collect C4.lowercase i											--	Lowercase all elements in the scripts array
				local unsorted = C4.copyArr scripts													--	Create a copy of the scripts array before sorting it
				sort scripts																		--	Sort the scripts array
				scripts = C4.reorderArr original unsorted scripts											--	Reorder the original array using the scripts array and the unsorted version
				--	Collect all scripts that are in the root directory, which has only 1 slash (/) in their names
				local root = #(); for i = scripts.count to 1 by -1 where C4.getCharCount scripts[i] "\\" == 1 do (append root scripts[i]; deleteItem scripts i)
				scriptCountInDirs = scripts.count														--	Store the number of scripts excluding the scripts in the root directory
				scripts += C4.reverseArr root														--	Reverse the root array because the scripts are collected starting from the end of the scripts array
				cacheArr = C4.copyArr scripts														--	Create a copy of the scripts array not to recreate it from scratch every time the user searches of filters scripts
				scripts = for i in scripts collect filterString i "\\"											--	Store the number of elements of the largest array of the scripts array
				local theMax = 0; for i in scripts where i.count > theMax do theMax = i.count
				theMax
			),
			
			fn createTVNodes refresh =
			(
				tv.enabled = false
				if not Supra.dialogBar and dialogPos != [0,0] do setDialogPos Supra [-1000,-1000]		--	If the dialog is undocked, move it off screen before starting creating nodes
				local s = timestamp()
				tv.nodes.clear()
				--	If refresh is on, rescan the current directory for scripts else copy cacheArr into the scripts array
				if refresh then theMax = initializeScripts() else (scripts = C4.copyArr cacheArr; scripts = for i in scripts collect (filterString i "\\"))
				local arr = #()
				--	Start creating nodes for root directories which is pretty-straightforward as they are unique in name
				for i = 1 to scriptCountInDirs do
				(
					if (local index = findItem arr scripts[i][1]) != 0 then scripts[i][1] = index
					else
					(
						append arr scripts[i][1]
						scripts[i][1] = (C4.addNode tv scripts[i][1] bold:true).index		--	Replace the element that holds the directory name with the created treeview node
					)
				)
				--	Start from the second directories to the last except the last element which holds the script name. Here loops goes through the same indices for all arrays, like 2 for all arrays and then 3, 4, ...
				for i = 2 to theMax do
				(
					--	Create an array with 2 arrays where the first array holds the name of the folders, and the second holds the corresponding treeview index
					local arr = #(#(), #())
					for f = 1 to scriptCountInDirs where scripts[f].count > i do
					(
						--	If you can find the name of the current element (directory) in the first array of arr, check if they both share the same parent node indices
						if (local index = findItem arr[1] scripts[f][i]) != 0 then
						(
							local v1 = (for k = 1 to i - 1 collect scripts[arr[2][index]][k]) as string		--	Collect all parent indices of the found element in the first array of arr, from the start to i - 1
							local v2 = (for k = 1 to i - 1 collect scripts[f][k]) as string				--	Collect all parent indices of the current element (directory), from the start to i - 1
							--	If the indices of these parents match, then they are from the same directory, so do not create a new node but instead replace the current element (directory) with the found index
							if v1 == v2 then scripts[f][i] = scripts[arr[2][index]][i]
							else
							(
								--	If the indices of these parents do not match, then they are from different directories, so create a new node and replace the current element (directory) with the index of the latest node
								arr[1][index] = scripts[f][i]
								arr[2][index] = f
								scripts[f][i] = (C4.addNode tv scripts[f][i] index:scripts[f][i - 1] bold:true).index
							)
						)
						else
						(
							--	If the current element (directory) can not be found in the first array of arr, create a new node, add the directory name to the first array of arr and the index of the current element to the second
							append arr[1] scripts[f][i]
							append arr[2] f
							scripts[f][i] = (if i == 1 then C4.addNode tv scripts[f][i] bold:true else C4.addNode tv scripts[f][i] index:scripts[f][i - 1] bold:true).index
						)
					)
				)
				directoryCount = tv.nodes.count; numVerPrefix = 0			--	Store the number of treeview nodes, which holds the number of directories so far
				local latest = #("", 0, ""), versionArr = #(), c, ss = 0
				local numChildren = for i = 1 to directoryCount collect 0		--	Create an array holding a value of 0 for each directory
				--	Loop through scripts where ops.searchFilter returns true, which happens either when both search and filter is turned off or when a script can match the criteria of either or both of them
				local charArr = #()
				local chars = #(" ", "-", "_"), n = 1
				for i = 1 to scripts.count do
				(
					local c = scripts[i].count
					if searchFilter scripts[i][c] (dirs[2][currentDirectory] + "/" + cacheArr[i]) &ss do
					(
						local nodeName = if ss != 0 then C4.addCount scripts[i][c] ss "()" searched else scripts[i][c]
						local sameParents = if i <= scriptCountInDirs then (for f = 1 to scripts[i].count - 1 collect scripts[i][f]) as string == latest[3] else true
						if getBaseName scripts[i][c] == latest[1] and sameParents then
						(
							if C4.appendIfNew versionArr (addNewNode nodeName latest) do (append charArr #(" ", ""); numVerPrefix += 1)
						)
						else
						(
							local theName = ""
							for f = 1 to 3 where theName == "" do (theName = getCommonName scripts[i][c] latest[1] chars[n]; if theName == "" do n = if n == 3 then 1 else n + 1)
							if theName != "" and sameParents then
							(
								if C4.appendIfNew versionArr (addNewNode nodeName latest) do (append charArr #(chars[n], " ..."); numVerPrefix += 1)
							)
							else
							(
								local index = (if i <= scriptCountInDirs then C4.addNode tv nodeName index:scripts[i][c - 1] else C4.addNode tv nodeName).index
								latest = #(getBaseName scripts[i][c], index)
								if i <= scriptCountInDirs do latest[3] = (for f = 1 to scripts[i].count - 1 collect scripts[i][f]) as string
							)
						)
						if i <= scriptCountInDirs do for f = 1 to c - 1 do numChildren[scripts[i][f]] += 1
					)
				)
				--	Start changing the names of the directory nodes to show the number of scripts each one currently have in the treeview
				for i = 1 to numChildren.count where numChildren[i] != 0 do tv.nodes[i].text = C4.addCount tv.nodes[i].text numChildren[i] "()" searched
				for i = 1 to versionArr.count do
				(
					local firstChild = getBaseName tv.nodes[versionArr[i]].child.text
					local lastChild = getBaseName tv.nodes[versionArr[i]].child.lastSibling.text
					local nodeName = getCommonName firstChild lastChild charArr[i][1]
					tv.nodes[versionArr[i]].text = C4.addCount ((getBaseName nodeName remove:false) + charArr[i][2]) tv.nodes[versionArr[i]].children "()" false
				)
				--	Remove the directory nodes from the treeview that do not have any children in the treeview as a result of search/filter
				if filterStr != "" or searchStr != "" do for i = directoryCount to 1 by -1 where tv.nodes[i].children == 0 do (tv.nodes.remove i; directoryCount -= 1)
				if expand do expandNodes()												--	Expand nodes if the expand option is on
				updateTitle()
				print (((timestamp()) - s) / 1000.0)
				gc light:true
				if not Supra.dialogBar and dialogPos != [0,0] do setDialogPos Supra dialogPos		--	If the dialog is undocked, move it back to where it was after finishing creating nodes
				tv.enabled = true
			)
		)
		
		local ops = settings false false #cui_floatable [0,0] [200,600] false false 1 #(#("Scripts", "Stdscripts"), #(getDir #scripts, (getDir #maxroot) + "stdplugs/stdscripts"))
		
		on Supra open do
		(
			--	Create the bitmap for showOptions button, and get it's mask from getOptionsMask fn
			showOptions.images = #(bitmap 14 14 color:((colorMan.getColor #text) * 255), C4.getOptionsMask(), 1, 1, 1, 1, 1)
			--	If there is no INI setting present (first time running), use the default settings above (ops array)
			local theOps = execute (getINISetting (getMAXINIFile()) "Light" "Supra")
			if theOps != OK then for i = 1 to 9 do setProperty ops #("autoLoad", "autoFocus", "dockState", "dialogPos", "dialogSize", "expand", "expandPath", "currentDirectory", "dirs")[i] theOps[i] else ops.dirs[2] = for i in ops.dirs[2] collect C4.replaceString i "\\" "/"
			Supra.resized [Supra.width, Supra.height]		--	Call the resized event handler so the controls are properly scaled and placed
			C4.setLayout tvdirs; C4.setLayout tv			--	Set treeview layout to most commonly used features
			ops.createTVNodes true					--	Create treeview nodes from scratch
			--	Dock dialog based on last setting, but first set the dock state to 0, so dockDialog fn doesn't ignore the call with ops.dockState != id condition
			case ops.dockState of
			(
				#cui_dock_left: (ops.dockState = #cui_floatable; ops.dockDialog #cui_dock_left)
				#cui_dock_right: (ops.dockState = #cui_floatable; ops.dockDialog #cui_dock_right)
			)
			if ops.expandPath then ops.expandPaths true else C4.addNode tvdirs ops.dirs[1][ops.currentDirectory] color:ops.clr
			ops.isOpen = true; updateToolbarButtons()
		)
		
		on Supra moved pos do (local dPos = getDialogPos Supra; if dPos.x >= 0 and dPos.y >= 0 do ops.dialogPos = getDialogPos Supra)
		
		--	Let resizing dialog when undocked
		on Supra resized size do
		(
			if ops.dockState == #cui_floatable do
			(
				--	Only resize if the width of the dialog is an even number because there are 2 controls that has to be scaled to the same size
				if mod size.x 2 == 0 then
				(
					ops.dialogSize = size		--	Set the size of the dialog to ops.dialogSize
					if size.x >= 200 then
					(
						--	If the width of the dialog is larger than or equal to 200, scale and position the controls accordingly else set the width of the dialog to 200
						tv.size = [size.x, size.y - (if tvdirs.size.y == 18 then 39 else 191)]
						tvdirs.size.x = size.x
						search.width = filter.width = (size.x / 2) - 32
						vFilter.pos.x = search.pos.x + search.width + 3
						filter.pos.x = vFilter.pos.x + 18
						showOptions.pos.x = size.x - 19
						ghost.width = size.x
					)
					else Supra.width = 200
				)
				else Supra.width = ops.dialogSize.x
			)
		)
		
		--	Position the dialog when first mouse button is hold down on treeview. Dialog must be undocked (ops.dockState = #cui_floatable)
		local leftDown = false, firstPoint = [0,0]
		on tv mouseMove button key x y do (if leftDown and ops.dockState == #cui_floatable and button == 1 do setDialogPos Supra ((getDialogPos Supra) + ([x,y] - firstPoint)))
		
		on tv mouseDown button key x y do
		(
			leftDown = true; firstPoint = [x,y]
			if button == 2 and key == 0 do ops.RMB = true
		)
		
		on tv mouseUp button key x y do
		(
			if button == 2 do
			(
				case key of
				(
					0: ops.RMB = false
					1: ops.expand = ops.expandNodes()												--	Shift right click to expand all directory nodes
					2: ops.createTVNodes true														--	Ctrl right click to recreate treeview nodes
					4: if ops.dockState == #cui_floatable do (Supra.width = 200; Supra.height = 600)		--	Alt right click to reset the dialog size
				)
			)
			leftDown = false
		)
		
		on tv nodeClick theNode do
		(
			local theFile = ops.dirs[2][ops.currentDirectory] + "/"
			local arr = filterString theNode.fullPath "/"
			--	Loop through the full path name and remove the number with parenthesis from each one
			for i = 1 to arr.count do theFile += C4.removeCount arr[i] "(" + "/"
			theFile = replace theFile theFile.count 1 ""
			if theNode.children != 0 then
			(
				case of
				(
					--	If a parent node is clicked while shift is pressed, expand/collapse the directory node with all subdirectories
					(keyboard.shiftPressed):
					(
						local arr = C4.getChildrenForward theNode
						for i in arr where i.children != 0 do join arr (C4.getChildrenForward i)
						for i = arr.count to 1 by -1 do arr[i].expanded = not theNode.expanded
						for i = 1 to 3 do theNode.expanded = not theNode.expanded
					)
					--	If a directory node (bold) is clicked, expand/collapse the directory node
					default: if ops.RMB and theNode.bold then (shellLaunch theFile ""; ops.RMB = false) else theNode.expanded = not theNode.expanded
				)
			)
			else
			(
				--	If the parent of a script node (not bold) is a version/prefix node, delete it from the path name
				if theNode.parent != undefined and not theNode.parent.bold do
				(
					theFile = filterString theFile "/"
					deleteItem theFile (theFile.count - 1)
					local str = ""; for i in theFile do str += i + "/"
					theFile = replace str str.count 1 ""
				)
				--	If a script node is right clicked, run the script. If ctrl is pressed, delete the script, else open it
				case of
				(
					(keyboard.controlPressed):
					(
						--	If search mode is active, remove the number with parenthesis from the script name
						local filename = if ops.searched then C4.removeCount theNode.text "(" else theNode.text
						if queryBox ("Are you sure you want to delete " + filename + "?") title:Supra.title do
						(
							local parents = for i in (C4.getParentNodes theNode) collect i.index		--	Collect the indices of all the parent nodes of the selected node
							tv.nodes.remove theNode.index									--	Remove the selected node
							deleteFile theFile												--	Delete the script
							--	Check if any of the parent nodes of the selected node has no children. If found, remove them from the treeview
							local deleted = for i in parents where tv.nodes[i].children == 0 collect (if not tv.nodes[i].bold do ops.numVerPrefix -= 1; tv.nodes.remove i; i)
							--	Loop through other parent nodes that have children and update their name to show the correct number of scripts
							for i in parents where findItem deleted i == 0 and tv.nodes[i].children != 0 do tv.nodes[i].text = C4.addCount tv.nodes[i].text (C4.getNumChildren tv.nodes[i]) "()" true
							ops.updateTitle()
						)
					)
					default: if ops.RMB then fileIn theFile else edit theFile
				)
			)
		)
		
		on tvdirs mouseMove button key x y do (if leftDown and ops.dockState == #cui_floatable and button == 1 do setDialogPos Supra ((getDialogPos Supra) + ([x,y] - firstPoint)))
		
		on tvdirs mouseDown button key x y do
		(
			leftDown = true; firstPoint = [x,y]
			if button == 2 and key == 0 do ops.expandPath = ops.expandPaths (findItem #(18, 21) tvdirs.size.y != 0)
		)
		
		on tvdirs mouseUp button key x y do leftDown = false
		
		on tvdirs nodeClick theNode do
		(
			case of
			(
				(keyboard.controlPressed):
				(
					--	If ctrl is pressed and the selected directory is not the current directory, remove it from the favourites list
					if tvdirs.nodes.count > 1 and theNode.index != ops.currentDirectory do
					(
						local active = ops.dirs[1][ops.currentDirectory]
						for i = 1 to 2 do deleteItem ops.dirs[i] theNode.index; tvdirs.nodes.remove theNode.index
						ops.currentDirectory = findItem (for i in tvdirs.nodes collect i.text) active
					)
				)
				default:
				(
					--	If a node is clicked ...
					if theNode.index != ops.currentDirectory do
					(
						tvdirs.nodes[ops.currentDirectory].foreColor = black		--	Make the previously selected directory node black
						theNode.foreColor = ops.clr							--	Make the current directory node blue
						ops.currentDirectory = theNode.index					--	Set ops.currentDirectory to the index of the currently selected directory node
						ops.createTVNodes true							--	Recreate treeview nodes
					)
				)
			)
		)
		
		on tvdirs beforeLabelEdit cancel do enableAccelerators = false		--	Turn off max hotkeys
		
		on tvdirs afterLabelEdit cancel str do
		(
			local currentDirectory = ops.dirs[1][ops.currentDirectory]
			for i = 1 to 2 do deleteItem ops.dirs[i] ops.newFolder[2]
			if findItem ops.dirs[1] str == 0 then
			(
				append ops.dirs[1] str
				ops.dirs[1] = C4.sort2 ops.dirs[1]
				local index = findItem ops.dirs[1] str
				insertItem ops.dirPath ops.dirs[2] index
				ops.currentDirectory = findItem ops.dirs[1] currentDirectory
				tvdirs.nodes.clear()
				for i in ops.dirs[1] do C4.addNode tvdirs i
				tvdirs.nodes[ops.currentDirectory].foreColor = ops.clr
				tvdirs.nodes[index].selected = true
			)
			else
			(
				tvdirs.nodes.remove ops.newFolder[2]
				ops.currentDirectory = findItem ops.dirs[1] currentDirectory
			)
		)
		
		on vSearch changed pState do
		(
			if pState then setFocus search
			else
			(
				search.text = ops.searchStr = ""
				if keyboard.controlPressed do (filter.text = ops.filterStr = ""; ops.filtered = (vFilter.checked = false))
				if ops.searched do ops.createTVNodes false		--	If a search has been done, create treeview nodes using cacheArr
				ops.searched = false							--	Set search state to false
				setFocus tv
			)
		)
		
		on search entered txt do
		(
			if txt != "" and txt != ops.searchStr do
			(
				ops.searchStr = txt = (search.text = C4.removeInvalidChars txt)		--	Remove invalid characters from txt for convenience
				ops.createTVNodes false										--	Create treeview nodes without rescanning for scripts by using cacheArr
				vSearch.checked = true
				ops.searched = true
			)
		)
		
		on vFilter changed pState do
		(
			if pState then setFocus filter
			else
			(
				filter.text = ops.filterStr = ""
				if keyboard.controlPressed do (search.text = ops.searchStr = ""; ops.searched = (vSearch.checked = false))
				if ops.filtered do ops.createTVNodes false		--	If a filtering has been done, create treeview nodes using cacheArr
				ops.filtered = false							--	Set filter state to false
				setFocus tv
			)
		)
		
		on filter entered txt do
		(
			if txt != "" and txt != ops.filterStr do
			(
				ops.filterStr = txt = (filter.text = C4.removeInvalidChars txt)			--	Remove invalid characters from txt for convenience
				ops.createTVNodes (not (ops.filtered = vFilter.checked = true))		--	Create treeview nodes without rescanning for scripts by using cacheArr
			)
		)
		
		on showOptions pressed do popupMenu SupraRC pos:(showOptions.pos + [16,-1]) rollout:Supra
		
		local focused = false
		on timeX tick do
		(
			--	If mouse is inside the unfocused dialog and autofocus option is turned on, set focus to dialog. If search or filter is on, set focus to search or filter edit text
			if C4.isMouseInside Supra [Supra.width, Supra.height] [0, 7, 0, 26] then
			(
				if not focused and ops.autoFocus do \
					if vSearch.checked or vFilter.checked then (if not vFilter.checked then setFocus search else if not vSearch.checked then setFocus filter else setFocus tv) else setFocus tv
				focused = true
			)
			else focused = false
		)
		
		on Supra close do
		(
			if Supra.dialogBar do ops.dockDialog #cui_floatable save:false
			local dPos = getDialogPos Supra; if dPos.x >= 0 and dPos.y >= 0 do ops.dialogPos = dPos
			local arr = #(ops.autoLoad, ops.autoFocus, ops.dockState, ops.dialogPos, ops.dialogSize, ops.expand, ops.expandPath, ops.currentDirectory, ops.dirs)
			setINISetting (getMAXINIFile()) "Light" "Supra" (arr as string)
			ops.isOpen = false; updateToolbarButtons()
		)
	)
	
	rcMenu SupraRC
	(
		fn dock0 = Supra.ops.dockState != #cui_floatable; fn dock1 = Supra.ops.dockState == #cui_floatable or Supra.ops.dockState == #cui_dock_left; fn dock2 = Supra.ops.dockState == #cui_floatable or Supra.ops.dockState == #cui_dock_right
		
		menuItem 		addFolder 		"Add Folder"
		seperator 		s01
		menuItem 		autoLoad 		"Auto Load"		checked:Supra.ops.autoLoad
		menuItem 		autoFocus 		"Auto Focus"		checked:Supra.ops.autoFocus
		menuItem 		dockLeft 			"Dock Left" 		filter:dock2
		menuItem 		dockRight 		"Dock Right" 		filter:dock1
		menuItem 		undockDialog		"Float" 			filter:dock0
		seperator 		s02
		menuItem 		quit 				"Exit"
		
		on addFolder picked do if (Supra.ops.dirPath = getSavePath initialDir:(C4.replaceString Supra.ops.dirs[2][Supra.ops.currentDirectory] "/" "\\")) != undefined do (Supra.ops.dirPath = C4.replaceString Supra.ops.dirPath "\\" "/"; Supra.ops.addNewDir str Supra.ops.dirPath)
		on autoLoad picked do Supra.ops.autoLoad = not Supra.ops.autoLoad
		on autoFocus picked do Supra.ops.autoFocus = not Supra.ops.autoFocus
		on dockLeft picked do Supra.ops.dockDialog #cui_dock_left
		on dockRight picked do Supra.ops.dockDialog #cui_dock_right
		on undockDialog picked do Supra.ops.dockDialog #cui_floatable
		on quit picked do (if Supra.ops.dockState != #cui_floatable do Supra.ops.dockDialog #cui_floatable save:false; destroyDialog Supra)
	)
	--registerRightClickMenu supraRC
	
	fn toggleSupra override = C4.toggleDialog "Supra" SupraRC override
	if C4 != undefined and classOf C4 == structDef and not C4.macroExists "Production Tools" "Supra" do macros.new "Production Tools" "Supra" "Supra" "Supra" " global Supra, toggleSupra\n on isChecked return Supra.ops.isOpen\n on execute do toggleSupra true"
	toggleSupra false
)