#
#  tk/event.rb - module for event
#

module TkEvent
end

########################

require 'tkutil'
# require 'tk'

########################

module TkEvent
  class Event < TkUtil::CallbackSubst
    module TypeNum
      KeyPress         =  2
      KeyRelease       =  3
      ButtonPress      =  4
      ButtonRelease    =  5
      MotionNotify     =  6
      EnterNotify      =  7
      LeaveNotify      =  8
      FocusIn          =  9
      FocusOut         = 10
      KeymapNotify     = 11
      Expose           = 12
      GraphicsExpose   = 13
      NoExpose         = 14
      VisibilityNotify = 15
      CreateNotify     = 16
      DestroyNotify    = 17
      UnmapNotify      = 18
      MapNotify        = 19
      MapRequest       = 20
      ReparentNotify   = 21
      ConfigureNotify  = 22
      ConfigureRequest = 23
      GravityNotify    = 24
      ResizeRequest    = 25
      CirculateNotify  = 26
      CirculateRequest = 27
      PropertyNotify   = 28
      SelectionClear   = 29
      SelectionRequest = 30
      SelectionNotify  = 31
      ColormapNotify   = 32
      ClientMessage    = 33
      MappingNotify    = 34
    end

    # [ <'%' subst-key char>, <proc type char>, <instance var (accessor) name>]
    KEY_TBL = [
      [ ?#, ?n, :serial ], 
      [ ?a, ?s, :above ], 
      [ ?b, ?n, :num ], 
      [ ?c, ?n, :count ], 
      [ ?d, ?s, :detail ], 
      [ ?f, ?b, :focus ], 
      [ ?h, ?n, :height ], 
      [ ?i, ?s, :win_hex ], 
      [ ?k, ?n, :keycode ], 
      [ ?m, ?s, :mode ], 
      [ ?o, ?b, :override ], 
      [ ?p, ?s, :place ], 
      [ ?s, ?x, :state ], 
      [ ?t, ?n, :time ], 
      [ ?w, ?n, :width ], 
      [ ?x, ?n, :x ], 
      [ ?y, ?n, :y ], 
      [ ?A, ?s, :char ], 
      [ ?B, ?n, :borderwidth ], 
      [ ?D, ?n, :wheel_delta ], 
      [ ?E, ?b, :send_event ], 
      [ ?K, ?s, :keysym ], 
      [ ?N, ?n, :keysym_num ], 
      [ ?R, ?s, :rootwin_id ], 
      [ ?S, ?s, :subwindow ], 
      [ ?T, ?n, :type ], 
      [ ?W, ?w, :widget ], 
      [ ?X, ?n, :x_root ], 
      [ ?Y, ?n, :y_root ], 
      nil
    ]

    # [ <proc type char>, <proc/method to convert tcl-str to ruby-obj>]
    PROC_TBL = [
      [ ?n, TkComm.method(:num_or_str) ], 
      [ ?s, TkComm.method(:string) ], 
      [ ?b, TkComm.method(:bool) ], 
      [ ?w, TkComm.method(:window) ], 

      [ ?x, proc{|val|
          begin
            TkComm::number(val)
          rescue ArgumentError
            val
          end
        }
      ], 

      nil
    ]

    # setup tables to be used by scan_args, _get_subst_key, _get_all_subst_keys
    #
    #     _get_subst_key() and _get_all_subst_keys() generates key-string 
    #     which describe how to convert callback arguments to ruby objects. 
    #     When binding parameters are given, use _get_subst_key(). 
    #     But when no parameters are given, use _get_all_subst_keys() to 
    #     create a Event class object as a callback parameter. 
    #
    #     scan_args() is used when doing callback. It convert arguments 
    #     ( which are Tcl strings ) to ruby objects based on the key string 
    #     that is generated by _get_subst_key() or _get_all_subst_keys(). 
    #
    _setup_subst_table(KEY_TBL, PROC_TBL);

    #
    # NOTE: The order of parameters which passed to callback procedure is 
    #        <extra_arg>, <extra_arg>, ... , <subst_arg>, <subst_arg>, ...
    #

    # If you need support extra arguments given by Tcl/Tk, 
    # please override _get_extra_args_tbl
    #
    #def self._get_extra_args_tbl
    #  # return an array of convert procs
    #  []
    #end

    alias button num
    alias delta  wheel_delta
    alias root   rootwin_id
    alias rootx  x_root
    alias root_x x_root
    alias rooty  y_root
    alias root_y y_root
    alias sendevent send_event

  end

  ###############################################

  def install_bind_for_event_class(klass, cmd, *args)
    extra_args_tbl = klass._get_extra_args_tbl

    if args.compact.size > 0
      args = args.join(' ')
      keys = klass._get_subst_key(args)

      if cmd.kind_of?(String)
        id = cmd
      elsif cmd.kind_of?(TkCallbackEntry)
        id = install_cmd(cmd)
      else
        id = install_cmd(proc{|*arg|
          ex_args = []
          extra_args_tbl.reverse_each{|conv| ex_args << conv.call(arg.pop)}
          TkUtil.eval_cmd(cmd, *(ex_args.concat(klass.scan_args(keys, arg))))
        })
      end
      id + ' ' + args
    else
      keys, args = klass._get_all_subst_keys

      if cmd.kind_of?(String)
        id = cmd
      elsif cmd.kind_of?(TkCallbackEntry)
        id = install_cmd(cmd)
      else
        id = install_cmd(proc{|*arg|
          ex_args = []
          extra_args_tbl.reverse_each{|conv| ex_args << conv.call(arg.pop)}
          TkUtil.eval_cmd(cmd, 
                          *(ex_args << klass.new(*klass.scan_args(keys, arg))))
        })
      end
      id + ' ' + args
    end
  end

  def install_bind(cmd, *args)
    install_bind_for_event_class(TkEvent::Event, cmd, *args)
  end
end
