Nenue@0: --- Actual BlizzUI modifications are applied here Nenue@0: -- @file-author@ Nenue@0: -- @project-revision@ @project-hash@ Nenue@0: -- @file-revision@ @file-hash@ Nenue@0: -- Created: 3/12/2016 12:47 AM Nenue@0: local MODULE = 'BuffFrame' Nenue@0: local _, A = ... Nenue@0: local B, _G = A.frame, _G Nenue@0: local type, unpack, select, pairs, ipairs = _G.type, _G.unpack, _G.select, _G.pairs, _G.ipairs Nenue@0: local min, ceil, mod, tonumber, tostring = _G.min, _G.ceil, _G.mod, _G.tonumber, _G.tostring Nenue@0: local floor, wipe, max = _G.math.floor, _G.table.wipe, _G.math.max Nenue@0: local CreateFrame, IsInGroup, GetCVarBool = _G.CreateFrame, _G.IsInGroup, _G.GetCVarBool Nenue@0: local BuffFrame, ConsolidatedBuffs = _G.BuffFrame, _G.ConsolidatedBuffs Nenue@0: local print, gprint, aprint, fprint = B.print('Buff'), B.print('SetGuides'), B.print('SetAnchors'), B.fprint Nenue@0: local displays, anchors, guides, decors, positioned, drawn, zoom = B.displays, {}, {}, {}, {}, {}, {} Nenue@0: local UnitAura, UnitName, RegisterStateDriver = _G.UnitAura, _G.UnitName, _G.RegisterStateDriver Nenue@0: Nenue@0: local M = B:RegisterModule(MODULE) Nenue@0: Nenue@0: M.GetBuffZoom = function(buffName) Nenue@0: local zoom = tonumber(B.displays[buffName].conf['Zoom']) / 100 / 2 Nenue@0: local zoomL, zoomU, zoomR, zoomD = zoom, zoom, 1-zoom, 1-zoom Nenue@0: print(buffName, zoom) Nenue@0: return function(self, ...) Nenue@0: if select('#',...) == 4 then Nenue@0: zoomL, zoomR, zoomU, zoomD = ... Nenue@0: end Nenue@0: self:SetTexCoord(zoomL, zoomR, zoomU, zoomD) Nenue@0: return zoomL, zoomR, zoomU, zoomD Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: Nenue@0: Nenue@0: M.UpdateButtonAlpha = function(self) Nenue@0: if not self.parent.timeLeft or not self:IsVisible() then Nenue@0: self:SetScript('OnUpdate', nil) Nenue@0: return Nenue@0: end Nenue@0: Nenue@0: if self.parent.timeLeft < _G.BUFF_WARNING_TIME then Nenue@0: self:SetAlpha(BuffFrame.BuffAlphaValue) Nenue@0: else Nenue@0: self:SetAlpha(1) Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: --- Called infrequently to align stencil frames Nenue@0: local refreshCount = 0 Nenue@0: M.UpdateGuideFrames = function(buffName) Nenue@0: refreshCount = refreshCount + 1 Nenue@0: local print = fprint() Nenue@0: Nenue@0: Nenue@0: local anchor = anchors[buffName] Nenue@0: local c, g, d = displays[buffName].conf, guides[buffName], decors[buffName] Nenue@0: local perRow = c['PerRow'] Nenue@0: local buffSpacing, buffSize, buffBorder, buffDurationSize, buffCountSize, relativeX, relativeY = c['Spacing'], c['Size'], c['Border'], c['DurationSize'], c['CountSize'], c['RelativeX'], c['RelativeY'] Nenue@0: local consolidated = (anchors[buffName].contains and IsInGroup()) Nenue@0: local consolidatedPosition = (consolidated and anchors[buffName].containPosition or 0) Nenue@0: Nenue@0: Nenue@0: print('|cFF00FF00Setting Guides ('..refreshCount..'):|r', buffName, 'user max:',c['Max'], 'hard max:', displays[buffName].maxIcons) Nenue@0: Nenue@0: local buffMax = min(c['Max'], displays[buffName].maxIcons) Nenue@0: local anchorFrom, anchorTo = c.Point[1], c.Point[2] Nenue@0: anchor.Zoom = M.GetBuffZoom(buffName) Nenue@0: Nenue@0: Nenue@0: Nenue@0: if consolidated then Nenue@0: buffMax = buffMax + 1 Nenue@0: end Nenue@0: Nenue@0: local legend = {} Nenue@0: legend.r, legend.g, legend.b, legend.a = unpack(displays[buffName].legendColor) Nenue@0: local horizFrom = (relativeX < 0) and 'RIGHT' or 'LEFT' Nenue@0: local horizTo = (relativeX < 0) and 'LEFT' or 'RIGHT' Nenue@0: local vertFrom = (relativeY < 0) and 'TOP' or 'BOTTOM' Nenue@0: local vertTo = (relativeY < 0) and 'BOTTOM' or 'TOP' Nenue@0: local previous, up Nenue@0: local bottom_extent = 0 Nenue@0: for i = 1, buffMax do Nenue@0: print('update idx', i) Nenue@0: if not g[i] then Nenue@0: g[i] = CreateFrame('Frame', buffName..'Guide'..i, anchor, displays[buffName].template or 'VeneerGuideTemplate') Nenue@0: RegisterStateDriver(g[i], "visibility", "[petbattle] [vehicleui] hide; show") Nenue@0: end Nenue@0: Nenue@0: local guide = g[i] Nenue@0: Nenue@0: local row = ceil(i / perRow) Nenue@0: local col = mod(i, perRow) Nenue@0: if col == 0 then Nenue@0: col = perRow Nenue@0: end Nenue@0: Nenue@0: guide.previous = previous Nenue@0: guide.up = up Nenue@0: local x, y, parent = 0, 0, anchor Nenue@0: if i == 1 then Nenue@0: parent = anchor Nenue@0: up = guide Nenue@0: elseif col == 1 then Nenue@0: parent = g[i-perRow] Nenue@0: y = (buffSpacing + bottom_extent) * relativeY Nenue@0: up = guide Nenue@0: anchorFrom = vertFrom .. horizFrom Nenue@0: anchorTo = vertFrom .. horizFrom Nenue@0: bottom_extent = 0 Nenue@0: else Nenue@0: parent = g[i-1] Nenue@0: x = buffSpacing * relativeX Nenue@0: anchorFrom = vertFrom .. horizFrom Nenue@0: anchorTo = vertFrom .. horizTo Nenue@0: end Nenue@0: previous = guide Nenue@0: guide.parent = parent Nenue@0: Nenue@0: --------------------------------- Nenue@0: -- Positioning layer Nenue@0: if i ~= consolidatedPosition or not consolidated then Nenue@0: guide:SetSize(buffSize, buffSize + buffDurationSize) Nenue@0: -- RaidBuffTray will fix the sizing Nenue@0: end Nenue@0: bottom_extent = max(bottom_extent, guide:GetHeight()) Nenue@0: Nenue@0: guide.info = {} -- UnitAura cache Nenue@0: Nenue@0: if i == consolidatedPosition then Nenue@0: guide.legend:SetTexture(1,1,0,0.5) Nenue@0: else Nenue@0: guide.legend:SetTexture(legend.r, legend.g, legend.b, legend.a) Nenue@0: end Nenue@0: Nenue@0: guide.idText:SetText(i) -- needs to reflect the current position Nenue@0: Nenue@0: guide:ClearAllPoints() Nenue@0: guide:SetPoint(anchorFrom, parent, anchorTo, x, y) Nenue@0: print(anchorFrom, parent, anchorTo, x, y) Nenue@0: Nenue@0: guide.icon:SetSize(buffSize - buffBorder * 2, buffSize - buffBorder * 2) Nenue@0: guide.icon:ClearAllPoints() Nenue@0: guide.icon:SetPoint('TOPLEFT', guide, 'TOPLEFT', buffBorder, -buffBorder ) Nenue@0: Nenue@0: local anchorTo, anchorFrom, x, y = unpack(c.DurationPoint) Nenue@0: guide.duration:ClearAllPoints() Nenue@0: guide.duration:SetPoint(anchorTo, guide, anchorFrom, x, y) Nenue@0: --guide.duration:SetSize(buffSize, buffDurationSize) Nenue@0: print(' duration ->', anchorFrom, anchorTo, x, y) Nenue@0: Nenue@0: local anchorTo, anchorFrom, x, y = unpack(c.CountPoint) Nenue@0: guide.count:ClearAllPoints() Nenue@0: guide.count:SetPoint(anchorTo, guide.icon, anchorFrom, x, y) Nenue@0: --guide.count:SetSize(buffSize, c.CountSize) Nenue@0: print(' count ->', anchorFrom, anchorTo, x, y) Nenue@0: Nenue@0: ----------------------------------- Nenue@0: -- Background decorations layer Nenue@0: if not d[i] then Nenue@0: d[i] = CreateFrame('Frame', buffName..i..'Decor', _G.UIParent, 'VeneerDecorTemplate') Nenue@0: RegisterStateDriver(d[i], "visibility", "[petbattle] [vehicleui] hide") Nenue@0: end Nenue@0: Nenue@0: d[i]:SetPoint('BOTTOMLEFT', guide.icon, 'BOTTOMLEFT', -buffBorder, -buffBorder) Nenue@0: d[i]:SetPoint('TOPRIGHT', guide.icon, 'TOPRIGHT', buffBorder, buffBorder) Nenue@0: Nenue@0: Nenue@0: guide:Show() Nenue@0: B.SetConfigLayers(guide) Nenue@0: end Nenue@0: Nenue@0: Nenue@0: if #guides[buffName] > buffMax then Nenue@0: local lim = #guides[buffName] Nenue@0: for i = buffMax+1, lim do Nenue@0: Nenue@0: local g = guides[buffName][i] Nenue@0: if g:IsVisible() then Nenue@0: print('cleaning up #', i, buffName) Nenue@0: g:Hide() Nenue@0: B.RemoveConfigLayers(g) Nenue@0: end Nenue@0: Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: anchor.last = previous Nenue@0: anchor.up = up Nenue@0: Nenue@0: print(anchor:GetName(), anchor:GetSize()) Nenue@0: end Nenue@0: Nenue@0: M.UpdateButtonPositions = function(buffName, auraType) Nenue@0: local print = fprint() Nenue@0: local c = auraType.conf Nenue@0: local numBuffs = 0 Nenue@0: local actualIcons = auraType.actualIcons() Nenue@0: local maxIcons = auraType.maxIcons Nenue@0: local anchor = anchors[buffName] Nenue@0: local buffMax = c['Max'] Nenue@0: local consolidated = (anchor.contains and IsInGroup()) Nenue@0: local consolidatedPosition = (consolidated and anchor.containPosition or 0) Nenue@0: Nenue@0: for k,v in pairs(decors[buffName]) do Nenue@0: print(v) Nenue@0: end Nenue@0: Nenue@0: if consolidated then Nenue@0: decors[buffName][1]:Hide() Nenue@0: numBuffs = numBuffs + 1 Nenue@0: buffMax = buffMax + 1 Nenue@0: end Nenue@0: Nenue@0: print(' ', 'frame count:', auraType.actualIcons(), 'hardmax:', maxIcons) Nenue@0: if auraType.actualIcons() > 0 then Nenue@0: for i = 1, actualIcons do Nenue@0: Nenue@0: Nenue@0: local buff = _G[buffName .. i] Nenue@0: local buffIcon = _G[buffName .. i .. 'Icon'] Nenue@0: local buffBorder = c['Border'] Nenue@0: local buffDuration = _G[buffName .. i .. 'Duration'] Nenue@0: local buffCount = _G[buffName .. i .. 'Count'] Nenue@0: local buffDurationSize = c['DurationSize'] Nenue@0: local debuffBorder = _G[buffName .. i .. 'Border'] Nenue@0: Nenue@0: Nenue@0: if buff and not buff.consolidated then Nenue@0: numBuffs = numBuffs + 1 Nenue@0: local guide = guides[buffName][numBuffs] Nenue@0: local deco = decors[buffName][numBuffs] Nenue@0: if numBuffs > buffMax then Nenue@0: -- if a limit is reached, start hiding Nenue@0: if guide then Nenue@0: guide.info = nil Nenue@0: end Nenue@0: if deco then Nenue@0: deco:Hide() Nenue@0: end Nenue@0: buff:Hide() Nenue@0: else Nenue@0: local buffData = guide.info Nenue@0: buffData.name, buffData.rank, buffData.icon, buffData.count, buffData.dispelType, buffData.duration, buffData.expires, buffData.caster, buffData.isStealable, buffData.shouldConsolidate, buffData.spellID, buffData.canApplyAura, buffData.isBossDebuff, buffData.value1, buffData.value2, buffData.value3 Nenue@0: = UnitAura(buff.unit, buff:GetID(), nil, buff.filters) Nenue@0: Nenue@0: if guide.caster and buffData.caster then Nenue@0: if (buffData.caster ~= 'player' or c.ShowSelfCast) then Nenue@0: guide.caster:SetText(UnitName(buffData.caster)) Nenue@0: else Nenue@0: guide.caster:SetText(nil) Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: Nenue@0: print(numBuffs, i, buff:GetName(), buff:GetID(), decors[buffName][numBuffs]:GetName()) Nenue@0: Nenue@0: buff:SetAllPoints(guide) Nenue@0: buffIcon:ClearAllPoints() Nenue@0: buffIcon:SetPoint('TOPLEFT', guide.icon, 'TOPLEFT', 0, 0) Nenue@0: buffIcon:SetPoint('BOTTOMRIGHT', guide.icon, 'BOTTOMRIGHT', 0, 0) Nenue@0: Nenue@0: deco.parent = buff Nenue@0: -- make sure so they aren't re-shown in pet battle Nenue@0: if not C_PetBattles.IsInBattle() then Nenue@0: deco:Show() Nenue@0: deco:SetAlpha(1) Nenue@0: end Nenue@0: Nenue@0: if debuffBorder then Nenue@0: deco.background:SetTexture(debuffBorder:GetVertexColor()) Nenue@0: debuffBorder:Hide() Nenue@0: else Nenue@0: if guide.info.caster == 'player' then Nenue@0: print(guide.info.caster) Nenue@0: deco.background:SetTexture(unpack(c.PlayerColor)) Nenue@0: elseif buffData.isBossDebuff then Nenue@0: print(guide.info.isBossDebuff) Nenue@0: deco.background:SetTexture(unpack(c.BossColor)) Nenue@0: else Nenue@0: print(guide.info.caster) Nenue@0: deco.background:SetTexture(unpack(c.Color)) Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: Nenue@0: buffDuration:ClearAllPoints() Nenue@0: local from, to = unpack(c.DurationPoint) Nenue@0: buffDuration:SetPoint(from, guide.duration, to) Nenue@0: buffDuration:SetText('WHAT') Nenue@0: Nenue@0: if buff.timeLeft and c.WarningFade then Nenue@0: deco:SetScript('OnUpdate', M.UpdateButtonAlpha) Nenue@0: else Nenue@0: deco:SetScript('OnUpdate', nil) Nenue@0: deco:SetAlpha(1.0) Nenue@0: end Nenue@0: Nenue@0: buffCount:ClearAllPoints() Nenue@0: local from, to = unpack(c.CountPoint) Nenue@0: buffCount:SetPoint(from, guide.count, to) Nenue@0: Nenue@0: if not drawn[buffName][numBuffs] then Nenue@0: anchors[buffName].Zoom(buffIcon) Nenue@0: Nenue@0: if buffDuration then Nenue@0: local font = buffDuration:GetFont() Nenue@0: buffDuration:SetFont(font, c.DurationSize, 'OUTLINE') Nenue@0: Nenue@0: end Nenue@0: Nenue@0: if buffCount then Nenue@0: local font = buffCount:GetFont() Nenue@0: buffCount:SetFont(font, c.CountSize, 'OUTLINE') Nenue@0: end Nenue@0: drawn[buffName][numBuffs] = true Nenue@0: end Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: end Nenue@0: end Nenue@0: -- clear any outliers Nenue@0: for i = numBuffs+1, buffMax do Nenue@0: if guides[buffName][i].caster then Nenue@0: guides[buffName][i].caster:SetText(nil) Nenue@0: end Nenue@0: --if not decors[buffName][i].parent or Nenue@0: Nenue@0: decors[buffName][i].parent = nil Nenue@0: decors[buffName][i]:SetAlpha(1.0) Nenue@0: decors[buffName][i]:SetScript('OnUpdate', nil) Nenue@0: decors[buffName][i]:Hide() Nenue@0: end Nenue@0: Nenue@0: -- parametric occlusion data for compacted anchor points Nenue@0: if numBuffs == 0 then Nenue@0: anchor.cutout_X = 0 Nenue@0: anchor.cutout_Y = 0 Nenue@0: anchor.outer_X = 0 Nenue@0: anchor.outer_Y = 0 Nenue@0: elseif numBuffs <= buffMax then Nenue@0: local sX, sY = guides[buffName][numBuffs]:GetWidth(), guides[buffName][numBuffs]:GetHeight() Nenue@0: local p = c.PerRow Nenue@0: local lX = mod(numBuffs, p) Nenue@0: local lY = floor(numBuffs / p) Nenue@0: local oX = min(numBuffs, c.PerRow) Nenue@0: local oY = ceil(numBuffs / p) Nenue@0: anchor.cutout_X = lX * sX + lX * c.Spacing -- max clearance to fit alongside the row Nenue@0: anchor.cutout_Y = lY * sY + lY * c.Spacing Nenue@0: anchor.outer_Y = oY * sY + oY * c.Spacing -- distance of farthest row Nenue@0: anchor.outer_X = oX * sX + oX * c.Spacing Nenue@0: Nenue@0: Nenue@0: print('|cFF0088FF', 'inner corner', lX, lY, 'outer corners', oX, oY) Nenue@0: print('cutout delta =', anchor.cutout_X, anchor.cutout_Y, 'out of', floor(anchor:GetWidth()), floor(anchor:GetHeight())) Nenue@0: print('extent delta =', anchor.outer_X, anchor.outer_Y) Nenue@0: else Nenue@0: anchor.cutout_X = 0 Nenue@0: anchor.cutout_Y = 0 Nenue@0: anchor.outer_X = 0 Nenue@0: anchor.outer_Y = 0 Nenue@0: end Nenue@0: Nenue@0: if anchor.attached then Nenue@0: M.UpdateAnchorChild(anchor, anchor.attached, anchor.attachmentConf) Nenue@0: end Nenue@0: Nenue@0: end Nenue@0: Nenue@0: M.PostBuffAnchors = function() Nenue@0: local print = fprint() Nenue@0: if M.ShowConsolidatedBuffs then Nenue@0: M.UpdateRaidBuffs() Nenue@0: end Nenue@0: for buttonName, auraType in pairs(displays) do Nenue@0: print('sending', buttonName, auraType) Nenue@0: -- if waiting for anchors Nenue@0: if not anchors[buttonName] then Nenue@0: return Nenue@0: end Nenue@0: Nenue@0: --if positioned[buttonName] == 0 then Nenue@0: print('possibly reloaded UI, check positions') Nenue@0: M.UpdateGuideFrames(buttonName) Nenue@0: --end Nenue@0: Nenue@0: M.UpdateButtonPositions(buttonName, auraType) Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: M.UpdateBuffs = function(buttonName, forced) Nenue@0: local print = B.fprint(buttonName) Nenue@0: local c = displays[buttonName].conf Nenue@0: if drawn[buttonName] then Nenue@0: wipe(drawn[buttonName]) Nenue@0: else Nenue@0: drawn[buttonName] = {} Nenue@0: end Nenue@0: Nenue@0: M.UpdateAnchorFrames(buttonName) Nenue@0: M.UpdateGuideFrames(buttonName) Nenue@0: M.UpdateButtonPositions(buttonName, displays[buttonName]) Nenue@0: end Nenue@0: Nenue@0: --- should only be called from user input Nenue@0: print('init def') Nenue@0: function M:OnInitialize () Nenue@0: drawn = B.Abstract(B.displays, 'drawn') Nenue@0: -- Lesser extent of guide frames that have been positioned Nenue@0: positioned = B.Abstract(B.displays, 'positioned', positioned) Nenue@0: -- Backdrop style frame Nenue@0: decors = B.Abstract(B.displays, 'decorator', decors) Nenue@0: -- Static positioning frames Nenue@0: guides = B.Abstract(B.displays, 'guides', guides) Nenue@0: -- Anchor points for guides Nenue@0: anchors = B.Abstract(B.displays, 'anchor') Nenue@0: -- Stored functions for doing icon texture adjustments Nenue@0: zoom = B.Abstract(B.displays, 'zoom', zoom) Nenue@0: Nenue@0: B:RegisterUnitEvent("UNIT_AURA", "player", "vehicle") Nenue@0: B:RegisterEvent("GROUP_ROSTER_UPDATE") Nenue@0: B:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED") Nenue@0: hooksecurefunc("BuffFrame_UpdateAllBuffAnchors", M.PostBuffAnchors) Nenue@0: hooksecurefunc("RaidBuffTray_Update", M.UpdateRaidBuffs) Nenue@0: end Nenue@0: print('update def') Nenue@0: function M:OnUpdate () Nenue@0: M.ShowConsolidated = (IsInGroup() and GetCVarBool("consolidateBuffs")) Nenue@0: M.ShowMissingBuffs = (IsInGroup() and B.Conf.RaidShowMissing) Nenue@0: Nenue@0: for name, auraType in pairs(displays) do Nenue@0: print(name, auraType) Nenue@0: M.UpdateBuffs(auraType.buffName, true) Nenue@0: end Nenue@0: Nenue@0: M.UpdateAnchorAnchors() Nenue@0: M.UpdateRaidBuffs() Nenue@0: M.UpdateBuffsTodo() Nenue@0: end