Quantcast

- Update Ace to r1390

urnati [05-04-26 - 19:53]
- Update Ace to r1390
- Config : 'fix' for profile delete
Filename
Titan/Titan.lua
Titan/Titan.toc
Titan/TitanConfig.lua
Titan/_Titan_Lib_Notes.txt
Titan/libs/Ace/Ace3.toc
Titan/libs/Ace/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua
Titan/libs/Ace/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua
Titan/libs/Ace/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua
Titan/libs/Ace/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua
Titan/libs/Ace/CHANGES.txt
Titan/libs/Ace/LibQTip-1.0/CHANGELOG.md
Titan/libs/Ace/LibQTip-1.0/LICENSE.txt
Titan/libs/Ace/LibQTip-1.0/LibQTip-1.0.lua
Titan/libs/Ace/LibQTip-1.0/LibQTip-1.0.toc
Titan/libs/Ace/LibQTip-1.0/LibStub/LibStub.lua
Titan/libs/Ace/LibQTip-1.0/README.md
Titan/libs/Ace/LibQTip-1.0/lib.xml
Titan/libs/Ace/changelog.txt
Titan/libs/LibQTip-1.0/CHANGELOG.md
Titan/libs/LibQTip-1.0/LICENSE.txt
Titan/libs/LibQTip-1.0/LibQTip-1.0.lua
Titan/libs/LibQTip-1.0/LibQTip-1.0.toc
Titan/libs/LibQTip-1.0/LibStub/LibStub.lua
Titan/libs/LibQTip-1.0/README.md
Titan/libs/LibQTip-1.0/lib.xml
TitanPost/TitanPost.lua
TitanUI/Tools.lua
diff --git a/Titan/Titan.lua b/Titan/Titan.lua
index 698b4ad..7d10a9c 100644
--- a/Titan/Titan.lua
+++ b/Titan/Titan.lua
@@ -916,7 +916,7 @@ local function handle_profile_cmds(cmd_list)
 	if (not cmd == "profile") then
 		return
 	end
-	AceConfigDialog:Open("Titan Panel Addon Chars")
+	AceConfigDialog:Open("Titan Panel Addon Profiles")
 end

 ---local Helper to handle 'silent' commands - Toggle "Silenced" setting.
@@ -2312,7 +2312,7 @@ local function GeneratorFunction(owner, rootDescription)
 	Titan_Menu.AddCommand(root, id, L["TITAN_PANEL_MENU_PROFILES"] .. " " .. L["TITAN_PANEL_MENU_CONFIGURATION"],
 		function()
 			TitanUpdateConfig("init")
-			AceConfigDialog:Open("Titan Panel Addon Chars")
+			AceConfigDialog:Open("Titan Panel Addon Profiles")
 		end
 	)

diff --git a/Titan/Titan.toc b/Titan/Titan.toc
index 1577b85..56ffd30 100644
--- a/Titan/Titan.toc
+++ b/Titan/Titan.toc
@@ -36,7 +36,7 @@ libs\Ace\AceGUI-3.0\AceGUI-3.0.xml
 libs\Ace\AceConfig-3.0\AceConfig-3.0.xml
 libs\Ace\AceLocale-3.0\AceLocale-3.0.xml
 libs\LibSharedMedia-3.0\lib.xml
-libs\Ace\LibQTip-1.0\lib.xml
+libs\LibQTip-1.0\lib.xml

 libs\LibDeflate\LibDeflate.lua
 libs\LibDataBroker-1.1.lua
diff --git a/Titan/TitanConfig.lua b/Titan/TitanConfig.lua
index 8802466..9cf0550 100644
--- a/Titan/TitanConfig.lua
+++ b/Titan/TitanConfig.lua
@@ -1206,14 +1206,7 @@ end

 --============= Profiles

----local Allow the user to load / delete / reset / sync profile data
----@param pos number Order of options
----@return table Config options
-local function CreateProfiles(pos)
-	--		AceConfigRegistry:NotifyChange("Titan Panel Addon Chars")
-	local p_info = {} -- used to hold info about each toon in players
-	local p_sync = {} -- profiles used as Sync
-
+local function GenProfileInfo(p_info, p_sync)
 	-- Rip through the players (with server name) to sort them
 	for index, id in TitanUtils_PlayerIter() do
 		-- collect some info on THIS toon for the config
@@ -1260,6 +1253,17 @@ local function CreateProfiles(pos)
 	table.sort(p_info, function(a, b)
 		return a.name < b.name
 	end)
+end
+
+---local Allow the user to load / delete / reset / sync profile data
+---@param pos number Order of options
+---@return table Config options
+local function CreateProfiles(pos)
+	--		AceConfigRegistry:NotifyChange("Titan Panel Addon Profiles")
+	local p_info = {} -- used to hold info about each toon in players
+	local p_sync = {} -- profiles used as Sync
+
+	GenProfileInfo(p_info, p_sync)

 	local opts = {}
 	opts.name = Config_locale.topic.profiles
@@ -1442,7 +1446,7 @@ local function CreateProfiles(pos)
 									L["TITAN_PANEL_MENU_POST_CLEAR_DESC"]
 									.. " > " .. this_toon.name .. ""
 									, "info")
-								AceConfigRegistry:NotifyChange("Titan Panel Addon Chars")
+								AceConfigRegistry:NotifyChange("Titan Panel Addon Profiles")
 							end,
 							-- Should be able to clear any specific toon info
 							--disabled = (this_toon.is_player or g_sync),
@@ -1499,7 +1503,7 @@ local function CreateProfiles(pos)
 						L["TITAN_PANEL_MENU_LOAD_SETTINGS"]
 						.. " > " .. this_toon.name .. ""
 						, "info")
-					AceConfigRegistry:NotifyChange("Titan Panel Addon Chars")
+					AceConfigRegistry:NotifyChange("Titan Panel Addon Profiles")
 				end,
 				-- does not make sense to load current character profile
 				disabled = (this_toon.is_player or g_sync),
@@ -1530,8 +1534,13 @@ local function CreateProfiles(pos)
 						.. "  " .. this_toon.name .. " "
 						.. L["TITAN_PANEL_MENU_PROFILE_DELETED"]
 						, "info")
-					--TitanUpdateChars() -- rebuild the toons
-					AceConfigRegistry:NotifyChange("Titan Panel Addon Chars")
+					-- bit of a hammer but trying to get Ace to reflect changes is not working...
+					C_Timer.After(0.1, function()
+---@diagnostic disable-next-line: param-type-mismatch
+						C_Timer.After(0.1, AceConfigDialog:CloseAll())
+						end)
+					--CreateProfiles(120) -- rebuild the toons
+					--AceConfigRegistry:NotifyChange(config_parent)
 				end,
 				-- can not delete current character profile
 				disabled = (this_toon.is_player
@@ -1589,7 +1598,7 @@ local function CreateProfiles(pos)
 						, "info")

 					--TitanUpdateChars()
-					AceConfigRegistry:NotifyChange("Titan Panel Addon Chars")
+					AceConfigRegistry:NotifyChange("Titan Panel Addon Profiles")
 				end,
 				disabled = not (this_toon.is_player),
 			}
@@ -1612,7 +1621,7 @@ local function CreateProfiles(pos)
 				func = function(info, v)
 					TitanPanel_SaveCustomProfile(this_toon.name) -- will output message on write
 					--TitanUpdateChars()            -- rebuild the toons
-					AceConfigRegistry:NotifyChange("Titan Panel Addon Chars")
+					AceConfigRegistry:NotifyChange("Titan Panel Addon Profiles")
 				end,
 			}
 			position = position + 1
@@ -1668,7 +1677,7 @@ local function CreateProfiles(pos)
 					--				TitanVariables_UseSettings(nil, this_toon.name, TITAN_PROFILE_USE)
 					TitanVariables_UseSettings(nil, TitanUtils_GetPlayer(), TITAN_PROFILE_USE)
 					--TitanUpdateChars()
-					AceConfigRegistry:NotifyChange("Titan Panel Addon Chars")
+					AceConfigRegistry:NotifyChange("Titan Panel Addon Profiles")
 				end,
 				-- cannot sync to yourself or if sync already set
 				disabled = (this_toon.is_player or this_toon.sync_set or g_sync),
@@ -1704,7 +1713,7 @@ local function CreateProfiles(pos)
 						, "info")

 					--TitanUpdateChars()
-					AceConfigRegistry:NotifyChange("Titan Panel Addon Chars")
+					AceConfigRegistry:NotifyChange("Titan Panel Addon Profiles")
 				end,
 				disabled = (not this_toon.sync_set) or g_sync,
 			}
@@ -1757,7 +1766,7 @@ local function CreateProfiles(pos)
 					-- Change over to new profile
 					TitanVariables_UseSettings(nil, TitanUtils_GetPlayer(), TITAN_PROFILE_USE)
 					--TitanUpdateChars()
-					AceConfigRegistry:NotifyChange("Titan Panel Addon Chars")
+					AceConfigRegistry:NotifyChange("Titan Panel Addon Profiles")
 				end,
 				-- Can allows set global sync
 				--disabled = this_toon.is_player or this_toon.sync_set,
@@ -1786,7 +1795,7 @@ local function CreateProfiles(pos)
 					TitanVariables_UseSettings(nil, TitanUtils_GetPlayer(), TITAN_PROFILE_USE)

 					--TitanUpdateChars()
-					AceConfigRegistry:NotifyChange("Titan Panel Addon Chars")
+					AceConfigRegistry:NotifyChange("Titan Panel Addon Profiles")
 				end,
 				disabled = (not g_sync),
 			}
@@ -3602,7 +3611,7 @@ local function BuiltTitanStructure()
 	titan_options.args.optionsAddons = CreateConfigAddons(90)
 	titan_options.args.optionsAddonAttempts = CreateAddonAttempts(100)
 	titan_options.args.optionsExtras = CreateExtras(110)
-	titan_options.args.optionsChars = CreateProfiles(120)
+	titan_options.args.optionsProfiles = CreateProfiles(120)
 	titan_options.args.optionsImportExport = CreateImportExportList(130)
 	titan_options.args.optionsAdvanced = CreateAdvanced(140)
 	titan_options.args.changeHistory = CreateHistory(150)
@@ -3655,7 +3664,7 @@ local function BuildAll()
 		AceConfig:RegisterOptionsTable("Titan Panel Addon Control", titan_options.args.optionsAddons)
 		AceConfig:RegisterOptionsTable("Titan Panel Addon Attempts", titan_options.args.optionsAddonAttempts)
 		AceConfig:RegisterOptionsTable("Titan Panel Addon Extras", titan_options.args.optionsExtras)
-		AceConfig:RegisterOptionsTable("Titan Panel Addon Chars", titan_options.args.optionsChars)
+		AceConfig:RegisterOptionsTable("Titan Panel Addon Profiles", titan_options.args.optionsProfiles)
 		AceConfig:RegisterOptionsTable("Titan Panel Addon Im_Ex", titan_options.args.optionsImportExport)
 		AceConfig:RegisterOptionsTable("Titan Panel Addon Advanced", titan_options.args.optionsAdvanced)
 		AceConfig:RegisterOptionsTable("Titan Panel Addon Changes", titan_options.args.changeHistory)
@@ -3684,7 +3693,7 @@ local function BuildAll()
 			AceConfigDialog:AddToBlizOptions("Titan Panel Adjust", titan_options.args.optionsAdjust.name, config_parent)
 			AceConfigDialog:AddToBlizOptions("Titan Panel Addon Control", titan_options.args.optionsAddons.name,
 				config_parent)
-			AceConfigDialog:AddToBlizOptions("Titan Panel Addon Chars", titan_options.args.optionsChars.name,
+			AceConfigDialog:AddToBlizOptions("Titan Panel Addon Profiles", titan_options.args.optionsProfiles.name,
 				config_parent)
 			AceConfigDialog:AddToBlizOptions("Titan Panel Addon Im_Ex", titan_options.args.optionsImportExport.name,
 				config_parent)
@@ -3741,7 +3750,7 @@ function TitanUpdateConfig(action)
 		AceConfig:RegisterOptionsTable("Titan Panel Addon Control", nuked)
 		AceConfig:RegisterOptionsTable("Titan Panel Addon Attempts", nuked)
 		AceConfig:RegisterOptionsTable("Titan Panel Addon Extras", nuked)
-		AceConfig:RegisterOptionsTable("Titan Panel Addon Chars", nuked)
+		AceConfig:RegisterOptionsTable("Titan Panel Addon Profiles", nuked)
 		AceConfig:RegisterOptionsTable("Titan Panel Addon Advanced", nuked)
 		AceConfig:RegisterOptionsTable("Titan Panel Addon Changes", nuked)
 		AceConfig:RegisterOptionsTable("Titan Panel Addon Slash", nuked)
diff --git a/Titan/_Titan_Lib_Notes.txt b/Titan/_Titan_Lib_Notes.txt
index 0dd0bb4..0cf0990 100644
--- a/Titan/_Titan_Lib_Notes.txt
+++ b/Titan/_Titan_Lib_Notes.txt
@@ -1,14 +1,27 @@
 From:
 Ace3 - https://www.curseforge.com/wow/addons/ace3
+- AceAddon
+- AceConfig
+- AceGUI
+- AceHook
+- AceLocale
+- AceSerializer
+- AceTimer
+- CallbackHandler
+- LibStib
+- and Ace files (.toc plus)

 LibQTip-1.0 - https://www.curseforge.com/wow/addons/libqtip-1-0
 LibSharedMedia-3.0 - https://www.wowace.com/projects/libsharedmedia-3-0 : https://www.curseforge.com/wow/addons/libsharedmedia-3-0


+*** 2026-May ****
+- Ace update from Release-r1390 2026-02-03
+- Moved LibQTip from /Ace to /libs
+
 *** 2025-Nov ****
 - Ace update from Release-r1377 2024-10-28

-
 *** 2025-Sep*
 - Dropped !LibUIDropDownMenu, again; updated wrappers to Blizz version
 LibUIDropDownMenu - https://www.curseforge.com/wow/addons/libuidropdownmenu
diff --git a/Titan/libs/Ace/Ace3.toc b/Titan/libs/Ace/Ace3.toc
index b0d60df..8669440 100644
--- a/Titan/libs/Ace/Ace3.toc
+++ b/Titan/libs/Ace/Ace3.toc
@@ -1,4 +1,4 @@
-## Interface: 11508, 11507, 20504, 30405, 40402, 50501, 50502, 110205, 110207, 120000
+## Interface: 11508, 11507, 20505, 30405, 38000, 40402, 50503, 50502, 120001, 110207, 120000

 ## Title: Lib: Ace3
 ## Notes: AddOn development framework
@@ -6,7 +6,7 @@
 ## X-Website: http://www.wowace.com
 ## X-Category: Library
 ## X-License: Limited BSD
-## Version: Release-r1377
+## Version: Release-r1390

 LibStub\LibStub.lua
 CallbackHandler-1.0\CallbackHandler-1.0.xml
diff --git a/Titan/libs/Ace/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua b/Titan/libs/Ace/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua
index 904458a..4558a8e 100644
--- a/Titan/libs/Ace/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua
+++ b/Titan/libs/Ace/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua
@@ -1,13 +1,13 @@
 --- AceConfigDialog-3.0 generates AceGUI-3.0 based windows based on option tables.
 -- @class file
 -- @name AceConfigDialog-3.0
--- @release $Id: AceConfigDialog-3.0.lua 1372 2025-10-05 05:38:34Z nevcairiel $
+-- @release $Id: AceConfigDialog-3.0.lua 1386 2025-12-11 18:25:02Z nevcairiel $

 local LibStub = LibStub
 local gui = LibStub("AceGUI-3.0")
 local reg = LibStub("AceConfigRegistry-3.0")

-local MAJOR, MINOR = "AceConfigDialog-3.0", 89
+local MAJOR, MINOR = "AceConfigDialog-3.0", 92
 local AceConfigDialog, oldminor = LibStub:NewLibrary(MAJOR, MINOR)

 if not AceConfigDialog then return end
@@ -1083,6 +1083,11 @@ local function InjectInfo(control, options, option, path, rootframe, appName)
 	control:SetCallback("OnRelease", CleanUserData)
 	control:SetCallback("OnLeave", OptionOnMouseLeave)
 	control:SetCallback("OnEnter", OptionOnMouseOver)
+
+	-- forward custom arg data directly
+	if control.SetCustomData and option.arg then
+		safecall(control.SetCustomData, control, option.arg)
+	end
 end

 local function CreateControl(userControlType, fallbackControlType)
@@ -1436,12 +1441,15 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
 				if control then
 					if control.width ~= "fill" then
 						local width = GetOptionsMemberValue("width",v,options,path,appName)
+						local relWidth = GetOptionsMemberValue("relWidth",v,options,path,appName)
 						if width == "double" then
 							control:SetWidth(width_multiplier * 2)
 						elseif width == "half" then
 							control:SetWidth(width_multiplier / 2)
 						elseif (type(width) == "number") then
 							control:SetWidth(width_multiplier * width)
+						elseif width == "relative" and relWidth then
+							control:SetRelativeWidth(relWidth)
 						elseif width == "full" then
 							control.width = "fill"
 						else
@@ -1945,6 +1953,8 @@ else
 	AceConfigDialog.BlizOptions = AceConfigDialog.BlizOptions or {}
 end

+AceConfigDialog.BlizOptionsIDMap = AceConfigDialog.BlizOptionsIDMap or {}
+
 local function FeedToBlizPanel(widget, event)
 	local path = widget:GetUserData("path")
 	AceConfigDialog:Open(widget:GetUserData("appName"), widget, unpack(path or emptyTbl))
@@ -1966,16 +1976,17 @@ end
 -- has to be a head-level note.
 --
 -- This function returns a reference to the container frame registered with the Interface
--- Options. You can use this reference to open the options with the API function
--- `InterfaceOptionsFrame_OpenToCategory`.
+-- Options, as well as the registered ID. You can use the ID to open the options with
+-- the API function `Settings.OpenToCategory`.
 -- @param appName The application name as given to `:RegisterOptionsTable()`
 -- @param name A descriptive name to display in the options tree (defaults to appName)
 -- @param parent The parent to use in the interface options tree.
 -- @param ... The path in the options table to feed into the interface options panel.
 -- @return The reference to the frame registered into the Interface Options.
--- @return The category ID to pass to Settings.OpenToCategory (or InterfaceOptionsFrame_OpenToCategory)
+-- @return The category ID to pass to Settings.OpenToCategory
 function AceConfigDialog:AddToBlizOptions(appName, name, parent, ...)
 	local BlizOptions = AceConfigDialog.BlizOptions
+	local BlizOptionsIDMap = AceConfigDialog.BlizOptionsIDMap

 	local key = appName
 	for n = 1, select("#", ...) do
@@ -2001,29 +2012,32 @@ function AceConfigDialog:AddToBlizOptions(appName, name, parent, ...)
 		end
 		group:SetCallback("OnShow", FeedToBlizPanel)
 		group:SetCallback("OnHide", ClearBlizPanel)
-		if Settings and Settings.RegisterCanvasLayoutCategory then
-			local categoryName = name or appName
-			if parent then
-				local category = Settings.GetCategory(parent)
-				if not category then
-					error(("The parent category '%s' was not found"):format(parent), 2)
-				end
-				local subcategory = Settings.RegisterCanvasLayoutSubcategory(category, group.frame, categoryName)

-				-- force the generated ID to be used for subcategories, as these can have very simple names like "Profiles"
-				group:SetName(subcategory.ID, parent)
-			else
-				local category = Settings.RegisterCanvasLayoutCategory(group.frame, categoryName)
-				-- using appName here would be cleaner, but would not be 100% compatible
-				-- but for top-level categories it should be fine, as these are typically addon names
-				category.ID = categoryName
-				group:SetName(categoryName, parent)
-				Settings.RegisterAddOnCategory(category)
+		local categoryName = name or appName
+		if parent then
+			local parentID = BlizOptionsIDMap[parent] or parent
+			local category = Settings.GetCategory(parentID)
+			if not category then
+				error(("The parent category '%s' was not found"):format(parent), 2)
 			end
+			local subcategory = Settings.RegisterCanvasLayoutSubcategory(category, group.frame, categoryName)
+			group:SetName(subcategory.ID, parentID)
 		else
-			group:SetName(name or appName, parent)
-			InterfaceOptions_AddCategory(group.frame)
+			if BlizOptionsIDMap[categoryName] then
+				error(("%s has already been added to the Blizzard Options Window with the given name: %s"):format(appName, categoryName), 2)
+			end
+
+			local category = Settings.RegisterCanvasLayoutCategory(group.frame, categoryName)
+			if not (C_SettingsUtil and C_SettingsUtil.OpenSettingsPanel) then
+				-- override the ID so the name can be used in Settings.OpenToCategory
+				-- unfortunately with incoming API changes in 12.0 (and likely classic at some point) this override is no longer possible
+				category.ID = categoryName
+			end
+			group:SetName(category.ID)
+			BlizOptionsIDMap[categoryName] = category.ID
+			Settings.RegisterAddOnCategory(category)
 		end
+
 		return group.frame, group.frame.name
 	else
 		error(("%s has already been added to the Blizzard Options Window with the given path"):format(appName), 2)
diff --git a/Titan/libs/Ace/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua b/Titan/libs/Ace/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua
index e0f5962..8adbe79 100644
--- a/Titan/libs/Ace/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua
+++ b/Titan/libs/Ace/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua
@@ -8,10 +8,10 @@
 -- :IterateOptionsTables() (and :GetOptionsTable() if only given one argument) return a function reference that the requesting config handling addon must call with valid "uiType", "uiName".
 -- @class file
 -- @name AceConfigRegistry-3.0
--- @release $Id: AceConfigRegistry-3.0.lua 1296 2022-11-04 18:50:10Z nevcairiel $
+-- @release $Id: AceConfigRegistry-3.0.lua 1385 2025-12-06 11:26:20Z nevcairiel $
 local CallbackHandler = LibStub("CallbackHandler-1.0")

-local MAJOR, MINOR = "AceConfigRegistry-3.0", 21
+local MAJOR, MINOR = "AceConfigRegistry-3.0", 22
 local AceConfigRegistry = LibStub:NewLibrary(MAJOR, MINOR)

 if not AceConfigRegistry then return end
@@ -92,6 +92,7 @@ local basekeys={
 	func=optmethodfalse,
 	arg={["*"]=true},
 	width=optstringnumber,
+	relWidth=optnumber,
 }

 local typedkeys={
diff --git a/Titan/libs/Ace/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua b/Titan/libs/Ace/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua
index 7900937..fef4557 100644
--- a/Titan/libs/Ace/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua
+++ b/Titan/libs/Ace/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua
@@ -2,7 +2,7 @@
 TreeGroup Container
 Container that uses a tree control to switch between groups.
 -------------------------------------------------------------------------------]]
-local Type, Version = "TreeGroup", 48
+local Type, Version = "TreeGroup", 49
 local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
 if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end

@@ -206,7 +206,7 @@ local function Button_OnEnter(frame)
 		tooltip:SetOwner(frame, "ANCHOR_NONE")
 		tooltip:ClearAllPoints()
 		tooltip:SetPoint("LEFT",frame,"RIGHT")
-		tooltip:SetText(frame.text:GetText() or "", 1, .82, 0, true)
+		tooltip:SetText(frame.text:GetText() or "", 1, .82, 0, 1, true)

 		tooltip:Show()
 	end
diff --git a/Titan/libs/Ace/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua b/Titan/libs/Ace/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua
index 0c779dc..ee5a83b 100644
--- a/Titan/libs/Ace/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua
+++ b/Titan/libs/Ace/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua
@@ -2,7 +2,7 @@
 Keybinding Widget
 Set Keybindings in the Config UI.
 -------------------------------------------------------------------------------]]
-local Type, Version = "Keybinding", 26
+local Type, Version = "Keybinding", 27
 local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
 if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end

@@ -31,12 +31,14 @@ local function Keybinding_OnClick(frame, button)
 		if self.waitingForKey then
 			frame:EnableKeyboard(false)
 			frame:EnableMouseWheel(false)
+			frame:EnableGamePadButton(false)
 			self.msgframe:Hide()
 			frame:UnlockHighlight()
 			self.waitingForKey = nil
 		else
 			frame:EnableKeyboard(true)
 			frame:EnableMouseWheel(true)
+			frame:EnableGamePadButton(true)
 			self.msgframe:Show()
 			frame:LockHighlight()
 			self.waitingForKey = true
@@ -72,6 +74,7 @@ local function Keybinding_OnKeyDown(frame, key)

 		frame:EnableKeyboard(false)
 		frame:EnableMouseWheel(false)
+		frame:EnableGamePadButton(false)
 		self.msgframe:Hide()
 		frame:UnlockHighlight()
 		self.waitingForKey = nil
@@ -119,6 +122,7 @@ local methods = {
 		self:SetDisabled(false)
 		self.button:EnableKeyboard(false)
 		self.button:EnableMouseWheel(false)
+		self.button:EnableGamePadButton(false)
 	end,

 	-- ["OnRelease"] = nil,
@@ -195,10 +199,12 @@ local function Constructor()
 	button:SetScript("OnKeyDown", Keybinding_OnKeyDown)
 	button:SetScript("OnMouseDown", Keybinding_OnMouseDown)
 	button:SetScript("OnMouseWheel", Keybinding_OnMouseWheel)
+	button:SetScript("OnGamePadButtonDown", Keybinding_OnKeyDown)
 	button:SetPoint("BOTTOMLEFT")
 	button:SetPoint("BOTTOMRIGHT")
 	button:SetHeight(24)
 	button:EnableKeyboard(false)
+	button:EnableGamePadButton(false)

 	local text = button:GetFontString()
 	text:SetPoint("LEFT", 7, 0)
diff --git a/Titan/libs/Ace/CHANGES.txt b/Titan/libs/Ace/CHANGES.txt
index 14b4f42..7cfb6ba 100644
--- a/Titan/libs/Ace/CHANGES.txt
+++ b/Titan/libs/Ace/CHANGES.txt
@@ -1,189 +1,113 @@
 ------------------------------------------------------------------------
-r1376 | nevcairiel | 2025-10-28 22:06:01 +0000 (Tue, 28 Oct 2025) | 1 line
+r1389 | nevcairiel | 2026-02-03 18:39:11 +0000 (Tue, 03 Feb 2026) | 1 line
 Changed paths:
    M /trunk/changelog.txt

 Update changelog
 ------------------------------------------------------------------------
-r1375 | funkehdude | 2025-10-24 04:07:54 +0000 (Fri, 24 Oct 2025) | 1 line
+r1388 | funkehdude | 2026-01-22 23:05:57 +0000 (Thu, 22 Jan 2026) | 1 line
 Changed paths:
-   M /trunk/Ace3.toc
-
-Bump toc
-------------------------------------------------------------------------
-r1374 | funkehdude | 2025-10-15 17:12:41 +0000 (Wed, 15 Oct 2025) | 1 line
-Changed paths:
-   M /trunk/Ace3.toc
+   M /trunk/.luacheckrc
+   M /trunk/AceTab-3.0/AceTab-3.0.lua

-Bump toc
+AceTab-3.0/AceTab-3.0: `NUM_CHAT_WINDOWS` was replaced by `Constants.ChatFrameConstants.MaxChatWindows`
 ------------------------------------------------------------------------
-r1373 | funkehdude | 2025-10-13 14:09:48 +0000 (Mon, 13 Oct 2025) | 1 line
+r1387 | funkehdude | 2026-01-13 16:57:21 +0000 (Tue, 13 Jan 2026) | 1 line
 Changed paths:
    M /trunk/Ace3.toc

 Bump toc
 ------------------------------------------------------------------------
-r1372 | nevcairiel | 2025-10-05 05:38:34 +0000 (Sun, 05 Oct 2025) | 1 line
+r1386 | nevcairiel | 2025-12-11 18:25:02 +0000 (Thu, 11 Dec 2025) | 5 lines
 Changed paths:
    M /trunk
    M /trunk/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua

-AceConfigDialog-3.0: Consistently provide an alpha value for GameTooltip:SetText
-------------------------------------------------------------------------
-r1371 | nevcairiel | 2025-10-03 10:25:33 +0000 (Fri, 03 Oct 2025) | 1 line
-Changed paths:
-   M /trunk
-   M /trunk/AceComm-3.0/ChatThrottleLib.lua
+AceConfigDialog-3.0: Forward the "arg" option table member to widgets

-ChatThrottleLib: Use C_BattleNet namespace, if available
+Widgets will receive the data through the SetCustomData function, if
+available, and can act on it as needed. This provides a clear lifecycle
+function before layout where the data is being made available.
 ------------------------------------------------------------------------
-r1370 | nevcairiel | 2025-10-03 00:16:25 +0000 (Fri, 03 Oct 2025) | 1 line
+r1385 | nevcairiel | 2025-12-06 11:26:20 +0000 (Sat, 06 Dec 2025) | 1 line
 Changed paths:
    M /trunk
-   M /trunk/.luacheckrc
+   M /trunk/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua
+   M /trunk/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua

-Update luacheck for chat changes
+AceConfig-3.0: Bump library versions for relative width support
 ------------------------------------------------------------------------
-r1369 | nevcairiel | 2025-10-02 23:56:28 +0000 (Thu, 02 Oct 2025) | 1 line
+r1384 | nevcairiel | 2025-12-06 10:23:20 +0000 (Sat, 06 Dec 2025) | 3 lines
 Changed paths:
    M /trunk
-   M /trunk/AceGUI-3.0/widgets/AceGUIWidget-EditBox.lua
-   M /trunk/AceGUI-3.0/widgets/AceGUIWidget-MultiLineEditBox.lua
+   M /trunk/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua

-AceGUI-3.0: EditBox: Fix InsertLink hook for 12.0
-------------------------------------------------------------------------
-r1368 | nevcairiel | 2025-10-02 23:52:43 +0000 (Thu, 02 Oct 2025) | 1 line
-Changed paths:
-   M /trunk
-   M /trunk/AceComm-3.0/ChatThrottleLib.lua
+AceGUI-3.0: Keybinding: Add gamepad support

-ChatThrottleLib: Properly use the right namespace for SendChatMessage
+Gamepad bindings are completely in line with the rest of the keybinding system in WoW, so all that's really necessary to make them work in AceGUI is to add a handler to catch bindings.
 ------------------------------------------------------------------------
-r1367 | funkehdude | 2025-09-08 17:06:01 +0000 (Mon, 08 Sep 2025) | 1 line
+r1383 | nevcairiel | 2025-12-06 10:19:35 +0000 (Sat, 06 Dec 2025) | 8 lines
 Changed paths:
+   M /trunk
    M /trunk/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua
+   M /trunk/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua

-AceConfigDialog-3.0: Remove untranslated text "Usage:" from input boxes that define a usage field
-------------------------------------------------------------------------
-r1366 | funkehdude | 2025-09-03 15:34:16 +0000 (Wed, 03 Sep 2025) | 1 line
-Changed paths:
-   M /trunk/Ace3.toc
+AceConfig-3.0: Widget width can be defined to be relative to the container

-Bump toc
-------------------------------------------------------------------------
-r1365 | funkehdude | 2025-07-11 17:08:49 +0000 (Fri, 11 Jul 2025) | 1 line
-Changed paths:
-   M /trunk/Ace3.toc
+Syntax in the config table:
+width = "relative"
+relWidth = "0.25"

-Bump toc
+This will result in a widget that takes up a quarter of the container's
+width.
 ------------------------------------------------------------------------
-r1364 | nevcairiel | 2025-07-05 16:01:08 +0000 (Sat, 05 Jul 2025) | 1 line
+r1382 | nevcairiel | 2025-12-05 08:44:39 +0000 (Fri, 05 Dec 2025) | 11 lines
 Changed paths:
    M /trunk
-   M /trunk/AceDB-3.0/AceDB-3.0.lua
+   M /trunk/.luacheckrc
+   M /trunk/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua

-AceDB-3.0: Avoid hitting the metatable when looking up the keys
-------------------------------------------------------------------------
-r1363 | nevcairiel | 2025-07-05 15:42:11 +0000 (Sat, 05 Jul 2025) | 3 lines
-Changed paths:
-   M /trunk
-   M /trunk/AceDB-3.0/AceDB-3.0.lua
+AceConfigDialog-3.0: Preserve the original ID for BlizzOptions categories

-AceDB-3.0: Aggressively cleanout empty profiles tables inside namespace on logout
+In Midnight, the ID must be numeric, so we can no longer use the name,
+and this may prevent taint spread by the ID field, since the
+automatically generated value is assigned securely.

-This should help cleanup unloaded empty namespaces
-------------------------------------------------------------------------
-r1362 | funkehdude | 2025-06-19 17:08:39 +0000 (Thu, 19 Jun 2025) | 1 line
-Changed paths:
-   M /trunk/Ace3.toc
+To open the settings panel through Settings.OpenToCategory, the ID needs
+to be passed, which is returned as the second value from :AddToBlizzOptions

-Bump toc
+This change becomes effective when the new C_SettingsUtil API is added
+to the various clients, currently in 12.0
 ------------------------------------------------------------------------
-r1361 | nevcairiel | 2025-05-17 12:20:39 +0000 (Sat, 17 May 2025) | 6 lines
+r1381 | nevcairiel | 2025-12-05 08:43:15 +0000 (Fri, 05 Dec 2025) | 4 lines
 Changed paths:
    M /trunk
-   M /trunk/AceDB-3.0/AceDB-3.0.lua
+   M /trunk/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua

-AceDB-3.0: Cleanup empty namespace tables
+AceConfigDialog-3.0: Remove InterfaceOptions_AddCategory support

-Some addons use a large amount of namespaces which rarely get used, and
-empty tables can clutter the SV. Cleaning up empty tables is consistent
-with the other cleanup tasks done at logout, as they'll be re-created if
-needed.
+All supported WoW versions have moved on to the new Settings interface,
+so this was unused.
 ------------------------------------------------------------------------
-r1360 | funkehdude | 2025-05-01 22:54:00 +0000 (Thu, 01 May 2025) | 1 line
+r1380 | funkehdude | 2025-12-03 00:09:20 +0000 (Wed, 03 Dec 2025) | 1 line
 Changed paths:
    M /trunk/Ace3.toc

 Bump toc
 ------------------------------------------------------------------------
-r1359 | funkehdude | 2025-03-21 19:41:37 +0000 (Fri, 21 Mar 2025) | 1 line
-Changed paths:
-   M /trunk/Ace3.toc
-
-bump toc
-------------------------------------------------------------------------
-r1358 | funkehdude | 2025-03-21 19:37:45 +0000 (Fri, 21 Mar 2025) | 1 line
-Changed paths:
-   M /trunk/Ace3.toc
-
-bump toc
-------------------------------------------------------------------------
-r1357 | funkehdude | 2025-01-23 06:13:10 +0000 (Thu, 23 Jan 2025) | 1 line
-Changed paths:
-   M /trunk/Ace3.toc
-
-bump toc
-------------------------------------------------------------------------
-r1356 | nevcairiel | 2024-12-05 06:15:30 +0000 (Thu, 05 Dec 2024) | 1 line
+r1379 | nevcairiel | 2025-11-27 18:58:03 +0000 (Thu, 27 Nov 2025) | 3 lines
 Changed paths:
    M /trunk
    M /trunk/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua

-AceGUI-3.0: TreeGroup: Re-factor button hiding to help avoid bizarre button breakage
-------------------------------------------------------------------------
-r1355 | funkehdude | 2024-11-20 01:54:56 +0000 (Wed, 20 Nov 2024) | 1 line
-Changed paths:
-   M /trunk/Ace3.toc
-
-bump toc
-------------------------------------------------------------------------
-r1354 | funkehdude | 2024-09-10 14:01:06 +0000 (Tue, 10 Sep 2024) | 1 line
-Changed paths:
-   M /trunk/Ace3.toc
-
-bump toc
-------------------------------------------------------------------------
-r1353 | nevcairiel | 2024-08-27 13:37:35 +0000 (Tue, 27 Aug 2024) | 8 lines
-Changed paths:
-   M /trunk
-   M /trunk/AceDB-3.0/AceDB-3.0.lua
-
-AceDB-3.0: Handle unloaded namespaces in Reset/Copy/Delete functions
+AceGUI-3.0: TreeGroup: Pass an explicit alpha value to SetText

-When applying profile changes to namespaces, we should also handle
-namespaces that are not currently loaded.
-
-These may be from optional Load-on-Demand parts that are not currently
-loaded, but the expectation is that the database behaves consistent
-no matter what is currently active.
+Fixes CF-#685
 ------------------------------------------------------------------------
-r1352 | funkehdude | 2024-07-24 18:29:31 +0000 (Wed, 24 Jul 2024) | 1 line
-Changed paths:
-   M /trunk/.luacheckrc
-
-Update luacheck
-------------------------------------------------------------------------
-r1351 | funkehdude | 2024-07-24 18:23:24 +0000 (Wed, 24 Jul 2024) | 1 line
-Changed paths:
-   M /trunk/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua
-
-AceConfigDialog-3.0: Don't change keyboard input propagation in combat when showing the popup
-------------------------------------------------------------------------
-r1350 | funkehdude | 2024-07-24 17:55:50 +0000 (Wed, 24 Jul 2024) | 1 line
+r1378 | funkehdude | 2025-11-19 19:46:34 +0000 (Wed, 19 Nov 2025) | 1 line
 Changed paths:
    M /trunk/Ace3.toc

-Restore old toc versions, these are here purely to compensate for bad addon updaters, we don't actually care if we fully support these versions of wow
+Bump toc
 ------------------------------------------------------------------------

diff --git a/Titan/libs/Ace/LibQTip-1.0/CHANGELOG.md b/Titan/libs/Ace/LibQTip-1.0/CHANGELOG.md
deleted file mode 100644
index 442bb65..0000000
--- a/Titan/libs/Ace/LibQTip-1.0/CHANGELOG.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# Lib: QTip-1.0
-
-## [10.0.7.1](https://github.com/Torhal/LibQTip-1.0/tree/10.0.7.1) (2023-03-29)
-[Full Changelog](https://github.com/Torhal/LibQTip-1.0/compare/9.0.1.2...10.0.7.1) [Previous Releases](https://github.com/Torhal/LibQTip-1.0/releases)
-
-- Create release.yml
-    Add release configuration for the BigWigs Packager.
-- Update ToC Interface and add X-Curse-Project-ID to support the BigWigs Packager.
-- Create README.md
-- update for WoW 9.1.5's new TooltipBackdropTemplate
diff --git a/Titan/libs/Ace/LibQTip-1.0/LICENSE.txt b/Titan/libs/Ace/LibQTip-1.0/LICENSE.txt
deleted file mode 100644
index 9bc7b5c..0000000
--- a/Titan/libs/Ace/LibQTip-1.0/LICENSE.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-Copyright (c) 2008, LibQTip Development Team
-
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-    * Redistributions of source code must retain the above copyright notice,
-      this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above copyright notice,
-      this list of conditions and the following disclaimer in the documentation
-      and/or other materials provided with the distribution.
-    * Redistribution of a stand alone version is strictly prohibited without
-      prior written authorization from the Lead of the LibQTip Development Team.
-    * Neither the name of the LibQTip Development Team nor the names of its contributors
-      may be used to endorse or promote products derived from this software without
-      specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Titan/libs/Ace/LibQTip-1.0/LibQTip-1.0.lua b/Titan/libs/Ace/LibQTip-1.0/LibQTip-1.0.lua
deleted file mode 100644
index bb38c75..0000000
--- a/Titan/libs/Ace/LibQTip-1.0/LibQTip-1.0.lua
+++ /dev/null
@@ -1,1565 +0,0 @@
-local MAJOR = "LibQTip-1.0"
-local MINOR = 49 -- Should be manually increased
-local LibStub = _G.LibStub
-
-assert(LibStub, MAJOR .. " requires LibStub")
-
-local lib, oldMinor = LibStub:NewLibrary(MAJOR, MINOR)
-
-if not lib then
-    return
-end -- No upgrade needed
-
-------------------------------------------------------------------------------
--- Upvalued globals
-------------------------------------------------------------------------------
-local table = _G.table
-local tinsert = table.insert
-local tremove = table.remove
-local wipe = table.wipe
-
-local error = error
-local math = math
-local min, max = math.min, math.max
-local next = next
-local pairs, ipairs = pairs, ipairs
-local select = select
-local setmetatable = setmetatable
-local tonumber, tostring = tonumber, tostring
-local type = type
-
-local CreateFrame = _G.CreateFrame
-local GameTooltip = _G.GameTooltip
-local UIParent = _G.UIParent
-
-local geterrorhandler = _G.geterrorhandler
-
-------------------------------------------------------------------------------
--- Tables and locals
-------------------------------------------------------------------------------
-lib.frameMetatable = lib.frameMetatable or {__index = CreateFrame("Frame")}
-
-lib.tipPrototype = lib.tipPrototype or setmetatable({}, lib.frameMetatable)
-lib.tipMetatable = lib.tipMetatable or {__index = lib.tipPrototype}
-
-lib.providerPrototype = lib.providerPrototype or {}
-lib.providerMetatable = lib.providerMetatable or {__index = lib.providerPrototype}
-
-lib.cellPrototype = lib.cellPrototype or setmetatable({}, lib.frameMetatable)
-lib.cellMetatable = lib.cellMetatable or {__index = lib.cellPrototype}
-
-lib.activeTooltips = lib.activeTooltips or {}
-
-lib.tooltipHeap = lib.tooltipHeap or {}
-lib.frameHeap = lib.frameHeap or {}
-lib.timerHeap = lib.timerHeap or {}
-lib.tableHeap = lib.tableHeap or {}
-
-lib.onReleaseHandlers = lib.onReleaseHandlers or {}
-
-local tipPrototype = lib.tipPrototype
-local tipMetatable = lib.tipMetatable
-
-local providerPrototype = lib.providerPrototype
-local providerMetatable = lib.providerMetatable
-
-local cellPrototype = lib.cellPrototype
-local cellMetatable = lib.cellMetatable
-
-local activeTooltips = lib.activeTooltips
-
-local highlightFrame = CreateFrame("Frame", nil, UIParent)
-highlightFrame:SetFrameStrata("TOOLTIP")
-highlightFrame:Hide()
-
-local DEFAULT_HIGHLIGHT_TEXTURE_PATH = [[Interface\QuestFrame\UI-QuestTitleHighlight]]
-
-local highlightTexture = highlightFrame:CreateTexture(nil, "OVERLAY")
-highlightTexture:SetTexture(DEFAULT_HIGHLIGHT_TEXTURE_PATH)
-highlightTexture:SetBlendMode("ADD")
-highlightTexture:SetAllPoints(highlightFrame)
-
-------------------------------------------------------------------------------
--- Private methods for Caches and Tooltip
-------------------------------------------------------------------------------
-local AcquireTooltip, ReleaseTooltip
-local AcquireCell, ReleaseCell
-local AcquireTable, ReleaseTable
-
-local InitializeTooltip, SetTooltipSize, ResetTooltipSize, FixCellSizes
-local ClearTooltipScripts
-local SetFrameScript, ClearFrameScripts
-
-------------------------------------------------------------------------------
--- Cache debugging.
-------------------------------------------------------------------------------
--- @debug @
-local usedTables, usedFrames, usedTooltips = 0, 0, 0
---@end-debug@]==]
-
-------------------------------------------------------------------------------
--- Internal constants to tweak the layout
-------------------------------------------------------------------------------
-local TOOLTIP_PADDING = 10
-local CELL_MARGIN_H = 6
-local CELL_MARGIN_V = 3
-
-------------------------------------------------------------------------------
--- Public library API
-------------------------------------------------------------------------------
---- Create or retrieve the tooltip with the given key.
--- If additional arguments are passed, they are passed to :SetColumnLayout for the acquired tooltip.
--- @name LibQTip:Acquire(key[, numColumns, column1Justification, column2justification, ...])
--- @param key string or table - the tooltip key. Any value that can be used as a table key is accepted though you should try to provide unique keys to avoid conflicts.
--- Numbers and booleans should be avoided and strings should be carefully chosen to avoid namespace clashes - no "MyTooltip" - you have been warned!
--- @return tooltip Frame object - the acquired tooltip.
--- @usage Acquire a tooltip with at least 5 columns, justification : left, center, left, left, left
--- <pre>local tip = LibStub('LibQTip-1.0'):Acquire('MyFooBarTooltip', 5, "LEFT", "CENTER")</pre>
-function lib:Acquire(key, ...)
-    if key == nil then
-        error("attempt to use a nil key", 2)
-    end
-
-    local tooltip = activeTooltips[key]
-
-    if not tooltip then
-        tooltip = AcquireTooltip()
-        InitializeTooltip(tooltip, key)
-        activeTooltips[key] = tooltip
-    end
-
-    if select("#", ...) > 0 then
-        -- Here we catch any error to properly report it for the calling code
-        local ok, msg = pcall(tooltip.SetColumnLayout, tooltip, ...)
-
-        if not ok then
-            error(msg, 2)
-        end
-    end
-
-    return tooltip
-end
-
-function lib:Release(tooltip)
-    local key = tooltip and tooltip.key
-
-    if not key or activeTooltips[key] ~= tooltip then
-        return
-    end
-
-    ReleaseTooltip(tooltip)
-    activeTooltips[key] = nil
-end
-
-function lib:IsAcquired(key)
-    if key == nil then
-        error("attempt to use a nil key", 2)
-    end
-
-    return not (not activeTooltips[key])
-end
-
-function lib:IterateTooltips()
-    return pairs(activeTooltips)
-end
-
-------------------------------------------------------------------------------
--- Frame cache (for lines and columns)
-------------------------------------------------------------------------------
-local frameHeap = lib.frameHeap
-
-local function AcquireFrame(parent)
-    local frame = tremove(frameHeap) or CreateFrame("Frame", nil, nil, BackdropTemplateMixin and "BackdropTemplate")
-    frame:SetParent(parent)
-    --[==[@debug@
-    usedFrames = usedFrames + 1
-    --@end-debug@]==]
-    return frame
-end
-
-local function ReleaseFrame(frame)
-    frame:Hide()
-    frame:SetParent(nil)
-    frame:ClearAllPoints()
-    frame:SetBackdrop(nil)
-
-    ClearFrameScripts(frame)
-
-    tinsert(frameHeap, frame)
-    --[==[@debug@
-    usedFrames = usedFrames - 1
-    --@end-debug@]==]
-end
-
-------------------------------------------------------------------------------
--- Timer cache
-------------------------------------------------------------------------------
-local timerHeap = lib.timerHeap
-
-local function AcquireTimer(parent)
-    local frame = tremove(timerHeap) or CreateFrame("Frame")
-    frame:SetParent(parent)
-    return frame
-end
-
-local function ReleaseTimer(frame)
-    frame:Hide()
-    frame:SetParent(nil)
-
-    ClearFrameScripts(frame)
-
-    tinsert(timerHeap, frame)
-end
-
-------------------------------------------------------------------------------
--- Dirty layout handler
-------------------------------------------------------------------------------
-lib.layoutCleaner = lib.layoutCleaner or CreateFrame("Frame")
-
-local layoutCleaner = lib.layoutCleaner
-layoutCleaner.registry = layoutCleaner.registry or {}
-
-function layoutCleaner:RegisterForCleanup(tooltip)
-    self.registry[tooltip] = true
-    self:Show()
-end
-
-function layoutCleaner:CleanupLayouts()
-    self:Hide()
-
-    for tooltip in pairs(self.registry) do
-        FixCellSizes(tooltip)
-    end
-
-    wipe(self.registry)
-end
-
-layoutCleaner:SetScript("OnUpdate", layoutCleaner.CleanupLayouts)
-
-------------------------------------------------------------------------------
--- CellProvider and Cell
-------------------------------------------------------------------------------
-function providerPrototype:AcquireCell()
-    local cell = tremove(self.heap)
-
-    if not cell then
-        cell = CreateFrame("Frame", nil, UIParent, BackdropTemplateMixin and "BackdropTemplate")
-        setmetatable(cell, self.cellMetatable)
-
-        if type(cell.InitializeCell) == "function" then
-            cell:InitializeCell()
-        end
-    end
-
-    self.cells[cell] = true
-
-    return cell
-end
-
-function providerPrototype:ReleaseCell(cell)
-    if not self.cells[cell] then
-        return
-    end
-
-    if type(cell.ReleaseCell) == "function" then
-        cell:ReleaseCell()
-    end
-
-    self.cells[cell] = nil
-    tinsert(self.heap, cell)
-end
-
-function providerPrototype:GetCellPrototype()
-    return self.cellPrototype, self.cellMetatable
-end
-
-function providerPrototype:IterateCells()
-    return pairs(self.cells)
-end
-
-function lib:CreateCellProvider(baseProvider)
-    local cellBaseMetatable, cellBasePrototype
-
-    if baseProvider and baseProvider.GetCellPrototype then
-        cellBasePrototype, cellBaseMetatable = baseProvider:GetCellPrototype()
-    else
-        cellBaseMetatable = cellMetatable
-    end
-
-    local newCellPrototype = setmetatable({}, cellBaseMetatable)
-    local newCellProvider = setmetatable({}, providerMetatable)
-
-    newCellProvider.heap = {}
-    newCellProvider.cells = {}
-    newCellProvider.cellPrototype = newCellPrototype
-    newCellProvider.cellMetatable = {__index = newCellPrototype}
-
-    return newCellProvider, newCellPrototype, cellBasePrototype
-end
-
-------------------------------------------------------------------------------
--- Basic label provider
-------------------------------------------------------------------------------
-if not lib.LabelProvider then
-    lib.LabelProvider, lib.LabelPrototype = lib:CreateCellProvider()
-end
-
-local labelProvider = lib.LabelProvider
-local labelPrototype = lib.LabelPrototype
-
-function labelPrototype:InitializeCell()
-    self.fontString = self:CreateFontString()
-    self.fontString:SetFontObject(_G.GameTooltipText)
-end
-
-function labelPrototype:SetupCell(tooltip, value, justification, font, leftPadding, rightPadding, maxWidth, minWidth, ...)
-    local fontString = self.fontString
-    local line = tooltip.lines[self._line]
-
-    -- detatch fs from cell for size calculations
-    fontString:ClearAllPoints()
-    fontString:SetFontObject(font or (line.is_header and tooltip:GetHeaderFont() or tooltip:GetFont()))
-    fontString:SetJustifyH(justification)
-    fontString:SetText(tostring(value))
-
-    leftPadding = leftPadding or 0
-    rightPadding = rightPadding or 0
-
-    local width = fontString:GetStringWidth() + leftPadding + rightPadding
-
-    if maxWidth and minWidth and (maxWidth < minWidth) then
-        error("maximum width cannot be lower than minimum width: " .. tostring(maxWidth) .. " < " .. tostring(minWidth), 2)
-    end
-
-    if maxWidth and (maxWidth < (leftPadding + rightPadding)) then
-        error("maximum width cannot be lower than the sum of paddings: " .. tostring(maxWidth) .. " < " .. tostring(leftPadding) .. " + " .. tostring(rightPadding), 2)
-    end
-
-    if minWidth and width < minWidth then
-        width = minWidth
-    end
-
-    if maxWidth and maxWidth < width then
-        width = maxWidth
-    end
-
-    fontString:SetWidth(width - (leftPadding + rightPadding))
-    -- Use GetHeight() instead of GetStringHeight() so lines which are longer than width will wrap.
-    local height = fontString:GetHeight()
-
-    -- reanchor fs to cell
-    fontString:SetWidth(0)
-    fontString:SetPoint("TOPLEFT", self, "TOPLEFT", leftPadding, 0)
-    fontString:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -rightPadding, 0)
-    --~ 	fs:SetPoint("TOPRIGHT", self, "TOPRIGHT", -r_pad, 0)
-
-    self._paddingL = leftPadding
-    self._paddingR = rightPadding
-
-    return width, height
-end
-
-function labelPrototype:getContentHeight()
-    local fontString = self.fontString
-    fontString:SetWidth(self:GetWidth() - (self._paddingL + self._paddingR))
-
-    local height = self.fontString:GetHeight()
-    fontString:SetWidth(0)
-
-    return height
-end
-
-function labelPrototype:GetPosition()
-    return self._line, self._column
-end
-
-------------------------------------------------------------------------------
--- Tooltip cache
-------------------------------------------------------------------------------
-local tooltipHeap = lib.tooltipHeap
-
--- Returns a tooltip
-function AcquireTooltip()
-    local tooltip = tremove(tooltipHeap)
-
-    if not tooltip then
-        local template = (TooltipBackdropTemplateMixin and "TooltipBackdropTemplate") or (BackdropTemplateMixin and "BackdropTemplate")
-        tooltip = CreateFrame("Frame", nil, UIParent, template)
-
-        local scrollFrame = CreateFrame("ScrollFrame", nil, tooltip)
-        scrollFrame:SetPoint("TOP", tooltip, "TOP", 0, -TOOLTIP_PADDING)
-        scrollFrame:SetPoint("BOTTOM", tooltip, "BOTTOM", 0, TOOLTIP_PADDING)
-        scrollFrame:SetPoint("LEFT", tooltip, "LEFT", TOOLTIP_PADDING, 0)
-        scrollFrame:SetPoint("RIGHT", tooltip, "RIGHT", -TOOLTIP_PADDING, 0)
-        tooltip.scrollFrame = scrollFrame
-
-        local scrollChild = CreateFrame("Frame", nil, tooltip.scrollFrame)
-        scrollFrame:SetScrollChild(scrollChild)
-        tooltip.scrollChild = scrollChild
-
-        setmetatable(tooltip, tipMetatable)
-    end
-
-    --[==[@debug@
-    usedTooltips = usedTooltips + 1
-    --@end-debug@]==]
-    return tooltip
-end
-
--- Cleans the tooltip and stores it in the cache
-function ReleaseTooltip(tooltip)
-    if tooltip.releasing then
-        return
-    end
-
-    tooltip.releasing = true
-    tooltip:Hide()
-
-    local releaseHandler = lib.onReleaseHandlers[tooltip]
-
-    if releaseHandler then
-        lib.onReleaseHandlers[tooltip] = nil
-
-        local success, errorMessage = pcall(releaseHandler, tooltip)
-
-        if not success then
-            geterrorhandler()(errorMessage)
-        end
-    elseif tooltip.OnRelease then
-        local success, errorMessage = pcall(tooltip.OnRelease, tooltip)
-        if not success then
-            geterrorhandler()(errorMessage)
-        end
-
-        tooltip.OnRelease = nil
-    end
-
-    tooltip.releasing = nil
-    tooltip.key = nil
-    tooltip.step = nil
-
-    ClearTooltipScripts(tooltip)
-
-    tooltip:SetAutoHideDelay(nil)
-    tooltip:ClearAllPoints()
-    tooltip:Clear()
-
-    if tooltip.slider then
-        tooltip.slider:SetValue(0)
-        tooltip.slider:Hide()
-        tooltip.scrollFrame:SetPoint("RIGHT", tooltip, "RIGHT", -TOOLTIP_PADDING, 0)
-        tooltip:EnableMouseWheel(false)
-    end
-
-    for i, column in ipairs(tooltip.columns) do
-        tooltip.columns[i] = ReleaseFrame(column)
-    end
-
-    tooltip.columns = ReleaseTable(tooltip.columns)
-    tooltip.lines = ReleaseTable(tooltip.lines)
-    tooltip.colspans = ReleaseTable(tooltip.colspans)
-
-    layoutCleaner.registry[tooltip] = nil
-
-    if TooltipBackdropTemplateMixin and not tooltip.NineSlice then
-        -- don't recycle outdated tooltips into heap
-        tooltip = nil
-    end
-
-    if tooltip then
-        tinsert(tooltipHeap, tooltip)
-    end
-
-    highlightTexture:SetTexture(DEFAULT_HIGHLIGHT_TEXTURE_PATH)
-    highlightTexture:SetTexCoord(0, 1, 0, 1)
-
-    --[==[@debug@
-    usedTooltips = usedTooltips - 1
-    --@end-debug@]==]
-end
-
-------------------------------------------------------------------------------
--- Cell 'cache' (just a wrapper to the provider's cache)
-------------------------------------------------------------------------------
--- Returns a cell for the given tooltip from the given provider
-function AcquireCell(tooltip, provider)
-    local cell = provider:AcquireCell(tooltip)
-
-    cell:SetParent(tooltip.scrollChild)
-    cell:SetFrameLevel(tooltip.scrollChild:GetFrameLevel() + 3)
-    cell._provider = provider
-
-    return cell
-end
-
--- Cleans the cell hands it to its provider for storing
-function ReleaseCell(cell)
-    if cell.fontString and cell.r then
-        cell.fontString:SetTextColor(cell.r, cell.g, cell.b, cell.a)
-    end
-
-    cell._font = nil
-    cell._justification = nil
-    cell._colSpan = nil
-    cell._line = nil
-    cell._column = nil
-
-    cell:Hide()
-    cell:ClearAllPoints()
-    cell:SetParent(nil)
-    cell:SetBackdrop(nil)
-
-    ClearFrameScripts(cell)
-
-    cell._provider:ReleaseCell(cell)
-    cell._provider = nil
-end
-
-------------------------------------------------------------------------------
--- Table cache
-------------------------------------------------------------------------------
-local tableHeap = lib.tableHeap
-
--- Returns a table
-function AcquireTable()
-    local tbl = tremove(tableHeap) or {}
-    --[==[@debug@
-    usedTables = usedTables + 1
-    --@end-debug@]==]
-    return tbl
-end
-
--- Cleans the table and stores it in the cache
-function ReleaseTable(tableInstance)
-    wipe(tableInstance)
-    tinsert(tableHeap, tableInstance)
-    --[==[@debug@
-    usedTables = usedTables - 1
-    --@end-debug@]==]
-end
-
-------------------------------------------------------------------------------
--- Tooltip prototype
-------------------------------------------------------------------------------
-function InitializeTooltip(tooltip, key)
-    ----------------------------------------------------------------------
-    -- (Re)set frame settings
-    ----------------------------------------------------------------------
-    if TooltipBackdropTemplateMixin then
-        tooltip.layoutType = GameTooltip.layoutType
-        NineSlicePanelMixin.OnLoad(tooltip.NineSlice)
-        if GameTooltip.layoutType then
-            tooltip.NineSlice:SetCenterColor(GameTooltip.NineSlice:GetCenterColor())
-            tooltip.NineSlice:SetBorderColor(GameTooltip.NineSlice:GetBorderColor())
-        end
-    else
-        local backdrop = GameTooltip:GetBackdrop()
-
-        tooltip:SetBackdrop(backdrop)
-
-        if backdrop then
-            tooltip:SetBackdropColor(GameTooltip:GetBackdropColor())
-            tooltip:SetBackdropBorderColor(GameTooltip:GetBackdropBorderColor())
-        end
-    end
-
-    tooltip:SetScale(GameTooltip:GetScale())
-    tooltip:SetAlpha(1)
-    tooltip:SetFrameStrata("TOOLTIP")
-    tooltip:SetClampedToScreen(false)
-
-    ----------------------------------------------------------------------
-    -- Internal data. Since it's possible to Acquire twice without calling
-    -- release, check for pre-existence.
-    ----------------------------------------------------------------------
-    tooltip.key = key
-    tooltip.columns = tooltip.columns or AcquireTable()
-    tooltip.lines = tooltip.lines or AcquireTable()
-    tooltip.colspans = tooltip.colspans or AcquireTable()
-    tooltip.regularFont = _G.GameTooltipText
-    tooltip.headerFont = _G.GameTooltipHeaderText
-    tooltip.labelProvider = labelProvider
-    tooltip.cell_margin_h = tooltip.cell_margin_h or CELL_MARGIN_H
-    tooltip.cell_margin_v = tooltip.cell_margin_v or CELL_MARGIN_V
-
-    ----------------------------------------------------------------------
-    -- Finishing procedures
-    ----------------------------------------------------------------------
-    tooltip:SetAutoHideDelay(nil)
-    tooltip:Hide()
-    ResetTooltipSize(tooltip)
-end
-
-function tipPrototype:SetDefaultProvider(myProvider)
-    if not myProvider then
-        return
-    end
-
-    self.labelProvider = myProvider
-end
-
-function tipPrototype:GetDefaultProvider()
-    return self.labelProvider
-end
-
-local function checkJustification(justification, level, silent)
-    if justification ~= "LEFT" and justification ~= "CENTER" and justification ~= "RIGHT" then
-        if silent then
-            return false
-        end
-        error("invalid justification, must one of LEFT, CENTER or RIGHT, not: " .. tostring(justification), level + 1)
-    end
-
-    return true
-end
-
-function tipPrototype:SetColumnLayout(numColumns, ...)
-    if type(numColumns) ~= "number" or numColumns < 1 then
-        error("number of columns must be a positive number, not: " .. tostring(numColumns), 2)
-    end
-
-    for i = 1, numColumns do
-        local justification = select(i, ...) or "LEFT"
-
-        checkJustification(justification, 2)
-
-        if self.columns[i] then
-            self.columns[i].justification = justification
-        else
-            self:AddColumn(justification)
-        end
-    end
-end
-
-function tipPrototype:AddColumn(justification)
-    justification = justification or "LEFT"
-    checkJustification(justification, 2)
-
-    local colNum = #self.columns + 1
-    local column = self.columns[colNum] or AcquireFrame(self.scrollChild)
-
-    column:SetFrameLevel(self.scrollChild:GetFrameLevel() + 1)
-    column.justification = justification
-    column.width = 0
-    column:SetWidth(1)
-    column:SetPoint("TOP", self.scrollChild)
-    column:SetPoint("BOTTOM", self.scrollChild)
-
-    if colNum > 1 then
-        local h_margin = self.cell_margin_h or CELL_MARGIN_H
-
-        column:SetPoint("LEFT", self.columns[colNum - 1], "RIGHT", h_margin, 0)
-        SetTooltipSize(self, self.width + h_margin, self.height)
-    else
-        column:SetPoint("LEFT", self.scrollChild)
-    end
-
-    column:Show()
-    self.columns[colNum] = column
-
-    return colNum
-end
-
-------------------------------------------------------------------------------
--- Convenient methods
-------------------------------------------------------------------------------
-function tipPrototype:Release()
-    lib:Release(self)
-end
-
-function tipPrototype:IsAcquiredBy(key)
-    return key ~= nil and self.key == key
-end
-
-------------------------------------------------------------------------------
--- Script hooks
-------------------------------------------------------------------------------
-local RawSetScript = lib.frameMetatable.__index.SetScript
-
-function ClearTooltipScripts(tooltip)
-    if tooltip.scripts then
-        for scriptType in pairs(tooltip.scripts) do
-            RawSetScript(tooltip, scriptType, nil)
-        end
-
-        tooltip.scripts = ReleaseTable(tooltip.scripts)
-    end
-end
-
-function tipPrototype:SetScript(scriptType, handler)
-    RawSetScript(self, scriptType, handler)
-
-    if handler then
-        if not self.scripts then
-            self.scripts = AcquireTable()
-        end
-
-        self.scripts[scriptType] = true
-    elseif self.scripts then
-        self.scripts[scriptType] = nil
-    end
-end
-
--- That might break some addons ; those addons were breaking other
--- addons' tooltip though.
-function tipPrototype:HookScript()
-    geterrorhandler()(":HookScript is not allowed on LibQTip tooltips")
-end
-
-------------------------------------------------------------------------------
--- Scrollbar data and functions
-------------------------------------------------------------------------------
-local BACKDROP_SLIDER_8_8 = BACKDROP_SLIDER_8_8 or {
-    bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
-    edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
-    tile = true,
-    tileEdge = true,
-    tileSize = 8,
-    edgeSize = 8,
-    insets = { left = 3, right = 3, top = 6, bottom = 6 },
-};
-
-local function slider_OnValueChanged(self)
-    self.scrollFrame:SetVerticalScroll(self:GetValue())
-end
-
-local function tooltip_OnMouseWheel(self, delta)
-    local slider = self.slider
-    local currentValue = slider:GetValue()
-    local minValue, maxValue = slider:GetMinMaxValues()
-    local stepValue = self.step or 10
-
-    if delta < 0 and currentValue < maxValue then
-        slider:SetValue(min(maxValue, currentValue + stepValue))
-    elseif delta > 0 and currentValue > minValue then
-        slider:SetValue(max(minValue, currentValue - stepValue))
-    end
-end
-
--- Set the step size for the scroll bar
-function tipPrototype:SetScrollStep(step)
-    self.step = step
-end
-
--- will resize the tooltip to fit the screen and show a scrollbar if needed
-function tipPrototype:UpdateScrolling(maxheight)
-    self:SetClampedToScreen(false)
-
-    -- all data is in the tooltip; fix colspan width and prevent the layout cleaner from messing up the tooltip later
-    FixCellSizes(self)
-    layoutCleaner.registry[self] = nil
-
-    local scale = self:GetScale()
-    local topside = self:GetTop()
-    local bottomside = self:GetBottom()
-    local screensize = UIParent:GetHeight() / scale
-    local tipsize = (topside - bottomside)
-
-    -- if the tooltip would be too high, limit its height and show the slider
-    if bottomside < 0 or topside > screensize or (maxheight and tipsize > maxheight) then
-        local shrink = (bottomside < 0 and (5 - bottomside) or 0) + (topside > screensize and (topside - screensize + 5) or 0)
-
-        if maxheight and tipsize - shrink > maxheight then
-            shrink = tipsize - maxheight
-        end
-
-        self:SetHeight(2 * TOOLTIP_PADDING + self.height - shrink)
-        self:SetWidth(2 * TOOLTIP_PADDING + self.width + 20)
-        self.scrollFrame:SetPoint("RIGHT", self, "RIGHT", -(TOOLTIP_PADDING + 20), 0)
-
-        if not self.slider then
-            local slider = CreateFrame("Slider", nil, self, BackdropTemplateMixin and "BackdropTemplate")
-            slider.scrollFrame = self.scrollFrame
-
-            slider:SetOrientation("VERTICAL")
-            slider:SetPoint("TOPRIGHT", self, "TOPRIGHT", -TOOLTIP_PADDING, -TOOLTIP_PADDING)
-            slider:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -TOOLTIP_PADDING, TOOLTIP_PADDING)
-            slider:SetBackdrop(BACKDROP_SLIDER_8_8)
-            slider:SetThumbTexture([[Interface\Buttons\UI-SliderBar-Button-Vertical]])
-            slider:SetMinMaxValues(0, 1)
-            slider:SetValueStep(1)
-            slider:SetWidth(12)
-            slider:SetScript("OnValueChanged", slider_OnValueChanged)
-            slider:SetValue(0)
-
-            self.slider = slider
-        end
-
-        self.slider:SetMinMaxValues(0, shrink)
-        self.slider:Show()
-
-        self:EnableMouseWheel(true)
-        self:SetScript("OnMouseWheel", tooltip_OnMouseWheel)
-    else
-        self:SetHeight(2 * TOOLTIP_PADDING + self.height)
-        self:SetWidth(2 * TOOLTIP_PADDING + self.width)
-
-        self.scrollFrame:SetPoint("RIGHT", self, "RIGHT", -TOOLTIP_PADDING, 0)
-
-        if self.slider then
-            self.slider:SetValue(0)
-            self.slider:Hide()
-
-            self:EnableMouseWheel(false)
-            self:SetScript("OnMouseWheel", nil)
-        end
-    end
-end
-
-------------------------------------------------------------------------------
--- Tooltip methods for changing its contents.
-------------------------------------------------------------------------------
-function tipPrototype:Clear()
-    for i, line in ipairs(self.lines) do
-        for _, cell in pairs(line.cells) do
-            if cell then
-                ReleaseCell(cell)
-            end
-        end
-
-        ReleaseTable(line.cells)
-
-        line.cells = nil
-        line.is_header = nil
-
-        ReleaseFrame(line)
-
-        self.lines[i] = nil
-    end
-
-    for _, column in ipairs(self.columns) do
-        column.width = 0
-        column:SetWidth(1)
-    end
-
-    wipe(self.colspans)
-
-    self.cell_margin_h = nil
-    self.cell_margin_v = nil
-
-    ResetTooltipSize(self)
-end
-
-function tipPrototype:SetCellMarginH(size)
-    if #self.lines > 0 then
-        error("Unable to set horizontal margin while the tooltip has lines.", 2)
-    end
-
-    if not size or type(size) ~= "number" or size < 0 then
-        error("Margin size must be a positive number or zero.", 2)
-    end
-
-    self.cell_margin_h = size
-end
-
-function tipPrototype:SetCellMarginV(size)
-    if #self.lines > 0 then
-        error("Unable to set vertical margin while the tooltip has lines.", 2)
-    end
-
-    if not size or type(size) ~= "number" or size < 0 then
-        error("Margin size must be a positive number or zero.", 2)
-    end
-
-    self.cell_margin_v = size
-end
-
-function SetTooltipSize(tooltip, width, height)
-    tooltip.height = height
-    tooltip.width = width
-
-    tooltip:SetHeight(2 * TOOLTIP_PADDING + height)
-    tooltip:SetWidth(2 * TOOLTIP_PADDING + width)
-
-    tooltip.scrollChild:SetHeight(height)
-    tooltip.scrollChild:SetWidth(width)
-end
-
--- Add 2 pixels to height so dangling letters (g, y, p, j, etc) are not clipped.
-function ResetTooltipSize(tooltip)
-    local h_margin = tooltip.cell_margin_h or CELL_MARGIN_H
-
-    SetTooltipSize(tooltip, max(0, (h_margin * (#tooltip.columns - 1)) + (h_margin / 2)), 2)
-end
-
-local function EnlargeColumn(tooltip, column, width)
-    if width > column.width then
-        SetTooltipSize(tooltip, tooltip.width + width - column.width, tooltip.height)
-
-        column.width = width
-        column:SetWidth(width)
-    end
-end
-
-local function ResizeLine(tooltip, line, height)
-    SetTooltipSize(tooltip, tooltip.width, tooltip.height + height - line.height)
-
-    line.height = height
-    line:SetHeight(height)
-end
-
-function FixCellSizes(tooltip)
-    local columns = tooltip.columns
-    local colspans = tooltip.colspans
-    local lines = tooltip.lines
-    local h_margin = tooltip.cell_margin_h or CELL_MARGIN_H
-
-    -- resize columns to make room for the colspans
-    while next(colspans) do
-        local maxNeedCols
-        local maxNeedWidthPerCol = 0
-
-        -- calculate the colspan with the highest additional width need per column
-        for colRange, width in pairs(colspans) do
-            local left, right = colRange:match("^(%d+)%-(%d+)$")
-
-            left, right = tonumber(left), tonumber(right)
-
-            for col = left, right - 1 do
-                width = width - columns[col].width - h_margin
-            end
-
-            width = width - columns[right].width
-
-            if width <= 0 then
-                colspans[colRange] = nil
-            else
-                width = width / (right - left + 1)
-
-                if width > maxNeedWidthPerCol then
-                    maxNeedCols = colRange
-                    maxNeedWidthPerCol = width
-                end
-            end
-        end
-
-        -- resize all columns for that colspan
-        if maxNeedCols then
-            local left, right = maxNeedCols:match("^(%d+)%-(%d+)$")
-
-            for col = left, right do
-                EnlargeColumn(tooltip, columns[col], columns[col].width + maxNeedWidthPerCol)
-            end
-
-            colspans[maxNeedCols] = nil
-        end
-    end
-
-    --now that the cell width is set, recalculate the rows' height
-    for _, line in ipairs(lines) do
-        if #(line.cells) > 0 then
-            local lineheight = 0
-
-            for _, cell in pairs(line.cells) do
-                if cell then
-                    lineheight = max(lineheight, cell:getContentHeight())
-                end
-            end
-
-            if lineheight > 0 then
-                ResizeLine(tooltip, line, lineheight)
-            end
-        end
-    end
-end
-
-local function _SetCell(tooltip, lineNum, colNum, value, font, justification, colSpan, provider, ...)
-    local line = tooltip.lines[lineNum]
-    local cells = line.cells
-
-    -- Unset: be quick
-    if value == nil then
-        local cell = cells[colNum]
-
-        if cell then
-            for i = colNum, colNum + cell._colSpan - 1 do
-                cells[i] = nil
-            end
-
-            ReleaseCell(cell)
-        end
-
-        return lineNum, colNum
-    end
-
-    font = font or (line.is_header and tooltip.headerFont or tooltip.regularFont)
-
-    -- Check previous cell
-    local cell
-    local prevCell = cells[colNum]
-
-    if prevCell then
-        -- There is a cell here
-        justification = justification or prevCell._justification
-        colSpan = colSpan or prevCell._colSpan
-
-        -- Clear the currently marked colspan
-        for i = colNum + 1, colNum + prevCell._colSpan - 1 do
-            cells[i] = nil
-        end
-
-        if provider == nil or prevCell._provider == provider then
-            -- Reuse existing cell
-            cell = prevCell
-            provider = cell._provider
-        else
-            -- A new cell is required
-            cells[colNum] = ReleaseCell(prevCell)
-        end
-    elseif prevCell == nil then
-        -- Creating a new cell, using meaningful defaults.
-        provider = provider or tooltip.labelProvider
-        justification = justification or tooltip.columns[colNum].justification or "LEFT"
-        colSpan = colSpan or 1
-    else
-        error("overlapping cells at column " .. colNum, 3)
-    end
-
-    local tooltipWidth = #tooltip.columns
-    local rightColNum
-
-    if colSpan > 0 then
-        rightColNum = colNum + colSpan - 1
-
-        if rightColNum > tooltipWidth then
-            error("ColSpan too big, cell extends beyond right-most column", 3)
-        end
-    else
-        -- Zero or negative: count back from right-most columns
-        rightColNum = max(colNum, tooltipWidth + colSpan)
-        -- Update colspan to its effective value
-        colSpan = 1 + rightColNum - colNum
-    end
-
-    -- Cleanup colspans
-    for i = colNum + 1, rightColNum do
-        local columnCell = cells[i]
-
-        if columnCell then
-            ReleaseCell(columnCell)
-        elseif columnCell == false then
-            error("overlapping cells at column " .. i, 3)
-        end
-
-        cells[i] = false
-    end
-
-    -- Create the cell
-    if not cell then
-        cell = AcquireCell(tooltip, provider)
-        cells[colNum] = cell
-    end
-
-    -- Anchor the cell
-    cell:SetPoint("LEFT", tooltip.columns[colNum])
-    cell:SetPoint("RIGHT", tooltip.columns[rightColNum])
-    cell:SetPoint("TOP", line)
-    cell:SetPoint("BOTTOM", line)
-
-    -- Store the cell settings directly into the cell
-    -- That's a bit risky but is really cheap compared to other ways to do it
-    cell._font, cell._justification, cell._colSpan, cell._line, cell._column = font, justification, colSpan, lineNum, colNum
-
-    -- Setup the cell content
-    local width, height = cell:SetupCell(tooltip, value, justification, font, ...)
-    cell:Show()
-
-    if colSpan > 1 then
-        -- Postpone width changes until the tooltip is shown
-        local colRange = colNum .. "-" .. rightColNum
-
-        tooltip.colspans[colRange] = max(tooltip.colspans[colRange] or 0, width)
-        layoutCleaner:RegisterForCleanup(tooltip)
-    else
-        -- Enlarge the column and tooltip if need be
-        EnlargeColumn(tooltip, tooltip.columns[colNum], width)
-    end
-
-    -- Enlarge the line and tooltip if need be
-    if height > line.height then
-        SetTooltipSize(tooltip, tooltip.width, tooltip.height + height - line.height)
-
-        line.height = height
-        line:SetHeight(height)
-    end
-
-    if rightColNum < tooltipWidth then
-        return lineNum, rightColNum + 1
-    else
-        return lineNum, nil
-    end
-end
-
-do
-    local function CreateLine(tooltip, font, ...)
-        if #tooltip.columns == 0 then
-            error("column layout should be defined before adding line", 3)
-        end
-
-        local lineNum = #tooltip.lines + 1
-        local line = tooltip.lines[lineNum] or AcquireFrame(tooltip.scrollChild)
-
-        line:SetFrameLevel(tooltip.scrollChild:GetFrameLevel() + 2)
-        line:SetPoint("LEFT", tooltip.scrollChild)
-        line:SetPoint("RIGHT", tooltip.scrollChild)
-
-        if lineNum > 1 then
-            local v_margin = tooltip.cell_margin_v or CELL_MARGIN_V
-
-            line:SetPoint("TOP", tooltip.lines[lineNum - 1], "BOTTOM", 0, -v_margin)
-            SetTooltipSize(tooltip, tooltip.width, tooltip.height + v_margin)
-        else
-            line:SetPoint("TOP", tooltip.scrollChild)
-        end
-
-        tooltip.lines[lineNum] = line
-
-        line.cells = line.cells or AcquireTable()
-        line.height = 0
-        line:SetHeight(1)
-        line:Show()
-
-        local colNum = 1
-
-        for i = 1, #tooltip.columns do
-            local value = select(i, ...)
-
-            if value ~= nil then
-                lineNum, colNum = _SetCell(tooltip, lineNum, i, value, font, nil, 1, tooltip.labelProvider)
-            end
-        end
-
-        return lineNum, colNum
-    end
-
-    function tipPrototype:AddLine(...)
-        return CreateLine(self, self.regularFont, ...)
-    end
-
-    function tipPrototype:AddHeader(...)
-        local line, col = CreateLine(self, self.headerFont, ...)
-
-        self.lines[line].is_header = true
-
-        return line, col
-    end
-end -- do-block
-
-local GenericBackdrop = {
-    bgFile = "Interface\\Tooltips\\UI-Tooltip-Background"
-}
-
-function tipPrototype:AddSeparator(height, r, g, b, a)
-    local lineNum, colNum = self:AddLine()
-    local line = self.lines[lineNum]
-    local color = _G.NORMAL_FONT_COLOR
-
-    height = height or 1
-
-    SetTooltipSize(self, self.width, self.height + height)
-
-    line.height = height
-    line:SetHeight(height)
-    line:SetBackdrop(GenericBackdrop)
-    line:SetBackdropColor(r or color.r, g or color.g, b or color.b, a or 1)
-
-    return lineNum, colNum
-end
-
-function tipPrototype:SetCellColor(lineNum, colNum, r, g, b, a)
-    local cell = self.lines[lineNum].cells[colNum]
-
-    if cell then
-        local sr, sg, sb, sa = self:GetBackdropColor()
-
-        cell:SetBackdrop(GenericBackdrop)
-        cell:SetBackdropColor(r or sr, g or sg, b or sb, a or sa)
-    end
-end
-
-function tipPrototype:SetColumnColor(colNum, r, g, b, a)
-    local column = self.columns[colNum]
-
-    if column then
-        local sr, sg, sb, sa = self:GetBackdropColor()
-        column:SetBackdrop(GenericBackdrop)
-        column:SetBackdropColor(r or sr, g or sg, b or sb, a or sa)
-    end
-end
-
-function tipPrototype:SetLineColor(lineNum, r, g, b, a)
-    local line = self.lines[lineNum]
-
-    if line then
-        local sr, sg, sb, sa = self:GetBackdropColor()
-
-        line:SetBackdrop(GenericBackdrop)
-        line:SetBackdropColor(r or sr, g or sg, b or sb, a or sa)
-    end
-end
-
-function tipPrototype:SetCellTextColor(lineNum, colNum, r, g, b, a)
-    local line = self.lines[lineNum]
-    local column = self.columns[colNum]
-
-    if not line or not column then
-        return
-    end
-
-    local cell = self.lines[lineNum].cells[colNum]
-
-    if cell then
-        if not cell.fontString then
-            error("cell's label provider did not assign a fontString field", 2)
-        end
-
-        if not cell.r then
-            cell.r, cell.g, cell.b, cell.a = cell.fontString:GetTextColor()
-        end
-
-        cell.fontString:SetTextColor(r or cell.r, g or cell.g, b or cell.b, a or cell.a)
-    end
-end
-
-function tipPrototype:SetColumnTextColor(colNum, r, g, b, a)
-    if not self.columns[colNum] then
-        return
-    end
-
-    for lineIndex = 1, #self.lines do
-        self:SetCellTextColor(lineIndex, colNum, r, g, b, a)
-    end
-end
-
-function tipPrototype:SetLineTextColor(lineNum, r, g, b, a)
-    local line = self.lines[lineNum]
-
-    if not line then
-        return
-    end
-
-    for cellIndex = 1, #line.cells do
-        self:SetCellTextColor(lineNum, line.cells[cellIndex]._column, r, g, b, a)
-    end
-end
-
-function tipPrototype:SetHighlightTexture(...)
-    return highlightTexture:SetTexture(...)
-end
-
-function tipPrototype:SetHighlightTexCoord(...)
-    highlightTexture:SetTexCoord(...)
-end
-
-do
-    local function checkFont(font, level, silent)
-        local bad = false
-
-        if not font then
-            bad = true
-        elseif type(font) == "string" then
-            local ref = _G[font]
-
-            if not ref or type(ref) ~= "table" or type(ref.IsObjectType) ~= "function" or not ref:IsObjectType("Font") then
-                bad = true
-            end
-        elseif type(font) ~= "table" or type(font.IsObjectType) ~= "function" or not font:IsObjectType("Font") then
-            bad = true
-        end
-
-        if bad then
-            if silent then
-                return false
-            end
-
-            error("font must be a Font instance or a string matching the name of a global Font instance, not: " .. tostring(font), level + 1)
-        end
-        return true
-    end
-
-    function tipPrototype:SetFont(font)
-        local is_string = type(font) == "string"
-
-        checkFont(font, 2)
-        self.regularFont = is_string and _G[font] or font
-    end
-
-    function tipPrototype:SetHeaderFont(font)
-        local is_string = type(font) == "string"
-
-        checkFont(font, 2)
-        self.headerFont = is_string and _G[font] or font
-    end
-
-    -- TODO: fixed argument positions / remove checks for performance?
-    function tipPrototype:SetCell(lineNum, colNum, value, ...)
-        -- Mandatory argument checking
-        if type(lineNum) ~= "number" then
-            error("line number must be a number, not: " .. tostring(lineNum), 2)
-        elseif lineNum < 1 or lineNum > #self.lines then
-            error("line number out of range: " .. tostring(lineNum), 2)
-        elseif type(colNum) ~= "number" then
-            error("column number must be a number, not: " .. tostring(colNum), 2)
-        elseif colNum < 1 or colNum > #self.columns then
-            error("column number out of range: " .. tostring(colNum), 2)
-        end
-
-        -- Variable argument checking
-        local font, justification, colSpan, provider
-        local i, arg = 1, ...
-
-        if arg == nil or checkFont(arg, 2, true) then
-            i, font, arg = 2, ...
-        end
-
-        if arg == nil or checkJustification(arg, 2, true) then
-            i, justification, arg = i + 1, select(i, ...)
-        end
-
-        if arg == nil or type(arg) == "number" then
-            i, colSpan, arg = i + 1, select(i, ...)
-        end
-
-        if arg == nil or type(arg) == "table" and type(arg.AcquireCell) == "function" then
-            i, provider = i + 1, arg
-        end
-
-        return _SetCell(self, lineNum, colNum, value, font, justification, colSpan, provider, select(i, ...))
-    end
-end -- do-block
-
-function tipPrototype:GetFont()
-    return self.regularFont
-end
-
-function tipPrototype:GetHeaderFont()
-    return self.headerFont
-end
-
-function tipPrototype:GetLineCount()
-    return #self.lines
-end
-
-function tipPrototype:GetColumnCount()
-    return #self.columns
-end
-
-------------------------------------------------------------------------------
--- Frame Scripts
-------------------------------------------------------------------------------
-local scripts = {
-    OnEnter = function(frame, ...)
-        highlightFrame:SetParent(frame)
-        highlightFrame:SetAllPoints(frame)
-        highlightFrame:Show()
-
-        if frame._OnEnter_func then
-            frame:_OnEnter_func(frame._OnEnter_arg, ...)
-        end
-    end,
-    OnLeave = function(frame, ...)
-        highlightFrame:Hide()
-        highlightFrame:ClearAllPoints()
-        highlightFrame:SetParent(nil)
-
-        if frame._OnLeave_func then
-            frame:_OnLeave_func(frame._OnLeave_arg, ...)
-        end
-    end,
-    OnMouseDown = function(frame, ...)
-        frame:_OnMouseDown_func(frame._OnMouseDown_arg, ...)
-    end,
-    OnMouseUp = function(frame, ...)
-        frame:_OnMouseUp_func(frame._OnMouseUp_arg, ...)
-    end,
-    OnReceiveDrag = function(frame, ...)
-        frame:_OnReceiveDrag_func(frame._OnReceiveDrag_arg, ...)
-    end
-}
-
-function SetFrameScript(frame, script, func, arg)
-    if not scripts[script] then
-        return
-    end
-
-    frame["_" .. script .. "_func"] = func
-    frame["_" .. script .. "_arg"] = arg
-
-    if script == "OnMouseDown" or script == "OnMouseUp" or script == "OnReceiveDrag" then
-        if func then
-            frame:SetScript(script, scripts[script])
-        else
-            frame:SetScript(script, nil)
-        end
-    end
-
-    -- if at least one script is set, set the OnEnter/OnLeave scripts for the highlight
-    if frame._OnEnter_func or frame._OnLeave_func or frame._OnMouseDown_func or frame._OnMouseUp_func or frame._OnReceiveDrag_func then
-        frame:EnableMouse(true)
-        frame:SetScript("OnEnter", scripts.OnEnter)
-        frame:SetScript("OnLeave", scripts.OnLeave)
-    else
-        frame:EnableMouse(false)
-        frame:SetScript("OnEnter", nil)
-        frame:SetScript("OnLeave", nil)
-    end
-end
-
-function ClearFrameScripts(frame)
-    if frame._OnEnter_func or frame._OnLeave_func or frame._OnMouseDown_func or frame._OnMouseUp_func or frame._OnReceiveDrag_func then
-        frame:EnableMouse(false)
-
-        frame:SetScript("OnEnter", nil)
-        frame._OnEnter_func = nil
-        frame._OnEnter_arg = nil
-
-        frame:SetScript("OnLeave", nil)
-        frame._OnLeave_func = nil
-        frame._OnLeave_arg = nil
-
-        frame:SetScript("OnReceiveDrag", nil)
-        frame._OnReceiveDrag_func = nil
-        frame._OnReceiveDrag_arg = nil
-
-        frame:SetScript("OnMouseDown", nil)
-        frame._OnMouseDown_func = nil
-        frame._OnMouseDown_arg = nil
-
-        frame:SetScript("OnMouseUp", nil)
-        frame._OnMouseUp_func = nil
-        frame._OnMouseUp_arg = nil
-    end
-end
-
-function tipPrototype:SetLineScript(lineNum, script, func, arg)
-    SetFrameScript(self.lines[lineNum], script, func, arg)
-end
-
-function tipPrototype:SetColumnScript(colNum, script, func, arg)
-    SetFrameScript(self.columns[colNum], script, func, arg)
-end
-
-function tipPrototype:SetCellScript(lineNum, colNum, script, func, arg)
-    local cell = self.lines[lineNum].cells[colNum]
-
-    if cell then
-        SetFrameScript(cell, script, func, arg)
-    end
-end
-
-------------------------------------------------------------------------------
--- Auto-hiding feature
-------------------------------------------------------------------------------
-
--- Script of the auto-hiding child frame
-local function AutoHideTimerFrame_OnUpdate(self, elapsed)
-    self.checkElapsed = self.checkElapsed + elapsed
-
-    if self.checkElapsed > 0.1 then
-        if self.parent:IsMouseOver() or (self.alternateFrame and self.alternateFrame:IsMouseOver()) then
-            self.elapsed = 0
-        else
-            self.elapsed = self.elapsed + self.checkElapsed
-
-            if self.elapsed >= self.delay then
-                lib:Release(self.parent)
-            end
-        end
-
-        self.checkElapsed = 0
-    end
-end
-
--- Usage:
--- :SetAutoHideDelay(0.25) => hides after 0.25sec outside of the tooltip
--- :SetAutoHideDelay(0.25, someFrame) => hides after 0.25sec outside of both the tooltip and someFrame
--- :SetAutoHideDelay() => disable auto-hiding (default)
-function tipPrototype:SetAutoHideDelay(delay, alternateFrame, releaseHandler)
-    local timerFrame = self.autoHideTimerFrame
-    delay = tonumber(delay) or 0
-
-    if releaseHandler then
-        if type(releaseHandler) ~= "function" then
-            error("releaseHandler must be a function", 2)
-        end
-
-        lib.onReleaseHandlers[self] = releaseHandler
-    end
-
-    if delay > 0 then
-        if not timerFrame then
-            timerFrame = AcquireTimer(self)
-            timerFrame:SetScript("OnUpdate", AutoHideTimerFrame_OnUpdate)
-
-            self.autoHideTimerFrame = timerFrame
-        end
-
-        timerFrame.parent = self
-        timerFrame.checkElapsed = 0
-        timerFrame.elapsed = 0
-        timerFrame.delay = delay
-        timerFrame.alternateFrame = alternateFrame
-        timerFrame:Show()
-    elseif timerFrame then
-        self.autoHideTimerFrame = nil
-
-        timerFrame.alternateFrame = nil
-        timerFrame:SetScript("OnUpdate", nil)
-
-        ReleaseTimer(timerFrame)
-    end
-end
-
-------------------------------------------------------------------------------
--- "Smart" Anchoring
-------------------------------------------------------------------------------
-local function GetTipAnchor(frame)
-    local x, y = frame:GetCenter()
-
-    if not x or not y then
-        return "TOPLEFT", "BOTTOMLEFT"
-    end
-
-    local hhalf = (x > UIParent:GetWidth() * 2 / 3) and "RIGHT" or (x < UIParent:GetWidth() / 3) and "LEFT" or ""
-    local vhalf = (y > UIParent:GetHeight() / 2) and "TOP" or "BOTTOM"
-
-    return vhalf .. hhalf, frame, (vhalf == "TOP" and "BOTTOM" or "TOP") .. hhalf
-end
-
-function tipPrototype:SmartAnchorTo(frame)
-    if not frame then
-        error("Invalid frame provided.", 2)
-    end
-
-    self:ClearAllPoints()
-    self:SetClampedToScreen(true)
-    self:SetPoint(GetTipAnchor(frame))
-end
-
-------------------------------------------------------------------------------
--- Debug slashcmds
-------------------------------------------------------------------------------
--- @debug @
-local print = print
-local function PrintStats()
-    local tipCache = tostring(#tooltipHeap)
-    local frameCache = tostring(#frameHeap)
-    local tableCache = tostring(#tableHeap)
-    local header = false
-
-    print("Tooltips used: " .. usedTooltips .. ", Cached: " .. tipCache .. ", Total: " .. tipCache + usedTooltips)
-    print("Frames used: " .. usedFrames .. ", Cached: " .. frameCache .. ", Total: " .. frameCache + usedFrames)
-    print("Tables used: " .. usedTables .. ", Cached: " .. tableCache .. ", Total: " .. tableCache + usedTables)
-
-    for k in pairs(activeTooltips) do
-        if not header then
-            print("Active tooltips:")
-            header = true
-        end
-        print("- " .. k)
-    end
-end
-
-SLASH_LibQTip1 = "/qtip"
-_G.SlashCmdList["LibQTip"] = PrintStats
---@end-debug@]==]
diff --git a/Titan/libs/Ace/LibQTip-1.0/LibQTip-1.0.toc b/Titan/libs/Ace/LibQTip-1.0/LibQTip-1.0.toc
deleted file mode 100644
index d7d75e8..0000000
--- a/Titan/libs/Ace/LibQTip-1.0/LibQTip-1.0.toc
+++ /dev/null
@@ -1,15 +0,0 @@
-## Interface: 100007
-## Title: Lib: QTip-1.0
-## Notes: Library providing multi-column tooltips.
-## Author: Torhal, Adirelle, Elkano, Tristanian
-## Version: 10.0.7.1
-## LoadOnDemand: 1
-## X-Credits: Kaelten (input on initial design)
-## X-Category: Library, Tooltip
-## X-Curse-Project-ID: 15487
-## X-Date: 2023-03-29T21:01:29Z
-## X-License: Ace3 BSD-like license
-## X-Website: http://www.wowace.com/addons/libqtip-1-0/
-
-LibStub\LibStub.lua
-lib.xml
diff --git a/Titan/libs/Ace/LibQTip-1.0/LibStub/LibStub.lua b/Titan/libs/Ace/LibQTip-1.0/LibStub/LibStub.lua
deleted file mode 100644
index 7e7b76d..0000000
--- a/Titan/libs/Ace/LibQTip-1.0/LibStub/LibStub.lua
+++ /dev/null
@@ -1,51 +0,0 @@
--- $Id: LibStub.lua 103 2014-10-16 03:02:50Z mikk $
--- LibStub is a simple versioning stub meant for use in Libraries.  http://www.wowace.com/addons/libstub/ for more info
--- LibStub is hereby placed in the Public Domain
--- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
-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]
-
--- Check to see is this version of the stub is obsolete
-if not LibStub or LibStub.minor < LIBSTUB_MINOR then
-	LibStub = LibStub or {libs = {}, minors = {} }
-	_G[LIBSTUB_MAJOR] = LibStub
-	LibStub.minor = LIBSTUB_MINOR
-
-	-- LibStub:NewLibrary(major, minor)
-	-- major (string) - the major version of the library
-	-- minor (string or number ) - the minor version of the library
-	--
-	-- returns nil if a newer or same version of the lib is already present
-	-- returns empty library object or old library object if upgrade is needed
-	function LibStub:NewLibrary(major, minor)
-		assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
-		minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
-
-		local oldminor = self.minors[major]
-		if oldminor and oldminor >= minor then return nil end
-		self.minors[major], self.libs[major] = minor, self.libs[major] or {}
-		return self.libs[major], oldminor
-	end
-
-	-- LibStub:GetLibrary(major, [silent])
-	-- major (string) - the major version of the library
-	-- silent (boolean) - if true, library is optional, silently return nil if its not found
-	--
-	-- throws an error if the library can not be found (except silent is set)
-	-- returns the library object if found
-	function LibStub:GetLibrary(major, silent)
-		if not self.libs[major] and not silent then
-			error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
-		end
-		return self.libs[major], self.minors[major]
-	end
-
-	-- LibStub:IterateLibraries()
-	--
-	-- Returns an iterator for the currently registered libraries
-	function LibStub:IterateLibraries()
-		return pairs(self.libs)
-	end
-
-	setmetatable(LibStub, { __call = LibStub.GetLibrary })
-end
diff --git a/Titan/libs/Ace/LibQTip-1.0/README.md b/Titan/libs/Ace/LibQTip-1.0/README.md
deleted file mode 100644
index b61c509..0000000
--- a/Titan/libs/Ace/LibQTip-1.0/README.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# LibQTip-1.0
-LibQTip is designed replace GameTooltip - but with added functionality, such as multiple columns - from a minimalist design perspective.
-
-## Features
-- Ability to display and handle multiple tooltips at the same time,
-- Unlimited number of columns and lines,
-- Column default and per cell justification,
-- Tooltip default and per cell font setting,
-- Colspans,
-- Possibility to add custom cells,
-- Optional scrollbar,
-- Optional scripts for lines, columns, or cells,
-- Optional automatic hiding,
-- Frames and tables recycling to reduce resource footprint.
-
-## Caveats
-Look [here](https://www.wowace.com/projects/libqtip-1-0/pages/getting-started) for information on embedding the latest beta/release.
-
-**In order to achieve effective frame recycling, tooltips must be released.**
-
-Holding a tooltip leads to the creation of a full set of frames for every AddOn which does not follow this practice. Moreover, releasing a tooltip has a very little overhead compared to its benefits.
-
-## Known issues
-Alignment may be altered when using :SetScale after filling the tooltip.
-
-## Documentation
-- [Getting Started Guide](https://www.wowace.com/projects/libqtip-1-0/pages/getting-started)
-- [How to Add Custom Cells](https://www.wowace.com/projects/libqtip-1-0/pages/how-to-add-custom-cells)
-- [API Reference](https://www.wowace.com/projects/libqtip-1-0/pages/api-reference)
-- [Standard CellProvider API](https://www.wowace.com/projects/libqtip-1-0/pages/standard-cell-provider-api)
diff --git a/Titan/libs/Ace/LibQTip-1.0/lib.xml b/Titan/libs/Ace/LibQTip-1.0/lib.xml
deleted file mode 100644
index f212246..0000000
--- a/Titan/libs/Ace/LibQTip-1.0/lib.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
-..\FrameXML\UI.xsd">
-	<Script file="LibQTip-1.0.lua"/>
-</Ui>
\ No newline at end of file
diff --git a/Titan/libs/Ace/changelog.txt b/Titan/libs/Ace/changelog.txt
index db97361..0aff887 100644
--- a/Titan/libs/Ace/changelog.txt
+++ b/Titan/libs/Ace/changelog.txt
@@ -1,3 +1,10 @@
+Ace3 Release - Revision r1390 (February 3rd, 2026)
+--------------------------------------------------
+- AceConfigDialog-3.0: The original category ID is now preserved in AddToBlizOptions in 12.0, making it mandatory for addons to store the second return value and forward it to Settings.OpenToCategory
+- AceConfig-3.0: Widgets can now specify a relative size with width="relative" and relWidth="0.5"
+- AceGUI-3.0: Keybinding: Add basic gamepad support
+- AceGUI-3.0: TreeGroup: Consistently provide an alpha value for GameTooltip:SetText
+
 Ace3 Release - Revision r1377 (October 28th, 2025)
 --------------------------------------------------
 - AceComm-3.0: Updated ChatThrottleLib for WoW 12.0
diff --git a/Titan/libs/LibQTip-1.0/CHANGELOG.md b/Titan/libs/LibQTip-1.0/CHANGELOG.md
new file mode 100644
index 0000000..442bb65
--- /dev/null
+++ b/Titan/libs/LibQTip-1.0/CHANGELOG.md
@@ -0,0 +1,10 @@
+# Lib: QTip-1.0
+
+## [10.0.7.1](https://github.com/Torhal/LibQTip-1.0/tree/10.0.7.1) (2023-03-29)
+[Full Changelog](https://github.com/Torhal/LibQTip-1.0/compare/9.0.1.2...10.0.7.1) [Previous Releases](https://github.com/Torhal/LibQTip-1.0/releases)
+
+- Create release.yml
+    Add release configuration for the BigWigs Packager.
+- Update ToC Interface and add X-Curse-Project-ID to support the BigWigs Packager.
+- Create README.md
+- update for WoW 9.1.5's new TooltipBackdropTemplate
diff --git a/Titan/libs/LibQTip-1.0/LICENSE.txt b/Titan/libs/LibQTip-1.0/LICENSE.txt
new file mode 100644
index 0000000..9bc7b5c
--- /dev/null
+++ b/Titan/libs/LibQTip-1.0/LICENSE.txt
@@ -0,0 +1,29 @@
+Copyright (c) 2008, LibQTip Development Team
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+    * Redistribution of a stand alone version is strictly prohibited without
+      prior written authorization from the Lead of the LibQTip Development Team.
+    * Neither the name of the LibQTip Development Team nor the names of its contributors
+      may be used to endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Titan/libs/LibQTip-1.0/LibQTip-1.0.lua b/Titan/libs/LibQTip-1.0/LibQTip-1.0.lua
new file mode 100644
index 0000000..bb38c75
--- /dev/null
+++ b/Titan/libs/LibQTip-1.0/LibQTip-1.0.lua
@@ -0,0 +1,1565 @@
+local MAJOR = "LibQTip-1.0"
+local MINOR = 49 -- Should be manually increased
+local LibStub = _G.LibStub
+
+assert(LibStub, MAJOR .. " requires LibStub")
+
+local lib, oldMinor = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not lib then
+    return
+end -- No upgrade needed
+
+------------------------------------------------------------------------------
+-- Upvalued globals
+------------------------------------------------------------------------------
+local table = _G.table
+local tinsert = table.insert
+local tremove = table.remove
+local wipe = table.wipe
+
+local error = error
+local math = math
+local min, max = math.min, math.max
+local next = next
+local pairs, ipairs = pairs, ipairs
+local select = select
+local setmetatable = setmetatable
+local tonumber, tostring = tonumber, tostring
+local type = type
+
+local CreateFrame = _G.CreateFrame
+local GameTooltip = _G.GameTooltip
+local UIParent = _G.UIParent
+
+local geterrorhandler = _G.geterrorhandler
+
+------------------------------------------------------------------------------
+-- Tables and locals
+------------------------------------------------------------------------------
+lib.frameMetatable = lib.frameMetatable or {__index = CreateFrame("Frame")}
+
+lib.tipPrototype = lib.tipPrototype or setmetatable({}, lib.frameMetatable)
+lib.tipMetatable = lib.tipMetatable or {__index = lib.tipPrototype}
+
+lib.providerPrototype = lib.providerPrototype or {}
+lib.providerMetatable = lib.providerMetatable or {__index = lib.providerPrototype}
+
+lib.cellPrototype = lib.cellPrototype or setmetatable({}, lib.frameMetatable)
+lib.cellMetatable = lib.cellMetatable or {__index = lib.cellPrototype}
+
+lib.activeTooltips = lib.activeTooltips or {}
+
+lib.tooltipHeap = lib.tooltipHeap or {}
+lib.frameHeap = lib.frameHeap or {}
+lib.timerHeap = lib.timerHeap or {}
+lib.tableHeap = lib.tableHeap or {}
+
+lib.onReleaseHandlers = lib.onReleaseHandlers or {}
+
+local tipPrototype = lib.tipPrototype
+local tipMetatable = lib.tipMetatable
+
+local providerPrototype = lib.providerPrototype
+local providerMetatable = lib.providerMetatable
+
+local cellPrototype = lib.cellPrototype
+local cellMetatable = lib.cellMetatable
+
+local activeTooltips = lib.activeTooltips
+
+local highlightFrame = CreateFrame("Frame", nil, UIParent)
+highlightFrame:SetFrameStrata("TOOLTIP")
+highlightFrame:Hide()
+
+local DEFAULT_HIGHLIGHT_TEXTURE_PATH = [[Interface\QuestFrame\UI-QuestTitleHighlight]]
+
+local highlightTexture = highlightFrame:CreateTexture(nil, "OVERLAY")
+highlightTexture:SetTexture(DEFAULT_HIGHLIGHT_TEXTURE_PATH)
+highlightTexture:SetBlendMode("ADD")
+highlightTexture:SetAllPoints(highlightFrame)
+
+------------------------------------------------------------------------------
+-- Private methods for Caches and Tooltip
+------------------------------------------------------------------------------
+local AcquireTooltip, ReleaseTooltip
+local AcquireCell, ReleaseCell
+local AcquireTable, ReleaseTable
+
+local InitializeTooltip, SetTooltipSize, ResetTooltipSize, FixCellSizes
+local ClearTooltipScripts
+local SetFrameScript, ClearFrameScripts
+
+------------------------------------------------------------------------------
+-- Cache debugging.
+------------------------------------------------------------------------------
+-- @debug @
+local usedTables, usedFrames, usedTooltips = 0, 0, 0
+--@end-debug@]==]
+
+------------------------------------------------------------------------------
+-- Internal constants to tweak the layout
+------------------------------------------------------------------------------
+local TOOLTIP_PADDING = 10
+local CELL_MARGIN_H = 6
+local CELL_MARGIN_V = 3
+
+------------------------------------------------------------------------------
+-- Public library API
+------------------------------------------------------------------------------
+--- Create or retrieve the tooltip with the given key.
+-- If additional arguments are passed, they are passed to :SetColumnLayout for the acquired tooltip.
+-- @name LibQTip:Acquire(key[, numColumns, column1Justification, column2justification, ...])
+-- @param key string or table - the tooltip key. Any value that can be used as a table key is accepted though you should try to provide unique keys to avoid conflicts.
+-- Numbers and booleans should be avoided and strings should be carefully chosen to avoid namespace clashes - no "MyTooltip" - you have been warned!
+-- @return tooltip Frame object - the acquired tooltip.
+-- @usage Acquire a tooltip with at least 5 columns, justification : left, center, left, left, left
+-- <pre>local tip = LibStub('LibQTip-1.0'):Acquire('MyFooBarTooltip', 5, "LEFT", "CENTER")</pre>
+function lib:Acquire(key, ...)
+    if key == nil then
+        error("attempt to use a nil key", 2)
+    end
+
+    local tooltip = activeTooltips[key]
+
+    if not tooltip then
+        tooltip = AcquireTooltip()
+        InitializeTooltip(tooltip, key)
+        activeTooltips[key] = tooltip
+    end
+
+    if select("#", ...) > 0 then
+        -- Here we catch any error to properly report it for the calling code
+        local ok, msg = pcall(tooltip.SetColumnLayout, tooltip, ...)
+
+        if not ok then
+            error(msg, 2)
+        end
+    end
+
+    return tooltip
+end
+
+function lib:Release(tooltip)
+    local key = tooltip and tooltip.key
+
+    if not key or activeTooltips[key] ~= tooltip then
+        return
+    end
+
+    ReleaseTooltip(tooltip)
+    activeTooltips[key] = nil
+end
+
+function lib:IsAcquired(key)
+    if key == nil then
+        error("attempt to use a nil key", 2)
+    end
+
+    return not (not activeTooltips[key])
+end
+
+function lib:IterateTooltips()
+    return pairs(activeTooltips)
+end
+
+------------------------------------------------------------------------------
+-- Frame cache (for lines and columns)
+------------------------------------------------------------------------------
+local frameHeap = lib.frameHeap
+
+local function AcquireFrame(parent)
+    local frame = tremove(frameHeap) or CreateFrame("Frame", nil, nil, BackdropTemplateMixin and "BackdropTemplate")
+    frame:SetParent(parent)
+    --[==[@debug@
+    usedFrames = usedFrames + 1
+    --@end-debug@]==]
+    return frame
+end
+
+local function ReleaseFrame(frame)
+    frame:Hide()
+    frame:SetParent(nil)
+    frame:ClearAllPoints()
+    frame:SetBackdrop(nil)
+
+    ClearFrameScripts(frame)
+
+    tinsert(frameHeap, frame)
+    --[==[@debug@
+    usedFrames = usedFrames - 1
+    --@end-debug@]==]
+end
+
+------------------------------------------------------------------------------
+-- Timer cache
+------------------------------------------------------------------------------
+local timerHeap = lib.timerHeap
+
+local function AcquireTimer(parent)
+    local frame = tremove(timerHeap) or CreateFrame("Frame")
+    frame:SetParent(parent)
+    return frame
+end
+
+local function ReleaseTimer(frame)
+    frame:Hide()
+    frame:SetParent(nil)
+
+    ClearFrameScripts(frame)
+
+    tinsert(timerHeap, frame)
+end
+
+------------------------------------------------------------------------------
+-- Dirty layout handler
+------------------------------------------------------------------------------
+lib.layoutCleaner = lib.layoutCleaner or CreateFrame("Frame")
+
+local layoutCleaner = lib.layoutCleaner
+layoutCleaner.registry = layoutCleaner.registry or {}
+
+function layoutCleaner:RegisterForCleanup(tooltip)
+    self.registry[tooltip] = true
+    self:Show()
+end
+
+function layoutCleaner:CleanupLayouts()
+    self:Hide()
+
+    for tooltip in pairs(self.registry) do
+        FixCellSizes(tooltip)
+    end
+
+    wipe(self.registry)
+end
+
+layoutCleaner:SetScript("OnUpdate", layoutCleaner.CleanupLayouts)
+
+------------------------------------------------------------------------------
+-- CellProvider and Cell
+------------------------------------------------------------------------------
+function providerPrototype:AcquireCell()
+    local cell = tremove(self.heap)
+
+    if not cell then
+        cell = CreateFrame("Frame", nil, UIParent, BackdropTemplateMixin and "BackdropTemplate")
+        setmetatable(cell, self.cellMetatable)
+
+        if type(cell.InitializeCell) == "function" then
+            cell:InitializeCell()
+        end
+    end
+
+    self.cells[cell] = true
+
+    return cell
+end
+
+function providerPrototype:ReleaseCell(cell)
+    if not self.cells[cell] then
+        return
+    end
+
+    if type(cell.ReleaseCell) == "function" then
+        cell:ReleaseCell()
+    end
+
+    self.cells[cell] = nil
+    tinsert(self.heap, cell)
+end
+
+function providerPrototype:GetCellPrototype()
+    return self.cellPrototype, self.cellMetatable
+end
+
+function providerPrototype:IterateCells()
+    return pairs(self.cells)
+end
+
+function lib:CreateCellProvider(baseProvider)
+    local cellBaseMetatable, cellBasePrototype
+
+    if baseProvider and baseProvider.GetCellPrototype then
+        cellBasePrototype, cellBaseMetatable = baseProvider:GetCellPrototype()
+    else
+        cellBaseMetatable = cellMetatable
+    end
+
+    local newCellPrototype = setmetatable({}, cellBaseMetatable)
+    local newCellProvider = setmetatable({}, providerMetatable)
+
+    newCellProvider.heap = {}
+    newCellProvider.cells = {}
+    newCellProvider.cellPrototype = newCellPrototype
+    newCellProvider.cellMetatable = {__index = newCellPrototype}
+
+    return newCellProvider, newCellPrototype, cellBasePrototype
+end
+
+------------------------------------------------------------------------------
+-- Basic label provider
+------------------------------------------------------------------------------
+if not lib.LabelProvider then
+    lib.LabelProvider, lib.LabelPrototype = lib:CreateCellProvider()
+end
+
+local labelProvider = lib.LabelProvider
+local labelPrototype = lib.LabelPrototype
+
+function labelPrototype:InitializeCell()
+    self.fontString = self:CreateFontString()
+    self.fontString:SetFontObject(_G.GameTooltipText)
+end
+
+function labelPrototype:SetupCell(tooltip, value, justification, font, leftPadding, rightPadding, maxWidth, minWidth, ...)
+    local fontString = self.fontString
+    local line = tooltip.lines[self._line]
+
+    -- detatch fs from cell for size calculations
+    fontString:ClearAllPoints()
+    fontString:SetFontObject(font or (line.is_header and tooltip:GetHeaderFont() or tooltip:GetFont()))
+    fontString:SetJustifyH(justification)
+    fontString:SetText(tostring(value))
+
+    leftPadding = leftPadding or 0
+    rightPadding = rightPadding or 0
+
+    local width = fontString:GetStringWidth() + leftPadding + rightPadding
+
+    if maxWidth and minWidth and (maxWidth < minWidth) then
+        error("maximum width cannot be lower than minimum width: " .. tostring(maxWidth) .. " < " .. tostring(minWidth), 2)
+    end
+
+    if maxWidth and (maxWidth < (leftPadding + rightPadding)) then
+        error("maximum width cannot be lower than the sum of paddings: " .. tostring(maxWidth) .. " < " .. tostring(leftPadding) .. " + " .. tostring(rightPadding), 2)
+    end
+
+    if minWidth and width < minWidth then
+        width = minWidth
+    end
+
+    if maxWidth and maxWidth < width then
+        width = maxWidth
+    end
+
+    fontString:SetWidth(width - (leftPadding + rightPadding))
+    -- Use GetHeight() instead of GetStringHeight() so lines which are longer than width will wrap.
+    local height = fontString:GetHeight()
+
+    -- reanchor fs to cell
+    fontString:SetWidth(0)
+    fontString:SetPoint("TOPLEFT", self, "TOPLEFT", leftPadding, 0)
+    fontString:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -rightPadding, 0)
+    --~ 	fs:SetPoint("TOPRIGHT", self, "TOPRIGHT", -r_pad, 0)
+
+    self._paddingL = leftPadding
+    self._paddingR = rightPadding
+
+    return width, height
+end
+
+function labelPrototype:getContentHeight()
+    local fontString = self.fontString
+    fontString:SetWidth(self:GetWidth() - (self._paddingL + self._paddingR))
+
+    local height = self.fontString:GetHeight()
+    fontString:SetWidth(0)
+
+    return height
+end
+
+function labelPrototype:GetPosition()
+    return self._line, self._column
+end
+
+------------------------------------------------------------------------------
+-- Tooltip cache
+------------------------------------------------------------------------------
+local tooltipHeap = lib.tooltipHeap
+
+-- Returns a tooltip
+function AcquireTooltip()
+    local tooltip = tremove(tooltipHeap)
+
+    if not tooltip then
+        local template = (TooltipBackdropTemplateMixin and "TooltipBackdropTemplate") or (BackdropTemplateMixin and "BackdropTemplate")
+        tooltip = CreateFrame("Frame", nil, UIParent, template)
+
+        local scrollFrame = CreateFrame("ScrollFrame", nil, tooltip)
+        scrollFrame:SetPoint("TOP", tooltip, "TOP", 0, -TOOLTIP_PADDING)
+        scrollFrame:SetPoint("BOTTOM", tooltip, "BOTTOM", 0, TOOLTIP_PADDING)
+        scrollFrame:SetPoint("LEFT", tooltip, "LEFT", TOOLTIP_PADDING, 0)
+        scrollFrame:SetPoint("RIGHT", tooltip, "RIGHT", -TOOLTIP_PADDING, 0)
+        tooltip.scrollFrame = scrollFrame
+
+        local scrollChild = CreateFrame("Frame", nil, tooltip.scrollFrame)
+        scrollFrame:SetScrollChild(scrollChild)
+        tooltip.scrollChild = scrollChild
+
+        setmetatable(tooltip, tipMetatable)
+    end
+
+    --[==[@debug@
+    usedTooltips = usedTooltips + 1
+    --@end-debug@]==]
+    return tooltip
+end
+
+-- Cleans the tooltip and stores it in the cache
+function ReleaseTooltip(tooltip)
+    if tooltip.releasing then
+        return
+    end
+
+    tooltip.releasing = true
+    tooltip:Hide()
+
+    local releaseHandler = lib.onReleaseHandlers[tooltip]
+
+    if releaseHandler then
+        lib.onReleaseHandlers[tooltip] = nil
+
+        local success, errorMessage = pcall(releaseHandler, tooltip)
+
+        if not success then
+            geterrorhandler()(errorMessage)
+        end
+    elseif tooltip.OnRelease then
+        local success, errorMessage = pcall(tooltip.OnRelease, tooltip)
+        if not success then
+            geterrorhandler()(errorMessage)
+        end
+
+        tooltip.OnRelease = nil
+    end
+
+    tooltip.releasing = nil
+    tooltip.key = nil
+    tooltip.step = nil
+
+    ClearTooltipScripts(tooltip)
+
+    tooltip:SetAutoHideDelay(nil)
+    tooltip:ClearAllPoints()
+    tooltip:Clear()
+
+    if tooltip.slider then
+        tooltip.slider:SetValue(0)
+        tooltip.slider:Hide()
+        tooltip.scrollFrame:SetPoint("RIGHT", tooltip, "RIGHT", -TOOLTIP_PADDING, 0)
+        tooltip:EnableMouseWheel(false)
+    end
+
+    for i, column in ipairs(tooltip.columns) do
+        tooltip.columns[i] = ReleaseFrame(column)
+    end
+
+    tooltip.columns = ReleaseTable(tooltip.columns)
+    tooltip.lines = ReleaseTable(tooltip.lines)
+    tooltip.colspans = ReleaseTable(tooltip.colspans)
+
+    layoutCleaner.registry[tooltip] = nil
+
+    if TooltipBackdropTemplateMixin and not tooltip.NineSlice then
+        -- don't recycle outdated tooltips into heap
+        tooltip = nil
+    end
+
+    if tooltip then
+        tinsert(tooltipHeap, tooltip)
+    end
+
+    highlightTexture:SetTexture(DEFAULT_HIGHLIGHT_TEXTURE_PATH)
+    highlightTexture:SetTexCoord(0, 1, 0, 1)
+
+    --[==[@debug@
+    usedTooltips = usedTooltips - 1
+    --@end-debug@]==]
+end
+
+------------------------------------------------------------------------------
+-- Cell 'cache' (just a wrapper to the provider's cache)
+------------------------------------------------------------------------------
+-- Returns a cell for the given tooltip from the given provider
+function AcquireCell(tooltip, provider)
+    local cell = provider:AcquireCell(tooltip)
+
+    cell:SetParent(tooltip.scrollChild)
+    cell:SetFrameLevel(tooltip.scrollChild:GetFrameLevel() + 3)
+    cell._provider = provider
+
+    return cell
+end
+
+-- Cleans the cell hands it to its provider for storing
+function ReleaseCell(cell)
+    if cell.fontString and cell.r then
+        cell.fontString:SetTextColor(cell.r, cell.g, cell.b, cell.a)
+    end
+
+    cell._font = nil
+    cell._justification = nil
+    cell._colSpan = nil
+    cell._line = nil
+    cell._column = nil
+
+    cell:Hide()
+    cell:ClearAllPoints()
+    cell:SetParent(nil)
+    cell:SetBackdrop(nil)
+
+    ClearFrameScripts(cell)
+
+    cell._provider:ReleaseCell(cell)
+    cell._provider = nil
+end
+
+------------------------------------------------------------------------------
+-- Table cache
+------------------------------------------------------------------------------
+local tableHeap = lib.tableHeap
+
+-- Returns a table
+function AcquireTable()
+    local tbl = tremove(tableHeap) or {}
+    --[==[@debug@
+    usedTables = usedTables + 1
+    --@end-debug@]==]
+    return tbl
+end
+
+-- Cleans the table and stores it in the cache
+function ReleaseTable(tableInstance)
+    wipe(tableInstance)
+    tinsert(tableHeap, tableInstance)
+    --[==[@debug@
+    usedTables = usedTables - 1
+    --@end-debug@]==]
+end
+
+------------------------------------------------------------------------------
+-- Tooltip prototype
+------------------------------------------------------------------------------
+function InitializeTooltip(tooltip, key)
+    ----------------------------------------------------------------------
+    -- (Re)set frame settings
+    ----------------------------------------------------------------------
+    if TooltipBackdropTemplateMixin then
+        tooltip.layoutType = GameTooltip.layoutType
+        NineSlicePanelMixin.OnLoad(tooltip.NineSlice)
+        if GameTooltip.layoutType then
+            tooltip.NineSlice:SetCenterColor(GameTooltip.NineSlice:GetCenterColor())
+            tooltip.NineSlice:SetBorderColor(GameTooltip.NineSlice:GetBorderColor())
+        end
+    else
+        local backdrop = GameTooltip:GetBackdrop()
+
+        tooltip:SetBackdrop(backdrop)
+
+        if backdrop then
+            tooltip:SetBackdropColor(GameTooltip:GetBackdropColor())
+            tooltip:SetBackdropBorderColor(GameTooltip:GetBackdropBorderColor())
+        end
+    end
+
+    tooltip:SetScale(GameTooltip:GetScale())
+    tooltip:SetAlpha(1)
+    tooltip:SetFrameStrata("TOOLTIP")
+    tooltip:SetClampedToScreen(false)
+
+    ----------------------------------------------------------------------
+    -- Internal data. Since it's possible to Acquire twice without calling
+    -- release, check for pre-existence.
+    ----------------------------------------------------------------------
+    tooltip.key = key
+    tooltip.columns = tooltip.columns or AcquireTable()
+    tooltip.lines = tooltip.lines or AcquireTable()
+    tooltip.colspans = tooltip.colspans or AcquireTable()
+    tooltip.regularFont = _G.GameTooltipText
+    tooltip.headerFont = _G.GameTooltipHeaderText
+    tooltip.labelProvider = labelProvider
+    tooltip.cell_margin_h = tooltip.cell_margin_h or CELL_MARGIN_H
+    tooltip.cell_margin_v = tooltip.cell_margin_v or CELL_MARGIN_V
+
+    ----------------------------------------------------------------------
+    -- Finishing procedures
+    ----------------------------------------------------------------------
+    tooltip:SetAutoHideDelay(nil)
+    tooltip:Hide()
+    ResetTooltipSize(tooltip)
+end
+
+function tipPrototype:SetDefaultProvider(myProvider)
+    if not myProvider then
+        return
+    end
+
+    self.labelProvider = myProvider
+end
+
+function tipPrototype:GetDefaultProvider()
+    return self.labelProvider
+end
+
+local function checkJustification(justification, level, silent)
+    if justification ~= "LEFT" and justification ~= "CENTER" and justification ~= "RIGHT" then
+        if silent then
+            return false
+        end
+        error("invalid justification, must one of LEFT, CENTER or RIGHT, not: " .. tostring(justification), level + 1)
+    end
+
+    return true
+end
+
+function tipPrototype:SetColumnLayout(numColumns, ...)
+    if type(numColumns) ~= "number" or numColumns < 1 then
+        error("number of columns must be a positive number, not: " .. tostring(numColumns), 2)
+    end
+
+    for i = 1, numColumns do
+        local justification = select(i, ...) or "LEFT"
+
+        checkJustification(justification, 2)
+
+        if self.columns[i] then
+            self.columns[i].justification = justification
+        else
+            self:AddColumn(justification)
+        end
+    end
+end
+
+function tipPrototype:AddColumn(justification)
+    justification = justification or "LEFT"
+    checkJustification(justification, 2)
+
+    local colNum = #self.columns + 1
+    local column = self.columns[colNum] or AcquireFrame(self.scrollChild)
+
+    column:SetFrameLevel(self.scrollChild:GetFrameLevel() + 1)
+    column.justification = justification
+    column.width = 0
+    column:SetWidth(1)
+    column:SetPoint("TOP", self.scrollChild)
+    column:SetPoint("BOTTOM", self.scrollChild)
+
+    if colNum > 1 then
+        local h_margin = self.cell_margin_h or CELL_MARGIN_H
+
+        column:SetPoint("LEFT", self.columns[colNum - 1], "RIGHT", h_margin, 0)
+        SetTooltipSize(self, self.width + h_margin, self.height)
+    else
+        column:SetPoint("LEFT", self.scrollChild)
+    end
+
+    column:Show()
+    self.columns[colNum] = column
+
+    return colNum
+end
+
+------------------------------------------------------------------------------
+-- Convenient methods
+------------------------------------------------------------------------------
+function tipPrototype:Release()
+    lib:Release(self)
+end
+
+function tipPrototype:IsAcquiredBy(key)
+    return key ~= nil and self.key == key
+end
+
+------------------------------------------------------------------------------
+-- Script hooks
+------------------------------------------------------------------------------
+local RawSetScript = lib.frameMetatable.__index.SetScript
+
+function ClearTooltipScripts(tooltip)
+    if tooltip.scripts then
+        for scriptType in pairs(tooltip.scripts) do
+            RawSetScript(tooltip, scriptType, nil)
+        end
+
+        tooltip.scripts = ReleaseTable(tooltip.scripts)
+    end
+end
+
+function tipPrototype:SetScript(scriptType, handler)
+    RawSetScript(self, scriptType, handler)
+
+    if handler then
+        if not self.scripts then
+            self.scripts = AcquireTable()
+        end
+
+        self.scripts[scriptType] = true
+    elseif self.scripts then
+        self.scripts[scriptType] = nil
+    end
+end
+
+-- That might break some addons ; those addons were breaking other
+-- addons' tooltip though.
+function tipPrototype:HookScript()
+    geterrorhandler()(":HookScript is not allowed on LibQTip tooltips")
+end
+
+------------------------------------------------------------------------------
+-- Scrollbar data and functions
+------------------------------------------------------------------------------
+local BACKDROP_SLIDER_8_8 = BACKDROP_SLIDER_8_8 or {
+    bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
+    edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
+    tile = true,
+    tileEdge = true,
+    tileSize = 8,
+    edgeSize = 8,
+    insets = { left = 3, right = 3, top = 6, bottom = 6 },
+};
+
+local function slider_OnValueChanged(self)
+    self.scrollFrame:SetVerticalScroll(self:GetValue())
+end
+
+local function tooltip_OnMouseWheel(self, delta)
+    local slider = self.slider
+    local currentValue = slider:GetValue()
+    local minValue, maxValue = slider:GetMinMaxValues()
+    local stepValue = self.step or 10
+
+    if delta < 0 and currentValue < maxValue then
+        slider:SetValue(min(maxValue, currentValue + stepValue))
+    elseif delta > 0 and currentValue > minValue then
+        slider:SetValue(max(minValue, currentValue - stepValue))
+    end
+end
+
+-- Set the step size for the scroll bar
+function tipPrototype:SetScrollStep(step)
+    self.step = step
+end
+
+-- will resize the tooltip to fit the screen and show a scrollbar if needed
+function tipPrototype:UpdateScrolling(maxheight)
+    self:SetClampedToScreen(false)
+
+    -- all data is in the tooltip; fix colspan width and prevent the layout cleaner from messing up the tooltip later
+    FixCellSizes(self)
+    layoutCleaner.registry[self] = nil
+
+    local scale = self:GetScale()
+    local topside = self:GetTop()
+    local bottomside = self:GetBottom()
+    local screensize = UIParent:GetHeight() / scale
+    local tipsize = (topside - bottomside)
+
+    -- if the tooltip would be too high, limit its height and show the slider
+    if bottomside < 0 or topside > screensize or (maxheight and tipsize > maxheight) then
+        local shrink = (bottomside < 0 and (5 - bottomside) or 0) + (topside > screensize and (topside - screensize + 5) or 0)
+
+        if maxheight and tipsize - shrink > maxheight then
+            shrink = tipsize - maxheight
+        end
+
+        self:SetHeight(2 * TOOLTIP_PADDING + self.height - shrink)
+        self:SetWidth(2 * TOOLTIP_PADDING + self.width + 20)
+        self.scrollFrame:SetPoint("RIGHT", self, "RIGHT", -(TOOLTIP_PADDING + 20), 0)
+
+        if not self.slider then
+            local slider = CreateFrame("Slider", nil, self, BackdropTemplateMixin and "BackdropTemplate")
+            slider.scrollFrame = self.scrollFrame
+
+            slider:SetOrientation("VERTICAL")
+            slider:SetPoint("TOPRIGHT", self, "TOPRIGHT", -TOOLTIP_PADDING, -TOOLTIP_PADDING)
+            slider:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -TOOLTIP_PADDING, TOOLTIP_PADDING)
+            slider:SetBackdrop(BACKDROP_SLIDER_8_8)
+            slider:SetThumbTexture([[Interface\Buttons\UI-SliderBar-Button-Vertical]])
+            slider:SetMinMaxValues(0, 1)
+            slider:SetValueStep(1)
+            slider:SetWidth(12)
+            slider:SetScript("OnValueChanged", slider_OnValueChanged)
+            slider:SetValue(0)
+
+            self.slider = slider
+        end
+
+        self.slider:SetMinMaxValues(0, shrink)
+        self.slider:Show()
+
+        self:EnableMouseWheel(true)
+        self:SetScript("OnMouseWheel", tooltip_OnMouseWheel)
+    else
+        self:SetHeight(2 * TOOLTIP_PADDING + self.height)
+        self:SetWidth(2 * TOOLTIP_PADDING + self.width)
+
+        self.scrollFrame:SetPoint("RIGHT", self, "RIGHT", -TOOLTIP_PADDING, 0)
+
+        if self.slider then
+            self.slider:SetValue(0)
+            self.slider:Hide()
+
+            self:EnableMouseWheel(false)
+            self:SetScript("OnMouseWheel", nil)
+        end
+    end
+end
+
+------------------------------------------------------------------------------
+-- Tooltip methods for changing its contents.
+------------------------------------------------------------------------------
+function tipPrototype:Clear()
+    for i, line in ipairs(self.lines) do
+        for _, cell in pairs(line.cells) do
+            if cell then
+                ReleaseCell(cell)
+            end
+        end
+
+        ReleaseTable(line.cells)
+
+        line.cells = nil
+        line.is_header = nil
+
+        ReleaseFrame(line)
+
+        self.lines[i] = nil
+    end
+
+    for _, column in ipairs(self.columns) do
+        column.width = 0
+        column:SetWidth(1)
+    end
+
+    wipe(self.colspans)
+
+    self.cell_margin_h = nil
+    self.cell_margin_v = nil
+
+    ResetTooltipSize(self)
+end
+
+function tipPrototype:SetCellMarginH(size)
+    if #self.lines > 0 then
+        error("Unable to set horizontal margin while the tooltip has lines.", 2)
+    end
+
+    if not size or type(size) ~= "number" or size < 0 then
+        error("Margin size must be a positive number or zero.", 2)
+    end
+
+    self.cell_margin_h = size
+end
+
+function tipPrototype:SetCellMarginV(size)
+    if #self.lines > 0 then
+        error("Unable to set vertical margin while the tooltip has lines.", 2)
+    end
+
+    if not size or type(size) ~= "number" or size < 0 then
+        error("Margin size must be a positive number or zero.", 2)
+    end
+
+    self.cell_margin_v = size
+end
+
+function SetTooltipSize(tooltip, width, height)
+    tooltip.height = height
+    tooltip.width = width
+
+    tooltip:SetHeight(2 * TOOLTIP_PADDING + height)
+    tooltip:SetWidth(2 * TOOLTIP_PADDING + width)
+
+    tooltip.scrollChild:SetHeight(height)
+    tooltip.scrollChild:SetWidth(width)
+end
+
+-- Add 2 pixels to height so dangling letters (g, y, p, j, etc) are not clipped.
+function ResetTooltipSize(tooltip)
+    local h_margin = tooltip.cell_margin_h or CELL_MARGIN_H
+
+    SetTooltipSize(tooltip, max(0, (h_margin * (#tooltip.columns - 1)) + (h_margin / 2)), 2)
+end
+
+local function EnlargeColumn(tooltip, column, width)
+    if width > column.width then
+        SetTooltipSize(tooltip, tooltip.width + width - column.width, tooltip.height)
+
+        column.width = width
+        column:SetWidth(width)
+    end
+end
+
+local function ResizeLine(tooltip, line, height)
+    SetTooltipSize(tooltip, tooltip.width, tooltip.height + height - line.height)
+
+    line.height = height
+    line:SetHeight(height)
+end
+
+function FixCellSizes(tooltip)
+    local columns = tooltip.columns
+    local colspans = tooltip.colspans
+    local lines = tooltip.lines
+    local h_margin = tooltip.cell_margin_h or CELL_MARGIN_H
+
+    -- resize columns to make room for the colspans
+    while next(colspans) do
+        local maxNeedCols
+        local maxNeedWidthPerCol = 0
+
+        -- calculate the colspan with the highest additional width need per column
+        for colRange, width in pairs(colspans) do
+            local left, right = colRange:match("^(%d+)%-(%d+)$")
+
+            left, right = tonumber(left), tonumber(right)
+
+            for col = left, right - 1 do
+                width = width - columns[col].width - h_margin
+            end
+
+            width = width - columns[right].width
+
+            if width <= 0 then
+                colspans[colRange] = nil
+            else
+                width = width / (right - left + 1)
+
+                if width > maxNeedWidthPerCol then
+                    maxNeedCols = colRange
+                    maxNeedWidthPerCol = width
+                end
+            end
+        end
+
+        -- resize all columns for that colspan
+        if maxNeedCols then
+            local left, right = maxNeedCols:match("^(%d+)%-(%d+)$")
+
+            for col = left, right do
+                EnlargeColumn(tooltip, columns[col], columns[col].width + maxNeedWidthPerCol)
+            end
+
+            colspans[maxNeedCols] = nil
+        end
+    end
+
+    --now that the cell width is set, recalculate the rows' height
+    for _, line in ipairs(lines) do
+        if #(line.cells) > 0 then
+            local lineheight = 0
+
+            for _, cell in pairs(line.cells) do
+                if cell then
+                    lineheight = max(lineheight, cell:getContentHeight())
+                end
+            end
+
+            if lineheight > 0 then
+                ResizeLine(tooltip, line, lineheight)
+            end
+        end
+    end
+end
+
+local function _SetCell(tooltip, lineNum, colNum, value, font, justification, colSpan, provider, ...)
+    local line = tooltip.lines[lineNum]
+    local cells = line.cells
+
+    -- Unset: be quick
+    if value == nil then
+        local cell = cells[colNum]
+
+        if cell then
+            for i = colNum, colNum + cell._colSpan - 1 do
+                cells[i] = nil
+            end
+
+            ReleaseCell(cell)
+        end
+
+        return lineNum, colNum
+    end
+
+    font = font or (line.is_header and tooltip.headerFont or tooltip.regularFont)
+
+    -- Check previous cell
+    local cell
+    local prevCell = cells[colNum]
+
+    if prevCell then
+        -- There is a cell here
+        justification = justification or prevCell._justification
+        colSpan = colSpan or prevCell._colSpan
+
+        -- Clear the currently marked colspan
+        for i = colNum + 1, colNum + prevCell._colSpan - 1 do
+            cells[i] = nil
+        end
+
+        if provider == nil or prevCell._provider == provider then
+            -- Reuse existing cell
+            cell = prevCell
+            provider = cell._provider
+        else
+            -- A new cell is required
+            cells[colNum] = ReleaseCell(prevCell)
+        end
+    elseif prevCell == nil then
+        -- Creating a new cell, using meaningful defaults.
+        provider = provider or tooltip.labelProvider
+        justification = justification or tooltip.columns[colNum].justification or "LEFT"
+        colSpan = colSpan or 1
+    else
+        error("overlapping cells at column " .. colNum, 3)
+    end
+
+    local tooltipWidth = #tooltip.columns
+    local rightColNum
+
+    if colSpan > 0 then
+        rightColNum = colNum + colSpan - 1
+
+        if rightColNum > tooltipWidth then
+            error("ColSpan too big, cell extends beyond right-most column", 3)
+        end
+    else
+        -- Zero or negative: count back from right-most columns
+        rightColNum = max(colNum, tooltipWidth + colSpan)
+        -- Update colspan to its effective value
+        colSpan = 1 + rightColNum - colNum
+    end
+
+    -- Cleanup colspans
+    for i = colNum + 1, rightColNum do
+        local columnCell = cells[i]
+
+        if columnCell then
+            ReleaseCell(columnCell)
+        elseif columnCell == false then
+            error("overlapping cells at column " .. i, 3)
+        end
+
+        cells[i] = false
+    end
+
+    -- Create the cell
+    if not cell then
+        cell = AcquireCell(tooltip, provider)
+        cells[colNum] = cell
+    end
+
+    -- Anchor the cell
+    cell:SetPoint("LEFT", tooltip.columns[colNum])
+    cell:SetPoint("RIGHT", tooltip.columns[rightColNum])
+    cell:SetPoint("TOP", line)
+    cell:SetPoint("BOTTOM", line)
+
+    -- Store the cell settings directly into the cell
+    -- That's a bit risky but is really cheap compared to other ways to do it
+    cell._font, cell._justification, cell._colSpan, cell._line, cell._column = font, justification, colSpan, lineNum, colNum
+
+    -- Setup the cell content
+    local width, height = cell:SetupCell(tooltip, value, justification, font, ...)
+    cell:Show()
+
+    if colSpan > 1 then
+        -- Postpone width changes until the tooltip is shown
+        local colRange = colNum .. "-" .. rightColNum
+
+        tooltip.colspans[colRange] = max(tooltip.colspans[colRange] or 0, width)
+        layoutCleaner:RegisterForCleanup(tooltip)
+    else
+        -- Enlarge the column and tooltip if need be
+        EnlargeColumn(tooltip, tooltip.columns[colNum], width)
+    end
+
+    -- Enlarge the line and tooltip if need be
+    if height > line.height then
+        SetTooltipSize(tooltip, tooltip.width, tooltip.height + height - line.height)
+
+        line.height = height
+        line:SetHeight(height)
+    end
+
+    if rightColNum < tooltipWidth then
+        return lineNum, rightColNum + 1
+    else
+        return lineNum, nil
+    end
+end
+
+do
+    local function CreateLine(tooltip, font, ...)
+        if #tooltip.columns == 0 then
+            error("column layout should be defined before adding line", 3)
+        end
+
+        local lineNum = #tooltip.lines + 1
+        local line = tooltip.lines[lineNum] or AcquireFrame(tooltip.scrollChild)
+
+        line:SetFrameLevel(tooltip.scrollChild:GetFrameLevel() + 2)
+        line:SetPoint("LEFT", tooltip.scrollChild)
+        line:SetPoint("RIGHT", tooltip.scrollChild)
+
+        if lineNum > 1 then
+            local v_margin = tooltip.cell_margin_v or CELL_MARGIN_V
+
+            line:SetPoint("TOP", tooltip.lines[lineNum - 1], "BOTTOM", 0, -v_margin)
+            SetTooltipSize(tooltip, tooltip.width, tooltip.height + v_margin)
+        else
+            line:SetPoint("TOP", tooltip.scrollChild)
+        end
+
+        tooltip.lines[lineNum] = line
+
+        line.cells = line.cells or AcquireTable()
+        line.height = 0
+        line:SetHeight(1)
+        line:Show()
+
+        local colNum = 1
+
+        for i = 1, #tooltip.columns do
+            local value = select(i, ...)
+
+            if value ~= nil then
+                lineNum, colNum = _SetCell(tooltip, lineNum, i, value, font, nil, 1, tooltip.labelProvider)
+            end
+        end
+
+        return lineNum, colNum
+    end
+
+    function tipPrototype:AddLine(...)
+        return CreateLine(self, self.regularFont, ...)
+    end
+
+    function tipPrototype:AddHeader(...)
+        local line, col = CreateLine(self, self.headerFont, ...)
+
+        self.lines[line].is_header = true
+
+        return line, col
+    end
+end -- do-block
+
+local GenericBackdrop = {
+    bgFile = "Interface\\Tooltips\\UI-Tooltip-Background"
+}
+
+function tipPrototype:AddSeparator(height, r, g, b, a)
+    local lineNum, colNum = self:AddLine()
+    local line = self.lines[lineNum]
+    local color = _G.NORMAL_FONT_COLOR
+
+    height = height or 1
+
+    SetTooltipSize(self, self.width, self.height + height)
+
+    line.height = height
+    line:SetHeight(height)
+    line:SetBackdrop(GenericBackdrop)
+    line:SetBackdropColor(r or color.r, g or color.g, b or color.b, a or 1)
+
+    return lineNum, colNum
+end
+
+function tipPrototype:SetCellColor(lineNum, colNum, r, g, b, a)
+    local cell = self.lines[lineNum].cells[colNum]
+
+    if cell then
+        local sr, sg, sb, sa = self:GetBackdropColor()
+
+        cell:SetBackdrop(GenericBackdrop)
+        cell:SetBackdropColor(r or sr, g or sg, b or sb, a or sa)
+    end
+end
+
+function tipPrototype:SetColumnColor(colNum, r, g, b, a)
+    local column = self.columns[colNum]
+
+    if column then
+        local sr, sg, sb, sa = self:GetBackdropColor()
+        column:SetBackdrop(GenericBackdrop)
+        column:SetBackdropColor(r or sr, g or sg, b or sb, a or sa)
+    end
+end
+
+function tipPrototype:SetLineColor(lineNum, r, g, b, a)
+    local line = self.lines[lineNum]
+
+    if line then
+        local sr, sg, sb, sa = self:GetBackdropColor()
+
+        line:SetBackdrop(GenericBackdrop)
+        line:SetBackdropColor(r or sr, g or sg, b or sb, a or sa)
+    end
+end
+
+function tipPrototype:SetCellTextColor(lineNum, colNum, r, g, b, a)
+    local line = self.lines[lineNum]
+    local column = self.columns[colNum]
+
+    if not line or not column then
+        return
+    end
+
+    local cell = self.lines[lineNum].cells[colNum]
+
+    if cell then
+        if not cell.fontString then
+            error("cell's label provider did not assign a fontString field", 2)
+        end
+
+        if not cell.r then
+            cell.r, cell.g, cell.b, cell.a = cell.fontString:GetTextColor()
+        end
+
+        cell.fontString:SetTextColor(r or cell.r, g or cell.g, b or cell.b, a or cell.a)
+    end
+end
+
+function tipPrototype:SetColumnTextColor(colNum, r, g, b, a)
+    if not self.columns[colNum] then
+        return
+    end
+
+    for lineIndex = 1, #self.lines do
+        self:SetCellTextColor(lineIndex, colNum, r, g, b, a)
+    end
+end
+
+function tipPrototype:SetLineTextColor(lineNum, r, g, b, a)
+    local line = self.lines[lineNum]
+
+    if not line then
+        return
+    end
+
+    for cellIndex = 1, #line.cells do
+        self:SetCellTextColor(lineNum, line.cells[cellIndex]._column, r, g, b, a)
+    end
+end
+
+function tipPrototype:SetHighlightTexture(...)
+    return highlightTexture:SetTexture(...)
+end
+
+function tipPrototype:SetHighlightTexCoord(...)
+    highlightTexture:SetTexCoord(...)
+end
+
+do
+    local function checkFont(font, level, silent)
+        local bad = false
+
+        if not font then
+            bad = true
+        elseif type(font) == "string" then
+            local ref = _G[font]
+
+            if not ref or type(ref) ~= "table" or type(ref.IsObjectType) ~= "function" or not ref:IsObjectType("Font") then
+                bad = true
+            end
+        elseif type(font) ~= "table" or type(font.IsObjectType) ~= "function" or not font:IsObjectType("Font") then
+            bad = true
+        end
+
+        if bad then
+            if silent then
+                return false
+            end
+
+            error("font must be a Font instance or a string matching the name of a global Font instance, not: " .. tostring(font), level + 1)
+        end
+        return true
+    end
+
+    function tipPrototype:SetFont(font)
+        local is_string = type(font) == "string"
+
+        checkFont(font, 2)
+        self.regularFont = is_string and _G[font] or font
+    end
+
+    function tipPrototype:SetHeaderFont(font)
+        local is_string = type(font) == "string"
+
+        checkFont(font, 2)
+        self.headerFont = is_string and _G[font] or font
+    end
+
+    -- TODO: fixed argument positions / remove checks for performance?
+    function tipPrototype:SetCell(lineNum, colNum, value, ...)
+        -- Mandatory argument checking
+        if type(lineNum) ~= "number" then
+            error("line number must be a number, not: " .. tostring(lineNum), 2)
+        elseif lineNum < 1 or lineNum > #self.lines then
+            error("line number out of range: " .. tostring(lineNum), 2)
+        elseif type(colNum) ~= "number" then
+            error("column number must be a number, not: " .. tostring(colNum), 2)
+        elseif colNum < 1 or colNum > #self.columns then
+            error("column number out of range: " .. tostring(colNum), 2)
+        end
+
+        -- Variable argument checking
+        local font, justification, colSpan, provider
+        local i, arg = 1, ...
+
+        if arg == nil or checkFont(arg, 2, true) then
+            i, font, arg = 2, ...
+        end
+
+        if arg == nil or checkJustification(arg, 2, true) then
+            i, justification, arg = i + 1, select(i, ...)
+        end
+
+        if arg == nil or type(arg) == "number" then
+            i, colSpan, arg = i + 1, select(i, ...)
+        end
+
+        if arg == nil or type(arg) == "table" and type(arg.AcquireCell) == "function" then
+            i, provider = i + 1, arg
+        end
+
+        return _SetCell(self, lineNum, colNum, value, font, justification, colSpan, provider, select(i, ...))
+    end
+end -- do-block
+
+function tipPrototype:GetFont()
+    return self.regularFont
+end
+
+function tipPrototype:GetHeaderFont()
+    return self.headerFont
+end
+
+function tipPrototype:GetLineCount()
+    return #self.lines
+end
+
+function tipPrototype:GetColumnCount()
+    return #self.columns
+end
+
+------------------------------------------------------------------------------
+-- Frame Scripts
+------------------------------------------------------------------------------
+local scripts = {
+    OnEnter = function(frame, ...)
+        highlightFrame:SetParent(frame)
+        highlightFrame:SetAllPoints(frame)
+        highlightFrame:Show()
+
+        if frame._OnEnter_func then
+            frame:_OnEnter_func(frame._OnEnter_arg, ...)
+        end
+    end,
+    OnLeave = function(frame, ...)
+        highlightFrame:Hide()
+        highlightFrame:ClearAllPoints()
+        highlightFrame:SetParent(nil)
+
+        if frame._OnLeave_func then
+            frame:_OnLeave_func(frame._OnLeave_arg, ...)
+        end
+    end,
+    OnMouseDown = function(frame, ...)
+        frame:_OnMouseDown_func(frame._OnMouseDown_arg, ...)
+    end,
+    OnMouseUp = function(frame, ...)
+        frame:_OnMouseUp_func(frame._OnMouseUp_arg, ...)
+    end,
+    OnReceiveDrag = function(frame, ...)
+        frame:_OnReceiveDrag_func(frame._OnReceiveDrag_arg, ...)
+    end
+}
+
+function SetFrameScript(frame, script, func, arg)
+    if not scripts[script] then
+        return
+    end
+
+    frame["_" .. script .. "_func"] = func
+    frame["_" .. script .. "_arg"] = arg
+
+    if script == "OnMouseDown" or script == "OnMouseUp" or script == "OnReceiveDrag" then
+        if func then
+            frame:SetScript(script, scripts[script])
+        else
+            frame:SetScript(script, nil)
+        end
+    end
+
+    -- if at least one script is set, set the OnEnter/OnLeave scripts for the highlight
+    if frame._OnEnter_func or frame._OnLeave_func or frame._OnMouseDown_func or frame._OnMouseUp_func or frame._OnReceiveDrag_func then
+        frame:EnableMouse(true)
+        frame:SetScript("OnEnter", scripts.OnEnter)
+        frame:SetScript("OnLeave", scripts.OnLeave)
+    else
+        frame:EnableMouse(false)
+        frame:SetScript("OnEnter", nil)
+        frame:SetScript("OnLeave", nil)
+    end
+end
+
+function ClearFrameScripts(frame)
+    if frame._OnEnter_func or frame._OnLeave_func or frame._OnMouseDown_func or frame._OnMouseUp_func or frame._OnReceiveDrag_func then
+        frame:EnableMouse(false)
+
+        frame:SetScript("OnEnter", nil)
+        frame._OnEnter_func = nil
+        frame._OnEnter_arg = nil
+
+        frame:SetScript("OnLeave", nil)
+        frame._OnLeave_func = nil
+        frame._OnLeave_arg = nil
+
+        frame:SetScript("OnReceiveDrag", nil)
+        frame._OnReceiveDrag_func = nil
+        frame._OnReceiveDrag_arg = nil
+
+        frame:SetScript("OnMouseDown", nil)
+        frame._OnMouseDown_func = nil
+        frame._OnMouseDown_arg = nil
+
+        frame:SetScript("OnMouseUp", nil)
+        frame._OnMouseUp_func = nil
+        frame._OnMouseUp_arg = nil
+    end
+end
+
+function tipPrototype:SetLineScript(lineNum, script, func, arg)
+    SetFrameScript(self.lines[lineNum], script, func, arg)
+end
+
+function tipPrototype:SetColumnScript(colNum, script, func, arg)
+    SetFrameScript(self.columns[colNum], script, func, arg)
+end
+
+function tipPrototype:SetCellScript(lineNum, colNum, script, func, arg)
+    local cell = self.lines[lineNum].cells[colNum]
+
+    if cell then
+        SetFrameScript(cell, script, func, arg)
+    end
+end
+
+------------------------------------------------------------------------------
+-- Auto-hiding feature
+------------------------------------------------------------------------------
+
+-- Script of the auto-hiding child frame
+local function AutoHideTimerFrame_OnUpdate(self, elapsed)
+    self.checkElapsed = self.checkElapsed + elapsed
+
+    if self.checkElapsed > 0.1 then
+        if self.parent:IsMouseOver() or (self.alternateFrame and self.alternateFrame:IsMouseOver()) then
+            self.elapsed = 0
+        else
+            self.elapsed = self.elapsed + self.checkElapsed
+
+            if self.elapsed >= self.delay then
+                lib:Release(self.parent)
+            end
+        end
+
+        self.checkElapsed = 0
+    end
+end
+
+-- Usage:
+-- :SetAutoHideDelay(0.25) => hides after 0.25sec outside of the tooltip
+-- :SetAutoHideDelay(0.25, someFrame) => hides after 0.25sec outside of both the tooltip and someFrame
+-- :SetAutoHideDelay() => disable auto-hiding (default)
+function tipPrototype:SetAutoHideDelay(delay, alternateFrame, releaseHandler)
+    local timerFrame = self.autoHideTimerFrame
+    delay = tonumber(delay) or 0
+
+    if releaseHandler then
+        if type(releaseHandler) ~= "function" then
+            error("releaseHandler must be a function", 2)
+        end
+
+        lib.onReleaseHandlers[self] = releaseHandler
+    end
+
+    if delay > 0 then
+        if not timerFrame then
+            timerFrame = AcquireTimer(self)
+            timerFrame:SetScript("OnUpdate", AutoHideTimerFrame_OnUpdate)
+
+            self.autoHideTimerFrame = timerFrame
+        end
+
+        timerFrame.parent = self
+        timerFrame.checkElapsed = 0
+        timerFrame.elapsed = 0
+        timerFrame.delay = delay
+        timerFrame.alternateFrame = alternateFrame
+        timerFrame:Show()
+    elseif timerFrame then
+        self.autoHideTimerFrame = nil
+
+        timerFrame.alternateFrame = nil
+        timerFrame:SetScript("OnUpdate", nil)
+
+        ReleaseTimer(timerFrame)
+    end
+end
+
+------------------------------------------------------------------------------
+-- "Smart" Anchoring
+------------------------------------------------------------------------------
+local function GetTipAnchor(frame)
+    local x, y = frame:GetCenter()
+
+    if not x or not y then
+        return "TOPLEFT", "BOTTOMLEFT"
+    end
+
+    local hhalf = (x > UIParent:GetWidth() * 2 / 3) and "RIGHT" or (x < UIParent:GetWidth() / 3) and "LEFT" or ""
+    local vhalf = (y > UIParent:GetHeight() / 2) and "TOP" or "BOTTOM"
+
+    return vhalf .. hhalf, frame, (vhalf == "TOP" and "BOTTOM" or "TOP") .. hhalf
+end
+
+function tipPrototype:SmartAnchorTo(frame)
+    if not frame then
+        error("Invalid frame provided.", 2)
+    end
+
+    self:ClearAllPoints()
+    self:SetClampedToScreen(true)
+    self:SetPoint(GetTipAnchor(frame))
+end
+
+------------------------------------------------------------------------------
+-- Debug slashcmds
+------------------------------------------------------------------------------
+-- @debug @
+local print = print
+local function PrintStats()
+    local tipCache = tostring(#tooltipHeap)
+    local frameCache = tostring(#frameHeap)
+    local tableCache = tostring(#tableHeap)
+    local header = false
+
+    print("Tooltips used: " .. usedTooltips .. ", Cached: " .. tipCache .. ", Total: " .. tipCache + usedTooltips)
+    print("Frames used: " .. usedFrames .. ", Cached: " .. frameCache .. ", Total: " .. frameCache + usedFrames)
+    print("Tables used: " .. usedTables .. ", Cached: " .. tableCache .. ", Total: " .. tableCache + usedTables)
+
+    for k in pairs(activeTooltips) do
+        if not header then
+            print("Active tooltips:")
+            header = true
+        end
+        print("- " .. k)
+    end
+end
+
+SLASH_LibQTip1 = "/qtip"
+_G.SlashCmdList["LibQTip"] = PrintStats
+--@end-debug@]==]
diff --git a/Titan/libs/LibQTip-1.0/LibQTip-1.0.toc b/Titan/libs/LibQTip-1.0/LibQTip-1.0.toc
new file mode 100644
index 0000000..d7d75e8
--- /dev/null
+++ b/Titan/libs/LibQTip-1.0/LibQTip-1.0.toc
@@ -0,0 +1,15 @@
+## Interface: 100007
+## Title: Lib: QTip-1.0
+## Notes: Library providing multi-column tooltips.
+## Author: Torhal, Adirelle, Elkano, Tristanian
+## Version: 10.0.7.1
+## LoadOnDemand: 1
+## X-Credits: Kaelten (input on initial design)
+## X-Category: Library, Tooltip
+## X-Curse-Project-ID: 15487
+## X-Date: 2023-03-29T21:01:29Z
+## X-License: Ace3 BSD-like license
+## X-Website: http://www.wowace.com/addons/libqtip-1-0/
+
+LibStub\LibStub.lua
+lib.xml
diff --git a/Titan/libs/LibQTip-1.0/LibStub/LibStub.lua b/Titan/libs/LibQTip-1.0/LibStub/LibStub.lua
new file mode 100644
index 0000000..7e7b76d
--- /dev/null
+++ b/Titan/libs/LibQTip-1.0/LibStub/LibStub.lua
@@ -0,0 +1,51 @@
+-- $Id: LibStub.lua 103 2014-10-16 03:02:50Z mikk $
+-- LibStub is a simple versioning stub meant for use in Libraries.  http://www.wowace.com/addons/libstub/ for more info
+-- LibStub is hereby placed in the Public Domain
+-- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
+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]
+
+-- Check to see is this version of the stub is obsolete
+if not LibStub or LibStub.minor < LIBSTUB_MINOR then
+	LibStub = LibStub or {libs = {}, minors = {} }
+	_G[LIBSTUB_MAJOR] = LibStub
+	LibStub.minor = LIBSTUB_MINOR
+
+	-- LibStub:NewLibrary(major, minor)
+	-- major (string) - the major version of the library
+	-- minor (string or number ) - the minor version of the library
+	--
+	-- returns nil if a newer or same version of the lib is already present
+	-- returns empty library object or old library object if upgrade is needed
+	function LibStub:NewLibrary(major, minor)
+		assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
+		minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
+
+		local oldminor = self.minors[major]
+		if oldminor and oldminor >= minor then return nil end
+		self.minors[major], self.libs[major] = minor, self.libs[major] or {}
+		return self.libs[major], oldminor
+	end
+
+	-- LibStub:GetLibrary(major, [silent])
+	-- major (string) - the major version of the library
+	-- silent (boolean) - if true, library is optional, silently return nil if its not found
+	--
+	-- throws an error if the library can not be found (except silent is set)
+	-- returns the library object if found
+	function LibStub:GetLibrary(major, silent)
+		if not self.libs[major] and not silent then
+			error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
+		end
+		return self.libs[major], self.minors[major]
+	end
+
+	-- LibStub:IterateLibraries()
+	--
+	-- Returns an iterator for the currently registered libraries
+	function LibStub:IterateLibraries()
+		return pairs(self.libs)
+	end
+
+	setmetatable(LibStub, { __call = LibStub.GetLibrary })
+end
diff --git a/Titan/libs/LibQTip-1.0/README.md b/Titan/libs/LibQTip-1.0/README.md
new file mode 100644
index 0000000..b61c509
--- /dev/null
+++ b/Titan/libs/LibQTip-1.0/README.md
@@ -0,0 +1,30 @@
+# LibQTip-1.0
+LibQTip is designed replace GameTooltip - but with added functionality, such as multiple columns - from a minimalist design perspective.
+
+## Features
+- Ability to display and handle multiple tooltips at the same time,
+- Unlimited number of columns and lines,
+- Column default and per cell justification,
+- Tooltip default and per cell font setting,
+- Colspans,
+- Possibility to add custom cells,
+- Optional scrollbar,
+- Optional scripts for lines, columns, or cells,
+- Optional automatic hiding,
+- Frames and tables recycling to reduce resource footprint.
+
+## Caveats
+Look [here](https://www.wowace.com/projects/libqtip-1-0/pages/getting-started) for information on embedding the latest beta/release.
+
+**In order to achieve effective frame recycling, tooltips must be released.**
+
+Holding a tooltip leads to the creation of a full set of frames for every AddOn which does not follow this practice. Moreover, releasing a tooltip has a very little overhead compared to its benefits.
+
+## Known issues
+Alignment may be altered when using :SetScale after filling the tooltip.
+
+## Documentation
+- [Getting Started Guide](https://www.wowace.com/projects/libqtip-1-0/pages/getting-started)
+- [How to Add Custom Cells](https://www.wowace.com/projects/libqtip-1-0/pages/how-to-add-custom-cells)
+- [API Reference](https://www.wowace.com/projects/libqtip-1-0/pages/api-reference)
+- [Standard CellProvider API](https://www.wowace.com/projects/libqtip-1-0/pages/standard-cell-provider-api)
diff --git a/Titan/libs/LibQTip-1.0/lib.xml b/Titan/libs/LibQTip-1.0/lib.xml
new file mode 100644
index 0000000..f212246
--- /dev/null
+++ b/Titan/libs/LibQTip-1.0/lib.xml
@@ -0,0 +1,4 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
+..\FrameXML\UI.xsd">
+	<Script file="LibQTip-1.0.lua"/>
+</Ui>
\ No newline at end of file
diff --git a/TitanPost/TitanPost.lua b/TitanPost/TitanPost.lua
index 293919c..8917dcb 100644
--- a/TitanPost/TitanPost.lua
+++ b/TitanPost/TitanPost.lua
@@ -551,7 +551,7 @@ local function GeneratorFunction(owner, rootDescription)
 		function()
 			TitanUpdateConfig("init")
 			-- Open the profile config as distinct frame
-			AceConfigDialog:Open("Titan Panel Addon Chars")
+			AceConfigDialog:Open("Titan Panel Addon Profiles")
 		end
 	)

diff --git a/TitanUI/Tools.lua b/TitanUI/Tools.lua
index 8788acf..ece9031 100755
--- a/TitanUI/Tools.lua
+++ b/TitanUI/Tools.lua
@@ -70,7 +70,7 @@ local function GeneratorFunction(owner, rootDescription)
 		GenCommand(root, id, config .. L["TITAN_PANEL_MENU_PROFILES"],
 			function()
 				TitanUpdateConfig("init")
-				AceConfigDialog:Open("Titan Panel Addon Chars")
+				AceConfigDialog:Open("Titan Panel Addon Profiles")
 			end)

 		elementDescription = root:CreateDivider()