Size aura cooldown text to its laid-out icon

Unit frame aura icons only get their size from the layout pass, but
RefreshUnit started their timers before it ran. A cooldown text created
on a never-laid-out icon saw a height of 0 and fell back to a 16pt font,
so some buff and debuff timers overflowed their icons. (Closes #64)

- RefreshUnit stores each aura's timer and starts them after
  LayoutAuras, once every icon has its final size.
- With dynamic size on, the cooldown text re-sizes its font whenever
  its frame's height changed since the last SetTimer, so icons that
  switch between the normal and own aura size keep a matching font.
This commit is contained in:
Brues
2026-10-25 11:48:24 -05:00
parent 987c337709
commit bd7bf3f39f
2 changed files with 60 additions and 49 deletions
+34 -36
View File
@@ -69,6 +69,35 @@ local function LayoutAuras(unit, unitstr)
end end
end end
-- Returns the cooldown start and duration of an aura, 0, 0 when it has none.
-- Start is capped to now: talent-extended auras run past their Spell.dbc base
-- duration, and a start in the future trips the cooldown text's 2^32
-- wraparound branch.
local function AuraTimer(duration, expirationTime)
if expirationTime <= 0 then return 0, 0 end
local now = GetTime()
local start, dur = expirationTime - duration, duration
if start > now or dur <= 0 then
start, dur = now, expirationTime - now
end
if dur <= 0 then return 0, 0 end
return start, dur
end
-- Starts the timers RefreshUnit stored on the shown icons of an aura block.
local function StartAuraTimers(icons)
if not icons then return end
local i = 1
while icons[i] and icons[i]:IsShown() do
local dur = icons[i].auraDuration
CooldownFrame_SetTimer(icons[i].cd, icons[i].auraStart, dur, dur > 0 and 1 or 0)
i = i + 1
end
end
-- ============================================================================ -- ============================================================================
-- GUID-based Roster Tracking for Smart Updates -- GUID-based Roster Tracking for Smart Updates
-- Only updates frames where the unit actually changed, not ALL 40 frames -- Only updates frames where the unit actually changed, not ALL 40 frames
@@ -1711,24 +1740,7 @@ function pfUI.uf:RefreshUnit(unit, component)
unit.buffs[i].stacks:SetText("") unit.buffs[i].stacks:SetText("")
end end
if expirationTime > 0 then unit.buffs[i].auraStart, unit.buffs[i].auraDuration = AuraTimer(duration, expirationTime)
-- pfUI's cooldown text falls into a 2^32 wraparound branch when start > GetTime(),
-- which happens for talent-extended buffs where the real duration exceeds the
-- Spell.dbc base. Anchor start to now in that case to keep the remaining math sane.
local now = GetTime()
local start = expirationTime - duration
local dur = duration
if start > now or dur <= 0 then
start, dur = now, expirationTime - now
end
if dur > 0 then
CooldownFrame_SetTimer(unit.buffs[i].cd, start, dur, 1)
else
CooldownFrame_SetTimer(unit.buffs[i].cd, 0, 0, 0)
end
else
CooldownFrame_SetTimer(unit.buffs[i].cd, 0, 0, 0)
end
else else
unit.buffs[i]:Hide() unit.buffs[i]:Hide()
end end
@@ -1771,24 +1783,7 @@ function pfUI.uf:RefreshUnit(unit, component)
if texture then if texture then
unit.debuffs[i]:Show() unit.debuffs[i]:Show()
if expirationTime > 0 then unit.debuffs[i].auraStart, unit.debuffs[i].auraDuration = AuraTimer(duration, expirationTime)
-- Cap start to now so talent-extended debuffs (expirationTime past
-- the dbc base duration) don't push start into the future and trip
-- CooldownFrame_SetTimer's 2^32-wraparound branch.
local now = GetTime()
local start = expirationTime - duration
local dur = duration
if start > now or dur <= 0 then
start, dur = now, expirationTime - now
end
if dur > 0 then
CooldownFrame_SetTimer(unit.debuffs[i].cd, start, dur, 1)
else
CooldownFrame_SetTimer(unit.debuffs[i].cd, 0, 0, 0)
end
else
CooldownFrame_SetTimer(unit.debuffs[i].cd, 0, 0, 0)
end
if stacks > 1 then if stacks > 1 then
unit.debuffs[i].stacks:SetText(stacks) unit.debuffs[i].stacks:SetText(stacks)
@@ -1806,8 +1801,11 @@ function pfUI.uf:RefreshUnit(unit, component)
end end
end end
-- timers start after the layout so each cooldown text is sized to its icon
if component == "all" or component == "aura" then if component == "all" or component == "aura" then
LayoutAuras(unit, unitstr) LayoutAuras(unit, unitstr)
StartAuraTimers(unit.buffs)
StartAuraTimers(unit.debuffs)
end end
-- indicators -- indicators
+26 -13
View File
@@ -59,18 +59,14 @@ pfUI:RegisterModule("cooldown", function ()
end end
end end
local height, size local function GetCooldownHeight(cooldown)
local textcount = 0 return cooldown:GetParent() and cooldown:GetParent():GetHeight() or cooldown:GetHeight() or 0
local function pfCreateCoolDown(cooldown, start, duration) end
textcount = textcount + 1
local name = cooldown.GetName and cooldown:GetName() or "pfCooldown" .. textcount
cooldown.pfCooldownText = CreateFrame("Frame", name .. "Text", cooldown:GetParent())
cooldown.pfCooldownText.cooldown = cooldown
cooldown.pfCooldownText:SetAllPoints(cooldown)
cooldown.pfCooldownText:SetFrameLevel(cooldown:GetParent():GetFrameLevel() + 2)
cooldown.pfCooldownText.text = cooldown.pfCooldownText:CreateFontString(name .. "TextString", "OVERLAY")
-- sizes the text to the cooldown's current height; the dynamic size follows
-- the frame, so SetCooldown calls this again whenever that height changes
local function pfUpdateCooldownFont(cooldown)
local size
if not cooldown.pfCooldownType then if not cooldown.pfCooldownType then
size = tonumber(C.appearance.cd.font_size_foreign) size = tonumber(C.appearance.cd.font_size_foreign)
elseif cooldown.pfCooldownType == "BLIZZARD" then elseif cooldown.pfCooldownType == "BLIZZARD" then
@@ -82,12 +78,27 @@ pfUI:RegisterModule("cooldown", function ()
end end
-- enforce dynamic font size -- enforce dynamic font size
if C.appearance.cd.dynamicsize == "1" and cooldown.GetParent then if C.appearance.cd.dynamicsize == "1" then
height = cooldown:GetParent() and cooldown:GetParent():GetHeight() or cooldown:GetHeight() or 0 local height = GetCooldownHeight(cooldown)
cooldown.pfCooldownText.height = height
size = math.max((height > 0 and height * .64 or 16), size) size = math.max((height > 0 and height * .64 or 16), size)
end end
cooldown.pfCooldownText.text:SetFont(pfUI.media[C.appearance.cd.font], size, "OUTLINE") cooldown.pfCooldownText.text:SetFont(pfUI.media[C.appearance.cd.font], size, "OUTLINE")
end
local textcount = 0
local function pfCreateCoolDown(cooldown, start, duration)
textcount = textcount + 1
local name = cooldown.GetName and cooldown:GetName() or "pfCooldown" .. textcount
cooldown.pfCooldownText = CreateFrame("Frame", name .. "Text", cooldown:GetParent())
cooldown.pfCooldownText.cooldown = cooldown
cooldown.pfCooldownText:SetAllPoints(cooldown)
cooldown.pfCooldownText:SetFrameLevel(cooldown:GetParent():GetFrameLevel() + 2)
cooldown.pfCooldownText.text = cooldown.pfCooldownText:CreateFontString(name .. "TextString", "OVERLAY")
pfUpdateCooldownFont(cooldown)
cooldown.pfCooldownText.text:SetPoint("CENTER", cooldown.pfCooldownText, "CENTER", 0, 0) cooldown.pfCooldownText.text:SetPoint("CENTER", cooldown.pfCooldownText, "CENTER", 0, 0)
cooldown.pfCooldownText:SetScript("OnUpdate", pfCooldownOnUpdate) cooldown.pfCooldownText:SetScript("OnUpdate", pfCooldownOnUpdate)
end end
@@ -136,6 +147,8 @@ pfUI:RegisterModule("cooldown", function ()
and start > 0 and duration > 0 and (not enable or enable > 0) then and start > 0 and duration > 0 and (not enable or enable > 0) then
if( not this.pfCooldownText ) then if( not this.pfCooldownText ) then
pfCreateCoolDown(this, start, duration) pfCreateCoolDown(this, start, duration)
elseif C.appearance.cd.dynamicsize == "1" and GetCooldownHeight(this) ~= this.pfCooldownText.height then
pfUpdateCooldownFont(this)
end end
this.pfCooldownText.start = start this.pfCooldownText.start = start