remove temp folder structure

This commit is contained in:
Crum
2018-02-19 21:03:21 -06:00
parent 85a2a5bcf7
commit 611f11aff9
408 changed files with 0 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
Copyright (c) 2006-2017 Trond A Ekseth <troeks@gmail.com>
Copyright (c) 2016-2017 Val Voronov <i.lightspark@gmail.com>
Copyright (c) 2016-2017 Adrian L Lange <contact@p3lim.net>
Copyright (c) 2016-2017 Rainrider <rainrider.wow@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.
+72
View File
@@ -0,0 +1,72 @@
local ns = oUF
local oUF = ns.oUF
local hiddenParent = CreateFrame("Frame")
-- sourced from FrameXML/PartyMemberFrame.lua
local MAX_PARTY_MEMBERS = MAX_PARTY_MEMBERS or 4
local hiddenParent = CreateFrame('Frame', nil, UIParent)
hiddenParent:SetAllPoints()
hiddenParent:Hide()
local function handleFrame(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 or frame.healthbar
if(health) then
health:UnregisterAllEvents()
end
local power = frame.manabar
if(power) then
power:UnregisterAllEvents()
end
local spell = frame.castBar or frame.spellbar
if(spell) then
spell:UnregisterAllEvents()
end
local buffFrame = frame.BuffFrame
if(buffFrame) then
buffFrame:UnregisterAllEvents()
end
end
end
function oUF:DisableBlizzard(unit)
if(not unit) then return end
if(unit == 'player') then
handleFrame(PlayerFrame)
elseif(unit == 'pet') then
handleFrame(PetFrame)
elseif(unit == 'target') then
handleFrame(TargetFrame)
handleFrame(ComboFrame)
elseif(unit == 'targettarget') then
handleFrame(TargetofTargetFrame)
elseif(unit:match('party%d?$')) then
local id = unit:match('party(%d)')
if(id) then
handleFrame('PartyMemberFrame' .. id)
else
for i = 1, MAX_PARTY_MEMBERS do
handleFrame(string.format('PartyMemberFrame%d', i))
end
end
end
end
+234
View File
@@ -0,0 +1,234 @@
local ns = oUF
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
},
health = {49 / 255, 207 / 255, 37 / 255},
disconnected = {.6, .6, .6},
tapped = {.6, .6, .6},
class = {},
reaction = {},
power = {},
}
-- We do this because people edit the vars directly, and changing the default
-- globals makes SPICE FLOW!
local function customClassColors()
if(CUSTOM_CLASS_COLORS) then
local function updateColors()
for classToken, color in next, CUSTOM_CLASS_COLORS do
colors.class[classToken] = {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 classToken, color in next, RAID_CLASS_COLORS do
colors.class[classToken] = {color.r, color.g, color.b}
end
local eventHandler = CreateFrame('Frame')
eventHandler:RegisterEvent('ADDON_LOADED')
eventHandler:SetScript('OnEvent', function(self)
if(customClassColors()) then
self:UnregisterEvent('ADDON_LOADED')
self: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
colors.power = {}
colors.power[0] = {0.00, 0.00, 1.00}
colors.power[1] = {1.00, 0.00, 0.00}
colors.power[2] = {1.00, 0.50, 0.25}
colors.power[3] = {1.00, 1.00, 0.00}
colors.power[4] = {0.00, 1.00, 1.00}
local function colorsAndPercent(a, b, ...)
if(a <= 0 or b == 0) then
return nil, unpack(arg)
elseif(a >= b) then
return nil, select(select('#', unpack(arg)) - 2, unpack(arg))
end
local num = select('#', unpack(arg)) / 3
local segment, relperc = math.modf((a / b) * (num - 1))
return relperc, select((segment * 3) + 1, unpack(arg))
end
-- http://www.wowwiki.com/ColorGradient
--[[ Colors: oUF:RGBColorGradient(a, b, ...)
Used to convert a percent value (the quotient of `a` and `b`) into a gradient from 2 or more RGB colors. If more than 2
colors are passed, the gradient will be between the two colors which perc lies in an evenly divided range. A RGB color
is a sequence of 3 consecutive RGB percent values (in the range [0-1]). If `a` is negative or `b` is zero then the first
RGB color (the first 3 RGB values passed to the function) is returned. If `a` is bigger than or equal to `b`, then the
last 3 RGB values are returned.
* self - the global oUF object
* a - value used as numerator to calculate the percentage (number)
* b - value used as denominator to calculate the percentage (number)
* ... - a list of RGB percent values. At least 6 values should be passed (number [0-1])
--]]
local function RGBColorGradient(...)
local relperc, r1, g1, b1, r2, g2, b2 = colorsAndPercent(unpack(arg))
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
--[[ Colors: oUF:RGBToHCY(r, g, b)
Used to convert a color from RGB to HCY color space.
* self - the global oUF object
* r - red color component (number [0-1])
* g - green color component (number [0-1])
* b - blue color component (number [0-1])
--]]
function oUF: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 = math.mod((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 math_abs = math.abs
--[[ Colors: oUF:HCYtoRGB(hue, chroma, luma)
Used to convert a color from HCY to RGB color space.
* self - the global oUF object
* hue - hue color component (number [0-1])
* chroma - chroma color component (number [0-1])
* luma - luminance color component (number [0-1])
--]]
function oUF: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 - math_abs(math.mod(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
--[[ Colors: oUF:HCYColorGradient(a, b, ...)
Used to convert a percent value (the quotient of `a` and `b`) into a gradient from 2 or more HCY colors. If more than 2
colors are passed, the gradient will be between the two colors which perc lies in an evenly divided range. A HCY color
is a sequence of 3 consecutive values in the range [0-1]. If `a` is negative or `b` is zero then the first
HCY color (the first 3 HCY values passed to the function) is returned. If `a` is bigger than or equal to `b`, then the
last 3 HCY values are returned.
* self - the global oUF object
* a - value used as numerator to calculate the percentage (number)
* b - value used as denominator to calculate the percentage (number)
* ... - a list of HCY color values. At least 6 values should be passed (number [0-1])
--]]
local function HCYColorGradient(...)
local relperc, r1, g1, b1, r2, g2, b2 = colorsAndPercent(unpack(arg))
if(not relperc) then
return r1, g1, b1
end
local h1, c1, y1 = self:RGBToHCY(r1, g1, b1)
local h2, c2, y2 = self: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 self:HCYtoRGB(math.mod(h1 + dh * relperc, 1), c, y)
else
return self:HCYtoRGB(h1 or h2, c, y)
end
end
--[[ Colors: oUF:ColorGradient(a, b, ...) or frame:ColorGradient(a, b, ...)
Used as a proxy to call the proper gradient function depending on the user's preference. If `oUF.useHCYColorGradient` is
set to true, `:HCYColorGradient` will be called, else `:RGBColorGradient`.
* self - the global oUF object or a unit frame
* a - value used as numerator to calculate the percentage (number)
* b - value used as denominator to calculate the percentage (number)
* ... - a list of color values. At least 6 values should be passed (number [0-1])
--]]
local function ColorGradient(...)
return (oUF.useHCYColorGradient and HCYColorGradient or RGBColorGradient)(unpack(arg))
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
@@ -0,0 +1,103 @@
--[[
# Element: Assistant Indicator
Toggles the visibility of an indicator based on the unit's raid assistant status.
## Widget
AssistantIndicator - Any UI widget.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
-- Position and size
local AssistantIndicator = self:CreateTexture(nil, 'OVERLAY')
AssistantIndicator:SetSize(16, 16)
AssistantIndicator:SetPoint('TOP', self)
-- Register it with oUF
self.AssistantIndicator = AssistantIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local UnitInRaid = UnitInRaid
local UnitIsPartyLeader = UnitIsPartyLeader
local UnitIsRaidOfficer = UnitIsRaidOfficer
local function Update(self, event)
local element = self.AssistantIndicator
--[[ Callback: AssistantIndicator:PreUpdate()
Called before the element has been updated.
* self - the AssistantIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local unit = self.unit
local isAssistant = UnitInRaid(unit) and not UnitIsPartyLeader(unit)
if(isAssistant) then
element:Show()
else
element:Hide()
end
--[[ Callback: AssistantIndicator:PostUpdate(isAssistant)
Called after the element has been updated.
* self - the AssistantIndicator element
* isAssistant - indicates whether the unit is a raid assistant (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(isAssistant)
end
end
local function Path(self, ...)
--[[ Override: AssistantIndicator.Override(self, event, ...)
Used to completely override the element's update process.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event (string)
--]]
return (self.AssistantIndicator.Override or Update) (self, unpack(arg))
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self)
local element = self.AssistantIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('PARTY_MEMBERS_CHANGED', Path)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\GroupFrame\UI-Group-AssistantIcon]])
end
return true
end
end
local function Disable(self)
local element = self.AssistantIndicator
if(element) then
element:Hide()
self:UnregisterEvent('PARTY_MEMBERS_CHANGED', Path)
end
end
oUF:AddElement('AssistantIndicator', Path, Enable, Disable)
+516
View File
@@ -0,0 +1,516 @@
--[[
# Element: Auras
Handles creation and updating of aura icons.
## Widget
Auras - A Frame to hold `Button`s representing both buffs and debuffs.
Buffs - A Frame to hold `Button`s representing buffs.
Debuffs - A Frame to hold `Button`s representing debuffs.
## Notes
At least one of the above widgets must be present for the element to work.
## Options
.disableMouse - Disables mouse events (boolean)
.disableCooldown - Disables the cooldown spiral (boolean)
.size - Aura icon size. Defaults to 16 (number)
.spacing - Spacing between each icon. Defaults to 0 (number)
.['spacing-x'] - Horizontal spacing between each icon. Takes priority over `spacing` (number)
.['spacing-y'] - Vertical spacing between each icon. Takes priority over `spacing` (number)
.['growth-x'] - Horizontal growth direction. Defaults to 'RIGHT' (string)
.['growth-y'] - Vertical growth direction. Defaults to 'UP' (string)
.initialAnchor - Anchor point for the icons. Defaults to 'BOTTOMLEFT' (string)
.filter - Custom filter list for auras to display. Defaults to 'HELPFUL' for buffs and 'HARMFUL' for
debuffs (string)
## Options Auras
.numBuffs - The maximum number of buffs to display. Defaults to 32 (number)
.numDebuffs - The maximum number of debuffs to display. Defaults to 40 (number)
.numTotal - The maximum number of auras to display. Prioritizes buffs over debuffs. Defaults to the sum of
.numBuffs and .numDebuffs (number)
.gap - Controls the creation of an invisible icon between buffs and debuffs. Defaults to false (boolean)
.buffFilter - Custom filter list for buffs to display. Takes priority over `filter` (string)
.debuffFilter - Custom filter list for debuffs to display. Takes priority over `filter` (string)
## Options Buffs
.num - Number of buffs to display. Defaults to 32 (number)
## Options Debuffs
.num - Number of debuffs to display. Defaults to 40 (number)
## Attributes
button.filter - the filter list used to determine the visibility of the aura (string)
button.isDebuff - indicates if the button holds a debuff (boolean)
## 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
--]]
local ns = oUF
local oUF = ns.oUF
local tinsert = table.insert
local floor = math.floor
local CreateFrame = CreateFrame
local GetTime = GetTime
local UnitAura = UnitAura
local VISIBLE = 1
local HIDDEN = 0
local function UpdateTooltip(self)
if self.filter == 'HELPFUL' then
GameTooltip:SetUnitBuff(self:GetParent().__owner.unit, self:GetID(), self.filter)
else
GameTooltip:SetUnitDebuff(self:GetParent().__owner.unit, self:GetID(), self.filter)
end
end
local function onEnter(self)
if(not self:IsVisible()) then return end
GameTooltip:SetOwner(self, 'ANCHOR_BOTTOMRIGHT')
self:UpdateTooltip()
end
local function onLeave()
GameTooltip:Hide()
end
local function createAuraIcon(element, index)
local button = CreateFrame('Button', '$parentButton' .. index, element)
button:RegisterForClicks('RightButtonUp')
local cd = CreateFrame('Cooldown', '$parentCooldown', button, 'oUF_CooldownFrameTemplate')
cd:SetAllPoints()
local icon = button:CreateTexture(nil, 'BORDER')
icon:SetAllPoints()
local count = button:CreateFontString(nil, 'OVERLAY', 'NumberFontNormal')
count:SetPoint('BOTTOMRIGHT', button, 'BOTTOMRIGHT', -1, 0)
local overlay = button:CreateTexture(nil, 'OVERLAY')
overlay:SetTexture([[Interface\Buttons\UI-Debuff-Overlays]])
overlay:SetAllPoints()
overlay:SetTexCoord(.296875, .5703125, 0, .515625)
button.overlay = overlay
button.UpdateTooltip = UpdateTooltip
button:SetScript('OnEnter', onEnter)
button:SetScript('OnLeave', onLeave)
button.icon = icon
button.count = count
button.cd = cd
--[[ Callback: Auras:PostCreateIcon(button)
Called after a new aura button has been created.
* self - the widget holding the aura buttons
* button - the newly created aura button (Button)
--]]
if(element.PostCreateIcon) then element:PostCreateIcon(button) end
return button
end
local function customFilter(element, unit, button, name)
if(name) then
return true
end
end
local function updateIcon(element, unit, index, offset, filter, isDebuff, visible)
local name, rank, texture, count, dispelType, duration, expiration = UnitAura(unit, index, filter)
if element.forceShow then
name, rank, texture = GetSpellInfo(26993)
count, dispelType, duration, expiration = 5, 'Magic', 0, 60
end
if(name) then
local position = visible + offset + 1
local button = element[position]
if(not button) then
--[[ Override: Auras:CreateIcon(position)
Used to create the aura button at a given position.
* self - the widget holding the aura buttons
* position - the position at which the aura button is to be created (number)
## Returns
* button - the button used to represent the aura (Button)
--]]
button = (element.CreateIcon or createAuraIcon) (element, position)
tinsert(element, button)
element.createdIcons = element.createdIcons + 1
end
button.filter = filter
button.isDebuff = isDebuff
--[[ Override: Auras:CustomFilter(unit, button, ...)
Defines a custom filter that controls if the aura button should be shown.
* self - the widget holding the aura buttons
* unit - the unit on which the aura is cast (string)
* button - the button displaying the aura (Button)
* ... - the return values from [UnitAura](http://wowprogramming.com/docs/api/UnitAura)
## Returns
* show - indicates whether the aura button should be shown (boolean)
--]]
local show = true
if not element.forceShow then
show = (element.CustomFilter or customFilter) (element, unit, button, name, rank, texture, count, dispelType, duration, expiration)
end
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.
if(button.cd and not element.disableCooldown) then
if(duration and duration > 0) then
button.cd:SetCooldown(GetTime() - (duration - expiration), duration)
button.cd:Show()
else
button.cd:Hide()
end
end
if(button.overlay) then
if((isDebuff and element.showDebuffType) or (not isDebuff and element.showBuffType) or element.showType) then
local color = DebuffTypeColor[dispelType] or DebuffTypeColor.none
button.overlay:SetVertexColor(color.r, color.g, color.b)
button.overlay:Show()
else
button.overlay:Hide()
end
end
if(button.icon) then button.icon:SetTexture(texture) end
if(button.count) then button.count:SetText(count > 1 and count) end
local size = element.size or 16
button:SetSize(size, size)
button:EnableMouse(not element.disableMouse)
button:SetID(index)
button:Show()
--[[ Callback: Auras:PostUpdateIcon(unit, button, index, position)
Called after the aura button has been updated.
* self - the widget holding the aura buttons
* unit - the unit on which the aura is cast (string)
* button - the updated aura button (Button)
* index - the index of the aura (number)
* position - the actual position of the aura button (number)
--]]
if(element.PostUpdateIcon) then
element:PostUpdateIcon(unit, button, index, position)
end
return VISIBLE
else
return HIDDEN
end
end
end
local function SetPosition(element, from, to)
local sizex = (element.size or 16) + (element['spacing-x'] or element.spacing or 0)
local sizey = (element.size or 16) + (element['spacing-y'] or element.spacing or 0)
local anchor = element.initialAnchor or 'BOTTOMLEFT'
local growthx = (element['growth-x'] == 'LEFT' and -1) or 1
local growthy = (element['growth-y'] == 'DOWN' and -1) or 1
local cols = floor(element:GetWidth() / sizex + 0.5)
for i = from, to do
local button = element[i]
-- Bail out if the to range is out of scope.
if(not button) then break end
local col = (i - 1) % cols
local row = floor((i - 1) / cols)
button:ClearAllPoints()
button:SetPoint(anchor, element, anchor, col * sizex * growthx, row * sizey * growthy)
end
end
local function filterIcons(element, unit, 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(element, unit, 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, #element do
element[i]:Hide()
end
end
return visible, hidden
end
local function UpdateAuras(self, event, unit)
if(self.unit ~= unit) then return end
local auras = self.Auras
if(auras) then
--[[ Callback: Auras:PreUpdate(unit)
Called before the element has been updated.
* self - the widget holding the aura buttons
* unit - the unit for which the update has been triggered (string)
--]]
if(auras.PreUpdate) then auras:PreUpdate(unit) end
local numBuffs = auras.numBuffs or 32
local numDebuffs = auras.numDebuffs or 40
local max = auras.numTotal or numBuffs + numDebuffs
local visibleBuffs, hiddenBuffs = filterIcons(auras, unit, auras.buffFilter or auras.filter or 'HELPFUL', math.min(numBuffs, max), nil, 0, true)
local hasGap
if(visibleBuffs ~= 0 and auras.gap) then
hasGap = true
visibleBuffs = visibleBuffs + 1
local button = auras[visibleBuffs]
if(not button) then
button = (auras.CreateIcon or createAuraIcon) (auras, visibleBuffs)
tinsert(auras, button)
auras.createdIcons = auras.createdIcons + 1
end
-- Prevent the button from displaying anything.
if(button.cd) then button.cd:Hide() end
if(button.icon) then button.icon:SetTexture() end
if(button.overlay) then button.overlay:Hide() end
if(button.stealable) then button.stealable:Hide() end
if(button.count) then button.count:SetText() end
button:EnableMouse(false)
button:Show()
--[[ Callback: Auras:PostUpdateGapIcon(unit, gapButton, visibleBuffs)
Called after an invisible aura button has been created. Only used by Auras when the `gap` option is enabled.
* self - the widget holding the aura buttons
* unit - the unit that has the invisible aura button (string)
* gapButton - the invisible aura button (Button)
* visibleBuffs - the number of currently visible aura buttons (number)
--]]
if(auras.PostUpdateGapIcon) then
auras:PostUpdateGapIcon(unit, button, visibleBuffs)
end
end
local visibleDebuffs, hiddenDebuffs = filterIcons(auras, unit, auras.debuffFilter or auras.filter or 'HARMFUL', math.min(numDebuffs, max - visibleBuffs), 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
--[[ Callback: Auras:PreSetPosition(max)
Called before the aura buttons have been (re-)anchored.
* self - the widget holding the aura buttons
* max - the maximum possible number of aura buttons (number)
## Returns
* from - the offset of the first aura button to be (re-)anchored (number)
* to - the offset of the last aura button to be (re-)anchored (number)
--]]
if(auras.PreSetPosition) then
fromRange, toRange = auras:PreSetPosition(max)
end
if(fromRange or auras.createdIcons > auras.anchoredIcons) then
--[[ Override: Auras:SetPosition(from, to)
Used to (re-)anchor the aura buttons.
Called when new aura buttons have been created or if :PreSetPosition is defined.
* self - the widget that holds the aura buttons
* from - the offset of the first aura button to be (re-)anchored (number)
* to - the offset of the last aura button to be (re-)anchored (number)
--]]
(auras.SetPosition or SetPosition) (auras, fromRange or auras.anchoredIcons + 1, toRange or auras.createdIcons)
auras.anchoredIcons = auras.createdIcons
end
--[[ Callback: Auras:PostUpdate(unit)
Called after the element has been updated.
* self - the widget holding the aura buttons
* unit - the unit for which the update has been triggered (string)
--]]
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(buffs, unit, 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(debuffs, unit, 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 function Update(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 function ForceUpdate(element)
return Update(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(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 = buffs.createdIcons or 0
buffs.anchoredIcons = 0
--buffs:Show()
end
local debuffs = self.Debuffs
if(debuffs) then
debuffs.__owner = self
debuffs.ForceUpdate = ForceUpdate
debuffs.createdIcons = debuffs.createdIcons or 0
debuffs.anchoredIcons = 0
--debuffs:Show()
end
local auras = self.Auras
if(auras) then
auras.__owner = self
auras.ForceUpdate = ForceUpdate
auras.createdIcons = auras.createdIcons or 0
auras.anchoredIcons = 0
--auras:Show()
end
return true
end
end
local function Disable(self)
if(self.Buffs or self.Debuffs or self.Auras) then
self:UnregisterEvent('UNIT_AURA', UpdateAuras)
if(self.Buffs) then self.Buffs:Hide() end
if(self.Debuffs) then self.Debuffs:Hide() end
if(self.Auras) then self.Auras:Hide() end
end
end
oUF:AddElement('Auras', Update, Enable, Disable)
+585
View File
@@ -0,0 +1,585 @@
--[[
# Element: Castbar
Handles the visibility and updating of spell castbars.
Based upon oUF_Castbar by starlon.
## Widget
Castbar - A `StatusBar` to represent spell cast/channel progress.
## Sub-Widgets
.Text - A `FontString` to represent spell name.
.Icon - A `Texture` to represent spell icon.
.Time - A `FontString` to represent spell duration.
.SafeZone - A `Texture` to represent latency.
## Notes
A default texture will be applied to the StatusBar and Texture widgets if they don't have a texture or a color set.
## Options
.timeToHold - indicates for how many seconds the castbar should be visible after a _FAILED or _INTERRUPTED
event. Defaults to 0 (number)
## 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 safezone
local SafeZone = Castbar:CreateTexture(nil, 'OVERLAY')
-- Register it with oUF
Castbar.bg = Background
Castbar.Spark = Spark
Castbar.Time = Time
Castbar.Text = Text
Castbar.Icon = Icon
Castbar.SafeZone = SafeZone
self.Castbar = Castbar
--]]
local ns = oUF
local oUF = ns.oUF
local GetNetStats = GetNetStats
local GetTime = GetTime
local UnitCastingInfo = UnitCastingInfo
local UnitChannelInfo = UnitChannelInfo
local UnitIsUnit = UnitIsUnit
local tradeskillCastTime, tradeskillCastDuration, tradeskillCurrent, tradeskillTotal, mergeTradeskill = 0, 0, 0, 0, false
local function updateSafeZone(self)
local safeZone = self.SafeZone
local width = self:GetWidth()
local _, _, ms = GetNetStats()
-- Guard against GetNetStats returning latencies of 0.
if(ms ~= 0) then
local safeZoneRatio = (ms / 1e3) / self.max
if(safeZoneRatio > 1) then
safeZoneRatio = 1
end
safeZone:SetWidth(width * safeZoneRatio)
safeZone:Show()
else
safeZone:Hide()
end
end
local function UNIT_SPELLCAST_SENT(self, event, unit, spell, rank, target)
local element = self.Castbar
element.curTarget = (target and target ~= '') and target or nil
if element.isTradeSkill then
element.tradeSkillCastName = spell
end
end
local function UNIT_SPELLCAST_START(self, event, unit)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local element = self.Castbar
local name, _, text, texture, startTime, endTime, isTradeSkill = UnitCastingInfo(unit)
if(not name) then
return element:Hide()
end
endTime = endTime / 1e3
startTime = startTime / 1e3
local max = endTime - startTime
element.castName = name
element.duration = GetTime() - startTime
element.max = max
element.delay = 0
element.casting = true
element.holdTime = 0
element.isTradeSkill = isTradeSkill
if(mergeTradeskill and isTradeSkill and UnitIsUnit(unit, 'player')) then
element.duration = element.duration + (element.max * tradeskillCurrent)
element.max = max * tradeskillTotal
if(unit == 'player') then
tradeskillCurrent = tradeskillCurrent + 1
tradeskillCastDuration = element.duration
tradeskillCastTime = max
end
element:SetValue(element.duration)
else
element:SetValue(0)
end
element:SetMinMaxValues(0, element.max)
if(element.Text) then element.Text:SetText(text) end
if(element.Icon) then element.Icon:SetTexture(texture) end
if(element.Time) then element.Time:SetText() end
local sf = element.SafeZone
if(sf) then
sf:ClearAllPoints()
sf:SetPoint('RIGHT')
sf:SetPoint('TOP')
sf:SetPoint('BOTTOM')
updateSafeZone(element)
end
--[[ Callback: Castbar:PostCastStart(unit, name)
Called after the element has been updated upon a spell cast start.
* self - the Castbar widget
* unit - unit for which the update has been triggered (string)
* name - name of the spell being cast (string)
--]]
if(element.PostCastStart) then
element:PostCastStart(unit, name)
end
element:Show()
end
local function UNIT_SPELLCAST_FAILED(self, event, unit, spellname)
if(not self.casting) then return end
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local element = self.Castbar
if(spellname and (element.castName ~= spellname and element.tradeSkillCastName ~= spellname)) then
return
end
if(mergeTradeskill and UnitIsUnit(unit, 'player')) then
mergeTradeskill = false
element.tradeSkillCastName = nil
end
local text = element.Text
if(text) then
text:SetText(FAILED)
end
element.casting = nil
element.holdTime = element.timeToHold or 0
--[[ Callback: Castbar:PostCastFailed(unit, name)
Called after the element has been updated upon a failed spell cast.
* self - the Castbar widget
* unit - unit for which the update has been triggered (string)
* name - name of the failed spell (string)
--]]
if(element.PostCastFailed) then
return element:PostCastFailed(unit, spellname)
end
end
local function UNIT_SPELLCAST_FAILED_QUIET(self, event, unit, spellname)
if(not self.casting) then return end
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local element = self.Castbar
if(spellname and (element.castName ~= spellname and element.tradeSkillCastName ~= spellname)) then
return
end
if(mergeTradeskill and UnitIsUnit(unit, 'player')) then
mergeTradeskill = false
element.tradeSkillCastName = nil
end
element.casting = nil
element:SetValue(0)
element:Hide()
end
local function UNIT_SPELLCAST_INTERRUPTED(self, event, unit, spellname)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local element = self.Castbar
if(spellname and element.castName ~= spellname) then
return
end
local text = element.Text
if(text) then
text:SetText(INTERRUPTED)
end
element.casting = nil
element.channeling = nil
element.holdTime = element.timeToHold or 0
--[[ Callback: Castbar:PostCastInterrupted(unit, name)
Called after the element has been updated upon an interrupted spell cast.
* self - the Castbar widget
* unit - unit for which the update has been triggered (string)
* name - name of the interrupted spell (string)
--]]
if(element.PostCastInterrupted) then
return element:PostCastInterrupted(unit, spellname)
end
end
local function UNIT_SPELLCAST_DELAYED(self, event, unit)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local element = self.Castbar
local name, _, _, _, startTime = UnitCastingInfo(unit)
if(not startTime or not element:IsShown()) then return end
local duration = GetTime() - (startTime / 1000)
if(duration < 0) then duration = 0 end
element.delay = element.delay + element.duration - duration
element.duration = duration
element:SetValue(duration)
--[[ Callback: Castbar:PostCastDelayed(unit, name)
Called after the element has been updated when a spell cast has been delayed.
* self - the Castbar widget
* unit - unit that the update has been triggered (string)
* name - name of the delayed spell (string)
--]]
if(element.PostCastDelayed) then
return element:PostCastDelayed(unit, name)
end
end
local function UNIT_SPELLCAST_STOP(self, event, unit, spellname)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local element = self.Castbar
if(spellname and (element.castName ~= spellname)) then
return
end
if(mergeTradeskill and UnitIsUnit(unit, 'player')) then
if(tradeskillCurrent == tradeskillTotal) then
mergeTradeskill = false
end
else
element.casting = nil
end
--[[ Callback: Castbar:PostCastStop(unit, name)
Called after the element has been updated when a spell cast has finished.
* self - the Castbar widget
* unit - unit for which the update has been triggered (string)
* name - name of the spell (string)
--]]
if(element.PostCastStop) then
return element:PostCastStop(unit, spellname)
end
end
local function UNIT_SPELLCAST_CHANNEL_START(self, event, unit)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local element = self.Castbar
local name, _, _, texture, startTime, endTime = UnitChannelInfo(unit)
if(not name) then
return
end
endTime = endTime / 1e3
startTime = startTime / 1e3
local max = (endTime - startTime)
local duration = endTime - GetTime()
element.duration = duration
element.max = max
element.delay = 0
element.startTime = startTime
element.endTime = endTime
element.extraTickRatio = 0
element.channeling = true
element.holdTime = 0
-- 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.
element.casting = nil
element.castName = nil
element:SetMinMaxValues(0, max)
element:SetValue(duration)
if(element.Text) then element.Text:SetText(name) end
if(element.Icon) then element.Icon:SetTexture(texture) end
if(element.Time) then element.Time:SetText() end
local sf = element.SafeZone
if(sf) then
sf:ClearAllPoints()
sf:SetPoint('LEFT')
sf:SetPoint('TOP')
sf:SetPoint('BOTTOM')
updateSafeZone(element)
end
--[[ Callback: Castbar:PostChannelStart(unit, name)
Called after the element has been updated upon a spell channel start.
* self - the Castbar widget
* unit - unit for which the update has been triggered (string)
* name - name of the channeled spell (string)
--]]
if(element.PostChannelStart) then
element:PostChannelStart(unit, name)
end
element:Show()
end
local function UNIT_SPELLCAST_CHANNEL_UPDATE(self, event, unit)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local element = self.Castbar
local name, _, _, _, startTime, endTime = UnitChannelInfo(unit)
if(not name or not element:IsShown()) then
return
end
local duration = (endTime / 1000) - GetTime()
element.delay = element.delay + element.duration - duration
element.duration = duration
element.max = (endTime - startTime) / 1000
element.startTime = startTime / 1000
element.endTime = endTime / 1000
element:SetMinMaxValues(0, element.max)
element:SetValue(duration)
--[[ Callback: Castbar:PostChannelUpdate(unit, name)
Called after the element has been updated after a channeled spell has been delayed or interrupted.
* self - the Castbar widget
* unit - unit for which the update has been triggered (string)
* name - name of the channeled spell (string)
--]]
if(element.PostChannelUpdate) then
return element:PostChannelUpdate(unit, name)
end
end
local function UNIT_SPELLCAST_CHANNEL_STOP(self, event, unit, spellname)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local element = self.Castbar
if(element:IsShown()) then
element.channeling = nil
--[[ Callback: Castbar:PostChannelUpdate(unit, name)
Called after the element has been updated after a channeled spell has been completed.
* self - the Castbar widget
* unit - unit for which the update has been triggered (string)
* name - name of the channeled spell (string)
--]]
if(element.PostChannelStop) then
return element:PostChannelStop(unit, spellname)
end
end
end
local function onUpdate(self, elapsed)
if(self.casting) then
local duration = self.duration + elapsed
if(duration >= self.max or (tradeskillTotal > 1 and duration >= (tradeskillCastDuration + tradeskillCastTime * 1.25))) then
self.casting = nil
self:Hide()
tradeskillTotal = 0
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:SetText(format('%.1f|cffff0000-%.1f|r', duration, self.delay))
end
else
if(self.CustomTimeText) then
self:CustomTimeText(duration)
else
self.Time:SetText(format('%.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:SetText(format('%.1f|cffff0000-%.1f|r', duration, self.delay))
end
else
if(self.CustomTimeText) then
self:CustomTimeText(duration)
else
self.Time:SetText(format('%.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.holdTime > 0) then
self.holdTime = self.holdTime - elapsed
else
self.casting = nil
self.castName = nil
self.channeling = nil
tradeskillTotal = 0
self:Hide()
end
end
local function Update(self, ...)
UNIT_SPELLCAST_START(self, ...)
return UNIT_SPELLCAST_CHANNEL_START(self, ...)
end
local function ForceUpdate(element)
return Update(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self, unit)
local element = self.Castbar
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
if(not (unit and unit:match('%wtarget$'))) then
self:RegisterEvent('UNIT_SPELLCAST_START', UNIT_SPELLCAST_START)
self:RegisterEvent('UNIT_SPELLCAST_FAILED', UNIT_SPELLCAST_FAILED)
self:RegisterEvent('UNIT_SPELLCAST_STOP', UNIT_SPELLCAST_STOP)
self:RegisterEvent('UNIT_SPELLCAST_INTERRUPTED', UNIT_SPELLCAST_INTERRUPTED)
self:RegisterEvent('UNIT_SPELLCAST_DELAYED', UNIT_SPELLCAST_DELAYED)
self:RegisterEvent('UNIT_SPELLCAST_CHANNEL_START', UNIT_SPELLCAST_CHANNEL_START)
self:RegisterEvent('UNIT_SPELLCAST_CHANNEL_UPDATE', UNIT_SPELLCAST_CHANNEL_UPDATE)
self:RegisterEvent('UNIT_SPELLCAST_CHANNEL_STOP', UNIT_SPELLCAST_CHANNEL_STOP)
self:RegisterEvent('UNIT_SPELLCAST_SENT', UNIT_SPELLCAST_SENT, true)
self:RegisterEvent('UNIT_SPELLCAST_FAILED_QUIET', UNIT_SPELLCAST_FAILED_QUIET)
end
element.holdTime = 0
element:SetScript('OnUpdate', element.OnUpdate or onUpdate)
if(self.unit == 'player') then
CastingBarFrame:UnregisterAllEvents()
CastingBarFrame.Show = CastingBarFrame.Hide
CastingBarFrame:Hide()
PetCastingBarFrame:UnregisterAllEvents()
PetCastingBarFrame.Show = PetCastingBarFrame.Hide
PetCastingBarFrame:Hide()
end
if(element:IsObjectType('StatusBar') and not element:GetStatusBarTexture()) then
element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
local spark = element.Spark
if(spark and spark:IsObjectType('Texture') and not spark:GetTexture()) then
spark:SetTexture([[Interface\CastingBar\UI-CastingBar-Spark]])
end
local safeZone = element.SafeZone
if(safeZone and safeZone:IsObjectType('Texture') and not safeZone:GetTexture()) then
safeZone:SetTexture(1, 0, 0)
end
element:Hide()
return true
end
end
local function Disable(self)
local element = self.Castbar
if(element) then
element:Hide()
self:UnregisterEvent('UNIT_SPELLCAST_START', UNIT_SPELLCAST_START)
self:UnregisterEvent('UNIT_SPELLCAST_FAILED', UNIT_SPELLCAST_FAILED)
self:UnregisterEvent('UNIT_SPELLCAST_STOP', UNIT_SPELLCAST_STOP)
self:UnregisterEvent('UNIT_SPELLCAST_INTERRUPTED', UNIT_SPELLCAST_INTERRUPTED)
self:UnregisterEvent('UNIT_SPELLCAST_DELAYED', UNIT_SPELLCAST_DELAYED)
self:UnregisterEvent('UNIT_SPELLCAST_CHANNEL_START', UNIT_SPELLCAST_CHANNEL_START)
self:UnregisterEvent('UNIT_SPELLCAST_CHANNEL_UPDATE', UNIT_SPELLCAST_CHANNEL_UPDATE)
self:UnregisterEvent('UNIT_SPELLCAST_CHANNEL_STOP', UNIT_SPELLCAST_CHANNEL_STOP)
self:UnregisterEvent('UNIT_SPELLCAST_SENT', UNIT_SPELLCAST_SENT)
self:UnregisterEvent('UNIT_SPELLCAST_FAILED_QUIET', UNIT_SPELLCAST_FAILED_QUIET)
element:SetScript('OnUpdate', nil)
end
end
hooksecurefunc('DoTradeSkill', function(_, num)
tradeskillCastTime = 0
tradeskillCastDuration = 0
tradeskillCurrent = 0
tradeskillTotal = num or 1
mergeTradeskill = true
end)
oUF:AddElement('Castbar', Update, Enable, Disable)
@@ -0,0 +1,102 @@
--[[
# Element: Combat Indicator
Toggles the visibility of an indicator based on the player's combat status.
## Widget
CombatIndicator - Any UI widget.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
-- Position and size
local CombatIndicator = self:CreateTexture(nil, 'OVERLAY')
CombatIndicator:SetSize(16, 16)
CombatIndicator:SetPoint('TOP', self)
-- Register it with oUF
self.CombatIndicator = CombatIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local UnitAffectingCombat = UnitAffectingCombat
local function Update(self, event)
local element = self.CombatIndicator
--[[ Callback: CombatIndicator:PreUpdate()
Called before the element has been updated.
* self - the CombatIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local inCombat = UnitAffectingCombat('player')
if(inCombat) then
element:Show()
else
element:Hide()
end
--[[ Callback: CombatIndicator:PostUpdate(inCombat)
Called after the element has been updated.
* self - the CombatIndicator element
* inCombat - indicates if the player is affecting combat (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(inCombat)
end
end
local function Path(self, ...)
--[[ Override: CombatIndicator.Override(self, event)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
--]]
return (self.CombatIndicator.Override or Update) (self, unpack(arg))
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self, unit)
local element = self.CombatIndicator
if(element and unit == 'player') then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('PLAYER_REGEN_DISABLED', Path)
self:RegisterEvent('PLAYER_REGEN_ENABLED', Path)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\CharacterFrame\UI-StateIcon]])
element:SetTexCoord(.5, 1, 0, .49)
end
return true
end
end
local function Disable(self)
local element = self.CombatIndicator
if(element) then
element:Hide()
self:UnregisterEvent('PLAYER_REGEN_DISABLED', Path)
self:UnregisterEvent('PLAYER_REGEN_ENABLED', Path)
end
end
oUF:AddElement('CombatIndicator', Path, Enable, Disable)
@@ -0,0 +1,118 @@
--[[
# Element: ComboPoints
Handles the visibility and updating of the player's combo points.
## Widget
ComboPoints - An `table` consisting of as many Textures as the theoretical maximum return of [GetComboPoints](http://wowprogramming.com/docs/api/GetComboPoints).
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
local ComboPoints = {}
for index = 1, 10 do
local Bar = CreateFrame('StatusBar', nil, self)
-- Position and size.
Bar:SetSize(16, 16)
Bar:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', (index - 1) * Bar:GetWidth(), 0)
ComboPoints[index] = Bar
end
-- Register with oUF
self.ComboPoints = ComboPoints
--]]
local ns = oUF
local oUF = ns.oUF
local GetComboPoints = GetComboPoints
local MAX_COMBO_POINTS = MAX_COMBO_POINTS
local function Update(self, event)
local element = self.ComboPoints
--[[ Callback: ComboPoints:PreUpdate()
Called before the element has been updated.
* self - the ComboPoints element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local cp = GetComboPoints('player', 'target')
for i = 1, MAX_COMBO_POINTS do
if(i <= cp) then
element[i]:Show()
else
element[i]:Hide()
end
end
--[[ Callback: ComboPoints:PostUpdate(role)
Called after the element has been updated.
* self - the ComboPoints element
* cpoint - the current amount of combo points (number)
--]]
if(element.PostUpdate) then
return element:PostUpdate(cp)
end
end
local function Path(self, ...)
--[[ Override: ComboPoints.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.ComboPoints.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local element = self.ComboPoints
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('PLAYER_COMBO_POINTS', Path, true)
self:RegisterEvent('PLAYER_TARGET_CHANGED', Path, true)
for index = 1, MAX_COMBO_POINTS do
local cp = element[index]
if(cp:IsObjectType('Texture') and not cp:GetTexture()) then
cp:SetTexture([[Interface\ComboFrame\ComboPoint]])
cp:SetTexCoord(0, 0.375, 0, 1)
end
end
return true
end
end
local function Disable(self)
local element = self.ComboPoints
if(element) then
for index = 1, MAX_COMBO_POINTS do
element[index]:Hide()
end
self:UnregisterEvent('PLAYER_COMBO_POINTS', Path)
self:UnregisterEvent('PLAYER_TARGET_CHANGED', Path)
end
end
oUF:AddElement('ComboPoints', Path, Enable, Disable)
+22
View File
@@ -0,0 +1,22 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file="power.lua"/>
<!--<Script file="auras.lua"/>-->
<Script file="health.lua"/>
<Script file="raidtargetindicator.lua"/>
<Script file="leaderindicator.lua"/>
<Script file="combatindicator.lua"/>
<Script file="restingindicator.lua"/>
<!--<Script file="pvpindicator.lua"/>-->
<Script file="portrait.lua"/>
<!--
<Script file="range.lua"/>
<Script file="castbar.lua"/>-->
<Script file="tags.lua"/>
<Script file="masterlooterindicator.lua"/>
<Script file="assistantindicator.lua"/>
<!--<Script file="readycheckindicator.lua"/>
<Script file="combopoints.lua"/>
<Script file="raidroleindicator.lua"/>
<Script file="happinessindicator.lua"/>
-->
</Ui>
@@ -0,0 +1,116 @@
--[[
# Element: HappinessIndicator
Handles the visibility and updating of player pet happiness.
## Widget
HappinessIndicator - A `Texture` used to display the current happiness level.
The element works by changing the texture's vertex color.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
-- Position and size
local HappinessIndicator = self:CreateTexture(nil, 'OVERLAY')
HappinessIndicator:SetSize(16, 16)
HappinessIndicator:SetPoint('TOPRIGHT', self)
-- Register it with oUF
self.HappinessIndicator = HappinessIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local GetPetHappiness = GetPetHappiness
local HasPetUI = HasPetUI
local function Update(self, event, unit)
if(not unit or self.unit ~= unit) then return end
local element = self.HappinessIndicator
--[[ Callback: HappinessIndicator:PreUpdate()
Called before the element has been updated.
* self - the ComboPoints element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local _, hunterPet = HasPetUI()
local happiness, damagePercentage = GetPetHappiness()
if(hunterPet and happiness) then
if(happiness == 1) then
element:SetTexCoord(0.375, 0.5625, 0, 0.359375)
elseif(happiness == 2) then
element:SetTexCoord(0.1875, 0.375, 0, 0.359375)
elseif(happiness == 3) then
element:SetTexCoord(0, 0.1875, 0, 0.359375)
end
element:Show()
else
return element:Hide()
end
--[[ Callback: HappinessIndicator:PostUpdate(role)
Called after the element has been updated.
* self - the ComboPoints element
* unit - the unit for which the update has been triggered (string)
* happiness - the numerical happiness value of the pet (1 = unhappy, 2 = content, 3 = happy) (number)
* damagePercentage - damage modifier, happiness affects this (unhappy = 75%, content = 100%, happy = 125%) (number)
--]]
if(element.PostUpdate) then
return element:PostUpdate(unit, happiness, damagePercentage)
end
end
local function Path(self, ...)
--[[ Override: HappinessIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.HappinessIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local element = self.HappinessIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_HAPPINESS', Path)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\PetPaperDollFrame\UI-PetHappiness]])
end
return true
end
end
local function Disable(self)
local element = self.HappinessIndicator
if(element) then
element:Hide()
self:UnregisterEvent('UNIT_HAPPINESS', Path)
end
end
oUF:AddElement('HappinessIndicator', Path, Enable, Disable)
+292
View File
@@ -0,0 +1,292 @@
--[[
# Element: Health Bar
Handles the updating of a status bar that displays the unit's health.
## Widget
Health - A `StatusBar` used to represent the unit's health.
## Sub-Widgets
.bg - A `Texture` used as a background. It will inherit the color of the main StatusBar.
## Notes
A default texture will be applied if the widget is a StatusBar and doesn't have a texture set.
## Options
.frequentUpdates - Indicates whether to use OnUpdate script instead of UNIT_HEALTH to update the bar (boolean)
.smoothGradient - 9 color values to be used with the .colorSmooth option (table)
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 (boolean)
.colorDisconnected - Use `self.colors.disconnected` to color the bar if the unit is offline (boolean)
.colorHappiness - Use `self.colors.happiness` to color the bar if the unit is pet based on pet happiness (boolean)
.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) (boolean)
.colorClassNPC - Use `self.colors.class[class]` to color the bar if the unit is a NPC (boolean)
.colorClassPet - Use `self.colors.class[class]` to color the bar if the unit is player controlled, but not a player
(boolean)
.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) (boolean)
.colorSmooth - Use `smoothGradient` if present or `self.colors.smooth` to color the bar with a smooth gradient
based on the player's current health percentage (boolean)
.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 (boolean)
## Sub-Widgets Options
.multiplier - Used to tint the background based on the main widgets R, G and B values. Defaults to 1 (number)[0-1]
## Attributes
.disconnected - Indicates whether the unit is disconnected (boolean)
## 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
Health.bg = Background
self.Health = Health
--]]
local ns = oUF
local oUF = ns.oUF
local unpack = unpack
local GetPetHappiness = GetPetHappiness
local UnitClass = UnitClass
local UnitHealth = UnitHealth
local UnitHealthMax = UnitHealthMax
local UnitIsConnected = UnitIsConnected
local UnitIsPlayer = UnitIsPlayer
local UnitIsTapped = UnitIsTapped
local UnitIsTappedByPlayer = UnitIsTappedByPlayer
local UnitIsUnit = UnitIsUnit
local UnitPlayerControlled = UnitPlayerControlled
local UnitReaction = UnitReaction
local updateFrequentUpdates
local function UpdateColor(element, unit, cur, max)
local parent = element.__owner
if element.frequentUpdates ~= element.__frequentUpdates then
element.__frequentUpdates = element.frequentUpdates
updateFrequentUpdates(parent, unit)
end
local r, g, b, t
if(element.colorTapping and not UnitPlayerControlled(unit) and (UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit))) then
t = parent.colors.tapped
elseif(element.colorDisconnected and element.disconnected) then
t = parent.colors.disconnected
elseif(element.colorHappiness and UnitIsUnit(unit, 'pet') and GetPetHappiness()) then
t = parent.colors.happiness[GetPetHappiness()]
elseif(element.colorClass and UnitIsPlayer(unit)) or
(element.colorClassNPC and not UnitIsPlayer(unit)) or
(element.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then
local _, class = UnitClass(unit)
t = parent.colors.class[class]
elseif(element.colorReaction and UnitReaction(unit, 'player')) then
t = parent.colors.reaction[UnitReaction(unit, 'player')]
elseif(element.colorSmooth) then
r, g, b = parent.ColorGradient(cur, max, unpack(element.smoothGradient or parent.colors.smooth))
elseif(element.colorHealth) then
t = parent.colors.health
end
if(t) then
r, g, b = t[1], t[2], t[3]
end
if(r or g or b) then
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
end
end
local function Update(self, event, unit)
if(not unit or self.unit ~= unit) then return end
local element = self.Health
--[[ Callback: Health:PreUpdate(unit)
Called before the element has been updated.
* self - the Health element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PreUpdate) then
element:PreUpdate(unit)
end
local cur, max = UnitHealth(unit), UnitHealthMax(unit)
local disconnected = not UnitIsConnected(unit)
element:SetMinMaxValues(0, max)
if(disconnected) then
element:SetValue(max)
else
element:SetValue(cur)
end
element.disconnected = disconnected
--[[ Override: Health:UpdateColor(unit, cur, max)
Used to completely override the internal function for updating the widgets' colors.
* self - the Health element
* unit - the unit for which the update has been triggered (string)
* cur - the unit's current health value (number)
* max - the unit's maximum possible health value (number)
--]]
element:UpdateColor(unit, cur, max)
--[[ Callback: Health:PostUpdate(unit, cur, max)
Called after the element has been updated.
* self - the Health element
* unit - the unit for which the update has been triggered (string)
* cur - the unit's current health value (number)
* max - the unit's maximum possible health value (number)
--]]
if(element.PostUpdate) then
return element:PostUpdate(unit, cur, max)
end
end
local function Path(self, ...)
--[[ Override: Health.Override(self, event, unit)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
--]]
return (self.Health.Override or Update) (self, unpack(arg))
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function onHealthUpdate()
if(this.disconnected) then return end
local unit = this.__owner.unit
local health = UnitHealth(unit)
if(health ~= this.min) then
this.min = health
return Path(this.__owner, 'OnHealthUpdate', unit)
end
end
function updateFrequentUpdates(self, unit)
if(not unit or string.match(unit, '%w+target$')) then return end
local element = self.Health
if(element.frequentUpdates and not element:GetScript('OnUpdate')) then
element:SetScript('OnUpdate', onHealthUpdate)
if((unit == 'party' or string.match(unit, 'party%d?$'))) then
self:RegisterEvent('UNIT_HEALTH', Path)
elseif(self:IsEventRegistered("UNIT_HEALTH")) then
self:UnregisterEvent('UNIT_HEALTH', Path)
end
elseif(not element.frequentUpdates and element:GetScript('OnUpdate')) then
element:SetScript('OnUpdate', nil)
self:RegisterEvent('UNIT_HEALTH', Path)
end
end
local function Enable(self, unit)
local element = self.Health
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
element.__frequentUpdates = element.frequentUpdates
updateFrequentUpdates(self, unit)
if(element.frequentUpdates and (unit and not string.match(unit, '%w+target$'))) then
element:SetScript('OnUpdate', onHealthUpdate)
-- The party frames need this to handle disconnect states correctly.
if(unit == 'party') then
self:RegisterEvent('UNIT_HEALTH', Path)
end
else
self:RegisterEvent('UNIT_HEALTH', Path)
end
self:RegisterEvent('UNIT_MAXHEALTH', Path)
self:RegisterEvent('UNIT_CONNECTION', Path)
self:RegisterEvent('UNIT_FACTION', Path) -- For tapping
self:RegisterEvent('UNIT_HAPPINESS', Path)
if(element:IsObjectType('StatusBar') and not element:GetStatusBarTexture()) then
element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
if(not element.UpdateColor) then
element.UpdateColor = UpdateColor
end
element:Show()
return true
end
end
local function Disable(self)
local element = self.Health
if(element) then
if(element:GetScript('OnUpdate')) then
element:SetScript('OnUpdate', nil)
end
element:Hide()
self:UnregisterEvent('UNIT_HEALTH', Path)
self:UnregisterEvent('UNIT_MAXHEALTH', Path)
self:UnregisterEvent('UNIT_CONNECTION', Path)
self:UnregisterEvent('UNIT_FACTION', Path)
self:UnregisterEvent('UNIT_HAPPINESS', Path)
end
end
oUF:AddElement('Health', Path, Enable, Disable)
@@ -0,0 +1,107 @@
--[[
# Element: Leader Indicator
Toggles the visibility of an indicator based on the unit's leader status.
## Widget
LeaderIndicator - Any UI widget.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
-- Position and size
local LeaderIndicator = self:CreateTexture(nil, 'OVERLAY')
LeaderIndicator:SetSize(16, 16)
LeaderIndicator:SetPoint('BOTTOM', self, 'TOP')
-- Register it with oUF
self.LeaderIndicator = LeaderIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local UnitInParty = UnitInParty
local UnitInRaid = UnitInRaid
local UnitIsPartyLeader = UnitIsPartyLeader
local function Update(self, event)
local element = self.LeaderIndicator
--[[ Callback: LeaderIndicator:PreUpdate()
Called before the element has been updated.
* self - the LeaderIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local unit = self.unit
local isLeader = (UnitInParty(unit) or UnitInRaid(unit)) and UnitIsPartyLeader(unit)
if(isLeader) then
element:Show()
else
element:Hide()
end
--[[ Callback: LeaderIndicator:PostUpdate(isLeader)
Called after the element has been updated.
* self - the LeaderIndicator element
* isLeader - indicates whether the element is shown (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(isLeader)
end
end
local function Path(self, ...)
--[[ Override: LeaderIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.LeaderIndicator.Override or Update) (self, unpack(arg))
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self)
local element = self.LeaderIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('PARTY_LEADER_CHANGED', Path)
self:RegisterEvent('PARTY_MEMBERS_CHANGED', Path)
self:RegisterEvent('RAID_ROSTER_UPDATE', Path)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\GroupFrame\UI-Group-LeaderIcon]])
end
return true
end
end
local function Disable(self)
local element = self.LeaderIndicator
if(element) then
element:Hide()
self:UnregisterEvent('PARTY_LEADER_CHANGED', Path)
self:UnregisterEvent('PARTY_MEMBERS_CHANGED', Path)
self:UnregisterEvent('RAID_ROSTER_UPDATE', Path)
end
end
oUF:AddElement('LeaderIndicator', Path, Enable, Disable)
@@ -0,0 +1,126 @@
--[[
# Element: Master Looter Indicator
Toggles the visibility of an indicator based on the unit's master looter status.
## Widget
MasterLooterIndicator - Any UI widget.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
-- Position and size
local MasterLooterIndicator = self:CreateTexture(nil, 'OVERLAY')
MasterLooterIndicator:SetSize(16, 16)
MasterLooterIndicator:SetPoint('TOPRIGHT', self)
-- Register it with oUF
self.MasterLooterIndicator = MasterLooterIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local GetLootMethod = GetLootMethod
local UnitInParty = UnitInParty
local UnitInRaid = UnitInRaid
local UnitIsUnit = UnitIsUnit
local function Update(self, event)
local unit = self.unit
local element = self.MasterLooterIndicator
--[[ Callback: MasterLooterIndicator:PreUpdate()
Called before the element has been updated.
* self - the MasterLooterIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local isShown = false
if(UnitInParty(unit) or UnitInRaid(unit)) then
local method, partyIndex, raidIndex = GetLootMethod()
if(method == 'master') then
local mlUnit
if(partyIndex) then
if(partyIndex == 0) then
mlUnit = 'player'
else
mlUnit = 'party' .. partyIndex
end
elseif(raidIndex) then
mlUnit = 'raid' .. raidIndex
end
if(mlUnit and UnitIsUnit(unit, mlUnit)) then
isShown = true
end
end
end
if isShown then
element:Show()
else
element:Hide()
end
--[[ Callback: MasterLooterIndicator:PostUpdate(isShown)
Called after the element has been updated.
* self - the MasterLooterIndicator element
* isShown - indicates whether the element is shown (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(isShown)
end
end
local function Path(self, ...)
--[[ Override: MasterLooterIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.MasterLooterIndicator.Override or Update) (self, unpack(arg))
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self, unit)
local element = self.MasterLooterIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('PARTY_LOOT_METHOD_CHANGED', Path, true)
self:RegisterEvent('PARTY_MEMBERS_CHANGED', Path, true)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\GroupFrame\UI-Group-MasterLooter]])
end
return true
end
end
local function Disable(self)
local element = self.MasterLooterIndicator
if(element) then
element:Hide()
self:UnregisterEvent('PARTY_LOOT_METHOD_CHANGED', Path)
self:UnregisterEvent('PARTY_MEMBERS_CHANGED', Path)
end
end
oUF:AddElement('MasterLooterIndicator', Path, Enable, Disable)
+148
View File
@@ -0,0 +1,148 @@
--[[
# Element: Portraits
Handles the updating of the unit's portrait.
## Widget
Portrait - A `PlayerModel` or a `Texture` used to represent the unit's portrait.
## Notes
A question mark model will be used if the widget is a PlayerModel and 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
--]]
local ns = oUF
local oUF = ns.oUF
local SetPortraitTexture = SetPortraitTexture
local UnitExists = UnitExists
local UnitName = UnitName
local UnitIsConnected = UnitIsConnected
local UnitIsUnit = UnitIsUnit
local UnitIsVisible = UnitIsVisible
local function Update(self, event, unit)
if(not unit or not UnitIsUnit(self.unit, unit)) then return end
local element = self.Portrait
--[[ Callback: Portrait:PreUpdate(unit)
Called before the element has been updated.
* self - the Portrait element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PreUpdate) then element:PreUpdate(unit) end
local name = UnitName(unit)
local isAvailable = UnitIsConnected(unit) and UnitIsVisible(unit)
if(event ~= 'OnUpdate' or element.name ~= name or element.state ~= isAvailable) then
if(element:IsObjectType('PlayerModel')) then
if(not isAvailable) then
element:SetModelScale(4.25)
element:SetCamera(0)
element:SetPosition(0, 0, -1.5)
element:SetModel([[Interface\Buttons\TalkToMeQuestionMark.m2]])
elseif(element.name ~= name or event == 'UNIT_MODEL_CHANGED') then
element:ClearModel()
element:SetUnit(unit)
element:SetModelScale(1)
element:SetCamera(0)
element:SetPosition(0, 0, 0)
else
element:SetCamera(0)
end
else
SetPortraitTexture(element, unit)
end
element.name = name
element.state = isAvailable
end
--[[ Callback: Portrait:PostUpdate(unit)
Called after the element has been updated.
* self - the Portrait element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PostUpdate) then
return element:PostUpdate(unit)
end
end
local function Path(self, ...)
--[[ Override: Portrait.Override(self, event, unit)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
--]]
return (self.Portrait.Override or Update) (self, unpack(arg))
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self, unit)
local element = self.Portrait
if(element) then
element.__owner = self
element.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
element:Show()
return true
end
end
local function Disable(self)
local element = self.Portrait
if(element) then
element: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)
+326
View File
@@ -0,0 +1,326 @@
--[[
# Element: Power Bar
Handles the updating of a status bar that displays the unit's power.
## Widget
Power - A `StatusBar` used to represent the unit's power.
## Sub-Widgets
.bg - A `Texture` used as a background. It will inherit the color of the main StatusBar.
## Notes
A default texture will be applied if the widget is a StatusBar and doesn't have a texture or a color set.
## Options
.frequentUpdates - Indicates whether to use OnUpdate script instead of UNIT_POWER to update the bar. Only valid for the
player and pet units (boolean)
.smoothGradient - 9 color values to be used with the .colorSmooth option (table)
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 (boolean)
.colorDisconnected - Use `self.colors.disconnected` to color the bar if the unit is offline (boolean)
.colorHappiness - Use `self.colors.happiness` to color the bar if the unit is pet based on pet happiness (boolean)
.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]` (boolean)
.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) (boolean)
.colorClassNPC - Use `self.colors.class[class]` to color the bar if the unit is a NPC (boolean)
.colorClassPet - Use `self.colors.class[class]` to color the bar if the unit is player controlled, but not a player
(boolean)
.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) (boolean)
.colorSmooth - Use `smoothGradient` if present or `self.colors.smooth` to color the bar with a smooth gradient
based on the player's current power percentage (boolean)
## Sub-Widget Options
.multiplier - A multiplier used to tint the background based on the main widgets R, G and B values. Defaults to 1
(number)[0-1]
## Attributes
.disconnected - Indicates whether the unit is disconnected (boolean)
.tapped - Indicates whether the unit is tapped by the player (boolean)
## 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
Power.bg = Background
self.Power = Power
--]]
local ns = oUF
local oUF = ns.oUF
local unpack = unpack
local GetPetHappiness = GetPetHappiness
local UnitClass = UnitClass
local UnitIsConnected = UnitIsConnected
local UnitIsPlayer = UnitIsPlayer
local UnitIsTapped = UnitIsTapped
local UnitIsTappedByPlayer = UnitIsTappedByPlayer
local UnitIsUnit = UnitIsUnit
local UnitMana = UnitMana
local UnitManaMax = UnitManaMax
local UnitPlayerControlled = UnitPlayerControlled
local UnitPowerType = UnitPowerType
local UnitReaction = UnitReaction
local updateFrequentUpdates
local function UpdateColor(element, unit, cur, min, max)
local parent = element.__owner
if element.frequentUpdates ~= element.__frequentUpdates then
element.__frequentUpdates = element.frequentUpdates
updateFrequentUpdates(element, unit)
end
local ptype = UnitPowerType(unit)
local r, g, b, t
if(element.colorTapping and element.tapped) then
t = parent.colors.tapped
elseif(element.colorDisconnected and element.disconnected) then
t = parent.colors.disconnected
elseif(element.colorHappiness and UnitIsUnit(unit, 'pet') and GetPetHappiness()) then
t = parent.colors.happiness[GetPetHappiness()]
elseif(element.colorPower) then
t = parent.colors.power[ptype]
elseif(element.colorClass and UnitIsPlayer(unit)) or
(element.colorClassNPC and not UnitIsPlayer(unit)) or
(element.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then
local _, class = UnitClass(unit)
t = parent.colors.class[class]
elseif(element.colorReaction and UnitReaction(unit, 'player')) then
t = parent.colors.reaction[UnitReaction(unit, 'player')]
elseif(element.colorSmooth) then
local adjust = 0 - (min or 0)
r, g, b = parent.ColorGradient(cur + adjust, max + adjust, unpack(element.smoothGradient or parent.colors.smooth))
end
if(t) then
r, g, b = t[1], t[2], t[3]
end
t = parent.colors.power[ptype]
element:SetStatusBarTexture(element.texture)
if(r or g or b) then
element:SetStatusBarColor(r, g, b)
end
local bg = element.bg
if(bg and b) then
local mu = bg.multiplier or 1
bg:SetVertexColor(r * mu, g * mu, b * mu)
end
end
local function Update(self, event, unit)
if(self.unit ~= unit) then return end
local element = self.Power
--[[ Callback: Power:PreUpdate(unit)
Called before the element has been updated.
* self - the Power element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PreUpdate) then
element:PreUpdate(unit)
end
local cur, max = UnitMana(unit), UnitManaMax(unit)
local disconnected = not UnitIsConnected(unit)
local tapped = not UnitPlayerControlled(unit) and (UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit))
element:SetMinMaxValues(0, max)
if(disconnected) then
element:SetValue(max)
else
element:SetValue(cur)
end
element.disconnected = disconnected
element.tapped = tapped
--[[ Override: Power:UpdateColor(unit, cur, max)
Used to completely override the internal function for updating the widget's colors.
* self - the Power element
* unit - the unit for which the update has been triggered (string)
* cur - the unit's current power value (number)
* max - the unit's maximum possible power value (number)
--]]
element:UpdateColor(unit, cur, max)
--[[ Callback: Power:PostUpdate(unit, cur, max)
Called after the element has been updated.
* self - the Power element
* unit - the unit for which the update has been triggered (string)
* cur - the unit's current power value (number)
* max - the unit's maximum possible power value (number)
--]]
if(element.PostUpdate) then
return element:PostUpdate(unit, cur, max)
end
end
local function Path(self, ...)
--[[ Override: Power.Override(self, event, unit, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
* ... - the arguments accompanying the event
--]]
return (self.Power.Override or Update) (self, unpack(arg))
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function onPowerUpdate()
if(this.disconnected) then return end
local unit = this.__owner.unit
local power = UnitMana(unit)
if(power ~= this.min) then
this.min = power
return Path(this.__owner, 'OnPowerUpdate', unit)
end
end
function updateFrequentUpdates(self, unit)
if(not unit or (unit ~= 'player' and unit ~= 'pet')) then return end
local element = self.Power
if(element.frequentUpdates and not element:GetScript('OnUpdate')) then
element:SetScript('OnUpdate', onPowerUpdate)
self:UnregisterEvent('UNIT_MANA', Path)
self:UnregisterEvent('UNIT_RAGE', Path)
self:UnregisterEvent('UNIT_FOCUS', Path)
self:UnregisterEvent('UNIT_ENERGY', Path)
elseif(not element.frequentUpdates and element:GetScript('OnUpdate')) then
element:SetScript('OnUpdate', nil)
self:RegisterEvent('UNIT_MANA', Path)
self:RegisterEvent('UNIT_RAGE', Path)
self:RegisterEvent('UNIT_FOCUS', Path)
self:RegisterEvent('UNIT_ENERGY', Path)
end
end
local function Enable(self, unit)
local element = self.Power
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
element.__frequentUpdates = element.frequentUpdates
updateFrequentUpdates(self, unit)
if(element.frequentUpdates and (unit == 'player' or unit == 'pet')) then
element:SetScript('OnUpdate', onPowerUpdate)
else
self:RegisterEvent('UNIT_MANA', Path)
self:RegisterEvent('UNIT_RAGE', Path)
self:RegisterEvent('UNIT_FOCUS', Path)
self:RegisterEvent('UNIT_ENERGY', Path)
end
self:RegisterEvent('UNIT_MAXMANA', Path)
self:RegisterEvent('UNIT_MAXRAGE', Path)
self:RegisterEvent('UNIT_MAXFOCUS', Path)
self:RegisterEvent('UNIT_MAXENERGY', Path)
self:RegisterEvent('UNIT_MAXRUNIC_POWER', Path)
self:RegisterEvent('UNIT_DISPLAYPOWER', Path)
self:RegisterEvent('UNIT_CONNECTION', Path)
self:RegisterEvent('UNIT_HAPPINESS', Path)
self:RegisterEvent('UNIT_FACTION', Path) -- For tapping
if(element:IsObjectType('StatusBar')) then
element.texture = element:GetStatusBarTexture() and element:GetStatusBarTexture():GetTexture() or [[Interface\TargetingFrame\UI-StatusBar]]
element:SetStatusBarTexture(element.texture)
end
if(not element.UpdateColor) then
element.UpdateColor = UpdateColor
end
element:Show()
return true
end
end
local function Disable(self)
local element = self.Power
if(element) then
element:Hide()
if(element:GetScript('OnUpdate')) then
element:SetScript('OnUpdate', nil)
else
self:UnregisterEvent('UNIT_MANA', Path)
self:UnregisterEvent('UNIT_RAGE', Path)
self:UnregisterEvent('UNIT_FOCUS', Path)
self:UnregisterEvent('UNIT_ENERGY', Path)
self:UnregisterEvent('UNIT_RUNIC_POWER', Path)
end
self:UnregisterEvent('UNIT_MAXMANA', Path)
self:UnregisterEvent('UNIT_MAXRAGE', Path)
self:UnregisterEvent('UNIT_MAXFOCUS', Path)
self:UnregisterEvent('UNIT_MAXENERGY', Path)
self:UnregisterEvent('UNIT_MAXRUNIC_POWER', Path)
self:UnregisterEvent('UNIT_DISPLAYPOWER', Path)
self:UnregisterEvent('UNIT_CONNECTION', Path)
self:UnregisterEvent('UNIT_HAPPINESS', Path)
self:UnregisterEvent('UNIT_FACTION', Path)
end
end
oUF:AddElement('Power', Path, Enable, Disable)
@@ -0,0 +1,118 @@
--[[
# Element: PvP Icon
Handles the visibility and updating of an indicator based on the unit's PvP status.
## Widget
PvPIndicator - A `Texture` used to display faction, FFA PvP status icon.
## Notes
This element updates by changing the texture.
## Examples
-- Position and size
local PvPIndicator = self:CreateTexture(nil, 'ARTWORK', nil, 1)
PvPIndicator:SetSize(30, 30)
PvPIndicator:SetPoint('RIGHT', self, 'LEFT')
-- Register it with oUF
self.PvPIndicator = PvPIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local UnitFactionGroup = UnitFactionGroup
local UnitIsPVP = UnitIsPVP
local UnitIsPVPFreeForAll = UnitIsPVPFreeForAll
local FFA_ICON = [[Interface\TargetingFrame\UI-PVP-FFA]]
local FACTION_ICON = [[Interface\TargetingFrame\UI-PVP-]]
local function Update(self, event, unit)
if(unit ~= self.unit) then return end
local element = self.PvPIndicator
--[[ Callback: PvPIndicator:PreUpdate(unit)
Called before the element has been updated.
* self - the PvPIndicator element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PreUpdate) then
element:PreUpdate(unit)
end
local status
local factionGroup = UnitFactionGroup(unit)
if(UnitIsPVPFreeForAll(unit)) then
element:SetTexture(FFA_ICON)
element:SetTexCoord(0, 0.65625, 0, 0.65625)
status = 'ffa'
elseif(factionGroup and factionGroup ~= 'Neutral' and UnitIsPVP(unit)) then
element:SetTexture(FACTION_ICON .. factionGroup)
element:SetTexCoord(0, 0.65625, 0, 0.65625)
status = factionGroup
end
if(status) then
element:Show()
else
element:Hide()
end
--[[ Callback: PvPIndicator:PostUpdate(unit, status)
Called after the element has been updated.
* self - the PvPIndicator element
* unit - the unit for which the update has been triggered (string)
* status - the unit's current PvP status or faction accounting for mercenary mode (string)['ffa', 'Alliance',
'Horde']
--]]
if(element.PostUpdate) then
return element:PostUpdate(unit, status)
end
end
local function Path(self, ...)
--[[Override: PvPIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.PvPIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local element = self.PvPIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_FACTION', Path)
return true
end
end
local function Disable(self)
local element = self.PvPIndicator
if(element) then
element:Hide()
self:UnregisterEvent('UNIT_FACTION', Path)
end
end
oUF:AddElement('PvPIndicator', Path, Enable, Disable)
@@ -0,0 +1,114 @@
--[[
# Element: Raid Role Indicator
Handles the visibility and updating of an indicator based on the unit's raid assignment (main tank or main assist).
## Widget
RaidRoleIndicator - A `Texture` representing the unit's raid assignment.
## Notes
This element updates by changing the texture.
## Examples
-- Position and size
local RaidRoleIndicator = self:CreateTexture(nil, 'OVERLAY')
RaidRoleIndicator:SetSize(16, 16)
RaidRoleIndicator:SetPoint('TOPLEFT')
-- Register it with oUF
self.RaidRoleIndicator = RaidRoleIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local GetPartyAssignment = GetPartyAssignment
local UnitInRaid = UnitInRaid
local MAINTANK_ICON = [[Interface\GROUPFRAME\UI-GROUP-MAINTANKICON]]
local MAINASSIST_ICON = [[Interface\GROUPFRAME\UI-GROUP-MAINASSISTICON]]
local function Update(self, event)
local unit = self.unit
local element = self.RaidRoleIndicator
--[[ Callback: RaidRoleIndicator:PreUpdate()
Called before the element has been updated.
* self - the RaidRoleIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local role, isShown
if(UnitInRaid(unit)) then
if(GetPartyAssignment('MAINTANK', unit)) then
isShown = true
element:SetTexture(MAINTANK_ICON)
role = 'MAINTANK'
elseif(GetPartyAssignment('MAINASSIST', unit)) then
isShown = true
element:SetTexture(MAINASSIST_ICON)
role = 'MAINASSIST'
end
end
if isShown then
element:Show()
else
element:Hide()
end
--[[ Callback: RaidRoleIndicator:PostUpdate(role)
Called after the element has been updated.
* self - the RaidRoleIndicator element
* role - the unit's raid assignment (string?)['MAINTANK', 'MAINASSIST']
--]]
if(element.PostUpdate) then
return element:PostUpdate(role)
end
end
local function Path(self, ...)
--[[ Override: RaidRoleIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.RaidRoleIndicator.Override or Update)(self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self)
local element = self.RaidRoleIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('PARTY_MEMBERS_CHANGED', Path, true)
return true
end
end
local function Disable(self)
local element = self.RaidRoleIndicator
if(element) then
element:Hide()
self:UnregisterEvent('PARTY_MEMBERS_CHANGED', Path)
end
end
oUF:AddElement('RaidRoleIndicator', Path, Enable, Disable)
@@ -0,0 +1,102 @@
--[[
# Element: Raid Target Indicator
Handles the visibility and updating of an indicator based on the unit's raid target assignment.
## Widget
RaidTargetIndicator - A `Texture` used to display the raid target icon.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture set.
## Examples
-- Position and size
local RaidTargetIndicator = self:CreateTexture(nil, 'OVERLAY')
RaidTargetIndicator:SetSize(16, 16)
RaidTargetIndicator:SetPoint('TOPRIGHT', self)
-- Register it with oUF
self.RaidTargetIndicator = RaidTargetIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local GetRaidTargetIndex = GetRaidTargetIndex
local SetRaidTargetIconTexture = SetRaidTargetIconTexture
local function Update(self, event)
local element = self.RaidTargetIndicator
--[[ Callback: RaidTargetIndicator:PreUpdate()
Called before the element has been updated.
* self - the RaidTargetIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local index = GetRaidTargetIndex(self.unit)
if(index) then
SetRaidTargetIconTexture(element, index)
element:Show()
else
element:Hide()
end
--[[ Callback: RaidTargetIndicator:PostUpdate(index)
Called after the element has been updated.
* self - the RaidTargetIndicator element
* index - the index of the raid target marker (number?)[1-8]
--]]
if(element.PostUpdate) then
return element:PostUpdate(index)
end
end
local function Path(self, ...)
--[[ Override: RaidTargetIndicator.Override(self, event)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
--]]
return (self.RaidTargetIndicator.Override or Update) (self, unpack(arg))
end
local function ForceUpdate(element)
if(not element.__owner.unit) then return end
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self)
local element = self.RaidTargetIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('RAID_TARGET_UPDATE', Path, true)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\TargetingFrame\UI-RaidTargetingIcons]])
end
return true
end
end
local function Disable(self)
local element = self.RaidTargetIndicator
if(element) then
element:Hide()
self:UnregisterEvent('RAID_TARGET_UPDATE', Path)
end
end
oUF:AddElement('RaidTargetIndicator', Path, Enable, Disable)
+137
View File
@@ -0,0 +1,137 @@
--[[
# Element: Range Fader
Changes the opacity of a unit frame based on whether the frame's unit is in the player's range.
## Widget
Range - A table containing opacity values.
## Notes
Offline units are handled as if they are in range.
## Options
.outsideAlpha - Opacity when the unit is out of range. Defaults to 0.55 (number)[0-1].
.insideAlpha - Opacity when the unit is within range. Defaults to 1 (number)[0-1].
## Examples
-- Register with oUF
self.Range = {
insideAlpha = 1,
outsideAlpha = 1/2,
}
--]]
local ns = oUF
local oUF = ns.oUF
local _FRAMES = {}
local OnRangeFrame
local UnitInRange, UnitIsConnected = UnitInRange, UnitIsConnected
local function Update(self, event)
local element = self.Range
local unit = self.unit
--[[ Callback: Range:PreUpdate()
Called before the element has been updated.
* self - the Range element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local inRange
local connected = UnitIsConnected(unit)
if(connected) then
inRange = UnitInRange(unit)
if(not inRange) then
self:SetAlpha(element.outsideAlpha)
else
self:SetAlpha(element.insideAlpha)
end
else
self:SetAlpha(element.insideAlpha)
end
--[[ Callback: Range:PostUpdate(object, inRange, isConnected)
Called after the element has been updated.
* self - the Range element
* object - the parent object
* inRange - indicates if the unit was within 40 yards of the player (boolean)
* isConnected - indicates if the unit is online (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(self, inRange, connected)
end
end
local function Path(self, ...)
--[[ Override: Range.Override(self, event)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
--]]
return (self.Range.Override or Update) (self, ...)
end
-- Internal updating method
local timer = 0
local function OnRangeUpdate(_, elapsed)
timer = timer + elapsed
if(timer >= .20) then
for _, object in next, _FRAMES do
if(object:IsShown()) then
Path(object, 'OnUpdate')
end
end
timer = 0
end
end
local function Enable(self)
local element = self.Range
if(element) then
element.__owner = self
element.insideAlpha = element.insideAlpha or 1
element.outsideAlpha = element.outsideAlpha or 0.55
if(not OnRangeFrame) then
OnRangeFrame = CreateFrame('Frame')
OnRangeFrame:SetScript('OnUpdate', OnRangeUpdate)
end
table.insert(_FRAMES, self)
OnRangeFrame:Show()
return true
end
end
local function Disable(self)
local element = self.Range
if(element) then
for index, frame in next, _FRAMES do
if(frame == self) then
table.remove(_FRAMES, index)
break
end
end
self:SetAlpha(element.insideAlpha)
if(#_FRAMES == 0) then
OnRangeFrame:Hide()
end
end
end
oUF:AddElement('Range', nil, Enable, Disable)
@@ -0,0 +1,150 @@
--[[
# Element: Ready Check Indicator
Handles the visibility and updating of an indicator based on the unit's ready check status.
## Widget
ReadyCheckIndicator - A `Texture` representing ready check status.
## Notes
This element updates by changing the texture.
Default textures will be applied if the layout does not provide custom ones. See Options.
## Options
.finishedTime - For how many seconds the icon should stick after a check has completed. Defaults to 10 (number).
.fadeTime - For how many seconds the icon should fade away after the stick duration has completed. Defaults to
1.5 (number).
.readyTexture - Path to an alternate texture for the ready check 'ready' status.
.notReadyTexture - Path to an alternate texture for the ready check 'notready' status.
.waitingTexture - Path to an alternate texture for the ready check 'waiting' status.
## Attributes
.status - the unit's ready check status (string?)['ready', 'noready', 'waiting']
## Examples
-- Position and size
local ReadyCheckIndicator = self:CreateTexture(nil, 'OVERLAY')
ReadyCheckIndicator:SetSize(16, 16)
ReadyCheckIndicator:SetPoint('TOP')
-- Register with oUF
self.ReadyCheckIndicator = ReadyCheckIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local GetReadyCheckStatus = GetReadyCheckStatus
local UnitExists = UnitExists
local function OnFinished(self)
local element = self:GetParent()
element:Hide()
--[[ Callback: ReadyCheckIndicator:PostUpdateFadeOut()
Called after the element has been faded out.
* self - the ReadyCheckIndicator element
--]]
if(element.PostUpdateFadeOut) then
element:PostUpdateFadeOut()
end
end
local function Update(self, event)
local element = self.ReadyCheckIndicator
--[[ Callback: ReadyCheckIndicator:PreUpdate()
Called before the element has been updated.
* self - the ReadyCheckIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local unit = self.unit
local status = GetReadyCheckStatus(unit)
if(UnitExists(unit) and status) then
if(status == 'ready') then
element:SetTexture(element.readyTexture)
elseif(status == 'notready') then
element:SetTexture(element.notReadyTexture)
else
element:SetTexture(element.waitingTexture)
end
element.status = status
element:Show()
elseif(event ~= 'READY_CHECK_FINISHED') then
element.status = nil
element:Hide()
end
if(event == 'READY_CHECK_FINISHED') then
if(element.status == 'waiting') then
element:SetTexture(element.notReadyTexture)
end
end
--[[ Callback: ReadyCheckIndicator:PostUpdate(status)
Called after the element has been updated.
* self - the ReadyCheckIndicator element
* status - the unit's ready check status (string?)['ready', 'notready', 'waiting']
--]]
if(element.PostUpdate) then
return element:PostUpdate(status)
end
end
local function Path(self, ...)
--[[ Override: ReadyCheckIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.ReadyCheckIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self, unit)
local element = self.ReadyCheckIndicator
if(element and (unit and (unit:sub(1, 5) == 'party' or unit:sub(1, 4) == 'raid'))) then
element.__owner = self
element.ForceUpdate = ForceUpdate
element.readyTexture = element.readyTexture or READY_CHECK_READY_TEXTURE
element.notReadyTexture = element.notReadyTexture or READY_CHECK_NOT_READY_TEXTURE
element.waitingTexture = element.waitingTexture or READY_CHECK_WAITING_TEXTURE
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 function Disable(self)
local element = self.ReadyCheckIndicator
if(element) then
element:Hide()
self:UnregisterEvent('READY_CHECK', Path)
self:UnregisterEvent('READY_CHECK_CONFIRM', Path)
self:UnregisterEvent('READY_CHECK_FINISHED', Path)
end
end
oUF:AddElement('ReadyCheckIndicator', Path, Enable, Disable)
@@ -0,0 +1,100 @@
--[[
# Element: Resting Indicator
Toggles the visibility of an indicator based on the player's resting status.
## Widget
RestingIndicator - Any UI widget.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
-- Position and size
local RestingIndicator = self:CreateTexture(nil, 'OVERLAY')
RestingIndicator:SetSize(16, 16)
RestingIndicator:SetPoint('TOPLEFT', self)
-- Register it with oUF
self.RestingIndicator = RestingIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local IsResting = IsResting
local function Update(self, event)
local element = self.RestingIndicator
--[[ Callback: RestingIndicator:PreUpdate()
Called before the element has been updated.
* self - the RestingIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local isResting = IsResting()
if(isResting) then
element:Show()
else
element:Hide()
end
--[[ Callback: RestingIndicator:PostUpdate(isResting)
Called after the element has been updated.
* self - the RestingIndicator element
* isResting - indicates if the player is resting (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(isResting)
end
end
local function Path(self, ...)
--[[ Override: RestingIndicator.Override(self, event)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
--]]
return (self.RestingIndicator.Override or Update) (self, unpack(arg))
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self, unit)
local element = self.RestingIndicator
if(element and unit == 'player') then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('PLAYER_UPDATE_RESTING', Path, true)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\CharacterFrame\UI-StateIcon]])
element:SetTexCoord(0, 0.5, 0, 0.421875)
end
return true
end
end
local function Disable(self)
local element = self.RestingIndicator
if(element) then
element:Hide()
self:UnregisterEvent('PLAYER_UPDATE_RESTING', Path)
end
end
oUF:AddElement('RestingIndicator', Path, Enable, Disable)
+828
View File
@@ -0,0 +1,828 @@
-- Credits: Vika, Cladhaire, Tekkub
--[[
# Element: Tags
Provides a system for text-based display of information by binding a tag string to a font string widget which in turn is
tied to a unit frame.
## Widget
A FontString to hold a tag string. Unlike other elements, this widget must not have a preset name.
## Notes
A `Tag` is a Lua string consisting of a function name surrounded by square brackets. The tag will be replaced by the
output of the function and displayed as text on the font string widget with that the tag has been registered. Literals
can be pre- or appended by separating them with a `>` before or `<` after the function name. The literals will be only
displayed when the function returns a non-nil value. I.e. `"[perhp<%]"` will display the current health as a percentage
of the maximum health followed by the % sign.
A `Tag String` is a Lua string consisting of one or multiple tags with optional literals between them. Each tag will be
updated individually and the output will follow the tags order. Literals will be displayed in the output string
regardless of whether the surrounding tag functions return a value. I.e. `"[curhp]/[maxhp]"` will resolve to something
like `2453/5000`.
A `Tag Function` is used to replace a single tag in a tag string by its output. A tag function receives only two
arguments - the unit and the realUnit of the unit frame used to register the tag (see Options for further details). The
tag function is called when the unit frame is shown or when a specified event has fired. It the tag is registered on an
eventless frame (i.e. one holding the unit "targettarget"), then the tag function is called in a set time interval.
A number of built-in tag functions exist. The layout can also define its own tag functions by adding them to the
`oUF.Tags.Methods` table. The events upon which the function will be called are specified in a white-space separated
list added to the `oUF.Tags.Events` table. Should an event fire without unit information, then it should also be listed
in the `oUF.Tags.SharedEvents` table as follows: `oUF.Tags.SharedEvents.EVENT_NAME = true`.
## Options
.overrideUnit - if specified on the font string widget, the frame's realUnit will be passed as the second argument to
every tag function whose name is contained in the relevant tag string. Otherwise the second argument
is always nil (boolean)
.frequentUpdates - defines how often the correspondig tag function(s) should be called. This will override the events for
the tag(s), if any. If the value is a number, it is taken as a time interval in seconds. If the value
is a boolean, the time interval is set to 0.5 seconds (number or boolean)
## Attributes
.parent - the unit frame on which the tag has been registered
## Examples
-- define the tag function
oUF.Tags.Methods['mylayout:threatname'] = function(unit, realUnit)
local color = _TAGS['threatcolor'](unit)
local name = _TAGS['name'](unit, realUnit)
return string.format('%s%s|r', color, name)
end
-- add the events
oUF.Tags.Events['mylayout:threatname'] = 'UNIT_NAME_UPDATE UNIT_THREAT_SITUATION_UPDATE'
-- create the text widget
local info = self.Health:CreateFontString(nil, 'OVERLAY', 'GameFontNormal')
info:SetPoint('LEFT')
-- register the tag on the text widget with oUF
self:Tag(info, '[mylayout:threatname]')
--]]
local ns = oUF
local oUF = ns.oUF
local _G = _G
local unpack = unpack
local floor = math.floor
local format = string.format
local tinsert, tremove = table.insert, table.remove
local GetComboPoints = GetComboPoints
local GetNumRaidMembers = GetNumRaidMembers
local GetPetHappiness = GetPetHappiness
local GetQuestDifficultyColor = GetQuestDifficultyColor
local GetRaidRosterInfo = GetRaidRosterInfo
local IsResting = IsResting
local UnitCanAttack = UnitCanAttack
local UnitClass = UnitClass
local UnitClassification = UnitClassification
local UnitCreatureFamily = UnitCreatureFamily
local UnitCreatureType = UnitCreatureType
local UnitFactionGroup = UnitFactionGroup
local UnitIsConnected = UnitIsConnected
local UnitIsDead = UnitIsDead
local UnitIsGhost = UnitIsGhost
local UnitIsPVP = UnitIsPVP
local UnitIsPartyLeader = UnitIsPartyLeader
local UnitIsPlayer = UnitIsPlayer
local UnitLevel = UnitLevel
local UnitMana = UnitMana
local UnitManaMax = UnitManaMax
local UnitName = UnitName
local UnitPowerType = UnitPowerType
local UnitRace = UnitRace
local UnitSex = UnitSex
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
if not r or type(r) == 'string' then
return '|cffFFFFFF'
end
return 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 999))
end
end]],
['leader'] = [[function(u)
if(UnitIsPartyLeader(u)) then
return 'L'
end
end]],
['leaderlong'] = [[function(u)
if(UnitIsPartyLeader(u)) then
return 'Leader'
end
end]],
['level'] = [[function(u)
local l = UnitLevel(u)
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 = UnitManaMax(u) - UnitMana(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 floor(UnitHealth(u) / m * 100 + .5)
end
end]],
['perpp'] = [[function(u)
local m = UnitManaMax(u)
if(m == 0) then
return 0
else
return floor(UnitMana(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]],
['cpoints'] = [[function(u)
local cp = GetComboPoints('player', 'target')
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'
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'
end
end]],
['group'] = [[function(unit)
local name, server = UnitName(unit)
if(server and server ~= '') then
name = format('%s-%s', name, server)
end
for i=1, GetNumRaidMembers() 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]],
['curmana'] = [[function(unit)
return UnitMana(unit, SPELL_POWER_MANA)
end]],
['maxmana'] = [[function(unit)
return UnitManaMax(unit, SPELL_POWER_MANA)
end]],
['happiness'] = [[function(u)
if(UnitIsUnit(u, 'pet')) then
local happiness = GetPetHappiness()
if(happiness == 1) then
return ':<'
elseif(happiness == 2) then
return ':|'
elseif(happiness == 3) then
return ':D'
end
end
end]],
['powercolor'] = [[function(u)
local pType, pToken, altR, altG, altB = UnitPowerType(u)
local t = _COLORS.power[pToken]
if(not t) then
if(altR) then
if(altR > 1 or altG > 1 or altB > 1) then
return Hex(altR / 255, altG / 255, altB / 255)
else
return Hex(altR, altG, altB)
end
else
return Hex(_COLORS.power[pType])
end
end
return Hex(t)
end]],
}
local tags = setmetatable(
{
curhp = UnitHealth,
curpp = UnitMana,
maxhp = UnitHealthMax,
maxpp = UnitManaMax,
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',
['maxhp'] = 'UNIT_MAXHEALTH',
['curpp'] = 'UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE',
['maxpp'] = 'UNIT_MAXENERGY UNIT_MAXFOCUS UNIT_MAXMANA UNIT_MAXRAGE',
['dead'] = 'UNIT_HEALTH',
['leader'] = 'PARTY_LEADER_CHANGED',
['leaderlong'] = 'PARTY_LEADER_CHANGED',
['level'] = 'UNIT_LEVEL PLAYER_LEVEL_UP',
['missinghp'] = 'UNIT_HEALTH UNIT_MAXHEALTH',
['missingpp'] = 'UNIT_MAXENERGY UNIT_MAXFOCUS UNIT_MAXMANA UNIT_MAXRAGE UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE',
['name'] = 'UNIT_NAME_UPDATE',
['offline'] = 'UNIT_HEALTH',
['perhp'] = 'UNIT_HEALTH UNIT_MAXHEALTH',
['perpp'] = 'UNIT_MAXENERGY UNIT_MAXFOCUS UNIT_MAXMANA UNIT_MAXRAGE UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE',
['plus'] = 'UNIT_CLASSIFICATION_CHANGED',
['pvp'] = 'UNIT_FACTION',
['rare'] = 'UNIT_CLASSIFICATION_CHANGED',
['resting'] = 'PLAYER_UPDATE_RESTING',
['status'] = 'UNIT_HEALTH PLAYER_UPDATE_RESTING',
['cpoints'] = 'PLAYER_COMBO_POINTS PLAYER_TARGET_CHANGED',
['smartlevel'] = 'UNIT_LEVEL PLAYER_LEVEL_UP UNIT_CLASSIFICATION_CHANGED',
['classification'] = 'UNIT_CLASSIFICATION_CHANGED',
['shortclassification'] = 'UNIT_CLASSIFICATION_CHANGED',
['group'] = 'PARTY_MEMBERS_CHANGED RAID_ROSTER_UPDATE',
['curmana'] = 'UNIT_MANA UNIT_MAXMANA',
['maxmana'] = 'UNIT_MANA UNIT_MAXMANA',
['happiness'] = 'UNIT_HAPPINESS',
['powercolor'] = 'UNIT_DISPLAYPOWER',
}
local unitlessEvents = {
PLAYER_LEVEL_UP = true,
PLAYER_UPDATE_RESTING = true,
PLAYER_TARGET_CHANGED = true,
RAID_ROSTER_UPDATE = true,
PARTY_MEMBERS_CHANGED = true,
PARTY_LEADER_CHANGED = true,
PLAYER_COMBO_POINTS = true,
}
local events = {}
local frame = CreateFrame('Frame')
frame:SetScript('OnEvent', function()
local strings = events[event]
if(strings) then
for _, fontstring in next, strings do
if(fontstring:IsVisible() and (unitlessEvents[event] or fontstring.parent.unit == arg1)) then
fontstring:UpdateTag()
end
end
end
end)
local onUpdates = {}
local eventlessUnits = {}
local function createOnUpdate(timer)
local OnUpdate = onUpdates[timer]
if(not OnUpdate) then
local total = timer
local frame = CreateFrame('Frame')
local strings = eventlessUnits[timer]
frame:SetScript('OnUpdate', function()
if(total >= timer) then
for _, fs in next, strings do
if(fs.parent:IsShown() and UnitExists(fs.parent.unit)) then
fs:UpdateTag()
end
end
total = 0
end
total = total + arg1
end)
onUpdates[timer] = frame
end
end
local function onShow(self)
for _, fs in next, self.__tags do
fs:UpdateTag()
end
end
local function getTagName(tag)
local tagStart = (string.match(tag, '>+()') or 2)
local tagEnd = string.match(tag, '.*()<+')
tagEnd = (tagEnd and tagEnd - 1) or -2
return string.sub(tag, tagStart, tagEnd), tagStart, tagEnd
end
local function registerEvent(fontstr, event)
if(not events[event]) then events[event] = {} end
frame:RegisterEvent(event)
tinsert(events[event], fontstr)
end
local function registerEvents(fontstr, tagstr)
for tag in string.gmatch(tagstr, _PATTERN) do
tag = getTagName(tag)
local tagevents = tagEvents[tag]
if(tagevents) then
for event in string.gmatch(tagevents, '%S+') do
registerEvent(fontstr, event)
end
end
end
end
local function unregisterEvents(fontstr)
for event, data in next, events do
for i, tagfsstr in next, data do
if(tagfsstr == fontstr) then
if(getn(data) == 1) then
frame:UnregisterEvent(event)
end
tremove(data, i)
end
end
end
end
local OnEnter = function(self)
for _, fs in pairs(self.__mousetags) do
fs:SetAlpha(1)
end
end
local OnLeave = function(self)
for _, fs in pairs(self.__mousetags) do
fs:SetAlpha(0)
end
end
local onUpdateDelay = {}
local tagPool = {}
local funcPool = {}
local tmp = {}
local escapeSequences = {
["||c"] = "|c",
["||r"] = "|r",
["||T"] = "|T",
["||t"] = "|t",
}
--[[ Tags: frame:Tag(fs, tagstr)
Used to register a tag on a unit frame.
* self - the unit frame on which to register the tag
* fs - the font string to display the tag (FontString)
* tagstr - the tag string (string)
--]]
local function Tag(self, fs, tagstr)
if(not fs or not tagstr) then return end
if(not self.__tags) then
self.__tags = {}
self.__mousetags = {}
tinsert(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
for escapeSequence, replacement in pairs(escapeSequences) do
while string.find(tagstr, escapeSequence) do
tagstr = string.gsub(tagstr, escapeSequence, replacement)
end
end
if string.find(tagstr, '%[mouseover%]') then
tinsert(self.__mousetags, fs)
fs:SetAlpha(0)
if not self.__HookFunc then
self:HookScript('OnEnter', OnEnter)
self:HookScript('OnLeave', OnLeave)
self.__HookFunc = true;
end
tagstr = string.gsub(tagstr, '%[mouseover%]', '')
else
for index, fontString in pairs(self.__mousetags) do
if fontString == fs then
self.__mousetags[index] = nil;
fs:SetAlpha(1)
end
end
end
local containsOnUpdate
for tag in string.gmatch(tagstr, _PATTERN) do
tag = getTagName(tag)
if not tagEvents[tag] then
containsOnUpdate = onUpdateDelay[tag] or 0.15;
end
end
local func = tagPool[tagstr]
if(not func) then
local format, numTags = string.gsub(string.gsub(tagstr, '%%', '%%%%'), _PATTERN, '%%s')
local args = {}
for bracket in string.gmatch(tagstr, _PATTERN) do
local tagFunc = funcPool[bracket] or tags[string.sub(bracket, 2, -2)]
if(not tagFunc) then
local tagName, tagStart, tagEnd = getTagName(bracket)
local tag = tags[tagName]
if(tag) then
tagStart = tagStart - 2
tagEnd = tagEnd + 2
if(tagStart ~= 0 and tagEnd ~= 0) then
local prefix = string.sub(bracket, 2, tagStart)
local suffix = string.sub(bracket, tagEnd, -2)
tagFunc = function(unit, realUnit)
local str = tag(unit, realUnit)
if(str) then
return prefix .. str .. suffix
end
end
elseif(tagStart ~= 0) then
local prefix = string.sub(bracket, 2, tagStart)
tagFunc = function(unit, realUnit)
local str = tag(unit, realUnit)
if(str) then
return prefix .. str
end
end
elseif(tagEnd ~= 0) then
local suffix = string.sub(bracket, tagEnd, -2)
tagFunc = function(unit, realUnit)
local str = tag(unit, realUnit)
if(str) then
return str .. suffix
end
end
end
funcPool[bracket] = tagFunc
end
end
if(tagFunc) then
tinsert(args, tagFunc)
else
numTags = -1
func = function(self)
return self:SetText(bracket)
end
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:SetText(string.format(
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:SetText(string.format(
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:SetText(string.format(
format,
args[1](unit, realUnit) or '',
args[2](unit, realUnit) or '',
args[3](unit, realUnit) or ''
))
end
elseif numTags ~= -1 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
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:SetText(string.format(format, unpack(tmp, 1, numTags)))
end
end
if numTags ~= -1 then
tagPool[tagstr] = func
end
end
fs.UpdateTag = func
local unit = self.unit
if(self.__eventless or fs.frequentUpdates) or containsOnUpdate then
local timer
if(type(fs.frequentUpdates) == 'number') then
timer = fs.frequentUpdates
elseif containsOnUpdate then
timer = containsOnUpdate
else
timer = .5
end
if(not eventlessUnits[timer]) then eventlessUnits[timer] = {} end
tinsert(eventlessUnits[timer], fs)
createOnUpdate(timer)
else
registerEvents(fs, tagstr)
end
tinsert(self.__tags, fs)
end
--[[ Tags: frame:Untag(fs)
Used to unregister a tag from a unit frame.
* self - the unit frame from which to unregister the tag
* fs - the font string holding the tag (FontString)
--]]
local function Untag(self, fs)
if(not fs) then return end
unregisterEvents(fs)
for _, timers in next, eventlessUnits do
for i, fontstr in next, timers do
if(fs == fontstr) then
tremove(timers, i)
end
end
end
for i, fontstr in next, self.__tags do
if(fontstr == fs) then
tremove(self.__tags, i)
end
end
fs.UpdateTag = nil
end
oUF.Tags = {
Methods = tags,
Events = tagEvents,
SharedEvents = unitlessEvents,
OnUpdateThrottle = onUpdateDelay,
}
oUF:RegisterMetaFunction('Tag', Tag)
oUF:RegisterMetaFunction('Untag', Untag)
+137
View File
@@ -0,0 +1,137 @@
local ns = oUF
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 unregisterEvent = frame_metatable.__index.UnregisterEvent
function Private.UpdateUnits(frame, unit, realUnit)
return true
end
local function onEvent()
if(this:IsVisible() or event == 'UNIT_COMBO_POINTS') then
--print(this, event, arg and unpack(arg))
--print(this, event, arg1, arg2, arg3, arg4, arg5)
return this[event](this, event, arg1, arg2, arg3, arg4, arg5)
end
end
local event_metatable = {
__call = function(funcs, self, ...)
for _, func in next, funcs do
func(self, unpack(arg))
end
end,
}
--[[ Events: frame:RegisterEvent(event, func, unitless)
Used to register a frame for a game event and add an event handler. OnUpdate polled frames are prevented from
registering events.
* self - frame that will be registered for the given event.
* event - name of the event to register (string)
* func - function that will be executed when the event fires. If a string is passed, then a function by that name
must be defined on the frame. Multiple functions can be added for the same frame and event
(string or function)
* unitless - indicates that the event does not fire for a specific unit, so the event arguments won't be
matched to the frame unit(s). Events that do not start with UNIT_ or are not known to be unit events are
automatically considered unitless (boolean)
--]]
function frame_metatable.__index:RegisterEvent(event, func)
-- Block OnUpdate polled frames from registering events.
-- UNIT_PORTRAIT_UPDATE and UNIT_MODEL_CHANGED which are used for
-- portrait updates.
if(self.__eventless and event ~= 'UNIT_PORTRAIT_UPDATE' and event ~= 'UNIT_MODEL_CHANGED') then return end
argcheck(event, 2, 'string')
if(type(func) == 'string' and type(self[func]) == 'function') then
func = self[func]
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(self:IsEventRegistered(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
registerEvent(self, event)
self.__registeredEvents[event] = true
end
end
--[[ Events: frame:IsEventRegistered(event, func)
Used to determine if a game event is registered.
* self - the frame registered for the event
* event - name of the registered event (string)
--]]
function frame_metatable.__index:IsEventRegistered(event)
argcheck(event, 2, 'string')
return self.__registeredEvents[event] and true or false
end
--[[ Events: frame:UnregisterEvent(event, func)
Used to remove a function from the event handler list for a game event.
* self - the frame registered for the event
* event - name of the registered event (string)
* func - function to be removed from the list of event handlers. If this is the only handler for the given event, then
the frame will be unregistered for the event
--]]
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 = getn(curev)
if(n == 1) then
local _, handler = next(curev)
self[event] = handler
elseif(n == 0) then
-- This should not happen
unregisterEvent(self, event)
self.__registeredEvents[event] = nil
end
break
end
end
elseif(curev == func) then
self[event] = nil
unregisterEvent(self, event)
self.__registeredEvents[event] = nil
end
end
+71
View File
@@ -0,0 +1,71 @@
local ns = oUF
local oUF = ns.oUF
local Private = oUF.Private
local argcheck = Private.argcheck
local queue = {}
local factory = CreateFrame('Frame')
factory:SetScript('OnEvent', function()
return this[event](this, event, arg and unpack(arg))
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
--[[ Factory: oUF:Factory(func)
Used to call a function directly if the current character is logged in and the factory is active. Else the function is
queued up to be executed at a later time (upon PLAYER_LOGIN by default).
* self - the global oUF object
* func - function to be executed or delayed (function)
--]]
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
--[[ Factory: oUF:EnableFactory()
Used to enable the factory.
* self - the global oUF object
--]]
function oUF:EnableFactory()
factory.active = true
end
--[[ Factory: oUF:DisableFactory()
Used to disable the factory.
* self - the global oUF object
--]]
function oUF:DisableFactory()
factory.active = nil
end
--[[ Factory: oUF:RunFactoryQueue()
Used to try to execute queued up functions. The current player must be logged in and the factory must be active for
this to succeed.
* self - the global oUF object
--]]
function oUF:RunFactoryQueue()
factory:PLAYER_LOGIN()
end
+4
View File
@@ -0,0 +1,4 @@
local ns = oUF
-- It's named Private for a reason!
ns.oUF.Private = nil
+5
View File
@@ -0,0 +1,5 @@
oUF = {}
local ns = oUF
ns.oUF = {}
ns.oUF.Private = {}
+61
View File
@@ -0,0 +1,61 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file="templates.lua"/>
<Include file="templates.xml"/>
<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"/>
<Include file="elements\elements.xml"/>
<Cooldown name="oUF_CooldownFrameTemplate" inherits="CooldownFrameTemplate" drawEdge="true" virtual="true"/>
<!--
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>
+698
View File
@@ -0,0 +1,698 @@
local ns = oUF
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, units, objects, headers = {}, {}, {}, {}
local elements = {}
local activeElements = {}
-- updating of "invalid" units.
local function enableTargetUpdate(object)
object.onUpdateFrequency = object.onUpdateFrequency or .5
object.__eventless = true
local total = 0
object:SetScript('OnUpdate', function()
if not this.unit then
return
elseif total > this.onUpdateFrequency then
this:UpdateAllElements('OnUpdate')
total = 0
end
total = total + GetTime()
end)
end
Private.enableTargetUpdate = enableTargetUpdate
local function updateActiveUnit(self, event, unit)
return true
end
local function iterateChildren(...)
for i = 1, table.getn(arg) do
local obj = arg[i]
if(type(obj) == 'table' and obj.isChild) then
updateActiveUnit(obj, 'iterateChildren')
end
end
end
local function onAttributeChanged(self, name, value)
if(name == 'unit' and value) then
if(self.hasChildren) then
iterateChildren(self:GetChildren())
end
if(not self.onlyProcessChildren) then
updateActiveUnit(self, 'OnAttributeChanged')
end
--[[
if(self.unit and self.unit == value) then
return
else
if(self.hasChildren) then
iterateChildren(self:GetChildren())
end
end
]]
end
end
local frame_metatable = {
__index = CreateFrame('Button')
}
Private.frame_metatable = frame_metatable
for k, v in next, {
UpdateElement = function(self, name)
local unit = self.unit
if(not unit or not UnitExists(unit)) then return end
local element = elements[name]
if(not element or not self:IsElementEnabled(name) or not activeElements[self]) then return end
if(element.update) then
element.update(self, 'OnShow', unit)
end
end,
UpdateElement = function(self, name)
local unit = self.unit
if(not unit or not UnitExists(unit)) then return end
local element = elements[name]
if(not element or not self:IsElementEnabled(name) or not activeElements[self]) then return end
if(element.update) then
element.update(self, 'OnShow', unit)
end
end,
--[[ frame:EnableElement(name, unit)
Used to activate an element for the given unit frame.
* self - unit frame for which the element should be enabled
* name - name of the element to be enabled (string)
* unit - unit to be passed to the element's Enable function. Defaults to the frame's unit (string?)
--]]
EnableElement = function(self, name, unit)
local unit = unit or self.unit
if not unit then return end
argcheck(name, 2, 'string')
argcheck(unit or self.unit, 3, 'string', 'nil')
local element = elements[name]
if(not element or self:IsElementEnabled(name) or not activeElements[self]) 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,
--[[ frame:DisableElement(name)
Used to deactivate an element for the given unit frame.
* self - unit frame for which the element should be disabled
* name - name of the element to be disabled (string)
--]]
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')
return elements[name].disable(self)
end,
--[[ frame:IsElementEnabled(name)
Used to check if an element is enabled on the given frame.
* self - unit frame
* name - name of the element (string)
--]]
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,
--[[ frame:Enable(asState)
Used to toggle the visibility of a unit frame based on the existence of its unit. This is a reference to
`RegisterUnitWatch`.
* self - unit frame
* asState - if true, the frame's "state-unitexists" attribute will be set to a boolean value denoting whether the
unit exists; if false, the frame will be shown if its unit exists, and hidden if it does not (boolean)
--]]
Enable = RegisterUnitWatch,
--[[ frame:Disable()
Used to UnregisterUnitWatch for the given frame and hide it.
* self - unit frame
--]]
Disable = function(self)
UnregisterUnitWatch(self)
self:Hide()
end,
--[[ frame:UpdateAllElements(event)
Used to update all enabled elements on the given frame.
* self - unit frame
* event - event name to pass to the elements' update functions (string)
--]]
UpdateAllElements = function(self, event)
local unit = self.unit
if(not UnitExists(unit)) then return end
assert(type(event) == 'string', "Invalid argument 'event' in UpdateAllElements.")
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,
SetUnit = function(self, unit)
if unit ~= unit then
self.unit = unit
end
end,
} do
frame_metatable.__index[k] = v
end
local secureDropdown
local function InitializeSecureMenu()
local unit = SecureTemplatesDropdown.unit
if(not unit) then return end
local unitType = string.match(unit, '^([a-z]+)[0-9]+$') or unit
local menu
if(unitType == 'party') then
menu = 'PARTY'
elseif(UnitIsUnit(unit, 'player')) then
menu = 'SELF'
elseif(UnitIsUnit(unit, 'pet')) then
menu = 'PET'
elseif(UnitIsPlayer(unit)) then
if(UnitInRaid(unit) or UnitInParty(unit)) then
menu = 'PARTY'
else
menu = 'PLAYER'
end
elseif(UnitIsUnit(unit, 'target')) then
menu = 'RAID_TARGET_ICON'
end
if(menu) then
UnitPopup_ShowMenu(SecureTemplatesDropdown, menu, unit)
end
end
local function togglemenu(self, unit)
if(not secureDropdown) then
secureDropdown = CreateFrame('Frame', 'SecureTemplatesDropdown', nil, 'UIDropDownMenuTemplate')
secureDropdown:SetID(1)
table.insert(UnitPopupFrames, secureDropdown:GetName())
UIDropDownMenu_Initialize(secureDropdown, InitializeSecureMenu, 'MENU')
end
if(secureDropdown.openedFor and secureDropdown.openedFor ~= self) then
CloseDropDownMenus()
end
secureDropdown.unit = string.lower(unit)
secureDropdown.openedFor = self
ToggleDropDownMenu(1, nil, secureDropdown, 'cursor')
end
local function onShow()
return this:UpdateAllElements('OnShow')
end
local function initObject(unit, style, styleFunc, header, ...)
local num = table.getn(arg)
for i = 1, num do
local object = arg[i]
local objectUnit = object.guessUnit or unit
local suffix = string.match(objectUnit or unit, '%w+target')
object.__elements = {}
object.__registeredEvents = {}
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)
object:SetScript("OnClick", function()
if arg1 == "RightButton" then
togglemenu(this, object.unit)
else
TargetUnit(this.unit)
end
end)
if(not header) then
-- Other target units are handled by :HandleUnit().
if(suffix == 'target') then
enableTargetUpdate(object)
else
oUF:HandleUnit(object, unit)
end
else
-- Used to update frames when they change position in a group.
object:RegisterEvent('RAID_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 kinda happy
_G.ClickCastFrames = ClickCastFrames or {}
ClickCastFrames[object] = true
end
end
local function walkObject(object, unit)
local parent = object:GetParent()
local style = parent.style or style
local styleFunc = styles[style]
local header = parent.headerType and parent
-- Check if we should leave the main frame blank.
if(object.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
--[[ oUF:RegisterInitCallback(func)
Used to add a function to a table to be executed upon unit frame/header initialization.
* self - the global oUF object
* func - function to be added
--]]
function oUF:RegisterInitCallback(func)
table.insert(callback, func)
end
--[[ oUF:RegisterMetaFunction(name, func)
Used to make a (table of) function(s) available to all unit frames.
* self - the global oUF object
* name - unique name of the function (string)
* func - function or a table of functions (function or table)
--]]
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
--[[ oUF:RegisterStyle(name, func)
Used to register a style with oUF. This will also set the active style if it hasn't been set yet.
* self - the global oUF object
* name - name of the style
* func - function(s) defining the style (function or table)
--]]
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
--[[ oUF:SetActiveStyle(name)
Used to set the active style.
* self - the global oUF object
* name - name of the style (string)
--]]
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
--[[ oUF:IterateStyles()
Returns an iterator over all registered styles.
* self - the global oUF object
--]]
function oUF.IterateStyles()
return iter, nil, nil
end
end
local getCondition
do
local conditions = {
raid40 = '[target=raid26,exists] show;',
raid25 = '[target=raid11,exists] show;',
raid10 = '[target=raid6,exists] show;',
raid = '[group:raid] show;',
party = '[group:party,nogroup:raid] show;',
solo = '[target=player,exists,nogroup:party] show;',
}
function getCondition(...)
local cond = ''
for i = 1, select('#', arg) do
local short = select(i, unpack(arg))
local condition = conditions[short]
if(condition) then
cond = cond .. condition
end
end
return cond .. 'hide'
end
end
local function generateName(unit, ...)
local name = 'oUF_' .. style:gsub('^oUF_?', ''):gsub('[^%a%d_]+', '')
local raid, party, groupFilter
for i = 1, select('#', arg), 2 do
local att, val = select(i, unpack(arg))
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
local base = name
local i = 2
while(_G[name]) do
name = base .. i
i = i + 1
end
return name
end
do
local function styleProxy(self, frame, ...)
return walkObject(_G[frame])
end
-- There has to be an easier way to do this.
local initialConfigFunction = function(self)
local header = self:GetParent()
local unit
if(not self.onlyProcessChildren) then
local groupFilter = header:GetAttribute('groupFilter')
if(header:GetAttribute('showRaid')) then
unit = 'raid'
elseif(header:GetAttribute('showParty')) then
unit = 'party'
end
self.menu = togglemenu
--self:SetAttribute('type1', 'target')
--self:SetAttribute('type2', 'menu')
self.guessUnit = unit
self.unit = "player"
-- self.onlyProcessChildren =true
end
styleProxy(nil, self:GetName())
end
local setAttribute = function(self, name, value)
if self.attributes[name] ~= value then
self.attributes[name] = value
if self:IsVisible() then
SecureGroupHeader_Update(self)
end
end
end
local getAttribute = function(self, name)
return self.attributes[name]
end
--[[ oUF:SpawnHeader(overrideName, template, visibility, ...)
Used to create a group header and apply the currently active style to it.
* self - the global oUF object
* overrideName - unique global name to be used for the header. Defaults to an auto-generated name based on the name
of the active style and other arguments passed to `:SpawnHeader` (string?)
* template - name of a template to be used for creating the header. Defaults to `'oUF_GroupHeaderTemplate'`
(string?)
* visibility - macro conditional(s) which define when to display the header (string).
* ... - further argument pairs. Consult [Group Headers](http://wowprogramming.com/docs/secure_template/Group_Headers)
for possible values.
In addition to the standard group headers, oUF implements some of its own attributes. These can be supplied by the
layout, but are optional.
* oUF-initialConfigFunction - can contain code that will be securely run at the end of the initial secure
configuration (string?)
* oUF-onlyProcessChildren - can be used to force headers to only process children (boolean?)
--]]
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 'oUF_GroupHeaderTemplate')
local isPetHeader = string.match(template, 'PetHeader')
local name = overrideName or generateName(nil, unpack(arg))
local header = CreateFrame('Frame', name, UIParent, template)
header:Hide()
header.attributes = {}
header.SetAttribute = setAttribute
header.GetAttribute = getAttribute
--header:SetAttribute('template', 'SecureUnitButtonTemplate')
for i = 1, getn(arg), 2 do
local att, val = select(i, unpack(arg))
if(not att) then break end
header:SetAttribute(att, val)
end
header.style = style
header.styleFunction = styleProxy
header.visibility = visibility
-- Expose the header through oUF.headers.
table.insert(headers, header)
header.initialConfigFunction = initialConfigFunction
header.headerType = isPetHeader and 'pet' or 'group'
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
RegisterStateDriver(header, 'visibility', list)
header.visibility = list
else
local condition = getCondition(string.split(',', visibility))
RegisterStateDriver(header, 'visibility', condition)
header.visibility = condition
end
end]]
return header
end
end
--[[ oUF:Spawn(unit, overrideName)
Used to create a single unit frame and apply the currently active style to it.
* self - the global oUF object
* unit - the frame's unit (string)
* overrideName - unique global name to use for the unit frame. Defaults to an auto-generated name based on the unit
(string?)
--]]
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 = string.lower(unit)
local name = overrideName or generateName(unit)
local object = CreateFrame('Button', name, UIParent)
object:Hide()
Private.UpdateUnits(object, unit)
self:DisableBlizzard(unit)
units[unit] = object
walkObject(object, unit)
object.unit = unit
return object
end
--[[ oUF:AddElement(name, update, enable, disable)
Used to register an element with oUF.
* self - the global oUF object
* name - unique name of the element (string)
* update - used to update the element (function?)
* enable - used to enable the element for a given unit frame and unit (function?)
* disable - used to disable the element for a given unit frame (function?)
--]]
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.units
Array containing all unit frames with existing units created by oUF:Spawn.
--]]
oUF.units = units
--[[ oUF.objects
Array containing all unit frames created by `oUF:Spawn`.
--]]
oUF.objects = objects
--[[ oUF.headers
Array containing all group headers created by `oUF:SpawnHeader`.
--]]
oUF.headers = headers
+22
View File
@@ -0,0 +1,22 @@
local ns = oUF
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('#', arg) do
if(type(value) == select(i, unpack(arg))) then return end
end
local types = strjoin(', ', unpack(arg))
local name = string.match(debugstack(2,2,0), ": in function [`<](.-)['>]")
error(string.format("Bad argument #%d to '%s' (%s expected, got %s)", num, name, types, type(value)), 3)
end
function Private.print(...)
print('|cff33ff99oUF:|r', unpack(arg))
end
function Private.error(...)
Private.print('|cffff0000Error:|r ' .. string.format(unpack(arg)))
end
+445
View File
@@ -0,0 +1,445 @@
local pairs = pairs
local ipairs = ipairs
local unitExistsWatchers = {}
local unitExistsCache = setmetatable({},{
__index = function(t, k)
local v = UnitExists(k) or false
t[k] = v
return v
end
})
local function updateUnitWatch(frame)
local unit = frame.unit
local exists = (unit and unitExistsCache[unit])
if exists then
if not frame:IsShown() then
frame:Show()
end
elseif frame:IsShown() then
frame:Hide()
end
end
local unitWatch = CreateFrame("Frame")
unitWatch:Hide()
local timer = 0
unitWatch:SetScript("OnUpdate", function()
timer = timer - arg1
if timer <= 0 then
timer = 0.2
for k in pairs(unitExistsCache) do
unitExistsCache[k] = nil
end
for frame in pairs(unitExistsWatchers) do
updateUnitWatch(frame)
end
end
end)
unitWatch:SetScript("OnEvent", function() timer = 0 end)
unitWatch:RegisterEvent("PLAYER_TARGET_CHANGED")
unitWatch:RegisterEvent("PLAYER_REGEN_DISABLED")
unitWatch:RegisterEvent("PLAYER_REGEN_ENABLED")
unitWatch:RegisterEvent("UNIT_PET")
unitWatch:RegisterEvent("RAID_ROSTER_UPDATE")
unitWatch:RegisterEvent("PARTY_MEMBERS_CHANGED")
function RegisterUnitWatch(frame)
unitExistsWatchers[frame] = true
unitWatch:Show()
updateUnitWatch(frame)
end
function UnregisterUnitWatch(frame)
unitExistsWatchers[frame] = nil
end
--[[
List of the various configuration attributes
======================================================
showRaid = [BOOLEAN] -- true if the header should be shown while in a raid
showParty = [BOOLEAN] -- true if the header should be shown while in a party and not in a raid
showPlayer = [BOOLEAN] -- true if the header should show the player when not in a raid
showSolo = [BOOLEAN] -- true if the header should be shown while not in a group (implies showPlayer)
nameList = [STRING] -- a comma separated list of player names (not used if 'groupFilter' is set)
groupFilter = [1-8, STRING] -- a comma seperated list of raid group numbers and/or uppercase class names and/or uppercase roles
strictFiltering = [BOOLEAN] - if true, then characters must match both a group and a class from the groupFilter list
point = [STRING] -- a valid XML anchoring point (Default: "TOP")
xOffset = [NUMBER] -- the x-Offset to use when anchoring the unit buttons (Default: 0)
yOffset = [NUMBER] -- the y-Offset to use when anchoring the unit buttons (Default: 0)
sortMethod = ["INDEX", "NAME"] -- defines how the group is sorted (Default: "INDEX")
sortDir = ["ASC", "DESC"] -- defines the sort order (Default: "ASC")
template = [STRING] -- the XML template to use for the unit buttons
templateType = [STRING] - specifies the frame type of the managed subframes (Default: "Button")
groupBy = [nil, "GROUP", "CLASS", "ROLE"] - specifies a "grouping" type to apply before regular sorting (Default: nil)
groupingOrder = [STRING] - specifies the order of the groupings (ie. "1,2,3,4,5,6,7,8")
maxColumns = [NUMBER] - maximum number of columns the header will create (Default: 1)
unitsPerColumn = [NUMBER or nil] - maximum units that will be displayed in a singe column, nil is infinate (Default: nil)
startingIndex = [NUMBER] - the index in the final sorted unit list at which to start displaying units (Default: 1)
columnSpacing = [NUMBER] - the ammount of space between the rows/columns (Default: 0)
columnAnchorPoint = [STRING] - the anchor point of each new column (ie. use LEFT for the columns to grow to the right)
--]]
function SecureGroupHeader_OnEvent()
if (event == "PARTY_MEMBERS_CHANGED" or event == "RAID_ROSTER_UPDATE") and this:IsVisible() then
SecureGroupHeader_Update(this)
end
end
-- relativePoint, xMultiplier, yMultiplier = getRelativePointAnchor(point)
-- Given a point return the opposite point and which axes the point
-- depends on.
local function getRelativePointAnchor(point)
point = strupper(point)
if point == "TOP" then
return "BOTTOM", 0, -1
elseif point == "BOTTOM" then
return "TOP", 0, 1
elseif point == "LEFT" then
return "RIGHT", 1, 0
elseif point == "RIGHT" then
return "LEFT", -1, 0
elseif point == "TOPLEFT" then
return "BOTTOMRIGHT", 1, -1
elseif point == "TOPRIGHT" then
return "BOTTOMLEFT", -1, -1
elseif point == "BOTTOMLEFT" then
return "TOPRIGHT", 1, 1
elseif point == "BOTTOMRIGHT" then
return "TOPLEFT", -1, 1
else
return "CENTER", 0, 0
end
end
function ApplyUnitButtonConfiguration(frame)
RegisterUnitWatch(frame)
end
local function ApplyConfig(header, newChild, defaultConfigFunction)
local configFunction = header.initialConfigFunction or defaultConfigFunction
if type(configFunction) == "function" then
configFunction(newChild)
return true
end
end
function SetupUnitButtonConfiguration(header, newChild, defaultConfigFunction)
if ApplyConfig(header, newChild, defaultConfigFunction) then
ApplyUnitButtonConfiguration(newChild)
end
end
-- empties tbl and assigns the value true to each key passed as part of ...
local function fillTable(tbl, ...)
for key in pairs(tbl) do
tbl[key] = nil
end
for i = 1, getn(arg), 1 do
local key = arg[i]
key = tonumber(key) or key
tbl[key] = true
end
end
-- same as fillTable() except that each key is also stored in
-- the array portion of the table in order
local function doubleFillTable(tbl, ...)
fillTable(tbl, unpack(arg))
for i = 1, getn(arg), 1 do
tbl[i] = arg[i]
end
end
--working tables
local tokenTable = {}
local sortingTable = {}
local groupingTable = {}
local tempTable = {}
-- creates child frames and finished configuring them
local function configureChildren(self)
local point = self:GetAttribute("point") or "TOP" --default anchor point of "TOP"
local relativePoint, xOffsetMult, yOffsetMult = getRelativePointAnchor(point)
local xMultiplier, yMultiplier = abs(xOffsetMult), abs(yOffsetMult)
local xOffset = self:GetAttribute("xOffset") or 0 --default of 0
local yOffset = self:GetAttribute("yOffset") or 0 --default of 0
local sortDir = self:GetAttribute("sortDir") or "ASC" --sort ascending by default
local columnSpacing = self:GetAttribute("columnSpacing") or 0
local startingIndex = self:GetAttribute("startingIndex") or 1
local unitCount = getn(sortingTable)
local numDisplayed = unitCount - (startingIndex - 1)
local unitsPerColumn = self:GetAttribute("unitsPerColumn")
local numColumns
if unitsPerColumn and numDisplayed > unitsPerColumn then
numColumns = min(ceil(numDisplayed / unitsPerColumn), (self:GetAttribute("maxColumns") or 1))
else
unitsPerColumn = numDisplayed
numColumns = 1
end
local loopStart = startingIndex
local loopFinish = min((startingIndex - 1) + unitsPerColumn * numColumns, unitCount)
local step = 1
numDisplayed = loopFinish - (loopStart - 1)
if sortDir == "DESC" then
loopStart = unitCount - (startingIndex - 1)
loopFinish = loopStart - (numDisplayed - 1)
step = -1
end
-- ensure there are enough buttons
local needButtons = max(1, numDisplayed)
if not self:GetAttribute("child"..needButtons) then
local name = self:GetName()
if not name then
self:Hide()
return
end
for i = 1, needButtons, 1 do
local childAttr = "child"..i
if not self:GetAttribute(childAttr) then
local newButton = CreateFrame("Button", name.."UnitButton"..i, self)
newButton:SetFrameStrata("LOW")
SetupUnitButtonConfiguration(self, newButton)
self:SetAttribute(childAttr, newButton)
end
end
end
local columnAnchorPoint, columnRelPoint, colxMulti, colyMulti
if numColumns > 1 then
columnAnchorPoint = self:GetAttribute("columnAnchorPoint")
columnRelPoint, colxMulti, colyMulti = getRelativePointAnchor(columnAnchorPoint)
end
local buttonNum = 0
local columnNum = 1
local columnUnitCount = 0
local currentAnchor = self
for i = loopStart, loopFinish, step do
buttonNum = buttonNum + 1
columnUnitCount = columnUnitCount + 1
if columnUnitCount > unitsPerColumn then
columnUnitCount = 1
columnNum = columnNum + 1
end
local unitButton = self:GetAttribute("child"..buttonNum)
unitButton:Hide()
unitButton:ClearAllPoints()
if buttonNum == 1 then
unitButton:SetPoint(point, currentAnchor, point, 0, 0)
if columnAnchorPoint then
unitButton:SetPoint(columnAnchorPoint, currentAnchor, columnAnchorPoint, 0, 0)
end
elseif columnUnitCount == 1 then
local columnAnchor = self:GetAttribute("child"..(buttonNum - unitsPerColumn))
unitButton:SetPoint(columnAnchorPoint, columnAnchor, columnRelPoint, colxMulti * columnSpacing, colyMulti * columnSpacing)
else
unitButton:SetPoint(point, currentAnchor, relativePoint, xMultiplier * xOffset, yMultiplier * yOffset)
end
unitButton.unit = sortingTable[sortingTable[i]]
unitButton:Show()
currentAnchor = unitButton
end
repeat
buttonNum = buttonNum + 1
local unitButton = self:GetAttribute("child"..buttonNum)
if unitButton then
unitButton:Hide()
unitButton.unit = nil
end
until not unitButton
local unitButton = self:GetAttribute("child1")
local unitButtonWidth = unitButton:GetWidth()
local unitButtonHeight = unitButton:GetHeight()
if numDisplayed > 0 then
local width = xMultiplier * (unitsPerColumn - 1) * unitButtonWidth + ((unitsPerColumn - 1) * (xOffset * xOffsetMult)) + unitButtonWidth
local height = yMultiplier * (unitsPerColumn - 1) * unitButtonHeight + ((unitsPerColumn - 1) * (yOffset * yOffsetMult)) + unitButtonHeight
if numColumns > 1 then
width = width + ((numColumns -1) * abs(colxMulti) * (width + columnSpacing))
height = height + ((numColumns -1) * abs(colyMulti) * (height + columnSpacing))
end
self:SetWidth(width)
self:SetHeight(height)
else
local minWidth = self:GetAttribute("minWidth") or (yMultiplier * unitButtonWidth)
local minHeight = self:GetAttribute("minHeight") or (xMultiplier * unitButtonHeight)
self:SetWidth(max(minWidth, 0.1))
self:SetHeight(max(minHeight, 0.1))
end
end
local function GetGroupHeaderType(self)
local type, start, stop
local nRaid = GetNumRaidMembers()
local nParty = GetNumPartyMembers()
if nRaid > 0 and self:GetAttribute("showRaid") then
type = "RAID"
elseif (nRaid > 0 or nParty > 0) and self:GetAttribute("showParty") then
type = "PARTY"
elseif self:GetAttribute("showSolo") then
type = "SOLO"
end
if type then
if type == "RAID" then
start = 1
stop = nRaid
else
if type == "SOLO" or self:GetAttribute("showPlayer") then
start = 0
else
start = 1
end
stop = nParty
end
end
return type, start, stop
end
local function GetGroupRosterInfo(type, index)
local _, unit, name, subgroup, className
if type == "RAID" then
unit = "raid"..index
name, _, subgroup, _, _, className = GetRaidRosterInfo(index)
else
if index > 0 then
unit = "party"..index
else
unit = "player"
end
if UnitExists(unit) then
name = UnitName(unit)
_, className = UnitClass(unit)
end
subgroup = 1
end
return unit, name, subgroup, className
end
function SecureGroupHeader_Update(self)
local nameList = self:GetAttribute("nameList")
local groupFilter = self:GetAttribute("groupFilter")
local sortMethod = self:GetAttribute("sortMethod")
local groupBy = self:GetAttribute("groupBy")
for key in pairs(sortingTable) do
sortingTable[key] = nil
end
table.setn(sortingTable, 0)
-- See if this header should be shown
local type, start, stop = GetGroupHeaderType(self)
if not type then
configureChildren(self)
return
end
if not groupFilter and not nameList then
groupFilter = "1,2,3,4,5,6,7,8"
end
if groupFilter then
-- filtering by a list of group numbers and/or classes
fillTable(tokenTable, strsplit(",", groupFilter))
local strictFiltering = self:GetAttribute("strictFiltering") -- non-strict by default
for i = start, stop, 1 do
local unit, name, subgroup, className = GetGroupRosterInfo(type, i)
if name and ((not strictFiltering) and (tokenTable[subgroup] or tokenTable[className])) or (tokenTable[subgroup] and tokenTable[className]) then
tinsert(sortingTable, name)
sortingTable[name] = unit
if groupBy == "GROUP" then
groupingTable[name] = subgroup
elseif groupBy == "CLASS" then
groupingTable[name] = className
end
end
end
if groupBy then
local groupingOrder = self:GetAttribute("groupingOrder")
doubleFillTable(tokenTable, strsplit(",", groupingOrder))
for k in pairs(tempTable) do
tempTable[k] = nil
end
for _, grouping in ipairs(tokenTable) do
grouping = tonumber(grouping) or grouping
for k in ipairs(groupingTable) do
groupingTable[k] = nil
end
table.setn(groupingTable, 0)
for index, name in ipairs(sortingTable) do
if groupingTable[name] == grouping then
tinsert(groupingTable, name)
tempTable[name] = true
end
end
if sortMethod == "NAME" then -- sort by ID by default
table.sort(groupingTable)
end
for _, name in ipairs(groupingTable) do
tinsert(tempTable, name)
end
end
-- handle units whose group didn't appear in groupingOrder
for k in ipairs(groupingTable) do
groupingTable[k] = nil
end
table.setn(groupingTable, 0)
for index, name in ipairs(sortingTable) do
if not tempTable[name] then
tinsert(groupingTable, name)
end
end
if sortMethod == "NAME" then -- sort by ID by default
table.sort(groupingTable)
end
for _, name in ipairs(groupingTable) do
tinsert(tempTable, name)
end
--copy the names back to sortingTable
for index, name in ipairs(tempTable) do
sortingTable[index] = name
end
elseif sortMethod == "NAME" then -- sort by ID by default
table.sort(sortingTable)
end
else
-- filtering via a list of names
doubleFillTable(sortingTable, strsplit(",", nameList))
for i = start, stop, 1 do
local unit, name = GetGroupRosterInfo(type, i)
if sortingTable[name] then
sortingTable[name] = unit
end
end
for i = getn(sortingTable), 1, -1 do
local name = sortingTable[i]
if sortingTable[name] == true then
tremove(sortingTable, i)
end
end
if sortMethod == "NAME" then
table.sort(sortingTable)
end
end
configureChildren(self)
end
+16
View File
@@ -0,0 +1,16 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Frame name="oUF_GroupHeaderTemplate" hidden="true" virtual="true">
<Scripts>
<OnLoad>
this:RegisterEvent("PARTY_MEMBERS_CHANGED")
this:RegisterEvent("RAID_ROSTER_UPDATE")
</OnLoad>
<OnEvent>
SecureGroupHeader_OnEvent(this, event)
</OnEvent>
<OnShow>
SecureGroupHeader_Update(this)
</OnShow>
</Scripts>
</Frame>
</Ui>
+18
View File
@@ -0,0 +1,18 @@
local ns = oUF
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(string.match(unit, '%w+target')) then
enableTargetUpdate(object)
end
end