initial commit

This commit is contained in:
Gitea
2020-11-13 14:27:50 -05:00
commit e2015fd9bb
581 changed files with 101308 additions and 0 deletions

View File

@@ -0,0 +1,315 @@
--[[
# Element: Additional Power Bar
Handles the visibility and updating of a status bar that displays the player's additional power, such as Mana for
Balance druids.
## Widget
AdditionalPower - A `StatusBar` that is used to display the player's additional power.
## Sub-Widgets
.bg - A `Texture` used as a background. Inherits the widget's color.
## Notes
A default texture will be applied if the widget is a StatusBar and doesn't have a texture set.
## Options
.frequentUpdates - Indicates whether to use UNIT_POWER_FREQUENT instead UNIT_POWER_UPDATE to update the bar (boolean)
.displayPairs - Use to override display pairs. (table)
.smoothGradient - 9 color values to be used with the .colorSmooth option (table)
The following options are listed by priority. The first check that returns true decides the color of the bar.
.colorPower - Use `self.colors.power[token]` to color the bar based on the player's additional power type
(boolean)
.colorClass - Use `self.colors.class[class]` to color the bar based on unit class. `class` is defined by the
second return of [UnitClass](http://wowprogramming.com/docs/api/UnitClass.html) (boolean)
.colorSmooth - Use `self.colors.smooth` to color the bar with a smooth gradient based on the player's current
additional power percentage (boolean)
## Sub-Widget Options
.multiplier - Used to tint the background based on the widget's R, G and B values. Defaults to 1 (number)[0-1]
## 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
AdditionalPower.bg = Background
self.AdditionalPower = AdditionalPower
--]]
local _, ns = ...
local oUF = ns.oUF
local _, playerClass = UnitClass('player')
-- ElvUI block
local unpack = unpack
local CopyTable = CopyTable
local UnitIsUnit = UnitIsUnit
local UnitPlayerControlled = UnitPlayerControlled
local UnitIsTapDenied = UnitIsTapDenied
local UnitThreatSituation = UnitThreatSituation
local UnitIsPlayer = UnitIsPlayer
local UnitClass = UnitClass
local UnitSelectionType = UnitSelectionType
local UnitReaction = UnitReaction
local UnitPower = UnitPower
local UnitPowerMax = UnitPowerMax
local UnitIsConnected = UnitIsConnected
local UnitHasVehicleUI = UnitHasVehicleUI
local UnitPowerType = UnitPowerType
-- end block
-- sourced from FrameXML/AlternatePowerBar.lua
local ADDITIONAL_POWER_BAR_NAME = ADDITIONAL_POWER_BAR_NAME or 'MANA'
local ADDITIONAL_POWER_BAR_INDEX = ADDITIONAL_POWER_BAR_INDEX or 0
local ALT_MANA_BAR_PAIR_DISPLAY_INFO = ALT_MANA_BAR_PAIR_DISPLAY_INFO
local function UpdateColor(self, event, unit, powerType)
if(not (unit and UnitIsUnit(unit, 'player') and powerType == ADDITIONAL_POWER_BAR_NAME)) then return end
local element = self.AdditionalPower
local r, g, b, t
if(element.colorPower) then
t = self.colors.power[ADDITIONAL_POWER_BAR_INDEX]
elseif(element.colorClass) then
t = self.colors.class[playerClass]
elseif(element.colorSmooth) then
r, g, b = self:ColorGradient(element.cur or 1, element.max or 1, unpack(element.smoothGradient or self.colors.smooth))
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
--[[ Callback: AdditionalPower:PostUpdateColor(r, g, b)
Called after the element color has been updated.
* self - the AdditionalPower element
* r - the red component of the used color (number)[0-1]
* g - the green component of the used color (number)[0-1]
* b - the blue component of the used color (number)[0-1]
--]]
if(element.PostUpdateColor) then
element:PostUpdateColor(r, g, b)
end
end
local function Update(self, event, unit, powerType)
if(not (unit and UnitIsUnit(unit, 'player') and powerType == ADDITIONAL_POWER_BAR_NAME)) then return end
local element = self.AdditionalPower
--[[ Callback: AdditionalPower:PreUpdate(unit)
Called before the element has been updated.
* self - the AdditionalPower element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PreUpdate) then
element:PreUpdate(unit)
end
local cur, max = UnitPower('player', ADDITIONAL_POWER_BAR_INDEX), UnitPowerMax('player', ADDITIONAL_POWER_BAR_INDEX)
element:SetMinMaxValues(0, max)
element:SetValue(cur)
element.cur = cur
element.max = max
--[[ Callback: AdditionalPower:PostUpdate(cur, max)
Called after the element has been updated.
* self - the AdditionalPower element
* cur - the current value of the player's additional power (number)
* max - the maximum value of the player's additional power (number)
--]]
if(element.PostUpdate) then
return element:PostUpdate(cur, max, event) -- ElvUI adds event
end
end
local function Path(self, ...)
--[[ Override: AdditionalPower.Override(self, event, unit, ...)
Used to completely override the element's update process.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
* ... - the arguments accompanying the event
--]]
(self.AdditionalPower.Override or Update) (self, ...);
--[[ Override: AdditionalPower.UpdateColor(self, event, unit, ...)
Used to completely override the internal function for updating the widgets' colors.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
* ... - the arguments accompanying the event
--]]
(self.AdditionalPower.UpdateColor or UpdateColor) (self, ...)
end
local function ElementEnable(self)
local element = self.AdditionalPower
if(element.frequentUpdates) then
self:RegisterEvent('UNIT_POWER_FREQUENT', Path)
else
self:RegisterEvent('UNIT_POWER_UPDATE', Path)
end
self:RegisterEvent('UNIT_MAXPOWER', Path)
element:Show()
element.__isEnabled = true
Path(self, 'ElementEnable', 'player', ADDITIONAL_POWER_BAR_NAME)
end
local function ElementDisable(self)
local element = self.AdditionalPower
self:UnregisterEvent('UNIT_MAXPOWER', Path)
self:UnregisterEvent('UNIT_POWER_FREQUENT', Path)
self:UnregisterEvent('UNIT_POWER_UPDATE', Path)
element:Hide()
element.__isEnabled = false
Path(self, 'ElementDisable', 'player', ADDITIONAL_POWER_BAR_NAME)
end
local function Visibility(self, event, unit)
local element = self.AdditionalPower
local shouldEnable
if(not UnitHasVehicleUI('player')) then
if(UnitPowerMax(unit, ADDITIONAL_POWER_BAR_INDEX) ~= 0) then
if(element.displayPairs[playerClass]) then
local powerType = UnitPowerType(unit)
shouldEnable = element.displayPairs[playerClass][powerType]
end
end
end
local isEnabled = element.__isEnabled
if(shouldEnable and not isEnabled) then
ElementEnable(self)
--[[ Callback: AdditionalPower:PostVisibility(isVisible)
Called after the element's visibility has been changed.
* self - the AdditionalPower element
* isVisible - the current visibility state of the element (boolean)
--]]
if(element.PostVisibility) then
element:PostVisibility(true)
end
elseif(not shouldEnable and (isEnabled or isEnabled == nil)) then
ElementDisable(self)
if(element.PostVisibility) then
element:PostVisibility(false)
end
elseif(shouldEnable and isEnabled) then
Path(self, event, unit, ADDITIONAL_POWER_BAR_NAME)
end
end
local function VisibilityPath(self, ...)
--[[ Override: AdditionalPower.OverrideVisibility(self, event, unit)
Used to completely override the element's visibility update process.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
--]]
(self.AdditionalPower.OverrideVisibility or Visibility) (self, ...)
end
local function ForceUpdate(element)
VisibilityPath(element.__owner, 'ForceUpdate', element.__owner.unit)
end
--[[ Power:SetFrequentUpdates(state, isForced)
Used to toggle frequent updates.
* self - the Power element
* state - the desired state (boolean)
* isForced - forces the event update even if the state wasn't changed (boolean)
--]]
local function SetFrequentUpdates(element, state, isForced)
if(element.frequentUpdates ~= state or isForced) then
element.frequentUpdates = state
if(state) then
element.__owner:UnregisterEvent('UNIT_POWER_UPDATE', Path)
element.__owner:RegisterEvent('UNIT_POWER_FREQUENT', Path)
else
element.__owner:UnregisterEvent('UNIT_POWER_FREQUENT', Path)
element.__owner:RegisterEvent('UNIT_POWER_UPDATE', Path)
end
end
end
local function Enable(self, unit)
local element = self.AdditionalPower
if(element and UnitIsUnit(unit, 'player')) then
element.__owner = self
element.ForceUpdate = ForceUpdate
element.SetFrequentUpdates = SetFrequentUpdates
self:RegisterEvent('UNIT_DISPLAYPOWER', VisibilityPath)
if(not element.displayPairs) then
element.displayPairs = CopyTable(ALT_MANA_BAR_PAIR_DISPLAY_INFO)
end
if(element:IsObjectType('StatusBar') and not (element:GetStatusBarTexture() or element:GetStatusBarAtlas())) then
element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
return true
end
end
local function Disable(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,303 @@
--[[
# Element: Alternative Power Bar
Handles the visibility and updating of a status bar that displays encounter- or quest-related power information, such as
the number of hour glass charges during the Murozond encounter in the dungeon End Time.
## Widget
AlternativePower - A `StatusBar` used to represent the unit's alternative power.
## Notes
If mouse interactivity is enabled for the widget, `OnEnter` and/or `OnLeave` handlers will be set to display a tooltip.
A default texture will be applied if the widget is a StatusBar and doesn't have a texture set.
## Options
.smoothGradient - 9 color values to be used with the .colorSmooth option (table)
.considerSelectionInCombatHostile - Indicates whether selection should be considered hostile while the unit is in
combat with the player (boolean)
The following options are listed by priority. The first check that returns true decides the color of the bar.
.colorThreat - Use `self.colors.threat[threat]` to color the bar based on the unit's threat status. `threat` is
defined by the first return of [UnitThreatSituation](https://wow.gamepedia.com/API_UnitThreatSituation) (boolean)
.colorPower - Use `self.colors.power[token]` to color the bar based on the unit's alternative power type
(boolean)
.colorClass - Use `self.colors.class[class]` to color the bar based on unit class. `class` is defined by the
second return of [UnitClass](http://wowprogramming.com/docs/api/UnitClass.html) (boolean)
.colorClassNPC - Use `self.colors.class[class]` to color the bar if the unit is a NPC (boolean)
.colorSelection - Use `self.colors.selection[selection]` to color the bar based on the unit's selection color.
`selection` is defined by the return value of Private.unitSelectionType, a wrapper function
for [UnitSelectionType](https://wow.gamepedia.com/API_UnitSelectionType) (boolean)
.colorReaction - Use `self.colors.reaction[reaction]` to color the bar based on the player's reaction towards the
unit. `reaction` is defined by the return value of
[UnitReaction](http://wowprogramming.com/docs/api/UnitReaction.html) (boolean)
.colorSmooth - Use `self.colors.smooth` to color the bar with a smooth gradient based on the unit's current
alternative power percentage (boolean)
## Examples
-- Position and size
local AlternativePower = CreateFrame('StatusBar', nil, self)
AlternativePower:SetHeight(20)
AlternativePower:SetPoint('BOTTOM')
AlternativePower:SetPoint('LEFT')
AlternativePower:SetPoint('RIGHT')
-- Register with oUF
self.AlternativePower = AlternativePower
--]]
local _, ns = ...
local oUF = ns.oUF
local Private = oUF.Private
local unitSelectionType = Private.unitSelectionType
-- sourced from FrameXML/UnitPowerBarAlt.lua
local ALTERNATE_POWER_INDEX = Enum.PowerType.Alternate or 10
local ALTERNATE_POWER_NAME = 'ALTERNATE'
local GameTooltip = GameTooltip
local function updateTooltip(self)
if GameTooltip:IsForbidden() then return end
local name, tooltip = GetUnitPowerBarStringsByID(self.__barID)
GameTooltip:SetText(name or '', 1, 1, 1)
GameTooltip:AddLine(tooltip or '', nil, nil, nil, true)
GameTooltip:Show()
end
local function onEnter(self)
if GameTooltip:IsForbidden() or not self:IsVisible() then return end
GameTooltip:ClearAllPoints()
GameTooltip_SetDefaultAnchor(GameTooltip, self)
self:UpdateTooltip()
end
local function onLeave()
if GameTooltip:IsForbidden() then return end
GameTooltip:Hide()
end
local function UpdateColor(self, event, unit, powerType)
if(self.unit ~= unit or powerType ~= ALTERNATE_POWER_NAME) then return end
local element = self.AlternativePower
local r, g, b, t
if(element.colorThreat and not UnitPlayerControlled(unit) and UnitThreatSituation('player', unit)) then
t = self.colors.threat[UnitThreatSituation('player', unit)]
elseif(element.colorPower) then
t = self.colors.power[ALTERNATE_POWER_INDEX]
elseif(element.colorClass and UnitIsPlayer(unit))
or (element.colorClassNPC and not UnitIsPlayer(unit)) then
local _, class = UnitClass(unit)
t = self.colors.class[class]
elseif(element.colorSelection and unitSelectionType(unit, element.considerSelectionInCombatHostile)) then
t = self.colors.selection[unitSelectionType(unit, element.considerSelectionInCombatHostile)]
elseif(element.colorReaction and UnitReaction(unit, 'player')) then
t = self.colors.reaction[UnitReaction(unit, 'player')]
elseif(element.colorSmooth) then
local adjust = 0 - (element.min or 0)
r, g, b = self:ColorGradient((element.cur or 1) + adjust, (element.max or 1) + adjust, unpack(element.smoothGradient or self.colors.smooth))
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
--[[ Callback: AlternativePower:PostUpdateColor(unit, r, g, b)
Called after the element color has been updated.
* self - the AlternativePower element
* unit - the unit for which the update has been triggered (string)
* r - the red component of the used color (number)[0-1]
* g - the green component of the used color (number)[0-1]
* b - the blue component of the used color (number)[0-1]
--]]
if(element.PostUpdateColor) then
element:PostUpdateColor(unit, r, g, b)
end
end
local function Update(self, event, unit, powerType)
if(self.unit ~= unit or powerType ~= ALTERNATE_POWER_NAME) then return end
local element = self.AlternativePower
--[[ Callback: AlternativePower:PreUpdate()
Called before the element has been updated.
* self - the AlternativePower element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local min, max, cur = 0
local barInfo = element.__barInfo
if(barInfo) then
cur = UnitPower(unit, ALTERNATE_POWER_INDEX)
max = UnitPowerMax(unit, ALTERNATE_POWER_INDEX)
if barInfo.minPower then
min = barInfo.minPower
end
element:SetMinMaxValues(min, max)
element:SetValue(cur)
end
element.cur = cur
element.min = min
element.max = max
--[[ Callback: AlternativePower:PostUpdate(unit, cur, min, max)
Called after the element has been updated.
* self - the AlternativePower element
* unit - the unit for which the update has been triggered (string)
* cur - the current value of the unit's alternative power (number?)
* min - the minimum value of the unit's alternative power (number?)
* max - the maximum value of the unit's alternative power (number?)
--]]
if(element.PostUpdate) then
return element:PostUpdate(unit, cur, min, max)
end
end
local function Path(self, ...)
--[[ Override: AlternativePower.Override(self, event, unit, ...)
Used to completely override the element's update process.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
* ... - the arguments accompanying the event
--]]
(self.AlternativePower.Override or Update) (self, ...);
--[[ Override: AlternativePower.UpdateColor(self, event, unit, ...)
Used to completely override the internal function for updating the widgets' colors.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
* ... - the arguments accompanying the event
--]]
(self.AlternativePower.UpdateColor or UpdateColor) (self, ...)
end
local function Visibility(self, event, unit)
if(unit ~= self.unit) then return end
local element = self.AlternativePower
local barID = UnitPowerBarID(unit)
local barInfo = GetUnitPowerBarInfoByID(barID)
element.__barID = barID
element.__barInfo = barInfo
if(barInfo and (barInfo.showOnRaid and (UnitInParty(unit) or UnitInRaid(unit))
or not barInfo.hideFromOthers
or UnitIsUnit(unit, 'player')))
then
self:RegisterEvent('UNIT_POWER_UPDATE', Path)
self:RegisterEvent('UNIT_MAXPOWER', Path)
element:Show()
Path(self, event, unit, ALTERNATE_POWER_NAME)
else
self:UnregisterEvent('UNIT_POWER_UPDATE', Path)
self:UnregisterEvent('UNIT_MAXPOWER', Path)
element:Hide()
Path(self, event, unit, ALTERNATE_POWER_NAME)
end
end
local function VisibilityPath(self, ...)
--[[ Override: AlternativePower.OverrideVisibility(self, event, unit)
Used to completely override the element's visibility update process.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
--]]
return (self.AlternativePower.OverrideVisibility or Visibility) (self, ...)
end
local function ForceUpdate(element)
return VisibilityPath(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self, unit)
local element = self.AlternativePower
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_POWER_BAR_SHOW', VisibilityPath)
self:RegisterEvent('UNIT_POWER_BAR_HIDE', VisibilityPath)
if(element:IsObjectType('StatusBar') and not (element:GetStatusBarTexture() or element:GetStatusBarAtlas())) then
element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
if(element:IsMouseEnabled()) then
if(not element:GetScript('OnEnter')) then
element:SetScript('OnEnter', onEnter)
end
if(not element:GetScript('OnLeave')) then
element:SetScript('OnLeave', onLeave)
end
--[[ Override: AlternativePower:UpdateTooltip()
Called when the mouse is over the widget. Used to populate its tooltip.
* self - the AlternativePower element
--]]
if(not element.UpdateTooltip) then
element.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 function Disable(self, unit)
local element = self.AlternativePower
if(element) then
element:Hide()
self:UnregisterEvent('UNIT_POWER_BAR_SHOW', VisibilityPath)
self:UnregisterEvent('UNIT_POWER_BAR_HIDE', VisibilityPath)
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('AlternativePower', VisibilityPath, Enable, Disable)

View File

@@ -0,0 +1,99 @@
--[[
# Element: Assistant Indicator
Toggles the visibility of an indicator based on the unit's raid assistant status.
## Widget
AssistantIndicator - Any UI widget.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
-- Position and size
local AssistantIndicator = self:CreateTexture(nil, 'OVERLAY')
AssistantIndicator:SetSize(16, 16)
AssistantIndicator:SetPoint('TOP', self)
-- Register it with oUF
self.AssistantIndicator = AssistantIndicator
--]]
local _, ns = ...
local oUF = ns.oUF
local function Update(self, event)
local element = self.AssistantIndicator
local unit = self.unit
--[[ Callback: AssistantIndicator:PreUpdate()
Called before the element has been updated.
* self - the AssistantIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local isAssistant = UnitInRaid(unit) and UnitIsGroupAssistant(unit) and not UnitIsGroupLeader(unit)
if(isAssistant) then
element:Show()
else
element:Hide()
end
--[[ Callback: AssistantIndicator:PostUpdate(isAssistant)
Called after the element has been updated.
* self - the AssistantIndicator element
* isAssistant - indicates whether the unit is a raid assistant (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(isAssistant)
end
end
local function Path(self, ...)
--[[ Override: AssistantIndicator.Override(self, event, ...)
Used to completely override the element's update process.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event (string)
--]]
return (self.AssistantIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self)
local element = self.AssistantIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('GROUP_ROSTER_UPDATE', Path, true)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\GroupFrame\UI-Group-AssistantIcon]])
end
return true
end
end
local function Disable(self)
local element = self.AssistantIndicator
if(element) then
element:Hide()
self:UnregisterEvent('GROUP_ROSTER_UPDATE', Path)
end
end
oUF:AddElement('AssistantIndicator', Path, Enable, Disable)

View File

@@ -0,0 +1,655 @@
--[[
# Element: Auras
Handles creation and updating of aura icons.
## Widget
Auras - A Frame to hold `Button`s representing both buffs and debuffs.
Buffs - A Frame to hold `Button`s representing buffs.
Debuffs - A Frame to hold `Button`s representing debuffs.
## Notes
At least one of the above widgets must be present for the element to work.
## Options
.disableMouse - Disables mouse events (boolean)
.disableCooldown - Disables the cooldown spiral (boolean)
.size - Aura icon size. Defaults to 16 (number)
.onlyShowPlayer - Shows only auras created by player/vehicle (boolean)
.showStealableBuffs - Displays the stealable texture on buffs that can be stolen (boolean)
.spacing - Spacing between each icon. Defaults to 0 (number)
.['spacing-x'] - Horizontal spacing between each icon. Takes priority over `spacing` (number)
.['spacing-y'] - Vertical spacing between each icon. Takes priority over `spacing` (number)
.['growth-x'] - Horizontal growth direction. Defaults to 'RIGHT' (string)
.['growth-y'] - Vertical growth direction. Defaults to 'UP' (string)
.initialAnchor - Anchor point for the icons. Defaults to 'BOTTOMLEFT' (string)
.filter - Custom filter list for auras to display. Defaults to 'HELPFUL' for buffs and 'HARMFUL' for
debuffs (string)
.tooltipAnchor - Anchor point for the tooltip. Defaults to 'ANCHOR_BOTTOMRIGHT', however, if a frame has anchoring
restrictions it will be set to 'ANCHOR_CURSOR' (string)
## Options Auras
.numBuffs - The maximum number of buffs to display. Defaults to 32 (number)
.numDebuffs - The maximum number of debuffs to display. Defaults to 40 (number)
.numTotal - The maximum number of auras to display. Prioritizes buffs over debuffs. Defaults to the sum of
.numBuffs and .numDebuffs (number)
.gap - Controls the creation of an invisible icon between buffs and debuffs. Defaults to false (boolean)
.buffFilter - Custom filter list for buffs to display. Takes priority over `filter` (string)
.debuffFilter - Custom filter list for debuffs to display. Takes priority over `filter` (string)
## Options Buffs
.num - Number of buffs to display. Defaults to 32 (number)
## Options Debuffs
.num - Number of debuffs to display. Defaults to 40 (number)
## Attributes
button.caster - the unit who cast the aura (string)
button.filter - the filter list used to determine the visibility of the aura (string)
button.isDebuff - indicates if the button holds a debuff (boolean)
button.isPlayer - indicates if the aura caster is the player or their vehicle (boolean)
## Examples
-- Position and size
local Buffs = CreateFrame('Frame', nil, self)
Buffs:SetPoint('RIGHT', self, 'LEFT')
Buffs:SetSize(16 * 2, 16 * 16)
-- Register with oUF
self.Buffs = Buffs
--]]
local _, ns = ...
local oUF = ns.oUF
local VISIBLE = 1
local HIDDEN = 0
-- ElvUI changed block
local CREATED = 2
local pcall = pcall
local tinsert = tinsert
local CreateFrame = CreateFrame
local GetSpellInfo = GetSpellInfo
local UnitAura = UnitAura
local UnitIsUnit = UnitIsUnit
local GameTooltip = GameTooltip
local floor, min = math.floor, math.min
-- end block
-- ElvUI adds IsForbidden checks
local function UpdateTooltip(self)
if GameTooltip:IsForbidden() then return end
GameTooltip:SetUnitAura(self:GetParent().__owner.unit, self:GetID(), self.filter)
end
local function onEnter(self)
if GameTooltip:IsForbidden() or not self:IsVisible() then return end
GameTooltip:SetOwner(self, self:GetParent().tooltipAnchor)
self:UpdateTooltip()
end
local function onLeave()
if GameTooltip:IsForbidden() then return end
GameTooltip:Hide()
end
local function createAuraIcon(element, index)
local button = CreateFrame('Button', element:GetName() .. 'Button' .. index, element, "BackdropTemplate")
button:RegisterForClicks('RightButtonUp')
local cd = CreateFrame('Cooldown', '$parentCooldown', button, 'CooldownFrameTemplate')
cd:SetAllPoints()
local icon = button:CreateTexture(nil, 'BORDER')
icon:SetAllPoints()
local countFrame = CreateFrame('Frame', nil, button)
countFrame:SetAllPoints(button)
countFrame:SetFrameLevel(cd:GetFrameLevel() + 1)
local count = countFrame:CreateFontString(nil, 'OVERLAY', 'NumberFontNormal')
count:SetPoint('BOTTOMRIGHT', countFrame, 'BOTTOMRIGHT', -1, 0)
local overlay = button:CreateTexture(nil, 'OVERLAY')
overlay:SetTexture([[Interface\Buttons\UI-Debuff-Overlays]])
overlay:SetAllPoints()
overlay:SetTexCoord(.296875, .5703125, 0, .515625)
button.overlay = overlay
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
--[[ Callback: Auras:PostCreateIcon(button)
Called after a new aura button has been created.
* self - the widget holding the aura buttons
* button - the newly created aura button (Button)
--]]
if(element.PostCreateIcon) then element:PostCreateIcon(button) end
return button
end
local function customFilter(element, unit, button, name)
if((element.onlyShowPlayer and button.isPlayer) or (not element.onlyShowPlayer and name)) then
return true
end
end
local function updateIcon(element, unit, index, offset, filter, isDebuff, visible)
local name, texture, count, debuffType, duration, expiration, caster, isStealable,
nameplateShowSelf, spellID, canApply, isBossDebuff, casterIsPlayer, nameplateShowAll,
timeMod, effect1, effect2, effect3 = UnitAura(unit, index, filter)
-- ElvUI changed block
if element.forceShow or element.forceCreate then
spellID = 47540
name, _, texture = GetSpellInfo(spellID)
if element.forceShow then
count, debuffType, duration, expiration, caster, isStealable, nameplateShowSelf, isBossDebuff = 5, "Magic", 0, 60, "player", nil, nil, nil
end
end
if isStealable then
element.hasStealable = true -- for Style Filters
end
-- end Block
if(name) then
local position = visible + offset + 1
local button = element[position]
if(not button) then
--[[ Override: Auras:CreateIcon(position)
Used to create the aura button at a given position.
* self - the widget holding the aura buttons
* position - the position at which the aura button is to be created (number)
## Returns
* button - the button used to represent the aura (Button)
--]]
button = (element.CreateIcon or createAuraIcon) (element, position)
tinsert(element, button)
element.createdIcons = element.createdIcons + 1
end
button.caster = caster
button.filter = filter
button.isDebuff = isDebuff
button.isPlayer = caster == 'player' or caster == 'vehicle'
--[[ Override: Auras:CustomFilter(unit, button, ...)
Defines a custom filter that controls if the aura button should be shown.
* self - the widget holding the aura buttons
* unit - the unit on which the aura is cast (string)
* button - the button displaying the aura (Button)
* ... - the return values from [UnitAura](http://wowprogramming.com/docs/api/UnitAura.html)
## Returns
* show - indicates whether the aura button should be shown (boolean)
--]]
-- ElvUI changed block
local show = not element.forceCreate
if not (element.forceShow or element.forceCreate) then
show = (element.CustomFilter or customFilter) (element, unit, button, name, texture,
count, debuffType, duration, expiration, caster, isStealable, nameplateShowSelf, spellID,
canApply, isBossDebuff, casterIsPlayer, nameplateShowAll,timeMod, effect1, effect2, effect3)
end
-- end block
if(show) then
-- We might want to consider delaying the creation of an actual cooldown
-- object to this point, but I think that will just make things needlessly
-- complicated.
if(button.cd and not element.disableCooldown) then
if(duration and duration > 0) then
button.cd:SetCooldown(expiration - duration, duration)
button.cd:Show()
else
button.cd:Hide()
end
end
if(button.overlay) then
if((isDebuff and element.showDebuffType) or (not isDebuff and element.showBuffType) or element.showType) then
local color = element.__owner.colors.debuff[debuffType] or element.__owner.colors.debuff.none
button.overlay:SetVertexColor(color[1], color[2], color[3])
button.overlay:Show()
else
button.overlay:Hide()
end
end
if(button.stealable) then
if(not isDebuff and isStealable and element.showStealableBuffs and not UnitIsUnit('player', unit)) then
button.stealable:Show()
else
button.stealable:Hide()
end
end
if(button.icon) then button.icon:SetTexture(texture) end
if(button.count) then button.count:SetText(count > 1 and count) end
local size = element.size or 16
button:SetSize(size, size)
button:EnableMouse(not element.disableMouse)
button:SetID(index)
button:Show()
--[[ Callback: Auras:PostUpdateIcon(unit, button, index, position)
Called after the aura button has been updated.
* self - the widget holding the aura buttons
* unit - the unit on which the aura is cast (string)
* button - the updated aura button (Button)
* index - the index of the aura (number)
* position - the actual position of the aura button (number)
* duration - the aura duration in seconds (number?)
* expiration - the point in time when the aura will expire. Comparable to GetTime() (number)
* debuffType - the debuff type of the aura (string?)['Curse', 'Disease', 'Magic', 'Poison']
* isStealable - whether the aura can be stolen or purged (boolean)
--]]
if(element.PostUpdateIcon) then
element:PostUpdateIcon(unit, button, index, position, duration, expiration, debuffType, isStealable)
end
return VISIBLE
-- ElvUI changed block
elseif element.forceCreate then
local size = element.size or 16
button:SetSize(size, size)
button:Hide()
if element.PostUpdateIcon then
element:PostUpdateIcon(unit, button, index, position, duration, expiration, debuffType, isStealable)
end
return CREATED
-- end block
else
return HIDDEN
end
end
end
local function SetPosition(element, from, to)
local sizex = (element.size or 16) + (element['spacing-x'] or element.spacing or 0)
local sizey = (element.size or 16) + (element['spacing-y'] or element.spacing or 0)
local anchor = element.initialAnchor or 'BOTTOMLEFT'
local growthx = (element['growth-x'] == 'LEFT' and -1) or 1
local growthy = (element['growth-y'] == 'DOWN' and -1) or 1
local cols = floor(element:GetWidth() / sizex + 0.5)
for i = from, to do
local button = element[i]
-- Bail out if the to range is out of scope.
if(not button) then break end
local col = (i - 1) % cols
local row = floor((i - 1) / cols)
button:ClearAllPoints()
button:SetPoint(anchor, element, anchor, col * sizex * growthx, row * sizey * growthy)
end
end
local function filterIcons(element, unit, filter, limit, isDebuff, offset, dontHide)
if(not offset) then offset = 0 end
local index = 1
local visible = 0
local hidden = 0
local created = 0 -- ElvUI
element.hasStealable = nil -- ElvUI
while(visible < limit) do
local result = updateIcon(element, unit, index, offset, filter, isDebuff, visible)
if(not result) then
break
elseif(result == VISIBLE) then
visible = visible + 1
elseif(result == HIDDEN) then
hidden = hidden + 1
-- ElvUI changed block
elseif result == CREATED then
visible = visible + 1
created = created + 1
-- end block
end
index = index + 1
end
visible = visible - created -- ElvUI changed
if(not dontHide) then
for i = visible + offset + 1, #element do
element[i]:Hide()
end
end
return visible, hidden
end
local function UpdateAuras(self, event, unit)
if(self.unit ~= unit) then return end
local auras = self.Auras
if(auras) then
--[[ Callback: Auras:PreUpdate(unit)
Called before the element has been updated.
* self - the widget holding the aura buttons
* unit - the unit for which the update has been triggered (string)
--]]
if(auras.PreUpdate) then auras:PreUpdate(unit) end
local numBuffs = auras.numBuffs or 32
local numDebuffs = auras.numDebuffs or 40
local max = auras.numTotal or numBuffs + numDebuffs
local visibleBuffs = filterIcons(auras, unit, auras.buffFilter or auras.filter or 'HELPFUL', min(numBuffs, max), nil, 0, true)
local hasGap
if(visibleBuffs ~= 0 and auras.gap) then
hasGap = true
visibleBuffs = visibleBuffs + 1
local button = auras[visibleBuffs]
if(not button) then
button = (auras.CreateIcon or createAuraIcon) (auras, visibleBuffs)
tinsert(auras, button)
auras.createdIcons = auras.createdIcons + 1
end
-- Prevent the button from displaying anything.
if(button.cd) then button.cd:Hide() end
if(button.icon) then button.icon:SetTexture() end
if(button.overlay) then button.overlay:Hide() end
if(button.stealable) then button.stealable:Hide() end
if(button.count) then button.count:SetText() end
button:EnableMouse(false)
button:Show()
--[[ Callback: Auras:PostUpdateGapIcon(unit, gapButton, visibleBuffs)
Called after an invisible aura button has been created. Only used by Auras when the `gap` option is enabled.
* self - the widget holding the aura buttons
* unit - the unit that has the invisible aura button (string)
* gapButton - the invisible aura button (Button)
* visibleBuffs - the number of currently visible aura buttons (number)
--]]
if(auras.PostUpdateGapIcon) then
auras:PostUpdateGapIcon(unit, button, visibleBuffs)
end
end
local visibleDebuffs = filterIcons(auras, unit, auras.debuffFilter or auras.filter or 'HARMFUL', min(numDebuffs, max - visibleBuffs), true, visibleBuffs)
auras.visibleDebuffs = visibleDebuffs
if(hasGap and visibleDebuffs == 0) then
auras[visibleBuffs]:Hide()
visibleBuffs = visibleBuffs - 1
end
auras.visibleBuffs = visibleBuffs
auras.visibleAuras = auras.visibleBuffs + auras.visibleDebuffs
local fromRange, toRange
--[[ Callback: Auras:PreSetPosition(max)
Called before the aura buttons have been (re-)anchored.
* self - the widget holding the aura buttons
* max - the maximum possible number of aura buttons (number)
## Returns
* from - the offset of the first aura button to be (re-)anchored (number)
* to - the offset of the last aura button to be (re-)anchored (number)
--]]
if(auras.PreSetPosition) then
fromRange, toRange = auras:PreSetPosition(max)
end
if(fromRange or auras.createdIcons > auras.anchoredIcons) then
--[[ Override: Auras:SetPosition(from, to)
Used to (re-)anchor the aura buttons.
Called when new aura buttons have been created or if :PreSetPosition is defined.
* self - the widget that holds the aura buttons
* from - the offset of the first aura button to be (re-)anchored (number)
* to - the offset of the last aura button to be (re-)anchored (number)
--]]
(auras.SetPosition or SetPosition) (auras, fromRange or auras.anchoredIcons + 1, toRange or auras.createdIcons)
auras.anchoredIcons = auras.createdIcons
end
--[[ Callback: Auras:PostUpdate(unit)
Called after the element has been updated.
* self - the widget holding the aura buttons
* unit - the unit for which the update has been triggered (string)
--]]
if(auras.PostUpdate) then auras:PostUpdate(unit) end
end
local buffs = self.Buffs
if(buffs) then
if(buffs.PreUpdate) then buffs:PreUpdate(unit) end
local numBuffs = buffs.num or 32
local visibleBuffs = filterIcons(buffs, unit, buffs.filter or 'HELPFUL', numBuffs)
buffs.visibleBuffs = visibleBuffs
local fromRange, toRange
if(buffs.PreSetPosition) then
fromRange, toRange = buffs:PreSetPosition(numBuffs)
end
if(fromRange or buffs.createdIcons > buffs.anchoredIcons) then
(buffs.SetPosition or SetPosition) (buffs, fromRange or buffs.anchoredIcons + 1, toRange or buffs.createdIcons)
buffs.anchoredIcons = buffs.createdIcons
end
if(buffs.PostUpdate) then buffs:PostUpdate(unit) end
end
local debuffs = self.Debuffs
if(debuffs) then
if(debuffs.PreUpdate) then debuffs:PreUpdate(unit) end
local numDebuffs = debuffs.num or 40
local visibleDebuffs = filterIcons(debuffs, unit, debuffs.filter or 'HARMFUL', numDebuffs, true)
debuffs.visibleDebuffs = visibleDebuffs
local fromRange, toRange
if(debuffs.PreSetPosition) then
fromRange, toRange = debuffs:PreSetPosition(numDebuffs)
end
if(fromRange or debuffs.createdIcons > debuffs.anchoredIcons) then
(debuffs.SetPosition or SetPosition) (debuffs, fromRange or debuffs.anchoredIcons + 1, toRange or debuffs.createdIcons)
debuffs.anchoredIcons = debuffs.createdIcons
end
if(debuffs.PostUpdate) then debuffs:PostUpdate(unit) end
end
end
local function Update(self, event, unit)
if (self.isForced and event ~= 'ElvUI_UpdateAllElements') or (self.unit ~= unit) then return end -- ElvUI changed
-- Assume no event means someone wants to re-anchor things. This is usually done by UpdateAllElements and :ForceUpdate.
if not event or event == 'ForceUpdate' or event == 'ElvUI_UpdateAllElements' then -- ElvUI changed
if self.Buffs then self.Buffs.anchoredIcons = 0 end
if self.Debuffs then self.Debuffs.anchoredIcons = 0 end
if self.Auras then self.Auras.anchoredIcons = 0 end
end
UpdateAuras(self, event, unit)
end
local function ForceUpdate(element)
return Update(element.__owner, 'ForceUpdate', element.__owner.unit)
end
-- ElvUI changed block
local onUpdateElapsed, onUpdateWait = 0, 0.25
local function onUpdateAuras(self, elapsed)
if onUpdateElapsed > onUpdateWait then
Update(self.__owner, 'OnUpdate', self.__owner.unit)
onUpdateElapsed = 0
else
onUpdateElapsed = onUpdateElapsed + elapsed
end
end
local function SetAuraUpdateSpeed(self, state)
onUpdateWait = state
end
local function SetAuraUpdateMethod(self, state, force)
if self.effectiveAura ~= state or force then
self.effectiveAura = state
if state then
self.updateAurasFrame:SetScript('OnUpdate', onUpdateAuras)
self:UnregisterEvent('UNIT_AURA', UpdateAuras)
else
self.updateAurasFrame:SetScript('OnUpdate', nil)
self:RegisterEvent('UNIT_AURA', UpdateAuras)
end
end
end
-- end block
local function Enable(self)
-- ElvUI changed block
if not self.updateAurasFrame then
self.updateAurasFrame = CreateFrame('Frame', nil, self)
self.updateAurasFrame.__owner = self
end
-- end block
if(self.Buffs or self.Debuffs or self.Auras) then
-- ElvUI changed block
self.SetAuraUpdateSpeed = SetAuraUpdateSpeed
self.SetAuraUpdateMethod = SetAuraUpdateMethod
SetAuraUpdateMethod(self, self.effectiveAura, true)
-- end block
local buffs = self.Buffs
if(buffs) then
buffs.__owner = self
buffs.ForceUpdate = ForceUpdate
buffs.createdIcons = buffs.createdIcons or 0
buffs.anchoredIcons = 0
-- Avoid parenting GameTooltip to frames with anchoring restrictions,
-- otherwise it'll inherit said restrictions which will cause issues
-- with its further positioning, clamping, etc
if(not pcall(self.GetCenter, self)) then
buffs.tooltipAnchor = 'ANCHOR_CURSOR'
else
buffs.tooltipAnchor = buffs.tooltipAnchor or 'ANCHOR_BOTTOMRIGHT'
end
buffs:Show()
end
local debuffs = self.Debuffs
if(debuffs) then
debuffs.__owner = self
debuffs.ForceUpdate = ForceUpdate
debuffs.createdIcons = debuffs.createdIcons or 0
debuffs.anchoredIcons = 0
-- Avoid parenting GameTooltip to frames with anchoring restrictions,
-- otherwise it'll inherit said restrictions which will cause issues
-- with its further positioning, clamping, etc
if(not pcall(self.GetCenter, self)) then
debuffs.tooltipAnchor = 'ANCHOR_CURSOR'
else
debuffs.tooltipAnchor = debuffs.tooltipAnchor or 'ANCHOR_BOTTOMRIGHT'
end
debuffs:Show()
end
local auras = self.Auras
if(auras) then
auras.__owner = self
auras.ForceUpdate = ForceUpdate
auras.createdIcons = auras.createdIcons or 0
auras.anchoredIcons = 0
-- Avoid parenting GameTooltip to frames with anchoring restrictions,
-- otherwise it'll inherit said restrictions which will cause issues
-- with its further positioning, clamping, etc
if(not pcall(self.GetCenter, self)) then
auras.tooltipAnchor = 'ANCHOR_CURSOR'
else
auras.tooltipAnchor = auras.tooltipAnchor or 'ANCHOR_BOTTOMRIGHT'
end
auras:Show()
end
return true
end
end
local function Disable(self)
-- ElvUI changed block
if self.updateAurasFrame then
self.updateAurasFrame:SetScript('OnUpdate', nil)
end
-- end block
if(self.Buffs or self.Debuffs or self.Auras) then
self:UnregisterEvent('UNIT_AURA', UpdateAuras)
if(self.Buffs) then self.Buffs:Hide() end
if(self.Debuffs) then self.Debuffs:Hide() end
if(self.Auras) then self.Auras:Hide() end
end
end
oUF:AddElement('Auras', Update, Enable, Disable)

View File

@@ -0,0 +1,518 @@
--[[
# Element: Castbar
Handles the visibility and updating of spell castbars.
## Widget
Castbar - A `StatusBar` to represent spell cast/channel progress.
## Sub-Widgets
.Icon - A `Texture` to represent spell icon.
.SafeZone - A `Texture` to represent latency.
.Shield - A `Texture` to represent if it's possible to interrupt or spell steal.
.Spark - A `Texture` to represent the castbar's edge.
.Text - A `FontString` to represent spell name.
.Time - A `FontString` to represent spell duration.
## Notes
A default texture will be applied to the StatusBar and Texture widgets if they don't have a texture or a color set.
## Options
.timeToHold - Indicates for how many seconds the castbar should be visible after a _FAILED or _INTERRUPTED
event. Defaults to 0 (number)
.hideTradeSkills - Makes the element ignore casts related to crafting professions (boolean)
## Attributes
.castID - A globally unique identifier of the currently cast spell (string?)
.casting - Indicates whether the current spell is an ordinary cast (boolean)
.channeling - Indicates whether the current spell is a channeled cast (boolean)
.notInterruptible - Indicates whether the current spell is interruptible (boolean)
.spellID - The spell identifier of the currently cast/channeled spell (number)
## Examples
-- Position and size
local Castbar = CreateFrame('StatusBar', nil, self)
Castbar:SetSize(20, 20)
Castbar:SetPoint('TOP')
Castbar:SetPoint('LEFT')
Castbar:SetPoint('RIGHT')
-- Add a background
local Background = Castbar:CreateTexture(nil, 'BACKGROUND')
Background:SetAllPoints(Castbar)
Background:SetTexture(1, 1, 1, .5)
-- Add a spark
local Spark = Castbar:CreateTexture(nil, 'OVERLAY')
Spark:SetSize(20, 20)
Spark:SetBlendMode('ADD')
Spark:SetPoint('CENTER', Castbar:GetStatusBarTexture(), 'RIGHT', 0, 0)
-- 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
Castbar.bg = Background
Castbar.Spark = Spark
Castbar.Time = Time
Castbar.Text = Text
Castbar.Icon = Icon
Castbar.Shield = Shield
Castbar.SafeZone = SafeZone
self.Castbar = Castbar
--]]
local _, ns = ...
local oUF = ns.oUF
local FALLBACK_ICON = 136243 -- Interface\ICONS\Trade_Engineering
-- ElvUI block
local select = select
local FAILED = FAILED
local INTERRUPTED = INTERRUPTED
local GetNetStats = GetNetStats
local UnitCastingInfo = UnitCastingInfo
local UnitChannelInfo = UnitChannelInfo
local UnitIsUnit = UnitIsUnit
local GetTime = GetTime
-- GLOBALS: PetCastingBarFrame, PetCastingBarFrame_OnLoad
-- GLOBALS: CastingBarFrame, CastingBarFrame_OnLoad, CastingBarFrame_SetUnit
local tradeskillCurrent, tradeskillTotal, mergeTradeskill = 0, 0, false
local UNIT_SPELLCAST_SENT = function (self, event, unit, target, castID, spellID)
local castbar = self.Castbar
castbar.curTarget = (target and target ~= "") and target or nil
if castbar.isTradeSkill then
castbar.tradeSkillCastId = castID
end
end
-- end block
local function resetAttributes(self)
self.castID = nil
self.casting = nil
self.channeling = nil
self.notInterruptible = nil
self.spellID = nil
self.spellName = nil -- ElvUI
end
local function CastStart(self, real, unit, castGUID)
if self.unit ~= unit then return end
if real == 'UNIT_SPELLCAST_START' and not castGUID then return end
local element = self.Castbar
local name, _, texture, startTime, endTime, isTradeSkill, castID, notInterruptible, spellID = UnitCastingInfo(unit)
local event = 'UNIT_SPELLCAST_START'
if(not name) then
name, _, texture, startTime, endTime, isTradeSkill, notInterruptible, spellID = UnitChannelInfo(unit)
event = 'UNIT_SPELLCAST_CHANNEL_START'
end
if(not name or (isTradeSkill and element.hideTradeSkills)) then
resetAttributes(element)
element:Hide()
return
end
endTime = endTime / 1000
startTime = startTime / 1000
element.max = endTime - startTime
element.startTime = startTime
element.delay = 0
element.casting = event == 'UNIT_SPELLCAST_START'
element.channeling = event == 'UNIT_SPELLCAST_CHANNEL_START'
element.notInterruptible = notInterruptible
element.holdTime = 0
element.castID = castID
element.spellID = spellID
element.spellName = name -- ElvUI
if(element.casting) then
element.duration = GetTime() - startTime
else
element.duration = endTime - GetTime()
end
-- ElvUI block
if(mergeTradeskill and isTradeSkill and UnitIsUnit(unit, "player")) then
element.duration = element.duration + (element.max * tradeskillCurrent);
element.max = element.max * tradeskillTotal;
element.holdTime = 1
if(unit == "player") then
tradeskillCurrent = tradeskillCurrent + 1;
end
end
-- end block
element:SetMinMaxValues(0, element.max)
element:SetValue(element.duration)
if(element.Icon) then element.Icon:SetTexture(texture or FALLBACK_ICON) end
if(element.Shield) then element.Shield:SetShown(notInterruptible) end
if(element.Spark) then element.Spark:Show() end
if(element.Text) then element.Text:SetText(name) end
if(element.Time) then element.Time:SetText() end
local safeZone = element.SafeZone
if(safeZone) then
local isHoriz = element:GetOrientation() == 'HORIZONTAL'
safeZone:ClearAllPoints()
safeZone:SetPoint(isHoriz and 'TOP' or 'LEFT')
safeZone:SetPoint(isHoriz and 'BOTTOM' or 'RIGHT')
if(element.casting) then
safeZone:SetPoint(element:GetReverseFill() and (isHoriz and 'LEFT' or 'BOTTOM') or (isHoriz and 'RIGHT' or 'TOP'))
else
safeZone:SetPoint(element:GetReverseFill() and (isHoriz and 'RIGHT' or 'TOP') or (isHoriz and 'LEFT' or 'BOTTOM'))
end
local ratio = (select(4, GetNetStats()) / 1000) / element.max
if(ratio > 1) then
ratio = 1
end
safeZone[isHoriz and 'SetWidth' or 'SetHeight'](safeZone, element[isHoriz and 'GetWidth' or 'GetHeight'](element) * ratio)
end
--[[ Callback: Castbar:PostCastStart(unit)
Called after the element has been updated upon a spell cast or channel start.
* self - the Castbar widget
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PostCastStart) then
element:PostCastStart(unit)
end
element:Show()
end
local function CastUpdate(self, event, unit, castID, spellID)
if(self.unit ~= unit) then return end
local element = self.Castbar
if(not element:IsShown() or element.castID ~= castID or element.spellID ~= spellID) then
return
end
local name, startTime, endTime, _
if(event == 'UNIT_SPELLCAST_DELAYED') then
name, _, _, startTime, endTime = UnitCastingInfo(unit)
else
name, _, _, startTime, endTime = UnitChannelInfo(unit)
end
if(not name) then return end
endTime = endTime / 1000
startTime = startTime / 1000
local delta
if(element.casting) then
delta = startTime - element.startTime
element.duration = GetTime() - startTime
else
delta = element.startTime - startTime
element.duration = endTime - GetTime()
end
if(delta < 0) then
delta = 0
end
element.max = endTime - startTime
element.startTime = startTime
element.delay = element.delay + delta
element:SetMinMaxValues(0, element.max)
element:SetValue(element.duration)
--[[ Callback: Castbar:PostCastUpdate(unit)
Called after the element has been updated when a spell cast or channel has been updated.
* self - the Castbar widget
* unit - the unit that the update has been triggered (string)
--]]
if(element.PostCastUpdate) then
return element:PostCastUpdate(unit)
end
end
local function CastStop(self, event, unit, castID, spellID)
if(self.unit ~= unit) then return end
local element = self.Castbar
if(not element:IsShown() or element.castID ~= castID or element.spellID ~= spellID) then
return
end
-- ElvUI block
if mergeTradeskill and UnitIsUnit(unit, "player") then
if tradeskillCurrent == tradeskillTotal then
mergeTradeskill = false
end
end
-- end block
resetAttributes(element)
--[[ Callback: Castbar:PostCastStop(unit, spellID)
Called after the element has been updated when a spell cast or channel has stopped.
* self - the Castbar widget
* unit - the unit for which the update has been triggered (string)
* spellID - the ID of the spell (number)
--]]
if(element.PostCastStop) then
return element:PostCastStop(unit, spellID)
end
end
local function CastFail(self, event, unit, castID, spellID)
if(self.unit ~= unit) then return end
local element = self.Castbar
if(not element:IsShown() or element.castID ~= castID or element.spellID ~= spellID) then
return
end
if(element.Text) then
element.Text:SetText(event == 'UNIT_SPELLCAST_FAILED' and FAILED or INTERRUPTED)
end
if(element.Spark) then element.Spark:Hide() end
element.holdTime = element.timeToHold or 0
-- ElvUI block
if mergeTradeskill and UnitIsUnit(unit, "player") then
mergeTradeskill = false
element.tradeSkillCastId = nil
end
-- end block
resetAttributes(element)
element:SetValue(element.max)
--[[ Callback: Castbar:PostCastFail(unit, spellID)
Called after the element has been updated upon a failed or interrupted spell cast.
* self - the Castbar widget
* unit - the unit for which the update has been triggered (string)
* spellID - the ID of the spell (number)
--]]
if(element.PostCastFail) then
return element:PostCastFail(unit, spellID)
end
end
local function CastInterruptible(self, event, unit)
if(self.unit ~= unit) then return end
local element = self.Castbar
if(not element:IsShown()) then return end
element.notInterruptible = event == 'UNIT_SPELLCAST_NOT_INTERRUPTIBLE'
if(element.Shield) then element.Shield:SetShown(element.notInterruptible) end
--[[ Callback: Castbar:PostCastInterruptible(unit)
Called after the element has been updated when a spell cast has become interruptible or uninterruptible.
* self - the Castbar widget
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PostCastInterruptible) then
return element:PostCastInterruptible(unit)
end
end
local function onUpdate(self, elapsed)
if(self.casting or self.channeling) then
local isCasting = self.casting
if(isCasting) then
self.duration = self.duration + elapsed
if(self.duration >= self.max) then
local spellID = self.spellID
resetAttributes(self)
self:Hide()
if(self.PostCastStop) then
self:PostCastStop(self.__owner.unit, spellID)
end
return
end
else
self.duration = self.duration - elapsed
if(self.duration <= 0) then
local spellID = self.spellID
resetAttributes(self)
self:Hide()
if(self.PostCastStop) then
self:PostCastStop(self.__owner.unit, spellID)
end
return
end
end
if(self.Time) then
if(self.delay ~= 0) then
if(self.CustomDelayText) then
self:CustomDelayText(self.duration)
else
self.Time:SetFormattedText('%.1f|cffff0000%s%.2f|r', self.duration, isCasting and '+' or '-', self.delay)
end
else
if(self.CustomTimeText) then
self:CustomTimeText(self.duration)
else
self.Time:SetFormattedText('%.1f', self.duration)
end
end
end
self:SetValue(self.duration)
elseif(self.holdTime > 0) then
self.holdTime = self.holdTime - elapsed
else
resetAttributes(self)
self:Hide()
end
end
local function Update(...)
CastStart(...)
end
local function ForceUpdate(element)
return Update(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self, unit)
local element = self.Castbar
if(element and unit and not unit:match('%wtarget$')) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_SPELLCAST_START', CastStart)
self:RegisterEvent('UNIT_SPELLCAST_CHANNEL_START', CastStart)
self:RegisterEvent('UNIT_SPELLCAST_STOP', CastStop)
self:RegisterEvent('UNIT_SPELLCAST_CHANNEL_STOP', CastStop)
self:RegisterEvent('UNIT_SPELLCAST_DELAYED', CastUpdate)
self:RegisterEvent('UNIT_SPELLCAST_CHANNEL_UPDATE', CastUpdate)
self:RegisterEvent('UNIT_SPELLCAST_FAILED', CastFail)
self:RegisterEvent('UNIT_SPELLCAST_INTERRUPTED', CastFail)
self:RegisterEvent('UNIT_SPELLCAST_INTERRUPTIBLE', CastInterruptible)
self:RegisterEvent('UNIT_SPELLCAST_NOT_INTERRUPTIBLE', CastInterruptible)
-- ElvUI block
self:RegisterEvent('UNIT_SPELLCAST_SENT', UNIT_SPELLCAST_SENT, true)
-- end block
element.holdTime = 0
element:SetScript('OnUpdate', element.OnUpdate or onUpdate)
if(self.unit == 'player' and not (self.hasChildren or self.isChild or self.isNamePlate)) then
CastingBarFrame_SetUnit(CastingBarFrame, nil)
CastingBarFrame_SetUnit(PetCastingBarFrame, nil)
end
if(element:IsObjectType('StatusBar') and not element:GetStatusBarTexture()) then
element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
local spark = element.Spark
if(spark and spark:IsObjectType('Texture') and not spark:GetTexture()) then
spark:SetTexture([[Interface\CastingBar\UI-CastingBar-Spark]])
end
local shield = element.Shield
if(shield and shield:IsObjectType('Texture') and not shield:GetTexture()) then
shield:SetTexture([[Interface\CastingBar\UI-CastingBar-Small-Shield]])
end
local safeZone = element.SafeZone
if(safeZone and safeZone:IsObjectType('Texture') and not safeZone:GetTexture()) then
safeZone:SetColorTexture(1, 0, 0)
end
element:Hide()
return true
end
end
local function Disable(self)
local element = self.Castbar
if(element) then
element:Hide()
self:UnregisterEvent('UNIT_SPELLCAST_START', CastStart)
self:UnregisterEvent('UNIT_SPELLCAST_CHANNEL_START', CastStart)
self:UnregisterEvent('UNIT_SPELLCAST_DELAYED', CastUpdate)
self:UnregisterEvent('UNIT_SPELLCAST_CHANNEL_UPDATE', CastUpdate)
self:UnregisterEvent('UNIT_SPELLCAST_STOP', CastStop)
self:UnregisterEvent('UNIT_SPELLCAST_CHANNEL_STOP', CastStop)
self:UnregisterEvent('UNIT_SPELLCAST_FAILED', CastFail)
self:UnregisterEvent('UNIT_SPELLCAST_INTERRUPTED', CastFail)
self:UnregisterEvent('UNIT_SPELLCAST_INTERRUPTIBLE', CastInterruptible)
self:UnregisterEvent('UNIT_SPELLCAST_NOT_INTERRUPTIBLE', CastInterruptible)
element:SetScript('OnUpdate', nil)
if(self.unit == 'player' and not (self.hasChildren or self.isChild or self.isNamePlate)) then
CastingBarFrame_OnLoad(CastingBarFrame, 'player', true, false)
PetCastingBarFrame_OnLoad(PetCastingBarFrame)
end
end
end
-- ElvUI block
hooksecurefunc(C_TradeSkillUI, "CraftRecipe", function(_, num)
tradeskillCurrent = 0
tradeskillTotal = num or 1
mergeTradeskill = true
end)
-- end block
oUF:AddElement('Castbar', Update, Enable, Disable)

View File

@@ -0,0 +1,357 @@
--[[
# Element: ClassPower
Handles the visibility and updating of the player's class resources (like Chi Orbs or Holy Power) and combo points.
## Widget
ClassPower - An `table` consisting of as many StatusBars as the theoretical maximum return of [UnitPowerMax](http://wowprogramming.com/docs/api/UnitPowerMax.html).
## Sub-Widgets
.bg - A `Texture` used as a background. It will inherit the color of the main StatusBar.
## Sub-Widget Options
.multiplier - Used to tint the background based on the widget's R, G and B values. Defaults to 1 (number)[0-1]
## Notes
A default texture will be applied if the sub-widgets are StatusBars and don't have a texture set.
If the sub-widgets are StatusBars, their minimum and maximum values will be set to 0 and 1 respectively.
Supported class powers:
- All - Combo Points
- Mage - Arcane Charges
- Monk - Chi Orbs
- Paladin - Holy Power
- Warlock - Soul Shards
## Examples
local ClassPower = {}
for index = 1, 10 do
local Bar = CreateFrame('StatusBar', nil, self)
-- Position and size.
Bar:SetSize(16, 16)
Bar:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', (index - 1) * Bar:GetWidth(), 0)
ClassPower[index] = Bar
end
-- Register with oUF
self.ClassPower = ClassPower
--]]
local _, ns = ...
local oUF = ns.oUF
local _, PlayerClass = UnitClass('player')
-- sourced from FrameXML/Constants.lua
local SPEC_MAGE_ARCANE = SPEC_MAGE_ARCANE or 1
local SPEC_MONK_WINDWALKER = SPEC_MONK_WINDWALKER or 3
local SPEC_PALADIN_RETRIBUTION = SPEC_PALADIN_RETRIBUTION or 3
local SPEC_WARLOCK_DESTRUCTION = SPEC_WARLOCK_DESTRUCTION or 3
local SPELL_POWER_ENERGY = Enum.PowerType.Energy or 3
local SPELL_POWER_COMBO_POINTS = Enum.PowerType.ComboPoints or 4
local SPELL_POWER_SOUL_SHARDS = Enum.PowerType.SoulShards or 7
local SPELL_POWER_HOLY_POWER = Enum.PowerType.HolyPower or 9
local SPELL_POWER_CHI = Enum.PowerType.Chi or 12
local SPELL_POWER_ARCANE_CHARGES = Enum.PowerType.ArcaneCharges or 16
-- Holds the class specific stuff.
local ClassPowerID, ClassPowerType
local ClassPowerEnable, ClassPowerDisable
local RequireSpec, RequirePower, RequireSpell
local function UpdateColor(element, powerType)
local color = element.__owner.colors.power[powerType]
local r, g, b = color[1], color[2], color[3]
for i = 1, #element do
local bar = element[i]
bar:SetStatusBarColor(r, g, b)
local bg = bar.bg
if(bg) then
local mu = bg.multiplier or 1
bg:SetVertexColor(r * mu, g * mu, b * mu)
end
end
--[[ Callback: ClassPower:PostUpdateColor(r, g, b)
Called after the element color has been updated.
* self - the ClassPower element
* r - the red component of the used color (number)[0-1]
* g - the green component of the used color (number)[0-1]
* b - the blue component of the used color (number)[0-1]
--]]
if(element.PostUpdateColor) then
element:PostUpdateColor(r, g, b)
end
end
local function Update(self, event, unit, powerType)
if(not (unit and (UnitIsUnit(unit, 'player') and (not powerType or powerType == ClassPowerType)
or unit == 'vehicle' and powerType == 'COMBO_POINTS'))) then
return
end
local element = self.ClassPower
--[[ Callback: ClassPower:PreUpdate(event)
Called before the element has been updated.
* self - the ClassPower element
]]
if(element.PreUpdate) then
element:PreUpdate()
end
local cur, max, mod, oldMax, chargedIndex
if(event ~= 'ClassPowerDisable') then
local powerID = unit == 'vehicle' and SPELL_POWER_COMBO_POINTS or ClassPowerID
cur = UnitPower(unit, powerID, true)
max = UnitPowerMax(unit, powerID)
mod = UnitPowerDisplayMod(powerID)
-- mod should never be 0, but according to Blizz code it can actually happen
cur = mod == 0 and 0 or cur / mod
-- BUG: Destruction is supposed to show partial soulshards, but Affliction and Demonology should only show full ones
if(ClassPowerType == 'SOUL_SHARDS' and GetSpecialization() ~= SPEC_WARLOCK_DESTRUCTION) then
cur = cur - cur % 1
end
if(PlayerClass == 'ROGUE') then
local chargedPoints = GetUnitChargedPowerPoints(unit)
-- according to Blizzard there will only be one
chargedIndex = chargedPoints and chargedPoints[1]
end
local numActive = cur + 0.9
for i = 1, max do
if(i > numActive) then
element[i]:Hide()
element[i]:SetValue(0)
else
element[i]:Show()
element[i]:SetValue(cur - i + 1)
end
end
oldMax = element.__max
if(max ~= oldMax) then
if(max < oldMax) then
for i = max + 1, oldMax do
element[i]:Hide()
element[i]:SetValue(0)
end
end
element.__max = max
end
end
--[[ Callback: ClassPower:PostUpdate(cur, max, hasMaxChanged, powerType)
Called after the element has been updated.
* self - the ClassPower element
* cur - the current amount of power (number)
* max - the maximum amount of power (number)
* hasMaxChanged - indicates whether the maximum amount has changed since the last update (boolean)
* powerType - the active power type (string)
* chargedIndex - the index of the currently charged power point (number?)
--]]
if(element.PostUpdate) then
return element:PostUpdate(cur, max, oldMax ~= max, powerType, chargedIndex)
end
end
local function Path(self, ...)
--[[ Override: ClassPower.Override(self, event, unit, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
* ... - the arguments accompanying the event
--]]
return (self.ClassPower.Override or Update) (self, ...)
end
local function Visibility(self, event, unit)
local element = self.ClassPower
local shouldEnable
if(UnitHasVehicleUI('player')) then
shouldEnable = PlayerVehicleHasComboPoints()
unit = 'vehicle'
elseif(ClassPowerID) then
if(not RequireSpec or RequireSpec == GetSpecialization()) then
-- use 'player' instead of unit because 'SPELLS_CHANGED' is a unitless event
if(not RequirePower or RequirePower == UnitPowerType('player')) then
if(not RequireSpell or IsPlayerSpell(RequireSpell)) then
self:UnregisterEvent('SPELLS_CHANGED', Visibility)
shouldEnable = true
unit = 'player'
else
self:RegisterEvent('SPELLS_CHANGED', Visibility, true)
end
end
end
end
local isEnabled = element.__isEnabled
local powerType = unit == 'vehicle' and 'COMBO_POINTS' or ClassPowerType
if(shouldEnable) then
--[[ Override: ClassPower:UpdateColor(powerType)
Used to completely override the internal function for updating the widgets' colors.
* self - the ClassPower element
* powerType - the active power type (string)
--]]
(element.UpdateColor or UpdateColor) (element, powerType)
end
if(shouldEnable and not isEnabled) then
ClassPowerEnable(self)
--[[ Callback: ClassPower:PostVisibility(isVisible)
Called after the element's visibility has been changed.
* self - the ClassPower element
* isVisible - the current visibility state of the element (boolean)
--]]
if(element.PostVisibility) then
element:PostVisibility(true)
end
elseif(not shouldEnable and (isEnabled or isEnabled == nil)) then
ClassPowerDisable(self)
if(element.PostVisibility) then
element:PostVisibility(false)
end
elseif(shouldEnable and isEnabled) then
Path(self, event, unit, powerType)
end
end
local function VisibilityPath(self, ...)
--[[ Override: ClassPower.OverrideVisibility(self, event, unit)
Used to completely override the internal visibility function.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
--]]
return (self.ClassPower.OverrideVisibility or Visibility) (self, ...)
end
local function ForceUpdate(element)
return VisibilityPath(element.__owner, 'ForceUpdate', element.__owner.unit)
end
do
function ClassPowerEnable(self)
self:RegisterEvent('UNIT_POWER_FREQUENT', Path)
self:RegisterEvent('UNIT_MAXPOWER', Path)
if(PlayerClass == 'ROGUE') then
self:RegisterEvent('UNIT_POWER_POINT_CHARGE', Path)
end
self.ClassPower.__isEnabled = true
if(UnitHasVehicleUI('player')) then
Path(self, 'ClassPowerEnable', 'vehicle', 'COMBO_POINTS')
else
Path(self, 'ClassPowerEnable', 'player', ClassPowerType)
end
end
function ClassPowerDisable(self)
self:UnregisterEvent('UNIT_POWER_FREQUENT', Path)
self:UnregisterEvent('UNIT_MAXPOWER', Path)
self:UnregisterEvent('UNIT_POWER_POINT_CHARGE', Path)
local element = self.ClassPower
for i = 1, #element do
element[i]:Hide()
end
element.__isEnabled = false
Path(self, 'ClassPowerDisable', 'player', ClassPowerType)
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'
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
RequirePower = SPELL_POWER_ENERGY
RequireSpell = 5221 -- Shred
end
elseif(PlayerClass == 'MAGE') then
ClassPowerID = SPELL_POWER_ARCANE_CHARGES
ClassPowerType = 'ARCANE_CHARGES'
RequireSpec = SPEC_MAGE_ARCANE
end
end
local function Enable(self, unit)
local element = self.ClassPower
if(element and UnitIsUnit(unit, 'player')) then
element.__owner = self
element.__max = #element
element.ForceUpdate = ForceUpdate
if(RequireSpec or RequireSpell) then
self:RegisterEvent('PLAYER_TALENT_UPDATE', VisibilityPath, true)
end
if(RequirePower) then
self:RegisterEvent('UNIT_DISPLAYPOWER', VisibilityPath)
end
element.ClassPowerEnable = ClassPowerEnable
element.ClassPowerDisable = ClassPowerDisable
for i = 1, #element do
local bar = element[i]
if(bar:IsObjectType('StatusBar')) then
if(not (bar:GetStatusBarTexture() or bar:GetStatusBarAtlas())) then
bar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
bar:SetMinMaxValues(0, 1)
end
end
return true
end
end
local function Disable(self)
if(self.ClassPower) then
ClassPowerDisable(self)
self:UnregisterEvent('PLAYER_TALENT_UPDATE', VisibilityPath)
self:UnregisterEvent('UNIT_DISPLAYPOWER', VisibilityPath)
self:UnregisterEvent('SPELLS_CHANGED', Visibility)
end
end
oUF:AddElement('ClassPower', VisibilityPath, Enable, Disable)

View File

@@ -0,0 +1,105 @@
--[[
# Element: Combat Indicator
Toggles the visibility of an indicator based on the player's combat status.
## Widget
CombatIndicator - Any UI widget.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
-- Position and size
local CombatIndicator = self:CreateTexture(nil, 'OVERLAY')
CombatIndicator:SetSize(16, 16)
CombatIndicator:SetPoint('TOP', self)
-- Register it with oUF
self.CombatIndicator = CombatIndicator
--]]
local _, ns = ...
local oUF = ns.oUF
local function Update(self, event, unit)
if not unit or self.unit ~= unit then return end
local element = self.CombatIndicator
--[[ Callback: CombatIndicator:PreUpdate()
Called before the element has been updated.
* self - the CombatIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local inCombat = UnitAffectingCombat(unit)
if(inCombat) then
element:Show()
else
element:Hide()
end
--[[ Callback: CombatIndicator:PostUpdate(inCombat)
Called after the element has been updated.
* self - the CombatIndicator element
* inCombat - indicates if the player is affecting combat (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(inCombat)
end
end
local function Path(self, ...)
--[[ Override: CombatIndicator.Override(self, event)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
--]]
return (self.CombatIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self, unit)
local element = self.CombatIndicator
if element then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_COMBAT', Path)
self:RegisterEvent('UNIT_FLAGS', Path)
self:RegisterEvent('PLAYER_REGEN_DISABLED', Path, true)
self:RegisterEvent('PLAYER_REGEN_ENABLED', Path, true)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\CharacterFrame\UI-StateIcon]])
element:SetTexCoord(.5, 1, 0, .49)
end
return true
end
end
local function Disable(self)
local element = self.CombatIndicator
if(element) then
element:Hide()
self:UnregisterEvent('UNIT_COMBAT', Path)
self:UnregisterEvent('UNIT_FLAGS', Path)
self:UnregisterEvent('PLAYER_REGEN_DISABLED', Path)
self:UnregisterEvent('PLAYER_REGEN_ENABLED', Path)
end
end
oUF:AddElement('CombatIndicator', Path, Enable, Disable)

View File

@@ -0,0 +1,104 @@
--[[
# Element: Group Role Indicator
Toggles the visibility of an indicator based on the unit's current group role (tank, healer or damager).
## Widget
GroupRoleIndicator - A `Texture` used to display the group role icon.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
-- Position and size
local GroupRoleIndicator = self:CreateTexture(nil, 'OVERLAY')
GroupRoleIndicator:SetSize(16, 16)
GroupRoleIndicator:SetPoint('LEFT', self)
-- Register it with oUF
self.GroupRoleIndicator = GroupRoleIndicator
--]]
local _, ns = ...
local oUF = ns.oUF
local function Update(self, event)
local element = self.GroupRoleIndicator
--[[ Callback: GroupRoleIndicator:PreUpdate()
Called before the element has been updated.
* self - the GroupRoleIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local role = UnitGroupRolesAssigned(self.unit)
if(role == 'TANK' or role == 'HEALER' or role == 'DAMAGER') then
element:SetTexCoord(GetTexCoordsForRoleSmallCircle(role))
element:Show()
else
element:Hide()
end
--[[ Callback: GroupRoleIndicator:PostUpdate(role)
Called after the element has been updated.
* self - the GroupRoleIndicator element
* role - the role as returned by [UnitGroupRolesAssigned](http://wowprogramming.com/docs/api/UnitGroupRolesAssigned.html)
--]]
if(element.PostUpdate) then
return element:PostUpdate(role)
end
end
local function Path(self, ...)
--[[ Override: GroupRoleIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.GroupRoleIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self)
local element = self.GroupRoleIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
if(self.unit == 'player') then
self:RegisterEvent('PLAYER_ROLES_ASSIGNED', Path, true)
else
self:RegisterEvent('GROUP_ROSTER_UPDATE', Path, true)
end
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\LFGFrame\UI-LFG-ICON-PORTRAITROLES]])
end
return true
end
end
local function Disable(self)
local element = self.GroupRoleIndicator
if(element) then
element:Hide()
self:UnregisterEvent('PLAYER_ROLES_ASSIGNED', Path)
self:UnregisterEvent('GROUP_ROSTER_UPDATE', Path, true)
end
end
oUF:AddElement('GroupRoleIndicator', Path, Enable, Disable)

View File

@@ -0,0 +1,379 @@
--[[
# Element: Health Bar
Handles the updating of a status bar that displays the unit's health.
## Widget
Health - A `StatusBar` used to represent the unit's health.
## Sub-Widgets
.bg - A `Texture` used as a background. It will inherit the color of the main StatusBar.
## Notes
A default texture will be applied if the widget is a StatusBar and doesn't have a texture set.
## Options
.smoothGradient - 9 color values to be used with the .colorSmooth option (table)
.considerSelectionInCombatHostile - Indicates whether selection should be considered hostile while the unit is in
combat with the player (boolean)
The following options are listed by priority. The first check that returns true decides the color of the bar.
.colorDisconnected - Use `self.colors.disconnected` to color the bar if the unit is offline (boolean)
.colorTapping - Use `self.colors.tapping` to color the bar if the unit isn't tapped by the player (boolean)
.colorThreat - Use `self.colors.threat[threat]` to color the bar based on the unit's threat status. `threat` is
defined by the first return of [UnitThreatSituation](https://wow.gamepedia.com/API_UnitThreatSituation) (boolean)
.colorClass - Use `self.colors.class[class]` to color the bar based on unit class. `class` is defined by the
second return of [UnitClass](http://wowprogramming.com/docs/api/UnitClass.html) (boolean)
.colorClassNPC - Use `self.colors.class[class]` to color the bar if the unit is a NPC (boolean)
.colorClassPet - Use `self.colors.class[class]` to color the bar if the unit is player controlled, but not a player
(boolean)
.colorSelection - Use `self.colors.selection[selection]` to color the bar based on the unit's selection color.
`selection` is defined by the return value of Private.unitSelectionType, a wrapper function
for [UnitSelectionType](https://wow.gamepedia.com/API_UnitSelectionType) (boolean)
.colorReaction - Use `self.colors.reaction[reaction]` to color the bar based on the player's reaction towards the
unit. `reaction` is defined by the return value of
[UnitReaction](http://wowprogramming.com/docs/api/UnitReaction.html) (boolean)
.colorSmooth - Use `smoothGradient` if present or `self.colors.smooth` to color the bar with a smooth gradient
based on the player's current health percentage (boolean)
.colorHealth - Use `self.colors.health` to color the bar. This flag is used to reset the bar color back to default
if none of the above conditions are met (boolean)
## Sub-Widgets Options
.multiplier - Used to tint the background based on the main widgets R, G and B values. Defaults to 1 (number)[0-1]
## Examples
-- Position and size
local Health = CreateFrame('StatusBar', nil, self)
Health:SetHeight(20)
Health:SetPoint('TOP')
Health:SetPoint('LEFT')
Health:SetPoint('RIGHT')
-- Add a background
local Background = Health:CreateTexture(nil, 'BACKGROUND')
Background:SetAllPoints(Health)
Background:SetTexture(1, 1, 1, .5)
-- Options
Health.colorTapping = true
Health.colorDisconnected = true
Health.colorClass = true
Health.colorReaction = true
Health.colorHealth = true
-- Make the background darker.
Background.multiplier = .5
-- Register it with oUF
Health.bg = Background
self.Health = Health
--]]
local _, ns = ...
local oUF = ns.oUF
local Private = oUF.Private
local unitSelectionType = Private.unitSelectionType
local function UpdateColor(self, event, unit)
if(not unit or self.unit ~= unit) then return end
local element = self.Health
local r, g, b, t
if(element.colorDisconnected and not UnitIsConnected(unit)) then
t = self.colors.disconnected
elseif(element.colorTapping and not UnitPlayerControlled(unit) and UnitIsTapDenied(unit)) then
t = self.colors.tapped
elseif(element.colorThreat and not UnitPlayerControlled(unit) and UnitThreatSituation('player', unit)) then
t = self.colors.threat[UnitThreatSituation('player', unit)]
elseif(element.colorClass and UnitIsPlayer(unit))
or (element.colorClassNPC and not UnitIsPlayer(unit))
or ((element.colorClassPet or element.colorPetByUnitClass) and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then
if element.colorPetByUnitClass then unit = unit == 'pet' and 'player' or gsub(unit, 'pet', '') end
local _, class = UnitClass(unit)
t = self.colors.class[class]
elseif(element.colorSelection and unitSelectionType(unit, element.considerSelectionInCombatHostile)) then
t = self.colors.selection[unitSelectionType(unit, element.considerSelectionInCombatHostile)]
elseif(element.colorReaction and UnitReaction(unit, 'player')) then
t = self.colors.reaction[UnitReaction(unit, 'player')]
elseif(element.colorSmooth) then
r, g, b = self:ColorGradient(element.cur or 1, element.max or 1, unpack(element.smoothGradient or self.colors.smooth))
elseif(element.colorHealth) then
t = self.colors.health
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
--[[ Callback: Health:PostUpdateColor(unit, r, g, b)
Called after the element color has been updated.
* self - the Health element
* unit - the unit for which the update has been triggered (string)
* r - the red component of the used color (number)[0-1]
* g - the green component of the used color (number)[0-1]
* b - the blue component of the used color (number)[0-1]
--]]
if(element.PostUpdateColor) then
element:PostUpdateColor(unit, r, g, b)
end
end
local function ColorPath(self, ...)
--[[ Override: Health.UpdateColor(self, event, unit)
Used to completely override the internal function for updating the widgets' colors.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
--]]
(self.Health.UpdateColor or UpdateColor) (self, ...)
end
local function Update(self, event, unit)
if(not unit or self.unit ~= unit) then return end
local element = self.Health
--[[ Callback: Health:PreUpdate(unit)
Called before the element has been updated.
* self - the Health element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PreUpdate) then
element:PreUpdate(unit)
end
local cur, max = UnitHealth(unit), UnitHealthMax(unit)
element:SetMinMaxValues(0, max)
if(UnitIsConnected(unit)) then
element:SetValue(cur)
else
element:SetValue(max)
end
element.cur = cur
element.max = max
--[[ Callback: Health:PostUpdate(unit, cur, max)
Called after the element has been updated.
* self - the Health element
* unit - the unit for which the update has been triggered (string)
* cur - the unit's current health value (number)
* max - the unit's maximum possible health value (number)
--]]
if(element.PostUpdate) then
element:PostUpdate(unit, cur, max)
end
end
local function Path(self, event, ...)
if (self.isForced and event ~= 'ElvUI_UpdateAllElements') then return end -- ElvUI changed
--[[ Override: Health.Override(self, event, unit)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
--]]
(self.Health.Override or Update) (self, event, ...);
ColorPath(self, event, ...)
end
local function ForceUpdate(element)
Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
--[[ Health:SetColorDisconnected(state, isForced)
Used to toggle coloring if the unit is offline.
* self - the Health element
* state - the desired state (boolean)
* isForced - forces the event update even if the state wasn't changed (boolean)
--]]
local function SetColorDisconnected(element, state, isForced)
if(element.colorDisconnected ~= state or isForced) then
element.colorDisconnected = state
if(state) then
element.__owner:RegisterEvent('UNIT_CONNECTION', ColorPath)
element.__owner:RegisterEvent('PARTY_MEMBER_ENABLE', ColorPath)
element.__owner:RegisterEvent('PARTY_MEMBER_DISABLE', ColorPath)
else
element.__owner:UnregisterEvent('UNIT_CONNECTION', ColorPath)
element.__owner:UnregisterEvent('PARTY_MEMBER_ENABLE', ColorPath)
element.__owner:UnregisterEvent('PARTY_MEMBER_DISABLE', ColorPath)
end
end
end
--[[ Health:SetColorSelection(state, isForced)
Used to toggle coloring by the unit's selection.
* self - the Health element
* state - the desired state (boolean)
* isForced - forces the event update even if the state wasn't changed (boolean)
--]]
local function SetColorSelection(element, state, isForced)
if(element.colorSelection ~= state or isForced) then
element.colorSelection = state
if(state) then
element.__owner:RegisterEvent('UNIT_FLAGS', ColorPath)
else
element.__owner:UnregisterEvent('UNIT_FLAGS', ColorPath)
end
end
end
--[[ Health:SetColorTapping(state, isForced)
Used to toggle coloring if the unit isn't tapped by the player.
* self - the Health element
* state - the desired state (boolean)
* isForced - forces the event update even if the state wasn't changed (boolean)
--]]
local function SetColorTapping(element, state, isForced)
if(element.colorTapping ~= state or isForced) then
element.colorTapping = state
if(state) then
element.__owner:RegisterEvent('UNIT_FACTION', ColorPath)
else
element.__owner:UnregisterEvent('UNIT_FACTION', ColorPath)
end
end
end
--[[ Health:SetColorThreat(state, isForced)
Used to toggle coloring by the unit's threat status.
* self - the Health element
* state - the desired state (boolean)
* isForced - forces the event update even if the state wasn't changed (boolean)
--]]
local function SetColorThreat(element, state, isForced)
if(element.colorThreat ~= state or isForced) then
element.colorThreat = state
if(state) then
element.__owner:RegisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
else
element.__owner:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
end
end
end
-- ElvUI changed block
local onUpdateElapsed, onUpdateWait = 0, 0.25
local function onUpdateHealth(self, elapsed)
if onUpdateElapsed > onUpdateWait then
Path(self.__owner, 'OnUpdate', self.__owner.unit)
onUpdateElapsed = 0
else
onUpdateElapsed = onUpdateElapsed + elapsed
end
end
local function SetHealthUpdateSpeed(self, state)
onUpdateWait = state
end
local function SetHealthUpdateMethod(self, state, force)
if self.effectiveHealth ~= state or force then
self.effectiveHealth = state
if state then
self.Health:SetScript('OnUpdate', onUpdateHealth)
self:UnregisterEvent('UNIT_HEALTH', Path)
self:UnregisterEvent('UNIT_MAXHEALTH', Path)
else
self.Health:SetScript('OnUpdate', nil)
self:RegisterEvent('UNIT_HEALTH', Path)
self:RegisterEvent('UNIT_MAXHEALTH', Path)
end
end
end
-- end block
local function Enable(self, unit)
local element = self.Health
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
element.SetColorDisconnected = SetColorDisconnected
element.SetColorSelection = SetColorSelection
element.SetColorTapping = SetColorTapping
element.SetColorThreat = SetColorThreat
-- ElvUI changed block
self.SetHealthUpdateSpeed = SetHealthUpdateSpeed
self.SetHealthUpdateMethod = SetHealthUpdateMethod
SetHealthUpdateMethod(self, self.effectiveHealth, true)
-- end block
if(element.colorDisconnected) then
self:RegisterEvent('UNIT_CONNECTION', ColorPath)
self:RegisterEvent('PARTY_MEMBER_ENABLE', ColorPath)
self:RegisterEvent('PARTY_MEMBER_DISABLE', ColorPath)
end
if(element.colorSelection) then
self:RegisterEvent('UNIT_FLAGS', ColorPath)
end
if(element.colorTapping) then
self:RegisterEvent('UNIT_FACTION', ColorPath)
end
if(element.colorThreat) then
self:RegisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
end
if(element:IsObjectType('StatusBar') and not (element:GetStatusBarTexture() or element:GetStatusBarAtlas())) then
element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
element:Show()
return true
end
end
local function Disable(self)
local element = self.Health
if(element) then
element:Hide()
element:SetScript('OnUpdate', nil) -- ElvUI changed
self:UnregisterEvent('UNIT_HEALTH', Path)
self:UnregisterEvent('UNIT_MAXHEALTH', Path)
self:UnregisterEvent('UNIT_CONNECTION', ColorPath)
self:UnregisterEvent('UNIT_FACTION', ColorPath)
self:UnregisterEvent('UNIT_FLAGS', ColorPath)
self:UnregisterEvent('PARTY_MEMBER_ENABLE', ColorPath)
self:UnregisterEvent('PARTY_MEMBER_DISABLE', ColorPath)
self:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
end
end
oUF:AddElement('Health', Path, Enable, Disable)

View File

@@ -0,0 +1,300 @@
--[[
# Element: Health Prediction Bars
Handles the visibility and updating of incoming heals and heal/damage absorbs.
## Widget
HealthPrediction - A `table` containing references to sub-widgets and options.
## Sub-Widgets
myBar - A `StatusBar` used to represent incoming heals from the player.
otherBar - A `StatusBar` used to represent incoming heals from others.
absorbBar - A `StatusBar` used to represent damage absorbs.
healAbsorbBar - A `StatusBar` used to represent heal absorbs.
overAbsorb - A `Texture` used to signify that the amount of damage absorb is greater than the unit's missing health.
overHealAbsorb - A `Texture` used to signify that the amount of heal absorb is greater than the unit's current health.
## Notes
A default texture will be applied to the StatusBar widgets if they don't have a texture set.
A default texture will be applied to the Texture widgets if they don't have a texture or a color set.
## Options
.maxOverflow - The maximum amount of overflow past the end of the health bar. Set this to 1 to disable the overflow.
Defaults to 1.05 (number)
## 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', myBar:GetStatusBarTexture(), 'RIGHT')
otherBar:SetWidth(200)
local absorbBar = CreateFrame('StatusBar', nil, self.Health)
absorbBar:SetPoint('TOP')
absorbBar:SetPoint('BOTTOM')
absorbBar:SetPoint('LEFT', otherBar:GetStatusBarTexture(), 'RIGHT')
absorbBar:SetWidth(200)
local healAbsorbBar = CreateFrame('StatusBar', nil, self.Health)
healAbsorbBar:SetPoint('TOP')
healAbsorbBar:SetPoint('BOTTOM')
healAbsorbBar:SetPoint('RIGHT', self.Health:GetStatusBarTexture())
healAbsorbBar:SetWidth(200)
healAbsorbBar:SetReverseFill(true)
local overAbsorb = self.Health:CreateTexture(nil, "OVERLAY")
overAbsorb:SetPoint('TOP')
overAbsorb:SetPoint('BOTTOM')
overAbsorb:SetPoint('LEFT', self.Health, 'RIGHT')
overAbsorb:SetWidth(10)
local overHealAbsorb = self.Health:CreateTexture(nil, "OVERLAY")
overHealAbsorb:SetPoint('TOP')
overHealAbsorb:SetPoint('BOTTOM')
overHealAbsorb:SetPoint('RIGHT', self.Health, 'LEFT')
overHealAbsorb:SetWidth(10)
-- Register with oUF
self.HealthPrediction = {
myBar = myBar,
otherBar = otherBar,
absorbBar = absorbBar,
healAbsorbBar = healAbsorbBar,
overAbsorb = overAbsorb,
overHealAbsorb = overHealAbsorb,
maxOverflow = 1.05,
}
--]]
local _, ns = ...
local oUF = ns.oUF
local function Update(self, event, unit)
if(self.unit ~= unit) then return end
local element = self.HealthPrediction
--[[ Callback: HealthPrediction:PreUpdate(unit)
Called before the element has been updated.
* self - the HealthPrediction element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PreUpdate) then
element:PreUpdate(unit)
end
local myIncomingHeal = UnitGetIncomingHeals(unit, 'player') or 0
local allIncomingHeal = UnitGetIncomingHeals(unit) or 0
local absorb = UnitGetTotalAbsorbs(unit) or 0
local healAbsorb = UnitGetTotalHealAbsorbs(unit) or 0
local health, maxHealth = UnitHealth(unit), UnitHealthMax(unit)
local otherIncomingHeal = 0
local hasOverHealAbsorb = false
if(healAbsorb > allIncomingHeal) then
healAbsorb = healAbsorb - allIncomingHeal
allIncomingHeal = 0
myIncomingHeal = 0
if(health < healAbsorb) then
hasOverHealAbsorb = true
end
else
allIncomingHeal = allIncomingHeal - healAbsorb
healAbsorb = 0
if(health + allIncomingHeal > maxHealth * element.maxOverflow) then
allIncomingHeal = maxHealth * element.maxOverflow - health
end
if(allIncomingHeal < myIncomingHeal) then
myIncomingHeal = allIncomingHeal
else
otherIncomingHeal = allIncomingHeal - myIncomingHeal
end
end
local hasOverAbsorb = false
if(health + allIncomingHeal + absorb >= maxHealth) and (absorb > 0) then
hasOverAbsorb = true
end
if(element.myBar) then
element.myBar:SetMinMaxValues(0, maxHealth)
element.myBar:SetValue(myIncomingHeal)
element.myBar:Show()
end
if(element.otherBar) then
element.otherBar:SetMinMaxValues(0, maxHealth)
element.otherBar:SetValue(otherIncomingHeal)
element.otherBar:Show()
end
if(element.absorbBar) then
element.absorbBar:SetMinMaxValues(0, maxHealth)
element.absorbBar:SetValue(absorb)
element.absorbBar:Show()
end
if(element.healAbsorbBar) then
element.healAbsorbBar:SetMinMaxValues(0, maxHealth)
element.healAbsorbBar:SetValue(healAbsorb)
element.healAbsorbBar:Show()
end
if(element.overAbsorb) then
if(hasOverAbsorb) then
element.overAbsorb:Show()
else
element.overAbsorb:Hide()
end
end
if(element.overHealAbsorb) then
if(hasOverHealAbsorb) then
element.overHealAbsorb:Show()
else
element.overHealAbsorb:Hide()
end
end
--[[ Callback: HealthPrediction:PostUpdate(unit, myIncomingHeal, otherIncomingHeal, absorb, healAbsorb, hasOverAbsorb, hasOverHealAbsorb)
Called after the element has been updated.
* self - the HealthPrediction element
* unit - the unit for which the update has been triggered (string)
* myIncomingHeal - the amount of incoming healing done by the player (number)
* otherIncomingHeal - the amount of incoming healing done by others (number)
* absorb - the amount of damage the unit can absorb without losing health (number)
* healAbsorb - the amount of healing the unit can absorb without gaining health (number)
* hasOverAbsorb - indicates if the amount of damage absorb is higher than the unit's missing health (boolean)
* hasOverHealAbsorb - indicates if the amount of heal absorb is higher than the unit's current health (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(unit, myIncomingHeal, otherIncomingHeal, absorb, healAbsorb, hasOverAbsorb, hasOverHealAbsorb, health, maxHealth)
end
end
local function Path(self, ...)
--[[ Override: HealthPrediction.Override(self, event, unit)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event
--]]
return (self.HealthPrediction.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local element = self.HealthPrediction
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_HEALTH', Path)
self:RegisterEvent('UNIT_MAXHEALTH', Path)
self:RegisterEvent('UNIT_HEAL_PREDICTION', Path)
self:RegisterEvent('UNIT_ABSORB_AMOUNT_CHANGED', Path)
self:RegisterEvent('UNIT_HEAL_ABSORB_AMOUNT_CHANGED', Path)
if(not element.maxOverflow) then
element.maxOverflow = 1.05
end
if(element.myBar) then
if(element.myBar:IsObjectType('StatusBar') and not element.myBar:GetStatusBarTexture()) then
element.myBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
end
if(element.otherBar) then
if(element.otherBar:IsObjectType('StatusBar') and not element.otherBar:GetStatusBarTexture()) then
element.otherBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
end
if(element.absorbBar) then
if(element.absorbBar:IsObjectType('StatusBar') and not element.absorbBar:GetStatusBarTexture()) then
element.absorbBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
end
if(element.healAbsorbBar) then
if(element.healAbsorbBar:IsObjectType('StatusBar') and not element.healAbsorbBar:GetStatusBarTexture()) then
element.healAbsorbBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
end
if(element.overAbsorb) then
if(element.overAbsorb:IsObjectType('Texture') and not element.overAbsorb:GetTexture()) then
element.overAbsorb:SetTexture([[Interface\RaidFrame\Shield-Overshield]])
element.overAbsorb:SetBlendMode('ADD')
end
end
if(element.overHealAbsorb) then
if(element.overHealAbsorb:IsObjectType('Texture') and not element.overHealAbsorb:GetTexture()) then
element.overHealAbsorb:SetTexture([[Interface\RaidFrame\Absorb-Overabsorb]])
element.overHealAbsorb:SetBlendMode('ADD')
end
end
return true
end
end
local function Disable(self)
local element = self.HealthPrediction
if(element) then
if(element.myBar) then
element.myBar:Hide()
end
if(element.otherBar) then
element.otherBar:Hide()
end
if(element.absorbBar) then
element.absorbBar:Hide()
end
if(element.healAbsorbBar) then
element.healAbsorbBar:Hide()
end
if(element.overAbsorb) then
element.overAbsorb:Hide()
end
if(element.overHealAbsorb) then
element.overHealAbsorb:Hide()
end
self:UnregisterEvent('UNIT_HEALTH', Path)
self:UnregisterEvent('UNIT_MAXHEALTH', Path)
self:UnregisterEvent('UNIT_HEAL_PREDICTION', Path)
self:UnregisterEvent('UNIT_ABSORB_AMOUNT_CHANGED', Path)
self:UnregisterEvent('UNIT_HEAL_ABSORB_AMOUNT_CHANGED', Path)
end
end
oUF:AddElement('HealthPrediction', Path, Enable, Disable)

View File

@@ -0,0 +1,109 @@
--[[
# Element: Leader Indicator
Toggles the visibility of an indicator based on the unit's leader status.
## Widget
LeaderIndicator - Any UI widget.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
-- Position and size
local LeaderIndicator = self:CreateTexture(nil, 'OVERLAY')
LeaderIndicator:SetSize(16, 16)
LeaderIndicator:SetPoint('BOTTOM', self, 'TOP')
-- Register it with oUF
self.LeaderIndicator = LeaderIndicator
--]]
local _, ns = ...
local oUF = ns.oUF
local function Update(self, event)
local element = self.LeaderIndicator
local unit = self.unit
--[[ Callback: LeaderIndicator:PreUpdate()
Called before the element has been updated.
* self - the LeaderIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
-- ElvUI changed block
local isLeader
if IsInInstance() then
isLeader = UnitIsGroupLeader(unit)
else
isLeader = UnitLeadsAnyGroup(unit)
end
-- end block
if(isLeader) then
element:Show()
else
element:Hide()
end
--[[ Callback: LeaderIndicator:PostUpdate(isLeader)
Called after the element has been updated.
* self - the LeaderIndicator element
* isLeader - indicates whether the element is shown (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(isLeader)
end
end
local function Path(self, ...)
--[[ Override: LeaderIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.LeaderIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self)
local element = self.LeaderIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('PARTY_LEADER_CHANGED', Path, true)
self:RegisterEvent('GROUP_ROSTER_UPDATE', Path, true)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\GroupFrame\UI-Group-LeaderIcon]])
end
return true
end
end
local function Disable(self)
local element = self.LeaderIndicator
if(element) then
element:Hide()
self:UnregisterEvent('PARTY_LEADER_CHANGED', Path)
self:UnregisterEvent('GROUP_ROSTER_UPDATE', Path)
end
end
oUF:AddElement('LeaderIndicator', Path, Enable, Disable)

View File

@@ -0,0 +1,90 @@
--[[
# Element: Party Indicator
Toggles the visibility of an indicator based on if the player was in a group before joining the instance.
## Widget
PartyIndicator - Player only widget.
]]
local _, ns = ...
local oUF = ns.oUF
local function Update(self, event)
local element = self.PartyIndicator
if(element.PreUpdate) then
element:PreUpdate()
end
local forced = not event or event == 'ElvUI_UpdateAllElements'
if forced or event == 'GROUP_ROSTER_UPDATE' then
if IsInGroup(LE_PARTY_CATEGORY_HOME) and IsInGroup(LE_PARTY_CATEGORY_INSTANCE) then
element:Show()
else
element:Hide()
end
end
if forced or event == 'UPDATE_CHAT_COLOR' then
local private = ChatTypeInfo.PARTY
if private and element.HomeIcon then
element.HomeIcon:SetVertexColor(private.r, private.g, private.b, 1)
end
local public = ChatTypeInfo.INSTANCE_CHAT
if public and element.InstanceIcon then
element.InstanceIcon:SetVertexColor(public.r, public.g, public.b, 1)
end
end
if(element.PostUpdate) then
return element:PostUpdate()
end
end
local function Path(self, ...)
--[[ Override: PartyIndicator.Override(self, event)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
--]]
return (self.PartyIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self)
local element = self.PartyIndicator
if element then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('UPDATE_CHAT_COLOR', Path, true)
self:RegisterEvent('GROUP_ROSTER_UPDATE', Path, true)
if(element.HomeIcon and element.HomeIcon:IsObjectType('Texture') and not element.HomeIcon:GetTexture()) then
element.HomeIcon:SetTexture([[Interface\FriendsFrame\UI-Toast-FriendOnlineIcon]])
end
if(element.InstanceIcon and element.InstanceIcon:IsObjectType('Texture') and not element.InstanceIcon:GetTexture()) then
element.InstanceIcon:SetTexture([[Interface\FriendsFrame\UI-Toast-FriendOnlineIcon]])
end
return true
end
end
local function Disable(self)
local element = self.PartyIndicator
if(element) then
element:Hide()
self:UnregisterEvent('UPDATE_CHAT_COLOR', Path)
self:UnregisterEvent('GROUP_ROSTER_UPDATE', Path)
end
end
oUF:AddElement('PartyIndicator', Path, Enable, Disable)

View File

@@ -0,0 +1,159 @@
--[[
# Element: Phasing Indicator
Toggles the visibility of an indicator based on the unit's phasing relative to the player.
## Widget
PhaseIndicator - Any UI widget.
## Sub-Widgets
Icon - A `Texture` to represent the phased status.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
OnEnter and OnLeave script handlers will be set to display a Tooltip if the widget is mouse enabled and does not have
OnEnter and/or OnLeave handlers.
## Examples
-- Position and size
local PhaseIndicator = CreateFrame('Frame', nil, self)
PhaseIndicator:SetSize(16, 16)
PhaseIndicator:SetPoint('TOPLEFT', self)
PhaseIndicator:EnableMouse(true)
local Icon = PhaseIndicator:CreateTexture(nil, 'OVERLAY')
Icon:SetAllPoints()
PhaseIndicator.Icon = Icon
-- Register it with oUF
self.PhaseIndicator = PhaseIndicator
--]]
local _, ns = ...
local oUF = ns.oUF
local GameTooltip = GameTooltip
--[[ Override: PhaseIndicator:UpdateTooltip()
Used to populate the tooltip when the widget is hovered.
* self - the PhaseIndicator widget
--]]
local function UpdateTooltip(element)
if GameTooltip:IsForbidden() then return end
local text = PartyUtil.GetPhasedReasonString(element.reason, element.__owner.unit)
if(text) then
GameTooltip:SetText(text, nil, nil, nil, nil, true)
GameTooltip:Show()
end
end
local function onEnter(element)
if GameTooltip:IsForbidden() or not element:IsVisible() then return end
if(element.reason) then
GameTooltip:SetOwner(element, 'ANCHOR_BOTTOMRIGHT')
element:UpdateTooltip()
end
end
local function onLeave()
if GameTooltip:IsForbidden() then return end
GameTooltip:Hide()
end
local function Update(self, event, unit)
if(self.unit ~= unit) then return end
local element = self.PhaseIndicator
--[[ Callback: PhaseIndicator:PreUpdate()
Called before the element has been updated.
* self - the PhaseIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local phaseReason = UnitIsPlayer(unit) and UnitIsConnected(unit) and UnitPhaseReason(unit) or nil
if(phaseReason) then
element:Show()
else
element:Hide()
end
element.reason = phaseReason
--[[ Callback: PhaseIndicator:PostUpdate(isInSamePhase, phaseReason)
Called after the element has been updated.
* self - the PhaseIndicator element
* isInSamePhase - indicates whether the unit is in the same phase as the player (boolean)
* phaseReason - the reason why the unit is in a different phase (number?)
--]]
if(element.PostUpdate) then
return element:PostUpdate(not phaseReason, phaseReason)
end
end
local function Path(self, ...)
--[[ Override: PhaseIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.PhaseIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local element = self.PhaseIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_PHASE', Path)
local icon = (element.Icon or element)
if(icon:IsObjectType('Texture') and not icon:GetTexture()) then
icon:SetTexture([[Interface\TargetingFrame\UI-PhasingIcon]])
end
if(element.IsMouseEnabled and element:IsMouseEnabled()) then
if(not element:GetScript('OnEnter')) then
element:SetScript('OnEnter', onEnter)
end
if(not element:GetScript('OnLeave')) then
element:SetScript('OnLeave', onLeave)
end
element.UpdateTooltip = element.UpdateTooltip or UpdateTooltip
end
return true
end
end
local function Disable(self)
local element = self.PhaseIndicator
if(element) then
element:Hide()
self:UnregisterEvent('UNIT_PHASE', Path)
end
end
oUF:AddElement('PhaseIndicator', Path, Enable, Disable)

View File

@@ -0,0 +1,152 @@
--[[
# Element: Portraits
Handles the updating of the unit's portrait.
## Widget
Portrait - A `PlayerModel` or a `Texture` used to represent the unit's portrait.
## Notes
A question mark model will be used if the widget is a PlayerModel and the client doesn't have the model information for
the unit.
## Examples
-- 3D Portrait
-- Position and size
local Portrait = CreateFrame('PlayerModel', nil, self)
Portrait:SetSize(32, 32)
Portrait:SetPoint('RIGHT', self, 'LEFT')
-- Register it with oUF
self.Portrait = Portrait
-- 2D Portrait
local Portrait = self:CreateTexture(nil, 'OVERLAY')
Portrait:SetSize(32, 32)
Portrait:SetPoint('RIGHT', self, 'LEFT')
-- Register it with oUF
self.Portrait = Portrait
--]]
local _, ns = ...
local oUF = ns.oUF
-- ElvUI block
local UnitIsUnit = UnitIsUnit
local UnitGUID = UnitGUID
local UnitIsConnected = UnitIsConnected
local UnitIsVisible = UnitIsVisible
local SetPortraitTexture = SetPortraitTexture
-- end block
local function Update(self, event, unit)
if(not unit or not UnitIsUnit(self.unit, unit)) then return end
--[[ Callback: Portrait:PreUpdate(unit)
Called before the element has been updated.
* self - the Portrait element
* unit - the unit for which the update has been triggered (string)
--]]
local element = self.Portrait
if(element.PreUpdate) then element:PreUpdate(unit) end
local guid = UnitGUID(unit)
local isAvailable = UnitIsConnected(unit) and UnitIsVisible(unit)
element.stateChanged = event ~= 'OnUpdate' or element.guid ~= guid or element.state ~= isAvailable
if element.stateChanged then -- ElvUI changed
element.playerModel = element:IsObjectType('PlayerModel')
element.state = isAvailable
element.guid = guid
if element.playerModel then
if not isAvailable then
element:SetCamDistanceScale(0.25)
element:SetPortraitZoom(0)
element:SetPosition(0, 0, 0.25)
element:ClearModel()
element:SetModel([[Interface\Buttons\TalkToMeQuestionMark.m2]])
else
element:SetCamDistanceScale(1)
element:SetPortraitZoom(1)
element:SetPosition(0, 0, 0)
element:ClearModel()
element:SetUnit(unit)
end
elseif not element.customTexture then -- ElvUI changed
SetPortraitTexture(element, unit)
end
end
--[[ Callback: Portrait:PostUpdate(unit)
Called after the element has been updated.
* self - the Portrait element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PostUpdate) then
return element:PostUpdate(unit, event)
end
end
local function Path(self, ...)
--[[ Override: Portrait.Override(self, event, unit)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
--]]
return (self.Portrait.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self, unit)
local element = self.Portrait
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_MODEL_CHANGED', Path)
self:RegisterEvent('UNIT_PORTRAIT_UPDATE', Path)
self:RegisterEvent('PORTRAITS_UPDATED', Path, true)
self:RegisterEvent('UNIT_CONNECTION', Path)
-- The quest log uses PARTY_MEMBER_{ENABLE,DISABLE} to handle updating of
-- party members overlapping quests. This will probably be enough to handle
-- model updating.
--
-- DISABLE isn't used as it fires when we most likely don't have the
-- information we want.
if(unit == 'party') then
self:RegisterEvent('PARTY_MEMBER_ENABLE', Path)
end
element:Show()
return true
end
end
local function Disable(self)
local element = self.Portrait
if(element) then
element:Hide()
self:UnregisterEvent('UNIT_MODEL_CHANGED', Path)
self:UnregisterEvent('UNIT_PORTRAIT_UPDATE', Path)
self:UnregisterEvent('PORTRAITS_UPDATED', 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,481 @@
--[[
# Element: Power Bar
Handles the updating of a status bar that displays the unit's power.
## Widget
Power - A `StatusBar` used to represent the unit's power.
## Sub-Widgets
.bg - A `Texture` used as a background. It will inherit the color of the main StatusBar.
## Notes
A default texture will be applied if the widget is a StatusBar and doesn't have a texture or a color set.
## Options
.frequentUpdates - Indicates whether to use UNIT_POWER_FREQUENT instead UNIT_POWER_UPDATE to update the
bar (boolean)
.displayAltPower - Use this to let the widget display alternative power, if the unit has one.
By default, it does so only for raid and party units. If none, the display will fall
back to the primary power (boolean)
.useAtlas - Use this to let the widget use an atlas for its texture if an atlas is present in
`self.colors.power` for the appropriate power type (boolean)
.smoothGradient - 9 color values to be used with the .colorSmooth option (table)
.considerSelectionInCombatHostile - Indicates whether selection should be considered hostile while the unit is in
combat with the player (boolean)
The following options are listed by priority. The first check that returns true decides the color of the bar.
.colorDisconnected - Use `self.colors.disconnected` to color the bar if the unit is offline (boolean)
.colorTapping - Use `self.colors.tapping` to color the bar if the unit isn't tapped by the player (boolean)
.colorThreat - Use `self.colors.threat[threat]` to color the bar based on the unit's threat status. `threat` is
defined by the first return of [UnitThreatSituation](https://wow.gamepedia.com/API_UnitThreatSituation) (boolean)
.colorPower - Use `self.colors.power[token]` to color the bar based on the unit's power type. This method will
fall-back to `:GetAlternativeColor()` if it can't find a color matching the token. If this function
isn't defined, then it will attempt to color based upon the alternative power colors returned by
[UnitPowerType](http://wowprogramming.com/docs/api/UnitPowerType.html). If these aren't
defined, then it will attempt to color the bar based upon `self.colors.power[type]`. In case of
failure it'll default to `self.colors.power.MANA` (boolean)
.colorClass - Use `self.colors.class[class]` to color the bar based on unit class. `class` is defined by the
second return of [UnitClass](http://wowprogramming.com/docs/api/UnitClass.html) (boolean)
.colorClassNPC - Use `self.colors.class[class]` to color the bar if the unit is a NPC (boolean)
.colorClassPet - Use `self.colors.class[class]` to color the bar if the unit is player controlled, but not a player
(boolean)
.colorSelection - Use `self.colors.selection[selection]` to color the bar based on the unit's selection color.
`selection` is defined by the return value of Private.unitSelectionType, a wrapper function
for [UnitSelectionType](https://wow.gamepedia.com/API_UnitSelectionType) (boolean)
.colorReaction - Use `self.colors.reaction[reaction]` to color the bar based on the player's reaction towards the
unit. `reaction` is defined by the return value of
[UnitReaction](http://wowprogramming.com/docs/api/UnitReaction.html) (boolean)
.colorSmooth - Use `smoothGradient` if present or `self.colors.smooth` to color the bar with a smooth gradient
based on the player's current power percentage (boolean)
## Sub-Widget Options
.multiplier - A multiplier used to tint the background based on the main widgets R, G and B values. Defaults to 1
(number)[0-1]
## Examples
-- Position and size
local Power = CreateFrame('StatusBar', nil, self)
Power:SetHeight(20)
Power:SetPoint('BOTTOM')
Power:SetPoint('LEFT')
Power:SetPoint('RIGHT')
-- Add a background
local Background = Power:CreateTexture(nil, 'BACKGROUND')
Background:SetAllPoints(Power)
Background:SetTexture(1, 1, 1, .5)
-- Options
Power.frequentUpdates = true
Power.colorTapping = true
Power.colorDisconnected = true
Power.colorPower = true
Power.colorClass = true
Power.colorReaction = true
-- Make the background darker.
Background.multiplier = .5
-- Register it with oUF
Power.bg = Background
self.Power = Power
--]]
local _, ns = ...
local oUF = ns.oUF
local Private = oUF.Private
local unitSelectionType = Private.unitSelectionType
-- sourced from FrameXML/UnitPowerBarAlt.lua
local ALTERNATE_POWER_INDEX = Enum.PowerType.Alternate or 10
--[[ Override: Power:GetDisplayPower()
Used to get info on the unit's alternative power, if any.
Should return the power type index (see [Enum.PowerType.Alternate](https://wow.gamepedia.com/Enum_Unit.PowerType))
and the minimum value for the given power type (see [info.minPower](https://wow.gamepedia.com/API_GetUnitPowerBarInfo))
or nil if the unit has no alternative (alternate) power or it should not be
displayed. In case of a nil return, the element defaults to the primary power
type and zero for the minimum value.
* self - the Power element
--]]
local function GetDisplayPower(element)
local unit = element.__owner.unit
local barInfo = GetUnitPowerBarInfo(unit)
if(barInfo and barInfo.showOnRaid and (UnitInParty(unit) or UnitInRaid(unit))) then
return ALTERNATE_POWER_INDEX, barInfo.minPower
end
end
local function UpdateColor(self, event, unit)
if(self.unit ~= unit) then return end
local element = self.Power
local pType, pToken, altR, altG, altB = UnitPowerType(unit)
local r, g, b, t, atlas
if(element.colorDisconnected and not UnitIsConnected(unit)) then
t = self.colors.disconnected
elseif(element.colorTapping and not UnitPlayerControlled(unit) and UnitIsTapDenied(unit)) then
t = self.colors.tapped
elseif(element.colorThreat and not UnitPlayerControlled(unit) and UnitThreatSituation('player', unit)) then
t = self.colors.threat[UnitThreatSituation('player', unit)]
elseif(element.colorPower) then
if(element.displayType ~= ALTERNATE_POWER_INDEX) then
t = self.colors.power[pToken]
if(not t) then
if(element.GetAlternativeColor) then
r, g, b = element:GetAlternativeColor(unit, pType, pToken, altR, altG, altB)
elseif(altR) then
r, g, b = altR, altG, altB
if(r > 1 or g > 1 or b > 1) then
-- BUG: As of 7.0.3, altR, altG, altB may be in 0-1 or 0-255 range.
r, g, b = r / 255, g / 255, b / 255
end
else
t = self.colors.power[pType] or self.colors.power.MANA
end
end
else
t = self.colors.power[ALTERNATE_POWER_INDEX]
end
if(element.useAtlas and t and t.atlas) then
atlas = t.atlas
end
elseif(element.colorClass and UnitIsPlayer(unit))
or (element.colorClassNPC and not UnitIsPlayer(unit))
or (element.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then
local _, class = UnitClass(unit)
t = self.colors.class[class]
elseif(element.colorSelection and unitSelectionType(unit, element.considerSelectionInCombatHostile)) then
t = self.colors.selection[unitSelectionType(unit, element.considerSelectionInCombatHostile)]
elseif(element.colorReaction and UnitReaction(unit, 'player')) then
t = self.colors.reaction[UnitReaction(unit, 'player')]
elseif(element.colorSmooth) then
local adjust = 0 - (element.min or 0)
r, g, b = self:ColorGradient((element.cur or 1) + adjust, (element.max or 1) + adjust, unpack(element.smoothGradient or self.colors.smooth))
end
if(t) then
r, g, b = t[1], t[2], t[3]
end
if(atlas) then
element:SetStatusBarAtlas(atlas)
element:SetStatusBarColor(1, 1, 1)
elseif(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
--[[ Callback: Power:PostUpdateColor(unit, r, g, b)
Called after the element color has been updated.
local bg = element.bg
if(bg and b) then
local mu = bg.multiplier or 1
bg:SetVertexColor(r * mu, g * mu, b * mu)
end
--]]
if(element.PostUpdateColor) then
element:PostUpdateColor(unit, r, g, b)
end
end
local function ColorPath(self, ...)
--[[ Override: Power.UpdateColor(self, event, unit)
Used to completely override the internal function for updating the widgets' colors.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
--]]
(self.Power.UpdateColor or UpdateColor) (self, ...)
end
local function Update(self, event, unit)
if(self.unit ~= unit) then return end
local element = self.Power
--[[ Callback: Power:PreUpdate(unit)
Called before the element has been updated.
* self - the Power element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PreUpdate) then
element:PreUpdate(unit)
end
local displayType, min
if(element.displayAltPower) then
displayType, min = element:GetDisplayPower()
end
local cur, max = UnitPower(unit, displayType), UnitPowerMax(unit, displayType)
if not min then min = 0 end
element:SetMinMaxValues(min, max)
if(UnitIsConnected(unit)) then
element:SetValue(cur)
else
element:SetValue(max)
end
element.cur = cur
element.min = min
element.max = max
element.displayType = displayType
--[[ Callback: Power:PostUpdate(unit, cur, min, max)
Called after the element has been updated.
* self - the Power element
* unit - the unit for which the update has been triggered (string)
* cur - the unit's current power value (number)
* min - the unit's minimum possible power value (number)
* max - the unit's maximum possible power value (number)
--]]
if(element.PostUpdate) then
element:PostUpdate(unit, cur, min, max)
end
end
local function Path(self, event, ...)
if (self.isForced and event ~= 'ElvUI_UpdateAllElements') then return end -- ElvUI changed
--[[ Override: Power.Override(self, event, unit, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
* ... - the arguments accompanying the event
--]]
(self.Power.Override or Update) (self, event, ...);
ColorPath(self, event, ...)
end
local function ForceUpdate(element)
Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
--[[ Power:SetColorDisconnected(state, isForced)
Used to toggle coloring if the unit is offline.
* self - the Power element
* state - the desired state (boolean)
* isForced - forces the event update even if the state wasn't changed (boolean)
--]]
local function SetColorDisconnected(element, state, isForced)
if(element.colorDisconnected ~= state or isForced) then
element.colorDisconnected = state
if(state) then
element.__owner:RegisterEvent('UNIT_CONNECTION', ColorPath)
else
element.__owner:UnregisterEvent('UNIT_CONNECTION', ColorPath)
end
end
end
--[[ Power:SetColorSelection(state, isForced)
Used to toggle coloring by the unit's selection.
* self - the Power element
* state - the desired state (boolean)
* isForced - forces the event update even if the state wasn't changed (boolean)
--]]
local function SetColorSelection(element, state, isForced)
if(element.colorSelection ~= state or isForced) then
element.colorSelection = state
if(state) then
element.__owner:RegisterEvent('UNIT_FLAGS', ColorPath)
else
element.__owner:UnregisterEvent('UNIT_FLAGS', ColorPath)
end
end
end
--[[ Power:SetColorTapping(state, isForced)
Used to toggle coloring if the unit isn't tapped by the player.
* self - the Power element
* state - the desired state (boolean)
* isForced - forces the event update even if the state wasn't changed (boolean)
--]]
local function SetColorTapping(element, state, isForced)
if(element.colorTapping ~= state or isForced) then
element.colorTapping = state
if(state) then
element.__owner:RegisterEvent('UNIT_FACTION', ColorPath)
else
element.__owner:UnregisterEvent('UNIT_FACTION', ColorPath)
end
end
end
--[[ Power:SetColorThreat(state, isForced)
Used to toggle coloring by the unit's threat status.
* self - the Power element
* state - the desired state (boolean)
* isForced - forces the event update even if the state wasn't changed (boolean)
--]]
local function SetColorThreat(element, state, isForced)
if(element.colorThreat ~= state or isForced) then
element.colorThreat = state
if(state) then
element.__owner:RegisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
else
element.__owner:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
end
end
end
--[[ Power:SetFrequentUpdates(state, isForced)
Used to toggle frequent updates.
* self - the Power element
* state - the desired state (boolean)
* isForced - forces the event update even if the state wasn't changed (boolean)
--]]
local function SetFrequentUpdates(element, state, isForced)
if(element.frequentUpdates ~= state or isForced) then
element.frequentUpdates = state
if(state) then
element.__owner:UnregisterEvent('UNIT_POWER_UPDATE', Path)
element.__owner:RegisterEvent('UNIT_POWER_FREQUENT', Path)
else
element.__owner:UnregisterEvent('UNIT_POWER_FREQUENT', Path)
element.__owner:RegisterEvent('UNIT_POWER_UPDATE', Path)
end
end
end
-- ElvUI changed block
local onUpdateElapsed, onUpdateWait = 0, 0.25
local function onUpdatePower(self, elapsed)
if onUpdateElapsed > onUpdateWait then
Path(self.__owner, 'OnUpdate', self.__owner.unit)
onUpdateElapsed = 0
else
onUpdateElapsed = onUpdateElapsed + elapsed
end
end
local function SetPowerUpdateSpeed(self, state)
onUpdateWait = state
end
local function SetPowerUpdateMethod(self, state, force)
if self.effectivePower ~= state or force then
self.effectivePower = state
if state then
self.Power:SetScript('OnUpdate', onUpdatePower)
self:UnregisterEvent('UNIT_POWER_FREQUENT', Path)
self:UnregisterEvent('UNIT_POWER_UPDATE', Path)
self:UnregisterEvent('UNIT_MAXPOWER', Path)
else
self.Power:SetScript('OnUpdate', nil)
self:RegisterEvent('UNIT_MAXPOWER', Path)
if self.Power.frequentUpdates then
self:RegisterEvent('UNIT_POWER_FREQUENT', Path)
else
self:RegisterEvent('UNIT_POWER_UPDATE', Path)
end
end
end
end
-- end block
local function Enable(self)
local element = self.Power
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
element.SetColorDisconnected = SetColorDisconnected
element.SetColorSelection = SetColorSelection
element.SetColorTapping = SetColorTapping
element.SetColorThreat = SetColorThreat
element.SetFrequentUpdates = SetFrequentUpdates
-- ElvUI changed block
self.SetPowerUpdateSpeed = SetPowerUpdateSpeed
self.SetPowerUpdateMethod = SetPowerUpdateMethod
SetPowerUpdateMethod(self, self.effectivePower, true)
-- end block
if(element.colorDisconnected) then
self:RegisterEvent('UNIT_CONNECTION', ColorPath)
end
if(element.colorSelection) then
self:RegisterEvent('UNIT_FLAGS', ColorPath)
end
if(element.colorTapping) then
self:RegisterEvent('UNIT_FACTION', ColorPath)
end
if(element.colorThreat) then
self:RegisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
end
self:RegisterEvent('UNIT_DISPLAYPOWER', Path)
self:RegisterEvent('UNIT_POWER_BAR_HIDE', Path)
self:RegisterEvent('UNIT_POWER_BAR_SHOW', Path)
if(element:IsObjectType('StatusBar') and not (element:GetStatusBarTexture() or element:GetStatusBarAtlas())) then
element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
if(not element.GetDisplayPower) then
element.GetDisplayPower = GetDisplayPower
end
element:Show()
return true
end
end
local function Disable(self)
local element = self.Power
if(element) then
element:Hide()
element:SetScript('OnUpdate', nil) -- ElvUI changed
self:UnregisterEvent('UNIT_DISPLAYPOWER', Path)
self:UnregisterEvent('UNIT_MAXPOWER', Path)
self:UnregisterEvent('UNIT_POWER_BAR_HIDE', Path)
self:UnregisterEvent('UNIT_POWER_BAR_SHOW', Path)
self:UnregisterEvent('UNIT_POWER_FREQUENT', Path)
self:UnregisterEvent('UNIT_POWER_UPDATE', Path)
self:UnregisterEvent('UNIT_CONNECTION', ColorPath)
self:UnregisterEvent('UNIT_FACTION', ColorPath)
self:UnregisterEvent('UNIT_FLAGS', ColorPath)
self:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
end
end
oUF:AddElement('Power', Path, Enable, Disable)

View File

@@ -0,0 +1,194 @@
--[[
# Element: Power Prediction Bar
Handles the visibility and updating of power cost prediction.
## Widget
PowerPrediction - A `table` containing the sub-widgets.
## Sub-Widgets
mainBar - A `StatusBar` used to represent power cost of spells on top of the Power element.
altBar - A `StatusBar` used to represent power cost of spells on top of the AdditionalPower element.
## Notes
A default texture will be applied if the widget is a StatusBar and doesn't have a texture set.
## 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
}
--]]
local _, ns = ...
local oUF = ns.oUF
-- sourced from FrameXML/AlternatePowerBar.lua
local ADDITIONAL_POWER_BAR_INDEX = ADDITIONAL_POWER_BAR_INDEX or 0
local ALT_MANA_BAR_PAIR_DISPLAY_INFO = ALT_MANA_BAR_PAIR_DISPLAY_INFO
local _, playerClass = UnitClass('player')
local function Update(self, event, unit)
if(self.unit ~= unit) then return end
local element = self.PowerPrediction
--[[ Callback: PowerPrediction:PreUpdate(unit)
Called before the element has been updated.
* self - the PowerPrediction element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PreUpdate) then
element:PreUpdate(unit)
end
local mainCost, altCost = 0, 0
local mainType = UnitPowerType(unit)
local mainMax = UnitPowerMax(unit, mainType)
local isPlayer = UnitIsUnit('player', unit)
local altManaInfo = isPlayer and ALT_MANA_BAR_PAIR_DISPLAY_INFO[playerClass]
local hasAltManaBar = altManaInfo and altManaInfo[mainType]
local _, _, _, startTime, endTime, _, _, _, spellID = UnitCastingInfo(unit)
if(event == 'UNIT_SPELLCAST_START' and startTime ~= endTime) then
local costTable = GetSpellPowerCost(spellID)
local checkRequiredAura = isPlayer and #costTable > 1
for _, costInfo in next, costTable do
local cost, ctype, cperc = costInfo.cost, costInfo.type, costInfo.costPercent
local checkSpec = not checkRequiredAura or costInfo.hasRequiredAura
if checkSpec and ctype == mainType then
mainCost = ((isPlayer or cost < mainMax) and cost) or (mainMax * cperc) / 100
element.mainCost = mainCost
break
elseif hasAltManaBar and checkSpec and ctype == ADDITIONAL_POWER_BAR_INDEX then
altCost = cost
element.altCost = altCost
break
end
end
elseif(spellID) then
-- if we try to cast a spell while casting another one we need to avoid
-- resetting the element
mainCost = element.mainCost or 0
altCost = element.altCost or 0
else
element.mainCost = mainCost
element.altCost = altCost
end
if(element.mainBar) then
element.mainBar:SetMinMaxValues(0, mainMax)
element.mainBar:SetValue(mainCost)
element.mainBar:Show()
end
if(element.altBar and hasAltManaBar) then
element.altBar:SetMinMaxValues(0, UnitPowerMax(unit, ADDITIONAL_POWER_BAR_INDEX))
element.altBar:SetValue(altCost)
element.altBar:Show()
end
--[[ Callback: PowerPrediction:PostUpdate(unit, mainCost, altCost, hasAltManaBar)
Called after the element has been updated.
* self - the PowerPrediction element
* unit - the unit for which the update has been triggered (string)
* mainCost - the main power type cost of the cast ability (number)
* altCost - the secondary power type cost of the cast ability (number)
* hasAltManaBar - indicates if the unit has a secondary power bar (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(unit, mainCost, altCost, hasAltManaBar)
end
end
local function Path(self, ...)
--[[ Override: PowerPrediction.Override(self, event, unit, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
* ... - the arguments accompanying the event
--]]
return (self.PowerPrediction.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local element = self.PowerPrediction
if(element) then
element.__owner = self
element.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(element.mainBar) then
if(element.mainBar:IsObjectType('StatusBar')
and not (element.mainBar:GetStatusBarTexture() or element.mainBar:GetStatusBarAtlas())) then
element.mainBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
end
if(element.altBar) then
if(element.altBar:IsObjectType('StatusBar')
and not (element.altBar:GetStatusBarTexture() or element.altBar:GetStatusBarAtlas())) then
element.altBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
end
return true
end
end
local function Disable(self)
local element = self.PowerPrediction
if(element) then
if(element.mainBar) then
element.mainBar:Hide()
end
if(element.altBar) then
element.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,119 @@
--[[
# Element: PvPClassificationIndicator
Handles the visibility and updating of an indicator based on the unit's PvP classification.
## Widget
PvPClassificationIndicator - A `Texture` used to display PvP classification.
## Notes
This element updates by changing the texture.
## Options
.useAtlasSize - Makes the element use preprogrammed atlas' size instead of its set dimensions (boolean)
## Examples
-- Position and size
local PvPClassificationIndicator = self:CreateTexture(nil, 'OVERLAY')
PvPClassificationIndicator:SetSize(24, 24)
PvPClassificationIndicator:SetPoint('CENTER')
-- Register it with oUF
self.PvPClassificationIndicator = PvPClassificationIndicator
--]]
local _, ns = ...
local oUF = ns.oUF
-- sourced from FrameXML/CompactUnitFrame.lua
local ICONS = {
[Enum.PvPUnitClassification.FlagCarrierHorde or 0] = "nameplates-icon-flag-horde",
[Enum.PvPUnitClassification.FlagCarrierAlliance or 1] = "nameplates-icon-flag-alliance",
[Enum.PvPUnitClassification.FlagCarrierNeutral or 2] = "nameplates-icon-flag-neutral",
[Enum.PvPUnitClassification.CartRunnerHorde or 3] = "nameplates-icon-cart-horde",
[Enum.PvPUnitClassification.CartRunnerAlliance or 4] = "nameplates-icon-cart-alliance",
[Enum.PvPUnitClassification.AssassinHorde or 5] = "nameplates-icon-bounty-horde",
[Enum.PvPUnitClassification.AssassinAlliance or 6] = "nameplates-icon-bounty-alliance",
[Enum.PvPUnitClassification.OrbCarrierBlue or 7] = "nameplates-icon-orb-blue",
[Enum.PvPUnitClassification.OrbCarrierGreen or 8] = "nameplates-icon-orb-green",
[Enum.PvPUnitClassification.OrbCarrierOrange or 9] = "nameplates-icon-orb-orange",
[Enum.PvPUnitClassification.OrbCarrierPurple or 10] = "nameplates-icon-orb-purple",
}
local function Update(self, event, unit)
if(unit ~= self.unit) then return end
local element = self.PvPClassificationIndicator
--[[ Callback: PvPClassificationIndicator:PreUpdate(unit)
Called before the element has been updated.
* self - the PvPClassificationIndicator element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PreUpdate) then
element:PreUpdate(unit)
end
local class = UnitPvpClassification(unit)
local icon = ICONS[class]
if(icon) then
element:SetAtlas(icon, element.useAtlasSize)
element:Show()
else
element:Hide()
end
--[[ Callback: PvPClassificationIndicator:PostUpdate(unit, class)
Called after the element has been updated.
* self - the PvPClassificationIndicator element
* unit - the unit for which the update has been triggered (string)
* class - the pvp classification of the unit (number?)
--]]
if(element.PostUpdate) then
return element:PostUpdate(unit, class)
end
end
local function Path(self, ...)
--[[Override: PvPClassificationIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.PvPClassificationIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local element = self.PvPClassificationIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_CLASSIFICATION_CHANGED', Path)
return true
end
end
local function Disable(self)
local element = self.PvPClassificationIndicator
if(element) then
element:Hide()
self:UnregisterEvent('UNIT_CLASSIFICATION_CHANGED', Path)
end
end
oUF:AddElement('PvPClassificationIndicator', Path, Enable, Disable)

View File

@@ -0,0 +1,151 @@
--[[
# Element: PvP and Honor Level Icons
Handles the visibility and updating of an indicator based on the unit's PvP status and honor level.
## Widget
PvPIndicator - A `Texture` used to display faction, FFA PvP status or honor level icon.
## Sub-Widgets
Badge - A `Texture` used to display the honor badge background image.
## Notes
This element updates by changing the texture.
The `Badge` sub-widget has to be on a lower sub-layer than the `PvP` texture.
## Examples
-- Position and size
local PvPIndicator = self:CreateTexture(nil, 'ARTWORK', nil, 1)
PvPIndicator:SetSize(30, 30)
PvPIndicator:SetPoint('RIGHT', self, 'LEFT')
local Badge = self:CreateTexture(nil, 'ARTWORK')
Badge:SetSize(50, 52)
Badge:SetPoint('CENTER', PvPIndicator, 'CENTER')
-- Register it with oUF
PvPIndicator.Badge = Badge
self.PvPIndicator = PvPIndicator
--]]
local _, ns = ...
local oUF = ns.oUF
local function Update(self, event, unit)
if(unit and unit ~= self.unit) then return end
local element = self.PvPIndicator
unit = unit or self.unit
--[[ Callback: PvPIndicator:PreUpdate(unit)
Called before the element has been updated.
* self - the PvPIndicator element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PreUpdate) then
element:PreUpdate(unit)
end
local status
local factionGroup = UnitFactionGroup(unit) or 'Neutral'
local honorRewardInfo = C_PvP.GetHonorRewardInfo(UnitHonorLevel(unit))
if(UnitIsPVPFreeForAll(unit)) then
status = 'FFA'
elseif(factionGroup ~= 'Neutral' and UnitIsPVP(unit)) then
if(unit == 'player' and UnitIsMercenary(unit)) then
if(factionGroup == 'Horde') then
factionGroup = 'Alliance'
elseif(factionGroup == 'Alliance') then
factionGroup = 'Horde'
end
end
status = factionGroup
end
if(status) then
element:Show()
if(element.Badge and honorRewardInfo) then
element:SetTexture(honorRewardInfo.badgeFileDataID)
element:SetTexCoord(0, 1, 0, 1)
element.Badge:SetAtlas('honorsystem-portrait-' .. factionGroup, false)
element.Badge:Show()
else
element:SetTexture([[Interface\TargetingFrame\UI-PVP-]] .. status)
element:SetTexCoord(0, 0.65625, 0, 0.65625)
if(element.Badge) then
element.Badge:Hide()
end
end
else
element:Hide()
if(element.Badge) then
element.Badge:Hide()
end
end
--[[ Callback: PvPIndicator:PostUpdate(unit, status)
Called after the element has been updated.
* self - the PvPIndicator element
* unit - the unit for which the update has been triggered (string)
* status - the unit's current PvP status or faction accounting for mercenary mode (string)['FFA', 'Alliance',
'Horde']
--]]
if(element.PostUpdate) then
return element:PostUpdate(unit, status)
end
end
local function Path(self, ...)
--[[Override: PvPIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.PvPIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local element = self.PvPIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_FACTION', Path)
self:RegisterEvent('HONOR_LEVEL_UPDATE', Path, true)
return true
end
end
local function Disable(self)
local element = self.PvPIndicator
if(element) then
element:Hide()
if(element.Badge) then
element.Badge:Hide()
end
self:UnregisterEvent('UNIT_FACTION', Path)
self:UnregisterEvent('HONOR_LEVEL_UPDATE', Path)
end
end
oUF:AddElement('PvPIndicator', Path, Enable, Disable)

View File

@@ -0,0 +1,100 @@
--[[
# Element: Quest Indicator
Handles the visibility and updating of an indicator based on the unit's involvement in a quest.
## Widget
QuestIndicator - Any UI widget.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
-- Position and size
local QuestIndicator = self:CreateTexture(nil, 'OVERLAY')
QuestIndicator:SetSize(16, 16)
QuestIndicator:SetPoint('TOPRIGHT', self)
-- Register it with oUF
self.QuestIndicator = QuestIndicator
--]]
local _, ns = ...
local oUF = ns.oUF
local function Update(self, event, unit)
if(unit ~= self.unit) then return end
local element = self.QuestIndicator
--[[ Callback: QuestIndicator:PreUpdate()
Called before the element has been updated.
* self - the QuestIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local isQuestBoss = UnitIsQuestBoss(unit)
if(isQuestBoss) then
element:Show()
else
element:Hide()
end
--[[ Callback: QuestIndicator:PostUpdate(isQuestBoss)
Called after the element has been updated.
* self - the QuestIndicator element
* isQuestBoss - indicates if the element is shown (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(isQuestBoss)
end
end
local function Path(self, ...)
--[[ Override: QuestIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.QuestIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local element = self.QuestIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_CLASSIFICATION_CHANGED', Path)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\TargetingFrame\PortraitQuestBadge]])
end
return true
end
end
local function Disable(self)
local element = self.QuestIndicator
if(element) then
element:Hide()
self:UnregisterEvent('UNIT_CLASSIFICATION_CHANGED', Path)
end
end
oUF:AddElement('QuestIndicator', Path, Enable, Disable)

View File

@@ -0,0 +1,106 @@
--[[
# Element: Raid Role Indicator
Handles the visibility and updating of an indicator based on the unit's raid assignment (main tank or main assist).
## Widget
RaidRoleIndicator - A `Texture` representing the unit's raid assignment.
## Notes
This element updates by changing the texture.
## Examples
-- Position and size
local RaidRoleIndicator = self:CreateTexture(nil, 'OVERLAY')
RaidRoleIndicator:SetSize(16, 16)
RaidRoleIndicator:SetPoint('TOPLEFT')
-- Register it with oUF
self.RaidRoleIndicator = RaidRoleIndicator
--]]
local _, ns = ...
local oUF = ns.oUF
local MAINTANK_ICON = [[Interface\GROUPFRAME\UI-GROUP-MAINTANKICON]]
local MAINASSIST_ICON = [[Interface\GROUPFRAME\UI-GROUP-MAINASSISTICON]]
local function Update(self, event)
local element = self.RaidRoleIndicator
local unit = self.unit
--[[ Callback: RaidRoleIndicator:PreUpdate()
Called before the element has been updated.
* self - the RaidRoleIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local role, isShown
if(UnitInRaid(unit) and not UnitHasVehicleUI(unit)) then
if(GetPartyAssignment('MAINTANK', unit)) then
isShown = true
element:SetTexture(MAINTANK_ICON)
role = 'MAINTANK'
elseif(GetPartyAssignment('MAINASSIST', unit)) then
isShown = true
element:SetTexture(MAINASSIST_ICON)
role = 'MAINASSIST'
end
end
element:SetShown(isShown)
--[[ Callback: RaidRoleIndicator:PostUpdate(role)
Called after the element has been updated.
* self - the RaidRoleIndicator element
* role - the unit's raid assignment (string?)['MAINTANK', 'MAINASSIST']
--]]
if(element.PostUpdate) then
return element:PostUpdate(role)
end
end
local function Path(self, ...)
--[[ Override: RaidRoleIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.RaidRoleIndicator.Override or Update)(self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self)
local element = self.RaidRoleIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('GROUP_ROSTER_UPDATE', Path, true)
return true
end
end
local function Disable(self)
local element = self.RaidRoleIndicator
if(element) then
element:Hide()
self:UnregisterEvent('GROUP_ROSTER_UPDATE', Path)
end
end
oUF:AddElement('RaidRoleIndicator', Path, Enable, Disable)

View File

@@ -0,0 +1,102 @@
--[[
# Element: Raid Target Indicator
Handles the visibility and updating of an indicator based on the unit's raid target assignment.
## Widget
RaidTargetIndicator - A `Texture` used to display the raid target icon.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture set.
## Examples
-- Position and size
local RaidTargetIndicator = self:CreateTexture(nil, 'OVERLAY')
RaidTargetIndicator:SetSize(16, 16)
RaidTargetIndicator:SetPoint('TOPRIGHT', self)
-- Register it with oUF
self.RaidTargetIndicator = RaidTargetIndicator
--]]
local _, ns = ...
local oUF = ns.oUF
local GetRaidTargetIndex = GetRaidTargetIndex
local SetRaidTargetIconTexture = SetRaidTargetIconTexture
local function Update(self, event)
local element = self.RaidTargetIndicator
--[[ Callback: RaidTargetIndicator:PreUpdate()
Called before the element has been updated.
* self - the RaidTargetIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local index = GetRaidTargetIndex(self.unit)
if(index) then
SetRaidTargetIconTexture(element, index)
element:Show()
else
element:Hide()
end
--[[ Callback: RaidTargetIndicator:PostUpdate(index)
Called after the element has been updated.
* self - the RaidTargetIndicator element
* index - the index of the raid target marker (number?)[1-8]
--]]
if(element.PostUpdate) then
return element:PostUpdate(index)
end
end
local function Path(self, ...)
--[[ Override: RaidTargetIndicator.Override(self, event)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
--]]
return (self.RaidTargetIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
if(not element.__owner.unit) then return end
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self)
local element = self.RaidTargetIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('RAID_TARGET_UPDATE', Path, true)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\TargetingFrame\UI-RaidTargetingIcons]])
end
return true
end
end
local function Disable(self)
local element = self.RaidTargetIndicator
if(element) then
element:Hide()
self:UnregisterEvent('RAID_TARGET_UPDATE', Path)
end
end
oUF:AddElement('RaidTargetIndicator', Path, Enable, Disable)

View File

@@ -0,0 +1,138 @@
--[[
# Element: Range Fader
Changes the opacity of a unit frame based on whether the frame's unit is in the player's range.
## Widget
Range - A table containing opacity values.
## Notes
Offline units are handled as if they are in range.
## Options
.outsideAlpha - Opacity when the unit is out of range. Defaults to 0.55 (number)[0-1].
.insideAlpha - Opacity when the unit is within range. Defaults to 1 (number)[0-1].
## Examples
-- Register with oUF
self.Range = {
insideAlpha = 1,
outsideAlpha = 1/2,
}
--]]
local _, ns = ...
local oUF = ns.oUF
local _FRAMES = {}
local OnRangeFrame
local UnitInRange, UnitIsConnected = UnitInRange, UnitIsConnected
local function Update(self, event)
local element = self.Range
local unit = self.unit
--[[ Callback: Range:PreUpdate()
Called before the element has been updated.
* self - the Range element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local inRange, checkedRange
local connected = UnitIsConnected(unit)
if(connected) then
inRange, checkedRange = UnitInRange(unit)
if(checkedRange and not inRange) then
self:SetAlpha(element.outsideAlpha)
else
self:SetAlpha(element.insideAlpha)
end
else
self:SetAlpha(element.insideAlpha)
end
--[[ Callback: Range:PostUpdate(object, inRange, checkedRange, isConnected)
Called after the element has been updated.
* self - the Range element
* object - the parent object
* inRange - indicates if the unit was within 40 yards of the player (boolean)
* checkedRange - indicates if the range check was actually performed (boolean)
* isConnected - indicates if the unit is online (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(self, inRange, checkedRange, connected)
end
end
local function Path(self, ...)
--[[ Override: Range.Override(self, event)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
--]]
return (self.Range.Override or Update) (self, ...)
end
-- Internal updating method
local timer = 0
local function OnRangeUpdate(_, elapsed)
timer = timer + elapsed
if(timer >= .20) then
for _, object in next, _FRAMES do
if(object:IsShown()) then
Path(object, 'OnUpdate')
end
end
timer = 0
end
end
local function Enable(self)
local element = self.Range
if(element) then
element.__owner = self
element.insideAlpha = element.insideAlpha or 1
element.outsideAlpha = element.outsideAlpha or 0.55
if(not OnRangeFrame) then
OnRangeFrame = CreateFrame('Frame')
OnRangeFrame:SetScript('OnUpdate', OnRangeUpdate)
end
table.insert(_FRAMES, self)
OnRangeFrame:Show()
return true
end
end
local function Disable(self)
local element = self.Range
if(element) then
for index, frame in next, _FRAMES do
if(frame == self) then
table.remove(_FRAMES, index)
break
end
end
self:SetAlpha(element.insideAlpha)
if(#_FRAMES == 0) then
OnRangeFrame:Hide()
end
end
end
oUF:AddElement('Range', nil, Enable, Disable)

View File

@@ -0,0 +1,163 @@
--[[
# Element: Ready Check Indicator
Handles the visibility and updating of an indicator based on the unit's ready check status.
## Widget
ReadyCheckIndicator - A `Texture` representing ready check status.
## Notes
This element updates by changing the texture.
Default textures will be applied if the layout does not provide custom ones. See Options.
## Options
.finishedTime - For how many seconds the icon should stick after a check has completed. Defaults to 10 (number).
.fadeTime - For how many seconds the icon should fade away after the stick duration has completed. Defaults to
1.5 (number).
.readyTexture - Path to an alternate texture for the ready check 'ready' status.
.notReadyTexture - Path to an alternate texture for the ready check 'notready' status.
.waitingTexture - Path to an alternate texture for the ready check 'waiting' status.
## Attributes
.status - the unit's ready check status (string?)['ready', 'noready', 'waiting']
## Examples
-- Position and size
local ReadyCheckIndicator = self:CreateTexture(nil, 'OVERLAY')
ReadyCheckIndicator:SetSize(16, 16)
ReadyCheckIndicator:SetPoint('TOP')
-- Register with oUF
self.ReadyCheckIndicator = ReadyCheckIndicator
--]]
local _, ns = ...
local oUF = ns.oUF
local Private = oUF.Private
local unitExists = Private.unitExists
local function OnFinished(self)
local element = self:GetParent()
element:Hide()
--[[ Callback: ReadyCheckIndicator:PostUpdateFadeOut()
Called after the element has been faded out.
* self - the ReadyCheckIndicator element
--]]
if(element.PostUpdateFadeOut) then
element:PostUpdateFadeOut()
end
end
local function Update(self, event)
local element = self.ReadyCheckIndicator
local unit = self.unit
--[[ Callback: ReadyCheckIndicator:PreUpdate()
Called before the element has been updated.
* self - the ReadyCheckIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local status = GetReadyCheckStatus(unit)
if(unitExists(unit) and status) then
if(status == 'ready') then
element:SetTexture(element.readyTexture)
elseif(status == 'notready') then
element:SetTexture(element.notReadyTexture)
else
element:SetTexture(element.waitingTexture)
end
element.status = status
element:Show()
elseif(event ~= 'READY_CHECK_FINISHED') then
element.status = nil
element:Hide()
end
if(event == 'READY_CHECK_FINISHED') then
if(element.status == 'waiting') then
element:SetTexture(element.notReadyTexture)
end
element.Animation:Play()
end
--[[ Callback: ReadyCheckIndicator:PostUpdate(status)
Called after the element has been updated.
* self - the ReadyCheckIndicator element
* status - the unit's ready check status (string?)['ready', 'notready', 'waiting']
--]]
if(element.PostUpdate) then
return element:PostUpdate(status)
end
end
local function Path(self, ...)
--[[ Override: ReadyCheckIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.ReadyCheckIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self, unit)
local element = self.ReadyCheckIndicator
unit = unit and unit:match('(%a+)%d*$')
if(element and (unit == 'party' or unit == 'raid')) then
element.__owner = self
element.ForceUpdate = ForceUpdate
element.readyTexture = element.readyTexture or READY_CHECK_READY_TEXTURE
element.notReadyTexture = element.notReadyTexture or READY_CHECK_NOT_READY_TEXTURE
element.waitingTexture = element.waitingTexture or READY_CHECK_WAITING_TEXTURE
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 function Disable(self)
local element = self.ReadyCheckIndicator
if(element) then
element:Hide()
self:UnregisterEvent('READY_CHECK', Path)
self:UnregisterEvent('READY_CHECK_CONFIRM', Path)
self:UnregisterEvent('READY_CHECK_FINISHED', Path)
end
end
oUF:AddElement('ReadyCheckIndicator', Path, Enable, Disable)

View File

@@ -0,0 +1,98 @@
--[[
# Element: Resting Indicator
Toggles the visibility of an indicator based on the player's resting status.
## Widget
RestingIndicator - Any UI widget.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
-- Position and size
local RestingIndicator = self:CreateTexture(nil, 'OVERLAY')
RestingIndicator:SetSize(16, 16)
RestingIndicator:SetPoint('TOPLEFT', self)
-- Register it with oUF
self.RestingIndicator = RestingIndicator
--]]
local _, ns = ...
local oUF = ns.oUF
local function Update(self, event)
local element = self.RestingIndicator
--[[ Callback: RestingIndicator:PreUpdate()
Called before the element has been updated.
* self - the RestingIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local isResting = IsResting()
if(isResting) then
element:Show()
else
element:Hide()
end
--[[ Callback: RestingIndicator:PostUpdate(isResting)
Called after the element has been updated.
* self - the RestingIndicator element
* isResting - indicates if the player is resting (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(isResting)
end
end
local function Path(self, ...)
--[[ Override: RestingIndicator.Override(self, event)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
--]]
return (self.RestingIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self, unit)
local element = self.RestingIndicator
if(element and UnitIsUnit(unit, 'player')) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('PLAYER_UPDATE_RESTING', Path, true)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\CharacterFrame\UI-StateIcon]])
element:SetTexCoord(0, 0.5, 0, 0.421875)
end
return true
end
end
local function Disable(self)
local element = self.RestingIndicator
if(element) then
element:Hide()
self:UnregisterEvent('PLAYER_UPDATE_RESTING', Path)
end
end
oUF:AddElement('RestingIndicator', Path, Enable, Disable)

View File

@@ -0,0 +1,100 @@
--[[
# Element: Resurrect Indicator
Handles the visibility and updating of an indicator based on the unit's incoming resurrect status.
## Widget
ResurrectIndicator - A `Texture` used to display if the unit has an incoming resurrect.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
-- Position and size
local ResurrectIndicator = self:CreateTexture(nil, 'OVERLAY')
ResurrectIndicator:SetSize(16, 16)
ResurrectIndicator:SetPoint('TOPRIGHT', self)
-- Register it with oUF
self.ResurrectIndicator = ResurrectIndicator
--]]
local _, ns = ...
local oUF = ns.oUF
local function Update(self, event, unit)
if(self.unit ~= unit) then return end
local element = self.ResurrectIndicator
--[[ Callback: ResurrectIndicator:PreUpdate()
Called before the element has been updated.
* self - the ResurrectIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local incomingResurrect = UnitHasIncomingResurrection(unit)
if(incomingResurrect) then
element:Show()
else
element:Hide()
end
--[[ Callback: ResurrectIndicator:PostUpdate(incomingResurrect)
Called after the element has been updated.
* self - the ResurrectIndicator element
* incomingResurrect - indicates if the unit has an incoming resurrection (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(incomingResurrect)
end
end
local function Path(self, ...)
--[[ Override: ResurrectIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.ResurrectIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local element = self.ResurrectIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('INCOMING_RESURRECT_CHANGED', Path)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\RaidFrame\Raid-Icon-Rez]])
end
return true
end
end
local function Disable(self)
local element = self.ResurrectIndicator
if(element) then
element:Hide()
self:UnregisterEvent('INCOMING_RESURRECT_CHANGED', Path)
end
end
oUF:AddElement('ResurrectIndicator', Path, Enable, Disable)

View File

@@ -0,0 +1,245 @@
--[[
# Element: Runes
Handles the visibility and updating of Death Knight's runes.
## Widget
Runes - An `table` holding `StatusBar`s.
## Sub-Widgets
.bg - A `Texture` used as a background. It will inherit the color of the main StatusBar.
## Notes
A default texture will be applied if the sub-widgets are StatusBars and don't have a texture set.
## Options
.colorSpec - Use `self.colors.runes[specID]` to color the bar based on player's spec. `specID` is defined by the return
value of [GetSpecialization](http://wowprogramming.com/docs/api/GetSpecialization.html) (boolean)
.sortOrder - Sorting order. Sorts by the remaining cooldown time, 'asc' - from the least cooldown time remaining (fully
charged) to the most (fully depleted), 'desc' - the opposite (string?)['asc', 'desc']
## Sub-Widgets Options
.multiplier - Used to tint the background based on the main widgets R, G and B values. Defaults to 1 (number)[0-1]
## Examples
local Runes = {}
for index = 1, 6 do
-- Position and size of the rune bar indicators
local Rune = CreateFrame('StatusBar', nil, self)
Rune:SetSize(120 / 6, 20)
Rune:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', index * 120 / 6, 0)
Runes[index] = Rune
end
-- Register with oUF
self.Runes = Runes
--]]
if(select(2, UnitClass('player')) ~= 'DEATHKNIGHT') then return end
local _, ns = ...
local oUF = ns.oUF
local runemap = {1, 2, 3, 4, 5, 6}
local hasSortOrder = false
local function onUpdate(self, elapsed)
local duration = self.duration + elapsed
self.duration = duration
self:SetValue(duration)
end
local function ascSort(runeAID, runeBID)
local runeAStart, _, runeARuneReady = GetRuneCooldown(runeAID)
local runeBStart, _, runeBRuneReady = GetRuneCooldown(runeBID)
if(runeARuneReady ~= runeBRuneReady) then
return runeARuneReady
elseif(runeAStart ~= runeBStart) then
return runeAStart < runeBStart
else
return runeAID < runeBID
end
end
local function descSort(runeAID, runeBID)
local runeAStart, _, runeARuneReady = GetRuneCooldown(runeAID)
local runeBStart, _, runeBRuneReady = GetRuneCooldown(runeBID)
if(runeARuneReady ~= runeBRuneReady) then
return runeBRuneReady
elseif(runeAStart ~= runeBStart) then
return runeAStart > runeBStart
else
return runeAID > runeBID
end
end
local function UpdateColor(self, event)
local element = self.Runes
local spec = GetSpecialization() or 0
local color
if(spec > 0 and spec < 4 and element.colorSpec) then
color = self.colors.runes[spec]
else
color = self.colors.power.RUNES
end
local r, g, b = color[1], color[2], color[3]
for index = 1, #element do
element[index]:SetStatusBarColor(r, g, b)
local bg = element[index].bg
if(bg) then
local mu = bg.multiplier or 1
bg:SetVertexColor(r * mu, g * mu, b * mu)
end
end
--[[ Callback: Runes:PostUpdateColor(r, g, b)
Called after the element color has been updated.
* self - the Runes element
* r - the red component of the used color (number)[0-1]
* g - the green component of the used color (number)[0-1]
* b - the blue component of the used color (number)[0-1]
--]]
if(element.PostUpdateColor) then
element:PostUpdateColor(r, g, b)
end
end
local function ColorPath(self, ...)
--[[ Override: Runes.UpdateColor(self, event, ...)
Used to completely override the internal function for updating the widgets' colors.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
(self.Runes.UpdateColor or UpdateColor) (self, ...)
end
local function Update(self, event)
local element = self.Runes
if(element.sortOrder == 'asc') then
table.sort(runemap, ascSort)
hasSortOrder = true
elseif(element.sortOrder == 'desc') then
table.sort(runemap, descSort)
hasSortOrder = true
elseif(hasSortOrder) then
table.sort(runemap)
hasSortOrder = false
end
local rune, start, duration, runeReady
for index, runeID in next, runemap do
rune = element[index]
if(not rune) then break end
if(UnitHasVehicleUI('player')) then
rune:Hide()
else
start, duration, runeReady = GetRuneCooldown(runeID)
if(runeReady) then
rune:SetMinMaxValues(0, 1)
rune:SetValue(1)
rune:SetScript('OnUpdate', nil)
elseif(start) then
rune.duration = GetTime() - start
rune:SetMinMaxValues(0, duration)
rune:SetValue(0)
rune:SetScript('OnUpdate', onUpdate)
end
rune:Show()
end
end
--[[ Callback: Runes:PostUpdate(runemap)
Called after the element has been updated.
* self - the Runes element
* runemap - the ordered list of runes' indices (table)
--]]
if(element.PostUpdate) then
return element:PostUpdate(runemap)
end
end
local function Path(self, ...)
--[[ Override: Runes.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
(self.Runes.Override or Update) (self, ...)
end
local function AllPath(...)
Path(...)
ColorPath(...)
end
local function ForceUpdate(element)
Path(element.__owner, 'ForceUpdate')
ColorPath(element.__owner, 'ForceUpdate')
end
local function Enable(self, unit)
local element = self.Runes
if(element and UnitIsUnit(unit, 'player')) then
element.__owner = self
element.ForceUpdate = ForceUpdate
for i = 1, #element do
local rune = element[i]
if(rune:IsObjectType('StatusBar') and not (rune:GetStatusBarTexture() or rune:GetStatusBarAtlas())) then
rune:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
end
-- ElvUI block
if element.IsObjectType and element:IsObjectType("Frame") then
element:Show()
end
-- end block
self:RegisterEvent('PLAYER_SPECIALIZATION_CHANGED', ColorPath)
self:RegisterEvent('RUNE_POWER_UPDATE', Path, true)
return true
end
end
local function Disable(self)
local element = self.Runes
if(element) then
for i = 1, #element do
element[i]:Hide()
end
-- ElvUI block
if element.IsObjectType and element:IsObjectType("Frame") then
element:Hide()
end
-- end block
self:UnregisterEvent('PLAYER_SPECIALIZATION_CHANGED', ColorPath)
self:UnregisterEvent('RUNE_POWER_UPDATE', Path)
end
end
oUF:AddElement('Runes', AllPath, Enable, Disable)

View File

@@ -0,0 +1,245 @@
--[[
# Element: Monk Stagger Bar
Handles the visibility and updating of the Monk's stagger bar.
## Widget
Stagger - A `StatusBar` used to represent the current stagger level.
## Sub-Widgets
.bg - A `Texture` used as a background. It will inherit the color of the main StatusBar.
## Notes
A default texture will be applied if the widget is a StatusBar and doesn't have a texture set.
## Sub-Widgets Options
.multiplier - Used to tint the background based on the main widgets R, G and B values. Defaults to 1 (number)[0-1]
## Examples
local Stagger = CreateFrame('StatusBar', nil, self)
Stagger:SetSize(120, 20)
Stagger:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', 0, 0)
-- Register with oUF
self.Stagger = Stagger
--]]
if(select(2, UnitClass('player')) ~= 'MONK') then return end
local _, ns = ...
local oUF = ns.oUF
-- ElvUI block
local GetSpecialization = GetSpecialization
local UnitHasVehiclePlayerFrameUI = UnitHasVehiclePlayerFrameUI
local UnitHealthMax = UnitHealthMax
local UnitIsUnit = UnitIsUnit
local UnitStagger = UnitStagger
-- GLOBALS: MonkStaggerBar
-- end block
-- sourced from FrameXML/Constants.lua
local SPEC_MONK_BREWMASTER = SPEC_MONK_BREWMASTER or 1
-- sourced from FrameXML/MonkStaggerBar.lua
local BREWMASTER_POWER_BAR_NAME = BREWMASTER_POWER_BAR_NAME or 'STAGGER'
-- percentages at which bar should change color
local STAGGER_YELLOW_TRANSITION = STAGGER_YELLOW_TRANSITION or 0.3
local STAGGER_RED_TRANSITION = STAGGER_RED_TRANSITION or 0.6
-- 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 function UpdateColor(self, event, unit)
if(unit and unit ~= self.unit) then return end
local element = self.Stagger
local colors = self.colors.power[BREWMASTER_POWER_BAR_NAME]
local perc = (element.cur or 0) / (element.max or 1)
local t
if(perc >= STAGGER_RED_TRANSITION) then
t = colors and colors[STAGGER_RED_INDEX]
elseif(perc > STAGGER_YELLOW_TRANSITION) then
t = colors and colors[STAGGER_YELLOW_INDEX]
else
t = colors and colors[STAGGER_GREEN_INDEX]
end
local r, g, b
if(t) then
r, g, b = t[1], t[2], t[3]
if(b) then
element:SetStatusBarColor(r, g, b)
local bg = element.bg
if(bg and b) then
local mu = bg.multiplier or 1
bg:SetVertexColor(r * mu, g * mu, b * mu)
end
end
end
--[[ Callback: Stagger:PostUpdateColor(r, g, b)
Called after the element color has been updated.
* self - the Stagger element
* r - the red component of the used color (number)[0-1]
* g - the green component of the used color (number)[0-1]
* b - the blue component of the used color (number)[0-1]
--]]
if(element.PostUpdateColor) then
element:PostUpdateColor(r, g, b)
end
end
local function Update(self, event, unit)
if(unit and unit ~= self.unit) then return end
local element = self.Stagger
--[[ Callback: Stagger:PreUpdate()
Called before the element has been updated.
* self - the Stagger element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
-- Blizzard code has nil checks for UnitStagger return
local cur = UnitStagger('player') or 0
local max = UnitHealthMax('player')
element:SetMinMaxValues(0, max)
element:SetValue(cur)
element.cur = cur
element.max = max
--[[ Callback: Stagger:PostUpdate(cur, max)
Called after the element has been updated.
* self - the Stagger element
* cur - the amount of staggered damage (number)
* max - the player's maximum possible health value (number)
--]]
if(element.PostUpdate) then
element:PostUpdate(cur, max)
end
end
local function Path(self, ...)
--[[ Override: Stagger.Override(self, event, unit)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
--]]
(self.Stagger.Override or Update)(self, ...);
--[[ Override: Stagger.UpdateColor(self, event, unit)
Used to completely override the internal function for updating the widgets' colors.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
--]]
(self.Stagger.UpdateColor or UpdateColor) (self, ...)
end
-- ElvUI changed
local function Visibility(self, event, unit)
local element = self.Stagger
local isShown = element:IsShown()
local useClassbar = (SPEC_MONK_BREWMASTER ~= GetSpecialization()) or UnitHasVehiclePlayerFrameUI('player')
local stateChanged = false
if useClassbar and isShown then
element:Hide()
self:UnregisterEvent('UNIT_AURA', Path)
stateChanged = true
elseif not useClassbar and not isShown then
element:Show()
self:RegisterEvent('UNIT_AURA', Path)
stateChanged = true
end
if element.PostVisibility then
element.PostVisibility(self, event, unit, not useClassbar, stateChanged)
end
if not useClassbar then
Path(self, event, unit)
end
end
-- end block
local function VisibilityPath(self, ...)
--[[ Override: Stagger.OverrideVisibility(self, event, unit)
Used to completely override the internal visibility toggling function.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
--]]
(self.Stagger.OverrideVisibility or Visibility)(self, ...)
end
local function ForceUpdate(element)
VisibilityPath(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self, unit)
local element = self.Stagger
if(element and UnitIsUnit(unit, 'player')) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_DISPLAYPOWER', VisibilityPath)
self:RegisterEvent('PLAYER_TALENT_UPDATE', VisibilityPath, true)
if(element:IsObjectType('StatusBar') and not (element:GetStatusBarTexture() or element:GetStatusBarAtlas())) then
element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
MonkStaggerBar:UnregisterEvent('PLAYER_ENTERING_WORLD')
MonkStaggerBar:UnregisterEvent('PLAYER_SPECIALIZATION_CHANGED')
MonkStaggerBar:UnregisterEvent('UNIT_DISPLAYPOWER')
MonkStaggerBar:UnregisterEvent('UNIT_EXITED_VEHICLE')
MonkStaggerBar:UnregisterEvent('UPDATE_VEHICLE_ACTIONBAR')
-- do not change this without taking Visibility into account
element:Hide()
return true
end
end
local function Disable(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:RegisterEvent('PLAYER_ENTERING_WORLD')
MonkStaggerBar:RegisterEvent('PLAYER_SPECIALIZATION_CHANGED')
MonkStaggerBar:RegisterEvent('UNIT_DISPLAYPOWER')
MonkStaggerBar:RegisterEvent('UNIT_EXITED_VEHICLE')
MonkStaggerBar:RegisterEvent('UPDATE_VEHICLE_ACTIONBAR')
end
end
oUF:AddElement('Stagger', VisibilityPath, Enable, Disable)

View File

@@ -0,0 +1,110 @@
--[[
# Element: SummonIndicator
Handles the visibility and updating of an indicator based on the unit's incoming summon status.
## Widget
SummonIndicator - A `Texture` used to display if the unit has an incoming summon.
## Notes
This element updates by changing the texture.
## Examples
-- Position and size
local SummonIndicator = self:CreateTexture(nil, 'OVERLAY')
SummonIndicator:SetSize(32, 32)
SummonIndicator:SetPoint('TOPRIGHT', self)
-- Register it with oUF
self.SummonIndicator = SummonIndicator
--]]
local _, ns = ...
local oUF = ns.oUF
-- sourced from Blizzard_APIDocumentation/IncomingSummonDocumentation.lua
local SUMMON_STATUS_NONE = Enum.SummonStatus.None or 0
local SUMMON_STATUS_PENDING = Enum.SummonStatus.Pending or 1
local SUMMON_STATUS_ACCEPTED = Enum.SummonStatus.Accepted or 2
local SUMMON_STATUS_DECLINED = Enum.SummonStatus.Declined or 3
local function Update(self, event, unit)
if(self.unit ~= unit) then return end
local element = self.SummonIndicator
--[[ Callback: SummonIndicator:PreUpdate()
Called before the element has been updated.
* self - the SummonIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local status = C_IncomingSummon.IncomingSummonStatus(unit)
if(status ~= SUMMON_STATUS_NONE) then
if(status == SUMMON_STATUS_PENDING) then
element:SetAtlas('Raid-Icon-SummonPending')
elseif(status == SUMMON_STATUS_ACCEPTED) then
element:SetAtlas('Raid-Icon-SummonAccepted')
elseif(status == SUMMON_STATUS_DECLINED) then
element:SetAtlas('Raid-Icon-SummonDeclined')
end
element:Show()
else
element:Hide()
end
--[[ Callback: SummonIndicator:PostUpdate(status)
Called after the element has been updated.
* self - the SummonIndicator element
* status - the unit's incoming summon status (number)[0-3]
--]]
if(element.PostUpdate) then
return element:PostUpdate(status)
end
end
local function Path(self, ...)
--[[ Override: SummonIndicator.Override(self, event)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.SummonIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local element = self.SummonIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('INCOMING_SUMMON_CHANGED', Path)
return true
end
end
local function Disable(self)
local element = self.SummonIndicator
if(element) then
element:Hide()
self:UnregisterEvent('INCOMING_SUMMON_CHANGED', Path)
end
end
oUF:AddElement('SummonIndicator', Path, Enable, Disable)

View File

@@ -0,0 +1,977 @@
-- Credits: Vika, Cladhaire, Tekkub
--[[
# Element: Tags
Provides a system for text-based display of information by binding a tag string to a font string widget which in turn is
tied to a unit frame.
## Widget
A FontString to hold a tag string. Unlike other elements, this widget must not have a preset name.
## Notes
A `Tag` is a Lua string consisting of a function name surrounded by square brackets. The tag will be replaced by the
output of the function and displayed as text on the font string widget with that the tag has been registered.
Literals can be pre or appended by separating them with a `>` before or `<` after the function name. The literals will be only
displayed when the function returns a non-nil value. I.e. `"[perhp<%]"` will display the current health as a percentage
of the maximum health followed by the % sign.
A `Tag String` is a Lua string consisting of one or multiple tags with optional literals between them.
Each tag will be updated individually and the output will follow the tags order. Literals will be displayed in the
output string regardless of whether the surrounding tag functions return a value. I.e. `"[curhp]/[maxhp]"` will resolve
to something like `2453/5000`.
A `Tag Function` is used to replace a single tag in a tag string by its output. A tag function receives only two
arguments - the unit and the realUnit of the unit frame used to register the tag (see Options for further details). The
tag function is called when the unit frame is shown or when a specified event has fired. It the tag is registered on an
eventless frame (i.e. one holding the unit "targettarget"), then the tag function is called in a set time interval.
A number of built-in tag functions exist. The layout can also define its own tag functions by adding them to the
`oUF.Tags.Methods` table. The events upon which the function will be called are specified in a white-space separated
list added to the `oUF.Tags.Events` table. Should an event fire without unit information, then it should also be listed
in the `oUF.Tags.SharedEvents` table as follows: `oUF.Tags.SharedEvents.EVENT_NAME = true`.
## Options
.overrideUnit - if specified on the font string widget, the frame's realUnit will be passed as the second argument to
every tag function whose name is contained in the relevant tag string. Otherwise the second argument
is always nil (boolean)
.frequentUpdates - defines how often the corresponding tag function(s) should be called. This will override the events
for the tag(s), if any. If the value is a number, it is taken as a time interval in seconds. If the
value is a boolean, the time interval is set to 0.5 seconds (number or boolean)
## Attributes
.parent - the unit frame on which the tag has been registered
## Examples
-- define the tag function
oUF.Tags.Methods['mylayout:threatname'] = function(unit, realUnit)
local color = _TAGS['threatcolor'](unit)
local name = _TAGS['name'](unit, realUnit)
return string.format('%s%s|r', color, name)
end
-- add the events
oUF.Tags.Events['mylayout:threatname'] = 'UNIT_NAME_UPDATE UNIT_THREAT_SITUATION_UPDATE'
-- create the text widget
local info = self.Health:CreateFontString(nil, 'OVERLAY', 'GameFontNormal')
info:SetPoint('LEFT')
-- register the tag on the text widget with oUF
self:Tag(info, '[mylayout:threatname]')
--]]
local _, ns = ...
local oUF = ns.oUF
local Private = oUF.Private
local unitExists = Private.unitExists
-- ElvUI block
local _G = _G
local CreateFrame = CreateFrame
local hooksecurefunc = hooksecurefunc
local setfenv, getfenv = setfenv, getfenv
local rawget, rawset, select = rawget, rawset, select
local format, tinsert, tremove = format, tinsert, tremove
local next, type, pcall, unpack = next, type, pcall, unpack
local error, assert, loadstring = error, assert, loadstring
-- end block
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
-- ElvUI block
if not r or type(r) == 'string' then --wtf?
return '|cffFFFFFF'
end
-- end block
return format('|cff%02x%02x%02x', r * 255, g * 255, b * 255)
end,
}
_ENV.ColorGradient = function(...)
return _ENV._FRAME:ColorGradient(...)
end
local _PROXY = setmetatable(_ENV, {__index = _G})
local tagStrings = {
['affix'] = [[function(u)
local c = UnitClassification(u)
if(c == 'minus') then
return 'Affix'
end
end]],
['arcanecharges'] = [[function()
if(GetSpecialization() == SPEC_MAGE_ARCANE) then
local num = UnitPower('player', Enum.PowerType.ArcaneCharges)
if(num > 0) then
return num
end
end
end]],
['arenaspec'] = [[function(u)
local id = u:match('arena(%d)$')
if(id) then
local specID = GetArenaOpponentSpec(tonumber(id))
if(specID and specID > 0) then
local _, specName = GetSpecializationInfoByID(specID)
return specName
end
end
end]],
['chi'] = [[function()
if(GetSpecialization() == SPEC_MONK_WINDWALKER) then
local num = UnitPower('player', Enum.PowerType.Chi)
if(num > 0) then
return num
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]],
['cpoints'] = [[function(u)
local cp = UnitPower(u, Enum.PowerType.ComboPoints)
if(cp > 0) then
return cp
end
end]],
['creature'] = [[function(u)
return UnitCreatureFamily(u) or UnitCreatureType(u)
end]],
['curmana'] = [[function(unit)
return UnitPower(unit, Enum.PowerType.Mana)
end]],
['dead'] = [[function(u)
if(UnitIsDead(u)) then
return 'Dead'
elseif(UnitIsGhost(u)) then
return 'Ghost'
end
end]],
['deficit:name'] = [[function(u)
local missinghp = _TAGS['missinghp'](u)
if(missinghp) then
return '-' .. missinghp
else
return _TAGS['name'](u)
end
end]],
['difficulty'] = [[function(u)
if UnitCanAttack('player', u) then
local l = UnitEffectiveLevel(u)
return Hex(GetCreatureDifficultyColor((l > 0) and l or 999))
end
end]],
['group'] = [[function(unit)
local name, server = UnitName(unit)
if(server and server ~= '') then
name = string.format('%s-%s', name, server)
end
for i=1, GetNumGroupMembers() do
local raidName, _, group = GetRaidRosterInfo(i)
if( raidName == name ) then
return group
end
end
end]],
['holypower'] = [[function()
if(GetSpecialization() == SPEC_PALADIN_RETRIBUTION) then
local num = UnitPower('player', Enum.PowerType.HolyPower)
if(num > 0) then
return num
end
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 = UnitEffectiveLevel(u)
if(UnitIsWildBattlePet(u) or UnitIsBattlePetCompanion(u)) then
l = UnitBattlePetLevel(u)
end
if(l > 0) then
return l
else
return '??'
end
end]],
['maxmana'] = [[function(unit)
return UnitPowerMax(unit, Enum.PowerType.Mana)
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]],
['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] or _COLORS.power.MANA)
end
end
return Hex(t)
end]],
['pvp'] = [[function(u)
if(UnitIsPVP(u)) then
return 'PvP'
end
end]],
['raidcolor'] = [[function(u)
local _, class = UnitClass(u)
if(class) then
return Hex(_COLORS.class[class])
else
local id = u:match('arena(%d)$')
if(id) then
local specID = GetArenaOpponentSpec(tonumber(id))
if(specID and specID > 0) then
_, _, _, _, _, class = GetSpecializationInfoByID(specID)
return Hex(_COLORS.class[class])
end
end
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]],
['runes'] = [[function()
local amount = 0
for i = 1, 6 do
local _, _, ready = GetRuneCooldown(i)
if(ready) then
amount = amount + 1
end
end
return amount
end]],
['sex'] = [[function(u)
local s = UnitSex(u)
if(s == 2) then
return 'Male'
elseif(s == 3) then
return 'Female'
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]],
['smartclass'] = [[function(u)
if(UnitIsPlayer(u)) then
return _TAGS['class'](u)
end
return _TAGS['creature'](u)
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]],
['soulshards'] = [[function()
local num = UnitPower('player', Enum.PowerType.SoulShards)
if(num > 0) then
return num
end
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]],
}
local tags = setmetatable(
{
curhp = UnitHealth,
curpp = UnitPower,
maxhp = UnitHealthMax,
maxpp = UnitPowerMax,
class = UnitClass,
faction = UnitFactionGroup,
race = UnitRace,
},
{
__index = function(self, key)
local tagString = tagStrings[key]
if(tagString) then
self[key] = tagString
tagStrings[key] = nil
end
return rawget(self, key)
end,
__newindex = function(self, key, val)
if(type(val) == 'string') then
local func, err = loadstring('return ' .. val)
if(func) then
val = func()
else
error(err, 3)
end
end
assert(type(val) == 'function', 'Tag function must be a function or a string that evaluates to a function.')
-- We don't want to clash with any custom envs
if(getfenv(val) == _G) then
-- pcall is needed for cases when Blizz functions are passed as
-- strings, for intance, 'UnitPowerMax', an attempt to set a
-- custom env will result in an error
pcall(setfenv, val, _PROXY)
end
rawset(self, key, val)
end,
}
)
_ENV._TAGS = tags
local vars = setmetatable({}, {
__newindex = function(self, key, val)
if(type(val) == 'string') then
local func = loadstring('return ' .. val)
if(func) then
val = func() or val
end
end
rawset(self, key, val)
end,
})
_ENV._VARS = vars
-- ElvUI sets UNIT_POWER_UPDATE to UNIT_POWER_FREQUENT in tagEvents
local tagEvents = {
['affix'] = 'UNIT_CLASSIFICATION_CHANGED',
['arcanecharges'] = 'UNIT_POWER_FREQUENT PLAYER_TALENT_UPDATE',
['arenaspec'] = 'ARENA_PREP_OPPONENT_SPECIALIZATIONS',
['chi'] = 'UNIT_POWER_FREQUENT PLAYER_TALENT_UPDATE',
['classification'] = 'UNIT_CLASSIFICATION_CHANGED',
['cpoints'] = 'UNIT_POWER_FREQUENT PLAYER_TARGET_CHANGED',
['curhp'] = 'UNIT_HEALTH UNIT_MAXHEALTH',
['curmana'] = 'UNIT_POWER_FREQUENT UNIT_MAXPOWER',
['curpp'] = 'UNIT_POWER_FREQUENT UNIT_MAXPOWER',
['dead'] = 'UNIT_HEALTH',
['deficit:name'] = 'UNIT_HEALTH UNIT_MAXHEALTH UNIT_NAME_UPDATE',
['difficulty'] = 'UNIT_FACTION',
['faction'] = 'NEUTRAL_FACTION_SELECT_RESULT',
['group'] = 'GROUP_ROSTER_UPDATE',
['holypower'] = 'UNIT_POWER_FREQUENT PLAYER_TALENT_UPDATE',
['leader'] = 'PARTY_LEADER_CHANGED',
['leaderlong'] = 'PARTY_LEADER_CHANGED',
['level'] = 'UNIT_LEVEL PLAYER_LEVEL_UP',
['maxhp'] = 'UNIT_MAXHEALTH',
['maxmana'] = 'UNIT_POWER_FREQUENT UNIT_MAXPOWER',
['maxpp'] = 'UNIT_MAXPOWER',
['missinghp'] = 'UNIT_HEALTH UNIT_MAXHEALTH',
['missingpp'] = 'UNIT_MAXPOWER UNIT_POWER_FREQUENT',
['name'] = 'UNIT_NAME_UPDATE',
['offline'] = 'UNIT_HEALTH UNIT_CONNECTION',
['perhp'] = 'UNIT_HEALTH UNIT_MAXHEALTH',
['perpp'] = 'UNIT_MAXPOWER UNIT_POWER_FREQUENT',
['plus'] = 'UNIT_CLASSIFICATION_CHANGED',
['powercolor'] = 'UNIT_DISPLAYPOWER',
['pvp'] = 'UNIT_FACTION',
['rare'] = 'UNIT_CLASSIFICATION_CHANGED',
['resting'] = 'PLAYER_UPDATE_RESTING',
['runes'] = 'RUNE_POWER_UPDATE',
['shortclassification'] = 'UNIT_CLASSIFICATION_CHANGED',
['smartlevel'] = 'UNIT_LEVEL PLAYER_LEVEL_UP UNIT_CLASSIFICATION_CHANGED',
['soulshards'] = 'UNIT_POWER_FREQUENT',
['status'] = 'UNIT_HEALTH PLAYER_UPDATE_RESTING UNIT_CONNECTION',
['threat'] = 'UNIT_THREAT_SITUATION_UPDATE',
['threatcolor'] = 'UNIT_THREAT_SITUATION_UPDATE',
}
local unitlessEvents = {
ARENA_PREP_OPPONENT_SPECIALIZATIONS = true,
GROUP_ROSTER_UPDATE = true,
NEUTRAL_FACTION_SELECT_RESULT = true,
PARTY_LEADER_CHANGED = true,
PLAYER_LEVEL_UP = true,
PLAYER_TARGET_CHANGED = true,
PLAYER_UPDATE_RESTING = true,
RUNE_POWER_UPDATE = true,
}
local events = {}
local eventFrame = CreateFrame('Frame')
eventFrame:SetScript('OnEvent', function(self, event, unit)
local strings = events[event]
if(strings) then
for _, fs in next, strings do
if(fs:IsVisible() and (unitlessEvents[event] or fs.parent.unit == unit or (fs.extraUnits and fs.extraUnits[unit]))) then
fs:UpdateTag()
end
end
end
end)
local onUpdates = {}
local eventlessUnits = {}
local function createOnUpdate(timer)
if(not onUpdates[timer]) then
local total = timer
local frame = CreateFrame('Frame')
local strings = eventlessUnits[timer]
frame:SetScript('OnUpdate', function(self, elapsed)
if(total >= timer) then
for _, fs in next, strings do
if(fs.parent:IsShown() and unitExists(fs.parent.unit)) then
fs:UpdateTag()
end
end
total = 0
end
total = total + elapsed
end)
onUpdates[timer] = frame
end
end
--[[ Tags: frame:UpdateTags()
Used to update all tags on a frame.
* self - the unit frame from which to update the tags
--]]
local function Update(self)
if(self.__tags) then
for fs in next, self.__tags do
fs:UpdateTag()
end
end
end
-- ElvUI block
local onEnter = function(self) for fs in next, self.__mousetags do fs:SetAlpha(1) end end
local onLeave = function(self) for fs in next, self.__mousetags do fs:SetAlpha(0) end end
local onUpdateDelay = {}
local escapeSequences = {
["||c"] = "|c",
["||r"] = "|r",
["||T"] = "|T",
["||t"] = "|t",
}
-- end block
local tagPool = {}
local funcPool = {}
local tmp = {}
local function getTagName(tag)
local tagStart = tag:match('>+()') or 2
local tagEnd = (tag:match('.-()<') or -1) - 1
return tag:sub(tagStart, tagEnd), tagStart, tagEnd
end
local function getTagFunc(tagstr)
local func = tagPool[tagstr]
if(not func) then
local frmt, 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, tagStart, tagEnd = getTagName(bracket)
local tag = tags[tagName]
if(tag) then
tagStart = tagStart - 2
tagEnd = tagEnd + 2
if(tagStart ~= 0 and tagEnd ~= 0) then
local prefix = bracket:sub(2, tagStart)
local suffix = bracket:sub(tagEnd, -2)
tagFunc = function(unit, realUnit)
local str = tag(unit, realUnit)
if(str) then
return prefix .. str .. suffix
end
end
elseif(tagStart ~= 0) then
local prefix = bracket:sub(2, tagStart)
tagFunc = function(unit, realUnit)
local str = tag(unit, realUnit)
if(str) then
return prefix .. str
end
end
elseif(tagEnd ~= 0) then
local suffix = bracket:sub(tagEnd, -2)
tagFunc = function(unit, realUnit)
local str = tag(unit, realUnit)
if(str) then
return str .. suffix
end
end
end
funcPool[bracket] = tagFunc
end
end
-- ElvUI changed
if(tagFunc) then
tinsert(args, tagFunc)
else
numTags = -1
func = function(self)
self:SetText(bracket)
end
end
-- end block
end
-- ElvUI changed
if numTags ~= -1 then
func = function(self)
local parent = self.parent
local unit = parent.unit
local customArgs = parent.__customargs
local realUnit = self.overrideUnit and parent.realUnit
_ENV._COLORS = parent.colors
_ENV._FRAME = parent
for i, fnc in next, args do
tmp[i] = fnc(unit, realUnit, customArgs[self]) or ''
end
-- We do 1, numTags because tmp can hold several unneeded variables.
self:SetFormattedText(frmt, unpack(tmp, 1, numTags))
end
tagPool[tagstr] = func
end
-- end block
end
return func
end
local function registerEvent(fontstr, event)
if(not events[event]) then events[event] = {} end
eventFrame:RegisterEvent(event)
tinsert(events[event], fontstr)
end
local function registerEvents(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 function unregisterEvents(fontstr)
for event, data in next, events do
for i, tagfsstr in next, data do
if(tagfsstr == fontstr) then
if(#data == 1) then
eventFrame:UnregisterEvent(event)
end
tremove(data, i)
end
end
end
end
-- this bullshit is to fix texture strings not adjusting to its inherited alpha
-- it is a blizzard issue with how texture strings are rendered
local alphaFix = CreateFrame('Frame')
alphaFix.fontStrings = {}
alphaFix:SetScript('OnUpdate', function()
local strs = alphaFix.fontStrings
if next(strs) then
for fs in next, strs do
strs[fs] = nil
local a = fs:GetAlpha()
fs:SetAlpha(0)
fs:SetAlpha(a)
end
else
alphaFix:Hide()
end
end)
local function fixAlpha(self)
alphaFix.fontStrings[self] = true
alphaFix:Show()
end
local taggedFS = {}
--[[ Tags: frame:Tag(fs, tagstr, ...)
Used to register a tag on a unit frame.
* self - the unit frame on which to register the tag
* fs - the font string to display the tag (FontString)
* tagstr - the tag string (string)
* ... - additional optional unitID(s) the tag should update for
--]]
local function Tag(self, fs, tagstr, ...)
if(not fs or not tagstr) then return end
if(not self.__tags) then
self.__tags = {}
self.__mousetags = {} -- ElvUI
self.__customargs = {} -- ElvUI
tinsert(self.__elements, Update)
elseif(self.__tags[fs]) then
-- We don't need to remove it from the __tags table as Untag handles
-- that for us.
self:Untag(fs)
end
-- ElvUI
if not fs.__HookedAlphaFix then
hooksecurefunc(fs, 'SetText', fixAlpha)
hooksecurefunc(fs, 'SetFormattedText', fixAlpha)
fs.__HookedAlphaFix = true
end
for escapeSequence, replacement in next, escapeSequences do
while tagstr:find(escapeSequence) do
tagstr = tagstr:gsub(escapeSequence, replacement)
end
end
local customArgs = tagstr:match('{(.-)}%]')
if customArgs then
self.__customargs[fs] = customArgs
tagstr = tagstr:gsub('{.-}%]', ']')
else
self.__customargs[fs] = nil
end
if tagstr:find('%[mouseover%]') then
self.__mousetags[fs] = true
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 fontString in next, self.__mousetags do
if fontString == fs then
self.__mousetags[fontString] = nil
fs:SetAlpha(1)
end
end
end
local containsOnUpdate
for tag in tagstr:gmatch(_PATTERN) do
tag = getTagName(tag)
if not tagEvents[tag] then
containsOnUpdate = onUpdateDelay[tag] or 0.15;
end
end
-- end block
fs.parent = self
fs.UpdateTag = getTagFunc(tagstr)
if(self.__eventless or fs.frequentUpdates) or containsOnUpdate then -- ElvUI changed
local timer
if(type(fs.frequentUpdates) == 'number') then
timer = fs.frequentUpdates
-- ElvUI added check
elseif containsOnUpdate then
timer = containsOnUpdate
-- end block
else
timer = .5
end
if(not eventlessUnits[timer]) then eventlessUnits[timer] = {} end
tinsert(eventlessUnits[timer], fs)
createOnUpdate(timer)
else
registerEvents(fs, tagstr)
if(...) then
if(not fs.extraUnits) then
fs.extraUnits = {}
end
for index = 1, select('#', ...) do
fs.extraUnits[select(index, ...)] = true
end
end
end
taggedFS[fs] = tagstr
self.__tags[fs] = true
end
--[[ Tags: frame:Untag(fs)
Used to unregister a tag from a unit frame.
* self - the unit frame from which to unregister the tag
* fs - the font string holding the tag (FontString)
--]]
local function Untag(self, fs)
if(not fs or not self.__tags) then return end
unregisterEvents(fs)
for _, timers in next, eventlessUnits do
for i, fontstr in next, timers do
if(fs == fontstr) then
tremove(timers, i)
end
end
end
fs.UpdateTag = nil
taggedFS[fs] = nil
self.__tags[fs] = nil
end
oUF.Tags = {
Methods = tags,
Events = tagEvents,
SharedEvents = unitlessEvents,
OnUpdateThrottle = onUpdateDelay, -- ElvUI
Vars = vars,
RefreshMethods = function(self, tag)
if(not tag) then return end
funcPool['[' .. tag .. ']'] = nil
-- If a tag's name contains magic chars, there's a chance that
-- string.match will fail to find the match.
tag = '%[' .. tag:gsub('[%^%$%(%)%%%.%*%+%-%?]', '%%%1') .. '%]'
for tagstr, func in next, tagPool do
if(tagstr:gsub("%[[^%[%]]*>", "["):gsub("<[^%[%]]*%]", "]"):match(tag)) then
tagPool[tagstr] = nil
for fs in next, taggedFS do
if(fs.UpdateTag == func) then
fs.UpdateTag = getTagFunc(tagstr)
if(fs:IsVisible()) then
fs:UpdateTag()
end
end
end
end
end
end,
RefreshEvents = function(self, tag)
if(not tag) then return end
-- If a tag's name contains magic chars, there's a chance that
-- string.match will fail to find the match.
tag = '%[' .. tag:gsub('[%^%$%(%)%%%.%*%+%-%?]', '%%%1') .. '%]'
for tagstr in next, tagPool do
if(tagstr:gsub("%[[^%[%]]*>", "["):gsub("<[^%[%]]*%]", "]"):match(tag)) then
for fs, ts in next, taggedFS do
if(ts == tagstr) then
unregisterEvents(fs)
registerEvents(fs, tagstr)
end
end
end
end
end,
}
oUF:RegisterMetaFunction('Tag', Tag)
oUF:RegisterMetaFunction('Untag', Untag)
oUF:RegisterMetaFunction('UpdateTags', Update)

View File

@@ -0,0 +1,132 @@
--[[
# Element: Threat Indicator
Handles the visibility and updating of an indicator based on the unit's current threat level.
## Widget
ThreatIndicator - A `Texture` used to display the current threat level.
The element works by changing the texture's vertex color.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Options
.feedbackUnit - The unit whose threat situation is being requested. If defined, it'll be passed as the first argument to
[UnitThreatSituation](https://wow.gamepedia.com/API_UnitThreatSituation).
## Examples
-- Position and size
local ThreatIndicator = self:CreateTexture(nil, 'OVERLAY')
ThreatIndicator:SetSize(16, 16)
ThreatIndicator:SetPoint('TOPRIGHT', self)
-- Register it with oUF
self.ThreatIndicator = ThreatIndicator
--]]
local _, ns = ...
local oUF = ns.oUF
local Private = oUF.Private
local unitExists = Private.unitExists
local function Update(self, event, unit)
if(unit ~= self.unit) then return end
local element = self.ThreatIndicator
--[[ Callback: ThreatIndicator:PreUpdate(unit)
Called before the element has been updated.
* self - the ThreatIndicator element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PreUpdate) then element:PreUpdate(unit) end
local feedbackUnit = element.feedbackUnit
unit = unit or self.unit
local status
-- BUG: Non-existent '*target' or '*pet' units cause UnitThreatSituation() errors
if(unitExists(unit)) then
if(feedbackUnit and feedbackUnit ~= unit and unitExists(feedbackUnit)) then
status = UnitThreatSituation(feedbackUnit, unit)
else
status = UnitThreatSituation(unit)
end
end
local r, g, b
if(status and status > 0) then
r, g, b = unpack(self.colors.threat[status])
if(element.SetVertexColor) then
element:SetVertexColor(r, g, b)
end
element:Show()
else
element:Hide()
end
--[[ Callback: ThreatIndicator:PostUpdate(unit, status, r, g, b)
Called after the element has been updated.
* self - the ThreatIndicator element
* unit - the unit for which the update has been triggered (string)
* status - the unit's threat status (see [UnitThreatSituation](http://wowprogramming.com/docs/api/UnitThreatSituation.html))
* r - the red color component based on the unit's threat status (number?)[0-1]
* g - the green color component based on the unit's threat status (number?)[0-1]
* b - the blue color component based on the unit's threat status (number?)[0-1]
--]]
if(element.PostUpdate) then
return element:PostUpdate(unit, status, r, g, b)
end
end
local function Path(self, ...)
--[[ Override: ThreatIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.ThreatIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local element = self.ThreatIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_THREAT_SITUATION_UPDATE', Path)
self:RegisterEvent('UNIT_THREAT_LIST_UPDATE', Path)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\RAIDFRAME\UI-RaidFrame-Threat]])
end
return true
end
end
local function Disable(self)
local element = self.ThreatIndicator
if(element) then
element:Hide()
self:UnregisterEvent('UNIT_THREAT_SITUATION_UPDATE', Path)
self:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', Path)
end
end
oUF:AddElement('ThreatIndicator', Path, Enable, Disable)

View File

@@ -0,0 +1,190 @@
--[[
# Element: Totem Indicator
Handles the updating and visibility of totems.
## Widget
Totems - A `table` to hold sub-widgets.
## Sub-Widgets
Totem - Any UI widget.
## Sub-Widget Options
.Icon - A `Texture` representing the totem icon.
.Cooldown - A `Cooldown` representing the duration of the totem.
## Notes
OnEnter and OnLeave script handlers will be set to display a Tooltip if the `Totem` widget is mouse enabled.
## Examples
local Totems = {}
for index = 1, 5 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
--]]
local _, ns = ...
local oUF = ns.oUF
local GameTooltip = GameTooltip
local function UpdateTooltip(self)
if GameTooltip:IsForbidden() then return end
GameTooltip:SetTotem(self:GetID())
end
local function OnEnter(self)
if GameTooltip:IsForbidden() or not self:IsVisible() then return end
GameTooltip:SetOwner(self, 'ANCHOR_BOTTOMRIGHT')
self:UpdateTooltip()
end
local function OnLeave()
if GameTooltip:IsForbidden() then return end
GameTooltip:Hide()
end
local function UpdateTotem(self, event, slot)
local element = self.Totems
if(slot > #element) then return end
--[[ Callback: Totems:PreUpdate(slot)
Called before the element has been updated.
* self - the Totems element
* slot - the slot of the totem to be updated (number)
--]]
if(element.PreUpdate) then element:PreUpdate(slot) end
local totem = element[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
--[[ Callback: Totems:PostUpdate(slot, haveTotem, name, start, duration, icon)
Called after the element has been updated.
* self - the Totems element
* slot - the slot of the updated totem (number)
* haveTotem - indicates if a totem is present in the given slot (boolean)
* name - the name of the totem (string)
* start - the value of `GetTime()` when the totem was created (number)
* duration - the total duration for which the totem should last (number)
* icon - the totem's icon (Texture)
--]]
if(element.PostUpdate) then
return element:PostUpdate(slot, haveTotem, name, start, duration, icon)
end
end
local function Path(self, ...)
--[[ Override: Totem.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.Totems.Override or UpdateTotem) (self, ...)
end
local function Update(self, event)
for i = 1, #self.Totems do
Path(self, event, i)
end
end
local function ForceUpdate(element)
return Update(element.__owner, 'ForceUpdate')
end
local function Enable(self)
local element = self.Totems
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
for i = 1, #element do
local totem = element[i]
totem:SetID(i)
if(totem:IsMouseEnabled()) then
totem:SetScript('OnEnter', OnEnter)
totem:SetScript('OnLeave', OnLeave)
--[[ Override: Totems[slot]:UpdateTooltip()
Used to populate the tooltip when the totem is hovered.
* self - the widget at the given slot index
--]]
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 function Disable(self)
local element = self.Totems
if(element) then
for i = 1, #element do
element[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)