summaryrefslogtreecommitdiff
path: root/lib/tk.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/tk.rb')
-rw-r--r--lib/tk.rb1215
1 files changed, 1215 insertions, 0 deletions
diff --git a/lib/tk.rb b/lib/tk.rb
new file mode 100644
index 0000000000..9c61269881
--- /dev/null
+++ b/lib/tk.rb
@@ -0,0 +1,1215 @@
+#
+# tk.rb - Tk interface for ruby
+# $Date: 1995/11/03 08:17:15 $
+# by Yukihiro Matsumoto <matz@caelum.co.jp>
+
+require "tkutil"
+
+trap "PIPE", proc{exit 0}
+trap "EXIT", proc{Tk.tk_exit}
+
+module Tk
+ include TkUtil
+ extend Tk
+
+ $0 =~ /\/(.*$)/
+
+ PORT = open(format("|%s -n %s", WISH_PATH, $1), "w+");
+ def tk_write(*args)
+ printf PORT, *args;
+ PORT.print "\n"
+ PORT.flush
+ end
+ tk_write '\
+wm withdraw .
+proc rb_out args {
+ puts [format %%s $args]
+ flush stdout
+}
+proc tkerror args { exit }
+proc keepalive {} { rb_out alive; after 120000 keepalive}
+after 120000 keepalive'
+
+ READABLE = []
+ READ_CMD = {}
+
+ def file_readable(port, cmd)
+ READABLE.push port
+ READ_CMD[port] = cmd
+ end
+
+ WRITABLE = []
+ WRITE_CMD = {}
+ def file_writable
+ WRITABLE.push port
+ WRITE_CMD[port] = cmd
+ end
+ module_function :file_readable, :file_writable
+
+ file_readable PORT, proc {
+ exit if not PORT.gets
+ Tk.dispatch($_.chop!)
+ }
+
+ def tk_exit
+ PORT.print "exit\n"
+ PORT.close
+ end
+
+ def error_at
+ n = 1
+ while c = caller(n)
+ break if c !~ /tk\.rb:/
+ n+=1
+ end
+ c
+ end
+
+ def tk_tcl2ruby(val)
+ case val
+ when /^-?\d+$/
+ val.to_i
+ when /^\./
+ $tk_window_list[val]
+ when /^rb_out (c\d+)/
+ $tk_cmdtbl[$1]
+ when / /
+ val.split.collect{|elt|
+ tk_tcl2ruby(elt)
+ }
+ when /^-?\d+\.\d*$/
+ val.to_f
+ else
+ val
+ end
+ end
+
+ def tk_split_list(str)
+ idx = str.index('{')
+ return tk_tcl2ruby(str) if not idx
+
+ list = tk_tcl2ruby(str[0,idx])
+ str = str[idx+1..-1]
+ i = -1
+ brace = 1
+ str.each_byte {|c|
+ i += 1
+ brace += 1 if c == ?{
+ brace -= 1 if c == ?}
+ break if brace == 0
+ }
+ if str[0, i] == ' '
+ list.push ' '
+ else
+ list.push tk_split_list(str[0, i])
+ end
+ list += tk_split_list(str[i+1..-1])
+ list
+ end
+ private :tk_tcl2ruby, :tk_split_list
+
+ def bool(val)
+ case bool
+ when "1", 1, 'yes', 'true'
+ TRUE
+ else
+ FALSE
+ end
+ end
+ def number(val)
+ case val
+ when /^-?\d+$/
+ val.to_i
+ when /^-?\d+\.\d*$/
+ val.to_f
+ else
+ val
+ end
+ end
+ def string(val)
+ if val == "{}"
+ ''
+ elsif val[0] == ?{
+ val[1..-2]
+ else
+ val
+ end
+ end
+ def list(val)
+ tk_split_list(val)
+ end
+ def window(val)
+ $tk_window_list[val]
+ end
+ def procedure(val)
+ if val =~ /^rb_out (c\d+)/
+ $tk_cmdtbl[$1]
+ else
+ nil
+ end
+ end
+ private :bool, :number, :string, :list, :window, :procedure
+
+ # mark for non-given arguments
+ None = Object.new
+ def None.to_s
+ 'None'
+ end
+
+ $tk_event_queue = []
+ def tk_call(*args)
+ args = args.collect{|s|
+ continue if s == None
+ if s == FALSE
+ s = "0"
+ elsif s == TRUE
+ s = "1"
+ elsif s.is_kind_of?(TkObject)
+ s = s.path
+ else
+ s = s.to_s
+ s.gsub!(/[{}]/, '\\\\\0')
+ end
+ "{#{s}}"
+ }
+ str = args.join(" ")
+ tk_write 'if [catch {%s} var] {puts "!$var"} {puts "=$var@@"};flush stdout', str
+ while PORT.gets
+ $_.chop!
+ if /^=(.*)@@$/
+ val = $1
+ break
+ elsif /^=/
+ val = $' + "\n"
+ while TRUE
+ PORT.gets
+ fail 'wish closed' if not $_
+ if ~/@@$/
+ val += $'
+ return val
+ else
+ val += $_
+ end
+ end
+ elsif /^!/
+ $@ = error_at
+ msg = $'
+ if msg =~ /unknown option "-(.*)"/
+ fail format("undefined method `%s' for %s(%s)'", $1, self, self.type)
+ else
+ fail format("%s - %s", self.type, msg)
+ end
+ end
+ $tk_event_queue.push $_
+ end
+
+ while ev = $tk_event_queue.shift
+ Tk.dispatch ev
+ end
+ fail 'wish closed' if not $_
+# tk_split_list(val)
+ val
+ end
+
+ def hash_kv(keys)
+ conf = []
+ if keys
+ for k, v in keys
+ conf.push("-#{k}")
+ v = install_cmd(v) if v.type == Proc
+ conf.push(v)
+ end
+ end
+ conf
+ end
+ private :tk_call, :error_at, :hash_kv
+
+ $tk_cmdid = "c00000"
+ def install_cmd(cmd)
+ return '' if cmd == '' # uninstall cmd
+ id = $tk_cmdid
+ $tk_cmdid = $tk_cmdid.next
+ $tk_cmdtbl[id] = cmd
+ @cmdtbl = [] if not @cmdtbl
+ @cmdtbl.push id
+ return format('rb_out %s', id)
+ end
+ def uninstall_cmd(id)
+ $tk_cmdtbl[id] = nil
+ end
+ private :install_cmd, :uninstall_cmd
+
+ $tk_window_list = {}
+ class Event
+ def initialize(seq,b,f,h,k,s,t,w,x,y,aa,ee,kk,nn,ww,tt,xx,yy)
+ @serial = seq
+ @num = b
+ @focus = (f == 1)
+ @height = h
+ @keycode = k
+ @state = s
+ @time = t
+ @width = w
+ @x = x
+ @y = y
+ @char = aa
+ @send_event = (ee == 1)
+ @keysym = kk
+ @keysym_num = nn
+ @type = tt
+ @widget = ww
+ @x_root = xx
+ @y_root = yy
+ end
+ attr :serial
+ attr :num
+ attr :focus
+ attr :height
+ attr :keycode
+ attr :state
+ attr :time
+ attr :width
+ attr :x
+ attr :y
+ attr :char
+ attr :send_event
+ attr :keysym
+ attr :keysym_num
+ attr :type
+ attr :widget
+ attr :x_root
+ attr :y_root
+ end
+
+ def install_bind(cmd)
+ id = install_cmd(proc{|args|
+ TkUtil.eval_cmd cmd, Event.new(*args)
+ })
+ id + " %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X %Y"
+ end
+
+ def _bind(path, context, cmd)
+ begin
+ id = install_bind(cmd)
+ tk_call 'bind', path, "<#{context}>", id
+ rescue
+ $tk_cmdtbl[id] = nil
+ fail
+ end
+ end
+ private :install_bind, :_bind
+
+ def bind_all(context, cmd=Proc.new)
+ _bind 'all', context, cmd
+ end
+
+ $tk_cmdtbl = {}
+
+ def after(ms, cmd=Proc.new)
+ myid = $tk_cmdid
+ tk_call 'after', ms,
+ install_cmd(proc{
+ TkUtil.eval_cmd cmd
+ uninstall_cmd myid
+ })
+ end
+
+ def update(idle=nil)
+ if idle
+ tk_call 'update', 'idletasks'
+ else
+ tk_call 'update'
+ end
+ end
+
+ def dispatch(line)
+ if line =~ /^c\d+/
+ cmd = $&
+ fail "no command `#{cmd}'" if not $tk_cmdtbl[cmd]
+ args = tk_split_list($')
+ TkUtil.eval_cmd $tk_cmdtbl[cmd], *args
+ elsif line =~ /^alive$/
+ # keep alive, do nothing
+ else
+ fail "malformed line <#{line}>"
+ end
+ end
+
+ def mainloop
+ begin
+ tk_write 'after idle {wm deiconify .}'
+ while TRUE
+ rf, wf = select(READABLE, WRITABLE)
+ for f in rf
+ READ_CMD[f].call(f) if READ_CMD[f]
+ if f.closed?
+ READABLE.delete f
+ READ_CMD[f] = nil
+ end
+ end
+ for f in wf
+ WRITE_CMD[f].call(f) if WRITE_CMD[f]
+ if f.closed?
+ WRITABLE.delete f
+ WRITE_CMD[f] = nil
+ end
+ end
+ end
+ rescue
+ exit if $! =~ /^Interrupt/
+ fail
+ ensure
+ tk_exit
+ end
+ end
+
+ def root
+ $tk_root
+ end
+
+ module_function :after, :update, :dispatch, :mainloop, :root
+
+ module Scrollable
+ def xscrollcommand(cmd)
+ configure_cmd 'xscrollcommand', cmd
+ end
+ def yscrollcommand(cmd)
+ configure_cmd 'yscrollcommand', cmd
+ end
+ end
+
+ module Wm
+ def aspect(*args)
+ w = window(tk_call('wm', 'grid', path, *args))
+ w.split.collect{|s|s.to_i} if args.length == 0
+ end
+ def client(name=None)
+ tk_call 'wm', 'client', path, name
+ end
+ def colormapwindows(*args)
+ list(tk_call('wm', 'colormapwindows', path, *args))
+ end
+ def wm_command(value=None)
+ string(tk_call('wm', 'command', path, value))
+ end
+ def deiconify
+ tk_call 'wm', 'deiconify', path
+ end
+ def focusmodel(*args)
+ tk_call 'wm', 'focusmodel', path, *args
+ end
+ def frame
+ tk_call 'wm', 'frame', path
+ end
+ def geometry(*args)
+ list(tk_call('wm', 'geometry', path, *args))
+ end
+ def grid(*args)
+ w = tk_call('wm', 'grid', path, *args)
+ list(w) if args.size == 0
+ end
+ def group(*args)
+ tk_call 'wm', 'path', path, *args
+ end
+ def iconbitmap(*args)
+ tk_call 'wm', 'bitmap', path, *args
+ end
+ def iconify
+ tk_call 'wm', 'iconify'
+ end
+ def iconmask(*args)
+ tk_call 'wm', 'iconmask', path, *args
+ end
+ def iconname(*args)
+ tk_call 'wm', 'iconname', path, *args
+ end
+ def iconposition(*args)
+ w = tk_call('wm', 'iconposition', path, *args)
+ list(w) if args.size == 0
+ end
+ def iconwindow(*args)
+ tk_call 'wm', 'iconwindow', path, *args
+ end
+ def maxsize(*args)
+ w = tk_call('wm', 'maxsize', path, *args)
+ list(w) if not args.size == 0
+ end
+ def minsize(*args)
+ w = tk_call('wm', 'minsize', path, *args)
+ list(w) if args.size == 0
+ end
+ def overrideredirect(bool=None)
+ if bool == None
+ bool(tk_call('wm', 'overrideredirect', path))
+ else
+ tk_call 'wm', 'overrideredirect', path, bool
+ end
+ end
+ def positionfrom(*args)
+ tk_call 'wm', 'positionfrom', path, *args
+ end
+ def protocol(name, func=None)
+ func = install_cmd(func) if not func == None
+ tk_call 'wm', 'command', path, name, func
+ end
+ def resizable(*args)
+ w = tk_call('wm', 'resizable', path, *args)
+ if args.length == 0
+ list(w).collect{|e| bool(e)}
+ end
+ end
+ def sizefrom(*args)
+ list(tk_call('wm', 'sizefrom', path, *args))
+ end
+ def state
+ tk_call 'wm', 'state', path
+ end
+ def title(*args)
+ tk_call 'wm', 'title', path, *args
+ end
+ def transient(*args)
+ tk_call 'wm', 'transient', path, *args
+ end
+ def withdraw
+ tk_call 'wm', 'withdraw', path
+ end
+ end
+end
+
+module TkSelection
+ include Tk
+ extend Tk
+ def clear(win=Tk.root)
+ tk_call 'selection', 'clear', win.path
+ end
+ def get(type=None)
+ tk_call 'selection', 'get', type
+ end
+ def TkSelection.handle(win, func, type=None, format=None)
+ id = install_cmd(func)
+ tk_call 'selection', 'handle', win.path, id, type, format
+ end
+ def handle(func, type=None, format=None)
+ TkSelection.handle self, func, type, format
+ end
+ def TkSelection.own(win, func=None)
+ id = install_cmd(func)
+ tk_call 'selection', 'own', win.path, id
+ end
+ def own(func=None)
+ TkSelection.own self, func
+ end
+
+ module_function :clear, :get
+end
+
+module TkWinfo
+ include Tk
+ extend Tk
+ def TkWinfo.atom(name)
+ tk_call 'winfo', name
+ end
+ def winfo_atom(name)
+ TkWinfo.atom name
+ end
+ def TkWinfo.atomname(id)
+ tk_call 'winfo', id
+ end
+ def winfo_atomname(id)
+ TkWinfo.atomname id
+ end
+ def TkWinfo.cells(window)
+ number(tk_call('winfo', window.path))
+ end
+ def winfo_cells
+ TkWinfo.cells self
+ end
+ def TkWinfo.children(window)
+ c = tk_call('winfo', 'children', window.path)
+ list(c)
+ end
+ def winfo_children
+ TkWinfo.children self
+ end
+ def TkWinfo.classname(window)
+ tk_call 'winfo', 'class', window.path
+ end
+ def winfo_classname
+ TkWinfo.classname self
+ end
+ def TkWinfo.containing(rootX, rootY)
+ path = tk_call('winfo', 'class', window.path)
+ window(path)
+ end
+ def winfo_containing(x, y)
+ TkWinfo.containing x, y
+ end
+ def TkWinfo.depth(window)
+ number(tk_call('winfo', 'depth', window.path))
+ end
+ def winfo_depth(window)
+ TkWinfo.depth self
+ end
+ def TkWinfo.exists(window)
+ bool(tk_call('winfo', 'exists', window.path))
+ end
+ def winfo_exists(window)
+ TkWinfo.exists self
+ end
+ def TkWinfo.fpixels(window, number)
+ number(tk_call('winfo', 'fpixels', window.path, number))
+ end
+ def winfo_fpixels(window, number)
+ TkWinfo.fpixels self
+ end
+ def TkWinfo.geometry(window)
+ list(tk_call('winfo', 'geometry', window.path))
+ end
+ def winfo_geometry(window)
+ TkWinfo.geometry self
+ end
+ def TkWinfo.height(window)
+ number(tk_call('winfo', 'height', window.path))
+ end
+ def winfo_height(window)
+ TkWinfo.height self
+ end
+ def TkWinfo.id(window)
+ number(tk_call('winfo', 'id', window.path))
+ end
+ def winfo_id(window)
+ TkWinfo.id self
+ end
+ def TkWinfo.ismapped(window)
+ bool(tk_call('winfo', 'ismapped', window.path))
+ end
+ def winfo_ismapped(window)
+ TkWinfo.ismapped self
+ end
+ def TkWinfo.parent(window)
+ window(tk_call('winfo', 'parent', window.path))
+ end
+ def winfo_parent(window)
+ TkWinfo.parent self
+ end
+ def TkWinfo.widget(id)
+ window(tk_call('winfo', 'pathname', id))
+ end
+ def winfo_widget(id)
+ TkWinfo.widget id
+ end
+ def TkWinfo.pixels(window, number)
+ number(tk_call('winfo', 'pixels', window.path, number))
+ end
+ def winfo_pixels(window, number)
+ TkWinfo.pixels self, number
+ end
+ def TkWinfo.reqheight(window)
+ number(tk_call('winfo', 'reqheight', window.path))
+ end
+ def winfo_reqheight(window)
+ TkWinfo.reqheight self
+ end
+ def TkWinfo.reqwidth(window)
+ number(tk_call('winfo', 'reqwidth', window.path))
+ end
+ def winfo_reqwidth(window)
+ TkWinfo.reqwidth self
+ end
+ def TkWinfo.rgb(window, color)
+ list(tk_call('winfo', 'rgb', window.path, color))
+ end
+ def winfo_rgb(window, color)
+ TkWinfo.rgb self, color
+ end
+ def TkWinfo.rootx(window)
+ number(tk_call('winfo', 'rootx', window.path))
+ end
+ def winfo_rootx(window)
+ TkWinfo.rootx self
+ end
+ def TkWinfo.rooty(window)
+ number(tk_call('winfo', 'rooty', window.path))
+ end
+ def winfo_rooty(window)
+ TkWinfo.rooty self
+ end
+ def TkWinfo.screen(window)
+ tk_call 'winfo', 'screen', window.path
+ end
+ def winfo_screen(window)
+ TkWinfo.screen self
+ end
+ def TkWinfo.screencells(window)
+ number(tk_call('winfo', 'screencells', window.path))
+ end
+ def winfo_screencells(window)
+ TkWinfo.screencells self
+ end
+ def TkWinfo.screendepth(window)
+ number(tk_call('winfo', 'screendepth', window.path))
+ end
+ def winfo_screendepth(window)
+ TkWinfo.screendepth self
+ end
+ def TkWinfo.screenheight (window)
+ number(tk_call('winfo', 'screenheight', window.path))
+ end
+ def winfo_screenheight(window)
+ TkWinfo.screenheight self
+ end
+ def TkWinfo.screenmmheight(window)
+ number(tk_call('winfo', 'screenmmheight', window.path))
+ end
+ def winfo_screenmmheight(window)
+ TkWinfo.screenmmheight self
+ end
+ def TkWinfo.screenmmwidth(window)
+ number(tk_call('winfo', 'screenmmwidth', window.path))
+ end
+ def winfo_screenmmwidth(window)
+ TkWinfo.screenmmwidth self
+ end
+ def TkWinfo.screenvisual(window)
+ tk_call 'winfo', 'screenvisual', window.path
+ end
+ def winfo_screenvisual(window)
+ TkWinfo.screenvisual self
+ end
+ def TkWinfo.screenwidth(window)
+ number(tk_call('winfo', 'screenwidth', window.path))
+ end
+ def winfo_screenwidth(window)
+ TkWinfo.screenwidth self
+ end
+ def TkWinfo.toplevel(window)
+ window(tk_call('winfo', 'toplevel', window.path))
+ end
+ def winfo_toplevel(window)
+ TkWinfo.toplevel self
+ end
+ def TkWinfo.visual(window)
+ tk_call 'winfo', 'visual', window.path
+ end
+ def winfo_visual(window)
+ TkWinfo.visual self
+ end
+ def TkWinfo.vrootheigh(window)
+ number(tk_call('winfo', 'vrootheight', window.path))
+ end
+ def winfo_vrootheight(window)
+ TkWinfo.vrootheight self
+ end
+ def TkWinfo.vrootwidth(window)
+ number(tk_call('winfo', 'vrootwidth', window.path))
+ end
+ def winfo_vrootwidth(window)
+ TkWinfo.vrootwidth self
+ end
+ def TkWinfo.vrootx(window)
+ number(tk_call('winfo', 'vrootx', window.path))
+ end
+ def winfo_vrootx(window)
+ TkWinfo.vrootx self
+ end
+ def TkWinfo.vrooty(window)
+ number(tk_call('winfo', 'vrooty', window.path))
+ end
+ def winfo_vrooty(window)
+ TkWinfo.vrooty self
+ end
+ def TkWinfo.width(window)
+ number(tk_call('winfo', 'width', window.path))
+ end
+ def winfo_width(window)
+ TkWinfo.width self
+ end
+ def TkWinfo.x(window)
+ number(tk_call('winfo', 'x', window.path))
+ end
+ def winfo_x(window)
+ TkWinfo.x self
+ end
+ def TkWinfo.y(window)
+ number(tk_call('winfo', 'y', window.path))
+ end
+ def winfo_y(window)
+ TkWinfo.y self
+ end
+end
+
+module TkPack
+ include Tk
+ extend Tk
+ def configure(win, *args)
+ if args[-1].is_kind_of(Hash)
+ keys = args.pop
+ end
+ wins = [win.epath]
+ for i in args
+ wins.push i.epath
+ end
+ tk_call "pack", 'configure', *(wins+hash_kv(keys))
+ end
+
+ def forget(*args)
+ tk_call 'pack', 'forget' *args
+ end
+
+ def propagate(master, bool=None)
+ bool(tk_call('pack', 'propagate', mastaer.epath, bool))
+ end
+ module_function :configure, :forget, :propagate
+end
+
+module TkOption
+ include Tk
+ extend Tk
+ def add pat, value, pri=None
+ tk_call 'option', 'add', pat, value, pri
+ end
+ def clear
+ tk_call 'option', 'clear'
+ end
+ def get win, classname, name
+ tk_call 'option', 'get', classname, name
+ end
+ def readfile file, pri=None
+ tk_call 'option', 'readfile', file, pri
+ end
+ module_function :add, :clear, :get, :readfile
+end
+
+class TkObject:TkKernel
+ include Tk
+
+ def path
+ return @path
+ end
+
+ def epath
+ return @path
+ end
+
+ def tk_send(cmd, *rest)
+ tk_call path, cmd, *rest
+ end
+ private :tk_send
+
+ def method_missing(id, *args)
+ if (args.length == 1)
+ configure id.id2name, args[0]
+ else
+ $@ = error_at
+ super
+ end
+ end
+
+ def []=(id, val)
+ configure id, val
+ end
+
+ def configure(slot, value)
+ if value == FALSE
+ value = "0"
+ elsif value.type == Proc
+ value = install_cmd(value)
+ end
+ tk_call path, 'configure', "-#{slot}", value
+ end
+
+ def configure_cmd(slot, value)
+ configure slot, install_cmd(value)
+ end
+
+ def bind(context, cmd=Proc.new)
+ _bind path, context, cmd
+ end
+end
+
+class TkWindow:TkObject
+ $tk_window_id = "w00000"
+ def initialize(parent=nil, keys=nil)
+ id = $tk_window_id
+ $tk_window_id = $tk_window_id.next
+ if !parent or parent == Tk.root
+ @path = format(".%s", id);
+ else
+ @path = format("%s.%s", parent.path, id)
+ end
+ $tk_window_list[@path] = self
+ create_self
+ if keys
+ tk_call @path, 'configure', *hash_kv(keys)
+ end
+ end
+
+ def create_self
+ end
+ private :create_self
+
+ def pack(keys = nil)
+ tk_call 'pack', epath, *hash_kv(keys)
+ self
+ end
+
+ def unpack(keys = nil)
+ tk_call 'pack', 'forget', epath
+ self
+ end
+
+ def focus
+ tk_call 'focus', path
+ self
+ end
+
+ def grab(*args)
+ if !args or args.length == 0
+ tk_call 'grab', 'set', path
+ elsif args.length == 1
+ case args[0]
+ when 'global'
+ tk_call 'grab', 'set', '-global', path
+ else
+ val = tk_call('grab', arg[0], path)
+ end
+ case args[0]
+ when 'current'
+ return window(val)
+ when 'status'
+ return val
+ end
+ else
+ fail 'wrong # of args'
+ end
+ end
+
+ def lower(below=None)
+ tk_call 'lower', path, below
+ self
+ end
+ def raise(above=None)
+ tk_call 'raise', path, above
+ self
+ end
+
+ def command(cmd)
+ configure_cmd 'command', cmd
+ end
+
+ def colormodel model=None
+ tk_call 'tk', 'colormodel', path, model
+ self
+ end
+
+ def destroy
+ tk_call 'destroy', path
+ if @cmdtbl
+ for id in @cmdtbl
+ uninstall_cmd id
+ end
+ end
+ $tk_window_list[path] = nil
+ end
+end
+
+class TkRoot:TkWindow
+ include Wm
+ def TkRoot.new
+ return $tk_root if $tk_root
+ super
+ end
+ def path
+ "."
+ end
+ $tk_root = TkRoot.new
+ $tk_window_list['.'] = $tk_root
+end
+
+class TkToplevel:TkWindow
+ include Wm
+ def initialize(parent=nil, screen=nil, classname=nil)
+ @screen = screen if screen
+ @classname = classname if classname
+ super
+ end
+
+ def create_self
+ s = []
+ s.push "-screen #@screen" if @screen
+ s.push "-class #@classname" if @classname
+ tk_call 'toplevel', path, *s
+ end
+end
+
+class TkFrame:TkWindow
+ def create_self
+ tk_call 'frame', @path
+ end
+end
+
+class TkLabel:TkWindow
+ def create_self
+ tk_call 'label', @path
+ end
+ def textvariable(v)
+ vn = @path + v.id2name
+ vset = format("global {%s}; set {%s}", vn, vn)
+ tk_call vset, eval(v.id2name).inspect
+ trace_var v, proc{|val|
+ tk_call vset, val.inspect
+ }
+ configure 'textvariable', vn
+ end
+end
+
+class TkButton:TkLabel
+ def create_self
+ tk_call 'button', @path
+ end
+ def invoke
+ tk_send 'invoke'
+ end
+ def flash
+ tk_send 'flash'
+ end
+end
+
+class TkRadioButton:TkButton
+ def create_self
+ tk_call 'radiobutton', @path
+ end
+ def deselect
+ tk_send 'deselect'
+ end
+ def select
+ tk_send 'select'
+ end
+ def variable(v)
+ vn = v.id2name; vn =~ /^./
+ vn = 'btns_selected_' + $'
+ trace_var v, proc{|val|
+ tk_call 'set', vn, val
+ }
+ @var_id = install_cmd(proc{|name1,|
+ val = tk_call('set', name1)
+ eval(format("%s = '%s'", v.id2name, val))
+ })
+ tk_call 'trace variable', vn, 'w', @var_id
+ configure 'variable', vn
+ end
+ def destroy
+ tk_call 'trace vdelete', vn, 'w', @var_id
+ super
+ end
+end
+
+class TkCheckButton:TkRadioButton
+ def create_self
+ tk_call 'checkbutton', @path
+ end
+ def toggle
+ tk_send 'toggle'
+ end
+end
+
+class TkMessage:TkLabel
+ def create_self
+ tk_call 'message', @path
+ end
+end
+
+class TkScale:TkWindow
+ def create_self
+ tk_call 'scale', path
+ end
+
+ def get
+ number(tk_send('get'))
+ end
+
+ def set(val)
+ tk_send "set", val
+ end
+
+ def value
+ get
+ end
+
+ def value= (val)
+ set val
+ end
+end
+
+class TkScrollbar:TkWindow
+ def create_self
+ tk_call 'scrollbar', path
+ end
+
+ def get
+ ary1 = tk_send('get', path).split
+ ary2 = []
+ for i in ary1
+ push number(i)
+ end
+ ary2
+ end
+
+ def set(first, last)
+ tk_send "set", first, last
+ end
+end
+
+# abstract class for Text and Listbox
+class TkTextWin:TkWindow
+ def bbox(index)
+ tk_send 'bbox', index
+ end
+ def delete(first, last=None)
+ tk_send 'delete', first, last
+ end
+ def get(*index)
+ tk_send 'get', *index
+ end
+ def insert(index, *rest)
+ tk_send 'insert', index, *rest
+ end
+ def index(index)
+ tk_send 'index', index
+ end
+ def insert(index, chars, *args)
+ tk_send 'insert', index, chars, *args
+ end
+ def scan_mark(x, y)
+ tk_send 'scan', 'mark', x, y
+ end
+ def scan_dragto(x, y)
+ tk_send 'scan', 'dragto', x, y
+ end
+ def see(index)
+ tk_send 'see', index
+ end
+end
+
+class TkListbox:TkTextWin
+ def create_self
+ tk_call 'listbox', path
+ end
+
+ def nearest(y)
+ tk_send 'nearest', y
+ end
+ def selection_anchor(index)
+ tk_send 'selection', 'anchor', index
+ end
+ def selection_clear(first, last=None)
+ tk_send 'selection', 'clear', first, last
+ end
+ def selection_includes
+ bool(tk_send('selection', 'includes'))
+ end
+ def selection_set(first, last=None)
+ tk_send 'selection', 'set', first, last
+ end
+ def xview(cmd, index, *more)
+ tk_send 'xview', cmd, index, *more
+ end
+ def yview(cmd, index, *more)
+ tk_send 'yview', cmd, index, *more
+ end
+end
+
+class TkMenu:TkWindow
+ def create_self
+ tk_call 'menu', path
+ end
+ def activate(index)
+ tk_send 'activate', index
+ end
+ def add(type, keys=nil)
+ tk_send 'add', type, *kv_hash(keys)
+ end
+ def index(index)
+ tk_send 'index', index
+ end
+ def invoke
+ tk_send 'invoke'
+ end
+ def insert(index, type, keys=nil)
+ tk_send 'add', index, type, *kv_hash(keys)
+ end
+ def post(x, y)
+ tk_send 'post', x, y
+ end
+ def postcascade(index)
+ tk_send 'postcascade', index
+ end
+ def postcommand(cmd)
+ configure_cmd 'postcommand', cmd
+ end
+ def menutype(index)
+ tk_send 'type', index
+ end
+ def unpost
+ tk_send 'unpost'
+ end
+ def yposition(index)
+ number(tk_send('yposition', index))
+ end
+end
+
+class TkMenubutton:TkLabel
+ def create_self
+ tk_call 'menubutton', path
+ end
+end
+
+module TkComposite
+ def initialize(parent=nil, *args)
+ @frame = TkFrame.new(parent)
+ @path = @epath = @frame.path
+ initialize_composite(*args)
+ end
+
+ def epath
+ @epath
+ end
+
+ def initialize_composite(*args) end
+ private :initialize_composite
+
+ def delegate(option, *wins)
+ @delegates = {} if not @delegates
+ @delegates['DEFAULT'] = @frame
+ if option.is_kind_of? String
+ @delegates[option] = wins
+ else
+ for i in option
+ @delegates[i] = wins
+ end
+ end
+ end
+
+ def configure(slot, value)
+ if @delegates and @delegates[slot]
+ for i in @delegates[slot]
+ if not i
+ i = @delegates['DEFALUT']
+ redo
+ else
+ last = i.configure(slot, value)
+ end
+ end
+ last
+ else
+ super
+ end
+ end
+end
+
+autoload :TkCanvas, 'tkcanvas'
+autoload :TkImage, 'tkcanvas'
+autoload :TkBitmapImage, 'tkcanvas'
+autoload :TkPhotoImage, 'tkcanvas'
+autoload :TkEntry, 'tkentry'
+autoload :TkText, 'tktext'