ext/tk/lib/tkafter.rb


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