Blind library and misc updates to see if addon still works

Aaron DeGrow [02-10-15 - 22:21]
Blind library and misc updates to see if addon still works
Filename
.gitignore
RangeReticle.lua
RangeReticle.txt
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
libs/LibStub/LibStub.lua
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e43b0f9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.DS_Store
diff --git a/RangeReticle.lua b/RangeReticle.lua
index 3b934e4..6a941a0 100755
--- a/RangeReticle.lua
+++ b/RangeReticle.lua
@@ -1,5 +1,5 @@
 -- Load the addon menu library
-local LAM = LibStub("LibAddonMenu-1.0")
+local LAM = LibStub("LibAddonMenu-2.0")
 local db
 local hostileOORColorHex, hostileIRColorHex, hostileIMRColorHex
 local alliesOORColorHex, alliesIRColorHex, alliesIMRColorHex
@@ -126,347 +126,625 @@ local function AddonSetup()

     previousDimensionsX = 10000
     previousDimensionsY = 10000
-end
-

+	SLASH_COMMANDS["/rret"] = CommandHandler
+end

 -- Create the settings in the control panel
 local function CreateSettings()
-	local panel = LAM:CreateControlPanel("RANGE_RETICLE_SETTINGS", "Range Reticle")
-
-	LAM:AddHeader(panel, "Range_Reticle_Settings_Hostile_Header", "Hostile")
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_Name_Enabled", "Show Name", "If enabled, the target name is shown above the reticle",
-				function() return db.hostileNameEnabled end,	--getFunc
-				function()							--setFunc
-					db.hostileNameEnabled = not db.hostileNameEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_Level_Enabled", "Show Level", "If enabled, the target level is shown above the reticle",
-				function() return db.hostileLevelEnabled end,	--getFunc
-				function()							--setFunc
-					db.hostileLevelEnabled = not db.hostileLevelEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_Range_Enabled", "Show Range", "If enabled, the target range is shown at the top-right of the reticle",
-				function() return db.hostileRangeEnabled end,	--getFunc
-				function()							--setFunc
-					db.hostileRangeEnabled = not db.hostileRangeEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_Difficulty_Enabled", "Show Target Difficulty", "If enabled, the target difficulty is shown as *'s above the reticle",
-				function() return db.hostileDifficultyEnabled end,	--getFunc
-				function()							--setFunc
-					db.hostileDifficultyEnabled = not db.hostileDifficultyEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_Reticle_Coloring_Enabled", "Colorize Reticle", "If enabled, the color of the target reticle is colorized to reflect range status",
-				function() return db.hostileReticleColoringEnabled end,	--getFunc
-				function()							--setFunc
-					db.hostileReticleColoringEnabled = not db.hostileReticleColoringEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_Range_Coloring_Enabled", "Colorize Range", "If enabled, the color of the target range is colorized to reflect range status",
-				function() return db.hostileRangeColoringEnabled end,	--getFunc
-				function()							--setFunc
-					db.hostileRangeColoringEnabled = not db.hostileRangeColoringEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_NameLevel_Coloring_Enabled", "Colorize Name and Level", "If enabled, the color of the name and level is colorized to reflect range status",
-				function() return db.hostileNameLevelColoringEnabled end,	--getFunc
-				function()							--setFunc
-					db.hostileNameLevelColoringEnabled = not db.hostileNameLevelColoringEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_OOR_Enabled", "Out Of Range", "If enabled, the reticle color will change when the target is out of range",
-				function() return db.hostileOutOfRangeEnabled end,	--getFunc
-				function()							--setFunc
-					db.hostileOutOfRangeEnabled = not db.hostileOutOfRangeEnabled
-				end)
-	LAM:AddColorPicker(panel, "Range_Reticle_Settings_Hostile_OOR_Color", "Out Of Range Color", "The reticle color when the target is out of range",
-				function() return db.hostileOORColor.r, db.hostileOORColor.g, db.hostileOORColor.b end,
-				function(r,g,b,a)
-					db.hostileOORColor.r = r
-					db.hostileOORColor.g = g
-					db.hostileOORColor.b = b
-					hostileOORColorHex = RGBPercToHex(r,g,b)
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_IR_Enabled", "In Range", "If enabled, the reticle color will change when the target is in range",
-				function() return db.hostileInRangeEnabled end,	--getFunc
-				function()							--setFunc
-					db.hostileInRangeEnabled = not db.hostileInRangeEnabled
-				end)
-	LAM:AddSlider(panel, "Range_Reticle_Settings_Hostile_IR_Distance", "In Range Distance", "Set the distance that determines when a target is in range", 0, 60, 1,
-					function() return db.hostileInRangeDistance end,
-					function(value)
-						db.hostileInRangeDistance = value
-					end)
-	LAM:AddColorPicker(panel, "Range_Reticle_Settings_Hostile_IR_Color", "In Range Color", "The reticle color when the target is in range",
-				function() return db.hostileIRColor.r, db.hostileIRColor.g, db.hostileIRColor.b end,
-				function(r,g,b,a)
-					db.hostileIRColor.r = r
-					db.hostileIRColor.g = g
-					db.hostileIRColor.b = b
-					hostileIRColorHex = RGBPercToHex(r,g,b)
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_IMR_Enabled", "In Melee Range", "If enabled, the reticle color will change when the target is in melee range",
-				function() return db.hostileInMeleeRangeEnabled end,	--getFunc
-				function()							--setFunc
-					db.hostileInMeleeRangeEnabled = not db.hostileInMeleeRangeEnabled
-				end)
-	LAM:AddSlider(panel, "Range_Reticle_Settings_Hostile_IMR_Distance", "In Melee Range Distance", "Set the distance that determines when a target is in melee range", 0, 60, 1,
-					function() return db.hostileInMeleeRangeDistance end,
-					function(value)
-						db.hostileInMeleeRangeDistance = value
-					end)
-	LAM:AddColorPicker(panel, "Range_Reticle_Settings_Hostile_IMR_Color", "In Melee Range Color", "The reticle color when the target is in melee range",
-				function() return db.hostileIMRColor.r, db.hostileIMRColor.g, db.hostileIMRColor.b end,
-				function(r,g,b,a)
-					db.hostileIMRColor.r = r
-					db.hostileIMRColor.g = g
-					db.hostileIMRColor.b = b
-					hostileIMRColorHex = RGBPercToHex(r,g,b)
-				end)
-
-	LAM:AddHeader(panel, "Range_Reticle_Settings_Allies_Header", "Allies")
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Allies_Name_Enabled", "Show Name", "If enabled, the target name is shown above the reticle",
-				function() return db.alliesNameEnabled end,	--getFunc
-				function()							--setFunc
-					db.alliesNameEnabled = not db.alliesNameEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Allies_Level_Enabled", "Show Level", "If enabled, the target level is shown above the reticle",
-				function() return db.alliesLevelEnabled end,	--getFunc
-				function()							--setFunc
-					db.alliesLevelEnabled = not db.alliesLevelEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Allies_Range_Enabled", "Show Range", "If enabled, the target range is shown at the top-right of the reticle",
-				function() return db.alliesRangeEnabled end,	--getFunc
-				function()							--setFunc
-					db.alliesRangeEnabled = not db.alliesRangeEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Allies_Reticle_Coloring_Enabled", "Colorize Reticle", "If enabled, the color of the target reticle is colorized to reflect range status",
-				function() return db.alliesReticleColoringEnabled end,	--getFunc
-				function()							--setFunc
-					db.alliesReticleColoringEnabled = not db.alliesReticleColoringEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Allies_Range_Coloring_Enabled", "Colorize Range", "If enabled, the color of the target range is colorized to reflect range status",
-				function() return db.alliesRangeColoringEnabled end,	--getFunc
-				function()							--setFunc
-					db.alliesRangeColoringEnabled = not db.alliesRangeColoringEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Allies_NameLevel_Coloring_Enabled", "Colorize Name and Level", "If enabled, the color of the name and level is colorized to reflect range status",
-				function() return db.alliesNameLevelColoringEnabled end,	--getFunc
-				function()							--setFunc
-					db.alliesNameLevelColoringEnabled = not db.alliesNameLevelColoringEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Allies_OOR_Enabled", "Out Of Range", "If enabled, the reticle color will change when the target is out of range",
-				function() return db.alliesOutOfRangeEnabled end,	--getFunc
-				function()							--setFunc
-					db.alliesOutOfRangeEnabled = not db.alliesOutOfRangeEnabled
-				end)
-	LAM:AddColorPicker(panel, "Range_Reticle_Settings_Allies_OOR_Color", "Out Of Range Color", "The reticle color when the target is out of range",
-				function() return db.alliesOORColor.r, db.alliesOORColor.g, db.alliesOORColor.b end,
-				function(r,g,b,a)
-					db.alliesOORColor.r = r
-					db.alliesOORColor.g = g
-					db.alliesOORColor.b = b
-					alliesOORColorHex = RGBPercToHex(r,g,b)
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Allies_IR_Enabled", "In Range", "If enabled, the reticle color will change when the target is in range",
-				function() return db.alliesInRangeEnabled end,	--getFunc
-				function()							--setFunc
-					db.alliesInRangeEnabled = not db.alliesInRangeEnabled
-				end)
-	LAM:AddSlider(panel, "Range_Reticle_Settings_Allies_IR_Distance", "In Range Distance", "Set the distance that determines when a target is in range", 0, 60, 1,
-					function() return db.alliesInRangeDistance end,
-					function(value)
-						db.alliesInRangeDistance = value
-					end)
-	LAM:AddColorPicker(panel, "Range_Reticle_Settings_Allies_IR_Color", "In Range Color", "The reticle color when the target is in range",
-				function() return db.alliesIRColor.r, db.alliesIRColor.g, db.alliesIRColor.b end,
-				function(r,g,b,a)
-					db.alliesIRColor.r = r
-					db.alliesIRColor.g = g
-					db.alliesIRColor.b = b
-					alliesIRColorHex = RGBPercToHex(r,g,b)
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Allies_IMR_Enabled", "In Melee Range", "If enabled, the reticle color will change when the target is in melee range",
-				function() return db.alliesInMeleeRangeEnabled end,	--getFunc
-				function()							--setFunc
-					db.alliesInMeleeRangeEnabled = not db.alliesInMeleeRangeEnabled
-				end)
-	LAM:AddSlider(panel, "Range_Reticle_Settings_Allies_IMR_Distance", "In Melee Range Distance", "Set the distance that determines when a target is in melee range", 0, 60, 1,
-					function() return db.alliesInMeleeRangeDistance end,
-					function(value)
-						db.alliesInMeleeRangeDistance = value
-					end)
-	LAM:AddColorPicker(panel, "Range_Reticle_Settings_Allies_IMR_Color", "In Melee Range Color", "The reticle color when the target is in melee range",
-				function() return db.alliesIMRColor.r, db.alliesIMRColor.g, db.alliesIMRColor.b end,
-				function(r,g,b,a)
-					db.alliesIMRColor.r = r
-					db.alliesIMRColor.g = g
-					db.alliesIMRColor.b = b
-					alliesIMRColorHex = RGBPercToHex(r,g,b)
-				end)
-
-	LAM:AddHeader(panel, "Range_Reticle_Settings_Neutral_Header", "Neutral")
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_Name_Enabled", "Show Name", "If enabled, the target name is shown above the reticle",
-				function() return db.neutralNameEnabled end,	--getFunc
-				function()							--setFunc
-					db.neutralNameEnabled = not db.neutralNameEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_Level_Enabled", "Show Level", "If enabled, the target level is shown above the reticle",
-				function() return db.neutralLevelEnabled end,	--getFunc
-				function()							--setFunc
-					db.neutralLevelEnabled = not db.neutralLevelEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_Range_Enabled", "Show Range", "If enabled, the target range is shown at the top-right of the reticle",
-				function() return db.neutralRangeEnabled end,	--getFunc
-				function()							--setFunc
-					db.neutralRangeEnabled = not db.neutralRangeEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_Difficulty_Enabled", "Show Target Difficulty", "If enabled, the target difficulty is shown as *'s above the reticle",
-				function() return db.neutralDifficultyEnabled end,	--getFunc
-				function()							--setFunc
-					db.neutralDifficultyEnabled = not db.neutralDifficultyEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_Reticle_Coloring_Enabled", "Colorize Reticle", "If enabled, the color of the target reticle is colorized to reflect range status",
-				function() return db.neutralReticleColoringEnabled end,	--getFunc
-				function()							--setFunc
-					db.neutralReticleColoringEnabled = not db.neutralReticleColoringEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_Range_Coloring_Enabled", "Colorize Range", "If enabled, the color of the target range is colorized to reflect range status",
-				function() return db.neutralRangeColoringEnabled end,	--getFunc
-				function()							--setFunc
-					db.neutralRangeColoringEnabled = not db.neutralRangeColoringEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_NameLevel_Coloring_Enabled", "Colorize Name and Level", "If enabled, the color of the name and level is colorized to reflect range status",
-				function() return db.neutralNameLevelColoringEnabled end,	--getFunc
-				function()							--setFunc
-					db.neutralNameLevelColoringEnabled = not db.neutralNameLevelColoringEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_OOR_Enabled", "Out Of Range", "If enabled, the reticle color will change when the target is out of range",
-				function() return db.neutralOutOfRangeEnabled end,	--getFunc
-				function()							--setFunc
-					db.neutralOutOfRangeEnabled = not db.neutralOutOfRangeEnabled
-				end)
-	LAM:AddColorPicker(panel, "Range_Reticle_Settings_Neutral_OOR_Color", "Out Of Range Color", "The reticle color when the target is out of range",
-				function() return db.neutralOORColor.r, db.neutralOORColor.g, db.neutralOORColor.b end,
-				function(r,g,b,a)
-					db.neutralOORColor.r = r
-					db.neutralOORColor.g = g
-					db.neutralOORColor.b = b
-					neutralOORColorHex = RGBPercToHex(r,g,b)
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_IR_Enabled", "In Range", "If enabled, the reticle color will change when the target is in range",
-				function() return db.neutralInRangeEnabled end,	--getFunc
-				function()							--setFunc
-					db.neutralInRangeEnabled = not db.neutralInRangeEnabled
-				end)
-	LAM:AddSlider(panel, "Range_Reticle_Settings_Neutral_IR_Distance", "In Range Distance", "Set the distance that determines when a target is in range", 0, 60, 1,
-					function() return db.neutralInRangeDistance end,
-					function(value)
-						db.neutralInRangeDistance = value
-					end)
-	LAM:AddColorPicker(panel, "Range_Reticle_Settings_Neutral_IR_Color", "In Range Color", "The reticle color when the target is in range",
-				function() return db.neutralIRColor.r, db.neutralIRColor.g, db.neutralIRColor.b end,
-				function(r,g,b,a)
-					db.neutralIRColor.r = r
-					db.neutralIRColor.g = g
-					db.neutralIRColor.b = b
-					neutralIRColorHex = RGBPercToHex(r,g,b)
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_IMR_Enabled", "In Melee Range", "If enabled, the reticle color will change when the target is in melee range",
-				function() return db.neutralInMeleeRangeEnabled end,	--getFunc
-				function()							--setFunc
-					db.neutralInMeleeRangeEnabled = not db.neutralInMeleeRangeEnabled
-				end)
-	LAM:AddSlider(panel, "Range_Reticle_Settings_Neutral_IMR_Distance", "In Melee Range Distance", "Set the distance that determines when a target is in melee range", 0, 60, 1,
-					function() return db.neutralInMeleeRangeDistance end,
-					function(value)
-						db.neutralInMeleeRangeDistance = value
-					end)
-	LAM:AddColorPicker(panel, "Range_Reticle_Settings_Neutral_IMR_Color", "In Melee Range Color", "The reticle color when the target is in melee range",
-				function() return db.neutralIMRColor.r, db.neutralIMRColor.g, db.neutralIMRColor.b end,
-				function(r,g,b,a)
-					db.neutralIMRColor.r = r
-					db.neutralIMRColor.g = g
-					db.neutralIMRColor.b = b
-					neutralIMRColorHex = RGBPercToHex(r,g,b)
-				end)
-
-	LAM:AddHeader(panel, "Range_Reticle_Settings_NPCs_Header", "NPCs")
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_NPCs_Name_Enabled", "Show Name", "If enabled, the target name is shown above the reticle",
-				function() return db.npcsNameEnabled end,	--getFunc
-				function()							--setFunc
-					db.npcsNameEnabled = not db.npcsNameEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_NPCs_Level_Enabled", "Show Level", "If enabled, the target level is shown above the reticle",
-				function() return db.npcsLevelEnabled end,	--getFunc
-				function()							--setFunc
-					db.npcsLevelEnabled = not db.npcsLevelEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_NPCs_Range_Enabled", "Show Range", "If enabled, the target range is shown at the top-right of the reticle",
-				function() return db.npcsRangeEnabled end,	--getFunc
-				function()							--setFunc
-					db.npcsRangeEnabled = not db.npcsRangeEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_NPCs_Reticle_Coloring_Enabled", "Colorize Reticle", "If enabled, the color of the target reticle is colorized to reflect range status",
-				function() return db.npcsReticleColoringEnabled end,	--getFunc
-				function()							--setFunc
-					db.npcsReticleColoringEnabled = not db.npcsReticleColoringEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_NPCs_Range_Coloring_Enabled", "Colorize Range", "If enabled, the color of the target range is colorized to reflect range status",
-				function() return db.npcsRangeColoringEnabled end,	--getFunc
-				function()							--setFunc
-					db.npcsRangeColoringEnabled = not db.npcsRangeColoringEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_NPCs_NameLevel_Coloring_Enabled", "Colorize Name and Level", "If enabled, the color of the name and level is colorized to reflect range status",
-				function() return db.npcsNameLevelColoringEnabled end,	--getFunc
-				function()							--setFunc
-					db.npcsNameLevelColoringEnabled = not db.npcsNameLevelColoringEnabled
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_NPCs_OOR_Enabled", "Out Of Range", "If enabled, the reticle color will change when the target is out of range",
-				function() return db.npcsOutOfRangeEnabled end,	--getFunc
-				function()							--setFunc
-					db.npcsOutOfRangeEnabled = not db.npcsOutOfRangeEnabled
-				end)
-	LAM:AddColorPicker(panel, "Range_Reticle_Settings_NPCs_OOR_Color", "Out Of Range Color", "The reticle color when the target is out of range",
-				function() return db.npcsOORColor.r, db.npcsOORColor.g, db.npcsOORColor.b end,
-				function(r,g,b,a)
-					db.npcsOORColor.r = r
-					db.npcsOORColor.g = g
-					db.npcsOORColor.b = b
-					npcsOORColorHex = RGBPercToHex(r,g,b)
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_NPCs_IR_Enabled", "In Range", "If enabled, the reticle color will change when the target is in range",
-				function() return db.npcsInRangeEnabled end,	--getFunc
-				function()							--setFunc
-					db.npcsInRangeEnabled = not db.npcsInRangeEnabled
-				end)
-	LAM:AddSlider(panel, "Range_Reticle_Settings_NPCs_IR_Distance", "In Range Distance", "Set the distance that determines when a target is in range", 0, 60, 1,
-					function() return db.npcsInRangeDistance end,
-					function(value)
-						db.npcsInRangeDistance = value
-					end)
-	LAM:AddColorPicker(panel, "Range_Reticle_Settings_NPCs_IR_Color", "In Range Color", "The reticle color when the target is in range",
-				function() return db.npcsIRColor.r, db.npcsIRColor.g, db.npcsIRColor.b end,
-				function(r,g,b,a)
-					db.npcsIRColor.r = r
-					db.npcsIRColor.g = g
-					db.npcsIRColor.b = b
-					npcsIRColorHex = RGBPercToHex(r,g,b)
-				end)
-	LAM:AddCheckbox(panel, "Range_Reticle_Settings_NPCs_IMR_Enabled", "In Melee Range", "If enabled, the reticle color will change when the target is in melee range",
-				function() return db.npcsInMeleeRangeEnabled end,	--getFunc
-				function()							--setFunc
-					db.npcsInMeleeRangeEnabled = not db.npcsInMeleeRangeEnabled
-				end)
-	LAM:AddSlider(panel, "Range_Reticle_Settings_NPCs_IMR_Distance", "In Melee Range Distance", "Set the distance that determines when a target is in melee range", 0, 60, 1,
-					function() return db.npcsInMeleeRangeDistance end,
-					function(value)
-						db.npcsInMeleeRangeDistance = value
-					end)
-	LAM:AddColorPicker(panel, "Range_Reticle_Settings_NPCs_IMR_Color", "In Melee Range Color", "The reticle color when the target is in melee range",
-				function() return db.npcsIMRColor.r, db.npcsIMRColor.g, db.npcsIMRColor.b end,
-				function(r,g,b,a)
-					db.npcsIMRColor.r = r
-					db.npcsIMRColor.g = g
-					db.npcsIMRColor.b = b
-					npcsIMRColorHex = RGBPercToHex(r,g,b)
-				end)
+    local panelData = {
+        type = "panel",
+        name = "RangeReticle",
+        displayName = "RangeReticle",
+        author = "Adein",
+        version = "0.6",
+        slashCommand = "/rret",	--(optional) will register a keybind to open to this panel
+        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)
+    }
+
+    local optionsTable = {
+        [1] = {
+            type = "header",
+            name = "Range Reticle Settings",
+            width = "full",	--or "half" (optional)
+        },
+        [2] = {
+            type = "submenu",
+            name = "Hostile Targets",
+            tooltip = "Settings for hostile targets",	--(optional)
+            controls = {
+                [1] = {
+                    type = "checkbox",
+                    name = "Show Name",
+                    tooltip = "If enabled, the target name is shown above the reticle",
+                    getFunc = function() return db.hostileNameEnabled end,
+                    setFunc = function() db.hostileNameEnabled = not db.hostileNameEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [2] = {
+                    type = "checkbox",
+                    name = "Show Level",
+                    tooltip = "If enabled, the target level is shown above the reticle",
+                    getFunc = function() return db.hostileLevelEnabled end,
+                    setFunc = function() db.hostileLevelEnabled = not db.hostileLevelEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [3] = {
+                    type = "checkbox",
+                    name = "Show Range",
+                    tooltip = "If enabled, the target range is shown at the top-right of the reticle",
+                    getFunc = function() return db.hostileRangeEnabled end,
+                    setFunc = function() db.hostileRangeEnabled = not db.hostileRangeEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [4] = {
+                    type = "checkbox",
+                    name = "Show Target Difficulty",
+                    tooltip = "If enabled, the target difficulty is shown as *'s above the reticle",
+                    getFunc = function() return db.hostileDifficultyEnabled end,
+                    setFunc = function() db.hostileDifficultyEnabled = not db.hostileDifficultyEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [5] = {
+                    type = "checkbox",
+                    name = "Colorize Reticle",
+                    tooltip = "If enabled, the color of the target reticle is colorized to reflect range status",
+                    getFunc = function() return db.hostileReticleColoringEnabled end,
+                    setFunc = function() db.hostileReticleColoringEnabled = not db.hostileReticleColoringEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [6] = {
+                    type = "checkbox",
+                    name = "Colorize Range",
+                    tooltip = "If enabled, the color of the target range is colorized to reflect range status",
+                    getFunc = function() return db.hostileRangeColoringEnabled end,
+                    setFunc = function() db.hostileRangeColoringEnabled = not db.hostileRangeColoringEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [7] = {
+                    type = "checkbox",
+                    name = "Colorize Name and Level",
+                    tooltip = "If enabled, the color of the name and level is colorized to reflect range status",
+                    getFunc = function() return db.hostileNameLevelColoringEnabled end,
+                    setFunc = function() db.hostileNameLevelColoringEnabled = not db.hostileNameLevelColoringEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [8] = {
+                    type = "checkbox",
+                    name = "Out Of Range",
+                    tooltip = "If enabled, the reticle color will change when the target is out of range",
+                    getFunc = function() return db.hostileOutOfRangeEnabled end,
+                    setFunc = function() db.hostileOutOfRangeEnabled = not db.hostileOutOfRangeEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [9] = {
+                    type = "colorpicker",
+                    name = "Out Of Range Color",
+                    tooltip = "The reticle color when the target is out of range",
+                    getFunc = function() return db.hostileOORColor.r, db.hostileOORColor.g, db.hostileOORColor.b end,
+                    setFunc = function(r,g,b,a)
+                        db.hostileOORColor.r = r
+                        db.hostileOORColor.g = g
+                        db.hostileOORColor.b = b
+                        hostileOORColorHex = RGBPercToHex(r,g,b)
+				        end,
+                    width = "half",	--or "half" (optional)
+                },
+                [10] = {
+                    type = "checkbox",
+                    name = "In Range",
+                    tooltip = "If enabled, the reticle color will change when the target is in range",
+                    getFunc = function() return db.hostileInRangeEnabled end,
+                    setFunc = function() db.hostileInRangeEnabled = not db.hostileInRangeEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [11] = {
+                    type = "slider",
+                    name = "In Range Distance",
+                    tooltip = "Set the distance that determines when a target is in range",
+                    min = 0,
+                    max = 60,
+                    step = 1,	--(optional)
+                    getFunc = function() return db.hostileInRangeDistance end,
+                    setFunc = function(value) db.hostileInRangeDistance = value end,
+                    width = "half",	--or "half" (optional)
+                },
+                [12] = {
+                    type = "colorpicker",
+                    name = "In Range Color",
+                    tooltip = "The reticle color when the target is in range",
+                    getFunc = function() return db.hostileIRColor.r, db.hostileIRColor.g, db.hostileIRColor.b end,
+                    setFunc = function(r,g,b,a)
+                        db.hostileIRColor.r = r
+                        db.hostileIRColor.g = g
+                        db.hostileIRColor.b = b
+                        hostileIRColorHex = RGBPercToHex(r,g,b)
+                        end,
+                    width = "half",	--or "half" (optional)
+                },
+                [13] = {
+                    type = "checkbox",
+                    name = "In Melee Range",
+                    tooltip = "If enabled, the reticle color will change when the target is in melee range",
+                    getFunc = function() return db.hostileInMeleeRangeEnabled end,
+                    setFunc = function() db.hostileInMeleeRangeEnabled = not db.hostileInMeleeRangeEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [14] = {
+                    type = "slider",
+                    name = "In Melee Range Distance",
+                    tooltip = "Set the distance that determines when a target is in melee range",
+                    min = 0,
+                    max = 60,
+                    step = 1,	--(optional)
+                    getFunc = function() return db.hostileInMeleeRangeDistance end,
+                    setFunc = function(value) db.hostileInMeleeRangeDistance = value end,
+                    width = "half",	--or "half" (optional)
+                },
+                [15] = {
+                    type = "colorpicker",
+                    name = "In Melee Range Color",
+                    tooltip = "The reticle color when the target is in melee range",
+                    getFunc = function() return db.hostileIMRColor.r, db.hostileIMRColor.g, db.hostileIMRColor.b end,
+                    setFunc = function(r,g,b,a)
+                        db.hostileIMRColor.r = r
+                        db.hostileIMRColor.g = g
+                        db.hostileIMRColor.b = b
+                        hostileIMRColorHex = RGBPercToHex(r,g,b)
+                        end,
+                    width = "half",	--or "half" (optional)
+                },
+            },
+        },
+        [3] = {
+            type = "submenu",
+            name = "Allies",
+            tooltip = "Settings for allies",	--(optional)
+            controls = {
+                [1] = {
+                    type = "checkbox",
+                    name = "Show Name",
+                    tooltip = "If enabled, the target name is shown above the reticle",
+                    getFunc = function() return db.alliesNameEnabled end,
+                    setFunc = function() db.alliesNameEnabled = not db.alliesNameEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [2] = {
+                    type = "checkbox",
+                    name = "Show Level",
+                    tooltip = "If enabled, the target level is shown above the reticle",
+                    getFunc = function() return db.alliesLevelEnabled end,
+                    setFunc = function() db.alliesLevelEnabled = not db.alliesLevelEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [3] = {
+                    type = "checkbox",
+                    name = "Show Range",
+                    tooltip = "If enabled, the target range is shown at the top-right of the reticle",
+                    getFunc = function() return db.alliesRangeEnabled end,
+                    setFunc = function() db.alliesRangeEnabled = not db.alliesRangeEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [4] = {
+                    type = "checkbox",
+                    name = "Show Target Difficulty",
+                    tooltip = "If enabled, the target difficulty is shown as *'s above the reticle",
+                    getFunc = function() return db.alliesDifficultyEnabled end,
+                    setFunc = function() db.alliesDifficultyEnabled = not db.alliesDifficultyEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [5] = {
+                    type = "checkbox",
+                    name = "Colorize Reticle",
+                    tooltip = "If enabled, the color of the target reticle is colorized to reflect range status",
+                    getFunc = function() return db.alliesReticleColoringEnabled end,
+                    setFunc = function() db.alliesReticleColoringEnabled = not db.alliesReticleColoringEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [6] = {
+                    type = "checkbox",
+                    name = "Colorize Range",
+                    tooltip = "If enabled, the color of the target range is colorized to reflect range status",
+                    getFunc = function() return db.alliesRangeColoringEnabled end,
+                    setFunc = function() db.alliesRangeColoringEnabled = not db.alliesRangeColoringEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [7] = {
+                    type = "checkbox",
+                    name = "Colorize Name and Level",
+                    tooltip = "If enabled, the color of the name and level is colorized to reflect range status",
+                    getFunc = function() return db.alliesNameLevelColoringEnabled end,
+                    setFunc = function() db.alliesNameLevelColoringEnabled = not db.alliesNameLevelColoringEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [8] = {
+                    type = "checkbox",
+                    name = "Out Of Range",
+                    tooltip = "If enabled, the reticle color will change when the target is out of range",
+                    getFunc = function() return db.alliesOutOfRangeEnabled end,
+                    setFunc = function() db.alliesOutOfRangeEnabled = not db.alliesOutOfRangeEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [9] = {
+                    type = "colorpicker",
+                    name = "Out Of Range Color",
+                    tooltip = "The reticle color when the target is out of range",
+                    getFunc = function() return db.alliesOORColor.r, db.alliesOORColor.g, db.alliesOORColor.b end,
+                    setFunc = function(r,g,b,a)
+                        db.alliesOORColor.r = r
+                        db.alliesOORColor.g = g
+                        db.alliesOORColor.b = b
+                        alliesOORColorHex = RGBPercToHex(r,g,b)
+				        end,
+                    width = "half",	--or "half" (optional)
+                },
+                [10] = {
+                    type = "checkbox",
+                    name = "In Range",
+                    tooltip = "If enabled, the reticle color will change when the target is in range",
+                    getFunc = function() return db.alliesInRangeEnabled end,
+                    setFunc = function() db.alliesInRangeEnabled = not db.alliesInRangeEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [11] = {
+                    type = "slider",
+                    name = "In Range Distance",
+                    tooltip = "Set the distance that determines when a target is in range",
+                    min = 0,
+                    max = 60,
+                    step = 1,	--(optional)
+                    getFunc = function() return db.alliesInRangeDistance end,
+                    setFunc = function(value) db.alliesInRangeDistance = value end,
+                    width = "half",	--or "half" (optional)
+                },
+                [12] = {
+                    type = "colorpicker",
+                    name = "In Range Color",
+                    tooltip = "The reticle color when the target is in range",
+                    getFunc = function() return db.alliesIRColor.r, db.alliesIRColor.g, db.alliesIRColor.b end,
+                    setFunc = function(r,g,b,a)
+                        db.alliesIRColor.r = r
+                        db.alliesIRColor.g = g
+                        db.alliesIRColor.b = b
+                        alliesIRColorHex = RGBPercToHex(r,g,b)
+                        end,
+                    width = "half",	--or "half" (optional)
+                },
+                [13] = {
+                    type = "checkbox",
+                    name = "In Melee Range",
+                    tooltip = "If enabled, the reticle color will change when the target is in melee range",
+                    getFunc = function() return db.alliesInMeleeRangeEnabled end,
+                    setFunc = function() db.alliesInMeleeRangeEnabled = not db.alliesInMeleeRangeEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [14] = {
+                    type = "slider",
+                    name = "In Melee Range Distance",
+                    tooltip = "Set the distance that determines when a target is in melee range",
+                    min = 0,
+                    max = 60,
+                    step = 1,	--(optional)
+                    getFunc = function() return db.alliesInMeleeRangeDistance end,
+                    setFunc = function(value) db.alliesInMeleeRangeDistance = value end,
+                    width = "half",	--or "half" (optional)
+                },
+                [15] = {
+                    type = "colorpicker",
+                    name = "In Melee Range Color",
+                    tooltip = "The reticle color when the target is in melee range",
+                    getFunc = function() return db.alliesIMRColor.r, db.alliesIMRColor.g, db.alliesIMRColor.b end,
+                    setFunc = function(r,g,b,a)
+                        db.alliesIMRColor.r = r
+                        db.alliesIMRColor.g = g
+                        db.alliesIMRColor.b = b
+                        alliesIMRColorHex = RGBPercToHex(r,g,b)
+                        end,
+                    width = "half",	--or "half" (optional)
+                },
+            },
+        },
+        [4] = {
+            type = "submenu",
+            name = "Neutral Targets",
+            tooltip = "Settings for neutral targets",	--(optional)
+            controls = {
+                [1] = {
+                    type = "checkbox",
+                    name = "Show Name",
+                    tooltip = "If enabled, the target name is shown above the reticle",
+                    getFunc = function() return db.neutralNameEnabled end,
+                    setFunc = function() db.neutralNameEnabled = not db.neutralNameEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [2] = {
+                    type = "checkbox",
+                    name = "Show Level",
+                    tooltip = "If enabled, the target level is shown above the reticle",
+                    getFunc = function() return db.neutralLevelEnabled end,
+                    setFunc = function() db.neutralLevelEnabled = not db.neutralLevelEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [3] = {
+                    type = "checkbox",
+                    name = "Show Range",
+                    tooltip = "If enabled, the target range is shown at the top-right of the reticle",
+                    getFunc = function() return db.neutralRangeEnabled end,
+                    setFunc = function() db.neutralRangeEnabled = not db.neutralRangeEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [4] = {
+                    type = "checkbox",
+                    name = "Show Target Difficulty",
+                    tooltip = "If enabled, the target difficulty is shown as *'s above the reticle",
+                    getFunc = function() return db.neutralDifficultyEnabled end,
+                    setFunc = function() db.neutralDifficultyEnabled = not db.neutralDifficultyEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [5] = {
+                    type = "checkbox",
+                    name = "Colorize Reticle",
+                    tooltip = "If enabled, the color of the target reticle is colorized to reflect range status",
+                    getFunc = function() return db.neutralReticleColoringEnabled end,
+                    setFunc = function() db.neutralReticleColoringEnabled = not db.neutralReticleColoringEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [6] = {
+                    type = "checkbox",
+                    name = "Colorize Range",
+                    tooltip = "If enabled, the color of the target range is colorized to reflect range status",
+                    getFunc = function() return db.neutralRangeColoringEnabled end,
+                    setFunc = function() db.neutralRangeColoringEnabled = not db.neutralRangeColoringEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [7] = {
+                    type = "checkbox",
+                    name = "Colorize Name and Level",
+                    tooltip = "If enabled, the color of the name and level is colorized to reflect range status",
+                    getFunc = function() return db.neutralNameLevelColoringEnabled end,
+                    setFunc = function() db.neutralNameLevelColoringEnabled = not db.neutralNameLevelColoringEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [8] = {
+                    type = "checkbox",
+                    name = "Out Of Range",
+                    tooltip = "If enabled, the reticle color will change when the target is out of range",
+                    getFunc = function() return db.neutralOutOfRangeEnabled end,
+                    setFunc = function() db.neutralOutOfRangeEnabled = not db.neutralOutOfRangeEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [9] = {
+                    type = "colorpicker",
+                    name = "Out Of Range Color",
+                    tooltip = "The reticle color when the target is out of range",
+                    getFunc = function() return db.neutralOORColor.r, db.neutralOORColor.g, db.neutralOORColor.b end,
+                    setFunc = function(r,g,b,a)
+                        db.neutralOORColor.r = r
+                        db.neutralOORColor.g = g
+                        db.neutralOORColor.b = b
+                        neutralOORColorHex = RGBPercToHex(r,g,b)
+				        end,
+                    width = "half",	--or "half" (optional)
+                },
+                [10] = {
+                    type = "checkbox",
+                    name = "In Range",
+                    tooltip = "If enabled, the reticle color will change when the target is in range",
+                    getFunc = function() return db.neutralInRangeEnabled end,
+                    setFunc = function() db.neutralInRangeEnabled = not db.neutralInRangeEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [11] = {
+                    type = "slider",
+                    name = "In Range Distance",
+                    tooltip = "Set the distance that determines when a target is in range",
+                    min = 0,
+                    max = 60,
+                    step = 1,	--(optional)
+                    getFunc = function() return db.neutralInRangeDistance end,
+                    setFunc = function(value) db.neutralInRangeDistance = value end,
+                    width = "half",	--or "half" (optional)
+                },
+                [12] = {
+                    type = "colorpicker",
+                    name = "In Range Color",
+                    tooltip = "The reticle color when the target is in range",
+                    getFunc = function() return db.neutralIRColor.r, db.neutralIRColor.g, db.neutralIRColor.b end,
+                    setFunc = function(r,g,b,a)
+                        db.neutralIRColor.r = r
+                        db.neutralIRColor.g = g
+                        db.neutralIRColor.b = b
+                        neutralIRColorHex = RGBPercToHex(r,g,b)
+                        end,
+                    width = "half",	--or "half" (optional)
+                },
+                [13] = {
+                    type = "checkbox",
+                    name = "In Melee Range",
+                    tooltip = "If enabled, the reticle color will change when the target is in melee range",
+                    getFunc = function() return db.neutralInMeleeRangeEnabled end,
+                    setFunc = function() db.neutralInMeleeRangeEnabled = not db.neutralInMeleeRangeEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [14] = {
+                    type = "slider",
+                    name = "In Melee Range Distance",
+                    tooltip = "Set the distance that determines when a target is in melee range",
+                    min = 0,
+                    max = 60,
+                    step = 1,	--(optional)
+                    getFunc = function() return db.neutralInMeleeRangeDistance end,
+                    setFunc = function(value) db.neutralInMeleeRangeDistance = value end,
+                    width = "half",	--or "half" (optional)
+                },
+                [15] = {
+                    type = "colorpicker",
+                    name = "In Melee Range Color",
+                    tooltip = "The reticle color when the target is in melee range",
+                    getFunc = function() return db.neutralIMRColor.r, db.neutralIMRColor.g, db.neutralIMRColor.b end,
+                    setFunc = function(r,g,b,a)
+                        db.neutralIMRColor.r = r
+                        db.neutralIMRColor.g = g
+                        db.neutralIMRColor.b = b
+                        neutralIMRColorHex = RGBPercToHex(r,g,b)
+                        end,
+                    width = "half",	--or "half" (optional)
+                },
+            },
+        },
+        [5] = {
+            type = "submenu",
+            name = "NPC Targets",
+            tooltip = "Settings for NPC targets",	--(optional)
+            controls = {
+                [1] = {
+                    type = "checkbox",
+                    name = "Show Name",
+                    tooltip = "If enabled, the target name is shown above the reticle",
+                    getFunc = function() return db.npcsNameEnabled end,
+                    setFunc = function() db.npcsNameEnabled = not db.npcsNameEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [2] = {
+                    type = "checkbox",
+                    name = "Show Level",
+                    tooltip = "If enabled, the target level is shown above the reticle",
+                    getFunc = function() return db.npcsLevelEnabled end,
+                    setFunc = function() db.npcsLevelEnabled = not db.npcsLevelEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [3] = {
+                    type = "checkbox",
+                    name = "Show Range",
+                    tooltip = "If enabled, the target range is shown at the top-right of the reticle",
+                    getFunc = function() return db.npcsRangeEnabled end,
+                    setFunc = function() db.npcsRangeEnabled = not db.npcsRangeEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [4] = {
+                    type = "checkbox",
+                    name = "Show Target Difficulty",
+                    tooltip = "If enabled, the target difficulty is shown as *'s above the reticle",
+                    getFunc = function() return db.npcsDifficultyEnabled end,
+                    setFunc = function() db.npcsDifficultyEnabled = not db.npcsDifficultyEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [5] = {
+                    type = "checkbox",
+                    name = "Colorize Reticle",
+                    tooltip = "If enabled, the color of the target reticle is colorized to reflect range status",
+                    getFunc = function() return db.npcsReticleColoringEnabled end,
+                    setFunc = function() db.npcsReticleColoringEnabled = not db.npcsReticleColoringEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [6] = {
+                    type = "checkbox",
+                    name = "Colorize Range",
+                    tooltip = "If enabled, the color of the target range is colorized to reflect range status",
+                    getFunc = function() return db.npcsRangeColoringEnabled end,
+                    setFunc = function() db.npcsRangeColoringEnabled = not db.npcsRangeColoringEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [7] = {
+                    type = "checkbox",
+                    name = "Colorize Name and Level",
+                    tooltip = "If enabled, the color of the name and level is colorized to reflect range status",
+                    getFunc = function() return db.npcsNameLevelColoringEnabled end,
+                    setFunc = function() db.npcsNameLevelColoringEnabled = not db.npcsNameLevelColoringEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [8] = {
+                    type = "checkbox",
+                    name = "Out Of Range",
+                    tooltip = "If enabled, the reticle color will change when the target is out of range",
+                    getFunc = function() return db.npcsOutOfRangeEnabled end,
+                    setFunc = function() db.npcsOutOfRangeEnabled = not db.npcsOutOfRangeEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [9] = {
+                    type = "colorpicker",
+                    name = "Out Of Range Color",
+                    tooltip = "The reticle color when the target is out of range",
+                    getFunc = function() return db.npcsOORColor.r, db.npcsOORColor.g, db.npcsOORColor.b end,
+                    setFunc = function(r,g,b,a)
+                        db.npcsOORColor.r = r
+                        db.npcsOORColor.g = g
+                        db.npcsOORColor.b = b
+                        npcsOORColorHex = RGBPercToHex(r,g,b)
+				        end,
+                    width = "half",	--or "half" (optional)
+                },
+                [10] = {
+                    type = "checkbox",
+                    name = "In Range",
+                    tooltip = "If enabled, the reticle color will change when the target is in range",
+                    getFunc = function() return db.npcsInRangeEnabled end,
+                    setFunc = function() db.npcsInRangeEnabled = not db.npcsInRangeEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [11] = {
+                    type = "slider",
+                    name = "In Range Distance",
+                    tooltip = "Set the distance that determines when a target is in range",
+                    min = 0,
+                    max = 60,
+                    step = 1,	--(optional)
+                    getFunc = function() return db.npcsInRangeDistance end,
+                    setFunc = function(value) db.npcsInRangeDistance = value end,
+                    width = "half",	--or "half" (optional)
+                },
+                [12] = {
+                    type = "colorpicker",
+                    name = "In Range Color",
+                    tooltip = "The reticle color when the target is in range",
+                    getFunc = function() return db.npcsIRColor.r, db.npcsIRColor.g, db.npcsIRColor.b end,
+                    setFunc = function(r,g,b,a)
+                        db.npcsIRColor.r = r
+                        db.npcsIRColor.g = g
+                        db.npcsIRColor.b = b
+                        npcsIRColorHex = RGBPercToHex(r,g,b)
+                        end,
+                    width = "half",	--or "half" (optional)
+                },
+                [13] = {
+                    type = "checkbox",
+                    name = "In Melee Range",
+                    tooltip = "If enabled, the reticle color will change when the target is in melee range",
+                    getFunc = function() return db.npcsInMeleeRangeEnabled end,
+                    setFunc = function() db.npcsInMeleeRangeEnabled = not db.npcsInMeleeRangeEnabled end,
+                    width = "half",	--or "half" (optional)
+                },
+                [14] = {
+                    type = "slider",
+                    name = "In Melee Range Distance",
+                    tooltip = "Set the distance that determines when a target is in melee range",
+                    min = 0,
+                    max = 60,
+                    step = 1,	--(optional)
+                    getFunc = function() return db.npcsInMeleeRangeDistance end,
+                    setFunc = function(value) db.npcsInMeleeRangeDistance = value end,
+                    width = "half",	--or "half" (optional)
+                },
+                [15] = {
+                    type = "colorpicker",
+                    name = "In Melee Range Color",
+                    tooltip = "The reticle color when the target is in melee range",
+                    getFunc = function() return db.npcsIMRColor.r, db.npcsIMRColor.g, db.npcsIMRColor.b end,
+                    setFunc = function(r,g,b,a)
+                        db.npcsIMRColor.r = r
+                        db.npcsIMRColor.g = g
+                        db.npcsIMRColor.b = b
+                        npcsIMRColorHex = RGBPercToHex(r,g,b)
+                        end,
+                    width = "half",	--or "half" (optional)
+                },
+            },
+        },
+    }
+
+    LAM:RegisterAddonPanel("RangeReticle", panelData)
+    LAM:RegisterOptionControls("RangeReticle", optionsTable)
 end

 function GetColor(imrColor, irColor, oorColor, inMeleeRangeEnabled, inRangeEnabled, outOfRangeEnabled, targetInMeleeRange, targetInRange)
@@ -500,6 +778,9 @@ function OnRangeUpdate()
     -- Get target name and reaction
 	local targetReaction = GetUnitReaction('reticleover')
 	local targetName = GetUnitName('reticleover')
+    local targetClass = GetUnitClass('reticleover') -- TODO
+    local targetRank, targetSubRank = GetUnitAvARank('reticleover') -- TODO
+    local targetGrouped = IsUnitGrouped('reticleover') -- TODO

     -- Local variables to store what needs to be done
     local nameEnabled = false
@@ -599,52 +880,11 @@ function OnRangeUpdate()
         local selfX, selfY, selfH = GetMapPlayerPosition('player')

         -- Get map details
-        local mapWidth, mapHeight = GetMapNumTiles()
         local mapType = GetMapType()
         local mapContentType = GetMapContentType()

-        --MAPTYPE_NONE: 0
-        --MAPTYPE_SUBZONE: 1
-        --MAPTYPE_ZONE: 2
-        --MAPTYPE_WORLD: 3
-        --MAPTYPE_ALLIANCE: 4
-        --MAPTYPE_COSMIC: 5
-
-        --MAP_CONTENT_NONE: 0
-        --MAP_CONTENT_AVA: 1
-        --MAP_CONTENT_DUNGEON: 2
-
         -- Calculate and display target range
         if targetX and targetY then
-            -- For debugging map types
-            --[[if true then
-            	CHAT_SYSTEM:AddMessage("Width: " .. tostring(mapWidth))
-            	CHAT_SYSTEM:AddMessage("Height: " .. tostring(mapHeight))
-            	CHAT_SYSTEM:AddMessage("Type: " .. tostring(mapType))
-            	CHAT_SYSTEM:AddMessage("Content: " .. tostring(mapContentType))
-            	local dimensionsX, dimensionsY = ZO_WorldMapContainer:GetDimensions()
-            	CHAT_SYSTEM:AddMessage("WMDimensions: " .. tostring(dimensionsX) .. ', ' .. tostring(dimensionsY))
-            	local dimensionsX1, dimensionsY1 = ZO_WorldMapContainer1:GetDimensions()
-            	CHAT_SYSTEM:AddMessage("1Dimensions: " .. tostring(dimensionsX1) .. ', ' .. tostring(dimensionsY1))
-            	local dimensionsX2, dimensionsY2 = ZO_WorldMapContainer2:GetDimensions()
-            	CHAT_SYSTEM:AddMessage("2Dimensions: " .. tostring(dimensionsX2) .. ', ' .. tostring(dimensionsY2))
-            	local dimensionsX3, dimensionsY3 = ZO_WorldMapContainer3:GetDimensions()
-            	CHAT_SYSTEM:AddMessage("3Dimensions: " .. tostring(dimensionsX3) .. ', ' .. tostring(dimensionsY3))
-            	local dimensionsX4, dimensionsY4 = ZO_WorldMapContainer4:GetDimensions()
-            	CHAT_SYSTEM:AddMessage("4Dimensions: " .. tostring(dimensionsX4) .. ', ' .. tostring(dimensionsY4))
-
-            	CHAT_SYSTEM:AddMessage("Self: " .. tostring(selfX) .. ', ' .. tostring(selfY))
-            	CHAT_SYSTEM:AddMessage("Target: " .. tostring(targetX) .. ', ' .. tostring(targetY))
-
-            	--local mdata = getmetatable(ZO_WorldMapContainer1)
-            	--local mdata = getmetatable(ZO_WorldMapContainer)
-            	--tprint(mdata)
-            	CHAT_SYSTEM:AddMessage("H: " .. tostring(ZO_WorldMapContainer:GetHeight()))  --405
-            	CHAT_SYSTEM:AddMessage("W: " .. tostring(ZO_WorldMapContainer:GetWidth()))	--405
-
-				CHAT_SYSTEM:AddMessage("ZIndex: " .. tostring(GetCurrentMapZoneIndex()))
-            end]]
-
         	local dimensionsX, dimensionsY = ZO_WorldMapContainer:GetDimensions()
         	local multiplier = 5.0

@@ -777,6 +1017,61 @@ function OnRangeUpdate()
     end
 end

+-- Slash command handlers
+local function CommandHandler(text)
+	-- Display help
+	if text == nil or string.len(text) <= 0 or string.lower(text) == "help" then
+		ChatMessage("RangeReticle Help:")
+		ChatMessage("/rret : display help.")
+		ChatMessage("/rret dbg : dump debug information to chat")
+    elseif text ~= nil and string.lower(text) == "dbg" then
+	end
+end
+
+-- Debug info to chat window
+local function Debug()
+    -- Get details of what's under the reticle
+    local targetX, targetY, targetH = GetMapPlayerPosition('reticleover')
+
+    -- Get details of the player
+    local selfX, selfY, selfH = GetMapPlayerPosition('player')
+
+    -- Get map details
+    local mapIndex = GetCurrentMapIndex()
+    local mapZoneIndex = GetCurrentMapZoneIndex()
+    local mapWidth, mapHeight = GetMapNumTiles()
+    local mapType = GetMapType()
+    local mapContentType = GetMapContentType()
+    local mapCurrentFloor, mapNumFloors =  GetMapFloorInfo()
+    local mapName = GetMapName()
+
+    --MAPTYPE_NONE: 0
+    --MAPTYPE_SUBZONE: 1
+    --MAPTYPE_ZONE: 2
+    --MAPTYPE_WORLD: 3
+    --MAPTYPE_ALLIANCE: 4
+    --MAPTYPE_COSMIC: 5
+
+    --MAP_CONTENT_NONE: 0
+    --MAP_CONTENT_AVA: 1
+    --MAP_CONTENT_DUNGEON: 2
+
+    CHAT_SYSTEM:AddMessage("Map Index: " .. tostring(mapIndex))
+    CHAT_SYSTEM:AddMessage("Map Zone Index: " .. tostring(mapZoneIndex))
+    CHAT_SYSTEM:AddMessage("Map W/H: " .. tostring(mapWidth) .. ', ' .. tostring(mapHeight))
+    CHAT_SYSTEM:AddMessage("Map Type: " .. tostring(mapType))
+    CHAT_SYSTEM:AddMessage("Map Content Type: " .. tostring(mapContentType))
+    CHAT_SYSTEM:AddMessage("Floor Cur/Num: " .. tostring(mapCurrentFloor) .. ', ' .. tostring(mapNumFloors))
+    CHAT_SYSTEM:AddMessage("Map Name: " .. tostring(mapName))
+    CHAT_SYSTEM:AddMessage("Target X/Y/H: " .. tostring(targetX) .. ', ' .. tostring(targetY) .. ', ' .. tostring(targetH))
+    CHAT_SYSTEM:AddMessage("Target X/Y/H: " .. tostring(selfX) .. ', ' .. tostring(selfY) .. ', ' .. tostring(selfH))
+
+    local dimensionsX, dimensionsY = ZO_WorldMapContainer:GetDimensions()
+    CHAT_SYSTEM:AddMessage("WMDimensions: " .. tostring(dimensionsX) .. ', ' .. tostring(dimensionsY))
+    local dimensionsX1, dimensionsY1 = ZO_WorldMapContainer1:GetDimensions()
+    CHAT_SYSTEM:AddMessage("1Dimensions: " .. tostring(dimensionsX1) .. ', ' .. tostring(dimensionsY1))
+end
+
 -- Reticle hidden update
 local function OnReticleHiddenUpdate(event)
     local reticleHidden = IsReticleHidden()
diff --git a/RangeReticle.txt b/RangeReticle.txt
index ba148c2..f4e3ed0 100755
--- a/RangeReticle.txt
+++ b/RangeReticle.txt
@@ -1,12 +1,12 @@
 ## Title: Range Reticle - by Adein
-## APIVersion: 100004
+## APIVersion: 100005
 ## Version: @project-version@
 ## Author: Adein
-## OptionalDependsOn: LibAddonMenu-1.0
+## OptionalDependsOn: LibAddonMenu-2.0
 ## SavedVariables: Range_ReticleDB

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

 RangeReticle.lua
 RangeReticle.xml
diff --git a/libs/LibAddonMenu-1.0/LibAddonMenu-1.0.lua b/libs/LibAddonMenu-1.0/LibAddonMenu-1.0.lua
deleted file mode 100755
index 7e382b1..0000000
--- a/libs/LibAddonMenu-1.0/LibAddonMenu-1.0.lua
+++ /dev/null
@@ -1,373 +0,0 @@
-local MAJOR, MINOR = "LibAddonMenu-1.0", 6
-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
-
---maybe return the controls from the creation functions?
-
-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]
-	ZO_PreHook("ZO_OptionsWindow_ChangePanels", function(panel)
-			local enable = (panel ~=  panelID)
-			ZO_OptionsWindowResetToDefaultButton:SetEnabled(enable)
-			ZO_OptionsWindowResetToDefaultButton:SetKeybindEnabled(enable)
-		end)
-
-	return panelID
-end
-
-function lam:AddHeader(panelID, controlName, text)
-	local header = wm:CreateControlFromVirtual(controlName, 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)
-	end
-	header.controlType = OPTIONS_SECTION_TITLE
-	header.panel = panelID
-	header.text = text
-
-	ZO_OptionsWindow_InitializeControl(header)
-
-	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 slider = wm:CreateControlFromVirtual(controlName, optionsWindow, "ZO_Options_Slider")
-	slider:SetAnchor(TOPLEFT, lastAddedControl[panelID], BOTTOMLEFT, 0, 6)
-	slider.controlType = OPTIONS_SLIDER
-	slider.system = SETTING_TYPE_UI
-	slider.panel = 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)
-
-	lastAddedControl[panelID] = slider
-
-	return slider
-end
-
-function lam:AddDropdown(panelID, controlName, text, tooltip, validChoices, getFunc, setFunc, warning, warningText)
-	local dropdown = wm:CreateControlFromVirtual(controlName, optionsWindow, "ZO_Options_Dropdown")
-	dropdown:SetAnchor(TOPLEFT, lastAddedControl[panelID], BOTTOMLEFT, 0, 6)
-	dropdown.controlType = OPTIONS_DROPDOWN
-	dropdown.system = SETTING_TYPE_UI
-	dropdown.panel = 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)
-
-	lastAddedControl[panelID] = dropdown
-
-	return dropdown
-end
-
-function lam:AddCheckbox(panelID, controlName, text, tooltip, getFunc, setFunc, warning, warningText)
-	local checkbox = wm:CreateControlFromVirtual(controlName, 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 = 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)
-
-	lastAddedControl[panelID] = checkbox
-
-	return checkbox
-end
-
-function lam:AddColorPicker(panelID, controlName, text, tooltip, getFunc, setFunc, warning, warningText)
-	local colorpicker = wm:CreateTopLevelWindow(controlName)
-	colorpicker:SetParent(optionsWindow)
-	colorpicker:SetAnchor(TOPLEFT, lastAddedControl[panelID], BOTTOMLEFT, 0, 10)
-	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 = 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)
-
-	lastAddedControl[panelID] = colorpicker
-
-	return colorpicker
-end
-
-function lam:AddEditBox(panelID, controlName, text, tooltip, isMultiLine, getFunc, setFunc, warning, warningText)
-	local editbox = wm:CreateTopLevelWindow(controlName)
-	editbox:SetParent(optionsWindow)
-	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.panel = 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)
-
-	lastAddedControl[panelID] = editbox
-
-	return editbox
-end
-
-function lam:AddButton(panelID, controlName, text, tooltip, onClick, warning, warningText)
-	local button = wm:CreateTopLevelWindow(controlName)
-	button:SetParent(optionsWindow)
-	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 = 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)
-
-	lastAddedControl[panelID] = button
-
-	return button
-end
-
-function lam:AddDescription(panelID, controlName, text, titleText)
-	local textBox = wm:CreateTopLevelWindow(controlName)
-	textBox:SetParent(optionsWindow)
-	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 = panelID
-
-	ZO_OptionsWindow_InitializeControl(textBox)
-
-	lastAddedControl[panelID] = textBox
-
-	return textBox
-end
-
-
---test controls & examples--
---[[local controlPanelID = lam:CreateControlPanel("ZAM_ADDON_OPTIONS", "ZAM Addons")
-lam:AddHeader(controlPanelID, "ZAM_Addons_TESTADDON", "TEST ADDON")
-lam:AddDescription(controlPanelID, "ZAM_Addons_TESTDESC", "This is a test description.", "Header")
-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..1ab94cf
--- /dev/null
+++ b/libs/LibAddonMenu-2.0/LibAddonMenu-2.0.lua
@@ -0,0 +1,322 @@
+--	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", 16
+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 = {}
+lam.widgets = lam.widgets or {}
+local widgets = lam.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)
+			KEYBOARD_OPTIONS:ChangePanels(lam.panelID)
+			--if not lam.panelSubCategoryControl then
+			--	lam.panelSubCategoryControl = _G["ZO_GameMenu_InGameNavigationContainerScrollChildZO_GameMenu_SubCategory"..(lam.panelID + 1)]
+			--end
+			--ZO_TreeEntry_OnMouseUp(lam.panelSubCategoryControl, true)
+			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(self, panel)
+	if panel == lam.panelID then	--our addon settings panel
+		oldDefaultButton:SetCallback(dummyFunc)
+		oldDefaultButton:SetHidden(true)
+		oldDefaultButton:SetAlpha(0)	--just because it still bugs out
+		panelWindow:SetDimensions(999, 960)
+		bgL:SetWidth(666)
+		bgR:SetWidth(333)
+	else
+		local shown = LAMAddonPanelsMenu.currentlySelected
+		if shown then shown:SetHidden(true) end
+		oldDefaultButton:SetCallback(oldCallback)
+		oldDefaultButton:SetHidden(false)
+		oldDefaultButton:SetAlpha(1)
+		panelWindow:SetDimensions(768, 914)
+		bgL:SetWidth(512)
+		bgR:SetWidth(256)
+	end
+end
+
+
+--INTERNAL FUNCTION
+--creates LAM's Addon Settings panel
+local function CreateAddonSettingsPanel()
+	if not LAMSettingsPanelCreated then
+		local controlPanelID = "LAM_ADDON_SETTINGS_PANEL"
+		--Russian for TERAB1T's RuESO addon, which creates an "ru" locale
+		--game font does not support Cyrillic, so they are using custom fonts + extended latin charset
+		--Spanish provided by Luisen75 for their translation project
+		local controlPanelNames = {
+			en = "Addon Settings",
+			fr = "Extensions",
+			de = "Erweiterungen",
+			ru = "Îacòpoéêè äoïoìîeîèé",
+			es = "Configura Addons",
+		}
+
+		ZO_OptionsWindow_AddUserPanel(controlPanelID, controlPanelNames[GetCVar("Language.2")] or controlPanelName["en"])
+
+		lam.panelID = _G[controlPanelID]
+
+		--ZO_PreHook("ZO_OptionsWindow_ChangePanels", HandlePanelSwitching)
+		ZO_PreHook(ZO_SharedOptions, "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.scrollChild, "ZO_DefaultTextButton")
+		button.name = addons[i].name
+		button.panel = _G[addons[i].panel]
+		button:SetText(button.name)
+		button:SetHorizontalAlignment(TEXT_ALIGN_LEFT)
+		button:SetWidth(190)
+		if i == 1 then
+			button:SetAnchor(TOPLEFT, list.scrollChild, TOPLEFT, 5, 5)
+		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)
+
+	list.scrollChild = LAMAddonPanelsMenuScrollChild
+	list.scrollChild:SetResizeToFitPadding(0, 15)
+
+	local generatedButtons
+	list:SetHandler("OnShow", function(self)
+			if not generatedButtons and #addonsForList > 0 then
+				--we're about to show our list for the first time - let's sort the buttons before creating them
+				table.sort(addonsForList, function(a, b)
+						return a.name < b.name
+					end)
+				CreateAddonButtons(list, addonsForList)
+				self.currentlySelected = LAMAddonMenuButton1 and LAMAddonMenuButton1.panel
+				--since our addon panels don't have a parent, let's make sure they hide when we're done with them
+				ZO_PreHookHandler(ZO_OptionsWindow, "OnHide", function() self.currentlySelected:SetHidden(true) end)
+				generatedButtons = true
+			end
+			if self.currentlySelected then self.currentlySelected:SetHidden(false) end
+		end)
+
+	--list.controlType = OPTIONS_CUSTOM
+	--list.panel = lam.panelID
+	list.data = {
+		controlType = OPTIONS_CUSTOM,
+		panel = lam.panelID,
+	}
+
+	ZO_OptionsWindow_InitializeControl(list)
+
+	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..187e901
--- /dev/null
+++ b/libs/LibAddonMenu-2.0/controls/button.lua
@@ -0,0 +1,89 @@
+--[[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 = 5
+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 or parent)
+
+	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.data = {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
+		control.warning.data = {tooltipText = buttonData.warning}
+	end
+
+	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
+	control.data = buttonData
+
+	if buttonData.disabled then
+		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..a777c7d
--- /dev/null
+++ b/libs/LibAddonMenu-2.0/controls/checkbox.lua
@@ -0,0 +1,172 @@
+--[[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 = 7
+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 or parent)
+	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
+		control.warning.data = {tooltipText = checkboxData.warning}
+	end
+
+	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
+	control.data = checkboxData
+	control.data.tooltipText = checkboxData.tooltip
+
+	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..abd9ba4
--- /dev/null
+++ b/libs/LibAddonMenu-2.0/controls/colorpicker.lua
@@ -0,0 +1,140 @@
+--[[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 = {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])
+	reference = "MyAddonColorpicker"	--(optional) unique global reference to control
+}	]]
+
+
+local widgetVersion = 5
+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 or parent)
+	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
+		control.warning.data = {tooltipText = colorpickerData.warning}
+	end
+
+	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
+	control.data = colorpickerData
+	control.data.tooltipText = colorpickerData.tooltip
+
+	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..54c9775
--- /dev/null
+++ b/libs/LibAddonMenu-2.0/controls/custom.lua
@@ -0,0 +1,45 @@
+--[[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)
+}	]]
+
+local widgetVersion = 4
+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
+end
+
+function LAMCreateControl.custom(parent, customData, controlName)
+	local control = wm:CreateTopLevelWindow(controlName or customData.reference)
+	control:SetResizeToFitDescendents(true)
+	control:SetParent(parent.scroll or parent)
+
+	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
+
+	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
diff --git a/libs/LibAddonMenu-2.0/controls/description.lua b/libs/LibAddonMenu-2.0/controls/description.lua
new file mode 100644
index 0000000..5d7219d
--- /dev/null
+++ b/libs/LibAddonMenu-2.0/controls/description.lua
@@ -0,0 +1,67 @@
+--[[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 = 4
+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(control.data.title)
+	end
+	control.desc:SetText(control.data.text)
+end
+
+function LAMCreateControl.description(parent, descriptionData, controlName)
+	local control = wm:CreateTopLevelWindow(controlName or descriptionData.reference)
+	control:SetResizeToFitDescendents(true)
+	control:SetParent(parent.scroll or parent)
+	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
+
+	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
diff --git a/libs/LibAddonMenu-2.0/controls/dropdown.lua b/libs/LibAddonMenu-2.0/controls/dropdown.lua
new file mode 100644
index 0000000..94cd820
--- /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 = 7
+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 or parent)
+	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(225, 26)
+		combobox:SetAnchor(TOPRIGHT, label, BOTTOMRIGHT)
+	else
+		control:SetDimensions(510, 30)
+		label:SetDimensions(300, 26)
+		combobox:SetDimensions(200, 26)
+		combobox:SetAnchor(TOPRIGHT)
+	end
+
+	if dropdownData.warning then
+		control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
+		control.warning:SetAnchor(RIGHT, combobox, LEFT, -5, 0)
+		--control.warning.tooltipText = dropdownData.warning
+		control.warning.data = {tooltipText = dropdownData.warning}
+	end
+
+	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
+	control.data = dropdownData
+	control.data.tooltipText = dropdownData.tooltip
+
+	if dropdownData.disabled then
+		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..0d273d3
--- /dev/null
+++ b/libs/LibAddonMenu-2.0/controls/editbox.lua
@@ -0,0 +1,155 @@
+--[[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 = 6
+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 or parent)
+	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
+		control.warning.data = {tooltipText = editboxData.warning}
+	end
+
+	control.panel = parent.panel or parent	--if this is in a submenu, panel is its parent
+	control.data = editboxData
+	control.data.tooltipText = editboxData.tooltip
+
+	if editboxData.disabled then
+		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..bbf2c60
--- /dev/null
+++ b/libs/LibAddonMenu-2.0/controls/header.lua
@@ -0,0 +1,47 @@
+--[[headerData = {
+	type = "header",
+	name = "My Header",
+	width = "full",	--or "half" (optional)
+	reference = "MyAddonHeader"	--(optional) unique global reference to control
+}	]]
+
+
+local widgetVersion = 4
+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(control.data.name)
+end
+
+function LAMCreateControl.header(parent, headerData, controlName)
+	local control = wm:CreateTopLevelWindow(controlName or headerData.reference)
+	control:SetParent(parent.scroll or parent)
+	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
+
+	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
diff --git a/libs/LibAddonMenu-2.0/controls/panel.lua b/libs/LibAddonMenu-2.0/controls/panel.lua
new file mode 100644
index 0000000..5f9f41b
--- /dev/null
+++ b/libs/LibAddonMenu-2.0/controls/panel.lua
@@ -0,0 +1,138 @@
+--[[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 = 8
+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 callbackRegistered = false
+LAMCreateControl.scrollCount = LAMCreateControl.scrollCount or 1
+function LAMCreateControl.panel(parent, panelData, controlName)
+	local control = wm:CreateTopLevelWindow(controlName)
+	control:SetParent(parent)
+
+	control.bg = wm:CreateControl(nil, control, CT_BACKDROP)
+	local bg = control.bg
+	bg:SetAnchorFill()
+	bg:SetEdgeTexture("EsoUI\\Art\\miscellaneous\\borderedinsettransparent_edgefile.dds", 128, 16)
+	bg:SetCenterColor(0, 0, 0, 0)
+
+	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"..LAMCreateControl.scrollCount, control, "ZO_ScrollContainer")
+	LAMCreateControl.scrollCount = LAMCreateControl.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 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
\ 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..f7ab0a3
--- /dev/null
+++ b/libs/LibAddonMenu-2.0/controls/slider.lua
@@ -0,0 +1,184 @@
+--[[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 = 5
+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 or parent)
+	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
+		control.warning.data = {tooltipText = sliderData.warning}
+	end
+
+	control.panel = parent.panel or parent	--if this is in a submenu, panel is the submenu's parent
+	control.data = sliderData
+	control.data.tooltipText = sliderData.tooltip
+
+	if sliderData.disabled then
+		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..761dda5
--- /dev/null
+++ b/libs/LibAddonMenu-2.0/controls/submenu.lua
@@ -0,0 +1,123 @@
+--[[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 = 7
+local LAM = LibStub("LibAddonMenu-2.0")
+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(control.data.name)
+	if control.data.tooltip then
+		--control.label.tooltipText = control.data.tooltip
+		control.label.data = {tooltipText = 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
+end
+
+
+function LAMCreateControl.submenu(parent, submenuData, controlName)
+	local control = wm:CreateTopLevelWindow(controlName or submenuData.reference)
+	control:SetParent(parent.scroll or parent)
+	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.data = {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)
+
+	--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.data = submenuData
+
+	control.UpdateValue = UpdateValue
+
+	if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then	--if our parent window wants to refresh controls, then add this to the list
+		tinsert(control.panel.controlsToRefresh, control)
+	end
+
+	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..928ab82
--- /dev/null
+++ b/libs/LibAddonMenu-2.0/controls/texture.lua
@@ -0,0 +1,51 @@
+--[[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 = 5
+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 or parent)
+
+	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.data = {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
diff --git a/libs/LibStub/LibStub.lua b/libs/LibStub/LibStub.lua
old mode 100755
new mode 100644
index bfd96df..879d132
--- a/libs/LibStub/LibStub.lua
+++ b/libs/LibStub/LibStub.lua
@@ -3,7 +3,7 @@
 -- LibStub developed for World of Warcraft by above members of the WowAce community.
 -- Ported to Elder Scrolls Online by Seerah

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

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

 	function LibStub:GetLibrary(major, silent)
 		if not self.libs[major] and not silent then
-			error(("Cannot find a library instance of %q."):strformat(tostring(major)), 2)
+			error(strformat("Cannot find a library instance of %q.", tostring(major)), 2)
 		end
 		return self.libs[major], self.minors[major]
 	end