From 04d99aa0558c34ad93f9bdf6f7f62d545f15ceb7 Mon Sep 17 00:00:00 2001 From: Krathe Date: Sun, 10 May 2026 16:09:16 +0100 Subject: [PATCH] (Personal Targeted Spells) Fix mover misaligned with icons in edit mode The saved position now represents the visual centre of the icon block. The container is offset by half the block width/height opposite to the growth direction, so the mover box and icons are correctly aligned. A one-time migration shifts existing saved positions so icon 1 stays at the same screen location after the update. --- Core.lua | 38 ++++++++++++++++++++++++++++++++ Features/TargetedSpells.lua | 44 ++++++++++++++++++++++++++++++++----- 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/Core.lua b/Core.lua index 553b15b5..52755c47 100644 --- a/Core.lua +++ b/Core.lua @@ -4065,6 +4065,44 @@ DF._MainEventDispatcher = function(self, event, arg1) end end + -- Migrate personal targeted spells container centre to icon-block midpoint (bug 880). + -- Previously the saved (x, y) was the position of icon 1 (container centre). + -- Now (x, y) is the visual centre of the icon block; the container is offset so + -- the block is centred there. Shift existing positions by halfBlock in the growth + -- direction so icon 1 stays at its old screen location for existing users. + local function MigratePersonalContainerPosition(partyDb) + if not partyDb or partyDb._personalContainerCenterMigrated then return end + local iconSize = partyDb.personalTargetedSpellSize or 40 + local scale = partyDb.personalTargetedSpellScale or 1.0 + local maxIcons = partyDb.personalTargetedSpellMaxIcons or 5 + local spacing = partyDb.personalTargetedSpellSpacing or 4 + local growthDirection = partyDb.personalTargetedSpellGrowth or "RIGHT" + local x = partyDb.personalTargetedSpellX or 0 + local y = partyDb.personalTargetedSpellY or -150 + + local scaledSize = iconSize * scale + local scaledSpacing = spacing * scale + local halfBlock = (maxIcons - 1) / 2 * (scaledSize + scaledSpacing) + + if growthDirection == "RIGHT" then + partyDb.personalTargetedSpellX = x + halfBlock + elseif growthDirection == "LEFT" then + partyDb.personalTargetedSpellX = x - halfBlock + elseif growthDirection == "UP" then + partyDb.personalTargetedSpellY = y + halfBlock + elseif growthDirection == "DOWN" then + partyDb.personalTargetedSpellY = y - halfBlock + -- CENTER_H / CENTER_V: no shift needed + end + partyDb._personalContainerCenterMigrated = true + end + MigratePersonalContainerPosition(DF.db.party) + if DandersFramesDB_v2 and DandersFramesDB_v2.profiles then + for _, profile in pairs(DandersFramesDB_v2.profiles) do + MigratePersonalContainerPosition(profile.party) + end + end + -- Wrap DF.db with overlay proxy (must happen AFTER all migrations, -- BEFORE anything that reads through the proxy) DF:WrapDB() diff --git a/Features/TargetedSpells.lua b/Features/TargetedSpells.lua index 833ce6e8..a79c40e6 100644 --- a/Features/TargetedSpells.lua +++ b/Features/TargetedSpells.lua @@ -2019,18 +2019,50 @@ local function GetPersonalMoverSize() return math.max(width, 50), math.max(height, 50) end +-- Compute the container CENTER offset from the saved icon-block centre (x, y). +-- The saved position represents the visual midpoint of the icon block. The +-- container is shifted opposite to the growth direction so that icon 1 (which +-- anchors to the container's CENTER) ends up in the right place, with the full +-- block symmetrically centred on the saved (x, y). +local function GetPersonalContainerPoint(x, y) + local db = DF:GetDB() + local iconSize = db.personalTargetedSpellSize or 40 + local scale = db.personalTargetedSpellScale or 1.0 + local maxIcons = db.personalTargetedSpellMaxIcons or 5 + local spacing = db.personalTargetedSpellSpacing or 4 + local growthDirection = db.personalTargetedSpellGrowth or "RIGHT" + + local scaledSize = iconSize * scale + local scaledSpacing = spacing * scale + local halfBlock = (maxIcons - 1) / 2 * (scaledSize + scaledSpacing) + + local cx, cy = x, y + if growthDirection == "RIGHT" then + cx = x - halfBlock + elseif growthDirection == "LEFT" then + cx = x + halfBlock + elseif growthDirection == "UP" then + cy = y - halfBlock + elseif growthDirection == "DOWN" then + cy = y + halfBlock + -- CENTER_H / CENTER_V: already symmetric, no adjustment needed + end + return cx, cy +end + -- Create the personal targeted spells container local function CreatePersonalContainer() if personalContainer then return personalContainer end - + local db = DF:GetDB() local x = db.personalTargetedSpellX or 0 local y = db.personalTargetedSpellY or -150 - + local container = CreateFrame("Frame", "DandersFramesPersonalTargetedSpells", UIParent) local w, h = GetPersonalMoverSize() container:SetSize(w, h) - container:SetPoint("CENTER", UIParent, "CENTER", x, y) + local cx, cy = GetPersonalContainerPoint(x, y) + container:SetPoint("CENTER", UIParent, "CENTER", cx, cy) container:SetFrameStrata("HIGH") container:Hide() container:EnableMouse(false) @@ -2696,7 +2728,8 @@ function DF:UpdatePersonalTargetedSpellsPosition() if personalContainer then personalContainer:ClearAllPoints() - personalContainer:SetPoint("CENTER", UIParent, "CENTER", x, y) + local cx, cy = GetPersonalContainerPoint(x, y) + personalContainer:SetPoint("CENTER", UIParent, "CENTER", cx, cy) local w, h = GetPersonalMoverSize() personalContainer:SetSize(w, h) personalContainer:SetAlpha(iconAlpha) @@ -2776,7 +2809,8 @@ function DF:CreatePersonalTargetedSpellsMover() -- Update container position live if personalContainer then personalContainer:ClearAllPoints() - personalContainer:SetPoint("CENTER", UIParent, "CENTER", x, y) + local cx, cy = GetPersonalContainerPoint(x, y) + personalContainer:SetPoint("CENTER", UIParent, "CENTER", cx, cy) end -- Snap preview