DEFINITIONS
This source file includes following functions.
1 #
2 # tkafter.rb : methods for Tcl/Tk after command
3 #
4 # $Id: tkafter.rb,v 1.5 2002/06/04 07:03:33 nagai Exp $
5 #
6 require 'tk'
7
8 class TkAfter
9 include TkCore
10 extend TkCore
11
12 Tk_CBID = [0]
13 Tk_CBTBL = {}
14
15 INTERP._invoke("proc", "rb_after", "id", "ruby [format \"TkAfter.callback %%Q!%s!\" $id]")
16
17 ###############################
18 # class methods
19 ###############################
20 def TkAfter.callback(obj_id)
21 @after_id = nil
22 ex_obj = Tk_CBTBL[obj_id]
23 return nil if ex_obj == nil; # canceled
24 _get_eval_string(ex_obj.do_callback)
25 end
26
27 def TkAfter.info
28 tk_call('after', 'info').split(' ').collect!{|id|
29 ret = Tk_CBTBL.find{|key,val| val.after_id == id}
30 (ret == nil)? id: ret[1]
31 }
32 end
33
34 ###############################
35 # instance methods
36 ###############################
37 def do_callback
38 @in_callback = true
39 begin
40 @return_value = @current_proc.call(self)
41 rescue StandardError, NameError
42 if @cancel_on_exception
43 cancel
44 return nil
45 else
46 fail $!
47 end
48 end
49 if @set_next
50 set_next_callback(@current_args)
51 else
52 @set_next = true
53 end
54 @in_callback = false
55 @return_value
56 end
57
58 def set_callback(sleep, args=nil)
59 @after_script = "rb_after #{@id}"
60 @after_id = tk_call('after', sleep, @after_script)
61 @current_args = args
62 @current_script = [sleep, @after_script]
63 end
64
65 def set_next_callback(args)
66 if @running == false || @proc_max == 0 || @do_loop == 0
67 Tk_CBTBL[@id] = nil ;# for GC
68 @running = false
69 return
70 end
71 if @current_pos >= @proc_max
72 if @do_loop < 0 || (@do_loop -= 1) > 0
73 @current_pos = 0
74 else
75 Tk_CBTBL[@id] = nil ;# for GC
76 @running = false
77 return
78 end
79 end
80
81 @current_args = args
82
83 if @sleep_time.kind_of? Proc
84 sleep = @sleep_time.call(self)
85 else
86 sleep = @sleep_time
87 end
88 @current_sleep = sleep
89
90 cmd, *cmd_args = @loop_proc[@current_pos]
91 @current_pos += 1
92 @current_proc = cmd
93
94 set_callback(sleep, cmd_args)
95 end
96
97 def initialize(*args)
98 @id = format("a%.4d", Tk_CBID[0])
99 Tk_CBID[0] += 1
100
101 @set_next = true
102
103 @init_sleep = 0
104 @init_proc = nil
105 @init_args = []
106
107 @current_script = []
108 @current_proc = nil
109 @current_args = nil
110 @return_value = nil
111
112 @sleep_time = 0
113 @current_sleep = 0
114 @loop_exec = 0
115 @do_loop = 0
116 @loop_proc = []
117 @proc_max = 0
118 @current_pos = 0
119
120 @after_id = nil
121 @after_script = nil
122
123 @cancel_on_exception = true
124
125 set_procs(*args) if args != []
126
127 @running = false
128 end
129
130 attr :after_id
131 attr :after_script
132 attr :current_proc
133 attr :current_args
134 attr :current_sleep
135 alias :current_interval :current_sleep
136 attr :return_value
137
138 attr_accessor :loop_exec
139
140 def get_procs
141 [@init_sleep, @init_proc, @init_args, @sleep_time, @loop_exec, @loop_proc]
142 end
143
144 def current_status
145 [@running, @current_sleep, @current_proc, @current_args,
146 @do_loop, @cancel_on_exception]
147 end
148
149 def cancel_on_exception?
150 @cancel_on_exception
151 end
152
153 def cancel_on_exception=(mode)
154 @cancel_on_exception = mode
155 end
156
157 def running?
158 @running
159 end
160
161 def loop_rest
162 @do_loop
163 end
164
165 def loop_rest=(rest)
166 @do_loop = rest
167 end
168
169 def set_procs(interval, loop_exec, *procs)
170 if !interval == 'idle' \
171 && !interval.kind_of?(Integer) && !interval.kind_of?(Proc)
172 fail format("%s need to be Integer or Proc", interval.inspect)
173 end
174 @sleep_time = interval
175
176 @loop_proc = []
177 procs.each{|e|
178 if e.kind_of? Proc
179 @loop_proc.push([e])
180 else
181 @loop_proc.push(e)
182 end
183 }
184 @proc_max = @loop_proc.size
185 @current_pos = 0
186
187 @do_loop = 0
188 if loop_exec
189 if loop_exec.kind_of?(Integer) && loop_exec < 0
190 @loop_exec = -1
191 elsif loop_exec == nil || loop_exec == false || loop_exec == 0
192 @loop_exec = 1
193 else
194 if not loop_exec.kind_of?(Integer)
195 fail format("%s need to be Integer", loop_exec.inspect)
196 end
197 @loop_exec = loop_exec
198 end
199 @do_loop = @loop_exec
200 end
201
202 self
203 end
204
205 def add_procs(*procs)
206 procs.each{|e|
207 if e.kind_of? Proc
208 @loop_proc.push([e])
209 else
210 @loop_proc.push(e)
211 end
212 }
213 @proc_max = @loop_proc.size
214
215 self
216 end
217
218 def set_start_proc(sleep, init_proc, *init_args)
219 if !sleep == 'idle' && !sleep.kind_of?(Integer)
220 fail format("%s need to be Integer", sleep.inspect)
221 end
222 @init_sleep = sleep
223 @init_proc = init_proc
224 @init_args = init_args
225 self
226 end
227
228 def start(*init_args)
229 return nil if @running
230
231 Tk_CBTBL[@id] = self
232 @do_loop = @loop_exec
233 @current_pos = 0
234
235 argc = init_args.size
236 if argc > 0
237 sleep = init_args.shift
238 if !sleep == 'idle' && !sleep.kind_of?(Integer)
239 fail format("%s need to be Integer", sleep.inspect)
240 end
241 @init_sleep = sleep
242 end
243 @init_proc = init_args.shift if argc > 1
244 @init_args = init_args if argc > 0
245
246 @current_sleep = @init_sleep
247 @running = true
248 if @init_proc
249 if not @init_proc.kind_of? Proc
250 fail format("%s need to be Proc", @init_proc.inspect)
251 end
252 @current_proc = @init_proc
253 set_callback(sleep, @init_args)
254 @set_next = false if @in_callback
255 else
256 set_next_callback(@init_args)
257 end
258
259 self
260 end
261
262 def restart(*restart_args)
263 cancel if @running
264 if restart_args == []
265 start(@init_sleep, @init_proc, *@init_args)
266 else
267 start(*restart_args)
268 end
269 end
270
271 def cancel
272 @running = false
273 tk_call 'after', 'cancel', @after_id if @after_id
274 @after_id = nil
275 Tk_CBTBL[@id] = nil ;# for GC
276 self
277 end
278 alias stop cancel
279
280 def continue(wait=nil)
281 sleep, cmd = @current_script
282 return nil if cmd == nil || @running == true
283 if wait
284 if not wait.kind_of? Integer
285 fail format("%s need to be Integer", wait.inspect)
286 end
287 sleep = wait
288 end
289 Tk_CBTBL[@id] = self
290 @running = true
291 @after_id = tk_call('after', sleep, cmd)
292 self
293 end
294
295 def skip
296 return nil if @running == false
297 cancel
298 Tk_CBTBL[@id] = self
299 @running = true
300 set_next_callback(@current_args)
301 self
302 end
303
304 def info
305 if @after_id
306 inf = tk_split_list(tk_call('after', 'info', @after_id))
307 [Tk_CBTBL[inf[0][1]], inf[1]]
308 else
309 nil
310 end
311 end
312 end