Update LAM to r21

Scott Yeskie [07-25-16 - 04:08]
Update LAM to r21
Filename
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
diff --git a/lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua b/lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua
index b1e505f..2cdb271 100644
--- a/lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua
+++ b/lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua
@@ -1,33 +1,33 @@
---	LibAddonMenu-2.0 & its files © Ryan Lakanen (Seerah)		--
---	Distributed under The Artistic License 2.0 (see LICENSE)	--
+-- LibAddonMenu-2.0 & its files © Ryan Lakanen (Seerah)         --
+-- Distributed under The Artistic License 2.0 (see LICENSE)     --
 ------------------------------------------------------------------


 --Register LAM with LibStub
-local MAJOR, MINOR = "LibAddonMenu-2.0", 20.2
+local MAJOR, MINOR = "LibAddonMenu-2.0", 21
 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
+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
-		d(MESSAGE_PREFIX .. msg)
-	else
-		messages[#messages + 1] = msg
-	end
+    if CHAT_SYSTEM.primaryContainer then
+        d(MESSAGE_PREFIX .. msg)
+    else
+        messages[#messages + 1] = msg
+    end
 end

 local function FlushMessages()
-	for i = 1, #messages do
-		d(MESSAGE_PREFIX .. messages[i])
-	end
-	messages = {}
+    for i = 1, #messages do
+        d(MESSAGE_PREFIX .. messages[i])
+    end
+    messages = {}
 end

 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
+    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--
@@ -38,76 +38,126 @@ local cm = CALLBACK_MANAGER
 local tconcat = table.concat
 local tinsert = table.insert

+local MIN_HEIGHT = 26
+local HALF_WIDTH_LINE_SPACING = 2
+local OPTIONS_CREATION_RUNNING = 1
+local OPTIONS_CREATED = 2
+local LAM_CONFIRM_DIALOG = "LAM_CONFIRM_DIALOG"
+
 local addonsForList = {}
 local addonToOptionsMap = {}
-local optionsCreated = {}
+local optionsState = {}
 lam.widgets = lam.widgets or {}
 local widgets = lam.widgets
 lam.util = lam.util or {}
 local util = lam.util

 local function GetDefaultValue(default)
-	if type(default) == "function" then
-		return default()
-	end
-	return default
+    if type(default) == "function" then
+        return default()
+    end
+    return default
 end

 local function GetStringFromValue(value)
-	if type(value) == "function" then
-		return value()
-	elseif type(value) == "number" then
-		return GetString(value)
-	end
-	return value
+    if type(value) == "function" then
+        return value()
+    elseif type(value) == "number" then
+        return GetString(value)
+    end
+    return value
 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
+    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(GetStringFromValue(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 = GetStringFromValue(control.data.tooltip)
-	control:SetMouseEnabled(true)
-	control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
-	control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
-	return control
+    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(GetStringFromValue(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 = GetStringFromValue(control.data.tooltip)
+    control:SetMouseEnabled(true)
+    control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
+    control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
+    return control
+end
+
+local function RequestRefreshIfNeeded(control)
+    if control.panel.data.registerForRefresh then
+        cm:FireCallbacks("LAM-RefreshPanel", control)
+    end
+end
+
+local function RegisterForRefreshIfNeeded(control)
+    -- if our parent window wants to refresh controls, then add this to the list
+    local panelData = control.panel.data
+    if panelData.registerForRefresh or panelData.registerForDefaults then
+        tinsert(control.panel.controlsToRefresh, control)
+    end
+end
+
+local function GetConfirmDialog()
+    if(not ESO_Dialogs[LAM_CONFIRM_DIALOG]) then
+        ESO_Dialogs[LAM_CONFIRM_DIALOG] = {
+            canQueue = true,
+            title = {
+                text = "",
+            },
+            mainText = {
+                text = "",
+            },
+            buttons = {
+                [1] = {
+                    text = SI_DIALOG_CONFIRM,
+                    callback = function(dialog) end,
+                },
+                [2] = {
+                    text = SI_DIALOG_CANCEL,
+                }
+            }
+        }
+    end
+    return ESO_Dialogs[LAM_CONFIRM_DIALOG]
+end
+
+local function ShowConfirmationDialog(title, body, callback)
+    local dialog = GetConfirmDialog()
+    dialog.title.text = title
+    dialog.mainText.text = body
+    dialog.buttons[1].callback = callback
+    ZO_Dialogs_ShowDialog(LAM_CONFIRM_DIALOG)
 end

 util.GetTooltipText = GetStringFromValue -- deprecated, use util.GetStringFromValue instead
@@ -115,6 +165,9 @@ util.GetStringFromValue = GetStringFromValue
 util.GetDefaultValue = GetDefaultValue
 util.CreateBaseControl = CreateBaseControl
 util.CreateLabelAndContainerControl = CreateLabelAndContainerControl
+util.RequestRefreshIfNeeded = RequestRefreshIfNeeded
+util.RegisterForRefreshIfNeeded = RegisterForRefreshIfNeeded
+util.ShowConfirmationDialog = ShowConfirmationDialog

 local ADDON_DATA_TYPE = 1
 local RESELECTING_DURING_REBUILD = true
@@ -123,98 +176,98 @@ 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)
+-- 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
+-- 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
+    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)
+-- * 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
+-- and returns true iff `data.filterText` matches the pattern
 local function GetSearchFilterFunc(searchEdit)
-	local text = searchEdit:GetText():lower()
-	local pattern = text:match("(%S+.-)%s*$")
+    local text = searchEdit:GetText():lower()
+    local pattern = text:match("(%S+.-)%s*$")

-	if not pattern then -- nothing but whitespace
-		return nil
-	end
+    if not pattern then -- nothing but whitespace
+        return nil
+    end

-	-- escape metacharacters, e.g. "ESO-Datenbank.de" => "ESO%-Datenbank%.de"
-	pattern = pattern:gsub("[-*+?^$().[%]%%]", "%%%0")
+    -- escape metacharacters, e.g. "ESO-Datenbank.de" => "ESO%-Datenbank%.de"
+    pattern = pattern:gsub("[-*+?^$().[%]%%]", "%%%0")

-	-- replace whitespace with "match shortest anything"
-	pattern = pattern:gsub("%s+", ".-")
+    -- replace whitespace with "match shortest anything"
+    pattern = pattern:gsub("%s+", ".-")

-	return function(data)
-		return data.filterText:lower():find(pattern) ~= nil
-	end
+    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)
+-- 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
+    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


@@ -222,245 +275,252 @@ end
 --each widget has its version checked before loading,
 --so we only have the most recent one in memory
 --Usage:
---	widgetType = "string"; the type of widget being registered
---	widgetVersion = integer; the widget's version number
+-- widgetType = "string"; the type of widget being registered
+-- widgetVersion = integer; the widget's version number
 LAMCreateControl = LAMCreateControl or {}
 local lamcc = LAMCreateControl

 function lam:RegisterWidget(widgetType, widgetVersion)
-	if widgets[widgetType] and widgets[widgetType] >= widgetVersion then
-		return false
-	else
-		widgets[widgetType] = widgetVersion
-		return true
-	end
+    if widgets[widgetType] and widgets[widgetType] >= widgetVersion then
+        return false
+    else
+        widgets[widgetType] = widgetVersion
+        return true
+    end
 end

 -- INTERNAL METHOD: fires the LAM-PanelOpened callback if not already done
 local function OpenCurrentPanel()
-	if(lam.currentAddonPanel and not lam.currentPanelOpened) then
-		lam.currentPanelOpened = true
-		cm:FireCallbacks("LAM-PanelOpened", lam.currentAddonPanel)
-	end
+    if(lam.currentAddonPanel and not lam.currentPanelOpened) then
+        lam.currentPanelOpened = true
+        cm:FireCallbacks("LAM-PanelOpened", lam.currentAddonPanel)
+    end
 end

 -- INTERNAL METHOD: fires the LAM-PanelClosed callback if not already done
 local function CloseCurrentPanel()
-	if(lam.currentAddonPanel and lam.currentPanelOpened) then
-		lam.currentPanelOpened = false
-		cm:FireCallbacks("LAM-PanelClosed", lam.currentAddonPanel)
-	end
+    if(lam.currentAddonPanel and lam.currentPanelOpened) then
+        lam.currentPanelOpened = false
+        cm:FireCallbacks("LAM-PanelClosed", lam.currentAddonPanel)
+    end
 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)

-	-- 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
-	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
-
-	if sm:GetScene("gameMenuInGame"):GetState() == SCENE_SHOWN then
-		openAddonSettingsMenu()
-	else
-		sm:CallWhen("gameMenuInGame", SCENE_SHOWN, openAddonSettingsMenu)
-		sm:Show("gameMenuInGame")
-	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
+    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
+
+    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
+    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
 --controls anchoring of these controls in the panel
 local function CreateOptionsControls(panel)
-	local addonID = panel:GetName()
-	local optionsTable = addonToOptionsMap[addonID]
-
-	if optionsTable then
-		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
-				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
-					end
-				end
-			end
-		end
-
-		local function DoCreateSettings()
-			if #fifo > 0 then
-				local nextCall = table.remove(fifo, 1)
-				nextCall()
-				if(nextCall == PrepareForNextPanel) then
-					DoCreateSettings()
-				else
-					zo_callLater(DoCreateSettings, THROTTLE_TIMEOUT)
-				end
-			else
-				optionsCreated[addonID] = true
-				cm:FireCallbacks("LAM-PanelControlsCreated", panel)
-				OpenCurrentPanel()
-			end
-		end
-
-		if SetupCreationCalls(panel, optionsTable) then
-			PrintLater(("The settings menu of %s is missing some entries."):format(addonID))
-		end
-		DoCreateSettings()
-	else
-		optionsCreated[addonID] = true
-		cm:FireCallbacks("LAM-PanelControlsCreated", panel)
-		OpenCurrentPanel()
-	end
+    local addonID = panel:GetName()
+    if(optionsState[addonID] == OPTIONS_CREATED) then
+        return false
+    elseif(optionsState[addonID] == OPTIONS_CREATION_RUNNING) then
+        return true
+    end
+    optionsState[addonID] = OPTIONS_CREATION_RUNNING
+
+    local function CreationFinished()
+        optionsState[addonID] = OPTIONS_CREATED
+        cm:FireCallbacks("LAM-PanelControlsCreated", panel)
+        OpenCurrentPanel()
+    end
+
+    local optionsTable = addonToOptionsMap[addonID]
+    if optionsTable then
+        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
+                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
+                    end
+                end
+            end
+        end
+
+        local function DoCreateSettings()
+            if #fifo > 0 then
+                local nextCall = table.remove(fifo, 1)
+                nextCall()
+                if(nextCall == PrepareForNextPanel) then
+                    DoCreateSettings()
+                else
+                    zo_callLater(DoCreateSettings, THROTTLE_TIMEOUT)
+                end
+            else
+                CreationFinished()
+            end
+        end
+
+        if SetupCreationCalls(panel, optionsTable) then
+            PrintLater(("The settings menu of %s is missing some entries."):format(addonID))
+        end
+        DoCreateSettings()
+    else
+        CreationFinished()
+    end
+
+    return true
 end

-
 --INTERNAL FUNCTION
 --handles switching between panels
-local function ToggleAddonPanels(panel)	--called in OnShow of newly shown panel
-	local currentlySelected = lam.currentAddonPanel
-	if currentlySelected and currentlySelected ~= panel then
-		currentlySelected:SetHidden(true)
-		CloseCurrentPanel()
-	end
-	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)
-	else
-		OpenCurrentPanel()
-	end
-
-	cm:FireCallbacks("LAM-RefreshPanel", panel)
+local function ToggleAddonPanels(panel) --called in OnShow of newly shown panel
+    local currentlySelected = lam.currentAddonPanel
+    if currentlySelected and currentlySelected ~= panel then
+        currentlySelected:SetHidden(true)
+        CloseCurrentPanel()
+    end
+    lam.currentAddonPanel = panel
+
+    -- refresh visible rows to reflect panel IsHidden status
+    ZO_ScrollList_RefreshVisible(lam.addonList)
+
+    if not CreateOptionsControls(panel) then
+        OpenCurrentPanel()
+    end
+
+    cm:FireCallbacks("LAM-RefreshPanel", panel)
 end

 local CheckSafetyAndInitialize
@@ -468,40 +528,40 @@ local CheckSafetyAndInitialize
 --METHOD: REGISTER ADDON PANEL
 --registers your addon with LibAddonMenu and creates a panel
 --Usage:
---	addonID = "string"; unique ID which will be the global name of your panel
---	panelData = table; data object for your panel - see controls\panel.lua
+-- 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)
-	CheckSafetyAndInitialize(addonID)
-	local container = lam:GetAddonPanelContainer()
-	local panel = lamcc.panel(container, panelData, addonID)	--addonID==global name of panel
-	panel:SetHidden(true)
-	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(),
-	}
+    CheckSafetyAndInitialize(addonID)
+    local container = lam:GetAddonPanelContainer()
+    local panel = lamcc.panel(container, panelData, addonID) --addonID==global name of panel
+    panel:SetHidden(true)
+    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)
+    tinsert(addonsForList, addonData)

-	if panelData.slashCommand then
-		SLASH_COMMANDS[panelData.slashCommand] = function()
-			lam:OpenToPanel(panel)
-		end
-	end
+    if panelData.slashCommand then
+        SLASH_COMMANDS[panelData.slashCommand] = function()
+            lam:OpenToPanel(panel)
+        end
+    end

-	return panel	--return for authors creating options manually
+    return panel --return for authors creating options manually
 end


@@ -512,20 +572,20 @@ end
 --see exampleoptions.lua for an example
 --see controls\<widget>.lua for each widget type
 --Usage:
---	addonID = "string"; the same string passed to :RegisterAddonPanel
---	optionsTable = table; the table containing all of the options controls and their data
-function lam:RegisterOptionControls(addonID, optionsTable)	--optionsTable = {sliderData, buttonData, etc}
-	addonToOptionsMap[addonID] = optionsTable
+-- addonID = "string"; the same string passed to :RegisterAddonPanel
+-- optionsTable = table; the table containing all of the options controls and their data
+function lam:RegisterOptionControls(addonID, optionsTable) --optionsTable = {sliderData, buttonData, etc}
+    addonToOptionsMap[addonID] = optionsTable
 end


 --INTERNAL FUNCTION
 --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
-	--Japanese provided by k0ta0uchi
+    --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
+    --Japanese provided by k0ta0uchi
     local controlPanelNames = {
         en = "Addon Settings",
         fr = "Extensions",
@@ -535,285 +595,285 @@ local function CreateAddonSettingsMenuEntry()
         jp = "アドオン設定",
     }

-	local panelData = {
-		id = KEYBOARD_OPTIONS.currentPanelId,
-		name = controlPanelNames[GetCVar("Language.2")] or controlPanelNames["en"],
-	}
+    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
+    KEYBOARD_OPTIONS.currentPanelId = panelData.id + 1
+    KEYBOARD_OPTIONS.panelNames[panelData.id] = panelData.name

-	lam.panelId = panelData.id
+    lam.panelId = panelData.id

-	local addonListSorted = false
+    local addonListSorted = false

-	function panelData.callback()
-		sm:AddFragment(lam:GetAddonSettingsFragment())
-		KEYBOARD_OPTIONS:ChangePanels(lam.panelId)
+    function panelData.callback()
+        sm:AddFragment(lam:GetAddonSettingsFragment())
+        KEYBOARD_OPTIONS:ChangePanels(lam.panelId)

-		local title = LAMAddonSettingsWindow:GetNamedChild("Title")
-		title:SetText(panelData.name)
+        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
+        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
+    function panelData.unselectedCallback()
+        sm:RemoveFragment(lam:GetAddonSettingsFragment())
+        if SetCameraOptionsPreviewModeEnabled then -- available since API version 100011
+            SetCameraOptionsPreviewModeEnabled(false)
+        end
+    end

-	ZO_GameMenu_AddSettingPanel(panelData)
+    ZO_GameMenu_AddSettingPanel(panelData)
 end


 --INTERNAL FUNCTION
 --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
+    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
 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
-			srchBg:SetAlpha(srchHover and 0.6 or 0.0)
-		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
+    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
+            srchBg:SetAlpha(srchHover and 0.6 or 0.0)
+        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 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
+    local tlw = wm:CreateTopLevelWindow("LAMAddonSettingsWindow")
+    tlw:SetHidden(true)
+    tlw:SetDimensions(1010, 914) -- same height as ZO_OptionsWindow

-	ZO_ReanchorControlForLeftSidePanel(tlw)
+    ZO_ReanchorControlForLeftSidePanel(tlw)

-	-- create black background for the window (mimic ZO_RightFootPrintBackground)
+    -- 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 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)
+    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)
+    -- 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 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)
+    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)
+    -- 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)
+    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)

-	local divider = wm:CreateControlFromVirtual("$(parent)Divider", tlw, "ZO_Options_Divider")
-	divider:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 108)
+    local divider = wm:CreateControlFromVirtual("$(parent)Divider", tlw, "ZO_Options_Divider")
+    divider:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 108)

-	-- create search filter box
+    -- create search filter box

-	local srchBox = CreateSearchFilterBox("$(parent)SearchFilter", tlw)
-	srchBox:SetAnchor(TOPLEFT, nil, TOPLEFT, 63, 120)
-	srchBox:SetDimensions(260, 30)
+    local srchBox = CreateSearchFilterBox("$(parent)SearchFilter", tlw)
+    srchBox:SetAnchor(TOPLEFT, nil, TOPLEFT, 63, 120)
+    srchBox:SetDimensions(260, 30)

-	-- create scrollable addon list
+    -- create scrollable addon list

-	local addonList = CreateAddonList("$(parent)AddonList", tlw)
-	addonList:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 160)
-	addonList:SetDimensions(285, 665)
+    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
+    lam.addonList = addonList -- for easy access from elsewhere

-	-- create container for option panels
+    -- 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)
+    local panelContainer = wm:CreateControl("$(parent)PanelContainer", tlw, CT_CONTROL)
+    panelContainer:SetAnchor(TOPLEFT, nil, TOPLEFT, 365, 120)
+    panelContainer:SetDimensions(645, 675)

-	return tlw
+    return tlw
 end


@@ -823,54 +883,51 @@ local hasInitialized = false

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

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

 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
-	if not hasInitialized then
-		hasInitialized = true
-	end
+    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
+    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")
+    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)
-		LAMAddonSettingsFragment:RegisterCallback("StateChange", function(oldState, newState)
-			if(newState == SCENE_FRAGMENT_SHOWN) then
-				OpenCurrentPanel()
-			elseif(newState == SCENE_FRAGMENT_HIDDEN) then
-				CloseCurrentPanel()
-			end
-		end)
-		CreateAddonSettingsMenuEntry()
-	end
-	return LAMAddonSettingsFragment
-end
-
-
--- vi: noexpandtab
+    assert(hasInitialized or safeToInitialize)
+    if not LAMAddonSettingsFragment then
+        local window = CreateAddonSettingsWindow()
+        LAMAddonSettingsFragment = ZO_FadeSceneFragment:New(window, true, 100)
+        LAMAddonSettingsFragment:RegisterCallback("StateChange", function(oldState, newState)
+            if(newState == SCENE_FRAGMENT_SHOWN) then
+                OpenCurrentPanel()
+            elseif(newState == SCENE_FRAGMENT_HIDDEN) then
+                CloseCurrentPanel()
+            end
+        end)
+        CreateAddonSettingsMenuEntry()
+    end
+    return LAMAddonSettingsFragment
+end
diff --git a/lib/LibAddonMenu-2.0/controls/button.lua b/lib/LibAddonMenu-2.0/controls/button.lua
index 340ff35..9bf5c01 100644
--- a/lib/LibAddonMenu-2.0/controls/button.lua
+++ b/lib/LibAddonMenu-2.0/controls/button.lua
@@ -1,89 +1,90 @@
 --[[buttonData = {
-	type = "button",
-	name = "My Button", -- string id or function returning a string
-	func = function() end,
-	tooltip = "Button's tooltip text.", -- string id or function returning a string (optional)
-	width = "full",	--or "half" (optional)
-	disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
-	icon = "icon\\path.dds",	--(optional)
-	warning = "Will need to reload the UI.",	--(optional)
-	reference = "MyAddonButton",	-- unique global reference to control (optional)
-}	]]
+    type = "button",
+    name = "My Button", -- string id or function returning a string
+    func = function() end,
+    tooltip = "Button's tooltip text.", -- string id or function returning a string (optional)
+    width = "full", --or "half" (optional)
+    disabled = function() return db.someBooleanSetting end, --or boolean (optional)
+    icon = "icon\\path.dds", --(optional)
+    isDangerous = false, -- boolean, if set to true, the button text will be red and a confirmation dialog with the button label and warning text will show on click before the callback is executed (optional)
+    warning = "Will need to reload the UI.", --(optional)
+    reference = "MyAddonButton", -- unique global reference to control (optional)
+} ]]

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

 local wm = WINDOW_MANAGER
-local cm = CALLBACK_MANAGER
-local tinsert = table.insert

 local function UpdateDisabled(control)
-	local disable
-	if type(control.data.disabled) == "function" then
-		disable = control.data.disabled()
-	else
-		disable = control.data.disabled
-	end
-
-	control.button:SetEnabled(not disable)
+    local disable = control.data.disabled
+    if type(disable) == "function" then
+        disable = disable()
+    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 = LAM.util.CreateBaseControl(parent, buttonData, controlName)
-	control:SetMouseEnabled(true)
+    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

-	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)
+        control.button:SetNormalTexture(buttonData.icon)
+        control.button:SetPressedOffset(2, 2)
+    else
+        --control.button = wm:CreateControlFromVirtual(controlName.."Button", control, "ZO_DefaultButton")
+        control.button = wm:CreateControlFromVirtual(nil, control, "ZO_DefaultButton")
+        control.button:SetWidth(width / 3)
+        control.button:SetText(LAM.util.GetStringFromValue(buttonData.name))
+        if buttonData.isDangerous then control.button:SetNormalFontColor(ZO_ERROR_COLOR:UnpackRGBA()) end
+    end
+    local button = control.button
+    button:SetAnchor(control.isHalfWidth and CENTER or RIGHT)
+    button:SetClickSound("Click")
+    button.data = {tooltipText = LAM.util.GetStringFromValue(buttonData.tooltip)}
+    button:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
+    button:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
+    button:SetHandler("OnClicked", function(...)
+        local args = {...}
+        local function callback()
+            buttonData.func(unpack(args))
+            LAM.util.RequestRefreshIfNeeded(control)
+        end

-	if buttonData.icon then
-		control.button = wm:CreateControl(nil, control, CT_BUTTON)
-		control.button:SetDimensions(26, 26)
-		control.button:SetNormalTexture(buttonData.icon)
-		control.button:SetPressedOffset(2, 2)
-	else
-		--control.button = wm:CreateControlFromVirtual(controlName.."Button", control, "ZO_DefaultButton")
-		control.button = wm:CreateControlFromVirtual(nil, control, "ZO_DefaultButton")
-		control.button:SetWidth(width / 3)
-		control.button:SetText(LAM.util.GetStringFromValue(buttonData.name))
-	end
-	local button = control.button
-	button:SetAnchor(control.isHalfWidth and CENTER or RIGHT)
-	button:SetClickSound("Click")
-	button.data = {tooltipText = LAM.util.GetStringFromValue(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)
+        if(buttonData.isDangerous) then
+            local title = LAM.util.GetStringFromValue(buttonData.name)
+            local body = LAM.util.GetStringFromValue(buttonData.warning)
+            LAM.util.ShowConfirmationDialog(title, body, callback)
+        else
+            callback()
+        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.data = {tooltipText = LAM.util.GetStringFromValue(buttonData.warning)}
-	end
+    if buttonData.warning then
+        control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
+        control.warning:SetAnchor(RIGHT, button, LEFT, -5, 0)
+        control.warning.data = {tooltipText = LAM.util.GetStringFromValue(buttonData.warning)}
+    end

-	if buttonData.disabled ~= nil then
-		control.UpdateDisabled = UpdateDisabled
-		control:UpdateDisabled()
+    if buttonData.disabled ~= nil then
+        control.UpdateDisabled = UpdateDisabled
+        control:UpdateDisabled()
+    end

-		--this is here because buttons don't have an UpdateValue method
-		if control.panel.data.registerForRefresh then	--if our parent window wants to refresh controls, then add this to the list
-			tinsert(control.panel.controlsToRefresh, control)
-		end
-	end
+    LAM.util.RegisterForRefreshIfNeeded(control)

-	return control
+    return control
 end
diff --git a/lib/LibAddonMenu-2.0/controls/checkbox.lua b/lib/LibAddonMenu-2.0/controls/checkbox.lua
index 0b9ea48..6e34fec 100644
--- a/lib/LibAddonMenu-2.0/controls/checkbox.lua
+++ b/lib/LibAddonMenu-2.0/controls/checkbox.lua
@@ -1,24 +1,23 @@
 --[[checkboxData = {
-	type = "checkbox",
-	name = "My Checkbox", -- or string id or function returning a string
-	getFunc = function() return db.var end,
-	setFunc = function(value) db.var = value doStuff() end,
-	tooltip = "Checkbox's tooltip text.", -- or string id or function returning a string (optional)
-	width = "full", -- or "half" (optional)
-	disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
-	warning = "Will need to reload the UI.", -- or string id or function returning a string (optional)
-	default = defaults.var,	-- a boolean or function that returns a boolean (optional)
-	reference = "MyAddonCheckbox", -- unique global reference to control (optional)
-}	]]
-
-
-local widgetVersion = 11
+    type = "checkbox",
+    name = "My Checkbox", -- or string id or function returning a string
+    getFunc = function() return db.var end,
+    setFunc = function(value) db.var = value doStuff() end,
+    tooltip = "Checkbox's tooltip text.", -- or string id or function returning a string (optional)
+    width = "full", -- or "half" (optional)
+    disabled = function() return db.someBooleanSetting end, --or boolean (optional)
+    warning = "Will need to reload the UI.", -- or string id or function returning a string (optional)
+    default = defaults.var, -- a boolean or function that returns a boolean (optional)
+    reference = "MyAddonCheckbox", -- unique global reference to control (optional)
+} ]]
+
+
+local widgetVersion = 12
 local LAM = LibStub("LibAddonMenu-2.0")
 if not LAM:RegisterWidget("checkbox", widgetVersion) then return end

 local wm = WINDOW_MANAGER
-local cm = CALLBACK_MANAGER
-local tinsert = table.insert
+
 --label
 local enabledColor = ZO_DEFAULT_ENABLED_COLOR
 local enabledHLcolor = ZO_HIGHLIGHT_TEXT
@@ -30,115 +29,111 @@ local checkboxHLcolor = ZO_HIGHLIGHT_TEXT


 local function UpdateDisabled(control)
-	local disable
-	if type(control.data.disabled) == "function" then
-		disable = control.data.disabled()
-	else
-		disable = control.data.disabled
-	end
-
-	control.label:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or control.value and ZO_DEFAULT_ENABLED_COLOR or ZO_DEFAULT_DISABLED_COLOR):UnpackRGBA())
-	control.checkbox:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or ZO_NORMAL_TEXT):UnpackRGBA())
-	--control:SetMouseEnabled(not disable)
-	--control:SetMouseEnabled(true)
-
-	control.isDisabled = disable
+    local disable
+    if type(control.data.disabled) == "function" then
+        disable = control.data.disabled()
+    else
+        disable = control.data.disabled
+    end
+
+    control.label:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or control.value and ZO_DEFAULT_ENABLED_COLOR or ZO_DEFAULT_DISABLED_COLOR):UnpackRGBA())
+    control.checkbox:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or ZO_NORMAL_TEXT):UnpackRGBA())
+    --control:SetMouseEnabled(not disable)
+    --control:SetMouseEnabled(true)
+
+    control.isDisabled = disable
 end

 local function ToggleCheckbox(control)
-	if control.value then
-		control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
-		control.checkbox:SetText(control.checkedText)
-	else
-		control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
-		control.checkbox:SetText(control.uncheckedText)
-	end
+    if control.value then
+        control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+        control.checkbox:SetText(control.checkedText)
+    else
+        control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
+        control.checkbox:SetText(control.uncheckedText)
+    end
 end

 local function UpdateValue(control, forceDefault, value)
-	if forceDefault then	--if we are forcing defaults
-		value = LAM.util.GetDefaultValue(control.data.default)
-		control.data.setFunc(value)
-	elseif value ~= nil then	--our value could be false
-		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()
-	end
-	control.value = value
-
-	ToggleCheckbox(control)
+    if forceDefault then --if we are forcing defaults
+        value = LAM.util.GetDefaultValue(control.data.default)
+        control.data.setFunc(value)
+    elseif value ~= nil then --our value could be false
+        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
+        LAM.util.RequestRefreshIfNeeded(control)
+    else
+        value = control.data.getFunc()
+    end
+    control.value = value
+
+    ToggleCheckbox(control)
 end

 local function OnMouseEnter(control)
-	ZO_Options_OnMouseEnter(control)
+    ZO_Options_OnMouseEnter(control)

-	if control.isDisabled then return end
+    if control.isDisabled then return end

-	local label = control.label
-	if control.value then
-		label:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA())
-	else
-		label:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA())
-	end
-	control.checkbox:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA())
+    local label = control.label
+    if control.value then
+        label:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA())
+    else
+        label:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA())
+    end
+    control.checkbox:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA())
 end

 local function OnMouseExit(control)
-	ZO_Options_OnMouseExit(control)
+    ZO_Options_OnMouseExit(control)

-	if control.isDisabled then return end
+    if control.isDisabled then return end

-	local label = control.label
-	if control.value then
-		label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
-	else
-		label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
-	end
-	control.checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA())
+    local label = control.label
+    if control.value then
+        label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+    else
+        label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
+    end
+    control.checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA())
 end

 --controlName is optional
 function LAMCreateControl.checkbox(parent, checkboxData, controlName)
-	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.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()
-
-	if checkboxData.warning then
-		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
-		control.warning:SetAnchor(RIGHT, checkbox, LEFT, -5, 0)
-		control.warning.data = {tooltipText = LAM.util.GetStringFromValue(checkboxData.warning)}
-	end
-
-	control.data.tooltipText = LAM.util.GetStringFromValue(checkboxData.tooltip)
-
-	if checkboxData.disabled ~= nil then
-		control.UpdateDisabled = UpdateDisabled
-		control:UpdateDisabled()
-	end
-	control.UpdateValue = UpdateValue
-	control: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
-		tinsert(control.panel.controlsToRefresh, control)
-	end
-
-	return control
+    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.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()
+
+    if checkboxData.warning then
+        control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
+        control.warning:SetAnchor(RIGHT, checkbox, LEFT, -5, 0)
+        control.warning.data = {tooltipText = LAM.util.GetStringFromValue(checkboxData.warning)}
+    end
+
+    control.data.tooltipText = LAM.util.GetStringFromValue(checkboxData.tooltip)
+
+    control.UpdateValue = UpdateValue
+    control:UpdateValue()
+    if checkboxData.disabled ~= nil then
+        control.UpdateDisabled = UpdateDisabled
+        control:UpdateDisabled()
+    end
+
+    LAM.util.RegisterForRefreshIfNeeded(control)
+
+    return control
 end
diff --git a/lib/LibAddonMenu-2.0/controls/colorpicker.lua b/lib/LibAddonMenu-2.0/controls/colorpicker.lua
index afb6063..eb5855a 100644
--- a/lib/LibAddonMenu-2.0/controls/colorpicker.lua
+++ b/lib/LibAddonMenu-2.0/controls/colorpicker.lua
@@ -1,110 +1,103 @@
 --[[colorpickerData = {
-	type = "colorpicker",
-	name = "My Color Picker", -- or string id or function returning a string
-	getFunc = function() return db.r, db.g, db.b, db.a end,	--(alpha is optional)
-	setFunc = function(r,g,b,a) db.r=r, db.g=g, db.b=b, db.a=a end,	--(alpha is optional)
-	tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional)
-	width = "full",	--or "half" (optional)
-	disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
-	warning = "Will need to reload the UI.",	-- or string id or function returning a string (optional)
-	default = {r = defaults.r, g = defaults.g, b = defaults.b, a = defaults.a},	--(optional) table of default color values (or default = defaultColor, where defaultColor is a table with keys of r, g, b[, a]) or a function that returns the color
-	reference = "MyAddonColorpicker"	-- unique global reference to control (optional)
-}	]]
-
-
-local widgetVersion = 10
+    type = "colorpicker",
+    name = "My Color Picker", -- or string id or function returning a string
+    getFunc = function() return db.r, db.g, db.b, db.a end, --(alpha is optional)
+    setFunc = function(r,g,b,a) db.r=r, db.g=g, db.b=b, db.a=a end, --(alpha is optional)
+    tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional)
+    width = "full", --or "half" (optional)
+    disabled = function() return db.someBooleanSetting end, --or boolean (optional)
+    warning = "Will need to reload the UI.", -- or string id or function returning a string (optional)
+    default = {r = defaults.r, g = defaults.g, b = defaults.b, a = defaults.a}, --(optional) table of default color values (or default = defaultColor, where defaultColor is a table with keys of r, g, b[, a]) or a function that returns the color
+    reference = "MyAddonColorpicker" -- unique global reference to control (optional)
+} ]]
+
+
+local widgetVersion = 11
 local LAM = LibStub("LibAddonMenu-2.0")
 if not LAM:RegisterWidget("colorpicker", widgetVersion) then return end

 local wm = WINDOW_MANAGER
-local cm = CALLBACK_MANAGER
-local tinsert = table.insert
-

 local function UpdateDisabled(control)
-	local disable
-	if type(control.data.disabled) == "function" then
-		disable = control.data.disabled()
-	else
-		disable = control.data.disabled
-	end
-
-	if disable then
-		control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
-	else
-		control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
-	end
-
-	control.isDisabled = disable
+    local disable
+    if type(control.data.disabled) == "function" then
+        disable = control.data.disabled()
+    else
+        disable = control.data.disabled
+    end
+
+    if disable then
+        control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
+    else
+        control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+    end
+
+    control.isDisabled = disable
 end

 local function UpdateValue(control, forceDefault, valueR, valueG, valueB, valueA)
-	if forceDefault then	--if we are forcing defaults
-		local color = LAM.util.GetDefaultValue(control.data.default)
-		valueR, valueG, valueB, valueA = color.r, color.g, color.b, color.a
-		control.data.setFunc(valueR, valueG, valueB, valueA)
-	elseif valueR and valueG and valueB then
-		control.data.setFunc(valueR, valueG, valueB, valueA or 1)
-		--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
-		valueR, valueG, valueB, valueA = control.data.getFunc()
-	end
-
-	control.thumb:SetColor(valueR, valueG, valueB, valueA or 1)
+    if forceDefault then --if we are forcing defaults
+        local color = LAM.util.GetDefaultValue(control.data.default)
+        valueR, valueG, valueB, valueA = color.r, color.g, color.b, color.a
+        control.data.setFunc(valueR, valueG, valueB, valueA)
+    elseif valueR and valueG and valueB then
+        control.data.setFunc(valueR, valueG, valueB, valueA or 1)
+        --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed
+        LAM.util.RequestRefreshIfNeeded(control)
+    else
+        valueR, valueG, valueB, valueA = control.data.getFunc()
+    end
+
+    control.thumb:SetColor(valueR, valueG, valueB, valueA or 1)
 end

 function LAMCreateControl.colorpicker(parent, colorpickerData, controlName)
-	local control = LAM.util.CreateLabelAndContainerControl(parent, colorpickerData, controlName)
-
-	control.color = control.container
-	local color = control.color
-
-	control.thumb = wm:CreateControl(nil, color, CT_TEXTURE)
-	local thumb = control.thumb
-	thumb:SetDimensions(36, 18)
-	thumb:SetAnchor(LEFT, color, LEFT, 4, 0)
-
-	color.border = wm:CreateControl(nil, color, CT_TEXTURE)
-	local border = color.border
-	border:SetTexture("EsoUI\\Art\\ChatWindow\\chatOptions_bgColSwatch_frame.dds")
-	border:SetTextureCoords(0, .625, 0, .8125)
-	border:SetDimensions(40, 22)
-	border:SetAnchor(CENTER, thumb, CENTER, 0, 0)
-
-	local function ColorPickerCallback(r, g, b, a)
-		control:UpdateValue(false, r, g, b, a)
-	end
-
-	control:SetHandler("OnMouseUp", function(self, btn, upInside)
-		if self.isDisabled then return end
-
-		if upInside then
-			local r, g, b, a = colorpickerData.getFunc()
-			COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a, LAM.util.GetStringFromValue(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.data = {tooltipText = LAM.util.GetStringFromValue(colorpickerData.warning)}
-	end
-
-	control.data.tooltipText = LAM.util.GetStringFromValue(colorpickerData.tooltip)
-
-	if colorpickerData.disabled ~= nil then
-		control.UpdateDisabled = UpdateDisabled
-		control:UpdateDisabled()
-	end
-	control.UpdateValue = UpdateValue
-	control: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
-		tinsert(control.panel.controlsToRefresh, control)
-	end
-
-	return control
+    local control = LAM.util.CreateLabelAndContainerControl(parent, colorpickerData, controlName)
+
+    control.color = control.container
+    local color = control.color
+
+    control.thumb = wm:CreateControl(nil, color, CT_TEXTURE)
+    local thumb = control.thumb
+    thumb:SetDimensions(36, 18)
+    thumb:SetAnchor(LEFT, color, LEFT, 4, 0)
+
+    color.border = wm:CreateControl(nil, color, CT_TEXTURE)
+    local border = color.border
+    border:SetTexture("EsoUI\\Art\\ChatWindow\\chatOptions_bgColSwatch_frame.dds")
+    border:SetTextureCoords(0, .625, 0, .8125)
+    border:SetDimensions(40, 22)
+    border:SetAnchor(CENTER, thumb, CENTER, 0, 0)
+
+    local function ColorPickerCallback(r, g, b, a)
+        control:UpdateValue(false, r, g, b, a)
+    end
+
+    control:SetHandler("OnMouseUp", function(self, btn, upInside)
+        if self.isDisabled then return end
+
+        if upInside then
+            local r, g, b, a = colorpickerData.getFunc()
+            COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a, LAM.util.GetStringFromValue(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.data = {tooltipText = LAM.util.GetStringFromValue(colorpickerData.warning)}
+    end
+
+    control.data.tooltipText = LAM.util.GetStringFromValue(colorpickerData.tooltip)
+
+    control.UpdateValue = UpdateValue
+    control:UpdateValue()
+    if colorpickerData.disabled ~= nil then
+        control.UpdateDisabled = UpdateDisabled
+        control:UpdateDisabled()
+    end
+
+    LAM.util.RegisterForRefreshIfNeeded(control)
+
+    return control
 end
diff --git a/lib/LibAddonMenu-2.0/controls/custom.lua b/lib/LibAddonMenu-2.0/controls/custom.lua
index 921402a..40a7c42 100644
--- a/lib/LibAddonMenu-2.0/controls/custom.lua
+++ b/lib/LibAddonMenu-2.0/controls/custom.lua
@@ -1,40 +1,35 @@
 --[[customData = {
-	type = "custom",
-	reference = "MyAddonCustomControl",	--(optional) unique name for your control to use as reference
-	refreshFunc = function(customControl) end,	--(optional) function to call when panel/controls refresh
-	width = "full",	--or "half" (optional)
-}	]]
+    type = "custom",
+    reference = "MyAddonCustomControl", --(optional) unique name for your control to use as reference
+    refreshFunc = function(customControl) end, --(optional) function to call when panel/controls refresh
+    width = "full", --or "half" (optional)
+} ]]

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

-local wm = WINDOW_MANAGER
-local tinsert = table.insert
-
 local function UpdateValue(control)
-	if control.data.refreshFunc then
-		control.data.refreshFunc(control)
-	end
+    if control.data.refreshFunc then
+        control.data.refreshFunc(control)
+    end
 end

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

-	if control.isHalfWidth then	--note these restrictions
-		control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4)
-	else
-		control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4)
-	end
+    if control.isHalfWidth then --note these restrictions
+        control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4)
+    else
+        control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4)
+    end

-	control.UpdateValue = UpdateValue
+    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
-		tinsert(control.panel.controlsToRefresh, control)
-	end
+    LAM.util.RegisterForRefreshIfNeeded(control)

-	return control
-end
\ No newline at end of file
+    return control
+end
diff --git a/lib/LibAddonMenu-2.0/controls/description.lua b/lib/LibAddonMenu-2.0/controls/description.lua
index c9211ee..da207a0 100644
--- a/lib/LibAddonMenu-2.0/controls/description.lua
+++ b/lib/LibAddonMenu-2.0/controls/description.lua
@@ -1,10 +1,10 @@
 --[[descriptionData = {
-	type = "description",
-	text = "My description text to display.", -- or string id or function returning a string
-	title = "My Title",	-- or string id or function returning a string (optional)
-	width = "full",	--or "half" (optional)
-	reference = "MyAddonDescription"	-- unique global reference to control (optional)
-}	]]
+    type = "description",
+    text = "My description text to display.", -- or string id or function returning a string
+    title = "My Title", -- or string id or function returning a string (optional)
+    width = "full", --or "half" (optional)
+    reference = "MyAddonDescription" -- unique global reference to control (optional)
+} ]]


 local widgetVersion = 8
@@ -12,52 +12,49 @@ local LAM = LibStub("LibAddonMenu-2.0")
 if not LAM:RegisterWidget("description", widgetVersion) then return end

 local wm = WINDOW_MANAGER
-local tinsert = table.insert

 local function UpdateValue(control)
-	if control.title then
-		control.title:SetText(LAM.util.GetStringFromValue(control.data.title))
-	end
-	control.desc:SetText(LAM.util.GetStringFromValue(control.data.text))
+    if control.title then
+        control.title:SetText(LAM.util.GetStringFromValue(control.data.title))
+    end
+    control.desc:SetText(LAM.util.GetStringFromValue(control.data.text))
 end

 function LAMCreateControl.description(parent, descriptionData, controlName)
-	local control = LAM.util.CreateBaseControl(parent, descriptionData, controlName)
-	local isHalfWidth = control.isHalfWidth
-	local width = control:GetWidth()
-	control:SetResizeToFitDescendents(true)
-
-	if isHalfWidth then
-		control:SetDimensionConstraints(width / 2, 0, width / 2, 0)
-	else
-		control:SetDimensionConstraints(width, 0, width, 0)
-	end
-
-	control.desc = wm:CreateControl(nil, control, CT_LABEL)
-	local desc = control.desc
-	desc:SetVerticalAlignment(TEXT_ALIGN_TOP)
-	desc:SetFont("ZoFontGame")
-	desc:SetText(LAM.util.GetStringFromValue(descriptionData.text))
-	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 width / 2 or width)
-		title:SetAnchor(TOPLEFT, control, TOPLEFT)
-		title:SetFont("ZoFontWinH4")
-		title:SetText(LAM.util.GetStringFromValue(descriptionData.title))
-		desc:SetAnchor(TOPLEFT, title, BOTTOMLEFT)
-	else
-		desc:SetAnchor(TOPLEFT)
-	end
-
-	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
-		tinsert(control.panel.controlsToRefresh, control)
-	end
-
-	return control
-
-end
\ No newline at end of file
+    local control = LAM.util.CreateBaseControl(parent, descriptionData, controlName)
+    local isHalfWidth = control.isHalfWidth
+    local width = control:GetWidth()
+    control:SetResizeToFitDescendents(true)
+
+    if isHalfWidth then
+        control:SetDimensionConstraints(width / 2, 0, width / 2, 0)
+    else
+        control:SetDimensionConstraints(width, 0, width, 0)
+    end
+
+    control.desc = wm:CreateControl(nil, control, CT_LABEL)
+    local desc = control.desc
+    desc:SetVerticalAlignment(TEXT_ALIGN_TOP)
+    desc:SetFont("ZoFontGame")
+    desc:SetText(LAM.util.GetStringFromValue(descriptionData.text))
+    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 width / 2 or width)
+        title:SetAnchor(TOPLEFT, control, TOPLEFT)
+        title:SetFont("ZoFontWinH4")
+        title:SetText(LAM.util.GetStringFromValue(descriptionData.title))
+        desc:SetAnchor(TOPLEFT, title, BOTTOMLEFT)
+    else
+        desc:SetAnchor(TOPLEFT)
+    end
+
+    control.UpdateValue = UpdateValue
+
+    LAM.util.RegisterForRefreshIfNeeded(control)
+
+    return control
+
+end
diff --git a/lib/LibAddonMenu-2.0/controls/dropdown.lua b/lib/LibAddonMenu-2.0/controls/dropdown.lua
index 6ed4370..0e5d3e2 100644
--- a/lib/LibAddonMenu-2.0/controls/dropdown.lua
+++ b/lib/LibAddonMenu-2.0/controls/dropdown.lua
@@ -1,131 +1,124 @@
 --[[dropdownData = {
-	type = "dropdown",
-	name = "My Dropdown", -- or string id or function returning a string
-	choices = {"table", "of", "choices"},
-	getFunc = function() return db.var end,
-	setFunc = function(var) db.var = var doStuff() end,
-	tooltip = "Dropdown's tooltip text.", -- or string id or function returning a string (optional)
-	sort = "name-up", --or "name-down", "numeric-up", "numeric-down" (optional) - if not provided, list will not be sorted
-	width = "full",	--or "half" (optional)
-	disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
-	warning = "Will need to reload the UI.",	 -- or string id or function returning a string (optional)
-	default = defaults.var,	-- default value or function that returns the default value (optional)
-	reference = "MyAddonDropdown"	-- unique global reference to control (optional)
-}	]]
-
-
-local widgetVersion = 12
+    type = "dropdown",
+    name = "My Dropdown", -- or string id or function returning a string
+    choices = {"table", "of", "choices"},
+    getFunc = function() return db.var end,
+    setFunc = function(var) db.var = var doStuff() end,
+    tooltip = "Dropdown's tooltip text.", -- or string id or function returning a string (optional)
+    sort = "name-up", --or "name-down", "numeric-up", "numeric-down" (optional) - if not provided, list will not be sorted
+    width = "full", --or "half" (optional)
+    disabled = function() return db.someBooleanSetting end, --or boolean (optional)
+    warning = "Will need to reload the UI.",  -- or string id or function returning a string (optional)
+    default = defaults.var, -- default value or function that returns the default value (optional)
+    reference = "MyAddonDropdown" -- unique global reference to control (optional)
+} ]]
+
+
+local widgetVersion = 13
 local LAM = LibStub("LibAddonMenu-2.0")
 if not LAM:RegisterWidget("dropdown", widgetVersion) then return end

 local wm = WINDOW_MANAGER
-local cm = CALLBACK_MANAGER
-local tinsert = table.insert
-

 local function UpdateDisabled(control)
-	local disable
-	if type(control.data.disabled) == "function" then
-		disable = control.data.disabled()
-	else
-		disable = control.data.disabled
-	end
-
-	control.dropdown:SetEnabled(not disable)
-	if disable then
-		control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
-	else
-		control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
-	end
+    local disable
+    if type(control.data.disabled) == "function" then
+        disable = control.data.disabled()
+    else
+        disable = control.data.disabled
+    end
+
+    control.dropdown:SetEnabled(not disable)
+    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 = LAM.util.GetDefaultValue(control.data.default)
-		control.data.setFunc(value)
-		control.dropdown:SetSelectedItem(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.dropdown:SetSelectedItem(value)
-	end
+    if forceDefault then --if we are forcing defaults
+        value = LAM.util.GetDefaultValue(control.data.default)
+        control.data.setFunc(value)
+        control.dropdown:SetSelectedItem(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
+        LAM.util.RequestRefreshIfNeeded(control)
+    else
+        value = control.data.getFunc()
+        control.dropdown:SetSelectedItem(value)
+    end
 end

 local function DropdownCallback(control, choiceText, choice)
-	choice.control:UpdateValue(false, choiceText)
+    choice.control:UpdateValue(false, choiceText)
 end

 local function UpdateChoices(control, choices)
-	control.dropdown:ClearItems()	--remove previous choices	--(need to call :SetSelectedItem()?)
-
-	--build new list of choices
-	local choices = choices or control.data.choices
-	for i = 1, #choices do
-		local entry = control.dropdown:CreateItemEntry(choices[i], DropdownCallback)
-		entry.control = control
-		control.dropdown:AddItem(entry, not control.data.sort and ZO_COMBOBOX_SUPRESS_UPDATE)	--if sort type/order isn't specified, then don't sort
-	end
+    control.dropdown:ClearItems() --remove previous choices --(need to call :SetSelectedItem()?)
+
+    --build new list of choices
+    local choices = choices or control.data.choices
+    for i = 1, #choices do
+        local entry = control.dropdown:CreateItemEntry(choices[i], DropdownCallback)
+        entry.control = control
+        control.dropdown:AddItem(entry, not control.data.sort and ZO_COMBOBOX_SUPRESS_UPDATE) --if sort type/order isn't specified, then don't sort
+    end
 end

 local function GrabSortingInfo(sortInfo)
-	local t, i = {}, 1
-	for info in string.gmatch(sortInfo, "([^%-]+)") do
-		t[i] = info
-		i = i + 1
-	end
+    local t, i = {}, 1
+    for info in string.gmatch(sortInfo, "([^%-]+)") do
+        t[i] = info
+        i = i + 1
+    end

-	return t
+    return t
 end

 function LAMCreateControl.dropdown(parent, dropdownData, controlName)
-	local control = LAM.util.CreateLabelAndContainerControl(parent, dropdownData, controlName)
-
-	local countControl = parent
-	local name = parent:GetName()
-	if not name or #name == 0 then
-		countControl = LAMCreateControl
-		name = "LAM"
-	end
-	local comboboxCount = (countControl.comboboxCount or 0) + 1
-	countControl.comboboxCount = comboboxCount
-	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)
-	local dropdown = control.dropdown
-	if dropdownData.sort then
-		local sortInfo = GrabSortingInfo(dropdownData.sort)
-		local sortType, sortOrder = sortInfo[1], sortInfo[2]
-		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
-
-	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 = LAM.util.GetStringFromValue(dropdownData.warning)}
-	end
-
-	if dropdownData.disabled ~= nil then
-		control.UpdateDisabled = UpdateDisabled
-		control:UpdateDisabled()
-	end
-	control.UpdateChoices = UpdateChoices
-	control:UpdateChoices(dropdownData.choices)
-	control.UpdateValue = UpdateValue
-	control: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
-		tinsert(control.panel.controlsToRefresh, control)
-	end
-
-	return control
+    local control = LAM.util.CreateLabelAndContainerControl(parent, dropdownData, controlName)
+
+    local countControl = parent
+    local name = parent:GetName()
+    if not name or #name == 0 then
+        countControl = LAMCreateControl
+        name = "LAM"
+    end
+    local comboboxCount = (countControl.comboboxCount or 0) + 1
+    countControl.comboboxCount = comboboxCount
+    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)
+    local dropdown = control.dropdown
+    if dropdownData.sort then
+        local sortInfo = GrabSortingInfo(dropdownData.sort)
+        local sortType, sortOrder = sortInfo[1], sortInfo[2]
+        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
+
+    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 = LAM.util.GetStringFromValue(dropdownData.warning)}
+    end
+
+    control.UpdateChoices = UpdateChoices
+    control:UpdateChoices(dropdownData.choices)
+    control.UpdateValue = UpdateValue
+    control:UpdateValue()
+    if dropdownData.disabled ~= nil then
+        control.UpdateDisabled = UpdateDisabled
+        control:UpdateDisabled()
+    end
+
+    LAM.util.RegisterForRefreshIfNeeded(control)
+
+    return control
 end
diff --git a/lib/LibAddonMenu-2.0/controls/editbox.lua b/lib/LibAddonMenu-2.0/controls/editbox.lua
index fdcadfb..d7e2054 100644
--- a/lib/LibAddonMenu-2.0/controls/editbox.lua
+++ b/lib/LibAddonMenu-2.0/controls/editbox.lua
@@ -1,160 +1,153 @@
 --[[editboxData = {
-	type = "editbox",
-	name = "My Editbox", -- or string id or function returning a string
-	getFunc = function() return db.text end,
-	setFunc = function(text) db.text = text doStuff() end,
-	tooltip = "Editbox's tooltip text.", -- or string id or function returning a string (optional)
-	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.",	-- or string id or function returning a string (optional)
-	default = defaults.text,	-- default value or function that returns the default value (optional)
-	reference = "MyAddonEditbox"	-- unique global reference to control (optional)
-}	]]
-
-
-local widgetVersion = 11
+    type = "editbox",
+    name = "My Editbox", -- or string id or function returning a string
+    getFunc = function() return db.text end,
+    setFunc = function(text) db.text = text doStuff() end,
+    tooltip = "Editbox's tooltip text.", -- or string id or function returning a string (optional)
+    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.", -- or string id or function returning a string (optional)
+    default = defaults.text, -- default value or function that returns the default value (optional)
+    reference = "MyAddonEditbox" -- unique global reference to control (optional)
+} ]]
+
+
+local widgetVersion = 12
 local LAM = LibStub("LibAddonMenu-2.0")
 if not LAM:RegisterWidget("editbox", widgetVersion) then return end

 local wm = WINDOW_MANAGER
-local cm = CALLBACK_MANAGER
-local tinsert = table.insert
-

 local function UpdateDisabled(control)
-	local disable
-	if type(control.data.disabled) == "function" then
-		disable = control.data.disabled()
-	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())
-	else
-		control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
-		control.editbox:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
-	end
-	--control.editbox:SetEditEnabled(not disable)
-	control.editbox:SetMouseEnabled(not disable)
+    local disable
+    if type(control.data.disabled) == "function" then
+        disable = control.data.disabled()
+    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())
+    else
+        control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+        control.editbox:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+    end
+    --control.editbox:SetEditEnabled(not disable)
+    control.editbox:SetMouseEnabled(not disable)
 end

 local function UpdateValue(control, forceDefault, value)
-	if forceDefault then	--if we are forcing defaults
-		value = LAM.util.GetDefaultValue(control.data.default)
-		control.data.setFunc(value)
-		control.editbox:SetText(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.editbox:SetText(value)
-	end
+    if forceDefault then --if we are forcing defaults
+        value = LAM.util.GetDefaultValue(control.data.default)
+        control.data.setFunc(value)
+        control.editbox:SetText(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
+        LAM.util.RequestRefreshIfNeeded(control)
+    else
+        value = control.data.getFunc()
+        control.editbox:SetText(value)
+    end
 end

 local MIN_HEIGHT = 24
 local HALF_WIDTH_LINE_SPACING = 2
 function LAMCreateControl.editbox(parent, editboxData, controlName)
-	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
-			end
-		end)
-	else
-		control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditForBackdrop")
-	end
-	local editbox = control.editbox
-	editbox:SetText(editboxData.getFunc())
-	editbox:SetMaxInputChars(3000)
-	editbox:SetHandler("OnFocusLost", function(self) control:UpdateValue(false, self:GetText()) end)
-	editbox:SetHandler("OnEscape", function(self) self:LoseFocus() control:UpdateValue(false, self:GetText()) end)
-	editbox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end)
-	editbox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) 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
-		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")
-		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 = LAM.util.GetStringFromValue(editboxData.warning)}
-	end
-
-	if editboxData.disabled ~= nil then
-		control.UpdateDisabled = UpdateDisabled
-		control:UpdateDisabled()
-	end
-	control.UpdateValue = UpdateValue
-	control: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
-		tinsert(control.panel.controlsToRefresh, control)
-	end
-
-	return control
+    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
+            end
+        end)
+    else
+        control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditForBackdrop")
+    end
+    local editbox = control.editbox
+    editbox:SetText(editboxData.getFunc())
+    editbox:SetMaxInputChars(3000)
+    editbox:SetHandler("OnFocusLost", function(self) control:UpdateValue(false, self:GetText()) end)
+    editbox:SetHandler("OnEscape", function(self) self:LoseFocus() control:UpdateValue(false, self:GetText()) end)
+    editbox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end)
+    editbox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) 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
+        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")
+        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 = LAM.util.GetStringFromValue(editboxData.warning)}
+    end
+
+    control.UpdateValue = UpdateValue
+    control:UpdateValue()
+    if editboxData.disabled ~= nil then
+        control.UpdateDisabled = UpdateDisabled
+        control:UpdateDisabled()
+    end
+
+    LAM.util.RegisterForRefreshIfNeeded(control)
+
+    return control
 end
diff --git a/lib/LibAddonMenu-2.0/controls/header.lua b/lib/LibAddonMenu-2.0/controls/header.lua
index 72ead4b..eadff38 100644
--- a/lib/LibAddonMenu-2.0/controls/header.lua
+++ b/lib/LibAddonMenu-2.0/controls/header.lua
@@ -1,45 +1,42 @@
 --[[headerData = {
-	type = "header",
-	name = "My Header", -- or string id or function returning a string
-	width = "full",	--or "half" (optional)
-	reference = "MyAddonHeader"	-- unique global reference to control (optional)
-}	]]
+    type = "header",
+    name = "My Header", -- or string id or function returning a string
+    width = "full", --or "half" (optional)
+    reference = "MyAddonHeader" -- unique global reference to control (optional)
+} ]]


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

 local wm = WINDOW_MANAGER
-local tinsert = table.insert

 local function UpdateValue(control)
-	control.header:SetText(LAM.util.GetStringFromValue(control.data.name))
+    control.header:SetText(LAM.util.GetStringFromValue(control.data.name))
 end

 local MIN_HEIGHT = 30
 function LAMCreateControl.header(parent, headerData, controlName)
-	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 width / 2 or width)
-	divider:SetAnchor(TOPLEFT)
-
-	control.header = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel")
-	local header = control.header
-	header:SetAnchor(TOPLEFT, divider, BOTTOMLEFT)
-	header:SetAnchor(BOTTOMRIGHT)
-	header:SetText(LAM.util.GetStringFromValue(headerData.name))
-
-	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
-		tinsert(control.panel.controlsToRefresh, control)
-	end
-
-	return control
-end
\ No newline at end of file
+    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 width / 2 or width)
+    divider:SetAnchor(TOPLEFT)
+
+    control.header = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel")
+    local header = control.header
+    header:SetAnchor(TOPLEFT, divider, BOTTOMLEFT)
+    header:SetAnchor(BOTTOMRIGHT)
+    header:SetText(LAM.util.GetStringFromValue(headerData.name))
+
+    control.UpdateValue = UpdateValue
+
+    LAM.util.RegisterForRefreshIfNeeded(control)
+
+    return control
+end
diff --git a/lib/LibAddonMenu-2.0/controls/iconpicker.lua b/lib/LibAddonMenu-2.0/controls/iconpicker.lua
index de720e9..df93550 100644
--- a/lib/LibAddonMenu-2.0/controls/iconpicker.lua
+++ b/lib/LibAddonMenu-2.0/controls/iconpicker.lua
@@ -1,441 +1,433 @@
 --[[iconpickerData = {
-	type = "iconpicker",
-	name = "My Icon Picker", -- or string id or function returning a string
-	choices = {"texture path 1", "texture path 2", "texture path 3"},
-	getFunc = function() return db.var end,
-	setFunc = function(var) db.var = var doStuff() end,
-	tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional)
-	choicesTooltips = {"icon tooltip 1", "icon tooltip 2", "icon tooltip 3"}, -- or array of string ids or array of functions returning a string (optional)
-	maxColumns = 5, -- number of icons in one row (optional)
-	visibleRows = 4.5, -- number of visible rows (optional)
-	iconSize = 28, -- size of the icons (optional)
-	defaultColor = ZO_ColorDef:New("FFFFFF"), -- default color of the icons (optional)
-	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.",	-- or string id or function returning a string (optional)
-	default = defaults.var,	-- default value or function that returns the default value (optional)
-	reference = "MyAddonIconPicker"	-- unique global reference to control (optional)
-}	]]
-
-local widgetVersion = 5
+    type = "iconpicker",
+    name = "My Icon Picker", -- or string id or function returning a string
+    choices = {"texture path 1", "texture path 2", "texture path 3"},
+    getFunc = function() return db.var end,
+    setFunc = function(var) db.var = var doStuff() end,
+    tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional)
+    choicesTooltips = {"icon tooltip 1", "icon tooltip 2", "icon tooltip 3"}, -- or array of string ids or array of functions returning a string (optional)
+    maxColumns = 5, -- number of icons in one row (optional)
+    visibleRows = 4.5, -- number of visible rows (optional)
+    iconSize = 28, -- size of the icons (optional)
+    defaultColor = ZO_ColorDef:New("FFFFFF"), -- default color of the icons (optional)
+    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.", -- or string id or function returning a string (optional)
+    default = defaults.var, -- default value or function that returns the default value (optional)
+    reference = "MyAddonIconPicker" -- unique global reference to control (optional)
+} ]]
+
+local widgetVersion = 6
 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
+    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
+    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)
+    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.GetStringFromValue(icon.tooltip))
-	InformationTooltipTopLevel:BringWindowToTop()
+    InitializeTooltip(InformationTooltip, icon, TOPLEFT, 0, 0, BOTTOMRIGHT)
+    SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(icon.tooltip))
+    InformationTooltipTopLevel:BringWindowToTop()
 end

 function IconPickerMenu:OnMouseExit(icon)
-	ClearTooltip(InformationTooltip)
+    ClearTooltip(InformationTooltip)
 end

 function IconPickerMenu:SetMaxColumns(value)
-	self.maxCols = value ~= nil and value or 5
+    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
+    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
+    self.visibleRows = value ~= nil and value or 4.5
 end

 function IconPickerMenu:SetMouseHandlers(onEnter, onExit)
-	self.customOnMouseEnter = onEnter
-	self.customOnMouseExit = 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
+    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
+    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
+    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
+    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
+    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
+    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, LAM.util.GetStringFromValue(choicesTooltips[i]))
-			addedChoices[texture] = true
-		end
-	end
+    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)
+                LAM.util.RequestRefreshIfNeeded(control)
+            end, LAM.util.GetStringFromValue(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
+    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
+    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
+    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 = LAM.util.GetDefaultValue(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
+    if forceDefault then --if we are forcing defaults
+        value = LAM.util.GetDefaultValue(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
+        LAM.util.RequestRefreshIfNeeded(control)
+    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
+    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 = LAM.util.GetStringFromValue(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
+    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 = LAM.util.GetStringFromValue(iconpickerData.warning)}
+    end
+
+    control.UpdateChoices = UpdateChoices
+    control.UpdateValue = UpdateValue
+    control:UpdateValue()
+    control.SetColor = SetColor
+    control:SetColor()
+    control.SetIconSize = SetIconSize
+    control:SetIconSize(iconSize)
+
+    if iconpickerData.disabled ~= nil then
+        control.UpdateDisabled = UpdateDisabled
+        control:UpdateDisabled()
+    end
+
+    LAM.util.RegisterForRefreshIfNeeded(control)
+
+    return control
 end
diff --git a/lib/LibAddonMenu-2.0/controls/panel.lua b/lib/LibAddonMenu-2.0/controls/panel.lua
index 315365a..124f9fe 100644
--- a/lib/LibAddonMenu-2.0/controls/panel.lua
+++ b/lib/LibAddonMenu-2.0/controls/panel.lua
@@ -1,15 +1,15 @@
 --[[panelData = {
-	type = "panel",
-	name = "Window Title", -- or string id or function returning a string
-	displayName = "My Longer Window Title",	 -- or string id or function returning a string (optional) (can be useful for long addon names or if you want to colorize it)
-	author = "Seerah",	 -- or string id or function returning a string (optional)
-	version = "2.0",	 -- or string id or function returning a string (optional)
-	keywords = "settings",	-- additional keywords for search filter (it looks for matches in name..keywords..author) (optional)
-	slashCommand = "/myaddon",	-- will register a keybind to open to this panel (don't forget to include the slash!) (optional)
-	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)
-	resetFunc = function() print("defaults reset") end,	--(optional) custom function to run after settings are reset to defaults
-}	]]
+    type = "panel",
+    name = "Window Title", -- or string id or function returning a string
+    displayName = "My Longer Window Title",  -- or string id or function returning a string (optional) (can be useful for long addon names or if you want to colorize it)
+    author = "Seerah",  -- or string id or function returning a string (optional)
+    version = "2.0",  -- or string id or function returning a string (optional)
+    keywords = "settings", -- additional keywords for search filter (it looks for matches in name..keywords..author) (optional)
+    slashCommand = "/myaddon", -- will register a keybind to open to this panel (don't forget to include the slash!) (optional)
+    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)
+    resetFunc = function() print("defaults reset") end, --(optional) custom function to run after settings are reset to defaults
+} ]]


 local widgetVersion = 10
@@ -20,113 +20,109 @@ local wm = WINDOW_MANAGER
 local cm = CALLBACK_MANAGER

 local function RefreshPanel(control)
-	local panel = control.panel or control	--callback can be fired by a single control or by the panel showing
-	local panelControls = panel.controlsToRefresh
-
-	for i = 1, #panelControls do
-		local updateControl = panelControls[i]
-		if  updateControl ~= control then
-			if updateControl.UpdateValue then
-				updateControl:UpdateValue()
-			end
-			if updateControl.UpdateDisabled then
-				updateControl:UpdateDisabled()
-			end
-		end
-	end
+    local panel = control.panel or control --callback can be fired by a single control or by the panel showing
+    local panelControls = panel.controlsToRefresh
+
+    for i = 1, #panelControls do
+        local updateControl = panelControls[i]
+        if updateControl ~= control and updateControl.UpdateValue then
+            updateControl:UpdateValue()
+        end
+        if updateControl.UpdateDisabled then
+            updateControl:UpdateDisabled()
+        end
+    end
 end

 local function ForceDefaults(panel)
-	local panelControls = panel.controlsToRefresh
+    local panelControls = panel.controlsToRefresh

-	for i = 1, #panelControls do
-		local updateControl = panelControls[i]
-		if updateControl.UpdateValue and updateControl.data.default ~= nil then
-			updateControl:UpdateValue(true)
-		end
-	end
+    for i = 1, #panelControls do
+        local updateControl = panelControls[i]
+        if updateControl.UpdateValue and updateControl.data.default ~= nil then
+            updateControl:UpdateValue(true)
+        end
+    end

-	if panel.data.resetFunc then
-		panel.data.resetFunc()
-	end
+    if panel.data.resetFunc then
+        panel.data.resetFunc()
+    end

-	cm:FireCallbacks("LAM-RefreshPanel", panel)
+    cm:FireCallbacks("LAM-RefreshPanel", panel)
 end
+
 ESO_Dialogs["LAM_DEFAULTS"] = {
-	title = {
-		text = SI_INTERFACE_OPTIONS_RESET_TO_DEFAULT_TOOLTIP,
-	},
-	mainText = {
-		text = SI_OPTIONS_RESET_PROMPT,
-		align = TEXT_ALIGN_CENTER,
-	},
-	buttons = {
-		[1] = {
-			text = SI_OPTIONS_RESET,
-			callback = function(dialog) ForceDefaults(dialog.data[1]) end,
-		},
-		[2] = {
-			text = SI_DIALOG_CANCEL,
-		},
-	},
+    title = {
+        text = SI_INTERFACE_OPTIONS_RESET_TO_DEFAULT_TOOLTIP,
+    },
+    mainText = {
+        text = SI_OPTIONS_RESET_PROMPT,
+        align = TEXT_ALIGN_CENTER,
+    },
+    buttons = {
+        [1] = {
+            text = SI_OPTIONS_RESET,
+            callback = function(dialog) ForceDefaults(dialog.data[1]) end,
+        },
+        [2] = {
+            text = SI_DIALOG_CANCEL,
+        },
+    },
 }

 local callbackRegistered = false
 LAMCreateControl.scrollCount = LAMCreateControl.scrollCount or 1
 function LAMCreateControl.panel(parent, panelData, controlName)
-	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, 0, 4)
-	label:SetText(LAM.util.GetStringFromValue(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:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2)
-		if panelData.author and panelData.version then
-			info:SetText(string.format("Version: %s  -  %s: %s", LAM.util.GetStringFromValue(panelData.version), GetString(SI_ADDON_MANAGER_AUTHOR), LAM.util.GetStringFromValue(panelData.author)))
-		elseif panelData.author then
-			info:SetText(string.format("%s: %s", GetString(SI_ADDON_MANAGER_AUTHOR), LAM.util.GetStringFromValue(panelData.author)))
-		else
-			info:SetText("Version: " .. LAM.util.GetStringFromValue(panelData.version))
-		end
-	end
-
-	control.container = wm:CreateControlFromVirtual("LAMAddonPanelContainer"..LAMCreateControl.scrollCount, control, "ZO_ScrollContainer")
-	LAMCreateControl.scrollCount = LAMCreateControl.scrollCount + 1
-	local container = control.container
-	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)
-
-	if panelData.registerForDefaults then
-		control.defaultButton = wm:CreateControlFromVirtual(nil, control, "ZO_DefaultTextButton")
-		local defaultButton = control.defaultButton
-		defaultButton:SetFont("ZoFontDialogKeybindDescription")
-		defaultButton:SetHorizontalAlignment(TEXT_ALIGN_LEFT)
-		--defaultButton:SetText("Reset To Defaults")
-		defaultButton:SetText(GetString(SI_OPTIONS_DEFAULTS))
-		defaultButton:SetDimensions(200, 30)
-		defaultButton:SetAnchor(TOPLEFT, control, BOTTOMLEFT, 0, 2)
-		defaultButton:SetHandler("OnClicked", function()
-				ZO_Dialogs_ShowDialog("LAM_DEFAULTS", {control})
-			end)
-	end
-
-	if panelData.registerForRefresh and not callbackRegistered then	--don't want to register our callback more than once
-		cm:RegisterCallback("LAM-RefreshPanel", RefreshPanel)
-		callbackRegistered = true
-	end
-
-	control.data = panelData
-	control.controlsToRefresh = {}
-
-	return control
+    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, 0, 4)
+    label:SetText(LAM.util.GetStringFromValue(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:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2)
+        if panelData.author and panelData.version then
+            info:SetText(string.format("Version: %s  -  %s: %s", LAM.util.GetStringFromValue(panelData.version), GetString(SI_ADDON_MANAGER_AUTHOR), LAM.util.GetStringFromValue(panelData.author)))
+        elseif panelData.author then
+            info:SetText(string.format("%s: %s", GetString(SI_ADDON_MANAGER_AUTHOR), LAM.util.GetStringFromValue(panelData.author)))
+        else
+            info:SetText("Version: " .. LAM.util.GetStringFromValue(panelData.version))
+        end
+    end
+
+    control.container = wm:CreateControlFromVirtual("LAMAddonPanelContainer"..LAMCreateControl.scrollCount, control, "ZO_ScrollContainer")
+    LAMCreateControl.scrollCount = LAMCreateControl.scrollCount + 1
+    local container = control.container
+    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)
+
+    if panelData.registerForDefaults then
+        control.defaultButton = wm:CreateControlFromVirtual(nil, control, "ZO_DefaultTextButton")
+        local defaultButton = control.defaultButton
+        defaultButton:SetFont("ZoFontDialogKeybindDescription")
+        defaultButton:SetHorizontalAlignment(TEXT_ALIGN_LEFT)
+        --defaultButton:SetText("Reset To Defaults")
+        defaultButton:SetText(GetString(SI_OPTIONS_DEFAULTS))
+        defaultButton:SetDimensions(200, 30)
+        defaultButton:SetAnchor(TOPLEFT, control, BOTTOMLEFT, 0, 2)
+        defaultButton:SetHandler("OnClicked", function()
+            ZO_Dialogs_ShowDialog("LAM_DEFAULTS", {control})
+        end)
+    end
+
+    if panelData.registerForRefresh and not callbackRegistered then --don't want to register our callback more than once
+        cm:RegisterCallback("LAM-RefreshPanel", RefreshPanel)
+        callbackRegistered = true
+    end
+
+    control.data = panelData
+    control.controlsToRefresh = {}
+
+    return control
 end
-
-
--- vi: noexpandtab
diff --git a/lib/LibAddonMenu-2.0/controls/slider.lua b/lib/LibAddonMenu-2.0/controls/slider.lua
index 801e16e..aef9438 100644
--- a/lib/LibAddonMenu-2.0/controls/slider.lua
+++ b/lib/LibAddonMenu-2.0/controls/slider.lua
@@ -1,166 +1,206 @@
 --[[sliderData = {
-	type = "slider",
-	name = "My Slider", -- or string id or function returning a string
-	getFunc = function() return db.var end,
-	setFunc = function(value) db.var = value doStuff() end,
-	min = 0,
-	max = 20,
-	step = 1,	--(optional)
-	decimals = 0, --(optional)
-	tooltip = "Slider's tooltip text.", -- or string id or function returning a string (optional)
-	width = "full",	--or "half" (optional)
-	disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
-	warning = "Will need to reload the UI.",	-- or string id or function returning a string (optional)
-	default = defaults.var,	-- default value or function that returns the default value (optional)
-	reference = "MyAddonSlider"	-- unique global reference to control (optional)
-}	]]
-
-
-local widgetVersion = 9
+    type = "slider",
+    name = "My Slider", -- or string id or function returning a string
+    getFunc = function() return db.var end,
+    setFunc = function(value) db.var = value doStuff() end,
+    min = 0,
+    max = 20,
+    step = 1, --(optional)
+    clampInput = true, -- boolean, if set to false the input won't clamp to min and max and allow any number instead (optional)
+    decimals = 0, -- when specified the input value is rounded to the specified number of decimals (optional)
+    autoSelect = false, -- boolean, automatically select everything in the text input field when it gains focus (optional)
+    inputLocation = "below", -- or "right", determines where the input field is shown. This should not be used within the addon menu and is for custom sliders (optional)
+    tooltip = "Slider's tooltip text.", -- or string id or function returning a string (optional)
+    width = "full", --or "half" (optional)
+    disabled = function() return db.someBooleanSetting end, --or boolean (optional)
+    warning = "Will need to reload the UI.", -- or string id or function returning a string (optional)
+    default = defaults.var, -- default value or function that returns the default value (optional)
+    reference = "MyAddonSlider" -- unique global reference to control (optional)
+} ]]
+
+local widgetVersion = 10
 local LAM = LibStub("LibAddonMenu-2.0")
 if not LAM:RegisterWidget("slider", widgetVersion) then return end

 local wm = WINDOW_MANAGER
-local cm = CALLBACK_MANAGER
-local round = zo_round
 local strformat = string.format
-local tinsert = table.insert
+
+local function RoundDecimalToPlace(d, place)
+    return tonumber(strformat("%." .. tostring(place) .. "f", d))
+end

 local function UpdateDisabled(control)
-	local disable
-	if type(control.data.disabled) == "function" then
-		disable = control.data.disabled()
-	else
-		disable = control.data.disabled
-	end
-
-	control.slider:SetEnabled(not disable)
-	control.slidervalue:SetEditEnabled(not disable)
-	if disable then
-		control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
-		control.minText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
-		control.maxText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
-		control.slidervalue:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA())
-	else
-		control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
-		control.minText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
-		control.maxText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
-		control.slidervalue:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
-	end
+    local disable
+    if type(control.data.disabled) == "function" then
+        disable = control.data.disabled()
+    else
+        disable = control.data.disabled
+    end
+
+    control.slider:SetEnabled(not disable)
+    control.slidervalue:SetEditEnabled(not disable)
+    if disable then
+        control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
+        control.minText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
+        control.maxText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
+        control.slidervalue:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA())
+    else
+        control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+        control.minText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+        control.maxText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+        control.slidervalue:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
+    end
 end

 local function UpdateValue(control, forceDefault, value)
-	if forceDefault then	--if we are forcing defaults
-		value = LAM.util.GetDefaultValue(control.data.default)
-		control.data.setFunc(value)
-	elseif value and value >= control.data.min and value <= control.data.max 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()
-	end
-
-	control.slider:SetValue(value)
-	control.slidervalue:SetText(value)
+    if forceDefault then --if we are forcing defaults
+        value = LAM.util.GetDefaultValue(control.data.default)
+        control.data.setFunc(value)
+    elseif value then
+        if control.data.decimals then
+            value = RoundDecimalToPlace(value, control.data.decimals)
+        end
+        if control.data.clampInput ~= false then
+            value = math.max(math.min(value, control.data.max), control.data.min)
+        end
+        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
+        LAM.util.RequestRefreshIfNeeded(control)
+    else
+        value = control.data.getFunc()
+    end
+
+    control.slider:SetValue(value)
+    control.slidervalue:SetText(value)
 end

-
 function LAMCreateControl.slider(parent, sliderData, controlName)
-	local control = LAM.util.CreateLabelAndContainerControl(parent, sliderData, controlName)
-
-	--skipping creating the backdrop...  Is this the actual slider texture?
-	control.slider = wm:CreateControl(nil, control.container, CT_SLIDER)
-	local slider = control.slider
-	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)
-	local minValue = sliderData.min
-	local maxValue = sliderData.max
-	slider:SetMinMax(minValue, maxValue)
-	slider:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end)
-	slider:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseExit(control) end)
-
-	slider.bg = wm:CreateControl(nil, slider, CT_BACKDROP)
-	local bg = slider.bg
-	bg:SetCenterColor(0, 0, 0)
-	bg:SetAnchor(TOPLEFT, slider, TOPLEFT, 0, 4)
-	bg:SetAnchor(BOTTOMRIGHT, slider, BOTTOMRIGHT, 0, -4)
-	bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-SliderBackdrop.dds", 32, 4)
-
-	control.minText = wm:CreateControl(nil, slider, CT_LABEL)
-	local minText = control.minText
-	minText:SetFont("ZoFontGameSmall")
-	minText:SetAnchor(TOPLEFT, slider, BOTTOMLEFT)
-	minText:SetText(sliderData.min)
-
-	control.maxText = wm:CreateControl(nil, slider, CT_LABEL)
-	local maxText = control.maxText
-	maxText:SetFont("ZoFontGameSmall")
-	maxText:SetAnchor(TOPRIGHT, slider, BOTTOMRIGHT)
-	maxText:SetText(sliderData.max)
-
-	control.slidervalueBG = wm:CreateControlFromVirtual(nil, slider, "ZO_EditBackdrop")
-	control.slidervalueBG:SetDimensions(50, 16)
-	control.slidervalueBG:SetAnchor(TOP, slider, BOTTOM, 0, 0)
-	control.slidervalue = wm:CreateControlFromVirtual(nil, control.slidervalueBG, "ZO_DefaultEditForBackdrop")
-	local slidervalue = control.slidervalue
-	slidervalue:ClearAnchors()
-	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)
-			self:LoseFocus()
-			control:UpdateValue()
-		end)
-	slidervalue:SetHandler("OnEnter", function(self)
-			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
-			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)
-			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.data = {tooltipText = LAM.util.GetStringFromValue(sliderData.warning)}
-	end
-
-	if sliderData.disabled ~= nil then
-		control.UpdateDisabled = UpdateDisabled
-		control:UpdateDisabled()
-	end
-	control.UpdateValue = UpdateValue
-	control: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
-		tinsert(control.panel.controlsToRefresh, control)
-	end
-
-	return control
+    local control = LAM.util.CreateLabelAndContainerControl(parent, sliderData, controlName)
+    local isInputOnRight = sliderData.inputLocation == "right"
+
+    --skipping creating the backdrop...  Is this the actual slider texture?
+    control.slider = wm:CreateControl(nil, control.container, CT_SLIDER)
+    local slider = control.slider
+    slider:SetAnchor(TOPLEFT)
+    slider:SetHeight(14)
+    if(isInputOnRight) then
+        slider:SetAnchor(TOPRIGHT, nil, nil, -60)
+    else
+        slider:SetAnchor(TOPRIGHT)
+    end
+    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)
+    local minValue = sliderData.min
+    local maxValue = sliderData.max
+    slider:SetMinMax(minValue, maxValue)
+    slider:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end)
+    slider:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseExit(control) end)
+
+    slider.bg = wm:CreateControl(nil, slider, CT_BACKDROP)
+    local bg = slider.bg
+    bg:SetCenterColor(0, 0, 0)
+    bg:SetAnchor(TOPLEFT, slider, TOPLEFT, 0, 4)
+    bg:SetAnchor(BOTTOMRIGHT, slider, BOTTOMRIGHT, 0, -4)
+    bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-SliderBackdrop.dds", 32, 4)
+
+    control.minText = wm:CreateControl(nil, slider, CT_LABEL)
+    local minText = control.minText
+    minText:SetFont("ZoFontGameSmall")
+    minText:SetAnchor(TOPLEFT, slider, BOTTOMLEFT)
+    minText:SetText(sliderData.min)
+
+    control.maxText = wm:CreateControl(nil, slider, CT_LABEL)
+    local maxText = control.maxText
+    maxText:SetFont("ZoFontGameSmall")
+    maxText:SetAnchor(TOPRIGHT, slider, BOTTOMRIGHT)
+    maxText:SetText(sliderData.max)
+
+    control.slidervalueBG = wm:CreateControlFromVirtual(nil, slider, "ZO_EditBackdrop")
+    if(isInputOnRight) then
+        control.slidervalueBG:SetDimensions(60, 26)
+        control.slidervalueBG:SetAnchor(LEFT, slider, RIGHT, 5, 0)
+    else
+        control.slidervalueBG:SetDimensions(50, 16)
+        control.slidervalueBG:SetAnchor(TOP, slider, BOTTOM, 0, 0)
+    end
+    control.slidervalue = wm:CreateControlFromVirtual(nil, control.slidervalueBG, "ZO_DefaultEditForBackdrop")
+    local slidervalue = control.slidervalue
+    slidervalue:ClearAnchors()
+    slidervalue:SetAnchor(TOPLEFT, control.slidervalueBG, TOPLEFT, 3, 1)
+    slidervalue:SetAnchor(BOTTOMRIGHT, control.slidervalueBG, BOTTOMRIGHT, -3, -1)
+    slidervalue:SetTextType(TEXT_TYPE_NUMERIC)
+    if(isInputOnRight) then
+        slidervalue:SetFont("ZoFontGameLarge")
+    else
+        slidervalue:SetFont("ZoFontGameSmall")
+    end
+
+    local isHandlingChange = false
+    local function HandleValueChanged(value)
+        if isHandlingChange then return end
+        if sliderData.decimals then
+            value = RoundDecimalToPlace(value, sliderData.decimals)
+        end
+        isHandlingChange = true
+        slider:SetValue(value)
+        slidervalue:SetText(value)
+        isHandlingChange = false
+    end
+
+    slidervalue:SetHandler("OnEscape", function(self)
+        HandleValueChanged(sliderData.getFunc())
+        self:LoseFocus()
+    end)
+    slidervalue:SetHandler("OnEnter", function(self)
+        self:LoseFocus()
+    end)
+    slidervalue:SetHandler("OnFocusLost", function(self)
+        local value = tonumber(self:GetText())
+        control:UpdateValue(false, value)
+    end)
+    slidervalue:SetHandler("OnTextChanged", function(self)
+        local value = tonumber(self:GetText())
+        if(value) then
+            HandleValueChanged(value)
+        end
+    end)
+    if(sliderData.autoSelect) then
+        ZO_PreHookHandler(slidervalue, "OnFocusGained", function(self)
+            self:SelectAll()
+        end)
+    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
+        HandleValueChanged(value)
+    end)
+    slider:SetHandler("OnSliderReleased", function(self, value)
+        control:UpdateValue(false, value)
+    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.data = {tooltipText = LAM.util.GetStringFromValue(sliderData.warning)}
+    end
+
+    control.UpdateValue = UpdateValue
+    control:UpdateValue()
+
+    if sliderData.disabled ~= nil then
+        control.UpdateDisabled = UpdateDisabled
+        control:UpdateDisabled()
+    end
+
+    LAM.util.RegisterForRefreshIfNeeded(control)
+
+    return control
 end
diff --git a/lib/LibAddonMenu-2.0/controls/submenu.lua b/lib/LibAddonMenu-2.0/controls/submenu.lua
index 2512753..1766a1f 100644
--- a/lib/LibAddonMenu-2.0/controls/submenu.lua
+++ b/lib/LibAddonMenu-2.0/controls/submenu.lua
@@ -1,10 +1,10 @@
 --[[submenuData = {
-	type = "submenu",
-	name = "Submenu Title", -- or string id or function returning a string
-	tooltip = "My submenu tooltip",	-- -- or string id or function returning a string (optional)
-	controls = {sliderData, buttonData}	--(optional) used by LAM
-	reference = "MyAddonSubmenu"	--(optional) unique global reference to control
-}	]]
+    type = "submenu",
+    name = "Submenu Title", -- or string id or function returning a string
+    tooltip = "My submenu tooltip", -- -- or string id or function returning a string (optional)
+    controls = {sliderData, buttonData} --(optional) used by LAM
+    reference = "MyAddonSubmenu" --(optional) unique global reference to control
+} ]]

 local widgetVersion = 11
 local LAM = LibStub("LibAddonMenu-2.0")
@@ -12,101 +12,97 @@ if not LAM:RegisterWidget("submenu", widgetVersion) then return end

 local wm = WINDOW_MANAGER
 local am = ANIMATION_MANAGER
-local tinsert = table.insert
-

 local function UpdateValue(control)
-	control.label:SetText(LAM.util.GetStringFromValue(control.data.name))
-	if control.data.tooltip then
-		control.label.data.tooltipText = LAM.util.GetStringFromValue(control.data.tooltip)
-	end
+    control.label:SetText(LAM.util.GetStringFromValue(control.data.name))
+    if control.data.tooltip then
+        control.label.data.tooltipText = LAM.util.GetStringFromValue(control.data.tooltip)
+    end
 end

 local function AnimateSubmenu(clicked)
-	local control = clicked:GetParent()
-	control.open = not control.open
-
-	if control.open then
-		control.animation:PlayFromStart()
-	else
-		control.animation:PlayFromEnd()
-	end
+    local control = clicked:GetParent()
+    control.open = not control.open
+
+    if control.open then
+        control.animation:PlayFromStart()
+    else
+        control.animation:PlayFromEnd()
+    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.data = submenuData
-
-	control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel")
-	local label = control.label
-	label:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5)
-	label:SetDimensions(width, 30)
-	label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
-	label:SetText(LAM.util.GetStringFromValue(submenuData.name))
-	label:SetMouseEnabled(true)
-	if submenuData.tooltip then
-		label.data = {tooltipText = LAM.util.GetStringFromValue(submenuData.tooltip)}
-		label:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
-		label:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
-	end
-
-	control.scroll = wm:CreateControl(nil, control, CT_SCROLL)
-	local scroll = control.scroll
-	scroll:SetParent(control)
-	scroll:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, 10)
-	scroll:SetDimensionConstraints(width + 5, 0, width + 5, 0)
-
-	control.bg = wm:CreateControl(nil, label, CT_BACKDROP)
-	local bg = control.bg
-	bg:SetAnchor(TOPLEFT, label, TOPLEFT, -5, -5)
-	bg:SetAnchor(BOTTOMRIGHT, scroll, BOTTOMRIGHT, -7, 0)
-	bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16)
-	bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds")
-	bg:SetInsets(16, 16, -16, -16)
-
-	control.arrow = wm:CreateControl(nil, bg, CT_TEXTURE)
-	local arrow = control.arrow
-	arrow:SetDimensions(28, 28)
-	arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds")	--list_sortup for the other way
-	arrow:SetAnchor(TOPRIGHT, bg, TOPRIGHT, -5, 5)
-
-	--figure out the cool animation later...
-	control.animation = am:CreateTimeline()
-	local animation = control.animation
-	animation:SetPlaybackType(ANIMATION_SIZE, 0)	--2nd arg = loop count
-
-	control:SetResizeToFitDescendents(true)
-	control.open = false
-	label:SetHandler("OnMouseUp", AnimateSubmenu)
-	animation:SetHandler("OnStop", function(self, completedPlaying)
-			scroll:SetResizeToFitDescendents(control.open)
-			if control.open then
-				control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortup.dds")
-				scroll:SetResizeToFitPadding(5, 20)
-			else
-				control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds")
-				scroll:SetResizeToFitPadding(5, 0)
-				scroll:SetHeight(0)
-			end
-		end)
-
-	--small strip at the bottom of the submenu that you can click to close it
-	control.btmToggle = wm:CreateControl(nil, control, CT_TEXTURE)
-	local btmToggle = control.btmToggle
-	btmToggle:SetMouseEnabled(true)
-	btmToggle:SetAnchor(BOTTOMLEFT, control.scroll, BOTTOMLEFT)
-	btmToggle:SetAnchor(BOTTOMRIGHT, control.scroll, BOTTOMRIGHT)
-	btmToggle:SetHeight(15)
-	btmToggle:SetAlpha(0)
-	btmToggle:SetHandler("OnMouseUp", AnimateSubmenu)
-
-	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
-		tinsert(control.panel.controlsToRefresh, control)
-	end
-
-	return control
+    local width = parent:GetWidth() - 45
+    local control = wm:CreateControl(controlName or submenuData.reference, parent.scroll or parent, CT_CONTROL)
+    control.panel = parent
+    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(width, 30)
+    label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
+    label:SetText(LAM.util.GetStringFromValue(submenuData.name))
+    label:SetMouseEnabled(true)
+    if submenuData.tooltip then
+        label.data = {tooltipText = LAM.util.GetStringFromValue(submenuData.tooltip)}
+        label:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
+        label:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
+    end
+
+    control.scroll = wm:CreateControl(nil, control, CT_SCROLL)
+    local scroll = control.scroll
+    scroll:SetParent(control)
+    scroll:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, 10)
+    scroll:SetDimensionConstraints(width + 5, 0, width + 5, 0)
+
+    control.bg = wm:CreateControl(nil, label, CT_BACKDROP)
+    local bg = control.bg
+    bg:SetAnchor(TOPLEFT, label, TOPLEFT, -5, -5)
+    bg:SetAnchor(BOTTOMRIGHT, scroll, BOTTOMRIGHT, -7, 0)
+    bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16)
+    bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds")
+    bg:SetInsets(16, 16, -16, -16)
+
+    control.arrow = wm:CreateControl(nil, bg, CT_TEXTURE)
+    local arrow = control.arrow
+    arrow:SetDimensions(28, 28)
+    arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds") --list_sortup for the other way
+    arrow:SetAnchor(TOPRIGHT, bg, TOPRIGHT, -5, 5)
+
+    --figure out the cool animation later...
+    control.animation = am:CreateTimeline()
+    local animation = control.animation
+    animation:SetPlaybackType(ANIMATION_SIZE, 0) --2nd arg = loop count
+
+    control:SetResizeToFitDescendents(true)
+    control.open = false
+    label:SetHandler("OnMouseUp", AnimateSubmenu)
+    animation:SetHandler("OnStop", function(self, completedPlaying)
+        scroll:SetResizeToFitDescendents(control.open)
+        if control.open then
+            control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortup.dds")
+            scroll:SetResizeToFitPadding(5, 20)
+        else
+            control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds")
+            scroll:SetResizeToFitPadding(5, 0)
+            scroll:SetHeight(0)
+        end
+    end)
+
+    --small strip at the bottom of the submenu that you can click to close it
+    control.btmToggle = wm:CreateControl(nil, control, CT_TEXTURE)
+    local btmToggle = control.btmToggle
+    btmToggle:SetMouseEnabled(true)
+    btmToggle:SetAnchor(BOTTOMLEFT, control.scroll, BOTTOMLEFT)
+    btmToggle:SetAnchor(BOTTOMRIGHT, control.scroll, BOTTOMRIGHT)
+    btmToggle:SetHeight(15)
+    btmToggle:SetAlpha(0)
+    btmToggle:SetHandler("OnMouseUp", AnimateSubmenu)
+
+    control.UpdateValue = UpdateValue
+
+    LAM.util.RegisterForRefreshIfNeeded(control)
+
+    return control
 end
diff --git a/lib/LibAddonMenu-2.0/controls/texture.lua b/lib/LibAddonMenu-2.0/controls/texture.lua
index 077862e..a42a29b 100644
--- a/lib/LibAddonMenu-2.0/controls/texture.lua
+++ b/lib/LibAddonMenu-2.0/controls/texture.lua
@@ -1,12 +1,12 @@
 --[[textureData = {
-	type = "texture",
-	image = "file/path.dds",
-	imageWidth = 64,	--max of 250 for half width, 510 for full
-	imageHeight = 32,	--max of 100
-	tooltip = "Image's tooltip text.",	-- or string id or function returning a string (optional)
-	width = "full",	--or "half" (optional)
-	reference = "MyAddonTexture"	--(optional) unique global reference to control
-}	]]
+    type = "texture",
+    image = "file/path.dds",
+    imageWidth = 64, --max of 250 for half width, 510 for full
+    imageHeight = 32, --max of 100
+    tooltip = "Image's tooltip text.", -- or string id or function returning a string (optional)
+    width = "full", --or "half" (optional)
+    reference = "MyAddonTexture" --(optional) unique global reference to control
+} ]]

 --add texture coords support?

@@ -18,28 +18,28 @@ local wm = WINDOW_MANAGER

 local MIN_HEIGHT = 26
 function LAMCreateControl.texture(parent, textureData, controlName)
-	local control = LAM.util.CreateBaseControl(parent, textureData, controlName)
-	local width = control:GetWidth()
-	control:SetResizeToFitDescendents(true)
-
-	if control.isHalfWidth then	--note these restrictions
-		control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4)
-	else
-		control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4)
-	end
-
-	control.texture = wm:CreateControl(nil, control, CT_TEXTURE)
-	local texture = control.texture
-	texture:SetAnchor(CENTER)
-	texture:SetDimensions(textureData.imageWidth, textureData.imageHeight)
-	texture:SetTexture(textureData.image)
-
-	if textureData.tooltip then
-		texture:SetMouseEnabled(true)
-		texture.data = {tooltipText = LAM.util.GetStringFromValue(textureData.tooltip)}
-		texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
-		texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseExit)
-	end
-
-	return control
-end
\ No newline at end of file
+    local control = LAM.util.CreateBaseControl(parent, textureData, controlName)
+    local width = control:GetWidth()
+    control:SetResizeToFitDescendents(true)
+
+    if control.isHalfWidth then --note these restrictions
+        control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4)
+    else
+        control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4)
+    end
+
+    control.texture = wm:CreateControl(nil, control, CT_TEXTURE)
+    local texture = control.texture
+    texture:SetAnchor(CENTER)
+    texture:SetDimensions(textureData.imageWidth, textureData.imageHeight)
+    texture:SetTexture(textureData.image)
+
+    if textureData.tooltip then
+        texture:SetMouseEnabled(true)
+        texture.data = {tooltipText = LAM.util.GetStringFromValue(textureData.tooltip)}
+        texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
+        texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseExit)
+    end
+
+    return control
+end