annotate Libs/AceTimer-3.0/AceTimer-3.0.lua @ 0:fc346da3afd9

First commit Hot Corners standalone.
author tercio
date Fri, 08 Aug 2014 12:35:17 -0300
parents
children c31ee4251181
rev   line source
tercio@0 1 --- **AceTimer-3.0** provides a central facility for registering timers.
tercio@0 2 -- AceTimer supports one-shot timers and repeating timers. All timers are stored in an efficient
tercio@0 3 -- data structure that allows easy dispatching and fast rescheduling. Timers can be registered
tercio@0 4 -- or canceled at any time, even from within a running timer, without conflict or large overhead.\\
tercio@0 5 -- AceTimer is currently limited to firing timers at a frequency of 0.01s. This constant may change
tercio@0 6 -- in the future, but for now it's required as animations with lower frequencies are buggy.
tercio@0 7 --
tercio@0 8 -- All `:Schedule` functions will return a handle to the current timer, which you will need to store if you
tercio@0 9 -- need to cancel the timer you just registered.
tercio@0 10 --
tercio@0 11 -- **AceTimer-3.0** can be embeded into your addon, either explicitly by calling AceTimer:Embed(MyAddon) or by
tercio@0 12 -- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
tercio@0 13 -- and can be accessed directly, without having to explicitly call AceTimer itself.\\
tercio@0 14 -- It is recommended to embed AceTimer, otherwise you'll have to specify a custom `self` on all calls you
tercio@0 15 -- make into AceTimer.
tercio@0 16 -- @class file
tercio@0 17 -- @name AceTimer-3.0
tercio@0 18 -- @release $Id: AceTimer-3.0.lua 1079 2013-02-17 19:56:06Z funkydude $
tercio@0 19
tercio@0 20 local MAJOR, MINOR = "AceTimer-3.0", 16 -- Bump minor on changes
tercio@0 21 local AceTimer, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
tercio@0 22
tercio@0 23 if not AceTimer then return end -- No upgrade needed
tercio@0 24
tercio@0 25 AceTimer.frame = AceTimer.frame or CreateFrame("Frame", "AceTimer30Frame") -- Animation parent
tercio@0 26 AceTimer.inactiveTimers = AceTimer.inactiveTimers or {} -- Timer recycling storage
tercio@0 27 AceTimer.activeTimers = AceTimer.activeTimers or {} -- Active timer list
tercio@0 28
tercio@0 29 -- Lua APIs
tercio@0 30 local type, unpack, next, error, pairs, tostring, select = type, unpack, next, error, pairs, tostring, select
tercio@0 31
tercio@0 32 -- Upvalue our private data
tercio@0 33 local inactiveTimers = AceTimer.inactiveTimers
tercio@0 34 local activeTimers = AceTimer.activeTimers
tercio@0 35
tercio@0 36 local function OnFinished(self)
tercio@0 37 local id = self.id
tercio@0 38 if type(self.func) == "string" then
tercio@0 39 -- We manually set the unpack count to prevent issues with an arg set that contains nil and ends with nil
tercio@0 40 -- e.g. local t = {1, 2, nil, 3, nil} print(#t) will result in 2, instead of 5. This fixes said issue.
tercio@0 41 self.object[self.func](self.object, unpack(self.args, 1, self.argsCount))
tercio@0 42 else
tercio@0 43 self.func(unpack(self.args, 1, self.argsCount))
tercio@0 44 end
tercio@0 45
tercio@0 46 -- If the id is different it means that the timer was already cancelled
tercio@0 47 -- and has been used to create a new timer during the OnFinished callback.
tercio@0 48 if not self.looping and id == self.id then
tercio@0 49 activeTimers[self.id] = nil
tercio@0 50 self.args = nil
tercio@0 51 inactiveTimers[self] = true
tercio@0 52 end
tercio@0 53 end
tercio@0 54
tercio@0 55 local function new(self, loop, func, delay, ...)
tercio@0 56 local timer = next(inactiveTimers)
tercio@0 57 if timer then
tercio@0 58 inactiveTimers[timer] = nil
tercio@0 59 else
tercio@0 60 local anim = AceTimer.frame:CreateAnimationGroup()
tercio@0 61 timer = anim:CreateAnimation()
tercio@0 62 timer:SetScript("OnFinished", OnFinished)
tercio@0 63 end
tercio@0 64
tercio@0 65 -- Very low delays cause the animations to fail randomly.
tercio@0 66 -- A limited resolution of 0.01 seems reasonable.
tercio@0 67 if delay < 0.01 then
tercio@0 68 delay = 0.01
tercio@0 69 end
tercio@0 70
tercio@0 71 timer.object = self
tercio@0 72 timer.func = func
tercio@0 73 timer.looping = loop
tercio@0 74 timer.args = {...}
tercio@0 75 timer.argsCount = select("#", ...)
tercio@0 76
tercio@0 77 local anim = timer:GetParent()
tercio@0 78 if loop then
tercio@0 79 anim:SetLooping("REPEAT")
tercio@0 80 else
tercio@0 81 anim:SetLooping("NONE")
tercio@0 82 end
tercio@0 83 timer:SetDuration(delay)
tercio@0 84
tercio@0 85 local id = tostring(timer.args)
tercio@0 86 timer.id = id
tercio@0 87 activeTimers[id] = timer
tercio@0 88
tercio@0 89 anim:Play()
tercio@0 90 return id
tercio@0 91 end
tercio@0 92
tercio@0 93 --- Schedule a new one-shot timer.
tercio@0 94 -- The timer will fire once in `delay` seconds, unless canceled before.
tercio@0 95 -- @param callback Callback function for the timer pulse (funcref or method name).
tercio@0 96 -- @param delay Delay for the timer, in seconds.
tercio@0 97 -- @param ... An optional, unlimited amount of arguments to pass to the callback function.
tercio@0 98 -- @usage
tercio@0 99 -- MyAddOn = LibStub("AceAddon-3.0"):NewAddon("MyAddOn", "AceTimer-3.0")
tercio@0 100 --
tercio@0 101 -- function MyAddOn:OnEnable()
tercio@0 102 -- self:ScheduleTimer("TimerFeedback", 5)
tercio@0 103 -- end
tercio@0 104 --
tercio@0 105 -- function MyAddOn:TimerFeedback()
tercio@0 106 -- print("5 seconds passed")
tercio@0 107 -- end
tercio@0 108 function AceTimer:ScheduleTimer(func, delay, ...)
tercio@0 109 if not func or not delay then
tercio@0 110 error(MAJOR..": ScheduleTimer(callback, delay, args...): 'callback' and 'delay' must have set values.", 2)
tercio@0 111 end
tercio@0 112 if type(func) == "string" then
tercio@0 113 if type(self) ~= "table" then
tercio@0 114 error(MAJOR..": ScheduleTimer(callback, delay, args...): 'self' - must be a table.", 2)
tercio@0 115 elseif not self[func] then
tercio@0 116 error(MAJOR..": ScheduleTimer(callback, delay, args...): Tried to register '"..func.."' as the callback, but it doesn't exist in the module.", 2)
tercio@0 117 end
tercio@0 118 end
tercio@0 119 return new(self, nil, func, delay, ...)
tercio@0 120 end
tercio@0 121
tercio@0 122 --- Schedule a repeating timer.
tercio@0 123 -- The timer will fire every `delay` seconds, until canceled.
tercio@0 124 -- @param callback Callback function for the timer pulse (funcref or method name).
tercio@0 125 -- @param delay Delay for the timer, in seconds.
tercio@0 126 -- @param ... An optional, unlimited amount of arguments to pass to the callback function.
tercio@0 127 -- @usage
tercio@0 128 -- MyAddOn = LibStub("AceAddon-3.0"):NewAddon("MyAddOn", "AceTimer-3.0")
tercio@0 129 --
tercio@0 130 -- function MyAddOn:OnEnable()
tercio@0 131 -- self.timerCount = 0
tercio@0 132 -- self.testTimer = self:ScheduleRepeatingTimer("TimerFeedback", 5)
tercio@0 133 -- end
tercio@0 134 --
tercio@0 135 -- function MyAddOn:TimerFeedback()
tercio@0 136 -- self.timerCount = self.timerCount + 1
tercio@0 137 -- print(("%d seconds passed"):format(5 * self.timerCount))
tercio@0 138 -- -- run 30 seconds in total
tercio@0 139 -- if self.timerCount == 6 then
tercio@0 140 -- self:CancelTimer(self.testTimer)
tercio@0 141 -- end
tercio@0 142 -- end
tercio@0 143 function AceTimer:ScheduleRepeatingTimer(func, delay, ...)
tercio@0 144 if not func or not delay then
tercio@0 145 error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): 'callback' and 'delay' must have set values.", 2)
tercio@0 146 end
tercio@0 147 if type(func) == "string" then
tercio@0 148 if type(self) ~= "table" then
tercio@0 149 error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): 'self' - must be a table.", 2)
tercio@0 150 elseif not self[func] then
tercio@0 151 error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): Tried to register '"..func.."' as the callback, but it doesn't exist in the module.", 2)
tercio@0 152 end
tercio@0 153 end
tercio@0 154 return new(self, true, func, delay, ...)
tercio@0 155 end
tercio@0 156
tercio@0 157 --- Cancels a timer with the given id, registered by the same addon object as used for `:ScheduleTimer`
tercio@0 158 -- Both one-shot and repeating timers can be canceled with this function, as long as the `id` is valid
tercio@0 159 -- and the timer has not fired yet or was canceled before.
tercio@0 160 -- @param id The id of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer`
tercio@0 161 function AceTimer:CancelTimer(id)
tercio@0 162 local timer = activeTimers[id]
tercio@0 163 if not timer then return false end
tercio@0 164
tercio@0 165 local anim = timer:GetParent()
tercio@0 166 anim:Stop()
tercio@0 167
tercio@0 168 activeTimers[id] = nil
tercio@0 169 timer.args = nil
tercio@0 170 inactiveTimers[timer] = true
tercio@0 171 return true
tercio@0 172 end
tercio@0 173
tercio@0 174 --- Cancels all timers registered to the current addon object ('self')
tercio@0 175 function AceTimer:CancelAllTimers()
tercio@0 176 for k,v in pairs(activeTimers) do
tercio@0 177 if v.object == self then
tercio@0 178 AceTimer.CancelTimer(self, k)
tercio@0 179 end
tercio@0 180 end
tercio@0 181 end
tercio@0 182
tercio@0 183 --- Returns the time left for a timer with the given id, registered by the current addon object ('self').
tercio@0 184 -- This function will return 0 when the id is invalid.
tercio@0 185 -- @param id The id of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer`
tercio@0 186 -- @return The time left on the timer.
tercio@0 187 function AceTimer:TimeLeft(id)
tercio@0 188 local timer = activeTimers[id]
tercio@0 189 if not timer then return 0 end
tercio@0 190 return timer:GetDuration() - timer:GetElapsed()
tercio@0 191 end
tercio@0 192
tercio@0 193
tercio@0 194 -- ---------------------------------------------------------------------
tercio@0 195 -- Upgrading
tercio@0 196
tercio@0 197 -- Upgrade from old hash-bucket based timers to animation timers
tercio@0 198 if oldminor and oldminor < 10 then
tercio@0 199 -- disable old timer logic
tercio@0 200 AceTimer.frame:SetScript("OnUpdate", nil)
tercio@0 201 AceTimer.frame:SetScript("OnEvent", nil)
tercio@0 202 AceTimer.frame:UnregisterAllEvents()
tercio@0 203 -- convert timers
tercio@0 204 for object,timers in pairs(AceTimer.selfs) do
tercio@0 205 for handle,timer in pairs(timers) do
tercio@0 206 if type(timer) == "table" and timer.callback then
tercio@0 207 local id
tercio@0 208 if timer.delay then
tercio@0 209 id = AceTimer.ScheduleRepeatingTimer(timer.object, timer.callback, timer.delay, timer.arg)
tercio@0 210 else
tercio@0 211 id = AceTimer.ScheduleTimer(timer.object, timer.callback, timer.when - GetTime(), timer.arg)
tercio@0 212 end
tercio@0 213 -- change id to the old handle
tercio@0 214 local t = activeTimers[id]
tercio@0 215 activeTimers[id] = nil
tercio@0 216 activeTimers[handle] = t
tercio@0 217 t.id = handle
tercio@0 218 end
tercio@0 219 end
tercio@0 220 end
tercio@0 221 AceTimer.selfs = nil
tercio@0 222 AceTimer.hash = nil
tercio@0 223 AceTimer.debug = nil
tercio@0 224 elseif oldminor and oldminor < 13 then
tercio@0 225 for handle, id in pairs(AceTimer.hashCompatTable) do
tercio@0 226 local t = activeTimers[id]
tercio@0 227 if t then
tercio@0 228 activeTimers[id] = nil
tercio@0 229 activeTimers[handle] = t
tercio@0 230 t.id = handle
tercio@0 231 end
tercio@0 232 end
tercio@0 233 AceTimer.hashCompatTable = nil
tercio@0 234 end
tercio@0 235
tercio@0 236 -- upgrade existing timers to the latest OnFinished
tercio@0 237 for timer in pairs(inactiveTimers) do
tercio@0 238 timer:SetScript("OnFinished", OnFinished)
tercio@0 239 end
tercio@0 240
tercio@0 241 for _,timer in pairs(activeTimers) do
tercio@0 242 timer:SetScript("OnFinished", OnFinished)
tercio@0 243 end
tercio@0 244
tercio@0 245 -- ---------------------------------------------------------------------
tercio@0 246 -- Embed handling
tercio@0 247
tercio@0 248 AceTimer.embeds = AceTimer.embeds or {}
tercio@0 249
tercio@0 250 local mixins = {
tercio@0 251 "ScheduleTimer", "ScheduleRepeatingTimer",
tercio@0 252 "CancelTimer", "CancelAllTimers",
tercio@0 253 "TimeLeft"
tercio@0 254 }
tercio@0 255
tercio@0 256 function AceTimer:Embed(target)
tercio@0 257 AceTimer.embeds[target] = true
tercio@0 258 for _,v in pairs(mixins) do
tercio@0 259 target[v] = AceTimer[v]
tercio@0 260 end
tercio@0 261 return target
tercio@0 262 end
tercio@0 263
tercio@0 264 -- AceTimer:OnEmbedDisable(target)
tercio@0 265 -- target (object) - target object that AceTimer is embedded in.
tercio@0 266 --
tercio@0 267 -- cancel all timers registered for the object
tercio@0 268 function AceTimer:OnEmbedDisable(target)
tercio@0 269 target:CancelAllTimers()
tercio@0 270 end
tercio@0 271
tercio@0 272 for addon in pairs(AceTimer.embeds) do
tercio@0 273 AceTimer:Embed(addon)
tercio@0 274 end