Create movers eagerly so they always show in Toggle Anchors

The Extra Action Button, Instance Swap, and class resource frame
movers only got built once their native frame had already appeared
on screen with a resolvable position -- so if the frame never showed
up in a session (e.g. a class resource bar the current class doesn't
use), Toggle Anchors had nothing to display for it. Movers are now
created up front from a default size/position, and just get resized
and anchored once the real frame shows up. Also fixes each mover's
right-click config shortcut, which pointed at a pre-restructure
options path.
This commit is contained in:
2026-08-18 16:00:49 +02:00
parent 6bf3864891
commit cc6cd4028b
3 changed files with 105 additions and 58 deletions
+42 -23
View File
@@ -1,13 +1,18 @@
local E, L, V, P, G = unpack(ElvUI) local E, L, V, P, G = unpack(ElvUI)
local CoA = E:GetModule("CoA") local CoA = E:GetModule("CoA")
-- defaultY staggers the movers' first-run default position (LEFT of screen,
-- spaced vertically) so they don't stack on top of each other before the
-- player has ever dragged them.
local FRAMES = { local FRAMES = {
{name = "CoAResourceSegmentBar", moverText = "Resource Segment Bar", hideKey = "hideResourceSegmentBar"}, {name = "CoAResourceSegmentBar", moverText = "Resource Segment Bar", hideKey = "hideResourceSegmentBar", defaultY = 40},
{name = "CoAResourceOrb", moverText = "Resource Orb", hideKey = "hideResourceOrb"}, {name = "CoAResourceOrb", moverText = "Resource Orb", hideKey = "hideResourceOrb", defaultY = 100},
{name = "CoAResourceBar", moverText = "Resource Bar", hideKey = "hideResourceBar"}, {name = "CoAResourceBar", moverText = "Resource Bar", hideKey = "hideResourceBar", defaultY = 160},
{name = "CoAMultiCastActionBarFrame", moverText = "Multi Cast Action Bar", hideKey = "hideMultiCastActionBar"}, {name = "CoAMultiCastActionBarFrame", moverText = "Multi Cast Action Bar", hideKey = "hideMultiCastActionBar", defaultY = 220},
} }
local DEFAULT_WIDTH, DEFAULT_HEIGHT = 150, 30
local FRAME_NAMES = {} local FRAME_NAMES = {}
for _, def in ipairs(FRAMES) do for _, def in ipairs(FRAMES) do
FRAME_NAMES[def.name] = true FRAME_NAMES[def.name] = true
@@ -179,30 +184,42 @@ local function LockPosition(frame, holder)
end) end)
end end
local function SetupMover(frame, name, moverText) -- Created eagerly (independent of the native frame ever showing up -- several
if frame.CoAMoverCreated then return true end -- of these are class-specific and may never appear for a given character) so
-- every mover always appears in Toggle Anchors. The default point is only
-- used until the player drags it once; after that E:CreateMover restores the
-- saved position from E.db.movers.
local function CreateMoverHolder(def)
if CoA.classResourceMoversCreated and CoA.classResourceMoversCreated[def.name] then return end
CoA.classResourceMoversCreated = CoA.classResourceMoversCreated or {}
CoA.classResourceMoversCreated[def.name] = true
local holder = CreateFrame("Frame", "CoA_"..def.name.."Holder", E.UIParent)
holder:Size(DEFAULT_WIDTH, DEFAULT_HEIGHT)
holder:Point("LEFT", E.UIParent, "LEFT", 150, def.defaultY)
E:CreateMover(holder, "CoA_"..def.name.."Mover", def.moverText, nil, nil, nil, "ALL,COA", nil, "CoA,classResources")
holder:SetAllPoints(_G["CoA_"..def.name.."Mover"])
end
local function SyncHolderSize(frame, name)
local holder = _G["CoA_"..name.."Holder"]
if not holder then return end
local width, height = frame:GetSize() local width, height = frame:GetSize()
if width == 0 or height == 0 then return false end if width > 0 and height > 0 then
local left, bottom = frame:GetLeft(), frame:GetBottom()
if not left or not bottom then return false end
frame.CoAMoverCreated = true
local holder = CreateFrame("Frame", "CoA_"..name.."Holder", E.UIParent)
holder:Size(width, height) holder:Size(width, height)
holder:Point("BOTTOMLEFT", E.UIParent, "BOTTOMLEFT", left, bottom) end
end
E:CreateMover(holder, "CoA_"..name.."Mover", moverText, nil, nil, nil, "ALL,COA", nil, "CoA,skin,classResources") local function AnchorFrame(frame, name)
holder:SetAllPoints(_G["CoA_"..name.."Mover"]) local holder = _G["CoA_"..name.."Holder"]
if not holder then return end
QueueAnchor(function() QueueAnchor(function()
AnchorToHolder(frame, holder) AnchorToHolder(frame, holder)
LockPosition(frame, holder) LockPosition(frame, holder)
end) end)
return true
end end
-- The server never Show()s a frame the current class doesn't use, so its -- The server never Show()s a frame the current class doesn't use, so its
@@ -259,15 +276,13 @@ local function TryHookAll()
DisableDrag(frame) DisableDrag(frame)
SetupVisibility(frame, def.hideKey) SetupVisibility(frame, def.hideKey)
FixTooltip(frame) FixTooltip(frame)
SyncHolderSize(frame, def.name)
AnchorFrame(frame, def.name)
if SetupMover(frame, def.name, def.moverText) then
hooked[def.name] = true hooked[def.name] = true
else else
allHooked = false allHooked = false
end end
else
allHooked = false
end
end end
end end
@@ -275,6 +290,10 @@ local function TryHookAll()
end end
function CoA:InitializeClassResources() function CoA:InitializeClassResources()
for _, def in ipairs(FRAMES) do
CreateMoverHolder(def)
end
if TryHookAll() then return end if TryHookAll() then return end
self.classResourcesTimer = self:ScheduleRepeatingTimer(function() self.classResourcesTimer = self:ScheduleRepeatingTimer(function()
+33 -18
View File
@@ -53,6 +53,11 @@ end
function CoA:UpdateExtraActionButtonSize() function CoA:UpdateExtraActionButtonSize()
UpdateSize() UpdateSize()
local holder = _G["CoA_ExtraActionBarHolder"]
if holder then
holder:Size(CoA.db.profile.extraActionButtonSize or 52)
end
end end
local function UpdateHotkeyText(button) local function UpdateHotkeyText(button)
@@ -157,26 +162,34 @@ local function SkinButton(button, container)
SkinGlow(button, name) SkinGlow(button, name)
end end
local function SetupMover(container, button) -- Created eagerly (independent of the native ExtraActionBar ever showing up)
if CoA.extraActionBarMoverCreated then return true end -- so the mover always appears in Toggle Anchors. The default point below is
-- only used until the player drags it once; after that E:CreateMover restores
local width, height = button:GetSize() -- the saved position from E.db.movers.
if width == 0 or height == 0 then return false end local function CreateMoverHolder()
if CoA.extraActionBarMoverCreated then return end
local left, bottom = button:GetLeft(), button:GetBottom()
if not left or not bottom then return false end
CoA.extraActionBarMoverCreated = true CoA.extraActionBarMoverCreated = true
local size = CoA.db.profile.extraActionButtonSize or 52
local holder = CreateFrame("Frame", "CoA_ExtraActionBarHolder", E.UIParent)
holder:Size(size, size)
holder:Point("BOTTOM", E.UIParent, "BOTTOM", 0, 260)
E:CreateMover(holder, "CoA_ExtraActionBarMover", "Extra Action Bar", nil, nil, nil, "ALL,COA", nil, "CoA,skins,extraActionButton")
holder:SetAllPoints(_G["CoA_ExtraActionBarMover"])
end
local function SetupContainer(container)
if container.CoAContainerSetup then return end
container.CoAContainerSetup = true
container:StripTextures(true) container:StripTextures(true)
container:EnableMouse(false) container:EnableMouse(false)
end
local holder = CreateFrame("Frame", "CoA_ExtraActionBarHolder", E.UIParent) local function AnchorContainer(container)
holder:Size(width, height) local holder = _G["CoA_ExtraActionBarHolder"]
holder:Point("BOTTOMLEFT", E.UIParent, "BOTTOMLEFT", left, bottom) if not holder then return end
E:CreateMover(holder, "CoA_ExtraActionBarMover", "Extra Action Bar", nil, nil, nil, "ALL,COA", nil, "CoA,skin,extraActionBar")
holder:SetAllPoints(_G["CoA_ExtraActionBarMover"])
local function Anchor() local function Anchor()
container:ClearAllPoints() container:ClearAllPoints()
@@ -191,8 +204,6 @@ local function SetupMover(container, button)
else else
Anchor() Anchor()
end end
return true
end end
local function TryHook() local function TryHook()
@@ -201,13 +212,17 @@ local function TryHook()
if container and button then if container and button then
SkinButton(button, container) SkinButton(button, container)
return SetupMover(container, button) SetupContainer(container)
AnchorContainer(container)
return true
end end
return false return false
end end
function CoA:InitializeExtraActionBar() function CoA:InitializeExtraActionBar()
CreateMoverHolder()
if TryHook() then return end if TryHook() then return end
self.extraActionBarTimer = self:ScheduleRepeatingTimer(function() self.extraActionBarTimer = self:ScheduleRepeatingTimer(function()
+28 -15
View File
@@ -19,8 +19,17 @@ local function UpdateFont(button)
) )
end end
local function SyncHolderSize(button)
local holder = _G["CoA_LayerPickerHolder"]
button = button or _G[BUTTON_NAME]
if holder and button then
holder:Size(button:GetSize())
end
end
function CoA:UpdateInstanceButtonFont() function CoA:UpdateInstanceButtonFont()
UpdateFont() UpdateFont()
SyncHolderSize()
end end
-- Hooked at file scope, so unlike the rest of the skin it stays live even when -- Hooked at file scope, so unlike the rest of the skin it stays live even when
@@ -69,24 +78,26 @@ local function DisableDrag(button)
end) end)
end end
local function SetupMover(button) -- Created eagerly (independent of the native LayerPickerFrame ever showing
if CoA.layerPickerMoverCreated then return true end -- up) so the mover always appears in Toggle Anchors. The default point below
-- is only used until the player drags it once; after that E:CreateMover
local width, height = button:GetSize() -- restores the saved position from E.db.movers.
if width == 0 or height == 0 then return false end local function CreateMoverHolder()
if CoA.layerPickerMoverCreated then return end
local left, bottom = button:GetLeft(), button:GetBottom()
if not left or not bottom then return false end
CoA.layerPickerMoverCreated = true CoA.layerPickerMoverCreated = true
local holder = CreateFrame("Frame", "CoA_LayerPickerHolder", E.UIParent) local holder = CreateFrame("Frame", "CoA_LayerPickerHolder", E.UIParent)
holder:Size(width, height) holder:Size(MIN_WIDTH, MIN_HEIGHT)
holder:Point("BOTTOMLEFT", E.UIParent, "BOTTOMLEFT", left, bottom) holder:Point("TOPLEFT", E.UIParent, "TOPLEFT", 250, -250)
E:CreateMover(holder, "CoA_LayerPickerMover", "Instance", nil, nil, nil, "ALL,COA", nil, "CoA,skin,instance") E:CreateMover(holder, "CoA_LayerPickerMover", "Instance", nil, nil, nil, "ALL,COA", nil, "CoA,skins,instanceSwap")
holder:SetAllPoints(_G["CoA_LayerPickerMover"]) holder:SetAllPoints(_G["CoA_LayerPickerMover"])
_G["CoA_LayerPickerMover"]:SetFrameStrata("FULLSCREEN") _G["CoA_LayerPickerMover"]:SetFrameStrata("FULLSCREEN")
end
local function AnchorButton(button)
local holder = _G["CoA_LayerPickerHolder"]
if not holder then return end
local function Anchor() local function Anchor()
button:ClearAllPoints() button:ClearAllPoints()
@@ -101,8 +112,6 @@ local function SetupMover(button)
else else
Anchor() Anchor()
end end
return true
end end
local function SkinButton(button) local function SkinButton(button)
@@ -122,13 +131,17 @@ local function TryHook()
if button then if button then
DisableDrag(button) DisableDrag(button)
SkinButton(button) SkinButton(button)
return SetupMover(button) SyncHolderSize(button)
AnchorButton(button)
return true
end end
return false return false
end end
function CoA:InitializeLayerPicker() function CoA:InitializeLayerPicker()
CreateMoverHolder()
if TryHook() then return end if TryHook() then return end
self.layerPickerTimer = self:ScheduleRepeatingTimer(function() self.layerPickerTimer = self:ScheduleRepeatingTimer(function()