Quantcast

- Fix drag and drop after 11.2.0 API change (ClearAllPoints)

urnati [09-08-25 - 10:00]
- Fix drag and drop after 11.2.0 API change (ClearAllPoints)
Filename
Titan/Titan.lua
Titan/TitanHistory.lua
Titan/TitanTemplate.lua
Titan/TitanUtils.lua
Titan/_TitanIDE.lua
diff --git a/Titan/Titan.lua b/Titan/Titan.lua
index fb94ce5..e71a4ec 100644
--- a/Titan/Titan.lua
+++ b/Titan/Titan.lua
@@ -42,29 +42,6 @@ end

 ---Titan Give the user a 'are you sure' popup whether to reset current toon back to default Titan settings.
 function TitanPanel_ResetToDefault()
---[[
-	StaticPopupDialogs["TITAN_RESET_BAR"] = {
-		text = TitanUtils_GetNormalText(L["TITAN_PANEL_MENU_TITLE"])
-			.. "\n\n" .. L["TITAN_PANEL_RESET_WARNING"],
-		button1 = ACCEPT,
-		button2 = CANCEL,
-		OnAccept = function(self)
-				-- build debug output
-				local str = "/titan reset"
-					.." "..tostring(TITAN_PROFILE_RESET)..""
-				Titan_Debug.Out('titan', 'profile', str)
-			TitanVariables_UseSettings(TitanSettings.Player, TITAN_PROFILE_RESET);
-			IsTitanPanelReset = true;
---			ReloadUI()
-		end,
-		showAlert = 1,
-		timeout = 0,
-		whileDead = 1,
-		hideOnEscape = 1
-	};
-	StaticPopup_Show("TITAN_RESET_BAR");
---]]
-
 	-- Found as of 2025 Sep, the reload is not needed
 	-- build debug output
 	local str = "/titan reset"
@@ -1766,27 +1743,34 @@ function TitanPanel_ReOrder(index)
 	end
 end

----Titan Remove a plugin then show all the shown all user selected plugins on the Titan bar(s).
---- This cancels all timers of name "TitanPanel"..id as a safeguard to destroy any active plugin timers
---- based on a fixed naming convention : TitanPanel..id, eg. "TitanPanelClock" this prevents "rogue"
---- timers being left behind by lack of an OnHide check
+---Titan Remove a plugin then show the rest of user selected plugins on the Titan bar(s).
 ---@param id string Unique ID of the plugin
-function TitanPanel_RemoveButton(id)
+---@param hide_plugin? boolean whether to hide plugin after removal
+function TitanPanel_RemoveButton(id, hide_plugin)
 	if (not TitanPanelSettings) then
 		return;
 	end

+	local hide_me = hide_plugin
+	if hide_me == nil then
+		hide_me = true -- not passed
+	else
+		-- was passed
+	end
+
 	local i = TitanPanel_GetButtonNumber(id)
 	local currentButton = TitanUtils_GetButton(id);

 	-- safeguard ...
+	-- This cancels all timers of name "TitanPanel"..id as a safeguard to destroy any active plugin timers
+	-- based on a fixed naming convention : TitanPanel..id, eg. "TitanPanelClock" this prevents "rogue"
+	-- timers being left behind by lack of an OnHide check
 ---@diagnostic disable-next-line: missing-parameter
 	if id then AceTimer.CancelAllTimers() end -- ??? seems confused 0 or 1 params  "TitanPanel" .. id

 	TitanPanel_ReOrder(i);
 	table.remove(TitanPanelSettings.Buttons, TitanUtils_GetCurrentIndex(TitanPanelSettings.Buttons, id));
-	--TitanDebug("_Remove: "..(id or "?").." "..(i or "?"))
-	if currentButton then
+	if currentButton and hide_me then
 		currentButton:Hide();
 	end
 	-- Show the existing buttons
diff --git a/Titan/TitanHistory.lua b/Titan/TitanHistory.lua
index cf573af..94a9824 100644
--- a/Titan/TitanHistory.lua
+++ b/Titan/TitanHistory.lua
@@ -25,7 +25,7 @@ Titan_Global.recent_changes = ""
 .. "-  --- Bar skin / color settings\n"
 .. "-  --- Hide Bar during combat\n"
 .. "-  --- Hide Bar in PvP and BG zones\n"
-.. "-  - : Per an API change in 11.2.0, disable drag & drop of Titan plugins for now..."
+.. "-  - : Fix drag & drop of Titan plugins, per an API change in 11.2.0."
 .. "-  Internal : \n"
 .. "-  - : Global profiles should be working again.\n"
 .. "-  - : More debug statements on login, reload, profile reset.\n"
diff --git a/Titan/TitanTemplate.lua b/Titan/TitanTemplate.lua
index e7483dc..582a694 100644
--- a/Titan/TitanTemplate.lua
+++ b/Titan/TitanTemplate.lua
@@ -383,9 +383,13 @@ end
 --- Set TITAN_PANEL_MOVING so any Titan routine will know a 'drag & drop' is in progress.
 --- Set TITAN_PANEL_MOVE_ADDON so sanity checks can be done on the 'drop'.
 local function TitanPanelButton_OnDragStart(self)
-	-- Due to API change in 11.2.0, :ClearAllPoints with also clear all plugins from Titan bar...
-	-- Dropped Ace Dewdrop-2.0 lib as of 2025 Sep; last updated 2008 Sep
-	-- Dropped Ace Tablet-2.0 lib as of 2025 Sep; last updated 2009 Jan (marked as abandoned)
+	-- Due to API change in 11.2.0, :ClearAllPoints immediately invalidates the rect...
+	-- Need to change order of events between drag start and stop:
+	-- - Remove but not Hide() the plugin - seems Hide() triggers OnDragStop without release of mouse button...
+	-- - Make ALL 'do not drag' checks BEFORE remove!!
+	--
+	-- Dropped Ace Dewdrop-2.0 lib support as of 2025 Sep; last updated 2008 Sep
+	-- Dropped Ace Tablet-2.0 lib support as of 2025 Sep; last updated 2009 Jan (marked as abandoned)

 	if TitanPanelGetVar("LockButtons") or InCombatLockdown() then
 		return -- not requested or not allowed
@@ -396,47 +400,27 @@ local function TitanPanelButton_OnDragStart(self)
 	local frname = self
 	local frstr = self:GetName()
 	local plugin_id = TitanUtils_GetButtonID(frstr)
-	-- See if the plugin is supposed to stay on the bar it is on
-	if TitanGetVar(plugin_id, "ForceBar") then
-		return -- not allowed
-	else
-		-- Proceed
-	end
-
-
---[[
-	-- Clear button positions or we'll grab the button and all buttons 'after'
-	for i, j in pairs(TitanPanelSettings.Buttons) do
-		local pluginid = _G[TitanUtils_ButtonName(TitanPanelSettings.Buttons[i])];
-		if pluginid then
-			pluginid:ClearAllPoints()
-		end
-	end
---]]
-
-	FROM_BAR_SHORT = TitanUtils_GetWhichBar(plugin_id) -- short name
 	local str = ""
 	str = "_OnDragStart start "
 		.." "..tostring(plugin_id)..""
-		.." from "..tostring(FROM_BAR_SHORT)..""
+--		.." from "..tostring(FROM_BAR_SHORT)..""
 	Titan_Debug.Out('titan', 'plugin_drag_drop', str)

-	-- Clear the plugin placement so we only move the intended plugin
---	frname:ClearAllPoints()
-	FROM_BAR_FRAME = TitanVariables_GetFrameName(FROM_BAR_SHORT)
-	TitanPanel_RemoveButton(plugin_id)

-	-- Start the drag; close any tooltips and open control frames
+	-- Tell Titan that a drag & drop is in process
+	TITAN_PANEL_MOVING = 1;
+	-- Start the drag
 	frname:StartMoving();
 	frname.isMoving = true;
+
+	-- Close any tooltips and control frames
 	TitanUtils_CloseAllControlFrames();
 	TitanPanelRightClickMenu_Close();
-
 	GameTooltip:Hide();
+
 	-- LibQTip-1.0 support code
 	LibQTip = LibStub("LibQTip-1.0", true)
 	if LibQTip then
-		local key, tip
 		for key, tip in LibQTip:IterateTooltips() do
 			if tip then
 				local _, relativeTo = tip:GetPoint()
@@ -449,18 +433,21 @@ local function TitanPanelButton_OnDragStart(self)
 	end
 	-- /LibQTip-1.0 support code

+	FROM_BAR_SHORT = TitanUtils_GetWhichBar(plugin_id) -- short name
+	str = "_OnDragStart moving"
+		.." "..tostring(plugin_id)..""
+		.." from "..tostring(FROM_BAR_SHORT)..""
+	Titan_Debug.Out('titan', 'plugin_drag_drop', str)
+	-- Clear the plugin placement so we only move the intended plugin
+	TitanPanel_RemoveButton(plugin_id, false)
+	frname:Show() -- 'remove' hid the plugin
+
 	-- Hold the plugin id so we can do checks on the drop
 	TITAN_PANEL_MOVE_ADDON = plugin_id

-	-- Tell Titan that a drag & drop is in process
-	TITAN_PANEL_MOVING = 1;
 	-- Store the OnEnter handler so the tooltip does not show - or other oddities
 	pluginOnEnter = self:GetScript("OnEnter")
 	self:SetScript("OnEnter", nil)
-
-	str = "_OnDragStart moving "
-		.." "..tostring(self:GetName())..""
-	Titan_Debug.Out('titan', 'plugin_drag_drop', str)
 end

 ---local Handle the OnDragStop event of the given Titan plugin.
@@ -469,103 +456,66 @@ end
 --- Clear TITAN_PANEL_MOVING.
 --- Clear TITAN_PANEL_MOVE_ADDON.
 local function TitanPanelButton_OnDragStop(self)
-	if TitanPanelGetVar("LockButtons") then
-		return
-	end
+	-- The plugin is under the cursor so we MUST place the plugin somewhere!
+	-- We cannot just return.
+	-- Also means we can no longer swap plugins.
+	-- For now, we will drop the plugin on the bar under the cursor;
+	-- placing the plugin 'right' if set for that plugin
+
+	local frname = self
+	local frstr = self:GetName()
+	local plugin_id = TitanUtils_GetButtonID(frstr)

 	local str = ""
 	str = "_OnDragStop start "
-		.." "..tostring(self:GetName())..""
+		.." "..tostring(plugin_id)..""
 	Titan_Debug.Out('titan', 'plugin_drag_drop', str)

-	local ok_to_move = true
-	local nonmovableFrom = false;
-	local nonmovableTo = false;
-	local frname = self;
-
 	if TITAN_PANEL_MOVING == 1 then
 		frname:StopMovingOrSizing();
 		frname.isMoving = false;
 		TITAN_PANEL_MOVING = 0;

-		-- See if the plugin is supposed to stay on the bar it is on
-		if TitanGetVar(TITAN_PANEL_MOVE_ADDON, "ForceBar") then
-			ok_to_move = false
-		end
+		local bar
+		local tbar = "" -- bar short name
+		local fbar = TitanGetVar(plugin_id, "ForceBar")

-		-- There could be several reasons to not allow the plugin to move
-		if ok_to_move then
-			for i, j in pairs(TitanPanelSettings.Buttons) do
-				local pluginid =
-					_G[TitanUtils_ButtonName(TitanPanelSettings.Buttons[i])];
-				--					_G["TitanPanel"..TitanPanelSettings.Buttons[i].."Button"];
-				if (pluginid and MouseIsOver(pluginid)) and frname ~= pluginid then
-					TITAN_PANEL_DROPOFF_ADDON = TitanPanelSettings.Buttons[i];
+		str = "_OnDragStop "
+			.." "..tostring(plugin_id)..""
+		if fbar == nil
+		or fbar == false then
+			-- Find which bar it was dropped on
+			for idx, v in pairs(TitanBarData) do
+				bar = idx
+				if (bar and MouseIsOver(_G[bar])) then
+					tbar = TitanBarData[bar].name
 				end
 			end
-
-			-- switching sides is not allowed
-			nonmovableFrom = TitanUtils_ToRight(TITAN_PANEL_MOVE_ADDON)
-			nonmovableTo = TitanUtils_ToRight(TITAN_PANEL_DROPOFF_ADDON)
-			if nonmovableTo ~= nonmovableFrom then
-				TITAN_PANEL_DROPOFF_ADDON = "";
-			end
-
-			if TITAN_PANEL_DROPOFF_ADDON == "" then
-				-- See if the plugin was dropped on a bar rather than
-				-- another plugin.
-				local bar
-				local tbar = nil
-				-- Find which bar it was dropped on
-				for idx, v in pairs(TitanBarData) do
-					bar = idx
-					if (bar and MouseIsOver(_G[bar])) then
-						tbar = bar
-					end
-				end
-
-				if tbar then
---					TitanPanel_RemoveButton(TITAN_PANEL_MOVE_ADDON)
-					TitanUtils_AddButtonOnBar(TitanBarData[tbar].name, TITAN_PANEL_MOVE_ADDON)
-				else
-					-- not sure what the user did...
-					-- Likely released on UI so put back on the bar it came from
-					TitanUtils_AddButtonOnBar(FROM_BAR_SHORT, TITAN_PANEL_MOVE_ADDON)
-				end
+			if tbar == "" then
+				-- not sure what the user did...
+				-- Likely released on UI so put back on the bar it came from
+				str = str .." back to"
+				tbar = FROM_BAR_SHORT
 			else
-				-- plugin was dropped on another plugin - swap (for now)
-				local dropoff = TitanUtils_GetCurrentIndex(TitanPanelSettings.Buttons
-				, TITAN_PANEL_DROPOFF_ADDON);
-				local pickup = TitanUtils_GetCurrentIndex(TitanPanelSettings.Buttons
-				, TITAN_PANEL_MOVE_ADDON);
-				local dropoffbar = TitanUtils_GetWhichBar(TITAN_PANEL_DROPOFF_ADDON);
-				local pickupbar = TitanUtils_GetWhichBar(TITAN_PANEL_MOVE_ADDON);
-
-				if dropoff ~= nil and dropoff ~= "" then
-					-- TODO: Change to 'insert' rather than swap
-					TitanPanelSettings.Buttons[dropoff] = TITAN_PANEL_MOVE_ADDON;
-					TitanPanelSettings.Location[dropoff] = dropoffbar;
-					TitanPanelSettings.Buttons[pickup] = TITAN_PANEL_DROPOFF_ADDON;
-					TitanPanelSettings.Location[pickup] = pickupbar;
-				end
+				str = str .." onto"
 			end
+		else
+			str = str .." force to"
+			tbar = fbar -- put it back; allows user to shift it
 		end

-		str = "_OnDragStop "
-			.." "..tostring(self:GetName())..""
-			.." ok:"..tostring(ok_to_move)..""
-			.." no from:"..tostring(nonmovableFrom)..""
-			.." no to:"..tostring(nonmovableTo)..""
-			.." Over:"..tostring(TITAN_PANEL_DROPOFF_ADDON)..""
+		str = str .." "..tostring(tbar)..""
 		Titan_Debug.Out('titan', 'plugin_drag_drop', str)
+		TitanUtils_AddButtonOnBar(tbar, TITAN_PANEL_MOVE_ADDON)

-		-- This is important! The start drag cleared the button positions so
-		-- the buttons need to be put back properly.
-		TitanPanel_InitPanelButtons();
+		-- The plugin was added a bar so clean up.
 		TITAN_PANEL_MOVE_ADDON = "";
-		TITAN_PANEL_DROPOFF_ADDON = "";
-		-- Restore the OnEnter script handler
-		if pluginOnEnter then self:SetScript("OnEnter", pluginOnEnter) end
+		if pluginOnEnter then
+			-- Restore the OnEnter script handler
+			self:SetScript("OnEnter", pluginOnEnter)
+		else
+			-- No OnEnter was found at drag start
+		end
 		pluginOnEnter = nil;

 	end
@@ -1109,6 +1059,32 @@ function TitanPanelDetectPluginMethod(id)
 	end)
 end

+---Titan Sets the OnDragStart & OnDragStop scripts of a Titan plugin.
+---@param self Button Plugin
+function TitanPanelButton_AddMouseScripts(self)
+	-- Ensure the id is not nil
+	if self then
+		self:RegisterForClicks("LeftButtonUp", "RightButtonUp", "MiddleButtonUp");
+		self:RegisterForDrag("LeftButton")
+
+		-- Set the OnDragStart script
+		self:SetScript("OnDragStart", function(self)
+			if not IsShiftKeyDown()
+				and not IsControlKeyDown()
+				and not IsAltKeyDown() then
+				TitanPanelButton_OnDragStart(self)
+			end
+		end)
+
+		-- Set the OnDragStop script
+		self:SetScript("OnDragStop", function(self)
+			TitanPanelButton_OnDragStop(self)
+		end)
+	else
+		-- nothing to add to ??
+	end
+end
+
 ---API Set the icon of the given Titan plugin.
 ---@param id string Plugin id
 ---@param iconCoords table? As {left, right, top, bottom}
diff --git a/Titan/TitanUtils.lua b/Titan/TitanUtils.lua
index 8efa14c..1fdd87c 100644
--- a/Titan/TitanUtils.lua
+++ b/Titan/TitanUtils.lua
@@ -2075,6 +2075,8 @@ NOTE:
 				result = TITAN_REGISTER_FAILED
 			else
 				-- We are almost done-
+				TitanPanelButton_AddMouseScripts(self)
+--[[
 				-- Allow mouse clicks on the plugin
 				local pluginID = TitanUtils_GetButtonID(self:GetName());
 				local plugin_id = TitanUtils_GetPlugin(pluginID);
@@ -2082,10 +2084,11 @@ NOTE:
 					self:RegisterForClicks("LeftButtonUp", "RightButtonUp", "MiddleButtonUp");
 					self:RegisterForDrag("LeftButton")
 -- Per an API change in 11.2.0, disable drag & drop for now...
---					if (plugin_id.id) then
---						TitanPanelDetectPluginMethod(plugin_id.id);
---					end
+					if (plugin_id.id) then
+						TitanPanelDetectPluginMethod(plugin_id.id);
+					end
 				end
+--]]
 				result = TITAN_REGISTERED
 				-- determine the plugin category
 				cat = (self.registry.category or "General")
diff --git a/Titan/_TitanIDE.lua b/Titan/_TitanIDE.lua
index 6b4aa02..2d407ba 100644
--- a/Titan/_TitanIDE.lua
+++ b/Titan/_TitanIDE.lua
@@ -157,6 +157,7 @@ C_Bank = {} -- 11.0.0 New Warbank - Hopefully WoW API extension will catch up so
 ---@field RequestTimePlayed table Override default - XP
 ---@field TIME_PLAYED_MSG table Override default - XP
 ---@field short_name string Placeholder for short bar name
+---@field RegisterForClicks function Variable params missed by VS Code plugin

 -- Ace references
 AceGUIWidgetLSMlists = {}