/*//////////   SCRIPT:   ScriptRun v.1.0   //////////*/
/*//////////   WRITTEN BY:   Branko Zivkovic   //////////*/
/*//////////   EMAIL:   barigazy@hotmail.com   //////////*/
(
global srForm, srRCMenu, srSETT, srGUI, srXML
try(srRCMenu.close()) catch()
try(srForm.close()) catch()
dotnet.loadAssembly "system.xml"

local srLVPaths, srLVScripts, srTitle, srTBox, srBtnAdd, srBtnDel, srBtnReload, srBtnEdit, srLblExt, srCBms, srCBmse, srCBmcr
local srFormPos, lvColumnWith = 241, maxItmCount = 20, srMODE = #none, lastUsedMXS, okToShow = true
local shortcutsArr = #(DataPair "ScriptRun" "v.1.0", DataPair "author:" "Branko Živkovic", DataPair "email:" "barigazy@hotmail.com", \
DataPair "Shortcuts" "TITLE BAR", DataPair "LMB" "move dialog", DataPair "MMB" "toggle options", DataPair "RMB" "close script", \
DataPair "Shortcuts" "SEARCH TEXT FIELD", DataPair "Escape" "clear text", DataPair "Tab" "jump to result list", DataPair "Enter" "select text", \
DataPair "Up" "select last list item", DataPair "Down" "select first list item", DataPair "$" "last used script", DataPair "*" "favorites list", \
DataPair "Shortcuts" "SEARCH RESULT LIST", DataPair "Escape" "close list", DataPair "Tab" "jump to text field", DataPair "LMB" "select list item", \
DataPair "DubleClick" "run script", DataPair "Enter" "run script", DataPair "MMB" "open script", DataPair "Ctrl+Enter" "open script", \
DataPair "RMB" "context menu", DataPair "Shift+Enter" "add to favorites", DataPair "Alt+Enter" "remove from favorites")

struct sr_Settings_struct (lvDataArr, locX, locY, ms, mse, mcr, mxsArr, mxsENArr, mxsFav)
struct sr_XML_struct
(
	xmlFile,
	sioDir = dotNetClass "System.IO.Directory",
	sioFile = dotNetClass "System.IO.File",
	sysStr = dotNetClass "System.String",
	fn compareFNames arr str ignoreCase:true multi:true = 
	(
		if multi then (for p in 1 to arr.count where (sysStr.Compare arr[p][2] str ignoreCase) == 0 collect p).count
		else (for p in 1 to arr.count where (sysStr.Compare arr[p] str ignoreCase) == 0 collect p).count
	),
	fn isValidXML file =
	(
		try ((dotNetObject "System.Xml.XmlDocument").Load file == undefined)
		catch (okToShow = false ; ((trimleft ((s=filterstring (getCurrentException()) ":")[s.count]) " ")+" Do you want to edit 'srSettings.xml' ?"))
	),
	fn xmlCreator dnXML: prtNode: tagName: innerTxt: attArr: make:#xmlElement =
	(
		local tag = if make != #xmlComment then (dnXML.createElement tagName) else (dnXML.createComment tagName)
		prtNode.AppendChild tag
		if innerTxt != unsupplied do tag.InnerText = innerTxt
		if attArr != unsupplied do (for i = 1 to attArr.count do tag.SetAttribute attArr[i][1] attArr[i][2]) ; tag
	),
	fn getXMLvalue dnXML: tagName: type: =
	(
		local val = (dnXML.selectNodes tagName).ItemOf[0].InnerText
		if type != unsupplied then val as type else val
	),
	fn saveXML xmlFile pX: pY: msExt: mseExt: mcrExt: dirArr: favArr: =
	(
		xmldoc = dotNetObject "System.Xml.XmlDocument"
		sRun = xmlCreator dnXML:xmldoc prtNode:xmldoc tagName:"ScriptRun" \
		attArr:#(#("version","1.0"), #("author","Branko Zivkovic"), #("email","barigazy@hotmail.com"))
		sPaths = xmlCreator dnXML:xmldoc prtNode:sRun tagName:"FolderPaths"
		cmt_sPaths = xmlCreator dnXML:xmldoc prtNode:sPaths tagName:"Child elements of the *FolderPaths* element tags (<fp_0 ... />, <fp_1 .../> etc.)" make:#xmlComment
		for i = 1 to dirArr.count do
		(
			fpe = xmlCreator dnXML:xmldoc prtNode:sPaths tagName:("fp_" + ((i-1) as String)) \
			attArr:#(#("path", dirArr[i][2]), #("use_subfolders", (dirArr[i][1] as String)))
		)
		sSett = xmlCreator dnXML:xmldoc prtNode:sRun tagName:"ScriptSettings"
		sLocX = xmlCreator dnXML:xmldoc prtNode:sSett tagName:"location_x" innerTxt:(pX as String)
		sLocY = xmlCreator dnXML:xmldoc prtNode:sSett tagName:"location_y" innerTxt:(pY as String)
		sMS = xmlCreator dnXML:xmldoc prtNode:sSett tagName:"use_ms" innerTxt:(msExt as String)
		sMSE = xmlCreator dnXML:xmldoc prtNode:sSett tagName:"use_mse" innerTxt:(mseExt as String)
		sMCR = xmlCreator dnXML:xmldoc prtNode:sSett tagName:"use_mcr" innerTxt:(mcrExt as String)
		sFav = xmlCreator dnXML:xmldoc prtNode:sRun tagName:"FavoriteScripts"
		cmt_sFav = xmlCreator dnXML:xmldoc prtNode:sFav tagName:"Child elements of the *FavoriteScripts* element tags (<fs_0 ... </fs_0>, <fs_1 ... </fs_1> etc.)" make:#xmlComment
		if favArr.count != 0 do
		(
			favArr = for s in favArr where sioFile.Exists s collect s
			if favArr.count != 0 do (for i = 1 to favArr.count do xmlCreator dnXML:xmldoc prtNode:sFav tagName:("fs_" + ((i-1) as String)) innerTxt:(favArr[i]))
		)
		xmldoc.Save xmlFile
	),
	fn loadXML xmlFile = if (v=isValidXML xmlFile) != true then (if queryBox v title:"srSettings.xml Error Message" beep:false do edit xmlFile) else 
	(
		local lvItms = #(), xpos, ypos, useMS, useMSE, useMCR, mxsFiles = #(), mxsFilesEN = #(), mxsFavorites = #()
		xmldoc = dotNetObject "System.Xml.XmlDocument"
		sioSOpt = dotNetClass "System.IO.SearchOption"
		xmldoc.Load xmlFile
		fp = xmldoc.selectNodes "//FolderPaths/*"
		if fp.count == 0 then lvItms = #(#(false, (getDir #scripts))) else
		(
			for i = 0 to fp.count-1 where fp.ItemOf[i].Name == ("fp_" + i as String) do
			(
				fpc = xmldoc.selectNodes ("//fp_" + i as String + "/@path | //fp_" + i as String + "/@use_subfolders")
				if lvItms.count != 0 then 
				(
					if (sioDir.Exists (fpc.ItemOf[0].Value) and (compareFNames lvItms (fpc.ItemOf[0].Value)) != 1) do 
					append lvItms #(fpc.ItemOf[1].Value as BooleanClass, fpc.ItemOf[0].Value)
				)
				else 
				(
					if sioDir.Exists (fpc.ItemOf[0].Value) do 
					append lvItms #(fpc.ItemOf[1].Value as BooleanClass, fpc.ItemOf[0].Value)
				)
			)
		)
		xpos = getXMLvalue dnXML:xmldoc tagName:"//location_x" type:Integer --or "//ScriptSettings/location_X"
		ypos = getXMLvalue dnXML:xmldoc tagName:"//location_y" type:Integer
		useMS = getXMLvalue dnXML:xmldoc tagName:"//use_ms" type:BooleanClass
		useMSE = getXMLvalue dnXML:xmldoc tagName:"//use_mse" type:BooleanClass
		useMCR = getXMLvalue dnXML:xmldoc tagName:"//use_mcr" type:BooleanClass
		if lvItms.count != 0 do
		(
			stateArr = #(useMS, useMSE, useMCR)
			extArr = #("*.ms", "*.mse", "*.mcr")
			for i = 1 to lvItms.count do
			(
				filtOpt = if lvItms[i][1] then sioSOpt.AllDirectories else sioSOpt.TopDirectoryOnly
				for s = 1 to 3 where stateArr[s] do join mxsFiles (sioDir.GetFiles lvItms[i][2] extArr[s] filtOpt)
			)
			mxsFiles = makeUniqueArray mxsFiles
			mxsFilesEN = for f in mxsFiles collect #(getFilenameFile f, toLower (trimleft (getFilenameType f) "."))
			fs = xmldoc.selectNodes "//FavoriteScripts/*"
			if fs.count != 1 do
			(
				for i = 0 to fs.count-1 where fs.ItemOf[i].Name == ("fs_" + i as String) do
				(
					fsc = getXMLvalue dnXML:xmldoc tagName:("//fs_" + i as String)
					if mxsFavorites.count == 0 then (if sioFile.Exists fsc do append mxsFavorites fsc)
					else (if sioFile.Exists fsc and (compareFNames mxsFavorites fsc multi:false) != 1 do append mxsFavorites fsc)					
				)
			)
			srSETT = sr_Settings_struct lvDataArr:lvItms locX:xpos locY:ypos ms:useMS mse:useMSE mcr:useMCR mxsArr:mxsFiles mxsENArr:mxsFilesEN mxsFav:mxsFavorites
		)
	),
	on create do
	(
		xmlFile = getdir #expression + "\\srSettings.xml"
		if sioFile.Exists xmlFile then loadXML xmlFile else
		(
			local posX = ((dotNetClass "Screen").PrimaryScreen.WorkingArea.Width/2) - 120
			local posY = ((dotNetClass "Screen").PrimaryScreen.WorkingArea.Height/2) - 11
			saveXML xmlFile pX:posX pY:posY msExt:true mseExt:true mcrExt:false dirArr:#(#(false, (getDir #scripts))) favArr:#()
			loadXML xmlFile
		)
	)
)
struct sr_GUI_struct
(
	fn defColor r g b = ((dotNetClass "System.Drawing.Color").FromArgb r g b),
	fn defSize x y = (dotNetObject "System.Drawing.Size" x y),
	fn defPoint x y = (dotNetObject "System.Drawing.Point" x y),
	fn defLVItem itm = (dotNetObject "ListViewItem" itm),
	C1 = (defColor 25 25 25), C2 = (defColor 170 170 170), C3 = (defColor 60 60 60), C4 = (defColor 230 230 230),
	C5 = (defColor 40 40 40), C6 = (defColor 51 153 255), C7 = (defColor 86 86 86), C8 = (defColor 150 10 10),
	C9 = (defColor 200 200 200), C10 = (defColor 135 185 235), C11 = (defColor 135 185 115), C12 = (defColor 235 115 115),
	F1 = (dotNetObject "System.Drawing.Font" "Tahoma" 7 ((dotNetClass "System.Drawing.FontStyle").bold)),
	F2 = (dotNetObject "System.Drawing.Font" "Impact" 12 ((dotNetClass "System.Drawing.FontStyle").italic)),
	F3 = (dotNetObject "System.Drawing.Font" "Tahoma" 8.5),
	mapped fn srDispose gdiObjs = (gdiObjs.Dispose),
	fn sortByName arr1 arr2 =
	(
		local first = arr1[1], second = arr2[1]
		case of (
			(first < second): -1
			(first > second): 1
			default:0
		)
	),
	fn findFile arr1 arr2 str =
	(
		local idx = (for i in 1 to arr1.count where (arr1[i][1] == str) collect i)
		if idx.count != 0 then (idx=idx[1] ; if srXML.sioFile.Exists arr2[idx] do arr2[idx]) else undefined
	),
	fn isFavorites arr str =
	(
		local tmpArr = for f in arr collect getFilenameFile f
		findItem tmpArr str != 0
	),
	fn logoTitle dnCtrl =
	(
		local cr = dnCtrl.ClientRectangle, crX = cr.x, crY = cr.y, crW = cr.Width, crH = cr.Height
		local srTempFile = (dotNetClass "System.IO.Path").GetTempFileName()
		local srImg = (dotNetClass "System.Drawing.Imaging.ImageFormat").png
		local srLogoBMP = dotNetObject "System.Drawing.Bitmap" crW crH
		local srGraph = (dotNetClass "System.Drawing.Graphics").FromImage srLogoBMP
		srGraph.SmoothingMode = srGraph.SmoothingMode.AntiAlias
		srGraph.Clear (dotNetClass "System.Drawing.Color").Transparent
		local srPen = dotNetObject "System.Drawing.Pen" C4 2
		local srBrushBlue = dotNetObject "System.Drawing.SolidBrush" C6
		local srRectC = (dotNetObject "System.Drawing.Rectangle" 204 2 10 10)
		srGraph.FillEllipse srBrushBlue srRectC
		srGraph.DrawEllipse srPen srRectC
		srGraph.DrawLine srPen (defPoint 205 16) (defPoint 207 11)
		srGraph.DrawImage srLogoBMP cr
		srDispose #(srBrushBlue, srPen, srGraph)
		srLogoBMP.Save srTempFile srImg
		deletefile srTempFile ; srLogoBMP
	),
	fn defForm dnForm x: y: =
	(
		dnForm.BackColor = C1
		dnForm.ClientSize = defSize 245 22
		dnForm.ShowInTaskbar = dnForm.Tag = false
		dnForm.StartPosition = dnForm.StartPosition.Manual
		dnForm.DesktopLocation = defPoint x y
		dnForm.FormBorderStyle = dnForm.FormBorderStyle.None
	),
	fn defCheckBox dnCBox x: y: check: = 
	(
		dnCBox.Size = defSize 14 14
		dnCBox.Location = defPoint x y
		dnCBox.Checked = check
	),
	fn defTextBox dnTBox =
	(
		dnTBox.Font = F1
		dnTBox.BackColor = C3
		dnTBox.ForeColor = C4
		dnTBox.Multiline = false
		dnTBox.Size = defSize 197 17
		dnTBox.Location = defPoint 4 3
		dnTBox.BorderStyle = dnTBox.BorderStyle.None
		dnTBox.AcceptsTab = dnTBox.AcceptsReturn = dnTBox.AutoSize = true
	),
	fn defLbl dnLbl =
	(
		dnLbl.Font = F2
		dnLbl.Text = "S.R."
		dnLbl.BackColor = C3
		dnLbl.ForeColor = C6
		dnLbl.Size = defSize 241 18
		dnLbl.Location = defPoint 2 2
		dnLbl.TextAlign = dnLbl.TextAlign.MiddleRight
		dnLbl.BackgroundImageLayout = dnLbl.BackgroundImageLayout.Center
		dnLbl.BackgroundImage = logoTitle dnLbl
		srTBox = dotNetObject "TextBox" ; defTextBox srTBox
		dnLbl.Controls.Add srTBox
	),
	fn defBtnLbl dnBtnLbl w: h: x: y: ms: mse: mcr: txt: =
	(
		dnBtnLbl.Font = F1
		dnBtnLbl.Text = txt
		dnBtnLbl.Visible = false
		dnBtnLbl.BackColor = C3
		dnBtnLbl.ForeColor = C2
		dnBtnLbl.Size = defSize w h
		dnBtnLbl.Location = defPoint x y
		dnBtnLbl.BorderStyle = dnBtnLbl.BorderStyle.FixedSingle
		if w != 241 then
		(
			dnBtnLbl.Cursor = (dotNetClass "Cursors").Hand
			dnBtnLbl.TextAlign = dnBtnLbl.TextAlign.MiddleCenter
			dotNet.addEventHandler dnBtnLbl "MouseHover" (fn mh s e = (s.ForeColor = srGUI.C4))
			dotNet.addEventHandler dnBtnLbl "MouseDown" (fn md s e = (s.BackColor = srGUI.C5))
			dotNet.addEventHandler dnBtnLbl "MouseLeave" (fn ml s e = (s.ForeColor = srGUI.C2 ; s.BackColor = srGUI.C3))
		)
		else
		(
			dnBtnLbl.TextAlign = dnBtnLbl.TextAlign.MiddleLeft
			srCBms = dotNetObject "CheckBox" ; defCheckBox srCBms x:103 y:1 check:ms
			srCBmse = dotNetObject "CheckBox" ; defCheckBox srCBmse x:147 y:1 check:mse
			srCBmcr = dotNetObject "CheckBox" ; defCheckBox srCBmcr x:193 y:1 check:mcr
			local cbArr = #(srCBms, srCBmse, srCBmcr)
			fn checkState s e =
			(
				case s of (
					(srCBms): (if not srCBmse.Checked and not srCBmcr.Checked do s.Checked = true)
					(srCBmse): (if not srCBms.Checked and not srCBmcr.Checked do s.Checked = true)
					(srCBmcr): (if not srCBms.Checked and not srCBmse.Checked do s.Checked = true)
				)
			)
			for cb in cbArr do (dotNet.addEventHandler cb "CheckedChanged" checkState)
			dnBtnLbl.Controls.addRange cbArr
		)
	),	
	fn setFormMaxHeight lv = (lv.Location.y+lv.Height+2),
	fn autoResizeColumn lv = (lv.AutoResizeColumn 0 (dotNetClass "ColumnHeaderAutoResizeStyle").ColumnContent ; lv.Columns.Item[0].Width),
	fn lvLimitedHeight dnForm =
	(
		local freeScreenSpace = (dotNetClass "Screen").PrimaryScreen.WorkingArea.Height - dnForm.DesktopLocation.y - 37
		local cnt = (floor (freeScreenSpace as Float / 15)) as Integer
		if cnt < 0 then 0 else cnt
	),
	fn findScript input arr cut:off =
	(
		if cut == on do input = trimLeft input "*"
		local filterArr = for v in 1 to arr.count where matchPattern arr[v][1] pattern:("*" + input + "*") collect arr[v]
		if filterArr.count > 1 do (qSort filterArr sortByName) ; filterArr
	),
	fn collectLVData lv =
	(
		local data = if lv.Items.count != 0 then
		(
			for i in 0 to lv.Items.count - 1 where srXML.sioDir.Exists (lv.Items.Item[i].Text) collect #(lv.Items.Item[i].Checked, lv.Items.Item[i].Text)
		)
		else #(#(false, (getDir #scripts)))
	),
	fn defListView dnListView x: y: bg: fg: arr: =
	(
		dnListView.Font = F1
		dnListView.Width = 241 
		dnListView.BackColor = bg
		dnListView.ForeColor = fg
		dnListView.GridLines = false
		dnListView.Location = defPoint x y
		dnListView.HideSelection = true
		dnListView.View = dnListView.View.Details
		dnListView.HeaderStyle = dnListView.HeaderStyle.None
		case dnListView of (
			(srLVPaths): (
				dnListView.Visible = false
				dnListView.BorderStyle = dnListView.BorderStyle.FixedSingle
				dnListView.ShowItemToolTips = dnListView.LabelEdit = dnListView.FullRowSelect = dnListView.CheckBoxes = dnListView.MultiSelect = true
				dnListView.Columns.Add "Paths" lvColumnWith
			)
			(srLVScripts): (
				dnListView.Height = 0
				dnListView.FullRowSelect = dnListView.MultiSelect = false
				dnListView.BorderStyle = dnListView.BorderStyle.None
				dnListView.Columns.Add "srColumn1" 203
				dnListView.Columns.Add "srColumn2" 38
				dnListView.Columns.Add "srColumn3" 0
			)
		)
	),
	fn adjustLVPathsColumnSize lv arrCnt =
	(
		local lvH = if arrCnt != 0 then
		(
			lvColumnWith = autoResizeColumn lv
			(lv.GetItemRect (0)).Height
		)
		else (lv.Columns.Item[0].Width = lv.Width ; 15)
		lv.Height = case of (
			(arrCnt == 0): lvH
			(arrCnt > 20): if lvColumnWith <= lv.Width then 2 + 20 * lvH else 18 + 20 * lvH
			default: if lvColumnWith <= lv.Width then 2 + arrCnt * lvH else 18 + arrCnt * lvH
		)
	),
	fn adjustLVScriptsColumnSize lv type: =
	(
		case type of (
			(1): (
				if lv.Columns.Item[0].Width != 203 do
				(
					lv.Sorting = lv.Sorting.Ascending
					lv.Columns.Item[0].Width = 203
					lv.Columns.item[1].width = 38
					lv.Columns.item[2].width = 0
				)
			)
			(2): (
				lv.Sorting = lv.Sorting.None
				lv.Columns.Item[0].Width = 0
				lv.Columns.item[1].width = 100
				lv.Columns.item[2].width = 141
			)
		)
	),
	fn showToolTips lv = (for i in 0 to lv.Items.count-1 do lv.Items.Item[i].ToolTipText = lv.Items.Item[i].Text),
	fn minimizeList lv = (lv.Items.Clear() ; lv.Height = 0 ; adjustLVScriptsColumnSize lv type:1 ; srMODE = #none),
	fn randomItemsColor lv =
	(
		for i in 1 to lv.Items.count do
		(
			if mod i 2 != 0 then
			(
				if srXML.sioDir.Exists (lv.Items.Item[i-1].Text) != true then
				(
					lv.Items.Item[i-1].BackColor = C8
					lv.Items.Item[i-1].ForeColor = C4
				)
				else 
				(
					lv.Items.Item[i-1].BackColor = C9
					lv.Items.Item[i-1].ForeColor = C5
				)
			)
			else
			(
				if srXML.sioDir.Exists (lv.Items.Item[i-1].Text) != true then
				(
					lv.Items.Item[i-1].BackColor = C8
					lv.Items.Item[i-1].ForeColor = C4
				)
				else 
				(
					lv.Items.Item[i-1].BackColor = C2
					lv.Items.Item[i-1].ForeColor = C5
				)
			)
		)
		showToolTips lv
	),
	fn fillLVPaths lv arr =
	(
		local lvi = for p in 1 to arr.count collect
		(
			lvItm = defLVItem arr[p][2]
			lvItm.Checked = arr[p][1]
			lvItm
		)
		lv.BeginUpdate()
		lv.Items.Clear()
		lv.Items.addRange lvi
		randomItemsColor lv
		adjustLVPathsColumnSize lv arr.count
		lv.EndUpdate()
		free lvi
	),
	fn fillLVScripts lv arr fav =
	(
		local lvi = for s in 1 to arr.count collect
		(
			lvItm = defLVItem arr[s][1]
			lvItm.UseItemStyleForSubItems = false
			lvSubItm = lvItm.SubItems.add arr[s][2]
			lvItm.ForeColor = lvSubItm.ForeColor = case arr[s][2] of
			(
				("ms"): C10
				("mse"): C12
				("mcr"): C11
			)
			if fav.count != 0 do 
			(
				if isFavorites fav arr[s][1] do 
				(
					lvSubItm.BackColor = C2
					lvSubItm.ForeColor = C5
				)
			)
			lvItm
		)
		lv.BeginUpdate()
		lv.Items.Clear()
		lv.Items.addRange lvi
		adjustLVScriptsColumnSize lv type:1
		lv.Height = if arr.count != 0 then (2 + arr.count * (lv.GetItemRect (0)).Height) else 0
		lv.EndUpdate()
		free lvi
	),
	fn fillLVShortcuts lv arr =
	(
		if lv.Columns.Item[0].Width != 0 do
		(
			local lvi = for n in 1 to arr.count collect
			(
				lvItm = defLVItem ""
				lvItm.UseItemStyleForSubItems = false
				case of (
					(n==1 or n==4 or n==8 or n==16): (
						clr = if n==1 then C2 else if n==4 then C10 else if n==8 then C11 else if n==16 do C12
						lvSubItm = lvItm.SubItems.add arr[n].v1
						lvSubItm.BackColor = clr
						lvSubItm.ForeColor = C5
						lvSubItm = lvItm.SubItems.add arr[n].v2
						lvSubItm.BackColor = clr
						lvSubItm.ForeColor = C5
					)
					(n==2 or n==3): (
						lvSubItm = lvItm.SubItems.add arr[n].v1
						lvSubItm = lvItm.SubItems.add arr[n].v2
					)
					((n>=5 and n<=7) or (n>=9 and n<=15) or (n>=17)): (
						clr = if (n>=5 and n<=7) then C10 else if (n>=9 and n<=15) then C11 else if (n>=17) do C12
						lvSubItm = lvItm.SubItems.add arr[n].v1
						lvSubItm.ForeColor = clr
						lvSubItm = lvItm.SubItems.add arr[n].v2
					)
				)
				lvItm
			)
			lv.BeginUpdate()
			lv.Items.Clear()
			adjustLVScriptsColumnSize lv type:2
			lv.Items.addRange lvi
			lv.Height = if arr.count != 0 then (2 + arr.count * (lv.GetItemRect (0)).Height) else 0
			lv.EndUpdate()
			free lvi	
		)
	)	
)
srXML = sr_XML_struct()
srGUI = sr_GUI_struct()
fn maxHW = (dotNetObject "maxCustomControls.win32HandleWrapper" (dotNetObject "System.IntPtr" (windows.getMaxHWND())))
fn DisableAccel = (enableAccelerators = false) ; fn EnableAccel = (enableAccelerators = true)
fn run_sr_RCMenu lvItm selmxs clickPos: encripted: =
(
	local rcmBtnRun, rcmBtnOpen, rcmBtnFav, rcmBtnArr
	local favTxt = if (lvItm.SubItems.Item[1].BackColor != lvItm.BackColor) then "Remove From Favorites" else "Add To Favorites"
	srRCMenu = dotNetObject "Form"	; srGUI.defForm srRCMenu x:(clickPos.x) y:(clickPos.y)
	rcmBtnRun = dotNetObject "Label" ; srGUI.defBtnLbl rcmBtnRun w:120 h:14 x:2 y:2 txt:"Run Selected Script" ; rcmBtnRun.Tag = selmxs
	if not encripted then
	(
		rcmBtnOpen = dotNetObject "Label" ; srGUI.defBtnLbl rcmBtnOpen w:120 h:14 x:2 y:17 txt:"Open Selected Script" ; rcmBtnOpen.Tag = selmxs
		rcmBtnFav = dotNetObject "Label"	; srGUI.defBtnLbl rcmBtnFav w:120 h:14 x:2 y:32 txt:favTxt ; rcmBtnFav.Tag = #(lvItm,selmxs)
		rcmBtnArr = #(rcmBtnRun, rcmBtnOpen, rcmBtnFav)
		srRCMenu.Tag = srGUI.defSize 124 48
		dotNet.addEventHandler rcmBtnOpen "MouseUp"  (fn rcmBtnOpenMU s e = (edit (s.Tag) ; try(srRCMenu.close()) catch()))
	)
	else
	(
		rcmBtnFav = dotNetObject "Label"	; srGUI.defBtnLbl rcmBtnFav w:120 h:14 x:2 y:17 txt:favTxt ; rcmBtnFav.Tag = #(lvItm,selmxs)
		rcmBtnArr = #(rcmBtnRun, rcmBtnFav)
		srRCMenu.Tag = srGUI.defSize 124 33
	)
	rcmBtnArr.Visible = on
	fn rcmBtnFavMU s e =
	(
		case s.Text of (
			("Add to Favorites"): (
				s.Tag[1].SubItems.Item[1].BackColor = srGUI.C2
				s.Tag[1].SubItems.Item[1].ForeColor = srGUI.C5
				appendIfUnique srSETT.mxsFav s.Tag[2]
			)
			("Remove From Favorites"): (
				s.Tag[1].SubItems.Item[1].BackColor = s.Tag[1].BackColor
				s.Tag[1].SubItems.Item[1].ForeColor = s.Tag[1].ForeColor
				local id = (findItem srSETT.mxsFav s.Tag[2])
				if id != 0 do
				(
					if srTBox.Text[1] != "*" then deleteItem srSETT.mxsFav id else
					(
						local lvH = (srLVScripts.GetItemRect (s.Tag[1].Index)).Height
						deleteItem srSETT.mxsFav id
						s.Tag[1].Remove()
						srLVScripts.Height -= lvH
					)
				)
			)
		)
		try(srRCMenu.close()) catch()
	)
	dotnet.addeventhandler srRCMenu "LostFocus" (fn srRCMenuLF s e = s.Close())
	dotnet.addeventhandler srRCMenu "Load" (fn srRCMenuL s e = (srForm.Tag = true ; s.Size = s.Tag))
	dotnet.addeventhandler srRCMenu "FormClosed" (fn srRCMenuFC s e = (srForm.Tag = false ; srTBox.Focus()))
	dotNet.addEventHandler rcmBtnRun "MouseUp" (fn rcmBtnRunMU s e = (fileIn (lastUsedMXS = s.Tag) ; try(srRCMenu.close()) catch()))
	dotNet.addEventHandler rcmBtnFav "MouseUp" rcmBtnFavMU
	srRCMenu.Controls.addRange rcmBtnArr
	srRCMenu.Show (maxHW())
)

srForm = dotNetObject "Form"	; srGUI.defForm srForm x:(srSETT.locX) y:(srSETT.locY)
srTitle = dotNetObject "Label" ; srGUI.defLbl srTitle
srBtnAdd = dotNetObject "Label"	; srGUI.defBtnLbl srBtnAdd w:120 h:14 x:2 y:22 txt:"Add Folder Path"
srBtnDel = dotNetObject "Label"	; srGUI.defBtnLbl srBtnDel w:120 h:14 x:123 y:22 txt:"Remove Paths"
srBtnEdit = dotNetObject "Label"	; srGUI.defBtnLbl srBtnEdit w:120 h:14 x:2 y:37 txt:"Edit Settings"
srBtnReload = dotNetObject "Label" ; srGUI.defBtnLbl srBtnReload w:120 h:14 x:123 y:37 txt:"Reload Settings"
srLblExt = dotNetObject "Label" ; srGUI.defBtnLbl srLblExt w:241 h:17 x:2 y:52 ms:(srSETT.ms) mse:(srSETT.mse) mcr:(srSETT.mcr) txt:" Script Extensions:         *.ms       *.mse      *.mcr"
srLVPaths = dotNetObject "ListView" ; srGUI.defListView srLVPaths x:2 y:70 bg:(srGUI.C9) fg:(srGUI.C5) arr:(srSETT.lvDataArr)
srLVScripts = dotNetObject "ListView" ; srGUI.defListView srLVScripts x:2 y:20 bg:(srGUI.C3) fg:(srGUI.C2)
srGUI.fillLVPaths srLVPaths srSETT.lvDataArr

local ctrlsArr = #(srBtnAdd, srBtnDel, srBtnEdit, srBtnReload, srLblExt, srLVPaths)
fn srTitleMD s e =
(
	srFormPos = [(mouse.screenpos.x - srForm.DesktopLocation.x), (mouse.screenpos.y - srForm.DesktopLocation.y)]
	case e.Button of (
		(e.Button.Left): s.Cursor = (dotNetClass "Cursors").NoMove2D
		(e.Button.Middle): (s.Cursor = (dotNetClass "Cursors").HSplit ; srTBox.Text = "")
		(e.Button.Right): (
			srTBox.Enabled = true ; s.Focus()
			s.BackColor = srTBox.BackColor = srGUI.C8
			srTBox.Text = "Bye Bye :)"
		)
	)
)
fn srTitleMM s e = (if e.Button == e.Button.Left do srForm.DesktopLocation = srGUI.defPoint (mouse.screenpos.x - srFormPos.x) (mouse.screenpos.y - srFormPos.y))
fn srTitleMU s e =
(
	case e.Button of (
		(e.Button.Left): (maxItmCount = srGUI.lvLimitedHeight srForm)
		(e.Button.Middle): (if srLVPaths.Visible != true then ctrlsArr.Visible = on else ctrlsArr.Visible = off)
		(e.Button.Right): (srForm.Close())
	)
	srFormPos = undefined
	s.Cursor = (dotNetClass "Cursors").Arrow
)
fn srBtnAddMU s e = 
(
	s.BackColor = srGUI.C3
	local newDir = getSavePath caption:"Add Directory Path" initialDir:(getDir #maxroot)
	if newDir != undefined and srXML.sioDir.Exists newDir == true do
	(
		local ListViewItem = srGUI.defLVItem newDir
		ListViewItem.Checked = false
		srLVPaths.Items.Add ListViewItem
		srGUI.adjustLVPathsColumnSize srLVPaths srLVPaths.Items.count
	)
)
fn srBtnDelMU s e = 
(
	s.BackColor = srGUI.C3
	local lvSIArr = for i in srLVPaths.SelectedIndices.count-1 to 0 by -1 collect srLVPaths.SelectedIndices.Item[i]
	for idx in lvSIArr do srLVPaths.Items.RemoveAt (idx)
	srGUI.adjustLVPathsColumnSize srLVPaths srLVPaths.Items.count
	free lvSIArr
)
fn srBtnEditMU s e = (s.BackColor = srGUI.C3 ; if srXML.sioFile.Exists (srXML.xmlFile) do edit srXML.xmlFile)
fn srBtnReloadMU s e =
(
	s.BackColor = srGUI.C3
	if srXML.sioFile.Exists (srXML.xmlFile) do srXML.loadXML srXML.xmlFile
	srGUI.fillLVPaths srLVPaths srSETT.lvDataArr
	srCBms.Checked = srSETT.ms
	srCBmse.Checked = srSETT.mse
	srCBmcr.Checked = srSETT.mcr	
)
fn srTBoxKD s e = 
(
	case (e.keyCode.ToString()) of (
		("Up"): (
			if srLVScripts.Columns.Item[0].Width != 0 and srLVScripts.Height != 0 then 
			(
				srLVScripts.Items.Item[srLVScripts.Items.count-1].Selected = srLVScripts.Items.Item[srLVScripts.Items.count-1].Focused = true
				srLVScripts.Focus()
			) 
			else s.SelectionStart = s.TextLength
		)
		("Down"): (
			if srLVScripts.Columns.Item[0].Width != 0 and srLVScripts.Height != 0 then 
			(
				srLVScripts.Items.Item[0].Selected = srLVScripts.Items.Item[0].Selected = true
				srLVScripts.Focus()
			) 
			else s.SelectionStart = s.TextLength
		)
	)
	if maxItmCount == 0 do (s.Text = "" ; messageBox "Move the dialog up to be able to see search result!" title:"WARNING" beep:false)
)
fn srTBoxKU s e =
(
	case (e.keyCode.ToString()) of (
		("Return"): (s.SelectAll())
		("Escape"): ( s.Text = "" ; srGUI.minimizeList srLVScripts)
		("Up"): (if srLVScripts.Columns.Item[0].Width == 0 or srLVScripts.Height == 0 do s.SelectionStart = s.TextLength)
		("Tab"): (
			if srLVScripts.Columns.Item[0].Width != 0 and srLVScripts.Height != 0 do
			(
				srLVScripts.TopItem.Selected = srLVScripts.TopItem.Focused = true
				srLVScripts.Focus()
			) 
		)
	)
	if maxItmCount != 0 do
	(
		local srFilterArr = #()
		srMODE = case s.Text[1] of (
			("$"): (s.Text = "$" ; s.SelectionStart = s.MaxLength = 1 ; #lastused)
			("*"): (s.MaxLength = 100 ; #favorites)
			("?"): (s.Text = "?" ; s.SelectionStart = s.MaxLength = 1 ; #shortcuts)
			(undefined):(s.MaxLength = 100 ; #none)
			default: (s.MaxLength = 100 ; #search)
		)
		case srMODE of (
			(#lastused): (
				if lastUsedMXS != undefined and srXML.sioFile.Exists lastUsedMXS then
				(
					srFilterArr = #(#(getFilenameFile lastUsedMXS, toLower (trimleft (getFilenameType lastUsedMXS) ".")))
					srGUI.fillLVScripts srLVScripts srFilterArr srSETT.mxsFav
				)
				else srGUI.minimizeList srLVScripts
			)
			(#search): (
				srFilterArr = (srGUI.findScript s.Text srSETT.mxsENArr)
				if srFilterArr.count > maxItmCount do (srFilterArr.count = maxItmCount)
				if srFilterArr.count != 0 then srGUI.fillLVScripts srLVScripts srFilterArr srSETT.mxsFav else srGUI.minimizeList srLVScripts
			)
			(#favorites): (
				if srSETT.mxsFav.count != 0 do
				(
					local extFav = for f in srSETT.mxsFav collect #(getFilenameFile f, toLower (trimleft (getFilenameType f) "."))
					srFilterArr = if s.TextLength >= 2 then (srGUI.findScript s.Text extFav cut:on) else (srGUI.findScript s.Text extFav)
					if srFilterArr.count > maxItmCount do (srFilterArr.count = maxItmCount)
					if srFilterArr.count != 0 then srGUI.fillLVScripts srLVScripts srFilterArr srSETT.mxsFav else srGUI.minimizeList srLVScripts
				)
			)
			(#shortcuts): (srGUI.fillLVShortcuts srLVScripts shortcutsArr)
		)
	)
)
fn srTBoxTC s e = (if s.TextLength == 0 and srLVScripts.Height != 0 do srGUI.minimizeList srLVScripts)
fn srTBoxEC s e = (if s.Enabled != true and srLVScripts.Height != 0 do (s.Text = "" ; srGUI.minimizeList srLVScripts))
fn srLVPathsVC s e = 
(
	if s.Visible != true then 
	(
		srForm.Height = 22
		srTitle.BackColor = srGUI.C3
		srTBox.Enabled = true ; srTBox.Focus()
		srXML.saveXML (srXML.xmlFile) pX:(s.Location.x) pY:(s.Location.y) msExt:(srCBms.Checked) mseExt:(srCBmse.Checked) \
		mcrExt:(srCBmcr.Checked) dirArr:(srGUI.collectLVData s) favArr:(srSETT.mxsFav) ; srXML.loadXML srXML.xmlFile
	)
	else 
	(
		if s.Items.count != srSETT.lvDataArr.count do 
		(
			s.Items.Clear()
			srGUI.fillLVPaths srLVPaths srSETT.lvDataArr
		)
		srForm.Height = srGUI.setFormMaxHeight s
		srTBox.Enabled = false
		srTitle.BackColor = srGUI.C7
	)
)
fn srLVScriptsMD s e =
(
	if s.Columns.Item[0].Width != 0 and e.Button == e.Button.Middle do
	(
		mPos = s.PointToClient (s.MousePosition)
		lvi = s.GetItemAt mPos.x mPos.y
		if lvi != undefined do (lvi.Selected = lvi.Focused = true)
	)
)
fn srLVScriptsMU s e = 
(	
	if srLVScripts.Columns.Item[0].Width == 0 then srTBox.Focus() else
	(
		local focusItm, selScript
		if e.Button != e.Button.Left do
		(
			focusItm = s.FocusedItem
			selScript = srGUI.findFile srSETT.mxsENArr srSETT.mxsArr focusItm.Text
		)
		if selScript != undefined do
		(
			case e.Button of (
				(e.Button.Middle): (if not (matchPattern (getFilenameType selScript) pattern:".mse") do edit selScript)
				(e.Button.Right): (
					if srForm.Tag do try(srRCMenu.close()) catch()
					local checkExt = (matchPattern (getFilenameType selScript) pattern:".mse")
					run_sr_RCMenu focusItm selScript clickPos:(s.mousePosition) encripted:checkExt 
				)
			)
		)
	)
)
fn srLVScriptsMDC s e =
(
	if e.Button == e.Button.Left do
	(
		if srLVScripts.Columns.Item[0].Width == 0 then srTBox.Focus() else
		(
			local selScript = srGUI.findFile srSETT.mxsENArr srSETT.mxsArr s.FocusedItem.Text
			if selScript != undefined do fileIn (lastUsedMXS = selScript)
		)
	)
)
fn srLVScriptsLF s e = 
(
	if s.SelectedIndices.count != 0 do
	(
		local idx = s.SelectedIndices.Item[0]
		if idx != undefined do s.Items.Item[idx].Selected = s.Items.Item[idx].Focused = false
	)
)
fn srLVScriptsKD s e =
(
	case (e.keyCode.ToString()) of (
		("Up"): (
			if (s.FocusedItem == s.Items.Item[0]) do
			(
				s.Items.Item[0].Selected = s.Items.Item[0].Focused = false
				srTBox.Focus()
				srTBox.SelectionStart = srTBox.TextLength
			)
		)
		("Down"): (
			if (s.FocusedItem == s.Items.Item[s.Items.count-1]) do
			(
				s.Items.Item[s.Items.count-1].Selected = s.Items.Item[s.Items.count-1].Focused = false
				srTBox.Focus()
				srTBox.SelectionStart = srTBox.TextLength
			)			
		)
	)
)
fn srLVScriptsKU s e =
(
	case (e.keyCode.ToString()) of (
		("Escape"): (
			srGUI.minimizeList s
			srTBox.Text = ""
			srTBox.Focus()
		)
		("Return"): ( 
			local focusItm = s.FocusedItem
			local selScript = srGUI.findFile srSETT.mxsENArr srSETT.mxsArr focusItm.Text
			if selScript != undefined do
			(
				case of (
					(keyboard.shiftPressed): (
						if (focusItm.SubItems.Item[1].BackColor == focusItm.BackColor) do
						(
							focusItm.SubItems.Item[1].BackColor = srGUI.C2
							focusItm.SubItems.Item[1].ForeColor = srGUI.C5
							appendIfUnique srSETT.mxsFav selScript
						)
					)
					(keyboard.controlPressed): (if not (matchPattern (getFilenameType selScript) pattern:".mse") do edit selScript)
					(keyboard.altPressed): (
						if (focusItm.SubItems.Item[1].BackColor != focusItm.BackColor) do
						(
							focusItm.SubItems.Item[1].BackColor = focusItm.BackColor
							focusItm.SubItems.Item[1].ForeColor = focusItm.ForeColor
							local id = (findItem srSETT.mxsFav selScript)
							if id != 0 do 
							( 
								if srTBox.Text[1] != "*" then deleteItem srSETT.mxsFav id else 
								(
									local lvH = (s.GetItemRect (focusItm.index)).Height
									deleteItem srSETT.mxsFav id
									focusItm.Remove() ; s.Height -= lvH
								)
							)
						)
					)
					default: fileIn (lastUsedMXS = selScript)
				)
			)
		)
		("Tab"): (srTBox.Focus() ; srTBox.SelectionStart = srTBox.TextLength)
	)
)
fn srLV s e = (srForm.Height = srGUI.setFormMaxHeight s)
fn srFormFC s e = 
(
	srXML.saveXML (srXML.xmlFile) pX:(s.Location.x) pY:(s.Location.y) msExt:(srCBms.Checked) mseExt:(srCBmse.Checked) \
	mcrExt:(srCBmcr.Checked) dirArr:(srGUI.collectLVData srLVPaths) favArr:(srSETT.mxsFav)
	(dotNetClass "System.GC").collect() ; gc() ; srForm=undefined ; clearListener()
)
dotnet.addeventhandler srForm "Load" (fn srFormL s e = (s.Height = 22 ; maxItmCount = srGUI.lvLimitedHeight s))
dotnet.addeventhandler srForm "FormClosed" srFormFC
dotNet.addEventHandler srTitle "MouseDown" srTitleMD	
dotNet.addEventHandler srTitle "MouseMove" srTitleMM
dotNet.addEventHandler srTitle "MouseUp" srTitleMU
dotnet.AddEventHandler srTBox "GotFocus" DisableAccel
dotnet.AddEventHandler srTBox "LostFocus" EnableAccel
dotnet.AddEventHandler srTBox "KeyDown" srTBoxKD
dotnet.AddEventHandler srTBox "TextChanged" srTBoxTC
dotnet.AddEventHandler srTBox "EnabledChanged" srTBoxEC
dotnet.AddEventHandler srTBox "KeyUp" srTBoxKU	
dotNet.addEventHandler srBtnAdd "MouseUp" srBtnAddMU
dotNet.addEventHandler srBtnDel "MouseUp" srBtnDelMU
dotNet.addEventHandler srBtnEdit "MouseUp" srBtnEditMU
dotNet.addEventHandler srBtnReload "MouseUp" srBtnReloadMU	
dotnet.AddEventHandler srLVPaths "BeforeLabelEdit" DisableAccel
dotnet.AddEventHandler srLVPaths "AfterLabelEdit" EnableAccel
dotnet.AddEventHandler srLVPaths "ItemSelectionChanged" (fn srLVPathsISC s e = srGUI.randomItemsColor s)
dotnet.AddEventHandler srLVPaths "SizeChanged" srLV
dotnet.AddEventHandler srLVPaths "VisibleChanged" srLVPathsVC
dotnet.AddEventHandler srLVScripts "SizeChanged" srLV
dotnet.AddEventHandler srLVScripts "MouseDown" srLVScriptsMD
dotnet.AddEventHandler srLVScripts "MouseUp" srLVScriptsMU
dotnet.AddEventHandler srLVScripts "MouseDoubleClick" srLVScriptsMDC
dotnet.AddEventHandler srLVScripts "KeyDown" srLVScriptsKD
dotnet.AddEventHandler srLVScripts "KeyUp" srLVScriptsKU
dotnet.AddEventHandler srLVScripts "LostFocus" srLVScriptsLF

srForm.Controls.addRange #(srTitle, srBtnAdd, srBtnDel, srBtnEdit, srBtnReload, srLblExt, srLVPaths, srLVScripts)
if okToShow do srForm.Show (maxHW()) ; ok
)