/ld26

To get this branch, use:
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
}