bzr branch
http://9ix.org/bzr/ld26
1
by Josh C
zoetrope 1.4 |
1 |
-- Class: Timer |
2 |
-- A timer allows delayed or periodic execution of a function according |
|
3 |
-- to elapsed time in an app. In order for it to work properly, it must |
|
4 |
-- receive update events, so it must be added somewhere in the current |
|
5 |
-- view or app. If you are using the <View> class, then this is already |
|
6 |
-- done for you; one is created as the View's timer property. |
|
7 |
||
8 |
Timer = Sprite:extend{ |
|
9 |
timers = {}, |
|
10 |
visible = false, |
|
11 |
active = false, |
|
12 |
solid = false, |
|
13 |
||
14 |
-- Method: wait |
|
15 |
||
16 |
-- Method: after |
|
17 |
-- Delays a function call after a certain a mount of time. |
|
18 |
-- |
|
19 |
-- Arguments: |
|
20 |
-- * delay - how long to wait, in seconds |
|
21 |
-- * func - function to call |
|
22 |
-- |
|
23 |
-- Returns: |
|
24 |
-- A <Promise> that is fulfilled after the function is called |
|
25 |
||
26 |
after = function (self, delay, func) |
|
27 |
if STRICT then |
|
28 |
assert(type(func) == 'function', 'func property of timer must be a function') |
|
29 |
assert(type(delay) == 'number', 'delay must be a number') |
|
30 |
||
31 |
if delay <= 0 then |
|
32 |
local info = debug.getinfo(2, 'Sl') |
|
33 |
print('Warning: timer delay is ' .. delay .. ', will be triggered immediately (' .. |
|
34 |
info.short_src .. ', line ' .. info.currentline .. ')') |
|
35 |
end |
|
36 |
end |
|
37 |
||
38 |
self.active = true |
|
39 |
local promise = Promise:new() |
|
40 |
table.insert(self.timers, { func = func, timeLeft = delay, promise = promise }) |
|
41 |
return promise |
|
42 |
end, |
|
43 |
||
44 |
-- Method: every |
|
45 |
-- Repeatedly makes a function call. To stop these calls from |
|
46 |
-- happening in the future, you must call stop(). |
|
47 |
-- |
|
48 |
-- Arguments: |
|
49 |
-- * delay - how often to make the function call, in seconds |
|
50 |
-- * func - function to call |
|
51 |
-- |
|
52 |
-- Returns: |
|
53 |
-- nothing |
|
54 |
||
55 |
every = function (self, delay, func) |
|
56 |
if STRICT then |
|
57 |
assert(type(func) == 'function', 'func property of timer must be a function') |
|
58 |
assert(type(delay) == 'number', 'delay must be a number') |
|
59 |
||
60 |
if delay <= 0 then |
|
61 |
local info = debug.getinfo(2, 'Sl') |
|
62 |
print('Warning: timer delay is ' .. delay .. ', will be triggered immediately (' .. |
|
63 |
info.short_src .. ', line ' .. info.currentline .. ')') |
|
64 |
end |
|
65 |
end |
|
66 |
||
67 |
self.active = true |
|
68 |
table.insert(self.timers, { func = func, timeLeft = delay, interval = delay }) |
|
69 |
end, |
|
70 |
||
71 |
-- Method: status |
|
72 |
-- Returns how much time is left before a function call is scheduled. |
|
73 |
-- |
|
74 |
-- Arguments: |
|
75 |
-- func - the function that is queued |
|
76 |
-- |
|
77 |
-- Returns: |
|
78 |
-- the time left until the soonest call matching these arguments, |
|
79 |
-- or nil if there is no call scheduled |
|
80 |
||
81 |
status = function (self, func, bind, arg) |
|
82 |
local result |
|
83 |
||
84 |
for _, t in pairs(self.timers) do |
|
85 |
if t.func == func and (not result or result < t.timeLeft) then |
|
86 |
result = t.timeLeft |
|
87 |
end |
|
88 |
end |
|
89 |
||
90 |
return result |
|
91 |
end, |
|
92 |
||
93 |
-- Method: stop |
|
94 |
-- Stops a timer from executing. The promise belonging to it is failed. |
|
95 |
-- If there is no function associated with this timer, then this has no effect. |
|
96 |
-- |
|
97 |
-- Arguments: |
|
98 |
-- func - function to stop; if omitted, stops all timers |
|
99 |
-- |
|
100 |
-- Returns: |
|
101 |
-- nothing |
|
102 |
||
103 |
stop = function (self, func, bind) |
|
104 |
local found = false |
|
105 |
||
106 |
for i, timer in ipairs(self.timers) do |
|
107 |
if not func or timer.func == func then |
|
108 |
if timer.promise then |
|
109 |
timer.promise:fail('Timer stopped') |
|
110 |
end |
|
111 |
||
112 |
table.remove(self.timers, i) |
|
113 |
found = true |
|
114 |
end |
|
115 |
end |
|
116 |
||
117 |
if STRICT and not found then |
|
118 |
local info = debug.getinfo(2, 'Sl') |
|
119 |
print('Warning: asked to stop a timer on a function that was not queued (' .. |
|
120 |
info.short_src .. ', line ' .. info.currentline .. ')') |
|
121 |
end |
|
122 |
end, |
|
123 |
||
124 |
update = function (self, elapsed) |
|
125 |
for i, timer in ipairs(self.timers) do |
|
126 |
timer.timeLeft = timer.timeLeft - elapsed |
|
127 |
||
128 |
if timer.timeLeft <= 0 then |
|
129 |
||
130 |
if timer.promise then |
|
131 |
timer.promise:fulfill(timer.func()) |
|
132 |
else |
|
133 |
timer.func() |
|
134 |
end |
|
135 |
||
136 |
if timer.interval then |
|
137 |
timer.timeLeft = timer.interval |
|
138 |
keepActive = true |
|
139 |
else |
|
140 |
table.remove(self.timers, i) |
|
141 |
end |
|
142 |
else |
|
143 |
keepActive = true |
|
144 |
end |
|
145 |
end |
|
146 |
||
147 |
self.active = (#self.timers > 0) |
|
148 |
end, |
|
149 |
||
150 |
__tostring = function (self) |
|
151 |
local result = 'Timer (' |
|
152 |
||
153 |
if self.active then |
|
154 |
result = result .. 'active, ' |
|
155 |
result = result .. #self.timers .. ' timers running' |
|
156 |
else |
|
157 |
result = result .. 'inactive' |
|
158 |
end |
|
159 |
||
160 |
return result .. ')' |
|
161 |
end |
|
162 |
} |