/trunk
local ADDON_NAME, ns = ... |
local oUF = ns.oUF or oUF |
local grid = CreateFrame("frame", nil, UIParent) |
local defaults = { |
[1] = {hidetooltips = { |
type = "checkbox", |
value = true, |
label = "Hide Tooltips", |
tooltip = "Hide tooltips when mousing over each unit", |
callback = function() grid:enable() end |
}}, |
[2] = {num_groups = { |
type = "slider", |
value = 4, |
min = 1, |
max = 8, |
step = 1, |
label = "Number of Groups", |
tooltip = "How many groups should be shown at a time", |
callback = function() grid:enable() end |
}}, |
[3] = {width = { |
type = "slider", |
value = 60, |
min = 20, |
max = 100, |
step = 2, |
label = "Width", |
tooltip = "The width of each player in the raid frames", |
callback = function() grid:callback() end |
}}, |
[4] = {height = { |
type = "slider", |
value = 50, |
min = 20, |
max = 100, |
step = 2, |
label = "Height", |
tooltip = "The height of each player in the raid frames", |
callback = function() grid:callback() end |
}}, |
[5] = {growth = { |
type = "dropdown", |
value = "LEFT", |
options = {"LEFT","RIGHT"}, |
label = "Growth Direction", |
tooltip = "The direction that new groups should be shown.", |
callback = function() grid:enable() end |
}}, |
[6] = {invert = { |
type = "checkbox", |
value = false, |
label = "Invert Frame Colors", |
tooltip = "Make the main color of the frames a dark grey, and the backgrounds the class color.", |
callback = function() grid:enable() end |
}}, |
[7] = {roleicon = { |
type = "checkbox", |
value = false, |
label = "Show role icon for tanks and healers", |
tooltip = "Will only show icon for tanks/healers", |
callback = function() grid:callback() end |
}}, |
} |
bdCore:addModule("Grid", defaults) |
local config = bdCore.config["Grid"] |
local raidpartyholder = CreateFrame('frame', "bdGrid", UIParent) |
raidpartyholder:RegisterEvent("GROUP_ROSTER_UPDATE") |
raidpartyholder:RegisterEvent("PLAYER_ENTERING_WORLD") |
raidpartyholder:RegisterEvent("PLAYER_REGEN_ENABLED") |
raidpartyholder:SetSize(config['width'], config['height']*5+8) |
raidpartyholder:EnableMouse() |
raidpartyholder:SetPoint("CENTER", UIParent, "CENTER", -200,40) |
raidpartyholder:SetScript("OnEvent", function(self, event, arg1) |
grid:containerSize() |
end) |
bdCore:makeMovable(raidpartyholder) |
-- make sizes outside of combat |
function grid:frameSize(frame) |
frame:SetSize(config['width'], config['height']) |
frame.Health:SetSize(config['width'], config['height']) |
frame.Debuffs:SetSize(44, 22) |
frame.RaidIcon:SetSize(12, 12) |
frame.Short:SetWidth(config['width']) |
frame.ReadyCheck:SetSize(12, 12) |
frame.ResurrectIcon:SetSize(16, 16) |
frame.Threat:SetSize(60, 50) |
frame.Buffs:SetSize(64, 16) |
frame.Debuffs:SetSize(44, 22) |
frame.Dispel:SetSize(60, 50) |
frame.Buffs:SetPoint("TOPLEFT", frame.Health, "TOPLEFT") |
frame.Debuffs:SetPoint("CENTER", frame.Health, "CENTER") |
if (config.roleicon) then |
frame.LFDRole:Show() |
else |
frame.LFDRole:Hide() |
end |
end |
function grid:containerSize() |
local num = GetNumGroupMembers() |
local size = math.floor(num/5); |
if (size == 0) then |
size = 1 |
end |
if (size > config['num_groups']) then |
size = config['num_groups'] |
end |
if (not UnitAffectingCombat('player')) then |
raidpartyholder:SetWidth(config['width']*size+(2*size)-2) |
end |
end |
-- Load |
function grid.layout(self, unit) |
self:RegisterForClicks('AnyDown') |
self.unit = unit |
-- Health |
self.Health = CreateFrame("StatusBar", nil, self) |
self.Health:SetStatusBarTexture(bdCore.media.flat) |
self.Health:SetAllPoints(self) |
self.Health.frequentUpdates = true |
self.Health.colorTapping = true |
self.Health.colorDisconnected = true |
self.Health.colorClass = true |
self.Health.colorReaction = true |
self.Health.colorHealth = true |
bdCore:setBackdrop(self.Health) |
self.Health.PostUpdate = function(s, unit, min, max) |
local r, g, b = self.Health:GetStatusBarColor() |
if (config.invert) then |
self.Health:SetStatusBarColor(unpack(bdCore.media.backdrop)) |
self.Health.background:SetBackdropColor(r/2, g/2, b/2) |
self.Short:SetTextColor(r*1.1, g*1.1, b*1.1) |
self.TotalAbsorb:SetStatusBarColor(1,1,1,.07) |
else |
self.Health:SetStatusBarColor(r/2, g/2, b/2) |
self.Health.background:SetBackdropColor(unpack(bdCore.media.backdrop)) |
self.Short:SetTextColor(1,1,1) |
self.TotalAbsorb:SetStatusBarColor(.1,.1,.1,.5) |
end |
end |
-- raid icon |
self.RaidIcon = self.Health:CreateTexture(nil, "OVERLAY", nil, 1) |
self.RaidIcon:SetPoint("TOP", self, "TOP", 0, -2) |
-- absorb |
self.TotalAbsorb = CreateFrame('StatusBar', nil, self.Health) |
--self.TotalAbsorb:SetFrameLevel(20) |
self.TotalAbsorb:SetPoint("TOPLEFT", self.Health, "TOPLEFT", 0, 0) |
self.TotalAbsorb:SetPoint("BOTTOMRIGHT", self.Health, "BOTTOMRIGHT", 0, 0) |
self.TotalAbsorb:SetStatusBarTexture(bdCore.media.flat) |
self.TotalAbsorb:SetStatusBarColor(.1,.1,.1,.5) |
-- Tags |
-- Status (offline/dead) |
self.Status = self.Health:CreateFontString(nil) |
self.Status:SetFont(bdCore.media.font, 12, "OUTLINE") |
self.Status:SetPoint('BOTTOMLEFT', self, "BOTTOMLEFT", 0, 0) |
oUF.Tags.Events["status"] = "UNIT_HEALTH UNIT_CONNECTION" |
oUF.Tags.Methods["status"] = function(unit) |
if not UnitIsConnected(unit) then |
return "offline" |
elseif UnitIsDead(unit) then |
return "dead" |
elseif UnitIsGhost(unit) then |
return "ghost" |
end |
end |
-- shortname |
self.Short = self.Health:CreateFontString(nil,"OVERLAY") |
self.Short:SetFont(bdCore.media.font, 13, "OUTLINE") |
self.Short:SetShadowOffset(0,0) |
self.Short:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 0, 1) |
self.Short:SetJustifyH("RIGHT") |
oUF.Tags.Events["self.Short"] = "UNIT_NAME_UPDATE" |
oUF.Tags.Methods["self.Short"] = function(unit) |
local name = UnitName(unit) |
--local class, classFileName = UnitClass(unit) |
return string.sub(name,1,4) |
end |
self:Tag(self.Short, '[self.Short]') |
self:Tag(self.Status, '[status]') |
-- Range |
self:SetScript("OnEnter", function() |
self.arrowmouseover = true |
if (not self.OoR) then |
ns:arrow(self, self.unit) |
end |
if (not config.hidetooltips) then |
UnitFrame_OnEnter(self) |
--else |
-- UnitFrame_OnLeave(self) |
end |
end) |
self:SetScript("OnLeave", function() |
self.freebarrow:Hide() |
self.arrowmouseover = false |
UnitFrame_OnLeave(self) |
end) |
-- Raid Icon |
self.RaidIcon = self.Health:CreateTexture(nil, "OVERLAY", nil, 1) |
self.RaidIcon:SetSize(12, 12) |
self.RaidIcon:SetPoint("TOP", self, "TOP", 0, -2) |
-- roll icon |
self.LFDRole = self.Health:CreateTexture(nil, "OVERLAY") |
self.LFDRole:SetSize(12, 12) |
self.LFDRole:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT",2,2) |
self.LFDRole.PostUpdate = function(self, role) |
if (role ~= "DAMAGER" and config.roleicon) then |
self:Show() |
else |
self:Hide() |
end |
end |
-- range/pointer arrow |
local range = { |
insideAlpha = 1, |
outsideAlpha = .4, |
} |
self.freebRange = range |
self.Range = false |
-- Readycheck |
self.ReadyCheck = self.Health:CreateTexture(nil, 'OVERLAY', nil, 7) |
self.ReadyCheck:SetPoint('BOTTOM', self, 'BOTTOM', 0, 2) |
-- ResurrectIcon |
self.ResurrectIcon = self.Health:CreateTexture(nil, 'OVERLAY') |
self.ResurrectIcon:SetPoint('CENTER', self, "CENTER", 0,0) |
-- Threat |
self.Threat = CreateFrame('frame', nil, self) |
self.Threat:SetFrameLevel(95) |
self.Threat:SetPoint('TOPRIGHT', self, "TOPRIGHT", 1, 1) |
self.Threat:SetPoint('BOTTOMLEFT', self, "BOTTOMLEFT", -1, -1) |
self.Threat:SetBackdrop({bgFile = bdCore.media.flat, edgeFile = bdCore.media.flat, edgeSize = 1}) |
self.Threat:SetBackdropBorderColor(1, 0, 0,1) |
self.Threat:SetBackdropColor(0,0,0,0) |
self.Threat.SetVertexColor = function() return end |
-- Buffs |
self.Buffs = CreateFrame("Frame", nil, self.Health) |
self.Buffs:SetPoint("TOPLEFT", self.Health, "TOPLEFT") |
self.Buffs:SetFrameLevel(21) |
self.Buffs:EnableMouse(false) |
self.Buffs.initialAnchor = "TOPLEFT" |
self.Buffs.size = 14 |
self.Buffs.spacing = 1 |
self.Buffs.num = 4 |
self.Buffs.onlyShowPlayer = true |
self.Buffs['growth-y'] = "DOWN" |
self.Buffs['growth-x'] = "RIGHT" |
self.Buffs.CustomFilter = function(unit, icon, button, name, rank, texture, count, dtype, duration, timeLeft, caster, isStealable, shouldConsolidate, spellID) |
return bdCore:filterAura(name,caster) |
end |
self.Buffs.PostUpdateIcon = function(buffs, unit, button) |
button:SetAlpha(0.8) |
button:EnableMouse(false) |
button.cd:GetRegions():SetAlpha(0) |
button.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92) |
end |
-- Dispells |
self.Dispel = CreateFrame('frame', nil, self.Health) |
self.Dispel:SetFrameLevel(100) |
self.Dispel:SetPoint('TOPRIGHT', self, "TOPRIGHT", 1, 1) |
self.Dispel:SetPoint('BOTTOMLEFT', self, "BOTTOMLEFT", -1, -1) |
self.Dispel:SetBackdrop({bgFile = bdCore.media.flat, edgeFile = bdCore.media.flat, edgeSize = 2}) |
self.Dispel:SetBackdropBorderColor(1, 0, 0,1) |
self.Dispel:SetBackdropColor(0,0,0,0) |
self.Dispel:Hide() |
local dispelClass = { |
["PRIEST"] = { ["Disease"] = true, ["Magic"] = true, }, --Purify |
["SHAMAN"] = { ["Curse"] = true, ["Magic"] = true, }, --Purify Spirit |
["PALADIN"] = { ["Poison"] = true, ["Disease"] = true, ["Magic"] = true, }, --Cleanse |
["MAGE"] = { ["Curse"] = true, }, --Remove Curse |
["DRUID"] = { ["Curse"] = true, ["Poison"] = true, ["Magic"] = true, }, --Nature's Cure |
["MONK"] = { ["Poison"] = true, ["Disease"] = true, ["Magic"] = true, }, --Detox |
} |
local dispelColors = { |
['Magic'] = {.16, .5, .81, 1}, |
['Poison'] = {.12, .76, .36, 1}, |
['Disease'] = {.76, .46, .12, 1}, |
['Curse'] = {.80, .33, .95, 1}, |
} |
local _, class = UnitClass("player") |
local dispellist = dispelClass[class] or {} |
self.Dispel:RegisterEvent("UNIT_AURA") |
self.Dispel:SetScript("OnEvent", function(s, event, unitid) |
if unitid ~= self.unit then return end |
local dispel = nil |
local dispelName = nil |
for i = 1, 20 do |
if (not dispel) then |
dispel = select(5, UnitDebuff(unitid, i)); |
dispelName = select(1, UnitDebuff(unitid, i)); |
end |
end |
--if (dispel and (dispelClass[class][dispel] or debuffwhitelist[dispelName])) then |
if (dispel) then |
self.Dispel:Show() |
self.Dispel:SetBackdropBorderColor(unpack(dispelColors[dispel])) |
if (not dispelColors[dispel]) then |
self.Dispel:Hide() |
end |
else |
self.Dispel:Hide() |
end |
end) |
-- Debuffs |
self.Debuffs = CreateFrame("Frame", nil, self.Health) |
self.Debuffs:SetFrameLevel(21) |
self.Debuffs:SetPoint("CENTER", self.Health, "CENTER") |
self.Debuffs.initialAnchor = "CENTER" |
self.Debuffs.size = 22 |
self.Debuffs.spacing = 1 |
self.Debuffs.num = 2 |
self.Debuffs.onlyShowPlayer = true |
self.Debuffs['growth-y'] = "DOWN" |
self.Debuffs['growth-x'] = "RIGHT" |
self.Debuffs.CustomFilter = function(unit, icon, blank, name, rank, texture, count, dtype, duration, timeLeft, caster, isStealable, shouldConsolidate, spellID) |
return bdCore:filterAura(name,caster) |
end |
self.Debuffs.PostUpdateIcon = function(buffs, unit, button) |
button:SetAlpha(0.8) |
button:EnableMouse(false) |
button.cd:GetRegions():SetAlpha(0) |
button.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92) |
button:SetBackdrop({bgFile = bdCore.media.flat, edgeFile = bdCore.media.flat, edgeSize = 2}) |
button:SetBackdropColor(.11,.15,.18, 1) |
button:SetBackdropBorderColor(.06, .08, .09, 1) |
end |
grid.frames[self] = self; |
if (not UnitAffectingCombat('player')) then |
grid:frameSize(self) |
end |
end |
-- Enable |
function grid:enable() |
for k, frame in pairs(grid.frames) do |
bdCore:Kill(frame) |
end |
grid.frames = {} |
oUF:Factory(function(self) |
self:SetActiveStyle("bdGrid") |
local party = self:SpawnHeader(nil, nil, 'raid,party,solo', |
'showParty', true, |
'showPlayer', true, |
'yOffset', -2, |
"xOffset", 2, |
"showParty", true, |
"showPlayer", true, |
"showSolo", true, |
"showRaid", true, |
"groupFilter", "1,2,3,4,5,6,7,8", |
"groupBy", "GROUP", |
"groupingOrder", "1,2,3,4,5,6,7,8", |
"maxColumns", config['num_groups'], |
"unitsPerColumn", 5, |
"columnSpacing", 2, |
"columnAnchorPoint", config.growth, |
"point", "TOP" |
) |
party:SetPoint("TOPRIGHT", raidpartyholder, "TOPRIGHT", 0, 0) |
if (config.growth == "RIGHT") then |
party:SetPoint("TOPLEFT", raidpartyholder, "TOPLEFT", 0, 0) |
end |
end) |
grid:callback() |
end |
grid.frames = {} |
function grid:callback() |
if (not UnitAffectingCombat("player")) then |
for k, frame in pairs(grid.frames) do |
grid:frameSize(frame) |
end |
end |
grid:containerSize() |
end |
grid:RegisterEvent("PLAYER_REGEN_ENABLED") |
grid:RegisterEvent("PLAYER_ENTERING_WORLD") |
grid:SetScript("OnEvent", function(self, event, arg1) |
grid:callback() |
end) |
oUF:RegisterStyle("bdGrid", grid.layout) |
grid:enable() |
-- bdCore:hookEvent("loaded_bdcore", function() |
-- print('loaded bdcore inside of bdgrid') |
-- end) |
-- Disable |
## Interface: 60200 |
## Title: |cffA02C2Fbd|rGrid |
## Version: 0 |
## DefaultState: Enabled |
## LoadOnDemand: 0 |
## X-oUF: oUFbdGrid |
## Dependencies: bdCore |
defaults.lua |
lib\oUF\oUF.xml |
lib\absorbs.lua |
lib\range.lua |
##lib\cluster.lua |
core.lua |
local bUI, F, C = select(2, ...):unpack() |
local media = bUI.media |
local parent, ns = ... |
local oUF = ns.oUF or oUF |
local update = 0.1 |
local healrange = 10 |
local units = {} |
local timer = 0 |
function round(num, idp) |
if idp and idp>0 then |
local mult = 10^idp |
return math.floor(num * mult + 0.5) / mult |
end |
return math.floor(num + 0.5) |
end |
local validUnit = function(unit) |
return UnitExists(unit) and not UnitIsDeadOrGhost(unit) and UnitIsConnected(unit) and not (UnitIsCharmed(unit) and not UnitIsEnemy("player", unit)) |
end |
local function getDistance(x1, y1, x2, y2) |
local xx = (x2 - x1) |
local yy = (y2 - y1) |
return (xx*xx + yy*yy)^0.5 |
end |
local clearDataid = function(id, id2) |
if units[id][id2] then |
units[id][id2] = nil |
units[id].numInRange = units[id].numInRange-1 |
end |
if units[id2][id] then |
units[id2][id] = nil |
units[id2].numInRange = units[id2].numInRange-1 |
end |
end |
local updatePos = function(self, elapsed) |
timer = timer + elapsed |
if(timer >= update) then |
for id, _ in next, units do |
local x, y = GetPlayerMapPosition(id) |
x = x*550 |
y = y*550 |
-- no idea why 550 is the magic number |
units[id].pos = ""..x.."\\"..y.."" |
end |
for id, _ in next, units do |
local pos = units[id].pos |
for id2, _ in next, units do |
if validUnit(id2) and (id ~= id2) then |
local pos2 = units[id2].pos |
local x1, y1 = strsplit("\\", pos) |
local x2, y2 = strsplit("\\", pos2) |
local xxyy = x1 + x2 + y1 + y2 |
local dist = getDistance(x1, y1, x2, y2) |
if dist < healrange and xxyy > 0 then |
if not units[id][id2] then |
units[id][id2] = true |
units[id].numInRange = units[id].numInRange+1 |
end |
if not units[id2][id] then |
units[id2][id] = true |
units[id2].numInRange = units[id2].numInRange+1 |
end |
else |
clearDataid(id, id2) |
end |
else |
clearDataid(id, id2) |
end |
end |
end |
timer = 0 |
end |
end |
oUF.Tags.Methods['freebgrid:cluster'] = function(u) |
if units[u] then |
local num = units[u].numInRange |
--print(u..": "..num) |
if num > 2 then |
if num > 6 then |
num = "6" |
end |
return num |
end |
end |
end |
local fillroster = function(unit) |
if (validUnit(unit)) then |
units[unit] = {} |
units[unit].pos = "" |
units[unit].numInRange = 1 |
else |
units[unit] = nil |
end |
--["pos"] = "", ["numInRange"] = 1 |
end |
local updateRoster = function() |
units = {} |
local numRaid = GetNumGroupMembers() |
if numRaid > 1 then |
for i=1, numRaid do |
local name = GetRaidRosterInfo(i) |
if name then |
local unit = "raid"..i |
fillroster(unit) |
end |
end |
else |
fillroster("player") |
local numParty = GetNumSubgroupMembers() |
for i=1, numParty do |
local unit = "party"..i |
fillroster(unit) |
end |
end |
end |
local frame = CreateFrame"Frame" |
frame:SetScript("OnEvent", function(self, event) |
updateRoster() |
end) |
local Enable = function(self) |
if self.clusterEnabled then |
self.freebCluster = self.Health:CreateFontString(nil, "OVERLAY") |
self.freebCluster:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", 0, 0) |
self.freebCluster:SetJustifyH("LEFT") |
self.freebCluster:SetFont(media.font, 12, "OUTLINE") |
self.freebCluster:SetTextColor(1,1,1) |
self.freebCluster:SetWidth(20) |
self.freebCluster.frequentUpdates = update |
self:Tag(self.freebCluster, "[freebgrid:cluster]") |
self.freebCluster:Show() |
self:HookScript("OnUpdate", function(self, elapsed) |
local text = tonumber(self.freebCluster:GetText()); |
if (text) then |
if (text < 4) then |
self.freebCluster:SetTextColor(.6,.6,.6) |
elseif (text == 5) then |
self.freebCluster:SetTextColor(.9,1,.9) |
elseif (text > 5) then |
self.freebCluster:SetTextColor(.6,1,.7) |
end |
end |
end) |
frame:RegisterEvent("GROUP_ROSTER_UPDATE") |
frame:RegisterEvent("PLAYER_ENTERING_WORLD") |
frame:RegisterEvent("ZONE_CHANGED_NEW_AREA") |
frame:SetScript("OnUpdate", updatePos) |
updateRoster() |
return true |
end |
end |
local Disable = function(self) |
if self.freebCluster then |
self.freebCluster.frequentUpdates = false |
self.freebCluster:Hide() |
end |
frame:UnregisterEvent("GROUP_ROSTER_UPDATE") |
frame:UnregisterEvent("PLAYER_ENTERING_WORLD") |
frame:UnregisterEvent("ZONE_CHANGED_NEW_AREA") |
frame:SetScript("OnUpdate", nil) |
units = {} |
end |
oUF:AddElement('freebCluster', nil, Enable, Disable) |
#!/usr/bin/env lua |
local tags = {} |
do |
for tag in io.popen('git tag'):lines() do |
local split = tag:gmatch('[^.]+') |
local release, api, bugfix = split(), split(), split() or 0 |
table.insert( |
tags, |
{ |
string = tag, |
release = release, |
api = api, |
bugfix = bugfix, |
} |
) |
end |
table.sort(tags, function(a,b) |
a = a.release * 1e4 + a.api * 100 + a.bugfix |
b = b.release * 1e4 + b.api * 100 + b.bugfix |
return a > b |
end) |
end |
local generateLog = function(prevTag, currentTag) |
local ti = table.insert |
local sf = string.format |
local out = {} |
ti(out, sf('[b]Changes in %s:[/b]', currentTag)) |
ti(out, '[list]') |
for line in io.popen(sf('git shortlog %s..%s', prevTag, currentTag)):lines() do |
if(line:sub(1, 6) == ' ') then |
local offset = line:match('() ', 7) |
if(offset) then |
line = line:sub(7, offset - 1) |
else |
line = line:sub(7) |
end |
ti(out, sf(' [*] %s', line)) |
elseif(#line == 0) then |
ti(out, ' [/list]') |
else |
ti(out, sf(' [*][i]%s[/i]', line)) |
ti(out, ' [list=1]') |
end |
end |
ti(out, '[/list]') |
local p = assert(io.popen(sf('git diff --shortstat %s..%s', prevTag, currentTag))) |
local stat = p:read'*a' |
p:close() |
ti(out, sf('[indent]%s[/indent]', stat:sub(2, -2))) |
return table.concat(out, '\n') |
end |
local stop |
local to = ... |
if(to) then |
for i=1, #tags do |
if(tags[i].string == to) then |
stop = i + 1 |
end |
end |
if(not stop) then stop = #tags end |
else |
stop = #tags |
end |
for i=2, stop do |
local current, prev = tags[i -1], tags[i] |
print(generateLog(prev.string, current.string)) |
end |
-- vim: set filetype=lua : |
#!/usr/bin/env lua |
-- docs |
-- oUF documentation generator |
-- |
-- This is really just a quick and dirty way of generating documentation for |
-- oUF[1]. The syntax is inspired by TomDoc[2], but a lot of the non-oUF and |
-- non-Lua things aren't implemented. |
-- |
-- Why implement my own documentation generator? |
-- It was mainly done because oUF is kind-of special, but also because the |
-- available alternatives aren't good enough or have issues I can't workaround. |
-- |
-- Things that need fixing: |
-- - No highlighting of Lua code. |
-- - Doesn't validate that comments are documentation strings. |
-- - Doesn't parse its own documentation header. |
-- - Close to zero error handling. |
-- |
-- Usage |
-- |
-- docs [docs path] [file...] |
-- |
-- Links |
-- |
-- [1] https://github.com/haste/oUF |
-- [2] http://tomdoc.org/ |
local out |
local lines |
local tisf = function(fmt, ...) |
table.insert(out, fmt:format(...)) |
end |
local trim = function(str) |
return str:match('^()%s*$') and '' or str:match('^%s*(.*%S)') |
end |
local findNextEmpty = function(start, stop) |
for i=start, stop or #lines do |
if(lines[i] == '') then |
return i |
end |
end |
end |
local findNextHeader = function(offest) |
for i=offest, #lines do |
local pre, header, post = unpack(lines, i, i + 2) |
-- Single lines without punctuation are headers. |
if(pre == '' and post == '' and not header:match'%.') then |
return i + 1 |
end |
end |
end |
local findNextArguent = function(start, stop, padding, pattern) |
for i=start, stop do |
local match, pad = lines[i]:match(pattern) |
if(match and pad == padding) then |
return i |
end |
end |
end |
local replaceMarkup = function(str) |
return str |
-- `in-line code` to <code>in-line code</code> |
:gsub('`([^`]+)`', '<code>%1</code>') |
-- [Link](http://example.com) to <a href="http://example.com">Link</a> |
:gsub('%[([^%]]+)%]%(([^)]+)%)', '<a href="%2">%1</a>') |
end |
local handleArguments = function(start, stop, pattern) |
tisf('<dl>') |
repeat |
-- Tear out the argument name and offset of where the description begins. |
local def, padding, offset = lines[start]:match(pattern) |
tisf('<dt>%s</dt>', def) |
-- Insert the first line of the description. |
tisf('<dd>') |
tisf(lines[start]:sub(offset)) |
-- Find the next argument in the list or continue to the end of the |
-- current section. |
local nextarg = findNextArguent(start + 1, stop, padding, pattern) |
nextarg = (nextarg or stop + 1) - 1 |
for i=start + 1, nextarg do |
tisf(trim(lines[i])) |
end |
tisf('</dd>') |
start = nextarg + 1 |
until start > stop |
tisf('</dl>') |
end |
local handleExamples = function(start, stop) |
-- An extra line gets added if we don't do this. |
tisf('<pre><code>%s', lines[start]:sub(3)) |
for i=start + 1, stop do |
tisf(lines[i]:sub(3)) |
end |
tisf('</code></pre>') |
end |
local handleParagraph = function(start, stop) |
tisf('<p>') |
for i=start, stop do |
tisf(trim(lines[i])) |
end |
tisf('</p>') |
end |
local handleSection = function(start, stop) |
while(start) do |
-- Find the next empty line or continue until the end of the section. |
-- findNextEmpty() returns the position of the empty line, so we need to |
-- subtract one from it. |
local nextEmpty = findNextEmpty(start + 1, stop) |
if(nextEmpty) then |
nextEmpty = nextEmpty - 1 |
else |
nextEmpty = stop |
end |
local line = lines[start] |
if(not line) then |
return |
elseif(line:match('^%S+%s*%- ')) then |
handleArguments(start, nextEmpty, '(%S+)%s*()%- ()') |
elseif(line:sub(1, 2) == ' ') then |
handleExamples(start, nextEmpty) |
else |
handleParagraph(start, nextEmpty) |
end |
start = findNextEmpty(nextEmpty, stop) |
if(start) then start = start + 1 end |
end |
end |
local generateDocs = function(str, level) |
lines = {} |
out = {} |
for line in str:gmatch('([^\n]*)\n') do |
table.insert(lines, line:gsub('\t*', ''):sub(2)) |
end |
-- The first line is always the main header. |
tisf('<h%d>%s</h%d>', level, lines[1], level) |
-- Then comes the main description. |
local offset = findNextHeader(1) |
-- Continue until two lines before the header or to the end of the comment. |
if(offset) then |
offset = offset - 2 |
else |
offset = #lines |
end |
local init = findNextEmpty(1) + 1 |
if(init > offset) then |
init = 2 |
end |
handleSection(init, offset) |
while(true) do |
offset = findNextHeader(offset) |
if(not offset) then break end |
-- Every section has a header. |
tisf('<h%d>%s</h%d>', level + 1, lines[offset], level + 1) |
-- Find out the size of the section. |
local start = findNextEmpty(offset) + 1 |
if(not lines[start]) then |
-- There's no section here, only a headline. |
break |
end |
local stop |
local nextHeader = findNextHeader(start) |
if(nextHeader) then |
stop = nextHeader - 2 |
else |
local nextEmpty = findNextEmpty(start) |
if(nextEmpty) then |
stop = nextEmpty - 1 |
else |
stop = #lines |
end |
end |
handleSection(start, stop) |
offset = stop + 1 |
end |
return table.concat(out, '\n') |
end |
local handleFile = function(path) |
local file = io.open(path, 'r') |
local content = file:read'*a' |
file:close() |
local out = {} |
local init = 1 |
repeat |
local _, comStart, depth = content:find('%-%-%[(=*)%[ ', init) |
if(comStart) then |
local comEnd = content:find('%]' .. depth .. '%]', comStart) |
local comment = content:sub(comStart, comEnd - 1) |
-- Convert markup to html. |
comment = replaceMarkup(comment) |
-- The first comment uses h1 and h2, while the subsequent ones uses h3 |
-- and h4. |
local level = init == 1 and 1 or 3 |
table.insert(out, generateDocs(comment, init == 1 and 1 or 3)) |
init = comEnd |
end |
until not comStart |
return table.concat(out, '\n') |
end |
local destination = (...) |
for i=2, select('#', ...) do |
local file = select(i, ...) |
local path, filename = file:match('(.+)/(.+)$') |
if(path:sub(1,3) == '../') then |
path = path:sub(4) |
end |
if(#path == 0) then path = nil end |
filename = filename:gsub('lua', 'html') |
local doc = handleFile(file) |
if(doc) then |
local dfPath = string.format('%s/%s', destination, path or '') |
os.execute(string.format('mkdir -p %s', dfPath)) |
local docFile = io.open(string.format('%s/%s', dfPath, filename), 'w+') |
docFile:write(doc) |
docFile:close() |
end |
end |
local parent, ns = ... |
local oUF = ns.oUF |
local hiddenParent = CreateFrame("Frame") |
hiddenParent:Hide() |
local HandleFrame = function(baseName) |
local frame |
if(type(baseName) == 'string') then |
frame = _G[baseName] |
else |
frame = baseName |
end |
if(frame) then |
frame:UnregisterAllEvents() |
frame:Hide() |
-- Keep frame hidden without causing taint |
frame:SetParent(hiddenParent) |
local health = frame.healthbar |
if(health) then |
health:UnregisterAllEvents() |
end |
local power = frame.manabar |
if(power) then |
power:UnregisterAllEvents() |
end |
local spell = frame.spellbar |
if(spell) then |
spell:UnregisterAllEvents() |
end |
local altpowerbar = frame.powerBarAlt |
if(altpowerbar) then |
altpowerbar:UnregisterAllEvents() |
end |
end |
end |
function oUF:DisableBlizzard(unit) |
if(not unit) then return end |
if(unit == 'player') then |
HandleFrame(PlayerFrame) |
-- For the damn vehicle support: |
PlayerFrame:RegisterEvent('PLAYER_ENTERING_WORLD') |
PlayerFrame:RegisterEvent('UNIT_ENTERING_VEHICLE') |
PlayerFrame:RegisterEvent('UNIT_ENTERED_VEHICLE') |
PlayerFrame:RegisterEvent('UNIT_EXITING_VEHICLE') |
PlayerFrame:RegisterEvent('UNIT_EXITED_VEHICLE') |
-- User placed frames don't animate |
PlayerFrame:SetUserPlaced(true) |
PlayerFrame:SetDontSavePosition(true) |
elseif(unit == 'pet') then |
HandleFrame(PetFrame) |
elseif(unit == 'target') then |
HandleFrame(TargetFrame) |
HandleFrame(ComboFrame) |
elseif(unit == 'focus') then |
HandleFrame(FocusFrame) |
HandleFrame(TargetofFocusFrame) |
elseif(unit == 'targettarget') then |
HandleFrame(TargetFrameToT) |
elseif(unit:match'(boss)%d?$' == 'boss') then |
local id = unit:match'boss(%d)' |
if(id) then |
HandleFrame('Boss' .. id .. 'TargetFrame') |
else |
for i=1, 4 do |
HandleFrame(('Boss%dTargetFrame'):format(i)) |
end |
end |
elseif(unit:match'(party)%d?$' == 'party') then |
local id = unit:match'party(%d)' |
if(id) then |
HandleFrame('PartyMemberFrame' .. id) |
else |
for i=1, 4 do |
HandleFrame(('PartyMemberFrame%d'):format(i)) |
end |
end |
elseif(unit:match'(arena)%d?$' == 'arena') then |
local id = unit:match'arena(%d)' |
if(id) then |
HandleFrame('ArenaEnemyFrame' .. id) |
else |
for i=1, 4 do |
HandleFrame(('ArenaEnemyFrame%d'):format(i)) |
end |
end |
-- Blizzard_ArenaUI should not be loaded |
Arena_LoadUI = function() end |
SetCVar('showArenaEnemyFrames', '0', 'SHOW_ARENA_ENEMY_FRAMES_TEXT') |
end |
end |
local parent, ns = ... |
local oUF = ns.oUF |
local Private = oUF.Private |
local frame_metatable = Private.frame_metatable |
local colors = { |
smooth = { |
1, 0, 0, |
1, 1, 0, |
0, 1, 0 |
}, |
disconnected = {.6, .6, .6}, |
tapped = {.6,.6,.6}, |
class = {}, |
reaction = {}, |
} |
-- We do this because people edit the vars directly, and changing the default |
-- globals makes SPICE FLOW! |
local customClassColors = function() |
if(CUSTOM_CLASS_COLORS) then |
local updateColors = function() |
for eclass, color in next, CUSTOM_CLASS_COLORS do |
colors.class[eclass] = {color.r, color.g, color.b} |
end |
for _, obj in next, oUF.objects do |
obj:UpdateAllElements("CUSTOM_CLASS_COLORS") |
end |
end |
updateColors() |
CUSTOM_CLASS_COLORS:RegisterCallback(updateColors) |
return true |
end |
end |
if not customClassColors() then |
for eclass, color in next, RAID_CLASS_COLORS do |
colors.class[eclass] = {color.r, color.g, color.b} |
end |
local f = CreateFrame("Frame") |
f:RegisterEvent("ADDON_LOADED") |
f:SetScript("OnEvent", function() |
if customClassColors() then |
f:UnregisterEvent("ADDON_LOADED") |
f:SetScript("OnEvent", nil) |
end |
end) |
end |
for eclass, color in next, FACTION_BAR_COLORS do |
colors.reaction[eclass] = {color.r, color.g, color.b} |
end |
local function ColorsAndPercent(a, b, ...) |
if a <= 0 or b == 0 then |
return nil, ... |
elseif a >= b then |
return nil, select(select('#', ...) - 2, ...) |
end |
local num = select('#', ...) / 3 |
local segment, relperc = math.modf((a/b)*(num-1)) |
return relperc, select((segment*3)+1, ...) |
end |
-- http://www.wowwiki.com/ColorGradient |
local RGBColorGradient = function(...) |
local relperc, r1, g1, b1, r2, g2, b2 = ColorsAndPercent(...) |
if relperc then |
return r1 + (r2-r1)*relperc, g1 + (g2-g1)*relperc, b1 + (b2-b1)*relperc |
else |
return r1, g1, b1 |
end |
end |
-- HCY functions are based on http://www.chilliant.com/rgb2hsv.html |
local function GetY(r, g, b) |
return 0.299 * r + 0.587 * g + 0.114 * b |
end |
local function RGBToHCY(r, g, b) |
local min, max = min(r, g, b), max(r, g, b) |
local chroma = max - min |
local hue |
if chroma > 0 then |
if r == max then |
hue = ((g - b) / chroma) % 6 |
elseif g == max then |
hue = (b - r) / chroma + 2 |
elseif b == max then |
hue = (r - g) / chroma + 4 |
end |
hue = hue / 6 |
end |
return hue, chroma, GetY(r, g, b) |
end |
local abs = math.abs |
local function HCYtoRGB(hue, chroma, luma) |
local r, g, b = 0, 0, 0 |
if hue and luma > 0 then |
local h2 = hue * 6 |
local x = chroma * (1 - abs(h2 % 2 - 1)) |
if h2 < 1 then |
r, g, b = chroma, x, 0 |
elseif h2 < 2 then |
r, g, b = x, chroma, 0 |
elseif h2 < 3 then |
r, g, b = 0, chroma, x |
elseif h2 < 4 then |
r, g, b = 0, x, chroma |
elseif h2 < 5 then |
r, g, b = x, 0, chroma |
else |
r, g, b = chroma, 0, x |
end |
local y = GetY(r, g, b) |
if luma < y then |
chroma = chroma * (luma / y) |
elseif y < 1 then |
chroma = chroma * (1 - luma) / (1 - y) |
end |
r = (r - y) * chroma + luma |
g = (g - y) * chroma + luma |
b = (b - y) * chroma + luma |
end |
return r, g, b |
end |
local HCYColorGradient = function(...) |
local relperc, r1, g1, b1, r2, g2, b2 = ColorsAndPercent(...) |
if not relperc then return r1, g1, b1 end |
local h1, c1, y1 = RGBToHCY(r1, g1, b1) |
local h2, c2, y2 = RGBToHCY(r2, g2, b2) |
local c = c1 + (c2-c1) * relperc |
local y = y1 + (y2-y1) * relperc |
if h1 and h2 then |
local dh = h2 - h1 |
if dh < -0.5 then |
dh = dh + 1 |
elseif dh > 0.5 then |
dh = dh - 1 |
end |
return HCYtoRGB((h1 + dh * relperc) % 1, c, y) |
else |
return HCYtoRGB(h1 or h2, c, y) |
end |
end |
local ColorGradient = function(...) |
return (oUF.useHCYColorGradient and HCYColorGradient or RGBColorGradient)(...) |
end |
Private.colors = colors |
oUF.colors = colors |
oUF.ColorGradient = ColorGradient |
oUF.RGBColorGradient = RGBColorGradient |
oUF.HCYColorGradient = HCYColorGradient |
oUF.useHCYColorGradient = false |
frame_metatable.__index.colors = colors |
frame_metatable.__index.ColorGradient = ColorGradient |
local parent, ns = ... |
-- It's named Private for a reason! |
ns.oUF.Private = nil |
Copyright (c) 2006-2014 Trond A Ekseth <troeks@gmail.com> |
Permission is hereby granted, free of charge, to any person |
obtaining a copy of this software and associated documentation |
files (the "Software"), to deal in the Software without |
restriction, including without limitation the rights to use, |
copy, modify, merge, publish, distribute, sublicense, and/or sell |
copies of the Software, and to permit persons to whom the |
Software is furnished to do so, subject to the following |
conditions: |
The above copyright notice and this permission notice shall be |
included in all copies or substantial portions of the Software. |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
OTHER DEALINGS IN THE SOFTWARE. |
local parent, ns = ... |
local oUF = ns.oUF |
local Private = oUF.Private |
local enableTargetUpdate = Private.enableTargetUpdate |
-- Handles unit specific actions. |
function oUF:HandleUnit(object, unit) |
local unit = object.unit or unit |
if(unit == 'target') then |
object:RegisterEvent('PLAYER_TARGET_CHANGED', object.UpdateAllElements) |
elseif(unit == 'mouseover') then |
object:RegisterEvent('UPDATE_MOUSEOVER_UNIT', object.UpdateAllElements) |
elseif(unit == 'focus') then |
object:RegisterEvent('PLAYER_FOCUS_CHANGED', object.UpdateAllElements) |
elseif(unit:match'(boss)%d?$' == 'boss') then |
object:RegisterEvent('INSTANCE_ENCOUNTER_ENGAGE_UNIT', object.UpdateAllElements, true) |
object:RegisterEvent('UNIT_TARGETABLE_CHANGED', object.UpdateAllElements) |
elseif(unit:match'%w+target') then |
enableTargetUpdate(object) |
end |
end |
local parent, ns = ... |
ns.oUF = {} |
ns.oUF.Private = {} |
local parent, ns = ... |
local oUF = ns.oUF |
local Private = oUF.Private |
local argcheck = Private.argcheck |
local error = Private.error |
local frame_metatable = Private.frame_metatable |
-- Original event methods |
local RegisterEvent = frame_metatable.__index.RegisterEvent |
local RegisterUnitEvent = frame_metatable.__index.RegisterUnitEvent |
local UnregisterEvent = frame_metatable.__index.UnregisterEvent |
local IsEventRegistered = frame_metatable.__index.IsEventRegistered |
local unitEvents = {} |
Private.UpdateUnits = function(frame, unit, realUnit) |
if unit == realUnit then |
realUnit = nil |
end |
if frame.unit ~= unit or frame.realUnit ~= realUnit then |
for event in next, unitEvents do |
-- IsEventRegistered returns the units in case of an event |
-- registered with RegisterUnitEvent |
local registered, unit1 = IsEventRegistered(frame, event) |
if registered and unit1 ~= unit then |
-- RegisterUnitEvent erases previously registered units so |
-- do not bother to unregister it |
RegisterUnitEvent(frame, event, unit, realUnit) |
end |
end |
frame.unit = unit |
frame.realUnit = realUnit |
frame.id = unit:match'^.-(%d+)' |
return true |
end |
end |
local OnEvent = function(self, event, ...) |
if self:IsVisible() then |
return self[event](self, event, ...) |
end |
end |
local event_metatable = { |
__call = function(funcs, self, ...) |
for _, func in next, funcs do |
func(self, ...) |
end |
end, |
} |
function frame_metatable.__index:RegisterEvent(event, func, unitless) |
-- Block OnUpdate polled frames from registering events. |
if(self.__eventless) then return end |
argcheck(event, 2, 'string') |
if(type(func) == 'string' and type(self[func]) == 'function') then |
func = self[func] |
end |
-- TODO: should warn the user. |
if not unitless and not (unitEvents[event] or event:match'^UNIT_') then |
unitless = true |
end |
local curev = self[event] |
local kind = type(curev) |
if(curev and func) then |
if(kind == 'function' and curev ~= func) then |
self[event] = setmetatable({curev, func}, event_metatable) |
elseif(kind == 'table') then |
for _, infunc in next, curev do |
if(infunc == func) then return end |
end |
table.insert(curev, func) |
end |
elseif(IsEventRegistered(self, event)) then |
return |
else |
if(type(func) == 'function') then |
self[event] = func |
elseif(not self[event]) then |
return error("Style [%s] attempted to register event [%s] on unit [%s] with a handler that doesn't exist.", self.style, event, self.unit or 'unknown') |
end |
if not self:GetScript('OnEvent') then |
self:SetScript('OnEvent', OnEvent) |
end |
if unitless then |
RegisterEvent(self, event) |
else |
unitEvents[event] = true |
RegisterUnitEvent(self, event, self.unit) |
end |
end |
end |
function frame_metatable.__index:UnregisterEvent(event, func) |
argcheck(event, 2, 'string') |
local curev = self[event] |
if(type(curev) == 'table' and func) then |
for k, infunc in next, curev do |
if(infunc == func) then |
table.remove(curev, k) |
local n = #curev |
if(n == 1) then |
local _, handler = next(curev) |
self[event] = handler |
elseif(n == 0) then |
-- This should not happen |
UnregisterEvent(self, event) |
end |
break |
end |
end |
elseif(curev == func) then |
self[event] = nil |
UnregisterEvent(self, event) |
end |
end |
local parent, ns = ... |
local oUF = ns.oUF |
local Private = oUF.Private |
local argcheck = Private.argcheck |
local _QUEUE = {} |
local _FACTORY = CreateFrame'Frame' |
_FACTORY:SetScript('OnEvent', function(self, event, ...) |
return self[event](self, event, ...) |
end) |
_FACTORY:RegisterEvent'PLAYER_LOGIN' |
_FACTORY.active = true |
function _FACTORY:PLAYER_LOGIN() |
if(not self.active) then return end |
for _, func in next, _QUEUE do |
func(oUF) |
end |
-- Avoid creating dupes. |
wipe(_QUEUE) |
end |
function oUF:Factory(func) |
argcheck(func, 2, 'function') |
-- Call the function directly if we're active and logged in. |
if(IsLoggedIn() and _FACTORY.active) then |
return func(self) |
else |
table.insert(_QUEUE, func) |
end |
end |
function oUF:EnableFactory() |
_FACTORY.active = true |
end |
function oUF:DisableFactory() |
_FACTORY.active = nil |
end |
function oUF:RunFactoryQueue() |
_FACTORY:PLAYER_LOGIN() |
end |
<Ui xmlns="http://www.blizzard.com/wow/ui/"> |
<Script file='init.lua' /> |
<Script file='private.lua' /> |
<Script file='ouf.lua' /> |
<Script file='events.lua'/> |
<Script file='factory.lua' /> |
<Script file='blizzard.lua' /> |
<Script file='units.lua' /> |
<Script file='colors.lua' /> |
<Script file='finalize.lua' /> |
<Script file='elements\power.lua' /> |
<Script file='elements\aura.lua' /> |
<Script file='elements\health.lua' /> |
<Script file='elements\cpoints.lua' /> |
<Script file='elements\ricons.lua' /> |
<Script file='elements\leader.lua' /> |
<Script file='elements\combat.lua' /> |
<Script file='elements\resting.lua' /> |
<Script file='elements\pvp.lua' /> |
<Script file='elements\portraits.lua' /> |
<Script file='elements\range.lua' /> |
<Script file='elements\castbar.lua' /> |
<Script file='elements\threat.lua' /> |
<Script file='elements\tags.lua' /> |
<Script file='elements\masterlooter.lua' /> |
<Script file='elements\assistant.lua' /> |
<Script file='elements\runebar.lua' /> |
<Script file='elements\lfdrole.lua' /> |
<Script file='elements\healprediction.lua' /> |
<Script file='elements\picon.lua' /> |
<Script file='elements\readycheck.lua' /> |
<Script file='elements\qicon.lua' /> |
<Script file='elements\eclipsebar.lua' /> |
<Script file='elements\altpowerbar.lua' /> |
<Script file='elements\totems.lua' /> |
<Script file='elements\resurrect.lua' /> |
<Script file='elements\druidmana.lua' /> |
<Script file='elements\classicons.lua' /> |
<Script file='elements\stagger.lua' /> |
<!-- Clique support --> |
<Button name="oUF_ClickCastUnitTemplate" virtual="true" inherits="SecureUnitButtonTemplate,SecureHandlerEnterLeaveTemplate"> |
<Attributes> |
<Attribute name="_onenter" type="string" value="local snippet = self:GetAttribute('clickcast_onenter'); if snippet then self:Run(snippet) end"/> |
<Attribute name="_onleave" type="string" value="local snippet = self:GetAttribute('clickcast_onleave'); if snippet then self:Run(snippet) end"/> |
</Attributes> |
</Button> |
<!-- Pet Battle Hider Frame --> |
<Frame name="oUF_PetBattleFrameHider" inherits="SecureHandlerStateTemplate" parent="UIParent" setAllPoints="true"> |
<Scripts> |
<OnLoad> |
RegisterStateDriver(self, "visibility", "[petbattle] hide; show") |
</OnLoad> |
</Scripts> |
</Frame> |
<!-- |
Sub-object as a child of the parent unit frame: |
<Button name="oUF_HeaderTargetTemplate" inherits="SecureUnitButtonTemplate" virtual="true"> |
<Frames> |
<Button name="$parentTarget" inherits="SecureUnitButtonTemplate"> |
<Attributes> |
<Attribute name="unitsuffix" type="string" value="target"/> |
<Attribute name="useparent-unit" type="boolean" value="true"/> |
</Attributes> |
</Button> |
</Frames> |
</Button> |
Separate unit template example: |
<Button name="oUF_HeaderSeparateSubOjectsTemplate" inherits="SecureUnitButtonTemplate" virtual="true"> |
<Attributes> |
<Attribute name="oUF-onlyProcessChildren" type="boolean" value="true"/> |
</Attributes> |
<Frames> |
<Button name="$parentUnit" inherits="SecureUnitButtonTemplate"> |
<Attributes> |
<Attribute name="useparent-unit" type="boolean" value="true"/> |
</Attributes> |
</Button> |
<Button name="$parentPet" inherits="SecureUnitButtonTemplate"> |
<Attributes> |
<Attribute name="unitsuffix" type="string" value="pet"/> |
<Attribute name="useparent-unit" type="boolean" value="true"/> |
</Attributes> |
</Button> |
<Button name="$parentTarget" inherits="SecureUnitButtonTemplate"> |
<Attributes> |
<Attribute name="unitsuffix" type="string" value="target"/> |
<Attribute name="useparent-unit" type="boolean" value="true"/> |
</Attributes> |
</Button> |
</Frames> |
</Button> |
--> |
</Ui> |
local parent, ns = ... |
local global = GetAddOnMetadata(parent, 'X-oUF') |
local _VERSION = GetAddOnMetadata(parent, 'version') |
local oUF = ns.oUF |
local Private = oUF.Private |
local argcheck = Private.argcheck |
local print = Private.print |
local error = Private.error |
local styles, style = {} |
local callback, objects = {}, {} |
local elements = {} |
local activeElements = {} |
-- updating of "invalid" units. |
local enableTargetUpdate = function(object) |
object.onUpdateFrequency = object.onUpdateFrequency or .5 |
object.__eventless = true |
local total = 0 |
object:SetScript('OnUpdate', function(self, elapsed) |
if(not self.unit) then |
return |
elseif(total > self.onUpdateFrequency) then |
self:UpdateAllElements'OnUpdate' |
total = 0 |
end |
total = total + elapsed |
end) |
end |
Private.enableTargetUpdate = enableTargetUpdate |
local updateActiveUnit = function(self, event, unit) |
-- Calculate units to work with |
local realUnit, modUnit = SecureButton_GetUnit(self), SecureButton_GetModifiedUnit(self) |
-- _GetUnit() doesn't rewrite playerpet -> pet like _GetModifiedUnit does. |
if(realUnit == 'playerpet') then |
realUnit = 'pet' |
elseif(realUnit == 'playertarget') then |
realUnit = 'target' |
end |
if(modUnit == "pet" and realUnit ~= "pet") then |
modUnit = "vehicle" |
end |
-- Drop out if the event unit doesn't match any of the frame units. |
if(not UnitExists(modUnit) or unit and unit ~= realUnit and unit ~= modUnit) then return end |
-- Change the active unit and run a full update. |
if Private.UpdateUnits(self, modUnit, realUnit) then |
self:UpdateAllElements('RefreshUnit') |
return true |
end |
end |
local iterateChildren = function(...) |
for l = 1, select("#", ...) do |
local obj = select(l, ...) |
if(type(obj) == 'table' and obj.isChild) then |
updateActiveUnit(obj, "iterateChildren") |
end |
end |
end |
local OnAttributeChanged = function(self, name, value) |
if(name == "unit" and value) then |
if(self.hasChildren) then |
iterateChildren(self:GetChildren()) |
end |
if(not self:GetAttribute'oUF-onlyProcessChildren') then |
updateActiveUnit(self, "OnAttributeChanged") |
end |
end |
end |
local frame_metatable = { |
__index = CreateFrame"Button" |
} |
Private.frame_metatable = frame_metatable |
for k, v in pairs{ |
EnableElement = function(self, name, unit) |
argcheck(name, 2, 'string') |
argcheck(unit, 3, 'string', 'nil') |
local element = elements[name] |
if(not element or self:IsElementEnabled(name)) then return end |
if(element.enable(self, unit or self.unit)) then |
activeElements[self][name] = true |
if(element.update) then |
table.insert(self.__elements, element.update) |
end |
end |
end, |
DisableElement = function(self, name) |
argcheck(name, 2, 'string') |
local enabled = self:IsElementEnabled(name) |
if(not enabled) then return end |
local update = elements[name].update |
for k, func in next, self.__elements do |
if(func == update) then |
table.remove(self.__elements, k) |
break |
end |
end |
activeElements[self][name] = nil |
-- We need to run a new update cycle in-case we knocked ourself out of sync. |
-- The main reason we do this is to make sure the full update is completed |
-- if an element for some reason removes itself _during_ the update |
-- progress. |
self:UpdateAllElements('DisableElement', name) |
return elements[name].disable(self) |
end, |
IsElementEnabled = function(self, name) |
argcheck(name, 2, 'string') |
local element = elements[name] |
if(not element) then return end |
local active = activeElements[self] |
return active and active[name] |
end, |
Enable = RegisterUnitWatch, |
Disable = function(self) |
UnregisterUnitWatch(self) |
self:Hide() |
end, |
UpdateAllElements = function(self, event) |
local unit = self.unit |
if(not UnitExists(unit)) then return end |
if(self.PreUpdate) then |
self:PreUpdate(event) |
end |
for _, func in next, self.__elements do |
func(self, event, unit) |
end |
if(self.PostUpdate) then |
self:PostUpdate(event) |
end |
end, |
} do |
frame_metatable.__index[k] = v |
end |
local OnShow = function(self) |
if(not updateActiveUnit(self, 'OnShow')) then |
return self:UpdateAllElements'OnShow' |
end |
end |
local UpdatePet = function(self, event, unit) |
local petUnit |
if(unit == 'target') then |
return |
elseif(unit == 'player') then |
petUnit = 'pet' |
else |
-- Convert raid26 -> raidpet26 |
petUnit = unit:gsub('^(%a+)(%d+)', '%1pet%2') |
end |
if(self.unit ~= petUnit) then return end |
if(not updateActiveUnit(self, event)) then |
return self:UpdateAllElements(event) |
end |
end |
local initObject = function(unit, style, styleFunc, header, ...) |
local num = select('#', ...) |
for i=1, num do |
local object = select(i, ...) |
local objectUnit = object:GetAttribute'oUF-guessUnit' or unit |
local suffix = object:GetAttribute'unitsuffix' |
object.__elements = {} |
object.style = style |
object = setmetatable(object, frame_metatable) |
-- Expose the frame through oUF.objects. |
table.insert(objects, object) |
-- We have to force update the frames when PEW fires. |
object:RegisterEvent("PLAYER_ENTERING_WORLD", object.UpdateAllElements) |
-- Handle the case where someone has modified the unitsuffix attribute in |
-- oUF-initialConfigFunction. |
if(suffix and not objectUnit:match(suffix)) then |
objectUnit = objectUnit .. suffix |
end |
if(not (suffix == 'target' or objectUnit and objectUnit:match'target')) then |
object:RegisterEvent('UNIT_ENTERED_VEHICLE', updateActiveUnit, true) |
object:RegisterEvent('UNIT_EXITED_VEHICLE', updateActiveUnit, true) |
-- We don't need to register UNIT_PET for the player unit. We register it |
-- mainly because UNIT_EXITED_VEHICLE and UNIT_ENTERED_VEHICLE doesn't always |
-- have pet information when they fire for party and raid units. |
if(objectUnit ~= 'player') then |
object:RegisterEvent('UNIT_PET', UpdatePet, true) |
end |
end |
if(not header) then |
-- No header means it's a frame created through :Spawn(). |
object:SetAttribute("*type1", "target") |
object:SetAttribute('*type2', 'togglemenu') |
-- No need to enable this for *target frames. |
if(not (unit:match'target' or suffix == 'target')) then |
object:SetAttribute('toggleForVehicle', true) |
end |
-- Other boss and target units are handled by :HandleUnit(). |
if(suffix == 'target') then |
enableTargetUpdate(object) |
else |
oUF:HandleUnit(object) |
end |
else |
-- Used to update frames when they change position in a group. |
object:RegisterEvent('GROUP_ROSTER_UPDATE', object.UpdateAllElements) |
if(num > 1) then |
if(object:GetParent() == header) then |
object.hasChildren = true |
else |
object.isChild = true |
end |
end |
if(suffix == 'target') then |
enableTargetUpdate(object) |
end |
end |
Private.UpdateUnits(object, objectUnit) |
styleFunc(object, objectUnit, not header) |
object:SetScript("OnAttributeChanged", OnAttributeChanged) |
object:SetScript("OnShow", OnShow) |
activeElements[object] = {} |
for element in next, elements do |
object:EnableElement(element, objectUnit) |
end |
for _, func in next, callback do |
func(object) |
end |
-- Make Clique happy |
_G.ClickCastFrames = ClickCastFrames or {} |
ClickCastFrames[object] = true |
end |
end |
local walkObject = function(object, unit) |
local parent = object:GetParent() |
local style = parent.style or style |
local styleFunc = styles[style] |
local header = parent:GetAttribute'oUF-headerType' and parent |
-- Check if we should leave the main frame blank. |
if(object:GetAttribute'oUF-onlyProcessChildren') then |
object.hasChildren = true |
object:SetScript('OnAttributeChanged', OnAttributeChanged) |
return initObject(unit, style, styleFunc, header, object:GetChildren()) |
end |
return initObject(unit, style, styleFunc, header, object, object:GetChildren()) |
end |
function oUF:RegisterInitCallback(func) |
table.insert(callback, func) |
end |
function oUF:RegisterMetaFunction(name, func) |
argcheck(name, 2, 'string') |
argcheck(func, 3, 'function', 'table') |
if(frame_metatable.__index[name]) then |
return |
end |
frame_metatable.__index[name] = func |
end |
function oUF:RegisterStyle(name, func) |
argcheck(name, 2, 'string') |
argcheck(func, 3, 'function', 'table') |
if(styles[name]) then return error("Style [%s] already registered.", name) end |
if(not style) then style = name end |
styles[name] = func |
end |
function oUF:SetActiveStyle(name) |
argcheck(name, 2, 'string') |
if(not styles[name]) then return error("Style [%s] does not exist.", name) end |
style = name |
end |
do |
local function iter(_, n) |
-- don't expose the style functions. |
return (next(styles, n)) |
end |
function oUF.IterateStyles() |
return iter, nil, nil |
end |
end |
local getCondition |
do |
local conditions = { |
raid40 = '[@raid26,exists] show;', |
raid25 = '[@raid11,exists] show;', |
raid10 = '[@raid6,exists] show;', |
raid = '[group:raid] show;', |
party = '[group:party,nogroup:raid] show;', |
solo = '[@player,exists,nogroup:party] show;', |
} |
function getCondition(...) |
local cond = '' |
for i=1, select('#', ...) do |
local short = select(i, ...) |
local condition = conditions[short] |
if(condition) then |
cond = cond .. condition |
end |
end |
return cond .. 'hide' |
end |
end |
local generateName = function(unit, ...) |
local name = 'oUF_' .. style:gsub('[^%a%d_]+', '') |
local raid, party, groupFilter |
for i=1, select('#', ...), 2 do |
local att, val = select(i, ...) |
if(att == 'showRaid') then |
raid = true |
elseif(att == 'showParty') then |
party = true |
elseif(att == 'groupFilter') then |
groupFilter = val |
end |
end |
local append |
if(raid) then |
if(groupFilter) then |
if(type(groupFilter) == 'number' and groupFilter > 0) then |
append = groupFilter |
elseif(groupFilter:match'TANK') then |
append = 'MainTank' |
elseif(groupFilter:match'ASSIST') then |
append = 'MainAssist' |
else |
local _, count = groupFilter:gsub(',', '') |
if(count == 0) then |
append = 'Raid' .. groupFilter |
else |
append = 'Raid' |
end |
end |
else |
append = 'Raid' |
end |
elseif(party) then |
append = 'Party' |
elseif(unit) then |
append = unit:gsub("^%l", string.upper) |
end |
if(append) then |
name = name .. append |
end |
-- Change oUF_LilyRaidRaid into oUF_LilyRaid |
name = name:gsub('(%u%l+)([%u%l]*)%1', '%1') |
-- Change oUF_LilyTargettarget into oUF_LilyTargetTarget |
name = name:gsub('t(arget)', 'T%1') |
local base = name |
local i = 2 |
while(_G[name]) do |
name = base .. i |
i = i + 1 |
end |
return name |
end |
do |
local styleProxy = function(self, frame, ...) |
return walkObject(_G[frame]) |
end |
-- There has to be an easier way to do this. |
local initialConfigFunction = [[ |
local header = self:GetParent() |
local frames = table.new() |
table.insert(frames, self) |
self:GetChildList(frames) |
for i=1, #frames do |
local frame = frames[i] |
local unit |
-- There's no need to do anything on frames with onlyProcessChildren |
if(not frame:GetAttribute'oUF-onlyProcessChildren') then |
RegisterUnitWatch(frame) |
-- Attempt to guess what the header is set to spawn. |
local groupFilter = header:GetAttribute'groupFilter' |
if(type(groupFilter) == 'string' and groupFilter:match('MAIN[AT]')) then |
local role = groupFilter:match('MAIN([AT])') |
if(role == 'T') then |
unit = 'maintank' |
else |
unit = 'mainassist' |
end |
elseif(header:GetAttribute'showRaid') then |
unit = 'raid' |
elseif(header:GetAttribute'showParty') then |
unit = 'party' |
end |
local headerType = header:GetAttribute'oUF-headerType' |
local suffix = frame:GetAttribute'unitsuffix' |
if(unit and suffix) then |
if(headerType == 'pet' and suffix == 'target') then |
unit = unit .. headerType .. suffix |
else |
unit = unit .. suffix |
end |
elseif(unit and headerType == 'pet') then |
unit = unit .. headerType |
end |
frame:SetAttribute('*type1', 'target') |
frame:SetAttribute('*type2', 'togglemenu') |
frame:SetAttribute('toggleForVehicle', true) |
frame:SetAttribute('oUF-guessUnit', unit) |
end |
local body = header:GetAttribute'oUF-initialConfigFunction' |
if(body) then |
frame:Run(body, unit) |
end |
end |
header:CallMethod('styleFunction', self:GetName()) |
local clique = header:GetFrameRef("clickcast_header") |
if(clique) then |
clique:SetAttribute("clickcast_button", self) |
clique:RunAttribute("clickcast_register") |
end |
]] |
function oUF:SpawnHeader(overrideName, template, visibility, ...) |
if(not style) then return error("Unable to create frame. No styles have been registered.") end |
template = (template or 'SecureGroupHeaderTemplate') |
local isPetHeader = template:match'PetHeader' |
local name = overrideName or generateName(nil, ...) |
local header = CreateFrame('Frame', name, oUF_PetBattleFrameHider, template) |
header:SetAttribute("template", "oUF_ClickCastUnitTemplate") |
for i=1, select("#", ...), 2 do |
local att, val = select(i, ...) |
if(not att) then break end |
header:SetAttribute(att, val) |
end |
header.style = style |
header.styleFunction = styleProxy |
-- We set it here so layouts can't directly override it. |
header:SetAttribute('initialConfigFunction', initialConfigFunction) |
header:SetAttribute('oUF-headerType', isPetHeader and 'pet' or 'group') |
if(Clique) then |
SecureHandlerSetFrameRef(header, 'clickcast_header', Clique.header) |
end |
if(header:GetAttribute'showParty') then |
self:DisableBlizzard'party' |
end |
if(visibility) then |
local type, list = string.split(' ', visibility, 2) |
if(list and type == 'custom') then |
RegisterAttributeDriver(header, 'state-visibility', list) |
else |
local condition = getCondition(string.split(',', visibility)) |
RegisterAttributeDriver(header, 'state-visibility', condition) |
end |
end |
return header |
end |
end |
function oUF:Spawn(unit, overrideName) |
argcheck(unit, 2, 'string') |
if(not style) then return error("Unable to create frame. No styles have been registered.") end |
unit = unit:lower() |
local name = overrideName or generateName(unit) |
local object = CreateFrame("Button", name, oUF_PetBattleFrameHider, "SecureUnitButtonTemplate") |
Private.UpdateUnits(object, unit) |
self:DisableBlizzard(unit) |
walkObject(object, unit) |
object:SetAttribute("unit", unit) |
RegisterUnitWatch(object) |
return object |
end |
function oUF:AddElement(name, update, enable, disable) |
argcheck(name, 2, 'string') |
argcheck(update, 3, 'function', 'nil') |
argcheck(enable, 4, 'function', 'nil') |
argcheck(disable, 5, 'function', 'nil') |
if(elements[name]) then return error('Element [%s] is already registered.', name) end |
elements[name] = { |
update = update; |
enable = enable; |
disable = disable; |
} |
end |
oUF.version = _VERSION |
oUF.objects = objects |
if(global) then |
if(parent ~= 'oUF' and global == 'oUF') then |
error("%s is doing it wrong and setting its global to oUF.", parent) |
else |
_G[global] = oUF |
end |
end |
local parent, ns = ... |
local Private = ns.oUF.Private |
function Private.argcheck(value, num, ...) |
assert(type(num) == 'number', "Bad argument #2 to 'argcheck' (number expected, got "..type(num)..")") |
for i=1,select("#", ...) do |
if type(value) == select(i, ...) then return end |
end |
local types = strjoin(", ", ...) |
local name = string.match(debugstack(2,2,0), ": in function [`<](.-)['>]") |
error(("Bad argument #%d to '%s' (%s expected, got %s"):format(num, name, types, type(value)), 3) |
end |
function Private.print(...) |
print("|cff33ff99oUF:|r", ...) |
end |
function Private.error(...) |
Private.print("|cffff0000Error:|r "..string.format(...)) |
end |
--[[ Element: Class Icons |
Toggles the visibility of icons depending on the player's class and |
specialization. |
Widget |
ClassIcons - An array consisting of as many UI Textures as the theoretical |
maximum return of `UnitPowerMax`. |
Notes |
Monk - Chi Orbs |
Paladin - Holy Power |
Priest - Shadow Orbs |
Warlock - Soul Shards |
Examples |
local ClassIcons = {} |
for index = 1, 6 do |
local Icon = self:CreateTexture(nil, 'BACKGROUND') |
-- Position and size. |
Icon:SetSize(16, 16) |
Icon:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', index * Icon:GetWidth(), 0) |
ClassIcons[index] = Icon |
end |
-- Register with oUF |
self.ClassIcons = ClassIcons |
Hooks |
OverrideVisibility(self) - Used to completely override the internal visibility |
function. Removing the table key entry will make |
the element fall-back to its internal function |
again. |
Override(self) - Used to completely override the internal update |
function. Removing the table key entry will make the |
element fall-back to its internal function again. |
UpdateTexture(element) - Used to completely override the internal function |
for updating the power icon textures. Removing the |
table key entry will make the element fall-back to |
its internal function again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local _, PlayerClass = UnitClass'player' |
-- Holds the class specific stuff. |
local ClassPowerID, ClassPowerType |
local ClassPowerEnable, ClassPowerDisable |
local RequireSpec, RequireSpell |
local UpdateTexture = function(element) |
local red, green, blue, desaturated |
if(PlayerClass == 'MONK') then |
red, green, blue = 0, 1, .59 |
desaturated = true |
elseif(PlayerClass == 'WARLOCK') then |
red, green, blue = 1, .5, 1 |
desaturated = true |
elseif(PlayerClass == 'PRIEST') then |
red, green, blue = 1, 1, 1 |
elseif(PlayerClass == 'PALADIN') then |
red, green, blue = 1, .96, .41 |
desaturated = true |
end |
for i = 1, #element do |
local icon = element[i] |
if(icon.SetDesaturated) then |
icon:SetDesaturated(desaturated) |
end |
icon:SetVertexColor(red, green, blue) |
end |
end |
local Update = function(self, event, unit, powerType) |
if(unit ~= 'player' or powerType ~= ClassPowerType) then |
return |
end |
local element = self.ClassIcons |
--[[ :PreUpdate() |
Called before the element has been updated |
Arguments |
self - The ClassIcons element |
event - The event, that the update is being triggered for |
]] |
if(element.PreUpdate) then |
element:PreUpdate(event) |
end |
local cur, max, oldMax |
if(event ~= 'ClassPowerDisable') then |
cur = UnitPower('player', ClassPowerID) |
max = UnitPowerMax('player', ClassPowerID) |
for i = 1, max do |
if(i <= cur) then |
element[i]:Show() |
else |
element[i]:Hide() |
end |
end |
oldMax = element.__max |
if(max ~= oldMax) then |
if(max < oldMax) then |
for i = max + 1, oldMax do |
element[i]:Hide() |
end |
end |
element.__max = max |
end |
end |
--[[ :PostUpdate(cur, max, hasMaxChanged, event) |
Called after the element has been updated |
Arguments |
self - The ClassIcons element |
cur - The current amount of power |
max - The maximum amount of power |
hasMaxChanged - Shows if the maximum amount has changed since the last |
update |
event - The event, which the update happened for |
]] |
if(element.PostUpdate) then |
return element:PostUpdate(cur, max, oldMax ~= max, event) |
end |
end |
local function Visibility(self, event, unit) |
local element = self.ClassIcons |
local shouldEnable |
if(not UnitHasVehicleUI('player')) then |
if(not RequireSpec or RequireSpec == GetSpecialization()) then |
if(not RequireSpell or IsPlayerSpell(RequireSpell)) then |
self:UnregisterEvent('SPELLS_CHANGED', Visibility) |
shouldEnable = true |
else |
self:RegisterEvent('SPELLS_CHANGED', Visibility, true) |
end |
end |
end |
local isEnabled = element.isEnabled |
if(shouldEnable and not isEnabled) then |
ClassPowerEnable(self) |
elseif(not shouldEnable and (isEnabled or isEnabled == nil)) then |
ClassPowerDisable(self) |
end |
end |
local Path = function(self, ...) |
return (self.ClassIcons.Override or Update) (self, ...) |
end |
local VisibilityPath = function(self, ...) |
return (self.ClassIcons.OverrideVisibility or Visibility) (self, ...) |
end |
local ForceUpdate = function(element) |
return VisibilityPath(element.__owner, 'ForceUpdate', element.__owner.unit) |
end |
do |
ClassPowerEnable = function(self) |
self:RegisterEvent('UNIT_DISPLAYPOWER', Path) |
self:RegisterEvent('UNIT_POWER_FREQUENT', Path) |
Path(self, 'ClassPowerEnable', 'player', ClassPowerType) |
self.ClassIcons.isEnabled = true |
end |
ClassPowerDisable = function(self) |
self:UnregisterEvent('UNIT_DISPLAYPOWER', Path) |
self:UnregisterEvent('UNIT_POWER_FREQUENT', Path) |
local element = self.ClassIcons |
for i = 1, #element do |
element[i]:Hide() |
end |
Path(self, 'ClassPowerDisable', 'player', ClassPowerType) |
self.ClassIcons.isEnabled = false |
end |
if(PlayerClass == 'MONK') then |
ClassPowerID = SPELL_POWER_CHI |
ClassPowerType = "CHI" |
elseif(PlayerClass == 'PALADIN') then |
ClassPowerID = SPELL_POWER_HOLY_POWER |
ClassPowerType = "HOLY_POWER" |
RequireSpell = 85673 -- Word of Glory |
elseif(PlayerClass == 'PRIEST') then |
ClassPowerID = SPELL_POWER_SHADOW_ORBS |
ClassPowerType = "SHADOW_ORBS" |
RequireSpec = SPEC_PRIEST_SHADOW |
RequireSpell = 95740 -- Shadow Orbs |
elseif(PlayerClass == 'WARLOCK') then |
ClassPowerID = SPELL_POWER_SOUL_SHARDS |
ClassPowerType = "SOUL_SHARDS" |
RequireSpec = SPEC_WARLOCK_AFFLICTION |
RequireSpell = WARLOCK_SOULBURN |
end |
end |
local Enable = function(self, unit) |
if(unit ~= 'player' or not ClassPowerID) then return end |
local element = self.ClassIcons |
if(not element) then return end |
element.__owner = self |
element.__max = #element |
element.ForceUpdate = ForceUpdate |
if(RequireSpec) then |
self:RegisterEvent('PLAYER_TALENT_UPDATE', VisibilityPath, true) |
end |
element.ClassPowerEnable = ClassPowerEnable |
element.ClassPowerDisable = ClassPowerDisable |
for i = 1, #element do |
local icon = element[i] |
if(icon:IsObjectType'Texture' and not icon:GetTexture()) then |
icon:SetTexCoord(0.45703125, 0.60546875, 0.44531250, 0.73437500) |
icon:SetTexture([[Interface\PlayerFrame\Priest-ShadowUI]]) |
end |
end |
(element.UpdateTexture or UpdateTexture) (element) |
return true |
end |
local Disable = function(self) |
local element = self.ClassIcons |
if(not element) then return end |
ClassPowerDisable(self) |
end |
oUF:AddElement('ClassIcons', VisibilityPath, Enable, Disable) |
--[[ Element: Raid Role Icon |
Handles visibility and updating of `self.RaidRole` based upon the units |
party assignment. |
Widget |
RaidRole - A Texture representing the units party assignment. This is can be |
main tank, main assist or blank. |
Notes |
This element updates by changing the texture. |
Examples |
-- Position and size |
local RaidRole = self:CreateTexture(nil, 'OVERLAY') |
RaidRole:SetSize(16, 16) |
RaidRole:SetPoint('TOPLEFT') |
-- Register it with oUF |
self.RaidRole = RaidRole |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local Update = function(self, event) |
local unit = self.unit |
if(not UnitInRaid(unit)) then return end |
local raidrole = self.RaidRole |
if(raidrole.PreUpdate) then |
raidrole:PreUpdate() |
end |
local inVehicle = UnitHasVehicleUI(unit) |
if(GetPartyAssignment('MAINTANK', unit) and not inVehicle) then |
raidrole:Show() |
raidrole:SetTexture[[Interface\GROUPFRAME\UI-GROUP-MAINTANKICON]] |
elseif(GetPartyAssignment('MAINASSIST', unit) and not inVehicle) then |
raidrole:Show() |
raidrole:SetTexture[[Interface\GROUPFRAME\UI-GROUP-MAINASSISTICON]] |
else |
raidrole:Hide() |
end |
if(raidrole.PostUpdate) then |
return raidrole:PostUpdate(rinfo) |
end |
end |
local Path = function(self, ...) |
return (self.RaidRole.Override or Update)(self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate') |
end |
local Enable = function(self) |
local raidrole = self.RaidRole |
if(raidrole) then |
raidrole.__owner = self |
raidrole.ForceUpdate = ForceUpdate |
self:RegisterEvent('GROUP_ROSTER_UPDATE', Path, true) |
return true |
end |
end |
local Disable = function(self) |
local raidrole = self.RaidRole |
if(raidrole) then |
self:UnregisterEvent('GROUP_ROSTER_UPDATE', Path) |
end |
end |
oUF:AddElement('RaidRole', Path, Enable, Disable) |
--[[ Element: Ready Check Icon |
Handles updating and visibility of `self.ReadyCheck` based upon the units |
ready check status. |
Widget |
ReadyCheck - A Texture representing ready check status. |
Notes |
This element updates by changing the texture. |
Options |
.finishedTime - The number of seconds the icon should stick after a check has |
completed. Defaults to 10 seconds. |
.fadeTime - The number of seconds the icon should used to fade away after |
the stick duration has completed. Defaults to 1.5 seconds. |
Examples |
-- Position and size |
local ReadyCheck = self:CreateTexture(nil, 'OVERLAY') |
ReadyCheck:SetSize(16, 16) |
ReadyCheck:SetPoint('TOP') |
-- Register with oUF |
self.ReadyCheck = ReadyCheck |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local _TIMERS = {} |
local ReadyCheckFrame |
local removeEntry = function(icon) |
_TIMERS[icon] = nil |
if(not next(_TIMERS)) then |
return ReadyCheckFrame:Hide() |
end |
end |
local Start = function(self) |
removeEntry(self) |
self:SetTexture(READY_CHECK_WAITING_TEXTURE) |
self.state = 'waiting' |
self:SetAlpha(1) |
self:Show() |
end |
local Confirm = function(self, ready) |
removeEntry(self) |
if(ready) then |
self:SetTexture(READY_CHECK_READY_TEXTURE) |
self.state = 'ready' |
else |
self:SetTexture(READY_CHECK_NOT_READY_TEXTURE) |
self.state = 'notready' |
end |
self:SetAlpha(1) |
self:Show() |
end |
local Finish = function(self) |
if(self.state == 'waiting') then |
self:SetTexture(READY_CHECK_AFK_TEXTURE) |
self.state = 'afk' |
end |
self.finishedTimer = self.finishedTime or 10 |
self.fadeTimer = self.fadeTime or 1.5 |
_TIMERS[self] = true |
ReadyCheckFrame:Show() |
end |
local OnUpdate = function(self, elapsed) |
for icon in next, _TIMERS do |
if(icon.finishedTimer) then |
icon.finishedTimer = icon.finishedTimer - elapsed |
if(icon.finishedTimer <= 0) then |
icon.finishedTimer = nil |
end |
elseif(icon.fadeTimer) then |
icon.fadeTimer = icon.fadeTimer - elapsed |
icon:SetAlpha(icon.fadeTimer / (icon.fadeTime or 1.5)) |
if(icon.fadeTimer <= 0) then |
icon:Hide() |
removeEntry(icon) |
end |
end |
end |
end |
local Update = function(self, event) |
local unit = self.unit |
local readyCheck = self.ReadyCheck |
if(event == 'READY_CHECK_FINISHED') then |
Finish(readyCheck) |
else |
local status = GetReadyCheckStatus(unit) |
if(UnitExists(unit) and status) then |
if(status == 'ready') then |
Confirm(readyCheck, 1) |
elseif(status == 'notready') then |
Confirm(readyCheck) |
else |
Start(readyCheck) |
end |
end |
end |
end |
local Path = function(self, ...) |
return (self.ReadyCheck.Override or Update) (self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate') |
end |
local Enable = function(self, unit) |
local readyCheck = self.ReadyCheck |
if(readyCheck and (unit and (unit:sub(1, 5) == 'party' or unit:sub(1,4) == 'raid'))) then |
readyCheck.__owner = self |
readyCheck.ForceUpdate = ForceUpdate |
if(not ReadyCheckFrame) then |
ReadyCheckFrame = CreateFrame'Frame' |
ReadyCheckFrame:SetScript('OnUpdate', OnUpdate) |
end |
self:RegisterEvent('READY_CHECK', Path, true) |
self:RegisterEvent('READY_CHECK_CONFIRM', Path, true) |
self:RegisterEvent('READY_CHECK_FINISHED', Path, true) |
return true |
end |
end |
local Disable = function(self) |
local readyCheck = self.ReadyCheck |
if(readyCheck) then |
readyCheck:Hide() |
self:UnregisterEvent('READY_CHECK', Path) |
self:UnregisterEvent('READY_CHECK_CONFIRM', Path) |
self:UnregisterEvent('READY_CHECK_FINISHED', Path) |
end |
end |
oUF:AddElement('ReadyCheck', Path, Enable, Disable) |
--[[ Element: Druid Mana Bar |
Handles updating and visibility of a status bar displaying the druid's mana |
while outside of caster form. |
Widget |
DruidMana - A StatusBar to represent current caster mana. |
Sub-Widgets |
.bg - A Texture which functions as a background. It will inherit the color of |
the main StatusBar. |
Notes |
The default StatusBar texture will be applied if the UI widget doesn't have a |
status bar texture or color defined. |
Options |
.colorClass - Use `self.colors.class[class]` to color the bar. This will |
always use DRUID as class. |
.colorSmooth - Use `self.colors.smooth` to color the bar with a smooth |
gradient based on the players current mana percentage. |
.colorPower - Use `self.colors.power[token]` to color the bar. This will |
always use MANA as token. |
Sub-Widget Options |
.multiplier - Defines a multiplier, which is used to tint the background based |
on the main widgets R, G and B values. Defaults to 1 if not |
present. |
Examples |
-- Position and size |
local DruidMana = CreateFrame("StatusBar", nil, self) |
DruidMana:SetSize(20, 20) |
DruidMana:SetPoint('TOP') |
DruidMana:SetPoint('LEFT') |
DruidMana:SetPoint('RIGHT') |
-- Add a background |
local Background = DruidMana:CreateTexture(nil, 'BACKGROUND') |
Background:SetAllPoints(DruidMana) |
Background:SetTexture(1, 1, 1, .5) |
-- Register it with oUF |
self.DruidMana = DruidMana |
self.DruidMana.bg = Background |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
if(select(2, UnitClass('player')) ~= 'DRUID') then return end |
local _, ns = ... |
local oUF = ns.oUF |
local function Update(self, event, unit, powertype) |
if(unit ~= 'player' or (powertype and powertype ~= 'MANA')) then return end |
local druidmana = self.DruidMana |
if(druidmana.PreUpdate) then druidmana:PreUpdate(unit) end |
-- Hide the bar if the active power type is mana. |
if(UnitPowerType('player') == SPELL_POWER_MANA) then |
return druidmana:Hide() |
else |
druidmana:Show() |
end |
local min, max = UnitPower('player', SPELL_POWER_MANA), UnitPowerMax('player', SPELL_POWER_MANA) |
druidmana:SetMinMaxValues(0, max) |
druidmana:SetValue(min) |
local r, g, b, t |
if(druidmana.colorClass) then |
t = self.colors.class['DRUID'] |
elseif(druidmana.colorSmooth) then |
r, g, b = self.ColorGradient(min, max, unpack(druidmana.smoothGradient or self.colors.smooth)) |
elseif(druidmana.colorPower) then |
t = self.colors.power['MANA'] |
end |
if(t) then |
r, g, b = t[1], t[2], t[3] |
end |
if(b) then |
druidmana:SetStatusBarColor(r, g, b) |
local bg = druidmana.bg |
if(bg) then |
local mu = bg.multiplier or 1 |
bg:SetVertexColor(r * mu, g * mu, b * mu) |
end |
end |
if(druidmana.PostUpdate) then |
return druidmana:PostUpdate(unit, min, max) |
end |
end |
local function Path(self, ...) |
return (self.DruidMana.Override or Update) (self, ...) |
end |
local function ForceUpdate(element) |
return Path(element.__owner, 'ForceUpdate', element.__owner.unit) |
end |
local OnDruidManaUpdate |
do |
local UnitPower = UnitPower |
OnDruidManaUpdate = function(self) |
local unit = self.__owner.unit |
local mana = UnitPower(unit, SPELL_POWER_MANA) |
if(mana ~= self.min) then |
self.min = mana |
return Path(self.__owner, 'OnDruidManaUpdate', unit) |
end |
end |
end |
local Enable = function(self, unit) |
local druidmana = self.DruidMana |
if(druidmana and unit == 'player') then |
druidmana.__owner = self |
druidmana.ForceUpdate = ForceUpdate |
if(druidmana.frequentUpdates) then |
druidmana:SetScript('OnUpdate', OnDruidManaUpdate) |
else |
self:RegisterEvent('UNIT_POWER', Path) |
end |
self:RegisterEvent('UNIT_DISPLAYPOWER', Path) |
self:RegisterEvent('UNIT_MAXPOWER', Path) |
if(druidmana:IsObjectType'StatusBar' and not druidmana:GetStatusBarTexture()) then |
druidmana:SetStatusBarTexture[[Interface\TargetingFrame\UI-StatusBar]] |
end |
return true |
end |
end |
local Disable = function(self) |
local druidmana = self.DruidMana |
if(druidmana) then |
if(druidmana:GetScript'OnUpdate') then |
druidmana:SetScript("OnUpdate", nil) |
else |
self:UnregisterEvent('UNIT_POWER', Path) |
end |
self:UnregisterEvent('UNIT_DISPLAYPOWER', Path) |
self:UnregisterEvent('UNIT_MAXPOWER', Path) |
end |
end |
oUF:AddElement('DruidMana', Path, Enable, Disable) |
--[[ Element: Health Bar |
Handles updating of `self.Health` based on the units health. |
Widget |
Health - A StatusBar used to represent current unit health. |
Sub-Widgets |
.bg - A Texture which functions as a background. It will inherit the color of |
the main StatusBar. |
Notes |
The default StatusBar texture will be applied if the UI widget doesn't have a |
status bar texture or color defined. |
Options |
The following options are listed by priority. The first check that returns |
true decides the color of the bar. |
.colorTapping - Use `self.colors.tapping` to color the bar if the unit |
isn't tapped by the player. |
.colorDisconnected - Use `self.colors.disconnected` to color the bar if the |
unit is offline. |
.colorClass - Use `self.colors.class[class]` to color the bar based on |
unit class. `class` is defined by the second return of |
[UnitClass](http://wowprogramming.com/docs/api/UnitClass). |
.colorClassNPC - Use `self.colors.class[class]` to color the bar if the |
unit is a NPC. |
.colorClassPet - Use `self.colors.class[class]` to color the bar if the |
unit is player controlled, but not a player. |
.colorReaction - Use `self.colors.reaction[reaction]` to color the bar |
based on the player's reaction towards the unit. |
`reaction` is defined by the return value of |
[UnitReaction](http://wowprogramming.com/docs/api/UnitReaction). |
.colorSmooth - Use `self.colors.smooth` to color the bar with a smooth |
gradient based on the player's current health percentage. |
.colorHealth - Use `self.colors.health` to color the bar. This flag is |
used to reset the bar color back to default if none of the |
above conditions are met. |
Sub-Widgets Options |
.multiplier - Defines a multiplier, which is used to tint the background based |
on the main widgets R, G and B values. Defaults to 1 if not |
present. |
Examples |
-- Position and size |
local Health = CreateFrame("StatusBar", nil, self) |
Health:SetHeight(20) |
Health:SetPoint('TOP') |
Health:SetPoint('LEFT') |
Health:SetPoint('RIGHT') |
-- Add a background |
local Background = Health:CreateTexture(nil, 'BACKGROUND') |
Background:SetAllPoints(Health) |
Background:SetTexture(1, 1, 1, .5) |
-- Options |
Health.frequentUpdates = true |
Health.colorTapping = true |
Health.colorDisconnected = true |
Health.colorClass = true |
Health.colorReaction = true |
Health.colorHealth = true |
-- Make the background darker. |
Background.multiplier = .5 |
-- Register it with oUF |
self.Health = Health |
self.Health.bg = Background |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
oUF.colors.health = {49/255, 207/255, 37/255} |
local Update = function(self, event, unit) |
if(self.unit ~= unit) then return end |
local health = self.Health |
if(health.PreUpdate) then health:PreUpdate(unit) end |
local min, max = UnitHealth(unit), UnitHealthMax(unit) |
local disconnected = not UnitIsConnected(unit) |
health:SetMinMaxValues(0, max) |
if(disconnected) then |
health:SetValue(max) |
else |
health:SetValue(min) |
end |
health.disconnected = disconnected |
local r, g, b, t |
if(health.colorTapping and not UnitPlayerControlled(unit) and |
UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) and not |
UnitIsTappedByAllThreatList(unit)) then |
t = self.colors.tapped |
elseif(health.colorDisconnected and not UnitIsConnected(unit)) then |
t = self.colors.disconnected |
elseif(health.colorClass and UnitIsPlayer(unit)) or |
(health.colorClassNPC and not UnitIsPlayer(unit)) or |
(health.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then |
local _, class = UnitClass(unit) |
t = self.colors.class[class] |
elseif(health.colorReaction and UnitReaction(unit, 'player')) then |
t = self.colors.reaction[UnitReaction(unit, "player")] |
elseif(health.colorSmooth) then |
r, g, b = self.ColorGradient(min, max, unpack(health.smoothGradient or self.colors.smooth)) |
elseif(health.colorHealth) then |
t = self.colors.health |
end |
if(t) then |
r, g, b = t[1], t[2], t[3] |
end |
if(b) then |
health:SetStatusBarColor(r, g, b) |
local bg = health.bg |
if(bg) then local mu = bg.multiplier or 1 |
bg:SetVertexColor(r * mu, g * mu, b * mu) |
end |
end |
if(health.PostUpdate) then |
return health:PostUpdate(unit, min, max) |
end |
end |
local Path = function(self, ...) |
return (self.Health.Override or Update) (self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate', element.__owner.unit) |
end |
local Enable = function(self, unit) |
local health = self.Health |
if(health) then |
health.__owner = self |
health.ForceUpdate = ForceUpdate |
if(health.frequentUpdates) then |
self:RegisterEvent('UNIT_HEALTH_FREQUENT', Path) |
else |
self:RegisterEvent('UNIT_HEALTH', Path) |
end |
self:RegisterEvent("UNIT_MAXHEALTH", Path) |
self:RegisterEvent('UNIT_CONNECTION', Path) |
-- For tapping. |
self:RegisterEvent('UNIT_FACTION', Path) |
if(health:IsObjectType'StatusBar' and not health:GetStatusBarTexture()) then |
health:SetStatusBarTexture[[Interface\TargetingFrame\UI-StatusBar]] |
end |
return true |
end |
end |
local Disable = function(self) |
local health = self.Health |
if(health) then |
health:Hide() |
self:UnregisterEvent('UNIT_HEALTH_FREQUENT', Path) |
self:UnregisterEvent('UNIT_HEALTH', Path) |
self:UnregisterEvent('UNIT_MAXHEALTH', Path) |
self:UnregisterEvent('UNIT_CONNECTION', Path) |
self:UnregisterEvent('UNIT_FACTION', Path) |
end |
end |
oUF:AddElement('Health', Path, Enable, Disable) |
--[[ Element: Combat Icon |
Toggles the visibility of `self.Combat` based on the player's combat status. |
Widget |
Combat - Any UI widget. |
Notes |
The default assistant icon will be applied if the UI widget is a texture and |
doesn't have a texture or color defined. |
Examples |
-- Position and size |
local Combat = self:CreateTexture(nil, "OVERLAY") |
Combat:SetSize(16, 16) |
Combat:SetPoint('TOP', self) |
-- Register it with oUF |
self.Combat = Combat |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local Update = function(self, event) |
local combat = self.Combat |
if(combat.PreUpdate) then |
combat:PreUpdate() |
end |
local inCombat = UnitAffectingCombat('player') |
if(inCombat) then |
combat:Show() |
else |
combat:Hide() |
end |
if(combat.PostUpdate) then |
return combat:PostUpdate(inCombat) |
end |
end |
local Path = function(self, ...) |
return (self.Combat.Override or Update) (self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate') |
end |
local Enable = function(self, unit) |
local combat = self.Combat |
if(combat and unit == 'player') then |
combat.__owner = self |
combat.ForceUpdate = ForceUpdate |
self:RegisterEvent("PLAYER_REGEN_DISABLED", Path, true) |
self:RegisterEvent("PLAYER_REGEN_ENABLED", Path, true) |
if(combat:IsObjectType"Texture" and not combat:GetTexture()) then |
combat:SetTexture[[Interface\CharacterFrame\UI-StateIcon]] |
combat:SetTexCoord(.5, 1, 0, .49) |
end |
return true |
end |
end |
local Disable = function(self) |
if(self.Combat) then |
self.Combat:Hide() |
self:UnregisterEvent("PLAYER_REGEN_DISABLED", Path) |
self:UnregisterEvent("PLAYER_REGEN_ENABLED", Path) |
end |
end |
oUF:AddElement('Combat', Path, Enable, Disable) |
--[[ Element: PvP Icon |
Handles updating and toggles visibility based upon the units PvP status. |
Widget |
PvP - A Texture used to display the faction or FFA icon. |
Notes |
This element updates by changing the texture. |
Examples |
-- Position and size |
local PvP = self:CreateTexture(nil, 'OVERLAY') |
PvP:SetSize(16, 16) |
PvP:SetPoint('TOPRIGHT', self) |
-- Register it with oUF |
self.PvP = PvP |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local Update = function(self, event, unit) |
if(unit ~= self.unit) then return end |
local pvp = self.PvP |
if(pvp.PreUpdate) then |
pvp:PreUpdate() |
end |
local status |
local factionGroup = UnitFactionGroup(unit) |
if(UnitIsPVPFreeForAll(unit)) then |
pvp:SetTexture[[Interface\TargetingFrame\UI-PVP-FFA]] |
status = 'ffa' |
-- XXX - WoW5: UnitFactionGroup() can return Neutral as well. |
elseif(factionGroup and factionGroup ~= 'Neutral' and UnitIsPVP(unit)) then |
pvp:SetTexture([[Interface\TargetingFrame\UI-PVP-]]..factionGroup) |
status = factionGroup |
end |
if(status) then |
pvp:Show() |
else |
pvp:Hide() |
end |
if(pvp.PostUpdate) then |
return pvp:PostUpdate(status) |
end |
end |
local Path = function(self, ...) |
return (self.PvP.Override or Update) (self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate', element.__owner.unit) |
end |
local Enable = function(self) |
local pvp = self.PvP |
if(pvp) then |
pvp.__owner = self |
pvp.ForceUpdate = ForceUpdate |
self:RegisterEvent("UNIT_FACTION", Path) |
return true |
end |
end |
local Disable = function(self) |
local pvp = self.PvP |
if(pvp) then |
pvp:Hide() |
self:UnregisterEvent("UNIT_FACTION", Path) |
end |
end |
oUF:AddElement('PvP', Path, Enable, Disable) |
--[[ Element: Phasing Icon |
Toggles visibility of the phase icon based on the units phasing compared to the |
player. |
Widget |
PhaseIcon - Any UI widget. |
Notes |
The default phasing icon will be used if the UI widget is a texture and doesn't |
have a texture or color defined. |
Examples |
-- Position and size |
local PhaseIcon = self:CreateTexture(nil, 'OVERLAY') |
PhaseIcon:SetSize(16, 16) |
PhaseIcon:SetPoint('TOPLEFT', self) |
-- Register it with oUF |
self.PhaseIcon = PhaseIcon |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local Update = function(self, event) |
local picon = self.PhaseIcon |
if(picon.PreUpdate) then |
picon:PreUpdate() |
end |
local inPhase = UnitInPhase(self.unit) |
if(inPhase) then |
picon:Hide() |
else |
picon:Show() |
end |
if(picon.PostUpdate) then |
return picon:PostUpdate(inPhase) |
end |
end |
local Path = function(self, ...) |
return (self.PhaseIcon.Override or Update) (self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate') |
end |
local Enable = function(self) |
local picon = self.PhaseIcon |
if(picon) then |
picon.__owner = self |
picon.ForceUpdate = ForceUpdate |
self:RegisterEvent('UNIT_PHASE', Path, true) |
if(picon:IsObjectType'Texture' and not picon:GetTexture()) then |
picon:SetTexture[[Interface\TargetingFrame\UI-PhasingIcon]] |
end |
return true |
end |
end |
local Disable = function(self) |
local picon = self.PhaseIcon |
if(picon) then |
picon:Hide() |
self:UnregisterEvent('UNIT_PHASE', Path) |
end |
end |
oUF:AddElement('PhaseIcon', Path, Enable, Disable) |
--[[ Element: Quest Icon |
Handles updating and toggles visibility based upon the units connection to a |
quest. |
Widget |
QuestIcon - Any UI widget. |
Notes |
The default quest icon will be used if the UI widget is a texture and doesn't |
have a texture or color defined. |
Examples |
-- Position and size |
local QuestIcon = self:CreateTexture(nil, 'OVERLAY') |
QuestIcon:SetSize(16, 16) |
QuestIcon:SetPoint('TOPRIGHT', self) |
-- Register it with oUF |
self.QuestIcon = QuestIcon |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local Update = function(self, event, unit) |
if(unit ~= self.unit) then return end |
local qicon = self.QuestIcon |
if(qicon.PreUpdate) then |
qicon:PreUpdate() |
end |
local isQuestBoss = UnitIsQuestBoss(unit) |
if(isQuestBoss) then |
qicon:Show() |
else |
qicon:Hide() |
end |
if(qicon.PostUpdate) then |
return qicon:PostUpdate(isQuestBoss) |
end |
end |
local Path = function(self, ...) |
return (self.QuestIcon.Override or Update) (self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate', element.__owner.unit) |
end |
local Enable = function(self) |
local qicon = self.QuestIcon |
if(qicon) then |
qicon.__owner = self |
qicon.ForceUpdate = ForceUpdate |
self:RegisterEvent('UNIT_CLASSIFICATION_CHANGED', Path) |
if(qicon:IsObjectType'Texture' and not qicon:GetTexture()) then |
qicon:SetTexture[[Interface\TargetingFrame\PortraitQuestBadge]] |
end |
return true |
end |
end |
local Disable = function(self) |
if(self.QuestIcon) then |
self.QuestIcon:Hide() |
self:UnregisterEvent('UNIT_CLASSIFICATION_CHANGED', Path) |
end |
end |
oUF:AddElement('QuestIcon', Path, Enable, Disable) |
--[[ Element: Assistant Icon |
Toggles visibility of `self.Assistant` based on the units raid officer status. |
Widget |
Assistant - Any UI widget. |
Notes |
The default assistant icon will be applied if the UI widget is a texture and |
doesn't have a texture or color defined. |
Examples |
-- Position and size |
local Assistant = self:CreateTexture(nil, "OVERLAY") |
Assistant:SetSize(16, 16) |
Assistant:SetPoint('TOP', self) |
-- Register it with oUF |
self.Assistant = Assistant |
Hooks and Callbacks |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local Update = function(self, event) |
local assistant = self.Assistant |
--[[ :PreUpdate() |
Called before the element has been updated. |
Arguments |
self - The Assistant element. |
]] |
if(assistant.PreUpdate) then |
assistant:PreUpdate() |
end |
local unit = self.unit |
local isAssistant = UnitInRaid(unit) and UnitIsGroupAssistant(unit) and not UnitIsGroupLeader(unit) |
if(isAssistant) then |
assistant:Show() |
else |
assistant:Hide() |
end |
--[[ :PostUpdate(isAssistant) |
Called after the element has been updated. |
Arguments |
self - The Assistant element. |
isAssistant - A boolean holding whether the unit is a raid officer or not. |
]] |
if(assistant.PostUpdate) then |
return assistant:PostUpdate(isAssistant) |
end |
end |
local Path = function(self, ...) |
--[[ :Override(self, event, ...) |
Used to completely override the internal update function. Removing the |
table key entry will make the element fall-back to its internal function |
again. |
Arguments |
self - The Assistant element. |
event - The UI event that fired. |
... - A vararg with the arguments that accompany the event. |
]] |
return (self.Assistant.Override or Update) (self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate') |
end |
local Enable = function(self) |
local assistant = self.Assistant |
if(assistant) then |
self:RegisterEvent("GROUP_ROSTER_UPDATE", Path, true) |
if(assistant:IsObjectType"Texture" and not assistant:GetTexture()) then |
assistant:SetTexture[[Interface\GroupFrame\UI-Group-AssistantIcon]] |
end |
assistant.__owner = self |
assistant.ForceUpdate = ForceUpdate |
return true |
end |
end |
local Disable = function(self) |
local assistant = self.Assistant |
if(assistant) then |
self:UnregisterEvent("GROUP_ROSTER_UPDATE", Path) |
assistant:Hide() |
end |
end |
oUF:AddElement('Assistant', Path, Enable, Disable) |
--[[ Element: Eclipse Bar |
Handle updating and visibility of the Druid eclipse state status bars. |
Widget |
EclipseBar - A table to hold the sub-widgets. |
Sub-Widgets |
LunarBar - A StatusBar used to represent the lunar power state. |
SolarBar - A StatusBar used to represent the solar power state. |
Notes |
The default StatusBar texture will be applied if the UI widget doesn't have a |
status bar texture or color defined. |
Examples |
local EclipseBar = CreateFrame('Frame', nil, self) |
EclipseBar:SetPoint('BOTTOM', self, 'TOP') |
EclipseBar:SetSize(160, 20) |
-- Position and size |
local LunarBar = CreateFrame('StatusBar', nil, EclipseBar) |
LunarBar:SetPoint('LEFT') |
LunarBar:SetSize(160, 20) |
local SolarBar = CreateFrame('StatusBar', nil, EclipseBar) |
SolarBar:SetPoint('LEFT', LunarBar:GetStatusBarTexture(), 'RIGHT') |
SolarBar:SetSize(160, 20) |
-- Register with oUF |
EclipseBar.LunarBar = LunarBar |
EclipseBar.SolarBar = SolarBar |
self.EclipseBar = EclipseBar |
Hooks and Callbacks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
if(select(2, UnitClass('player')) ~= 'DRUID') then return end |
local parent, ns = ... |
local oUF = ns.oUF |
local ECLIPSE_BAR_SOLAR_BUFF = GetSpellInfo(171744) |
local ECLIPSE_BAR_LUNAR_BUFF = GetSpellInfo(171743) |
local SPELL_POWER_ECLIPSE = SPELL_POWER_ECLIPSE |
local MOONKIN_FORM = MOONKIN_FORM |
local UNIT_POWER = function(self, event, unit, powerType) |
if(self.unit ~= unit or (event == 'UNIT_POWER_FREQUENT' and powerType ~= 'ECLIPSE')) then return end |
local eb = self.EclipseBar |
local power = UnitPower('player', SPELL_POWER_ECLIPSE) |
local maxPower = UnitPowerMax('player', SPELL_POWER_ECLIPSE) |
if(eb.LunarBar) then |
eb.LunarBar:SetMinMaxValues(-maxPower, maxPower) |
eb.LunarBar:SetValue(power) |
end |
if(eb.SolarBar) then |
eb.SolarBar:SetMinMaxValues(-maxPower, maxPower) |
eb.SolarBar:SetValue(power * -1) |
end |
if(eb.PostUpdatePower) then |
--[[ :PostUpdatePower(unit) |
Callback which is called after lunar and solar bar was updated. |
Arguments |
self - The widget that holds the eclipse frame. |
unit - The unit that has the widget. |
power - The unit's current power. |
maxPower - The unit's maximum power. |
]] |
return eb:PostUpdatePower(unit, power, maxPower) |
end |
end |
local UPDATE_VISIBILITY = function(self, event) |
local eb = self.EclipseBar |
-- check form/mastery |
local showBar |
local form = GetShapeshiftFormID() |
if(not form) then |
local ptt = GetSpecialization() |
if(ptt and ptt == 1) then -- player has balance spec |
showBar = true |
end |
elseif(form == MOONKIN_FORM) then |
showBar = true |
end |
if(UnitHasVehicleUI'player') then |
showBar = false |
end |
if(showBar) then |
eb:Show() |
else |
eb:Hide() |
end |
if(eb.PostUpdateVisibility) then |
--[[ :PostUpdateVisibility(unit) |
Callback which is called after the eclipse frame was shown or hidden. |
Arguments |
self - The widget that holds the eclipse frame. |
unit - The unit that has the widget. |
]] |
return eb:PostUpdateVisibility(self.unit) |
end |
end |
local UNIT_AURA = function(self, event, unit) |
if(self.unit ~= unit) then return end |
local eb = self.EclipseBar |
local hasSolarEclipse = not not UnitBuff(unit, ECLIPSE_BAR_SOLAR_BUFF) |
local hasLunarEclipse = not not UnitBuff(unit, ECLIPSE_BAR_LUNAR_BUFF) |
if(eb.hasSolarEclipse == hasSolarEclipse and eb.hasLunarEclipse == hasLunarEclipse) then return end |
eb.hasSolarEclipse = hasSolarEclipse |
eb.hasLunarEclipse = hasLunarEclipse |
if(eb.PostUnitAura) then |
--[[ :PostUnitAura(unit) |
Callback which is called after the eclipse state was checked. |
Arguments |
self - The widget that holds the eclipse frame. |
unit - The unit that has the widget. |
]] |
return eb:PostUnitAura(unit) |
end |
end |
local ECLIPSE_DIRECTION_CHANGE = function(self, event, direction) |
local eb = self.EclipseBar |
eb.directionIsLunar = direction == "moon" |
eb.direction = direction |
if(eb.PostDirectionChange) then |
--[[ :PostDirectionChange(unit) |
Callback which is called after eclipse direction was changed. |
Arguments |
self - The widget that holds the eclipse frame. |
unit - The unit that has the widget. |
]] |
return eb:PostDirectionChange(self.unit) |
end |
end |
local Update = function(self, event, ...) |
UNIT_POWER(self, event, ...) |
UNIT_AURA(self, event, ...) |
ECLIPSE_DIRECTION_CHANGE(self, event) |
return UPDATE_VISIBILITY(self, event) |
end |
local ForceUpdate = function(element) |
return Update(element.__owner, 'ForceUpdate', element.__owner.unit, 'ECLIPSE') |
end |
local function Enable(self) |
local eb = self.EclipseBar |
if(eb) then |
eb.__owner = self |
eb.ForceUpdate = ForceUpdate |
if(eb.LunarBar and eb.LunarBar:IsObjectType'StatusBar' and not eb.LunarBar:GetStatusBarTexture()) then |
eb.LunarBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]]) |
end |
if(eb.SolarBar and eb.SolarBar:IsObjectType'StatusBar' and not eb.SolarBar:GetStatusBarTexture()) then |
eb.SolarBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]]) |
end |
self:RegisterEvent('ECLIPSE_DIRECTION_CHANGE', ECLIPSE_DIRECTION_CHANGE, true) |
self:RegisterEvent('PLAYER_TALENT_UPDATE', UPDATE_VISIBILITY, true) |
self:RegisterEvent('UNIT_AURA', UNIT_AURA) |
self:RegisterEvent('UNIT_POWER_FREQUENT', UNIT_POWER) |
self:RegisterEvent('UPDATE_SHAPESHIFT_FORM', UPDATE_VISIBILITY, true) |
return true |
end |
end |
local function Disable(self) |
local eb = self.EclipseBar |
if(eb) then |
eb:Hide() |
self:UnregisterEvent('ECLIPSE_DIRECTION_CHANGE', ECLIPSE_DIRECTION_CHANGE) |
self:UnregisterEvent('PLAYER_TALENT_UPDATE', UPDATE_VISIBILITY) |
self:UnregisterEvent('UNIT_AURA', UNIT_AURA) |
self:UnregisterEvent('UNIT_POWER_FREQUENT', UNIT_POWER) |
self:UnregisterEvent('UPDATE_SHAPESHIFT_FORM', UPDATE_VISIBILITY) |
end |
end |
oUF:AddElement('EclipseBar', Update, Enable, Disable) |
--[[ Element: Totem Indicator |
Handles updating and visibility of Shaman totems, Druid mushrooms and Death |
Knight ghouls. |
Widget |
Totems - A table to hold sub-widgets. |
Sub-Widgets |
Totem - Any UI widget. |
.Icon - A Texture representing the totem icon. |
.Cooldown - A Cooldown representing the duration of the totem. |
Notes |
OnEnter and OnLeave will be set to display the default Tooltip, if the |
`Totem` widget is mouse enabled. |
Options |
:UpdateTooltip - The function that should populate the tooltip, when the |
`Totem` widget is hovered. A default function, which calls |
`:SetTotem(id)`, will be used if none is defined. |
Examples |
local Totems = {} |
for index = 1, MAX_TOTEMS do |
-- Position and size of the totem indicator |
local Totem = CreateFrame('Button', nil, self) |
Totem:SetSize(40, 40) |
Totem:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', index * Totem:GetWidth(), 0) |
local Icon = Totem:CreateTexture(nil, "OVERLAY") |
Icon:SetAllPoints() |
local Cooldown = CreateFrame("Cooldown", nil, Totem) |
Cooldown:SetAllPoints() |
Totem.Icon = Icon |
Totem.Cooldown = Cooldown |
Totems[index] = Totem |
end |
-- Register with oUF |
self.Totems = Totems |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
-- Order the list based upon the default UIs priorities. |
local priorities = STANDARD_TOTEM_PRIORITIES |
if(select(2, UnitClass'player') == 'SHAMAN') then |
priorities = SHAMAN_TOTEM_PRIORITIES |
end |
local UpdateTooltip = function(self) |
GameTooltip:SetTotem(self:GetID()) |
end |
local OnEnter = function(self) |
if(not self:IsVisible()) then return end |
GameTooltip:SetOwner(self, 'ANCHOR_BOTTOMRIGHT') |
self:UpdateTooltip() |
end |
local OnLeave = function() |
GameTooltip:Hide() |
end |
local UpdateTotem = function(self, event, slot) |
if(slot > MAX_TOTEMS) then return end |
local totems = self.Totems |
if(totems.PreUpdate) then totems:PreUpdate(priorities[slot]) end |
local totem = totems[priorities[slot]] |
local haveTotem, name, start, duration, icon = GetTotemInfo(slot) |
if(duration > 0) then |
if(totem.Icon) then |
totem.Icon:SetTexture(icon) |
end |
if(totem.Cooldown) then |
totem.Cooldown:SetCooldown(start, duration) |
end |
totem:Show() |
else |
totem:Hide() |
end |
if(totems.PostUpdate) then |
return totems:PostUpdate(priorities[slot], haveTotem, name, start, duration, icon) |
end |
end |
local Path = function(self, ...) |
return (self.Totems.Override or UpdateTotem) (self, ...) |
end |
local Update = function(self, event) |
for i = 1, MAX_TOTEMS do |
Path(self, event, i) |
end |
end |
local ForceUpdate = function(element) |
return Update(element.__owner, 'ForceUpdate') |
end |
local Enable = function(self) |
local totems = self.Totems |
if(totems) then |
totems.__owner = self |
totems.__map = { unpack(priorities) } |
totems.ForceUpdate = ForceUpdate |
for i = 1, MAX_TOTEMS do |
local totem = totems[i] |
totem:SetID(priorities[i]) |
if(totem:IsMouseEnabled()) then |
totem:SetScript('OnEnter', OnEnter) |
totem:SetScript('OnLeave', OnLeave) |
if(not totem.UpdateTooltip) then |
totem.UpdateTooltip = UpdateTooltip |
end |
end |
end |
self:RegisterEvent('PLAYER_TOTEM_UPDATE', Path, true) |
TotemFrame.Show = TotemFrame.Hide |
TotemFrame:Hide() |
TotemFrame:UnregisterEvent"PLAYER_TOTEM_UPDATE" |
TotemFrame:UnregisterEvent"PLAYER_ENTERING_WORLD" |
TotemFrame:UnregisterEvent"UPDATE_SHAPESHIFT_FORM" |
TotemFrame:UnregisterEvent"PLAYER_TALENT_UPDATE" |
return true |
end |
end |
local Disable = function(self) |
if(self.Totems) then |
for i = 1, MAX_TOTEMS do |
self.Totems[i]:Hide() |
end |
TotemFrame.Show = nil |
TotemFrame:Show() |
TotemFrame:RegisterEvent"PLAYER_TOTEM_UPDATE" |
TotemFrame:RegisterEvent"PLAYER_ENTERING_WORLD" |
TotemFrame:RegisterEvent"UPDATE_SHAPESHIFT_FORM" |
TotemFrame:RegisterEvent"PLAYER_TALENT_UPDATE" |
self:UnregisterEvent('PLAYER_TOTEM_UPDATE', Path) |
end |
end |
oUF:AddElement("Totems", Update, Enable, Disable) |
--[[ Element: Resting Icon |
Toggles visibility of the resting icon. |
Widget |
Resting - Any UI widget. |
Notes |
The default resting icon will be used if the UI widget is a texture and doesn't |
have a texture or color defined. |
Examples |
-- Position and size |
local Resting = self:CreateTexture(nil, 'OVERLAY') |
Resting:SetSize(16, 16) |
Resting:SetPoint('TOPLEFT', self) |
-- Register it with oUF |
self.Resting = Resting |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local Update = function(self, event) |
local resting = self.Resting |
if(resting.PreUpdate) then |
resting:PreUpdate() |
end |
local isResting = IsResting() |
if(isResting) then |
resting:Show() |
else |
resting:Hide() |
end |
if(resting.PostUpdate) then |
return resting:PostUpdate(isResting) |
end |
end |
local Path = function(self, ...) |
return (self.Resting.Override or Update) (self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate') |
end |
local Enable = function(self, unit) |
local resting = self.Resting |
if(resting and unit == 'player') then |
resting.__owner = self |
resting.ForceUpdate = ForceUpdate |
self:RegisterEvent("PLAYER_UPDATE_RESTING", Path, true) |
if(resting:IsObjectType"Texture" and not resting:GetTexture()) then |
resting:SetTexture[[Interface\CharacterFrame\UI-StateIcon]] |
resting:SetTexCoord(0, .5, 0, .421875) |
end |
return true |
end |
end |
local Disable = function(self) |
local resting = self.Resting |
if(resting) then |
resting:Hide() |
self:UnregisterEvent("PLAYER_UPDATE_RESTING", Path) |
end |
end |
oUF:AddElement('Resting', Path, Enable, Disable) |
--[[ Element: Resurrect Icon |
Handles updating and toggles visibility of incoming resurrect icon. |
Widget |
ResurrectIcon - A Texture used to display if the unit has an incoming |
resurrect. |
Notes |
The default resurrect icon will be used if the UI widget is a texture and |
doesn't have a texture or color defined. |
Examples |
-- Position and size |
local ResurrectIcon = self:CreateTexture(nil, 'OVERLAY') |
ResurrectIcon:SetSize(16, 16) |
ResurrectIcon:SetPoint('TOPRIGHT', self) |
-- Register it with oUF |
self.ResurrectIcon = ResurrectIcon |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local Update = function(self, event) |
local resurrect = self.ResurrectIcon |
if(resurrect.PreUpdate) then |
resurrect:PreUpdate() |
end |
local incomingResurrect = UnitHasIncomingResurrection(self.unit) |
if(incomingResurrect) then |
resurrect:Show() |
else |
resurrect:Hide() |
end |
if(resurrect.PostUpdate) then |
return resurrect:PostUpdate(incomingResurrect) |
end |
end |
local Path = function(self, ...) |
return (self.ResurrectIcon.Override or Update) (self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate') |
end |
local Enable = function(self) |
local resurrect = self.ResurrectIcon |
if(resurrect) then |
resurrect.__owner = self |
resurrect.ForceUpdate = ForceUpdate |
self:RegisterEvent('INCOMING_RESURRECT_CHANGED', Path, true) |
if(resurrect:IsObjectType('Texture') and not resurrect:GetTexture()) then |
resurrect:SetTexture[[Interface\RaidFrame\Raid-Icon-Rez]] |
end |
return true |
end |
end |
local Disable = function(self) |
local resurrect = self.ResurrectIcon |
if(resurrect) then |
self:UnregisterEvent('INCOMING_RESURRECT_CHANGED', Path) |
end |
end |
oUF:AddElement('ResurrectIcon', Path, Enable, Disable) |
--[[ Element: Castbar |
Handles updating and visibility of unit castbars. |
Widget |
Castbar - A StatusBar to represent spell progress. |
Sub-Widgets |
.Text - A FontString to represent spell name. |
.Icon - A Texture to represent spell icon. |
.Time - A FontString to represent spell duration. |
.Shield - A Texture to represent if it's possible to interrupt or spell |
steal. |
.SafeZone - A Texture to represent latency. |
Credits |
Based upon oUF_Castbar by starlon. |
Notes |
The default texture will be applied if the UI widget doesn't have a texture or |
color defined. |
Examples |
-- Position and size |
local Castbar = CreateFrame("StatusBar", nil, self) |
Castbar:SetSize(20, 20) |
Castbar:SetPoint('TOP') |
Castbar:SetPoint('LEFT') |
Castbar:SetPoint('RIGHT') |
-- Add a background |
local Background = Castbar:CreateTexture(nil, 'BACKGROUND') |
Background:SetAllPoints(Castbar) |
Background:SetTexture(1, 1, 1, .5) |
-- Add a spark |
local Spark = Castbar:CreateTexture(nil, "OVERLAY") |
Spark:SetSize(20, 20) |
Spark:SetBlendMode("ADD") |
-- Add a timer |
local Time = Castbar:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") |
Time:SetPoint("RIGHT", Castbar) |
-- Add spell text |
local Text = Castbar:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") |
Text:SetPoint("LEFT", Castbar) |
-- Add spell icon |
local Icon = Castbar:CreateTexture(nil, "OVERLAY") |
Icon:SetSize(20, 20) |
Icon:SetPoint("TOPLEFT", Castbar, "TOPLEFT") |
-- Add Shield |
local Shield = Castbar:CreateTexture(nil, "OVERLAY") |
Shield:SetSize(20, 20) |
Shield:SetPoint("CENTER", Castbar) |
-- Add safezone |
local SafeZone = Castbar:CreateTexture(nil, "OVERLAY") |
-- Register it with oUF |
self.Castbar = Castbar |
self.Castbar.bg = Background |
self.Castbar.Spark = Spark |
self.Castbar.Time = Time |
self.Castbar.Text = Text |
self.Castbar.Icon = Icon |
self.Castbar.SafeZone = SafeZone |
Hooks and Callbacks |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local UnitName = UnitName |
local GetTime = GetTime |
local UnitCastingInfo = UnitCastingInfo |
local UnitChannelInfo = UnitChannelInfo |
local updateSafeZone = function(self) |
local sz = self.SafeZone |
local width = self:GetWidth() |
local _, _, _, ms = GetNetStats() |
-- Guard against GetNetStats returning latencies of 0. |
if(ms ~= 0) then |
-- MADNESS! |
local safeZonePercent = (width / self.max) * (ms / 1e5) |
if(safeZonePercent > 1) then safeZonePercent = 1 end |
sz:SetWidth(width * safeZonePercent) |
sz:Show() |
else |
sz:Hide() |
end |
end |
local UNIT_SPELLCAST_START = function(self, event, unit, spell) |
if(self.unit ~= unit and self.realUnit ~= unit) then return end |
local castbar = self.Castbar |
local name, _, text, texture, startTime, endTime, _, castid, interrupt = UnitCastingInfo(unit) |
if(not name) then |
castbar:Hide() |
return |
end |
endTime = endTime / 1e3 |
startTime = startTime / 1e3 |
local max = endTime - startTime |
castbar.castid = castid |
castbar.duration = GetTime() - startTime |
castbar.max = max |
castbar.delay = 0 |
castbar.casting = true |
castbar.interrupt = interrupt |
castbar:SetMinMaxValues(0, max) |
castbar:SetValue(0) |
if(castbar.Text) then castbar.Text:SetText(text) end |
if(castbar.Icon) then castbar.Icon:SetTexture(texture) end |
if(castbar.Time) then castbar.Time:SetText() end |
local shield = castbar.Shield |
if(shield and interrupt) then |
shield:Show() |
elseif(shield) then |
shield:Hide() |
end |
local sf = castbar.SafeZone |
if(sf) then |
sf:ClearAllPoints() |
sf:SetPoint'RIGHT' |
sf:SetPoint'TOP' |
sf:SetPoint'BOTTOM' |
updateSafeZone(castbar) |
end |
if(castbar.PostCastStart) then |
castbar:PostCastStart(unit, name, castid) |
end |
castbar:Show() |
end |
local UNIT_SPELLCAST_FAILED = function(self, event, unit, spellname, _, castid) |
if(self.unit ~= unit and self.realUnit ~= unit) then return end |
local castbar = self.Castbar |
if(castbar.castid ~= castid) then |
return |
end |
castbar.casting = nil |
castbar.interrupt = nil |
castbar:SetValue(0) |
castbar:Hide() |
if(castbar.PostCastFailed) then |
return castbar:PostCastFailed(unit, spellname, castid) |
end |
end |
local UNIT_SPELLCAST_INTERRUPTED = function(self, event, unit, spellname, _, castid) |
if(self.unit ~= unit and self.realUnit ~= unit) then return end |
local castbar = self.Castbar |
if(castbar.castid ~= castid) then |
return |
end |
castbar.casting = nil |
castbar.channeling = nil |
castbar:SetValue(0) |
castbar:Hide() |
if(castbar.PostCastInterrupted) then |
return castbar:PostCastInterrupted(unit, spellname, castid) |
end |
end |
local UNIT_SPELLCAST_INTERRUPTIBLE = function(self, event, unit) |
if(self.unit ~= unit and self.realUnit ~= unit) then return end |
local shield = self.Castbar.Shield |
if(shield) then |
shield:Hide() |
end |
local castbar = self.Castbar |
if(castbar.PostCastInterruptible) then |
return castbar:PostCastInterruptible(unit) |
end |
end |
local UNIT_SPELLCAST_NOT_INTERRUPTIBLE = function(self, event, unit) |
if(self.unit ~= unit and self.realUnit ~= unit) then return end |
local shield = self.Castbar.Shield |
if(shield) then |
shield:Show() |
end |
local castbar = self.Castbar |
if(castbar.PostCastNotInterruptible) then |
return castbar:PostCastNotInterruptible(unit) |
end |
end |
local UNIT_SPELLCAST_DELAYED = function(self, event, unit, spellname, _, castid) |
if(self.unit ~= unit and self.realUnit ~= unit) then return end |
local castbar = self.Castbar |
local name, _, text, texture, startTime, endTime = UnitCastingInfo(unit) |
if(not startTime or not castbar:IsShown()) then return end |
local duration = GetTime() - (startTime / 1000) |
if(duration < 0) then duration = 0 end |
castbar.delay = castbar.delay + castbar.duration - duration |
castbar.duration = duration |
castbar:SetValue(duration) |
if(castbar.PostCastDelayed) then |
return castbar:PostCastDelayed(unit, name, castid) |
end |
end |
local UNIT_SPELLCAST_STOP = function(self, event, unit, spellname, _, castid) |
if(self.unit ~= unit and self.realUnit ~= unit) then return end |
local castbar = self.Castbar |
if(castbar.castid ~= castid) then |
return |
end |
castbar.casting = nil |
castbar.interrupt = nil |
castbar:SetValue(0) |
castbar:Hide() |
if(castbar.PostCastStop) then |
return castbar:PostCastStop(unit, spellname, castid) |
end |
end |
local UNIT_SPELLCAST_CHANNEL_START = function(self, event, unit, spellname) |
if(self.unit ~= unit and self.realUnit ~= unit) then return end |
local castbar = self.Castbar |
local name, _, text, texture, startTime, endTime, isTrade, interrupt = UnitChannelInfo(unit) |
if(not name) then |
return |
end |
endTime = endTime / 1e3 |
startTime = startTime / 1e3 |
local max = (endTime - startTime) |
local duration = endTime - GetTime() |
castbar.duration = duration |
castbar.max = max |
castbar.delay = 0 |
castbar.channeling = true |
castbar.interrupt = interrupt |
-- We have to do this, as it's possible for spell casts to never have _STOP |
-- executed or be fully completed by the OnUpdate handler before CHANNEL_START |
-- is called. |
castbar.casting = nil |
castbar.castid = nil |
castbar:SetMinMaxValues(0, max) |
castbar:SetValue(duration) |
if(castbar.Text) then castbar.Text:SetText(name) end |
if(castbar.Icon) then castbar.Icon:SetTexture(texture) end |
if(castbar.Time) then castbar.Time:SetText() end |
local shield = castbar.Shield |
if(shield and interrupt) then |
shield:Show() |
elseif(shield) then |
shield:Hide() |
end |
local sf = castbar.SafeZone |
if(sf) then |
sf:ClearAllPoints() |
sf:SetPoint'LEFT' |
sf:SetPoint'TOP' |
sf:SetPoint'BOTTOM' |
updateSafeZone(castbar) |
end |
if(castbar.PostChannelStart) then castbar:PostChannelStart(unit, name) end |
castbar:Show() |
end |
local UNIT_SPELLCAST_CHANNEL_UPDATE = function(self, event, unit, spellname) |
if(self.unit ~= unit and self.realUnit ~= unit) then return end |
local castbar = self.Castbar |
local name, _, text, texture, startTime, endTime, oldStart = UnitChannelInfo(unit) |
if(not name or not castbar:IsShown()) then |
return |
end |
local duration = (endTime / 1000) - GetTime() |
castbar.delay = castbar.delay + castbar.duration - duration |
castbar.duration = duration |
castbar.max = (endTime - startTime) / 1000 |
castbar:SetMinMaxValues(0, castbar.max) |
castbar:SetValue(duration) |
if(castbar.PostChannelUpdate) then |
return castbar:PostChannelUpdate(unit, name) |
end |
end |
local UNIT_SPELLCAST_CHANNEL_STOP = function(self, event, unit, spellname) |
if(self.unit ~= unit and self.realUnit ~= unit) then return end |
local castbar = self.Castbar |
if(castbar:IsShown()) then |
castbar.channeling = nil |
castbar.interrupt = nil |
castbar:SetValue(castbar.max) |
castbar:Hide() |
if(castbar.PostChannelStop) then |
return castbar:PostChannelStop(unit, spellname) |
end |
end |
end |
local onUpdate = function(self, elapsed) |
if(self.casting) then |
local duration = self.duration + elapsed |
if(duration >= self.max) then |
self.casting = nil |
self:Hide() |
if(self.PostCastStop) then self:PostCastStop(self.__owner.unit) end |
return |
end |
if(self.Time) then |
if(self.delay ~= 0) then |
if(self.CustomDelayText) then |
self:CustomDelayText(duration) |
else |
self.Time:SetFormattedText("%.1f|cffff0000-%.1f|r", duration, self.delay) |
end |
else |
if(self.CustomTimeText) then |
self:CustomTimeText(duration) |
else |
self.Time:SetFormattedText("%.1f", duration) |
end |
end |
end |
self.duration = duration |
self:SetValue(duration) |
if(self.Spark) then |
self.Spark:SetPoint("CENTER", self, "LEFT", (duration / self.max) * self:GetWidth(), 0) |
end |
elseif(self.channeling) then |
local duration = self.duration - elapsed |
if(duration <= 0) then |
self.channeling = nil |
self:Hide() |
if(self.PostChannelStop) then self:PostChannelStop(self.__owner.unit) end |
return |
end |
if(self.Time) then |
if(self.delay ~= 0) then |
if(self.CustomDelayText) then |
self:CustomDelayText(duration) |
else |
self.Time:SetFormattedText("%.1f|cffff0000-%.1f|r", duration, self.delay) |
end |
else |
if(self.CustomTimeText) then |
self:CustomTimeText(duration) |
else |
self.Time:SetFormattedText("%.1f", duration) |
end |
end |
end |
self.duration = duration |
self:SetValue(duration) |
if(self.Spark) then |
self.Spark:SetPoint("CENTER", self, "LEFT", (duration / self.max) * self:GetWidth(), 0) |
end |
else |
self.unitName = nil |
self.casting = nil |
self.castid = nil |
self.channeling = nil |
self:SetValue(1) |
self:Hide() |
end |
end |
local Update = function(self, ...) |
UNIT_SPELLCAST_START(self, ...) |
return UNIT_SPELLCAST_CHANNEL_START(self, ...) |
end |
local ForceUpdate = function(element) |
return Update(element.__owner, 'ForceUpdate', element.__owner.unit) |
end |
local Enable = function(object, unit) |
local castbar = object.Castbar |
if(castbar) then |
castbar.__owner = object |
castbar.ForceUpdate = ForceUpdate |
if(not (unit and unit:match'%wtarget$')) then |
object:RegisterEvent("UNIT_SPELLCAST_START", UNIT_SPELLCAST_START) |
object:RegisterEvent("UNIT_SPELLCAST_FAILED", UNIT_SPELLCAST_FAILED) |
object:RegisterEvent("UNIT_SPELLCAST_STOP", UNIT_SPELLCAST_STOP) |
object:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED", UNIT_SPELLCAST_INTERRUPTED) |
object:RegisterEvent("UNIT_SPELLCAST_INTERRUPTIBLE", UNIT_SPELLCAST_INTERRUPTIBLE) |
object:RegisterEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE", UNIT_SPELLCAST_NOT_INTERRUPTIBLE) |
object:RegisterEvent("UNIT_SPELLCAST_DELAYED", UNIT_SPELLCAST_DELAYED) |
object:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START", UNIT_SPELLCAST_CHANNEL_START) |
object:RegisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE", UNIT_SPELLCAST_CHANNEL_UPDATE) |
object:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP", UNIT_SPELLCAST_CHANNEL_STOP) |
end |
castbar:SetScript("OnUpdate", castbar.OnUpdate or onUpdate) |
if(object.unit == "player") then |
CastingBarFrame:UnregisterAllEvents() |
CastingBarFrame.Show = CastingBarFrame.Hide |
CastingBarFrame:Hide() |
elseif(object.unit == 'pet') then |
PetCastingBarFrame:UnregisterAllEvents() |
PetCastingBarFrame.Show = PetCastingBarFrame.Hide |
PetCastingBarFrame:Hide() |
end |
if(castbar:IsObjectType'StatusBar' and not castbar:GetStatusBarTexture()) then |
castbar:SetStatusBarTexture[[Interface\TargetingFrame\UI-StatusBar]] |
end |
local spark = castbar.Spark |
if(spark and spark:IsObjectType'Texture' and not spark:GetTexture()) then |
spark:SetTexture[[Interface\CastingBar\UI-CastingBar-Spark]] |
end |
local shield = castbar.Shield |
if(shield and shield:IsObjectType'Texture' and not shield:GetTexture()) then |
shield:SetTexture[[Interface\CastingBar\UI-CastingBar-Small-Shield]] |
end |
local sz = castbar.SafeZone |
if(sz and sz:IsObjectType'Texture' and not sz:GetTexture()) then |
sz:SetTexture(1, 0, 0) |
end |
castbar:Hide() |
return true |
end |
end |
local Disable = function(object, unit) |
local castbar = object.Castbar |
if(castbar) then |
castbar:Hide() |
object:UnregisterEvent("UNIT_SPELLCAST_START", UNIT_SPELLCAST_START) |
object:UnregisterEvent("UNIT_SPELLCAST_FAILED", UNIT_SPELLCAST_FAILED) |
object:UnregisterEvent("UNIT_SPELLCAST_STOP", UNIT_SPELLCAST_STOP) |
object:UnregisterEvent("UNIT_SPELLCAST_INTERRUPTED", UNIT_SPELLCAST_INTERRUPTED) |
object:UnregisterEvent("UNIT_SPELLCAST_INTERRUPTIBLE", UNIT_SPELLCAST_INTERRUPTIBLE) |
object:UnregisterEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE", UNIT_SPELLCAST_NOT_INTERRUPTIBLE) |
object:UnregisterEvent("UNIT_SPELLCAST_DELAYED", UNIT_SPELLCAST_DELAYED) |
object:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_START", UNIT_SPELLCAST_CHANNEL_START) |
object:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE", UNIT_SPELLCAST_CHANNEL_UPDATE) |
object:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_STOP", UNIT_SPELLCAST_CHANNEL_STOP) |
castbar:SetScript("OnUpdate", nil) |
end |
end |
oUF:AddElement('Castbar', Update, Enable, Disable) |
--[[ Element: Combo Point Icons |
Toggles visibility of the player and vehicles combo points. |
Widget |
CPoints - An array consisting of five UI widgets. |
Notes |
The default combo point texture will be applied to textures within the CPoints |
array that don't have a texture or color defined. |
Examples |
local CPoints = {} |
for index = 1, MAX_COMBO_POINTS do |
local CPoint = self:CreateTexture(nil, 'BACKGROUND') |
-- Position and size of the combo point. |
CPoint:SetSize(12, 16) |
CPoint:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', index * CPoint:GetWidth(), 0) |
CPoints[index] = CPoint |
end |
-- Register with oUF |
self.CPoints = CPoints |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local GetComboPoints = GetComboPoints |
local MAX_COMBO_POINTS = MAX_COMBO_POINTS |
local Update = function(self, event, unit) |
if(unit == 'pet') then return end |
local cpoints = self.CPoints |
if(cpoints.PreUpdate) then |
cpoints:PreUpdate() |
end |
local cp |
if(UnitHasVehicleUI'player') then |
cp = GetComboPoints('vehicle', 'target') |
else |
cp = GetComboPoints('player', 'target') |
end |
for i=1, MAX_COMBO_POINTS do |
if(i <= cp) then |
cpoints[i]:Show() |
else |
cpoints[i]:Hide() |
end |
end |
if(cpoints.PostUpdate) then |
return cpoints:PostUpdate(cp) |
end |
end |
local Path = function(self, ...) |
return (self.CPoints.Override or Update) (self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate', element.__owner.unit) |
end |
local Enable = function(self) |
local cpoints = self.CPoints |
if(cpoints) then |
cpoints.__owner = self |
cpoints.ForceUpdate = ForceUpdate |
self:RegisterEvent('UNIT_COMBO_POINTS', Path, true) |
self:RegisterEvent('PLAYER_TARGET_CHANGED', Path, true) |
for index = 1, MAX_COMBO_POINTS do |
local cpoint = cpoints[index] |
if(cpoint:IsObjectType'Texture' and not cpoint:GetTexture()) then |
cpoint:SetTexture[[Interface\ComboFrame\ComboPoint]] |
cpoint:SetTexCoord(0, 0.375, 0, 1) |
end |
end |
return true |
end |
end |
local Disable = function(self) |
local cpoints = self.CPoints |
if(cpoints) then |
for index = 1, MAX_COMBO_POINTS do |
cpoints[index]:Hide() |
end |
self:UnregisterEvent('UNIT_COMBO_POINTS', Path) |
self:UnregisterEvent('PLAYER_TARGET_CHANGED', Path) |
end |
end |
oUF:AddElement('CPoints', Path, Enable, Disable) |
--[[ Element: Master Looter Icon |
Toggles visibility of the master looter icon. |
Widget |
MasterLooter - Any UI widget. |
Notes |
The default master looter icon will be applied if the UI widget is a texture |
and doesn't have a texture or color defined. |
Examples |
-- Position and size |
local MasterLooter = self:CreateTexture(nil, 'OVERLAY') |
MasterLooter:SetSize(16, 16) |
MasterLooter:SetPoint('TOPRIGHT', self) |
-- Register it with oUF |
self.MasterLooter = MasterLooter |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local Update = function(self, event) |
local unit = self.unit |
local masterlooter = self.MasterLooter |
if(not (UnitInParty(unit) or UnitInRaid(unit))) then |
return masterlooter:Hide() |
end |
if(masterlooter.PreUpdate) then |
masterlooter:PreUpdate() |
end |
local method, pid, rid = GetLootMethod() |
if(method == 'master') then |
local mlUnit |
if(pid) then |
if(pid == 0) then |
mlUnit = 'player' |
else |
mlUnit = 'party'..pid |
end |
elseif(rid) then |
mlUnit = 'raid'..rid |
end |
if(UnitIsUnit(unit, mlUnit)) then |
masterlooter:Show() |
elseif(masterlooter:IsShown()) then |
masterlooter:Hide() |
end |
else |
masterlooter:Hide() |
end |
if(masterlooter.PostUpdate) then |
return masterlooter:PostUpdate(masterlooter:IsShown()) |
end |
end |
local Path = function(self, ...) |
return (self.MasterLooter.Override or Update) (self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate') |
end |
local function Enable(self, unit) |
local masterlooter = self.MasterLooter |
if(masterlooter) then |
masterlooter.__owner = self |
masterlooter.ForceUpdate = ForceUpdate |
self:RegisterEvent('PARTY_LOOT_METHOD_CHANGED', Path, true) |
self:RegisterEvent('GROUP_ROSTER_UPDATE', Path, true) |
if(masterlooter:IsObjectType('Texture') and not masterlooter:GetTexture()) then |
masterlooter:SetTexture([[Interface\GroupFrame\UI-Group-MasterLooter]]) |
end |
return true |
end |
end |
local function Disable(self) |
if(self.MasterLooter) then |
self.MasterLooter:Hide() |
self:UnregisterEvent('PARTY_LOOT_METHOD_CHANGED', Path) |
self:UnregisterEvent('GROUP_ROSTER_UPDATE', Path) |
end |
end |
oUF:AddElement('MasterLooter', Path, Enable, Disable) |
--[[ Element: Alternative Power Bar |
Handles visibility and updating of the alternative power bar. |
This bar is used to display encounter/quest related power information, such as |
the number of hour glass uses left on the end boss in End Time. |
Widget |
AltPowerBar - A StatusBar to represent alternative power. |
Options |
.colorTexture - Use the vertex color values returned by |
UnitAlternatePowerTextureInfo to color the bar. |
Notes |
OnEnter and OnLeave handlers to display a tooltip will be set on the widget if |
it is mouse enabled. |
Examples |
-- Position and size |
local AltPowerBar = CreateFrame('StatusBar', nil, self) |
AltPowerBar:SetHeight(20) |
AltPowerBar:SetPoint('BOTTOM') |
AltPowerBar:SetPoint('LEFT') |
AltPowerBar:SetPoint('RIGHT') |
-- Register with oUF |
self.AltPowerBar = AltPowerBar |
Callbacks |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local ALTERNATE_POWER_INDEX = ALTERNATE_POWER_INDEX |
--[[ :UpdateTooltip() |
The function called when the widget is hovered. Used to populate the tooltip. |
Arguments |
self - The AltPowerBar element. |
]] |
local UpdateTooltip = function(self) |
GameTooltip:SetText(self.powerName, 1, 1, 1) |
GameTooltip:AddLine(self.powerTooltip, nil, nil, nil, 1) |
GameTooltip:Show() |
end |
local OnEnter = function(self) |
if(not self:IsVisible()) then return end |
GameTooltip_SetDefaultAnchor(GameTooltip, self) |
self:UpdateTooltip() |
end |
local OnLeave = function() |
GameTooltip:Hide() |
end |
local UpdatePower = function(self, event, unit, powerType) |
if(self.unit ~= unit or powerType ~= 'ALTERNATE') then return end |
local altpowerbar = self.AltPowerBar |
--[[ :PreUpdate() |
Called before the element has been updated. |
Arguments |
self - The AltPowerBar element. |
]] |
if(altpowerbar.PreUpdate) then |
altpowerbar:PreUpdate() |
end |
local _, r, g, b |
if(altpowerbar.colorTexture) then |
_, r, g, b = UnitAlternatePowerTextureInfo(unit, 2) |
end |
local cur = UnitPower(unit, ALTERNATE_POWER_INDEX) |
local max = UnitPowerMax(unit, ALTERNATE_POWER_INDEX) |
local barType, min, _, _, _, _, _, _, _, powerName, powerTooltip = UnitAlternatePowerInfo(unit) |
altpowerbar.barType = barType |
altpowerbar.powerName = powerName |
altpowerbar.powerTooltip = powerTooltip |
altpowerbar:SetMinMaxValues(min, max) |
altpowerbar:SetValue(math.min(math.max(cur, min), max)) |
if(b) then |
altpowerbar:SetStatusBarColor(r, g, b) |
end |
--[[ :PostUpdate(min, cur, max) |
Called after the element has been updated. |
Arguments |
self - The AltPowerBar element. |
min - The minimum possible power value for the active type. |
cur - The current power value. |
max - The maximum possible power value for the active type. |
]] |
if(altpowerbar.PostUpdate) then |
return altpowerbar:PostUpdate(min, cur, max) |
end |
end |
--[[ Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local Path = function(self, ...) |
return (self.AltPowerBar.Override or UpdatePower)(self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate', element.__owner.unit, 'ALTERNATE') |
end |
local Toggler = function(self, event, unit) |
if(unit ~= self.unit) then return end |
local altpowerbar = self.AltPowerBar |
local barType, _, _, _, _, hideFromOthers, showOnRaid = UnitAlternatePowerInfo(unit) |
if(barType and (showOnRaid and (UnitInParty(unit) or UnitInRaid(unit)) or not hideFromOthers or unit == 'player' or self.realUnit == 'player')) then |
self:RegisterEvent('UNIT_POWER', Path) |
self:RegisterEvent('UNIT_MAXPOWER', Path) |
ForceUpdate(altpowerbar) |
altpowerbar:Show() |
else |
self:UnregisterEvent('UNIT_POWER', Path) |
self:UnregisterEvent('UNIT_MAXPOWER', Path) |
altpowerbar:Hide() |
end |
end |
local Enable = function(self, unit) |
local altpowerbar = self.AltPowerBar |
if(altpowerbar) then |
altpowerbar.__owner = self |
altpowerbar.ForceUpdate = ForceUpdate |
self:RegisterEvent('UNIT_POWER_BAR_SHOW', Toggler) |
self:RegisterEvent('UNIT_POWER_BAR_HIDE', Toggler) |
altpowerbar:Hide() |
if(altpowerbar:IsMouseEnabled()) then |
if(not altpowerbar:GetScript('OnEnter')) then |
altpowerbar:SetScript('OnEnter', OnEnter) |
end |
altpowerbar:SetScript('OnLeave', OnLeave) |
if(not altpowerbar.UpdateTooltip) then |
altpowerbar.UpdateTooltip = UpdateTooltip |
end |
end |
if(unit == 'player') then |
PlayerPowerBarAlt:UnregisterEvent'UNIT_POWER_BAR_SHOW' |
PlayerPowerBarAlt:UnregisterEvent'UNIT_POWER_BAR_HIDE' |
PlayerPowerBarAlt:UnregisterEvent'PLAYER_ENTERING_WORLD' |
end |
return true |
end |
end |
local Disable = function(self, unit) |
local altpowerbar = self.AltPowerBar |
if(altpowerbar) then |
altpowerbar:Hide() |
self:UnregisterEvent('UNIT_POWER_BAR_SHOW', Toggler) |
self:UnregisterEvent('UNIT_POWER_BAR_HIDE', Toggler) |
if(unit == 'player') then |
PlayerPowerBarAlt:RegisterEvent'UNIT_POWER_BAR_SHOW' |
PlayerPowerBarAlt:RegisterEvent'UNIT_POWER_BAR_HIDE' |
PlayerPowerBarAlt:RegisterEvent'PLAYER_ENTERING_WORLD' |
end |
end |
end |
oUF:AddElement('AltPowerBar', Toggler, Enable, Disable) |
--[[ Element: Threat Icon |
Handles updating and toggles visibility of current threat level icon. |
Widget |
Threat - A Texture used to display the current threat level. |
Notes |
This element updates by changing colors of the texture. |
The default threat icon will be used if the UI widget is a texture and doesn't |
have a texture or color defined. |
Examples |
-- Position and size |
local Threat = self:CreateTexture(nil, 'OVERLAY') |
Threat:SetSize(16, 16) |
Threat:SetPoint('TOPRIGHT', self) |
-- Register it with oUF |
self.Threat = Threat |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local Update = function(self, event, unit) |
if(unit ~= self.unit) then return end |
local threat = self.Threat |
if(threat.PreUpdate) then threat:PreUpdate(unit) end |
unit = unit or self.unit |
local status = UnitThreatSituation(unit) |
local r, g, b |
if(status and status > 0) then |
r, g, b = GetThreatStatusColor(status) |
threat:SetVertexColor(r, g, b) |
threat:Show() |
else |
threat:Hide() |
end |
if(threat.PostUpdate) then |
return threat:PostUpdate(unit, status, r, g, b) |
end |
end |
local Path = function(self, ...) |
return (self.Threat.Override or Update) (self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate', element.__owner.unit) |
end |
local Enable = function(self) |
local threat = self.Threat |
if(threat) then |
threat.__owner = self |
threat.ForceUpdate = ForceUpdate |
self:RegisterEvent("UNIT_THREAT_SITUATION_UPDATE", Path) |
if(threat:IsObjectType"Texture" and not threat:GetTexture()) then |
threat:SetTexture[[Interface\Minimap\ObjectIcons]] |
threat:SetTexCoord(6/8, 7/8, 1/8, 2/8) |
end |
return true |
end |
end |
local Disable = function(self) |
local threat = self.Threat |
if(threat) then |
threat:Hide() |
self:UnregisterEvent("UNIT_THREAT_SITUATION_UPDATE", Path) |
end |
end |
oUF:AddElement('Threat', Path, Enable, Disable) |
--[[ Element: LFD Role Icon |
Toggles visibility of the LFD role icon based upon the units current dungeon |
role. |
Widget |
LFDRole - A Texture containing the LFD role icons at specific locations. Look |
at the default LFD role icon texture for an example of this. |
Alternatively you can look at the return values of |
GetTexCoordsForRoleSmallCircle(role). |
Notes |
The default LFD role texture will be applied if the UI widget is a texture and |
doesn't have a texture or color defined. |
Examples |
-- Position and size |
local LFDRole = self:CreateTexture(nil, "OVERLAY") |
LFDRole:SetSize(16, 16) |
LFDRole:SetPoint("LEFT", self) |
-- Register it with oUF |
self.LFDRole = LFDRole |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local Update = function(self, event) |
local lfdrole = self.LFDRole |
if(lfdrole.PreUpdate) then |
lfdrole:PreUpdate() |
end |
local role = UnitGroupRolesAssigned(self.unit) |
if(role == 'TANK' or role == 'HEALER' or role == 'DAMAGER') then |
lfdrole:SetTexCoord(GetTexCoordsForRoleSmallCircle(role)) |
lfdrole:Show() |
else |
lfdrole:Hide() |
end |
if(lfdrole.PostUpdate) then |
return lfdrole:PostUpdate(role) |
end |
end |
local Path = function(self, ...) |
return (self.LFDRole.Override or Update) (self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate') |
end |
local Enable = function(self) |
local lfdrole = self.LFDRole |
if(lfdrole) then |
lfdrole.__owner = self |
lfdrole.ForceUpdate = ForceUpdate |
if(self.unit == "player") then |
self:RegisterEvent("PLAYER_ROLES_ASSIGNED", Path, true) |
else |
self:RegisterEvent("GROUP_ROSTER_UPDATE", Path, true) |
end |
if(lfdrole:IsObjectType"Texture" and not lfdrole:GetTexture()) then |
lfdrole:SetTexture[[Interface\LFGFrame\UI-LFG-ICON-PORTRAITROLES]] |
end |
return true |
end |
end |
local Disable = function(self) |
local lfdrole = self.LFDRole |
if(lfdrole) then |
lfdrole:Hide() |
self:UnregisterEvent("PLAYER_ROLES_ASSIGNED", Path) |
self:UnregisterEvent("GROUP_ROSTER_UPDATE", Path) |
end |
end |
oUF:AddElement('LFDRole', Path, Enable, Disable) |
--[[ Element: Portraits |
Handles updating of the unit's portrait. |
Widget |
Portrait - A PlayerModel or Texture used to represent the unit's portrait. |
Notes |
The quest delivery question mark will be used instead of the unit's model when |
the client doesn't have the model information for the unit. |
Examples |
-- 3D Portrait |
-- Position and size |
local Portrait = CreateFrame('PlayerModel', nil, self) |
Portrait:SetSize(32, 32) |
Portrait:SetPoint('RIGHT', self, 'LEFT') |
-- Register it with oUF |
self.Portrait = Portrait |
-- 2D Portrait |
local Portrait = self:CreateTexture(nil, 'OVERLAY') |
Portrait:SetSize(32, 32) |
Portrait:SetPoint('RIGHT', self, 'LEFT') |
-- Register it with oUF |
self.Portrait = Portrait |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local Update = function(self, event, unit) |
if(not unit or not UnitIsUnit(self.unit, unit)) then return end |
local portrait = self.Portrait |
if(portrait.PreUpdate) then portrait:PreUpdate(unit) end |
if(portrait:IsObjectType'Model') then |
local guid = UnitGUID(unit) |
if(not UnitExists(unit) or not UnitIsConnected(unit) or not UnitIsVisible(unit)) then |
portrait:SetCamDistanceScale(0.25) |
portrait:SetPortraitZoom(0) |
portrait:SetPosition(0,0,0.5) |
portrait:ClearModel() |
portrait:SetModel('interface\\buttons\\talktomequestionmark.m2') |
portrait.guid = nil |
elseif(portrait.guid ~= guid or event == 'UNIT_MODEL_CHANGED') then |
portrait:SetCamDistanceScale(1) |
portrait:SetPortraitZoom(1) |
portrait:SetPosition(0,0,0) |
portrait:ClearModel() |
portrait:SetUnit(unit) |
portrait.guid = guid |
end |
else |
SetPortraitTexture(portrait, unit) |
end |
if(portrait.PostUpdate) then |
return portrait:PostUpdate(unit) |
end |
end |
local Path = function(self, ...) |
return (self.Portrait.Override or Update) (self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate', element.__owner.unit) |
end |
local Enable = function(self, unit) |
local portrait = self.Portrait |
if(portrait) then |
portrait:Show() |
portrait.__owner = self |
portrait.ForceUpdate = ForceUpdate |
self:RegisterEvent("UNIT_PORTRAIT_UPDATE", Path) |
self:RegisterEvent("UNIT_MODEL_CHANGED", Path) |
self:RegisterEvent('UNIT_CONNECTION', Path) |
-- The quest log uses PARTY_MEMBER_{ENABLE,DISABLE} to handle updating of |
-- party members overlapping quests. This will probably be enough to handle |
-- model updating. |
-- |
-- DISABLE isn't used as it fires when we most likely don't have the |
-- information we want. |
if(unit == 'party') then |
self:RegisterEvent('PARTY_MEMBER_ENABLE', Path) |
end |
return true |
end |
end |
local Disable = function(self) |
local portrait = self.Portrait |
if(portrait) then |
portrait:Hide() |
self:UnregisterEvent("UNIT_PORTRAIT_UPDATE", Path) |
self:UnregisterEvent("UNIT_MODEL_CHANGED", Path) |
self:UnregisterEvent('PARTY_MEMBER_ENABLE', Path) |
self:UnregisterEvent('UNIT_CONNECTION', Path) |
end |
end |
oUF:AddElement('Portrait', Path, Enable, Disable) |
--[[ Element: Auras |
Handles creation and updating of aura icons. |
Widget |
Auras - A Frame to hold icons representing both buffs and debuffs. |
Buffs - A Frame to hold icons representing buffs. |
Debuffs - A Frame to hold icons representing debuffs. |
Options |
.disableCooldown - Disables the cooldown spiral. Defaults to false. |
.size - Aura icon size. Defaults to 16. |
.onlyShowPlayer - Only show auras created by player/vehicle. |
.showStealableBuffs - Display the stealable texture on buffs that can be |
stolen. |
.spacing - Spacing between each icon. Defaults to 0. |
.['spacing-x'] - Horizontal spacing between each icon. Takes priority over |
`spacing`. |
.['spacing-y'] - Vertical spacing between each icon. Takes priority over |
`spacing`. |
.['growth-x'] - Horizontal growth direction. Defaults to RIGHT. |
.['growth-y'] - Vertical growth direction. Defaults to UP. |
.initialAnchor - Anchor point for the icons. Defaults to BOTTOMLEFT. |
.filter - Custom filter list for auras to display. Defaults to |
HELPFUL on buffs and HARMFUL on debuffs. |
Options Auras |
.numBuffs - The maximum number of buffs to display. Defaults to 32. |
.numDebuffs - The maximum number of debuffs to display. Defaults to 40. |
.gap - Controls the creation of an invisible icon between buffs and |
debuffs. Defaults to false. |
.buffFilter - Custom filter list for buffs to display. Takes priority over |
`filter`. |
.debuffFilter - Custom filter list for debuffs to display. Takes priority over |
`filter`. |
Options Buffs |
.num - Number of buffs to display. Defaults to 32. |
Options Debuffs |
.num - Number of debuffs to display. Defaults to 40. |
Examples |
-- Position and size |
local Buffs = CreateFrame("Frame", nil, self) |
Buffs:SetPoint("RIGHT", self, "LEFT") |
Buffs:SetSize(16 * 2, 16 * 16) |
-- Register with oUF |
self.Buffs = Buffs |
Hooks and Callbacks |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local VISIBLE = 1 |
local HIDDEN = 0 |
local UpdateTooltip = function(self) |
GameTooltip:SetUnitAura(self:GetParent().__owner.unit, self:GetID(), self.filter) |
end |
local OnEnter = function(self) |
if(not self:IsVisible()) then return end |
GameTooltip:SetOwner(self, "ANCHOR_BOTTOMRIGHT") |
self:UpdateTooltip() |
end |
local OnLeave = function() |
GameTooltip:Hide() |
end |
local createAuraIcon = function(icons, index) |
icons.createdIcons = icons.createdIcons + 1 |
local button = CreateFrame("Button", nil, icons) |
button:RegisterForClicks'RightButtonUp' |
local cd = CreateFrame("Cooldown", nil, button, "CooldownFrameTemplate") |
cd:SetAllPoints(button) |
local icon = button:CreateTexture(nil, "BORDER") |
icon:SetAllPoints(button) |
local count = button:CreateFontString(nil, "OVERLAY") |
count:SetFontObject(NumberFontNormal) |
count:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", -1, 0) |
local overlay = button:CreateTexture(nil, "OVERLAY") |
overlay:SetTexture"Interface\\Buttons\\UI-Debuff-Overlays" |
overlay:SetAllPoints(button) |
overlay:SetTexCoord(.296875, .5703125, 0, .515625) |
button.overlay = overlay |
local stealable = button:CreateTexture(nil, 'OVERLAY') |
stealable:SetTexture[[Interface\TargetingFrame\UI-TargetingFrame-Stealable]] |
stealable:SetPoint('TOPLEFT', -3, 3) |
stealable:SetPoint('BOTTOMRIGHT', 3, -3) |
stealable:SetBlendMode'ADD' |
button.stealable = stealable |
button.UpdateTooltip = UpdateTooltip |
button:SetScript("OnEnter", OnEnter) |
button:SetScript("OnLeave", OnLeave) |
table.insert(icons, button) |
button.icon = icon |
button.count = count |
button.cd = cd |
--[[ :PostCreateIcon(button) |
Callback which is called after a new aura icon button has been created. |
Arguments |
button - The newly created aura icon button. |
]] |
if(icons.PostCreateIcon) then icons:PostCreateIcon(button) end |
return button |
end |
local customFilter = function(icons, unit, icon, name, rank, texture, count, dtype, duration, timeLeft, caster) |
if((icons.onlyShowPlayer and icon.isPlayer) or (not icons.onlyShowPlayer and name)) then |
return true |
end |
end |
local updateIcon = function(unit, icons, index, offset, filter, isDebuff, visible) |
local name, rank, texture, count, dtype, duration, timeLeft, caster, isStealable, shouldConsolidate, spellID, canApplyAura, isBossDebuff = UnitAura(unit, index, filter) |
if(name) then |
local n = visible + offset + 1 |
local icon = icons[n] |
if(not icon) then |
--[[ :CreateIcon(index) |
A function which creates the aura icon for a given index. |
Arguments |
index - The offset the icon should be created at. |
Returns |
A button used to represent aura icons. |
]] |
icon = (icons.CreateIcon or createAuraIcon) (icons, n) |
end |
local isPlayer |
if(caster == 'player' or caster == 'vehicle') then |
isPlayer = true |
end |
icon.owner = caster |
icon.filter = filter |
icon.isDebuff = isDebuff |
icon.isPlayer = isPlayer |
--[[ :CustomFilter(unit, icon, ...) |
Defines a custom filter which controls if the aura icon should be shown |
or not. |
Arguments |
self - The widget that holds the aura icon. |
unit - The unit that has the aura. |
icon - The button displaying the aura. |
... - The return values from |
[UnitAura](http://wowprogramming.com/docs/api/UnitAura). |
Returns |
A boolean value telling the aura element if it should be show the icon |
or not. |
]] |
local show = (icons.CustomFilter or customFilter) (icons, unit, icon, name, rank, texture, count, dtype, duration, timeLeft, caster, isStealable, shouldConsolidate, spellID, canApplyAura, isBossDebuff) |
if(show) then |
-- We might want to consider delaying the creation of an actual cooldown |
-- object to this point, but I think that will just make things needlessly |
-- complicated. |
local cd = icon.cd |
if(cd and not icons.disableCooldown) then |
if(duration and duration > 0) then |
cd:SetCooldown(timeLeft - duration, duration) |
cd:Show() |
else |
cd:Hide() |
end |
end |
if((isDebuff and icons.showDebuffType) or (not isDebuff and icons.showBuffType) or icons.showType) then |
local color = DebuffTypeColor[dtype] or DebuffTypeColor.none |
icon.overlay:SetVertexColor(color.r, color.g, color.b) |
icon.overlay:Show() |
else |
icon.overlay:Hide() |
end |
local stealable = not isDebuff and isStealable |
if(stealable and icons.showStealableBuffs and not UnitIsUnit('player', unit)) then |
icon.stealable:Show() |
else |
icon.stealable:Hide() |
end |
icon.icon:SetTexture(texture) |
icon.count:SetText((count > 1 and count)) |
local size = icons.size or 16 |
icon:SetSize(size, size) |
icon:EnableMouse(true) |
icon:SetID(index) |
icon:Show() |
--[[ :PostUpdateIcon(unit, icon, index, offest) |
Callback which is called after the aura icon was updated. |
Arguments |
self - The widget that holds the aura icon. |
unit - The unit that has the aura. |
icon - The button that was updated. |
index - The index of the aura. |
offset - The offset the button was created at. |
]] |
if(icons.PostUpdateIcon) then |
icons:PostUpdateIcon(unit, icon, index, n) |
end |
return VISIBLE |
else |
return HIDDEN |
end |
end |
end |
--[[ :SetPosition(from, to) |
Function used to (re-)anchor aura icons. This function is only called when |
new aura icons have been created or if :PreSetPosition is defined. |
Arguments |
self - The widget that holds the aura icons. |
from - The aura icon before the new aura icon. |
to - The current number of created icons. |
]] |
local SetPosition = function(icons, from, to) |
local sizex = (icons.size or 16) + (icons['spacing-x'] or icons.spacing or 0) |
local sizey = (icons.size or 16) + (icons['spacing-y'] or icons.spacing or 0) |
local anchor = icons.initialAnchor or "BOTTOMLEFT" |
local growthx = (icons["growth-x"] == "LEFT" and -1) or 1 |
local growthy = (icons["growth-y"] == "DOWN" and -1) or 1 |
local cols = math.floor(icons:GetWidth() / sizex + .5) |
for i = from, to do |
local button = icons[i] |
-- Bail out if the to range is out of scope. |
if(not button) then break end |
local col = (i - 1) % cols |
local row = math.floor((i - 1) / cols) |
button:ClearAllPoints() |
button:SetPoint(anchor, icons, anchor, col * sizex * growthx, row * sizey * growthy) |
end |
end |
local filterIcons = function(unit, icons, filter, limit, isDebuff, offset, dontHide) |
if(not offset) then offset = 0 end |
local index = 1 |
local visible = 0 |
local hidden = 0 |
while(visible < limit) do |
local result = updateIcon(unit, icons, index, offset, filter, isDebuff, visible) |
if(not result) then |
break |
elseif(result == VISIBLE) then |
visible = visible + 1 |
elseif(result == HIDDEN) then |
hidden = hidden + 1 |
end |
index = index + 1 |
end |
if(not dontHide) then |
for i = visible + offset + 1, #icons do |
icons[i]:Hide() |
end |
end |
return visible, hidden |
end |
local UpdateAuras = function(self, event, unit) |
if(self.unit ~= unit) then return end |
local auras = self.Auras |
if(auras) then |
if(auras.PreUpdate) then auras:PreUpdate(unit) end |
local numBuffs = auras.numBuffs or 32 |
local numDebuffs = auras.numDebuffs or 40 |
local max = numBuffs + numDebuffs |
local visibleBuffs, hiddenBuffs = filterIcons(unit, auras, auras.buffFilter or auras.filter or 'HELPFUL', numBuffs, nil, 0, true) |
local hasGap |
if(visibleBuffs ~= 0 and auras.gap) then |
hasGap = true |
visibleBuffs = visibleBuffs + 1 |
local icon = auras[visibleBuffs] or (auras.CreateIcon or createAuraIcon) (auras, visibleBuffs) |
-- Prevent the icon from displaying anything. |
if(icon.cd) then icon.cd:Hide() end |
icon:EnableMouse(false) |
icon.icon:SetTexture() |
icon.overlay:Hide() |
icon.stealable:Hide() |
icon.count:SetText() |
icon:Show() |
--[[ :PostUpdateGapIcon(unit, icon, visibleBuffs) |
Callback which is called after an invisible aura icon has been |
created. This is only used by Auras when the `gap` option is enabled. |
Arguments |
self - The widget that holds the aura icon. |
unit - The unit that has the aura icon. |
icon - The invisible aura icon / gap. |
visibleBuffs - The number of currently visible buffs. |
]] |
if(auras.PostUpdateGapIcon) then |
auras:PostUpdateGapIcon(unit, icon, visibleBuffs) |
end |
end |
local visibleDebuffs, hiddenDebuffs = filterIcons(unit, auras, auras.debuffFilter or auras.filter or 'HARMFUL', numDebuffs, true, visibleBuffs) |
auras.visibleDebuffs = visibleDebuffs |
if(hasGap and visibleDebuffs == 0) then |
auras[visibleBuffs]:Hide() |
visibleBuffs = visibleBuffs - 1 |
end |
auras.visibleBuffs = visibleBuffs |
auras.visibleAuras = auras.visibleBuffs + auras.visibleDebuffs |
local fromRange, toRange |
if(auras.PreSetPosition) then |
fromRange, toRange = auras:PreSetPosition(max) |
end |
if(fromRange or auras.createdIcons > auras.anchoredIcons) then |
(auras.SetPosition or SetPosition) (auras, fromRange or auras.anchoredIcons + 1, toRange or auras.createdIcons) |
auras.anchoredIcons = auras.createdIcons |
end |
if(auras.PostUpdate) then auras:PostUpdate(unit) end |
end |
local buffs = self.Buffs |
if(buffs) then |
if(buffs.PreUpdate) then buffs:PreUpdate(unit) end |
local numBuffs = buffs.num or 32 |
local visibleBuffs, hiddenBuffs = filterIcons(unit, buffs, buffs.filter or 'HELPFUL', numBuffs) |
buffs.visibleBuffs = visibleBuffs |
local fromRange, toRange |
if(buffs.PreSetPosition) then |
fromRange, toRange = buffs:PreSetPosition(numBuffs) |
end |
if(fromRange or buffs.createdIcons > buffs.anchoredIcons) then |
(buffs.SetPosition or SetPosition) (buffs, fromRange or buffs.anchoredIcons + 1, toRange or buffs.createdIcons) |
buffs.anchoredIcons = buffs.createdIcons |
end |
if(buffs.PostUpdate) then buffs:PostUpdate(unit) end |
end |
local debuffs = self.Debuffs |
if(debuffs) then |
if(debuffs.PreUpdate) then debuffs:PreUpdate(unit) end |
local numDebuffs = debuffs.num or 40 |
local visibleDebuffs, hiddenDebuffs = filterIcons(unit, debuffs, debuffs.filter or 'HARMFUL', numDebuffs, true) |
debuffs.visibleDebuffs = visibleDebuffs |
local fromRange, toRange |
if(debuffs.PreSetPosition) then |
fromRange, toRange = debuffs:PreSetPosition(numDebuffs) |
end |
if(fromRange or debuffs.createdIcons > debuffs.anchoredIcons) then |
(debuffs.SetPosition or SetPosition) (debuffs, fromRange or debuffs.anchoredIcons + 1, toRange or debuffs.createdIcons) |
debuffs.anchoredIcons = debuffs.createdIcons |
end |
if(debuffs.PostUpdate) then debuffs:PostUpdate(unit) end |
end |
end |
local Update = function(self, event, unit) |
if(self.unit ~= unit) then return end |
UpdateAuras(self, event, unit) |
-- Assume no event means someone wants to re-anchor things. This is usually |
-- done by UpdateAllElements and :ForceUpdate. |
if(event == 'ForceUpdate' or not event) then |
local buffs = self.Buffs |
if(buffs) then |
(buffs.SetPosition or SetPosition) (buffs, 1, buffs.createdIcons) |
end |
local debuffs = self.Debuffs |
if(debuffs) then |
(debuffs.SetPosition or SetPosition) (debuffs, 1, debuffs.createdIcons) |
end |
local auras = self.Auras |
if(auras) then |
(auras.SetPosition or SetPosition) (auras, 1, auras.createdIcons) |
end |
end |
end |
local ForceUpdate = function(element) |
return Update(element.__owner, 'ForceUpdate', element.__owner.unit) |
end |
local Enable = function(self) |
if(self.Buffs or self.Debuffs or self.Auras) then |
self:RegisterEvent("UNIT_AURA", UpdateAuras) |
local buffs = self.Buffs |
if(buffs) then |
buffs.__owner = self |
buffs.ForceUpdate = ForceUpdate |
buffs.createdIcons = 0 |
buffs.anchoredIcons = 0 |
end |
local debuffs = self.Debuffs |
if(debuffs) then |
debuffs.__owner = self |
debuffs.ForceUpdate = ForceUpdate |
debuffs.createdIcons = 0 |
debuffs.anchoredIcons = 0 |
end |
local auras = self.Auras |
if(auras) then |
auras.__owner = self |
auras.ForceUpdate = ForceUpdate |
auras.createdIcons = 0 |
auras.anchoredIcons = 0 |
end |
return true |
end |
end |
local Disable = function(self) |
if(self.Buffs or self.Debuffs or self.Auras) then |
self:UnregisterEvent("UNIT_AURA", UpdateAuras) |
end |
end |
oUF:AddElement('Aura', Update, Enable, Disable) |
--[[ Element: Heal Prediction Bar |
Handle updating and visibility of the heal prediction status bars. |
Widget |
HealPrediction - A table containing `myBar` and `otherBar`. |
Sub-Widgets |
myBar - A StatusBar used to represent your incoming heals. |
otherBar - A StatusBar used to represent other peoples incoming heals. |
absorbBar - A StatusBar used to represent total absorbs. |
healAbsorbBar - A StatusBar used to represent heal absorbs. |
Notes |
The default StatusBar texture will be applied if the UI widget doesn't have a |
status bar texture or color defined. |
Options |
.maxOverflow - Defines the maximum amount of overflow past the end of the |
health bar. |
.frequentUpdates - Update on UNIT_HEALTH_FREQUENT instead of UNIT_HEALTH. Use |
this if .frequentUpdates is also set on the Health element. |
Examples |
-- Position and size |
local myBar = CreateFrame('StatusBar', nil, self.Health) |
myBar:SetPoint('TOP') |
myBar:SetPoint('BOTTOM') |
myBar:SetPoint('LEFT', self.Health:GetStatusBarTexture(), 'RIGHT') |
myBar:SetWidth(200) |
local otherBar = CreateFrame('StatusBar', nil, self.Health) |
otherBar:SetPoint('TOP') |
otherBar:SetPoint('BOTTOM') |
otherBar:SetPoint('LEFT', self.Health:GetStatusBarTexture(), 'RIGHT') |
otherBar:SetWidth(200) |
local absorbBar = CreateFrame('StatusBar', nil, self.Health) |
absorbBar:SetPoint('TOP') |
absorbBar:SetPoint('BOTTOM') |
absorbBar:SetPoint('LEFT', self.Health:GetStatusBarTexture(), 'RIGHT') |
absorbBar:SetWidth(200) |
local healAbsorbBar = CreateFrame('StatusBar', nil, self.Health) |
healAbsorbBar:SetPoint('TOP') |
healAbsorbBar:SetPoint('BOTTOM') |
healAbsorbBar:SetPoint('LEFT', self.Health:GetStatusBarTexture(), 'RIGHT') |
healAbsorbBar:SetWidth(200) |
-- Register with oUF |
self.HealPrediction = { |
myBar = myBar, |
otherBar = otherBar, |
absorbBar = absorbBar, |
healAbsorbBar = healAbsorbBar, |
maxOverflow = 1.05, |
frequentUpdates = true, |
} |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local _, ns = ... |
local oUF = ns.oUF |
local function Update(self, event, unit) |
if(self.unit ~= unit) then return end |
local hp = self.HealPrediction |
if(hp.PreUpdate) then hp:PreUpdate(unit) end |
local myIncomingHeal = UnitGetIncomingHeals(unit, 'player') or 0 |
local allIncomingHeal = UnitGetIncomingHeals(unit) or 0 |
local totalAbsorb = UnitGetTotalAbsorbs(unit) or 0 |
local myCurrentHealAbsorb = UnitGetTotalHealAbsorbs(unit) or 0 |
local health, maxHealth = UnitHealth(unit), UnitHealthMax(unit) |
local overHealAbsorb = false |
if(health < myCurrentHealAbsorb) then |
overHealAbsorb = true |
myCurrentHealAbsorb = health |
end |
if(health - myCurrentHealAbsorb + allIncomingHeal > maxHealth * hp.maxOverflow) then |
allIncomingHeal = maxHealth * hp.maxOverflow - health + myCurrentHealAbsorb |
end |
local otherIncomingHeal = 0 |
if(allIncomingHeal < myIncomingHeal) then |
myIncomingHeal = allIncomingHeal |
else |
otherIncomingHeal = allIncomingHeal - myIncomingHeal |
end |
local overAbsorb = false |
if(health - myCurrentHealAbsorb + allIncomingHeal + totalAbsorb >= maxHealth or health + totalAbsorb >= maxHealth) then |
if(totalAbsorb > 0) then |
overAbsorb = true |
end |
if(allIncomingHeal > myCurrentHealAbsorb) then |
totalAbsorb = max(0, maxHealth - (health - myCurrentHealAbsorb + allIncomingHeal)) |
else |
totalAbsorb = max(0, maxHealth - health) |
end |
end |
if(myCurrentHealAbsorb > allIncomingHeal) then |
myCurrentHealAbsorb = myCurrentHealAbsorb - allIncomingHeal |
else |
myCurrentHealAbsorb = 0 |
end |
if(hp.myBar) then |
hp.myBar:SetMinMaxValues(0, maxHealth) |
hp.myBar:SetValue(myIncomingHeal) |
hp.myBar:Show() |
end |
if(hp.otherBar) then |
hp.otherBar:SetMinMaxValues(0, maxHealth) |
hp.otherBar:SetValue(otherIncomingHeal) |
hp.otherBar:Show() |
end |
if(hp.absorbBar) then |
hp.absorbBar:SetMinMaxValues(0, maxHealth) |
hp.absorbBar:SetValue(totalAbsorb) |
hp.absorbBar:Show() |
end |
if(hp.healAbsorbBar) then |
hp.healAbsorbBar:SetMinMaxValues(0, maxHealth) |
hp.healAbsorbBar:SetValue(myCurrentHealAbsorb) |
hp.healAbsorbBar:Show() |
end |
if(hp.PostUpdate) then |
return hp:PostUpdate(unit, overAbsorb, overHealAbsorb) |
end |
end |
local function Path(self, ...) |
return (self.HealPrediction.Override or Update) (self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate', element.__owner.unit) |
end |
local function Enable(self) |
local hp = self.HealPrediction |
if(hp) then |
hp.__owner = self |
hp.ForceUpdate = ForceUpdate |
self:RegisterEvent('UNIT_HEAL_PREDICTION', Path) |
self:RegisterEvent('UNIT_MAXHEALTH', Path) |
if(hp.frequentUpdates) then |
self:RegisterEvent('UNIT_HEALTH_FREQUENT', Path) |
else |
self:RegisterEvent('UNIT_HEALTH', Path) |
end |
self:RegisterEvent('UNIT_ABSORB_AMOUNT_CHANGED', Path) |
self:RegisterEvent('UNIT_HEAL_ABSORB_AMOUNT_CHANGED', Path) |
if(not hp.maxOverflow) then |
hp.maxOverflow = 1.05 |
end |
if(hp.myBar) then |
if(hp.myBar:IsObjectType'StatusBar' and not hp.myBar:GetStatusBarTexture()) then |
hp.myBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]]) |
end |
hp.myBar:Show() |
end |
if(hp.otherBar) then |
if(hp.otherBar:IsObjectType'StatusBar' and not hp.otherBar:GetStatusBarTexture()) then |
hp.otherBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]]) |
end |
hp.otherBar:Show() |
end |
if(hp.absorbBar) then |
if(hp.absorbBar:IsObjectType'StatusBar' and not hp.absorbBar:GetStatusBarTexture()) then |
hp.absorbBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]]) |
end |
hp.absorbBar:Show() |
end |
if(hp.healAbsorbBar) then |
if(hp.healAbsorbBar:IsObjectType'StatusBar' and not hp.healAbsorbBar:GetStatusBarTexture()) then |
hp.healAbsorbBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]]) |
end |
hp.healAbsorbBar:Show() |
end |
return true |
end |
end |
local function Disable(self) |
local hp = self.HealPrediction |
if(hp) then |
if(hp.myBar) then |
hp.myBar:Hide() |
end |
if(hp.otherBar) then |
hp.otherBar:Hide() |
end |
if(hp.absorbBar) then |
hp.absorbBar:Hide() |
end |
if(hp.healAbsorbBar) then |
hp.healAbsorbBar:Hide() |
end |
self:UnregisterEvent('UNIT_HEAL_PREDICTION', Path) |
self:UnregisterEvent('UNIT_MAXHEALTH', Path) |
self:UnregisterEvent('UNIT_HEALTH', Path) |
self:UnregisterEvent('UNIT_HEALTH_FREQUENT', Path) |
self:UnregisterEvent('UNIT_ABSORB_AMOUNT_CHANGED', Path) |
self:UnregisterEvent('UNIT_HEAL_ABSORB_AMOUNT_CHANGED', Path) |
end |
end |
oUF:AddElement('HealPrediction', Path, Enable, Disable) |
--[[ Element: Leader Icon |
Toggles visibility based on the units leader status. |
Widget |
Leader - Any UI widget. |
Notes |
The default leader icon will be applied if the UI widget is a texture and |
doesn't have a texture or color defined. |
Examples |
-- Position and size |
local Leader = self:CreateTexture(nil, "OVERLAY") |
Leader:SetSize(16, 16) |
Leader:SetPoint("BOTTOM", self, "TOP") |
-- Register it with oUF |
self.Leader = Leadera |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local Update = function(self, event) |
local leader = self.Leader |
if(leader.PreUpdate) then |
leader:PreUpdate() |
end |
local unit = self.unit |
local isLeader = (UnitInParty(unit) or UnitInRaid(unit)) and UnitIsGroupLeader(unit) |
if(isLeader) then |
leader:Show() |
else |
leader:Hide() |
end |
if(leader.PostUpdate) then |
return leader:PostUpdate(isLeader) |
end |
end |
local Path = function(self, ...) |
return (self.Leader.Override or Update) (self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate') |
end |
local Enable = function(self) |
local leader = self.Leader |
if(leader) then |
leader.__owner = self |
leader.ForceUpdate = ForceUpdate |
self:RegisterEvent("PARTY_LEADER_CHANGED", Path, true) |
self:RegisterEvent("GROUP_ROSTER_UPDATE", Path, true) |
if(leader:IsObjectType"Texture" and not leader:GetTexture()) then |
leader:SetTexture[[Interface\GroupFrame\UI-Group-LeaderIcon]] |
end |
return true |
end |
end |
local Disable = function(self) |
local leader = self.Leader |
if(leader) then |
leader:Hide() |
self:UnregisterEvent("PARTY_LEADER_CHANGED", Path) |
self:UnregisterEvent("GROUP_ROSTER_UPDATE", Path) |
end |
end |
oUF:AddElement('Leader', Path, Enable, Disable) |
--[[ Element: Power Bar |
Handles updating of `self.Power` based upon the units power. |
Widget |
Power - A StatusBar used to represent mana. |
Sub-Widgets |
.bg - A Texture which functions as a background. It will inherit the color of |
the main StatusBar. |
Notes |
The default StatusBar texture will be applied if the UI widget doesn't have a |
status bar texture or color defined. |
Options |
.displayAltPower - Use this to let the widget display alternate power if the |
unit has one. If no alternate power the display will fall |
back to primary power. |
The following options are listed by priority. The first check that returns |
true decides the color of the bar. |
.colorTapping - Use `self.colors.tapping` to color the bar if the unit |
isn't tapped by the player. |
.colorDisconnected - Use `self.colors.disconnected` to color the bar if the |
unit is offline. |
.altPowerColor - A table containing the RGB values to use for a fixed |
color if the alt power bar is being displayed instead |
.colorPower - Use `self.colors.power[token]` to color the bar based on |
the unit's power type. This method will fall-back to |
`:GetAlternativeColor()` if it can't find a color matching |
the token. If this function isn't defined, then it will |
attempt to color based upon the alternative power colors |
returned by [UnitPowerType](http://wowprogramming.com/docs/api/UnitPowerType). |
Finally, if these aren't defined, then it will attempt to |
color the bar based upon `self.colors.power[type]`. |
.colorClass - Use `self.colors.class[class]` to color the bar based on |
unit class. `class` is defined by the second return of |
[UnitClass](http://wowprogramming.com/docs/api/UnitClass). |
.colorClassNPC - Use `self.colors.class[class]` to color the bar if the |
unit is a NPC. |
.colorClassPet - Use `self.colors.class[class]` to color the bar if the |
unit is player controlled, but not a player. |
.colorReaction - Use `self.colors.reaction[reaction]` to color the bar |
based on the player's reaction towards the unit. |
`reaction` is defined by the return value of |
[UnitReaction](http://wowprogramming.com/docs/api/UnitReaction). |
.colorSmooth - Use `self.colors.smooth` to color the bar with a smooth |
gradient based on the player's current health percentage. |
Sub-Widget Options |
.multiplier - Defines a multiplier, which is used to tint the background based |
on the main widgets R, G and B values. Defaults to 1 if not |
present. |
Examples |
-- Position and size |
local Power = CreateFrame("StatusBar", nil, self) |
Power:SetHeight(20) |
Power:SetPoint('BOTTOM') |
Power:SetPoint('LEFT') |
Power:SetPoint('RIGHT') |
-- Add a background |
local Background = Power:CreateTexture(nil, 'BACKGROUND') |
Background:SetAllPoints(Power) |
Background:SetTexture(1, 1, 1, .5) |
-- Options |
Power.frequentUpdates = true |
Power.colorTapping = true |
Power.colorDisconnected = true |
Power.colorPower = true |
Power.colorClass = true |
Power.colorReaction = true |
-- Make the background darker. |
Background.multiplier = .5 |
-- Register it with oUF |
self.Power = Power |
self.Power.bg = Background |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
oUF.colors.power = {} |
for power, color in next, PowerBarColor do |
if (type(power) == "string") then |
oUF.colors.power[power] = {color.r, color.g, color.b} |
end |
end |
oUF.colors.power[0] = oUF.colors.power["MANA"] |
oUF.colors.power[1] = oUF.colors.power["RAGE"] |
oUF.colors.power[2] = oUF.colors.power["FOCUS"] |
oUF.colors.power[3] = oUF.colors.power["ENERGY"] |
oUF.colors.power[4] = oUF.colors.power["CHI"] |
oUF.colors.power[5] = oUF.colors.power["RUNES"] |
oUF.colors.power[6] = oUF.colors.power["RUNIC_POWER"] |
oUF.colors.power[7] = oUF.colors.power["SOUL_SHARDS"] |
oUF.colors.power[8] = oUF.colors.power["ECLIPSE"] |
oUF.colors.power[9] = oUF.colors.power["HOLY_POWER"] |
local GetDisplayPower = function(unit) |
local _, min, _, _, _, _, showOnRaid = UnitAlternatePowerInfo(unit) |
if(showOnRaid) then |
return ALTERNATE_POWER_INDEX, min |
end |
end |
local Update = function(self, event, unit) |
if(self.unit ~= unit) then return end |
local power = self.Power |
if(power.PreUpdate) then power:PreUpdate(unit) end |
local displayType, min |
if power.displayAltPower then |
displayType, min = GetDisplayPower(unit) |
end |
local cur, max = UnitPower(unit, displayType), UnitPowerMax(unit, displayType) |
local disconnected = not UnitIsConnected(unit) |
power:SetMinMaxValues(min or 0, max) |
if(disconnected) then |
power:SetValue(max) |
else |
power:SetValue(cur) |
end |
power.disconnected = disconnected |
local r, g, b, t |
if(power.colorTapping and not UnitPlayerControlled(unit) and |
UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) and not |
UnitIsTappedByAllThreatList(unit)) then |
t = self.colors.tapped |
elseif(power.colorDisconnected and disconnected) then |
t = self.colors.disconnected |
elseif(displayType == ALTERNATE_POWER_INDEX and power.altPowerColor) then |
t = power.altPowerColor |
elseif(power.colorPower) then |
local ptype, ptoken, altR, altG, altB = UnitPowerType(unit) |
t = self.colors.power[ptoken] |
if(not t) then |
if(power.GetAlternativeColor) then |
r, g, b = power:GetAlternativeColor(unit, ptype, ptoken, altR, altG, altB) |
elseif(altR) then |
r, g, b = altR, altG, altB |
else |
t = self.colors.power[ptype] |
end |
end |
elseif(power.colorClass and UnitIsPlayer(unit)) or |
(power.colorClassNPC and not UnitIsPlayer(unit)) or |
(power.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then |
local _, class = UnitClass(unit) |
t = self.colors.class[class] |
elseif(power.colorReaction and UnitReaction(unit, 'player')) then |
t = self.colors.reaction[UnitReaction(unit, "player")] |
elseif(power.colorSmooth) then |
local adjust = 0 - (min or 0) |
r, g, b = self.ColorGradient(cur + adjust, max + adjust, unpack(power.smoothGradient or self.colors.smooth)) |
end |
if(t) then |
r, g, b = t[1], t[2], t[3] |
end |
if(b) then |
power:SetStatusBarColor(r, g, b) |
local bg = power.bg |
if(bg) then |
local mu = bg.multiplier or 1 |
bg:SetVertexColor(r * mu, g * mu, b * mu) |
end |
end |
if(power.PostUpdate) then |
return power:PostUpdate(unit, cur, max, min) |
end |
end |
local Path = function(self, ...) |
return (self.Power.Override or Update) (self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate', element.__owner.unit) |
end |
local Enable = function(self, unit) |
local power = self.Power |
if(power) then |
power.__owner = self |
power.ForceUpdate = ForceUpdate |
if(power.frequentUpdates and (unit == 'player' or unit == 'pet')) then |
self:RegisterEvent('UNIT_POWER_FREQUENT', Path) |
else |
self:RegisterEvent('UNIT_POWER', Path) |
end |
self:RegisterEvent('UNIT_POWER_BAR_SHOW', Path) |
self:RegisterEvent('UNIT_POWER_BAR_HIDE', Path) |
self:RegisterEvent('UNIT_DISPLAYPOWER', Path) |
self:RegisterEvent('UNIT_CONNECTION', Path) |
self:RegisterEvent('UNIT_MAXPOWER', Path) |
-- For tapping. |
self:RegisterEvent('UNIT_FACTION', Path) |
if(power:IsObjectType'StatusBar' and not power:GetStatusBarTexture()) then |
power:SetStatusBarTexture[[Interface\TargetingFrame\UI-StatusBar]] |
end |
return true |
end |
end |
local Disable = function(self) |
local power = self.Power |
if(power) then |
self:UnregisterEvent('UNIT_POWER_FREQUENT', Path) |
self:UnregisterEvent('UNIT_POWER', Path) |
self:UnregisterEvent('UNIT_POWER_BAR_SHOW', Path) |
self:UnregisterEvent('UNIT_POWER_BAR_HIDE', Path) |
self:UnregisterEvent('UNIT_DISPLAYPOWER', Path) |
self:UnregisterEvent('UNIT_CONNECTION', Path) |
self:UnregisterEvent('UNIT_MAXPOWER', Path) |
self:UnregisterEvent('UNIT_FACTION', Path) |
end |
end |
oUF:AddElement('Power', Path, Enable, Disable) |
--[[ Element: Range Fader |
Widget |
Range - A table containing opacity values. |
Options |
.outsideAlpha - Opacity when the unit is out of range. Values 0 (fully |
transparent) - 1 (fully opaque). |
.insideAlpha - Opacity when the unit is within range. Values 0 (fully |
transparent) - 1 (fully opaque). |
Examples |
-- Register with oUF |
self.Range = { |
insideAlpha = 1, |
outsideAlpha = 1/2, |
} |
Hooks |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local _FRAMES = {} |
local OnRangeFrame |
local UnitInRange, UnitIsConnected = UnitInRange, UnitIsConnected |
-- updating of range. |
local timer = 0 |
local OnRangeUpdate = function(self, elapsed) |
timer = timer + elapsed |
if(timer >= .20) then |
for _, object in next, _FRAMES do |
if(object:IsShown()) then |
local range = object.Range |
if(UnitIsConnected(object.unit)) then |
local inRange, checkedRange = UnitInRange(object.unit) |
if(checkedRange and not inRange) then |
if(range.Override) then |
--[[ .Override(self, status) |
A function used to override the calls to :SetAlpha(). |
Arguments |
self - The unit object. |
status - The range status of the unit. Either `inside` or |
`outside`. |
]] |
range.Override(object, 'outside') |
else |
object:SetAlpha(range.outsideAlpha) |
end |
else |
if(range.Override) then |
range.Override(object, 'inside') |
elseif(object:GetAlpha() ~= range.insideAlpha) then |
object:SetAlpha(range.insideAlpha) |
end |
end |
else |
if(range.Override) then |
range.Override(object, 'offline') |
elseif(object:GetAlpha() ~= range.insideAlpha) then |
object:SetAlpha(range.insideAlpha) |
end |
end |
end |
end |
timer = 0 |
end |
end |
local Enable = function(self) |
local range = self.Range |
if(range and range.insideAlpha and range.outsideAlpha) then |
table.insert(_FRAMES, self) |
if(not OnRangeFrame) then |
OnRangeFrame = CreateFrame"Frame" |
OnRangeFrame:SetScript("OnUpdate", OnRangeUpdate) |
end |
OnRangeFrame:Show() |
return true |
end |
end |
local Disable = function(self) |
local range = self.Range |
if(range) then |
for k, frame in next, _FRAMES do |
if(frame == self) then |
table.remove(_FRAMES, k) |
break |
end |
end |
self:SetAlpha(1) |
if(#_FRAMES == 0) then |
OnRangeFrame:Hide() |
end |
end |
end |
oUF:AddElement('Range', nil, Enable, Disable) |
--[[ Element: Monk Stagger Bar |
Handles updating and visibility of the monk's stagger bar. |
Widget |
Stagger - A StatusBar |
Sub-Widgets |
.bg - A Texture that functions as a background. It will inherit the color |
of the main StatusBar. |
Notes |
The default StatusBar texture will be applied if the UI widget doesn't have a |
status bar texture or color defined. |
In order to override the internal update define the 'OnUpdate' script on the |
widget in the layout |
Sub-Widgets Options |
.multiplier - Defines a multiplier, which is used to tint the background based |
on the main widgets R, G and B values. Defaults to 1 if not |
present. |
Examples |
local Stagger = CreateFrame('StatusBar', nil, self) |
Stagger:SetSize(120, 20) |
Stagger:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', 0, 0) |
-- Register with oUF |
self.Stagger = Stagger |
Hooks |
OverrideVisibility(self) - Used to completely override the internal visibility |
function. Removing the table key entry will make |
the element fall-back to its internal function |
again. |
Override(self) - Used to completely override the internal |
update function. Removing the table key entry will |
make the element fall-back to its internal function |
again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
-- percentages at which the bar should change color |
local STAGGER_YELLOW_TRANSITION = STAGGER_YELLOW_TRANSITION |
local STAGGER_RED_TRANSITION = STAGGER_RED_TRANSITION |
-- table indices of bar colors |
local GREEN_INDEX = 1; |
local YELLOW_INDEX = 2; |
local RED_INDEX = 3; |
local STANCE_OF_THE_STURY_OX_ID = 23 |
local UnitHealthMax = UnitHealthMax |
local UnitStagger = UnitStagger |
local _, playerClass = UnitClass("player") |
-- TODO: fix color in the power element |
oUF.colors.power[BREWMASTER_POWER_BAR_NAME] = { |
{0.52, 1.0, 0.52}, |
{1.0, 0.98, 0.72}, |
{1.0, 0.42, 0.42}, |
} |
local color |
local Update = function(self, event, unit) |
if unit and unit ~= self.unit then return end |
local element = self.Stagger |
if(element.PreUpdate) then |
element:PreUpdate() |
end |
local maxHealth = UnitHealthMax("player") |
local stagger = UnitStagger("player") |
local staggerPercent = stagger / maxHealth |
element:SetMinMaxValues(0, maxHealth) |
element:SetValue(stagger) |
local rgb |
if(staggerPercent >= STAGGER_RED_TRANSITION) then |
rgb = color[RED_INDEX] |
elseif(staggerPercent > STAGGER_YELLOW_TRANSITION) then |
rgb = color[YELLOW_INDEX] |
else |
rgb = color[GREEN_INDEX] |
end |
local r, g, b = rgb[1], rgb[2], rgb[3] |
element:SetStatusBarColor(r, g, b) |
local bg = element.bg |
if(bg) then |
local mu = bg.multiplier or 1 |
bg:SetVertexColor(r * mu, g * mu, b * mu) |
end |
if(element.PostUpdate) then |
element:PostUpdate(maxHealth, stagger, staggerPercent, r, g, b) |
end |
end |
local Path = function(self, ...) |
return (self.Stagger.Override or Update)(self, ...) |
end |
local Visibility = function(self, event, unit) |
if(STANCE_OF_THE_STURY_OX_ID ~= GetShapeshiftFormID() or UnitHasVehiclePlayerFrameUI("player")) then |
if self.Stagger:IsShown() then |
self.Stagger:Hide() |
self:UnregisterEvent('UNIT_AURA', Path) |
end |
elseif not self.Stagger:IsShown() then |
self.Stagger:Show() |
self:RegisterEvent('UNIT_AURA', Path) |
return Path(self, event, unit) |
end |
end |
local VisibilityPath = function(self, ...) |
return (self.Stagger.OverrideVisibility or Visibility)(self, ...) |
end |
local ForceUpdate = function(element) |
return VisibilityPath(element.__owner, "ForceUpdate", element.__owner.unit) |
end |
local Enable = function(self, unit) |
if(playerClass ~= "MONK") then return end |
local element = self.Stagger |
if(element) then |
element.__owner = self |
element.ForceUpdate = ForceUpdate |
element:Hide() |
color = self.colors.power[BREWMASTER_POWER_BAR_NAME] |
self:RegisterEvent('UNIT_DISPLAYPOWER', VisibilityPath) |
self:RegisterEvent('UPDATE_SHAPESHIFT_FORM', VisibilityPath) |
if(element:IsObjectType'StatusBar' and not element:GetStatusBarTexture()) then |
element:SetStatusBarTexture[[Interface\TargetingFrame\UI-StatusBar]] |
end |
MonkStaggerBar.Show = MonkStaggerBar.Hide |
MonkStaggerBar:UnregisterEvent'PLAYER_ENTERING_WORLD' |
MonkStaggerBar:UnregisterEvent'PLAYER_SPECIALIZATION_CHANGED' |
MonkStaggerBar:UnregisterEvent'UNIT_DISPLAYPOWER' |
MonkStaggerBar:UnregisterEvent'UPDATE_VEHICLE_ACTION_BAR' |
return true |
end |
end |
local Disable = function(self) |
local element = self.Stagger |
if(element) then |
element:Hide() |
self:UnregisterEvent('UNIT_AURA', Path) |
self:UnregisterEvent('UNIT_DISPLAYPOWER', VisibilityPath) |
self:UnregisterEvent('UPDATE_SHAPESHIFT_FORM', VisibilityPath) |
MonkStaggerBar.Show = nil |
MonkStaggerBar:Show() |
MonkStaggerBar:UnregisterEvent'PLAYER_ENTERING_WORLD' |
MonkStaggerBar:UnregisterEvent'PLAYER_SPECIALIZATION_CHANGED' |
MonkStaggerBar:UnregisterEvent'UNIT_DISPLAYPOWER' |
MonkStaggerBar:UnregisterEvent'UPDATE_VEHICLE_ACTION_BAR' |
end |
end |
oUF:AddElement("Stagger", VisibilityPath, Enable, Disable) |
--[[ Element: Raid Icon |
Handles updating and toggles visibility of raid target icons. |
Widget |
RaidIcon - A Texture used to display the raid target icon. |
Notes |
This element updates by changing the texture. |
The default raid icons will be used if the UI widget is a texture and doesn't |
have a texture or color defined. |
Examples |
-- Position and size |
local RaidIcon = self:CreateTexture(nil, 'OVERLAY') |
RaidIcon:SetSize(16, 16) |
RaidIcon:SetPoint('TOPRIGHT', self) |
-- Register it with oUF |
self.RaidIcon = RaidIcon |
Hooks |
Override(self) - Used to completely override the internal update function. |
Removing the table key entry will make the element fall-back |
to its internal function again. |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local GetRaidTargetIndex = GetRaidTargetIndex |
local SetRaidTargetIconTexture = SetRaidTargetIconTexture |
local Update = function(self, event) |
local icon = self.RaidIcon |
if(icon.PreUpdate) then |
icon:PreUpdate() |
end |
local index = GetRaidTargetIndex(self.unit) |
if(index) then |
SetRaidTargetIconTexture(icon, index) |
icon:Show() |
else |
icon:Hide() |
end |
if(icon.PostUpdate) then |
return icon:PostUpdate(index) |
end |
end |
local Path = function(self, ...) |
return (self.RaidIcon.Override or Update) (self, ...) |
end |
local ForceUpdate = function(element) |
if(not element.__owner.unit) then return end |
return Path(element.__owner, 'ForceUpdate') |
end |
local Enable = function(self) |
local ricon = self.RaidIcon |
if(ricon) then |
ricon.__owner = self |
ricon.ForceUpdate = ForceUpdate |
self:RegisterEvent("RAID_TARGET_UPDATE", Path, true) |
if(ricon:IsObjectType"Texture" and not ricon:GetTexture()) then |
ricon:SetTexture[[Interface\TargetingFrame\UI-RaidTargetingIcons]] |
end |
return true |
end |
end |
local Disable = function(self) |
local ricon = self.RaidIcon |
if(ricon) then |
ricon:Hide() |
self:UnregisterEvent("RAID_TARGET_UPDATE", Path) |
end |
end |
oUF:AddElement('RaidIcon', Path, Enable, Disable) |
--[[ Element: Runes Bar |
Handle updating and visibility of the Death Knight's Rune indicators. |
Widget |
Runes - An array holding six StatusBar's. |
Sub-Widgets |
.bg - A Texture which functions as a background. It will inherit the color of |
the main StatusBar. |
Notes |
The default StatusBar texture will be applied if the UI widget doesn't have a |
status bar texture or color defined. |
Sub-Widgets Options |
.multiplier - Defines a multiplier, which is used to tint the background based |
on the main widgets R, G and B values. Defaults to 1 if not |
present. |
Examples |
local Runes = {} |
for index = 1, 6 do |
-- Position and size of the rune bar indicators |
local Rune = CreateFrame('StatusBar', nil, self) |
Rune:SetSize(120 / 6, 20) |
Rune:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', index * 120 / 6, 0) |
Runes[index] = Rune |
end |
-- Register with oUF |
self.Runes = Runes |
]] |
if select(2, UnitClass("player")) ~= "DEATHKNIGHT" then return end |
local parent, ns = ... |
local oUF = ns.oUF |
oUF.colors.runes = { |
{1, 0, 0}, -- blood |
{0, .5, 0}, -- unholy |
{0, 1, 1}, -- frost |
{.9, .1, 1}, -- death |
} |
local runemap = { 1, 2, 5, 6, 3, 4 } |
local OnUpdate = function(self, elapsed) |
local duration = self.duration + elapsed |
if(duration >= self.max) then |
return self:SetScript("OnUpdate", nil) |
else |
self.duration = duration |
return self:SetValue(duration) |
end |
end |
local UpdateType = function(self, event, rid, alt) |
local runes = self.Runes |
local rune = runes[runemap[rid]] |
local colors = self.colors.runes[GetRuneType(rid) or alt] |
local r, g, b = colors[1], colors[2], colors[3] |
rune:SetStatusBarColor(r, g, b) |
if(rune.bg) then |
local mu = rune.bg.multiplier or 1 |
rune.bg:SetVertexColor(r * mu, g * mu, b * mu) |
end |
if(runes.PostUpdateType) then |
return runes:PostUpdateType(rune, rid, alt) |
end |
end |
local UpdateRune = function(self, event, rid) |
local runes = self.Runes |
local rune = runes[runemap[rid]] |
if(not rune) then return end |
if(UnitHasVehicleUI'player') then |
return rune:Hide() |
else |
rune:Show() |
end |
local start, duration, runeReady = GetRuneCooldown(rid) |
if(runeReady) then |
rune:SetMinMaxValues(0, 1) |
rune:SetValue(1) |
rune:SetScript("OnUpdate", nil) |
else |
rune.duration = GetTime() - start |
rune.max = duration |
rune:SetMinMaxValues(1, duration) |
rune:SetScript("OnUpdate", OnUpdate) |
end |
if(runes.PostUpdateRune) then |
return runes:PostUpdateRune(rune, rid, start, duration, runeReady) |
end |
end |
local Update = function(self, event) |
for i=1, 6 do |
UpdateRune(self, event, i) |
end |
end |
local ForceUpdate = function(element) |
return Update(element.__owner, 'ForceUpdate') |
end |
local Enable = function(self, unit) |
local runes = self.Runes |
if(runes and unit == 'player') then |
runes.__owner = self |
runes.ForceUpdate = ForceUpdate |
for i=1, 6 do |
local rune = runes[runemap[i]] |
if(rune:IsObjectType'StatusBar' and not rune:GetStatusBarTexture()) then |
rune:SetStatusBarTexture[[Interface\TargetingFrame\UI-StatusBar]] |
end |
-- From my minor testing this is a okey solution. A full login always remove |
-- the death runes, or at least the clients knowledge about them. |
UpdateType(self, nil, i, math.floor((i+1)/2)) |
end |
self:RegisterEvent("RUNE_POWER_UPDATE", UpdateRune, true) |
self:RegisterEvent("RUNE_TYPE_UPDATE", UpdateType, true) |
-- oUF leaves the vehicle events registered on the player frame, so |
-- buffs and such are correctly updated when entering/exiting vehicles. |
-- |
-- This however makes the code also show/hide the RuneFrame. |
RuneFrame.Show = RuneFrame.Hide |
RuneFrame:Hide() |
return true |
end |
end |
local Disable = function(self) |
RuneFrame.Show = nil |
RuneFrame:Show() |
self:UnregisterEvent("RUNE_POWER_UPDATE", UpdateRune) |
self:UnregisterEvent("RUNE_TYPE_UPDATE", UpdateType) |
end |
oUF:AddElement("Runes", Update, Enable, Disable) |
--[[ |
-- Credits: Vika, Cladhaire, Tekkub |
]] |
local parent, ns = ... |
local oUF = ns.oUF |
local _PATTERN = '%[..-%]+' |
local _ENV = { |
Hex = function(r, g, b) |
if type(r) == "table" then |
if r.r then r, g, b = r.r, r.g, r.b else r, g, b = unpack(r) end |
end |
return string.format("|cff%02x%02x%02x", r*255, g*255, b*255) |
end, |
ColorGradient = oUF.ColorGradient, |
} |
local _PROXY = setmetatable(_ENV, {__index = _G}) |
local tagStrings = { |
["creature"] = [[function(u) |
return UnitCreatureFamily(u) or UnitCreatureType(u) |
end]], |
["dead"] = [[function(u) |
if(UnitIsDead(u)) then |
return 'Dead' |
elseif(UnitIsGhost(u)) then |
return 'Ghost' |
end |
end]], |
["difficulty"] = [[function(u) |
if UnitCanAttack("player", u) then |
local l = UnitLevel(u) |
return Hex(GetQuestDifficultyColor((l > 0) and l or 99)) |
end |
end]], |
["leader"] = [[function(u) |
if(UnitIsGroupLeader(u)) then |
return 'L' |
end |
end]], |
["leaderlong"] = [[function(u) |
if(UnitIsGroupLeader(u)) then |
return 'Leader' |
end |
end]], |
["level"] = [[function(u) |
local l = UnitLevel(u) |
if(UnitIsWildBattlePet(u) or UnitIsBattlePetCompanion(u)) then |
l = UnitBattlePetLevel(u) |
end |
if(l > 0) then |
return l |
else |
return '??' |
end |
end]], |
["missinghp"] = [[function(u) |
local current = UnitHealthMax(u) - UnitHealth(u) |
if(current > 0) then |
return current |
end |
end]], |
["missingpp"] = [[function(u) |
local current = UnitPowerMax(u) - UnitPower(u) |
if(current > 0) then |
return current |
end |
end]], |
["name"] = [[function(u, r) |
return UnitName(r or u) |
end]], |
["offline"] = [[function(u) |
if(not UnitIsConnected(u)) then |
return 'Offline' |
end |
end]], |
["perhp"] = [[function(u) |
local m = UnitHealthMax(u) |
if(m == 0) then |
return 0 |
else |
return math.floor(UnitHealth(u)/m*100+.5) |
end |
end]], |
["perpp"] = [[function(u) |
local m = UnitPowerMax(u) |
if(m == 0) then |
return 0 |
else |
return math.floor(UnitPower(u)/m*100+.5) |
end |
end]], |
["plus"] = [[function(u) |
local c = UnitClassification(u) |
if(c == 'elite' or c == 'rareelite') then |
return '+' |
end |
end]], |
["pvp"] = [[function(u) |
if(UnitIsPVP(u)) then |
return 'PvP' |
end |
end]], |
["raidcolor"] = [[function(u) |
local _, x = UnitClass(u) |
if(x) then |
return Hex(_COLORS.class[x]) |
end |
end]], |
["rare"] = [[function(u) |
local c = UnitClassification(u) |
if(c == 'rare' or c == 'rareelite') then |
return 'Rare' |
end |
end]], |
["resting"] = [[function(u) |
if(u == 'player' and IsResting()) then |
return 'zzz' |
end |
end]], |
["sex"] = [[function(u) |
local s = UnitSex(u) |
if(s == 2) then |
return 'Male' |
elseif(s == 3) then |
return 'Female' |
end |
end]], |
["smartclass"] = [[function(u) |
if(UnitIsPlayer(u)) then |
return _TAGS['class'](u) |
end |
return _TAGS['creature'](u) |
end]], |
["status"] = [[function(u) |
if(UnitIsDead(u)) then |
return 'Dead' |
elseif(UnitIsGhost(u)) then |
return 'Ghost' |
elseif(not UnitIsConnected(u)) then |
return 'Offline' |
else |
return _TAGS['resting'](u) |
end |
end]], |
["threat"] = [[function(u) |
local s = UnitThreatSituation(u) |
if(s == 1) then |
return '++' |
elseif(s == 2) then |
return '--' |
elseif(s == 3) then |
return 'Aggro' |
end |
end]], |
["threatcolor"] = [[function(u) |
return Hex(GetThreatStatusColor(UnitThreatSituation(u))) |
end]], |
["cpoints"] = [[function(u) |
local cp |
if(UnitHasVehicleUI'player') then |
cp = GetComboPoints('vehicle', 'target') |
else |
cp = GetComboPoints('player', 'target') |
end |
if(cp > 0) then |
return cp |
end |
end]], |
['smartlevel'] = [[function(u) |
local c = UnitClassification(u) |
if(c == 'worldboss') then |
return 'Boss' |
else |
local plus = _TAGS['plus'](u) |
local level = _TAGS['level'](u) |
if(plus) then |
return level .. plus |
else |
return level |
end |
end |
end]], |
["classification"] = [[function(u) |
local c = UnitClassification(u) |
if(c == 'rare') then |
return 'Rare' |
elseif(c == 'rareelite') then |
return 'Rare Elite' |
elseif(c == 'elite') then |
return 'Elite' |
elseif(c == 'worldboss') then |
return 'Boss' |
elseif(c == 'minus') then |
return 'Affix' |
end |
end]], |
["shortclassification"] = [[function(u) |
local c = UnitClassification(u) |
if(c == 'rare') then |
return 'R' |
elseif(c == 'rareelite') then |
return 'R+' |
elseif(c == 'elite') then |
return '+' |
elseif(c == 'worldboss') then |
return 'B' |
elseif(c == 'minus') then |
return '-' |
end |
end]], |
["group"] = [[function(unit) |
local name, server = UnitName(unit) |
if(server and server ~= "") then |
name = string.format("%s-%s", name, server) |
end |
for i=1, GetNumGroupMembers() do |
local raidName, _, group = GetRaidRosterInfo(i) |
if( raidName == name ) then |
return group |
end |
end |
end]], |
["deficit:name"] = [[function(u) |
local missinghp = _TAGS['missinghp'](u) |
if(missinghp) then |
return '-' .. missinghp |
else |
return _TAGS['name'](u) |
end |
end]], |
['pereclipse'] = [[function(u) |
local m = UnitPowerMax('player', SPELL_POWER_ECLIPSE) |
if(m == 0) then |
return 0 |
else |
return math.abs(UnitPower('player', SPELL_POWER_ECLIPSE)/m*100) |
end |
end]], |
['curmana'] = [[function(unit) |
return UnitPower(unit, SPELL_POWER_MANA) |
end]], |
['maxmana'] = [[function(unit) |
return UnitPowerMax(unit, SPELL_POWER_MANA) |
end]], |
['soulshards'] = [[function() |
if(IsPlayerSpell(WARLOCK_SOULBURN)) then |
local num = UnitPower('player', SPELL_POWER_SOUL_SHARDS) |
if(num > 0) then |
return num |
end |
end |
end]], |
['holypower'] = [[function() |
if(IsPlayerSpell(85673)) then |
local num = UnitPower('player', SPELL_POWER_HOLY_POWER) |
if(num > 0) then |
return num |
end |
end |
end]], |
['chi'] = [[function() |
local num = UnitPower('player', SPELL_POWER_CHI) |
if(num > 0) then |
return num |
end |
end]], |
['shadoworbs'] = [[function() |
if(IsPlayerSpell(95740)) then |
local num = UnitPower('player', SPELL_POWER_SHADOW_ORBS) |
if(num > 0) then |
return num |
end |
end |
end]], |
['affix'] = [[function(u) |
local c = UnitClassification(u) |
if(c == 'minus') then |
return 'Affix' |
end |
end]], |
} |
local tags = setmetatable( |
{ |
curhp = UnitHealth, |
curpp = UnitPower, |
maxhp = UnitHealthMax, |
maxpp = UnitPowerMax, |
class = UnitClass, |
faction = UnitFactionGroup, |
race = UnitRace, |
}, |
{ |
__index = function(self, key) |
local tagFunc = tagStrings[key] |
if(tagFunc) then |
local func, err = loadstring('return ' .. tagFunc) |
if(func) then |
func = func() |
-- Want to trigger __newindex, so no rawset. |
self[key] = func |
tagStrings[key] = nil |
return func |
else |
error(err, 3) |
end |
end |
end, |
__newindex = function(self, key, val) |
if(type(val) == 'string') then |
tagStrings[key] = val |
elseif(type(val) == 'function') then |
-- So we don't clash with any custom envs. |
if(getfenv(val) == _G) then |
setfenv(val, _PROXY) |
end |
rawset(self, key, val) |
end |
end, |
} |
) |
_ENV._TAGS = tags |
local tagEvents = { |
["curhp"] = "UNIT_HEALTH", |
["dead"] = "UNIT_HEALTH", |
["leader"] = "PARTY_LEADER_CHANGED", |
["leaderlong"] = "PARTY_LEADER_CHANGED", |
["level"] = "UNIT_LEVEL PLAYER_LEVEL_UP", |
["maxhp"] = "UNIT_MAXHEALTH", |
["missinghp"] = "UNIT_HEALTH UNIT_MAXHEALTH", |
["name"] = "UNIT_NAME_UPDATE", |
["perhp"] = "UNIT_HEALTH UNIT_MAXHEALTH", |
["pvp"] = "UNIT_FACTION", |
["resting"] = "PLAYER_UPDATE_RESTING", |
["smartlevel"] = "UNIT_LEVEL PLAYER_LEVEL_UP UNIT_CLASSIFICATION_CHANGED", |
["threat"] = "UNIT_THREAT_SITUATION_UPDATE", |
["threatcolor"] = "UNIT_THREAT_SITUATION_UPDATE", |
['cpoints'] = 'UNIT_COMBO_POINTS PLAYER_TARGET_CHANGED', |
['affix'] = 'UNIT_CLASSIFICATION_CHANGED', |
['plus'] = 'UNIT_CLASSIFICATION_CHANGED', |
['rare'] = 'UNIT_CLASSIFICATION_CHANGED', |
['classification'] = 'UNIT_CLASSIFICATION_CHANGED', |
['shortclassification'] = 'UNIT_CLASSIFICATION_CHANGED', |
["group"] = "GROUP_ROSTER_UPDATE", |
["curpp"] = 'UNIT_POWER', |
["maxpp"] = 'UNIT_MAXPOWER', |
["missingpp"] = 'UNIT_MAXPOWER UNIT_POWER', |
["perpp"] = 'UNIT_MAXPOWER UNIT_POWER', |
["offline"] = "UNIT_HEALTH UNIT_CONNECTION", |
["status"] = "UNIT_HEALTH PLAYER_UPDATE_RESTING UNIT_CONNECTION", |
["pereclipse"] = 'UNIT_POWER', |
['curmana'] = 'UNIT_POWER UNIT_MAXPOWER', |
['maxmana'] = 'UNIT_POWER UNIT_MAXPOWER', |
['soulshards'] = 'UNIT_POWER SPELLS_CHANGED', |
['holypower'] = 'UNIT_POWER SPELLS_CHANGED', |
['chi'] = 'UNIT_POWER', |
['shadoworbs'] = 'UNIT_POWER SPELLS_CHANGED', |
} |
local unitlessEvents = { |
PLAYER_LEVEL_UP = true, |
PLAYER_UPDATE_RESTING = true, |
PLAYER_TARGET_CHANGED = true, |
PARTY_LEADER_CHANGED = true, |
GROUP_ROSTER_UPDATE = true, |
UNIT_COMBO_POINTS = true |
} |
local events = {} |
local frame = CreateFrame"Frame" |
frame:SetScript('OnEvent', function(self, event, unit) |
local strings = events[event] |
if(strings) then |
for k, fontstring in next, strings do |
if(fontstring:IsVisible() and (unitlessEvents[event] or fontstring.parent.unit == unit)) then |
fontstring:UpdateTag() |
end |
end |
end |
end) |
local OnUpdates = {} |
local eventlessUnits = {} |
local createOnUpdate = function(timer) |
local OnUpdate = OnUpdates[timer] |
if(not OnUpdate) then |
local total = timer |
local frame = CreateFrame'Frame' |
local strings = eventlessUnits[timer] |
frame:SetScript('OnUpdate', function(self, elapsed) |
if(total >= timer) then |
for k, fs in next, strings do |
if(fs.parent:IsShown() and UnitExists(fs.parent.unit)) then |
fs:UpdateTag() |
end |
end |
total = 0 |
end |
total = total + elapsed |
end) |
OnUpdates[timer] = frame |
end |
end |
local OnShow = function(self) |
for _, fs in next, self.__tags do |
fs:UpdateTag() |
end |
end |
local getTagName = function(tag) |
local s = (tag:match('>+()') or 2) |
local e = tag:match('.*()<+') |
e = (e and e - 1) or -2 |
return tag:sub(s, e), s, e |
end |
local RegisterEvent = function(fontstr, event) |
if(not events[event]) then events[event] = {} end |
frame:RegisterEvent(event) |
table.insert(events[event], fontstr) |
end |
local RegisterEvents = function(fontstr, tagstr) |
for tag in tagstr:gmatch(_PATTERN) do |
tag = getTagName(tag) |
local tagevents = tagEvents[tag] |
if(tagevents) then |
for event in tagevents:gmatch'%S+' do |
RegisterEvent(fontstr, event) |
end |
end |
end |
end |
local UnregisterEvents = function(fontstr) |
for event, data in pairs(events) do |
for k, tagfsstr in pairs(data) do |
if(tagfsstr == fontstr) then |
if(#data == 1) then |
frame:UnregisterEvent(event) |
end |
table.remove(data, k) |
end |
end |
end |
end |
local tagPool = {} |
local funcPool = {} |
local tmp = {} |
local Tag = function(self, fs, tagstr) |
if(not fs or not tagstr) then return end |
if(not self.__tags) then |
self.__tags = {} |
table.insert(self.__elements, OnShow) |
else |
-- Since people ignore everything that's good practice - unregister the tag |
-- if it already exists. |
for _, tag in pairs(self.__tags) do |
if(fs == tag) then |
-- We don't need to remove it from the __tags table as Untag handles |
-- that for us. |
self:Untag(fs) |
end |
end |
end |
fs.parent = self |
local func = tagPool[tagstr] |
if(not func) then |
local format, numTags = tagstr:gsub('%%', '%%%%'):gsub(_PATTERN, '%%s') |
local args = {} |
for bracket in tagstr:gmatch(_PATTERN) do |
local tagFunc = funcPool[bracket] or tags[bracket:sub(2, -2)] |
if(not tagFunc) then |
local tagName, s, e = getTagName(bracket) |
local tag = tags[tagName] |
if(tag) then |
s = s - 2 |
e = e + 2 |
if(s ~= 0 and e ~= 0) then |
local pre = bracket:sub(2, s) |
local ap = bracket:sub(e, -2) |
tagFunc = function(u,r) |
local str = tag(u,r) |
if(str) then |
return pre..str..ap |
end |
end |
elseif(s ~= 0) then |
local pre = bracket:sub(2, s) |
tagFunc = function(u,r) |
local str = tag(u,r) |
if(str) then |
return pre..str |
end |
end |
elseif(e ~= 0) then |
local ap = bracket:sub(e, -2) |
tagFunc = function(u,r) |
local str = tag(u,r) |
if(str) then |
return str..ap |
end |
end |
end |
funcPool[bracket] = tagFunc |
end |
end |
if(tagFunc) then |
table.insert(args, tagFunc) |
else |
return error(('Attempted to use invalid tag %s.'):format(bracket), 3) |
end |
end |
if(numTags == 1) then |
func = function(self) |
local parent = self.parent |
local realUnit |
if(self.overrideUnit) then |
realUnit = parent.realUnit |
end |
_ENV._COLORS = parent.colors |
return self:SetFormattedText( |
format, |
args[1](parent.unit, realUnit) or '' |
) |
end |
elseif(numTags == 2) then |
func = function(self) |
local parent = self.parent |
local unit = parent.unit |
local realUnit |
if(self.overrideUnit) then |
realUnit = parent.realUnit |
end |
_ENV._COLORS = parent.colors |
return self:SetFormattedText( |
format, |
args[1](unit, realUnit) or '', |
args[2](unit, realUnit) or '' |
) |
end |
elseif(numTags == 3) then |
func = function(self) |
local parent = self.parent |
local unit = parent.unit |
local realUnit |
if(self.overrideUnit) then |
realUnit = parent.realUnit |
end |
_ENV._COLORS = parent.colors |
return self:SetFormattedText( |
format, |
args[1](unit, realUnit) or '', |
args[2](unit, realUnit) or '', |
args[3](unit, realUnit) or '' |
) |
end |
else |
func = function(self) |
local parent = self.parent |
local unit = parent.unit |
local realUnit |
if(self.overrideUnit) then |
realUnit = parent.realUnit |
end |
_ENV._COLORS = parent.colors |
for i, func in next, args do |
tmp[i] = func(unit, realUnit) or '' |
end |
-- We do 1, numTags because tmp can hold several unneeded variables. |
return self:SetFormattedText(format, unpack(tmp, 1, numTags)) |
end |
end |
tagPool[tagstr] = func |
end |
fs.UpdateTag = func |
local unit = self.unit |
if((unit and unit:match'%w+target') or fs.frequentUpdates) then |
local timer |
if(type(fs.frequentUpdates) == 'number') then |
timer = fs.frequentUpdates |
else |
timer = .5 |
end |
if(not eventlessUnits[timer]) then eventlessUnits[timer] = {} end |
table.insert(eventlessUnits[timer], fs) |
createOnUpdate(timer) |
else |
RegisterEvents(fs, tagstr) |
end |
table.insert(self.__tags, fs) |
end |
local Untag = function(self, fs) |
if(not fs) then return end |
UnregisterEvents(fs) |
for _, timers in next, eventlessUnits do |
for k, fontstr in next, timers do |
if(fs == fontstr) then |
table.remove(timers, k) |
end |
end |
end |
for k, fontstr in next, self.__tags do |
if(fontstr == fs) then |
table.remove(self.__tags, k) |
end |
end |
fs.UpdateTag = nil |
end |
oUF.Tags = { |
Methods = tags, |
Events = tagEvents, |
SharedEvents = unitlessEvents, |
} |
oUF:RegisterMetaFunction('Tag', Tag) |
oUF:RegisterMetaFunction('Untag', Untag) |
## Interface: 60000 |
## Title: oUF |
## Author: Haste |
## Version: 1.6.8 |
## OptionalDeps: Clique |
## X-eMail: troeks@gmail.com |
## X-oUF: oUF |
## Notes: Unit frame framework. Does nothing by itself. |
## Notes-ruRU: ÐаÑÐºÐ°Ñ Ð´Ð»Ñ Ð¼Ð¾Ð´Ð¸ÑикаÑии ÑÑеймов игÑоков. Сам по Ñебе не Ð´ÐµÐ»Ð°ÐµÑ Ð½Ð¸Ñего. |
oUF.xml |
local parent, ns = ... |
local oUF = ns.oUF or oUF |
local function Update(self, event, unit) |
if(self.unit ~= unit) then return end |
local ta = self.TotalAbsorb |
if(ta.PreUpdate) then ta:PreUpdate(unit) end |
local allAbsorbs = UnitGetTotalAbsorbs(unit) or 0 |
local health, maxHealth = UnitHealth(unit), UnitHealthMax(unit) |
--[[if(health + allAbsorbs > maxHealth * ta.maxOverflow) then |
allAbsorbs = maxHealth * ta.maxOverflow - health |
end--]] |
ta:SetMinMaxValues(0, maxHealth) |
ta:SetValue(allAbsorbs) |
ta:Show() |
if(ta.PostUpdate) then |
return ta:PostUpdate(unit) |
end |
end |
local function Path(self, ...) |
return (self.TotalAbsorb.Override or Update) (self, ...) |
end |
local ForceUpdate = function(element) |
return Path(element.__owner, 'ForceUpdate', element.__owner.unit) |
end |
local function Enable(self) |
local ta = self.TotalAbsorb |
if(ta) then |
ta.__owner = self |
ta.ForceUpdate = ForceUpdate |
self:RegisterEvent('UNIT_ABSORB_AMOUNT_CHANGED', Path) |
self:RegisterEvent('UNIT_MAXHEALTH', Path) |
self:RegisterEvent('UNIT_HEALTH', Path) |
if(not ta.maxOverflow) then |
ta.maxOverflow = 1.05 |
end |
if(ta and ta:IsObjectType'StatusBar' and not ta:GetStatusBarTexture()) then |
ta:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]]) |
end |
return true |
end |
end |
local function Disable(self) |
local ta = self.TotalAbsorb |
if(ta) then |
self:UnregisterEvent('UNIT_ABSORB_AMOUNT_CHANGED', Path) |
self:UnregisterEvent('UNIT_MAXHEALTH', Path) |
self:UnregisterEvent('UNIT_HEALTH', Path) |
end |
end |
oUF:AddElement('TotalAbsorb', Path, Enable, Disable) |
local parent, ns = ... |
local oUF = ns.oUF or oUF |
-- oUF range element with code sniplets from TomTom |
local _FRAMES = {} |
local OnRangeFrame |
local update = .10 |
local UnitInRange, UnitIsConnected = UnitInRange, UnitIsConnected |
local SetMapToCurrentZone, WorldMapFrame = SetMapToCurrentZone, WorldMapFrame |
local GetPlayerMapPosition, GetPlayerFacing = GetPlayerMapPosition, GetPlayerFacing |
local select, next = select, next |
local pi = math.pi |
local twopi = pi * 2 |
local atan2 = math.atan2 |
local modf = math.modf |
local abs = math.abs |
local floor = floor |
local function ColorGradient(perc, ...) |
local num = select("#", ...) |
local hexes = type(select(1, ...)) == "string" |
if perc == 1 then |
return select(num-2, ...), select(num-1, ...), select(num, ...) |
end |
num = num / 3 |
local segment, relperc = modf(perc*(num-1)) |
local r1, g1, b1, r2, g2, b2 |
r1, g1, b1 = select((segment*3)+1, ...), select((segment*3)+2, ...), select((segment*3)+3, ...) |
r2, g2, b2 = select((segment*3)+4, ...), select((segment*3)+5, ...), select((segment*3)+6, ...) |
if not r2 or not g2 or not b2 then |
return r1, g1, b1 |
else |
return r1 + (r2-r1)*relperc, |
g1 + (g2-g1)*relperc, |
b1 + (b2-b1)*relperc |
end |
end |
local function ColorTexture(texture, angle) |
local perc = abs((pi - abs(angle)) / pi) |
local gr,gg,gb = 0, 1, 0 |
local mr,mg,mb = 1, 1, 0 |
local br,bg,bb = 1, 0, 0 |
local r,g,b = ColorGradient(perc, br, bg, bb, mr, mg, mb, gr, gg, gb) |
texture:SetVertexColor(r,g,b) |
end |
local function RotateTexture(frame, angle) |
if not frame:IsShown() then |
frame:Show() |
end |
angle = angle - GetPlayerFacing() |
local cell = floor(angle / twopi * 108 + 0.5) % 108 |
if cell == frame.cell then return end |
frame.cell = cell |
local column = cell % 9 |
local row = floor(cell / 9) |
ColorTexture(frame.arrow, angle) |
local xstart = (column * 56) / 512 |
local ystart = (row * 42) / 512 |
local xend = ((column + 1) * 56) / 512 |
local yend = ((row + 1) * 42) / 512 |
frame.arrow:SetTexCoord(xstart,xend,ystart,yend) |
end |
local px, py, tx, ty |
local function GetBearing(unit) |
if unit == 'player' then return end |
px, py = GetPlayerMapPosition("player") |
if((px or 0)+(py or 0) <= 0) then |
if WorldMapFrame:IsVisible() then return end |
SetMapToCurrentZone() |
px, py = GetPlayerMapPosition("player") |
if((px or 0)+(py or 0) <= 0) then return end |
end |
tx, ty = GetPlayerMapPosition(unit) |
if((tx or 0)+(ty or 0) <= 0) then return end |
return pi - atan2(px-tx,ty-py) |
end |
function ns:arrow(object, unit) |
if(not object.OoR or not UnitIsConnected(unit)) then return end |
local bearing = GetBearing(unit) |
if bearing then |
RotateTexture(object.freebarrow, bearing) |
end |
end |
local timer = 0 |
local OnRangeUpdate = function(self, elapsed) |
timer = timer + elapsed |
if(timer >= update) then |
for _, object in next, _FRAMES do |
if(object:IsShown()) then |
local range = object.freebRange |
if(UnitIsConnected(object.unit)) then |
local inRange, checkRange = UnitInRange(object.unit) |
if(checkRange and not inRange) then |
object:SetAlpha(range.outsideAlpha) |
object.OoR = true |
--print(object.arrowmouseover) |
if (object.arrowmouseover == true) then |
local bearing = GetBearing(object.unit) |
if bearing then |
RotateTexture(object.freebarrow, bearing) |
elseif object.freebarrow:IsShown() then |
object.freebarrow:Hide() |
end |
end |
else |
object.OoR = false |
if(object:GetAlpha() ~= range.insideAlpha) then |
object:SetAlpha(range.insideAlpha) |
if (object.freebarrow:IsShown()) then |
object.freebarrow:Hide() |
end |
end |
end |
end |
elseif(object.freebarrow:IsShown()) then |
object.freebarrow:Hide() |
end |
end |
timer = 0 |
end |
end |
local Enable = function(self) |
local range = self.freebRange |
if(range and range.insideAlpha and range.outsideAlpha) then |
table.insert(_FRAMES, self) |
if(not OnRangeFrame) then |
OnRangeFrame = CreateFrame"Frame" |
OnRangeFrame:SetScript("OnUpdate", OnRangeUpdate) |
end |
OnRangeFrame:Show() |
local frame = CreateFrame("Frame", nil, UIParent) |
frame:SetAllPoints(self) |
frame:SetFrameStrata("HIGH") |
frame:SetScale(1) |
frame.arrow = frame:CreateTexture(nil, "OVERLAY") |
frame.arrow:SetTexture(bdCore.media.arrow) |
frame.arrow:SetPoint("TOPRIGHT", frame, "TOPRIGHT") |
frame.arrow:SetSize(24, 24) |
self.freebarrow = frame |
self.freebarrow:Hide() |
return true |
end |
end |
local Disable = function(self) |
local range = self.freebRange |
if(range) then |
for k, frame in next, _FRAMES do |
if(frame == self) then |
table.remove(_FRAMES, k) |
break |
end |
end |
if(#_FRAMES == 0) then |
OnRangeFrame:Hide() |
end |
end |
end |
oUF:AddElement('freebRange', nil, Enable, Disable) |