commit from backup

This commit is contained in:
mikx
2018-01-05 06:40:15 -05:00
commit 58b08d6ae0
142 changed files with 29080 additions and 0 deletions

22
Libraries/oUF/LICENSE Normal file
View File

@@ -0,0 +1,22 @@
Copyright (c) 2006-2014 Trond A Ekseth <troeks@gmail.com>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

102
Libraries/oUF/blizzard.lua Normal file
View File

@@ -0,0 +1,102 @@
local parent, ns = ...
local oUF = ns.oUF
local hiddenParent = CreateFrame("Frame")
hiddenParent:Hide()
local HandleFrame = function(baseName)
local frame
if(type(baseName) == 'string') then
frame = _G[baseName]
else
frame = baseName
end
if(frame) then
frame:UnregisterAllEvents()
frame:Hide()
-- Keep frame hidden without causing taint
frame:SetParent(hiddenParent)
local health = frame.healthbar
if(health) then
health:UnregisterAllEvents()
end
local power = frame.manabar
if(power) then
power:UnregisterAllEvents()
end
local spell = frame.spellbar
if(spell) then
spell:UnregisterAllEvents()
end
local altpowerbar = frame.powerBarAlt
if(altpowerbar) then
altpowerbar:UnregisterAllEvents()
end
end
end
function oUF:DisableBlizzard(unit)
if(not unit) then return end
if(unit == 'player') then
HandleFrame(PlayerFrame)
-- For the damn vehicle support:
PlayerFrame:RegisterEvent('PLAYER_ENTERING_WORLD')
PlayerFrame:RegisterEvent('UNIT_ENTERING_VEHICLE')
PlayerFrame:RegisterEvent('UNIT_ENTERED_VEHICLE')
PlayerFrame:RegisterEvent('UNIT_EXITING_VEHICLE')
PlayerFrame:RegisterEvent('UNIT_EXITED_VEHICLE')
-- User placed frames don't animate
PlayerFrame:SetUserPlaced(true)
PlayerFrame:SetDontSavePosition(true)
elseif(unit == 'pet') then
HandleFrame(PetFrame)
elseif(unit == 'target') then
HandleFrame(TargetFrame)
HandleFrame(ComboFrame)
elseif(unit == 'focus') then
HandleFrame(FocusFrame)
HandleFrame(TargetofFocusFrame)
elseif(unit == 'targettarget') then
HandleFrame(TargetFrameToT)
elseif(unit:match'(boss)%d?$' == 'boss') then
local id = unit:match'boss(%d)'
if(id) then
HandleFrame('Boss' .. id .. 'TargetFrame')
else
for i=1, 5 do
HandleFrame(('Boss%dTargetFrame'):format(i))
end
end
elseif(unit:match'(party)%d?$' == 'party') then
local id = unit:match'party(%d)'
if(id) then
HandleFrame('PartyMemberFrame' .. id)
else
for i=1, 4 do
HandleFrame(('PartyMemberFrame%d'):format(i))
end
end
elseif(unit:match'(arena)%d?$' == 'arena') then
local id = unit:match'arena(%d)'
if(id) then
HandleFrame('ArenaEnemyFrame' .. id)
else
for i=1, 5 do
HandleFrame(('ArenaEnemyFrame%d'):format(i))
end
end
-- Blizzard_ArenaUI should not be loaded
Arena_LoadUI = function() end
SetCVar('showArenaEnemyFrames', '0', 'SHOW_ARENA_ENEMY_FRAMES_TEXT')
end
end

168
Libraries/oUF/colors.lua Normal file
View File

@@ -0,0 +1,168 @@
local parent, ns = ...
local oUF = ns.oUF
local Private = oUF.Private
local frame_metatable = Private.frame_metatable
local colors = {
smooth = {
1, 0, 0,
1, 1, 0,
0, 1, 0
},
disconnected = {.6, .6, .6},
tapped = {.6,.6,.6},
class = {},
reaction = {},
}
-- We do this because people edit the vars directly, and changing the default
-- globals makes SPICE FLOW!
local customClassColors = function()
if(CUSTOM_CLASS_COLORS) then
local updateColors = function()
for eclass, color in next, CUSTOM_CLASS_COLORS do
colors.class[eclass] = {color.r, color.g, color.b}
end
for _, obj in next, oUF.objects do
obj:UpdateAllElements("CUSTOM_CLASS_COLORS")
end
end
updateColors()
CUSTOM_CLASS_COLORS:RegisterCallback(updateColors)
return true
end
end
if not customClassColors() then
for eclass, color in next, RAID_CLASS_COLORS do
colors.class[eclass] = {color.r, color.g, color.b}
end
local f = CreateFrame("Frame")
f:RegisterEvent("ADDON_LOADED")
f:SetScript("OnEvent", function()
if customClassColors() then
f:UnregisterEvent("ADDON_LOADED")
f:SetScript("OnEvent", nil)
end
end)
end
for eclass, color in next, FACTION_BAR_COLORS do
colors.reaction[eclass] = {color.r, color.g, color.b}
end
local function ColorsAndPercent(a, b, ...)
if a <= 0 or b == 0 then
return nil, ...
elseif a >= b then
return nil, select(select('#', ...) - 2, ...)
end
local num = select('#', ...) / 3
local segment, relperc = math.modf((a/b)*(num-1))
return relperc, select((segment*3)+1, ...)
end
-- http://www.wowwiki.com/ColorGradient
local RGBColorGradient = function(...)
local relperc, r1, g1, b1, r2, g2, b2 = ColorsAndPercent(...)
if relperc then
return r1 + (r2-r1)*relperc, g1 + (g2-g1)*relperc, b1 + (b2-b1)*relperc
else
return r1, g1, b1
end
end
-- HCY functions are based on http://www.chilliant.com/rgb2hsv.html
local function GetY(r, g, b)
return 0.299 * r + 0.587 * g + 0.114 * b
end
local function RGBToHCY(r, g, b)
local min, max = min(r, g, b), max(r, g, b)
local chroma = max - min
local hue
if chroma > 0 then
if r == max then
hue = ((g - b) / chroma) % 6
elseif g == max then
hue = (b - r) / chroma + 2
elseif b == max then
hue = (r - g) / chroma + 4
end
hue = hue / 6
end
return hue, chroma, GetY(r, g, b)
end
local abs = math.abs
local function HCYtoRGB(hue, chroma, luma)
local r, g, b = 0, 0, 0
if hue and luma > 0 then
local h2 = hue * 6
local x = chroma * (1 - abs(h2 % 2 - 1))
if h2 < 1 then
r, g, b = chroma, x, 0
elseif h2 < 2 then
r, g, b = x, chroma, 0
elseif h2 < 3 then
r, g, b = 0, chroma, x
elseif h2 < 4 then
r, g, b = 0, x, chroma
elseif h2 < 5 then
r, g, b = x, 0, chroma
else
r, g, b = chroma, 0, x
end
local y = GetY(r, g, b)
if luma < y then
chroma = chroma * (luma / y)
elseif y < 1 then
chroma = chroma * (1 - luma) / (1 - y)
end
r = (r - y) * chroma + luma
g = (g - y) * chroma + luma
b = (b - y) * chroma + luma
end
return r, g, b
end
local HCYColorGradient = function(...)
local relperc, r1, g1, b1, r2, g2, b2 = ColorsAndPercent(...)
if not relperc then return r1, g1, b1 end
local h1, c1, y1 = RGBToHCY(r1, g1, b1)
local h2, c2, y2 = RGBToHCY(r2, g2, b2)
local c = c1 + (c2-c1) * relperc
local y = y1 + (y2-y1) * relperc
if h1 and h2 then
local dh = h2 - h1
if dh < -0.5 then
dh = dh + 1
elseif dh > 0.5 then
dh = dh - 1
end
return HCYtoRGB((h1 + dh * relperc) % 1, c, y)
else
return HCYtoRGB(h1 or h2, c, y)
end
end
local ColorGradient = function(...)
return (oUF.useHCYColorGradient and HCYColorGradient or RGBColorGradient)(...)
end
Private.colors = colors
oUF.colors = colors
oUF.ColorGradient = ColorGradient
oUF.RGBColorGradient = RGBColorGradient
oUF.HCYColorGradient = HCYColorGradient
oUF.useHCYColorGradient = false
frame_metatable.__index.colors = colors
frame_metatable.__index.ColorGradient = ColorGradient

View File

@@ -0,0 +1,194 @@
--[[ Element: Additional Power Bar
Handles updating and visibility of a status bar displaying the player's
alternate/additional power, such as Mana for Balance druids.
Widget
AdditionalPower - A StatusBar to represent current caster mana.
Sub-Widgets
.bg - A Texture which functions as a background. It will inherit the color of
the main StatusBar.
Notes
The default StatusBar texture will be applied if the UI widget doesn't have a
status bar texture or color defined.
Options
.colorClass - Use `self.colors.class[class]` to color the bar.
.colorSmooth - Use `self.colors.smooth` to color the bar with a smooth
gradient based on the players current mana percentage.
.colorPower - Use `self.colors.power[token]` to color the bar. This will
always use MANA as token.
Sub-Widget Options
.multiplier - Defines a multiplier, which is used to tint the background based
on the main widgets R, G and B values. Defaults to 1 if not
present.
Examples
-- Position and size
local AdditionalPower = CreateFrame("StatusBar", nil, self)
AdditionalPower:SetSize(20, 20)
AdditionalPower:SetPoint('TOP')
AdditionalPower:SetPoint('LEFT')
AdditionalPower:SetPoint('RIGHT')
-- Add a background
local Background = AdditionalPower:CreateTexture(nil, 'BACKGROUND')
Background:SetAllPoints(AdditionalPower)
Background:SetTexture(1, 1, 1, .5)
-- Register it with oUF
self.AdditionalPower = AdditionalPower
self.AdditionalPower.bg = Background
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local _, ns = ...
local oUF = ns.oUF
local playerClass = select(2, UnitClass('player'))
local ADDITIONAL_POWER_BAR_NAME = ADDITIONAL_POWER_BAR_NAME
local ADDITIONAL_POWER_BAR_INDEX = ADDITIONAL_POWER_BAR_INDEX
local function Update(self, event, unit, powertype)
if(unit ~= 'player' or (powertype and powertype ~= ADDITIONAL_POWER_BAR_NAME)) then return end
local element = self.AdditionalPower
if(element.PreUpdate) then element:PreUpdate(unit) end
local cur = UnitPower('player', ADDITIONAL_POWER_BAR_INDEX)
local max = UnitPowerMax('player', ADDITIONAL_POWER_BAR_INDEX)
element:SetMinMaxValues(0, max)
element:SetValue(cur)
local r, g, b, t
if(element.colorClass) then
t = self.colors.class[playerClass]
elseif(element.colorSmooth) then
r, g, b = self.ColorGradient(cur, max, unpack(element.smoothGradient or self.colors.smooth))
elseif(element.colorPower) then
t = self.colors.power[ADDITIONAL_POWER_BAR_NAME]
end
if(t) then
r, g, b = t[1], t[2], t[3]
end
if(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
if(element.PostUpdate) then
return element:PostUpdate(unit, cur, max, event)
end
end
local function Path(self, ...)
return (self.AdditionalPower.Override or Update) (self, ...)
end
local function ElementEnable(self)
self:RegisterEvent('UNIT_POWER_FREQUENT', Path)
self:RegisterEvent('UNIT_DISPLAYPOWER', Path)
self:RegisterEvent('UNIT_MAXPOWER', Path)
self.AdditionalPower:Show()
if self.AdditionalPower.PostUpdateVisibility then
self.AdditionalPower:PostUpdateVisibility(true, not self.AdditionalPower.isEnabled)
end
self.AdditionalPower.isEnabled = true
Path(self, 'ElementEnable', 'player', ADDITIONAL_POWER_BAR_NAME)
end
local function ElementDisable(self)
self:UnregisterEvent('UNIT_POWER_FREQUENT', Path)
self:UnregisterEvent('UNIT_DISPLAYPOWER', Path)
self:UnregisterEvent('UNIT_MAXPOWER', Path)
self.AdditionalPower:Hide()
if self.AdditionalPower.PostUpdateVisibility then
self.AdditionalPower:PostUpdateVisibility(false, self.AdditionalPower.isEnabled)
end
self.AdditionalPower.isEnabled = nil
Path(self, 'ElementDisable', 'player', ADDITIONAL_POWER_BAR_NAME)
end
local function Visibility(self, event, unit)
local shouldEnable
if(not UnitHasVehicleUI('player')) then
if(UnitPowerMax(unit, ADDITIONAL_POWER_BAR_INDEX) ~= 0) then
if(ALT_MANA_BAR_PAIR_DISPLAY_INFO[playerClass]) then
local powerType = UnitPowerType(unit)
shouldEnable = ALT_MANA_BAR_PAIR_DISPLAY_INFO[playerClass][powerType]
end
end
end
if(shouldEnable) then
ElementEnable(self)
else
ElementDisable(self)
end
end
local VisibilityPath = function(self, ...)
return (self.AdditionalPower.OverrideVisibility or Visibility) (self, ...)
end
local function ForceUpdate(element)
return VisibilityPath(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local Enable = function(self, unit)
local element = self.AdditionalPower
if(element and unit == 'player') then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_DISPLAYPOWER', VisibilityPath)
if(element:IsObjectType'StatusBar' and not element:GetStatusBarTexture()) then
element:SetStatusBarTexture[[Interface\TargetingFrame\UI-StatusBar]]
end
return true
end
end
local Disable = function(self)
local element = self.AdditionalPower
if(element) then
ElementDisable(self)
self:UnregisterEvent('UNIT_DISPLAYPOWER', VisibilityPath)
end
end
oUF:AddElement('AdditionalPower', VisibilityPath, Enable, Disable)

View File

@@ -0,0 +1,203 @@
--[[ Element: Alternative Power Bar
Handles visibility and updating of the alternative power bar.
This bar is used to display encounter/quest related power information, such as
the number of hour glass uses left on the end boss in End Time.
Widget
AltPowerBar - A StatusBar to represent alternative power.
Options
.colorTexture - Use the vertex color values returned by
UnitAlternatePowerTextureInfo to color the bar.
Notes
OnEnter and OnLeave handlers to display a tooltip will be set on the widget if
it is mouse enabled.
Examples
-- Position and size
local AltPowerBar = CreateFrame('StatusBar', nil, self)
AltPowerBar:SetHeight(20)
AltPowerBar:SetPoint('BOTTOM')
AltPowerBar:SetPoint('LEFT')
AltPowerBar:SetPoint('RIGHT')
-- Register with oUF
self.AltPowerBar = AltPowerBar
Callbacks
]]
local parent, ns = ...
local oUF = ns.oUF
local ALTERNATE_POWER_INDEX = ALTERNATE_POWER_INDEX
--[[ :UpdateTooltip()
The function called when the widget is hovered. Used to populate the tooltip.
Arguments
self - The AltPowerBar element.
]]
local UpdateTooltip = function(self)
GameTooltip:SetText(self.powerName, 1, 1, 1)
GameTooltip:AddLine(self.powerTooltip, nil, nil, nil, 1)
GameTooltip:Show()
end
local OnEnter = function(self)
if(not self:IsVisible()) then return end
GameTooltip_SetDefaultAnchor(GameTooltip, self)
self:UpdateTooltip()
end
local OnLeave = function()
GameTooltip:Hide()
end
local UpdatePower = function(self, event, unit, powerType)
if(self.unit ~= unit or powerType ~= 'ALTERNATE') or not unit then return end
local altpowerbar = self.AltPowerBar
--[[ :PreUpdate()
Called before the element has been updated.
Arguments
self - The AltPowerBar element.
]]
if(altpowerbar.PreUpdate) then
altpowerbar:PreUpdate()
end
local _, r, g, b
if(altpowerbar.colorTexture) then
_, r, g, b = UnitAlternatePowerTextureInfo(unit, 2)
end
local cur = UnitPower(unit, ALTERNATE_POWER_INDEX)
local max = UnitPowerMax(unit, ALTERNATE_POWER_INDEX)
local barType, min, _, _, _, _, _, _, _, _, powerName, powerTooltip = UnitAlternatePowerInfo(unit)
altpowerbar.barType = barType
altpowerbar.powerName = powerName
altpowerbar.powerTooltip = powerTooltip
altpowerbar:SetMinMaxValues(min, max)
altpowerbar:SetValue(math.min(math.max(cur, min), max))
if(b) then
altpowerbar:SetStatusBarColor(r, g, b)
end
--[[ :PostUpdate(min, cur, max)
Called after the element has been updated.
Arguments
self - The AltPowerBar element.
min - The minimum possible power value for the active type.
cur - The current power value.
max - The maximum possible power value for the active type.
]]
if(altpowerbar.PostUpdate) then
return altpowerbar:PostUpdate(min, cur, max)
end
end
--[[ Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local Path = function(self, ...)
return (self.AltPowerBar.Override or UpdatePower)(self, ...)
end
local ForceUpdate = function(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit, 'ALTERNATE')
end
local Toggler = function(self, event, unit)
if(unit ~= self.unit) or not unit then return end
local altpowerbar = self.AltPowerBar
local barType, _, _, _, _, hideFromOthers, showOnRaid = UnitAlternatePowerInfo(unit)
if(barType and (showOnRaid and (UnitInParty(unit) or UnitInRaid(unit)) or not hideFromOthers or unit == 'player' or self.realUnit == 'player')) then
self:RegisterEvent('UNIT_POWER', Path)
self:RegisterEvent('UNIT_MAXPOWER', Path)
ForceUpdate(altpowerbar)
altpowerbar:Show()
else
self:UnregisterEvent('UNIT_POWER', Path)
self:UnregisterEvent('UNIT_MAXPOWER', Path)
altpowerbar:Hide()
end
end
local Enable = function(self, unit)
local altpowerbar = self.AltPowerBar
if(altpowerbar) then
altpowerbar.__owner = self
altpowerbar.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_POWER_BAR_SHOW', Toggler)
self:RegisterEvent('UNIT_POWER_BAR_HIDE', Toggler)
altpowerbar:Hide()
if(altpowerbar:IsMouseEnabled()) then
if(not altpowerbar:GetScript('OnEnter')) then
altpowerbar:SetScript('OnEnter', OnEnter)
end
if(not altpowerbar:GetScript('OnLeave')) then
altpowerbar:SetScript('OnLeave', OnLeave)
end
if(not altpowerbar.UpdateTooltip) then
altpowerbar.UpdateTooltip = UpdateTooltip
end
end
if(unit == 'player') then
PlayerPowerBarAlt:UnregisterEvent'UNIT_POWER_BAR_SHOW'
PlayerPowerBarAlt:UnregisterEvent'UNIT_POWER_BAR_HIDE'
PlayerPowerBarAlt:UnregisterEvent'PLAYER_ENTERING_WORLD'
end
return true
end
end
local Disable = function(self, unit)
local altpowerbar = self.AltPowerBar
if(altpowerbar) then
altpowerbar:Hide()
self:UnregisterEvent('UNIT_POWER_BAR_SHOW', Toggler)
self:UnregisterEvent('UNIT_POWER_BAR_HIDE', Toggler)
if(unit == 'player') then
PlayerPowerBarAlt:RegisterEvent'UNIT_POWER_BAR_SHOW'
PlayerPowerBarAlt:RegisterEvent'UNIT_POWER_BAR_HIDE'
PlayerPowerBarAlt:RegisterEvent'PLAYER_ENTERING_WORLD'
end
end
end
oUF:AddElement('AltPowerBar', Toggler, Enable, Disable)

View File

@@ -0,0 +1,112 @@
--[[ Element: Assistant Icon
Toggles visibility of `self.Assistant` based on the units raid officer status.
Widget
Assistant - Any UI widget.
Notes
The default assistant icon will be applied if the UI widget is a texture and
doesn't have a texture or color defined.
Examples
-- Position and size
local Assistant = self:CreateTexture(nil, "OVERLAY")
Assistant:SetSize(16, 16)
Assistant:SetPoint('TOP', self)
-- Register it with oUF
self.Assistant = Assistant
Hooks and Callbacks
]]
local parent, ns = ...
local oUF = ns.oUF
local Update = function(self, event)
if not self.unit then return; end
local assistant = self.Assistant
--[[ :PreUpdate()
Called before the element has been updated.
Arguments
self - The Assistant element.
]]
if(assistant.PreUpdate) then
assistant:PreUpdate()
end
local unit = self.unit
local isAssistant = UnitInRaid(unit) and UnitIsGroupAssistant(unit) and not UnitIsGroupLeader(unit)
if(isAssistant) then
assistant:Show()
else
assistant:Hide()
end
--[[ :PostUpdate(isAssistant)
Called after the element has been updated.
Arguments
self - The Assistant element.
isAssistant - A boolean holding whether the unit is a raid officer or not.
]]
if(assistant.PostUpdate) then
return assistant:PostUpdate(isAssistant)
end
end
local Path = function(self, ...)
--[[ :Override(self, event, ...)
Used to completely override the internal update function. Removing the
table key entry will make the element fall-back to its internal function
again.
Arguments
self - The Assistant element.
event - The UI event that fired.
... - A vararg with the arguments that accompany the event.
]]
return (self.Assistant.Override or Update) (self, ...)
end
local ForceUpdate = function(element)
return Path(element.__owner, 'ForceUpdate')
end
local Enable = function(self)
local assistant = self.Assistant
if(assistant) then
self:RegisterEvent("GROUP_ROSTER_UPDATE", Path, true)
if(assistant:IsObjectType"Texture" and not assistant:GetTexture()) then
assistant:SetTexture[[Interface\GroupFrame\UI-Group-AssistantIcon]]
end
assistant.__owner = self
assistant.ForceUpdate = ForceUpdate
return true
end
end
local Disable = function(self)
local assistant = self.Assistant
if(assistant) then
self:UnregisterEvent("GROUP_ROSTER_UPDATE", Path)
assistant:Hide()
end
end
oUF:AddElement('Assistant', Path, Enable, Disable)

View File

@@ -0,0 +1,525 @@
--[[ Element: Auras
Handles creation and updating of aura icons.
Widget
Auras - A Frame to hold icons representing both buffs and debuffs.
Buffs - A Frame to hold icons representing buffs.
Debuffs - A Frame to hold icons representing debuffs.
Options
.disableCooldown - Disables the cooldown spiral. Defaults to false.
.size - Aura icon size. Defaults to 16.
.onlyShowPlayer - Only show auras created by player/vehicle.
.showStealableBuffs - Display the stealable texture on buffs that can be
stolen.
.spacing - Spacing between each icon. Defaults to 0.
.['spacing-x'] - Horizontal spacing between each icon. Takes priority over
`spacing`.
.['spacing-y'] - Vertical spacing between each icon. Takes priority over
`spacing`.
.['growth-x'] - Horizontal growth direction. Defaults to RIGHT.
.['growth-y'] - Vertical growth direction. Defaults to UP.
.initialAnchor - Anchor point for the icons. Defaults to BOTTOMLEFT.
.filter - Custom filter list for auras to display. Defaults to
HELPFUL on buffs and HARMFUL on debuffs.
Options Auras
.numBuffs - The maximum number of buffs to display. Defaults to 32.
.numDebuffs - The maximum number of debuffs to display. Defaults to 40.
.gap - Controls the creation of an invisible icon between buffs and
debuffs. Defaults to false.
.buffFilter - Custom filter list for buffs to display. Takes priority over
`filter`.
.debuffFilter - Custom filter list for debuffs to display. Takes priority over
`filter`.
Options Buffs
.num - Number of buffs to display. Defaults to 32.
Options Debuffs
.num - Number of debuffs to display. Defaults to 40.
Examples
-- Position and size
local Buffs = CreateFrame("Frame", nil, self)
Buffs:SetPoint("RIGHT", self, "LEFT")
Buffs:SetSize(16 * 2, 16 * 16)
-- Register with oUF
self.Buffs = Buffs
Hooks and Callbacks
]]
local parent, ns = ...
local oUF = ns.oUF
local VISIBLE = 1
local HIDDEN = 0
local UpdateTooltip = function(self)
GameTooltip:SetUnitAura(self:GetParent().__owner.unit, self:GetID(), self.filter)
end
local OnEnter = function(self)
if(not self:IsVisible()) then return end
GameTooltip:SetOwner(self, "ANCHOR_BOTTOMRIGHT")
self:UpdateTooltip()
end
local OnLeave = function()
GameTooltip:Hide()
end
local createAuraIcon = function(icons, index)
local button = CreateFrame("Button", icons:GetDebugName().."Button"..index, icons)
button:RegisterForClicks'RightButtonUp'
local cd = CreateFrame("Cooldown", "$parentCooldown", button, "CooldownFrameTemplate")
cd:SetAllPoints(button)
local icon = button:CreateTexture(nil, "BORDER")
icon:SetAllPoints(button)
local count = button:CreateFontString(nil, "OVERLAY")
count:SetFontObject(NumberFontNormal)
count:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", -1, 0)
local overlay = button:CreateTexture(nil, "OVERLAY")
overlay:SetTexture"Interface\\Buttons\\UI-Debuff-Overlays"
overlay:SetAllPoints(button)
overlay:SetTexCoord(.296875, .5703125, 0, .515625)
button.overlay = overlay
local stealable = button:CreateTexture(nil, 'OVERLAY')
stealable:SetTexture[[Interface\TargetingFrame\UI-TargetingFrame-Stealable]]
stealable:SetPoint('TOPLEFT', -3, 3)
stealable:SetPoint('BOTTOMRIGHT', 3, -3)
stealable:SetBlendMode'ADD'
button.stealable = stealable
button.UpdateTooltip = UpdateTooltip
button:SetScript("OnEnter", OnEnter)
button:SetScript("OnLeave", OnLeave)
button.icon = icon
button.count = count
button.cd = cd
--[[ :PostCreateIcon(button)
Callback which is called after a new aura icon button has been created.
Arguments
button - The newly created aura icon button.
]]
if(icons.PostCreateIcon) then icons:PostCreateIcon(button) end
return button
end
local customFilter = function(icons, unit, icon, name)
if((icons.onlyShowPlayer and icon.isPlayer) or (not icons.onlyShowPlayer and name)) then
return true
end
end
local updateIcon = function(unit, icons, index, offset, filter, isDebuff, visible)
local name, rank, texture, count, dispelType, duration, expiration, caster, isStealable,
nameplateShowSelf, spellID, canApply, isBossDebuff, casterIsPlayer, nameplateShowAll,
timeMod, effect1, effect2, effect3 = UnitAura(unit, index, filter)
if icons.forceShow then
spellID = 47540
name, rank, texture = GetSpellInfo(spellID)
count, dispelType, duration, expiration, caster, isStealable, nameplateShowSelf, canApplyAura, isBossDebuff = 5, 'Magic', 0, 60, 'player', nil, nil, nil, nil
end
if(name) then
local n = visible + offset + 1
local icon = icons[n]
if(not icon) then
--[[ :CreateIcon(index)
A function which creates the aura icon for a given index.
Arguments
index - The offset the icon should be created at.
Returns
A button used to represent aura icons.
]]
local prev = icons.createdIcons
icon = (icons.CreateIcon or createAuraIcon) (icons, n)
-- XXX: Update the counters if the layout doesn't.
if(prev == icons.createdIcons) then
table.insert(icons, icon)
icons.createdIcons = icons.createdIcons + 1
end
end
local isPlayer
if(caster == 'player' or caster == 'vehicle') then
isPlayer = true
end
icon.owner = caster
icon.filter = filter
icon.isDebuff = isDebuff
icon.isPlayer = isPlayer
--[[ :CustomFilter(unit, icon, ...)
Defines a custom filter which controls if the aura icon should be shown
or not.
Arguments
self - The widget that holds the aura icon.
unit - The unit that has the aura.
icon - The button displaying the aura.
... - The return values from
[UnitAura](http://wowprogramming.com/docs/api/UnitAura).
Returns
A boolean value telling the aura element if it should be show the icon
or not.
]]
local show = true
if not icons.forceShow then
show = (icons.CustomFilter or customFilter) (icons, unit, icon, name, rank, texture,
count, dispelType, duration, expiration, caster, isStealable, nameplateShowSelf, spellID,
canApply, isBossDebuff, casterIsPlayer, nameplateShowAll,timeMod, effect1, effect2, effect3)
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.
local cd = icon.cd
if(cd and not icons.disableCooldown) then
if(duration and duration > 0) then
cd:SetCooldown(expiration - duration, duration)
cd:Show()
else
cd:Hide()
end
end
if((isDebuff and icons.showDebuffType) or (not isDebuff and icons.showBuffType) or icons.showType) then
local color = DebuffTypeColor[dispelType] or DebuffTypeColor.none
icon.overlay:SetVertexColor(color.r, color.g, color.b)
icon.overlay:Show()
else
icon.overlay:Hide()
end
local stealable = not isDebuff and isStealable
if(stealable and icons.showStealableBuffs and not UnitIsUnit('player', unit)) then
icon.stealable:Show()
else
icon.stealable:Hide()
end
icon.icon:SetTexture(texture)
icon.count:SetText((count > 1 and count))
local size = icons.size or 16
icon:SetSize(size, size)
icon:EnableMouse(true)
icon:SetID(index)
icon:Show()
--[[ :PostUpdateIcon(unit, icon, index, offest)
Callback which is called after the aura icon was updated.
Arguments
self - The widget that holds the aura icon.
unit - The unit that has the aura.
icon - The button that was updated.
index - The index of the aura.
offset - The offset the button was created at.
]]
if(icons.PostUpdateIcon) then
icons:PostUpdateIcon(unit, icon, index, n)
end
return VISIBLE
else
return HIDDEN
end
end
end
--[[ :SetPosition(from, to)
Function used to (re-)anchor aura icons. This function is only called when
new aura icons have been created or if :PreSetPosition is defined.
Arguments
self - The widget that holds the aura icons.
from - The aura icon before the new aura icon.
to - The current number of created icons.
]]
local SetPosition = function(icons, from, to)
local sizex = (icons.size or 16) + (icons['spacing-x'] or icons.spacing or 0)
local sizey = (icons.size or 16) + (icons['spacing-y'] or icons.spacing or 0)
local anchor = icons.initialAnchor or "BOTTOMLEFT"
local growthx = (icons["growth-x"] == "LEFT" and -1) or 1
local growthy = (icons["growth-y"] == "DOWN" and -1) or 1
local cols = math.floor(icons:GetWidth() / sizex + .5)
for i = from, to do
local button = icons[i]
-- Bail out if the to range is out of scope.
if(not button) then break end
local col = (i - 1) % cols
local row = math.floor((i - 1) / cols)
button:ClearAllPoints()
button:SetPoint(anchor, icons, anchor, col * sizex * growthx, row * sizey * growthy)
end
end
local filterIcons = function(unit, icons, filter, limit, isDebuff, offset, dontHide)
if(not offset) then offset = 0 end
local index = 1
local visible = 0
local hidden = 0
while(visible < limit) do
local result = updateIcon(unit, icons, index, offset, filter, isDebuff, visible)
if(not result) then
break
elseif(result == VISIBLE) then
visible = visible + 1
elseif(result == HIDDEN) then
hidden = hidden + 1
end
index = index + 1
end
if(not dontHide) then
for i = visible + offset + 1, #icons do
icons[i]:Hide()
end
end
return visible, hidden
end
local UpdateAuras = function(self, event, unit)
if(self.unit ~= unit) then return end
local auras = self.Auras
if(auras) then
if(auras.PreUpdate) then auras:PreUpdate(unit) end
local numBuffs = auras.numBuffs or 32
local numDebuffs = auras.numDebuffs or 40
local max = numBuffs + numDebuffs
local visibleBuffs, hiddenBuffs = filterIcons(unit, auras, auras.buffFilter or auras.filter or 'HELPFUL', numBuffs, nil, 0, true)
local hasGap
if(visibleBuffs ~= 0 and auras.gap) then
hasGap = true
visibleBuffs = visibleBuffs + 1
local icon = auras[visibleBuffs]
if(not icon) then
local prev = auras.createdIcons
icon = (auras.CreateIcon or createAuraIcon) (auras, visibleBuffs)
-- XXX: Update the counters if the layout doesn't.
if(prev == auras.createdIcons) then
table.insert(auras, icon)
auras.createdIcons = auras.createdIcons + 1
end
end
-- Prevent the icon from displaying anything.
if(icon.cd) then icon.cd:Hide() end
icon:EnableMouse(false)
icon.icon:SetTexture()
icon.overlay:Hide()
icon.stealable:Hide()
icon.count:SetText()
icon:Show()
--[[ :PostUpdateGapIcon(unit, icon, visibleBuffs)
Callback which is called after an invisible aura icon has been
created. This is only used by Auras when the `gap` option is enabled.
Arguments
self - The widget that holds the aura icon.
unit - The unit that has the aura icon.
icon - The invisible aura icon / gap.
visibleBuffs - The number of currently visible buffs.
]]
if(auras.PostUpdateGapIcon) then
auras:PostUpdateGapIcon(unit, icon, visibleBuffs)
end
end
local visibleDebuffs, hiddenDebuffs = filterIcons(unit, auras, auras.debuffFilter or auras.filter or 'HARMFUL', numDebuffs, true, visibleBuffs)
auras.visibleDebuffs = visibleDebuffs
if(hasGap and visibleDebuffs == 0) then
auras[visibleBuffs]:Hide()
visibleBuffs = visibleBuffs - 1
end
auras.visibleBuffs = visibleBuffs
auras.visibleAuras = auras.visibleBuffs + auras.visibleDebuffs
local fromRange, toRange
if(auras.PreSetPosition) then
fromRange, toRange = auras:PreSetPosition(max)
end
if(fromRange or auras.createdIcons > auras.anchoredIcons) then
(auras.SetPosition or SetPosition) (auras, fromRange or auras.anchoredIcons + 1, toRange or auras.createdIcons)
auras.anchoredIcons = auras.createdIcons
end
if(auras.PostUpdate) then auras:PostUpdate(unit) end
end
local buffs = self.Buffs
if(buffs) then
if(buffs.PreUpdate) then buffs:PreUpdate(unit) end
local numBuffs = buffs.num or 32
local visibleBuffs, hiddenBuffs = filterIcons(unit, buffs, buffs.filter or 'HELPFUL', numBuffs)
buffs.visibleBuffs = visibleBuffs
local fromRange, toRange
if(buffs.PreSetPosition) then
fromRange, toRange = buffs:PreSetPosition(numBuffs)
end
if(fromRange or buffs.createdIcons > buffs.anchoredIcons) then
(buffs.SetPosition or SetPosition) (buffs, fromRange or buffs.anchoredIcons + 1, toRange or buffs.createdIcons)
buffs.anchoredIcons = buffs.createdIcons
end
if(buffs.PostUpdate) then buffs:PostUpdate(unit) end
end
local debuffs = self.Debuffs
if(debuffs) then
if(debuffs.PreUpdate) then debuffs:PreUpdate(unit) end
local numDebuffs = debuffs.num or 40
local visibleDebuffs, hiddenDebuffs = filterIcons(unit, debuffs, debuffs.filter or 'HARMFUL', numDebuffs, true)
debuffs.visibleDebuffs = visibleDebuffs
local fromRange, toRange
if(debuffs.PreSetPosition) then
fromRange, toRange = debuffs:PreSetPosition(numDebuffs)
end
if(fromRange or debuffs.createdIcons > debuffs.anchoredIcons) then
(debuffs.SetPosition or SetPosition) (debuffs, fromRange or debuffs.anchoredIcons + 1, toRange or debuffs.createdIcons)
debuffs.anchoredIcons = debuffs.createdIcons
end
if(debuffs.PostUpdate) then debuffs:PostUpdate(unit) end
end
end
local Update = function(self, event, unit)
if(self.unit ~= unit) then return end
UpdateAuras(self, event, unit)
-- Assume no event means someone wants to re-anchor things. This is usually
-- done by UpdateAllElements and :ForceUpdate.
if(event == 'ForceUpdate' or not event) then
local buffs = self.Buffs
if(buffs) then
(buffs.SetPosition or SetPosition) (buffs, 1, buffs.createdIcons)
end
local debuffs = self.Debuffs
if(debuffs) then
(debuffs.SetPosition or SetPosition) (debuffs, 1, debuffs.createdIcons)
end
local auras = self.Auras
if(auras) then
(auras.SetPosition or SetPosition) (auras, 1, auras.createdIcons)
end
end
end
local ForceUpdate = function(element)
return Update(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local Enable = function(self)
if(self.Buffs or self.Debuffs or self.Auras) then
self:RegisterEvent("UNIT_AURA", UpdateAuras)
local buffs = self.Buffs
if(buffs) then
buffs.__owner = self
buffs.ForceUpdate = ForceUpdate
buffs.createdIcons = 0
buffs.anchoredIcons = 0
end
local debuffs = self.Debuffs
if(debuffs) then
debuffs.__owner = self
debuffs.ForceUpdate = ForceUpdate
debuffs.createdIcons = 0
debuffs.anchoredIcons = 0
end
local auras = self.Auras
if(auras) then
auras.__owner = self
auras.ForceUpdate = ForceUpdate
auras.createdIcons = 0
auras.anchoredIcons = 0
end
return true
end
end
local Disable = function(self)
if(self.Buffs or self.Debuffs or self.Auras) then
self:UnregisterEvent("UNIT_AURA", UpdateAuras)
end
end
oUF:AddElement('Aura', Update, Enable, Disable)

View File

@@ -0,0 +1,602 @@
--[[ Element: Castbar
Handles updating and visibility of unit castbars.
Widget
Castbar - A StatusBar to represent spell progress.
Sub-Widgets
.Text - A FontString to represent spell name.
.Icon - A Texture to represent spell icon.
.Time - A FontString to represent spell duration.
.Shield - A Texture to represent if it's possible to interrupt or spell
steal.
.SafeZone - A Texture to represent latency.
Options
.timeToHold - A Number to indicate for how many seconds the castbar should be
visible after a _FAILED or _INTERRUPTED event. Defaults to 0.
Credits
Based upon oUF_Castbar by starlon.
Notes
The default texture will be applied if the UI widget doesn't have a texture or
color defined.
Examples
-- Position and size
local Castbar = CreateFrame("StatusBar", nil, self)
Castbar:SetSize(20, 20)
Castbar:SetPoint('TOP')
Castbar:SetPoint('LEFT')
Castbar:SetPoint('RIGHT')
-- Add a background
local Background = Castbar:CreateTexture(nil, 'BACKGROUND')
Background:SetAllPoints(Castbar)
Background:SetTexture(1, 1, 1, .5)
-- Add a spark
local Spark = Castbar:CreateTexture(nil, "OVERLAY")
Spark:SetSize(20, 20)
Spark:SetBlendMode("ADD")
-- Add a timer
local Time = Castbar:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
Time:SetPoint("RIGHT", Castbar)
-- Add spell text
local Text = Castbar:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
Text:SetPoint("LEFT", Castbar)
-- Add spell icon
local Icon = Castbar:CreateTexture(nil, "OVERLAY")
Icon:SetSize(20, 20)
Icon:SetPoint("TOPLEFT", Castbar, "TOPLEFT")
-- Add Shield
local Shield = Castbar:CreateTexture(nil, "OVERLAY")
Shield:SetSize(20, 20)
Shield:SetPoint("CENTER", Castbar)
-- Add safezone
local SafeZone = Castbar:CreateTexture(nil, "OVERLAY")
-- Register it with oUF
self.Castbar = Castbar
self.Castbar.bg = Background
self.Castbar.Spark = Spark
self.Castbar.Time = Time
self.Castbar.Text = Text
self.Castbar.Icon = Icon
self.Castbar.SafeZone = SafeZone
Hooks and Callbacks
]]
local _, ns = ...
local oUF = ns.oUF
local GetNetStats = GetNetStats
local GetTime = GetTime
local UnitCastingInfo = UnitCastingInfo
local UnitChannelInfo = UnitChannelInfo
local tradeskillCurrent, tradeskillTotal, mergeTradeskill = 0, 0, false
local updateSafeZone = function(self)
local sz = self.SafeZone
local width = self:GetWidth()
local _, _, _, ms = GetNetStats()
-- Guard against GetNetStats returning latencies of 0.
if(ms ~= 0) then
-- MADNESS!
local safeZonePercent = (width / self.max) * (ms / 1e5)
if(safeZonePercent > 1) then safeZonePercent = 1 end
sz:SetWidth(width * safeZonePercent)
sz:Show()
else
sz:Hide()
end
end
local UNIT_SPELLCAST_SENT = function (self, event, unit, spell, rank, target, castid)
local castbar = self.Castbar
castbar.curTarget = (target and target ~= "") and target or nil
if castbar.isTradeSkill then
castbar.tradeSkillCastId = castid
end
end
local UNIT_SPELLCAST_START = function(self, event, unit)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local castbar = self.Castbar
local name, _, text, texture, startTime, endTime, isTradeSkill, castid, notInterruptible, spellid = UnitCastingInfo(unit)
if(not name) then
return castbar:Hide()
end
endTime = endTime / 1e3
startTime = startTime / 1e3
local max = endTime - startTime
castbar.castid = castid
castbar.duration = GetTime() - startTime
castbar.max = max
castbar.delay = 0
castbar.casting = true
castbar.interrupt = notInterruptible -- NOTE: deprecated; to be removed
castbar.notInterruptible = notInterruptible
castbar.holdTime = 0
castbar.isTradeSkill = isTradeSkill
if(mergeTradeskill and isTradeSkill and UnitIsUnit(unit, "player")) then
castbar.duration = castbar.duration + (castbar.max * tradeskillCurrent);
castbar.max = max * tradeskillTotal;
if(unit == "player") then
tradeskillCurrent = tradeskillCurrent + 1;
end
castbar:SetValue(castbar.duration)
else
castbar:SetValue(0)
end
castbar:SetValue(0)
castbar:SetMinMaxValues(0, castbar.max)
if(castbar.Text) then castbar.Text:SetText(text) end
if(castbar.Icon) then castbar.Icon:SetTexture(texture) end
if(castbar.Time) then castbar.Time:SetText() end
local shield = castbar.Shield
if(shield and notInterruptible) then
shield:Show()
elseif(shield) then
shield:Hide()
end
local sf = castbar.SafeZone
if(sf) then
sf:ClearAllPoints()
sf:SetPoint'RIGHT'
sf:SetPoint'TOP'
sf:SetPoint'BOTTOM'
updateSafeZone(castbar)
end
if(castbar.PostCastStart) then
castbar:PostCastStart(unit, name, castid, spellid)
end
castbar:Show()
end
local UNIT_SPELLCAST_FAILED = function(self, event, unit, spellname, _, castid, spellid)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local castbar = self.Castbar
if (castbar.castid ~= castid) and (castbar.tradeSkillCastId ~= castid) then
return
end
if(mergeTradeskill and UnitIsUnit(unit, "player")) then
mergeTradeskill = false;
castbar.tradeSkillCastId = nil
end
local text = castbar.Text
if(text) then
text:SetText(FAILED)
end
castbar.casting = nil
castbar.interrupt = nil -- NOTE: deprecated; to be removed
castbar.notInterruptible = nil
castbar.holdTime = castbar.timeToHold or 0
if(castbar.PostCastFailed) then
return castbar:PostCastFailed(unit, spellname, castid, spellid)
end
end
local UNIT_SPELLCAST_FAILED_QUIET = function(self, event, unit, spellname, _, castid)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local castbar = self.Castbar
if (castbar.castid ~= castid) and (castbar.tradeSkillCastId ~= castid) then
return
end
if(mergeTradeskill and UnitIsUnit(unit, "player")) then
mergeTradeskill = false;
castbar.tradeSkillCastId = nil
end
castbar.casting = nil
castbar.interrupt = nil -- NOTE: deprecated; to be removed
castbar.notInterruptible = nil
castbar:SetValue(0)
castbar:Hide()
end
local UNIT_SPELLCAST_INTERRUPTED = function(self, event, unit, spellname, _, castid, spellid)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local castbar = self.Castbar
if (castbar.castid ~= castid) then
return
end
local text = castbar.Text
if(text) then
text:SetText(INTERRUPTED)
end
castbar.casting = nil
castbar.channeling = nil
castbar.holdTime = castbar.timeToHold or 0
if(castbar.PostCastInterrupted) then
return castbar:PostCastInterrupted(unit, spellname, castid, spellid)
end
end
local UNIT_SPELLCAST_INTERRUPTIBLE = function(self, event, unit)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local castbar = self.Castbar
local shield = castbar.Shield
if(shield) then
shield:Hide()
end
castbar.interrupt = nil -- NOTE: deprecated; to be removed
castbar.notInterruptible = nil
if(castbar.PostCastInterruptible) then
return castbar:PostCastInterruptible(unit)
end
end
local UNIT_SPELLCAST_NOT_INTERRUPTIBLE = function(self, event, unit)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local castbar = self.Castbar
local shield = castbar.Shield
if(shield) then
shield:Show()
end
castbar.interrupt = nil -- NOTE: deprecated; to be removed
castbar.notInterruptible = nil
if(castbar.PostCastNotInterruptible) then
return castbar:PostCastNotInterruptible(unit)
end
end
local UNIT_SPELLCAST_DELAYED = function(self, event, unit, _, _, _, spellid)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local castbar = self.Castbar
local name, _, _, _, startTime, _, _, castid = UnitCastingInfo(unit)
if(not startTime or not castbar:IsShown()) then return end
local duration = GetTime() - (startTime / 1000)
if(duration < 0) then duration = 0 end
castbar.delay = castbar.delay + castbar.duration - duration
castbar.duration = duration
castbar:SetValue(duration)
if(castbar.PostCastDelayed) then
return castbar:PostCastDelayed(unit, name, castid, spellid)
end
end
local UNIT_SPELLCAST_STOP = function(self, event, unit, spellname, _, castid, spellid)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local castbar = self.Castbar
if (castbar.castid ~= castid) then
return
end
if(mergeTradeskill and UnitIsUnit(unit, "player")) then
if(tradeskillCurrent == tradeskillTotal) then
mergeTradeskill = false;
end
else
castbar.casting = nil
castbar.interrupt = nil -- NOTE: deprecated; to be removed
castbar.notInterruptible = nil
end
if(castbar.PostCastStop) then
return castbar:PostCastStop(unit, spellname, castid, spellid)
end
end
local UNIT_SPELLCAST_CHANNEL_START = function(self, event, unit, _, _, _, spellid)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local castbar = self.Castbar
local name, _, _, texture, startTime, endTime, _, notInterruptible = UnitChannelInfo(unit)
if(not name) then
return
end
endTime = endTime / 1e3
startTime = startTime / 1e3
local max = (endTime - startTime)
local duration = endTime - GetTime()
castbar.duration = duration
castbar.max = max
castbar.delay = 0
castbar.startTime = startTime
castbar.endTime = endTime
castbar.extraTickRatio = 0
castbar.channeling = true
castbar.interrupt = notInterruptible -- NOTE: deprecated; to be removed
castbar.notInterruptible = notInterruptible
castbar.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.
castbar.casting = nil
castbar.castid = nil
castbar:SetMinMaxValues(0, max)
castbar:SetValue(duration)
if(castbar.Text) then castbar.Text:SetText(name) end
if(castbar.Icon) then castbar.Icon:SetTexture(texture) end
if(castbar.Time) then castbar.Time:SetText() end
local shield = castbar.Shield
if(shield and notInterruptible) then
shield:Show()
elseif(shield) then
shield:Hide()
end
local sf = castbar.SafeZone
if(sf) then
sf:ClearAllPoints()
sf:SetPoint'LEFT'
sf:SetPoint'TOP'
sf:SetPoint'BOTTOM'
updateSafeZone(castbar)
end
if(castbar.PostChannelStart) then castbar:PostChannelStart(unit, name, spellid) end
castbar:Show()
end
local UNIT_SPELLCAST_CHANNEL_UPDATE = function(self, event, unit, _, _, _, spellid)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local castbar = self.Castbar
local name, _, _, _, startTime, endTime = UnitChannelInfo(unit)
if(not name or not castbar:IsShown()) then
return
end
local duration = (endTime / 1000) - GetTime()
local startDelay = castbar.startTime - startTime / 1000
castbar.startTime = startTime / 1000
castbar.endTime = endTime / 1000
castbar.delay = castbar.delay + startDelay
castbar.duration = duration
castbar.max = (endTime - startTime) / 1000
castbar:SetMinMaxValues(0, castbar.max)
castbar:SetValue(duration)
if(castbar.PostChannelUpdate) then
return castbar:PostChannelUpdate(unit, name, spellid)
end
end
local UNIT_SPELLCAST_CHANNEL_STOP = function(self, event, unit, spellname, _, _, spellid)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local castbar = self.Castbar
if(castbar:IsShown()) then
castbar.channeling = nil
castbar.interrupt = nil -- NOTE: deprecated; to be removed
castbar.notInterruptible = nil
if(castbar.PostChannelStop) then
return castbar:PostChannelStop(unit, spellname, spellid)
end
end
end
local onUpdate = function(self, elapsed)
if(self.casting) then
local duration = self.duration + elapsed
if(duration >= self.max) then
self.casting = nil
self:Hide()
if(self.PostCastStop) then self:PostCastStop(self.__owner.unit) end
return
end
if(self.Time) then
if(self.delay ~= 0) then
if(self.CustomDelayText) then
self:CustomDelayText(duration)
else
self.Time:SetFormattedText("%.1f|cffff0000-%.1f|r", duration, self.delay)
end
else
if(self.CustomTimeText) then
self:CustomTimeText(duration)
else
self.Time:SetFormattedText("%.1f", duration)
end
end
end
self.duration = duration
self:SetValue(duration)
if(self.Spark) then
self.Spark:SetPoint("CENTER", self, "LEFT", (duration / self.max) * self:GetWidth(), 0)
end
elseif(self.channeling) then
local duration = self.duration - elapsed
if(duration <= 0) then
self.channeling = nil
self:Hide()
if(self.PostChannelStop) then self:PostChannelStop(self.__owner.unit) end
return
end
if(self.Time) then
if(self.delay ~= 0) then
if(self.CustomDelayText) then
self:CustomDelayText(duration)
else
self.Time:SetFormattedText("%.1f|cffff0000-%.1f|r", duration, self.delay)
end
else
if(self.CustomTimeText) then
self:CustomTimeText(duration)
else
self.Time:SetFormattedText("%.1f", duration)
end
end
end
self.duration = duration
self:SetValue(duration)
if(self.Spark) then
self.Spark:SetPoint("CENTER", self, "LEFT", (duration / self.max) * self:GetWidth(), 0)
end
elseif(self.holdTime > 0) then
self.holdTime = self.holdTime - elapsed
else
self.casting = nil
self.castid = nil
self.channeling = nil
self:Hide()
end
end
local Update = function(self, ...)
UNIT_SPELLCAST_START(self, ...)
return UNIT_SPELLCAST_CHANNEL_START(self, ...)
end
local ForceUpdate = function(element)
return Update(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local Enable = function(self, unit)
local castbar = self.Castbar
if(castbar) then
castbar.__owner = self
castbar.ForceUpdate = ForceUpdate
if(not (unit and unit:match'%wtarget$')) then
self:RegisterEvent("UNIT_SPELLCAST_SENT", UNIT_SPELLCAST_SENT, true)
self:RegisterEvent("UNIT_SPELLCAST_START", UNIT_SPELLCAST_START)
self:RegisterEvent("UNIT_SPELLCAST_FAILED", UNIT_SPELLCAST_FAILED)
self:RegisterEvent("UNIT_SPELLCAST_FAILED_QUIET", UNIT_SPELLCAST_FAILED_QUIET)
self:RegisterEvent("UNIT_SPELLCAST_STOP", UNIT_SPELLCAST_STOP)
self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED", UNIT_SPELLCAST_INTERRUPTED)
self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTIBLE", UNIT_SPELLCAST_INTERRUPTIBLE)
self:RegisterEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE", UNIT_SPELLCAST_NOT_INTERRUPTIBLE)
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)
end
castbar.holdTime = 0
castbar:SetScript("OnUpdate", castbar.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(castbar:IsObjectType'StatusBar' and not castbar:GetStatusBarTexture()) then
castbar:SetStatusBarTexture[[Interface\TargetingFrame\UI-StatusBar]]
end
local spark = castbar.Spark
if(spark and spark:IsObjectType'Texture' and not spark:GetTexture()) then
spark:SetTexture[[Interface\CastingBar\UI-CastingBar-Spark]]
end
local shield = castbar.Shield
if(shield and shield:IsObjectType'Texture' and not shield:GetTexture()) then
shield:SetTexture[[Interface\CastingBar\UI-CastingBar-Small-Shield]]
end
local sz = castbar.SafeZone
if(sz and sz:IsObjectType'Texture' and not sz:GetTexture()) then
sz:SetColorTexture(1, 0, 0)
end
castbar:Hide()
return true
end
end
local Disable = function(self)
local castbar = self.Castbar
if(castbar) then
castbar:Hide()
self:UnregisterEvent("UNIT_SPELLCAST_SENT", UNIT_SPELLCAST_SENT)
self:UnregisterEvent("UNIT_SPELLCAST_START", UNIT_SPELLCAST_START)
self:UnregisterEvent("UNIT_SPELLCAST_FAILED", UNIT_SPELLCAST_FAILED)
self:UnregisterEvent("UNIT_SPELLCAST_FAILED_QUIET", UNIT_SPELLCAST_FAILED_QUIET)
self:UnregisterEvent("UNIT_SPELLCAST_STOP", UNIT_SPELLCAST_STOP)
self:UnregisterEvent("UNIT_SPELLCAST_INTERRUPTED", UNIT_SPELLCAST_INTERRUPTED)
self:UnregisterEvent("UNIT_SPELLCAST_INTERRUPTIBLE", UNIT_SPELLCAST_INTERRUPTIBLE)
self:UnregisterEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE", UNIT_SPELLCAST_NOT_INTERRUPTIBLE)
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)
castbar:SetScript("OnUpdate", nil)
end
end
hooksecurefunc(C_TradeSkillUI, "CraftRecipe", function(_, num)
tradeskillCurrent = 0
tradeskillTotal = num or 1
mergeTradeskill = true
end)
oUF:AddElement('Castbar', Update, Enable, Disable)

View File

@@ -0,0 +1,291 @@
--[[ Element: Class Icons
Toggles the visibility of icons depending on the player's class and
specialization.
Widget
ClassIcons - An array consisting of as many UI Textures as the theoretical
maximum return of `UnitPowerMax`.
Notes
All - Combo Points
Mage - Arcane Charges
Monk - Chi Orbs
Paladin - Holy Power
Warlock - Soul Shards
Examples
local ClassIcons = {}
for index = 1, 6 do
local Icon = self:CreateTexture(nil, 'BACKGROUND')
-- Position and size.
Icon:SetSize(16, 16)
Icon:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', index * Icon:GetWidth(), 0)
ClassIcons[index] = Icon
end
-- Register with oUF
self.ClassIcons = ClassIcons
Hooks
OverrideVisibility(self) - Used to completely override the internal visibility
function. Removing the table key entry will make
the element fall-back to its internal function
again.
Override(self) - Used to completely override the internal update
function. Removing the table key entry will make the
element fall-back to its internal function again.
UpdateTexture(element) - Used to completely override the internal function
for updating the power icon textures. Removing the
table key entry will make the element fall-back to
its internal function again.
]]
local parent, ns = ...
local oUF = ns.oUF
local _, PlayerClass = UnitClass'player'
-- Holds the class specific stuff.
local ClassPowerID, ClassPowerType
local ClassPowerEnable, ClassPowerDisable
local RequireSpec, RequireSpell, RequireFormID
local UpdateTexture = function(element)
local color = oUF.colors.power[ClassPowerType or 'COMBO_POINTS']
for i = 1, #element do
local icon = element[i]
if(icon.SetDesaturated) then
icon:SetDesaturated(PlayerClass ~= 'PRIEST')
end
icon:SetVertexColor(color[1], color[2], color[3])
end
end
local Update = function(self, event, unit, powerType)
if(not (unit == 'player' and powerType == ClassPowerType
or unit == 'vehicle' and powerType == 'COMBO_POINTS')) then
return
end
local element = self.ClassIcons
--[[ :PreUpdate()
Called before the element has been updated
Arguments
self - The ClassIcons element
event - The event, that the update is being triggered for
]]
if(element.PreUpdate) then
element:PreUpdate(event)
end
local cur, max, oldMax
if(event ~= 'ClassPowerDisable') then
if(unit == 'vehicle') then
-- XXX: UnitPower is bugged for vehicles, always returns 0 combo points
cur = GetComboPoints(unit)
max = MAX_COMBO_POINTS
else
cur = UnitPower('player', ClassPowerID)
max = UnitPowerMax('player', ClassPowerID)
end
for i = 1, max do
if(i <= cur) then
element[i]:Show()
else
element[i]:Hide()
end
end
oldMax = element.__max
if(max ~= oldMax) then
if(max < oldMax) then
for i = max + 1, oldMax do
element[i]:Hide()
end
end
element.__max = max
end
end
--[[ :PostUpdate(cur, max, hasMaxChanged, event)
Called after the element has been updated
Arguments
self - The ClassIcons element
cur - The current amount of power
max - The maximum amount of power
hasMaxChanged - Shows if the maximum amount has changed since the last
update
powerType - The type of power used
event - The event, which the update happened for
]]
if(element.PostUpdate) then
return element:PostUpdate(cur, max, oldMax ~= max, powerType, event)
end
end
local Path = function(self, ...)
return (self.ClassIcons.Override or Update) (self, ...)
end
local function Visibility(self, event, unit)
local element = self.ClassIcons
local shouldEnable
if(UnitHasVehicleUI('player')) then
shouldEnable = true
unit = 'vehicle'
elseif(ClassPowerID) then
if(not RequireSpec or RequireSpec == GetSpecialization()) then
if(not RequireFormID or RequireFormID == GetShapeshiftFormID()) then
if(not RequireSpell or IsPlayerSpell(RequireSpell)) then
if(not RequirePower or RequirePower == UnitPowerType('player')) then
self:UnregisterEvent('SPELLS_CHANGED', Visibility)
shouldEnable = true
else
self:RegisterEvent('SPELLS_CHANGED', Visibility, true)
end
else
self:RegisterEvent('SPELLS_CHANGED', Visibility, true)
end
end
end
end
local isEnabled = element.isEnabled
if(shouldEnable and not isEnabled) then
ClassPowerEnable(self)
elseif(not shouldEnable and (isEnabled or isEnabled == nil)) then
ClassPowerDisable(self)
elseif(shouldEnable and isEnabled) then
Path(self, event, unit, unit == 'vehicle' and 'COMBO_POINTS' or ClassPowerType)
end
end
local VisibilityPath = function(self, ...)
return (self.ClassIcons.OverrideVisibility or Visibility) (self, ...)
end
local ForceUpdate = function(element)
return VisibilityPath(element.__owner, 'ForceUpdate', element.__owner.unit)
end
do
ClassPowerEnable = function(self)
self:RegisterEvent('UNIT_DISPLAYPOWER', VisibilityPath)
self:RegisterEvent('UNIT_POWER_FREQUENT', Path)
self:RegisterEvent('UNIT_MAXPOWER', Path)
if(UnitHasVehicleUI('player')) then
Path(self, 'ClassPowerEnable', 'vehicle', 'COMBO_POINTS')
else
Path(self, 'ClassPowerEnable', 'player', ClassPowerType)
end
self.ClassIcons.isEnabled = true
end
ClassPowerDisable = function(self)
self:UnregisterEvent('UNIT_DISPLAYPOWER', VisibilityPath)
self:UnregisterEvent('UNIT_POWER_FREQUENT', Path)
self:UnregisterEvent('UNIT_MAXPOWER', Path)
local element = self.ClassIcons
for i = 1, #element do
element[i]:Hide()
end
Path(self, 'ClassPowerDisable', 'player', ClassPowerType)
self.ClassIcons.isEnabled = false
end
if(PlayerClass == 'MONK') then
ClassPowerID = SPELL_POWER_CHI
ClassPowerType = "CHI"
RequireSpec = SPEC_MONK_WINDWALKER
elseif(PlayerClass == 'PALADIN') then
ClassPowerID = SPELL_POWER_HOLY_POWER
ClassPowerType = "HOLY_POWER"
RequireSpec = SPEC_PALADIN_RETRIBUTION
elseif(PlayerClass == 'WARLOCK') then
ClassPowerID = SPELL_POWER_SOUL_SHARDS
ClassPowerType = "SOUL_SHARDS"
elseif(PlayerClass == 'ROGUE' or PlayerClass == 'DRUID') then
ClassPowerID = SPELL_POWER_COMBO_POINTS
ClassPowerType = 'COMBO_POINTS'
if(PlayerClass == 'DRUID') then
RequireFormID = 1 --CAT_FORM
RequireSpell = 5221 -- Shred
end
elseif(PlayerClass == 'MAGE') then
ClassPowerID = SPELL_POWER_ARCANE_CHARGES
ClassPowerType = 'ARCANE_CHARGES'
RequireSpec = SPEC_MAGE_ARCANE
end
end
local Enable = function(self, unit)
if(unit ~= 'player') then return end
local element = self.ClassIcons
if(not element) then return end
element.__owner = self
element.__max = #element
element.ForceUpdate = ForceUpdate
if(RequireSpec or RequireSpell) then
self:RegisterEvent('PLAYER_TALENT_UPDATE', VisibilityPath, true)
end
if(RequireFormID) then
self:RegisterEvent('UPDATE_SHAPESHIFT_FORM', VisibilityPath, true)
end
element.ClassPowerEnable = ClassPowerEnable
element.ClassPowerDisable = ClassPowerDisable
local isChildrenTextures
for i = 1, #element do
local icon = element[i]
if(icon:IsObjectType'Texture') then
if(not icon:GetTexture()) then
icon:SetTexCoord(0.45703125, 0.60546875, 0.44531250, 0.73437500)
icon:SetTexture([[Interface\PlayerFrame\Priest-ShadowUI]])
end
isChildrenTextures = true
end
end
if(isChildrenTextures) then
(element.UpdateTexture or UpdateTexture) (element)
end
return true
end
local Disable = function(self)
local element = self.ClassIcons
if(not element) then return end
ClassPowerDisable(self)
end
oUF:AddElement('ClassIcons', VisibilityPath, Enable, Disable)

View File

@@ -0,0 +1,86 @@
--[[ Element: Combat Icon
Toggles the visibility of `self.Combat` based on the player's combat status.
Widget
Combat - Any UI widget.
Notes
The default assistant icon will be applied if the UI widget is a texture and
doesn't have a texture or color defined.
Examples
-- Position and size
local Combat = self:CreateTexture(nil, "OVERLAY")
Combat:SetSize(16, 16)
Combat:SetPoint('TOP', self)
-- Register it with oUF
self.Combat = Combat
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local parent, ns = ...
local oUF = ns.oUF
local Update = function(self, event)
local combat = self.Combat
if(combat.PreUpdate) then
combat:PreUpdate()
end
local inCombat = UnitAffectingCombat('player')
if(inCombat) then
combat:Show()
else
combat:Hide()
end
if(combat.PostUpdate) then
return combat:PostUpdate(inCombat)
end
end
local Path = function(self, ...)
return (self.Combat.Override or Update) (self, ...)
end
local ForceUpdate = function(element)
return Path(element.__owner, 'ForceUpdate')
end
local Enable = function(self, unit)
local combat = self.Combat
if(combat and unit == 'player') then
combat.__owner = self
combat.ForceUpdate = ForceUpdate
self:RegisterEvent("PLAYER_REGEN_DISABLED", Path, true)
self:RegisterEvent("PLAYER_REGEN_ENABLED", Path, true)
if(combat:IsObjectType"Texture" and not combat:GetTexture()) then
combat:SetTexture[[Interface\CharacterFrame\UI-StateIcon]]
combat:SetTexCoord(.5, 1, 0, .49)
end
return true
end
end
local Disable = function(self)
if(self.Combat) then
self.Combat:Hide()
self:UnregisterEvent("PLAYER_REGEN_DISABLED", Path)
self:UnregisterEvent("PLAYER_REGEN_ENABLED", Path)
end
end
oUF:AddElement('Combat', Path, Enable, Disable)

View File

@@ -0,0 +1,239 @@
--[[ Element: Heal Prediction Bar
Handle updating and visibility of the heal prediction status bars.
Widget
HealPrediction - A table containing `myBar` and `otherBar`.
Sub-Widgets
myBar - A StatusBar used to represent your incoming heals.
otherBar - A StatusBar used to represent other peoples incoming heals.
absorbBar - A StatusBar used to represent total absorbs.
healAbsorbBar - A StatusBar used to represent heal absorbs.
Notes
The default StatusBar texture will be applied if the UI widget doesn't have a
status bar texture or color defined.
Options
.maxOverflow - Defines the maximum amount of overflow past the end of the
health bar.
.frequentUpdates - Update on UNIT_HEALTH_FREQUENT instead of UNIT_HEALTH. Use
this if .frequentUpdates is also set on the Health element.
Examples
-- Position and size
local myBar = CreateFrame('StatusBar', nil, self.Health)
myBar:SetPoint('TOP')
myBar:SetPoint('BOTTOM')
myBar:SetPoint('LEFT', self.Health:GetStatusBarTexture(), 'RIGHT')
myBar:SetWidth(200)
local otherBar = CreateFrame('StatusBar', nil, self.Health)
otherBar:SetPoint('TOP')
otherBar:SetPoint('BOTTOM')
otherBar:SetPoint('LEFT', self.Health:GetStatusBarTexture(), 'RIGHT')
otherBar:SetWidth(200)
local absorbBar = CreateFrame('StatusBar', nil, self.Health)
absorbBar:SetPoint('TOP')
absorbBar:SetPoint('BOTTOM')
absorbBar:SetPoint('LEFT', self.Health:GetStatusBarTexture(), 'RIGHT')
absorbBar:SetWidth(200)
local healAbsorbBar = CreateFrame('StatusBar', nil, self.Health)
healAbsorbBar:SetPoint('TOP')
healAbsorbBar:SetPoint('BOTTOM')
healAbsorbBar:SetPoint('LEFT', self.Health:GetStatusBarTexture(), 'RIGHT')
healAbsorbBar:SetWidth(200)
-- Register with oUF
self.HealPrediction = {
myBar = myBar,
otherBar = otherBar,
absorbBar = absorbBar,
healAbsorbBar = healAbsorbBar,
maxOverflow = 1.05,
frequentUpdates = true,
}
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local _, ns = ...
local oUF = ns.oUF
local function Update(self, event, unit)
if(self.unit ~= unit) or not unit then return end
local hp = self.HealPrediction
hp.parent = self
if(hp.PreUpdate) then hp:PreUpdate(unit) end
local myIncomingHeal = UnitGetIncomingHeals(unit, 'player') or 0
local allIncomingHeal = UnitGetIncomingHeals(unit) or 0
local totalAbsorb = UnitGetTotalAbsorbs(unit) or 0
local myCurrentHealAbsorb = UnitGetTotalHealAbsorbs(unit) or 0
local health, maxHealth = UnitHealth(unit), UnitHealthMax(unit)
local overHealAbsorb = false
if(health < myCurrentHealAbsorb) then
overHealAbsorb = true
myCurrentHealAbsorb = health
end
if(health - myCurrentHealAbsorb + allIncomingHeal > maxHealth * hp.maxOverflow) then
allIncomingHeal = maxHealth * hp.maxOverflow - health + myCurrentHealAbsorb
end
local otherIncomingHeal = 0
if(allIncomingHeal < myIncomingHeal) then
myIncomingHeal = allIncomingHeal
else
otherIncomingHeal = allIncomingHeal - myIncomingHeal
end
local overAbsorb = false
if(health - myCurrentHealAbsorb + allIncomingHeal + totalAbsorb >= maxHealth or health + totalAbsorb >= maxHealth) then
if(totalAbsorb > 0) then
overAbsorb = true
end
if(allIncomingHeal > myCurrentHealAbsorb) then
totalAbsorb = max(0, maxHealth - (health - myCurrentHealAbsorb + allIncomingHeal))
else
totalAbsorb = max(0, maxHealth - health)
end
end
if(myCurrentHealAbsorb > allIncomingHeal) then
myCurrentHealAbsorb = myCurrentHealAbsorb - allIncomingHeal
else
myCurrentHealAbsorb = 0
end
if(hp.myBar) then
hp.myBar:SetMinMaxValues(0, maxHealth)
hp.myBar:SetValue(myIncomingHeal)
hp.myBar:Show()
end
if(hp.otherBar) then
hp.otherBar:SetMinMaxValues(0, maxHealth)
hp.otherBar:SetValue(otherIncomingHeal)
hp.otherBar:Show()
end
if(hp.absorbBar) then
hp.absorbBar:SetMinMaxValues(0, maxHealth)
hp.absorbBar:SetValue(totalAbsorb)
hp.absorbBar:Show()
end
if(hp.healAbsorbBar) then
hp.healAbsorbBar:SetMinMaxValues(0, maxHealth)
hp.healAbsorbBar:SetValue(myCurrentHealAbsorb)
hp.healAbsorbBar:Show()
end
if(hp.PostUpdate) then
return hp:PostUpdate(unit, myIncomingHeal, allIncomingHeal, totalAbsorb, myCurrentHealAbsorb)
end
end
local function Path(self, ...)
return (self.HealPrediction.Override or Update) (self, ...)
end
local ForceUpdate = function(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local hp = self.HealPrediction
if(hp) then
hp.__owner = self
hp.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_HEAL_PREDICTION', Path)
self:RegisterEvent('UNIT_MAXHEALTH', Path)
if(hp.frequentUpdates) then
self:RegisterEvent('UNIT_HEALTH_FREQUENT', Path)
else
self:RegisterEvent('UNIT_HEALTH', Path)
end
self:RegisterEvent('UNIT_ABSORB_AMOUNT_CHANGED', Path)
self:RegisterEvent('UNIT_HEAL_ABSORB_AMOUNT_CHANGED', Path)
if(not hp.maxOverflow) then
hp.maxOverflow = 1.05
end
if(hp.myBar) then
if(hp.myBar:IsObjectType'StatusBar' and not hp.myBar:GetStatusBarTexture()) then
hp.myBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
hp.myBar:Show()
end
if(hp.otherBar) then
if(hp.otherBar:IsObjectType'StatusBar' and not hp.otherBar:GetStatusBarTexture()) then
hp.otherBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
hp.otherBar:Show()
end
if(hp.absorbBar) then
if(hp.absorbBar:IsObjectType'StatusBar' and not hp.absorbBar:GetStatusBarTexture()) then
hp.absorbBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
hp.absorbBar:Show()
end
if(hp.healAbsorbBar) then
if(hp.healAbsorbBar:IsObjectType'StatusBar' and not hp.healAbsorbBar:GetStatusBarTexture()) then
hp.healAbsorbBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
hp.healAbsorbBar:Show()
end
return true
end
end
local function Disable(self)
local hp = self.HealPrediction
if(hp) then
if(hp.myBar) then
hp.myBar:Hide()
end
if(hp.otherBar) then
hp.otherBar:Hide()
end
if(hp.absorbBar) then
hp.absorbBar:Hide()
end
if(hp.healAbsorbBar) then
hp.healAbsorbBar:Hide()
end
self:UnregisterEvent('UNIT_HEAL_PREDICTION', Path)
self:UnregisterEvent('UNIT_MAXHEALTH', Path)
self:UnregisterEvent('UNIT_HEALTH', Path)
self:UnregisterEvent('UNIT_HEALTH_FREQUENT', Path)
self:UnregisterEvent('UNIT_ABSORB_AMOUNT_CHANGED', Path)
self:UnregisterEvent('UNIT_HEAL_ABSORB_AMOUNT_CHANGED', Path)
end
end
oUF:AddElement('HealPrediction', Path, Enable, Disable)

View File

@@ -0,0 +1,215 @@
--[[ Element: Health Bar
Handles updating of `self.Health` based on the units health.
Widget
Health - A StatusBar used to represent current unit health.
Sub-Widgets
.bg - A Texture which functions as a background. It will inherit the color of
the main StatusBar.
Notes
The default StatusBar texture will be applied if the UI widget doesn't have a
status bar texture or color defined.
Options
The following options are listed by priority. The first check that returns
true decides the color of the bar.
.colorTapping - Use `self.colors.tapping` to color the bar if the unit
isn't tapped by the player.
.colorDisconnected - Use `self.colors.disconnected` to color the bar if the
unit is offline.
.colorClass - Use `self.colors.class[class]` to color the bar based on
unit class. `class` is defined by the second return of
[UnitClass](http://wowprogramming.com/docs/api/UnitClass).
.colorClassNPC - Use `self.colors.class[class]` to color the bar if the
unit is a NPC.
.colorClassPet - Use `self.colors.class[class]` to color the bar if the
unit is player controlled, but not a player.
.colorReaction - Use `self.colors.reaction[reaction]` to color the bar
based on the player's reaction towards the unit.
`reaction` is defined by the return value of
[UnitReaction](http://wowprogramming.com/docs/api/UnitReaction).
.colorSmooth - Use `self.colors.smooth` to color the bar with a smooth
gradient based on the player's current health percentage.
.colorHealth - Use `self.colors.health` to color the bar. This flag is
used to reset the bar color back to default if none of the
above conditions are met.
Sub-Widgets Options
.multiplier - Defines a multiplier, which is used to tint the background based
on the main widgets R, G and B values. Defaults to 1 if not
present.
Examples
-- Position and size
local Health = CreateFrame("StatusBar", nil, self)
Health:Height(20)
Health:SetPoint('TOP')
Health:SetPoint('LEFT')
Health:SetPoint('RIGHT')
-- Add a background
local Background = Health:CreateTexture(nil, 'BACKGROUND')
Background:SetAllPoints(Health)
Background:SetTexture(1, 1, 1, .5)
-- Options
Health.frequentUpdates = true
Health.colorTapping = true
Health.colorDisconnected = true
Health.colorClass = true
Health.colorReaction = true
Health.colorHealth = true
-- Make the background darker.
Background.multiplier = .5
-- Register it with oUF
self.Health = Health
self.Health.bg = Background
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local parent, ns = ...
local oUF = ns.oUF
local updateFrequentUpdates
oUF.colors.health = {49/255, 207/255, 37/255}
local Update = function(self, event, unit)
if(not unit or self.unit ~= unit) then return end
local health = self.Health
if(health.PreUpdate) then health:PreUpdate(unit) end
local min, max = UnitHealth(unit), UnitHealthMax(unit)
local disconnected = not UnitIsConnected(unit)
health:SetMinMaxValues(0, max)
if(disconnected) then
health:SetValue(max)
else
health:SetValue(min)
end
health.disconnected = disconnected
if health.frequentUpdates ~= health.__frequentUpdates then
health.__frequentUpdates = health.frequentUpdates
updateFrequentUpdates(self)
end
local r, g, b, t
if(health.colorTapping and not UnitPlayerControlled(unit) and UnitIsTapDenied(unit)) then
t = self.colors.tapped
elseif(health.colorDisconnected and not UnitIsConnected(unit)) then
t = self.colors.disconnected
elseif(health.colorClass and UnitIsPlayer(unit)) or
(health.colorClassNPC and not UnitIsPlayer(unit)) or
(health.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then
local _, class = UnitClass(unit)
t = self.colors.class[class]
elseif(health.colorReaction and UnitReaction(unit, 'player')) then
t = self.colors.reaction[UnitReaction(unit, "player")]
elseif(health.colorSmooth) then
r, g, b = self.ColorGradient(min, max, unpack(health.smoothGradient or self.colors.smooth))
elseif(health.colorHealth) then
t = self.colors.health
end
if(t) then
r, g, b = t[1], t[2], t[3]
end
if(b) then
health:SetStatusBarColor(r, g, b)
local bg = health.bg
if(bg) then local mu = bg.multiplier or 1
bg:SetVertexColor(r * mu, g * mu, b * mu)
end
end
if(health.PostUpdate) then
return health:PostUpdate(unit, min, max)
end
end
local Path = function(self, ...)
return (self.Health.Override or Update) (self, ...)
end
local ForceUpdate = function(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
function updateFrequentUpdates(self)
local health = self.Health
if health.frequentUpdates and not self:IsEventRegistered("UNIT_HEALTH_FREQUENT") then
if GetCVarBool("predictedHealth") ~= true then
SetCVar("predictedHealth", "1")
end
self:RegisterEvent('UNIT_HEALTH_FREQUENT', Path)
if self:IsEventRegistered("UNIT_HEALTH") then
self:UnregisterEvent("UNIT_HEALTH", Path)
end
elseif not self:IsEventRegistered("UNIT_HEALTH") then
self:RegisterEvent('UNIT_HEALTH', Path)
if self:IsEventRegistered("UNIT_HEALTH_FREQUENT") then
self:UnregisterEvent("UNIT_HEALTH_FREQUENT", Path)
end
end
end
local Enable = function(self, unit)
local health = self.Health
if(health) then
health.__owner = self
health.ForceUpdate = ForceUpdate
health.__frequentUpdates = health.frequentUpdates
updateFrequentUpdates(self)
self:RegisterEvent("UNIT_MAXHEALTH", Path)
self:RegisterEvent('UNIT_CONNECTION', Path)
-- For tapping.
self:RegisterEvent('UNIT_FACTION', Path)
if(health:IsObjectType'StatusBar' and not health:GetStatusBarTexture()) then
health:SetStatusBarTexture[[Interface\TargetingFrame\UI-StatusBar]]
end
return true
end
end
local Disable = function(self)
local health = self.Health
if(health) then
health:Hide()
self:UnregisterEvent('UNIT_HEALTH_FREQUENT', Path)
self:UnregisterEvent('UNIT_HEALTH', Path)
self:UnregisterEvent('UNIT_MAXHEALTH', Path)
self:UnregisterEvent('UNIT_CONNECTION', Path)
self:UnregisterEvent('UNIT_FACTION', Path)
end
end
oUF:AddElement('Health', Path, Enable, Disable)

View File

@@ -0,0 +1,87 @@
--[[ Element: Leader Icon
Toggles visibility based on the units leader status.
Widget
Leader - Any UI widget.
Notes
The default leader icon will be applied if the UI widget is a texture and
doesn't have a texture or color defined.
Examples
-- Position and size
local Leader = self:CreateTexture(nil, "OVERLAY")
Leader:SetSize(16, 16)
Leader:SetPoint("BOTTOM", self, "TOP")
-- Register it with oUF
self.Leader = Leadera
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local parent, ns = ...
local oUF = ns.oUF
local Update = function(self, event)
local leader = self.Leader
if(leader.PreUpdate) then
leader:PreUpdate()
end
local unit = self.unit
local isLeader = (UnitInParty(unit) or UnitInRaid(unit)) and UnitIsGroupLeader(unit)
if(isLeader) then
leader:Show()
else
leader:Hide()
end
if(leader.PostUpdate) then
return leader:PostUpdate(isLeader)
end
end
local Path = function(self, ...)
return (self.Leader.Override or Update) (self, ...)
end
local ForceUpdate = function(element)
return Path(element.__owner, 'ForceUpdate')
end
local Enable = function(self)
local leader = self.Leader
if(leader) then
leader.__owner = self
leader.ForceUpdate = ForceUpdate
self:RegisterEvent("PARTY_LEADER_CHANGED", Path, true)
self:RegisterEvent("GROUP_ROSTER_UPDATE", Path, true)
if(leader:IsObjectType"Texture" and not leader:GetTexture()) then
leader:SetTexture[[Interface\GroupFrame\UI-Group-LeaderIcon]]
end
return true
end
end
local Disable = function(self)
local leader = self.Leader
if(leader) then
leader:Hide()
self:UnregisterEvent("PARTY_LEADER_CHANGED", Path)
self:UnregisterEvent("GROUP_ROSTER_UPDATE", Path)
end
end
oUF:AddElement('Leader', Path, Enable, Disable)

View File

@@ -0,0 +1,94 @@
--[[ Element: LFD Role Icon
Toggles visibility of the LFD role icon based upon the units current dungeon
role.
Widget
LFDRole - A Texture containing the LFD role icons at specific locations. Look
at the default LFD role icon texture for an example of this.
Alternatively you can look at the return values of
GetTexCoordsForRoleSmallCircle(role).
Notes
The default LFD role texture will be applied if the UI widget is a texture and
doesn't have a texture or color defined.
Examples
-- Position and size
local LFDRole = self:CreateTexture(nil, "OVERLAY")
LFDRole:SetSize(16, 16)
LFDRole:SetPoint("LEFT", self)
-- Register it with oUF
self.LFDRole = LFDRole
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local parent, ns = ...
local oUF = ns.oUF
local Update = function(self, event)
local lfdrole = self.LFDRole
if(lfdrole.PreUpdate) then
lfdrole:PreUpdate()
end
local role = UnitGroupRolesAssigned(self.unit)
if(role == 'TANK' or role == 'HEALER' or role == 'DAMAGER') then
lfdrole:SetTexCoord(GetTexCoordsForRoleSmallCircle(role))
lfdrole:Show()
else
lfdrole:Hide()
end
if(lfdrole.PostUpdate) then
return lfdrole:PostUpdate(role)
end
end
local Path = function(self, ...)
return (self.LFDRole.Override or Update) (self, ...)
end
local ForceUpdate = function(element)
return Path(element.__owner, 'ForceUpdate')
end
local Enable = function(self)
local lfdrole = self.LFDRole
if(lfdrole) then
lfdrole.__owner = self
lfdrole.ForceUpdate = ForceUpdate
if(self.unit == "player") then
self:RegisterEvent("PLAYER_ROLES_ASSIGNED", Path, true)
else
self:RegisterEvent("GROUP_ROSTER_UPDATE", Path, true)
end
if(lfdrole:IsObjectType"Texture" and not lfdrole:GetTexture()) then
lfdrole:SetTexture[[Interface\LFGFrame\UI-LFG-ICON-PORTRAITROLES]]
end
return true
end
end
local Disable = function(self)
local lfdrole = self.LFDRole
if(lfdrole) then
lfdrole:Hide()
self:UnregisterEvent("PLAYER_ROLES_ASSIGNED", Path)
self:UnregisterEvent("GROUP_ROSTER_UPDATE", Path)
end
end
oUF:AddElement('LFDRole', Path, Enable, Disable)

View File

@@ -0,0 +1,106 @@
--[[ Element: Master Looter Icon
Toggles visibility of the master looter icon.
Widget
MasterLooter - Any UI widget.
Notes
The default master looter icon will be applied if the UI widget is a texture
and doesn't have a texture or color defined.
Examples
-- Position and size
local MasterLooter = self:CreateTexture(nil, 'OVERLAY')
MasterLooter:SetSize(16, 16)
MasterLooter:SetPoint('TOPRIGHT', self)
-- Register it with oUF
self.MasterLooter = MasterLooter
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local parent, ns = ...
local oUF = ns.oUF
local Update = function(self, event)
local unit = self.unit
local masterlooter = self.MasterLooter
if(not (UnitInParty(unit) or UnitInRaid(unit))) then
return masterlooter:Hide()
end
if(masterlooter.PreUpdate) then
masterlooter:PreUpdate()
end
local method, pid, rid = GetLootMethod()
if(method == 'master') then
local mlUnit
if(pid) then
if(pid == 0) then
mlUnit = 'player'
else
mlUnit = 'party'..pid
end
elseif(rid) then
mlUnit = 'raid'..rid
end
if(unit and mlUnit and UnitIsUnit(unit, mlUnit)) then
masterlooter:Show()
elseif(masterlooter:IsShown()) then
masterlooter:Hide()
end
else
masterlooter:Hide()
end
if(masterlooter.PostUpdate) then
return masterlooter:PostUpdate(masterlooter:IsShown())
end
end
local Path = function(self, ...)
return (self.MasterLooter.Override or Update) (self, ...)
end
local ForceUpdate = function(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self, unit)
local masterlooter = self.MasterLooter
if(masterlooter) then
masterlooter.__owner = self
masterlooter.ForceUpdate = ForceUpdate
self:RegisterEvent('PARTY_LOOT_METHOD_CHANGED', Path, true)
self:RegisterEvent('GROUP_ROSTER_UPDATE', Path, true)
if(masterlooter:IsObjectType('Texture') and not masterlooter:GetTexture()) then
masterlooter:SetTexture([[Interface\GroupFrame\UI-Group-MasterLooter]])
end
return true
end
end
local function Disable(self)
if(self.MasterLooter) then
self.MasterLooter:Hide()
self:UnregisterEvent('PARTY_LOOT_METHOD_CHANGED', Path)
self:UnregisterEvent('GROUP_ROSTER_UPDATE', Path)
end
end
oUF:AddElement('MasterLooter', Path, Enable, Disable)

View File

@@ -0,0 +1,85 @@
--[[ Element: Phasing Icon
Toggles visibility of the phase icon based on the units phasing compared to the
player.
Widget
PhaseIcon - Any UI widget.
Notes
The default phasing icon will be used if the UI widget is a texture and doesn't
have a texture or color defined.
Examples
-- Position and size
local PhaseIcon = self:CreateTexture(nil, 'OVERLAY')
PhaseIcon:SetSize(16, 16)
PhaseIcon:SetPoint('TOPLEFT', self)
-- Register it with oUF
self.PhaseIcon = PhaseIcon
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local parent, ns = ...
local oUF = ns.oUF
local Update = function(self, event)
local picon = self.PhaseIcon
if(picon.PreUpdate) then
picon:PreUpdate()
end
local inPhase = UnitInPhase(self.unit)
if(inPhase) then
picon:Hide()
else
picon:Show()
end
if(picon.PostUpdate) then
return picon:PostUpdate(inPhase)
end
end
local Path = function(self, ...)
return (self.PhaseIcon.Override or Update) (self, ...)
end
local ForceUpdate = function(element)
return Path(element.__owner, 'ForceUpdate')
end
local Enable = function(self)
local picon = self.PhaseIcon
if(picon) then
picon.__owner = self
picon.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_PHASE', Path, true)
if(picon:IsObjectType'Texture' and not picon:GetTexture()) then
picon:SetTexture[[Interface\TargetingFrame\UI-PhasingIcon]]
end
return true
end
end
local Disable = function(self)
local picon = self.PhaseIcon
if(picon) then
picon:Hide()
self:UnregisterEvent('UNIT_PHASE', Path)
end
end
oUF:AddElement('PhaseIcon', Path, Enable, Disable)

View File

@@ -0,0 +1,122 @@
--[[ Element: Portraits
Handles updating of the unit's portrait.
Widget
Portrait - A PlayerModel or Texture used to represent the unit's portrait.
Notes
The quest delivery question mark will be used instead of the unit's model when
the client doesn't have the model information for the unit.
Examples
-- 3D Portrait
-- Position and size
local Portrait = CreateFrame('PlayerModel', nil, self)
Portrait:SetSize(32, 32)
Portrait:SetPoint('RIGHT', self, 'LEFT')
-- Register it with oUF
self.Portrait = Portrait
-- 2D Portrait
local Portrait = self:CreateTexture(nil, 'OVERLAY')
Portrait:SetSize(32, 32)
Portrait:SetPoint('RIGHT', self, 'LEFT')
-- Register it with oUF
self.Portrait = Portrait
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local parent, ns = ...
local oUF = ns.oUF
local Update = function(self, event, unit)
if(not unit or not UnitIsUnit(self.unit, unit)) then return end
local portrait = self.Portrait
local modelUpdated = false
if(portrait.PreUpdate) then portrait:PreUpdate(unit) end
if(portrait:IsObjectType'Model') then
local guid = UnitGUID(unit)
if(not UnitExists(unit) or not UnitIsConnected(unit) or not UnitIsVisible(unit)) then
portrait:SetCamDistanceScale(0.25)
portrait:SetPortraitZoom(0)
portrait:SetPosition(0,0,0.5)
portrait:ClearModel()
portrait:SetModel('interface\\buttons\\talktomequestionmark.m2')
portrait.guid = nil
modelUpdated = true
elseif(portrait.guid ~= guid or event == 'UNIT_MODEL_CHANGED') then
portrait:SetCamDistanceScale(1)
portrait:SetPortraitZoom(1)
portrait:SetPosition(0,0,0)
portrait:ClearModel()
portrait:SetUnit(unit)
portrait.guid = guid
modelUpdated = true
end
else
SetPortraitTexture(portrait, unit)
end
if(portrait.PostUpdate) then
return portrait:PostUpdate(unit, event, modelUpdated)
end
end
local Path = function(self, ...)
return (self.Portrait.Override or Update) (self, ...)
end
local ForceUpdate = function(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local Enable = function(self, unit)
local portrait = self.Portrait
if(portrait) then
portrait:Show()
portrait.__owner = self
portrait.ForceUpdate = ForceUpdate
self:RegisterEvent("UNIT_PORTRAIT_UPDATE", Path)
self:RegisterEvent("UNIT_MODEL_CHANGED", Path)
self:RegisterEvent('UNIT_CONNECTION', Path)
-- The quest log uses PARTY_MEMBER_{ENABLE,DISABLE} to handle updating of
-- party members overlapping quests. This will probably be enough to handle
-- model updating.
--
-- DISABLE isn't used as it fires when we most likely don't have the
-- information we want.
if(unit == 'party') then
self:RegisterEvent('PARTY_MEMBER_ENABLE', Path)
end
return true
end
end
local Disable = function(self)
local portrait = self.Portrait
if(portrait) then
portrait:Hide()
self:UnregisterEvent("UNIT_PORTRAIT_UPDATE", Path)
self:UnregisterEvent("UNIT_MODEL_CHANGED", Path)
self:UnregisterEvent('PARTY_MEMBER_ENABLE', Path)
self:UnregisterEvent('UNIT_CONNECTION', Path)
end
end
oUF:AddElement('Portrait', Path, Enable, Disable)

View File

@@ -0,0 +1,318 @@
--[[ Element: Power Bar
Handles updating of `self.Power` based upon the units power.
Widget
Power - A StatusBar used to represent mana.
Sub-Widgets
.bg - A Texture which functions as a background. It will inherit the color of
the main StatusBar.
Notes
The default StatusBar texture will be applied if the UI widget doesn't have a
status bar texture or color defined.
Options
.displayAltPower - Use this to let the widget display alternate power if the
unit has one. If no alternate power the display will fall
back to primary power.
.useAtlas - Use this to let the widget use an atlas for its texture if
`.atlas` is defined on the widget or an atlas is present in
`self.colors.power` for the appropriate power type.
.atlas - A custom atlas
The following options are listed by priority. The first check that returns
true decides the color of the bar.
.colorTapping - Use `self.colors.tapping` to color the bar if the unit
isn't tapped by the player.
.colorDisconnected - Use `self.colors.disconnected` to color the bar if the
unit is offline.
.altPowerColor - A table containing the RGB values to use for a fixed
color if the alt power bar is being displayed instead
.colorPower - Use `self.colors.power[token]` to color the bar based on
the unit's power type. This method will fall-back to
`:GetAlternativeColor()` if it can't find a color matching
the token. If this function isn't defined, then it will
attempt to color based upon the alternative power colors
returned by [UnitPowerType](http://wowprogramming.com/docs/api/UnitPowerType).
Finally, if these aren't defined, then it will attempt to
color the bar based upon `self.colors.power[type]`.
.colorClass - Use `self.colors.class[class]` to color the bar based on
unit class. `class` is defined by the second return of
[UnitClass](http://wowprogramming.com/docs/api/UnitClass).
.colorClassNPC - Use `self.colors.class[class]` to color the bar if the
unit is a NPC.
.colorClassPet - Use `self.colors.class[class]` to color the bar if the
unit is player controlled, but not a player.
.colorReaction - Use `self.colors.reaction[reaction]` to color the bar
based on the player's reaction towards the unit.
`reaction` is defined by the return value of
[UnitReaction](http://wowprogramming.com/docs/api/UnitReaction).
.colorSmooth - Use `self.colors.smooth` to color the bar with a smooth
gradient based on the player's current health percentage.
Sub-Widget Options
.multiplier - Defines a multiplier, which is used to tint the background based
on the main widgets R, G and B values. Defaults to 1 if not
present.
Examples
-- Position and size
local Power = CreateFrame("StatusBar", nil, self)
Power:SetHeight(20)
Power:SetPoint('BOTTOM')
Power:SetPoint('LEFT')
Power:SetPoint('RIGHT')
-- Add a background
local Background = Power:CreateTexture(nil, 'BACKGROUND')
Background:SetAllPoints(Power)
Background:SetTexture(1, 1, 1, .5)
-- Options
Power.frequentUpdates = true
Power.colorTapping = true
Power.colorDisconnected = true
Power.colorPower = true
Power.colorClass = true
Power.colorReaction = true
-- Make the background darker.
Background.multiplier = .5
-- Register it with oUF
self.Power = Power
self.Power.bg = Background
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local parent, ns = ...
local oUF = ns.oUF
local updateFrequentUpdates
oUF.colors.power = {}
for power, color in next, PowerBarColor do
if (type(power) == "string") then
if(type(select(2, next(color))) == 'table') then
oUF.colors.power[power] = {}
for index, color in next, color do
oUF.colors.power[power][index] = {color.r, color.g, color.b}
end
else
oUF.colors.power[power] = {color.r, color.g, color.b, atlas = color.atlas}
end
end
end
-- sourced from FrameXML/Constants.lua
oUF.colors.power[0] = oUF.colors.power.MANA
oUF.colors.power[1] = oUF.colors.power.RAGE
oUF.colors.power[2] = oUF.colors.power.FOCUS
oUF.colors.power[3] = oUF.colors.power.ENERGY
oUF.colors.power[4] = oUF.colors.power.COMBO_POINTS
oUF.colors.power[5] = oUF.colors.power.RUNES
oUF.colors.power[6] = oUF.colors.power.RUNIC_POWER
oUF.colors.power[7] = oUF.colors.power.SOUL_SHARDS
oUF.colors.power[8] = oUF.colors.power.LUNAR_POWER
oUF.colors.power[9] = oUF.colors.power.HOLY_POWER
oUF.colors.power[11] = oUF.colors.power.MAELSTROM
oUF.colors.power[12] = oUF.colors.power.CHI
oUF.colors.power[13] = oUF.colors.power.INSANITY
oUF.colors.power[16] = oUF.colors.power.ARCANE_CHARGES
oUF.colors.power[17] = oUF.colors.power.FURY
oUF.colors.power[18] = oUF.colors.power.PAIN
local GetDisplayPower = function(unit)
if not unit then return; end
local _, min, _, _, _, _, showOnRaid = UnitAlternatePowerInfo(unit)
if(showOnRaid) then
return ALTERNATE_POWER_INDEX, min
end
end
local Update = function(self, event, unit)
if(self.unit ~= unit) or not unit then return end
local power = self.Power
if(power.PreUpdate) then power:PreUpdate(unit) end
local displayType, min
if power.displayAltPower then
displayType, min = GetDisplayPower(unit)
end
local cur, max = UnitPower(unit, displayType), UnitPowerMax(unit, displayType)
local disconnected = not UnitIsConnected(unit)
local tapped = not UnitPlayerControlled(unit) and UnitIsTapDenied(unit)
if max == 0 then
max = 1
end
power:SetMinMaxValues(min or 0, max)
if(disconnected) then
power:SetValue(max)
else
power:SetValue(cur)
end
power.disconnected = disconnected
power.tapped = tapped
if power.frequentUpdates ~= power.__frequentUpdates then
power.__frequentUpdates = power.frequentUpdates
updateFrequentUpdates(self)
end
local ptype, ptoken, altR, altG, altB = UnitPowerType(unit)
local r, g, b, t
if(power.colorTapping and not UnitPlayerControlled(unit) and UnitIsTapDenied(unit)) then
t = self.colors.tapped
elseif(power.colorDisconnected and disconnected) then
t = self.colors.disconnected
elseif(displayType == ALTERNATE_POWER_INDEX and power.altPowerColor) then
t = power.altPowerColor
elseif(power.colorPower) then
t = self.colors.power[ptoken]
if(not t) then
if(power.GetAlternativeColor) then
r, g, b = power:GetAlternativeColor(unit, ptype, ptoken, altR, altG, altB)
elseif(altR) then
-- As of 7.0.3, altR, altG, altB may be in 0-1 or 0-255 range.
if(altR > 1) or (altG > 1) or (altB > 1) then
r, g, b = altR / 255, altG / 255, altB / 255
else
r, g, b = altR, altG, altB
end
else
t = self.colors.power[ptype]
end
end
elseif(power.colorClass and UnitIsPlayer(unit)) or
(power.colorClassNPC and not UnitIsPlayer(unit)) or
(power.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then
local _, class = UnitClass(unit)
t = self.colors.class[class]
elseif(power.colorReaction and UnitReaction(unit, 'player')) then
t = self.colors.reaction[UnitReaction(unit, "player")]
elseif(power.colorSmooth) then
local adjust = 0 - (min or 0)
r, g, b = self.ColorGradient(cur + adjust, max + adjust, unpack(power.smoothGradient or self.colors.smooth))
end
if(t) then
r, g, b = t[1], t[2], t[3]
end
t = self.colors.power[ptoken or ptype]
local atlas = power.atlas or (t and t.atlas)
if(power.useAtlas and atlas and displayType ~= ALTERNATE_POWER_INDEX) then
power:SetStatusBarAtlas(atlas)
power:SetStatusBarColor(1, 1, 1)
if(power.colorTapping or power.colorDisconnected) then
t = disconnected and self.colors.disconnected or self.colors.tapped
power:GetStatusBarTexture():SetDesaturated(disconnected or tapped)
end
if(t and b) then
r, g, b = t[1], t[2], t[3]
end
else
power:SetStatusBarTexture(power.texture)
if(b) then
power:SetStatusBarColor(r, g, b)
end
end
local bg = power.bg
if(bg and b) then
local mu = bg.multiplier or 1
bg:SetVertexColor(r * mu, g * mu, b * mu)
end
if(power.PostUpdate) then
return power:PostUpdate(unit, cur, max, min, ptoken, ptype)
end
end
local Path = function(self, ...)
return (self.Power.Override or Update) (self, ...)
end
local ForceUpdate = function(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
function updateFrequentUpdates(self)
local power = self.Power
if power.frequentUpdates and not self:IsEventRegistered('UNIT_POWER_FREQUENT') then
self:RegisterEvent('UNIT_POWER_FREQUENT', Path)
if self:IsEventRegistered('UNIT_POWER') then
self:UnregisterEvent('UNIT_POWER', Path)
end
elseif not self:IsEventRegistered('UNIT_POWER') then
self:RegisterEvent('UNIT_POWER', Path)
if self:IsEventRegistered('UNIT_POWER_FREQUENT') then
self:UnregisterEvent('UNIT_POWER_FREQUENT', Path)
end
end
end
local Enable = function(self, unit)
local power = self.Power
if(power) then
power.__owner = self
power.ForceUpdate = ForceUpdate
power.__frequentUpdates = power.frequentUpdates
updateFrequentUpdates(self)
self:RegisterEvent('UNIT_POWER_BAR_SHOW', Path)
self:RegisterEvent('UNIT_POWER_BAR_HIDE', Path)
self:RegisterEvent('UNIT_DISPLAYPOWER', Path)
self:RegisterEvent('UNIT_CONNECTION', Path)
self:RegisterEvent('UNIT_MAXPOWER', Path)
-- For tapping.
self:RegisterEvent('UNIT_FACTION', Path)
if(power:IsObjectType'StatusBar') then
power.texture = power:GetStatusBarTexture() and power:GetStatusBarTexture():GetTexture() or [[Interface\TargetingFrame\UI-StatusBar]]
power:SetStatusBarTexture(power.texture)
end
return true
end
end
local Disable = function(self)
local power = self.Power
if(power) then
self:UnregisterEvent('UNIT_POWER_FREQUENT', Path)
self:UnregisterEvent('UNIT_POWER', Path)
self:UnregisterEvent('UNIT_POWER_BAR_SHOW', Path)
self:UnregisterEvent('UNIT_POWER_BAR_HIDE', Path)
self:UnregisterEvent('UNIT_DISPLAYPOWER', Path)
self:UnregisterEvent('UNIT_CONNECTION', Path)
self:UnregisterEvent('UNIT_MAXPOWER', Path)
self:UnregisterEvent('UNIT_FACTION', Path)
end
end
oUF:AddElement('Power', Path, Enable, Disable)

View File

@@ -0,0 +1,169 @@
--[[ Element: Power Prediction Bar
Handles updating and visibility of the power prediction status bars.
Widget
PowerPrediction - A table containing `mainBar` and `altBar`.
Sub-Widgets
mainBar - A StatusBar used to represent power cost of spells, that consume
your main power, e.g. mana for mages;
altBar - A StatusBar used to represent power cost of spells, that consume
your additional power, e.g. mana for balance druids.
Notes
The default StatusBar texture will be applied if the UI widget doesn't have a
status bar texture.
Examples
-- Position and size
local mainBar = CreateFrame('StatusBar', nil, self.Power)
mainBar:SetReverseFill(true)
mainBar:SetPoint('TOP')
mainBar:SetPoint('BOTTOM')
mainBar:SetPoint('RIGHT', self.Power:GetStatusBarTexture(), 'RIGHT')
mainBar:SetWidth(200)
local altBar = CreateFrame('StatusBar', nil, self.AdditionalPower)
altBar:SetReverseFill(true)
altBar:SetPoint('TOP')
altBar:SetPoint('BOTTOM')
altBar:SetPoint('RIGHT', self.AdditionalPower:GetStatusBarTexture(), 'RIGHT')
altBar:SetWidth(200)
-- Register with oUF
self.PowerPrediction = {
mainBar = mainBar,
altBar = altBar
}
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local _, ns = ...
local oUF = ns.oUF
local playerClass = select(2, UnitClass('player'))
local function Update(self, event, unit)
if(self.unit ~= unit) then return end
local pp = self.PowerPrediction
if(pp.PreUpdate) then
pp:PreUpdate(unit)
end
local _, _, _, _, startTime, endTime, _, _, _, spellID = UnitCastingInfo(unit)
local mainPowerType = UnitPowerType(unit)
local hasAltManaBar = ALT_MANA_BAR_PAIR_DISPLAY_INFO[playerClass] and ALT_MANA_BAR_PAIR_DISPLAY_INFO[playerClass][mainPowerType]
local mainCost, altCost = 0, 0
if(event == 'UNIT_SPELLCAST_START' or startTime ~= endTime) then
local costTable = GetSpellPowerCost(spellID)
for _, costInfo in pairs(costTable) do
--[[costInfo content:
-- name: string (powerToken)
-- type: number (powerType)
-- cost: number
-- costPercent: number
-- costPerSec: number
-- minCost: number
-- hasRequiredAura: boolean
-- requiredAuraID: number
]]
if(costInfo.type == mainPowerType) then
mainCost = costInfo.cost
break
elseif(costInfo.type == ADDITIONAL_POWER_BAR_INDEX) then
altCost = costInfo.cost
break
end
end
end
if(pp.mainBar) then
pp.mainBar:SetMinMaxValues(0, UnitPowerMax(unit, mainPowerType))
pp.mainBar:SetValue(mainCost)
pp.mainBar:Show()
end
if(pp.altBar and hasAltManaBar) then
pp.altBar:SetMinMaxValues(0, UnitPowerMax(unit, ADDITIONAL_POWER_BAR_INDEX))
pp.altBar:SetValue(altCost)
pp.altBar:Show()
end
if(pp.PostUpdate) then
return pp:PostUpdate(unit, mainCost, altCost, hasAltManaBar)
end
end
local function Path(self, ...)
return (self.PowerPrediction.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local pp = self.PowerPrediction
if(pp) then
pp.__owner = self
pp.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_SPELLCAST_START', Path)
self:RegisterEvent('UNIT_SPELLCAST_STOP', Path)
self:RegisterEvent('UNIT_SPELLCAST_FAILED', Path)
self:RegisterEvent('UNIT_SPELLCAST_SUCCEEDED', Path)
self:RegisterEvent('UNIT_DISPLAYPOWER', Path)
if(pp.mainBar) then
if(pp.mainBar:IsObjectType('StatusBar') and not pp.mainBar:GetStatusBarTexture()) then
pp.mainBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
end
if(pp.altBar) then
if(pp.altBar:IsObjectType('StatusBar') and not pp.altBar:GetStatusBarTexture()) then
pp.altBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
end
return true
end
end
local function Disable(self)
local pp = self.PowerPrediction
if(pp) then
if(pp.mainBar) then
pp.mainBar:Hide()
end
if(pp.altBar) then
pp.altBar:Hide()
end
self:UnregisterEvent('UNIT_SPELLCAST_START', Path)
self:UnregisterEvent('UNIT_SPELLCAST_STOP', Path)
self:UnregisterEvent('UNIT_SPELLCAST_FAILED', Path)
self:UnregisterEvent('UNIT_SPELLCAST_SUCCEEDED', Path)
self:UnregisterEvent('UNIT_DISPLAYPOWER', Path)
end
end
oUF:AddElement('PowerPrediction', Path, Enable, Disable)

View File

@@ -0,0 +1,160 @@
--[[ Element: PvP and Prestige Icons
Handles updating and visibility of PvP and prestige icons based on unit's PvP
status and prestige level.
Widget
PvP - A Texture used to display faction, FFA PvP status or prestige icon.
Sub-Widgets
Prestige - A Texture used to display prestige background image.
Notes
This element updates by changing the texture;
`Prestige` texture has to be on a lower sub-layer than `PvP` texture.
Examples
-- Position and size
local PvP = self:CreateTexture(nil, 'ARTWORK', nil, 1)
PvP:SetSize(30, 30)
PvP:SetPoint('RIGHT', self, 'LEFT')
local Prestige = self:CreateTexture(nil, 'ARTWORK')
Prestige:SetSize(50, 52)
Prestige:SetPoint('CENTER', PvP, 'CENTER')
-- Register it with oUF
self.PvP = PvP
self.PvP.Prestige = Prestige
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local parent, ns = ...
local oUF = ns.oUF
local function Update(self, event, unit)
if(unit ~= self.unit) then return end
local pvp = self.PvP
if(pvp.PreUpdate) then
pvp:PreUpdate(unit)
end
local status
local hasPrestige
local level = UnitPrestige(unit)
local factionGroup = UnitFactionGroup(unit)
if(UnitIsPVPFreeForAll(unit)) then
if(level > 0 and pvp.Prestige) then
pvp:SetTexture(GetPrestigeInfo(level))
pvp:SetTexCoord(0, 1, 0, 1)
pvp.Prestige:SetAtlas('honorsystem-portrait-neutral', false)
hasPrestige = true
else
pvp:SetTexture('Interface\\TargetingFrame\\UI-PVP-FFA')
pvp:SetTexCoord(0, 0.65625, 0, 0.65625)
end
status = 'ffa'
elseif(factionGroup and factionGroup ~= 'Neutral' and UnitIsPVP(unit)) then
if(UnitIsMercenary(unit)) then
if(factionGroup == 'Horde') then
factionGroup = 'Alliance'
elseif(factionGroup == 'Alliance') then
factionGroup = 'Horde'
end
end
if(level > 0 and pvp.Prestige) then
pvp:SetTexture(GetPrestigeInfo(level))
pvp:SetTexCoord(0, 1, 0, 1)
pvp.Prestige:SetAtlas('honorsystem-portrait-'..factionGroup, false)
hasPrestige = true
else
pvp:SetTexture('Interface\\TargetingFrame\\UI-PVP-'..factionGroup)
pvp:SetTexCoord(0, 0.65625, 0, 0.65625)
end
status = factionGroup
end
if(status) then
pvp:Show()
if(pvp.Prestige) then
if(hasPrestige) then
pvp.Prestige:Show()
else
pvp.Prestige:Hide()
end
end
else
pvp:Hide()
if(pvp.Prestige) then
pvp.Prestige:Hide()
end
end
if(pvp.PostUpdate) then
return pvp:PostUpdate(unit, status, hasPrestige, level)
end
end
local function Path(self, ...)
return (self.PvP.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local pvp = self.PvP
if(pvp) then
pvp.__owner = self
pvp.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_FACTION', Path)
if(pvp.Prestige) then
self:RegisterEvent('HONOR_PRESTIGE_UPDATE', Path)
end
return true
end
end
local function Disable(self)
local pvp = self.PvP
if(pvp) then
pvp:Hide()
self:UnregisterEvent('UNIT_FACTION', Path)
if(pvp.Prestige) then
pvp.Prestige:Hide()
self:UnregisterEvent('HONOR_PRESTIGE_UPDATE', Path)
end
end
end
oUF:AddElement('PvP', Path, Enable, Disable)

View File

@@ -0,0 +1,86 @@
--[[ Element: Quest Icon
Handles updating and toggles visibility based upon the units connection to a
quest.
Widget
QuestIcon - Any UI widget.
Notes
The default quest icon will be used if the UI widget is a texture and doesn't
have a texture or color defined.
Examples
-- Position and size
local QuestIcon = self:CreateTexture(nil, 'OVERLAY')
QuestIcon:SetSize(16, 16)
QuestIcon:SetPoint('TOPRIGHT', self)
-- Register it with oUF
self.QuestIcon = QuestIcon
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local parent, ns = ...
local oUF = ns.oUF
local Update = function(self, event, unit)
if(unit ~= self.unit) then return end
local qicon = self.QuestIcon
if(qicon.PreUpdate) then
qicon:PreUpdate()
end
local isQuestBoss = UnitIsQuestBoss(unit)
if(isQuestBoss) then
qicon:Show()
else
qicon:Hide()
end
if(qicon.PostUpdate) then
return qicon:PostUpdate(isQuestBoss)
end
end
local Path = function(self, ...)
return (self.QuestIcon.Override or Update) (self, ...)
end
local ForceUpdate = function(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local Enable = function(self)
local qicon = self.QuestIcon
if(qicon) then
qicon.__owner = self
qicon.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_CLASSIFICATION_CHANGED', Path)
if(qicon:IsObjectType'Texture' and not qicon:GetTexture()) then
qicon:SetTexture[[Interface\TargetingFrame\PortraitQuestBadge]]
end
return true
end
end
local Disable = function(self)
if(self.QuestIcon) then
self.QuestIcon:Hide()
self:UnregisterEvent('UNIT_CLASSIFICATION_CHANGED', Path)
end
end
oUF:AddElement('QuestIcon', Path, Enable, Disable)

View File

@@ -0,0 +1,89 @@
--[[ Element: Raid Role Icon
Handles visibility and updating of `self.RaidRole` based upon the units
party assignment.
Widget
RaidRole - A Texture representing the units party assignment. This is can be
main tank, main assist or blank.
Notes
This element updates by changing the texture.
Examples
-- Position and size
local RaidRole = self:CreateTexture(nil, 'OVERLAY')
RaidRole:SetSize(16, 16)
RaidRole:SetPoint('TOPLEFT')
-- Register it with oUF
self.RaidRole = RaidRole
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local parent, ns = ...
local oUF = ns.oUF
local Update = function(self, event)
local unit = self.unit
if(not UnitInRaid(unit)) then return end
local raidrole = self.RaidRole
if(raidrole.PreUpdate) then
raidrole:PreUpdate()
end
local inVehicle = UnitHasVehicleUI(unit)
if(GetPartyAssignment('MAINTANK', unit) and not inVehicle) then
raidrole:Show()
raidrole:SetTexture[[Interface\GROUPFRAME\UI-GROUP-MAINTANKICON]]
elseif(GetPartyAssignment('MAINASSIST', unit) and not inVehicle) then
raidrole:Show()
raidrole:SetTexture[[Interface\GROUPFRAME\UI-GROUP-MAINASSISTICON]]
else
raidrole:Hide()
end
if(raidrole.PostUpdate) then
return raidrole:PostUpdate(rinfo)
end
end
local Path = function(self, ...)
return (self.RaidRole.Override or Update)(self, ...)
end
local ForceUpdate = function(element)
return Path(element.__owner, 'ForceUpdate')
end
local Enable = function(self)
local raidrole = self.RaidRole
if(raidrole) then
raidrole.__owner = self
raidrole.ForceUpdate = ForceUpdate
self:RegisterEvent('GROUP_ROSTER_UPDATE', Path, true)
return true
end
end
local Disable = function(self)
local raidrole = self.RaidRole
if(raidrole) then
self:UnregisterEvent('GROUP_ROSTER_UPDATE', Path)
end
end
oUF:AddElement('RaidRole', Path, Enable, Disable)

View File

@@ -0,0 +1,250 @@
local parent, ns = ...
local oUF = ns.oUF
local _FRAMES = {}
local OnRangeFrame
local UnitIsConnected = UnitIsConnected
local tinsert, tremove, twipe = table.insert, table.remove, table.wipe
local friendlySpells, resSpells, longEnemySpells, enemySpells, petSpells = {}, {}, {}, {}, {}
local addSpellRetry = {}
local SpellRange = LibStub("SpellRange-1.0")
local function AddSpell(table, spellID)
table[#table + 1] = spellID
end
local _,class = UnitClass("player")
do
if class == "PRIEST" then
AddSpell(enemySpells, 585) -- Smite (40 yards)
AddSpell(enemySpells, 589) -- Shadow Word: Pain (40 yards)
AddSpell(friendlySpells, 2061) -- Flash Heal (40 yards)
AddSpell(friendlySpells, 17) -- Power Word: Shield (40 yards)
AddSpell(resSpells, 2006) -- Resurrection (40 yards)
elseif class == "DRUID" then
AddSpell(enemySpells, 8921) -- Moonfire (40 yards, all specs, lvl 3)
AddSpell(friendlySpells, 8936) -- Regrowth (40 yards, all specs, lvl 5)
AddSpell(resSpells, 50769) -- Revive (40 yards, all specs, lvl 14)
elseif class == "PALADIN" then
AddSpell(enemySpells, 20271) -- Judgement (30 yards)
AddSpell(longEnemySpells, 20473) -- Holy Shock (40 yards)
AddSpell(friendlySpells, 19750) -- Flash of Light (40 yards)
AddSpell(resSpells, 7328) -- Redemption (40 yards)
elseif class == "SHAMAN" then
AddSpell(enemySpells, 188196) -- Lightning Bolt (Elemental) (40 yards)
AddSpell(enemySpells, 187837) -- Lightning Bolt (Enhancement) (40 yards)
AddSpell(enemySpells, 403) -- Lightning Bolt (Resto) (40 yards)
AddSpell(friendlySpells, 8004) -- Healing Surge (Resto/Elemental) (40 yards)
AddSpell(friendlySpells, 188070) -- Healing Surge (Enhancement) (40 yards)
AddSpell(resSpells, 2008) -- Ancestral Spirit (40 yards)
elseif class == "WARLOCK" then
AddSpell(enemySpells, 5782) -- Fear (30 yards)
AddSpell(longEnemySpells, 234153) -- Drain Life (40 yards)
AddSpell(longEnemySpells, 198590) --Drain Soul (40 yards)
AddSpell(longEnemySpells, 232670) --Shadow Bolt (40 yards, lvl 1 spell)
AddSpell(petSpells, 755) -- Health Funnel (45 yards)
AddSpell(friendlySpells, 20707) -- Soulstone (40 yards)
elseif class == "MAGE" then
AddSpell(enemySpells, 118) -- Polymorph (30 yards)
AddSpell(longEnemySpells, 116) -- Frostbolt (Frost) (40 yards)
AddSpell(longEnemySpells, 44425) -- Arcane Barrage (Arcane) (40 yards)
AddSpell(longEnemySpells, 133) -- Fireball (Fire) (40 yards)
AddSpell(friendlySpells, 130) -- Slow Fall (40 yards)
elseif class == "HUNTER" then
AddSpell(petSpells, 982) -- Mend Pet (45 yards)
AddSpell(enemySpells, 75) -- Auto Shot (40 yards)
elseif class == "DEATHKNIGHT" then
AddSpell(enemySpells, 49576) -- Death Grip
AddSpell(longEnemySpells, 47541) -- Death Coil (Unholy) (40 yards)
AddSpell(resSpells, 61999) -- Raise Ally (40 yards)
elseif class == "ROGUE" then
AddSpell(enemySpells, 185565) -- Poisoned Knife (Assassination) (30 yards)
AddSpell(enemySpells, 185763) -- Pistol Shot (Outlaw) (20 yards)
AddSpell(enemySpells, 114014) -- Shuriken Toss (Sublety) (30 yards)
AddSpell(enemySpells, 1725) -- Distract (30 yards)
AddSpell(friendlySpells, 57934) -- Tricks of the Trade (100 yards)
elseif class == "WARRIOR" then
AddSpell(enemySpells, 5246) -- Intimidating Shout (Arms/Fury) (8 yards)
AddSpell(enemySpells, 100) -- Charge (Arms/Fury) (8-25 yards)
AddSpell(longEnemySpells, 355) -- Taunt (30 yards)
elseif class == "MONK" then
AddSpell(enemySpells, 115546) -- Provoke (30 yards)
AddSpell(longEnemySpells, 117952) -- Crackling Jade Lightning (40 yards)
AddSpell(friendlySpells, 116694) -- Effuse (40 yards)
AddSpell(resSpells, 115178) -- Resuscitate (40 yards)
elseif class == "DEMONHUNTER" then
AddSpell(enemySpells, 183752) -- Consume Magic (20 yards)
AddSpell(longEnemySpells, 185123) -- Throw Glaive (Havoc) (30 yards)
AddSpell(longEnemySpells, 204021) -- Fiery Brand (Vengeance) (30 yards)
end
end
local function getUnit(unit)
if not unit:find("party") or not unit:find("raid") then
for i=1, 4 do
if UnitIsUnit(unit, "party"..i) then
return "party"..i
end
end
for i=1, 40 do
if UnitIsUnit(unit, "raid"..i) then
return "raid"..i
end
end
else
return unit
end
end
local function friendlyIsInRange(unit)
if CheckInteractDistance(unit, 1) and UnitInPhase(unit) then --Inspect (28 yards) and same phase as you
return true
end
if UnitIsDeadOrGhost(unit) and #resSpells > 0 then
for _, spellID in ipairs(resSpells) do
if SpellRange.IsSpellInRange(spellID, unit) == 1 then
return true
end
end
return false
end
if #friendlySpells == 0 and (UnitInRaid(unit) or UnitInParty(unit)) then
unit = getUnit(unit)
return unit and UnitInRange(unit)
else
for _, spellID in ipairs(friendlySpells) do
if SpellRange.IsSpellInRange(spellID, unit) == 1 then
return true
end
end
end
return false
end
local function petIsInRange(unit)
if CheckInteractDistance(unit, 2) then
return true
end
for _, spellID in ipairs(friendlySpells) do
if SpellRange.IsSpellInRange(spellID, unit) == 1 then
return true
end
end
for _, spellID in ipairs(petSpells) do
if SpellRange.IsSpellInRange(spellID, unit) == 1 then
return true
end
end
return false
end
local function enemyIsInRange(unit)
if CheckInteractDistance(unit, 2) then
return true
end
for _, spellID in ipairs(enemySpells) do
if SpellRange.IsSpellInRange(spellID, unit) == 1 then
return true
end
end
return false
end
local function enemyIsInLongRange(unit)
for _, spellID in ipairs(longEnemySpells) do
if SpellRange.IsSpellInRange(spellID, unit) == 1 then
return true
end
end
return false
end
-- updating of range.
local timer = 0
local OnRangeUpdate = function(self, elapsed)
timer = timer + elapsed
if(timer >= .20) then
for _, object in next, _FRAMES do
if(object:IsShown()) then
local range = object.Range
local unit = object.unit
if(unit) then
if UnitCanAttack("player", unit) then
if enemyIsInRange(unit) then
object:SetAlpha(range.insideAlpha)
elseif enemyIsInLongRange(unit) then
object:SetAlpha(range.insideAlpha)
else
object:SetAlpha(range.outsideAlpha)
end
elseif UnitIsUnit(unit, "pet") then
if petIsInRange(unit) then
object:SetAlpha(range.insideAlpha)
else
object:SetAlpha(range.outsideAlpha)
end
else
if friendlyIsInRange(unit) and UnitIsConnected(unit) then
object:SetAlpha(range.insideAlpha)
else
object:SetAlpha(range.outsideAlpha)
end
end
else
object:SetAlpha(range.insideAlpha)
end
end
end
timer = 0
end
end
local Enable = function(self)
local range = self.Range
if(range and range.insideAlpha and range.outsideAlpha) then
tinsert(_FRAMES, self)
if(not OnRangeFrame) then
OnRangeFrame = CreateFrame"Frame"
OnRangeFrame:SetScript("OnUpdate", OnRangeUpdate)
end
OnRangeFrame:Show()
return true
end
end
local Disable = function(self)
local range = self.Range
if(range) then
for k, frame in next, _FRAMES do
if(frame == self) then
tremove(_FRAMES, k)
frame:SetAlpha(1)
break
end
end
if(#_FRAMES == 0) then
OnRangeFrame:Hide()
end
end
end
oUF:AddElement('Range', nil, Enable, Disable)

View File

@@ -0,0 +1,159 @@
--[[ Element: Ready Check Icon
Handles updating and visibility of `self.ReadyCheck` based upon the units
ready check status.
Widget
ReadyCheck - A Texture representing ready check status.
Notes
This element updates by changing the texture.
Options
.finishedTime - The number of seconds the icon should stick after a check has
completed. Defaults to 10 seconds.
.fadeTime - The number of seconds the icon should used to fade away after
the stick duration has completed. Defaults to 1.5 seconds.
.readyTexture - Path to alternate texture for the ready check "ready" status.
.notReadyTexture - Path to alternate texture for the ready check "notready" status.
.waitingTexture - Path to alternate texture for the ready check "waiting" status.
Examples
-- Position and size
local ReadyCheck = self:CreateTexture(nil, 'OVERLAY')
ReadyCheck:SetSize(16, 16)
ReadyCheck:SetPoint('TOP')
-- Register with oUF
self.ReadyCheck = ReadyCheck
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local parent, ns = ...
local oUF = ns.oUF
local function OnFinished(self)
local element = self:GetParent()
element:Hide()
--[[ :PostUpdateFadeOut()
Called after the element has been faded out.
Arguments
self - The ReadyCheck element.
]]
if(element.PostUpdateFadeOut) then
element:PostUpdateFadeOut()
end
end
local Update = function(self, event)
local element = self.ReadyCheck
--[[ :PreUpdate()
Called before the element has been updated.
Arguments
self - The ReadyCheck 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 or READY_CHECK_READY_TEXTURE)
elseif(status == 'notready') then
element:SetTexture(element.notReadyTexture or READY_CHECK_NOT_READY_TEXTURE)
else
element:SetTexture(element.waitingTexture or READY_CHECK_WAITING_TEXTURE)
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 or READY_CHECK_NOT_READY_TEXTURE)
end
element.Animation:Play()
end
--[[ :PostUpdate(status)
Called after the element has been updated.
Arguments
self - The ReadyCheck element.
status - The units ready check status, if any.
]]
if(element.PostUpdate) then
return element:PostUpdate(status)
end
end
local Path = function(self, ...)
return (self.ReadyCheck.Override or Update) (self, ...)
end
local ForceUpdate = function(element)
return Path(element.__owner, 'ForceUpdate')
end
local Enable = function(self, unit)
local element = self.ReadyCheck
if(element and (unit and (unit:sub(1, 5) == 'party' or unit:sub(1,4) == 'raid'))) then
element.__owner = self
element.ForceUpdate = ForceUpdate
local AnimationGroup = element:CreateAnimationGroup()
AnimationGroup:HookScript('OnFinished', OnFinished)
element.Animation = AnimationGroup
local Animation = AnimationGroup:CreateAnimation('Alpha')
Animation:SetFromAlpha(1)
Animation:SetToAlpha(0)
Animation:SetDuration(element.fadeTime or 1.5)
Animation:SetStartDelay(element.finishedTime or 10)
self:RegisterEvent('READY_CHECK', Path, true)
self:RegisterEvent('READY_CHECK_CONFIRM', Path, true)
self:RegisterEvent('READY_CHECK_FINISHED', Path, true)
return true
end
end
local Disable = function(self)
local element = self.ReadyCheck
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('ReadyCheck', Path, Enable, Disable)

View File

@@ -0,0 +1,85 @@
--[[ Element: Resting Icon
Toggles visibility of the resting icon.
Widget
Resting - Any UI widget.
Notes
The default resting icon will be used if the UI widget is a texture and doesn't
have a texture or color defined.
Examples
-- Position and size
local Resting = self:CreateTexture(nil, 'OVERLAY')
Resting:SetSize(16, 16)
Resting:SetPoint('TOPLEFT', self)
-- Register it with oUF
self.Resting = Resting
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local parent, ns = ...
local oUF = ns.oUF
local Update = function(self, event)
local resting = self.Resting
if(resting.PreUpdate) then
resting:PreUpdate()
end
local isResting = IsResting()
if(isResting) then
resting:Show()
else
resting:Hide()
end
if(resting.PostUpdate) then
return resting:PostUpdate(isResting)
end
end
local Path = function(self, ...)
return (self.Resting.Override or Update) (self, ...)
end
local ForceUpdate = function(element)
return Path(element.__owner, 'ForceUpdate')
end
local Enable = function(self, unit)
local resting = self.Resting
if(resting and unit == 'player') then
resting.__owner = self
resting.ForceUpdate = ForceUpdate
self:RegisterEvent("PLAYER_UPDATE_RESTING", Path, true)
if(resting:IsObjectType"Texture" and not resting:GetTexture()) then
resting:SetTexture[[Interface\CharacterFrame\UI-StateIcon]]
resting:SetTexCoord(0, .5, 0, .421875)
end
return true
end
end
local Disable = function(self)
local resting = self.Resting
if(resting) then
resting:Hide()
self:UnregisterEvent("PLAYER_UPDATE_RESTING", Path)
end
end
oUF:AddElement('Resting', Path, Enable, Disable)

View File

@@ -0,0 +1,85 @@
--[[ Element: Resurrect Icon
Handles updating and toggles visibility of incoming resurrect icon.
Widget
ResurrectIcon - A Texture used to display if the unit has an incoming
resurrect.
Notes
The default resurrect icon will be used if the UI widget is a texture and
doesn't have a texture or color defined.
Examples
-- Position and size
local ResurrectIcon = self:CreateTexture(nil, 'OVERLAY')
ResurrectIcon:SetSize(16, 16)
ResurrectIcon:SetPoint('TOPRIGHT', self)
-- Register it with oUF
self.ResurrectIcon = ResurrectIcon
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local parent, ns = ...
local oUF = ns.oUF
local Update = function(self, event)
if not self.unit then return; end
local resurrect = self.ResurrectIcon
if(resurrect.PreUpdate) then
resurrect:PreUpdate()
end
local incomingResurrect = UnitHasIncomingResurrection(self.unit)
if(incomingResurrect) then
resurrect:Show()
else
resurrect:Hide()
end
if(resurrect.PostUpdate) then
return resurrect:PostUpdate(incomingResurrect)
end
end
local Path = function(self, ...)
return (self.ResurrectIcon.Override or Update) (self, ...)
end
local ForceUpdate = function(element)
return Path(element.__owner, 'ForceUpdate')
end
local Enable = function(self)
local resurrect = self.ResurrectIcon
if(resurrect) then
resurrect.__owner = self
resurrect.ForceUpdate = ForceUpdate
self:RegisterEvent('INCOMING_RESURRECT_CHANGED', Path, true)
if(resurrect:IsObjectType('Texture') and not resurrect:GetTexture()) then
resurrect:SetTexture[[Interface\RaidFrame\Raid-Icon-Rez]]
end
return true
end
end
local Disable = function(self)
local resurrect = self.ResurrectIcon
if(resurrect) then
self:UnregisterEvent('INCOMING_RESURRECT_CHANGED', Path)
end
end
oUF:AddElement('ResurrectIcon', Path, Enable, Disable)

View File

@@ -0,0 +1,92 @@
--[[ Element: Raid Icon
Handles updating and toggles visibility of raid target icons.
Widget
RaidIcon - A Texture used to display the raid target icon.
Notes
This element updates by changing the texture.
The default raid icons will be used if the UI widget is a texture and doesn't
have a texture or color defined.
Examples
-- Position and size
local RaidIcon = self:CreateTexture(nil, 'OVERLAY')
RaidIcon:SetSize(16, 16)
RaidIcon:SetPoint('TOPRIGHT', self)
-- Register it with oUF
self.RaidIcon = RaidIcon
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local parent, ns = ...
local oUF = ns.oUF
local GetRaidTargetIndex = GetRaidTargetIndex
local SetRaidTargetIconTexture = SetRaidTargetIconTexture
local Update = function(self, event)
if not self.unit then return end
local icon = self.RaidIcon
if(icon.PreUpdate) then
icon:PreUpdate()
end
local index = GetRaidTargetIndex(self.unit)
if(index) then
SetRaidTargetIconTexture(icon, index)
icon:Show()
else
icon:Hide()
end
if(icon.PostUpdate) then
return icon:PostUpdate(index)
end
end
local Path = function(self, ...)
return (self.RaidIcon.Override or Update) (self, ...)
end
local ForceUpdate = function(element)
if(not element.__owner.unit) then return end
return Path(element.__owner, 'ForceUpdate')
end
local Enable = function(self)
local ricon = self.RaidIcon
if(ricon) then
ricon.__owner = self
ricon.ForceUpdate = ForceUpdate
self:RegisterEvent("RAID_TARGET_UPDATE", Path, true)
if(ricon:IsObjectType"Texture" and not ricon:GetTexture()) then
ricon:SetTexture[[Interface\TargetingFrame\UI-RaidTargetingIcons]]
end
return true
end
end
local Disable = function(self)
local ricon = self.RaidIcon
if(ricon) then
ricon:Hide()
self:UnregisterEvent("RAID_TARGET_UPDATE", Path)
end
end
oUF:AddElement('RaidIcon', Path, Enable, Disable)

View File

@@ -0,0 +1,191 @@
--[[ Element: Runes Bar
Handle updating and visibility of the Death Knight's Rune indicators.
Widget
Runes - An array holding StatusBar's.
Sub-Widgets
.bg - A Texture which functions as a background. It will inherit the color of
the main StatusBar.
Notes
The default StatusBar texture will be applied if the UI widget doesn't have a
status bar texture or color defined.
Sub-Widgets Options
.multiplier - Defines a multiplier, which is used to tint the background based
on the main widgets R, G and B values. Defaults to 1 if not
present.
Examples
local Runes = {}
for index = 1, 6 do
-- Position and size of the rune bar indicators
local Rune = CreateFrame('StatusBar', nil, self)
Rune:SetSize(120 / 6, 20)
Rune:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', index * 120 / 6, 0)
Runes[index] = Rune
end
-- Register with oUF
self.Runes = Runes
Hooks
Override(self) - Used to completely override the internal update
function. Removing the table key entry will make the
element fall-back to its internal function again.
]]
if select(2, UnitClass("player")) ~= "DEATHKNIGHT" then return end
local parent, ns = ...
local oUF = ns.oUF
local OnUpdate = function(self, elapsed)
local duration = self.duration + elapsed
self.duration = duration
self:SetValue(duration)
end
local Update = function(self, event, rid, energized)
local runes = self.Runes
local rune = runes[rid]
if(not rune) then return end
local start, duration, runeReady
if(UnitHasVehicleUI'player') then
rune:Hide()
else
start, duration, runeReady = GetRuneCooldown(rid)
if(not start) then return end
if(energized or runeReady) then
rune:SetMinMaxValues(0, 1)
rune:SetValue(1)
rune:SetScript("OnUpdate", nil)
else
rune.duration = GetTime() - start
rune.max = duration
rune:SetMinMaxValues(1, duration)
rune:SetScript("OnUpdate", OnUpdate)
end
rune:Show()
end
if(runes.PostUpdate) then
return runes:PostUpdate(rune, rid, energized and 0 or start, duration, energized or runeReady)
end
end
local Path = function(self, event, ...)
local runes = self.Runes
local UpdateMethod = runes.Override or Update
if(event == 'RUNE_POWER_UPDATE') then
return UpdateMethod(self, event, ...)
else
for index = 1, #runes do
UpdateMethod(self, event, index)
end
end
end
local function RunesEnable(self)
self:RegisterEvent('UNIT_ENTERED_VEHICLE', VisibilityPath)
self:UnregisterEvent("UNIT_EXITED_VEHICLE", VisibilityPath)
self.Runes:Show()
if self.Runes.PostUpdateVisibility then
self.Runes:PostUpdateVisibility(true, not self.Runes.isEnabled)
end
self.Runes.isEnabled = true
Path(self, 'RunesEnable')
end
local function RunesDisable(self)
self:UnregisterEvent('UNIT_ENTERED_VEHICLE', VisibilityPath)
self:RegisterEvent("UNIT_EXITED_VEHICLE", VisibilityPath)
self.Runes:Hide()
if self.Runes.PostUpdateVisibility then
self.Runes:PostUpdateVisibility(false, self.Runes.isEnabled)
end
self.Runes.isEnabled = false
Path(self, 'RunesDisable')
end
local function Visibility(self, event, ...)
local element = self.Runes
local shouldEnable
if not (UnitHasVehicleUI('player')) then
shouldEnable = true
end
local isEnabled = element.isEnabled
if(shouldEnable and not isEnabled) then
RunesEnable(self)
elseif(not shouldEnable and (isEnabled or isEnabled == nil)) then
RunesDisable(self)
elseif(shouldEnable and isEnabled) then
Path(self, event, ...)
end
end
local VisibilityPath = function(self, ...)
return (self.Runes.OverrideVisibility or Visibility) (self, ...)
end
local ForceUpdate = function(element)
return VisibilityPath(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local Enable = function(self, unit)
local runes = self.Runes
if(runes and unit == 'player') then
runes.__owner = self
runes.ForceUpdate = ForceUpdate
for i = 1, #runes do
local rune = runes[i]
local r, g, b = unpack(self.colors.power.RUNES)
if(rune:IsObjectType'StatusBar' and not rune:GetStatusBarTexture()) then
rune:SetStatusBarTexture[[Interface\TargetingFrame\UI-StatusBar]]
rune:SetStatusBarColor(r, g, b)
end
if(rune.bg) then
local mu = rune.bg.multiplier or 1
rune.bg:SetVertexColor(r * mu, g * mu, b * mu)
end
end
self:RegisterEvent("RUNE_POWER_UPDATE", Path, true)
return true
end
end
local Disable = function(self)
self:UnregisterEvent("RUNE_POWER_UPDATE", Path)
RunesDisable(self)
end
oUF:AddElement("Runes", VisibilityPath, Enable, Disable)

View File

@@ -0,0 +1,188 @@
--[[ Element: Monk Stagger Bar
Handles updating and visibility of the monk's stagger bar.
Widget
Stagger - A StatusBar
Sub-Widgets
.bg - A Texture that functions as a background. It will inherit the color
of the main StatusBar.
Notes
The default StatusBar texture will be applied if the UI widget doesn't have a
status bar texture or color defined.
In order to override the internal update define the 'OnUpdate' script on the
widget in the layout
Sub-Widgets Options
.multiplier - Defines a multiplier, which is used to tint the background based
on the main widgets R, G and B values. Defaults to 1 if not
present.
Examples
local Stagger = CreateFrame('StatusBar', nil, self)
Stagger:SetSize(120, 20)
Stagger:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', 0, 0)
-- Register with oUF
self.Stagger = Stagger
Hooks
OverrideVisibility(self) - Used to completely override the internal visibility
function. Removing the table key entry will make
the element fall-back to its internal function
again.
Override(self) - Used to completely override the internal
update function. Removing the table key entry will
make the element fall-back to its internal function
again.
]]
local parent, ns = ...
local oUF = ns.oUF
-- percentages at which the bar should change color
local STAGGER_YELLOW_TRANSITION = STAGGER_YELLOW_TRANSITION
local STAGGER_RED_TRANSITION = STAGGER_RED_TRANSITION
-- table indices of bar colors
local STAGGER_GREEN_INDEX = STAGGER_GREEN_INDEX or 1
local STAGGER_YELLOW_INDEX = STAGGER_YELLOW_INDEX or 2
local STAGGER_RED_INDEX = STAGGER_RED_INDEX or 3
local UnitHealthMax = UnitHealthMax
local UnitStagger = UnitStagger
local _, playerClass = UnitClass("player")
local color
local Update = function(self, event, unit)
if unit and unit ~= self.unit then return end
local element = self.Stagger
if(element.PreUpdate) then
element:PreUpdate()
end
local maxHealth = UnitHealthMax("player")
local stagger = UnitStagger("player") or 0 --For some reason stagger sometimes is nil
local staggerPercent = stagger / maxHealth
element:SetMinMaxValues(0, maxHealth)
element:SetValue(stagger)
local rgb
if(staggerPercent >= STAGGER_RED_TRANSITION) then
rgb = color[STAGGER_RED_INDEX]
elseif(staggerPercent > STAGGER_YELLOW_TRANSITION) then
rgb = color[STAGGER_YELLOW_INDEX]
else
rgb = color[STAGGER_GREEN_INDEX]
end
local r, g, b = rgb[1], rgb[2], rgb[3]
element:SetStatusBarColor(r, g, b)
local bg = element.bg
if(bg) then
local mu = bg.multiplier or 1
bg:SetVertexColor(r * mu, g * mu, b * mu)
end
if(element.PostUpdate) then
element:PostUpdate(maxHealth, stagger, staggerPercent, r, g, b)
end
end
local Path = function(self, ...)
return (self.Stagger.Override or Update)(self, ...)
end
local Visibility = function(self, event, unit)
local isShown = self.Stagger:IsShown()
local stateChanged = false
if(SPEC_MONK_BREWMASTER ~= GetSpecialization() or UnitHasVehiclePlayerFrameUI('player')) then
if isShown then
self.Stagger:Hide()
self:UnregisterEvent('UNIT_AURA', Path)
stateChanged = true
end
if(self.Stagger.PostUpdateVisibility) then
self.Stagger.PostUpdateVisibility(self, event, unit, false, stateChanged)
end
else
if(not isShown) then
self.Stagger:Show()
self:RegisterEvent('UNIT_AURA', Path)
stateChanged = true
end
if(self.Stagger.PostUpdateVisibility) then
self.Stagger.PostUpdateVisibility(self, event, unit, true, stateChanged)
end
return Path(self, event, unit)
end
end
local VisibilityPath = function(self, ...)
return (self.Stagger.OverrideVisibility or Visibility)(self, ...)
end
local ForceUpdate = function(element)
return VisibilityPath(element.__owner, "ForceUpdate", element.__owner.unit)
end
local Enable = function(self, unit)
if(playerClass ~= "MONK") then return end
local element = self.Stagger
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
element:Hide()
color = self.colors.power[BREWMASTER_POWER_BAR_NAME]
self:RegisterEvent('UNIT_DISPLAYPOWER', VisibilityPath)
self:RegisterEvent('PLAYER_TALENT_UPDATE', VisibilityPath, true)
if(element:IsObjectType'StatusBar' and not element:GetStatusBarTexture()) then
element:SetStatusBarTexture[[Interface\TargetingFrame\UI-StatusBar]]
end
MonkStaggerBar:UnregisterEvent'PLAYER_ENTERING_WORLD'
MonkStaggerBar:UnregisterEvent'PLAYER_SPECIALIZATION_CHANGED'
MonkStaggerBar:UnregisterEvent'UNIT_DISPLAYPOWER'
MonkStaggerBar:UnregisterEvent'UPDATE_VEHICLE_ACTION_BAR'
return true
end
end
local Disable = function(self)
local element = self.Stagger
if(element) then
element:Hide()
self:UnregisterEvent('UNIT_AURA', Path)
self:UnregisterEvent('UNIT_DISPLAYPOWER', VisibilityPath)
self:UnregisterEvent('PLAYER_TALENT_UPDATE', VisibilityPath)
MonkStaggerBar:UnregisterEvent'PLAYER_ENTERING_WORLD'
MonkStaggerBar:UnregisterEvent'PLAYER_SPECIALIZATION_CHANGED'
MonkStaggerBar:UnregisterEvent'UNIT_DISPLAYPOWER'
MonkStaggerBar:UnregisterEvent'UPDATE_VEHICLE_ACTION_BAR'
end
end
oUF:AddElement("Stagger", VisibilityPath, Enable, Disable)

View File

@@ -0,0 +1,781 @@
--[[
-- Credits: Vika, Cladhaire, Tekkub
]]
local parent, ns = ...
local oUF = ns.oUF
local format = string.format
local tinsert, tremove = table.insert, table.remove
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 --wtf?
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(GetCreatureDifficultyColor((l > 0) and l or 999))
end
end]],
["leader"] = [[function(u)
if(UnitIsGroupLeader(u)) then
return 'L'
end
end]],
["leaderlong"] = [[function(u)
if(UnitIsGroupLeader(u)) then
return 'Leader'
end
end]],
["level"] = [[function(u)
local l = UnitLevel(u)
if(UnitIsWildBattlePet(u) or UnitIsBattlePetCompanion(u)) then
l = UnitBattlePetLevel(u)
end
if(l > 0) then
return l
else
return '??'
end
end]],
["missinghp"] = [[function(u)
local current = UnitHealthMax(u) - UnitHealth(u)
if(current > 0) then
return current
end
end]],
["missingpp"] = [[function(u)
local current = UnitPowerMax(u) - UnitPower(u)
if(current > 0) then
return current
end
end]],
["name"] = [[function(u, r)
return UnitName(r or u)
end]],
["offline"] = [[function(u)
if(not UnitIsConnected(u)) then
return 'Offline'
end
end]],
["perhp"] = [[function(u)
local m = UnitHealthMax(u)
if(m == 0) then
return 0
else
return math.floor(UnitHealth(u)/m*100+.5)
end
end]],
["perpp"] = [[function(u)
local m = UnitPowerMax(u)
if(m == 0) then
return 0
else
return math.floor(UnitPower(u)/m*100+.5)
end
end]],
["plus"] = [[function(u)
local c = UnitClassification(u)
if(c == 'elite' or c == 'rareelite') then
return '+'
end
end]],
["pvp"] = [[function(u)
if(UnitIsPVP(u)) then
return 'PvP'
end
end]],
["raidcolor"] = [[function(u)
local _, x = UnitClass(u)
if(x) then
return Hex(_COLORS.class[x])
end
end]],
["rare"] = [[function(u)
local c = UnitClassification(u)
if(c == 'rare' or c == 'rareelite') then
return 'Rare'
end
end]],
["resting"] = [[function(u)
if(u == 'player' and IsResting()) then
return 'zzz'
end
end]],
["sex"] = [[function(u)
local s = UnitSex(u)
if(s == 2) then
return 'Male'
elseif(s == 3) then
return 'Female'
end
end]],
["smartclass"] = [[function(u)
if(UnitIsPlayer(u)) then
return _TAGS['class'](u)
end
return _TAGS['creature'](u)
end]],
["status"] = [[function(u)
if(UnitIsDead(u)) then
return 'Dead'
elseif(UnitIsGhost(u)) then
return 'Ghost'
elseif(not UnitIsConnected(u)) then
return 'Offline'
else
return _TAGS['resting'](u)
end
end]],
["threat"] = [[function(u)
local s = UnitThreatSituation(u)
if(s == 1) then
return '++'
elseif(s == 2) then
return '--'
elseif(s == 3) then
return 'Aggro'
end
end]],
["threatcolor"] = [[function(u)
return Hex(GetThreatStatusColor(UnitThreatSituation(u)))
end]],
["cpoints"] = [[function(u)
local cp
if(UnitHasVehicleUI'player') then
cp = GetComboPoints('vehicle', 'target')
else
cp = GetComboPoints('player', 'target')
end
if(cp > 0) then
return cp
end
end]],
['smartlevel'] = [[function(u)
local c = UnitClassification(u)
if(c == 'worldboss') then
return 'Boss'
else
local plus = _TAGS['plus'](u)
local level = _TAGS['level'](u)
if(plus) then
return level .. plus
else
return level
end
end
end]],
["classification"] = [[function(u)
local c = UnitClassification(u)
if(c == 'rare') then
return 'Rare'
elseif(c == 'rareelite') then
return 'Rare Elite'
elseif(c == 'elite') then
return 'Elite'
elseif(c == 'worldboss') then
return 'Boss'
elseif(c == 'minus') then
return 'Affix'
end
end]],
["shortclassification"] = [[function(u)
local c = UnitClassification(u)
if(c == 'rare') then
return 'R'
elseif(c == 'rareelite') then
return 'R+'
elseif(c == 'elite') then
return '+'
elseif(c == 'worldboss') then
return 'B'
elseif(c == 'minus') then
return '-'
end
end]],
["group"] = [[function(unit)
local name, server = UnitName(unit)
if(server and server ~= "") then
name = format("%s-%s", name, server)
end
for i=1, GetNumGroupMembers() do
local raidName, _, group = GetRaidRosterInfo(i)
if( raidName == name ) then
return group
end
end
end]],
["deficit:name"] = [[function(u)
local missinghp = _TAGS['missinghp'](u)
if(missinghp) then
return '-' .. missinghp
else
return _TAGS['name'](u)
end
end]],
['curmana'] = [[function(unit)
return UnitPower(unit, SPELL_POWER_MANA)
end]],
['maxmana'] = [[function(unit)
return UnitPowerMax(unit, SPELL_POWER_MANA)
end]],
['soulshards'] = [[function()
local num = UnitPower('player', SPELL_POWER_SOUL_SHARDS)
if(num > 0) then
return num
end
end]],
['holypower'] = [[function()
if(GetSpecialization() == SPEC_PALADIN_RETRIBUTION) then
local num = UnitPower('player', SPELL_POWER_HOLY_POWER)
if(num > 0) then
return num
end
end
end]],
['chi'] = [[function()
if(GetSpecialization() == SPEC_MONK_WINDWALKER) then
local num = UnitPower('player', SPELL_POWER_CHI)
if(num > 0) then
return num
end
end
end]],
['arcanecharges'] = [[function()
if(GetSpecialization() == SPEC_MAGE_ARCANE) then
local num = UnitPower('player', SPELL_POWER_ARCANE_CHARGES)
if(num > 0) then
return num
end
end
end]],
['affix'] = [[function(u)
local c = UnitClassification(u)
if(c == 'minus') then
return 'Affix'
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 = UnitPower,
maxhp = UnitHealthMax,
maxpp = UnitPowerMax,
class = UnitClass,
faction = UnitFactionGroup,
race = UnitRace,
},
{
__index = function(self, key)
local tagFunc = tagStrings[key]
if(tagFunc) then
local func, err = loadstring('return ' .. tagFunc)
if(func) then
func = func()
-- Want to trigger __newindex, so no rawset.
self[key] = func
tagStrings[key] = nil
return func
else
error(err, 3)
end
end
end,
__newindex = function(self, key, val)
if(type(val) == 'string') then
tagStrings[key] = val
elseif(type(val) == 'function') then
-- So we don't clash with any custom envs.
if(getfenv(val) == _G) then
setfenv(val, _PROXY)
end
rawset(self, key, val)
end
end,
}
)
_ENV._TAGS = tags
local tagEvents = {
["curhp"] = "UNIT_HEALTH",
["dead"] = "UNIT_HEALTH",
["leader"] = "PARTY_LEADER_CHANGED",
["leaderlong"] = "PARTY_LEADER_CHANGED",
["level"] = "UNIT_LEVEL PLAYER_LEVEL_UP",
["maxhp"] = "UNIT_MAXHEALTH",
["missinghp"] = "UNIT_HEALTH UNIT_MAXHEALTH",
["name"] = "UNIT_NAME_UPDATE",
["perhp"] = "UNIT_HEALTH UNIT_MAXHEALTH",
["pvp"] = "UNIT_FACTION",
["resting"] = "PLAYER_UPDATE_RESTING",
["smartlevel"] = "UNIT_LEVEL PLAYER_LEVEL_UP UNIT_CLASSIFICATION_CHANGED",
["threat"] = "UNIT_THREAT_SITUATION_UPDATE",
["threatcolor"] = "UNIT_THREAT_SITUATION_UPDATE",
['cpoints'] = 'UNIT_COMBO_POINTS PLAYER_TARGET_CHANGED',
['affix'] = 'UNIT_CLASSIFICATION_CHANGED',
['plus'] = 'UNIT_CLASSIFICATION_CHANGED',
['rare'] = 'UNIT_CLASSIFICATION_CHANGED',
['classification'] = 'UNIT_CLASSIFICATION_CHANGED',
['shortclassification'] = 'UNIT_CLASSIFICATION_CHANGED',
["group"] = "GROUP_ROSTER_UPDATE",
["curpp"] = 'UNIT_POWER',
["maxpp"] = 'UNIT_MAXPOWER',
["missingpp"] = 'UNIT_MAXPOWER UNIT_POWER',
["perpp"] = 'UNIT_MAXPOWER UNIT_POWER',
["offline"] = "UNIT_HEALTH UNIT_CONNECTION",
["status"] = "UNIT_HEALTH PLAYER_UPDATE_RESTING UNIT_CONNECTION",
['curmana'] = 'UNIT_POWER UNIT_MAXPOWER',
['maxmana'] = 'UNIT_POWER UNIT_MAXPOWER',
['soulshards'] = 'UNIT_POWER',
['holypower'] = 'UNIT_POWER SPELLS_CHANGED',
['chi'] = 'UNIT_POWER SPELLS_CHANGED',
['arcanecharges'] = 'UNIT_POWER SPELLS_CHANGED',
['powercolor'] = 'UNIT_DISPLAYPOWER',
}
local unitlessEvents = {
PLAYER_LEVEL_UP = true,
PLAYER_UPDATE_RESTING = true,
PLAYER_TARGET_CHANGED = true,
PARTY_LEADER_CHANGED = true,
GROUP_ROSTER_UPDATE = true,
UNIT_COMBO_POINTS = true
}
local events = {}
local frame = CreateFrame"Frame"
frame:SetScript('OnEvent', function(self, event, unit)
local strings = events[event]
if(strings) then
for k, fontstring in next, strings do
if(fontstring:IsVisible() and (unitlessEvents[event] or fontstring.parent.unit == unit)) then
fontstring:UpdateTag()
end
end
end
end)
local OnUpdates = {}
local eventlessUnits = {}
local createOnUpdate = function(timer)
local OnUpdate = OnUpdates[timer]
if(not OnUpdate) then
local total = timer
local frame = CreateFrame'Frame'
local strings = eventlessUnits[timer]
frame:SetScript('OnUpdate', function(self, elapsed)
if(total >= timer) then
for k, fs in next, strings do
if(fs.parent:IsVisible() and UnitExists(fs.parent.unit)) then
fs:UpdateTag()
end
end
total = 0
end
total = total + elapsed
end)
OnUpdates[timer] = frame
end
end
local OnShow = function(self)
for _, fs in next, self.__tags do
fs:UpdateTag()
end
end
local getTagName = function(tag)
local s = (tag:match('>+()') or 2)
local e = tag:match('.*()<+')
e = (e and e - 1) or -2
return tag:sub(s, e), s, e
end
local RegisterEvent = function(fontstr, event)
if(not events[event]) then events[event] = {} end
frame:RegisterEvent(event)
tinsert(events[event], fontstr)
end
local RegisterEvents = function(fontstr, tagstr)
for tag in tagstr:gmatch(_PATTERN) do
tag = getTagName(tag)
local tagevents = tagEvents[tag]
if(tagevents) then
for event in tagevents:gmatch'%S+' do
RegisterEvent(fontstr, event)
end
end
end
end
local UnregisterEvents = function(fontstr)
for event, data in pairs(events) do
for k, tagfsstr in pairs(data) do
if(tagfsstr == fontstr) then
if(#data == 1) then
frame:UnregisterEvent(event)
end
tremove(data, k)
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",
}
local Tag = function(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 tagstr:find(escapeSequence) do
tagstr = tagstr:gsub(escapeSequence, replacement)
end
end
if tagstr:find('%[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 = tagstr:gsub('%[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 tagstr:gmatch(_PATTERN) do
if not tagEvents[tag:sub(2, -2)] then
containsOnUpdate = onUpdateDelay[tag:sub(2, -2)] or 0.15;
end
end
local func = tagPool[tagstr]
if(not func) then
local format, numTags = tagstr:gsub('%%', '%%%%'):gsub(_PATTERN, '%%s')
local args = {}
for bracket in tagstr:gmatch(_PATTERN) do
local tagFunc = funcPool[bracket] or tags[bracket:sub(2, -2)]
if(not tagFunc) then
local tagName, s, e = getTagName(bracket)
local tag = tags[tagName]
if(tag) then
s = s - 2
e = e + 2
if(s ~= 0 and e ~= 0) then
local pre = bracket:sub(2, s)
local ap = bracket:sub(e, -2)
tagFunc = function(u,r)
local str = tag(u,r)
if(str) then
return pre..str..ap
end
end
elseif(s ~= 0) then
local pre = bracket:sub(2, s)
tagFunc = function(u,r)
local str = tag(u,r)
if(str) then
return pre..str
end
end
elseif(e ~= 0) then
local ap = bracket:sub(e, -2)
tagFunc = function(u,r)
local str = tag(u,r)
if(str) then
return str..ap
end
end
end
funcPool[bracket] = tagFunc
end
end
if(tagFunc) then
tinsert(args, tagFunc)
else
numTags = -1
func = function(self)
return self:SetFormattedText('[invalid tag]')
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:SetFormattedText(
format,
args[1](parent.unit, realUnit) or ''
)
end
elseif(numTags == 2) then
func = function(self)
local parent = self.parent
local unit = parent.unit
local realUnit
if(self.overrideUnit) then
realUnit = parent.realUnit
end
_ENV._COLORS = parent.colors
return self:SetFormattedText(
format,
args[1](unit, realUnit) or '',
args[2](unit, realUnit) or ''
)
end
elseif(numTags == 3) then
func = function(self)
local parent = self.parent
local unit = parent.unit
local realUnit
if(self.overrideUnit) then
realUnit = parent.realUnit
end
_ENV._COLORS = parent.colors
return self:SetFormattedText(
format,
args[1](unit, realUnit) or '',
args[2](unit, realUnit) or '',
args[3](unit, realUnit) or ''
)
end
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:SetFormattedText(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
local Untag = function(self, fs)
if(not fs) then return end
UnregisterEvents(fs)
for _, timers in next, eventlessUnits do
for k, fontstr in next, timers do
if(fs == fontstr) then
tremove(timers, k)
end
end
end
for k, fontstr in next, self.__tags do
if(fontstr == fs) then
tremove(self.__tags, k)
end
end
fs.UpdateTag = nil
end
oUF.Tags = {
Methods = tags,
Events = tagEvents,
SharedEvents = unitlessEvents,
OnUpdateThrottle = onUpdateDelay,
}
oUF:RegisterMetaFunction('Tag', Tag)
oUF:RegisterMetaFunction('Untag', Untag)

View File

@@ -0,0 +1,97 @@
--[[ Element: Threat Icon
Handles updating and toggles visibility of current threat level icon.
Widget
Threat - A Texture used to display the current threat level.
Notes
This element updates by changing colors of the texture.
The default threat icon will be used if the UI widget is a texture and doesn't
have a texture or color defined.
Examples
-- Position and size
local Threat = self:CreateTexture(nil, 'OVERLAY')
Threat:SetSize(16, 16)
Threat:SetPoint('TOPRIGHT', self)
-- Register it with oUF
self.Threat = Threat
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local parent, ns = ...
local oUF = ns.oUF
local Update = function(self, event, unit)
if(unit ~= self.unit) or not unit or not IsLoggedIn() then return end
local threat = self.Threat
if(threat.PreUpdate) then threat:PreUpdate(unit) end
local status = UnitThreatSituation(unit)
local r, g, b
if(status and status > 0) then
r, g, b = GetThreatStatusColor(status)
if threat:IsObjectType"Texture" then
threat:SetVertexColor(r, g, b)
end
threat:Show()
else
threat:Hide()
end
if(threat.PostUpdate) then
return threat:PostUpdate(unit, status, r, g, b)
end
end
local Path = function(self, ...)
return (self.Threat.Override or Update) (self, ...)
end
local ForceUpdate = function(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local Enable = function(self)
local threat = self.Threat
if(threat) then
threat.__owner = self
threat.ForceUpdate = ForceUpdate
self:RegisterEvent("UNIT_THREAT_SITUATION_UPDATE", Path)
self:RegisterEvent("UNIT_THREAT_LIST_UPDATE", Path)
if(threat:IsObjectType"Texture" and not threat:GetTexture()) then
threat:SetTexture[[Interface\Minimap\ObjectIcons]]
threat:SetTexCoord(6/8, 7/8, 1/8, 2/8)
end
return true
end
end
local Disable = function(self)
local threat = self.Threat
if(threat) then
threat:Hide()
self:UnregisterEvent("UNIT_THREAT_SITUATION_UPDATE", Path)
self:UnregisterEvent("UNIT_THREAT_LIST_UPDATE", Path)
threat:Hide()
end
end
oUF:AddElement('Threat', Path, Enable, Disable)

View File

@@ -0,0 +1,167 @@
--[[ Element: Totem Indicator
Handles updating and visibility of Shaman totems, Druid mushrooms and Death
Knight ghouls.
Widget
Totems - A table to hold sub-widgets.
Sub-Widgets
Totem - Any UI widget.
.Icon - A Texture representing the totem icon.
.Cooldown - A Cooldown representing the duration of the totem.
Notes
OnEnter and OnLeave will be set to display the default Tooltip, if the
`Totem` widget is mouse enabled.
Options
:UpdateTooltip - The function that should populate the tooltip, when the
`Totem` widget is hovered. A default function, which calls
`:SetTotem(id)`, will be used if none is defined.
Examples
local Totems = {}
for index = 1, MAX_TOTEMS do
-- Position and size of the totem indicator
local Totem = CreateFrame('Button', nil, self)
Totem:SetSize(40, 40)
Totem:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', index * Totem:GetWidth(), 0)
local Icon = Totem:CreateTexture(nil, "OVERLAY")
Icon:SetAllPoints()
local Cooldown = CreateFrame("Cooldown", nil, Totem, "CooldownFrameTemplate")
Cooldown:SetAllPoints()
Totem.Icon = Icon
Totem.Cooldown = Cooldown
Totems[index] = Totem
end
-- Register with oUF
self.Totems = Totems
Hooks
Override(self) - Used to completely override the internal update function.
Removing the table key entry will make the element fall-back
to its internal function again.
]]
local parent, ns = ...
local oUF = ns.oUF
local UpdateTooltip = function(self)
GameTooltip:SetTotem(self:GetID())
end
local OnEnter = function(self)
if(not self:IsVisible()) then return end
GameTooltip:SetOwner(self, 'ANCHOR_BOTTOMRIGHT')
self:UpdateTooltip()
end
local OnLeave = function()
GameTooltip:Hide()
end
local UpdateTotem = function(self, event, slot)
local totems = self.Totems
if(slot > #totems) then return end
if(totems.PreUpdate) then totems:PreUpdate(slot) end
local totem = totems[slot]
local haveTotem, name, start, duration, icon = GetTotemInfo(slot)
if(haveTotem and duration > 0) then
if(totem.Icon) then
totem.Icon:SetTexture(icon)
end
if(totem.Cooldown) then
totem.Cooldown:SetCooldown(start, duration)
end
totem:Show()
else
totem:Hide()
end
if(totems.PostUpdate) then
return totems:PostUpdate(slot, haveTotem, name, start, duration, icon)
end
end
local Path = function(self, ...)
return (self.Totems.Override or UpdateTotem) (self, ...)
end
local Update = function(self, event)
for i = 1, #self.Totems do
Path(self, event, i)
end
end
local ForceUpdate = function(element)
return Update(element.__owner, 'ForceUpdate')
end
local Enable = function(self)
local totems = self.Totems
if(totems) then
totems.__owner = self
totems.ForceUpdate = ForceUpdate
for i = 1, #totems do
local totem = totems[i]
totem:SetID(i)
if(totem:IsMouseEnabled()) then
totem:SetScript('OnEnter', OnEnter)
totem:SetScript('OnLeave', OnLeave)
if(not totem.UpdateTooltip) then
totem.UpdateTooltip = UpdateTooltip
end
end
end
self:RegisterEvent('PLAYER_TOTEM_UPDATE', Path, true)
TotemFrame:UnregisterEvent"PLAYER_TOTEM_UPDATE"
TotemFrame:UnregisterEvent"PLAYER_ENTERING_WORLD"
TotemFrame:UnregisterEvent"UPDATE_SHAPESHIFT_FORM"
TotemFrame:UnregisterEvent"PLAYER_TALENT_UPDATE"
return true
end
end
local Disable = function(self)
local totems = self.Totems
if(totems) then
for i = 1, #totems do
totems[i]:Hide()
end
TotemFrame:RegisterEvent"PLAYER_TOTEM_UPDATE"
TotemFrame:RegisterEvent"PLAYER_ENTERING_WORLD"
TotemFrame:RegisterEvent"UPDATE_SHAPESHIFT_FORM"
TotemFrame:RegisterEvent"PLAYER_TALENT_UPDATE"
self:UnregisterEvent('PLAYER_TOTEM_UPDATE', Path)
end
end
oUF:AddElement("Totems", Update, Enable, Disable)

127
Libraries/oUF/events.lua Normal file
View File

@@ -0,0 +1,127 @@
local parent, ns = ...
local oUF = ns.oUF
local Private = oUF.Private
local argcheck = Private.argcheck
local error = Private.error
local frame_metatable = Private.frame_metatable
-- Original event methods
local RegisterEvent = frame_metatable.__index.RegisterEvent
local RegisterUnitEvent = frame_metatable.__index.RegisterUnitEvent
local UnregisterEvent = frame_metatable.__index.UnregisterEvent
local IsEventRegistered = frame_metatable.__index.IsEventRegistered
local unitEvents = {}
Private.UpdateUnits = function(frame, unit, realUnit)
if unit == realUnit then
realUnit = nil
end
if frame.unit ~= unit or frame.realUnit ~= realUnit then
for event in next, unitEvents do
-- IsEventRegistered returns the units in case of an event
-- registered with RegisterUnitEvent
local registered, unit1 = IsEventRegistered(frame, event)
if registered and unit1 ~= unit then
-- RegisterUnitEvent erases previously registered units so
-- do not bother to unregister it
RegisterUnitEvent(frame, event, unit, realUnit)
end
end
frame.unit = unit
frame.realUnit = realUnit
frame.id = unit:match'^.-(%d+)'
return true
end
end
local OnEvent = function(self, event, ...)
if self:IsVisible() or event == 'UNIT_COMBO_POINTS' then
return self[event](self, event, ...)
end
end
local event_metatable = {
__call = function(funcs, self, ...)
for _, func in next, funcs do
func(self, ...)
end
end,
}
function frame_metatable.__index:RegisterEvent(event, func, unitless)
-- Block OnUpdate polled frames from registering events.
if(self.__eventless) then return end
argcheck(event, 2, 'string')
if(type(func) == 'string' and type(self[func]) == 'function') then
func = self[func]
end
-- TODO: should warn the user.
if not unitless and not (unitEvents[event] or event:match'^UNIT_') then
unitless = true
end
local curev = self[event]
local kind = type(curev)
if(curev and func) then
if(kind == 'function' and curev ~= func) then
self[event] = setmetatable({curev, func}, event_metatable)
elseif(kind == 'table') then
for _, infunc in next, curev do
if(infunc == func) then return end
end
table.insert(curev, func)
end
elseif(IsEventRegistered(self, event)) then
return
else
if(type(func) == 'function') then
self[event] = func
elseif(not self[event]) then
return error("Style [%s] attempted to register event [%s] on unit [%s] with a handler that doesn't exist.", self.style, event, self.unit or 'unknown')
end
if not self:GetScript('OnEvent') then
self:SetScript('OnEvent', OnEvent)
end
if unitless then
RegisterEvent(self, event)
else
unitEvents[event] = true
RegisterUnitEvent(self, event, self.unit)
end
end
end
function frame_metatable.__index:UnregisterEvent(event, func)
argcheck(event, 2, 'string')
local curev = self[event]
if(type(curev) == 'table' and func) then
for k, infunc in next, curev do
if(infunc == func) then
table.remove(curev, k)
local n = #curev
if(n == 1) then
local _, handler = next(curev)
self[event] = handler
elseif(n == 0) then
-- This should not happen
UnregisterEvent(self, event)
end
break
end
end
elseif(curev == func) then
self[event] = nil
UnregisterEvent(self, event)
end
end

48
Libraries/oUF/factory.lua Normal file
View File

@@ -0,0 +1,48 @@
local parent, ns = ...
local oUF = ns.oUF
local Private = oUF.Private
local argcheck = Private.argcheck
local _QUEUE = {}
local _FACTORY = CreateFrame'Frame'
_FACTORY:SetScript('OnEvent', function(self, event, ...)
return self[event](self, event, ...)
end)
_FACTORY:RegisterEvent'PLAYER_LOGIN'
_FACTORY.active = true
function _FACTORY:PLAYER_LOGIN()
if(not self.active) then return end
for _, func in next, _QUEUE do
func(oUF)
end
-- Avoid creating dupes.
wipe(_QUEUE)
end
function oUF:Factory(func)
argcheck(func, 2, 'function')
-- Call the function directly if we're active and logged in.
if(IsLoggedIn() and _FACTORY.active) then
return func(self)
else
table.insert(_QUEUE, func)
end
end
function oUF:EnableFactory()
_FACTORY.active = true
end
function oUF:DisableFactory()
_FACTORY.active = nil
end
function oUF:RunFactoryQueue()
_FACTORY:PLAYER_LOGIN()
end

View File

@@ -0,0 +1,4 @@
local parent, ns = ...
-- It's named Private for a reason!
ns.oUF.Private = nil

3
Libraries/oUF/init.lua Normal file
View File

@@ -0,0 +1,3 @@
local parent, ns = ...
ns.oUF = {}
ns.oUF.Private = {}

11
Libraries/oUF/oUF.toc Normal file
View File

@@ -0,0 +1,11 @@
## Interface: 60000
## Title: oUF
## Author: Haste
## Version: 1.6.8
## OptionalDeps: Clique
## X-eMail: troeks@gmail.com
## X-oUF: oUF
## Notes: Unit frame framework. Does nothing by itself.
## Notes-ruRU: Каркас для модификации фреймов игроков. Сам по себе не делает ничего.
oUF.xml

101
Libraries/oUF/oUF.xml Normal file
View File

@@ -0,0 +1,101 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file='init.lua' />
<Script file='private.lua' />
<Script file='ouf.lua' />
<Script file='events.lua'/>
<Script file='factory.lua' />
<Script file='blizzard.lua' />
<Script file='units.lua' />
<Script file='colors.lua' />
<Script file='finalize.lua' />
<Script file='elements\power.lua' />
<Script file='elements\aura.lua' />
<Script file='elements\health.lua' />
<Script file='elements\ricons.lua' />
<Script file='elements\leader.lua' />
<Script file='elements\combat.lua' />
<Script file='elements\resting.lua' />
<Script file='elements\pvp.lua' />
<Script file='elements\portraits.lua' />
<Script file='elements\range.lua' />
<Script file='elements\castbar.lua' />
<Script file='elements\threat.lua' />
<Script file='elements\tags.lua' />
<Script file='elements\masterlooter.lua' />
<Script file='elements\assistant.lua' />
<Script file='elements\runebar.lua' />
<Script file='elements\lfdrole.lua' />
<Script file='elements\healprediction.lua' />
<Script file='elements\powerprediction.lua' />
<Script file='elements\picon.lua' />
<Script file='elements\readycheck.lua' />
<Script file='elements\qicon.lua' />
<Script file='elements\altpowerbar.lua' />
<Script file='elements\totems.lua' />
<Script file='elements\resurrect.lua' />
<Script file='elements\raidrole.lua' />
<Script file='elements\additionalpower.lua' />
<Script file='elements\classicons.lua' />
<Script file='elements\stagger.lua' />
<!-- Clique support -->
<Button name="oUF_ClickCastUnitTemplate" virtual="true" inherits="SecureUnitButtonTemplate,SecureHandlerEnterLeaveTemplate">
<Attributes>
<Attribute name="_onenter" type="string" value="local snippet = self:GetAttribute('clickcast_onenter'); if snippet then self:Run(snippet) end"/>
<Attribute name="_onleave" type="string" value="local snippet = self:GetAttribute('clickcast_onleave'); if snippet then self:Run(snippet) end"/>
</Attributes>
</Button>
<!-- Pet Battle Hider Frame -->
<Frame name="oUF_PetBattleFrameHider" frameStrata="LOW" inherits="SecureHandlerStateTemplate" parent="UIParent" setAllPoints="true">
<Scripts>
<OnLoad>
RegisterStateDriver(self, "visibility", "[petbattle] hide; show")
</OnLoad>
</Scripts>
</Frame>
<!--
Sub-object as a child of the parent unit frame:
<Button name="oUF_HeaderTargetTemplate" inherits="SecureUnitButtonTemplate" virtual="true">
<Frames>
<Button name="$parentTarget" inherits="SecureUnitButtonTemplate">
<Attributes>
<Attribute name="unitsuffix" type="string" value="target"/>
<Attribute name="useparent-unit" type="boolean" value="true"/>
</Attributes>
</Button>
</Frames>
</Button>
Separate unit template example:
<Button name="oUF_HeaderSeparateSubOjectsTemplate" inherits="SecureUnitButtonTemplate" virtual="true">
<Attributes>
<Attribute name="oUF-onlyProcessChildren" type="boolean" value="true"/>
</Attributes>
<Frames>
<Button name="$parentUnit" inherits="SecureUnitButtonTemplate">
<Attributes>
<Attribute name="useparent-unit" type="boolean" value="true"/>
</Attributes>
</Button>
<Button name="$parentPet" inherits="SecureUnitButtonTemplate">
<Attributes>
<Attribute name="unitsuffix" type="string" value="pet"/>
<Attribute name="useparent-unit" type="boolean" value="true"/>
</Attributes>
</Button>
<Button name="$parentTarget" inherits="SecureUnitButtonTemplate">
<Attributes>
<Attribute name="unitsuffix" type="string" value="target"/>
<Attribute name="useparent-unit" type="boolean" value="true"/>
</Attributes>
</Button>
</Frames>
</Button>
-->
</Ui>

599
Libraries/oUF/ouf.lua Normal file
View File

@@ -0,0 +1,599 @@
local parent, ns = ...
local global = GetAddOnMetadata(parent, 'X-oUF')
local _VERSION = GetAddOnMetadata(parent, 'version')
local oUF = ns.oUF
local Private = oUF.Private
local argcheck = Private.argcheck
local print = Private.print
local error = Private.error
local styles, style = {}
local callback, objects, headers = {}, {}, {}
local elements = {}
local activeElements = {}
-- updating of "invalid" units.
local enableTargetUpdate = function(object)
object.onUpdateFrequency = object.onUpdateFrequency or .5
object.__eventless = true
local total = 0
object:SetScript('OnUpdate', function(self, elapsed)
if(not self.unit) then
return
elseif(total > self.onUpdateFrequency) then
self:UpdateAllElements'OnUpdate'
total = 0
end
total = total + elapsed
end)
end
Private.enableTargetUpdate = enableTargetUpdate
local updateActiveUnit = function(self, event, unit)
-- Calculate units to work with
local realUnit, modUnit = SecureButton_GetUnit(self), SecureButton_GetModifiedUnit(self)
-- _GetUnit() doesn't rewrite playerpet -> pet like _GetModifiedUnit does.
if(realUnit == 'playerpet') then
realUnit = 'pet'
elseif(realUnit == 'playertarget') then
realUnit = 'target'
end
if(modUnit == 'pet' and realUnit ~= 'pet') then
modUnit = 'vehicle'
end
if(not UnitExists(modUnit)) then return end
-- Change the active unit and run a full update.
if Private.UpdateUnits(self, modUnit, realUnit) then
self:UpdateAllElements('RefreshUnit')
return true
end
end
local iterateChildren = function(...)
for l = 1, select("#", ...) do
local obj = select(l, ...)
if(type(obj) == 'table' and obj.isChild) then
updateActiveUnit(obj, "iterateChildren")
end
end
end
local OnAttributeChanged = function(self, name, value)
if(name == "unit" and value) then
if(self.hasChildren) then
iterateChildren(self:GetChildren())
end
if(not self:GetAttribute'oUF-onlyProcessChildren') then
updateActiveUnit(self, "OnAttributeChanged")
end
end
end
local frame_metatable = {
__index = CreateFrame"Button"
}
Private.frame_metatable = frame_metatable
for k, v in pairs{
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,
EnableElement = function(self, name, unit)
argcheck(name, 2, 'string')
argcheck(unit, 3, 'string', 'nil')
local element = elements[name]
if(not element or self:IsElementEnabled(name) 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,
DisableElement = function(self, name)
argcheck(name, 2, 'string')
local enabled = self:IsElementEnabled(name)
if(not enabled) then return end
local update = elements[name].update
for k, func in next, self.__elements do
if(func == update) then
table.remove(self.__elements, k)
break
end
end
activeElements[self][name] = nil
-- We need to run a new update cycle in-case we knocked ourself out of sync.
-- The main reason we do this is to make sure the full update is completed
-- if an element for some reason removes itself _during_ the update
-- progress.
self:UpdateAllElements('DisableElement', name)
return elements[name].disable(self)
end,
IsElementEnabled = function(self, name)
argcheck(name, 2, 'string')
local element = elements[name]
if(not element) then return end
local active = activeElements[self]
return active and active[name]
end,
Enable = RegisterUnitWatch,
Disable = function(self)
UnregisterUnitWatch(self)
self:Hide()
end,
UpdateAllElements = function(self, event)
local unit = self.unit
if(not UnitExists(unit)) then return end
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,
} do
frame_metatable.__index[k] = v
end
local OnShow = function(self)
if(not updateActiveUnit(self, 'OnShow')) then
return self:UpdateAllElements'OnShow'
end
end
local UpdatePet = function(self, event, unit)
local petUnit
if(unit == 'target') then
return
elseif(unit == 'player') then
petUnit = 'pet'
else
-- Convert raid26 -> raidpet26
petUnit = unit:gsub('^(%a+)(%d+)', '%1pet%2')
end
if(self.unit ~= petUnit) then return end
if(not updateActiveUnit(self, event)) then
return self:UpdateAllElements(event)
end
end
local initObject = function(unit, style, styleFunc, header, ...)
local num = select('#', ...)
for i=1, num do
local object = select(i, ...)
local objectUnit = object:GetAttribute'oUF-guessUnit' or unit
local suffix = object:GetAttribute'unitsuffix'
object.__elements = {}
object.style = style
object = setmetatable(object, frame_metatable)
-- Expose the frame through oUF.objects.
table.insert(objects, object)
-- We have to force update the frames when PEW fires.
object:RegisterEvent("PLAYER_ENTERING_WORLD", object.UpdateAllElements)
-- Handle the case where someone has modified the unitsuffix attribute in
-- oUF-initialConfigFunction.
if(suffix and not objectUnit:match(suffix)) then
objectUnit = objectUnit .. suffix
end
if(not (suffix == 'target' or objectUnit and objectUnit:match'target')) then
object:RegisterEvent('UNIT_ENTERED_VEHICLE', updateActiveUnit)
object:RegisterEvent('UNIT_EXITED_VEHICLE', updateActiveUnit)
-- We don't need to register UNIT_PET for the player unit. We register it
-- mainly because UNIT_EXITED_VEHICLE and UNIT_ENTERED_VEHICLE doesn't always
-- have pet information when they fire for party and raid units.
if(objectUnit ~= 'player') then
object:RegisterEvent('UNIT_PET', UpdatePet, true)
end
end
if(not header) then
-- No header means it's a frame created through :Spawn().
object:SetAttribute("*type1", "target")
object:SetAttribute('*type2', 'togglemenu')
-- No need to enable this for *target frames.
if(not (unit:match'target' or suffix == 'target')) then
object:SetAttribute('toggleForVehicle', true)
end
-- Other boss and target units are handled by :HandleUnit().
if(suffix == 'target') then
enableTargetUpdate(object)
else
oUF:HandleUnit(object)
end
else
-- Used to update frames when they change position in a group.
object:RegisterEvent('GROUP_ROSTER_UPDATE', object.UpdateAllElements)
if(num > 1) then
if(object:GetParent() == header) then
object.hasChildren = true
else
object.isChild = true
end
end
if(suffix == 'target') then
enableTargetUpdate(object)
end
end
Private.UpdateUnits(object, objectUnit)
styleFunc(object, objectUnit, not header)
object:SetScript("OnAttributeChanged", OnAttributeChanged)
object:SetScript("OnShow", OnShow)
activeElements[object] = {}
for element in next, elements do
object:EnableElement(element, objectUnit)
end
for _, func in next, callback do
func(object)
end
-- Make Clique happy
_G.ClickCastFrames = ClickCastFrames or {}
ClickCastFrames[object] = true
end
end
local walkObject = function(object, unit)
local parent = object:GetParent()
local style = parent.style or style
local styleFunc = styles[style]
local header = parent:GetAttribute'oUF-headerType' and parent
-- Check if we should leave the main frame blank.
if(object:GetAttribute'oUF-onlyProcessChildren') then
object.hasChildren = true
object:SetScript('OnAttributeChanged', OnAttributeChanged)
return initObject(unit, style, styleFunc, header, object:GetChildren())
end
return initObject(unit, style, styleFunc, header, object, object:GetChildren())
end
function oUF:RegisterInitCallback(func)
table.insert(callback, func)
end
function oUF:RegisterMetaFunction(name, func)
argcheck(name, 2, 'string')
argcheck(func, 3, 'function', 'table')
if(frame_metatable.__index[name]) then
return
end
frame_metatable.__index[name] = func
end
function oUF:RegisterStyle(name, func)
argcheck(name, 2, 'string')
argcheck(func, 3, 'function', 'table')
if(styles[name]) then return error("Style [%s] already registered.", name) end
if(not style) then style = name end
styles[name] = func
end
function oUF:SetActiveStyle(name)
argcheck(name, 2, 'string')
if(not styles[name]) then return error("Style [%s] does not exist.", name) end
style = name
end
do
local function iter(_, n)
-- don't expose the style functions.
return (next(styles, n))
end
function oUF.IterateStyles()
return iter, nil, nil
end
end
local getCondition
do
local conditions = {
raid40 = '[@raid26,exists] show;',
raid25 = '[@raid11,exists] show;',
raid10 = '[@raid6,exists] show;',
raid = '[group:raid] show;',
party = '[group:party,nogroup:raid] show;',
solo = '[@player,exists,nogroup:party] show;',
}
function getCondition(...)
local cond = ''
for i=1, select('#', ...) do
local short = select(i, ...)
local condition = conditions[short]
if(condition) then
cond = cond .. condition
end
end
return cond .. 'hide'
end
end
local generateName = function(unit, ...)
local name = 'oUF_' .. style:gsub('[^%a%d_]+', '')
local raid, party, groupFilter
for i=1, select('#', ...), 2 do
local att, val = select(i, ...)
if(att == 'showRaid') then
raid = true
elseif(att == 'showParty') then
party = true
elseif(att == 'groupFilter') then
groupFilter = val
end
end
local append
if(raid) then
if(groupFilter) then
if(type(groupFilter) == 'number' and groupFilter > 0) then
append = groupFilter
elseif(groupFilter:match'TANK') then
append = 'MainTank'
elseif(groupFilter:match'ASSIST') then
append = 'MainAssist'
else
local _, count = groupFilter:gsub(',', '')
if(count == 0) then
append = 'Raid' .. groupFilter
else
append = 'Raid'
end
end
else
append = 'Raid'
end
elseif(party) then
append = 'Party'
elseif(unit) then
append = unit:gsub("^%l", string.upper)
end
if(append) then
name = name .. append
end
-- Change oUF_LilyRaidRaid into oUF_LilyRaid
name = name:gsub('(%u%l+)([%u%l]*)%1', '%1')
-- Change oUF_LilyTargettarget into oUF_LilyTargetTarget
name = name:gsub('t(arget)', 'T%1')
local base = name
local i = 2
while(_G[name]) do
name = base .. i
i = i + 1
end
return name
end
do
local styleProxy = function(self, frame, ...)
return walkObject(_G[frame])
end
-- There has to be an easier way to do this.
local initialConfigFunction = [[
local header = self:GetParent()
local frames = table.new()
table.insert(frames, self)
self:GetChildList(frames)
for i=1, #frames do
local frame = frames[i]
local unit
-- There's no need to do anything on frames with onlyProcessChildren
if(not frame:GetAttribute'oUF-onlyProcessChildren') then
RegisterUnitWatch(frame)
-- Attempt to guess what the header is set to spawn.
local groupFilter = header:GetAttribute'groupFilter'
if(type(groupFilter) == 'string' and groupFilter:match('MAIN[AT]')) then
local role = groupFilter:match('MAIN([AT])')
if(role == 'T') then
unit = 'maintank'
else
unit = 'mainassist'
end
elseif(header:GetAttribute'showRaid') then
unit = 'raid'
elseif(header:GetAttribute'showParty') then
unit = 'party'
end
local headerType = header:GetAttribute'oUF-headerType'
local suffix = frame:GetAttribute'unitsuffix'
if(unit and suffix) then
if(headerType == 'pet' and suffix == 'target') then
unit = unit .. headerType .. suffix
else
unit = unit .. suffix
end
elseif(unit and headerType == 'pet') then
unit = unit .. headerType
end
frame:SetAttribute('*type1', 'target')
frame:SetAttribute('*type2', 'togglemenu')
frame:SetAttribute('toggleForVehicle', true)
frame:SetAttribute('oUF-guessUnit', unit)
end
local body = header:GetAttribute'oUF-initialConfigFunction'
if(body) then
frame:Run(body, unit)
end
end
header:CallMethod('styleFunction', self:GetName())
local clique = header:GetFrameRef("clickcast_header")
if(clique) then
clique:SetAttribute("clickcast_button", self)
clique:RunAttribute("clickcast_register")
end
]]
function oUF:SpawnHeader(overrideName, template, visibility, ...)
if(not style) then return error("Unable to create frame. No styles have been registered.") end
template = (template or 'SecureGroupHeaderTemplate')
local isPetHeader = template:match'PetHeader'
local name = overrideName or generateName(nil, ...)
local header = CreateFrame('Frame', name, oUF_PetBattleFrameHider, template)
header:SetAttribute("template", "oUF_ClickCastUnitTemplate")
for i=1, select("#", ...), 2 do
local att, val = select(i, ...)
if(not att) then break end
header:SetAttribute(att, val)
end
header.style = style
header.styleFunction = styleProxy
-- Expose the header through oUF.headers.
table.insert(headers, header)
-- We set it here so layouts can't directly override it.
header:SetAttribute('initialConfigFunction', initialConfigFunction)
header:SetAttribute('oUF-headerType', isPetHeader and 'pet' or 'group')
if(Clique) then
SecureHandlerSetFrameRef(header, 'clickcast_header', Clique.header)
end
if(header:GetAttribute'showParty') then
self:DisableBlizzard'party'
end
if(visibility) then
local type, list = string.split(' ', visibility, 2)
if(list and type == 'custom') then
RegisterAttributeDriver(header, 'state-visibility', list)
else
local condition = getCondition(string.split(',', visibility))
RegisterAttributeDriver(header, 'state-visibility', condition)
end
end
return header
end
end
function oUF:Spawn(unit, overrideName, overrideTemplate)
argcheck(unit, 2, 'string')
if(not style) then return error("Unable to create frame. No styles have been registered.") end
unit = unit:lower()
local name = overrideName or generateName(unit)
local object = CreateFrame("Button", name, oUF_PetBattleFrameHider, overrideTemplate or "SecureUnitButtonTemplate")
Private.UpdateUnits(object, unit)
self:DisableBlizzard(unit)
walkObject(object, unit)
object:SetAttribute("unit", unit)
RegisterUnitWatch(object)
return object
end
function oUF:AddElement(name, update, enable, disable)
argcheck(name, 2, 'string')
argcheck(update, 3, 'function', 'nil')
argcheck(enable, 4, 'function', 'nil')
argcheck(disable, 5, 'function', 'nil')
if(elements[name]) then return error('Element [%s] is already registered.', name) end
elements[name] = {
update = update;
enable = enable;
disable = disable;
}
end
oUF.version = _VERSION
oUF.objects = objects
oUF.headers = headers
if(global) then
if(parent ~= 'oUF' and global == 'oUF') then
error("%s is doing it wrong and setting its global to oUF.", parent)
else
_G[global] = oUF
end
end

22
Libraries/oUF/private.lua Normal file
View File

@@ -0,0 +1,22 @@
local parent, ns = ...
local Private = ns.oUF.Private
function Private.argcheck(value, num, ...)
assert(type(num) == 'number', "Bad argument #2 to 'argcheck' (number expected, got "..type(num)..")")
for i=1,select("#", ...) do
if type(value) == select(i, ...) then return end
end
local types = strjoin(", ", ...)
local name = string.match(debugstack(2,2,0), ": in function [`<](.-)['>]")
error(("Bad argument #%d to '%s' (%s expected, got %s"):format(num, name, types, type(value)), 3)
end
function Private.print(...)
print("|cff33ff99oUF:|r", ...)
end
function Private.error(...)
Private.print("|cffff0000Error:|r "..string.format(...))
end

23
Libraries/oUF/units.lua Normal file
View File

@@ -0,0 +1,23 @@
local parent, ns = ...
local oUF = ns.oUF
local Private = oUF.Private
local enableTargetUpdate = Private.enableTargetUpdate
-- Handles unit specific actions.
function oUF:HandleUnit(object, unit)
local unit = object.unit or unit
if(unit == 'target') then
object:RegisterEvent('PLAYER_TARGET_CHANGED', object.UpdateAllElements)
elseif(unit == 'mouseover') then
object:RegisterEvent('UPDATE_MOUSEOVER_UNIT', object.UpdateAllElements)
elseif(unit == 'focus') then
object:RegisterEvent('PLAYER_FOCUS_CHANGED', object.UpdateAllElements)
elseif(unit:match'(boss)%d?$' == 'boss') then
object:RegisterEvent('INSTANCE_ENCOUNTER_ENGAGE_UNIT', object.UpdateAllElements, true)
object:RegisterEvent('UNIT_TARGETABLE_CHANGED', object.UpdateAllElements)
elseif(unit:match'%w+target') then
enableTargetUpdate(object)
end
end

View File

@@ -0,0 +1,84 @@
#!/usr/bin/env lua
local tags = {}
do
for tag in io.popen('git tag'):lines() do
local split = tag:gmatch('[^.]+')
local release, api, bugfix = split(), split(), split() or 0
table.insert(
tags,
{
string = tag,
release = release,
api = api,
bugfix = bugfix,
}
)
end
table.sort(tags, function(a,b)
a = a.release * 1e4 + a.api * 100 + a.bugfix
b = b.release * 1e4 + b.api * 100 + b.bugfix
return a > b
end)
end
local generateLog = function(prevTag, currentTag)
local ti = table.insert
local sf = string.format
local out = {}
ti(out, sf('[b]Changes in %s:[/b]', currentTag))
ti(out, '[list]')
for line in io.popen(sf('git shortlog %s..%s', prevTag, currentTag)):lines() do
if(line:sub(1, 6) == ' ') then
local offset = line:match('() ', 7)
if(offset) then
line = line:sub(7, offset - 1)
else
line = line:sub(7)
end
ti(out, sf(' [*] %s', line))
elseif(#line == 0) then
ti(out, ' [/list]')
else
ti(out, sf(' [*][i]%s[/i]', line))
ti(out, ' [list=1]')
end
end
ti(out, '[/list]')
local p = assert(io.popen(sf('git diff --shortstat %s..%s', prevTag, currentTag)))
local stat = p:read'*a'
p:close()
ti(out, sf('[indent]%s[/indent]', stat:sub(2, -2)))
return table.concat(out, '\n')
end
local stop
local to = ...
if(to) then
for i=1, #tags do
if(tags[i].string == to) then
stop = i + 1
end
end
if(not stop) then stop = #tags end
else
stop = #tags
end
for i=2, stop do
local current, prev = tags[i -1], tags[i]
print(generateLog(prev.string, current.string))
end
-- vim: set filetype=lua :

254
Libraries/oUF/utils/docs Normal file
View File

@@ -0,0 +1,254 @@
#!/usr/bin/env lua
-- docs
-- oUF documentation generator
--
-- This is really just a quick and dirty way of generating documentation for
-- oUF[1]. The syntax is inspired by TomDoc[2], but a lot of the non-oUF and
-- non-Lua things aren't implemented.
--
-- Why implement my own documentation generator?
-- It was mainly done because oUF is kind-of special, but also because the
-- available alternatives aren't good enough or have issues I can't workaround.
--
-- Things that need fixing:
-- - No highlighting of Lua code.
-- - Doesn't validate that comments are documentation strings.
-- - Doesn't parse its own documentation header.
-- - Close to zero error handling.
--
-- Usage
--
-- docs [docs path] [file...]
--
-- Links
--
-- [1] https://github.com/haste/oUF
-- [2] http://tomdoc.org/
local out
local lines
local tisf = function(fmt, ...)
table.insert(out, fmt:format(...))
end
local trim = function(str)
return str:match('^()%s*$') and '' or str:match('^%s*(.*%S)')
end
local findNextEmpty = function(start, stop)
for i=start, stop or #lines do
if(lines[i] == '') then
return i
end
end
end
local findNextHeader = function(offest)
for i=offest, #lines do
local pre, header, post = unpack(lines, i, i + 2)
-- Single lines without punctuation are headers.
if(pre == '' and post == '' and not header:match'%.') then
return i + 1
end
end
end
local findNextArguent = function(start, stop, padding, pattern)
for i=start, stop do
local match, pad = lines[i]:match(pattern)
if(match and pad == padding) then
return i
end
end
end
local replaceMarkup = function(str)
return str
-- `in-line code` to <code>in-line code</code>
:gsub('`([^`]+)`', '<code>%1</code>')
-- [Link](http://example.com) to <a href="http://example.com">Link</a>
:gsub('%[([^%]]+)%]%(([^)]+)%)', '<a href="%2">%1</a>')
end
local handleArguments = function(start, stop, pattern)
tisf('<dl>')
repeat
-- Tear out the argument name and offset of where the description begins.
local def, padding, offset = lines[start]:match(pattern)
tisf('<dt>%s</dt>', def)
-- Insert the first line of the description.
tisf('<dd>')
tisf(lines[start]:sub(offset))
-- Find the next argument in the list or continue to the end of the
-- current section.
local nextarg = findNextArguent(start + 1, stop, padding, pattern)
nextarg = (nextarg or stop + 1) - 1
for i=start + 1, nextarg do
tisf(trim(lines[i]))
end
tisf('</dd>')
start = nextarg + 1
until start > stop
tisf('</dl>')
end
local handleExamples = function(start, stop)
-- An extra line gets added if we don't do this.
tisf('<pre><code>%s', lines[start]:sub(3))
for i=start + 1, stop do
tisf(lines[i]:sub(3))
end
tisf('</code></pre>')
end
local handleParagraph = function(start, stop)
tisf('<p>')
for i=start, stop do
tisf(trim(lines[i]))
end
tisf('</p>')
end
local handleSection = function(start, stop)
while(start) do
-- Find the next empty line or continue until the end of the section.
-- findNextEmpty() returns the position of the empty line, so we need to
-- subtract one from it.
local nextEmpty = findNextEmpty(start + 1, stop)
if(nextEmpty) then
nextEmpty = nextEmpty - 1
else
nextEmpty = stop
end
local line = lines[start]
if(not line) then
return
elseif(line:match('^%S+%s*%- ')) then
handleArguments(start, nextEmpty, '(%S+)%s*()%- ()')
elseif(line:sub(1, 2) == ' ') then
handleExamples(start, nextEmpty)
else
handleParagraph(start, nextEmpty)
end
start = findNextEmpty(nextEmpty, stop)
if(start) then start = start + 1 end
end
end
local generateDocs = function(str, level)
lines = {}
out = {}
for line in str:gmatch('([^\n]*)\n') do
table.insert(lines, line:gsub('\t*', ''):sub(2))
end
-- The first line is always the main header.
tisf('<h%d>%s</h%d>', level, lines[1], level)
-- Then comes the main description.
local offset = findNextHeader(1)
-- Continue until two lines before the header or to the end of the comment.
if(offset) then
offset = offset - 2
else
offset = #lines
end
local init = findNextEmpty(1) + 1
if(init > offset) then
init = 2
end
handleSection(init, offset)
while(true) do
offset = findNextHeader(offset)
if(not offset) then break end
-- Every section has a header.
tisf('<h%d>%s</h%d>', level + 1, lines[offset], level + 1)
-- Find out the size of the section.
local start = findNextEmpty(offset) + 1
if(not lines[start]) then
-- There's no section here, only a headline.
break
end
local stop
local nextHeader = findNextHeader(start)
if(nextHeader) then
stop = nextHeader - 2
else
local nextEmpty = findNextEmpty(start)
if(nextEmpty) then
stop = nextEmpty - 1
else
stop = #lines
end
end
handleSection(start, stop)
offset = stop + 1
end
return table.concat(out, '\n')
end
local handleFile = function(path)
local file = io.open(path, 'r')
local content = file:read'*a'
file:close()
local out = {}
local init = 1
repeat
local _, comStart, depth = content:find('%-%-%[(=*)%[ ', init)
if(comStart) then
local comEnd = content:find('%]' .. depth .. '%]', comStart)
local comment = content:sub(comStart, comEnd - 1)
-- Convert markup to html.
comment = replaceMarkup(comment)
-- The first comment uses h1 and h2, while the subsequent ones uses h3
-- and h4.
local level = init == 1 and 1 or 3
table.insert(out, generateDocs(comment, init == 1 and 1 or 3))
init = comEnd
end
until not comStart
return table.concat(out, '\n')
end
local destination = (...)
for i=2, select('#', ...) do
local file = select(i, ...)
local path, filename = file:match('(.+)/(.+)$')
if(path:sub(1,3) == '../') then
path = path:sub(4)
end
if(#path == 0) then path = nil end
filename = filename:gsub('lua', 'html')
local doc = handleFile(file)
if(doc) then
local dfPath = string.format('%s/%s', destination, path or '')
os.execute(string.format('mkdir -p %s', dfPath))
local docFile = io.open(string.format('%s/%s', dfPath, filename), 'w+')
docFile:write(doc)
docFile:close()
end
end