ElvUI/Libraries/oUF_Plugins/oUF_Fader/oUF_Fader.lua

347 lines
8.9 KiB
Lua
Raw Permalink Normal View History

2020-11-13 14:27:50 -05:00
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)