summaryrefslogtreecommitdiff
path: root/lib/tk.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/tk.rb')
-rw-r--r--lib/tk.rb557
1 files changed, 54 insertions, 503 deletions
diff --git a/lib/tk.rb b/lib/tk.rb
index 9c61269881..5a725aac11 100644
--- a/lib/tk.rb
+++ b/lib/tk.rb
@@ -3,477 +3,10 @@
# $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
+if defined? Thread and $tk_thread_safe
+ require "tkthcore"
+else
+ require "tkcore"
end
module TkSelection
@@ -550,11 +83,11 @@ module TkWinfo
def winfo_depth(window)
TkWinfo.depth self
end
- def TkWinfo.exists(window)
+ def TkWinfo.exist?(window)
bool(tk_call('winfo', 'exists', window.path))
end
- def winfo_exists(window)
- TkWinfo.exists self
+ def winfo_exist?(window)
+ TkWinfo.exist? self
end
def TkWinfo.fpixels(window, number)
number(tk_call('winfo', 'fpixels', window.path, number))
@@ -580,11 +113,11 @@ module TkWinfo
def winfo_id(window)
TkWinfo.id self
end
- def TkWinfo.ismapped(window)
+ def TkWinfo.mapped?(window)
bool(tk_call('winfo', 'ismapped', window.path))
end
- def winfo_ismapped(window)
- TkWinfo.ismapped self
+ def winfo_mapped?(window)
+ TkWinfo.mapped? self
end
def TkWinfo.parent(window)
window(tk_call('winfo', 'parent', window.path))
@@ -742,7 +275,7 @@ module TkPack
include Tk
extend Tk
def configure(win, *args)
- if args[-1].is_kind_of(Hash)
+ if args[-1].kind_of?(Hash)
keys = args.pop
end
wins = [win.epath]
@@ -780,7 +313,7 @@ module TkOption
module_function :add, :clear, :get, :readfile
end
-class TkObject:TkKernel
+class TkObject<TkKernel
include Tk
def path
@@ -822,16 +355,16 @@ class TkObject:TkKernel
configure slot, install_cmd(value)
end
- def bind(context, cmd=Proc.new)
- _bind path, context, cmd
+ def bind(context, cmd=Proc.new, args=nil)
+ _bind path, context, cmd, args
end
end
-class TkWindow:TkObject
+class TkWindow<TkObject
$tk_window_id = "w00000"
def initialize(parent=nil, keys=nil)
id = $tk_window_id
- $tk_window_id = $tk_window_id.next
+ $tk_window_id = $tk_window_id.succ
if !parent or parent == Tk.root
@path = format(".%s", id);
else
@@ -880,7 +413,7 @@ class TkWindow:TkObject
return val
end
else
- fail 'wrong # of args'
+ fail ArgumentError, 'wrong # of args'
end
end
@@ -913,7 +446,7 @@ class TkWindow:TkObject
end
end
-class TkRoot:TkWindow
+class TkRoot<TkWindow
include Wm
def TkRoot.new
return $tk_root if $tk_root
@@ -926,7 +459,7 @@ class TkRoot:TkWindow
$tk_window_list['.'] = $tk_root
end
-class TkToplevel:TkWindow
+class TkToplevel<TkWindow
include Wm
def initialize(parent=nil, screen=nil, classname=nil)
@screen = screen if screen
@@ -942,20 +475,21 @@ class TkToplevel:TkWindow
end
end
-class TkFrame:TkWindow
+class TkFrame<TkWindow
def create_self
tk_call 'frame', @path
end
end
-class TkLabel:TkWindow
+class TkLabel<TkWindow
def create_self
tk_call 'label', @path
end
def textvariable(v)
- vn = @path + v.id2name
+ v = v.id2name unless v.kind_of "String"
+ vn = @path + v
vset = format("global {%s}; set {%s}", vn, vn)
- tk_call vset, eval(v.id2name).inspect
+ tk_call vset, eval(v).inspect
trace_var v, proc{|val|
tk_call vset, val.inspect
}
@@ -963,7 +497,7 @@ class TkLabel:TkWindow
end
end
-class TkButton:TkLabel
+class TkButton<TkLabel
def create_self
tk_call 'button', @path
end
@@ -975,7 +509,7 @@ class TkButton:TkLabel
end
end
-class TkRadioButton:TkButton
+class TkRadioButton<TkButton
def create_self
tk_call 'radiobutton', @path
end
@@ -986,8 +520,13 @@ class TkRadioButton:TkButton
tk_send 'select'
end
def variable(v)
- vn = v.id2name; vn =~ /^./
- vn = 'btns_selected_' + $'
+ v = v.id2name unless v.kind_of "String"
+ if v =~ /^\$/
+ v = $'
+ else
+ fail ArgumentError, "variable must be global(%s)", v
+ end
+ vn = 'btns_selected_' + v
trace_var v, proc{|val|
tk_call 'set', vn, val
}
@@ -1004,7 +543,7 @@ class TkRadioButton:TkButton
end
end
-class TkCheckButton:TkRadioButton
+class TkCheckButton<TkRadioButton
def create_self
tk_call 'checkbutton', @path
end
@@ -1013,13 +552,13 @@ class TkCheckButton:TkRadioButton
end
end
-class TkMessage:TkLabel
+class TkMessage<TkLabel
def create_self
tk_call 'message', @path
end
end
-class TkScale:TkWindow
+class TkScale<TkWindow
def create_self
tk_call 'scale', path
end
@@ -1041,11 +580,23 @@ class TkScale:TkWindow
end
end
-class TkScrollbar:TkWindow
+class TkScrollbar<TkWindow
def create_self
tk_call 'scrollbar', path
end
+ def delta(deltax=None, deltay=None)
+ number(tk_send('delta', deltax, deltay))
+ end
+
+ def fraction(x=None, y=None)
+ number(tk_send('fraction', x, y))
+ end
+
+ def identify(x=None, y=None)
+ tk_send('fraction', x, y)
+ end
+
def get
ary1 = tk_send('get', path).split
ary2 = []
@@ -1061,7 +612,7 @@ class TkScrollbar:TkWindow
end
# abstract class for Text and Listbox
-class TkTextWin:TkWindow
+class TkTextWin<TkWindow
def bbox(index)
tk_send 'bbox', index
end
@@ -1091,7 +642,7 @@ class TkTextWin:TkWindow
end
end
-class TkListbox:TkTextWin
+class TkListbox<TkTextWin
def create_self
tk_call 'listbox', path
end
@@ -1119,7 +670,7 @@ class TkListbox:TkTextWin
end
end
-class TkMenu:TkWindow
+class TkMenu<TkWindow
def create_self
tk_call 'menu', path
end
@@ -1158,7 +709,7 @@ class TkMenu:TkWindow
end
end
-class TkMenubutton:TkLabel
+class TkMenubutton<TkLabel
def create_self
tk_call 'menubutton', path
end
@@ -1181,7 +732,7 @@ module TkComposite
def delegate(option, *wins)
@delegates = {} if not @delegates
@delegates['DEFAULT'] = @frame
- if option.is_kind_of? String
+ if option.kind_of? String
@delegates[option] = wins
else
for i in option