mirror of
https://github.com/Bluewhale1337/ElvUIModernized.git
synced 2026-07-27 08:24:44 +00:00
remove temp folder structure
This commit is contained in:
@@ -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.
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,4 @@
|
||||
local ns = oUF
|
||||
|
||||
-- It's named Private for a reason!
|
||||
ns.oUF.Private = nil
|
||||
@@ -0,0 +1,5 @@
|
||||
oUF = {}
|
||||
|
||||
local ns = oUF
|
||||
ns.oUF = {}
|
||||
ns.oUF.Private = {}
|
||||
@@ -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>
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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>
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user