Compare with Previous | Blame | View Log
--[[ oUF Element: .AuraBars Options regarding visual layout: - <element>.auraBarHeight Sets the height of the statusbars and icons. - <element>.auraBarWidth Sets the width of the statusbars (excluding icon). Will use the framewidth of <element> by default. - <element>.auraBarTexture Sets the statusbar texture. - <element>.fgalpha Foreground alpha. - <element>.bgalpha Background alpha. - <element>.spellTimeObject, <element>.spellNameObject Objects passed by CreateFontObject(). These will ignore the following options: <element>.spellTimeFont, <element>.spellTimeSize <element>.spellNameFont, <element>.spellNameSize - <element>.spellTimeFont, <element>.spellTimeSize, <element>.spellNameFont, <element>.spellNameSize Options to control the texts on the statusbars. - <element>.gap Will add space between the statusbars and icons by amount of .gap in pixels. - <element>.spacing Will add space between statusbars by amount of .spacing in pixels. Options regarding functionality: - <element>.down Will let the aurabars grow downwards. - <element>.filter(name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable) Use this to filter out specific casts. - <element>.sort Will enable sorting if set to true or 1 (or whatever). See functions for info on how to override the sort function. - <element>.scaleTime Will add time-scaling (bar widths according to the total duration of the aura assigned to it). Will use the minimum of <element>.scaleTime and the total aura duration to determine the width in percent. Functions that can be overridden from within a layout: - <element>.PostCreateBar(bar) To do stuff to a bar once it has been created, such as set a backdrop, etc, use this function. Use bar:GetParent() to get the <element> object. - <element>.sort(a, b) Custom compare function to sort aura's before the bars are being updated. Is being called every UNIT_AURA for the <element>'s unit. --]] local _, ns = ... local oUF = ns.oUF or oUF assert(oUF, 'oUF_AuraBars was unable to locate oUF install.') --[[ Shortens an spell name to a given length ]]-- local function ShortenedSpellName(spellName, length) return string.len(spellName) > length and string.gsub(spellName, '%s?(.)%S+%s', '%1. ') or spellName end --[[ Rounds a number to a given number of decimal places. ]]-- local function Round(number, decimalPlaces) if decimalPlaces and decimalPlaces > 0 then local mult = 10^decimalPlaces return math.floor(number * mult + .5) / mult end return math.floor(num + .5) end --[[ Formats time in seconds to either h:m m:s s ]]-- local function FormatTime(timeInSec) local h = math.floor(timeInSec / 3600) local m = math.floor((timeInSec - (3600 * h)) / 60) local s = math.floor(timeInSec - ((3600 * h) + (60 * m))) if h > 0 then return h .. ":" .. m .. "h" elseif m > 0 then return m .. "m" else return s .. "s" end end --[[ Creates a bar to represent an aura ]]-- local function CreateAuraBar(oUF, anchor) local auraBarParent = oUF.AuraBars -- the main bar local statusBar = CreateFrame("StatusBar", nil, auraBarParent) statusBar:SetHeight(auraBarParent.auraBarHeight or 20) statusBar:SetWidth((auraBarParent.auraBarWidth or auraBarParent:GetWidth()) - (statusBar:GetHeight() + (auraBarParent.gap or 0))) statusBar:SetStatusBarTexture(auraBarParent.auraBarTexture or [[Interface\TargetingFrame\UI-StatusBar]]) --statusBar:SetStatusBarColor(auraBarParent.auraBarColor or 0, .5, 0) statusBar:SetAlpha(auraBarParent.fgalpha or 1) -- the background statusBar.bg = statusBar:CreateTexture(nil, "BORDER") statusBar.bg:SetAllPoints(statusBar) statusBar.bg:SetTexture(auraBarParent.auraBarTexture or [[Interface\TargetingFrame\UI-StatusBar]]) --statusBar.bg:SetVertexColor(unpack(auraBarParent.bgColor or {.5, 1, .5})) --statusBar.bg:SetAlpha(auraBarParent.bgalpha or 1) if auraBarParent.down == true then if auraBarParent == anchor then -- Root frame so indent for icon statusBar:SetPoint('TOPLEFT', anchor, 'BOTTOMLEFT', (statusBar:GetHeight() + (auraBarParent.gap or 0) ), 0) else statusBar:SetPoint('TOPLEFT', anchor, 'BOTTOMLEFT', 0, (-auraBarParent.spacing or 0)) end else if auraBarParent == anchor then -- Root frame so indent for icon statusBar:SetPoint('BOTTOMLEFT', anchor, 'TOPLEFT', (statusBar:GetHeight() + (auraBarParent.gap or 0) ), 0) else statusBar:SetPoint('BOTTOMLEFT', anchor, 'TOPLEFT', 0, (auraBarParent.spacing or 0)) end end statusBar.icon = statusBar:CreateTexture(nil, 'BACKGROUND') statusBar.icon:SetHeight(statusBar:GetHeight()) statusBar.icon:SetWidth(statusBar:GetHeight()) statusBar.icon:SetTexCoord(.07, .93, .07, .93) statusBar.icon:SetPoint'TOP' statusBar.icon:SetPoint('LEFT', auraBarParent) statusBar.spelltime = statusBar:CreateFontString(nil, 'ARTWORK') if auraBarParent.spellTimeObject then statusBar.spelltime:SetFontObject(auraBarParent.spellTimeObject) else statusBar.spelltime:SetFont(auraBarParent.spellTimeFont or [[Fonts\FRIZQT__.TTF]], auraBarParent.spellTimeSize or 10) end statusBar.spelltime:SetTextColor(1 ,1, 1) statusBar.spelltime:SetJustifyH'RIGHT' statusBar.spelltime:SetJustifyV'CENTER' statusBar.spelltime:SetPoint'RIGHT' statusBar.spellname = statusBar:CreateFontString(nil, 'ARTWORK') if auraBarParent.spellNameObject then statusBar.spellname:SetFontObject(auraBarParent.spellNameObject) else statusBar.spellname:SetFont(auraBarParent.spellNameFont or [[Fonts\FRIZQT__.TTF]], auraBarParent.spellNameSize or 10) end statusBar.spellname:SetTextColor(1, 1, 1) statusBar.spellname:SetJustifyH'LEFT' statusBar.spellname:SetJustifyV'CENTER' statusBar.spellname:SetPoint'LEFT' statusBar.spellname:SetPoint('RIGHT', statusBar.spelltime, 'LEFT') if auraBarParent.PostCreateBar then auraBarParent.PostCreateBar(statusBar) end return statusBar end --[[ Update all visable bars, if a bar's aura expires there is no need to remove expired auras, as the Update function will be triggered when the buff drops ]]-- local function UpdateBars(auraBars) local bars = auraBars.bars local timenow = GetTime() for index = 1, #bars do local bar = bars[index] if not bar:IsVisible() then break end if bar.aura.noTime then bar.spelltime:SetText() else local timeleft = bar.aura.expirationTime - timenow bar:SetValue(timeleft) bar.spelltime:SetText(FormatTime(timeleft)) end end end --[[ Default filter ]]-- local function DefaultFilter(name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable) if unitCaster == 'player' then return true end end local sort = function(a, b) local compa, compb = a.noTime and math.huge or a.expirationTime, b.noTime and math.huge or b.expirationTime return compa > compb end --[[ Main update function, gathers the buffs/debuffs base on a filter. Then for each buff/debuff a status bar is shown monitoring it's remaining time. ]]-- local function Update(self, event, unit) if self.unit ~= unit then return end local helpOrHarm = UnitIsFriend('player', unit) and 'HELPFUL' or 'HARMFUL' -- Create a table of auras to display local auras = {} local lastAuraIndex = 0 for index = 1, 40 do local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable = UnitAura(unit, index, helpOrHarm) if not name then break end if (self.AuraBars.filter or DefaultFilter)(name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable) then lastAuraIndex = lastAuraIndex + 1 auras[lastAuraIndex] = {} auras[lastAuraIndex].name = name auras[lastAuraIndex].rank = rank auras[lastAuraIndex].icon = icon auras[lastAuraIndex].count = count auras[lastAuraIndex].debuffType = debuffType auras[lastAuraIndex].duration = duration auras[lastAuraIndex].expirationTime = expirationTime auras[lastAuraIndex].unitCaster = unitCaster auras[lastAuraIndex].isStealable = isStealable auras[lastAuraIndex].noTime = (duration == 0 and expirationTime == 0) end end if self.AuraBars.sort then table.sort(auras, type(self.AuraBars.sort) == 'function' and self.AuraBars.sort or sort) end -- Show and configure bars for buffs/debuffs. local bars = self.AuraBars.bars for index = 1 , lastAuraIndex do local aura = auras[index] local bar = bars[index] if not bar then bar = CreateAuraBar(self, index == 1 and self.AuraBars or bars[index - 1]) bars[index] = bar end -- Backup the details of the aura onto the bar, so the OnUpdate function can use it bar.aura = aura -- Configure if bar.aura.noTime then bar:SetMinMaxValues(0, 1) bar:SetValue(1) else if self.AuraBars.scaleTime then local maxvalue = math.min(self.AuraBars.scaleTime, bar.aura.duration) bar:SetMinMaxValues(0, maxvalue) bar:SetWidth( ( maxvalue / self.AuraBars.scaleTime ) * ( ( self.AuraBars.auraBarWidth or self.AuraBars:GetWidth() ) - ( bar:GetHeight() + (self.AuraBars.gap or 0) ) ) ) -- icon size + gap else bar:SetMinMaxValues(0, bar.aura.duration) end bar:SetValue(bar.aura.expirationTime - GetTime()) end bar.icon:SetTexture(bar.aura.icon) bar.spellname:SetText(bar.aura.count > 1 and string.format("%s [%d]", ShortenedSpellName(bar.aura.name, 20), bar.aura.count) or ShortenedSpellName(bar.aura.name, 20)) bar.spelltime:SetText(not bar.noTime and FormatTime(bar.aura.expirationTime-GetTime())) -- Colour bars --[[local r, g, b = .1, .4, .7 -- Colour for buffs (This is Magic Blue) local bgMod = 0.2 if helpOrHarm == 'HARMFUL' then local debuffType = bar.aura.debuffType and bar.aura.debuffType or 'none' r, g, b = DebuffTypeColor[debuffType].r, DebuffTypeColor[debuffType].g, DebuffTypeColor[debuffType].b end bar:SetStatusBarColor(r, g, b) bar.bg:SetVertexColor(r * bgMod, g * bgMod, b * bgMod)--]] bar:Show() end -- Hide unused bars. for index = lastAuraIndex + 1, #bars do bars[index]:Hide() end end --[[ Enable function for oUF ]]-- local function Enable(self) if self.AuraBars then self:RegisterEvent('UNIT_AURA', Update) self.AuraBars.bars = self.AuraBars.bars or {} self.AuraBars:SetScript('OnUpdate', UpdateBars) return true -- Ensure we get an update when the parent frame is displayed end end --[[ Disable function for oUF ]]-- local function Disable(self) local auraFrame = self.AuraBars if auraFrame then self:UnregisterEvent('UNIT_AURA', Update) auraFrame:SetScript'OnUpdate' end end oUF:AddElement('AuraBars', Update, Enable, Disable)