
	----------------------------------------------------------------------
	-- Leatrix Sounds 8.1.02 (9th April 2019, www.leatrix.com)
	----------------------------------------------------------------------

	-- Create local table
	local LeaSoundsLC = {}

	-- Version
	LeaSoundsLC["AddonVer"] = "8.1.02"
	LeaSoundsLC["RestartReq"] = true

	-- If client restart is required and has not been done, show warning and quit
	if LeaSoundsLC["RestartReq"] then
		local metaVer = GetAddOnMetadata("Leatrix_Sounds", "Version")
		if metaVer and metaVer ~= LeaSoundsLC["AddonVer"] then
			C_Timer.After(1, function()
				print("NOTICE!|nYou must fully restart your game client before you can use this version of Leatrix Sounds.")
			end)
			return
		end
	end

	-- Create locals
	local void, Leatrix_Sounds = ...
	local L = Leatrix_Sounds.L
	local frameWidth = 725
	local showingPanel = "SoundKitBrowser"

	----------------------------------------------------------------------
	-- L00: Functions
	----------------------------------------------------------------------

	-- Print text
	function LeaSoundsLC:Print(text)
		DEFAULT_CHAT_FRAME:AddMessage(L[text], 1.0, 0.85, 0.0)
	end

	-- Lock and unlock an item
	function LeaSoundsLC:LockItem(item, lock)
		if lock then
			item:Disable()
			item:SetAlpha(0.3)
		else
			item:Enable()
			item:SetAlpha(1.0)
		end
	end

	-- Create an editbox
	function LeaSoundsLC:CreateEditBox(frame, parent, width, maxchars, anchor, x, y)

		-- Create editbox
		local eb = CreateFrame("EditBox", nil, parent, "InputBoxTemplate")
		eb:SetPoint(anchor, x, y)
		eb:SetWidth(width)
		eb:SetHeight(24)
		eb:SetFontObject("GameFontNormal")
		eb:SetTextColor(1.0, 1.0, 1.0)
		eb:SetAutoFocus(false) 
		eb:SetMaxLetters(maxchars) 
		eb:SetScript("OnEscapePressed", eb.ClearFocus)
		eb:SetScript("OnEnterPressed", eb.ClearFocus)

		-- Add editbox border and backdrop
		eb.f = CreateFrame("FRAME", nil, eb)
		eb.f:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = false, tileSize = 16, edgeSize = 16, insets = { left = 5, right = 5, top = 5, bottom = 5 }})
		eb.f:SetPoint("LEFT", -6, 0)
		eb.f:SetWidth(eb:GetWidth()+6)
		eb.f:SetHeight(eb:GetHeight())
		eb.f:SetBackdropColor(1.0, 1.0, 1.0, 0.3)

		return eb

	end

	-- Create a button
	function LeaSoundsLC:CreateButton(name, frame, label, anchor, x, y, height)
		local mbtn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
		mbtn:SetHeight(height)
		mbtn:SetPoint(anchor, x, y)
		mbtn:SetHitRectInsets(0, 0, 0, 0)
		mbtn:SetText(L[label])

		-- Create fontstring and set button width based on it
		mbtn.f = mbtn:CreateFontString(nil, 'ARTWORK', 'GameFontNormal')
		mbtn.f:SetText(L[label])
		mbtn:SetWidth(mbtn.f:GetStringWidth() + 20)

		-- Set skinned button textures
		mbtn:SetNormalTexture("Interface\\AddOns\\Leatrix_Sounds\\Leatrix_Sounds.blp")
		mbtn:GetNormalTexture():SetTexCoord(0.5, 1, 0, 1)
		mbtn:SetHighlightTexture("Interface\\AddOns\\Leatrix_Sounds\\Leatrix_Sounds.blp")
		mbtn:GetHighlightTexture():SetTexCoord(0, 0.5, 0, 1)

		-- Hide the default textures
		mbtn:HookScript("OnShow", function() mbtn.Left:Hide(); mbtn.Middle:Hide(); mbtn.Right:Hide() end)
		mbtn:HookScript("OnEnable", function() mbtn.Left:Hide(); mbtn.Middle:Hide(); mbtn.Right:Hide() end)
		mbtn:HookScript("OnDisable", function() mbtn.Left:Hide(); mbtn.Middle:Hide(); mbtn.Right:Hide() end)
		mbtn:HookScript("OnMouseDown", function() mbtn.Left:Hide(); mbtn.Middle:Hide(); mbtn.Right:Hide() end)
		mbtn:HookScript("OnMouseUp", function() mbtn.Left:Hide(); mbtn.Middle:Hide(); mbtn.Right:Hide() end)

		return mbtn
	end

	-- Create a subheading
	function LeaSoundsLC:MakeTx(frame, title, x, y)
		local text = frame:CreateFontString(nil, 'ARTWORK', 'GameFontNormal')
		text:SetPoint("TOPLEFT", x, y)
		text:SetText(L[title])
		return text
	end

	----------------------------------------------------------------------
	-- L10: Sound Kit Browser
	----------------------------------------------------------------------

	-- Sound Kit Browser Massive Function
	local function MassiveFuncSoundKitBrowser()

		local ListingCount = #Leatrix_Sounds.Sounds

		-- Main function
		function LeaSoundsLC:MainFuncSoundKitBrowser()

			-- Create tables
			local ListData, playlist, searchTable = {}, {}, {}
			local scrollFrame, willPlay, musicHandle, LastPlayed, LastMusicHandle
			local numButtons = 15
			local uframe = CreateFrame("FRAME")

			-- Add titles to track table
			tinsert(Leatrix_Sounds.Sounds, 1, "|cffffd800" .. L["Leatrix Sounds"] .. " " .. LeaSoundsLC["AddonVer"] .. " - " .. L["Sound Kit Browser"])
			tinsert(Leatrix_Sounds.Sounds, 2, "|cffffffaa{" .. ListingCount .. " " .. L["results"] .. "}")
			tinsert(Leatrix_Sounds.Sounds, 3, "|cffffffff")
			tinsert(Leatrix_Sounds.Sounds, 4, "|cffffd800" .. L["Tracks"])

			-- Show list items
			local function UpdateList()
				FauxScrollFrame_Update(scrollFrame, #ListData, numButtons, 16)
				for index = 1, numButtons do
					local offset = index + FauxScrollFrame_GetOffset(scrollFrame)
					local button = scrollFrame.buttons[index]
					button.index = offset
					if offset <= #ListData then
						-- Show track listing
						button:SetText(ListData[offset])
						-- Set width of highlight texture
						if button:GetTextWidth() > frameWidth - 60 then
							button.t:SetSize(frameWidth - 60, 16)
						else
							button.t:SetSize(button:GetTextWidth(), 16)
						end
						-- Show the button
						button:Show()
						-- Hide highlight bar texture by default
						button.s:Hide()
						-- Hide highlight bar if the button is a heading
						if strfind(button:GetText(), "|c") then button.t:Hide() end
						-- Show last played track highlight bar texture 
						if LastPlayed == button:GetText() then
							button.s:Show()
						end
						-- Set width of highlight bar
						if button:GetTextWidth() > frameWidth - 60 then
							button.s:SetSize(frameWidth - 60, 16)
						else
							button.s:SetSize(button:GetTextWidth(), 16)
						end
						-- Limit click to label width
						local bWidth = button:GetFontString():GetStringWidth() or 0
						if bWidth > frameWidth - 60 then bWidth = frameWidth - 60 end
						button:SetHitRectInsets(0, 454 - bWidth, 0, 0)
						-- Disable label click movement
						button:SetPushedTextOffset(0, 0)
						-- Disable word wrap and set width
						button:GetFontString():SetWidth(frameWidth - 60)
						button:GetFontString():SetWordWrap(false)
					else
						button:Hide()
					end
				end
			end

			-- Create scroll bar
			scrollFrame = CreateFrame("ScrollFrame", "LeaSoundsSoundKitBrowserScrollFrame", LeaSoundsLC["PageSoundKitBrowser"], "FauxScrollFrameTemplate")
			scrollFrame:SetPoint("TOPLEFT", 0, -32)
			scrollFrame:SetPoint("BOTTOMRIGHT", -30, 52)
			scrollFrame:SetFrameLevel(30)
			scrollFrame:SetScript("OnVerticalScroll", function(self, offset)
				FauxScrollFrame_OnVerticalScroll(self, offset, 16, UpdateList)
			end)

			-- Add stop button
			local stopBtn = LeaSoundsLC:CreateButton("StopSoundKitPlaybackButton", LeaSoundsLC["PageSoundKitBrowser"], "Stop", "BOTTOMRIGHT", -16, 12, 25)
			stopBtn:Hide(); stopBtn:Show()
			LeaSoundsLC:LockItem(stopBtn, true)
			stopBtn:SetScript("OnClick", function()
				if musicHandle then
					StopSound(musicHandle)
					musicHandle = nil
					-- Hide highlight bars
					LastPlayed = ""
					UpdateList()
				end
				-- Lock button and cancel update script
				LeaSoundsLC:LockItem(stopBtn, true)
				uframe:UnregisterEvent("SOUNDKIT_FINISHED")
				uframe:UnregisterEvent("LOADING_SCREEN_DISABLED")
			end)

			-- Add Switch to File Browser button
			local switchButton = LeaSoundsLC:CreateButton("SwitchToFileBrowserButton", LeaSoundsLC["PageSoundKitBrowser"], "Switch to File Browser", "BOTTOMRIGHT", -16, 10, 25)
			switchButton:Hide(); switchButton:Show()
			switchButton:SetScript("OnClick", function()
				if musicHandle then
					StopSound(musicHandle)
					musicHandle = nil
					-- Hide highlight bars
					LastPlayed = ""
					UpdateList()
				end
				-- Lock stop button, cancel update script and show File Browser
				LeaSoundsLC:LockItem(stopBtn, true)
				uframe:UnregisterEvent("SOUNDKIT_FINISHED")
				uframe:UnregisterEvent("LOADING_SCREEN_DISABLED")
				LeaSoundsLC["PageSoundKitBrowser"]:Hide()
				LeaSoundsLC["PageFileBrowser"]:ClearAllPoints()
				LeaSoundsLC["PageFileBrowser"]:SetPoint(LeaSoundsLC["PageSoundKitBrowser"]:GetPoint())
				LeaSoundsLC["PageFileBrowser"]:Show()
				showingPanel = "FileBrowser"
			end)

			-- Store currently playing track number
			local tracknumber = 1

			-- Function to play a track and show the static highlight bar
			local function PlayTrack()
				-- Play tracks
				if musicHandle then StopSound(musicHandle) end
				local file, soundID = playlist[tracknumber]:match("([^,]+)%#([^,]+)")
				willPlay, musicHandle = PlaySound(soundID, "Master", false, true)
				-- Store its handle for later use
				LastMusicHandle = musicHandle
				LastPlayed = playlist[tracknumber]
				tracknumber = tracknumber + 1
				-- Show static highlight bar
				for index = 1, numButtons do
					local button = scrollFrame.buttons[index]
					local item = button:GetText()
					if item then
						local item, void = item:match("([^,]+)%#([^,]+)")
						if item == file then
							button.s:Show()
						else
							button.s:Hide()
						end
					end
				end
			end

			-- Create editbox for search
			local searchLabel = LeaSoundsLC:MakeTx(LeaSoundsLC["PageSoundKitBrowser"], "Search", 16, -278)
			searchLabel:ClearAllPoints()
			searchLabel:SetPoint("BOTTOMLEFT", 16, 16)

			local sBox = LeaSoundsLC:CreateEditBox("SearchBoxSoundKitBrowser", LeaSoundsLC["PageSoundKitBrowser"], 278, 10, "TOPLEFT", 101, -272)
			sBox:SetMaxLetters(70)
			sBox:ClearAllPoints()
			sBox:SetPoint("LEFT", searchLabel, "RIGHT", 16, 0)

			-- Reposition stop button so its next to the search box
			stopBtn:ClearAllPoints()
			stopBtn:SetPoint("LEFT", sBox, "RIGHT", 10, 0)

			-- Function to show search results
			local function ShowSearchResults()
				-- Get unescaped editbox text
				local searchText = gsub(strlower(sBox:GetText()), '(['..("%^$().[]*+-?"):gsub("(.)", "%%%1")..'])', "%%%1")
				-- Wipe the track listing
				wipe(ListData)
				-- Set the track list heading
				ListData[1] = "|cffffd800" .. L["Leatrix Sounds"] .. " " .. LeaSoundsLC["AddonVer"] .. " - " .. L["Sound Kit Browser"]
				-- Show the subheading only if no search results are being shown
				if searchText == "" then
					ListData = Leatrix_Sounds.Sounds
					UpdateList()
				else
					ListData[2] = ""
				end
				-- Traverse music listing and populate ListData
				if searchText ~= "" then
					tinsert(ListData, "|cffffffff")
					tinsert(ListData, "|cffffd800" .. L["Tracks"])
					local word1, word2, word3, word4, word5 = strsplit(" ", (strtrim(searchText):gsub("%s+", " ")))
					local hash = {}
					local trackCount = 0
					for k = 1, ListingCount + 4 do
						local v = Leatrix_Sounds.Sounds[k]
						if strfind(v, "#") and strfind(strlower(v), word1) then
							if not word2 or word2 ~= "" and strfind(strlower(v), word2) then
								if not word3 or word3 ~= "" and strfind(strlower(v), word3) then
									if not word4 or word4 ~= "" and strfind(strlower(v), word4) then
										if not word5 or word5 ~= "" and strfind(strlower(v), word5) then
											-- Show track
											tinsert(ListData, v)
											trackCount = trackCount + 1
											hash[v] = true
										end
									end
								end
							end
						end
					end
					-- Set results tag
					if trackCount == 1 then
						ListData[2] = "|cffffffaa{" .. trackCount .. " " .. L["result"] .. "}"
					else
						ListData[2] = "|cffffffaa{" .. trackCount .. " " .. L["results"] .. "}"
					end
				end
				-- Refresh the track listing
				UpdateList()
				-- Set track listing to top
				scrollFrame:SetVerticalScroll(0)
			end

			-- When editbox is changed by user, stop playback and show search results
			sBox:HookScript("OnTextChanged", function(self, userInput)
				if userInput then
					if LeaSoundsLC.timer then LeaSoundsLC.timer:Cancel() end
					LeaSoundsLC.timer = C_Timer.NewTimer(0.5, function()
						stopBtn:Click()
						ListData = searchTable
						ShowSearchResults()
					end)
				end
			end)

			-- When enter key is pressed, stop playback and show search results
			sBox:HookScript("OnEnterPressed", function()
				ListData = searchTable
				stopBtn:Click()
				ShowSearchResults()
			end)

			-- Create list items
			scrollFrame.buttons = {}
			for i = 1, numButtons do
				scrollFrame.buttons[i] = CreateFrame("Button", nil, LeaSoundsLC["PageSoundKitBrowser"])
				local button = scrollFrame.buttons[i]

				button:SetSize(470 - 14, 16)
				button:SetNormalFontObject("GameFontHighlightLeft")
				button:SetPoint("TOPLEFT", 16, -6+ -(i - 1) * 16 - 8)

				-- Create highlight bar texture
				button.t = button:CreateTexture(nil, "BACKGROUND")
				button.t:SetPoint("TOPLEFT", button, 0, 0)
				button.t:SetSize(516, 16)

				button.t:SetColorTexture(0.3, 0.3, 0.0, 0.8)
				button.t:SetAlpha(0.7)
				button.t:Hide()

				-- Create last playing highlight bar texture
				button.s = button:CreateTexture(nil, "BACKGROUND")
				button.s:SetPoint("TOPLEFT", button, 0, 0)
				button.s:SetSize(516, 16)

				button.s:SetColorTexture(0.3, 0.4, 0.00, 0.6)
				button.s:Hide()

				button:SetScript("OnEnter", function()
					-- Highlight links only
					if not string.match(button:GetText() or "", "|c") then
						button.t:Show()
					end
				end)

				button:SetScript("OnLeave", function()
					button.t:Hide()
				end)

				button:RegisterForClicks("LeftButtonUp", "RightButtonUp")

				-- Handler for playing next sound kit in playlist
				uframe:SetScript("OnEvent", function(self, event, stoppedHandle)
					if event == "SOUNDKIT_FINISHED" then
						-- Do nothing if stopped sound kit handle doesnt match last played track handle
						if LastMusicHandle and LastMusicHandle ~= stoppedHandle then return end
						-- Reset track number if playlist has reached the end
						if tracknumber == #playlist then tracknumber = 1 end
						-- Play next track
						PlayTrack()
					elseif event == "LOADING_SCREEN_DISABLED" then
						-- Restart player if it stopped between tracks during loading screen
						if playlist and tracknumber and playlist[tracknumber] and not willPlay and not musicHandle then
							tracknumber = tracknumber - 1
							C_Timer.After(0.1, PlayTrack)
						end
					end
				end)

				-- Click handler for track and back button
				button:SetScript("OnClick", function(self, btn)
					if btn == "LeftButton" then
						-- Remove focus from search box
						sBox:ClearFocus()
						-- Get clicked track text
						local item = self:GetText()
						-- Do nothing if its a blank line or informational heading
						if not item or strfind(item, "|c") then return end
						if strfind(item, "#") then
							-- Enable sound if required
							if GetCVar("Sound_EnableAllSound") == "0" then SetCVar("Sound_EnableAllSound", "1") end
							-- Disable music if it's currently enabled
							if GetCVar("Sound_EnableMusic") == "1" then	SetCVar("Sound_EnableMusic", "0") end
							-- Add all tracks to playlist
							wipe(playlist)
							local StartItem = 0
							-- Get item clicked row number
							for index = 1, #ListData do
								local item = ListData[index]
								if self:GetText() == item then StartItem = index end
							end
							-- Add all items from clicked item onwards to playlist
							for index = StartItem, #ListData do
								local item = ListData[index]
								if item then
									if strfind(item, "#") then 
										tinsert(playlist, item)
									end
								end
							end
							-- Add all items up to clicked item to playlist
							for index = 1, StartItem do
								local item = ListData[index]
								if item then
									if strfind(item, "#") then 
										tinsert(playlist, item)
									end
								end
							end
							-- Enable the stop button
							LeaSoundsLC:LockItem(stopBtn, false)
							-- Store information about the track we are about to play
							tracknumber = 1
							LastPlayed = item
							-- Play first track
							PlayTrack()
							-- Play subsequent tracks
							uframe:RegisterEvent("SOUNDKIT_FINISHED")
							uframe:RegisterEvent("LOADING_SCREEN_DISABLED")
							return
						end
					end
				end)

			end

			-- Delete the global scroll frame pointer
			_G.LeaSoundsSoundKitBrowserScrollFrame = nil

			-- Show listing on startup
			ListData = Leatrix_Sounds.Sounds
			UpdateList()

			-- Manage events
			LeaSoundsLC["PageSoundKitBrowser"]:RegisterEvent("PLAYER_LOGOUT")
			LeaSoundsLC["PageSoundKitBrowser"]:RegisterEvent("UI_SCALE_CHANGED")
			LeaSoundsLC["PageSoundKitBrowser"]:SetScript("OnEvent", function(self, event)
				if event == "PLAYER_LOGOUT" then
					-- Stop playing at reload or logout
					if musicHandle then
						StopSound(musicHandle)
					end
				elseif event == "UI_SCALE_CHANGED" then
					-- Refresh list
					UpdateList()
				end
			end)

		end

		----------------------------------------------------------------------
		-- L30: Events
		----------------------------------------------------------------------

		-- Create event frame to run main sound kit browser function
		local eFrame = CreateFrame("FRAME")
		eFrame:RegisterEvent("PLAYER_LOGIN")
		eFrame:SetScript("OnEvent", LeaSoundsLC.MainFuncSoundKitBrowser)

		----------------------------------------------------------------------
		-- L40: Panel
		----------------------------------------------------------------------

		-- Create the panel
		local PageSoundKitBrowser = CreateFrame("Frame", nil, UIParent)

		-- Make it a system frame
		_G["LeaSoundsSoundKitBrowserGlobalPanel"] = PageSoundKitBrowser
		table.insert(UISpecialFrames, "LeaSoundsSoundKitBrowserGlobalPanel")

		-- Set frame parameters
		LeaSoundsLC["PageSoundKitBrowser"] = PageSoundKitBrowser
		PageSoundKitBrowser:SetSize(frameWidth, 308)
		PageSoundKitBrowser:SetScale(1.1)
		PageSoundKitBrowser:Hide()
		PageSoundKitBrowser:SetFrameStrata("FULLSCREEN_DIALOG")
		PageSoundKitBrowser:SetFrameLevel(30)
		PageSoundKitBrowser:SetClampedToScreen(true)
		PageSoundKitBrowser:SetClampRectInsets(550, -550, -200, 200)
		PageSoundKitBrowser:ClearAllPoints()
		PageSoundKitBrowser:SetPoint("CENTER", 0, 0)
		PageSoundKitBrowser:EnableMouse(true)
		PageSoundKitBrowser:SetMovable(true)
		PageSoundKitBrowser:RegisterForDrag("LeftButton")
		PageSoundKitBrowser:SetScript("OnDragStart", PageSoundKitBrowser.StartMoving)
		PageSoundKitBrowser:SetScript("OnDragStop", function()
			PageSoundKitBrowser:StopMovingOrSizing()
			PageSoundKitBrowser:SetUserPlaced(false)
		end)

		-- Add background color
		PageSoundKitBrowser.t = PageSoundKitBrowser:CreateTexture(nil, "BACKGROUND")
		PageSoundKitBrowser.t:SetAllPoints()
		PageSoundKitBrowser.t:SetColorTexture(0.05, 0.05, 0.05, 0.9)

		-- Add textures
		PageSoundKitBrowser.mainTex = PageSoundKitBrowser:CreateTexture(nil, "BORDER")
		PageSoundKitBrowser.mainTex:SetTexture("Interface\\ACHIEVEMENTFRAME\\UI-GuildAchievement-Parchment-Horizontal-Desaturated.png")
		PageSoundKitBrowser.mainTex:SetSize(frameWidth, 273)
		PageSoundKitBrowser.mainTex:SetPoint("TOPRIGHT")
		PageSoundKitBrowser.mainTex:SetVertexColor(0.7, 0.7, 0.7, 0.7)
		PageSoundKitBrowser.mainTex:SetTexCoord(0.09, 1, 0, 1)

		PageSoundKitBrowser.footTex = PageSoundKitBrowser:CreateTexture(nil, "BORDER")
		PageSoundKitBrowser.footTex:SetTexture("Interface\\ACHIEVEMENTFRAME\\UI-GuildAchievement-Parchment-Horizontal-Desaturated.png")
		PageSoundKitBrowser.footTex:SetSize(frameWidth, 48)
		PageSoundKitBrowser.footTex:SetPoint("BOTTOM")
		PageSoundKitBrowser.footTex:SetVertexColor(0.5, 0.5, 0.5, 1.0)

		-- Add close Button
		PageSoundKitBrowser.cb = CreateFrame("Button", nil, PageSoundKitBrowser, "UIPanelCloseButton") 
		PageSoundKitBrowser.cb:SetSize(30, 30)
		PageSoundKitBrowser.cb:SetPoint("TOPRIGHT", 0, 0)

	end

	----------------------------------------------------------------------
	-- L50: File Browser
	----------------------------------------------------------------------

	-- File Browser Massive Function
	local function MassiveFuncFileBrowser()

		local ListingCount = #Leatrix_Sounds.Tracks

		-- Main function
		function LeaSoundsLC:MainFuncFileBrowser()

			-- Create tables
			local ListData, playlist, searchTable = {}, {}, {}
			local scrollFrame, willPlay, musicHandle, LastPlayed
			local numButtons = 15

			-- Add titles to track table
			tinsert(Leatrix_Sounds.Tracks, 1, "|cffffd800" .. L["Leatrix Sounds"] .. " " .. LeaSoundsLC["AddonVer"] .. " - " .. L["File Browser"])
			tinsert(Leatrix_Sounds.Tracks, 2, "|cffffffaa{" .. ListingCount .. " " .. L["results"] .. "}")
			tinsert(Leatrix_Sounds.Tracks, 3, "|cffffffff")
			tinsert(Leatrix_Sounds.Tracks, 4, "|cffffd800" .. L["Tracks"])

			-- Show list items
			local function UpdateList()
				FauxScrollFrame_Update(scrollFrame, #ListData, numButtons, 16)
				for index = 1, numButtons do
					local offset = index + FauxScrollFrame_GetOffset(scrollFrame)
					local button = scrollFrame.buttons[index]
					button.index = offset
					if offset <= #ListData then
						-- Show track listing
						button:SetText(ListData[offset])
						-- Set width of highlight texture
						if button:GetTextWidth() > frameWidth - 60 then
							button.t:SetSize(frameWidth - 60, 16)
						else
							button.t:SetSize(button:GetTextWidth(), 16)
						end
						-- Show the button
						button:Show()
						-- Hide highlight bar texture by default
						button.s:Hide()
						-- Hide highlight bar if the button is a heading
						if strfind(button:GetText(), "|c") then button.t:Hide() end
						-- Show last played track highlight bar texture 
						if LastPlayed == button:GetText() then
							button.s:Show()
						end
						-- Set width of highlight bar
						if button:GetTextWidth() > frameWidth - 60 then
							button.s:SetSize(frameWidth - 60, 16)
						else
							button.s:SetSize(button:GetTextWidth(), 16)
						end
						-- Limit click to label width
						local bWidth = button:GetFontString():GetStringWidth() or 0
						if bWidth > frameWidth - 60 then bWidth = frameWidth - 60 end
						button:SetHitRectInsets(0, 454 - bWidth, 0, 0)
						-- Disable label click movement
						button:SetPushedTextOffset(0, 0)
						-- Disable word wrap and set width
						button:GetFontString():SetWidth(frameWidth - 60)
						button:GetFontString():SetWordWrap(false)
					else
						button:Hide()
					end
				end
			end

			-- Create scroll bar
			scrollFrame = CreateFrame("ScrollFrame", "LeaSoundsFileBrowserScrollFrame", LeaSoundsLC["PageFileBrowser"], "FauxScrollFrameTemplate")
			scrollFrame:SetPoint("TOPLEFT", 0, -32)
			scrollFrame:SetPoint("BOTTOMRIGHT", -30, 52)
			scrollFrame:SetFrameLevel(40)
			scrollFrame:SetScript("OnVerticalScroll", function(self, offset)
				FauxScrollFrame_OnVerticalScroll(self, offset, 16, UpdateList)
			end)

			-- Add stop button
			local stopBtn = LeaSoundsLC:CreateButton("StopFilePlaybackButton", LeaSoundsLC["PageFileBrowser"], "Stop", "BOTTOMRIGHT", -16, 12, 25)
			stopBtn:Hide(); stopBtn:Show()
			LeaSoundsLC:LockItem(stopBtn, true)
			stopBtn:SetScript("OnClick", function()
				if musicHandle then
					StopSound(musicHandle)
					musicHandle = nil
					-- Hide highlight bars
					LastPlayed = ""
					UpdateList()
				end
				-- Lock button
				LeaSoundsLC:LockItem(stopBtn, true)
			end)

			-- Add Switch to Sound Kit Browser button
			local switchButton = LeaSoundsLC:CreateButton("SwitchToSoundKitBrowserButton", LeaSoundsLC["PageFileBrowser"], "Switch to Sound Kit Browser", "BOTTOMRIGHT", -16, 10, 25)
			switchButton:Hide(); switchButton:Show()
			switchButton:SetScript("OnClick", function()
				if musicHandle then
					StopSound(musicHandle)
					musicHandle = nil
					-- Hide highlight bars
					LastPlayed = ""
					UpdateList()
				end
				-- Lock stop button and show sound kit browser
				LeaSoundsLC:LockItem(stopBtn, true)
				LeaSoundsLC["PageFileBrowser"]:Hide()
				LeaSoundsLC["PageSoundKitBrowser"]:ClearAllPoints()
				LeaSoundsLC["PageSoundKitBrowser"]:SetPoint(LeaSoundsLC["PageFileBrowser"]:GetPoint())
				LeaSoundsLC["PageSoundKitBrowser"]:Show()
				showingPanel = "SoundKitBrowser"
			end)

			-- Create editbox for search
			local searchLabel = LeaSoundsLC:MakeTx(LeaSoundsLC["PageFileBrowser"], "Search", 16, -278)
			searchLabel:ClearAllPoints()
			searchLabel:SetPoint("BOTTOMLEFT", 16, 16)

			local sBox = LeaSoundsLC:CreateEditBox("SearchBoxFileBrowser", LeaSoundsLC["PageFileBrowser"], 278, 10, "TOPLEFT", 101, -272)
			sBox:SetMaxLetters(70)
			sBox:ClearAllPoints()
			sBox:SetPoint("LEFT", searchLabel, "RIGHT", 16, 0)

			-- Reposition stop button so its next to the search box
			stopBtn:ClearAllPoints()
			stopBtn:SetPoint("LEFT", sBox, "RIGHT", 10, 0)

			-- Function to show search results
			local function ShowSearchResults()
				-- Get unescaped editbox text
				local searchText = gsub(strlower(sBox:GetText()), '(['..("%^$().[]*+-?"):gsub("(.)", "%%%1")..'])', "%%%1")
				-- Wipe the track listing
				wipe(ListData)
				-- Set the track list heading
				ListData[1] = "|cffffd800" .. L["Leatrix Sounds"] .. " " .. LeaSoundsLC["AddonVer"] .. " - " .. L["File Browser"]
				-- Show the subheading only if no search results are being shown
				if searchText == "" then
					ListData = Leatrix_Sounds.Tracks
					UpdateList()
				else
					ListData[2] = ""
				end
				-- Traverse music listing and populate ListData
				if searchText ~= "" then
					tinsert(ListData, "|cffffffff")
					tinsert(ListData, "|cffffd800" .. L["Tracks"])
					local word1, word2, word3, word4, word5 = strsplit(" ", (strtrim(searchText):gsub("%s+", " ")))
					local trackCount = 0
					for k = 1, ListingCount + 4 do
						local v = Leatrix_Sounds.Tracks[k]
						if (strfind(v, ".ogg") or strfind(v, ".mp3")) and strfind(strlower(v), word1) then
							if not word2 or word2 ~= "" and strfind(strlower(v), word2) then
								if not word3 or word3 ~= "" and strfind(strlower(v), word3) then
									if not word4 or word4 ~= "" and strfind(strlower(v), word4) then
										if not word5 or word5 ~= "" and strfind(strlower(v), word5) then
											-- Show track
											tinsert(ListData, v)
											trackCount = trackCount + 1
										end
									end
								end
							end
						end
					end
					-- Set results tag
					if trackCount == 1 then
						ListData[2] = "|cffffffaa{" .. trackCount .. " " .. L["result"] .. "}"
					else
						ListData[2] = "|cffffffaa{" .. trackCount .. " " .. L["results"] .. "}"
					end
				end
				-- Refresh the track listing
				UpdateList()
				-- Set track listing to top
				scrollFrame:SetVerticalScroll(0)
			end

			-- When editbox is changed by user, stop playback and show search results
			sBox:HookScript("OnTextChanged", function(self, userInput)
				if userInput then
					if LeaSoundsLC.Timer then LeaSoundsLC.Timer:Cancel() end
					LeaSoundsLC.Timer = C_Timer.NewTimer(0.5, function()
						stopBtn:Click()
						ListData = searchTable
						ShowSearchResults()
					end)
				end
			end)

			-- When enter key is pressed, stop playback and show search results
			sBox:HookScript("OnEnterPressed", function()
				ListData = searchTable
				stopBtn:Click()
				ShowSearchResults()
			end)

			-- Create list items
			scrollFrame.buttons = {}
			for i = 1, numButtons do
				scrollFrame.buttons[i] = CreateFrame("Button", nil, LeaSoundsLC["PageFileBrowser"])
				local button = scrollFrame.buttons[i]

				button:SetSize(470 - 14, 16)
				button:SetNormalFontObject("GameFontHighlightLeft")
				button:SetPoint("TOPLEFT", 16, -6+ -(i - 1) * 16 - 8)

				-- Create highlight bar texture
				button.t = button:CreateTexture(nil, "BACKGROUND")
				button.t:SetPoint("TOPLEFT", button, 0, 0)
				button.t:SetSize(516, 16)

				button.t:SetColorTexture(0.3, 0.3, 0.0, 0.8)
				button.t:SetAlpha(0.7)
				button.t:Hide()

				-- Create last playing highlight bar texture
				button.s = button:CreateTexture(nil, "BACKGROUND")
				button.s:SetPoint("TOPLEFT", button, 0, 0)
				button.s:SetSize(516, 16)

				button.s:SetColorTexture(0.3, 0.4, 0.00, 0.6)
				button.s:Hide()

				button:SetScript("OnEnter", function()
					-- Highlight links only
					if not string.match(button:GetText() or "", "|c") then
						button.t:Show()
					end
				end)

				button:SetScript("OnLeave", function()
					button.t:Hide()
				end)

				button:RegisterForClicks("LeftButtonUp", "RightButtonUp")

				-- Click handler for track and back button
				button:SetScript("OnClick", function(self, btn)
					if btn == "LeftButton" then
						-- Remove focus from search box
						sBox:ClearFocus()
						-- Get clicked track text
						local item = self:GetText()
						-- Do nothing if its a blank line or informational heading
						if not item or strfind(item, "|c") then return end
						if strfind(item, ".ogg") or strfind(item, ".mp3") then
							-- Enable sound if required
							if GetCVar("Sound_EnableAllSound") == "0" then SetCVar("Sound_EnableAllSound", "1") end
							-- Disable music if it's currently enabled
							if GetCVar("Sound_EnableMusic") == "1" then	SetCVar("Sound_EnableMusic", "0") end
							-- Add all tracks to playlist
							local StartItem = 0
							-- Get item clicked row number
							for index = 1, #ListData do
								local item = ListData[index]
								if self:GetText() == item then StartItem = index end
							end
							-- Enable the stop button
							LeaSoundsLC:LockItem(stopBtn, false)
							-- Play track
							if musicHandle then StopSound(musicHandle) end
							local file = item
							willPlay, musicHandle = PlaySoundFile(item, "Master")
							-- Store track name
							LastPlayed = item
							-- Show static highlight bar
							for index = 1, numButtons do
								local button = scrollFrame.buttons[index]
								local item = button:GetText()
								if item then
									if item == file then
										button.s:Show()
									else
										button.s:Hide()
									end
								end
							end
							return
						end
					end
				end)

			end

			-- Delete the global scroll frame pointer
			_G.LeaSoundsFileBrowserScrollFrame = nil

			-- Show listing on startup
			ListData = Leatrix_Sounds.Tracks
			UpdateList()

			-- Manage events
			LeaSoundsLC["PageFileBrowser"]:RegisterEvent("PLAYER_LOGOUT")
			LeaSoundsLC["PageFileBrowser"]:RegisterEvent("UI_SCALE_CHANGED")
			LeaSoundsLC["PageFileBrowser"]:SetScript("OnEvent", function(self, event)
				if event == "PLAYER_LOGOUT" then
					-- Stop playing at reload or logout
					if musicHandle then
						StopSound(musicHandle)
					end
				elseif event == "UI_SCALE_CHANGED" then
					-- Refresh list
					UpdateList()
				end
			end)

		end

		----------------------------------------------------------------------
		-- L60: Events
		----------------------------------------------------------------------

		-- Create event frame to run main function
		local eFrame = CreateFrame("FRAME")
		eFrame:RegisterEvent("PLAYER_LOGIN")
		eFrame:SetScript("OnEvent", LeaSoundsLC.MainFuncFileBrowser)

		----------------------------------------------------------------------
		-- L70: Panel
		----------------------------------------------------------------------

		-- Create the panel
		local PageFileBrowser = CreateFrame("Frame", nil, UIParent)

		-- Make it a system frame
		_G["LeaSoundsFileBrowserGlobalPanel"] = PageFileBrowser
		table.insert(UISpecialFrames, "LeaSoundsFileBrowserGlobalPanel")

		-- Set frame parameters
		LeaSoundsLC["PageFileBrowser"] = PageFileBrowser
		PageFileBrowser:SetSize(frameWidth, 308)
		PageFileBrowser:SetScale(1.1)
		PageFileBrowser:Hide()
		PageFileBrowser:SetFrameStrata("FULLSCREEN_DIALOG")
		PageFileBrowser:SetFrameLevel(40)
		PageFileBrowser:SetClampedToScreen(true)
		PageFileBrowser:SetClampRectInsets(550, -550, -200, 200)
		PageFileBrowser:ClearAllPoints()
		PageFileBrowser:SetPoint("CENTER", 0, 0)
		PageFileBrowser:EnableMouse(true)
		PageFileBrowser:SetMovable(true)
		PageFileBrowser:RegisterForDrag("LeftButton")
		PageFileBrowser:SetScript("OnDragStart", PageFileBrowser.StartMoving)
		PageFileBrowser:SetScript("OnDragStop", function()
			PageFileBrowser:StopMovingOrSizing()
			PageFileBrowser:SetUserPlaced(false)
		end)

		-- Add background color
		PageFileBrowser.t = PageFileBrowser:CreateTexture(nil, "BACKGROUND")
		PageFileBrowser.t:SetAllPoints()
		PageFileBrowser.t:SetColorTexture(0.05, 0.05, 0.05, 0.9)

		-- Add textures
		PageFileBrowser.mainTex = PageFileBrowser:CreateTexture(nil, "BORDER")
		PageFileBrowser.mainTex:SetTexture("Interface\\ACHIEVEMENTFRAME\\UI-GuildAchievement-Parchment-Horizontal-Desaturated.png")
		PageFileBrowser.mainTex:SetSize(frameWidth, 273)
		PageFileBrowser.mainTex:SetPoint("TOPRIGHT")
		PageFileBrowser.mainTex:SetVertexColor(0.7, 0.7, 0.7, 0.7)
		PageFileBrowser.mainTex:SetTexCoord(0.09, 1, 0, 1)

		PageFileBrowser.footTex = PageFileBrowser:CreateTexture(nil, "BORDER")
		PageFileBrowser.footTex:SetTexture("Interface\\ACHIEVEMENTFRAME\\UI-GuildAchievement-Parchment-Horizontal-Desaturated.png")
		PageFileBrowser.footTex:SetSize(frameWidth, 48)
		PageFileBrowser.footTex:SetPoint("BOTTOM")
		PageFileBrowser.footTex:SetVertexColor(0.5, 0.5, 0.5, 1.0)

		-- Add close Button
		PageFileBrowser.cb = CreateFrame("Button", nil, PageFileBrowser, "UIPanelCloseButton") 
		PageFileBrowser.cb:SetSize(30, 30)
		PageFileBrowser.cb:SetPoint("TOPRIGHT", 0, 0)

	end

	-- Run massive functions
	MassiveFuncSoundKitBrowser()
	MassiveFuncFileBrowser()

	----------------------------------------------------------------------
	-- L20: Commands
	----------------------------------------------------------------------

	-- Slash command function
	local function SlashFunc(str)
		local str = string.lower(str)
		if str and str ~= "" then
			-- Traverse parameters
			if str == "ver" then
				-- Print addon version
				LeaSoundsLC:Print("Leatrix Sounds " .. LeaSoundsLC["AddonVer"])
				return
			else
				-- Invalid command entered
				LeaSoundsLC:Print("Invalid command.")
				return
			end
		else
			-- Prevent panel from showing if a game options panel is showing
			if InterfaceOptionsFrame:IsShown() or VideoOptionsFrame:IsShown() or ChatConfigFrame:IsShown() then return end
			-- Prevent panel from showing if Blizzard Store is showing
			if StoreFrame and StoreFrame:GetAttribute("isshown") then return end
			-- Toggle the correct panel if game options panel and Blizzard Store is not showing
			if showingPanel == "SoundKitBrowser" then
				if LeaSoundsLC["PageSoundKitBrowser"]:IsShown() then
					LeaSoundsLC["PageSoundKitBrowser"]:Hide()
				else
					LeaSoundsLC["PageSoundKitBrowser"]:Show()
				end
			elseif showingPanel == "FileBrowser" then
				if LeaSoundsLC["PageFileBrowser"]:IsShown() then
					LeaSoundsLC["PageFileBrowser"]:Hide()
				else
					LeaSoundsLC["PageFileBrowser"]:Show()
				end
			end
		end
	end

	-- Add slash commands
	_G.SLASH_Leatrix_Sounds1 = "/lts"
	_G.SLASH_Leatrix_Sounds2 = "/leasounds" 
	SlashCmdList["Leatrix_Sounds"] = function(self)
		-- Run slash command function
		SlashFunc(self)
		-- Redirect tainted variables
		RunScript('ACTIVE_CHAT_EDIT_BOX = ACTIVE_CHAT_EDIT_BOX')
		RunScript('LAST_ACTIVE_CHAT_EDIT_BOX = LAST_ACTIVE_CHAT_EDIT_BOX')
	end
