From 4cb164ee2a30ecb59ce93670e569f384c7da7521 Mon Sep 17 00:00:00 2001 From: nagai Date: Tue, 4 Jun 2002 07:03:33 +0000 Subject: * 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 --- ext/tk/lib/tk.rb | 296 +++++++++++++++++++++++++++++++++++++++--------- ext/tk/lib/tkafter.rb | 42 ++++--- ext/tk/lib/tkcanvas.rb | 33 ++++-- ext/tk/lib/tkclass.rb | 11 +- ext/tk/lib/tkdialog.rb | 1 + ext/tk/lib/tkentry.rb | 7 +- ext/tk/lib/tkfont.rb | 17 +-- ext/tk/lib/tkmenubar.rb | 10 +- ext/tk/lib/tktext.rb | 65 +++++++++-- 9 files changed, 370 insertions(+), 112 deletions(-) (limited to 'ext/tk') 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 TkObjectparent} 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 TkListboxval}) else tk_call 'itemconfigure', index, "-#{key}", val @@ -3198,7 +3357,7 @@ class TkListboxval}) else tk_call 'entryconfigure', index, "-#{key}", val @@ -3333,7 +3496,7 @@ class TkMenu +# +# $Id$ # require 'tk' @@ -11,18 +12,16 @@ class TkAfter Tk_CBID = [0] Tk_CBTBL = {} - INTERP._invoke("proc", "rb_after", "args", "ruby [format \"TkAfter.callback %%Q!%s!\" $args]") + INTERP._invoke("proc", "rb_after", "id", "ruby [format \"TkAfter.callback %%Q!%s!\" $id]") ############################### # class methods ############################### - def TkAfter.callback(arg) + def TkAfter.callback(obj_id) @after_id = nil - arg = Array(tk_split_list(arg)) - obj_id = arg.shift ex_obj = Tk_CBTBL[obj_id] return nil if ex_obj == nil; # canceled - _get_eval_string(ex_obj.do_callback(*arg)) + _get_eval_string(ex_obj.do_callback) end def TkAfter.info @@ -35,10 +34,10 @@ class TkAfter ############################### # instance methods ############################### - def do_callback(*args) + def do_callback @in_callback = true begin - ret = @current_proc.call(*args) + @return_value = @current_proc.call(self) rescue StandardError, NameError if @cancel_on_exception cancel @@ -48,21 +47,22 @@ class TkAfter end end if @set_next - set_next_callback(*args) + set_next_callback(@current_args) else @set_next = true end @in_callback = false - ret + @return_value end def set_callback(sleep, args=nil) - @after_script = "rb_after #{@id} #{_get_eval_string(args)}" + @after_script = "rb_after #{@id}" @after_id = tk_call('after', sleep, @after_script) + @current_args = args @current_script = [sleep, @after_script] end - def set_next_callback(*args) + def set_next_callback(args) if @running == false || @proc_max == 0 || @do_loop == 0 Tk_CBTBL[@id] = nil ;# for GC @running = false @@ -81,7 +81,7 @@ class TkAfter @current_args = args if @sleep_time.kind_of? Proc - sleep = @sleep_time.call(*args) + sleep = @sleep_time.call(self) else sleep = @sleep_time end @@ -91,15 +91,7 @@ class TkAfter @current_pos += 1 @current_proc = cmd - if cmd_args[0].kind_of? Proc - #c = cmd_args.shift - #cb_args = c.call(*(cmd_args + args)) - cb_args = cmd_args[0].call(*args) - else - cb_args = cmd_args - end - - set_callback(sleep, cb_args) + set_callback(sleep, cmd_args) end def initialize(*args) @@ -115,6 +107,7 @@ class TkAfter @current_script = [] @current_proc = nil @current_args = nil + @return_value = nil @sleep_time = 0 @current_sleep = 0 @@ -137,7 +130,10 @@ class TkAfter attr :after_id attr :after_script attr :current_proc + attr :current_args attr :current_sleep + alias :current_interval :current_sleep + attr :return_value attr_accessor :loop_exec @@ -257,7 +253,7 @@ class TkAfter set_callback(sleep, @init_args) @set_next = false if @in_callback else - set_next_callback(*@init_args) + set_next_callback(@init_args) end self diff --git a/ext/tk/lib/tkcanvas.rb b/ext/tk/lib/tkcanvas.rb index 94376072d3..ac6ed5362f 100644 --- a/ext/tk/lib/tkcanvas.rb +++ b/ext/tk/lib/tkcanvas.rb @@ -1,4 +1,4 @@ - +# # tkcanvas.rb - Tk canvas classes # $Date$ # by Yukihiro Matsumoto @@ -180,7 +180,7 @@ class TkCanvasvalue}) else tk_send 'itemconfigure', tagid(tagOrId), "-#{key}", value @@ -226,7 +229,7 @@ class TkCanvas "(t1)&&(t2)" @@ -473,6 +476,7 @@ class TkcTag +# +# $Id$ require "tk" @@ -13,6 +15,7 @@ Radiobutton = TkRadioButton Checkbutton = TkCheckButton Message = TkMessage Entry = TkEntry +Spinbox = TkSpinbox Text = TkText Scale = TkScale Scrollbar = TkScrollbar @@ -28,10 +31,16 @@ Polygon = TkcPolygon Rectangle = TkcRectangle TextItem = TkcText WindowItem = TkcWindow +BitmapImage = TkBitmapImage +PhotoImage = TkPhotoImage Selection = TkSelection Winfo = TkWinfo Pack = TkPack +Grid = TkGrid +Place = TkPlace Variable = TkVariable +Font = TkFont +VirtualEvent = TkVirtualEvent def Mainloop Tk.mainloop diff --git a/ext/tk/lib/tkdialog.rb b/ext/tk/lib/tkdialog.rb index 1133db6ae9..8b8ee69128 100644 --- a/ext/tk/lib/tkdialog.rb +++ b/ext/tk/lib/tkdialog.rb @@ -23,6 +23,7 @@ class TkDialog < TkWindow @button_configs = proc{|num| button_configs num} if keys.kind_of? Hash + keys = _symbolkey2str(keys) @title = keys['title'] if keys['title'] @message = keys['message'] if keys['message'] @bitmap = keys['bitmap'] if keys['bitmap'] diff --git a/ext/tk/lib/tkentry.rb b/ext/tk/lib/tkentry.rb index f301bbdace..f2706125cb 100644 --- a/ext/tk/lib/tkentry.rb +++ b/ext/tk/lib/tkentry.rb @@ -73,6 +73,7 @@ class TkEntryval}) else tk_send 'tag', 'configure', tag, "-#{key}", val @@ -214,7 +217,7 @@ class TkText