---------------------------------------------------------------
-- Animation.lua: Taint-free animation replacement
---------------------------------------------------------------
-- Provides a replacement for managing alpha animations without
-- risk of spreading taint, which might happen when the "real"
-- functions are called from secure code.
local _, db = ...
---------------------------------------------------------------
-- Fade: Taint-free fade functions
---------------------------------------------------------------
local FADEFRAMES = {}
local FadeManager = CreateFrame("Frame")
local function FadeRemoveFrame(frame)
tDeleteItem(FADEFRAMES, frame)
end
local function FadeOnUpdate(self, elapsed)
local index = 1
local frame, fadeInfo
while FADEFRAMES[index] do
frame = FADEFRAMES[index]
fadeInfo = FADEFRAMES[index].fadeInfo
-- Reset the timer if there isn't one, this is just an internal counter
if ( not fadeInfo.fadeTimer ) then
fadeInfo.fadeTimer = 0
end
fadeInfo.fadeTimer = fadeInfo.fadeTimer + elapsed
-- If the fadeTimer is less then the desired fade time then set the alpha otherwise hold the fade state, call the finished function, or just finish the fade
if fadeInfo.fadeTimer < fadeInfo.timeToFade then
if fadeInfo.mode == "IN" then
frame:SetAlpha((fadeInfo.fadeTimer / fadeInfo.timeToFade) * (fadeInfo.endAlpha - fadeInfo.startAlpha) + fadeInfo.startAlpha)
elseif fadeInfo.mode == "OUT" then
frame:SetAlpha(((fadeInfo.timeToFade - fadeInfo.fadeTimer) / fadeInfo.timeToFade) * (fadeInfo.startAlpha - fadeInfo.endAlpha) + fadeInfo.endAlpha)
end
else
frame:SetAlpha(fadeInfo.endAlpha)
-- If there is a fadeHoldTime then wait until its passed to continue on
if fadeInfo.fadeHoldTime and fadeInfo.fadeHoldTime > 0 then
fadeInfo.fadeHoldTime = fadeInfo.fadeHoldTime - elapsed
else
-- Complete the fade and call the finished function if there is one
FadeRemoveFrame(frame)
if fadeInfo.finishedFunc then
fadeInfo.finishedFunc(fadeInfo.finishedArg1, fadeInfo.finishedArg2, fadeInfo.finishedArg3, fadeInfo.finishedArg4)
fadeInfo.finishedFunc = nil
end
end
end
index = index + 1
end
if #FADEFRAMES == 0 then
self:SetScript("OnUpdate", nil)
end
end
-- Generic fade function
local function FadeFrame(frame, fadeInfo)
if not frame then
return
end
if not fadeInfo.mode then
fadeInfo.mode = "IN"
end
local alpha
if fadeInfo.mode == "IN" then
if not fadeInfo.startAlpha then
fadeInfo.startAlpha = 0
end
if not fadeInfo.endAlpha then
fadeInfo.endAlpha = 1.0
end
alpha = 0
elseif fadeInfo.mode == "OUT" then
if not fadeInfo.startAlpha then
fadeInfo.startAlpha = 1.0
end
if not fadeInfo.endAlpha then
fadeInfo.endAlpha = 0
end
alpha = 1.0
end
frame:SetAlpha(fadeInfo.startAlpha)
frame.fadeInfo = fadeInfo
local index = 1
while FADEFRAMES[index] do
-- If frame is already set to fade then return
if FADEFRAMES[index] == frame then
return
end
index = index + 1
end
tinsert(FADEFRAMES, frame)
FadeManager:SetScript("OnUpdate", FadeOnUpdate)
end
-- Convenience function for simple fade in
db.UIFrameFadeIn = function (frame, timeToFade, startAlpha, endAlpha)
local fadeInfo = {}
fadeInfo.mode = "IN"
fadeInfo.timeToFade = timeToFade
fadeInfo.startAlpha = startAlpha
fadeInfo.endAlpha = endAlpha
FadeFrame(frame, fadeInfo)
end
-- Convenience function for simple fade out
db.UIFrameFadeOut = function (frame, timeToFade, startAlpha, endAlpha)
local fadeInfo = {}
fadeInfo.mode = "OUT"
fadeInfo.timeToFade = timeToFade
fadeInfo.startAlpha = startAlpha
fadeInfo.endAlpha = endAlpha
FadeFrame(frame, fadeInfo)
end
---------------------------------------------------------------
-- Flash: Taint-free flash functions
---------------------------------------------------------------
local FlashManager = CreateFrame("FRAME")
local FLASHFRAMES = {}
local FlashTimers = {}
local FlashTimerRefCount = {}
-- Function to stop flashing
local function FlashStop(frame)
tDeleteItem(FLASHFRAMES, frame)
frame:SetAlpha(1.0)
frame.flashTimer = nil
if frame.syncId then
FlashTimerRefCount[frame.syncId] = FlashTimerRefCount[frame.syncId]-1
if FlashTimerRefCount[frame.syncId] == 0 then
FlashTimers[frame.syncId] = nil
FlashTimerRefCount[frame.syncId] = nil
end
frame.syncId = nil
end
if frame.showWhenDone then
frame:Show()
else
frame:Hide()
end
end
-- Called every frame to update flashing frames
local function FlashOnUpdate(self, elapsed)
local frame
local index = #FLASHFRAMES
-- Update timers for all synced frames
for syncId, timer in pairs(FlashTimers) do
FlashTimers[syncId] = timer + elapsed
end
while FLASHFRAMES[index] do
frame = FLASHFRAMES[index]
frame.flashTimer = frame.flashTimer + elapsed
if (frame.flashTimer > frame.flashDuration) and frame.flashDuration ~= -1 then
FlashStop(frame)
else
local flashTime = frame.flashTimer
local alpha
if frame.syncId then
flashTime = FlashTimers[frame.syncId]
end
flashTime = flashTime%(frame.fadeInTime+frame.fadeOutTime+(frame.flashInHoldTime or 0)+(frame.flashOutHoldTime or 0))
if flashTime < frame.fadeInTime then
alpha = flashTime/frame.fadeInTime
elseif flashTime < frame.fadeInTime+(frame.flashInHoldTime or 0) then
alpha = 1
elseif flashTime < frame.fadeInTime+(frame.flashInHoldTime or 0)+frame.fadeOutTime then
alpha = 1 - ((flashTime - frame.fadeInTime - (frame.flashInHoldTime or 0))/frame.fadeOutTime)
else
alpha = 0
end
frame:SetAlpha(alpha)
frame:Show()
end
-- Loop in reverse so that removing frames is safe
index = index - 1
end
if #FLASHFRAMES == 0 then
self:SetScript("OnUpdate", nil)
end
end
-- Function to start a frame flashing
db.UIFrameFlash = function(frame, fadeInTime, fadeOutTime, flashDuration, showWhenDone, flashInHoldTime, flashOutHoldTime, syncId)
if frame then
local index = 1
-- If frame is already set to flash then return
while FLASHFRAMES[index] do
if FLASHFRAMES[index] == frame then
return
end
index = index + 1
end
if syncId then
frame.syncId = syncId
if FlashTimers[syncId] == nil then
FlashTimers[syncId] = 0
FlashTimerRefCount[syncId] = 0
end
FlashTimerRefCount[syncId] = FlashTimerRefCount[syncId]+1
else
frame.syncId = nil
end
-- Time it takes to fade in a flashing frame
frame.fadeInTime = fadeInTime
-- Time it takes to fade out a flashing frame
frame.fadeOutTime = fadeOutTime
-- How long to keep the frame flashing
frame.flashDuration = flashDuration
-- Show the flashing frame when the fadeOutTime has passed
frame.showWhenDone = showWhenDone
-- Internal timer
frame.flashTimer = 0
-- How long to hold the faded in state
frame.flashInHoldTime = flashInHoldTime
-- How long to hold the faded out state
frame.flashOutHoldTime = flashOutHoldTime
tinsert(FLASHFRAMES, frame)
FlashManager:SetScript("OnUpdate", FlashOnUpdate)
end
end