NameplateBuffContainerMixin = {} -- Lay the visible buff icons out in a row. -- -- Ascension gets this from SharedXML's HorizontalLayoutFrame, whose -- LayoutMixin reads a layoutIndex off each child and honours the spacing and -- fixedHeight attributes declared in the XML. That is a general layout engine -- and this is a single row of equally sized icons, so the engine is not worth -- dragging in for it - the two attributes it would have read are inlined here -- as the constants they were. local BUFF_SPACING = 4 local BUFF_FIXED_HEIGHT = 14 function NameplateBuffContainerMixin:Layout() local shown, totalWidth, height = {}, 0, BUFF_FIXED_HEIGHT for _, buff in ipairs(self.buffList) do if buff:IsShown() then shown[#shown + 1] = buff end end if #shown == 0 then -- A zero-width frame still anchors its children, so give it a real -- size rather than leaving whatever the last update left behind. self:SetSize(1, BUFF_FIXED_HEIGHT) return end for i, buff in ipairs(shown) do buff:ClearAllPoints() if i == 1 then buff:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", 0, 0) else buff:SetPoint("BOTTOMLEFT", shown[i - 1], "BOTTOMRIGHT", BUFF_SPACING, 0) end local w = buff:GetWidth() totalWidth = totalWidth + w + (i > 1 and BUFF_SPACING or 0) local h = buff:GetHeight() if h and h > height then height = h end end self:SetSize(totalWidth, height) end function NameplateBuffContainerMixin:OnLoad() self.buffList = {} self.targetYOffset = 0 self.baseYOffset = 0 self.BuffFrameUpdateTime = 0 self:RegisterEvent("PLAYER_TARGET_CHANGED") end function NameplateBuffContainerMixin:OnEvent(event, ...) if event == "PLAYER_TARGET_CHANGED" then self:UpdateAnchor() end end function NameplateBuffContainerMixin:OnUpdate(elapsed) if ( self.BuffFrameUpdateTime > 0 ) then self.BuffFrameUpdateTime = self.BuffFrameUpdateTime - elapsed else self.BuffFrameUpdateTime = self.BuffFrameUpdateTime + TOOLTIP_UPDATE_TIME end end function NameplateBuffContainerMixin:SetTargetYOffset(targetYOffset) self.targetYOffset = targetYOffset end function NameplateBuffContainerMixin:GetTargetYOffset() return self.targetYOffset end function NameplateBuffContainerMixin:SetBaseYOffset(baseYOffset) self.baseYOffset = baseYOffset end function NameplateBuffContainerMixin:GetBaseYOffset() return self.baseYOffset end function NameplateBuffContainerMixin:UpdateAnchor() local isTarget = self:GetParent().unit and UnitIsUnit(self:GetParent().unit, "target") local targetYOffset = self:GetBaseYOffset() + (isTarget and self:GetTargetYOffset() or 0.0) if self:GetParent().unit and self:GetParent():ShouldShowName() then self:SetPoint("BOTTOM", self:GetParent().name, "TOP", 0, 5 + targetYOffset) else self:SetPoint("BOTTOM", self:GetParent().healthBar, "TOP", 0, targetYOffset) end end function NameplateBuffContainerMixin:SetActive(isActive) self.isActive = isActive if not isActive then self.unit = nil for _, buff in ipairs(self.buffList) do buff:Hide() buff.expireTime = nil buff.CooldownText:SetText("") end self:Layout() end end function NameplateBuffContainerMixin:UpdateBuffs(unit, filter, allowList) if not self.isActive then for i = 1, BUFF_MAX_DISPLAY do if self.buffList[i] then self.buffList[i]:Hide() end end return end self.unit = unit self.filter = filter self:UpdateAnchor() if filter == "NONE" then for i, buff in ipairs(self.buffList) do buff:Hide() end else -- Some buffs may be filtered out, use this to create the buff frames. local buffIndex = 1 local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, canStealOrPurge, shouldConsolidate, spellID for i = 1, BUFF_MAX_DISPLAY do name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, canStealOrPurge, shouldConsolidate, spellID = UnitAura(unit, i, filter) if name then if AuraUtil.UnitShouldShowBuff(unit, name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, canStealOrPurge, shouldConsolidate, spellID) then if (not self.buffList[buffIndex]) then self.buffList[buffIndex] = CreateFrame("Frame", self:GetParent():GetName() .. "Buff" .. buffIndex, self, "NameplateBuffButtonTemplate") self.buffList[buffIndex].layoutIndex = buffIndex end local buff = self.buffList[buffIndex] buff:EnableMouse(false) buff:SetID(i) buff.name = name buff.Icon:SetTexture(icon) if (count > 1) then buff.CountFrame.Count:SetText(count) buff.CountFrame.Count:Show() else buff.CountFrame.Count:Hide() end buff.expireTime = expirationTime -- Do not retain the previous unit's countdown until the -- next throttled update when an icon is reused. buff.CooldownText:SetText("") buff:Show() buffIndex = buffIndex + 1 end else break end end for i = buffIndex, BUFF_MAX_DISPLAY do if self.buffList[i] then self.buffList[i]:Hide() end end end self:Layout() end NameplateBuffButtonTemplateMixin = {} function NameplateBuffButtonTemplateMixin:OnUpdate(elapsed) if self:GetParent().BuffFrameUpdateTime > 0 then return end -- UnitAura returns expirationTime 0 for an aura with no duration, and the -- subtraction below then produced 0 - GetTime(): a large negative number, -- which sails past the "> 60" test and lands in the "< 3" branch, so a -- permanent buff drew a counter like -91234.5 across its icon. Nothing -- throws, so it reads as a display glitch rather than as a missing check. if not self.expireTime or self.expireTime == 0 then self.CooldownText:SetText("") return end local timeLeft = self.expireTime - GetTime() if timeLeft <= 0 then self.CooldownText:SetText("") self:Hide() self:GetParent():Layout() elseif timeLeft > 60 then self.CooldownText:SetText("") elseif timeLeft < 3 then self.CooldownText:SetFormattedText("%.1f", timeLeft) else self.CooldownText:SetFormattedText("%d", timeLeft) end end