--------------------------------------------------------------- -- Animation.lua: Taint-free animation framework --------------------------------------------------------------- -- Provides a framework for managing alpha animations without -- risk of spreading taint, which might happen when the "real" -- functions are called from secure code. local _, L = ... --------------------------------------------------------------- -- 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 L.UIFrameFadeIn = function (frame, timeToFade, startAlpha, endAlpha, info) local fadeInfo = info or {} fadeInfo.mode = "IN" fadeInfo.timeToFade = timeToFade fadeInfo.startAlpha = startAlpha fadeInfo.endAlpha = endAlpha FadeFrame(frame, fadeInfo) end -- Convenience function for simple fade out L.UIFrameFadeOut = function (frame, timeToFade, startAlpha, endAlpha, info) local fadeInfo = info or {} fadeInfo.mode = "OUT" fadeInfo.timeToFade = timeToFade fadeInfo.startAlpha = startAlpha fadeInfo.endAlpha = endAlpha FadeFrame(frame, fadeInfo) end -- Expose removal of frame from fader L.UIFrameStopFading = function(frame) FadeRemoveFrame(frame) 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 L.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