Update libraries

Scott Yeskie [03-20-16 - 20:35]
Update libraries

- LAM to r19
- LibStub to 3
Filename
CyrHUD.txt
lib/LibAddonMenu-2.0/LICENSE
lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua
lib/LibAddonMenu-2.0/controls/button.lua
lib/LibAddonMenu-2.0/controls/checkbox.lua
lib/LibAddonMenu-2.0/controls/colorpicker.lua
lib/LibAddonMenu-2.0/controls/custom.lua
lib/LibAddonMenu-2.0/controls/description.lua
lib/LibAddonMenu-2.0/controls/dropdown.lua
lib/LibAddonMenu-2.0/controls/editbox.lua
lib/LibAddonMenu-2.0/controls/header.lua
lib/LibAddonMenu-2.0/controls/iconpicker.lua
lib/LibAddonMenu-2.0/controls/panel.lua
lib/LibAddonMenu-2.0/controls/slider.lua
lib/LibAddonMenu-2.0/controls/submenu.lua
lib/LibAddonMenu-2.0/controls/texture.lua
lib/LibStub/LibStub.lua
diff --git a/CyrHUD.txt b/CyrHUD.txt
index 960fde2..e67a4a7 100644
--- a/CyrHUD.txt
+++ b/CyrHUD.txt
@@ -17,6 +17,7 @@ lib/LibAddonMenu-2.0/controls/description.lua
 lib/LibAddonMenu-2.0/controls/dropdown.lua
 lib/LibAddonMenu-2.0/controls/editbox.lua
 lib/LibAddonMenu-2.0/controls/header.lua
+lib/LibAddonMenu-2.0/controls/iconpicker.lua
 lib/LibAddonMenu-2.0/controls/slider.lua
 lib/LibAddonMenu-2.0/controls/texture.lua

diff --git a/lib/LibAddonMenu-2.0/LICENSE b/lib/LibAddonMenu-2.0/LICENSE
index 82fcf2f..f69cbd4 100644
--- a/lib/LibAddonMenu-2.0/LICENSE
+++ b/lib/LibAddonMenu-2.0/LICENSE
@@ -1,6 +1,6 @@
                The Artistic License 2.0

-           Copyright (c) 2015 Ryan Lakanen (Seerah)
+           Copyright (c) 2016 Ryan Lakanen (Seerah)

      Everyone is permitted to copy and distribute verbatim copies
       of this license document, but changing it is not allowed.
diff --git a/lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua b/lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua
index 03fb4c4..568b95d 100644
--- a/lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua
+++ b/lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua
@@ -4,14 +4,14 @@


 --Register LAM with LibStub
-local MAJOR, MINOR = "LibAddonMenu-2.0", 17
+local MAJOR, MINOR = "LibAddonMenu-2.0", 19
 local lam, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
 if not lam then return end	--the same or newer version of this lib is already loaded into memory

 local messages = {}
 local MESSAGE_PREFIX = "[LAM2] "
 local function PrintLater(msg)
-	if(CHAT_SYSTEM.primaryContainer) then
+	if CHAT_SYSTEM.primaryContainer then
 		d(MESSAGE_PREFIX .. msg)
 	else
 		messages[#messages + 1] = msg
@@ -25,23 +25,188 @@ local function FlushMessages()
 	messages = {}
 end

-if(LAMSettingsPanelCreated and not LAMCompatibilityWarning) then
+if LAMSettingsPanelCreated and not LAMCompatibilityWarning then
 	PrintLater("An old version of LibAddonMenu with compatibility issues was detected. For more information on how to proceed search for LibAddonMenu on esoui.com")
 	LAMCompatibilityWarning = true
 end

 --UPVALUES--
 local wm = WINDOW_MANAGER
+local em = EVENT_MANAGER
+local sm = SCENE_MANAGER
 local cm = CALLBACK_MANAGER
+local tconcat = table.concat
 local tinsert = table.insert
-local optionsWindow = ZO_OptionsWindowSettingsScrollChild
-local _

 local addonsForList = {}
 local addonToOptionsMap = {}
 local optionsCreated = {}
 lam.widgets = lam.widgets or {}
 local widgets = lam.widgets
+lam.util = {}
+local util = lam.util
+
+local function GetTooltipText(tooltip)
+	if type(tooltip) == "string" then
+		return tooltip
+	elseif type(tooltip) == "function" then
+		return tostring(tooltip())
+	end
+	return nil
+end
+
+local function CreateBaseControl(parent, controlData, controlName)
+	local control = wm:CreateControl(controlName or controlData.reference, parent.scroll or parent, CT_CONTROL)
+	control.panel = parent.panel or parent	-- if this is in a submenu, panel is the submenu's parent
+	control.data = controlData
+
+	control.isHalfWidth = controlData.width == "half"
+	local width = 510 -- set default width in case a custom parent object is passed
+	if control.panel.GetWidth ~= nil then width = control.panel:GetWidth() - 60 end
+	control:SetWidth(width)
+	return control
+end
+
+local MIN_HEIGHT = 26
+local HALF_WIDTH_LINE_SPACING = 2
+local function CreateLabelAndContainerControl(parent, controlData, controlName)
+	local control = CreateBaseControl(parent, controlData, controlName)
+	local width = control:GetWidth()
+
+	local container = wm:CreateControl(nil, control, CT_CONTROL)
+	container:SetDimensions(width / 3, MIN_HEIGHT)
+	control.container = container
+
+	local label = wm:CreateControl(nil, control, CT_LABEL)
+	label:SetFont("ZoFontWinH4")
+	label:SetHeight(MIN_HEIGHT)
+	label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
+	label:SetText(controlData.name)
+	control.label = label
+
+	if control.isHalfWidth then
+		control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING)
+		label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0)
+		label:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0)
+		container:SetAnchor(TOPRIGHT, control.label, BOTTOMRIGHT, 0, HALF_WIDTH_LINE_SPACING)
+	else
+		control:SetDimensions(width, MIN_HEIGHT)
+		container:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0)
+		label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0)
+		label:SetAnchor(TOPRIGHT, container, TOPLEFT, 5, 0)
+	end
+
+	control.data.tooltipText = GetTooltipText(control.data.tooltip)
+	control:SetMouseEnabled(true)
+	control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
+	control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
+	return control
+end
+
+util.GetTooltipText = GetTooltipText
+util.CreateBaseControl = CreateBaseControl
+util.CreateLabelAndContainerControl = CreateLabelAndContainerControl
+
+local ADDON_DATA_TYPE = 1
+local RESELECTING_DURING_REBUILD = true
+local USER_REQUESTED_OPEN = true
+
+
+--INTERNAL FUNCTION
+--scrolls ZO_ScrollList `list` to move the row corresponding to `data`
+--	into view (does nothing if there is no such row in the list)
+--unlike ZO_ScrollList_ScrollDataIntoView, this function accounts for
+--	fading near the list's edges - it avoids the fading area by scrolling
+--	a little further than the ZO function
+local function ScrollDataIntoView(list, data)
+	local targetIndex = data.sortIndex
+	if not targetIndex then return end
+
+	local scrollMin, scrollMax = list.scrollbar:GetMinMax()
+	local scrollTop = list.scrollbar:GetValue()
+	local controlHeight = list.controlHeight
+	local targetMin = controlHeight * (targetIndex - 1) - 64
+	-- subtracting 64 ain't arbitrary, it's the maximum fading height
+	-- (libraries/zo_templates/scrolltemplates.lua/UpdateScrollFade)
+
+	if targetMin < scrollTop then
+		ZO_ScrollList_ScrollAbsolute(list, zo_max(targetMin, scrollMin))
+	else
+		local listHeight = ZO_ScrollList_GetHeight(list)
+		local targetMax = controlHeight * targetIndex + 64 - listHeight
+
+		if targetMax > scrollTop then
+			ZO_ScrollList_ScrollAbsolute(list, zo_min(targetMax, scrollMax))
+		end
+	end
+end
+
+
+--INTERNAL FUNCTION
+--constructs a string pattern from the text in `searchEdit` control
+--	* metacharacters are escaped, losing their special meaning
+--	* whitespace matches anything (including empty substring)
+--if there is nothing but whitespace, returns nil
+--otherwise returns a filter function, which takes a `data` table argument
+--	and returns true iff `data.filterText` matches the pattern
+local function GetSearchFilterFunc(searchEdit)
+	local text = searchEdit:GetText():lower()
+	local pattern = text:match("(%S+.-)%s*$")
+
+	if not pattern then -- nothing but whitespace
+		return nil
+	end
+
+	-- escape metacharacters, e.g. "ESO-Datenbank.de" => "ESO%-Datenbank%.de"
+	pattern = pattern:gsub("[-*+?^$().[%]%%]", "%%%0")
+
+	-- replace whitespace with "match shortest anything"
+	pattern = pattern:gsub("%s+", ".-")
+
+	return function(data)
+		return data.filterText:lower():find(pattern) ~= nil
+	end
+end
+
+
+--INTERNAL FUNCTION
+--populates `addonList` with entries from `addonsForList`
+--	addonList = ZO_ScrollList control
+--	filter = [optional] function(data)
+local function PopulateAddonList(addonList, filter)
+	local entryList = ZO_ScrollList_GetDataList(addonList)
+	local numEntries = 0
+	local selectedData = nil
+
+	ZO_ScrollList_Clear(addonList)
+
+	for i, data in ipairs(addonsForList) do
+		if not filter or filter(data) then
+			local dataEntry = ZO_ScrollList_CreateDataEntry(ADDON_DATA_TYPE, data)
+			numEntries = numEntries + 1
+			data.sortIndex = numEntries
+			entryList[numEntries] = dataEntry
+			-- select the first panel passing the filter, or the currently
+			-- shown panel, but only if it passes the filter as well
+			if selectedData == nil or data.panel == lam.currentAddonPanel then
+				selectedData = data
+			end
+		else
+			data.sortIndex = nil
+		end
+	end
+
+	ZO_ScrollList_Commit(addonList)
+
+	if selectedData then
+		if selectedData.panel == lam.currentAddonPanel then
+			ZO_ScrollList_SelectData(addonList, selectedData, nil, RESELECTING_DURING_REBUILD)
+		else
+			ZO_ScrollList_SelectData(addonList, selectedData, nil)
+		end
+		ScrollDataIntoView(addonList, selectedData)
+	end
+end


 --METHOD: REGISTER WIDGET--
@@ -66,33 +231,83 @@ end
 --METHOD: OPEN TO ADDON PANEL--
 --opens to a specific addon's option panel
 --Usage:
---  panel = userdata; the panel returned by the :RegisterOptionsPanel method
+--	panel = userdata; the panel returned by the :RegisterOptionsPanel method
 local locSettings = GetString(SI_GAME_MENU_SETTINGS)
 function lam:OpenToPanel(panel)
-	SCENE_MANAGER:Show("gameMenuInGame")
-	zo_callLater(function()
-		local settingsMenu = ZO_GameMenu_InGame.gameMenu.headerControls[locSettings]
-		settingsMenu:SetOpen(true)
-		SCENE_MANAGER:AddFragment(OPTIONS_WINDOW_FRAGMENT)
-		KEYBOARD_OPTIONS:ChangePanels(lam.panelID)
-		for i, child in pairs(settingsMenu.children) do
-			if type(child) == "table" and child.data.name == KEYBOARD_OPTIONS.panelNames[lam.panelID] then
-				ZO_TreeEntry_OnMouseUp(child.control, true)
-				break
-			end
+
+	-- find and select the panel's row in addon list
+
+	local addonList = lam.addonList
+	local selectedData = nil
+
+	for _, addonData in ipairs(addonsForList) do
+		if addonData.panel == panel then
+			selectedData = addonData
+			ScrollDataIntoView(addonList, selectedData)
+			break
 		end
-		local scroll = LAMAddonPanelsMenuScrollChild
-		for i = 1, scroll:GetNumChildren() do
-			local button = scroll:GetChild(i)
-			if button.panel == panel then
-				zo_callHandler(button, "OnClicked")
-				ZO_Scroll_ScrollControlToTop(LAMAddonPanelsMenu, button)
-				break
+	end
+
+	ZO_ScrollList_SelectData(addonList, selectedData)
+	ZO_ScrollList_RefreshVisible(addonList, selectedData)
+
+	local srchEdit = LAMAddonSettingsWindow:GetNamedChild("SearchFilterEdit")
+	srchEdit:Clear()
+
+	-- note that ZO_ScrollList doesn't require `selectedData` to be actually
+	-- present in the list, and that the list will only be populated once LAM
+	-- "Addon Settings" menu entry is selected for the first time
+
+	local function openAddonSettingsMenu()
+		local gameMenu = ZO_GameMenu_InGame.gameMenu
+		local settingsMenu = gameMenu.headerControls[locSettings]
+
+		if settingsMenu then -- an instance of ZO_TreeNode
+			local children = settingsMenu:GetChildren()
+			for i = 1, (children and #children or 0) do
+				local childNode = children[i]
+				local data = childNode:GetData()
+				if data and data.id == lam.panelId then
+					-- found LAM "Addon Settings" node, yay!
+					childNode:GetTree():SelectNode(childNode)
+					break
+				end
 			end
 		end
-	end, 200)
+	end
+
+	if sm:GetScene("gameMenuInGame"):GetState() == SCENE_SHOWN then
+		openAddonSettingsMenu()
+	else
+		sm:CallWhen("gameMenuInGame", SCENE_SHOWN, openAddonSettingsMenu)
+		sm:Show("gameMenuInGame")
+	end
 end

+local TwinOptionsContainer_Index = 0
+local function TwinOptionsContainer(parent, leftWidget, rightWidget)
+	TwinOptionsContainer_Index = TwinOptionsContainer_Index + 1
+	local cParent = parent.scroll or parent
+	local panel = parent.panel or cParent
+	local container = wm:CreateControl("$(parent)TwinContainer" .. tostring(TwinOptionsContainer_Index),
+										cParent, CT_CONTROL)
+	container:SetResizeToFitDescendents(true)
+	container:SetAnchor(select(2, leftWidget:GetAnchor(0) ))
+
+	leftWidget:ClearAnchors()
+	leftWidget:SetAnchor(TOPLEFT, container, TOPLEFT)
+	rightWidget:SetAnchor(TOPLEFT, leftWidget, TOPRIGHT, 5, 0)
+
+	leftWidget:SetWidth( leftWidget:GetWidth() - 2.5 ) -- fixes bad alignment with 'full' controls
+	rightWidget:SetWidth( rightWidget:GetWidth() - 2.5 )
+
+	leftWidget:SetParent(container)
+	rightWidget:SetParent(container)
+
+	container.data = {type = "container"}
+	container.panel = panel
+	return container
+end

 --INTERNAL FUNCTION
 --creates controls when options panel is first shown
@@ -102,86 +317,112 @@ local function CreateOptionsControls(panel)
 	local optionsTable = addonToOptionsMap[addonID]

 	if optionsTable then
-		local isHalf, widget
-		local lastAddedControl, lacAtHalfRow, oIndex, widgetData, widgetType
-		local submenu, subWidgetData, sIndex, subWidgetType, subWidget
-		local anchorOffset = 0
-		local anchorOffsetSub
-		local lastAddedControlSub, lacAtHalfRowSub
-		for oIndex=1,#optionsTable do
-			widgetData = optionsTable[oIndex]
-			widgetType = widgetData.type
-			if widgetType == "submenu" then
-				submenu = LAMCreateControl[widgetType](panel, widgetData)
-				if lastAddedControl then
-					submenu:SetAnchor(TOPLEFT, lastAddedControl, BOTTOMLEFT, 0, 15 + anchorOffset)
-				else
-					submenu:SetAnchor(TOPLEFT)
+		local function CreateAndAnchorWidget(parent, widgetData, offsetX, offsetY, anchorTarget, wasHalf)
+			local widget
+			local status, err = pcall(function() widget = LAMCreateControl[widgetData.type](parent, widgetData) end)
+			if not status then
+				return err or true, offsetY, anchorTarget, wasHalf
+			else
+				local isHalf = (widgetData.width == "half")
+				if not anchorTarget then -- the first widget in a panel is just placed in the top left corner
+					widget:SetAnchor(TOPLEFT)
+					anchorTarget = widget
+				elseif wasHalf and isHalf then -- when the previous widget was only half width and this one is too, we place it on the right side
+					widget.lineControl = anchorTarget
+					isHalf = false
+					offsetY = 0
+					anchorTarget = TwinOptionsContainer(parent, anchorTarget, widget)
+				else -- otherwise we just put it below the previous one normally
+					widget:SetAnchor(TOPLEFT, anchorTarget, BOTTOMLEFT, 0, 15)
+					offsetY = 0
+					anchorTarget = widget
 				end
-				lastAddedControl = submenu
-				lacAtHalfRow = false
-
-				anchorOffsetSub = 0
-				lacAtHalfRowSub = nil
-				lastAddedControlSub = nil
-				for sIndex=1,#widgetData.controls do
-					subWidgetData = widgetData.controls[sIndex]
-					subWidgetType = subWidgetData.type
-					subWidget = LAMCreateControl[subWidgetType](submenu, subWidgetData)
-					isHalf = subWidgetData.width == "half"
-					if lastAddedControlSub then
-						if lacAtHalfRowSub and isHalf then
-							subWidget:SetAnchor(TOPLEFT, lastAddedControlSub, TOPRIGHT, 5, 0)
-							lacAtHalfRowSub = false
-							anchorOffsetSub = zo_max(0, subWidget:GetHeight() - lastAddedControlSub:GetHeight())
-						else
-							subWidget:SetAnchor(TOPLEFT, lastAddedControlSub, BOTTOMLEFT, 0, 15 + anchorOffsetSub)
-							lacAtHalfRowSub = isHalf
-							anchorOffsetSub = 0
-							lastAddedControlSub = subWidget
+				return false, offsetY, anchorTarget, isHalf
+			end
+		end
+
+		local THROTTLE_TIMEOUT, THROTTLE_COUNT = 10, 20
+		local fifo = {}
+		local anchorOffset, lastAddedControl, wasHalf
+		local CreateWidgetsInPanel, err
+
+		local function PrepareForNextPanel()
+			anchorOffset, lastAddedControl, wasHalf = 0, nil, false
+		end
+
+		local function SetupCreationCalls(parent, widgetDataTable)
+			fifo[#fifo + 1] = PrepareForNextPanel
+			local count = #widgetDataTable
+			for i = 1, count, THROTTLE_COUNT do
+				fifo[#fifo + 1] = function()
+					CreateWidgetsInPanel(parent, widgetDataTable, i, zo_min(i + THROTTLE_COUNT - 1, count))
+				end
+			end
+			return count ~= NonContiguousCount(widgetDataTable)
+		end
+
+		CreateWidgetsInPanel = function(parent, widgetDataTable, startIndex, endIndex)
+			for i=startIndex,endIndex do
+				local widgetData = widgetDataTable[i]
+				if not widgetData then
+					PrintLater("Skipped creation of missing entry in the settings menu of " .. addonID .. ".")
+				else
+					local widgetType = widgetData.type
+					local offsetX = 0
+					local isSubmenu = (widgetType == "submenu")
+					if isSubmenu then
+						wasHalf = false
+						offsetX = 5
+					end
+
+					err, anchorOffset, lastAddedControl, wasHalf = CreateAndAnchorWidget(parent, widgetData, offsetX, anchorOffset, lastAddedControl, wasHalf)
+					if err then
+						PrintLater(("Could not create %s '%s' of %s."):format(widgetData.type, widgetData.name or "unnamed", addonID))
+					end
+
+					if isSubmenu then
+						if SetupCreationCalls(lastAddedControl, widgetData.controls) then
+							PrintLater(("The sub menu '%s' of %s is missing some entries."):format(widgetData.name or "unnamed", addonID))
 						end
-					else
-						subWidget:SetAnchor(TOPLEFT)
-						lacAtHalfRowSub = isHalf
-						lastAddedControlSub = subWidget
 					end
 				end
-			else
-				widget = LAMCreateControl[widgetType](panel, widgetData)
-				isHalf = widgetData.width == "half"
-				if lastAddedControl then
-					if lacAtHalfRow and isHalf then
-						widget:SetAnchor(TOPLEFT, lastAddedControl, TOPRIGHT, 10, 0)
-						anchorOffset = zo_max(0, widget:GetHeight() - lastAddedControl:GetHeight())
-						lacAtHalfRow = false
-					else
-						widget:SetAnchor(TOPLEFT, lastAddedControl, BOTTOMLEFT, 0, 15 + anchorOffset)
-						lacAtHalfRow = isHalf
-						anchorOffset = 0
-						lastAddedControl = widget
-					end
+			end
+		end
+
+		local function DoCreateSettings()
+			if #fifo > 0 then
+				local nextCall = table.remove(fifo, 1)
+				nextCall()
+				if(nextCall == PrepareForNextPanel) then
+					DoCreateSettings()
 				else
-					widget:SetAnchor(TOPLEFT)
-					lacAtHalfRow = isHalf
-					lastAddedControl = widget
+					zo_callLater(DoCreateSettings, THROTTLE_TIMEOUT)
 				end
+			else
+				optionsCreated[addonID] = true
+				cm:FireCallbacks("LAM-PanelControlsCreated", panel)
 			end
 		end
-	end

-	optionsCreated[addonID] = true
-	cm:FireCallbacks("LAM-PanelControlsCreated", panel)
+		if SetupCreationCalls(panel, optionsTable) then
+			PrintLater(("The settings menu of %s is missing some entries."):format(addonID))
+		end
+		DoCreateSettings()
+	end
 end


 --INTERNAL FUNCTION
 --handles switching between panels
 local function ToggleAddonPanels(panel)	--called in OnShow of newly shown panel
-	local currentlySelected = LAMAddonPanelsMenu.currentlySelected
+	local currentlySelected = lam.currentAddonPanel
 	if currentlySelected and currentlySelected ~= panel then
 		currentlySelected:SetHidden(true)
 	end
-	LAMAddonPanelsMenu.currentlySelected = panel
+	lam.currentAddonPanel = panel
+
+	-- refresh visible rows to reflect panel IsHidden status
+	ZO_ScrollList_RefreshVisible(lam.addonList)

 	if not optionsCreated[panel:GetName()] then	--if this is the first time opening this panel, create these options
 		CreateOptionsControls(panel)
@@ -190,8 +431,7 @@ local function ToggleAddonPanels(panel)	--called in OnShow of newly shown panel
 	cm:FireCallbacks("LAM-RefreshPanel", panel)
 end

-local Initialize
-local hasInitialized = false
+local CheckSafetyAndInitialize

 --METHOD: REGISTER ADDON PANEL
 --registers your addon with LibAddonMenu and creates a panel
@@ -199,21 +439,36 @@ local hasInitialized = false
 --	addonID = "string"; unique ID which will be the global name of your panel
 --	panelData = table; data object for your panel - see controls\panel.lua
 function lam:RegisterAddonPanel(addonID, panelData)
-	if(not hasInitialized) then Initialize(addonID) end
-	local panel = lamcc.panel(nil, panelData, addonID)	--addonID==global name of panel
+	CheckSafetyAndInitialize(addonID)
+	local container = lam:GetAddonPanelContainer()
+	local panel = lamcc.panel(container, panelData, addonID)	--addonID==global name of panel
 	panel:SetHidden(true)
-	panel:SetAnchor(TOPLEFT, LAMAddonPanelsMenu, TOPRIGHT, 10, 0)
-	panel:SetAnchor(BOTTOMLEFT, LAMAddonPanelsMenu, BOTTOMRIGHT, 10, 0)
-	panel:SetWidth(549)
-	panel:SetDrawLayer(DL_OVERLAY)
-	tinsert(addonsForList, {panel = addonID, name = panelData.name})
+	panel:SetAnchorFill(container)
 	panel:SetHandler("OnShow", ToggleAddonPanels)
+
+	local function stripMarkup(str)
+		return str:gsub("|[Cc]%x%x%x%x%x%x", ""):gsub("|[Rr]", "")
+	end
+
+	local filterParts = {panelData.name, nil, nil}
+	-- append keywords and author separately, the may be nil
+	filterParts[#filterParts + 1] = panelData.keywords
+	filterParts[#filterParts + 1] = panelData.author
+
+	local addonData = {
+		panel = panel,
+		name = stripMarkup(panelData.name),
+		filterText = stripMarkup(tconcat(filterParts, "\t")):lower(),
+	}
+
+	tinsert(addonsForList, addonData)
+
 	if panelData.slashCommand then
 		SLASH_COMMANDS[panelData.slashCommand] = function()
 			lam:OpenToPanel(panel)
 		end
 	end
-
+
 	return panel	--return for authors creating options manually
 end

@@ -233,152 +488,348 @@ end


 --INTERNAL FUNCTION
---handles switching between LAM's Addon Settings panel and other panels in the Settings menu
-local oldDefaultButton = ZO_OptionsWindowResetToDefaultButton
-local oldCallback = oldDefaultButton.callback
-local dummyFunc = function() end
-local panelWindow = ZO_OptionsWindow
-local bgL = ZO_OptionsWindowBGLeft
-local bgR = ZO_OptionsWindowBGLeftBGRight
-local function HandlePanelSwitching(self, panel)
-	if panel == lam.panelID then	--our addon settings panel
-		oldDefaultButton:SetCallback(dummyFunc)
-		oldDefaultButton:SetHidden(true)
-		oldDefaultButton:SetAlpha(0)	--just because it still bugs out
-		panelWindow:SetDimensions(999, 960)
-		bgL:SetWidth(666)
-		bgR:SetWidth(333)
-	else
-		local shown = LAMAddonPanelsMenu.currentlySelected
-		if shown then shown:SetHidden(true) end
-		oldDefaultButton:SetCallback(oldCallback)
-		oldDefaultButton:SetHidden(false)
-		oldDefaultButton:SetAlpha(1)
-		panelWindow:SetDimensions(768, 914)
-		bgL:SetWidth(512)
-		bgR:SetWidth(256)
+--creates LAM's Addon Settings entry in ZO_GameMenu
+local function CreateAddonSettingsMenuEntry()
+	--Russian for TERAB1T's RuESO addon, which creates an "ru" locale
+	--game font does not support Cyrillic, so they are using custom fonts + extended latin charset
+	--Spanish provided by Luisen75 for their translation project
+	local controlPanelNames = {
+		en = "Addon Settings",
+		fr = "Extensions",
+		de = "Erweiterungen",
+		ru = "Îacòpoéêè äoïoìîeîèé",
+		es = "Configura Addons",
+	}
+
+	local panelData = {
+		id = KEYBOARD_OPTIONS.currentPanelId,
+		name = controlPanelNames[GetCVar("Language.2")] or controlPanelNames["en"],
+	}
+
+	KEYBOARD_OPTIONS.currentPanelId = panelData.id + 1
+	KEYBOARD_OPTIONS.panelNames[panelData.id] = panelData.name
+
+	lam.panelId = panelData.id
+
+	local addonListSorted = false
+
+	function panelData.callback()
+		sm:AddFragment(lam:GetAddonSettingsFragment())
+		KEYBOARD_OPTIONS:ChangePanels(lam.panelId)
+
+		local title = LAMAddonSettingsWindow:GetNamedChild("Title")
+		title:SetText(panelData.name)
+
+		if not addonListSorted and #addonsForList > 0 then
+			local searchEdit = LAMAddonSettingsWindow:GetNamedChild("SearchFilterEdit")
+			--we're about to show our list for the first time - let's sort it
+			table.sort(addonsForList, function(a, b) return a.name < b.name end)
+			PopulateAddonList(lam.addonList, GetSearchFilterFunc(searchEdit))
+			addonListSorted = true
+		end
+	end
+
+	function panelData.unselectedCallback()
+		sm:RemoveFragment(lam:GetAddonSettingsFragment())
+		if SetCameraOptionsPreviewModeEnabled then -- available since API version 100011
+			SetCameraOptionsPreviewModeEnabled(false)
+		end
 	end
+
+	ZO_GameMenu_AddSettingPanel(panelData)
 end


 --INTERNAL FUNCTION
---creates LAM's Addon Settings panel
-local function CreateAddonSettingsPanel()
-	if not LAMSettingsPanelCreated then
-		local controlPanelID = "LAM_ADDON_SETTINGS_PANEL"
-		--Russian for TERAB1T's RuESO addon, which creates an "ru" locale
-		--game font does not support Cyrillic, so they are using custom fonts + extended latin charset
-		--Spanish provided by Luisen75 for their translation project
-		local controlPanelNames = {
-			en = "Addon Settings",
-			fr = "Extensions",
-			de = "Erweiterungen",
-			ru = "Îacòpoéêè äoïoìîeîèé",
-			es = "Configura Addons",
-		}
-
-		ZO_OptionsWindow_AddUserPanel(controlPanelID, controlPanelNames[GetCVar("Language.2")] or controlPanelNames["en"], PANEL_TYPE_SETTINGS)
-
-		lam.panelID = _G[controlPanelID]
-
-		ZO_PreHook(ZO_KeyboardOptions, "ChangePanels", HandlePanelSwitching)
-
-		LAMSettingsPanelCreated = true
+--creates the left-hand menu in LAM's window
+local function CreateAddonList(name, parent)
+	local addonList = wm:CreateControlFromVirtual(name, parent, "ZO_ScrollList")
+
+	local function addonListRow_OnMouseDown(control, button)
+		if button == 1 then
+			local data = ZO_ScrollList_GetData(control)
+			ZO_ScrollList_SelectData(addonList, data, control)
+		end
+	end
+
+	local function addonListRow_OnMouseEnter(control)
+		ZO_ScrollList_MouseEnter(addonList, control)
 	end
+
+	local function addonListRow_OnMouseExit(control)
+		ZO_ScrollList_MouseExit(addonList, control)
+	end
+
+	local function addonListRow_Select(previouslySelectedData, selectedData, reselectingDuringRebuild)
+		if not reselectingDuringRebuild then
+			if previouslySelectedData then
+				previouslySelectedData.panel:SetHidden(true)
+			end
+			if selectedData then
+				selectedData.panel:SetHidden(false)
+				PlaySound(SOUNDS.MENU_SUBCATEGORY_SELECTION)
+			end
+		end
+	end
+
+	local function addonListRow_Setup(control, data)
+		control:SetText(data.name)
+		control:SetSelected(not data.panel:IsHidden())
+	end
+
+	ZO_ScrollList_AddDataType(addonList, ADDON_DATA_TYPE, "ZO_SelectableLabel", 28, addonListRow_Setup)
+	-- I don't know how to make highlights clear properly; they often
+	-- get stuck and after a while the list is full of highlighted rows
+	--ZO_ScrollList_EnableHighlight(addonList, "ZO_ThinListHighlight")
+	ZO_ScrollList_EnableSelection(addonList, "ZO_ThinListHighlight", addonListRow_Select)
+
+	local addonDataType = ZO_ScrollList_GetDataTypeTable(addonList, ADDON_DATA_TYPE)
+	local addonListRow_CreateRaw = addonDataType.pool.m_Factory
+
+	local function addonListRow_Create(pool)
+		local control = addonListRow_CreateRaw(pool)
+		control:SetHandler("OnMouseDown", addonListRow_OnMouseDown)
+		--control:SetHandler("OnMouseEnter", addonListRow_OnMouseEnter)
+		--control:SetHandler("OnMouseExit", addonListRow_OnMouseExit)
+		control:SetHeight(28)
+		control:SetFont("ZoFontHeader")
+		control:SetHorizontalAlignment(TEXT_ALIGN_LEFT)
+		control:SetVerticalAlignment(TEXT_ALIGN_CENTER)
+		control:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
+		return control
+	end
+
+	addonDataType.pool.m_Factory = addonListRow_Create
+
+	return addonList
 end


 --INTERNAL FUNCTION
---adds each registered addon to the menu in LAM's panel
-local function CreateAddonButtons(list, addons)
-	for i = 1, #addons do
-		local button = wm:CreateControlFromVirtual("LAMAddonMenuButton"..i, list.scrollChild, "ZO_DefaultTextButton")
-		button.name = addons[i].name
-		button.panel = _G[addons[i].panel]
-		button:SetText(button.name)
-		button:SetHorizontalAlignment(TEXT_ALIGN_LEFT)
-		button:SetWidth(190)
-		if i == 1 then
-			button:SetAnchor(TOPLEFT, list.scrollChild, TOPLEFT, 5, 5)
+local function CreateSearchFilterBox(name, parent)
+	local boxControl = wm:CreateControl(name, parent, CT_CONTROL)
+
+	local srchButton =  wm:CreateControl("$(parent)Button", boxControl, CT_BUTTON)
+	srchButton:SetDimensions(32, 32)
+	srchButton:SetAnchor(LEFT, nil, LEFT, 2, 0)
+	srchButton:SetNormalTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_up.dds")
+	srchButton:SetPressedTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_down.dds")
+	srchButton:SetMouseOverTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_over.dds")
+
+	local srchEdit = wm:CreateControlFromVirtual("$(parent)Edit", boxControl, "ZO_DefaultEdit")
+	srchEdit:SetAnchor(LEFT, srchButton, RIGHT, 4, 1)
+	srchEdit:SetAnchor(RIGHT, nil, RIGHT, -4, 1)
+	srchEdit:SetColor(ZO_NORMAL_TEXT:UnpackRGBA())
+
+	local srchBg = wm:CreateControl("$(parent)Bg", boxControl, CT_BACKDROP)
+	srchBg:SetAnchorFill()
+	srchBg:SetAlpha(0)
+	srchBg:SetCenterColor(0, 0, 0, 0.5)
+	srchBg:SetEdgeColor(ZO_DISABLED_TEXT:UnpackRGBA())
+	srchBg:SetEdgeTexture("", 1, 1, 0, 0)
+
+	-- search backdrop should appear whenever you hover over either
+	-- the magnifying glass button or the edit field (which is only
+	-- visible when it contains some text), and also while the edit
+	-- field has keyboard focus
+
+	local srchActive = false
+	local srchHover = false
+
+	local function srchBgUpdateAlpha()
+		if srchActive or srchEdit:HasFocus() then
+			srchBg:SetAlpha(srchHover and 0.8 or 0.6)
 		else
-			button:SetAnchor(TOPLEFT, _G["LAMAddonMenuButton"..i-1], BOTTOMLEFT)
+			srchBg:SetAlpha(srchHover and 0.6 or 0.0)
 		end
-		button:SetHandler("OnClicked", function(self) self.panel:SetHidden(false) end)
 	end
+
+	local function srchMouseEnter(control)
+		srchHover = true
+		srchBgUpdateAlpha()
+	end
+
+	local function srchMouseExit(control)
+		srchHover = false
+		srchBgUpdateAlpha()
+	end
+
+	boxControl:SetMouseEnabled(true)
+	boxControl:SetHitInsets(1, 1, -1, -1)
+	boxControl:SetHandler("OnMouseEnter", srchMouseEnter)
+	boxControl:SetHandler("OnMouseExit", srchMouseExit)
+
+	srchButton:SetHandler("OnMouseEnter", srchMouseEnter)
+	srchButton:SetHandler("OnMouseExit", srchMouseExit)
+
+	local focusLostTime = 0
+
+	srchButton:SetHandler("OnClicked", function(self)
+		srchEdit:Clear()
+		if GetFrameTimeMilliseconds() - focusLostTime < 100 then
+			-- re-focus the edit box if it lost focus due to this
+			-- button click (note that this handler may run a few
+			-- frames later)
+			srchEdit:TakeFocus()
+		end
+	end)
+
+	srchEdit:SetHandler("OnMouseEnter", srchMouseEnter)
+	srchEdit:SetHandler("OnMouseExit", srchMouseExit)
+	srchEdit:SetHandler("OnFocusGained", srchBgUpdateAlpha)
+
+	srchEdit:SetHandler("OnFocusLost", function()
+		focusLostTime = GetFrameTimeMilliseconds()
+		srchBgUpdateAlpha()
+	end)
+
+	srchEdit:SetHandler("OnEscape", function(self)
+		self:Clear()
+		self:LoseFocus()
+	end)
+
+	srchEdit:SetHandler("OnTextChanged", function(self)
+		local filterFunc = GetSearchFilterFunc(self)
+		if filterFunc then
+			srchActive = true
+			srchBg:SetEdgeColor(ZO_SECOND_CONTRAST_TEXT:UnpackRGBA())
+			srchButton:SetState(BSTATE_PRESSED)
+		else
+			srchActive = false
+			srchBg:SetEdgeColor(ZO_DISABLED_TEXT:UnpackRGBA())
+			srchButton:SetState(BSTATE_NORMAL)
+		end
+		srchBgUpdateAlpha()
+		PopulateAddonList(lam.addonList, filterFunc)
+		PlaySound(SOUNDS.SPINNER_DOWN)
+	end)
+
+	return boxControl
 end


 --INTERNAL FUNCTION
---creates the left-hand menu in LAM's panel
-local function CreateAddonList()
-	local list
-	--check if an earlier loaded copy of LAM created it already
-	list = LAMAddonPanelsMenu or wm:CreateControlFromVirtual("LAMAddonPanelsMenu", optionsWindow, "ZO_ScrollContainer")
-	list:ClearAnchors()
-	list:SetAnchor(TOPLEFT)
-	list:SetHeight(675)
-	list:SetWidth(200)
-
-	list.bg = list.bg or wm:CreateControl(nil, list, CT_BACKDROP)
-	local bg = list.bg
-	bg:SetAnchorFill()	--offsets of 8?
-	bg:SetEdgeTexture("EsoUI\\Art\\miscellaneous\\borderedinsettransparent_edgefile.dds", 128, 16)
-	bg:SetCenterColor(0, 0, 0, 0)
-
-	list.scrollChild = LAMAddonPanelsMenuScrollChild
-	list.scrollChild:SetResizeToFitPadding(0, 15)
-
-	local generatedButtons
-	list:SetHandler("OnShow", function(self)
-			if not generatedButtons and #addonsForList > 0 then
-				--we're about to show our list for the first time - let's sort the buttons before creating them
-				table.sort(addonsForList, function(a, b)
-						return a.name < b.name
-					end)
-				CreateAddonButtons(list, addonsForList)
-				self.currentlySelected = LAMAddonMenuButton1 and LAMAddonMenuButton1.panel
-				--since our addon panels don't have a parent, let's make sure they hide when we're done with them
-				ZO_PreHookHandler(ZO_OptionsWindow, "OnHide", function() self.currentlySelected:SetHidden(true) end)
-				generatedButtons = true
-			end
-			if self.currentlySelected then self.currentlySelected:SetHidden(false) end
-		end)
-
-	--list.controlType = OPTIONS_CUSTOM
-	--list.panel = lam.panelID
-	list.data = {
-		controlType = OPTIONS_CUSTOM,
-		panel = lam.panelID,
-	}
-
-	ZO_OptionsWindow_InitializeControl(list)
+--creates LAM's Addon Settings top-level window
+local function CreateAddonSettingsWindow()
+	local tlw = wm:CreateTopLevelWindow("LAMAddonSettingsWindow")
+	tlw:SetHidden(true)
+	tlw:SetDimensions(1010, 914) -- same height as ZO_OptionsWindow
+
+	ZO_ReanchorControlForLeftSidePanel(tlw)
+
+	-- create black background for the window (mimic ZO_RightFootPrintBackground)
+
+	local bgLeft = wm:CreateControl("$(parent)BackgroundLeft", tlw, CT_TEXTURE)
+	bgLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_left.dds")
+	bgLeft:SetDimensions(1024, 1024)
+	bgLeft:SetAnchor(TOPLEFT, nil, TOPLEFT)
+	bgLeft:SetDrawLayer(DL_BACKGROUND)
+	bgLeft:SetExcludeFromResizeToFitExtents(true)
+
+	local bgRight = wm:CreateControl("$(parent)BackgroundRight", tlw, CT_TEXTURE)
+	bgRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_right.dds")
+	bgRight:SetDimensions(64, 1024)
+	bgRight:SetAnchor(TOPLEFT, bgLeft, TOPRIGHT)
+	bgRight:SetDrawLayer(DL_BACKGROUND)
+	bgRight:SetExcludeFromResizeToFitExtents(true)
+
+	-- create gray background for addon list (mimic ZO_TreeUnderlay)
+
+	local underlayLeft = wm:CreateControl("$(parent)UnderlayLeft", tlw, CT_TEXTURE)
+	underlayLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_left.dds")
+	underlayLeft:SetDimensions(256, 1024)
+	underlayLeft:SetAnchor(TOPLEFT, bgLeft, TOPLEFT)
+	underlayLeft:SetDrawLayer(DL_BACKGROUND)
+	underlayLeft:SetExcludeFromResizeToFitExtents(true)
+
+	local underlayRight = wm:CreateControl("$(parent)UnderlayRight", tlw, CT_TEXTURE)
+	underlayRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_right.dds")
+	underlayRight:SetDimensions(128, 1024)
+	underlayRight:SetAnchor(TOPLEFT, underlayLeft, TOPRIGHT)
+	underlayRight:SetDrawLayer(DL_BACKGROUND)
+	underlayRight:SetExcludeFromResizeToFitExtents(true)
+
+	-- create title bar (mimic ZO_OptionsWindow)
+
+	local title = wm:CreateControl("$(parent)Title", tlw, CT_LABEL)
+	title:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 70)
+	title:SetFont("ZoFontWinH1")
+	title:SetModifyTextType(MODIFY_TEXT_TYPE_UPPERCASE)

-	return list
+	local divider = wm:CreateControlFromVirtual("$(parent)Divider", tlw, "ZO_Options_Divider")
+	divider:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 108)
+
+	-- create search filter box
+
+	local srchBox = CreateSearchFilterBox("$(parent)SearchFilter", tlw)
+	srchBox:SetAnchor(TOPLEFT, nil, TOPLEFT, 63, 120)
+	srchBox:SetDimensions(260, 30)
+
+	-- create scrollable addon list
+
+	local addonList = CreateAddonList("$(parent)AddonList", tlw)
+	addonList:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 160)
+	addonList:SetDimensions(285, 665)
+
+	lam.addonList = addonList -- for easy access from elsewhere
+
+	-- create container for option panels
+
+	local panelContainer = wm:CreateControl("$(parent)PanelContainer", tlw, CT_CONTROL)
+	panelContainer:SetAnchor(TOPLEFT, nil, TOPLEFT, 365, 120)
+	panelContainer:SetDimensions(645, 675)
+
+	return tlw
 end

+
 --INITIALIZING
 local safeToInitialize = false
+local hasInitialized = false

 local eventHandle = table.concat({MAJOR, MINOR}, "r")
 local function OnLoad(_, addonName)
 	-- wait for the first loaded event
-	EVENT_MANAGER:UnregisterForEvent(eventHandle, EVENT_ADD_ON_LOADED)
+	em:UnregisterForEvent(eventHandle, EVENT_ADD_ON_LOADED)
 	safeToInitialize = true
 end
-EVENT_MANAGER:RegisterForEvent(eventHandle, EVENT_ADD_ON_LOADED, OnLoad)
+em:RegisterForEvent(eventHandle, EVENT_ADD_ON_LOADED, OnLoad)

 local function OnActivated(_, addonName)
-	EVENT_MANAGER:UnregisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED)
+	em:UnregisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED)
 	FlushMessages()
 end
-EVENT_MANAGER:RegisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED, OnActivated)
+em:RegisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED, OnActivated)

-function Initialize(addonID)
-	if(not safeToInitialize) then
+function CheckSafetyAndInitialize(addonID)
+	if not safeToInitialize then
 		local msg = string.format("The panel with id '%s' was registered before addon loading has completed. This might break the AddOn Settings menu.", addonID)
 		PrintLater(msg)
 	end
-	CreateAddonSettingsPanel()
-	CreateAddonList()
-	hasInitialized = true
+	if not hasInitialized then
+		hasInitialized = true
+	end
+end
+
+
+--TODO documentation
+function lam:GetAddonPanelContainer()
+	local fragment = lam:GetAddonSettingsFragment()
+	local window = fragment:GetControl()
+	return window:GetNamedChild("PanelContainer")
+end
+
+
+--TODO documentation
+function lam:GetAddonSettingsFragment()
+	assert(hasInitialized or safeToInitialize)
+	if not LAMAddonSettingsFragment then
+		local window = CreateAddonSettingsWindow()
+		LAMAddonSettingsFragment = ZO_FadeSceneFragment:New(window, true, 100)
+		CreateAddonSettingsMenuEntry()
+	end
+	return LAMAddonSettingsFragment
 end
+
+
+-- vi: noexpandtab
diff --git a/lib/LibAddonMenu-2.0/controls/button.lua b/lib/LibAddonMenu-2.0/controls/button.lua
index 8a6ecda..7489872 100644
--- a/lib/LibAddonMenu-2.0/controls/button.lua
+++ b/lib/LibAddonMenu-2.0/controls/button.lua
@@ -11,7 +11,7 @@
 }	]]


-local widgetVersion = 6
+local widgetVersion = 8
 local LAM = LibStub("LibAddonMenu-2.0")
 if not LAM:RegisterWidget("button", widgetVersion) then return end

@@ -26,19 +26,25 @@ local function UpdateDisabled(control)
 	else
 		disable = control.data.disabled
 	end
-
+
 	control.button:SetEnabled(not disable)
 end


 --controlName is optional
+local MIN_HEIGHT = 28 -- default_button height
+local HALF_WIDTH_LINE_SPACING = 2
 function LAMCreateControl.button(parent, buttonData, controlName)
-	local control = wm:CreateControl(controlName or buttonData.reference, parent.scroll or parent, CT_CONTROL)
-
-	local isHalfWidth = buttonData.width == "half"
-	control:SetDimensions(isHalfWidth and 250 or 510, isHalfWidth and 55 or 28)
+	local control = LAM.util.CreateBaseControl(parent, buttonData, controlName)
 	control:SetMouseEnabled(true)

+	local width = control:GetWidth()
+	if control.isHalfWidth then
+		control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING)
+	else
+		control:SetDimensions(width, MIN_HEIGHT)
+	end
+
 	if buttonData.icon then
 		control.button = wm:CreateControl(nil, control, CT_BUTTON)
 		control.button:SetDimensions(26, 26)
@@ -47,34 +53,29 @@ function LAMCreateControl.button(parent, buttonData, controlName)
 	else
 		--control.button = wm:CreateControlFromVirtual(controlName.."Button", control, "ZO_DefaultButton")
 		control.button = wm:CreateControlFromVirtual(nil, control, "ZO_DefaultButton")
-		control.button:SetWidth(isHalfWidth and 180 or 200)
+		control.button:SetWidth(width / 3)
 		control.button:SetText(buttonData.name)
 	end
 	local button = control.button
-	button:SetAnchor(isHalfWidth and CENTER or RIGHT)
+	button:SetAnchor(control.isHalfWidth and CENTER or RIGHT)
 	button:SetClickSound("Click")
-	--button.tooltipText = buttonData.tooltip
-	button.data = {tooltipText = buttonData.tooltip}
+	button.data = {tooltipText = LAM.util.GetTooltipText(buttonData.tooltip)}
 	button:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
 	button:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
 	button:SetHandler("OnClicked", function(self, ...)
-			buttonData.func(self, ...)
-			if control.panel.data.registerForRefresh then
-				cm:FireCallbacks("LAM-RefreshPanel", control)
-			end
-		end)
+		buttonData.func(self, ...)
+		if control.panel.data.registerForRefresh then
+			cm:FireCallbacks("LAM-RefreshPanel", control)
+		end
+	end)

 	if buttonData.warning then
 		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
 		control.warning:SetAnchor(RIGHT, button, LEFT, -5, 0)
-		--control.warning.tooltipText = buttonData.warning
 		control.warning.data = {tooltipText = buttonData.warning}
 	end

-	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
-	control.data = buttonData
-
-	if buttonData.disabled then
+	if buttonData.disabled ~= nil then
 		control.UpdateDisabled = UpdateDisabled
 		control:UpdateDisabled()

@@ -85,4 +86,4 @@ function LAMCreateControl.button(parent, buttonData, controlName)
 	end

 	return control
-end
\ No newline at end of file
+end
diff --git a/lib/LibAddonMenu-2.0/controls/checkbox.lua b/lib/LibAddonMenu-2.0/controls/checkbox.lua
index ef8bf09..46fe069 100644
--- a/lib/LibAddonMenu-2.0/controls/checkbox.lua
+++ b/lib/LibAddonMenu-2.0/controls/checkbox.lua
@@ -12,7 +12,7 @@
 }	]]


-local widgetVersion = 8
+local widgetVersion = 10
 local LAM = LibStub("LibAddonMenu-2.0")
 if not LAM:RegisterWidget("checkbox", widgetVersion) then return end

@@ -101,62 +101,35 @@ local function OnMouseExit(control)
 	control.checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA())
 end

-
 --controlName is optional
 function LAMCreateControl.checkbox(parent, checkboxData, controlName)
-	local control = wm:CreateControl(controlName or checkboxData.reference, parent.scroll or parent, CT_CONTROL)
-	control:SetMouseEnabled(true)
-	--control.tooltipText = checkboxData.tooltip
+	local control = LAM.util.CreateLabelAndContainerControl(parent, checkboxData, controlName)
 	control:SetHandler("OnMouseEnter", OnMouseEnter)
 	control:SetHandler("OnMouseExit", OnMouseExit)
 	control:SetHandler("OnMouseUp", function(control)
-			if control.isDisabled then return end
-			PlaySound(SOUNDS.DEFAULT_CLICK)
-			control.value = not control.value
-			control:UpdateValue(false, control.value)
-		end)
-
-	control.label = wm:CreateControl(nil, control, CT_LABEL)
-	local label = control.label
-	label:SetFont("ZoFontWinH4")
-	label:SetText(checkboxData.name)
-	label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
-	label:SetHeight(26)
+		if control.isDisabled then return end
+		PlaySound(SOUNDS.DEFAULT_CLICK)
+		control.value = not control.value
+		control:UpdateValue(false, control.value)
+	end)

-	control.checkbox = wm:CreateControl(nil, control, CT_LABEL)
+	control.checkbox = wm:CreateControl(nil, control.container, CT_LABEL)
 	local checkbox = control.checkbox
+	checkbox:SetAnchor(LEFT, control.container, LEFT, 0, 0)
 	checkbox:SetFont("ZoFontGameBold")
 	checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA())
 	control.checkedText = GetString(SI_CHECK_BUTTON_ON):upper()
 	control.uncheckedText = GetString(SI_CHECK_BUTTON_OFF):upper()

-	local isHalfWidth = checkboxData.width == "half"
-	if isHalfWidth then
-		control:SetDimensions(250, 55)
-		checkbox:SetDimensions(100, 26)
-		checkbox:SetAnchor(BOTTOMRIGHT)
-		label:SetAnchor(TOPLEFT)
-		label:SetAnchor(TOPRIGHT)
-	else
-		control:SetDimensions(510, 30)
-		checkbox:SetDimensions(200, 26)
-		checkbox:SetAnchor(RIGHT)
-		label:SetAnchor(LEFT)
-		label:SetAnchor(RIGHT, checkbox, LEFT, -5, 0)
-	end
-
 	if checkboxData.warning then
 		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
 		control.warning:SetAnchor(RIGHT, checkbox, LEFT, -5, 0)
-		--control.warning.tooltipText = checkboxData.warning
 		control.warning.data = {tooltipText = checkboxData.warning}
 	end

-	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
-	control.data = checkboxData
-	control.data.tooltipText = checkboxData.tooltip
+	control.data.tooltipText = LAM.util.GetTooltipText(checkboxData.tooltip)

-	if checkboxData.disabled then
+	if checkboxData.disabled ~= nil then
 		control.UpdateDisabled = UpdateDisabled
 		control:UpdateDisabled()
 	end
@@ -168,4 +141,4 @@ function LAMCreateControl.checkbox(parent, checkboxData, controlName)
 	end

 	return control
-end
\ No newline at end of file
+end
diff --git a/lib/LibAddonMenu-2.0/controls/colorpicker.lua b/lib/LibAddonMenu-2.0/controls/colorpicker.lua
index c5724b0..184a2e4 100644
--- a/lib/LibAddonMenu-2.0/controls/colorpicker.lua
+++ b/lib/LibAddonMenu-2.0/controls/colorpicker.lua
@@ -12,7 +12,7 @@
 }	]]


-local widgetVersion = 6
+local widgetVersion = 8
 local LAM = LibStub("LibAddonMenu-2.0")
 if not LAM:RegisterWidget("colorpicker", widgetVersion) then return end

@@ -38,7 +38,7 @@ local function UpdateDisabled(control)
 	control.isDisabled = disable
 end

-local function UpdateValue(control, forceDefault, valueR, valueG, valueB, valueA)
+local function UpdateValue(control, forceDefault, valueR, valueG, valueB, valueA)
 	if forceDefault then	--if we are forcing defaults
 		local color = control.data.default
 		valueR, valueG, valueB, valueA = color.r, color.g, color.b, color.a
@@ -53,39 +53,14 @@ local function UpdateValue(control, forceDefault, valueR, valueG, valueB, valueA
 		valueR, valueG, valueB, valueA = control.data.getFunc()
 	end

-	control.thumb:SetColor(valueR, valueG, valueB, valueA or 1)
+	control.thumb:SetColor(valueR, valueG, valueB, valueA or 1)
 end

-
 function LAMCreateControl.colorpicker(parent, colorpickerData, controlName)
-	local control = wm:CreateControl(controlName or colorpickerData.reference, parent.scroll or parent, CT_CONTROL)
-	control:SetMouseEnabled(true)
-	control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
-	control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
-
-	control.label = wm:CreateControl(nil, control, CT_LABEL)
-	local label = control.label
-	label:SetDimensions(300, 26)
-	label:SetAnchor(TOPLEFT)
-	label:SetFont("ZoFontWinH4")
-	label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
-	label:SetText(colorpickerData.name)
-
-	control.color = wm:CreateControl(nil, control, CT_CONTROL)
-	local color = control.color
+	local control = LAM.util.CreateLabelAndContainerControl(parent, colorpickerData, controlName)

-	local isHalfWidth = colorpickerData.width == "half"
-	if isHalfWidth then
-		control:SetDimensions(250, 55)
-		label:SetDimensions(250, 26)
-		color:SetDimensions(100, 24)
-		color:SetAnchor(TOPRIGHT, label, BOTTOMRIGHT)
-	else
-		control:SetDimensions(510, 30)
-		label:SetDimensions(300, 26)
-		color:SetDimensions(200, 24)
-		color:SetAnchor(TOPRIGHT)
-	end
+	control.color = control.container
+	local color = control.color

 	control.thumb = wm:CreateControl(nil, color, CT_TEXTURE)
 	local thumb = control.thumb
@@ -100,30 +75,27 @@ function LAMCreateControl.colorpicker(parent, colorpickerData, controlName)
 	border:SetAnchor(CENTER, thumb, CENTER, 0, 0)

 	local function ColorPickerCallback(r, g, b, a)
-			control:UpdateValue(false, r, g, b, a)
-		end
+		control:UpdateValue(false, r, g, b, a)
+	end

 	control:SetHandler("OnMouseUp", function(self, btn, upInside)
-			if self.isDisabled then return end
+		if self.isDisabled then return end

-			if upInside then
-				local r, g, b, a = colorpickerData.getFunc()
-				COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a, colorpickerData.name)
-			end
-		end)
+		if upInside then
+			local r, g, b, a = colorpickerData.getFunc()
+			COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a, colorpickerData.name)
+		end
+	end)

 	if colorpickerData.warning then
 		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
 		control.warning:SetAnchor(RIGHT, control.color, LEFT, -5, 0)
-		--control.warning.tooltipText = colorpickerData.warning
 		control.warning.data = {tooltipText = colorpickerData.warning}
 	end

-	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
-	control.data = colorpickerData
-	control.data.tooltipText = colorpickerData.tooltip
+	control.data.tooltipText = LAM.util.GetTooltipText(colorpickerData.tooltip)

-	if colorpickerData.disabled then
+	if colorpickerData.disabled ~= nil then
 		control.UpdateDisabled = UpdateDisabled
 		control:UpdateDisabled()
 	end
@@ -135,4 +107,4 @@ function LAMCreateControl.colorpicker(parent, colorpickerData, controlName)
 	end

 	return control
-end
\ No newline at end of file
+end
diff --git a/lib/LibAddonMenu-2.0/controls/custom.lua b/lib/LibAddonMenu-2.0/controls/custom.lua
index 6a31c34..921402a 100644
--- a/lib/LibAddonMenu-2.0/controls/custom.lua
+++ b/lib/LibAddonMenu-2.0/controls/custom.lua
@@ -5,7 +5,7 @@
 	width = "full",	--or "half" (optional)
 }	]]

-local widgetVersion = 5
+local widgetVersion = 6
 local LAM = LibStub("LibAddonMenu-2.0")
 if not LAM:RegisterWidget("custom", widgetVersion) then return end

@@ -18,21 +18,17 @@ local function UpdateValue(control)
 	end
 end

+local MIN_HEIGHT = 26
 function LAMCreateControl.custom(parent, customData, controlName)
-	local control = wm:CreateControl(controlName or customData.reference, parent.scroll or parent, CT_CONTROL)
+	local control = LAM.util.CreateBaseControl(parent, customData, controlName)
+	local width = control:GetWidth()
 	control:SetResizeToFitDescendents(true)

-	local isHalfWidth = customData.width == "half"
-	if isHalfWidth then	--note these restrictions
-		control:SetDimensionConstraints(250, 55, 250, 100)
-		control:SetDimensions(250, 55)
+	if control.isHalfWidth then	--note these restrictions
+		control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4)
 	else
-		control:SetDimensionConstraints(510, 30, 510, 100)
-		control:SetDimensions(510, 30)
+		control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4)
 	end
-
-	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
-	control.data = customData

 	control.UpdateValue = UpdateValue

diff --git a/lib/LibAddonMenu-2.0/controls/description.lua b/lib/LibAddonMenu-2.0/controls/description.lua
index b886b83..233d525 100644
--- a/lib/LibAddonMenu-2.0/controls/description.lua
+++ b/lib/LibAddonMenu-2.0/controls/description.lua
@@ -7,7 +7,7 @@
 }	]]


-local widgetVersion = 5
+local widgetVersion = 7
 local LAM = LibStub("LibAddonMenu-2.0")
 if not LAM:RegisterWidget("description", widgetVersion) then return end

@@ -22,15 +22,15 @@ local function UpdateValue(control)
 end

 function LAMCreateControl.description(parent, descriptionData, controlName)
-	local control = wm:CreateControl(controlName or descriptionData.reference, parent.scroll or parent, CT_CONTROL)
+	local control = LAM.util.CreateBaseControl(parent, descriptionData, controlName)
+	local isHalfWidth = control.isHalfWidth
+	local width = control:GetWidth()
 	control:SetResizeToFitDescendents(true)
-	local isHalfWidth = descriptionData.width == "half"
+
 	if isHalfWidth then
-		control:SetDimensionConstraints(250, 55, 250, 100)
-		control:SetDimensions(250, 55)
+		control:SetDimensionConstraints(width / 2, 0, width / 2, 0)
 	else
-		control:SetDimensionConstraints(510, 40, 510, 100)
-		control:SetDimensions(510, 30)
+		control:SetDimensionConstraints(width, 0, width, 0)
 	end

 	control.desc = wm:CreateControl(nil, control, CT_LABEL)
@@ -38,12 +38,12 @@ function LAMCreateControl.description(parent, descriptionData, controlName)
 	desc:SetVerticalAlignment(TEXT_ALIGN_TOP)
 	desc:SetFont("ZoFontGame")
 	desc:SetText(descriptionData.text)
-	desc:SetWidth(isHalfWidth and 250 or 510)
+	desc:SetWidth(isHalfWidth and width / 2 or width)

 	if descriptionData.title then
 		control.title = wm:CreateControl(nil, control, CT_LABEL)
 		local title = control.title
-		title:SetWidth(isHalfWidth and 250 or 510)
+		title:SetWidth(isHalfWidth and width / 2 or width)
 		title:SetAnchor(TOPLEFT, control, TOPLEFT)
 		title:SetFont("ZoFontWinH4")
 		title:SetText(descriptionData.title)
@@ -52,9 +52,6 @@ function LAMCreateControl.description(parent, descriptionData, controlName)
 		desc:SetAnchor(TOPLEFT)
 	end

-	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
-	control.data = descriptionData
-
 	control.UpdateValue = UpdateValue

 	if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then	--if our parent window wants to refresh controls, then add this to the list
diff --git a/lib/LibAddonMenu-2.0/controls/dropdown.lua b/lib/LibAddonMenu-2.0/controls/dropdown.lua
index 795404c..5bdd546 100644
--- a/lib/LibAddonMenu-2.0/controls/dropdown.lua
+++ b/lib/LibAddonMenu-2.0/controls/dropdown.lua
@@ -14,7 +14,7 @@
 }	]]


-local widgetVersion = 8
+local widgetVersion = 10
 local LAM = LibStub("LibAddonMenu-2.0")
 if not LAM:RegisterWidget("dropdown", widgetVersion) then return end

@@ -82,19 +82,8 @@ local function GrabSortingInfo(sortInfo)
 	return t
 end

-
 function LAMCreateControl.dropdown(parent, dropdownData, controlName)
-	local control = wm:CreateControl(controlName or dropdownData.reference, parent.scroll or parent, CT_CONTROL)
-	control:SetMouseEnabled(true)
-	control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
-	control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
-
-	control.label = wm:CreateControl(nil, control, CT_LABEL)
-	local label = control.label
-	label:SetAnchor(TOPLEFT)
-	label:SetFont("ZoFontWinH4")
-	label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
-	label:SetText(dropdownData.name)
+	local control = LAM.util.CreateLabelAndContainerControl(parent, dropdownData, controlName)

 	local countControl = parent
 	local name = parent:GetName()
@@ -104,9 +93,11 @@ function LAMCreateControl.dropdown(parent, dropdownData, controlName)
 	end
 	local comboboxCount = (countControl.comboboxCount or 0) + 1
 	countControl.comboboxCount = comboboxCount
-	control.combobox = wm:CreateControlFromVirtual(zo_strjoin(nil, name, "Combobox", comboboxCount), control, "ZO_ComboBox")
+	control.combobox = wm:CreateControlFromVirtual(zo_strjoin(nil, name, "Combobox", comboboxCount), control.container, "ZO_ComboBox")

 	local combobox = control.combobox
+	combobox:SetAnchor(TOPLEFT)
+	combobox:SetDimensions(control.container:GetDimensions())
 	combobox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end)
 	combobox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end)
 	control.dropdown = ZO_ComboBox_ObjectFromContainer(combobox)
@@ -117,30 +108,13 @@ function LAMCreateControl.dropdown(parent, dropdownData, controlName)
 		dropdown:SetSortOrder(sortOrder == "up" and ZO_SORT_ORDER_UP or ZO_SORT_ORDER_DOWN, sortType == "name" and ZO_SORT_BY_NAME or ZO_SORT_BY_NAME_NUMERIC)
 	end

-	local isHalfWidth = dropdownData.width == "half"
-	if isHalfWidth then
-		control:SetDimensions(250, 55)
-		label:SetDimensions(250, 26)
-		combobox:SetDimensions(225, 26)
-		combobox:SetAnchor(TOPRIGHT, label, BOTTOMRIGHT)
-	else
-		control:SetDimensions(510, 30)
-		label:SetDimensions(300, 26)
-		combobox:SetDimensions(200, 26)
-		combobox:SetAnchor(TOPRIGHT)
-	end
-
 	if dropdownData.warning then
 		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
 		control.warning:SetAnchor(RIGHT, combobox, LEFT, -5, 0)
 		control.warning.data = {tooltipText = dropdownData.warning}
 	end

-	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
-	control.data = dropdownData
-	control.data.tooltipText = dropdownData.tooltip
-
-	if dropdownData.disabled then
+	if dropdownData.disabled ~= nil then
 		control.UpdateDisabled = UpdateDisabled
 		control:UpdateDisabled()
 	end
@@ -154,4 +128,4 @@ function LAMCreateControl.dropdown(parent, dropdownData, controlName)
 	end

 	return control
-end
\ No newline at end of file
+end
diff --git a/lib/LibAddonMenu-2.0/controls/editbox.lua b/lib/LibAddonMenu-2.0/controls/editbox.lua
index 3ab069f..1f9bb47 100644
--- a/lib/LibAddonMenu-2.0/controls/editbox.lua
+++ b/lib/LibAddonMenu-2.0/controls/editbox.lua
@@ -4,7 +4,8 @@
 	tooltip = "Editbox's tooltip text.",
 	getFunc = function() return db.text end,
 	setFunc = function(text) db.text = text doStuff() end,
-	isMultiline = true,	--boolean
+	isMultiline = true,	--boolean (optional)
+	isExtraWide = true,	--boolean (optional)
 	width = "full",	--or "half" (optional)
 	disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
 	warning = "Will need to reload the UI.",	--(optional)
@@ -13,7 +14,7 @@
 }	]]


-local widgetVersion = 7
+local widgetVersion = 9
 local LAM = LibStub("LibAddonMenu-2.0")
 if not LAM:RegisterWidget("editbox", widgetVersion) then return end

@@ -29,7 +30,7 @@ local function UpdateDisabled(control)
 	else
 		disable = control.data.disabled
 	end
-
+
 	if disable then
 		control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
 		control.editbox:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA())
@@ -41,7 +42,7 @@ local function UpdateDisabled(control)
 	control.editbox:SetMouseEnabled(not disable)
 end

-local function UpdateValue(control, forceDefault, value)
+local function UpdateValue(control, forceDefault, value)
 	if forceDefault then	--if we are forcing defaults
 		value = control.data.default
 		control.data.setFunc(value)
@@ -58,45 +59,37 @@ local function UpdateValue(control, forceDefault, value)
 	end
 end

-
+local MIN_HEIGHT = 24
+local HALF_WIDTH_LINE_SPACING = 2
 function LAMCreateControl.editbox(parent, editboxData, controlName)
-	local control = wm:CreateControl(controlName or editboxData.reference, parent.scroll or parent, CT_CONTROL)
-	control:SetMouseEnabled(true)
-	control:SetResizeToFitDescendents(true)
-	control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
-	control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
-
-	control.label = wm:CreateControl(nil, control, CT_LABEL)
-	local label = control.label
-	label:SetAnchor(TOPLEFT)
-	label:SetFont("ZoFontWinH4")
-	label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
-	label:SetText(editboxData.name)
-
-	control.bg = wm:CreateControlFromVirtual(nil, control, "ZO_EditBackdrop")
+	local control = LAM.util.CreateLabelAndContainerControl(parent, editboxData, controlName)
+
+	local container = control.container
+	control.bg = wm:CreateControlFromVirtual(nil, container, "ZO_EditBackdrop")
 	local bg = control.bg
+	bg:SetAnchorFill()

 	if editboxData.isMultiline then
 		control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditMultiLineForBackdrop")
 		control.editbox:SetHandler("OnMouseWheel", function(self, delta)
-				if self:HasFocus() then	--only set focus to new spots if the editbox is currently in use
-					local cursorPos = self:GetCursorPosition()
-					local text = self:GetText()
-					local textLen = text:len()
-					local newPos
-					if delta > 0 then	--scrolling up
-						local reverseText = text:reverse()
-						local revCursorPos = textLen - cursorPos
-						local revPos = reverseText:find("\n", revCursorPos+1)
-						newPos = revPos and textLen - revPos
-					else	--scrolling down
-						newPos = text:find("\n", cursorPos+1)
-					end
-					if newPos then	--if we found a new line, then scroll, otherwise don't
-						self:SetCursorPosition(newPos)
-					end
+			if self:HasFocus() then	--only set focus to new spots if the editbox is currently in use
+				local cursorPos = self:GetCursorPosition()
+				local text = self:GetText()
+				local textLen = text:len()
+				local newPos
+				if delta > 0 then	--scrolling up
+					local reverseText = text:reverse()
+					local revCursorPos = textLen - cursorPos
+					local revPos = reverseText:find("\n", revCursorPos+1)
+					newPos = revPos and textLen - revPos
+				else	--scrolling down
+					newPos = text:find("\n", cursorPos+1)
 				end
-			end)
+				if newPos then	--if we found a new line, then scroll, otherwise don't
+					self:SetCursorPosition(newPos)
+				end
+			end
+		end)
 	else
 		control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditForBackdrop")
 	end
@@ -108,37 +101,51 @@ function LAMCreateControl.editbox(parent, editboxData, controlName)
 	editbox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end)
 	editbox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end)

-	local isHalfWidth = editboxData.width == "half"
-	if isHalfWidth then
-		control:SetDimensions(250, 55)
-		label:SetDimensions(250, 26)
-		bg:SetDimensions(225, editboxData.isMultiline and 74 or 24)
-		bg:SetAnchor(TOPRIGHT, label, BOTTOMRIGHT)
-		if editboxData.isMultiline then
-			editbox:SetDimensionConstraints(210, 74, 210, 500)
-		end
+	local MIN_WIDTH = (parent.GetWidth and (parent:GetWidth() / 10)) or (parent.panel.GetWidth and (parent.panel:GetWidth() / 10)) or 0
+
+	control.label:ClearAnchors()
+	container:ClearAnchors()
+
+	control.label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0)
+	container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0)
+
+	if control.isHalfWidth then
+		container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0)
+	end
+
+	if editboxData.isExtraWide then
+		container:SetAnchor(BOTTOMLEFT, control, BOTTOMLEFT, 0, 0)
 	else
-		control:SetDimensions(510, 30)
-		label:SetDimensions(300, 26)
-		bg:SetDimensions(200, editboxData.isMultiline and 100 or 24)
-		bg:SetAnchor(TOPRIGHT)
-		if editboxData.isMultiline then
-			editbox:SetDimensionConstraints(185, 100, 185, 500)
-		end
+		container:SetWidth(MIN_WIDTH * 3.2)
 	end

+	if editboxData.isMultiline then
+		container:SetHeight(MIN_HEIGHT * 3)
+	else
+		container:SetHeight(MIN_HEIGHT)
+	end
+
+	if control.isHalfWidth ~= true and editboxData.isExtraWide ~= true then
+		control:SetHeight(container:GetHeight())
+	else
+		control:SetHeight(container:GetHeight() + control.label:GetHeight())
+	end
+
+	editbox:ClearAnchors()
+	editbox:SetAnchor(TOPLEFT, container, TOPLEFT, 2, 2)
+	editbox:SetAnchor(BOTTOMRIGHT, container, BOTTOMRIGHT, -2, -2)
+
 	if editboxData.warning then
 		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
-		control.warning:SetAnchor(TOPRIGHT, control.bg, TOPLEFT, -5, 0)
-		--control.warning.tooltipText = editboxData.warning
+		if editboxData.isExtraWide then
+			control.warning:SetAnchor(BOTTOMRIGHT, control.bg, TOPRIGHT, 2, 0)
+		else
+			control.warning:SetAnchor(TOPRIGHT, control.bg, TOPLEFT, -5, 0)
+		end
 		control.warning.data = {tooltipText = editboxData.warning}
 	end

-	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
-	control.data = editboxData
-	control.data.tooltipText = editboxData.tooltip
-
-	if editboxData.disabled then
+	if editboxData.disabled ~= nil then
 		control.UpdateDisabled = UpdateDisabled
 		control:UpdateDisabled()
 	end
@@ -150,4 +157,4 @@ function LAMCreateControl.editbox(parent, editboxData, controlName)
 	end

 	return control
-end
\ No newline at end of file
+end
diff --git a/lib/LibAddonMenu-2.0/controls/header.lua b/lib/LibAddonMenu-2.0/controls/header.lua
index 83c862b..344f56b 100644
--- a/lib/LibAddonMenu-2.0/controls/header.lua
+++ b/lib/LibAddonMenu-2.0/controls/header.lua
@@ -6,7 +6,7 @@
 }	]]


-local widgetVersion = 5
+local widgetVersion = 6
 local LAM = LibStub("LibAddonMenu-2.0")
 if not LAM:RegisterWidget("header", widgetVersion) then return end

@@ -17,14 +17,16 @@ local function UpdateValue(control)
 	control.header:SetText(control.data.name)
 end

+local MIN_HEIGHT = 30
 function LAMCreateControl.header(parent, headerData, controlName)
-	local control = wm:CreateControl(controlName or headerData.reference, parent.scroll or parent, CT_CONTROL)
-	local isHalfWidth = headerData.width == "half"
-	control:SetDimensions(isHalfWidth and 250 or 510, 30)
+	local control = LAM.util.CreateBaseControl(parent, headerData, controlName)
+	local isHalfWidth = control.isHalfWidth
+	local width = control:GetWidth()
+	control:SetDimensions(isHalfWidth and width / 2 or width, MIN_HEIGHT)

 	control.divider = wm:CreateControlFromVirtual(nil, control, "ZO_Options_Divider")
 	local divider = control.divider
-	divider:SetWidth(isHalfWidth and 250 or 510)
+	divider:SetWidth(isHalfWidth and width / 2 or width)
 	divider:SetAnchor(TOPLEFT)

 	control.header = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel")
@@ -33,9 +35,6 @@ function LAMCreateControl.header(parent, headerData, controlName)
 	header:SetAnchor(BOTTOMRIGHT)
 	header:SetText(headerData.name)

-	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
-	control.data = headerData
-
 	control.UpdateValue = UpdateValue

 	if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then	--if our parent window wants to refresh controls, then add this to the list
diff --git a/lib/LibAddonMenu-2.0/controls/iconpicker.lua b/lib/LibAddonMenu-2.0/controls/iconpicker.lua
new file mode 100644
index 0000000..93c47f3
--- /dev/null
+++ b/lib/LibAddonMenu-2.0/controls/iconpicker.lua
@@ -0,0 +1,441 @@
+--[[iconpickerData = {
+	type = "iconpicker",
+	name = "My Icon Picker",
+	tooltip = "Color Picker's tooltip text.",
+	choices = {"texture path 1", "texture path 2", "texture path 3"},
+	choicesTooltips = {"icon tooltip 1", "icon tooltip 2", "icon tooltip 3"}, --(optional)
+	getFunc = function() return db.var end,
+	setFunc = function(var) db.var = var doStuff() end,
+	maxColumns = 5, --(optional) number of icons in one row
+	visibleRows = 4.5, --(optional) number of visible rows
+	iconSize = 28, --(optional) size of the icons
+	defaultColor = ZO_ColorDef:New("FFFFFF"), --(optional) default color of the icons
+	width = "full",	--or "half" (optional)
+	beforeShow = function(control, iconPicker) return preventShow end, --(optional)
+	disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
+	warning = "Will need to reload the UI.",	--(optional)
+	default = defaults.var,	--(optional)
+	reference = "MyAddonIconPicker"	--(optional) unique global reference to control
+}	]]
+
+local widgetVersion = 3
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("iconpicker", widgetVersion) then return end
+
+local wm = WINDOW_MANAGER
+local cm = CALLBACK_MANAGER
+local tinsert = table.insert
+
+local IconPickerMenu = ZO_Object:Subclass()
+local iconPicker
+LAM.util.GetIconPickerMenu = function()
+	if not iconPicker then
+		iconPicker = IconPickerMenu:New("LAMIconPicker")
+		local sceneFragment = LAM:GetAddonSettingsFragment()
+		ZO_PreHook(sceneFragment, "OnHidden", function()
+			if not iconPicker.control:IsHidden() then
+				iconPicker:Clear()
+			end
+		end)
+	end
+	return iconPicker
+end
+
+function IconPickerMenu:New(...)
+	local object = ZO_Object.New(self)
+	object:Initialize(...)
+	return object
+end
+
+function IconPickerMenu:Initialize(name)
+	local control = wm:CreateTopLevelWindow(name)
+	control:SetDrawTier(DT_HIGH)
+	control:SetHidden(true)
+	self.control = control
+
+	local scrollContainer = wm:CreateControlFromVirtual(name .. "ScrollContainer", control, "ZO_ScrollContainer")
+	-- control:SetDimensions(control.container:GetWidth(), height) -- adjust to icon size / col count
+	scrollContainer:SetAnchorFill()
+	ZO_Scroll_SetUseFadeGradient(scrollContainer, false)
+	ZO_Scroll_SetHideScrollbarOnDisable(scrollContainer, false)
+	ZO_VerticalScrollbarBase_OnMouseExit(scrollContainer:GetNamedChild("ScrollBar")) -- scrollbar initialization seems to be broken so we force it to update the correct alpha value
+	local scroll = GetControl(scrollContainer, "ScrollChild")
+	self.scroll = scroll
+	self.scrollContainer = scrollContainer
+
+	local bg = wm:CreateControl(nil, scrollContainer, CT_BACKDROP)
+	bg:SetAnchor(TOPLEFT, scrollContainer, TOPLEFT, 0, -3)
+	bg:SetAnchor(BOTTOMRIGHT, scrollContainer, BOTTOMRIGHT, 2, 5)
+	bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16)
+	bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds")
+	bg:SetInsets(16, 16, -16, -16)
+
+	local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE)
+	mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds")
+	mungeOverlay:SetDrawLevel(1)
+	mungeOverlay:SetAddressMode(TEX_MODE_WRAP)
+	mungeOverlay:SetAnchorFill()
+
+	local mouseOver = wm:CreateControl(nil, scrollContainer, CT_TEXTURE)
+	mouseOver:SetDrawLevel(2)
+	mouseOver:SetTexture("EsoUI/Art/Buttons/minmax_mouseover.dds")
+	mouseOver:SetHidden(true)
+
+	local function IconFactory(pool)
+		local icon = wm:CreateControl(name .. "Entry" .. pool:GetNextControlId(), scroll, CT_TEXTURE)
+		icon:SetMouseEnabled(true)
+		icon:SetDrawLevel(3)
+		icon:SetHandler("OnMouseEnter", function()
+			mouseOver:SetAnchor(TOPLEFT, icon, TOPLEFT, 0, 0)
+			mouseOver:SetAnchor(BOTTOMRIGHT, icon, BOTTOMRIGHT, 0, 0)
+			mouseOver:SetHidden(false)
+			if self.customOnMouseEnter then
+				self.customOnMouseEnter(icon)
+			else
+				self:OnMouseEnter(icon)
+			end
+		end)
+		icon:SetHandler("OnMouseExit", function()
+			mouseOver:ClearAnchors()
+			mouseOver:SetHidden(true)
+			if self.customOnMouseExit then
+				self.customOnMouseExit(icon)
+			else
+				self:OnMouseExit(icon)
+			end
+		end)
+		icon:SetHandler("OnMouseUp", function(control, ...)
+			PlaySound("Click")
+			icon.OnSelect(icon, icon.texture)
+			self:Clear()
+		end)
+		return icon
+	end
+
+	local function ResetFunction(icon)
+		icon:ClearAnchors()
+	end
+
+	self.iconPool = ZO_ObjectPool:New(IconFactory, ResetFunction)
+	self:SetMaxColumns(1)
+	self.icons = {}
+	self.color = ZO_DEFAULT_ENABLED_COLOR
+
+	EVENT_MANAGER:RegisterForEvent(name .. "_OnGlobalMouseUp", EVENT_GLOBAL_MOUSE_UP, function()
+		if self.refCount ~= nil then
+			local moc = wm:GetMouseOverControl()
+			if(moc:GetOwningWindow() ~= control) then
+				self.refCount = self.refCount - 1
+				if self.refCount <= 0 then
+					self:Clear()
+				end
+			end
+		end
+	end)
+end
+
+function IconPickerMenu:OnMouseEnter(icon)
+	InitializeTooltip(InformationTooltip, icon, TOPLEFT, 0, 0, BOTTOMRIGHT)
+	SetTooltipText(InformationTooltip, LAM.util.GetTooltipText(icon.tooltip))
+	InformationTooltipTopLevel:BringWindowToTop()
+end
+
+function IconPickerMenu:OnMouseExit(icon)
+	ClearTooltip(InformationTooltip)
+end
+
+function IconPickerMenu:SetMaxColumns(value)
+	self.maxCols = value ~= nil and value or 5
+end
+
+local DEFAULT_SIZE = 28
+function IconPickerMenu:SetIconSize(value)
+	local iconSize = DEFAULT_SIZE
+	if value ~= nil then iconSize = math.max(iconSize, value) end
+	self.iconSize = iconSize
+end
+
+function IconPickerMenu:SetVisibleRows(value)
+	self.visibleRows = value ~= nil and value or 4.5
+end
+
+function IconPickerMenu:SetMouseHandlers(onEnter, onExit)
+	self.customOnMouseEnter = onEnter
+	self.customOnMouseExit = onExit
+end
+
+function IconPickerMenu:UpdateDimensions()
+	local iconSize = self.iconSize
+	local width = iconSize * self.maxCols + 20
+	local height = iconSize * self.visibleRows
+	self.control:SetDimensions(width, height)
+
+	local icons = self.icons
+	for i = 1, #icons do
+		local icon = icons[i]
+		icon:SetDimensions(iconSize, iconSize)
+	end
+end
+
+function IconPickerMenu:UpdateAnchors()
+	local iconSize = self.iconSize
+	local col, maxCols = 1, self.maxCols
+	local previousCol, previousRow
+	local scroll = self.scroll
+	local icons = self.icons
+
+	for i = 1, #icons do
+		local icon = icons[i]
+		icon:ClearAnchors()
+		if i == 1 then
+			icon:SetAnchor(TOPLEFT, scroll, TOPLEFT, 0, 0)
+			previousRow = icon
+		elseif col == 1 then
+			icon:SetAnchor(TOPLEFT, previousRow, BOTTOMLEFT, 0, 0)
+			previousRow = icon
+		else
+			icon:SetAnchor(TOPLEFT, previousCol, TOPRIGHT, 0, 0)
+		end
+		previousCol = icon
+		col = col >= maxCols and 1 or col + 1
+	end
+end
+
+function IconPickerMenu:Clear()
+	self.icons = {}
+	self.iconPool:ReleaseAllObjects()
+	self.control:SetHidden(true)
+	self.color = ZO_DEFAULT_ENABLED_COLOR
+	self.refCount = nil
+	self.parent = nil
+	self.customOnMouseEnter = nil
+	self.customOnMouseExit = nil
+end
+
+function IconPickerMenu:AddIcon(texturePath, callback, tooltip)
+	local icon, key = self.iconPool:AcquireObject()
+	icon:SetTexture(texturePath)
+	icon:SetColor(self.color:UnpackRGBA())
+	icon.texture = texturePath
+	icon.tooltip = tooltip
+	icon.OnSelect = callback
+	self.icons[#self.icons + 1] = icon
+end
+
+function IconPickerMenu:Show(parent)
+	if #self.icons == 0 then return false end
+	if not self.control:IsHidden() then self:Clear() return false end
+	self:UpdateDimensions()
+	self:UpdateAnchors()
+
+	local control = self.control
+	control:ClearAnchors()
+	control:SetAnchor(TOPLEFT, parent, BOTTOMLEFT, 0, 8)
+	control:SetHidden(false)
+	control:BringWindowToTop()
+	self.parent = parent
+	self.refCount = 2
+
+	return true
+end
+
+function IconPickerMenu:SetColor(color)
+	local icons = self.icons
+	self.color = color
+	for i = 1, #icons do
+		local icon = icons[i]
+		icon:SetColor(color:UnpackRGBA())
+	end
+end
+
+-------------------------------------------------------------
+
+local function UpdateChoices(control, choices, choicesTooltips)
+	local data = control.data
+	if not choices then
+		choices, choicesTooltips = data.choices, data.choicesTooltips or {}
+	end
+	local addedChoices = {}
+
+	local iconPicker = LAM.util.GetIconPickerMenu()
+	iconPicker:Clear()
+	for i = 1, #choices do
+		local texture = choices[i]
+		if not addedChoices[texture] then -- remove duplicates
+			iconPicker:AddIcon(choices[i], function(self, texture)
+				control.icon:SetTexture(texture)
+				data.setFunc(texture)
+				if control.panel.data.registerForRefresh then
+					cm:FireCallbacks("LAM-RefreshPanel", control)
+				end
+			end, choicesTooltips[i])
+			addedChoices[texture] = true
+		end
+	end
+end
+
+local function IsDisabled(control)
+	if type(control.data.disabled) == "function" then
+		return control.data.disabled()
+	else
+		return control.data.disabled
+	end
+end
+
+local function SetColor(control, color)
+	local icon = control.icon
+	if IsDisabled(control) then
+		icon:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
+	else
+		icon.color = color or control.data.defaultColor or ZO_DEFAULT_ENABLED_COLOR
+		icon:SetColor(icon.color:UnpackRGBA())
+	end
+
+	local iconPicker = LAM.util.GetIconPickerMenu()
+	if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then
+		iconPicker:SetColor(icon.color)
+	end
+end
+
+local function UpdateDisabled(control)
+	local disable = IsDisabled(control)
+
+	control.dropdown:SetMouseEnabled(not disable)
+	control.dropdownButton:SetEnabled(not disable)
+
+	local iconPicker = LAM.util.GetIconPickerMenu()
+	if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then
+		iconPicker:Clear()
+	end
+
+	SetColor(control)
+	if disable then
+		control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
+	else
+		control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+	end
+end
+
+local function UpdateValue(control, forceDefault, value)
+	if forceDefault then	--if we are forcing defaults
+		value = control.data.default
+		control.data.setFunc(value)
+		control.icon:SetTexture(value)
+	elseif value then
+		control.data.setFunc(value)
+		--after setting this value, let's refresh the others to see if any should be disabled or have their settings changed
+		if control.panel.data.registerForRefresh then
+			cm:FireCallbacks("LAM-RefreshPanel", control)
+		end
+	else
+		value = control.data.getFunc()
+		control.icon:SetTexture(value)
+	end
+end
+
+local MIN_HEIGHT = 26
+local HALF_WIDTH_LINE_SPACING = 2
+local function SetIconSize(control, size)
+	local icon = control.icon
+	icon.size = size
+	icon:SetDimensions(size, size)
+
+	local height = size + 4
+	control.dropdown:SetDimensions(size + 20, height)
+	height = math.max(height, MIN_HEIGHT)
+	control.container:SetHeight(height)
+	if control.lineControl then
+		control.lineControl:SetHeight(MIN_HEIGHT + size + HALF_WIDTH_LINE_SPACING)
+	else
+		control:SetHeight(height)
+	end
+
+	local iconPicker = LAM.util.GetIconPickerMenu()
+	if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then
+		iconPicker:SetIconSize(size)
+		iconPicker:UpdateDimensions()
+		iconPicker:UpdateAnchors()
+	end
+end
+
+function LAMCreateControl.iconpicker(parent, iconpickerData, controlName)
+	local control = LAM.util.CreateLabelAndContainerControl(parent, iconpickerData, controlName)
+
+	local function ShowIconPicker()
+		local iconPicker = LAM.util.GetIconPickerMenu()
+		if iconPicker.parent == control.container then
+			iconPicker:Clear()
+		else
+			iconPicker:SetMaxColumns(iconpickerData.maxColumns)
+			iconPicker:SetVisibleRows(iconpickerData.visibleRows)
+			iconPicker:SetIconSize(control.icon.size)
+			UpdateChoices(control)
+			iconPicker:SetColor(control.icon.color)
+			if iconpickerData.beforeShow then
+				if iconpickerData.beforeShow(control, iconPicker) then
+					iconPicker:Clear()
+					return
+				end
+			end
+			iconPicker:Show(control.container)
+		end
+	end
+
+	local iconSize = iconpickerData.iconSize ~= nil and iconpickerData.iconSize or DEFAULT_SIZE
+	control.dropdown = wm:CreateControl(nil, control.container, CT_CONTROL)
+	local dropdown = control.dropdown
+	dropdown:SetAnchor(LEFT, control.container, LEFT, 0, 0)
+	dropdown:SetMouseEnabled(true)
+	dropdown:SetHandler("OnMouseUp", ShowIconPicker)
+	dropdown:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end)
+	dropdown:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end)
+
+	control.icon = wm:CreateControl(nil, dropdown, CT_TEXTURE)
+	local icon = control.icon
+	icon:SetAnchor(LEFT, dropdown, LEFT, 3, 0)
+	icon:SetDrawLevel(2)
+
+	local dropdownButton = wm:CreateControlFromVirtual(nil, dropdown, "ZO_DropdownButton")
+	dropdownButton:SetDimensions(16, 16)
+	dropdownButton:SetHandler("OnClicked", ShowIconPicker)
+	dropdownButton:SetAnchor(RIGHT, dropdown, RIGHT, -3, 0)
+	control.dropdownButton = dropdownButton
+
+	control.bg = wm:CreateControl(nil, dropdown, CT_BACKDROP)
+	local bg = control.bg
+	bg:SetAnchor(TOPLEFT, dropdown, TOPLEFT, 0, -3)
+	bg:SetAnchor(BOTTOMRIGHT, dropdown, BOTTOMRIGHT, 2, 5)
+	bg:SetEdgeTexture("EsoUI/Art/Tooltips/UI-Border.dds", 128, 16)
+	bg:SetCenterTexture("EsoUI/Art/Tooltips/UI-TooltipCenter.dds")
+	bg:SetInsets(16, 16, -16, -16)
+	local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE)
+	mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds")
+	mungeOverlay:SetDrawLevel(1)
+	mungeOverlay:SetAddressMode(TEX_MODE_WRAP)
+	mungeOverlay:SetAnchorFill()
+
+	if iconpickerData.warning then
+		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
+		control.warning:SetAnchor(RIGHT, control.container, LEFT, -5, 0)
+		control.warning.data = {tooltipText = iconpickerData.warning}
+	end
+
+	if iconpickerData.disabled ~= nil then
+		control.UpdateDisabled = UpdateDisabled
+		control:UpdateDisabled()
+	end
+
+	control.UpdateChoices = UpdateChoices
+	control.UpdateValue = UpdateValue
+	control:UpdateValue()
+	control.SetColor = SetColor
+	control:SetColor()
+	control.SetIconSize = SetIconSize
+	control:SetIconSize(iconSize)
+
+	if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then	--if our parent window wants to refresh controls, then add this to the list
+		tinsert(control.panel.controlsToRefresh, control)
+	end
+
+	return control
+end
diff --git a/lib/LibAddonMenu-2.0/controls/panel.lua b/lib/LibAddonMenu-2.0/controls/panel.lua
index 8db73ee..92aa61e 100644
--- a/lib/LibAddonMenu-2.0/controls/panel.lua
+++ b/lib/LibAddonMenu-2.0/controls/panel.lua
@@ -4,6 +4,7 @@
 	displayName = "My Longer Window Title",	--(optional) (can be useful for long addon names or if you want to colorize it)
 	author = "Seerah",	--(optional)
 	version = "2.0",	--(optional)
+	keywords = "settings",	--(optional) additional keywords for search filter (it looks for matches in name..keywords..author)
 	slashCommand = "/myaddon",	--(optional) will register a keybind to open to this panel (don't forget to include the slash!)
 	registerForRefresh = true,	--boolean (optional) (will refresh all options controls when a setting is changed and when the panel is shown)
 	registerForDefaults = true,	--boolean (optional) (will set all options controls back to default values)
@@ -11,7 +12,7 @@
 }	]]


-local widgetVersion = 8
+local widgetVersion = 9
 local LAM = LibStub("LibAddonMenu-2.0")
 if not LAM:RegisterWidget("panel", widgetVersion) then return end

@@ -53,7 +54,7 @@ local function ForceDefaults(panel)
 end
 ESO_Dialogs["LAM_DEFAULTS"] = {
 	title = {
-		text = SI_OPTIONS_RESET_TITLE,
+		text = SI_INTERFACE_OPTIONS_RESET_TO_DEFAULT_TOOLTIP,
 	},
 	mainText = {
 		text = SI_OPTIONS_RESET_PROMPT,
@@ -73,29 +74,19 @@ ESO_Dialogs["LAM_DEFAULTS"] = {
 local callbackRegistered = false
 LAMCreateControl.scrollCount = LAMCreateControl.scrollCount or 1
 function LAMCreateControl.panel(parent, panelData, controlName)
-	local control = wm:CreateTopLevelWindow(controlName)
-	control:SetParent(parent)
-
-	control.bg = wm:CreateControl(nil, control, CT_BACKDROP)
-	local bg = control.bg
-	bg:SetAnchorFill()
-	bg:SetEdgeTexture("EsoUI\\Art\\miscellaneous\\borderedinsettransparent_edgefile.dds", 128, 16)
-	bg:SetCenterColor(0, 0, 0, 0)
+	local control = wm:CreateControl(controlName, parent, CT_CONTROL)

 	control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel")
 	local label = control.label
-	label:SetAnchor(TOPLEFT, control, TOPLEFT, 10, 10)
-	label:SetText(panelData.displayName and panelData.displayName or panelData.name)
+	label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 4)
+	label:SetText(panelData.displayName or panelData.name)

 	if panelData.author or panelData.version then
 		control.info = wm:CreateControl(nil, control, CT_LABEL)
 		local info = control.info
 		info:SetFont("$(CHAT_FONT)|14|soft-shadow-thin")
-		info:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA())
-		info:SetHeight(13)
-		info:SetAnchor(TOPRIGHT, control, BOTTOMRIGHT, -5, 2)
+		info:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2)
 		if panelData.author and panelData.version then
-			--info:SetText("Version: "..panelData.version.."  -  "..GetString(SI_ADDON_MANAGER_AUTHOR)..": "..panelData.author)
 			info:SetText(string.format("Version: %s  -  %s: %s", panelData.version, GetString(SI_ADDON_MANAGER_AUTHOR), panelData.author))
 		elseif panelData.author then
 			info:SetText(string.format("%s: %s", GetString(SI_ADDON_MANAGER_AUTHOR), panelData.author))
@@ -107,7 +98,7 @@ function LAMCreateControl.panel(parent, panelData, controlName)
 	control.container = wm:CreateControlFromVirtual("LAMAddonPanelContainer"..LAMCreateControl.scrollCount, control, "ZO_ScrollContainer")
 	LAMCreateControl.scrollCount = LAMCreateControl.scrollCount + 1
 	local container = control.container
-	container:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, 20)
+	container:SetAnchor(TOPLEFT, control.info or label, BOTTOMLEFT, 0, 20)
 	container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, -3, -3)
 	control.scroll = GetControl(control.container, "ScrollChild")
 	control.scroll:SetResizeToFitPadding(0, 20)
@@ -118,7 +109,7 @@ function LAMCreateControl.panel(parent, panelData, controlName)
 		defaultButton:SetFont("ZoFontDialogKeybindDescription")
 		defaultButton:SetHorizontalAlignment(TEXT_ALIGN_LEFT)
 		--defaultButton:SetText("Reset To Defaults")
-		defaultButton:SetText(GetString(SI_OPTIONS_RESET_TITLE))
+		defaultButton:SetText(GetString(SI_OPTIONS_DEFAULTS))
 		defaultButton:SetDimensions(200, 30)
 		defaultButton:SetAnchor(TOPLEFT, control, BOTTOMLEFT, 0, 2)
 		defaultButton:SetHandler("OnClicked", function()
@@ -135,4 +126,7 @@ function LAMCreateControl.panel(parent, panelData, controlName)
 	control.controlsToRefresh = {}

 	return control
-end
\ No newline at end of file
+end
+
+
+-- vi: noexpandtab
diff --git a/lib/LibAddonMenu-2.0/controls/slider.lua b/lib/LibAddonMenu-2.0/controls/slider.lua
index 845fa7d..fa16686 100644
--- a/lib/LibAddonMenu-2.0/controls/slider.lua
+++ b/lib/LibAddonMenu-2.0/controls/slider.lua
@@ -5,6 +5,7 @@
 	min = 0,
 	max = 20,
 	step = 1,	--(optional)
+	decimals = 0, --(optional)
 	getFunc = function() return db.var end,
 	setFunc = function(value) db.var = value doStuff() end,
 	width = "full",	--or "half" (optional)
@@ -15,7 +16,7 @@
 }	]]


-local widgetVersion = 6
+local widgetVersion = 8
 local LAM = LibStub("LibAddonMenu-2.0")
 if not LAM:RegisterWidget("slider", widgetVersion) then return end

@@ -68,39 +69,18 @@ end


 function LAMCreateControl.slider(parent, sliderData, controlName)
-	local control = wm:CreateControl(controlName or sliderData.reference, parent.scroll or parent, CT_CONTROL)
-	local isHalfWidth = sliderData.width == "half"
-	if isHalfWidth then
-		control:SetDimensions(250, 55)
-	else
-		control:SetDimensions(510, 40)
-	end
-	control:SetMouseEnabled(true)
-	--control.tooltipText = sliderData.tooltip
-	control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
-	control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
-
-	control.label = wm:CreateControl(nil, control, CT_LABEL)
-	local label = control.label
-	label:SetFont("ZoFontWinH4")
-	label:SetDimensions(isHalfWidth and 250 or 300, 26)
-	label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
-	label:SetAnchor(isHalfWidth and TOPLEFT or LEFT)
-	label:SetText(sliderData.name)
+	local control = LAM.util.CreateLabelAndContainerControl(parent, sliderData, controlName)

 	--skipping creating the backdrop...  Is this the actual slider texture?
-	control.slider = wm:CreateControl(nil, control, CT_SLIDER)
+	control.slider = wm:CreateControl(nil, control.container, CT_SLIDER)
 	local slider = control.slider
-	slider:SetDimensions(190, 14)
-	if isHalfWidth then
-		slider:SetAnchor(TOPRIGHT, label, BOTTOMRIGHT, -5, 2)
-	else
-		slider:SetAnchor(RIGHT, control, RIGHT, -5, -5)
-	end
+	slider:SetAnchor(TOPLEFT)
+	slider:SetAnchor(TOPRIGHT)
+	slider:SetHeight(14)
 	slider:SetMouseEnabled(true)
 	slider:SetOrientation(ORIENTATION_HORIZONTAL)
 	--put nil for highlighted texture file path, and what look to be texture coords
-	slider:SetThumbTexture("EsoUI\\Art\\Miscellaneous\\scrollbox_elevator.dds", "EsoUI\\Art\\Miscellaneous\\scrollbox_elevator_disabled.dds", nil, 8, 16)
+	slider:SetThumbTexture("EsoUI\\Art\\Miscellaneous\\scrollbox_elevator.dds", "EsoUI\\Art\\Miscellaneous\\scrollbox_elevator_disabled.dds", nil, 8, 16)
 	local minValue = sliderData.min
 	local maxValue = sliderData.max
 	slider:SetMinMax(minValue, maxValue)
@@ -132,8 +112,8 @@ function LAMCreateControl.slider(parent, sliderData, controlName)
 	control.slidervalue = wm:CreateControlFromVirtual(nil, control.slidervalueBG, "ZO_DefaultEditForBackdrop")
 	local slidervalue = control.slidervalue
 	slidervalue:ClearAnchors()
-	slidervalue:SetAnchor(TOPLEFT, slidervaluebg, TOPLEFT, 3, 1)
-	slidervalue:SetAnchor(BOTTOMRIGHT, slidervaluebg, BOTTOMRIGHT, -3, -1)
+	slidervalue:SetAnchor(TOPLEFT, control.slidervalueBG, TOPLEFT, 3, 1)
+	slidervalue:SetAnchor(BOTTOMRIGHT, control.slidervalueBG, BOTTOMRIGHT, -3, -1)
 	slidervalue:SetTextType(TEXT_TYPE_NUMERIC)
 	slidervalue:SetFont("ZoFontGameSmall")
 	slidervalue:SetHandler("OnEscape", function(self)
@@ -144,31 +124,34 @@ function LAMCreateControl.slider(parent, sliderData, controlName)
 			self:LoseFocus()
 			control:UpdateValue(false, tonumber(self:GetText()))
 		end)
-
+	local function RoundDecimalToPlace(d, place)
+		return tonumber(string.format("%." .. tostring(place) .. "f", d))
+	end
 	local range = maxValue - minValue
 	slider:SetValueStep(sliderData.step or 1)
 	slider:SetHandler("OnValueChanged", function(self, value, eventReason)
 			if eventReason == EVENT_REASON_SOFTWARE then return end
-			self:SetValue(value)	--do we actually need this line?
-			slidervalue:SetText(value)
+			local new_value = sliderData.decimals and RoundDecimalToPlace(value, sliderData.decimals) or value
+			self:SetValue(new_value)	--do we actually need this line?
+			slidervalue:SetText(new_value)
 		end)
 	slider:SetHandler("OnSliderReleased", function(self, value)
 			--sliderData.setFunc(value)
-			control:UpdateValue(false, value)	--does this work here instead?
+			local new_value = sliderData.decimals and RoundDecimalToPlace(value, sliderData.decimals) or value
+			control:UpdateValue(false, new_value)	--does this work here instead?
+		end)
+	slider:SetHandler("OnMouseWheel", function(self, value)
+			local new_value = (tonumber(slidervalue:GetText()) or sliderData.min or 0) + ((sliderData.step or 1) * value)
+			control:UpdateValue(false, new_value)
 		end)

 	if sliderData.warning then
 		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
 		control.warning:SetAnchor(RIGHT, slider, LEFT, -5, 0)
-		--control.warning.tooltipText = sliderData.warning
 		control.warning.data = {tooltipText = sliderData.warning}
 	end

-	control.panel = parent.panel or parent	--if this is in a submenu, panel is the submenu's parent
-	control.data = sliderData
-	control.data.tooltipText = sliderData.tooltip
-
-	if sliderData.disabled then
+	if sliderData.disabled ~= nil then
 		control.UpdateDisabled = UpdateDisabled
 		control:UpdateDisabled()
 	end
@@ -180,4 +163,4 @@ function LAMCreateControl.slider(parent, sliderData, controlName)
 	end

 	return control
-end
\ No newline at end of file
+end
diff --git a/lib/LibAddonMenu-2.0/controls/submenu.lua b/lib/LibAddonMenu-2.0/controls/submenu.lua
index d3da3eb..a7950ee 100644
--- a/lib/LibAddonMenu-2.0/controls/submenu.lua
+++ b/lib/LibAddonMenu-2.0/controls/submenu.lua
@@ -6,7 +6,7 @@
 	reference = "MyAddonSubmenu"	--(optional) unique global reference to control
 }	]]

-local widgetVersion = 8
+local widgetVersion = 9
 local LAM = LibStub("LibAddonMenu-2.0")
 if not LAM:RegisterWidget("submenu", widgetVersion) then return end

@@ -18,7 +18,7 @@ local tinsert = table.insert
 local function UpdateValue(control)
 	control.label:SetText(control.data.name)
 	if control.data.tooltip then
-		control.label.data = {tooltipText = control.data.tooltip}
+		control.label.data.tooltipText = LAM.util.GetTooltipText(control.data.tooltip)
 	end
 end

@@ -33,21 +33,21 @@ local function AnimateSubmenu(clicked)
 	end
 end

-
 function LAMCreateControl.submenu(parent, submenuData, controlName)
+	local width = parent:GetWidth() - 45
 	local control = wm:CreateControl(controlName or submenuData.reference, parent.scroll or parent, CT_CONTROL)
 	control.panel = parent
-	control:SetDimensions(523, 40)
+	control.data = submenuData

 	control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel")
 	local label = control.label
 	label:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5)
-	label:SetDimensions(520, 30)
+	label:SetDimensions(width, 30)
 	label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
 	label:SetText(submenuData.name)
 	label:SetMouseEnabled(true)
 	if submenuData.tooltip then
-		label.data = {tooltipText = submenuData.tooltip}
+		label.data = {tooltipText = LAM.util.GetTooltipText(submenuData.tooltip)}
 		label:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
 		label:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
 	end
@@ -56,7 +56,7 @@ function LAMCreateControl.submenu(parent, submenuData, controlName)
 	local scroll = control.scroll
 	scroll:SetParent(control)
 	scroll:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, 10)
-	scroll:SetDimensionConstraints(525, 0, 525, 2500)
+	scroll:SetDimensionConstraints(width + 5, 0, width + 5, 2500)

 	control.bg = wm:CreateControl(nil, label, CT_BACKDROP)
 	local bg = control.bg
@@ -102,8 +102,6 @@ function LAMCreateControl.submenu(parent, submenuData, controlName)
 	btmToggle:SetAlpha(0)
 	btmToggle:SetHandler("OnMouseUp", AnimateSubmenu)

-	control.data = submenuData
-
 	control.UpdateValue = UpdateValue

 	if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then	--if our parent window wants to refresh controls, then add this to the list
diff --git a/lib/LibAddonMenu-2.0/controls/texture.lua b/lib/LibAddonMenu-2.0/controls/texture.lua
index 26b0353..711c6fd 100644
--- a/lib/LibAddonMenu-2.0/controls/texture.lua
+++ b/lib/LibAddonMenu-2.0/controls/texture.lua
@@ -10,23 +10,22 @@

 --add texture coords support?

-local widgetVersion = 6
+local widgetVersion = 7
 local LAM = LibStub("LibAddonMenu-2.0")
 if not LAM:RegisterWidget("texture", widgetVersion) then return end

 local wm = WINDOW_MANAGER

+local MIN_HEIGHT = 26
 function LAMCreateControl.texture(parent, textureData, controlName)
-	local control = wm:CreateControl(controlName or textureData.reference, parent.scroll or parent, CT_CONTROL)
+	local control = LAM.util.CreateBaseControl(parent, textureData, controlName)
+	local width = control:GetWidth()
 	control:SetResizeToFitDescendents(true)

-	local isHalfWidth = textureData.width == "half"
-	if isHalfWidth then
-		control:SetDimensionConstraints(250, 55, 250, 100)
-		control:SetDimensions(250, 55)
+	if control.isHalfWidth then	--note these restrictions
+		control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4)
 	else
-		control:SetDimensionConstraints(510, 30, 510, 100)
-		control:SetDimensions(510, 30)
+		control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4)
 	end

 	control.texture = wm:CreateControl(nil, control, CT_TEXTURE)
@@ -37,14 +36,10 @@ function LAMCreateControl.texture(parent, textureData, controlName)

 	if textureData.tooltip then
 		texture:SetMouseEnabled(true)
-		--texture.tooltipText = textureData.tooltip
-		texture.data = {tooltipText = textureData.tooltip}
+		texture.data = {tooltipText = LAM.util.GetTooltipText(textureData.tooltip)}
 		texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
 		texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseExit)
 	end

-	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
-	control.data = textureData
-
 	return control
 end
\ No newline at end of file
diff --git a/lib/LibStub/LibStub.lua b/lib/LibStub/LibStub.lua
index 879d132..2c56077 100644
--- a/lib/LibStub/LibStub.lua
+++ b/lib/LibStub/LibStub.lua
@@ -3,7 +3,7 @@
 -- LibStub developed for World of Warcraft by above members of the WowAce community.
 -- Ported to Elder Scrolls Online by Seerah

-local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2  -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
+local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 3
 local LibStub = _G[LIBSTUB_MAJOR]

 local strformat = string.format
@@ -14,7 +14,9 @@ if not LibStub or LibStub.minor < LIBSTUB_MINOR then

 	function LibStub:NewLibrary(major, minor)
 		assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
-		minor = assert(tonumber(zo_strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
+		if type(minor) ~= "number" then
+			minor = assert(tonumber(zo_strmatch(minor, "%d+%.?%d*")), "Minor version must either be a number or contain a number.")
+		end

 		local oldminor = self.minors[major]
 		if oldminor and oldminor >= minor then return nil end