347 lines
8.9 KiB
Lua
347 lines
8.9 KiB
Lua
|
local _, ns = ...
|
||
|
local oUF = _G.oUF or ns.oUF
|
||
|
assert(oUF, "oUF_Fader cannot find an instance of oUF. If your oUF is embedded into a layout, it may not be embedded properly.")
|
||
|
|
||
|
-------------
|
||
|
-- Credits -- p3lim, Azilroka, Simpy
|
||
|
-------------
|
||
|
|
||
|
local _G = _G
|
||
|
local pairs, ipairs, type = pairs, ipairs, type
|
||
|
local next, tinsert, tremove = next, tinsert, tremove
|
||
|
local CreateFrame = CreateFrame
|
||
|
local GetMouseFocus = GetMouseFocus
|
||
|
local UnitAffectingCombat = UnitAffectingCombat
|
||
|
local UnitCastingInfo = UnitCastingInfo
|
||
|
local UnitChannelInfo = UnitChannelInfo
|
||
|
local UnitExists = UnitExists
|
||
|
local UnitHasVehicleUI = UnitHasVehicleUI
|
||
|
local UnitHealth = UnitHealth
|
||
|
local UnitHealthMax = UnitHealthMax
|
||
|
local UnitPower = UnitPower
|
||
|
local UnitPowerMax = UnitPowerMax
|
||
|
local UnitPowerType = UnitPowerType
|
||
|
|
||
|
-- These variables will be left-over when disabled if they were used (for reuse later if they become re-enabled):
|
||
|
---- Fader.HoverHooked, Fader.TargetHooked
|
||
|
|
||
|
local E -- ElvUI engine defined in ClearTimers
|
||
|
local MIN_ALPHA, MAX_ALPHA = .35, 1
|
||
|
local onRangeObjects, onRangeFrame = {}
|
||
|
local PowerTypesFull = {MANA = true, FOCUS = true, ENERGY = true}
|
||
|
|
||
|
local function ClearTimers(element)
|
||
|
if not E then E = _G.ElvUI[1] end
|
||
|
|
||
|
if element.configTimer then
|
||
|
E:CancelTimer(element.configTimer)
|
||
|
element.configTimer = nil
|
||
|
end
|
||
|
|
||
|
if element.delayTimer then
|
||
|
E:CancelTimer(element.delayTimer)
|
||
|
element.delayTimer = nil
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function ToggleAlpha(self, element, endAlpha)
|
||
|
element:ClearTimers()
|
||
|
|
||
|
if element.Smooth then
|
||
|
E:UIFrameFadeOut(self, element.Smooth, self:GetAlpha(), endAlpha)
|
||
|
else
|
||
|
self:SetAlpha(endAlpha)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function Update(self, _, unit)
|
||
|
local element = self.Fader
|
||
|
if self.isForced or (not element or not element.count or element.count <= 0) then
|
||
|
self:SetAlpha(1)
|
||
|
return
|
||
|
end
|
||
|
|
||
|
unit = unit or self.unit
|
||
|
|
||
|
-- range fader
|
||
|
if element.Range then
|
||
|
if element.UpdateRange then
|
||
|
element.UpdateRange(self, unit)
|
||
|
end
|
||
|
if element.RangeAlpha then
|
||
|
ToggleAlpha(self, element, element.RangeAlpha)
|
||
|
end
|
||
|
return
|
||
|
end
|
||
|
|
||
|
-- normal fader
|
||
|
local _, powerType
|
||
|
if element.Power then
|
||
|
_, powerType = UnitPowerType(unit)
|
||
|
end
|
||
|
|
||
|
if
|
||
|
(element.Casting and (UnitCastingInfo(unit) or UnitChannelInfo(unit))) or
|
||
|
(element.Combat and UnitAffectingCombat(unit)) or
|
||
|
(element.PlayerTarget and UnitExists('target')) or
|
||
|
(element.UnitTarget and UnitExists(unit..'target')) or
|
||
|
(element.Focus and UnitExists('focus')) or
|
||
|
(element.Health and UnitHealth(unit) < UnitHealthMax(unit)) or
|
||
|
(element.Power and (PowerTypesFull[powerType] and UnitPower(unit) < UnitPowerMax(unit))) or
|
||
|
(element.Vehicle and UnitHasVehicleUI(unit)) or
|
||
|
(element.Hover and GetMouseFocus() == (self.__faderobject or self))
|
||
|
then
|
||
|
ToggleAlpha(self, element, element.MaxAlpha)
|
||
|
else
|
||
|
if element.Delay then
|
||
|
if element.DelayAlpha then
|
||
|
ToggleAlpha(self, element, element.DelayAlpha)
|
||
|
end
|
||
|
|
||
|
element:ClearTimers()
|
||
|
element.delayTimer = E:ScheduleTimer(ToggleAlpha, element.Delay, self, element, element.MinAlpha)
|
||
|
else
|
||
|
ToggleAlpha(self, element, element.MinAlpha)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function ForceUpdate(element)
|
||
|
return Update(element.__owner, "ForceUpdate", element.__owner.unit)
|
||
|
end
|
||
|
|
||
|
local function onRangeUpdate(frame, elapsed)
|
||
|
frame.timer = (frame.timer or 0) + elapsed
|
||
|
|
||
|
if (frame.timer >= .20) then
|
||
|
for _, object in next, onRangeObjects do
|
||
|
if object:IsVisible() then
|
||
|
object.Fader:ForceUpdate()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
frame.timer = 0
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function HoverScript(self)
|
||
|
local Fader = self.__faderelement or self.Fader
|
||
|
if Fader and Fader.HoverHooked == 1 then
|
||
|
Fader:ForceUpdate()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function TargetScript(self)
|
||
|
if self.Fader and self.Fader.TargetHooked == 1 then
|
||
|
if self:IsShown() then
|
||
|
self.Fader:ForceUpdate()
|
||
|
else
|
||
|
self:SetAlpha(0)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local options = {
|
||
|
Range = {
|
||
|
enable = function(self)
|
||
|
if not onRangeFrame then
|
||
|
onRangeFrame = CreateFrame('Frame')
|
||
|
onRangeFrame:SetScript('OnUpdate', onRangeUpdate)
|
||
|
end
|
||
|
|
||
|
onRangeFrame:Show()
|
||
|
tinsert(onRangeObjects, self)
|
||
|
end,
|
||
|
disable = function(self)
|
||
|
if onRangeFrame then
|
||
|
for idx, obj in next, onRangeObjects do
|
||
|
if obj == self then
|
||
|
self.Fader.RangeAlpha = nil
|
||
|
tremove(onRangeObjects, idx)
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if #onRangeObjects == 0 then
|
||
|
onRangeFrame:Hide()
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
},
|
||
|
Hover = {
|
||
|
enable = function(self)
|
||
|
if not self.Fader.HoverHooked then
|
||
|
local Frame = self.__faderobject or self
|
||
|
Frame:HookScript('OnEnter', HoverScript)
|
||
|
Frame:HookScript('OnLeave', HoverScript)
|
||
|
end
|
||
|
|
||
|
self.Fader.HoverHooked = 1 -- on state
|
||
|
end,
|
||
|
disable = function(self)
|
||
|
if self.Fader.HoverHooked == 1 then
|
||
|
self.Fader.HoverHooked = 0 -- off state
|
||
|
end
|
||
|
end
|
||
|
},
|
||
|
Combat = {
|
||
|
enable = function(self)
|
||
|
self:RegisterEvent('PLAYER_REGEN_ENABLED', Update, true)
|
||
|
self:RegisterEvent('PLAYER_REGEN_DISABLED', Update, true)
|
||
|
self:RegisterEvent('UNIT_FLAGS', Update)
|
||
|
end,
|
||
|
events = {'PLAYER_REGEN_ENABLED','PLAYER_REGEN_DISABLED','UNIT_FLAGS'}
|
||
|
},
|
||
|
Target = { --[[ UnitTarget, PlayerTarget ]]
|
||
|
enable = function(self)
|
||
|
if not self.Fader.TargetHooked then
|
||
|
self:HookScript('OnShow', TargetScript)
|
||
|
self:HookScript('OnHide', TargetScript)
|
||
|
end
|
||
|
|
||
|
self.Fader.TargetHooked = 1 -- on state
|
||
|
|
||
|
if not self:IsShown() then
|
||
|
self:SetAlpha(0)
|
||
|
end
|
||
|
|
||
|
self:RegisterEvent('UNIT_TARGET', Update)
|
||
|
self:RegisterEvent('PLAYER_TARGET_CHANGED', Update, true)
|
||
|
self:RegisterEvent('PLAYER_FOCUS_CHANGED', Update, true)
|
||
|
end,
|
||
|
events = {'UNIT_TARGET','PLAYER_TARGET_CHANGED','PLAYER_FOCUS_CHANGED'},
|
||
|
disable = function(self)
|
||
|
if self.Fader.TargetHooked == 1 then
|
||
|
self.Fader.TargetHooked = 0 -- off state
|
||
|
end
|
||
|
end
|
||
|
},
|
||
|
Focus = {
|
||
|
enable = function(self)
|
||
|
self:RegisterEvent('PLAYER_FOCUS_CHANGED', Update, true)
|
||
|
end,
|
||
|
events = {'PLAYER_FOCUS_CHANGED'}
|
||
|
},
|
||
|
Health = {
|
||
|
enable = function(self)
|
||
|
self:RegisterEvent('UNIT_HEALTH', Update)
|
||
|
self:RegisterEvent('UNIT_MAXHEALTH', Update)
|
||
|
end,
|
||
|
events = {'UNIT_HEALTH','UNIT_MAXHEALTH'}
|
||
|
},
|
||
|
Power = {
|
||
|
enable = function(self)
|
||
|
self:RegisterEvent('UNIT_POWER_UPDATE', Update)
|
||
|
self:RegisterEvent('UNIT_MAXPOWER', Update)
|
||
|
end,
|
||
|
events = {'UNIT_POWER_UPDATE','UNIT_MAXPOWER'}
|
||
|
},
|
||
|
Vehicle = {
|
||
|
enable = function(self)
|
||
|
self:RegisterEvent('UNIT_ENTERED_VEHICLE', Update, true)
|
||
|
self:RegisterEvent('UNIT_EXITED_VEHICLE', Update, true)
|
||
|
end,
|
||
|
events = {'UNIT_ENTERED_VEHICLE','UNIT_EXITED_VEHICLE'}
|
||
|
},
|
||
|
Casting = {
|
||
|
enable = function(self)
|
||
|
self:RegisterEvent('UNIT_SPELLCAST_START', Update)
|
||
|
self:RegisterEvent('UNIT_SPELLCAST_FAILED', Update)
|
||
|
self:RegisterEvent('UNIT_SPELLCAST_STOP', Update)
|
||
|
self:RegisterEvent('UNIT_SPELLCAST_INTERRUPTED', Update)
|
||
|
self:RegisterEvent('UNIT_SPELLCAST_CHANNEL_START', Update)
|
||
|
self:RegisterEvent('UNIT_SPELLCAST_CHANNEL_STOP', Update)
|
||
|
end,
|
||
|
events = {'UNIT_SPELLCAST_START','UNIT_SPELLCAST_FAILED','UNIT_SPELLCAST_STOP','UNIT_SPELLCAST_INTERRUPTED','UNIT_SPELLCAST_CHANNEL_START','UNIT_SPELLCAST_CHANNEL_STOP'}
|
||
|
},
|
||
|
MinAlpha = {
|
||
|
countIgnored = true,
|
||
|
enable = function(self, state)
|
||
|
self.Fader.MinAlpha = state or MIN_ALPHA
|
||
|
end
|
||
|
},
|
||
|
MaxAlpha = {
|
||
|
countIgnored = true,
|
||
|
enable = function(self, state)
|
||
|
self.Fader.MaxAlpha = state or MAX_ALPHA
|
||
|
end
|
||
|
},
|
||
|
Smooth = {countIgnored = true},
|
||
|
DelayAlpha = {countIgnored = true},
|
||
|
Delay = {countIgnored = true},
|
||
|
}
|
||
|
|
||
|
local function CountOption(element, state, oldState)
|
||
|
if state and not oldState then
|
||
|
element.count = (element.count or 0) + 1
|
||
|
elseif oldState and element.count and not state then
|
||
|
element.count = element.count - 1
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function SetOption(element, opt, state)
|
||
|
local option = ((opt == 'UnitTarget' or opt == 'PlayerTarget') and 'Target') or opt
|
||
|
local oldState = element[opt]
|
||
|
|
||
|
if option and options[option] and (oldState ~= state) then
|
||
|
element[opt] = state
|
||
|
|
||
|
if state then
|
||
|
if type(state) == 'table' then
|
||
|
state.__faderelement = element
|
||
|
element.__owner.__faderobject = state
|
||
|
end
|
||
|
|
||
|
if options[option].enable then
|
||
|
options[option].enable(element.__owner, state)
|
||
|
end
|
||
|
else
|
||
|
if options[option].events and next(options[option].events) then
|
||
|
for _, event in ipairs(options[option].events) do
|
||
|
element.__owner:UnregisterEvent(event, Update)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if options[option].disable then
|
||
|
options[option].disable(element.__owner)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if not options[option].countIgnored then
|
||
|
CountOption(element, state, oldState)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function Enable(self)
|
||
|
if self.Fader then
|
||
|
self.Fader.__owner = self
|
||
|
self.Fader.ForceUpdate = ForceUpdate
|
||
|
self.Fader.SetOption = SetOption
|
||
|
self.Fader.ClearTimers = ClearTimers
|
||
|
|
||
|
self.Fader.MinAlpha = MIN_ALPHA
|
||
|
self.Fader.MaxAlpha = MAX_ALPHA
|
||
|
|
||
|
return true
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function Disable(self)
|
||
|
if self.Fader then
|
||
|
for opt in pairs(options) do
|
||
|
if opt == 'Target' then
|
||
|
self.Fader:SetOption('UnitTarget')
|
||
|
self.Fader:SetOption('PlayerTarget')
|
||
|
else
|
||
|
self.Fader:SetOption(opt)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
self.Fader.count = nil
|
||
|
self.Fader:ClearTimers()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
oUF:AddElement('Fader', nil, Enable, Disable)
|