Updated to LibAddonMenu 2.0 and added a backup warning message.

Jayden Platell [06-26-14 - 09:41]
Updated to LibAddonMenu 2.0 and added a backup warning message.
Filename
Librarian.lua
Librarian.txt
Librarian.xml
LibrarianSettings.lua
Libs/LibAddonMenu-1.0/LibAddonMenu-1.0.lua
Libs/LibAddonMenu-2.0/LibAddonMenu-2.0.lua
Libs/LibAddonMenu-2.0/controls/button.lua
Libs/LibAddonMenu-2.0/controls/checkbox.lua
Libs/LibAddonMenu-2.0/controls/colorpicker.lua
Libs/LibAddonMenu-2.0/controls/custom.lua
Libs/LibAddonMenu-2.0/controls/description.lua
Libs/LibAddonMenu-2.0/controls/dropdown.lua
Libs/LibAddonMenu-2.0/controls/editbox.lua
Libs/LibAddonMenu-2.0/controls/header.lua
Libs/LibAddonMenu-2.0/controls/panel.lua
Libs/LibAddonMenu-2.0/controls/slider.lua
Libs/LibAddonMenu-2.0/controls/submenu.lua
Libs/LibAddonMenu-2.0/controls/texture.lua
diff --git a/Librarian.lua b/Librarian.lua
index 9742434..8d2fec3 100644
--- a/Librarian.lua
+++ b/Librarian.lua
@@ -10,7 +10,7 @@ ZO_CreateStringId("SI_LIBRARIAN_SORT_TYPE_TITLE", "Title")
 ZO_CreateStringId("SI_LIBRARIAN_SORT_TYPE_WORD_COUNT", "Words")
 ZO_CreateStringId("SI_LIBRARIAN_MARK_UNREAD", "Mark as Unread")
 ZO_CreateStringId("SI_LIBRARIAN_MARK_READ", "Mark as Read")
-ZO_CreateStringId("SI_LIBRARIAN_CREDIT", "Librarian 1.1.3 by Flamage")
+ZO_CreateStringId("SI_LIBRARIAN_CREDIT", "Librarian 1.2.0 by Flamage")
 ZO_CreateStringId("SI_LIBRARIAN_BOOK_COUNT", "%d Books")
 ZO_CreateStringId("SI_LIBRARIAN_UNREAD_COUNT", "%s (%d Unread)")
 ZO_CreateStringId("SI_LIBRARIAN_SHOW_ALL_BOOKS", "Show books for all characters")
@@ -19,6 +19,7 @@ ZO_CreateStringId("SI_LIBRARIAN_NEW_BOOK_FOUND_WITH_TITLE", "Book added to libra
 ZO_CreateStringId("SI_LIBRARIAN_FULLTEXT_SEARCH", "Full-text Search:")
 ZO_CreateStringId("SI_LIBRARIAN_SEARCH_HINT", "Enter text to search for.")
 ZO_CreateStringId("SI_LIBRARIAN_RELOAD_REMINDER", "ReloadUI suggested to update Librarian database.")
+ZO_CreateStringId("SI_LIBRARIAN_BACKUP_REMINDER", "Remember to backup your Librarian SavedVariables regularly.  Look up Librarian on ESOUI for instructions.")

 local SORT_ARROW_UP = "EsoUI/Art/Miscellaneous/list_sortUp.dds"
 local SORT_ARROW_DOWN = "EsoUI/Art/Miscellaneous/list_sortDown.dds"
diff --git a/Librarian.txt b/Librarian.txt
index 28df18f..07e56f9 100644
--- a/Librarian.txt
+++ b/Librarian.txt
@@ -1,10 +1,11 @@
 ## Title: Librarian
 ## Author: Flamage
-## APIVersion: 100004
+## APIVersion: 100007
 ## SavedVariables: Librarian_SavedVariables
+## OptionalDependsOn: LibAddonMenu-2.0

 Libs\LibStub\LibStub.lua
-Libs\LibAddonMenu-1.0\LibAddonMenu-1.0.lua
+Libs\LibAddonMenu-2.0\LibAddonMenu-2.0.lua

 Librarian.lua
 LibrarianSettings.lua
diff --git a/Librarian.xml b/Librarian.xml
index 5ed5901..824b809 100644
--- a/Librarian.xml
+++ b/Librarian.xml
@@ -85,8 +85,14 @@
                 </Control>
                 <Control name="$(parent)List" inherits="ZO_ScrollList">
                     <Anchor point="TOPLEFT" relativeTo="$(parent)Headers" relativePoint="BOTTOMLEFT" />
-                    <Anchor point="BOTTOMRIGHT" offsetX="-12" offsetY="0" />
+                    <Anchor point="BOTTOMRIGHT" offsetX="-12" offsetY="-29" />
                 </Control>
+                <Label name="$(parent)BackupPSA" font="ZoFontGame" color="INTERFACE_COLOR_TYPE_TEXT_COLORS:INTERFACE_TEXT_COLOR_DISABLED">
+                    <Anchor point="BOTTOMLEFT" offsetX="29" />
+                    <OnInitialized>
+                        self:SetText(GetString(SI_LIBRARIAN_BACKUP_REMINDER))
+                    </OnInitialized>
+                </Label>
                 <Button name="$(parent)ShowAllBooks" inherits="ZO_CheckButton">
                     <Anchor point="BOTTOMLEFT" offsetX="29" offsetY="27"/>
                     <Controls>
diff --git a/LibrarianSettings.lua b/LibrarianSettings.lua
index 0704268..6fb6be5 100644
--- a/LibrarianSettings.lua
+++ b/LibrarianSettings.lua
@@ -69,50 +69,68 @@ function LibrarianSettings:Initialise(settings)
 	if self.settings.reloadReminderBookCount == nil then
 		self.settings.reloadReminderBookCount = 5
 	end
-
-	local LAM = LibStub("LibAddonMenu-1.0")
-	local optionsPanel = LAM:CreateControlPanel("LibrarianOptions", "Librarian")
-	LAM:AddHeader(optionsPanel, "LibrarianOptionsHeader", nil)
-
-	LAM:AddDropdown(optionsPanel,
-		"LibrarianOptionsTimeFormat",
-		"Time Format",
-		"Select a format to display times in.",
-		map(timeFormats, function(item) return item.name end),
-		function() return getSettingByValue(timeFormats, self.settings.timeFormat).name end,
-		function(name)
-			self.settings.timeFormat = getSettingByName(timeFormats, name).value
-			LIBRARIAN:CommitScrollList()
-		end)
-
-	LAM:AddDropdown(optionsPanel,
-		"LibrarianOptionsAlertSetting",
-		"Alert Settings",
-		"Select a style of alert.",
-		map(alertStyles, function(item) return item.name end),
-		function() return getSettingByValue(alertStyles, self.settings.alertStyle).name end,
-		function(name)
-			local setting = getSettingByName(alertStyles, name)
-			self.settings.alertStyle = setting.value
-			self.settings.chatEnabled = setting.chat
-			self.settings.alertEnabled = setting.alert
-		end)
-
-	LAM:AddCheckbox(optionsPanel,
-		"LibrarianOptionsUnreadIndicator",
-		"Unread Indicator",
-		"Show unread indicator in book reader.",
-		function() return self.settings.showUnreadIndicatorInReader end,
-		function(value) self.settings.showUnreadIndicatorInReader = value end)
-
-	LAM:AddDropdown(optionsPanel,
-		"LibrarianOptionsReloadReminder",
-		"ReloadUI reminder after",
-		"Reminder to /reloadui after this number of new books are discovered.",
-		map(reloadReminders, function(item) return item.name end),
-		function() return getSettingByValue(reloadReminders, self.settings.reloadReminderBookCount).name end,
-		function(name)
-			local setting = getSettingByName(reloadReminders, name)
-			self.settings.reloadReminderBookCount = setting.value
-		end)
+
+  local panelData = {
+    type = "panel",
+    name = "Librarian",
+    displayName = "Librarian Book Manager",
+    author = "Flamage",
+    version = "1.2.0",
+    slashCommand = "/lo"
+  }
+
+  local optionsTable = {
+    [1] = {
+      type = "dropdown",
+      name = "Time Format",
+      tooltip = "Select a format to display times in.",
+      choices = map(timeFormats, function(item) return item.name end),
+      getFunc = function() return getSettingByValue(timeFormats, self.settings.timeFormat).name end,
+      setFunc = function(name)
+        self.settings.timeFormat = getSettingByName(timeFormats, name).value
+        LIBRARIAN:CommitScrollList()
+      end
+    },
+    [2] = {
+      type = "dropdown",
+      name = "Alert Settings",
+      tooltip = "Select a style of alert.",
+      choices = map(alertStyles, function(item) return item.name end),
+      getFunc = function() return getSettingByValue(alertStyles, self.settings.alertStyle).name end,
+      setFunc = function(name)
+        local setting = getSettingByName(alertStyles, name)
+        self.settings.alertStyle = setting.value
+        self.settings.chatEnabled = setting.chat
+        self.settings.alertEnabled = setting.alert
+      end
+    },
+    [3] = {
+      type = "dropdown",
+      name = "ReloadUI reminder after",
+      tooltip = "Reminder to /reloadui after this number of new books are discovered.",
+      choices = map(reloadReminders, function(item) return item.name end),
+      getFunc = function() return getSettingByValue(reloadReminders, self.settings.reloadReminderBookCount).name end,
+      setFunc = function(name)
+        local setting = getSettingByName(reloadReminders, name)
+        self.settings.reloadReminderBookCount = setting.value
+      end
+    },
+    [4] = {
+      type = "checkbox",
+      name = "Unread Indicator",
+      tooltip = "Show an unread indicator in book reader.",
+      getFunc = function() return self.settings.showUnreadIndicatorInReader end,
+      setFunc = function(value) self.settings.showUnreadIndicatorInReader = value end
+    },
+    [5] = {
+      type = "button",
+      name = "Import from Lore Library",
+      tooltip = "Import any missing books from the Lore Library.  Works with all books once Eidetic Memory is unlocked.",
+      func = function() LIBRARIAN:ImportFromLoreLibrary() end
+    }
+  }
+
+  local LAM = LibStub("LibAddonMenu-2.0")
+  LAM:RegisterAddonPanel("LibrarianOptions", panelData)
+  LAM:RegisterOptionControls("LibrarianOptions", optionsTable)
 end
\ No newline at end of file
diff --git a/Libs/LibAddonMenu-1.0/LibAddonMenu-1.0.lua b/Libs/LibAddonMenu-1.0/LibAddonMenu-1.0.lua
deleted file mode 100644
index e09debc..0000000
--- a/Libs/LibAddonMenu-1.0/LibAddonMenu-1.0.lua
+++ /dev/null
@@ -1,485 +0,0 @@
-local MAJOR, MINOR = "LibAddonMenu-1.0", 7
-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
-
---UPVALUES--
-lam.lastAddedControl = {}
-local lastAddedControl = lam.lastAddedControl
-local wm = GetWindowManager()
-local strformat = string.format
-local tostring = tostring
-local round = zo_round
-local optionsWindow = ZO_OptionsWindowSettingsScrollChild
-local openSubMenu
-
-
-function lam:CreateControlPanel(controlPanelID, controlPanelName)
-	local panelID
-
-	if _G[controlPanelID] then
-		panelID = _G[controlPanelID]
-		return panelID
-	end
-
-	ZO_OptionsWindow_AddUserPanel(controlPanelID, controlPanelName)
-
-	--disables Defaults button because we don't need it, but keybind still works :/ ...
-	panelID = _G[controlPanelID]
-
-	return panelID
-end
-
-function lam:AddHeader(panelID, controlName, text)
-	local isSubMenu = type(panelID) == "userdata"
-	--local header = wm:CreateControlFromVirtual(controlName, optionsWindow, lastAddedControl[panelID] and "ZO_Options_SectionTitle_WithDivider" or "ZO_Options_SectionTitle")
-	local header = wm:CreateControlFromVirtual(controlName, isSubMenu and panelID or optionsWindow, lastAddedControl[panelID] and "ZO_Options_SectionTitle_WithDivider" or "ZO_Options_SectionTitle")
-	if lastAddedControl[panelID] then
-		header:SetAnchor(TOPLEFT, lastAddedControl[panelID], BOTTOMLEFT, 0, 15)
-	else
-		header:SetAnchor(TOPLEFT)
-		if not isSubMenu then
-			header:SetHandler("OnShow", function()
-				ZO_OptionsWindowResetToDefaultButton:SetEnabled(false)
-				ZO_OptionsWindowResetToDefaultButton:SetKeybindEnabled(false)
-				ZO_OptionsWindowResetToDefaultButton:SetHidden(true)
-				--ZO_OptionsWindowResetToDefaultButton:SetAlpha(0)
-			end)
-			header:SetHandler("OnHide", function()
-				ZO_OptionsWindowResetToDefaultButton:SetEnabled(true)
-				ZO_OptionsWindowResetToDefaultButton:SetKeybindEnabled(true)
-				ZO_OptionsWindowResetToDefaultButton:SetHidden(false)
-				--ZO_OptionsWindowResetToDefaultButton:SetAlpha(1)
-			end)
-		end
-	end
-	header.controlType = OPTIONS_SECTION_TITLE
-	header.panel = isSubMenu and panelID.panel or panelID
-	header.text = text
-
-	ZO_OptionsWindow_InitializeControl(header)
-	if isSubMenu then header:SetParent(panelID) end
-
-	lastAddedControl[panelID] = header
-
-	return header
-end
-
-
---To-Do list:
---extra sub-options window out to the right?? (or maybe addon list?)
---find alternatives to handler hooks
-
-function lam:AddSlider(panelID, controlName, text, tooltip, minValue, maxValue, step, getFunc, setFunc, warning, warningText)
-	local isSubMenu = type(panelID) == "userdata"
-	local slider = wm:CreateControlFromVirtual(controlName, isSubMenu and panelID or optionsWindow, "ZO_Options_Slider")
-	slider:SetAnchor(TOPLEFT, lastAddedControl[panelID], BOTTOMLEFT, 0, 6)
-	slider.controlType = OPTIONS_SLIDER
-	slider.system = SETTING_TYPE_UI
-	slider.panel = isSubMenu and panelID.panel or panelID
-	slider.text = text
-	slider.tooltipText = tooltip
-	slider.showValue = true
-	slider.showValueMin = minValue
-	slider.showValueMax = maxValue
-	local range = maxValue - minValue
-	local slidercontrol = slider:GetNamedChild("Slider")
-	local slidervalue = slider:GetNamedChild("ValueLabel")
-	slidercontrol:SetValueStep(1/range * step)
-	slider:SetHandler("OnShow", function()
-			local curValue = getFunc()
-			slidercontrol:SetValue((curValue - minValue)/range)
-			slidervalue:SetText(tostring(curValue))
-		end)
-	slidercontrol:SetHandler("OnValueChanged", function (self, value)
-			self:SetValue(value)
-			value = round(value*range + minValue)
-			slidervalue:SetText(strformat("%d", value))
-		end)
-	slidercontrol:SetHandler("OnSliderReleased", function(self, value)
-			value = round(value*range + minValue)
-			setFunc(value)
-		end)
-
-	if warning then
-		slider.warning = wm:CreateControlFromVirtual(controlName.."WarningIcon", slider, "ZO_Options_WarningIcon")
-		slider.warning:SetAnchor(RIGHT, slidercontrol, LEFT, -5, 0)
-		slider.warning.tooltipText = warningText
-	end
-
-	ZO_OptionsWindow_InitializeControl(slider)
-	if isSubMenu then slider:SetParent(panelID) end
-
-	lastAddedControl[panelID] = slider
-
-	return slider
-end
-
-function lam:AddDropdown(panelID, controlName, text, tooltip, validChoices, getFunc, setFunc, warning, warningText)
-	local isSubMenu = type(panelID) == "userdata"
-	local dropdown = wm:CreateControlFromVirtual(controlName, isSubMenu and panelID or optionsWindow, "ZO_Options_Dropdown")
-	dropdown:SetAnchor(TOPLEFT, lastAddedControl[panelID], BOTTOMLEFT, 0, 6)
-	dropdown.controlType = OPTIONS_DROPDOWN
-	dropdown.system = SETTING_TYPE_UI
-	dropdown.panel = isSubMenu and panelID.panel or panelID
-	dropdown.text = text
-	dropdown.tooltipText = tooltip
-	dropdown.valid = validChoices
-	local dropmenu = ZO_ComboBox_ObjectFromContainer(GetControl(dropdown, "Dropdown"))
-	local setText = dropmenu.m_selectedItemText.SetText
-	local selectedName
-	ZO_PreHookHandler(dropmenu.m_selectedItemText, "OnTextChanged", function(self)
-			if dropmenu.m_selectedItemData then
-				selectedName = dropmenu.m_selectedItemData.name
-				setText(self, selectedName)
-				setFunc(selectedName)
-			end
-		end)
-	dropdown:SetHandler("OnShow", function()
-			dropmenu:SetSelectedItem(getFunc())
-		end)
-
-	if warning then
-		dropdown.warning = wm:CreateControlFromVirtual(controlName.."WarningIcon", dropdown, "ZO_Options_WarningIcon")
-		dropdown.warning:SetAnchor(RIGHT, dropdown:GetNamedChild("Dropdown"), LEFT, -5, 0)
-		dropdown.warning.tooltipText = warningText
-	end
-
-	ZO_OptionsWindow_InitializeControl(dropdown)
-	if isSubMenu then dropdown:SetParent(panelID) end
-
-	lastAddedControl[panelID] = dropdown
-
-	return dropdown
-end
-
-function lam:AddCheckbox(panelID, controlName, text, tooltip, getFunc, setFunc, warning, warningText)
-	local isSubMenu = type(panelID) == "userdata"
-	local checkbox = wm:CreateControlFromVirtual(controlName, isSubMenu and panelID or optionsWindow, "ZO_Options_Checkbox")
-	checkbox:SetAnchor(TOPLEFT, lastAddedControl[panelID], BOTTOMLEFT, 0, 6)
-	checkbox.controlType = OPTIONS_CHECKBOX
-	checkbox.system = SETTING_TYPE_UI
-	checkbox.settingId = _G[strformat("SETTING_%s", controlName)]
-	checkbox.panel = isSubMenu and panelID.panel or panelID
-	checkbox.text = text
-	checkbox.tooltipText = tooltip
-
-	local checkboxButton = checkbox:GetNamedChild("Checkbox")
-
-	ZO_PreHookHandler(checkbox, "OnShow", function()
-			checkboxButton:SetState(getFunc() and 1 or 0)
-			checkboxButton:toggleFunction(getFunc())
-		end)
-	ZO_PreHookHandler(checkboxButton, "OnClicked", function() setFunc(not getFunc()) end)
-
-	if warning then
-		checkbox.warning = wm:CreateControlFromVirtual(controlName.."WarningIcon", checkbox, "ZO_Options_WarningIcon")
-		checkbox.warning:SetAnchor(RIGHT, checkboxButton, LEFT, -5, 0)
-		checkbox.warning.tooltipText = warningText
-	end
-
-	ZO_OptionsWindow_InitializeControl(checkbox)
-	if isSubMenu then checkbox:SetParent(panelID) end
-
-	lastAddedControl[panelID] = checkbox
-
-	return checkbox
-end
-
-function lam:AddColorPicker(panelID, controlName, text, tooltip, getFunc, setFunc, warning, warningText)
-	local isSubMenu = type(panelID) == "userdata"
-	local colorpicker = wm:CreateTopLevelWindow(controlName)
-	colorpicker:SetAnchor(TOPLEFT, lastAddedControl[panelID], BOTTOMLEFT, 0, 10)
-	colorpicker:SetParent(isSubMenu and panelID or optionsWindow)
-	colorpicker:SetResizeToFitDescendents(true)
-	colorpicker:SetWidth(510)
-	colorpicker:SetMouseEnabled(true)
-
-	colorpicker.label = wm:CreateControl(controlName.."Label", colorpicker, CT_LABEL)
-	local label = colorpicker.label
-	label:SetDimensions(300, 26)
-	label:SetAnchor(TOPLEFT)
-	label:SetFont("ZoFontWinH4")
-	label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
-	label:SetText(text)
-
-	colorpicker.color = wm:CreateControl(controlName.."Color", colorpicker, CT_CONTROL)
-	local color = colorpicker.color
-	color:SetDimensions(200,26)
-	color:SetAnchor(RIGHT)
-
-	color.thumb = wm:CreateControl(controlName.."ColorThumb", color, CT_TEXTURE)
-	local thumb = color.thumb
-	thumb:SetDimensions(36, 18)
-	thumb:SetAnchor(LEFT, color, LEFT, 4, 0)
-	local r, g, b, a = getFunc()
-	thumb:SetColor(r, g, b, a or 1)
-
-	color.border = wm:CreateControl(controlName.."ColorBorder", 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 ColorPickerCallback
-	if not ColorPickerCallback then
-		ColorPickerCallback = function(r, g, b, a)
-			thumb:SetColor(r, g, b, a or 1)
-			setFunc(r, g, b, a)
-		end
-	end
-
-	colorpicker.controlType = OPTIONS_CUSTOM
-	colorpicker.customSetupFunction = function(colorpicker)
-			colorpicker:SetHandler("OnMouseUp", function(self, btn, upInside)
-					if upInside then
-						local r, g, b, a = getFunc()
-						COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a, text)
-					end
-				end)
-		end
-	colorpicker.panel = isSubMenu and panelID.panel or panelID
-	colorpicker.tooltipText = tooltip
-	colorpicker:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
-	colorpicker:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
-
-	if warning then
-		colorpicker.warning = wm:CreateControlFromVirtual(controlName.."WarningIcon", colorpicker, "ZO_Options_WarningIcon")
-		colorpicker.warning:SetAnchor(RIGHT, colorpicker:GetNamedChild("Color"), LEFT, -5, 0)
-		colorpicker.warning.tooltipText = warningText
-	end
-
-	ZO_OptionsWindow_InitializeControl(colorpicker)
-	if isSubMenu then colorpicker:SetParent(panelID) end
-
-	lastAddedControl[panelID] = colorpicker
-
-	return colorpicker
-end
-
-function lam:AddEditBox(panelID, controlName, text, tooltip, isMultiLine, getFunc, setFunc, warning, warningText)
-	local isSubMenu = type(panelID) == "userdata"
-	local editbox = wm:CreateTopLevelWindow(controlName)
-	editbox:SetAnchor(TOPLEFT, lastAddedControl[panelID], BOTTOMLEFT, 0, 10)
-	editbox:SetResizeToFitDescendents(true)
-	editbox:SetWidth(510)
-	editbox:SetMouseEnabled(true)
-
-	editbox.label = wm:CreateControl(controlName.."Label", editbox, CT_LABEL)
-	local label = editbox.label
-	label:SetDimensions(300, 26)
-	label:SetAnchor(TOPLEFT)
-	label:SetFont("ZoFontWinH4")
-	label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
-	label:SetText(text)
-
-	editbox.bg = wm:CreateControlFromVirtual(controlName.."BG", editbox, "ZO_EditBackdrop")
-	local bg = editbox.bg
-	bg:SetDimensions(200,isMultiLine and 100 or 24)
-	bg:SetAnchor(RIGHT)
-	editbox.edit = wm:CreateControlFromVirtual(controlName.."Edit", bg, isMultiLine and "ZO_DefaultEditMultiLineForBackdrop" or "ZO_DefaultEditForBackdrop")
-	editbox.edit:SetText(getFunc())
-	editbox.edit:SetHandler("OnFocusLost", function(self) setFunc(self:GetText()) end)
-	editbox.edit:SetHandler("OnEscape", function(self) self:LoseFocus() end)
-	editbox.edit:SetMaxInputChars(1040)
-
-	editbox.panel = isSubMenu and panelID.panel or panelID
-	editbox.tooltipText = tooltip
-	editbox:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
-	editbox:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
-
-	if warning then
-		editbox.warning = wm:CreateControlFromVirtual(controlName.."WarningIcon", editbox, "ZO_Options_WarningIcon")
-		editbox.warning:SetAnchor(TOPRIGHT, editbox:GetNamedChild("BG"), TOPLEFT, -5, 0)
-		editbox.warning.tooltipText = warningText
-	end
-
-	ZO_OptionsWindow_InitializeControl(editbox)
-	editbox:SetParent(isSubMenu and panelID or optionsWindow)
-
-	lastAddedControl[panelID] = editbox
-
-	return editbox
-end
-
-function lam:AddButton(panelID, controlName, text, tooltip, onClick, warning, warningText)
-	local isSubMenu = type(panelID) == "userdata"
-	local button = wm:CreateTopLevelWindow(controlName)
-	button:SetAnchor(TOPLEFT, lastAddedControl[panelID], BOTTOMLEFT, 0, 6)
-	button:SetDimensions(510, 28)
-	button:SetMouseEnabled(true)
-
-	button.btn = wm:CreateControlFromVirtual(controlName.."Button", button, "ZO_DefaultButton")
-	local btn = button.btn
-	btn:SetAnchor(TOPRIGHT)
-	btn:SetWidth(200)
-	btn:SetText(text)
-	btn:SetHandler("OnClicked", onClick)
-
-	button.controlType = OPTIONS_CUSTOM
-	button.customSetupFunction = function() end	--move handlers into this function? (since I created a function...)
-	button.panel = isSubMenu and panelID.panel or panelID
-	btn.tooltipText = tooltip
-	btn:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
-	btn:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
-
-	if warning then
-		button.warning = wm:CreateControlFromVirtual(controlName.."WarningIcon", button, "ZO_Options_WarningIcon")
-		button.warning:SetAnchor(RIGHT, btn, LEFT, -5, 0)
-		button.warning.tooltipText = warningText
-	end
-
-	ZO_OptionsWindow_InitializeControl(button)
-	button:SetParent(isSubMenu and panelID or optionsWindow)
-
-	lastAddedControl[panelID] = button
-
-	return button
-end
-
-function lam:AddDescription(panelID, controlName, text, titleText)
-	local isSubMenu = type(panelID) == "userdata"
-	local textBox = wm:CreateTopLevelWindow(controlName)
-	textBox:SetAnchor(TOPLEFT, lastAddedControl[panelID], BOTTOMLEFT, 0, 10)
-	textBox:SetResizeToFitDescendents(true)
-	textBox:SetWidth(510)
-
-	if titleText then
-		textBox.title = wm:CreateControl(controlName.."Title", textBox, CT_LABEL)
-		local title = textBox.title
-		title:SetWidth(510)
-		title:SetAnchor(TOPLEFT, textBox, TOPLEFT)
-		title:SetFont("ZoFontWinH4")
-		title:SetText(titleText)
-	end
-
-	textBox.desc = wm:CreateControl(controlName.."Text", textBox, CT_LABEL)
-	local desc = textBox.desc
-	desc:SetWidth(510)
-	if titleText then
-		desc:SetAnchor(TOPLEFT, textBox.title, BOTTOMLEFT)
-	else
-		desc:SetAnchor(TOPLEFT)
-	end
-	desc:SetVerticalAlignment(TEXT_ALIGN_TOP)
-	desc:SetFont("ZoFontGame")
-	desc:SetText(text)
-
-	textBox.controlType = OPTIONS_CUSTOM
-	textBox.panel = isSubMenu and panelID.panel or panelID
-
-	ZO_OptionsWindow_InitializeControl(textBox)
-	textBox:SetParent(isSubMenu and panelID or optionsWindow)
-
-	lastAddedControl[panelID] = textBox
-
-	return textBox
-end
-
---window doesn't hide when escape is pressed
---color-picker is hidden for some reason
-function lam:AddSubMenu(panelID, controlName, text, tooltip)
-	local menubtn = wm:CreateTopLevelWindow(controlName)
-	menubtn:SetParent(optionsWindow)
-	menubtn:SetAnchor(TOPLEFT, lastAddedControl[panelID], BOTTOMLEFT, 0, 6)
-	menubtn:SetDimensions(510, 28)
-	menubtn:SetMouseEnabled(true)
-
-	menubtn.label = wm:CreateControl(controlName.."Text", menubtn, CT_LABEL)
-	local label = menubtn.label
-	label:SetAnchor(TOPLEFT, textBox, TOPLEFT)
-	label:SetDimensions(300, 28)
-	label:SetFont("ZoFontWinH4")
-	label:SetText(text)
-
-	menubtn.btn = wm:CreateControlFromVirtual(controlName.."Button", menubtn, "ZO_DefaultButton")
-	local btn = menubtn.btn
-	btn:SetAnchor(TOPRIGHT)
-	btn:SetWidth(200)
-	btn:SetText(GetString("SI_GAMECAMERAACTIONTYPE", 13).." |t32:32:esoui\\art\\crafting\\smithing_rightarrow_up.dds|t")
-	--btn:SetText("Open -->")
-
-	menubtn.window = wm:CreateTopLevelWindow(controlName.."Window")
-	local window = menubtn.window
-	--window:SetParent(menubtn)
-	window:SetAnchor(TOPLEFT, menubtn, TOPRIGHT)
-	window:SetDimensions(555, 300)
-	window:SetClampedToScreen(true)
-	window:SetClampedToScreenInsets(-5, -20, 5, 5)
-	window.bg = wm:CreateControlFromVirtual(controlName.."WindowBG", window, "ZO_DefaultBackdrop")
-	window:SetHidden(true)
-
-	window.settings = wm:CreateControlFromVirtual(controlName.."WindowSettings", window, "ZO_ScrollContainer")
-	local settings = window.settings
-	settings:SetAnchor(TOPLEFT, window, TOPLEFT, 10, 10)
-	settings:SetAnchor(BOTTOMRIGHT, window, BOTTOMRIGHT, -5, -5)
-	local scroll = settings:GetNamedChild("ScrollChild")
-	scroll.panel = panelID
-
-	btn:SetHandler("OnClicked", function()
-			if window:IsHidden() then	--if this submenu isn't open yet, then...
-				if openSubMenu then openSubMenu:SetHidden(true) end	--if a submenu was already open, then close it
-				window:SetHidden(false)	--show this submenu
-				openSubMenu = window	--this submenu is now our open menu
-			else
-				window:SetHidden(true)
-				openSubMenu = nil	--no more open submenus
-			end
-		end)
-	menubtn:SetHandler("OnHide", function()
-			if openSubMenu then
-				openSubMenu:SetHidden(true)
-			end
-		end)
-	ZO_OptionsWindow:SetHandler("OnHide", function()
-			if openSubMenu then
-				openSubMenu:SetHidden(true)
-			end
-		end)
-
-	menubtn.controlType = OPTIONS_CUSTOM
-	menubtn.customSetupFunction = function() end	--move handlers into this function? (since I created a function...)
-	menubtn.panel = panelID
-	btn.tooltipText = tooltip
-	btn:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
-	btn:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
-
-	ZO_OptionsWindow_InitializeControl(menubtn)
-
-	lastAddedControl[panelID] = menubtn
-
-	lam:AddHeader(scroll, controlName.."MenuHeader", text)	--create the header for our menu
-
-	return scroll
-end
-
-
-
---test controls & examples--
---[[local controlPanelID = lam:CreateControlPanel("ZAM_TEST_ADDON_OPTIONS", "ZAM Test")
-lam:AddHeader(controlPanelID, "ZAM_Addons_TESTADDON", "TEST ADDON")
-lam:AddDescription(controlPanelID, "ZAM_Addons_TESTDESC", "This is a test description.", "Header")
-local window = lam:AddSubMenu(controlPanelID, "ZAM_Addons_TESTMENU", "Click for more options.", "This is some tooltip text.")
-lam:AddHeader(window, "ZAM_Addons_TESTMENU_HEADER", "Header")
-lam:AddSlider(window, "ZAM_Addons_TESTMENU_SLIDER", "Test slider", "Adjust the slider.", 1, 10, 1, function() return 7 end, function(value) end, true, "needs UI reload")
-lam:AddHeader(window, "ZAM_Addons_TESTMENU_HEADER2", "Header 2")
-lam:AddColorPicker(window, "ZAM_Addons_TESTMENU_COLORPICKER", "Test color picker", "What's your favorite color?", function() return 1, 1, 0 end, function(r,g,b) print(r,g,b) end)
-local window2 = lam:AddSubMenu(controlPanelID, "ZAM_Addons_TESTMENU2", "Click for more options.", "This is some tooltip text.")
-lam:AddHeader(window2, "ZAM_Addons_TESTMENU2_HEADER", "Header")
-lam:AddSlider(window2, "ZAM_Addons_TESTMENU2_SLIDER", "Test slider", "Adjust the slider.", 1, 10, 1, function() return 7 end, function(value) end, true, "needs UI reload")
-lam:AddHeader(window2, "ZAM_Addons_TESTMENU2_HEADER2", "Header 2")
-lam:AddColorPicker(window2, "ZAM_Addons_TESTMENU2_COLORPICKER", "Test color picker", "What's your favorite color?", function() return 1, 1, 0 end, function(r,g,b) print(r,g,b) end)
-lam:AddSlider(controlPanelID, "ZAM_TESTSLIDER", "Test slider", "Adjust the slider.", 1, 10, 1, function() return 7 end, function(value) end, true, "needs UI reload")
-lam:AddDropdown(controlPanelID, "ZAM_TESTDROPDOWN", "Test Dropdown", "Pick something!", {"thing 1", "thing 2", "thing 3"}, function() return "thing 2" end, function(self,valueString) print(valueString) end)
-local checkbox1 = true
-lam:AddCheckbox(controlPanelID, "ZAM_TESTCHECKBOX", "Test Checkbox", "On or off?", function() return checkbox1 end, function(value) checkbox1 = not checkbox1 print(value, checkbox1) end)
-lam:AddColorPicker(controlPanelID, "ZAM_TESTCOLORPICKER", "Test color picker", "What's your favorite color?", function() return 1, 1, 0 end, function(r,g,b) print(r,g,b) end)
-lam:AddEditBox(controlPanelID, "ZAM_TESTEDITBOX", "Test Edit Box", "This is a tooltip!", false, function() return "hi" end, function(text) print(text) end)
-lam:AddHeader(controlPanelID, "ZAM_Addons_TESTADDON2", "TEST ADDON 2")
-local checkbox2 = false
-lam:AddCheckbox(controlPanelID, "ZAM_TESTCHECKBOX2", "Test Checkbox 2", "On or off?", function() return checkbox2 end, function(value) checkbox2 = not checkbox2 print(value, checkbox2) end)
-lam:AddButton(controlPanelID, "ZAM_TESTBUTTON", "Test Button", "Click me", function() print("hi") end, true, "oh noez!")
-lam:AddEditBox(controlPanelID, "ZAM_TESTEDITBOX2", "Test Edit Box 2", "This is a tooltip!", true, function() return "hi" end, function(text) print(text) end, true, "warning text")
-lam:AddSlider(controlPanelID, "ZAM_TESTSLIDER2", "Test slider 2", "Adjust the slider.", 50, 100, 10, function() return 80 end, function(value) end)
-lam:AddDropdown(controlPanelID, "ZAM_TESTDROPDOWN2", "Test Dropdown 2", "Pick something!", {"thing 4", "thing 5", "thing 6"}, function() return "thing 6" end, function(self,valueString) print(valueString) end)
-]]--
\ No newline at end of file
diff --git a/Libs/LibAddonMenu-2.0/LibAddonMenu-2.0.lua b/Libs/LibAddonMenu-2.0/LibAddonMenu-2.0.lua
new file mode 100644
index 0000000..a501670
--- /dev/null
+++ b/Libs/LibAddonMenu-2.0/LibAddonMenu-2.0.lua
@@ -0,0 +1,299 @@
+--	LibAddonMenu-2.0 & its files © Ryan Lakanen (Seerah)	--
+--	All Rights Reserved										--
+--	Permission is granted to use Seerah's LibAddonMenu-2.0	--
+--	in your project. Any modifications to LibAddonMenu-2.0	--
+--	may not be redistributed.								--
+--------------------------------------------------------------
+
+
+--Register LAM with LibStub
+local MAJOR, MINOR = "LibAddonMenu-2.0", 8
+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
+
+
+--UPVALUES--
+local wm = WINDOW_MANAGER
+local cm = CALLBACK_MANAGER
+local tinsert = table.insert
+local optionsWindow = ZO_OptionsWindowSettingsScrollChild
+local _
+
+local addonsForList = {}
+local addonToOptionsMap = {}
+local optionsCreated = {}
+local widgets = {}
+
+
+--METHOD: REGISTER WIDGET--
+--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
+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
+end
+
+
+--METHOD: OPEN TO ADDON PANEL--
+--opens to a specific addon's option panel
+--Usage:
+--	panel = userdata; the panel returned by the :RegisterOptionsPanel method
+--local settings = {en = "Settings", de = "Einstellungen", fr = "Réglages"}
+--local locSettings = settings[GetCVar("Language.2")]
+local locSettings = GetString(SI_GAME_MENU_SETTINGS)
+function lam:OpenToPanel(panel)
+	SCENE_MANAGER:Show("gameMenuInGame")
+	zo_callLater(function()
+			ZO_GameMenu_InGame.gameMenu.headerControls[locSettings]:SetOpen(true)
+			SCENE_MANAGER:AddFragment(OPTIONS_WINDOW_FRAGMENT)
+			ZO_OptionsWindow_ChangePanels(lam.panelID)
+			panel:SetHidden(false)
+		end, 200)
+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 lastAddedControl, lacAtHalfRow
+		for _, widgetData in ipairs(optionsTable) do
+			local widgetType = widgetData.type
+			if widgetType == "submenu" then
+				local submenu = LAMCreateControl[widgetType](panel, widgetData)
+				if lastAddedControl then
+					submenu:SetAnchor(TOPLEFT, lastAddedControl, BOTTOMLEFT, 0, 15)
+				else
+					submenu:SetAnchor(TOPLEFT)
+				end
+				lastAddedControl = submenu
+				lacAtHalfRow = false
+
+				local lastAddedControlSub, lacAtHalfRowSub
+				for _, subWidgetData in ipairs(widgetData.controls) do
+					local subWidgetType = subWidgetData.type
+					local subWidget = LAMCreateControl[subWidgetType](submenu, subWidgetData)
+					local isHalf = subWidgetData.width == "half"
+					if lastAddedControlSub then
+						if lacAtHalfRowSub and isHalf then
+							subWidget:SetAnchor(TOPLEFT, lastAddedControlSub, TOPRIGHT, 5, 0)
+							lacAtHalfRowSub = false
+						else
+							subWidget:SetAnchor(TOPLEFT, lastAddedControlSub, BOTTOMLEFT, 0, 15)
+							lacAtHalfRowSub = isHalf and true or false
+							lastAddedControlSub = subWidget
+						end
+					else
+						subWidget:SetAnchor(TOPLEFT)
+						lacAtHalfRowSub = isHalf and true or false
+						lastAddedControlSub = subWidget
+					end
+				end
+			else
+				local widget = LAMCreateControl[widgetType](panel, widgetData)
+				local isHalf = widgetData.width == "half"
+				if lastAddedControl then
+					if lacAtHalfRow and isHalf then
+						widget:SetAnchor(TOPLEFT, lastAddedControl, TOPRIGHT, 10, 0)
+						lacAtHalfRow = false
+					else
+						widget:SetAnchor(TOPLEFT, lastAddedControl, BOTTOMLEFT, 0, 15)
+						lacAtHalfRow = isHalf and true or false
+						lastAddedControl = widget
+					end
+				else
+					widget:SetAnchor(TOPLEFT)
+					lacAtHalfRow = isHalf and true or false
+					lastAddedControl = widget
+				end
+			end
+		end
+	end
+
+	optionsCreated[addonID] = true
+	cm:FireCallbacks("LAM-PanelControlsCreated", panel)
+end
+
+
+--INTERNAL FUNCTION
+--handles switching between panels
+local function ToggleAddonPanels(panel)	--called in OnShow of newly shown panel
+	local currentlySelected = LAMAddonPanelsMenu.currentlySelected
+	if currentlySelected and currentlySelected ~= panel then
+		currentlySelected:SetHidden(true)
+	end
+	LAMAddonPanelsMenu.currentlySelected = panel
+
+	if not optionsCreated[panel:GetName()] then	--if this is the first time opening this panel, create these options
+		CreateOptionsControls(panel)
+	end
+
+	cm:FireCallbacks("LAM-RefreshPanel", panel)
+end
+
+
+--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
+function lam:RegisterAddonPanel(addonID, panelData)
+	local panel = lamcc.panel(nil, panelData, addonID)	--addonID==global name of panel
+	panel:SetHidden(true)
+	panel:SetAnchor(TOPLEFT, LAMAddonPanelsMenu, TOPRIGHT, 10, 0)
+	panel:SetAnchor(BOTTOMLEFT, LAMAddonPanelsMenu, BOTTOMRIGHT, 10, 0)
+	panel:SetWidth(549)
+	panel:SetDrawLayer(DL_OVERLAY)
+	tinsert(addonsForList, {panel = addonID, name = panelData.name})
+	panel:SetHandler("OnShow", ToggleAddonPanels)
+	if panelData.slashCommand then
+		SLASH_COMMANDS[panelData.slashCommand] = function()
+			lam:OpenToPanel(panel)
+		end
+	end
+
+	return panel	--return for authors creating options manually
+end
+
+
+--METHOD: REGISTER OPTION CONTROLS
+--registers the options you want shown for your addon
+--these are stored in a table where each key-value pair is the order
+--of the options in the panel and the data for that control, respectively
+--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
+end
+
+
+--INTERNAL FUNCTION
+--handles switching between LAM's Addon Settings panel and other panels in the Settings menu
+local oldDefaultButton = ZO_OptionsWindowResetToDefaultButton
+local oldCallback = oldDefaultButton.callback
+local dummyFunc = function() end
+local panelWindow = ZO_OptionsWindow
+local bgL = ZO_OptionsWindowBGLeft
+local bgR = ZO_OptionsWindowBGLeftBGRight
+local function HandlePanelSwitching(panel)
+	if panel == lam.panelID then	--our addon settings panel
+		oldDefaultButton:SetCallback(dummyFunc)
+		oldDefaultButton:SetHidden(true)
+		oldDefaultButton:SetAlpha(0)	--just because it still bugs out
+		panelWindow:SetDimensions(999, 960)
+		bgL:SetWidth(666)
+		bgR:SetWidth(333)
+	else
+		local shown = LAMAddonPanelsMenu.currentlySelected
+		if shown then shown:SetHidden(true) end
+		oldDefaultButton:SetCallback(oldCallback)
+		oldDefaultButton:SetHidden(false)
+		oldDefaultButton:SetAlpha(1)
+		panelWindow:SetDimensions(768, 914)
+		bgL:SetWidth(512)
+		bgR:SetWidth(256)
+	end
+end
+
+
+--INTERNAL FUNCTION
+--creates LAM's Addon Settings panel
+local function CreateAddonSettingsPanel()
+	if not LAMSettingsPanelCreated then
+		local controlPanelID = "LAM_ADDON_SETTINGS_PANEL"
+		local controlPanelNames = {en = "Addon Settings", fr = "Extensions", de = "Erweiterungen"}
+
+		ZO_OptionsWindow_AddUserPanel(controlPanelID, controlPanelNames[GetCVar("Language.2")])
+
+		lam.panelID = _G[controlPanelID]
+
+		ZO_PreHook("ZO_OptionsWindow_ChangePanels", HandlePanelSwitching)
+
+		LAMSettingsPanelCreated = true
+	end
+end
+
+
+--INTERNAL FUNCTION
+--adds each registered addon to the menu in LAM's panel
+local function CreateAddonButtons(list, addons)
+	for i = 1, #addons do
+		local button = wm:CreateControlFromVirtual("LAMAddonMenuButton"..i, list, "ZO_DefaultTextButton")
+		button.name = addons[i].name
+		button.panel = _G[addons[i].panel]
+		button:SetText(button.name)
+		button:SetHorizontalAlignment(TEXT_ALIGN_LEFT)
+		button:SetWidth(190)
+		if i == 1 then
+			button:SetAnchor(TOPLEFT, list, TOPLEFT, 5, 5)
+		else
+			button:SetAnchor(TOPLEFT, _G["LAMAddonMenuButton"..i-1], BOTTOMLEFT)
+		end
+		button:SetHandler("OnClicked", function(self) self.panel:SetHidden(false) end)
+	end
+end
+
+
+--INTERNAL FUNCTION
+--creates the left-hand menu in LAM's panel
+local function CreateAddonList()
+	local list
+	--check if an earlier loaded copy of LAM created it already
+	list = LAMAddonPanelsMenu or wm:CreateControlFromVirtual("LAMAddonPanelsMenu", optionsWindow, "ZO_ScrollContainer")
+	list:ClearAnchors()
+	list:SetAnchor(TOPLEFT)
+	list:SetHeight(675)
+	list:SetWidth(200)
+
+	list.bg = list.bg or wm:CreateControl(nil, list, CT_BACKDROP)
+	local bg = list.bg
+	bg:SetAnchorFill()	--offsets of 8?
+	bg:SetEdgeTexture("EsoUI\\Art\\miscellaneous\\borderedinsettransparent_edgefile.dds", 128, 16)
+	bg:SetCenterColor(0, 0, 0, 0)
+
+	local generatedButtons
+	list:SetHandler("OnShow", function(self)
+			if not generatedButtons and #addonsForList > 0 then
+				--we're about to show our list for the first time - let's sort the buttons before creating them
+				table.sort(addonsForList, function(a, b)
+						return a.name < b.name
+					end)
+				CreateAddonButtons(list, addonsForList)
+				self.currentlySelected = LAMAddonMenuButton1 and LAMAddonMenuButton1.panel
+				--since our addon panels don't have a parent, let's make sure they hide when we're done with them
+				ZO_PreHookHandler(ZO_OptionsWindow, "OnHide", function() self.currentlySelected:SetHidden(true) end)
+				generatedButtons = true
+			end
+			if self.currentlySelected then self.currentlySelected:SetHidden(false) end
+		end)
+
+	list.controlType = OPTIONS_CUSTOM
+	list.panel = lam.panelID
+
+	ZO_OptionsWindow_InitializeControl(list)
+
+	return list
+end
+
+
+--INITIALIZING
+CreateAddonSettingsPanel()
+CreateAddonList()
+
diff --git a/Libs/LibAddonMenu-2.0/controls/button.lua b/Libs/LibAddonMenu-2.0/controls/button.lua
new file mode 100644
index 0000000..9954a1e
--- /dev/null
+++ b/Libs/LibAddonMenu-2.0/controls/button.lua
@@ -0,0 +1,87 @@
+--[[buttonData = {
+	type = "button",
+	name = "My Button",
+	tooltip = "Button's tooltip text.",
+	func = function() end,
+	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"	--(optional) unique global reference to control
+}	]]
+
+
+local widgetVersion = 2
+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)
+end
+
+
+--controlName is optional
+function LAMCreateControl.button(parent, buttonData, controlName)
+	local control = wm:CreateTopLevelWindow(controlName or buttonData.reference)
+	control:SetParent(parent.scroll)
+
+	local isHalfWidth = buttonData.width == "half"
+	control:SetDimensions(isHalfWidth and 250 or 510, isHalfWidth and 55 or 28)
+	control:SetMouseEnabled(true)
+
+	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(isHalfWidth and 180 or 200)
+		control.button:SetText(buttonData.name)
+	end
+	local button = control.button
+	button:SetAnchor(isHalfWidth and CENTER or RIGHT)
+	button:SetClickSound("Click")
+	button.tooltipText = 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.warning then
+		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
+		control.warning:SetAnchor(RIGHT, button, LEFT, -5, 0)
+		control.warning.tooltipText = buttonData.warning
+	end
+
+	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
+	control.data = buttonData
+
+	if buttonData.disabled then
+		control.UpdateDisabled = UpdateDisabled
+		control:UpdateDisabled()
+
+		--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
+
+	return control
+end
\ No newline at end of file
diff --git a/Libs/LibAddonMenu-2.0/controls/checkbox.lua b/Libs/LibAddonMenu-2.0/controls/checkbox.lua
new file mode 100644
index 0000000..8432109
--- /dev/null
+++ b/Libs/LibAddonMenu-2.0/controls/checkbox.lua
@@ -0,0 +1,170 @@
+--[[checkboxData = {
+	type = "checkbox",
+	name = "My Checkbox",
+	tooltip = "Checkbox's tooltip text.",
+	getFunc = function() return db.var end,
+	setFunc = function(value) db.var = value doStuff() end,
+	width = "full",	--or "half" (optional)
+	disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
+	warning = "Will need to reload the UI.",	--(optional)
+	default = defaults.var,	--(optional)
+	reference = "MyAddonCheckbox"	--(optional) unique global reference to control
+}	]]
+
+
+local widgetVersion = 4
+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
+local disabledColor = ZO_DEFAULT_DISABLED_COLOR
+local disabledHLcolor = ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR
+--checkbox
+local checkboxColor = ZO_NORMAL_TEXT
+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
+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
+end
+
+local function UpdateValue(control, forceDefault, value)
+	if forceDefault then	--if we are forcing defaults
+		value = 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)
+end
+
+local function OnMouseEnter(control)
+	ZO_Options_OnMouseEnter(control)
+
+	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())
+end
+
+local function OnMouseExit(control)
+    ZO_Options_OnMouseExit(control)
+
+	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())
+end
+
+
+--controlName is optional
+function LAMCreateControl.checkbox(parent, checkboxData, controlName)
+	local control = wm:CreateTopLevelWindow(controlName or checkboxData.reference)
+	control:SetParent(parent.scroll)
+	control:SetMouseEnabled(true)
+	control.tooltipText = checkboxData.tooltip
+	control:SetHandler("OnMouseEnter", OnMouseEnter)
+	control:SetHandler("OnMouseExit", OnMouseExit)
+	control:SetHandler("OnMouseUp", function(control)
+			if control.isDisabled then return end
+			PlaySound(SOUNDS.DEFAULT_CLICK)
+			control.value = not control.value
+			control:UpdateValue(false, control.value)
+		end)
+
+	control.label = wm:CreateControl(nil, control, CT_LABEL)
+	local label = control.label
+	label:SetFont("ZoFontWinH4")
+	label:SetText(checkboxData.name)
+	label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
+	label:SetHeight(26)
+
+	control.checkbox = wm:CreateControl(nil, control, CT_LABEL)
+	local checkbox = control.checkbox
+	checkbox:SetFont("ZoFontGameBold")
+	checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA())
+	control.checkedText = GetString(SI_CHECK_BUTTON_ON):upper()
+	control.uncheckedText = GetString(SI_CHECK_BUTTON_OFF):upper()
+
+	local isHalfWidth = checkboxData.width == "half"
+	if isHalfWidth then
+		control:SetDimensions(250, 55)
+		checkbox:SetDimensions(100, 26)
+		checkbox:SetAnchor(BOTTOMRIGHT)
+		label:SetAnchor(TOPLEFT)
+		label:SetAnchor(TOPRIGHT)
+	else
+		control:SetDimensions(510, 30)
+		checkbox:SetDimensions(200, 26)
+		checkbox:SetAnchor(RIGHT)
+		label:SetAnchor(LEFT)
+		label:SetAnchor(RIGHT, checkbox, LEFT, -5, 0)
+	end
+
+	if checkboxData.warning then
+		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
+		control.warning:SetAnchor(RIGHT, checkbox, LEFT, -5, 0)
+		control.warning.tooltipText = checkboxData.warning
+	end
+
+	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
+	control.data = checkboxData
+
+	if checkboxData.disabled 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
+end
\ No newline at end of file
diff --git a/Libs/LibAddonMenu-2.0/controls/colorpicker.lua b/Libs/LibAddonMenu-2.0/controls/colorpicker.lua
new file mode 100644
index 0000000..af645ba
--- /dev/null
+++ b/Libs/LibAddonMenu-2.0/controls/colorpicker.lua
@@ -0,0 +1,138 @@
+--[[colorpickerData = {
+	type = "colorpicker",
+	name = "My Color Picker",
+	tooltip = "Color Picker's tooltip text.",
+	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)
+	width = "full",	--or "half" (optional)
+	disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
+	warning = "Will need to reload the UI.",	--(optional)
+	default = {defaults.r, defaults.g, defaults.b, defaults.a},	--(optional) table of default color values
+	reference = "MyAddonColorpicker"	--(optional) unique global reference to control
+}	]]
+
+
+local widgetVersion = 2
+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
+end
+
+local function UpdateValue(control, forceDefault, valueR, valueG, valueB, valueA)
+	if forceDefault then	--if we are forcing defaults
+		local color = control.data.default
+		valueR, valueG, valueB, valueA = color.r, color.g, color.b, color.a
+		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)
+end
+
+
+function LAMCreateControl.colorpicker(parent, colorpickerData, controlName)
+	local control = wm:CreateTopLevelWindow(controlName or colorpickerData.reference)
+	control:SetParent(parent.scroll)
+	control:SetMouseEnabled(true)
+	control.tooltipText = colorpickerData.tooltip
+	control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
+	control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
+
+	control.label = wm:CreateControl(nil, control, CT_LABEL)
+	local label = control.label
+	label:SetDimensions(300, 26)
+	label:SetAnchor(TOPLEFT)
+	label:SetFont("ZoFontWinH4")
+	label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
+	label:SetText(colorpickerData.name)
+
+	control.color = wm:CreateControl(nil, control, CT_CONTROL)
+	local color = control.color
+
+	local isHalfWidth = colorpickerData.width == "half"
+	if isHalfWidth then
+		control:SetDimensions(250, 55)
+		label:SetDimensions(250, 26)
+		color:SetDimensions(100, 24)
+		color:SetAnchor(TOPRIGHT, label, BOTTOMRIGHT)
+	else
+		control:SetDimensions(510, 30)
+		label:SetDimensions(300, 26)
+		color:SetDimensions(200, 24)
+		color:SetAnchor(TOPRIGHT)
+	end
+
+	control.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, colorpickerData.name)
+			end
+		end)
+
+	if colorpickerData.warning then
+		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
+		control.warning:SetAnchor(RIGHT, control.color, LEFT, -5, 0)
+		control.warning.tooltipText = colorpickerData.warning
+	end
+
+	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
+	control.data = colorpickerData
+
+	if colorpickerData.disabled 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
+end
\ No newline at end of file
diff --git a/Libs/LibAddonMenu-2.0/controls/custom.lua b/Libs/LibAddonMenu-2.0/controls/custom.lua
new file mode 100644
index 0000000..ae7cdb2
--- /dev/null
+++ b/Libs/LibAddonMenu-2.0/controls/custom.lua
@@ -0,0 +1,31 @@
+--[[customData = {
+	type = "custom",
+	reference = "MyAddonCustomControl",	--unique name for your control to use as reference
+	width = "full",	--or "half" (optional)
+}	]]
+
+local widgetVersion = 2
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("custom", widgetVersion) then return end
+
+local wm = WINDOW_MANAGER
+
+function LAMCreateControl.custom(parent, customData, controlName)
+	local control = wm:CreateTopLevelWindow(controlName or customData.reference)
+	control:SetResizeToFitDescendents(true)
+	control:SetParent(parent.scroll)
+
+	local isHalfWidth = customData.width == "half"
+	if isHalfWidth then	--note these restrictions
+		control:SetDimensionConstraints(250, 55, 250, 100)
+		control:SetDimensions(250, 55)
+	else
+		control:SetDimensionConstraints(510, 30, 510, 100)
+		control:SetDimensions(510, 30)
+	end
+
+	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
+	control.data = customData
+
+	return control
+end
\ No newline at end of file
diff --git a/Libs/LibAddonMenu-2.0/controls/description.lua b/Libs/LibAddonMenu-2.0/controls/description.lua
new file mode 100644
index 0000000..2db253b
--- /dev/null
+++ b/Libs/LibAddonMenu-2.0/controls/description.lua
@@ -0,0 +1,53 @@
+--[[descriptionData = {
+	type = "description",
+	title = "My Title",	--(optional)
+	text = "My description text to display.",
+	width = "full",	--or "half" (optional)
+	reference = "MyAddonDescription"	--(optional) unique global reference to control
+}	]]
+
+
+local widgetVersion = 2
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("description", widgetVersion) then return end
+
+local wm = WINDOW_MANAGER
+
+function LAMCreateControl.description(parent, descriptionData, controlName)
+	local control = wm:CreateTopLevelWindow(controlName or descriptionData.reference)
+	control:SetResizeToFitDescendents(true)
+	control:SetParent(parent.scroll)
+	local isHalfWidth = descriptionData.width == "half"
+	if isHalfWidth then
+		control:SetDimensionConstraints(250, 55, 250, 100)
+		control:SetDimensions(250, 55)
+	else
+		control:SetDimensionConstraints(510, 40, 510, 100)
+		control:SetDimensions(510, 30)
+	end
+
+	control.desc = wm:CreateControl(nil, control, CT_LABEL)
+	local desc = control.desc
+	desc:SetVerticalAlignment(TEXT_ALIGN_TOP)
+	desc:SetFont("ZoFontGame")
+	desc:SetText(descriptionData.text)
+	desc:SetWidth(isHalfWidth and 250 or 510)
+
+	if descriptionData.title then
+		control.title = wm:CreateControl(nil, control, CT_LABEL)
+		local title = control.title
+		title:SetWidth(isHalfWidth and 250 or 510)
+		title:SetAnchor(TOPLEFT, control, TOPLEFT)
+		title:SetFont("ZoFontWinH4")
+		title:SetText(descriptionData.title)
+		desc:SetAnchor(TOPLEFT, title, BOTTOMLEFT)
+	else
+		desc:SetAnchor(TOPLEFT)
+	end
+
+	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
+	control.data = descriptionData
+
+	return control
+
+end
\ No newline at end of file
diff --git a/Libs/LibAddonMenu-2.0/controls/dropdown.lua b/Libs/LibAddonMenu-2.0/controls/dropdown.lua
new file mode 100644
index 0000000..e338db6
--- /dev/null
+++ b/Libs/LibAddonMenu-2.0/controls/dropdown.lua
@@ -0,0 +1,153 @@
+--[[dropdownData = {
+	type = "dropdown",
+	name = "My Dropdown",
+	tooltip = "Dropdown's tooltip text.",
+	choices = {"table", "of", "choices"},
+	sort = "name-up", --or "name-down", "numeric-up", "numeric-down" (optional) - if not provided, list will not be sorted
+	getFunc = function() return db.var end,
+	setFunc = function(var) db.var = var doStuff() end,
+	width = "full",	--or "half" (optional)
+	disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
+	warning = "Will need to reload the UI.",	--(optional)
+	default = defaults.var,	--(optional)
+	reference = "MyAddonDropdown"	--(optional) unique global reference to control
+}	]]
+
+
+local widgetVersion = 3
+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
+end
+
+local function UpdateValue(control, forceDefault, value)
+	if forceDefault then	--if we are forcing defaults
+		value = 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
+end
+
+local function DropdownCallback(choice, choiceText, choice)
+	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
+end
+
+local function GrabSortingInfo(sortInfo)
+	local t, i = {}, 1
+	for info in string.gmatch(sortInfo, "([^%-]+)") do
+		t[i] = info
+		i = i + 1
+	end
+
+	return t
+end
+
+
+local comboboxCount = 1
+function LAMCreateControl.dropdown(parent, dropdownData, controlName)
+	local control = wm:CreateTopLevelWindow(controlName or dropdownData.reference)
+	control:SetParent(parent.scroll)
+	control:SetMouseEnabled(true)
+	control.tooltipText = dropdownData.tooltip
+	control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
+	control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
+
+	control.label = wm:CreateControl(nil, control, CT_LABEL)
+	local label = control.label
+	label:SetAnchor(TOPLEFT)
+	label:SetFont("ZoFontWinH4")
+	label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
+	label:SetText(dropdownData.name)
+
+	control.combobox = wm:CreateControlFromVirtual(parent:GetName().."Combobox"..comboboxCount, control, "ZO_ComboBox")
+	comboboxCount = comboboxCount + 1
+	local combobox = control.combobox
+	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
+
+	local isHalfWidth = dropdownData.width == "half"
+	if isHalfWidth then
+		control:SetDimensions(250, 55)
+		label:SetDimensions(250, 26)
+		combobox:SetDimensions(240, 26)
+		--dropdown:SetWidth(240)
+		combobox:SetAnchor(TOPRIGHT, label, BOTTOMRIGHT)
+	else
+		control:SetDimensions(510, 30)
+		label:SetDimensions(300, 26)
+		combobox:SetDimensions(200, 26)
+		--dropdown:SetWidth(200)
+		combobox:SetAnchor(TOPRIGHT)
+	end
+
+	if warning then
+		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
+		control.warning:SetAnchor(RIGHT, combobox, LEFT, -5, 0)
+		control.warning.tooltipText = warningText
+	end
+
+	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
+	control.data = dropdownData
+
+	if dropdownData.disabled 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
+end
\ No newline at end of file
diff --git a/Libs/LibAddonMenu-2.0/controls/editbox.lua b/Libs/LibAddonMenu-2.0/controls/editbox.lua
new file mode 100644
index 0000000..f2b4ded
--- /dev/null
+++ b/Libs/LibAddonMenu-2.0/controls/editbox.lua
@@ -0,0 +1,153 @@
+--[[editboxData = {
+	type = "editbox",
+	name = "My Editbox",
+	tooltip = "Editbox's tooltip text.",
+	getFunc = function() return db.text end,
+	setFunc = function(text) db.text = text doStuff() end,
+	isMultiline = true,	--boolean
+	width = "full",	--or "half" (optional)
+	disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
+	warning = "Will need to reload the UI.",	--(optional)
+	default = defaults.text,	--(optional)
+	reference = "MyAddonEditbox"	--(optional) unique global reference to control
+}	]]
+
+
+local widgetVersion = 3
+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)
+end
+
+local function UpdateValue(control, forceDefault, value)
+	if forceDefault then	--if we are forcing defaults
+		value = 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
+end
+
+
+function LAMCreateControl.editbox(parent, editboxData, controlName)
+	local control = wm:CreateTopLevelWindow(controlName or editboxData.reference)
+	control:SetParent(parent.scroll)
+	control:SetMouseEnabled(true)
+	control:SetResizeToFitDescendents(true)
+	control.tooltipText = editboxData.tooltip
+	control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
+	control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
+
+	control.label = wm:CreateControl(nil, control, CT_LABEL)
+	local label = control.label
+	label:SetAnchor(TOPLEFT)
+	label:SetFont("ZoFontWinH4")
+	label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
+	label:SetText(editboxData.name)
+
+	control.bg = wm:CreateControlFromVirtual(nil, control, "ZO_EditBackdrop")
+	local bg = control.bg
+
+	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 isHalfWidth = editboxData.width == "half"
+	if isHalfWidth then
+		control:SetDimensions(250, 55)
+		label:SetDimensions(250, 26)
+		bg:SetDimensions(225, editboxData.isMultiline and 74 or 24)
+		bg:SetAnchor(TOPRIGHT, label, BOTTOMRIGHT)
+		if editboxData.isMultiline then
+			editbox:SetDimensionConstraints(210, 74, 210, 500)
+		end
+	else
+		control:SetDimensions(510, 30)
+		label:SetDimensions(300, 26)
+		bg:SetDimensions(200, editboxData.isMultiline and 100 or 24)
+		bg:SetAnchor(TOPRIGHT)
+		if editboxData.isMultiline then
+			editbox:SetDimensionConstraints(185, 100, 185, 500)
+		end
+	end
+
+	if editboxData.warning then
+		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
+		control.warning:SetAnchor(TOPRIGHT, control.bg, TOPLEFT, -5, 0)
+		control.warning.tooltipText = editboxData.warning
+	end
+
+	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
+	control.data = editboxData
+
+	if editboxData.disabled 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
+end
\ No newline at end of file
diff --git a/Libs/LibAddonMenu-2.0/controls/header.lua b/Libs/LibAddonMenu-2.0/controls/header.lua
new file mode 100644
index 0000000..46250ca
--- /dev/null
+++ b/Libs/LibAddonMenu-2.0/controls/header.lua
@@ -0,0 +1,36 @@
+--[[headerData = {
+	type = "header",
+	name = "My Header",
+	width = "full",	--or "half" (optional)
+	reference = "MyAddonHeader"	--(optional) unique global reference to control
+}	]]
+
+
+local widgetVersion = 2
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("header", widgetVersion) then return end
+
+local wm = WINDOW_MANAGER
+
+function LAMCreateControl.header(parent, headerData, controlName)
+	local control = wm:CreateTopLevelWindow(controlName or headerData.reference)
+	control:SetParent(parent.scroll)
+	local isHalfWidth = headerData.width == "half"
+	control:SetDimensions(isHalfWidth and 250 or 510, 30)
+
+	control.divider = wm:CreateControlFromVirtual(nil, control, "ZO_Options_Divider")
+	local divider = control.divider
+	divider:SetWidth(isHalfWidth and 250 or 510)
+	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(headerData.name)
+
+	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
+	control.data = headerData
+
+	return control
+end
\ No newline at end of file
diff --git a/Libs/LibAddonMenu-2.0/controls/panel.lua b/Libs/LibAddonMenu-2.0/controls/panel.lua
new file mode 100644
index 0000000..ed3d2ff
--- /dev/null
+++ b/Libs/LibAddonMenu-2.0/controls/panel.lua
@@ -0,0 +1,136 @@
+--[[panelData = {
+	type = "panel",
+	name = "Window Title",
+	displayName = "My Longer Window Title",	--(optional) (can be useful for long addon names or if you want to colorize it)
+	author = "Seerah",	--(optional)
+	version = "2.0",	--(optional)
+	slashCommand = "/myaddon",	--(optional) will register a keybind to open to this panel (don't forget to include the slash!)
+	registerForRefresh = true,	--boolean (optional) (will refresh all options controls when a setting is changed and when the panel is shown)
+	registerForDefaults = true,	--boolean (optional) (will set all options controls back to default values)
+	resetFunc = function() print("defaults reset") end,	--(optional) custom function to run after settings are reset to defaults
+}	]]
+
+
+local widgetVersion = 5
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("panel", widgetVersion) then return end
+
+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
+end
+
+local function ForceDefaults(panel)
+	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
+
+	if panel.data.resetFunc then
+		panel.data.resetFunc()
+	end
+
+	cm:FireCallbacks("LAM-RefreshPanel", panel)
+end
+ESO_Dialogs["LAM_DEFAULTS"] = {
+	title = {
+		text = SI_OPTIONS_RESET_TITLE,
+	},
+	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 scrollCount = 1
+function LAMCreateControl.panel(parent, panelData, controlName)
+	local control = wm:CreateTopLevelWindow(controlName)
+	control:SetParent(parent)
+
+	control.bg = wm:CreateControl(nil, control, CT_BACKDROP)
+	local bg = control.bg
+	bg:SetAnchorFill()
+	bg:SetEdgeTexture("EsoUI\\Art\\miscellaneous\\borderedinsettransparent_edgefile.dds", 128, 16)
+	bg:SetCenterColor(0, 0, 0, 0)
+
+	control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel")
+	local label = control.label
+	label:SetAnchor(TOPLEFT, control, TOPLEFT, 10, 10)
+	label:SetText(panelData.displayName and panelData.displayName or panelData.name)
+
+	if panelData.author or panelData.version then
+		control.info = wm:CreateControl(nil, control, CT_LABEL)
+		local info = control.info
+		info:SetFont("$(CHAT_FONT)|14|soft-shadow-thin")
+		info:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA())
+		info:SetHeight(13)
+		info:SetAnchor(TOPRIGHT, control, BOTTOMRIGHT, -5, 2)
+		if panelData.author and panelData.version then
+			--info:SetText("Version: "..panelData.version.."  -  "..GetString(SI_ADDON_MANAGER_AUTHOR)..": "..panelData.author)
+			info:SetText(string.format("Version: %s  -  %s: %s", panelData.version, GetString(SI_ADDON_MANAGER_AUTHOR), panelData.author))
+		elseif panelData.author then
+			info:SetText(string.format("%s: %s", GetString(SI_ADDON_MANAGER_AUTHOR), panelData.author))
+		else
+			info:SetText("Version: "..panelData.version)
+		end
+	end
+
+	control.container = wm:CreateControlFromVirtual("LAMAddonPanelContainer"..scrollCount, control, "ZO_ScrollContainer")
+	scrollCount = scrollCount + 1
+	local container = control.container
+	container:SetAnchor(TOPLEFT, 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_RESET_TITLE))
+		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 then
+		cm:RegisterCallback("LAM-RefreshPanel", RefreshPanel)
+	end
+
+	control.data = panelData
+	control.controlsToRefresh = {}
+
+	return control
+end
\ No newline at end of file
diff --git a/Libs/LibAddonMenu-2.0/controls/slider.lua b/Libs/LibAddonMenu-2.0/controls/slider.lua
new file mode 100644
index 0000000..b28e1b8
--- /dev/null
+++ b/Libs/LibAddonMenu-2.0/controls/slider.lua
@@ -0,0 +1,182 @@
+--[[sliderData = {
+	type = "slider",
+	name = "My Slider",
+	tooltip = "Slider's tooltip text.",
+	min = 0,
+	max = 20,
+	step = 1,	--(optional)
+	getFunc = function() return db.var end,
+	setFunc = function(value) db.var = value doStuff() end,
+	width = "full",	--or "half" (optional)
+	disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
+	warning = "Will need to reload the UI.",	--(optional)
+	default = defaults.var,	--(optional)
+	reference = "MyAddonSlider"	--(optional) unique global reference to control
+}	]]
+
+
+local widgetVersion = 2
+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 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
+end
+
+local function UpdateValue(control, forceDefault, value)
+	if forceDefault then	--if we are forcing defaults
+		value = 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)
+end
+
+
+function LAMCreateControl.slider(parent, sliderData, controlName)
+	local control = wm:CreateTopLevelWindow(controlName or sliderData.reference)
+	control:SetParent(parent.scroll)
+	local isHalfWidth = sliderData.width == "half"
+	if isHalfWidth then
+		control:SetDimensions(250, 55)
+	else
+		control:SetDimensions(510, 40)
+	end
+	control:SetMouseEnabled(true)
+	control.tooltipText = sliderData.tooltip
+	control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
+	control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
+
+	control.label = wm:CreateControl(nil, control, CT_LABEL)
+	local label = control.label
+	label:SetFont("ZoFontWinH4")
+	label:SetDimensions(isHalfWidth and 250 or 300, 26)
+	label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
+	label:SetAnchor(isHalfWidth and TOPLEFT or LEFT)
+	label:SetText(sliderData.name)
+
+	--skipping creating the backdrop...  Is this the actual slider texture?
+	control.slider = wm:CreateControl(nil, control, CT_SLIDER)
+	local slider = control.slider
+	slider:SetDimensions(190, 14)
+	if isHalfWidth then
+		slider:SetAnchor(TOPRIGHT, label, BOTTOMRIGHT, -5, 2)
+	else
+		slider:SetAnchor(RIGHT, control, RIGHT, -5, -5)
+	end
+	slider: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, slidervaluebg, TOPLEFT, 3, 1)
+	slidervalue:SetAnchor(BOTTOMRIGHT, 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 range = maxValue - minValue
+	slider:SetValueStep(sliderData.step or 1)
+	slider:SetHandler("OnValueChanged", function(self, value, eventReason)
+			if eventReason == EVENT_REASON_SOFTWARE then return end
+			self:SetValue(value)	--do we actually need this line?
+			slidervalue:SetText(value)
+		end)
+	slider:SetHandler("OnSliderReleased", function(self, value)
+			--sliderData.setFunc(value)
+			control:UpdateValue(false, value)	--does this work here instead?
+		end)
+
+	if sliderData.warning then
+		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
+		control.warning:SetAnchor(RIGHT, slider, LEFT, -5, 0)
+		control.warning.tooltipText = sliderData.warning
+	end
+
+	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
+	control.data = sliderData
+
+	if sliderData.disabled 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
+end
\ No newline at end of file
diff --git a/Libs/LibAddonMenu-2.0/controls/submenu.lua b/Libs/LibAddonMenu-2.0/controls/submenu.lua
new file mode 100644
index 0000000..8a599c0
--- /dev/null
+++ b/Libs/LibAddonMenu-2.0/controls/submenu.lua
@@ -0,0 +1,97 @@
+--[[submenuData = {
+	type = "submenu",
+	name = "Submenu Title",
+	tooltip = "My submenu tooltip",	--(optional)
+	controls = {sliderData, buttonData}	--(optional) used by LAM
+	reference = "MyAddonSubmenu"	--(optional) unique global reference to control
+}	]]
+
+local widgetVersion = 3
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("submenu", widgetVersion) then return end
+
+local wm = WINDOW_MANAGER
+local am = ANIMATION_MANAGER
+
+
+local function AnimateSubmenu(label)
+	local control = label: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 control = wm:CreateTopLevelWindow(controlName or submenuData.reference)
+	control:SetParent(parent.scroll)
+	control.panel = parent
+	control:SetDimensions(523, 40)
+
+	control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel")
+	local label = control.label
+	label:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5)
+	label:SetDimensions(520, 30)
+	label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
+	label:SetText(submenuData.name)
+	label:SetMouseEnabled(true)
+	if submenuData.tooltip then
+		label.tooltipText = 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(525, 0, 525, 2500)
+
+	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
+	--animation:SetDuration(1)
+	--animation:SetEasingFunction(ZO_LinearEase)	--is this needed?
+	--animation:SetHeightStartAndEnd(40, 80)	--SetStartAndEndHeight
+	--animation:SetStartAndEndHeight(40, 80)	--SetStartAndEndHeight
+	--animation:SetAnimatedControl(control)
+
+	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)
+
+	control.data = submenuData
+
+	return control
+end
+
diff --git a/Libs/LibAddonMenu-2.0/controls/texture.lua b/Libs/LibAddonMenu-2.0/controls/texture.lua
new file mode 100644
index 0000000..fc4be69
--- /dev/null
+++ b/Libs/LibAddonMenu-2.0/controls/texture.lua
@@ -0,0 +1,50 @@
+--[[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.",	--(optional)
+	width = "full",	--or "half" (optional)
+	reference = "MyAddonTexture"	--(optional) unique global reference to control
+}	]]
+
+--add texture coords support?
+
+local widgetVersion = 2
+local LAM = LibStub("LibAddonMenu-2.0")
+if not LAM:RegisterWidget("texture", widgetVersion) then return end
+
+local wm = WINDOW_MANAGER
+
+function LAMCreateControl.texture(parent, textureData, controlName)
+	local control = wm:CreateTopLevelWindow(controlName or textureData.reference)
+	control:SetResizeToFitDescendents(true)
+	control:SetParent(parent.scroll)
+
+	local isHalfWidth = textureData.width == "half"
+	if isHalfWidth then
+		control:SetDimensionConstraints(250, 55, 250, 100)
+		control:SetDimensions(250, 55)
+	else
+		control:SetDimensionConstraints(510, 30, 510, 100)
+		control:SetDimensions(510, 30)
+	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.tooltipText = textureData.tooltip
+		texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
+		texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseExit)
+	end
+
+	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
+	control.data = textureData
+
+	return control
+end
\ No newline at end of file