summaryrefslogtreecommitdiff
path: root/ext/tk/lib/tk.rb
diff options
context:
space:
mode:
authornagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2002-06-04 07:03:33 +0000
committernagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2002-06-04 07:03:33 +0000
commit4cb164ee2a30ecb59ce93670e569f384c7da7521 (patch)
treeb72a391e53110bb8b216ef9d16741b314f148ce6 /ext/tk/lib/tk.rb
parentdc010ff5157787b80ed35410587d0b988d55dda4 (diff)
* tkfont.rb: Fix bugs on TkFont.init_widget_font for Tk8.x.
* tkafter.rb: Add self to 1st argument of interval- and loop-proc TkAfter#current_interval returns an interval (sleep) time value TkAfter#current_args returns an array of arguments TkAfter#return_value returns a return value of last loop-proc e.g. TkAfter.new( proc{|obj| 500 - obj.current_interval}, 10, [proc{|obj| p obj.current_args}, 'proc', 1], proc{|obj| p obj.current_args; ['return', 2]}, [proc{|obj| p obj.return_value p ['proc', obj.current_args[0].call(obj.return_value[1], obj.current_args[1])]}, proc{|*args| args[0] + args[1]}, 1], proc{p ['proc', 4]} ).start(100) * tk*.rb: Allow to use Symbols for parameters. Allow new notation of constructor (also allow old notation). e.g. TkFrame.new('classname'=>'User'){|base| pack f = TkFrame.new(base, :classname=>'ButtonFrame').pack TkButton.new( :parent => f, :text => 'Quit', :command => proc{exit} ).pack( :fill => :x, :pady => 2 ) } * tkcanvas.rb: (TkcItem) Add 'coords' parameter to the canvas item constructor (for new notation of constructor). e.g. c = TkCanvas.new.pack l = TkcLine.new(c, :coords=>[[0,0], [100,100]]) * tcltklib.c: New 'mainloop' and 'mainloop_watchdog'. The priority of their event-loop can be controlled. They accept an optional argument. If it false, they don't exit although the root widget is destroyed. This function is sometimes useful, if it is used with 'restart'. 'mainloop' can't treat Thread#join/value in a callback routine. (e.g. TkButton.new(:command=>proc{p Thread.new{button.invoke}.value}) ) 'mainloop_watchdog' can treat them, but watchdog thread is always running (so, a little heavier than 'mainloop'). If the purpose of using Thread#join/value is to do something under some safe-level, please use Proc object. (e.g. :command=>proc{$SAFE=1;proc{$SAFE=2;button.invoke}.call;p $SAFE}) * tk.rb: Support functions of new 'mainloop' and 'mainloop_watchdog'. * tk.rb: (Tk.restart) Add 'app-name' paramater and 'use' parameter. 'app-name' specifies the name and the resource class of the application. If 'app-name' is specified to 'xxx', the application class on the resource database is set to 'Xxx' and the application name is changed by the same rule of Tk.appname method. 'use' specifies the main window for embedding the root widget instead of generating a new window. * tk.rb: Add new parameter 'widgetname' to the widget constructor to support effective use of Resource Database. For example, the resource 'Xxx*quit.text: QUIT' can set the text of the button generated by the following code. e.g. Tk.restart('Xxx') TkButton.new(nil, 'widgetname'=>'quit', 'command'=>proc{exit}).pack Tk.mainloop * tk.rb: TkOption::get always returns a tainted string. Add TkOption::new_proc_class. It generates a class to import procedures defined on the resource database. For example, there is a following resource file. ----< resource-test >------------ *CMD.foo: {|*args| p [$SAFE, :foo, args]} *CMD.XXX.bar: {|*args| p [$SAFE, :bar, args]} *Button.command: ruby {p self; p $SAFE; TkOption::CMD::XXX.bar(1,2,3)} --------------------------------- The following code is a sample of use of the resource file. e.g. require 'tk' TkOption.readfile 'resource-test' p TkOption.new_proc_class(:CMD, [:foo], 1) p TkOption.new_proc_class(:XXX, [:bar], 2, false, TkOption::CMD) TkButton.new(:text=>'test').pack Tk.mainloop git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2515 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/tk/lib/tk.rb')
-rw-r--r--ext/tk/lib/tk.rb296
1 files changed, 242 insertions, 54 deletions
diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb
index bac2ae35f9..2e33c4294c 100644
--- a/ext/tk/lib/tk.rb
+++ b/ext/tk/lib/tk.rb
@@ -132,6 +132,13 @@ module TkComm
end
private :tk_tcl2ruby, :tk_split_list, :tk_split_simplelist
+ def _symbolkey2str(keys)
+ h = {}
+ keys.each{|key,value| h[key.to_s] = value}
+ h
+ end
+ private :_symbolkey2str
+
def hash_kv(keys)
conf = []
if keys and keys != None
@@ -204,6 +211,8 @@ module TkComm
return nil if str == None
if str.kind_of?(String)
# do nothing
+ elsif str.kind_of?(Symbol)
+ str = str.id2name
elsif str.kind_of?(Hash)
str = hash_kv(str).join(" ")
elsif str.kind_of?(Array)
@@ -259,13 +268,15 @@ module TkComm
end
private :install_cmd, :uninstall_cmd
- def install_win(ppath)
- id = format("w%.4d", Tk_IDs[1])
- Tk_IDs[1] += 1
+ def install_win(ppath,name=nil)
+ if !name or name == ''
+ name = format("w%.4d", Tk_IDs[1])
+ Tk_IDs[1] += 1
+ end
if !ppath or ppath == "."
- @path = format(".%s", id);
+ @path = format(".%s", name);
else
- @path = format("%s.%s", ppath, id)
+ @path = format("%s.%s", ppath, name)
end
Tk_WINDOWS[@path] = self
end
@@ -483,6 +494,8 @@ module TkCore
}
EOL
+ EventFlag = TclTkLib::EventFlag
+
def callback_break
fail TkCallbackBreak, "Tk callback returns 'break' status"
end
@@ -616,12 +629,42 @@ module TkCore
tk_call('info', *args)
end
- def mainloop
- TclTkLib.mainloop
+ def mainloop(check_root = true)
+ TclTkLib.mainloop(check_root)
end
- def restart
+ def mainloop_watchdog(check_root = true)
+ TclTkLib.mainloop_watchdog(check_root)
+ end
+
+ def do_one_event(flag = 0)
+ TclTkLib.do_one_event(flag)
+ end
+
+ def set_eventloop_tick(timer_tick)
+ TclTkLib.set_eventloop_tick(timer_tick)
+ end
+
+ def get_eventloop_tick()
+ TclTkLib.get_eventloop_tick
+ end
+
+ def set_eventloop_weight(loop_max, no_event_tick)
+ TclTkLib.set_eventloop_weight(loop_max, no_event_tick)
+ end
+
+ def get_eventloop_weight()
+ TclTkLib.get_eventloop_weight
+ end
+
+ def restart(app_name = nil, use = nil)
+ tk_call('set', 'argv0', app_name) if app_name
+ if use
+ tk_call('set', 'argc', 2)
+ tk_call('set', 'argv', "-use #{use}")
+ end
TkCore::INTERP.restart
+ TkComm::Tk_CMDTBL.clear
TkComm::Tk_WINDOWS.clear
nil
end
@@ -2077,12 +2120,87 @@ module TkOption
tk_call 'option', 'clear'
end
def get win, name, klass
- tk_call 'option', 'get', win ,name, klass
+ tk_call('option', 'get', win ,name, klass).taint
end
def readfile file, pri=None
tk_call 'option', 'readfile', file, pri
end
module_function :add, :clear, :get, :readfile
+
+ # support procs on the resource database
+ @@resource_proc_class = Class.new
+ class << @@resource_proc_class
+ private :new
+
+ CARRIER = '.'.freeze
+ METHOD_TBL = {}
+ ADD_METHOD = false
+ SAFE_MODE = 4
+
+ def __check_proc_string__(str)
+ # If you want to check the proc_string, do it in this method.
+ str
+ end
+
+ def method_missing(id, *args)
+ res_proc = self::METHOD_TBL[id]
+ unless res_proc.kind_of? Proc
+ if id == :new || (!self::METHOD_TBL.has_key?(id) && !self::ADD_METHOD)
+ raise NoMethodError,
+ "not support resource-proc '#{id.id2name}' for #{self.name}"
+ end
+ proc_str = TkOption.get(self::CARRIER, id.id2name, '')
+ proc_str = '{' + proc_str + '}' unless /\A\{.*\}\Z/ =~ proc_str
+ proc_str = __check_proc_string__(proc_str)
+ res_proc = eval 'Proc.new' + proc_str
+ self::METHOD_TBL[id] = res_proc
+ end
+ proc{
+ $SAFE = self::SAFE_MODE
+ res_proc.call(*args)
+ }.call
+ end
+
+ private :__check_proc_string__, :method_missing
+ end
+
+ def new_proc_class(klass, func, safe = 4, add = false, parent = nil)
+ klass = klass.to_s if klass.kind_of? Symbol
+ unless (?A..?Z) === klass[0]
+ fail ArgumentError, "bad string '#{klass}' for class name"
+ end
+ unless func.kind_of? Array
+ fail ArgumentError, "method-list must be Array"
+ end
+ func_str = func.join(' ')
+ if parent == nil
+ install_win(parent)
+ elsif parent <= @@resource_proc_class
+ install_win(parent::CARRIER)
+ else
+ fail ArgumentError, "parent must be Resource-Proc class"
+ end
+ carrier = Tk.tk_call('frame', @path, '-class', klass)
+
+ body = <<-"EOD"
+ class #{klass} < TkOption.module_eval('@@resource_proc_class')
+ CARRIER = '#{carrier}'.freeze
+ METHOD_TBL = {}
+ ADD_METHOD = #{add}
+ SAFE_MODE = #{safe}
+ %w(#{func_str}).each{|f| METHOD_TBL[f.intern] = nil }
+ end
+ EOD
+
+ if parent.kind_of?(Class) && parent <= @@resource_proc_class
+ parent.class_eval body
+ eval parent.name + '::' + klass
+ else
+ eval body
+ eval 'TkOption::' + klass
+ end
+ end
+ module_function :new_proc_class
end
module TkTreatFont
@@ -2096,6 +2214,7 @@ module TkTreatFont
alias fontobj font_configinfo
def font_configure(slot)
+ slot = _symbolkey2str(slot)
if (fnt = slot.delete('font'))
if fnt.kind_of? TkFont
return fnt.call_font_configure(self.path, self.path,'configure',slot)
@@ -2203,6 +2322,7 @@ module TkTreatItemFont
def tagfont_configure(tagOrId, slot)
pathname = __item_pathname(tagOrId)
+ slot = _symbolkey2str(slot)
if (fnt = slot.delete('font'))
if fnt.kind_of? TkFont
return fnt.call_font_configure(pathname, self.path,
@@ -2345,7 +2465,7 @@ class TkObject<TkKernel
end
def cget(slot)
- case slot
+ case slot.to_s
when 'text', 'label', 'show', 'data', 'file'
tk_call path, 'cget', "-#{slot}"
else
@@ -2355,16 +2475,20 @@ class TkObject<TkKernel
def configure(slot, value=None)
if slot.kind_of? Hash
- if (slot['font'] || slot['kanjifont'] ||
- slot['latinfont'] || slot['asciifont'] )
- font_configure(slot.dup)
+ if (slot['font'] || slot[:font] ||
+ slot['kanjifont'] || slot[:kanjifont] ||
+ slot['latinfont'] || slot[:latinfont] ||
+ slot['asciifont'] || slot[:asciifont] )
+ font_configure(slot)
else
tk_call path, 'configure', *hash_kv(slot)
end
else
- if (slot == 'font' || slot == 'kanjifont' ||
- slot == 'latinfont' || slot == 'asciifont')
+ if (slot == 'font' || slot == :font ||
+ slot == 'kanjifont' || slot == :kanjifont ||
+ slot == 'latinfont' || slot == :latinfont ||
+ slot == 'asciifont' || slot == :asciifont )
if value == None
fontobj
else
@@ -2381,11 +2505,12 @@ class TkObject<TkKernel
end
def configinfo(slot = nil)
- if slot == 'font' || slot == 'kanjifont'
+ if slot == 'font' || slot == :font ||
+ slot == 'kanjifont' || slot == :kanjifont
fontobj
else
if slot
- case slot
+ case slot.to_s
when 'text', 'label', 'show', 'data', 'file'
conf = tk_split_simplelist(tk_send('configure', "-#{slot}") )
else
@@ -2455,7 +2580,19 @@ class TkWindow<TkObject
extend TkBindCore
def initialize(parent=nil, keys=nil)
- install_win(if parent then parent.path end)
+ if parent.kind_of? Hash
+ keys = _symbolkey2str(parent)
+ keydup = true
+ parent = keys.delete('parent')
+ widgetname = keys.delete('widgetname')
+ install_win(if parent then parent.path end, widgetname)
+ elsif keys
+ keys = _symbolkey2str(keys)
+ widgetname = keys.delete('widgetname')
+ install_win(if parent then parent.path end, widgetname)
+ else
+ install_win(if parent then parent.path end)
+ end
if self.method(:create_self).arity == 0
p 'create_self has no arg' if $DEBUG
create_self
@@ -2464,10 +2601,9 @@ class TkWindow<TkObject
configure(keys)
end
else
- p 'create_self has an arg' if $DEBUG
+ p 'create_self has args' if $DEBUG
fontkeys = {}
if keys
- keys = keys.dup
['font', 'kanjifont', 'latinfont', 'asciifont'].each{|key|
fontkeys[key] = keys.delete(key) if keys.key?(key)
}
@@ -2668,17 +2804,17 @@ class TkWindow<TkObject
tk_call 'grab', 'set', path
elsif args.length == 1
case args[0]
- when 'global'
+ when 'global', :global
return(tk_call 'grab', 'set', '-global', path)
- when 'release'
+ when 'release', :release
return(tk_call 'grab', 'release', path)
else
val = tk_call('grab', args[0], path)
end
case args[0]
- when 'current'
+ when 'current', :current
return window(val)
- when 'status'
+ when 'status', :status
return val
end
else
@@ -2811,15 +2947,27 @@ class TkToplevel<TkWindow
#################
def initialize(parent=nil, screen=nil, classname=nil, keys=nil)
+ if parent.kind_of? Hash
+ keys = _symbolkey2str(parent)
+ @screen = keys['screen']
+ @classname = keys['class']
+ @colormap = keys['colormap']
+ @container = keys['container']
+ @screen = keys['screen']
+ @use = keys['use']
+ @visual = keys['visual']
+ super(keys)
+ return
+ end
if screen.kind_of? Hash
- keys = screen
+ keys = _symbolkey2str(screen)
else
@screen = screen
end
@classname = classname
if keys.kind_of? Hash
- if keys.key?('classname')
- keys = keys.dup
+ keys = _symbolkey2str(keys)
+ if keys.key?(:classname) || keys.key?('classname')
keys['class'] = keys.delete('classname')
end
@classname = keys['class']
@@ -2875,17 +3023,24 @@ class TkFrame<TkWindow
#################
def initialize(parent=nil, keys=nil)
- if keys.kind_of? Hash
- if keys.key?('classname')
- keys = keys.dup
- keys['class'] = keys.delete('classname')
+ if parent.kind_of? Hash
+ keys = _symbolkey2str(parent)
+ else
+ if keys
+ keys = _symbolkey2str(keys)
+ keys['parent'] = parent
+ else
+ keys = {'parent'=>parent}
end
- @classname = keys['class']
- @colormap = keys['colormap']
- @container = keys['container']
- @visual = keys['visual']
end
- super(parent, keys)
+ if keys.key?('classname')
+ keys['class'] = keys.delete('classname')
+ end
+ @classname = keys['class']
+ @colormap = keys['colormap']
+ @container = keys['container']
+ @visual = keys['visual']
+ super(keys)
end
def create_self(keys)
@@ -3170,7 +3325,7 @@ class TkListbox<TkTextWin
end
def itemcget(index, key)
- case key
+ case key.to_s
when 'text', 'label', 'show'
tk_send 'itemcget', index, "-#{key}"
else
@@ -3179,16 +3334,20 @@ class TkListbox<TkTextWin
end
def itemconfigure(index, key, val=None)
if key.kind_of? Hash
- if (key['font'] || key['kanjifont'] ||
- key['latinfont'] || key['asciifont'])
- tagfont_configure(index, key.dup)
+ if (key['font'] || key[:font] ||
+ key['kanjifont'] || key[:kanjifont] ||
+ key['latinfont'] || key[:latinfont] ||
+ key['asciifont'] || key[:asciifont] )
+ tagfont_configure(index, _symbolkey2str(key))
else
tk_send 'itemconfigure', index, *hash_kv(key)
end
else
- if (key == 'font' || key == 'kanjifont' ||
- key == 'latinfont' || key == 'asciifont' )
+ if (key == 'font' || key == :font ||
+ key == 'kanjifont' || key == :kanjifont ||
+ key == 'latinfont' || key == :latinfont ||
+ key == 'asciifont' || key == :asciifont )
tagfont_configure(index, {key=>val})
else
tk_call 'itemconfigure', index, "-#{key}", val
@@ -3198,7 +3357,7 @@ class TkListbox<TkTextWin
def itemconfiginfo(index, key=nil)
if key
- case key
+ case key.to_s
when 'text', 'label', 'show'
conf = tk_split_simplelist(tk_send('itemconfigure',index,"-#{key}"))
else
@@ -3305,7 +3464,7 @@ class TkMenu<TkWindow
number(tk_send('yposition', index))
end
def entrycget(index, key)
- case key
+ case key.to_s
when 'text', 'label', 'show'
tk_send 'entrycget', index, "-#{key}"
else
@@ -3314,16 +3473,20 @@ class TkMenu<TkWindow
end
def entryconfigure(index, key, val=None)
if key.kind_of? Hash
- if (key['font'] || key['kanjifont'] ||
- key['latinfont'] || key['asciifont'])
- tagfont_configure(index, key.dup)
+ if (key['font'] || key[:font] ||
+ key['kanjifont'] || key[:kanjifont] ||
+ key['latinfont'] || key[:latinfont] ||
+ key['asciifont'] || key[:asciifont])
+ tagfont_configure(index, _symbolkey2str(key))
else
tk_send 'entryconfigure', index, *hash_kv(key)
end
else
- if (key == 'font' || key == 'kanjifont' ||
- key == 'latinfont' || key == 'asciifont' )
+ if (key == 'font' || key == :font ||
+ key == 'kanjifont' || key == :kanjifont ||
+ key == 'latinfont' || key == :latinfont ||
+ key == 'asciifont' || key == :asciifont )
tagfont_configure({key=>val})
else
tk_call 'entryconfigure', index, "-#{key}", val
@@ -3333,7 +3496,7 @@ class TkMenu<TkWindow
def entryconfiginfo(index, key=nil)
if key
- case key
+ case key.to_s
when 'text', 'label', 'show'
conf = tk_split_simplelist(tk_send('entryconfigure',index,"-#{key}"))
else
@@ -3371,17 +3534,28 @@ end
class TkMenuClone<TkMenu
def initialize(parent, type=None)
+ widgetname = nil
+ if parent.kind_of? Hash
+ keys = _symbolkey2str(parent)
+ parent = keys.delete('parent')
+ widgetname = keys.delete('widgetname')
+ type = keys.delete('type'); type = None unless type
+ end
unless parent.kind_of?(TkMenu)
fail ArgumentError, "parent must be TkMenu"
end
@parent = parent
- install_win(@parent.path)
+ install_win(@parent.path, widgetname)
tk_call @parent.path, 'clone', @path, type
end
end
module TkSystemMenu
def initialize(parent, keys=nil)
+ if parent.kind_of? Hash
+ keys = _symbolkey2str(parent)
+ parent = keys.delete('parent')
+ end
fail unless parent.kind_of? TkMenu
@path = format("%s.%s", parent.path, self.type::SYSMENU_NAME)
TkComm::Tk_WINDOWS[@path] = self
@@ -3437,6 +3611,12 @@ class TkOptionMenubutton<TkMenubutton
end
def initialize(parent=nil, var=TkVariable.new, firstval=nil, *vals)
+ if parent.kind_of Hash
+ keys = _symbolkey2str(parent)
+ parent = keys['parent']
+ var = keys['variable'] if keys['variable']
+ firstval, *vals = keys['values']
+ end
fail unless var.kind_of? TkVariable
@variable = var
firstval = @variable.value unless firstval
@@ -3498,9 +3678,17 @@ module TkComposite
extend Tk
def initialize(parent=nil, *args)
- @frame = TkFrame.new(parent)
- @path = @epath = @frame.path
- initialize_composite(*args)
+ if parent.kind_of? Hash
+ keys = _symbolkey2str(parent)
+ parent = keys['parent']
+ keys['parent'] = @frame = TkFrame.new(parent)
+ @path = @epath = @frame.path
+ initialize_composite(keys)
+ else
+ @frame = TkFrame.new(parent)
+ @path = @epath = @frame.path
+ initialize_composite(*args)
+ end
end
def epath