From 4ae99a8896f7ac00dec7e2c86183d4015a3a8477 Mon Sep 17 00:00:00 2001 From: nagai Date: Sat, 1 May 2004 16:09:54 +0000 Subject: * renewal Ruby/Tk git-svn-id: http://svn.ruby-lang.org/repos/ruby/branches/ruby_1_8@6237 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/tk/lib/multi-tk.rb | 406 ++- ext/tk/lib/tk.rb | 6531 ++++++++++++--------------------------------- ext/tk/lib/tkafter.rb | 414 +-- ext/tk/lib/tkbgerror.rb | 29 +- ext/tk/lib/tkcanvas.rb | 1023 +------ ext/tk/lib/tkconsole.rb | 28 +- ext/tk/lib/tkdialog.rb | 276 +- ext/tk/lib/tkentry.rb | 294 +- ext/tk/lib/tkfont.rb | 1390 +--------- ext/tk/lib/tkmacpkg.rb | 56 +- ext/tk/lib/tkmenubar.rb | 143 +- ext/tk/lib/tkmngfocus.rb | 33 +- ext/tk/lib/tkpalette.rb | 54 +- ext/tk/lib/tkscrollbox.rb | 32 +- ext/tk/lib/tktext.rb | 1358 +--------- ext/tk/lib/tkvirtevent.rb | 85 +- ext/tk/lib/tkwinpkg.rb | 84 +- 17 files changed, 2086 insertions(+), 10150 deletions(-) (limited to 'ext/tk/lib') diff --git a/ext/tk/lib/multi-tk.rb b/ext/tk/lib/multi-tk.rb index c2dcb4f97..a3cd3857a 100644 --- a/ext/tk/lib/multi-tk.rb +++ b/ext/tk/lib/multi-tk.rb @@ -3,6 +3,7 @@ # by Hidetoshi NAGAI require 'tcltklib' +require 'tkutil' require 'thread' ################################################ @@ -13,7 +14,6 @@ TclTkLib.mainloop_abort_on_exception = true # TclTkLib.mainloop_abort_on_exception = nil - ################################################ # exceptiopn to treat the return value from IP class MultiTkIp_OK < Exception @@ -48,12 +48,15 @@ class MultiTkIp ###################################### - @@CB_ENTRY_CLASS = Class.new{|c| + @@CB_ENTRY_CLASS = Class.new(TkCallbackEntry){|c| def initialize(ip, cmd) @ip = ip @cmd = cmd end attr_reader :ip, :cmd + def inspect + cmd.inspect + end def call(*args) begin unless @ip.deleted? @@ -68,8 +71,11 @@ class MultiTkIp ###################################### - def _keys2opts(keys) - keys.collect{|k,v| "-#{k} #{v}"}.join(' ') + def _keys2opts(src_keys) + return nil if src_keys == nil + keys = {}; src_keys.each{|k, v| keys[k.to_s] = v} + #keys.collect{|k,v| "-#{k} #{v}"}.join(' ') + keys.collect{|k,v| "-#{k} #{TclTkLib._conv_listelement(TkComm::_get_eval_string(v))}"}.join(' ') end private :_keys2opts @@ -136,10 +142,11 @@ class MultiTkIp rescue SystemExit # delete IP unless @interp.deleted? - if @interp._invoke('info', 'command', '.') != "" - @interp._invoke('destroy', '.') - end - @interp.delete + # if @interp._invoke('info', 'command', '.') != "" + # @interp._invoke('destroy', '.') + # end + # @interp.delete + @interp._eval_without_enc('exit') end _check_and_return(thread, MultiTkIp_OK.new(nil)) break @@ -200,14 +207,14 @@ class MultiTkIp @@DEFAULT_MASTER = self.allocate @@DEFAULT_MASTER.instance_eval{ - @encoding = [].taint - @tk_windows = {}.taint @tk_table_list = [].taint @slave_ip_tbl = {}.taint + @slave_ip_top = {}.taint + unless keys.kind_of? Hash fail ArgumentError, "expecting a Hash object for the 2nd argument" end @@ -274,23 +281,28 @@ class MultiTkIp tk_opts = {} keys.each{|k,v| - if k.to_s == 'name' + k_str = k.to_s + if k_str == 'name' name = v - elsif k.to_s == 'safe' + elsif k_str == 'safe' safe = v - elsif SAFE_OPT_LIST.member?(k.to_s) - safe_opts[k] = v + elsif SAFE_OPT_LIST.member?(k_str) + safe_opts[k_str] = v else - tk_opts[k] = v + tk_opts[k_str] = v end } - [name, safe, safe_opts, tk_opts] + if keys['without_tk'] || keys[:without_tk] + [name, safe, safe_opts, nil] + else + [name, safe, safe_opts, tk_opts] + end end private :_parse_slaveopts def _create_slave_ip_name - name = SLAVE_IP_ID.join + name = SLAVE_IP_ID.join('') SLAVE_IP_ID[1].succ! name end @@ -388,14 +400,18 @@ class MultiTkIp # procedure to delete slave interpreter slave_delete_proc = proc{ unless slave_ip.deleted? - if slave_ip._invoke('info', 'command', '.') != "" - slave_ip._invoke('destroy', '.') - end - slave_ip.delete + #if slave_ip._invoke('info', 'command', '.') != "" + # slave_ip._invoke('destroy', '.') + #end + #slave_ip.delete + slave_ip._eval_without_enc('exit') end + top.destroy if top.winfo_exist? } tag = TkBindTag.new.bind('Destroy', slave_delete_proc) + top.bindtags = top.bindtags.unshift(tag) + # create control frame TkFrame.new(top, :bg=>'red', :borderwidth=>3, :relief=>'ridge') {|fc| fc.bindtags = fc.bindtags.unshift(tag) @@ -421,23 +437,45 @@ class MultiTkIp # return keys loadTk_keys['use'] = TkWinfo.id(c) - loadTk_keys + [loadTk_keys, top.path] end private :__create_safetk_frame def __create_safe_slave_obj(safe_opts, app_name, tk_opts) # safe interpreter - # at present, not enough support for '-deleteHook' option ip_name = _create_slave_ip_name slave_ip = @interp.create_slave(ip_name, true) - @interp._eval("::safe::interpInit #{ip_name} "+_keys2opts(safe_opts)) - tk_opts = __check_safetk_optkeys(tk_opts) - unless tk_opts.key?('use') - tk_opts = __create_safetk_frame(slave_ip, ip_name, app_name, tk_opts) - end - slave_ip._invoke('set', 'argv0', app_name) if app_name.kind_of?(String) - @interp._eval("::safe::loadTk #{ip_name} #{_keys2opts(tk_opts)}") @slave_ip_tbl[ip_name] = slave_ip + + @interp._eval("::safe::interpInit #{ip_name}") + + slave_ip._invoke('set', 'argv0', app_name) if app_name.kind_of?(String) + + if tk_opts + tk_opts = __check_safetk_optkeys(tk_opts) + if tk_opts.key?('use') + @slave_ip_top[ip_name] = '' + else + tk_opts, top_path = __create_safetk_frame(slave_ip, ip_name, app_name, + tk_opts) + @slave_ip_top[ip_name] = top_path + end + @interp._eval("::safe::loadTk #{ip_name} #{_keys2opts(tk_opts)}") + else + @slave_ip_top[ip_name] = nil + end + + if safe_opts.key?('deleteHook') || safe_opts.key?(:deleteHook) + @interp._eval("::safe::interpConfigure #{ip_name} " + + _keys2opts(safe_opts)) + else + @interp._eval("::safe::interpConfigure #{ip_name} " + + _keys2opts(safe_opts) + '-deleteHook {' + + TkComm._get_eval_string(proc{|slave| + self._default_delete_hook(slave) + }) + '}') + end + [slave_ip, ip_name] end @@ -481,15 +519,15 @@ class MultiTkIp fail ArgumentError, "expecting a Hash object for the 2nd argument" end - @encoding = [] @tk_windows = {} @tk_table_list = [] @slave_ip_tbl = {} + @slave_ip_top = {} - @encoding.taint unless @encoding.tainted? @tk_windows.taint unless @tk_windows.tainted? @tk_table_list.taint unless @tk_table_list.tainted? @slave_ip_tbl.taint unless @slave_ip_tbl.tainted? + @slave_ip_top.taint unless @slave_ip_top.tainted? name, safe, safe_opts, tk_opts = _parse_slaveopts(keys) @@ -532,6 +570,34 @@ class MultiTkIp self.freeze # defend against modification end + + ###################################### + + def _default_delete_hook(slave) + if @slave_ip_top[slave].kind_of?(String) + # call default hook of safetk.tcl (ignore exceptions) + if @slave_ip_top[slave] == '' + begin + @interp._eval("::safe::disallowTk #{slave}") + rescue + warn("Waring: fail to call '::safe::disallowTk'") if $DEBUG + end + else # toplevel path + begin + @interp._eval("::safe::tkDelete {} #{@slave_ip_top[slave]} #{slave}") + rescue + warn("Waring: fail to call '::safe::tkDelete'") if $DEBUG + begin + @interp._eval("destroy #{@slave_ip_top[slave]}") + rescue + warn("Waring: fail to destroy toplevel") if $DEBUG + end + end + end + end + @slave_ip_tbl.delete(slave) + @slave_ip_top.delete(slave) + end end @@ -796,6 +862,10 @@ class MultiTkIp rescue SystemExit # exit IP warn("Warning: "+ $! + " on " + self.inspect) if $DEBUG + begin + self._eval_without_enc('exit') + rescue Exception + end self.delete ret = nil rescue Exception => e @@ -823,6 +893,10 @@ class MultiTkIp rescue SystemExit # exit IP warn("Warning: " + $! + " on " + self.inspect) if $DEBUG + begin + self._eval_without_enc('exit') + rescue Exception + end self.delete rescue Exception => e # others --> warning @@ -868,10 +942,12 @@ class << MultiTkIp __getip.do_one_event(flag) end def mainloop_abort_on_exception - __getip.mainloop_abort_on_exception + # __getip.mainloop_abort_on_exception + TclTkLib.mainloop_abort_on_exception end def mainloop_abort_on_exception=(mode) - __getip.mainloop_abort_on_exception=(mode) + # __getip.mainloop_abort_on_exception=(mode) + TclTkLib.mainloop_abort_on_exception=(mode) end def set_eventloop_tick(tick) __getip.set_eventloop_tick(tick) @@ -919,6 +995,22 @@ class << MultiTkIp __getip._invoke(*args) end + def _eval_without_enc(str) + __getip._eval_without_enc(str) + end + + def _invoke_without_enc(*args) + __getip._invoke_without_enc(*args) + end + + def _eval_with_enc(str) + __getip._eval_with_enc(str) + end + + def _invoke_with_enc(*args) + __getip._invoke_with_enc(*args) + end + def _toUTF8(str, encoding) __getip._toUTF8(str, encoding) end @@ -938,6 +1030,54 @@ class << MultiTkIp def _return_value __getip._return_value end + + def _get_variable(var, flag) + __getip._get_variable(var, flag) + end + def _get_variable2(var, idx, flag) + __getip._get_variable2(var, idx, flag) + end + def _set_variable(var, value, flag) + __getip._set_variable(var, value, flag) + end + def _set_variable2(var, idx, value, flag) + __getip._set_variable2(var, idx, value, flag) + end + def _unset_variable(var, flag) + __getip._unset_variable(var, flag) + end + def _unset_variable2(var, idx, flag) + __getip._unset_variable2(var, idx, flag) + end + + def _get_global_var(var) + __getip._get_global_var(var) + end + def _get_global_var2(var, idx) + __getip._get_global_var2(var, idx) + end + def _set_global_var(var, value) + __getip._set_global_var(var, value) + end + def _set_global_var2(var, idx, value) + __getip._set_global_var2(var, idx, value) + end + def _unset_global_var(var) + __getip._unset_global_var(var) + end + def _unset_global_var2(var, idx) + __getip._unset_global_var2(var, idx) + end + + def _split_tklist(str) + __getip._split_tklist(str) + end + def _merge_tklist(*args) + __getip._merge_tklist(*args) + end + def _conv_listelement(arg) + __getip._conv_listelement(arg) + end end @@ -952,12 +1092,12 @@ class << TclTkLib def do_one_event(flag = TclTkLib::EventFlag::ALL) MultiTkIp.do_one_event(flag) end - def mainloop_abort_on_exception - MultiTkIp.mainloop_abort_on_exception - end - def mainloop_abort_on_exception=(mode) - MultiTkIp.mainloop_abort_on_exception=(mode) - end + #def mainloop_abort_on_exception + # MultiTkIp.mainloop_abort_on_exception + #end + #def mainloop_abort_on_exception=(mode) + # MultiTkIp.mainloop_abort_on_exception=(mode) + #end def set_eventloop_tick(tick) MultiTkIp.set_eventloop_tick(tick) end @@ -979,12 +1119,19 @@ class << TclTkLib def restart MultiTkIp.restart end + + def _merge_tklist(*args) + MultiTkIp._merge_tklist(*args) + end + def _conv_listelement(arg) + MultiTkIp._conv_listelement(arg) + end end # depend on TclTkIp class MultiTkIp - def mainloop(check_root = true, restart_on_dead = true) + def mainloop(check_root = true, restart_on_dead = false) return self if self.slave? unless restart_on_dead @interp.mainloop(check_root) @@ -1022,6 +1169,10 @@ class MultiTkIp end def delete + if safe? + # do 'exit' to call the delete_hook procedure + @interp._eval_without_enc('exit') + end @interp.delete end @@ -1041,6 +1192,22 @@ class MultiTkIp @interp._invoke(*args) end + def _eval_without_enc(str) + @interp._eval_without_enc(str) + end + + def _invoke_without_enc(*args) + @interp._invoke_without_enc(*args) + end + + def _eval_with_enc(str) + @interp._eval_with_enc(str) + end + + def _invoke_with_enc(*args) + @interp._invoke_with_enc(*args) + end + def _toUTF8(str, encoding) @interp._toUTF8(str, encoding) end @@ -1060,6 +1227,54 @@ class MultiTkIp def _return_value @interp._return_value end + + def _get_variable(var, flag) + @interp._get_variable(var, flag) + end + def _get_variable2(var, idx, flag) + @interp._get_variable2(var, idx, flag) + end + def _set_variable(var, value, flag) + @interp._set_variable(var, value, flag) + end + def _set_variable2(var, idx, value, flag) + @interp._set_variable2(var, idx, value, flag) + end + def _unset_variable(var, flag) + @interp._unset_variable(var, flag) + end + def _unset_variable2(var, idx, flag) + @interp._unset_variable2(var, idx, flag) + end + + def _get_global_var(var) + @interp._get_global_var(var) + end + def _get_global_var2(var, idx) + @interp._get_global_var2(var, idx) + end + def _set_global_var(var, value) + @interp._set_global_var(var, value) + end + def _set_global_var2(var, idx, value) + @interp._set_global_var2(var, idx, value) + end + def _unset_global_var(var) + @interp._unset_global_var(var) + end + def _unset_global_var2(var, idx) + @interp._unset_global_var2(var, idx) + end + + def _split_tklist(str) + @interp._split_tklist(str) + end + def _merge_tklist(*args) + @interp._merge_tklist(*args) + end + def _conv_listelement(arg) + @interp._conv_listelement(arg) + end end @@ -1090,7 +1305,7 @@ class MultiTkIp else list.push str[0..i-1] end - list += tk_split_simplelist(str[i+1..-1]) + list += _lst2ary(str[i+1..-1]) list end private :_lst2ary @@ -1224,6 +1439,14 @@ class MultiTkIp self end + def recursion_limit(slave = '', limit = None) + number(@interp._invoke('interp', 'recursionlimit', + _slavearg(slave), limit)) + end + def self.recursion_limit(slave = '', limit = None) + __getip.recursion_limit(slave) + end + def alias_target(aliascmd, slave = '') @interp._invoke('interp', 'target', _slavearg(slave), aliascmd) end @@ -1309,35 +1532,94 @@ class MultiTkIp end -# encoding convert +# Safe Base :: manipulating safe interpreter class MultiTkIp - # from tkencoding.rb by ttate@jaist.ac.jp - alias __eval _eval - alias __invoke _invoke + def safeip_configure(slave, slot, value=None) + # use for '-noStatics' option ==> {statics=>false} + # for '-nestedLoadOk' option ==> {nested=>true} + if slot.kind_of?(Hash) + ip = MultiTkIp.__getip + ip._eval('::safe::interpConfigure ' + @ip_name + ' ' + + hash_kv(slot).join(' ')) + else + ip._eval('::safe::interpConfigure ' + @ip_name + ' ' + + "-#{slot} #{_get_eval_string(value)}") + end + self + end + + def safeip_configinfo(slot = nil) + ip = MultiTkIp.__getip + ret = {} + if slot + conf = _lst2ary(ip._eval("::safe::interpConfigure " + + @ip_name + " -#{slot}")) + if conf[0] == '-deleteHook' + if conf[1] =~ /^rb_out (c\d+)/ + ret[conf[0][1..-1]] = MultiTkIp._tk_cmd_tbl[$1] + else + ret[conf[0][1..-1]] = conf[1] + end + else + ret[conf[0][1..-1]] = conf[1] + end + else + Hash[*_lst2ary(ip._eval("::safe::interpConfigure " + + @ip_name))].each{|k, v| + if k == '-deleteHook' + if v =~ /^rb_out (c\d+)/ + ret[k[1..-1]] = MultiTkIp._tk_cmd_tbl[$1] + else + ret[k[1..-1]] = v + end + else + ret[k[1..-1]] = v + end + } + end + ret + end + def safeip_delete(slave) + ip = MultiTkIp.__getip + ip._eval("::safe::interpDelete " + @ip_name) + end + + def safeip_add_to_access_path(slave, dir) + ip = MultiTkIp.__getip + ip._eval("::safe::interpAddToAccessPath #{@ip_name} #{dir}") + end + + def safeip_find_in_access_path(slave, dir) + ip = MultiTkIp.__getip + ip._eval("::safe::interpFindInAccessPath #{@ip_name} #{dir}") + end + + def safeip_set_log_cmd(slave, cmd = Proc.new) + ip = MultiTkIp.__getip + ip._eval("::safe::setLogCmd #{@ip_name} #{_get_eval_string(cmd)}") + end +end + + +# encoding convert +class MultiTkIp def encoding - @encoding[0] + @interp.encoding end def encoding=(enc) - @encoding[0] = enc + @interp.encoding = enc end - - def _eval(cmd) - if @encoding[0] != nil - _fromUTF8(__eval(_toUTF8(cmd, @encoding[0])), @encoding[0]) - else - __eval(cmd) - end + + def encoding_convertfrom(str, enc=None) + @interp.encoding_convertfrom(str, enc) end + alias encoding_convert_from encoding_convertfrom - def _invoke(*cmds) - if defined?(@encoding[0]) && @encoding[0] != nil - cmds = cmds.collect{|cmd| _toUTF8(cmd, @encoding[0])} - _fromUTF8(__invoke(*cmds), @encoding[0]) - else - __invoke(*cmds) - end + def encoding_convertto(str, enc=None) + @interp.encoding_convertto(str, enc) end + alias encoding_convert_to encoding_convertto end diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb index 6bae4d8f4..36a9e54f2 100644 --- a/ext/tk/lib/tk.rb +++ b/ext/tk/lib/tk.rb @@ -4,17 +4,30 @@ # by Yukihiro Matsumoto # use Shigehiro's tcltklib -require "tcltklib" -require "tkutil" +require 'tcltklib' +require 'tkutil' +# autoload +require 'tk/autoload' + +class TclTkIp + # backup original (without encoding) _eval and _invoke + alias _eval_without_enc _eval + alias _invoke_without_enc _invoke +end + +# define TkComm module (step 1: basic functions) module TkComm + include TkUtil + extend TkUtil + WidgetClassNames = {}.taint - None = Object.new - def None.to_s - 'None' - end - None.freeze + # None = Object.new ### --> definition is moved to TkUtil module + # def None.to_s + # 'None' + # end + # None.freeze #Tk_CMDTBL = {} #Tk_WINDOWS = {} @@ -36,6 +49,21 @@ module TkComm @cmdtbl = [].taint } + unless const_defined?(:GET_CONFIGINFO_AS_ARRAY) + # GET_CONFIGINFO_AS_ARRAY = false => returns a Hash { opt =>val, ... } + # true => returns an Array [[opt,val], ... ] + # val is a list which includes resource info. + GET_CONFIGINFO_AS_ARRAY = true + end + unless const_defined?(:GET_CONFIGINFOwoRES_AS_ARRAY) + # for configinfo without resource info; list of [opt, value] pair + # false => returns a Hash { opt=>val, ... } + # true => returns an Array [[opt,val], ... ] + GET_CONFIGINFOwoRES_AS_ARRAY = true + end + # *** ATTENTION *** + # 'current_configinfo' method always returns a Hash under all cases of above. + def error_at frames = caller() frames.delete_if do |c| @@ -50,7 +78,7 @@ module TkComm begin #tk_class = TkCore::INTERP._invoke('winfo', 'class', path) - tk_class = Tk.ip_invoke('winfo', 'class', path) + tk_class = Tk.ip_invoke_without_enc('winfo', 'class', path) rescue return path end @@ -82,14 +110,20 @@ module TkComm private :_genobj_for_tkwidget module_function :_genobj_for_tkwidget - def tk_tcl2ruby(val) + def tk_tcl2ruby(val, enc_mode = nil) if val =~ /^rb_out (c\d+)/ #return Tk_CMDTBL[$1] return TkCore::INTERP.tk_cmd_tbl[$1] - end - if val.include? ?\s - return val.split.collect{|v| tk_tcl2ruby(v)} - end + #cmd_obj = TkCore::INTERP.tk_cmd_tbl[$1] + #if cmd_obj.kind_of?(Proc) || cmd_obj.kind_of?(Method) + # cmd_obj + #else + # cmd_obj.cmd + #end + end + #if val.include? ?\s + # return val.split.collect{|v| tk_tcl2ruby(v)} + #end case val when /^@font/ TkFont.get_obj(val) @@ -101,17 +135,122 @@ module TkComm TkCore::INTERP.tk_windows[val] : _genobj_for_tkwidget(val) when /^i\d+$/ TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val - when / / - val.split.collect{|elt| - tk_tcl2ruby(elt) - } when /^-?\d+\.?\d*(e[-+]?\d+)?$/ val.to_f + when /[^\\] / + tk_split_escstr(val).collect{|elt| + tk_tcl2ruby(elt) + } + when /\\ / + val.gsub(/\\ /, ' ') else - val + if enc_mode + _fromUTF8(val) + else + val + end + end + end + + private :tk_tcl2ruby + +unless const_defined?(:USE_TCLs_LIST_FUNCTIONS) + USE_TCLs_LIST_FUNCTIONS = true +end + +if USE_TCLs_LIST_FUNCTIONS + ########################################################################### + # use Tcl function version of split_list + ########################################################################### + + def tk_split_escstr(str) + TkCore::INTERP._split_tklist(str) + end + + def tk_split_sublist(str) + return [] if str == "" + list = TkCore::INTERP._split_tklist(str) + if list.size == 1 + tk_tcl2ruby(list[0]) + else + list.collect{|token| tk_split_sublist(token)} + end + end + + def tk_split_list(str) + return [] if str == "" + TkCore::INTERP._split_tklist(str).collect{|token| tk_split_sublist(token)} + end + + def tk_split_simplelist(str) + #lst = TkCore::INTERP._split_tklist(str) + #if (lst.size == 1 && lst =~ /^\{.*\}$/) + # TkCore::INTERP._split_tklist(str[1..-2]) + #else + # lst + #end + TkCore::INTERP._split_tklist(str) + end + + def array2tk_list(ary) + return "" if ary.size == 0 + + dst = ary.collect{|e| + if e.kind_of? Array + array2tk_list(e) + elsif e.kind_of? Hash + tmp_ary = [] + e.each{|k,v| tmp_ary << k << v } + array2tk_list(tmp_ary) + else + _get_eval_string(e) + end + } + TkCore::INTERP._merge_tklist(*dst) + end + +else + ########################################################################### + # use Ruby script version of split_list (traditional methods) + ########################################################################### + + def tk_split_escstr(str) + return [] if str == "" + list = [] + token = nil + escape = false + brace = 0 + str.split('').each {|c| + brace += 1 if c == '{' && !escape + brace -= 1 if c == '}' && !escape + if brace == 0 && c == ' ' && !escape + list << token.gsub(/^\{(.*)\}$/, '\1') if token + token = nil + else + token = (token || "") << c + end + escape = (c == '\\' && !escape) + } + list << token.gsub(/^\{(.*)\}$/, '\1') if token + list + end + + def tk_split_sublist(str) + return [] if str == "" + return [tk_split_sublist(str[1..-2])] if str =~ /^\{.*\}$/ + list = tk_split_escstr(str) + if list.size == 1 + tk_tcl2ruby(list[0]) + else + list.collect{|token| tk_split_sublist(token)} end end + def tk_split_list(str) + return [] if str == "" + tk_split_escstr(str).collect{|token| tk_split_sublist(token)} + end +=begin def tk_split_list(str) return [] if str == "" idx = str.index('{') @@ -130,11 +269,13 @@ module TkComm list = [] if list == "" str = str[idx+1..-1] i = -1 + escape = false brace = 1 str.each_byte {|c| i += 1 - brace += 1 if c == ?{ - brace -= 1 if c == ?} + brace += 1 if c == ?{ && !escape + brace -= 1 if c == ?} && !escape + escape = (c == ?\\) break if brace == 0 } if str.size == i + 1 @@ -148,56 +289,33 @@ module TkComm list += tk_split_list(str[i+1..-1]) list end +=end def tk_split_simplelist(str) return [] if str == "" - idx = str.index('{') - while idx and idx > 0 and str[idx-1] == ?\\ - idx = str.index('{', idx+1) - end - return str.split unless idx - - list = str[0,idx].split - 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 + list = [] + token = nil + escape = false + brace = 0 + str.split('').each {|c| + if c == '\\' && !escape + escape = true + token = (token || "") << c if brace > 0 + next + end + brace += 1 if c == '{' && !escape + brace -= 1 if c == '}' && !escape + if brace == 0 && c == ' ' && !escape + list << token.gsub(/^\{(.*)\}$/, '\1') if token + token = nil + else + token = (token || "") << c + end + escape = false } - if i == 0 - list.push '' - elsif str[0, i] == ' ' - list.push ' ' - else - list.push str[0..i-1] - end - list += tk_split_simplelist(str[i+1..-1]) + list << token.gsub(/^\{(.*)\}$/, '\1') if token list 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 - for k, v in keys - conf.push("-#{k}") - conf.push(v) - end - end - conf - end - private :hash_kv - module_function :hash_kv def array2tk_list(ary) ary.collect{|e| @@ -211,9 +329,61 @@ module TkComm end }.join(" ") end +end + + private :tk_split_escstr, :tk_split_sublist + private :tk_split_list, :tk_split_simplelist private :array2tk_list + + module_function :tk_split_escstr, :tk_split_sublist + module_function :tk_split_list, :tk_split_simplelist module_function :array2tk_list + private_class_method :tk_split_escstr, :tk_split_sublist + private_class_method :tk_split_list, :tk_split_simplelist + private_class_method :array2tk_list + +=begin + ### --> definition is moved to TkUtil module + def _symbolkey2str(keys) + h = {} + keys.each{|key,value| h[key.to_s] = value} + h + end + private :_symbolkey2str + module_function :_symbolkey2str +=end + +=begin + ### --> definition is moved to TkUtil module + # def hash_kv(keys, enc_mode = nil, conf = [], flat = false) + def hash_kv(keys, enc_mode = nil, conf = nil) + # Hash {key=>val, key=>val, ... } or Array [ [key, val], [key, val], ... ] + # ==> Array ['-key', val, '-key', val, ... ] + dst = [] + if keys and keys != None + keys.each{|k, v| + #dst.push("-#{k}") + dst.push('-' + k.to_s) + if v != None + # v = _get_eval_string(v, enc_mode) if (enc_mode || flat) + v = _get_eval_string(v, enc_mode) if enc_mode + dst.push(v) + end + } + end + if conf + conf + dst + else + dst + end + end + private :hash_kv + module_function :hash_kv +=end + +=begin + ### --> definition is moved to TkUtil module def bool(val) case val when "1", 1, 'yes', 'true' @@ -222,6 +392,7 @@ module TkComm false end end + def number(val) case val when /^-?\d+$/ @@ -229,19 +400,27 @@ module TkComm when /^-?\d+\.?\d*(e[-+]?\d+)?$/ val.to_f else - fail(ArgumentError, - Kernel.format('invalid value for Number:"%s"', val.to_s)) + fail(ArgumentError, "invalid value for Number:'#{val}'") end end def string(val) if val == "{}" '' - elsif val[0] == ?{ + elsif val[0] == ?{ && val[-1] == ?} val[1..-2] else val end end + def num_or_str(val) + begin + number(val) + rescue ArgumentError + string(val) + end + end +=end + def list(val) tk_split_list(val) end @@ -257,6 +436,13 @@ module TkComm nil end end + def image_obj(val) + if val =~ /^i\d+$/ + TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val + else + val + end + end def procedure(val) if val =~ /^rb_out (c\d+)/ #Tk_CMDTBL[$1] @@ -268,19 +454,34 @@ module TkComm end end private :bool, :number, :string, :list, :simplelist, :window, :procedure - module_function :bool, :number, :string, :list, :simplelist - module_function :window, :procedure + module_function :bool, :number, :num_or_str, :string, :list, :simplelist + module_function :window, :image_obj, :procedure + + def _toUTF8(str, encoding = nil) + TkCore::INTERP._toUTF8(str, encoding) + end + def _fromUTF8(str, encoding = nil) + TkCore::INTERP._fromUTF8(str, encoding) + end + private :_toUTF8, :_fromUTF8 + module_function :_toUTF8, :_fromUTF8 - def _get_eval_string(str) +=begin + ### --> definition is moved to TkUtil module + def _get_eval_string(str, enc_mode = nil) return nil if str == None - if str.kind_of?(String) - # do nothing + if str.kind_of?(TkObject) + str = str.path + elsif str.kind_of?(String) + str = _toUTF8(str) if enc_mode elsif str.kind_of?(Symbol) str = str.id2name + str = _toUTF8(str) if enc_mode elsif str.kind_of?(Hash) - str = hash_kv(str).join(" ") + str = hash_kv(str, enc_mode).join(" ") elsif str.kind_of?(Array) str = array2tk_list(str) + str = _toUTF8(str) if enc_mode elsif str.kind_of?(Proc) str = install_cmd(str) elsif str == nil @@ -291,28 +492,102 @@ module TkComm str = "1" elsif (str.respond_to?(:to_eval)) str = str.to_eval() + str = _toUTF8(str) if enc_mode else str = str.to_s() || '' unless str.kind_of? String fail RuntimeError, "fail to convert the object to a string" end - str + str = _toUTF8(str) if enc_mode end return str end +=end +=begin + def _get_eval_string(obj, enc_mode = nil) + case obj + when Numeric + obj.to_s + when String + (enc_mode)? _toUTF8(obj): obj + when Symbol + (enc_mode)? _toUTF8(obj.id2name): obj.id2name + when TkObject + obj.path + when Hash + hash_kv(obj, enc_mode).join(' ') + when Array + (enc_mode)? _toUTF8(array2tk_list(obj)): array2tk_list(obj) + when Proc, Method, TkCallbackEntry + install_cmd(obj) + when false + '0' + when true + '1' + when nil + '' + when None + nil + else + if (obj.respond_to?(:to_eval)) + (enc_mode)? _toUTF8(obj.to_eval): obj.to_eval + else + begin + obj = obj.to_s || '' + rescue + fail RuntimeError, "fail to convert object '#{obj}' to string" + end + (enc_mode)? _toUTF8(obj): obj + end + end + end private :_get_eval_string module_function :_get_eval_string +=end + +=begin + ### --> definition is moved to TkUtil module + def _get_eval_enc_str(obj) + return obj if obj == None + _get_eval_string(obj, true) + end + private :_get_eval_enc_str + module_function :_get_eval_enc_str +=end - def ruby2tcl(v) +=begin + ### --> obsolete + def ruby2tcl(v, enc_mode = nil) if v.kind_of?(Hash) v = hash_kv(v) v.flatten! - v.collect{|e|ruby2tcl(e)} + v.collect{|e|ruby2tcl(e, enc_mode)} else - _get_eval_string(v) + _get_eval_string(v, enc_mode) end end private :ruby2tcl +=end + +=begin + ### --> definition is moved to TkUtil module + def _conv_args(args, enc_mode, *src_args) + conv_args = [] + src_args.each{|arg| + conv_args << _get_eval_string(arg, enc_mode) unless arg == None + # if arg.kind_of?(Hash) + # arg.each{|k, v| + # args << '-' + k.to_s + # args << _get_eval_string(v, enc_mode) + # } + # elsif arg != None + # args << _get_eval_string(arg, enc_mode) + # end + } + args + conv_args + end + private :_conv_args +=end def _curr_cmd_id #id = format("c%.4d", Tk_IDs[0]) @@ -331,20 +606,26 @@ module TkComm return '' if cmd == '' id = _next_cmd_id #Tk_CMDTBL[id] = cmd - TkCore::INTERP.tk_cmd_tbl[id] = TkCore::INTERP.get_cb_entry(cmd) + if cmd.kind_of?(TkCallbackEntry) + TkCore::INTERP.tk_cmd_tbl[id] = cmd + else + TkCore::INTERP.tk_cmd_tbl[id] = TkCore::INTERP.get_cb_entry(cmd) + end @cmdtbl = [] unless defined? @cmdtbl @cmdtbl.taint unless @cmdtbl.tainted? @cmdtbl.push id - return Kernel.format("rb_out %s", id); + #return Kernel.format("rb_out %s", id); + return 'rb_out ' + id end def uninstall_cmd(id) id = $1 if /rb_out (c\d+)/ =~ id #Tk_CMDTBL.delete(id) TkCore::INTERP.tk_cmd_tbl.delete(id) end - private :install_cmd, :uninstall_cmd - module_function :install_cmd + # private :install_cmd, :uninstall_cmd + module_function :install_cmd, :uninstall_cmd +=begin def install_win(ppath,name=nil) if !name or name == '' #name = format("w%.4d", Tk_IDs[1]) @@ -362,6 +643,29 @@ module TkComm #Tk_WINDOWS[@path] = self TkCore::INTERP.tk_windows[@path] = self end +=end + def install_win(ppath,name=nil) + if name + if name == '' + raise ArgumentError, "invalid wiget-name '#{name}'" + end + if name[0] == ?. + @path = '' + name + @path.freeze + return TkCore::INTERP.tk_windows[@path] = self + end + else + name = "w" + Tk_IDs[1] + Tk_IDs[1].succ! + end + if !ppath or ppath == '.' + @path = '.' + name + else + @path = ppath + '.' + name + end + @path.freeze + TkCore::INTERP.tk_windows[@path] = self + end def uninstall_win() #Tk_WINDOWS.delete(@path) @@ -369,163 +673,22 @@ module TkComm end private :install_win, :uninstall_win - class Event - 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 - - EV_KEY = '#abcdfhikmopstwxyABDEKNRSTWXY' - EV_TYPE = 'nsnnsbnsnsbsxnnnnsnnbsnssnwnn' - - def self.scan_args(arg_str, arg_val) - arg_cnv = [] - arg_str.strip.split(/\s+/).each_with_index{|kwd,idx| - if kwd =~ /^%(.)$/ - if num = EV_KEY.index($1) - case EV_TYPE[num] - when ?n - begin - val = TkComm::number(arg_val[idx]) - rescue ArgumentError - # ignore --> no convert - val = TkComm::string(arg_val[idx]) - end - arg_cnv << val - when ?s - arg_cnv << TkComm::string(arg_val[idx]) - when ?b - arg_cnv << TkComm::bool(arg_val[idx]) - when ?w - arg_cnv << TkComm::window(arg_val[idx]) - when ?x - begin - arg_cnv << TkComm::number(arg_val[idx]) - rescue ArgumentError - arg_cnv << arg_val[idx] - end - else - arg_cnv << arg_val[idx] - end - else - arg_cnv << arg_val[idx] - end - else - arg_cnv << arg_val[idx] - end - } - arg_cnv - end - - def initialize(seq,a,b,c,d,f,h,i,k,m,o,p,s,t,w,x,y, - aa,bb,dd,ee,kk,nn,rr,ss,tt,ww,xx,yy) - @serial = seq - @above = a - @num = b - @count = c - @detail = d - @focus = f - @height = h - @win_hex = i - @keycode = k - @mode = m - @override = o - @place = p - @state = s - @time = t - @width = w - @x = x - @y = y - @char = aa - @borderwidth = bb - @wheel_delta = dd - @send_event = ee - @keysym = kk - @keysym_num = nn - @rootwin_id = rr - @subwindow = ss - @type = tt - @widget = ww - @x_root = xx - @y_root = yy - end - attr :serial - attr :above - attr :num - attr :count - attr :detail - attr :focus - attr :height - attr :win_hex - attr :keycode - attr :mode - attr :override - attr :place - attr :state - attr :time - attr :width - attr :x - attr :y - attr :char - attr :borderwidth - attr :wheel_delta - attr :send_event - attr :keysym - attr :keysym_num - attr :rootwin_id - attr :subwindow - attr :type - attr :widget - attr :x_root - attr :y_root - end - - def install_bind(cmd, args=nil) - if args - id = install_cmd(proc{|*arg| - TkUtil.eval_cmd(cmd, *Event.scan_args(args, arg)) - }) - id + " " + args + def _epath(win) + if win.kind_of?(TkObject) + win.epath + elsif win.respond_to?(:epath) + win.epath else - args = ' %# %a %b %c %d %f %h %i %k %m %o %p %s %t %w %x %y' + - ' %A %B %D %E %K %N %R %S %T %W %X %Y' - id = install_cmd(proc{|*arg| - TkUtil.eval_cmd(cmd, Event.new(*Event.scan_args(args, arg))) - }) - id + args + win end end + private :_epath +end + +# define TkComm module (step 2: event binding) +module TkComm + include TkEvent + extend TkEvent def tk_event_sequence(context) if context.kind_of? TkVirtualEvent @@ -550,7 +713,8 @@ module TkComm def _bind_core(mode, what, context, cmd, args=nil) id = install_bind(cmd, args) if cmd begin - tk_call(*(what + ["<#{tk_event_sequence(context)}>", mode + id])) + tk_call_without_enc(*(what + ["<#{tk_event_sequence(context)}>", + mode + id])) rescue uninstall_cmd(id) if cmd fail @@ -566,12 +730,12 @@ module TkComm end def _bind_remove(what, context) - tk_call(*(what + ["<#{tk_event_sequence(context)}>", ''])) + tk_call_without_enc(*(what + ["<#{tk_event_sequence(context)}>", ''])) end def _bindinfo(what, context=nil) if context - tk_call(*what+["<#{tk_event_sequence(context)}>"]).collect {|cmdline| + tk_call_without_enc(*what+["<#{tk_event_sequence(context)}>"]) .collect {|cmdline| if cmdline =~ /^rb_out (c\d+)\s+(.*)$/ #[Tk_CMDTBL[$1], $2] [TkCore::INTERP.tk_cmd_tbl[$1], $2] @@ -580,7 +744,7 @@ module TkComm end } else - tk_split_simplelist(tk_call(*what)).collect!{|seq| + tk_split_simplelist(tk_call_without_enc(*what)).collect!{|seq| l = seq.scan(/<*[^<>]+>*/).collect!{|subseq| case (subseq) when /^<<[^<>]+>>$/ @@ -635,25 +799,9 @@ module TkComm def bindinfo_all(context=nil) _bindinfo(['bind', 'all'], context) end - - def pack(*args) - TkPack.configure(*args) - end - - def grid(*args) - TkGrid.configure(*args) - end - - def update(idle=nil) - if idle - tk_call 'update', 'idletasks' - else - tk_call 'update' - end - end - end + module TkCore include TkComm extend TkComm @@ -662,7 +810,8 @@ module TkCore if self.const_defined? :IP_NAME name = IP_NAME.to_s else - name = nil + #name = nil + name = $0 end if self.const_defined? :IP_OPTS if IP_OPTS.kind_of?(Hash) @@ -689,7 +838,14 @@ module TkCore @init_ip_env = [].taint # table of Procs @add_tk_procs = [].taint # table of [name, args, body] - @cb_entry_class = Class.new{|c| + @cb_entry_class = Class.new(TkCallbackEntry){|c| + class << c + def inspect + sprintf("#", self.__id__) + end + alias to_s inspect + end + def initialize(ip, cmd) @ip = ip @cmd = cmd @@ -698,9 +854,16 @@ module TkCore def call(*args) @ip.cb_eval(@cmd, *args) end - } + def inspect + sprintf("#", self.__id__) + end + alias to_s inspect + }.freeze } + def INTERP.cb_entry_class + @cb_entry_class + end def INTERP.tk_cmd_tbl @tk_cmd_tbl end @@ -708,6 +871,15 @@ module TkCore @tk_windows end + class Tk_OBJECT_TABLE + def initialize(id) + @id = id + end + def method_missing(m, *args, &b) + TkCore::INTERP.tk_object_table(@id).send(m, *args, &b) + end + end + def INTERP.tk_object_table(id) @tk_table_list[id] end @@ -715,20 +887,21 @@ module TkCore id = @tk_table_list.size (tbl = {}).tainted? || tbl.taint @tk_table_list << tbl - obj = Object.new - obj.instance_eval <<-EOD - def self.method_missing(m, *args) - TkCore::INTERP.tk_object_table(#{id}).send(m, *args) - end - EOD - return obj +# obj = Object.new +# obj.instance_eval <<-EOD +# def self.method_missing(m, *args) +# TkCore::INTERP.tk_object_table(#{id}).send(m, *args) +# end +# EOD +# return obj + Tk_OBJECT_TABLE.new(id) end def INTERP.get_cb_entry(cmd) @cb_entry_class.new(__getip, cmd).freeze end def INTERP.cb_eval(cmd, *args) - TkComm._get_eval_string(TkUtil.eval_cmd(cmd, *args)) + TkUtil._get_eval_string(TkUtil.eval_cmd(cmd, *args)) end def INTERP.init_ip_env(script = Proc.new) @@ -746,15 +919,64 @@ module TkCore end end + WIDGET_DESTROY_HOOK = '' + INTERP._invoke_without_enc('event', 'add', + "<#{WIDGET_DESTROY_HOOK}>", 'Destroy') + INTERP._invoke_without_enc('bind', 'all', "<#{WIDGET_DESTROY_HOOK}>", + install_bind(proc{|xpath| + path = xpath[1..-1] + unless TkCore::INTERP.deleted? + if (widget = TkCore::INTERP.tk_windows[path]) + if widget.respond_to?(:__destroy_hook__) + begin + widget.__destroy_hook__ + rescue Exception + end + end + end + end + }, 'x%W')) + INTERP.add_tk_procs(TclTkLib::FINALIZE_PROC_NAME, '', + "bind all <#{WIDGET_DESTROY_HOOK}> {}") + + INTERP.add_tk_procs('rb_out', 'args', <<-'EOL') + if {[set st [catch {eval {ruby_cmd TkCore callback} $args} ret]] != 0} { + #return -code $st $ret + set idx [string first "\n\n" $ret] + if {$idx > 0} { + return -code $st \ + -errorinfo [string range $ret [expr $idx + 2] \ + [string length $ret]] \ + [string range $ret 0 [expr $idx - 1]] + } else { + return -code $st $ret + } + } else { + return $ret + } + EOL +=begin INTERP.add_tk_procs('rb_out', 'args', <<-'EOL') - regsub -all {!} $args {\\!} args - regsub -all "{" $args "\\{" args + #regsub -all {\\} $args {\\\\} args + #regsub -all {!} $args {\\!} args + #regsub -all "{" $args "\\{" args + regsub -all {(\\|!|\{|\})} $args {\\\1} args if {[set st [catch {ruby [format "TkCore.callback %%Q!%s!" $args]} ret]] != 0} { - return -code $st $ret - } { + #return -code $st $ret + set idx [string first "\n\n" $ret] + if {$idx > 0} { + return -code $st \ + -errorinfo [string range $ret [expr $idx + 2] \ + [string length $ret]] \ + [string range $ret 0 [expr $idx - 1]] + } else { + return -code $st $ret + } + } else { return $ret } EOL +=end EventFlag = TclTkLib::EventFlag @@ -766,31 +988,64 @@ module TkCore fail TkCallbackContinue, "Tk callback returns 'continue' status" end - def TkCore.callback(arg) - # arg = tk_split_list(arg) - arg = tk_split_simplelist(arg) - #_get_eval_string(TkUtil.eval_cmd(Tk_CMDTBL[arg.shift], *arg)) - #_get_eval_string(TkUtil.eval_cmd(TkCore::INTERP.tk_cmd_tbl[arg.shift], - # *arg)) - cb_obj = TkCore::INTERP.tk_cmd_tbl[arg.shift] - unless $DEBUG - cb_obj.call(*arg) - else - begin - raise 'check backtrace' - rescue - # ignore backtrace before 'callback' - pos = -($!.backtrace.size) - end + def TkCore.callback(*arg) + begin + TkCore::INTERP.tk_cmd_tbl[arg.shift].call(*arg) + rescue Exception => e begin - cb_obj.call(*arg) - rescue - trace = $!.backtrace - raise $!, "\n#{trace[0]}: #{$!.message} (#{$!.class})\n" + - "\tfrom #{trace[1..pos].join("\n\tfrom ")}" + msg = _toUTF8(e.class.inspect) + ': ' + + _toUTF8(e.message) + "\n" + + "\n---< backtrace of Ruby side >-----\n" + + _toUTF8(e.backtrace.join("\n")) + + "\n---< backtrace of Tk side >-------" + msg.instance_variable_set(:@encoding, 'utf-8') + rescue Exception + msg = e.class.inspect + ': ' + e.message + "\n" + + "\n---< backtrace of Ruby side >-----\n" + + e.backtrace.join("\n") + + "\n---< backtrace of Tk side >-------" end + fail(e, msg) end end +=begin + def TkCore.callback(arg_str) + # arg = tk_split_list(arg_str) + arg = tk_split_simplelist(arg_str) + #_get_eval_string(TkUtil.eval_cmd(Tk_CMDTBL[arg.shift], *arg)) + #_get_eval_string(TkUtil.eval_cmd(TkCore::INTERP.tk_cmd_tbl[arg.shift], + # *arg)) + # TkCore::INTERP.tk_cmd_tbl[arg.shift].call(*arg) + begin + TkCore::INTERP.tk_cmd_tbl[arg.shift].call(*arg) + rescue Exception => e + raise(e, e.class.inspect + ': ' + e.message + "\n" + + "\n---< backtrace of Ruby side >-----\n" + + e.backtrace.join("\n") + + "\n---< backtrace of Tk side >-------") + end +#=begin +# cb_obj = TkCore::INTERP.tk_cmd_tbl[arg.shift] +# unless $DEBUG +# cb_obj.call(*arg) +# else +# begin +# raise 'check backtrace' +# rescue +# # ignore backtrace before 'callback' +# pos = -($!.backtrace.size) +# end +# begin +# cb_obj.call(*arg) +# rescue +# trace = $!.backtrace +# raise $!, "\n#{trace[0]}: #{$!.message} (#{$!.class})\n" + +# "\tfrom #{trace[1..pos].join("\n\tfrom ")}" +# end +# end +#=end + end +=end def load_cmd_on_ip(tk_cmd) bool(tk_call('auto_load', tk_cmd)) @@ -799,7 +1054,7 @@ module TkCore def after(ms, cmd=Proc.new) myid = _curr_cmd_id cmdid = install_cmd(cmd) - tk_call("after",ms,cmdid) + tk_call_without_enc("after",ms,cmdid) # return id # return # if false #defined? Thread # Thread.start do @@ -817,86 +1072,43 @@ module TkCore def after_idle(cmd=Proc.new) myid = _curr_cmd_id cmdid = install_cmd(cmd) - tk_call('after','idle',cmdid) + tk_call_without_enc('after','idle',cmdid) end - def clock_clicks(ms=nil) - if ms - tk_call('clock','clicks','-milliseconds').to_i - else - tk_call('clock','clicks').to_i - end + def windowingsystem + tk_call_without_enc('tk', 'windowingsystem') end - def clock_format(clk, form=nil) - if form - tk_call('clock','format',clk,'-format',form).to_i + def scaling(scale=nil) + if scale + tk_call_without_enc('tk', 'scaling', scale) else - tk_call('clock','format',clk).to_i + Float(number(tk_call_without_enc('tk', 'scaling'))) end end - - def clock_formatGMT(clk, form=nil) - if form - tk_call('clock','format',clk,'-format',form,'-gmt','1').to_i + def scaling_displayof(win, scale=nil) + if scale + tk_call_without_enc('tk', 'scaling', '-displayof', win, scale) else - tk_call('clock','format',clk,'-gmt','1').to_i + Float(number(tk_call_without_enc('tk', '-displayof', win, 'scaling'))) end end - def clock_scan(str, base=nil) - if base - tk_call('clock','scan',str,'-base',base).to_i - else - tk_call('clock','scan',str).to_i - end + def appname(name=None) + tk_call('tk', 'appname', name) end - def clock_scanGMT(str, base=nil) - if base - tk_call('clock','scan',str,'-base',base,'-gmt','1').to_i - else - tk_call('clock','scan',str,'-gmt','1').to_i - end - end - - def clock_seconds - tk_call('clock','seconds').to_i - end - - def windowingsystem - tk_call('tk', 'windowingsystem') - end - - def scaling(scale=nil) - if scale - tk_call('tk', 'scaling', scale) - else - Float(number(tk_call('tk', 'scaling'))) - end - end - def scaling_displayof(win, scale=nil) - if scale - tk_call('tk', 'scaling', '-displayof', win, scale) - else - Float(number(tk_call('tk', '-displayof', win, 'scaling'))) - end - end - - def appname(name=None) - tk_call('tk', 'appname', name) - end - - def appsend(interp, async, *args) - if async - tk_call('send', '-async', '--', interp, *args) + def appsend(interp, async, *args) + if async + tk_call('send', '-async', '--', interp, *args) else tk_call('send', '--', interp, *args) end end def rb_appsend(interp, async, *args) - args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"]/, '\\\\\&')} + #args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"]/, '\\\\\&')} + args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"\\]/, '\\\\\&')} args.push(').to_s"') appsend(interp, async, 'ruby "(', *args) end @@ -911,7 +1123,8 @@ module TkCore end def rb_appsend_displayof(interp, win, async, *args) - args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"]/, '\\\\\&')} + #args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"]/, '\\\\\&')} + args = args.collect!{|c| _get_eval_string(c).gsub(/[\[\]$"\\]/, '\\\\\&')} args.push(').to_s"') appsend_displayof(interp, win, async, 'ruby "(', *args) end @@ -971,147 +1184,154 @@ module TkCore end def event_generate(window, context, keys=nil) - window = window.path if window.kind_of? TkObject + #window = window.path if window.kind_of?(TkObject) if keys - tk_call('event', 'generate', window, - "<#{tk_event_sequence(context)}>", *hash_kv(keys)) + tk_call_without_enc('event', 'generate', window, + "<#{tk_event_sequence(context)}>", + *hash_kv(keys, true)) else - tk_call('event', 'generate', window, "<#{tk_event_sequence(context)}>") + tk_call_without_enc('event', 'generate', window, + "<#{tk_event_sequence(context)}>") end + nil end def messageBox(keys) - tk_call 'tk_messageBox', *hash_kv(keys) + tk_call('tk_messageBox', *hash_kv(keys)) end def getOpenFile(keys = nil) - tk_call 'tk_getOpenFile', *hash_kv(keys) + tk_call('tk_getOpenFile', *hash_kv(keys)) end def getSaveFile(keys = nil) - tk_call 'tk_getSaveFile', *hash_kv(keys) + tk_call('tk_getSaveFile', *hash_kv(keys)) end def chooseColor(keys = nil) - tk_call 'tk_chooseColor', *hash_kv(keys) + tk_call('tk_chooseColor', *hash_kv(keys)) end def chooseDirectory(keys = nil) - tk_call 'tk_chooseDirectory', *hash_kv(keys) + tk_call('tk_chooseDirectory', *hash_kv(keys)) end - def ip_eval(cmd_string) - res = INTERP._eval(cmd_string) + def _ip_eval_core(enc_mode, cmd_string) + case enc_mode + when nil + res = INTERP._eval(cmd_string) + when false + res = INTERP._eval_without_enc(cmd_string) + when true + res = INTERP._eval_with_enc(cmd_string) + end if INTERP._return_value() != 0 fail RuntimeError, res, error_at end return res end + private :_ip_eval_core - def ip_invoke(*args) - res = INTERP._invoke(*args) + def ip_eval(cmd_string) + _ip_eval_core(nil, cmd_string) + end + + def ip_eval_without_enc(cmd_string) + _ip_eval_core(false, cmd_string) + end + + def ip_eval_with_enc(cmd_string) + _ip_eval_core(true, cmd_string) + end + + def _ip_invoke_core(enc_mode, *args) + case enc_mode + when false + res = INTERP._invoke_without_enc(*args) + when nil + res = INTERP._invoke(*args) + when true + res = INTERP._invoke_with_enc(*args) + end if INTERP._return_value() != 0 fail RuntimeError, res, error_at end return res end + private :_ip_invoke_core - def tk_call(*args) - puts args.inspect if $DEBUG - args.collect! {|x|ruby2tcl(x)} - args.compact! - args.flatten! - print "=> ", args.join(" ").inspect, "\n" if $DEBUG + def ip_invoke(*args) + _ip_invoke_core(nil, *args) + end + + def ip_invoke_without_enc(*args) + _ip_invoke_core(false, *args) + end + + def ip_invoke_with_enc(*args) + _ip_invoke_core(true, *args) + end + + def _tk_call_core(enc_mode, *args) + ### puts args.inspect if $DEBUG + #args.collect! {|x|ruby2tcl(x, enc_mode)} + #args.compact! + #args.flatten! + args = _conv_args([], enc_mode, *args) + puts 'invoke args => ' + args.inspect if $DEBUG + ### print "=> ", args.join(" ").inspect, "\n" if $DEBUG begin # res = INTERP._invoke(*args).taint - res = INTERP._invoke(*args) # _invoke returns a TAINTED string + # res = INTERP._invoke(enc_mode, *args) + res = _ip_invoke_core(enc_mode, *args) + # >>>>> _invoke returns a TAINTED string <<<<< rescue NameError => err -# err = $! + # err = $! begin args.unshift "unknown" #res = INTERP._invoke(*args).taint - res = INTERP._invoke(*args) # _invoke returns a TAINTED string + #res = INTERP._invoke(enc_mode, *args) + res = _ip_invoke_core(enc_mode, *args) + # >>>>> _invoke returns a TAINTED string <<<<< rescue StandardError => err2 - fail err2 unless /^invalid command/ =~ err2 + fail err2 unless /^invalid command/ =~ err2.message fail err end end if INTERP._return_value() != 0 fail RuntimeError, res, error_at end - print "==> ", res.inspect, "\n" if $DEBUG + ### print "==> ", res.inspect, "\n" if $DEBUG return res end -end - -module TkPackage - include TkCore - extend TkPackage - - TkCommandNames = ['package'.freeze].freeze - - def add_path(path) - Tk::AUTO_PATH.value = Tk::AUTO_PATH.to_a << path - end - - def forget(package) - tk_call('package', 'forget', package) - nil - end - - def names - tk_split_simplelist(tk_call('package', 'names')) - end - - def provide(package, version=nil) - if version - tk_call('package', 'provide', package, version) - nil - else - tk_call('package', 'provide', package) - end - end - - def present(package, version=None) - tk_call('package', 'present', package, version) - end - - def present_exact(package, version) - tk_call('package', 'present', '-exact', package, version) - end - - def require(package, version=None) - tk_call('package', 'require', package, version) - end - - def require_exact(package, version) - tk_call('package', 'require', '-exact', package, version) - end + private :_tk_call_core - def versions(package) - tk_split_simplelist(tk_call('package', 'versions', package)) + def tk_call(*args) + _tk_call_core(nil, *args) end - def vcompare(version1, version2) - Integer(tk_call('package', 'vcompare', version1, version2)) + def tk_call_without_enc(*args) + _tk_call_core(false, *args) end - def vsatisfies(version1, version2) - bool(tk_call('package', 'vsatisfies', version1, version2)) + def tk_call_with_enc(*args) + _tk_call_core(true, *args) end end + module Tk include TkCore extend Tk - TCL_VERSION = INTERP._invoke("info", "tclversion").freeze - TCL_PATCHLEVEL = INTERP._invoke("info", "patchlevel").freeze + TCL_VERSION = INTERP._invoke_without_enc("info", "tclversion").freeze + TCL_PATCHLEVEL = INTERP._invoke_without_enc("info", "patchlevel").freeze - TK_VERSION = INTERP._invoke("set", "tk_version").freeze - TK_PATCHLEVEL = INTERP._invoke("set", "tk_patchLevel").freeze + TK_VERSION = INTERP._invoke_without_enc("set", "tk_version").freeze + TK_PATCHLEVEL = INTERP._invoke_without_enc("set", "tk_patchLevel").freeze - JAPANIZED_TK = (INTERP._invoke("info", "commands", "kanji") != "").freeze + JAPANIZED_TK = (INTERP._invoke_without_enc("info", "commands", + "kanji") != "").freeze def Tk.const_missing(sym) case(sym) @@ -1131,8 +1351,11 @@ module Tk # tk_split_simplelist(INTERP._invoke('set', 'tcl_libPath')) when :PLATFORM, :TCL_PLATFORM - Hash[*tk_split_simplelist(INTERP._invoke('array', 'get', - 'tcl_platform'))] + if $SAFE >= 4 + fail SecurityError, "can't get #{sym} when $SAFE >= 4" + end + Hash[*tk_split_simplelist(INTERP._invoke_without_enc('array', 'get', + 'tcl_platform'))] when :ENV Hash[*tk_split_simplelist(INTERP._invoke('array', 'get', 'env'))] @@ -1148,7 +1371,7 @@ module Tk when :PRIV, :PRIVATE, :TK_PRIV priv = {} - if INTERP._invoke('info', 'vars', 'tk::Priv') != "" + if INTERP._invoke_without_enc('info', 'vars', 'tk::Priv') != "" var_nam = 'tk::Priv' else var_nam = 'tkPriv' @@ -1176,44 +1399,116 @@ module Tk TkRoot.new end + def Tk.load_tclscript(file, enc=nil) + if enc + # TCL_VERSION >= 8.5 + tk_call('source', '-encoding', enc, file) + else + tk_call('source', file) + end + end + + def Tk.load_tcllibrary(file, pkg_name=None, interp=None) + tk_call('load', file, pkg_name, interp) + end + + def Tk.unload_tcllibrary(*args) + if args[-1].kind_of?(Hash) + keys = _symbolkey2str(args.pop) + nocomp = (keys['nocomplain'])? '-nocomplain': None + keeplib = (keys['keeplibrary'])? '-keeplibrary': None + tk_call('unload', nocomp, keeplib, '--', *args) + else + tk_call('unload', *args) + end + end + def Tk.bell(nice = false) if nice - tk_call 'bell', '-nice' + tk_call_without_enc('bell', '-nice') else - tk_call 'bell' + tk_call_without_enc('bell') end + nil end def Tk.bell_on_display(win, nice = false) if nice - tk_call('bell', '-displayof', win, '-nice') + tk_call_without_enc('bell', '-displayof', win, '-nice') else - tk_call('bell', '-displayof', win) + tk_call_without_enc('bell', '-displayof', win) end + nil end def Tk.destroy(*wins) - tk_call('destroy', *wins) + tk_call_without_enc('destroy', *wins) end def Tk.exit - tk_call('destroy', '.') + tk_call_without_enc('destroy', '.') + end + + def Tk.pack(*args) + #TkPack.configure(*args) + TkPack(*args) + end + + def Tk.grid(*args) + TkGrid.configure(*args) + end + + def Tk.update(idle=nil) + if idle + tk_call_without_enc('update', 'idletasks') + else + tk_call_without_enc('update') + end + end + def Tk.update_idletasks + update(true) + end + +=begin + # See tcltklib.c for the reason of why the following methods are disabled. + def Tk.thread_update(idle=nil) + if idle + tk_call_without_enc('thread_update', 'idletasks') + else + tk_call_without_enc('thread_update') + end + end + def Tk.thread_update_idletasks + thread_update(true) end +=end - def Tk.current_grabs - tk_split_list(tk_call('grab', 'current')) + def Tk.current_grabs(win = nil) + if win + window(tk_call_without_enc('grab', 'current', win)) + else + tk_split_list(tk_call_without_enc('grab', 'current')) + end end def Tk.focus(display=nil) if display == nil - window(tk_call('focus')) + window(tk_call_without_enc('focus')) + else + window(tk_call_without_enc('focus', '-displayof', display)) + end + end + + def Tk.focus_to(win, force=false) + if force + tk_call_without_enc('focus', '-force', win) else - window(tk_call('focus', '-displayof', display)) + tk_call_without_enc('focus', win) end end def Tk.focus_lastfor(win) - window(tk_call('focus', '-lastfor', win)) + window(tk_call_without_enc('focus', '-lastfor', win)) end def Tk.focus_next(win) @@ -1225,7 +1520,7 @@ module Tk end def Tk.strictMotif(bool=None) - bool(tk_call('set', 'tk_strictMotif', bool)) + bool(tk_call_without_enc('set', 'tk_strictMotif', bool)) end def Tk.show_kinsoku(mode='both') @@ -1258,410 +1553,200 @@ module Tk end end - def Tk.toUTF8(str,encoding) - INTERP._toUTF8(str,encoding) + def Tk.toUTF8(str, encoding = nil) + _toUTF8(str, encoding) end - def Tk.fromUTF8(str,encoding) - INTERP._fromUTF8(str,encoding) + def Tk.fromUTF8(str, encoding = nil) + _fromUTF8(str, encoding) end +end - module Scrollable - def xscrollcommand(cmd=Proc.new) - configure_cmd 'xscrollcommand', cmd - end - def yscrollcommand(cmd=Proc.new) - configure_cmd 'yscrollcommand', cmd - end - def xview(*index) - v = tk_send('xview', *index) - list(v) if index.size == 0 - end - def yview(*index) - v = tk_send('yview', *index) - list(v) if index.size == 0 - end - def xscrollbar(bar=nil) - if bar - @xscrollbar = bar - @xscrollbar.orient 'horizontal' - self.xscrollcommand {|*arg| @xscrollbar.set(*arg)} - @xscrollbar.command {|*arg| self.xview(*arg)} - end - @xscrollbar - end - def yscrollbar(bar=nil) - if bar - @yscrollbar = bar - @yscrollbar.orient 'vertical' - self.yscrollcommand {|*arg| @yscrollbar.set(*arg)} - @yscrollbar.command {|*arg| self.yview(*arg)} - end - @yscrollbar - end +########################################### +# string with Tcl's encoding +########################################### +module Tk + def Tk.subst_utf_backslash(str) + Tk::EncodedString.subst_utf_backslash(str) end + def Tk.subst_tk_backslash(str) + Tk::EncodedString.subst_tk_backslash(str) + end + def Tk.utf_to_backslash_sequence(str) + Tk::EncodedString.utf_to_backslash_sequence(str) + end + def Tk.utf_to_backslash(str) + Tk::EncodedString.utf_to_backslash_sequence(str) + end + def Tk.to_backslash_sequence(str) + Tk::EncodedString.to_backslash_sequence(str) + end +end - module Wm - include TkComm - TkCommandNames = ['wm'.freeze].freeze +########################################### +# convert kanji string to/from utf-8 +########################################### +if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK) + class TclTkIp + # from tkencoding.rb by ttate@jaist.ac.jp + attr_accessor :encoding - def aspect(*args) - w = tk_call('wm', 'aspect', path, *args) - if args.length == 0 - list(w) - else - self - end - end - def attributes(slot=nil,value=None) - if slot == nil - lst = tk_split_list(tk_call('wm', 'attributes', path)) - info = {} - while key = lst.shift - info[key[1..-1]] = lst.shift - end - info - elsif slot.kind_of? Hash - tk_call('wm', 'attributes', path, *hash_kv(slot)) - self - elsif value == None - tk_call('wm', 'attributes', path, "-#{slot}") - else - tk_call('wm', 'attributes', path, "-#{slot}", value) - self - end - end - def client(name=None) - if name == None - tk_call 'wm', 'client', path - else - name = '' if name == nil - tk_call 'wm', 'client', path, name - self - end - end - def colormapwindows(*args) - r = tk_call('wm', 'colormapwindows', path, *args) - if args.size == 0 - list(r) - else - self - end - end - def wm_command(value=nil) - if value - tk_call('wm', 'command', path, value) - self - else - procedure(tk_call('wm', 'command', path)) - end - end - def deiconify(ex = true) - tk_call('wm', 'deiconify', path) if ex - self - end - def focusmodel(mode = nil) - if mode - tk_call 'wm', 'focusmodel', path, mode - self + alias __eval _eval + alias __invoke _invoke + + alias __toUTF8 _toUTF8 + alias __fromUTF8 _fromUTF8 + +=begin + #### --> definition is moved to TclTkIp module + + def _toUTF8(str, encoding = nil) + # decide encoding + if encoding + encoding = encoding.to_s + elsif str.kind_of?(Tk::EncodedString) && str.encoding != nil + encoding = str.encoding.to_s + elsif str.instance_variable_get(:@encoding) + encoding = str.instance_variable_get(:@encoding).to_s + elsif defined?(@encoding) && @encoding != nil + encoding = @encoding.to_s else - tk_call 'wm', 'focusmodel', path + encoding = __invoke('encoding', 'system') end - end - def frame - tk_call('wm', 'frame', path) - end - def geometry(geom=nil) - if geom - tk_call('wm', 'geometry', path, geom) - self + + # convert + case encoding + when 'utf-8', 'binary' + str else - tk_call('wm', 'geometry', path) + __toUTF8(str, encoding) end end - def grid(*args) - w = tk_call('wm', 'grid', path, *args) - if args.size == 0 - list(w) - else - self + + def _fromUTF8(str, encoding = nil) + unless encoding + if defined?(@encoding) && @encoding != nil + encoding = @encoding.to_s + else + encoding = __invoke('encoding', 'system') + end end - end - def group(*args) - w = tk_call('wm', 'group', path, *args) - if args.size == 0 - window(w) + + if str.kind_of?(Tk::EncodedString) + if str.encoding == 'binary' + str + else + __fromUTF8(str, encoding) + end + elsif str.instance_variable_get(:@encoding).to_s == 'binary' + str else - self + __fromUTF8(str, encoding) end end - def iconbitmap(bmp=nil) - if bmp - tk_call 'wm', 'iconbitmap', path, bmp - self - else - tk_call 'wm', 'iconbitmap', path - end +=end + + def _eval(cmd) + _fromUTF8(__eval(_toUTF8(cmd))) end - def iconify(ex = true) - tk_call('wm', 'iconify', path) if ex - self + + def _invoke(*cmds) + _fromUTF8(__invoke(*(cmds.collect{|cmd| _toUTF8(cmd)}))) end - def iconmask(bmp=nil) - if bmp - tk_call 'wm', 'iconmask', path, bmp - self + + alias _eval_with_enc _eval + alias _invoke_with_enc _invoke + +=begin + def _eval(cmd) + if defined?(@encoding) && @encoding != 'utf-8' + ret = if cmd.kind_of?(Tk::EncodedString) + case cmd.encoding + when 'utf-8', 'binary' + __eval(cmd) + else + __eval(_toUTF8(cmd, cmd.encoding)) + end + elsif cmd.instance_variable_get(:@encoding) == 'binary' + __eval(cmd) + else + __eval(_toUTF8(cmd, @encoding)) + end + if ret.kind_of?(String) && ret.instance_variable_get(:@encoding) == 'binary' + ret + else + _fromUTF8(ret, @encoding) + end else - tk_call 'wm', 'iconmask', path + __eval(cmd) end end - def iconname(name=nil) - if name - tk_call 'wm', 'iconname', path, name - self + + def _invoke(*cmds) + if defined?(@encoding) && @encoding != 'utf-8' + cmds = cmds.collect{|cmd| + if cmd.kind_of?(Tk::EncodedString) + case cmd.encoding + when 'utf-8', 'binary' + cmd + else + _toUTF8(cmd, cmd.encoding) + end + elsif cmd.instance_variable_get(:@encoding) == 'binary' + cmd + else + _toUTF8(cmd, @encoding) + end + } + ret = __invoke(*cmds) + if ret.kind_of?(String) && ret.instance_variable_get(:@encoding) == 'binary' + ret + else + _fromUTF8(ret, @encoding) + end else - tk_call 'wm', 'iconname', path - end + __invoke(*cmds) + end end - def iconposition(*args) - w = tk_call('wm', 'iconposition', path, *args) - if args.size == 0 - list(w) - else - self +=end + end + + module Tk + module Encoding + extend Encoding + + TkCommandNames = ['encoding'.freeze].freeze + + def encoding=(name) + TkCore::INTERP.encoding = name end - end - def iconwindow(*args) - w = tk_call('wm', 'iconwindow', path, *args) - if args.size == 0 - window(w) - else - self + + def encoding + TkCore::INTERP.encoding end - end - def maxsize(*args) - w = tk_call('wm', 'maxsize', path, *args) - if args.size == 0 - list(w) - else - self + + def encoding_names + tk_split_simplelist(tk_call('encoding', 'names')) end - end - def minsize(*args) - w = tk_call('wm', 'minsize', path, *args) - if args.size == 0 - list(w) - else - self + + def encoding_system + tk_call('encoding', 'system') end - end - def overrideredirect(bool=None) - if bool == None - bool(tk_call('wm', 'overrideredirect', path)) - else - tk_call 'wm', 'overrideredirect', path, bool - self + + def encoding_system=(enc) + tk_call('encoding', 'system', enc) end - end - def positionfrom(who=None) - if who == None - r = tk_call('wm', 'positionfrom', path) - (r == "")? nil: r - else - tk_call('wm', 'positionfrom', path, who) - self + + def encoding_convertfrom(str, enc=None) + TkCore::INTERP.__invoke('encoding', 'convertfrom', enc, str) end - end - def protocol(name=nil, cmd=nil) - if cmd - tk_call('wm', 'protocol', path, name, cmd) - self - elsif name - result = tk_call('wm', 'protocol', path, name) - (result == "")? nil : tk_tcl2ruby(result) - else - tk_split_simplelist(tk_call('wm', 'protocol', path)) + alias encoding_convert_from encoding_convertfrom + + def encoding_convertto(str, enc=None) + TkCore::INTERP.__invoke('encoding', 'convertto', enc, str) end - end - def resizable(*args) - w = tk_call('wm', 'resizable', path, *args) - if args.length == 0 - list(w).collect{|e| bool(e)} - else - self - end - end - def sizefrom(who=None) - if who == None - r = tk_call('wm', 'sizefrom', path) - (r == "")? nil: r - else - tk_call('wm', 'sizefrom', path, who) - self - end - end - def stackorder - list(tk_call('wm', 'stackorder', path)) - end - def stackorder_isabove(win) - bool(tk_call('wm', 'stackorder', path, 'isabove', win)) - end - def stackorder_isbelow(win) - bool(tk_call('wm', 'stackorder', path, 'isbelow', win)) - end - def state(state=nil) - if state - tk_call 'wm', 'state', path, state - self - else - tk_call 'wm', 'state', path - end - end - def title(str=nil) - if str - tk_call('wm', 'title', path, str) - self - else - tk_call('wm', 'title', path) - end - end - def transient(master=nil) - if master - tk_call('wm', 'transient', path, master) - self - else - window(tk_call('wm', 'transient', path, master)) - end - end - def withdraw(ex = true) - tk_call('wm', 'withdraw', path) if ex - self - end - end -end - -########################################### -# string with Tcl's encoding -########################################### -module Tk - class EncodedString < String - @@enc_buf = '__rb_encoding_buffer__' - - def self.tk_escape(str) - s = '"' + str.gsub(/[\[\]$"]/, '\\\\\&') + '"' - TkCore::INTERP.__eval(Kernel.format('global %s; set %s %s', - @@enc_buf, @@enc_buf, s)) - end - - def self.new(str, enc = Tk.encoding_system) - obj = super(self.tk_escape(str)) - obj.instance_eval{@enc = enc} - obj - end - - def self.new_without_escape(str, enc = Tk.encoding_system) - obj = super(str) - obj.instance_eval{@enc = enc} - obj - end - - def encoding - @enc - end - end - def Tk.EncodedString(str, enc = Tk.encoding_system) - Tk::EncodedString.new(str, enc) - end - - class UTF8_String < EncodedString - def self.new(str) - super(str, 'utf-8') - end - def self.new_without_escape(str) - super(str, 'utf-8') - end - end - def Tk.UTF8_String(str) - Tk::UTF8_String.new(str) - end -end - - -########################################### -# convert kanji string to/from utf-8 -########################################### -if /^8\.[1-9]/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK - class TclTkIp - # from tkencoding.rb by ttate@jaist.ac.jp - alias __eval _eval - alias __invoke _invoke - - attr_accessor :encoding - - def _eval(cmd) - if defined? @encoding - if cmd.kind_of?(Tk::EncodedString) - _fromUTF8(__eval(_toUTF8(cmd, cmd.encoding)), @encoding) - else - _fromUTF8(__eval(_toUTF8(cmd, @encoding)), @encoding) - end - else - __eval(cmd) - end - end - - def _invoke(*cmds) - if defined? @encoding - cmds = cmds.collect{|cmd| - if cmd.kind_of?(Tk::EncodedString) - _toUTF8(cmd, cmd.encoding) - else - _toUTF8(cmd, @encoding) - end - } - _fromUTF8(__invoke(*cmds), @encoding) - else - __invoke(*cmds) - end - end - end - - module Tk - module Encoding - extend Encoding - - TkCommandNames = ['encoding'.freeze].freeze - - def encoding=(name) - TkCore::INTERP.encoding = name - end - - def encoding - TkCore::INTERP.encoding - end - - def encoding_names - tk_split_simplelist(tk_call('encoding', 'names')) - end - - def encoding_system - tk_call('encoding', 'system') - end - - def encoding_system=(enc) - tk_call('encoding', 'system', enc) - end - - def encoding_convertfrom(str, enc=None) - TkCore::INTERP.__invoke('encoding', 'convertfrom', enc, str) - end - alias encoding_convert_from encoding_convertfrom - - def encoding_convertto(str, enc=None) - TkCore::INTERP.__invoke('encoding', 'convertto', enc, str) - end - alias encoding_convert_to encoding_convertto + alias encoding_convert_to encoding_convertto end extend Encoding @@ -1688,6 +1773,9 @@ else class TclTkIp alias __eval _eval alias __invoke _invoke + + alias _eval_with_enc _eval + alias _invoke_with_enc _invoke end module Tk @@ -1720,4191 +1808,1004 @@ else end alias encoding_convert_to encoding_convertto end - - extend Encoding end end -module TkBindCore - def bind(context, cmd=Proc.new, args=nil) - Tk.bind(self, context, cmd, args) - end - - def bind_append(context, cmd=Proc.new, args=nil) - Tk.bind_append(self, context, cmd, args) - end - def bind_remove(context) - Tk.bind_remove(self, context) - end - - def bindinfo(context=nil) - Tk.bindinfo(self, context) +module TkTreatFont + def font_configinfo(name = nil) + ret = TkFont.used_on(self.path) + if ret == nil +=begin + if name + ret = name + else + ret = TkFont.init_widget_font(self.path, self.path, 'configure') + end +=end + ret = TkFont.init_widget_font(self.path, self.path, 'configure') + end + ret end -end - -class TkBindTag - include TkBindCore - - #BTagID_TBL = {} - BTagID_TBL = TkCore::INTERP.create_table - Tk_BINDTAG_ID = ["btag".freeze, "00000".taint].freeze + alias fontobj font_configinfo - TkCore::INTERP.init_ip_env{ BTagID_TBL.clear } + def font_configure(slot) + slot = _symbolkey2str(slot) - def TkBindTag.id2obj(id) - BTagID_TBL[id]? BTagID_TBL[id]: id - end + if slot.key?('font') + fnt = slot.delete('font') + if fnt.kind_of? TkFont + return fnt.call_font_configure(self.path, self.path,'configure',slot) + else + if fnt + if (slot.key?('kanjifont') || + slot.key?('latinfont') || + slot.key?('asciifont')) + fnt = TkFont.new(fnt) - def TkBindTag.new_by_name(name, *args, &b) - return BTagID_TBL[name] if BTagID_TBL[name] - self.new(*args, &b).instance_eval{ - BTagID_TBL.delete @id - @id = name - BTagID_TBL[@id] = self - } - end + lfnt = slot.delete('latinfont') + lfnt = slot.delete('asciifont') if slot.key?('asciifont') + kfnt = slot.delete('kanjifont') - def initialize(*args, &b) - @id = Tk_BINDTAG_ID.join - Tk_BINDTAG_ID[1].succ! - BTagID_TBL[@id] = self - bind(*args, &b) if args != [] - end + fnt.latin_replace(lfnt) if lfnt + fnt.kanji_replace(kfnt) if kfnt + else + slot['font'] = fnt + tk_call(self.path, 'configure', *hash_kv(slot)) + end + end + return self + end + end - ALL = self.new_by_name('all') + lfnt = slot.delete('latinfont') + lfnt = slot.delete('asciifont') if slot.key?('asciifont') + kfnt = slot.delete('kanjifont') - def name - @id - end + if lfnt && kfnt + return TkFont.new(lfnt, kfnt).call_font_configure(self.path, self.path, + 'configure', slot) + end - def to_eval - @id + latinfont_configure(lfnt) if lfnt + kanjifont_configure(kfnt) if kfnt + + tk_call(self.path, 'configure', *hash_kv(slot)) if slot != {} + self end - def inspect - Kernel.format "#", @id - end -end + def latinfont_configure(ltn, keys=nil) + if (fobj = TkFont.used_on(self.path)) + fobj = TkFont.new(fobj) # create a new TkFont object + elsif Tk::JAPANIZED_TK + fobj = fontobj # create a new TkFont object + else + tk_call(self.path, 'configure', '-font', ltn) + return self + end -class TkBindTagAll", @id + return fobj.call_font_configure(self.path, self.path, 'configure', {}) end -end - -class TkVariable - include Tk - extend TkCore - - include Comparable - - #TkCommandNames = ['tkwait'.freeze].freeze - TkCommandNames = ['vwait'.freeze].freeze - - #TkVar_CB_TBL = {} - #TkVar_ID_TBL = {} - TkVar_CB_TBL = TkCore::INTERP.create_table - TkVar_ID_TBL = TkCore::INTERP.create_table - Tk_VARIABLE_ID = ["v".freeze, "00000".taint].freeze - - TkCore::INTERP.add_tk_procs('rb_var', 'args', - "ruby [format \"TkVariable.callback %%Q!%s!\" $args]") - def TkVariable.callback(args) - name1,name2,op = tk_split_list(args) - if TkVar_CB_TBL[name1] - _get_eval_string(TkVar_CB_TBL[name1].trace_callback(name2,op)) + def font_copy(window, tag=nil) + if tag + fnt = window.tagfontobj(tag).dup else - '' + fnt = window.fontobj.dup end + fnt.call_font_configure(self.path, self.path, 'configure', {}) + self end - def initialize(val="") - @id = Tk_VARIABLE_ID.join - Tk_VARIABLE_ID[1].succ! - TkVar_ID_TBL[@id] = self - - @trace_var = nil - @trace_elem = nil - @trace_opts = nil - -=begin - if val == [] - # INTERP._eval(format('global %s; set %s(0) 0; unset %s(0)', - # @id, @id, @id)) - elsif val.kind_of?(Array) - a = [] - # val.each_with_index{|e,i| a.push(i); a.push(array2tk_list(e))} - # s = '"' + a.join(" ").gsub(/[\[\]$"]/, '\\\\\&') + '"' - val.each_with_index{|e,i| a.push(i); a.push(e)} - s = '"' + array2tk_list(a).gsub(/[\[\]$"]/, '\\\\\&') + '"' - INTERP._eval(format('global %s; array set %s %s', @id, @id, s)) - elsif val.kind_of?(Hash) - s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\ - .gsub(/[\[\]$"]/, '\\\\\&') + '"' - INTERP._eval(format('global %s; array set %s %s', @id, @id, s)) - else - s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"' - INTERP._eval(format('global %s; set %s %s', @id, @id, s)) - end -=end - if val.kind_of?(Hash) - s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\ - .gsub(/[\[\]$"]/, '\\\\\&') + '"' - INTERP._eval(Kernel.format('global %s; array set %s %s', @id, @id, s)) - else - s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"' - INTERP._eval(Kernel.format('global %s; set %s %s', @id, @id, s)) - end - end - - def wait(on_thread = false, check_root = false) - if $SAFE >= 4 - fail SecurityError, "can't wait variable at $SAFE >= 4" - end - if on_thread - if check_root - INTERP._thread_tkwait('variable', @id) - else - INTERP._thread_vwait(@id) - end - else - if check_root - INTERP._invoke('tkwait', 'variable', @id) - else - INTERP._invoke('vwait', @id) - end - end - end - def eventloop_wait(check_root = false) - wait(false, check_root) - end - def thread_wait(check_root = false) - wait(true, check_root) - end - def tkwait(on_thread = true) - wait(on_thread, true) - end - def eventloop_tkwait - wait(false, true) - end - def thread_tkwait - wait(true, true) - end - - def id - @id - end - - def value - begin - INTERP._eval(Kernel.format('global %s; set %s', @id, @id)) - rescue - if INTERP._eval(Kernel.format('global %s; array exists %s', - @id, @id)) != "1" - fail - else - Hash[*tk_split_simplelist(INTERP._eval(Kernel.format('global %s; array get %s', @id, @id)))] - end - end - end - - def value=(val) - begin - s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"' - INTERP._eval(Kernel.format('global %s; set %s %s', @id, @id, s)) - rescue - if INTERP._eval(Kernel.format('global %s; array exists %s', - @id, @id)) != "1" - fail - else - if val == [] - INTERP._eval(Kernel.format('global %s; unset %s; set %s(0) 0; unset %s(0)', @id, @id, @id, @id)) - elsif val.kind_of?(Array) - a = [] - val.each_with_index{|e,i| a.push(i); a.push(array2tk_list(e))} - s = '"' + a.join(" ").gsub(/[\[\]$"]/, '\\\\\&') + '"' - INTERP._eval(Kernel.format('global %s; unset %s; array set %s %s', - @id, @id, @id, s)) - elsif val.kind_of?(Hash) - s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\ - .gsub(/[\[\]$"]/, '\\\\\&') + '"' - INTERP._eval(Kernel.format('global %s; unset %s; array set %s %s', - @id, @id, @id, s)) - else - fail - end - end - end - end - - def [](index) - INTERP._eval(Kernel.format('global %s; set %s(%s)', - @id, @id, _get_eval_string(index))) - end - - def []=(index,val) - INTERP._eval(Kernel.format('global %s; set %s(%s) %s', @id, @id, - _get_eval_string(index), _get_eval_string(val))) - end - - def numeric - number(value) - end - def numeric=(val) - case val - when Numeric - self.value=(val) - when TkVariable - self.value=(val.numeric) - else - raise ArgumentError, "Numeric is expected" - end - end - - def to_i - number(value).to_i - end - - def to_f - number(value).to_f - end - - def to_s - string(value).to_s - end - - def to_sym - value.intern - end - - def list - tk_split_list(value) - end - alias to_a list - - def list=(val) - case val - when Array - self.value=(val) - when TkVariable - self.value=(val.list) - else - raise ArgumentError, "Array is expected" - end - end - - def inspect - Kernel.format "#", @id - end - - def coerce(other) - case other - when TkVariable - [other.value, self.value] - when String - [other, self.to_s] - when Symbol - [other, self.to_sym] - when Integer - [other, self.to_i] - when Float - [other, self.to_f] - when Array - [other, self.to_a] - else - [other, self.value] - end - end - - def &(other) - if other.kind_of?(Array) - self.to_a & other.to_a - else - self.to_i & other.to_i - end - end - def |(other) - if other.kind_of?(Array) - self.to_a | other.to_a - else - self.to_i | other.to_i - end - end - def +(other) - case other - when Array - self.to_a + other - when String - self.value + other - else - begin - number(self.value) + other - rescue - self.value + other.to_s - end - end - end - def -(other) - if other.kind_of?(Array) - self.to_a - other - else - number(self.value) - other - end - end - def *(other) - begin - number(self.value) * other - rescue - self.value * other - end - end - def /(other) - number(self.value) / other - end - def %(other) - begin - number(self.value) % other - rescue - self.value % other - end - end - def **(other) - number(self.value) ** other - end - def =~(other) - self.value =~ other - end - - def ==(other) - case other - when TkVariable - self.equal?(other) - when String - self.to_s == other - when Symbol - self.to_sym == other - when Integer - self.to_i == other - when Float - self.to_f == other - when Array - self.to_a == other - when Hash - self.value == other - else - false - end - end - - def zero? - numeric.zero? - end - def nonzero? - !(numeric.zero?) - end - - def <=>(other) - if other.kind_of?(TkVariable) - begin - val = other.numeric - other = val - rescue - other = other.value - end - end - if other.kind_of?(Numeric) - begin - return self.numeric <=> other - rescue - return self.value <=> other.to_s - end - else - return self.value <=> other - end - end - - def to_eval - @id - end - - def unset(elem=nil) - if elem - INTERP._eval(Kernel.format('global %s; unset %s(%s)', - @id, @id, tk_tcl2ruby(elem))) - else - INTERP._eval(Kernel.format('global %s; unset %s', @id, @id)) - end - end - alias remove unset - - def trace_callback(elem, op) - if @trace_var.kind_of? Array - @trace_var.each{|m,e| e.call(self,elem,op) if m.index(op)} - end - if elem.kind_of? String - if @trace_elem[elem].kind_of? Array - @trace_elem[elem].each{|m,e| e.call(self,elem,op) if m.index(op)} - end - end - end - - def trace(opts, cmd) - @trace_var = [] if @trace_var == nil - opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') - @trace_var.unshift([opts,cmd]) - if @trace_opts == nil - TkVar_CB_TBL[@id] = self - @trace_opts = opts - Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var') - else - newopts = @trace_opts.dup - opts.each_byte{|c| newopts += c.chr unless newopts.index(c)} - if newopts != @trace_opts - Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var') - @trace_opts.replace(newopts) - Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var') - end - end - end - - def trace_element(elem, opts, cmd) - @trace_elem = {} if @trace_elem == nil - @trace_elem[elem] = [] if @trace_elem[elem] == nil - opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') - @trace_elem[elem].unshift([opts,cmd]) - if @trace_opts == nil - TkVar_CB_TBL[@id] = self - @trace_opts = opts - Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var') - else - newopts = @trace_opts.dup - opts.each_byte{|c| newopts += c.chr unless newopts.index(c)} - if newopts != @trace_opts - Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var') - @trace_opts.replace(newopts) - Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var') - end - end - end - - def trace_vinfo - return [] unless @trace_var - @trace_var.dup - end - def trace_vinfo_for_element(elem) - return [] unless @trace_elem - return [] unless @trace_elem[elem] - @trace_elem[elem].dup - end - - def trace_vdelete(opts,cmd) - return unless @trace_var.kind_of? Array - opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') - idx = -1 - newopts = '' - @trace_var.each_with_index{|e,i| - if idx < 0 && e[0] == opts && e[1] == cmd - idx = i - next - end - e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)} - } - if idx >= 0 - @trace_var.delete_at(idx) - else - return - end - - @trace_elem.each{|elem| - @trace_elem[elem].each{|e| - e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)} - } - } - - newopts = ['r','w','u'].find_all{|c| newopts.index(c)}.join('') - if newopts != @trace_opts - Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var') - @trace_opts.replace(newopts) - if @trace_opts != '' - Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var') - end - end - end - - def trace_vdelete_for_element(elem,opts,cmd) - return unless @trace_elem.kind_of? Hash - return unless @trace_elem[elem].kind_of? Array - opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') - idx = -1 - @trace_elem[elem].each_with_index{|e,i| - if idx < 0 && e[0] == opts && e[1] == cmd - idx = i - next - end - } - if idx >= 0 - @trace_elem[elem].delete_at(idx) - else - return - end - - newopts = '' - @trace_var.each{|e| - e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)} - } - @trace_elem.each{|elem| - @trace_elem[elem].each{|e| - e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)} - } - } - - newopts = ['r','w','u'].find_all{|c| newopts.index(c)}.join('') - if newopts != @trace_opts - Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var') - @trace_opts.replace(newopts) - if @trace_opts != '' - Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var') - end - end - end -end - -class TkVarAccess= Tk8.4a2 ? - if slot - conf = tk_split_list(tk_call('place', 'configure', - win.epath, "-#{slot}") ) - conf[0] = conf[0][1..-1] - conf - else - tk_split_simplelist(tk_call('place', 'configure', - win.epath)).collect{|conflist| - conf = tk_split_simplelist(conflist) - conf[0] = conf[0][1..-1] - conf - } - end - end - - def forget(win) - tk_call 'place', 'forget', win - end - - def info(win) - ilist = list(tk_call('place', 'info', win.epath)) - info = {} - while key = ilist.shift - info[key[1..-1]] = ilist.shift - end - return info - end - - def slaves(master) - list(tk_call('place', 'slaves', master.epath)) - end - - module_function :configure, :configinfo, :forget, :info, :slaves -end - -module TkOptionDB - include Tk - extend Tk - - TkCommandNames = ['option'.freeze].freeze - - module Priority - WidgetDefault = 20 - StartupFile = 40 - UserDefault = 60 - Interactive = 80 - end - - def add(pat, value, pri=None) - if $SAFE >= 4 - fail SecurityError, "can't call 'TkOptionDB.add' at $SAFE >= 4" - end - tk_call 'option', 'add', pat, value, pri - end - def clear - if $SAFE >= 4 - fail SecurityError, "can't call 'TkOptionDB.crear' at $SAFE >= 4" - end - tk_call 'option', 'clear' - end - def get(win, name, klass) - tk_call('option', 'get', win ,name, klass) - end - def readfile(file, pri=None) - tk_call 'option', 'readfile', file, pri - end - module_function :add, :clear, :get, :readfile - - def read_entries(file, f_enc=nil) - if TkCore::INTERP.safe? - fail SecurityError, - "can't call 'TkOptionDB.read_entries' on a safe interpreter" - end - - i_enc = Tk.encoding() - - unless f_enc - f_enc = i_enc - end - - ent = [] - cline = '' - open(file, 'r') {|f| - while line = f.gets - cline += line.chomp! - case cline - when /\\$/ # continue - cline.chop! - next - when /^!/ # coment - cline = '' - next - when /^([^:]+):\s(.*)$/ - pat = $1 - val = $2 - p "ResourceDB: #{[pat, val].inspect}" if $DEBUG - pat = TkCore::INTERP._toUTF8(pat, f_enc) - pat = TkCore::INTERP._fromUTF8(pat, i_enc) - val = TkCore::INTERP._toUTF8(val, f_enc) - val = TkCore::INTERP._fromUTF8(val, i_enc) - ent << [pat, val] - cline = '' - else # unknown --> ignore - cline = '' - next - end - end - } - ent - end - module_function :read_entries - - def read_with_encoding(file, f_enc=nil, pri=None) - # try to read the file as an OptionDB file - readfile(file, pri).each{|pat, val| - add(pat, val, pri) - } - -=begin - i_enc = Tk.encoding() - - unless f_enc - f_enc = i_enc - end - - cline = '' - open(file, 'r') {|f| - while line = f.gets - cline += line.chomp! - case cline - when /\\$/ # continue - cline.chop! - next - when /^!/ # coment - cline = '' - next - when /^([^:]+):\s(.*)$/ - pat = $1 - val = $2 - p "ResourceDB: #{[pat, val].inspect}" if $DEBUG - pat = TkCore::INTERP._toUTF8(pat, f_enc) - pat = TkCore::INTERP._fromUTF8(pat, i_enc) - val = TkCore::INTERP._toUTF8(val, f_enc) - val = TkCore::INTERP._fromUTF8(val, i_enc) - add(pat, val, pri) - cline = '' - else # unknown --> ignore - cline = '' - next - end - end - } -=end - end - module_function :read_with_encoding - - # support procs on the resource database - @@resource_proc_class = Class.new - class << @@resource_proc_class - private :new - - CARRIER = '.'.freeze - METHOD_TBL = TkCore::INTERP.create_table - ADD_METHOD = false - SAFE_MODE = 4 - - def __closed_block_check__(str) - depth = 0 - str.scan(/[{}]/){|x| - if x == "{" - depth += 1 - elsif x == "}" - depth -= 1 - end - if depth <= 0 && !($' =~ /\A\s*\Z/) - fail RuntimeError, "bad string for procedure : #{str.inspect}" - end - } - str - end - - def __check_proc_string__(str) - # If you want to check the proc_string, do it in this method. - # Please define this in the block given to 'new_proc_class' 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 = TkOptionDB.get(self::CARRIER, id.id2name, '').strip - proc_str = '{' + proc_str + '}' unless /\A\{.*\}\Z/ =~ proc_str - proc_str = __closed_block_check__(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 :__closed_block_check__, :__check_proc_string__, :method_missing - end - @@resource_proc_class.freeze - - def __create_new_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} < TkOptionDB.module_eval('@@resource_proc_class') - CARRIER = '#{carrier}'.freeze - METHOD_TBL = TkCore::INTERP.create_table - 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('TkOptionDB::' + klass) - end - end - module_function :__create_new_class - private_class_method :__create_new_class - - def __remove_methods_of_proc_class(klass) - # for security, make these methods invalid - class << klass - attr_reader :class_eval, :name, :superclass, - :ancestors, :const_defined?, :const_get, :const_set, - :constants, :included_modules, :instance_methods, - :method_defined?, :module_eval, :private_instance_methods, - :protected_instance_methods, :public_instance_methods, - :remove_const, :remove_method, :undef_method, - :to_s, :inspect, :display, :method, :methods, - :instance_eval, :instance_variables, :kind_of?, :is_a?, - :private_methods, :protected_methods, :public_methods - end - end - module_function :__remove_methods_of_proc_class - private_class_method :__remove_methods_of_proc_class - - RAND_BASE_CNT = [0] - RAND_BASE_HEAD = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' - RAND_BASE_CHAR = RAND_BASE_HEAD + 'abcdefghijklmnopqrstuvwxyz0123456789_' - def __get_random_basename - name = '%s%03d' % [RAND_BASE_HEAD[rand(RAND_BASE_HEAD.size),1], - RAND_BASE_CNT[0]] - len = RAND_BASE_CHAR.size - (6+rand(10)).times{ - name << RAND_BASE_CHAR[rand(len),1] - } - RAND_BASE_CNT[0] = RAND_BASE_CNT[0] + 1 - name - end - module_function :__get_random_basename - private_class_method :__get_random_basename - - # define new proc class : - # If you want to modify the new class or create a new subclass, - # you must do such operation in the block parameter. - # Because the created class is flozen after evaluating the block. - def new_proc_class(klass, func, safe = 4, add = false, parent = nil, &b) - new_klass = __create_new_class(klass, func, safe, add, parent) - new_klass.class_eval(&b) if block_given? - __remove_methods_of_proc_class(new_klass) - new_klass.freeze - new_klass - end - module_function :new_proc_class - - def eval_under_random_base(parent = nil, &b) - new_klass = __create_new_class(__get_random_basename(), - [], 4, false, parent) - ret = new_klass.class_eval(&b) if block_given? - __remove_methods_of_proc_class(new_klass) - new_klass.freeze - ret - end - module_function :eval_under_random_base - - def new_proc_class_random(klass, func, safe = 4, add = false, &b) - eval_under_random_base(){ - TkOption.new_proc_class(klass, func, safe, add, self, &b) - } - end - module_function :new_proc_class_random -end -TkOption = TkOptionDB -TkResourceDB = TkOptionDB - -module TkTreatFont - def font_configinfo(name = nil) - ret = TkFont.used_on(self.path) - if ret == nil -=begin - if name - ret = name - else - ret = TkFont.init_widget_font(self.path, self.path, 'configure') - end -=end - ret = TkFont.init_widget_font(self.path, self.path, 'configure') - end - ret - end - alias fontobj font_configinfo - - def font_configure(slot) - slot = _symbolkey2str(slot) - - if slot.key?('font') - fnt = slot.delete('font') - if fnt.kind_of? TkFont - return fnt.call_font_configure(self.path, self.path,'configure',slot) - else - if fnt - if (slot.key?('kanjifont') || - slot.key?('latinfont') || - slot.key?('asciifont')) - fnt = TkFont.new(fnt) - - lfnt = slot.delete('latinfont') - lfnt = slot.delete('asciifont') if slot.key?('asciifont') - kfnt = slot.delete('kanjifont') - - fnt.latin_replace(lfnt) if lfnt - fnt.kanji_replace(kfnt) if kfnt - else - slot['font'] = fnt - tk_call(self.path, 'configure', *hash_kv(slot)) - end - end - return self - end - end - - lfnt = slot.delete('latinfont') - lfnt = slot.delete('asciifont') if slot.key?('asciifont') - kfnt = slot.delete('kanjifont') - - if lfnt && kfnt - return TkFont.new(lfnt, kfnt).call_font_configure(self.path, self.path, - 'configure', slot) - end - - latinfont_configure(lfnt) if lfnt - kanjifont_configure(kfnt) if kfnt - - tk_call(self.path, 'configure', *hash_kv(slot)) if slot != {} - self - end - - def latinfont_configure(ltn, keys=nil) - if (fobj = TkFont.used_on(self.path)) - fobj = TkFont.new(fobj) # create a new TkFont object - elsif Tk::JAPANIZED_TK - fobj = fontobj # create a new TkFont object - else - tk_call(self.path, 'configure', '-font', ltn) - return self - end - - if fobj.kind_of?(TkFont) - if ltn.kind_of? TkFont - conf = {} - ltn.latin_configinfo.each{|key,val| conf[key] = val} - if keys - fobj.latin_configure(conf.update(keys)) - else - fobj.latin_configure(conf) - end - else - fobj.latin_replace(ltn) - end - end - - return fobj.call_font_configure(self.path, self.path, 'configure', {}) - end - alias asciifont_configure latinfont_configure - - def kanjifont_configure(knj, keys=nil) - if (fobj = TkFont.used_on(self.path)) - fobj = TkFont.new(fobj) # create a new TkFont object - elsif Tk::JAPANIZED_TK - fobj = fontobj # create a new TkFont object - else - tk_call(self.path, 'configure', '-font', knj) - return self - end - - if fobj.kind_of?(TkFont) - if knj.kind_of? TkFont - conf = {} - knj.kanji_configinfo.each{|key,val| conf[key] = val} - if keys - fobj.kanji_configure(conf.update(keys)) - else - fobj.kanji_configure(conf) - end - else - fobj.kanji_replace(knj) - end - end - - return fobj.call_font_configure(self.path, self.path, 'configure', {}) - end - - def font_copy(window, tag=nil) - if tag - fnt = window.tagfontobj(tag).dup - else - fnt = window.fontobj.dup - end - fnt.call_font_configure(self.path, self.path, 'configure', {}) - self - end - - def latinfont_copy(window, tag=nil) - fontobj.dup.call_font_configure(self.path, self.path, 'configure', {}) - if tag - fontobj.latin_replace(window.tagfontobj(tag).latin_font_id) - else - fontobj.latin_replace(window.fontobj.latin_font_id) - end - self - end - alias asciifont_copy latinfont_copy - - def kanjifont_copy(window, tag=nil) - fontobj.dup.call_font_configure(self.path, self.path, 'configure', {}) - if tag - fontobj.kanji_replace(window.tagfontobj(tag).kanji_font_id) - else - fontobj.kanji_replace(window.fontobj.kanji_font_id) - end - self - end -end - -module TkTreatItemFont - def __conf_cmd(idx) - raise NotImplementedError, "need to define `__conf_cmd'" - end - def __item_pathname(tagOrId) - raise NotImplementedError, "need to define `__item_pathname'" - end - private :__conf_cmd, :__item_pathname - - def tagfont_configinfo(tagOrId, name = nil) - pathname = __item_pathname(tagOrId) - ret = TkFont.used_on(pathname) - if ret == nil -=begin - if name - ret = name - else - ret = TkFont.init_widget_font(pathname, self.path, - __conf_cmd(0), __conf_cmd(1), tagOrId) - end -=end - ret = TkFont.init_widget_font(pathname, self.path, - __conf_cmd(0), __conf_cmd(1), tagOrId) - end - ret - end - alias tagfontobj tagfont_configinfo - - def tagfont_configure(tagOrId, slot) - pathname = __item_pathname(tagOrId) - slot = _symbolkey2str(slot) - - if slot.key?('font') - fnt = slot.delete('font') - if fnt.kind_of? TkFont - return fnt.call_font_configure(pathname, self.path, - __conf_cmd(0), __conf_cmd(1), - tagOrId, slot) - else - if fnt - if (slot.key?('kanjifont') || - slot.key?('latinfont') || - slot.key?('asciifont')) - fnt = TkFont.new(fnt) - - lfnt = slot.delete('latinfont') - lfnt = slot.delete('asciifont') if slot.key?('asciifont') - kfnt = slot.delete('kanjifont') - - fnt.latin_replace(lfnt) if lfnt - fnt.kanji_replace(kfnt) if kfnt - end - - slot['font'] = fnt - tk_call(self.path, __conf_cmd(0), __conf_cmd(1), - tagOrId, *hash_kv(slot)) - end - return self - end - end - - lfnt = slot.delete('latinfont') - lfnt = slot.delete('asciifont') if slot.key?('asciifont') - kfnt = slot.delete('kanjifont') - - if lfnt && kfnt - return TkFont.new(lfnt, kfnt).call_font_configure(pathname, self.path, - __conf_cmd(0), - __conf_cmd(1), - tagOrId, slot) - end - - latintagfont_configure(tagOrId, lfnt) if lfnt - kanjitagfont_configure(tagOrId, kfnt) if kfnt - - tk_call(self.path, __conf_cmd(0), __conf_cmd(1), - tagOrId, *hash_kv(slot)) if slot != {} - self - end - - def latintagfont_configure(tagOrId, ltn, keys=nil) - pathname = __item_pathname(tagOrId) - if (fobj = TkFont.used_on(pathname)) - fobj = TkFont.new(fobj) # create a new TkFont object - elsif Tk::JAPANIZED_TK - fobj = tagfontobj(tagOrId) # create a new TkFont object - else - tk_call(self.path, __conf_cmd(0), __conf_cmd(1), tagOrId, '-font', ltn) - return self - end - - if fobj.kind_of?(TkFont) - if ltn.kind_of? TkFont - conf = {} - ltn.latin_configinfo.each{|key,val| conf[key] = val} - if keys - fobj.latin_configure(conf.update(keys)) - else - fobj.latin_configure(conf) - end - else - fobj.latin_replace(ltn) - end - end - - return fobj.call_font_configure(pathname, self.path, - __conf_cmd(0), __conf_cmd(1), tagOrId, {}) - end - alias asciitagfont_configure latintagfont_configure - - def kanjitagfont_configure(tagOrId, knj, keys=nil) - pathname = __item_pathname(tagOrId) - if (fobj = TkFont.used_on(pathname)) - fobj = TkFont.new(fobj) # create a new TkFont object - elsif Tk::JAPANIZED_TK - fobj = tagfontobj(tagOrId) # create a new TkFont object - else - tk_call(self.path, __conf_cmd(0), __conf_cmd(1), tagOrId, '-font', knj) - return self - end - - if fobj.kind_of?(TkFont) - if knj.kind_of? TkFont - conf = {} - knj.kanji_configinfo.each{|key,val| conf[key] = val} - if keys - fobj.kanji_configure(conf.update(keys)) - else - fobj.kanji_configure(conf) - end - else - fobj.kanji_replace(knj) - end - end - - return fobj.call_font_configure(pathname, self.path, - __conf_cmd(0), __conf_cmd(1), tagOrId, {}) - end - - def tagfont_copy(tagOrId, window, wintag=nil) - pathname = __item_pathname(tagOrId) - if wintag - fnt = window.tagfontobj(wintag).dup - else - fnt = window.fontobj.dup - end - fnt.call_font_configure(pathname, self.path, - __conf_cmd(0), __conf_cmd(1), tagOrId, {}) - return self - end - - def latintagfont_copy(tagOrId, window, wintag=nil) - pathname = __item_pathname(tagOrId) - tagfontobj(tagOrId).dup.call_font_configure(pathname, self.path, - __conf_cmd(0), __conf_cmd(1), - tagOrId, {}) - if wintag - tagfontobj(tagOrId). - latin_replace(window.tagfontobj(wintag).latin_font_id) - else - tagfontobj(tagOrId).latin_replace(window.fontobj.latin_font_id) - end - self - end - alias asciitagfont_copy latintagfont_copy - - def kanjitagfont_copy(tagOrId, window, wintag=nil) - pathname = __item_pathname(tagOrId) - tagfontobj(tagOrId).dup.call_font_configure(pathname, self.path, - __conf_cmd(0), __conf_cmd(1), - tagOrId, {}) - if wintag - tagfontobj(tagOrId). - kanji_replace(window.tagfontobj(wintag).kanji_font_id) - else - tagfontobj(tagOrId).kanji_replace(window.fontobj.kanji_font_id) - end - self - end -end - -class TkObject 0 - tk_call path, 'configure', *hash_kv(slot) - end - - else - if (slot == 'font' || slot == :font || - slot == 'kanjifont' || slot == :kanjifont || - slot == 'latinfont' || slot == :latinfont || - slot == 'asciifont' || slot == :asciifont ) - if value == None - fontobj - else - font_configure({slot=>value}) - end - else - tk_call path, 'configure', "-#{slot}", value - end - end - self - end - - def configure_cmd(slot, value) - configure slot, install_cmd(value) - end - - def configinfo(slot = nil) - if slot == 'font' || slot == :font || - slot == 'kanjifont' || slot == :kanjifont - conf = tk_split_simplelist(tk_send('configure', "-#{slot}") ) - conf[0] = conf[0][1..-1] - conf[4] = fontobj(conf[4]) - conf - else - if slot - case slot.to_s - when 'text', 'label', 'show', 'data', 'file' - conf = tk_split_simplelist(tk_send('configure', "-#{slot}") ) - else - conf = tk_split_list(tk_send('configure', "-#{slot}") ) - end - conf[0] = conf[0][1..-1] - conf - else - ret = tk_split_simplelist(tk_send('configure') ).collect{|conflist| - conf = tk_split_simplelist(conflist) - conf[0] = conf[0][1..-1] - case conf[0] - when 'text', 'label', 'show', 'data', 'file' - else - if conf[3] - if conf[3].index('{') - conf[3] = tk_split_list(conf[3]) - else - conf[3] = tk_tcl2ruby(conf[3]) - end - end - if conf[4] - if conf[4].index('{') - conf[4] = tk_split_list(conf[4]) - else - conf[4] = tk_tcl2ruby(conf[4]) - end - end - end - conf - } - fontconf = ret.assoc('font') - if fontconf - ret.delete_if{|item| item[0] == 'font' || item[0] == 'kanjifont'} - fontconf[4] = fontobj(fontconf[4]) - ret.push(fontconf) - else - ret - end - end - end - end - - def event_generate(context, keys=nil) - if keys - tk_call('event', 'generate', path, - "<#{tk_event_sequence(context)}>", *hash_kv(keys)) - else - tk_call('event', 'generate', path, "<#{tk_event_sequence(context)}>") - end - end - - def tk_trace_variable(v) - unless v.kind_of?(TkVariable) - fail(ArgumentError, - Kernel.format("type error (%s); must be TkVariable object", - v.class)) - end - v - end - private :tk_trace_variable - - def destroy - # tk_call 'trace', 'vdelete', @tk_vn, 'w', @var_id if @var_id - end -end - -class TkWindowtarget} - end - tk_call 'pack', epath, *hash_kv(keys) - self - end - - def unpack - tk_call 'pack', 'forget', epath - self - end - alias pack_forget unpack - - def pack_config(slot, value=None) - if slot.kind_of? Hash - tk_call 'pack', 'configure', epath, *hash_kv(slot) - else - tk_call 'pack', 'configure', epath, "-#{slot}", value - end - end - - def pack_info() - ilist = list(tk_call('pack', 'info', epath)) - info = {} - while key = ilist.shift - info[key[1..-1]] = ilist.shift - end - return info - end - - def pack_propagate(mode=None) - if mode == None - bool(tk_call('pack', 'propagate', epath)) - else - tk_call('pack', 'propagate', epath, mode) - self - end - end - - def pack_slaves() - list(tk_call('pack', 'slaves', epath)) - end - - def grid(keys = nil) - tk_call 'grid', epath, *hash_kv(keys) - self - end - - def grid_in(target, keys = nil) - if keys - keys = keys.dup - keys['in'] = target - else - keys = {'in'=>target} - end - tk_call 'grid', epath, *hash_kv(keys) - self - end - - def ungrid - tk_call 'grid', 'forget', epath - self - end - alias grid_forget ungrid - - def grid_bbox(*args) - list(tk_call('grid', 'bbox', epath, *args)) - end - - def grid_config(slot, value=None) - if slot.kind_of? Hash - tk_call 'grid', 'configure', epath, *hash_kv(slot) - else - tk_call 'grid', 'configure', epath, "-#{slot}", value - end - end - - def grid_columnconfig(index, keys) - tk_call('grid', 'columnconfigure', epath, index, *hash_kv(keys)) - end - - def grid_rowconfig(index, keys) - tk_call('grid', 'rowconfigure', epath, index, *hash_kv(keys)) - end - - def grid_columnconfiginfo(index, slot=nil) - if slot - tk_call('grid', 'columnconfigure', epath, index, "-#{slot}").to_i - else - ilist = list(tk_call('grid', 'columnconfigure', epath, index)) - info = {} - while key = ilist.shift - info[key[1..-1]] = ilist.shift - end - info - end - end - - def grid_rowconfiginfo(index, slot=nil) - if slot - tk_call('grid', 'rowconfigure', epath, index, "-#{slot}").to_i - else - ilist = list(tk_call('grid', 'rowconfigure', epath, index)) - info = {} - while key = ilist.shift - info[key[1..-1]] = ilist.shift - end - info - end - end - - def grid_info() - list(tk_call('grid', 'info', epath)) - end - - def grid_location(x, y) - list(tk_call('grid', 'location', epath, x, y)) - end - - def grid_propagate(mode=None) - if mode == None - bool(tk_call('grid', 'propagate', epath)) - else - tk_call('grid', 'propagate', epath, mode) - self - end - end - - def grid_remove() - tk_call 'grid', 'remove', epath - self - end - - def grid_size() - list(tk_call('grid', 'size', epath)) - end - - def grid_slaves(args) - list(tk_call('grid', 'slaves', epath, *hash_kv(args))) - end - - def place(keys = nil) - tk_call 'place', epath, *hash_kv(keys) - self - end - - def place_in(target, keys = nil) - if keys - keys = keys.dup - keys['in'] = target - else - keys = {'in'=>target} - end - tk_call 'place', epath, *hash_kv(keys) - self - end - - def unplace - tk_call 'place', 'forget', epath - self - end - alias place_forget unplace - - def place_config(slot, value=None) - if slot.kind_of? Hash - tk_call 'place', 'configure', epath, *hash_kv(slot) - else - tk_call 'place', 'configure', epath, "-#{slot}", value - end - end - - def place_configinfo(slot = nil) - # for >= Tk8.4a2 ? - if slot - conf = tk_split_list(tk_call('place', 'configure', epath, "-#{slot}") ) - conf[0] = conf[0][1..-1] - conf - else - tk_split_simplelist(tk_call('place', - 'configure', epath)).collect{|conflist| - conf = tk_split_simplelist(conflist) - conf[0] = conf[0][1..-1] - conf - } - end - end - - def place_info() - ilist = list(tk_call('place', 'info', epath)) - info = {} - while key = ilist.shift - info[key[1..-1]] = ilist.shift - end - return info - end - - def place_slaves() - list(tk_call('place', 'slaves', epath)) - end - - def focus(force=false) - if force - tk_call 'focus', '-force', path - else - tk_call 'focus', path - end - self - end - - def grab(*args) - if !args or args.length == 0 - tk_call 'grab', 'set', path - self - elsif args.length == 1 - case args[0] - when 'global', :global - #return(tk_call('grab', 'set', '-global', path)) - tk_call('grab', 'set', '-global', path) - return self - when 'release', :release - #return tk_call('grab', 'release', path) - tk_call('grab', 'release', path) - return self - else - val = tk_call('grab', args[0], path) - end - case args[0] - when 'current', :current - return window(val) - when 'status', :status - return val - end - self - else - fail ArgumentError, 'wrong # of args' - end - end - - def grab_current - grab('current') - end - def grab_release - grab('release') - end - def grab_set - grab('set') - end - def grab_set_global - grab('global') - end - def grab_status - grab('status') - end - - def lower(below=None) - tk_call 'lower', epath, below - self - end - def raise(above=None) - tk_call 'raise', epath, above - self - end - - def command(cmd=Proc.new) - configure_cmd 'command', cmd - end - - def colormodel model=None - tk_call 'tk', 'colormodel', path, model - self - end - - def caret(keys=nil) - TkXIM.caret(path, keys) - end - - def destroy - super - children = [] - rexp = /^#{self.path}\.[^.]+$/ - TkCore::INTERP.tk_windows.each{|path, obj| - children << [path, obj] if path =~ rexp - } - if defined?(@cmdtbl) - for id in @cmdtbl - uninstall_cmd id - end - end - - children.each{|path, obj| - if defined?(@cmdtbl) - for id in @cmdtbl - uninstall_cmd id - end - end - TkCore::INTERP.tk_windows.delete(path) - } - - begin - tk_call 'destroy', epath - rescue - end - uninstall_win - end - - def wait_visibility(on_thread = true) - if $SAFE >= 4 - fail SecurityError, "can't wait visibility at $SAFE >= 4" - end - if on_thread - INTERP._thread_tkwait('visibility', path) - else - INTERP._invoke('tkwait', 'visibility', path) - end - end - def eventloop_wait_visibility - wait_visibility(false) - end - def thread_wait_visibility - wait_visibility(true) - end - alias wait wait_visibility - alias tkwait wait_visibility - alias eventloop_wait eventloop_wait_visibility - alias eventloop_tkwait eventloop_wait_visibility - alias eventloop_tkwait_visibility eventloop_wait_visibility - alias thread_wait thread_wait_visibility - alias thread_tkwait thread_wait_visibility - alias thread_tkwait_visibility thread_wait_visibility - - def wait_destroy(on_thread = true) - if $SAFE >= 4 - fail SecurityError, "can't wait destroy at $SAFE >= 4" - end - if on_thread - INTERP._thread_tkwait('window', epath) - else - INTERP._invoke('tkwait', 'window', epath) - end - end - def eventloop_wait_destroy - wait_destroy(false) - end - def thread_wait_destroy - wait_destroy(true) - end - alias tkwait_destroy wait_destroy - alias eventloop_tkwait_destroy eventloop_wait_destroy - alias thread_tkwait_destroy thread_wait_destroy - - def bindtags(taglist=nil) - if taglist - fail ArgumentError, "taglist must be Array" unless taglist.kind_of? Array - tk_call('bindtags', path, taglist) - taglist - else - list(tk_call('bindtags', path)).collect{|tag| - if tag.kind_of?(String) - if cls = WidgetClassNames[tag] - cls - elsif btag = TkBindTag.id2obj(tag) - btag - else - tag - end - else - tag - end - } - end - end - - def bindtags=(taglist) - bindtags(taglist) - end - - def bindtags_shift - taglist = bindtags - tag = taglist.shift - bindtags(taglist) - tag - end - - def bindtags_unshift(tag) - bindtags(bindtags().unshift(tag)) - end -end - -class TkRoottrue, :widgetname=>'.') - if keys # wm commands - keys.each{|k,v| - if v.kind_of? Array - new.send(k,*v) - else - new.send(k,v) - end - } - end - ROOT[0] = new - Tk_WINDOWS["."] = new - end -=end - def TkRoot.new(keys=nil, &b) - unless TkCore::INTERP.tk_windows['.'] - TkCore::INTERP.tk_windows['.'] = - super(:without_creating=>true, :widgetname=>'.') - end - root = TkCore::INTERP.tk_windows['.'] - if keys # wm commands - keys.each{|k,v| - if v.kind_of? Array - root.send(k,*v) - else - root.send(k,v) - end - } - end - root.instance_eval(&b) if block_given? - root - end - - WidgetClassName = 'Tk'.freeze - WidgetClassNames[WidgetClassName] = self - - def create_self - @path = '.' - end - private :create_self - - def path - "." - end - - def TkRoot.destroy - TkCore::INTERP._invoke('destroy', '.') - end -end - -class TkToplevelparent} - end - end - if keys.key?('classname') - keys['class'] = keys.delete('classname') - end - @classname = keys['class'] - @colormap = keys['colormap'] - @container = keys['container'] - @visual = keys['visual'] - if !@classname && my_class_name - keys['class'] = @classname = my_class_name - end - if @classname.kind_of? TkBindTag - @db_class = @classname - @classname = @classname.id - elsif @classname - @db_class = TkDatabaseClass.new(@classname) - else - @db_class = self.class - @classname = @db_class::WidgetClassName - end - super(keys) - end - - def create_self(keys) - if keys and keys != None - tk_call 'frame', @path, *hash_kv(keys) - else - tk_call 'frame', @path - end - end - private :create_self - - def database_classname - @classname - end - - def self.database_class - if self == WidgetClassNames[WidgetClassName] || self.name == '' - self - else - TkDatabaseClass.new(self.name) - end - end - def self.database_classname - self.database_class.name - end - - def self.bind(*args) - if self == WidgetClassNames[WidgetClassName] || self.name == '' - super(*args) - else - TkDatabaseClass.new(self.name).bind(*args) - end - end - def self.bind_append(*args) - if self == WidgetClassNames[WidgetClassName] || self.name == '' - super(*args) - else - TkDatabaseClass.new(self.name).bind_append(*args) - end - end - def self.bind_remove(*args) - if self == WidgetClassNames[WidgetClassName] || self.name == '' - super(*args) - else - TkDatabaseClass.new(self.name).bind_remove(*args) - end - end - def self.bindinfo(*args) - if self == WidgetClassNames[WidgetClassName] || self.name == '' - super(*args) - else - TkDatabaseClass.new(self.name).bindinfo(*args) - end - end -end - -class TkLabelFramevalue) - end - - def configure(slot, value=None) - if (slot == 'command' || slot == :command) - configure('command'=>value) - elsif slot.kind_of?(Hash) && - (slot.key?('command') || slot.key?(:command)) - slot = _symbolkey2str(slot) - slot['command'] = _wrap_command_arg(slot.delete('command')) - end - super(slot, value) - end - - def command(cmd=Proc.new) - configure('command'=>cmd) - end - - def get(x=None, y=None) - number(tk_send('get', x, y)) - end - - def coords(val=None) - tk_split_list(tk_send('coords', val)) - end - - def identify(x, y) - tk_send('identify', x, y) - end - - def set(val) - tk_send("set", val) - end - - def value - get - end - - def value= (val) - set(val) - end -end - -class TkScrollbar 0 + tk_call(path, 'configure', *hash_kv(slot)) end else - if (key == 'font' || key == :font || - key == 'kanjifont' || key == :kanjifont || - key == 'latinfont' || key == :latinfont || - key == 'asciifont' || key == :asciifont ) - if val == None - tagfontobj(index) + if (slot == 'font' || slot == :font || + slot == 'kanjifont' || slot == :kanjifont || + slot == 'latinfont' || slot == :latinfont || + slot == 'asciifont' || slot == :asciifont ) + if value == None + fontobj else - tagfont_configure(index, {key=>val}) + font_configure({slot=>value}) end else - tk_call 'itemconfigure', index, "-#{key}", val + tk_call(path, 'configure', "-#{slot}", value) end end self end - def itemconfiginfo(index, key=nil) - if key - case key.to_s - when 'text', 'label', 'show' - conf = tk_split_simplelist(tk_send('itemconfigure',index,"-#{key}")) - when 'font', 'kanjifont' - conf = tk_split_simplelist(tk_send('itemconfigure',index,"-#{key}") ) - conf[4] = tagfont_configinfo(index, conf[4]) - else - conf = tk_split_list(tk_send('itemconfigure',index,"-#{key}")) - end - conf[0] = conf[0][1..-1] - conf - else - ret = tk_split_simplelist(tk_send('itemconfigure', - index)).collect{|conflist| - conf = tk_split_simplelist(conflist) + def configure_cmd(slot, value) + configure(slot, install_cmd(value)) + end + + def configinfo(slot = nil) + if TkComm::GET_CONFIGINFO_AS_ARRAY + if slot == 'font' || slot == :font || + slot == 'kanjifont' || slot == :kanjifont + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('configure', "-#{slot}"))) conf[0] = conf[0][1..-1] - case conf[0] - when 'text', 'label', 'show' + conf[4] = fontobj(conf[4]) + conf + else + if slot + case slot.to_s + when 'text', 'label', 'show', 'data', 'file' + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('configure', "-#{slot}"))) + else + conf = tk_split_list(_fromUTF8(tk_send_without_enc('configure', "-#{slot}"))) + end + conf[0] = conf[0][1..-1] + conf else - if conf[3] - if conf[3].index('{') - conf[3] = tk_split_list(conf[3]) + ret = tk_split_simplelist(_fromUTF8(tk_send_without_enc('configure'))).collect{|conflist| + conf = tk_split_simplelist(conflist) + conf[0] = conf[0][1..-1] + case conf[0] + when 'text', 'label', 'show', 'data', 'file' else - conf[3] = tk_tcl2ruby(conf[3]) + if conf[3] + if conf[3].index('{') + conf[3] = tk_split_list(conf[3]) + else + conf[3] = tk_tcl2ruby(conf[3]) + end + end + if conf[4] + if conf[4].index('{') + conf[4] = tk_split_list(conf[4]) + else + conf[4] = tk_tcl2ruby(conf[4]) + end + end end + conf[1] = conf[1][1..-1] if conf.size == 2 # alias info + conf + } + fontconf = ret.assoc('font') + if fontconf + ret.delete_if{|item| item[0] == 'font' || item[0] == 'kanjifont'} + fontconf[4] = fontobj(fontconf[4]) + ret.push(fontconf) + else + ret + end + end + end + else # ! TkComm::GET_CONFIGINFO_AS_ARRAY + if slot == 'font' || slot == :font || + slot == 'kanjifont' || slot == :kanjifont + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('configure', "-#{slot}"))) + key = conf.shift[1..-1] + conf[3] = fontobj(conf[3]) + { key => conf } + else + if slot + case slot.to_s + when 'text', 'label', 'show', 'data', 'file' + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('configure', "-#{slot}"))) + else + conf = tk_split_list(_fromUTF8(tk_send_without_enc('configure', "-#{slot}"))) end - if conf[4] - if conf[4].index('{') - conf[4] = tk_split_list(conf[4]) + key = conf.shift[1..-1] + { key => conf } + else + ret = {} + tk_split_simplelist(_fromUTF8(tk_send_without_enc('configure'))).each{|conflist| + conf = tk_split_simplelist(conflist) + key = conf.shift[1..-1] + case key + when 'text', 'label', 'show', 'data', 'file' + else + if conf[2] + if conf[2].index('{') + conf[2] = tk_split_list(conf[2]) + else + conf[2] = tk_tcl2ruby(conf[2]) + end + end + if conf[3] + if conf[3].index('{') + conf[3] = tk_split_list(conf[3]) + else + conf[3] = tk_tcl2ruby(conf[3]) + end + end + end + if conf.size == 1 + ret[key] = conf[0][1..-1] # alias info else - conf[4] = tk_tcl2ruby(conf[4]) + ret[key] = conf end + } + fontconf = ret['font'] + if fontconf + ret.delete('font') + ret.delete('kanjifont') + fontconf[3] = fontobj(fontconf[3]) + ret['font'] = fontconf end + ret end - conf - } - fontconf = ret.assoc('font') - if fontconf - ret.delete_if{|item| item[0] == 'font' || item[0] == 'kanjifont'} - fontconf[4] = tagfont_configinfo(index, fontconf[4]) - ret.push(fontconf) + end + end + end + + def current_configinfo(slot = nil) + if TkComm::GET_CONFIGINFO_AS_ARRAY + if slot + conf = configinfo(slot) + {conf[0] => conf[4]} else + ret = {} + configinfo().each{|conf| + ret[conf[0]] = conf[4] if conf.size > 2 + } ret end + else # ! TkComm::GET_CONFIGINFO_AS_ARRAY + ret = {} + configinfo(slot).each{|key, conf| + ret[key] = conf[-1] if conf.kind_of?(Array) + } + ret end end -end - -module TkTreatMenuEntryFont - include TkTreatItemFont - ItemCMD = ['entryconfigure'.freeze, TkComm::None].freeze - def __conf_cmd(idx) - ItemCMD[idx] + def event_generate(context, keys=nil) + if keys + #tk_call('event', 'generate', path, + # "<#{tk_event_sequence(context)}>", *hash_kv(keys)) + tk_call_without_enc('event', 'generate', path, + "<#{tk_event_sequence(context)}>", + *hash_kv(keys, true)) + else + #tk_call('event', 'generate', path, "<#{tk_event_sequence(context)}>") + tk_call_without_enc('event', 'generate', path, + "<#{tk_event_sequence(context)}>") + end end - - def __item_pathname(tagOrId) - self.path + ';' + tagOrId.to_s + + def tk_trace_variable(v) + unless v.kind_of?(TkVariable) + fail(ArgumentError, "type error (#{v.class}); must be TkVariable object") + end + v end + private :tk_trace_variable - private :__conf_cmd, :__item_pathname + def destroy + tk_call 'trace', 'vdelete', @tk_vn, 'w', @var_id if @var_id + end end -class TkMenutarget} + end + #tk_call 'pack', epath, *hash_kv(keys) + TkPack.configure(self, keys) self end - def postcommand(cmd=Proc.new) - configure_cmd 'postcommand', cmd + + def pack_forget + #tk_call_without_enc('pack', 'forget', epath) + TkPack.forget(self) self end - def set_focus - tk_call('tk_menuSetFocus', path) - end - def tearoffcommand(cmd=Proc.new) - configure_cmd 'tearoffcommand', cmd - self + alias unpack pack_forget + + def pack_config(slot, value=None) + #if slot.kind_of? Hash + # tk_call 'pack', 'configure', epath, *hash_kv(slot) + #else + # tk_call 'pack', 'configure', epath, "-#{slot}", value + #end + if slot.kind_of? Hash + TkPack.configure(self, slot) + else + TkPack.configure(self, slot=>value) + end end - def menutype(index) - tk_send 'type', index + + def pack_info() + #ilist = list(tk_call('pack', 'info', epath)) + #info = {} + #while key = ilist.shift + # info[key[1..-1]] = ilist.shift + #end + #return info + TkPack.info(self) end - def unpost - tk_send 'unpost' + + def pack_propagate(mode=None) + #if mode == None + # bool(tk_call('pack', 'propagate', epath)) + #else + # tk_call('pack', 'propagate', epath, mode) + # self + #end + if mode == None + TkPack.propagate(self) + else + TkPack.propagate(self, mode) + self + end end - def yposition(index) - number(tk_send('yposition', index)) + + def pack_slaves() + #list(tk_call('pack', 'slaves', epath)) + TkPack.slaves(self) end - def entrycget(index, key) - case key.to_s - when 'text', 'label', 'show' - tk_send 'entrycget', index, "-#{key}" - when 'font', 'kanjifont' - #fnt = tk_tcl2ruby(tk_send('entrycget', index, "-#{key}")) - fnt = tk_tcl2ruby(tk_send('entrycget', index, '-font')) - unless fnt.kind_of?(TkFont) - fnt = tagfontobj(index, fnt) - end - if key.to_s == 'kanjifont' && JAPANIZED_TK && TK_VERSION =~ /^4\.*/ - # obsolete; just for compatibility - fnt.kanji_font - else - fnt - end + + def grid(keys = nil) + #tk_call 'grid', epath, *hash_kv(keys) + if keys + TkGrid.configure(self, keys) else - tk_tcl2ruby(tk_send('entrycget', index, "-#{key}")) + TkGrid.configure(self) end + self end - def entryconfigure(index, key, val=None) - if key.kind_of? Hash - 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 + def grid_in(target, keys = nil) + if keys + keys = keys.dup + keys['in'] = target else - if (key == 'font' || key == :font || - key == 'kanjifont' || key == :kanjifont || - key == 'latinfont' || key == :latinfont || - key == 'asciifont' || key == :asciifont ) - if val == None - tagfontobj(index) - else - tagfont_configure(index, {key=>val}) - end - else - tk_call 'entryconfigure', index, "-#{key}", val - end + keys = {'in'=>target} end + #tk_call 'grid', epath, *hash_kv(keys) + TkGrid.configure(self, keys) self end - def entryconfiginfo(index, key=nil) - if key - case key.to_s - when 'text', 'label', 'show' - conf = tk_split_simplelist(tk_send('entryconfigure',index,"-#{key}")) - when 'font', 'kanjifont' - conf = tk_split_simplelist(tk_send('entryconfigure',index,"-#{key}")) - conf[4] = tagfont_configinfo(index, conf[4]) - else - conf = tk_split_list(tk_send('entryconfigure',index,"-#{key}")) - end - conf[0] = conf[0][1..-1] - conf - else - ret = tk_split_simplelist(tk_send('entryconfigure', - index)).collect{|conflist| - conf = tk_split_simplelist(conflist) - conf[0] = conf[0][1..-1] - case conf[0] - when 'text', 'label', 'show' - else - if conf[3] - if conf[3].index('{') - conf[3] = tk_split_list(conf[3]) - else - conf[3] = tk_tcl2ruby(conf[3]) - end - end - if conf[4] - if conf[4].index('{') - conf[4] = tk_split_list(conf[4]) - else - conf[4] = tk_tcl2ruby(conf[4]) - end - end - end - conf - } - if fontconf - ret.delete_if{|item| item[0] == 'font' || item[0] == 'kanjifont'} - fontconf[4] = tagfont_configinfo(index, fontconf[4]) - ret.push(fontconf) - else - ret - end - end + def grid_forget + #tk_call('grid', 'forget', epath) + TkGrid.forget(self) + self end -end + alias ungrid grid_forget -class TkMenuClonevalue) end end -end -class TkSysMenu_Help return value of tk_optionMenu - @path = path - #TkComm::Tk_WINDOWS[@path] = self - TkCore::INTERP.tk_windows[@path] = self - end + def grid_size() + #list(tk_call('grid', 'size', epath)) + TkGrid.size(self) 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 'variable option must be TkVariable' unless var.kind_of? TkVariable - @variable = var - firstval = @variable.value unless firstval - @variable.value = firstval - install_win(if parent then parent.path end) - @menu = OptionMenu.new(tk_call('tk_optionMenu', @path, @variable.id, - firstval, *vals)) + def grid_slaves(args) + #list(tk_call('grid', 'slaves', epath, *hash_kv(args))) + TkGrid.slaves(self, args) end - def value - @variable.value + def place(keys) + #tk_call 'place', epath, *hash_kv(keys) + TkPlace.configure(self, keys) + self end - def activate(index) - @menu.activate(index) + def place_in(target, keys = nil) + if keys + keys = keys.dup + keys['in'] = target + else + keys = {'in'=>target} + end + #tk_call 'place', epath, *hash_kv(keys) + TkPlace.configure(self, keys) self end - def add(value) - @menu.add('radiobutton', 'variable'=>@variable, - 'label'=>value, 'value'=>value) + + def place_forget + #tk_call 'place', 'forget', epath + TkPlace.forget(self) self end - def index(index) - @menu.index(index) + alias unplace place_forget + + def place_config(slot, value=None) + #if slot.kind_of? Hash + # tk_call 'place', 'configure', epath, *hash_kv(slot) + #else + # tk_call 'place', 'configure', epath, "-#{slot}", value + #end + TkPlace.configure(self, slot, value) + end + + def place_configinfo(slot = nil) + # for >= Tk8.4a2 ? + #if slot + # conf = tk_split_list(tk_call('place', 'configure', epath, "-#{slot}") ) + # conf[0] = conf[0][1..-1] + # conf + #else + # tk_split_simplelist(tk_call('place', + # 'configure', epath)).collect{|conflist| + # conf = tk_split_simplelist(conflist) + # conf[0] = conf[0][1..-1] + # conf + # } + #end + TkPlace.configinfo(slot) end - def invoke(index) - @menu.invoke(index) + + def place_info() + #ilist = list(tk_call('place', 'info', epath)) + #info = {} + #while key = ilist.shift + # info[key[1..-1]] = ilist.shift + #end + #return info + TkPlace.info(self) end - def insert(index, value) - @menu.add(index, 'radiobutton', 'variable'=>@variable, - 'label'=>value, 'value'=>value) - self + + def place_slaves() + #list(tk_call('place', 'slaves', epath)) + TkPlace.slaves(self) end - def delete(index, last=None) - @menu.delete(index, last) + + def set_focus(force=false) + if force + tk_call_without_enc('focus', '-force', path) + else + tk_call_without_enc('focus', path) + end self end - def yposition(index) - @menu.yposition(index) + alias focus set_focus + + def grab(opt = nil) + unless opt + tk_call_without_enc('grab', 'set', path) + return self + end + + case opt + when 'global', :global + #return(tk_call('grab', 'set', '-global', path)) + tk_call_without_enc('grab', 'set', '-global', path) + return self + when 'release', :release + #return tk_call('grab', 'release', path) + tk_call_without_enc('grab', 'release', path) + return self + when 'current', :current + return window(tk_call_without_enc('grab', 'current', path)) + when 'status', :status + return tk_call_without_enc('grab', 'status', path) + else + return tk_call_without_enc('grab', args[0], path) + end end - def menu - @menu + + def grab_current + grab('current') end - def menucget(key) - @menu.cget(key) + def grab_release + grab('release') end - def menuconfigure(key, val=None) - @menu.configure(key, val) - self + def grab_set + grab('set') end - def menuconfiginfo(key=nil) - @menu.configinfo(key) + def grab_set_global + grab('global') end - def entrycget(index, key) - @menu.entrycget(index, key) + def grab_status + grab('status') end - def entryconfigure(index, key, val=None) - @menu.entryconfigure(index, key, val) + + def lower(below=None) + # below = below.epath if below.kind_of?(TkObject) + below = _epath(below) + tk_call 'lower', epath, below self end - def entryconfiginfo(index, key=nil) - @menu.entryconfiginfo(index, key) + def raise(above=None) + #above = above.epath if above.kind_of?(TkObject) + above = _epath(above) + tk_call 'raise', epath, above + self end -end - -module TkComposite - include Tk - extend Tk - def initialize(parent=nil, *args) - @delegates = {} - - if parent.kind_of? Hash - keys = _symbolkey2str(parent) - parent = keys.delete('parent') - @frame = TkFrame.new(parent) - @delegates['DEFAULT'] = @frame - @path = @epath = @frame.path - initialize_composite(keys) + def command(cmd=nil, &b) + if cmd + configure_cmd('command', cmd) + elsif b + configure_cmd('command', Proc.new(&b)) else - @frame = TkFrame.new(parent) - @delegates['DEFAULT'] = @frame - @path = @epath = @frame.path - initialize_composite(*args) + cget('command') end end - def epath - @epath + def colormodel(model=None) + tk_call('tk', 'colormodel', path, model) + self end - def initialize_composite(*args) end - private :initialize_composite + def caret(keys=nil) + TkXIM.caret(path, keys) + end - def delegate(option, *wins) - if @delegates[option].kind_of?(Array) - for i in wins - @delegates[option].push(i) + def destroy + super + children = [] + rexp = /^#{self.path}\.[^.]+$/ + TkCore::INTERP.tk_windows.each{|path, obj| + children << [path, obj] if path =~ rexp + } + if defined?(@cmdtbl) + for id in @cmdtbl + uninstall_cmd id end - else - @delegates[option] = wins end - end - def configure(slot, value=None) - if slot.kind_of? Hash - slot.each{|slot,value| configure slot, value} - else - if @delegates and @delegates[slot] - for i in @delegates[slot] - if not i - i = @delegates['DEFALUT'] - redo - else - last = i.configure(slot, value) - end + children.each{|path, obj| + if defined?(@cmdtbl) + for id in @cmdtbl + uninstall_cmd id end - last - else - super end + TkCore::INTERP.tk_windows.delete(path) + } + + begin + tk_call_without_enc('destroy', epath) + rescue end + uninstall_win end -end -module TkClipboard - include Tk - extend Tk - - TkCommandNames = ['clipboard'.freeze].freeze - - def self.clear(win=nil) - if win - tk_call 'clipboard', 'clear', '-displayof', win + def wait_visibility(on_thread = true) + if $SAFE >= 4 + fail SecurityError, "can't wait visibility at $SAFE >= 4" + end + on_thread &= (Thread.list.size != 1) + if on_thread + INTERP._thread_tkwait('visibility', path) else - tk_call 'clipboard', 'clear' + INTERP._invoke('tkwait', 'visibility', path) end end - def self.clear_on_display(win) - tk_call 'clipboard', 'clear', '-displayof', win + def eventloop_wait_visibility + wait_visibility(false) + end + def thread_wait_visibility + wait_visibility(true) end + alias wait wait_visibility + alias tkwait wait_visibility + alias eventloop_wait eventloop_wait_visibility + alias eventloop_tkwait eventloop_wait_visibility + alias eventloop_tkwait_visibility eventloop_wait_visibility + alias thread_wait thread_wait_visibility + alias thread_tkwait thread_wait_visibility + alias thread_tkwait_visibility thread_wait_visibility - def self.get(type=nil) - if type - tk_call 'clipboard', 'get', '-type', type - else - tk_call 'clipboard', 'get' + def wait_destroy(on_thread = true) + if $SAFE >= 4 + fail SecurityError, "can't wait destroy at $SAFE >= 4" end - end - def self.get_on_display(win, type=nil) - if type - tk_call 'clipboard', 'get', '-displayof', win, '-type', type + on_thread &= (Thread.list.size != 1) + if on_thread + INTERP._thread_tkwait('window', epath) else - tk_call 'clipboard', 'get', '-displayof', win + INTERP._invoke('tkwait', 'window', epath) end end - - def self.set(data, keys=nil) - clear - append(data, keys) + def eventloop_wait_destroy + wait_destroy(false) end - def self.set_on_display(win, data, keys=nil) - clear(win) - append_on_display(win, data, keys) + def thread_wait_destroy + wait_destroy(true) end + alias tkwait_destroy wait_destroy + alias eventloop_tkwait_destroy eventloop_wait_destroy + alias thread_tkwait_destroy thread_wait_destroy - def self.append(data, keys=nil) - args = ['clipboard', 'append'] - args += hash_kv(keys) - args += ['--', data] - tk_call(*args) - end - def self.append_on_display(win, data, keys=nil) - args = ['clipboard', 'append', '-displayof', win] - args += hash_kv(keys) - args += ['--', data] - tk_call(*args) + def bindtags(taglist=nil) + if taglist + fail ArgumentError, "taglist must be Array" unless taglist.kind_of? Array + tk_call('bindtags', path, taglist) + taglist + else + list(tk_call('bindtags', path)).collect{|tag| + if tag.kind_of?(String) + if cls = WidgetClassNames[tag] + cls + elsif btag = TkBindTag.id2obj(tag) + btag + else + tag + end + else + tag + end + } + end end - def clear - TkClipboard.clear_on_display(self) - self - end - def get(type=nil) - TkClipboard.get_on_display(self, type) + def bindtags=(taglist) + bindtags(taglist) + taglist end - def set(data, keys=nil) - TkClipboard.set_on_display(self, data, keys) - self + + def bindtags_shift + taglist = bindtags + tag = taglist.shift + bindtags(taglist) + tag end - def append(data, keys=nil) - TkClipboard.append_on_display(self, data, keys) - self + + def bindtags_unshift(tag) + bindtags(bindtags().unshift(tag)) end end -# widget_destroy_hook -require 'tkvirtevent' -TkBindTag::ALL.bind(TkVirtualEvent.new('Destroy'), proc{|xpath| - path = xpath[1..-1] - if (widget = TkCore::INTERP.tk_windows[path]) - if widget.respond_to?(:__destroy_hook__) - begin - widget.__destroy_hook__ - rescue Exception - end - end - end - }, 'x%W') # freeze core modules #TclTkLib.freeze @@ -5916,27 +2817,11 @@ TkBindTag::ALL.bind(TkVirtualEvent.new('Destroy'), proc{|xpath| #TkCore.freeze #Tk.freeze -# autoload -autoload :TkCanvas, 'tkcanvas' -autoload :TkImage, 'tkcanvas' -autoload :TkBitmapImage, 'tkcanvas' -autoload :TkPhotoImage, 'tkcanvas' -autoload :TkEntry, 'tkentry' -autoload :TkSpinbox, 'tkentry' -autoload :TkText, 'tktext' -autoload :TkDialog, 'tkdialog' -autoload :TkDialog2, 'tkdialog' -autoload :TkWarning, 'tkdialog' -autoload :TkWarning2, 'tkdialog' -autoload :TkMenubar, 'tkmenubar' -autoload :TkAfter, 'tkafter' -autoload :TkTimer, 'tkafter' -autoload :TkPalette, 'tkpalette' -autoload :TkFont, 'tkfont' -autoload :TkBgError, 'tkbgerror' -autoload :TkManageFocus, 'tkmngfocus' -autoload :TkPalette, 'tkpalette' -autoload :TkWinDDE, 'tkwinpkg' -autoload :TkWinRegistry, 'tkwinpkg' -autoload :TkMacResource, 'tkmacpkg' -autoload :TkConsole, 'tkconsole' +module Tk + autoload :AUTO_PATH, 'tk/variable' + autoload :TCL_PACKAGE_PATH, 'tk/variable' + autoload :PACKAGE_PATH, 'tk/variable' + autoload :TCL_LIBRARY_PATH, 'tk/variable' + autoload :LIBRARY_PATH, 'tk/variable' + autoload :TCL_PRECISION, 'tk/variable' +end diff --git a/ext/tk/lib/tkafter.rb b/ext/tk/lib/tkafter.rb index 53e78b880..f65945884 100644 --- a/ext/tk/lib/tkafter.rb +++ b/ext/tk/lib/tkafter.rb @@ -1,414 +1,4 @@ # -# tkafter.rb : methods for Tcl/Tk after command +# tkafter.rb - load tk/after.rb # -# $Id$ -# -require 'tk' - -class TkTimer - include TkCore - extend TkCore - - TkCommandNames = ['after'.freeze].freeze - - Tk_CBID = ['a'.freeze, '00000'.taint].freeze - Tk_CBTBL = {}.taint - - TkCore::INTERP.add_tk_procs('rb_after', 'id', <<-'EOL') - if {[set st [catch {ruby [format "TkTimer.callback %%Q!%s!" $id]} ret]] != 0} { - return -code $st $ret - } { - return $ret - } - EOL - - - ############################### - # class methods - ############################### - def self.callback(obj_id) - @after_id = nil - ex_obj = Tk_CBTBL[obj_id] - return "" if ex_obj == nil; # canceled - ex_obj.cb_call - end - - def self.info - tk_call('after', 'info').split(' ').collect!{|id| - ret = Tk_CBTBL.find{|key,val| val.after_id == id} - (ret == nil)? id: ret[1] - } - end - - ############################### - # instance methods - ############################### - def do_callback - @in_callback = true - begin - @return_value = @current_proc.call(self) - rescue Exception => e - if @cancel_on_exception - cancel - @return_value = e - return e - else - fail e - end - end - if @set_next - set_next_callback(@current_args) - else - @set_next = true - end - @in_callback = false - @return_value - end - - def set_callback(sleep, args=nil) - @after_script = "rb_after #{@id}" - @after_id = tk_call('after', sleep, @after_script) - @current_args = args - @current_script = [sleep, @after_script] - self - end - - def set_next_callback(args) - if @running == false || @proc_max == 0 || @do_loop == 0 - Tk_CBTBL.delete(@id) ;# for GC - @running = false - @wait_var.value = 0 - return - end - if @current_pos >= @proc_max - if @do_loop < 0 || (@do_loop -= 1) > 0 - @current_pos = 0 - else - Tk_CBTBL.delete(@id) ;# for GC - @running = false - @wait_var.value = 0 - return - end - end - - @current_args = args - - if @sleep_time.kind_of? Proc - sleep = @sleep_time.call(self) - else - sleep = @sleep_time - end - @current_sleep = sleep - - cmd, *cmd_args = @loop_proc[@current_pos] - @current_pos += 1 - @current_proc = cmd - - set_callback(sleep, cmd_args) - end - - def initialize(*args) - @id = Tk_CBID.join - Tk_CBID[1].succ! - - @wait_var = TkVariable.new(0) - - @cb_cmd = TkCore::INTERP.get_cb_entry(self.method(:do_callback)) - - @set_next = true - - @init_sleep = 0 - @init_proc = nil - @init_args = [] - - @current_script = [] - @current_proc = nil - @current_args = nil - @return_value = nil - - @sleep_time = 0 - @current_sleep = 0 - @loop_exec = 0 - @do_loop = 0 - @loop_proc = [] - @proc_max = 0 - @current_pos = 0 - - @after_id = nil - @after_script = nil - - @cancel_on_exception = true - - set_procs(*args) if args != [] - - @running = false - @in_callback = false - end - - 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 - - def cb_call - @cb_cmd.call - end - - def get_procs - [@init_sleep, @init_proc, @init_args, @sleep_time, @loop_exec, @loop_proc] - end - - def current_status - [@running, @current_sleep, @current_proc, @current_args, - @do_loop, @cancel_on_exception] - end - - def cancel_on_exception? - @cancel_on_exception - end - - def cancel_on_exception=(mode) - @cancel_on_exception = mode - self - end - - def running? - @running - end - - def loop_rest - @do_loop - end - - def loop_rest=(rest) - @do_loop = rest - self - end - - def set_procs(interval, loop_exec, *procs) - if !interval == 'idle' \ - && !interval.kind_of?(Integer) && !interval.kind_of?(Proc) - fail Kernel.format("%s need to be Integer or Proc", interval.inspect) - end - @sleep_time = interval - - @loop_proc = [] - procs.each{|e| - if e.kind_of? Proc - @loop_proc.push([e]) - else - @loop_proc.push(e) - end - } - @proc_max = @loop_proc.size - @current_pos = 0 - - @do_loop = 0 - if loop_exec - if loop_exec.kind_of?(Integer) && loop_exec < 0 - @loop_exec = -1 - elsif loop_exec == nil || loop_exec == false || loop_exec == 0 - @loop_exec = 1 - else - if not loop_exec.kind_of?(Integer) - fail Kernel.format("%s need to be Integer", loop_exec.inspect) - end - @loop_exec = loop_exec - end - @do_loop = @loop_exec - end - - self - end - - def add_procs(*procs) - procs.each{|e| - if e.kind_of? Proc - @loop_proc.push([e]) - else - @loop_proc.push(e) - end - } - @proc_max = @loop_proc.size - - self - end - - def delete_procs(*procs) - procs.each{|e| - if e.kind_of? Proc - @loop_proc.delete([e]) - else - @loop_proc.delete(e) - end - } - @proc_max = @loop_proc.size - - cancel if @proc_max == 0 - - self - end - - def delete_at(n) - @loop_proc.delete_at(n) - @proc_max = @loop_proc.size - cancel if @proc_max == 0 - self - end - - def set_start_proc(sleep, init_proc, *init_args) - if !sleep == 'idle' && !sleep.kind_of?(Integer) - fail Kernel.format("%s need to be Integer", sleep.inspect) - end - @init_sleep = sleep - @init_proc = init_proc - @init_args = init_args - self - end - - def start(*init_args) - return nil if @running - - Tk_CBTBL[@id] = self - @do_loop = @loop_exec - @current_pos = 0 - - argc = init_args.size - if argc > 0 - sleep = init_args.shift - if !sleep == 'idle' && !sleep.kind_of?(Integer) - fail Kernel.format("%s need to be Integer", sleep.inspect) - end - @init_sleep = sleep - end - @init_proc = init_args.shift if argc > 1 - @init_args = init_args if argc > 0 - - @current_sleep = @init_sleep - @running = true - if @init_proc - if not @init_proc.kind_of? Proc - fail Kernel.format("%s need to be Proc", @init_proc.inspect) - end - @current_proc = @init_proc - set_callback(@init_sleep, @init_args) - @set_next = false if @in_callback - else - set_next_callback(@init_args) - end - - self - end - - def reset(*reset_args) - restart() if @running - - if @init_proc - @return_value = @init_proc.call(self) - else - @return_value = nil - end - - @current_pos = 0 - @current_args = @init_args - @set_next = false if @in_callback - - self - end - - def restart(*restart_args) - cancel if @running - if restart_args == [] - start(@init_sleep, @init_proc, *@init_args) - else - start(*restart_args) - end - end - - def cancel - @running = false - @wait_var.value = 0 - tk_call 'after', 'cancel', @after_id if @after_id - @after_id = nil - Tk_CBTBL.delete(@id) ;# for GC - self - end - alias stop cancel - - def continue(wait=nil) - fail RuntimeError, "is already running" if @running - sleep, cmd = @current_script - fail RuntimeError, "no procedure to continue" unless cmd - if wait - if not wait.kind_of? Integer - fail RuntimeError, Kernel.format("%s need to be Integer", wait.inspect) - end - sleep = wait - end - Tk_CBTBL[@id] = self - @running = true - @after_id = tk_call('after', sleep, cmd) - self - end - - def skip - fail RuntimeError, "is not running now" unless @running - cancel - Tk_CBTBL[@id] = self - @running = true - set_next_callback(@current_args) - self - end - - def info - if @after_id - inf = tk_split_list(tk_call('after', 'info', @after_id)) - [Tk_CBTBL[inf[0][1]], inf[1]] - else - nil - end - end - - def wait(on_thread = true, check_root = false) - if $SAFE >= 4 - fail SecurityError, "can't wait timer at $SAFE >= 4" - end - - unless @running - if @return_value.kind_of?(Exception) - fail @return_value - else - return @return_value - end - end - - @wait_var.wait(on_thread, check_root) - if @return_value.kind_of?(Exception) - fail @return_value - else - @return_value - end - end - def eventloop_wait(check_root = false) - wait(false, check_root) - end - def thread_wait(check_root = false) - wait(true, check_root) - end - def tkwait(on_thread = true) - wait(on_thread, true) - end - def eventloop_tkwait - wait(false, true) - end - def thread_tkwait - wait(true, true) - end -end - -TkAfter = TkTimer +require 'tk/timer' diff --git a/ext/tk/lib/tkbgerror.rb b/ext/tk/lib/tkbgerror.rb index 760a3901b..deba7a57f 100644 --- a/ext/tk/lib/tkbgerror.rb +++ b/ext/tk/lib/tkbgerror.rb @@ -1,29 +1,4 @@ # -# tkbgerror -- bgerror ( tkerror ) module -# 1998/07/16 by Hidetoshi Nagai +# tkbgerror.rb - load tk/bgerror.rb # -require 'tk' - -module TkBgError - extend Tk - - TkCommandNames = ['bgerror'.freeze].freeze - - def bgerror(message) - tk_call 'bgerror', message - end - alias tkerror bgerror - alias show bgerror - module_function :bgerror, :tkerror, :show - - def set_handler(hdlr = Proc.new) #==> handler :: proc{|msg| ...body... } - tk_call('proc', 'bgerror', 'msg', install_cmd(hdlr) + ' $msg') - end - def set_default - begin - tk_call('rename', 'bgerror', '') - rescue RuntimeError - end - end - module_function :set_handler, :set_default -end +require 'tk/bgerror' diff --git a/ext/tk/lib/tkcanvas.rb b/ext/tk/lib/tkcanvas.rb index ccb02c056..952461429 100644 --- a/ext/tk/lib/tkcanvas.rb +++ b/ext/tk/lib/tkcanvas.rb @@ -1,1021 +1,4 @@ # -# tkcanvas.rb - Tk canvas classes -# $Date$ -# by Yukihiro Matsumoto -# $Date$ -# by Hidetoshi Nagai - -require "tk" -require 'tkfont' - -module TkTreatCItemFont - include TkTreatItemFont - - ItemCMD = ['itemconfigure'.freeze, TkComm::None].freeze - def __conf_cmd(idx) - ItemCMD[idx] - end - - def __item_pathname(tagOrId) - if tagOrId.kind_of?(TkcItem) || tagOrId.kind_of?(TkcTag) - self.path + ';' + tagOrId.id.to_s - else - self.path + ';' + tagOrId.to_s - end - end - - private :__conf_cmd, :__item_pathname -end - -class TkCanvasvalue}) - end - else - tk_send 'itemconfigure', tagid(tagOrId), "-#{key}", value - end - end - self - end -# def itemconfigure(tagOrId, key, value=None) -# if key.kind_of? Hash -# tk_send 'itemconfigure', tagid(tagOrId), *hash_kv(key) -# else -# tk_send 'itemconfigure', tagid(tagOrId), "-#{key}", value -# end -# end -# def itemconfigure(tagOrId, keys) -# tk_send 'itemconfigure', tagid(tagOrId), *hash_kv(keys) -# end - - def itemconfiginfo(tagOrId, key=nil) - if key - case key.to_s - when 'dash', 'activedash', 'disableddash' - conf = tk_split_simplelist(tk_send('itemconfigure', - tagid(tagOrId), "-#{key}")) - if conf[3] && conf[3] =~ /^[0-9]/ - conf[3] = list(conf[3]) - end - if conf[4] && conf[4] =~ /^[0-9]/ - conf[4] = list(conf[4]) - end - when 'text', 'label', 'show', 'data', 'file', 'maskdata', 'maskfile' - conf = tk_split_simplelist(tk_send('itemconfigure', - tagid(tagOrId), "-#{key}")) - when 'font', 'kanjifont' - conf = tk_split_simplelist(tk_send('itemconfigure', - tagid(tagOrId),"-#{key}") ) - conf[4] = tagfont_configinfo(tagid(tagOrId), conf[4]) - else - conf = tk_split_list(tk_send('itemconfigure', - tagid(tagOrId), "-#{key}")) - end - conf[0] = conf[0][1..-1] - conf - else - ret = tk_split_simplelist(tk_send('itemconfigure', - tagid(tagOrId))).collect{|conflist| - conf = tk_split_simplelist(conflist) - conf[0] = conf[0][1..-1] - case conf[0] - when 'text', 'label', 'show', 'data', 'file', 'maskdata', 'maskfile' - when 'dash', 'activedash', 'disableddash' - if conf[3] && conf[3] =~ /^[0-9]/ - conf[3] = list(conf[3]) - end - if conf[4] && conf[4] =~ /^[0-9]/ - conf[4] = list(conf[4]) - end - else - if conf[3] - if conf[3].index('{') - conf[3] = tk_split_list(conf[3]) - else - conf[3] = tk_tcl2ruby(conf[3]) - end - end - if conf[4] - if conf[4].index('{') - conf[4] = tk_split_list(conf[4]) - else - conf[4] = tk_tcl2ruby(conf[4]) - end - end - end - conf - } - fontconf = ret.assoc('font') - if fontconf - ret.delete_if{|item| item[0] == 'font' || item[0] == 'kanjifont'} - fontconf[4] = tagfont_configinfo(tagid(tagOrId), fontconf[4]) - ret.push(fontconf) - else - ret - end - end - end - - def lower(tag, below=None) - tk_send 'lower', tagid(tag), tagid(below) - self - end - - def move(tag, x, y) - tk_send 'move', tagid(tag), x, y - self - end - - def postscript(keys) - tk_send "postscript", *hash_kv(keys) - end - - def raise(tag, above=None) - tk_send 'raise', tagid(tag), tagid(above) - self - end - - def scale(tag, x, y, xs, ys) - tk_send 'scale', tagid(tag), x, y, xs, ys - self - end - - def scan_mark(x, y) - tk_send 'scan', 'mark', x, y - self - end - def scan_dragto(x, y) - tk_send 'scan', 'dragto', x, y - self - end - - def select(mode, *args) - r = tk_send('select', mode, *args) - (mode == 'item')? TkcItem.id2obj(self, r): self - end - def select_adjust(tagOrId, index) - select('adjust', tagid(tagOrId), index) - end - def select_clear - select('clear') - end - def select_from(tagOrId, index) - select('from', tagid(tagOrId), index) - end - def select_item - select('item') - end - def select_to(tagOrId, index) - select('to', tagid(tagOrId), index) - end - - def itemtype(tag) - TkcItem.type2class(tk_send('type', tagid(tag))) - end -end - -module TkcTagAccess - include TkComm - include TkTreatTagFont - - def addtag(tag) - @c.addtag(tag, 'with', @id) - self - end - - def bbox - @c.bbox(@id) - end - - def bind(seq, cmd=Proc.new, args=nil) - @c.itembind @id, seq, cmd, args - self - end - - def bind_append(seq, cmd=Proc.new, args=nil) - @c.itembind_append @id, seq, cmd, args - self - end - - def bind_remove(seq) - @c.itembind_remove @id, seq - self - end - - def bindinfo(seq=nil) - @c.itembindinfo @id, seq - end - - def cget(option) - @c.itemcget @id, option - end - - def configure(key, value=None) - @c.itemconfigure @id, key, value - self - end -# def configure(keys) -# @c.itemconfigure @id, keys -# end - - def configinfo(key=nil) - @c.itemconfiginfo @id, key - end - - def coords(*args) - @c.coords @id, *args - end - - def dchars(first, last=None) - @c.dchars @id, first, last - self - end - - def dtag(tag_to_del=None) - @c.dtag @id, tag_to_del - self - end - - def find - @c.find 'withtag', @id - end - alias list find - - def focus - @c.itemfocus @id - end - - def gettags - @c.gettags @id - end - - def icursor(index) - @c.icursor @id, index - self - end - - def index(index) - @c.index @id, index - end - - def insert(beforethis, string) - @c.insert @id, beforethis, string - self - end - - def lower(belowthis=None) - @c.lower @id, belowthis - self - end - - def move(xamount, yamount) - @c.move @id, xamount, yamount - self - end - - def raise(abovethis=None) - @c.raise @id, abovethis - self - end - - def scale(xorigin, yorigin, xscale, yscale) - @c.scale @id, xorigin, yorigin, xscale, yscale - self - end - - def select_adjust(index) - @c.select('adjust', @id, index) - self - end - def select_from(index) - @c.select('from', @id, index) - self - end - def select_to(index) - @c.select('to', @id, index) - self - end - - def itemtype - @c.itemtype @id - end - - # Following operators support logical expressions of canvas tags - # (for Tk8.3+). - # If tag1.path is 't1' and tag2.path is 't2', then - # ltag = tag1 & tag2; ltag.path => "(t1)&&(t2)" - # ltag = tag1 | tag2; ltag.path => "(t1)||(t2)" - # ltag = tag1 ^ tag2; ltag.path => "(t1)^(t2)" - # ltag = - tag1; ltag.path => "!(t1)" - def & (tag) - if tag.kind_of? TkObject - TkcTagString.new(@c, '(' + @id + ')&&(' + tag.path + ')') - else - TkcTagString.new(@c, '(' + @id + ')&&(' + tag.to_s + ')') - end - end - - def | (tag) - if tag.kind_of? TkObject - TkcTagString.new(@c, '(' + @id + ')||(' + tag.path + ')') - else - TkcTagString.new(@c, '(' + @id + ')||(' + tag.to_s + ')') - end - end - - def ^ (tag) - if tag.kind_of? TkObject - TkcTagString.new(@c, '(' + @id + ')^(' + tag.path + ')') - else - TkcTagString.new(@c, '(' + @id + ')^(' + tag.to_s + ')') - end - end - - def -@ - TkcTagString.new(@c, '!(' + @id + ')') - end -end - -class TkcTagvalue, ...} for the message text - return nil - end - def msgframe_config - # returns a Hash {option=>value, ...} for the message text frame - return nil - end - def bitmap - # returns a bitmap name or a bitmap file path - # (@ + path ; e.g. '@/usr/share/bitmap/sample.xbm') - return "info" - end - def bitmap_config - # returns nil or a Hash {option=>value, ...} for the bitmap - return nil - end - def default_button - # returns a default button's number or name - # if nil or null string, set no-default - return 0 - end - def buttons - #return "BUTTON1 BUTTON2" - return ["BUTTON1", "BUTTON2"] - end - def button_configs(num) - # returns nil / Proc / Array or Hash (see _set_button_config) - return nil - end - def btnframe_config - # returns nil or a Hash {option=>value, ...} for the button frame - return nil - end -end - - # -# TkDialog : with showing at initialize +# tkdialog.rb - load tk/dialog.rb # -class TkDialog < TkDialog2 - def self.show(*args) - self.new(*args) - end - - def initialize(*args) - super(*args) - show - end -end - - -# -# dialog for warning -# -class TkWarning2 < TkDialog2 - def initialize(parent = nil, mes = nil) - if !mes - if parent.kind_of? TkWindow - mes = "" - else - mes = parent.to_s - parent = nil - end - end - super(parent, :message=>mes) - end - - def show(mes = nil) - mes_bup = @message - @message = mes if mes - ret = super() - @message = mes_bup - ret - end - - ####### - private - - def title - return "WARNING"; - end - def bitmap - return "warning"; - end - def default_button - return 0; - end - def buttons - return "OK"; - end -end - -class TkWarning < TkWarning2 - def self.show(*args) - self.new(*args) - end - def initialize(*args) - super(*args) - show - end -end +require 'tk/dialog' diff --git a/ext/tk/lib/tkentry.rb b/ext/tk/lib/tkentry.rb index fe9a7b627..2dcfcab5d 100644 --- a/ext/tk/lib/tkentry.rb +++ b/ext/tk/lib/tkentry.rb @@ -1,292 +1,4 @@ # -# tkentry.rb - Tk entry classes -# $Date$ -# by Yukihiro Matsumoto - -require 'tk.rb' - -class TkEntry'Helvetica'.freeze, - 'size'=>-12, 'weight'=>'bold'.freeze} - #knj = 'k14' - #knj = '-misc-fixed-medium-r-normal--14-*-*-*-c-*-jisx0208.1983-0' - knj = '-*-fixed-bold-r-normal--12-*-*-*-c-*-jisx0208.1983-0' - when 'windows' - ltn = {'family'=>'MS Sans Serif'.freeze, 'size'=>8} - knj = 'mincho' - when 'macintosh' - ltn = 'system' - knj = 'mincho' - else # unknown - ltn = 'Helvetica' - knj = 'mincho' - end - end - rescue - ltn = 'Helvetica' - knj = 'mincho' - end - - else # not JAPANIZED_TK - begin - platform = tk_call('set', 'tcl_platform(platform)') - case platform - when 'unix' - ltn = {'family'=>'Helvetica'.freeze, - 'size'=>-12, 'weight'=>'bold'.freeze} - #knj = 'k14' - #knj = '-misc-fixed-medium-r-normal--14-*-*-*-c-*-jisx0208.1983-0' - knj = '-*-fixed-bold-r-normal--12-*-*-*-c-*-jisx0208.1983-0' - when 'windows' - ltn = {'family'=>'MS Sans Serif'.freeze, 'size'=>8} - knj = 'mincho' - when 'macintosh' - ltn = 'system' - knj = 'mincho' - else # unknown - ltn = 'Helvetica' - knj = 'mincho' - end - rescue - ltn = 'Helvetica' - knj = 'mincho' - end - - knj = ltn - end - - DEFAULT_LATIN_FONT_NAME = ltn.freeze - DEFAULT_KANJI_FONT_NAME = knj.freeze - - else # unknown version - DEFAULT_LATIN_FONT_NAME = 'Helvetica'.freeze - DEFAULT_KANJI_FONT_NAME = 'mincho'.freeze - - end - - if $DEBUG - print "default latin font = "; p DEFAULT_LATIN_FONT_NAME - print "default kanji font = "; p DEFAULT_KANJI_FONT_NAME - end - - - ################################### - class DescendantFont - def initialize(compound, type) - unless compound.kind_of?(TkFont) - fail ArgumentError, "a TkFont object is expected for the 1st argument" - end - @compound = compound - case type - when 'kanji', 'latin', 'ascii' - @type = type - else - fail ArgumentError, "unknown type '#{type}'" - end - end - - def dup - fail RuntimeError, "cannot dupulicate a descendant font" - end - def clone - fail RuntimeError, "cannot clone a descendant font" - end - - def to_eval - @compound.__send__(@type + '_font_id') - end - def font - @compound.__send__(@type + '_font_id') - end - - def [](slot) - @compound.__send__(@type + '_configinfo', slot) - end - def []=(slot, value=None) - @compound.__send__(@type + '_configure', slot, value) - end - - def method_missing(id, *args) - @compound.__send__(@type + '_' + id.id2name, *args) - end - end - - - ################################### - # class methods - ################################### - def TkFont.families(window=nil) - case (Tk::TK_VERSION) - when /^4\.*/ - ['fixed'] - - when /^8\.*/ - if window - tk_split_simplelist(tk_call('font', 'families', '-displayof', window)) - else - tk_split_simplelist(tk_call('font', 'families')) - end - end - end - - def TkFont.names - case (Tk::TK_VERSION) - when /^4\.*/ - r = ['fixed'] - r += ['a14', 'k14'] if JAPANIZED_TK - Tk_FontNameTBL.each_value{|obj| r.push(obj)} - r | [] - - when /^8\.*/ - tk_split_simplelist(tk_call('font', 'names')) - - end - end - - def TkFont.create_copy(font) - fail 'source-font must be a TkFont object' unless font.kind_of? TkFont - keys = {} - font.configinfo.each{|key,value| keys[key] = value } - TkFont.new(font.latin_font_id, font.kanji_font_id, keys) - end - - def TkFont.get_obj(name) - if name =~ /^(@font[0-9]+)(|c|l|k)$/ - Tk_FontNameTBL[$1] - else - nil - end - end - - def TkFont.init_widget_font(path, *args) - case (Tk::TK_VERSION) - when /^4\.*/ - conf = tk_split_simplelist(tk_call(*args)). - find_all{|prop| prop[0..5]=='-font ' || prop[0..10]=='-kanjifont '}. - collect{|prop| tk_split_simplelist(prop)} - if font_inf = conf.assoc('-font') - ltn = font_inf[4] - ltn = nil if ltn == [] - else - #ltn = nil - raise RuntimeError, "unknown option '-font'" - end - if font_inf = conf.assoc('-kanjifont') - knj = font_inf[4] - knj = nil if knj == [] - else - knj = nil - end - TkFont.new(ltn, knj).call_font_configure(path, *(args + [{}])) - - when /^8\.*/ - font_prop = tk_split_simplelist(tk_call(*args)).find{|prop| - prop[0..5] == '-font ' - } - unless font_prop - raise RuntimeError, "unknown option '-font'" - end - fnt = tk_split_simplelist(font_prop)[4] - if fnt == "" - TkFont.new(nil, nil).call_font_configure(path, *(args + [{}])) - else - begin - compound = tk_split_simplelist( - Hash[*tk_split_simplelist(tk_call('font', 'configure', - fnt))].collect{|key,value| - [key[1..-1], value] - }.assoc('compound')[1]) - rescue - compound = [] - end - if compound == [] - #TkFont.new(fnt, DEFAULT_KANJI_FONT_NAME) \ - #.call_font_configure(path, *(args + [{}])) - TkFont.new(fnt).call_font_configure(path, *(args + [{}])) - else - TkFont.new(compound[0], compound[1]) \ - .call_font_configure(path, *(args + [{}])) - end - end - end - end - - def TkFont.used_on(path=nil) - if path - Tk_FontUseTBL[path] - else - Tk_FontUseTBL.values | [] - end - end - - def TkFont.failsafe(font) - begin - if /^8\.*/ === Tk::TK_VERSION && JAPANIZED_TK - tk_call('font', 'failsafe', font) - end - rescue - end - end - - ################################### - # instance methods - ################################### - private - ################################### - def initialize(ltn=nil, knj=nil, keys=nil) - @id = Tk_FontID.join - Tk_FontID[1].succ! - Tk_FontNameTBL[@id] = self - - @latin_desscendant = nil - @kanji_desscendant = nil - - if knj.kind_of?(Hash) && !keys - keys = knj - knj = nil - end - - # compound font check - if Tk::TK_VERSION == '8.0' && JAPANIZED_TK - begin - compound = tk_split_simplelist(tk_call('font', 'configure', - ltn, '-compound')) - if knj == nil - if compound != [] - ltn, knj = compound - end - else - if compound != [] - ltn = compound[0] - end - compound = tk_split_simplelist(tk_call('font', 'configure', - knj, '-compound')) - if compound != [] - knj = compound[1] - end - end - rescue - end - end - - if ltn - knj = ltn if JAPANIZED_TK && !knj - else - ltn = DEFAULT_LATIN_FONT_NAME - knj = DEFAULT_KANJI_FONT_NAME if JAPANIZED_TK && !knj - end - - create_compoundfont(ltn, knj, keys) - end - - def _get_font_info_from_hash(font) - font = _symbolkey2str(font) - foundry = (info = font['foundry'] .to_s)? info: '*' - family = (info = font['family'] .to_s)? info: '*' - weight = (info = font['weight'] .to_s)? info: '*' - slant = (info = font['slant'] .to_s)? info: '*' - swidth = (info = font['swidth'] .to_s)? info: '*' - adstyle = (info = font['adstyle'] .to_s)? info: '*' - pixels = (info = font['pixels'] .to_s)? info: '*' - points = (info = font['points'] .to_s)? info: '*' - resx = (info = font['resx'] .to_s)? info: '*' - resy = (info = font['resy'] .to_s)? info: '*' - space = (info = font['space'] .to_s)? info: '*' - avgWidth = (info = font['avgWidth'].to_s)? info: '*' - charset = (info = font['charset'] .to_s)? info: '*' - encoding = (info = font['encoding'].to_s)? info: '*' - - [foundry, family, weight, slant, swidth, adstyle, - pixels, points, resx, resy, space, avgWidth, charset, encoding] - end - - def create_latinfont_tk4x(font) - if font.kind_of? Hash - @latinfont = '-' + _get_font_info_from_hash(font).join('-') + '-' - - elsif font.kind_of? Array - finfo = {} - finfo['family'] = font[0].to_s - if font[1] - fsize = font[1].to_s - if fsize != '0' && fsize =~ /^(|\+|-)([0-9]+)$/ - if $1 == '-' - finfo['pixels'] = $2 - else - finfo['points'] = $2 - end - else - finfo['points'] = '13' - end - end - font[2..-1].each{|style| - case (style) - when 'normal' - finfo['weight'] = style - when 'bold' - finfo['weight'] = style - when 'roman' - finfo['slant'] = 'r' - when 'italic' - finfo['slant'] = 'i' - end - } - - @latinfont = '-' + _get_font_info_from_hash(finfo).join('-') + '-' - - elsif font.kind_of? TkFont - @latinfont = font.latin_font - - else - if font - @latinfont = font - else - @latinfont = DEFAULT_LATIN_FONT_NAME - end - - end - end - - def create_kanjifont_tk4x(font) - unless JAPANIZED_TK - @kanjifont = "" - return - end - - if font.kind_of? Hash - @kanjifont = '-' + _get_font_info_from_hash(font).join('-') + '-' - - elsif font.kind_of? Array - finfo = {} - finfo['family'] = font[0].to_s - if font[1] - fsize = font[1].to_s - if fsize != '0' && fsize =~ /^(|\+|-)([0-9]+)$/ - if $1 == '-' - finfo['pixels'] = $2 - else - finfo['points'] = $2 - end - else - finfo['points'] = '13' - end - end - font[2..-1].each{|style| - case (style) - when 'normal' - finfo['weight'] = style - when 'bold' - finfo['weight'] = style - when 'roman' - finfo['slant'] = 'r' - when 'italic' - finfo['slant'] = 'i' - end - } - - @kanjifont = '-' + _get_font_info_from_hash(finfo).join('-') + '-' - elsif font.kind_of? TkFont - @kanjifont = font.kanji_font_id - else - if font - @kanjifont = font - else - @kanjifont = DEFAULT_KANJI_FONT_NAME - end - end - end - - def create_compoundfont_tk4x(ltn, knj, keys) - create_latinfont(ltn) - create_kanjifont(knj) - - if JAPANIZED_TK - @compoundfont = [[@latinfont], [@kanjifont]] - @fontslot = {'font'=>@latinfont, 'kanjifont'=>@kanjifont} - else - @compoundfont = @latinfont - @fontslot = {'font'=>@latinfont} - end - end - - def create_latinfont_tk8x(font) - @latinfont = @id + 'l' - - if JAPANIZED_TK - if font.kind_of? Hash - if font[:charset] || font['charset'] - tk_call('font', 'create', @latinfont, *hash_kv(font)) - else - tk_call('font', 'create', @latinfont, - '-charset', 'iso8859', *hash_kv(font)) - end - elsif font.kind_of? Array - tk_call('font', 'create', @latinfont, '-copy', array2tk_list(font)) - tk_call('font', 'configure', @latinfont, '-charset', 'iso8859') - elsif font.kind_of? TkFont - tk_call('font', 'create', @latinfont, '-copy', font.latin_font) - elsif font - tk_call('font', 'create', @latinfont, '-copy', font, - '-charset', 'iso8859') - else - tk_call('font', 'create', @latinfont, '-charset', 'iso8859') - end - else - if font.kind_of? Hash - tk_call('font', 'create', @latinfont, *hash_kv(font)) - else - keys = {} - if font.kind_of? Array - actual_core(array2tk_list(font)).each{|key,val| keys[key] = val} - elsif font.kind_of? TkFont - actual_core(font.latin_font).each{|key,val| keys[key] = val} - elsif font - actual_core(font).each{|key,val| keys[key] = val} - end - tk_call('font', 'create', @latinfont, *hash_kv(keys)) - end - - if font && @compoundfont - keys = {} - actual_core(@latinfont).each{|key,val| keys[key] = val} - tk_call('font', 'configure', @compoundfont, *hash_kv(keys)) - end - end - end - - def create_kanjifont_tk8x(font) - @kanjifont = @id + 'k' - - if JAPANIZED_TK - if font.kind_of? Hash - if font[:charset] || font['charset'] - tk_call('font', 'create', @kanjifont, *hash_kv(font)) - else - tk_call('font', 'create', @kanjifont, - '-charset', 'jisx0208.1983', *hash_kv(font)) - end - elsif font.kind_of? Array - tk_call('font', 'create', @kanjifont, '-copy', array2tk_list(font)) - tk_call('font', 'configure', @kanjifont, '-charset', 'jisx0208.1983') - elsif font.kind_of? TkFont - tk_call('font', 'create', @kanjifont, '-copy', font.kanji_font_id) - elsif font - tk_call('font', 'create', @kanjifont, '-copy', font, - '-charset', 'jisx0208.1983') - else - tk_call('font', 'create', @kanjifont, '-charset', 'jisx0208.1983') - end - # end of JAPANIZED_TK - - else - if font.kind_of? Hash - tk_call('font', 'create', @kanjifont, *hash_kv(font)) - else - keys = {} - if font.kind_of? Array - actual_core(array2tk_list(font)).each{|key,val| keys[key] = val} - elsif font.kind_of? TkFont - actual_core(font.kanji_font_id).each{|key,val| keys[key] = val} - elsif font - actual_core(font).each{|key,val| keys[key] = val} - end - tk_call('font', 'create', @kanjifont, *hash_kv(keys)) - end - - if font && @compoundfont - keys = {} - actual_core(@kanjifont).each{|key,val| keys[key] = val} - tk_call('font', 'configure', @compoundfont, *hash_kv(keys)) - end - end - end - - def create_compoundfont_tk8x(ltn, knj, keys) - create_latinfont(ltn) - create_kanjifont(knj) - - @compoundfont = @id + 'c' - if JAPANIZED_TK - unless keys - keys = {} - else - keys = keys.dup - end - if (tk_call('font', 'configure', @latinfont, '-underline') == '1' && - tk_call('font', 'configure', @kanjifont, '-underline') == '1' && - !keys.key?('underline')) - keys['underline'] = true - end - if (tk_call('font', 'configure', @latinfont, '-overstrike') == '1' && - tk_call('font', 'configure', @kanjifont, '-overstrike') == '1' && - !keys.key?('overstrike')) - keys['overstrike'] = true - end - - @fontslot = {'font'=>@compoundfont} - begin - tk_call('font', 'create', @compoundfont, - '-compound', [@latinfont, @kanjifont], *hash_kv(keys)) - rescue RuntimeError => e - if ltn == knj - if e.message =~ /kanji font .* specified/ - tk_call('font', 'delete', @latinfont) - create_latinfont(DEFAULT_LATIN_FONT_NAME) - opts = [] - Hash[*(tk_split_simplelist(tk_call('font', 'configure', - @kanjifont)))].each{|k,v| - case k - when '-size', '-weight', '-slant', '-underline', '-overstrike' - opts << k << v - end - } - tk_call('font', 'configure', @latinfont, *opts) - tk_call('font', 'create', @compoundfont, - '-compound', [@latinfont, @kanjifont], *hash_kv(keys)) - - elsif e.message =~ /ascii font .* specified/ - tk_call('font', 'delete', @kanjifont) - create_kanjifont(DEFAULT_KANJI_FONT_NAME) - opts = [] - Hash[*(tk_split_simplelist(tk_call('font', 'configure', - @latinfont)))].each{|k,v| - case k - when '-size', '-weight', '-slant', '-underline', '-overstrike' - opts << k << v - end - } - tk_call('font', 'configure', @kanjifont, *opts) - tk_call('font', 'create', @compoundfont, - '-compound', [@latinfont, @kanjifont], *hash_kv(keys)) - - else - raise e - end - else - raise e - end - end - else - tk_call('font', 'create', @compoundfont) - - latinkeys = {} - begin - actual_core(@latinfont).each{|key,val| latinkeys[key] = val} - rescue - latinkeys {} - end - if latinkeys != {} - tk_call('font', 'configure', @compoundfont, *hash_kv(latinkeys)) - end - - if knj - kanjikeys = {} - begin - actual_core(@kanjifont).each{|key,val| kanjikeys[key] = val} - rescue - kanjikeys {} - end - if kanjikeys != {} - tk_call('font', 'configure', @compoundfont, *hash_kv(kanjikeys)) - end - end - - @fontslot = {'font'=>@compoundfont} - tk_call('font', 'configure', @compoundfont, *hash_kv(keys)) - end - end - - def actual_core_tk4x(font, window=nil, option=nil) - # dummy - if option - "" - else - [['family',[]], ['size',[]], ['weight',[]], ['slant',[]], - ['underline',[]], ['overstrike',[]], ['charset',[]], - ['pointadjust',[]]] - end - end - - def actual_core_tk8x(font, window=nil, option=nil) - if option == 'compound' - "" - elsif option - if window - tk_call('font', 'actual', font, "-displayof", window, "-#{option}") - else - tk_call('font', 'actual', font, "-#{option}") - end - else - l = tk_split_simplelist(if window - tk_call('font', 'actual', font, - "-displayof", window) - else - tk_call('font', 'actual', font) - end) - r = [] - while key=l.shift - if key == '-compound' - l.shift - else - r.push [key[1..-1], l.shift] - end - end - r - end - end - - def configure_core_tk4x(font, slot, value=None) - #"" - self - end - - def configinfo_core_tk4x(font, option=nil) - # dummy - if option - "" - else - [['family',[]], ['size',[]], ['weight',[]], ['slant',[]], - ['underline',[]], ['overstrike',[]], ['charset',[]], - ['pointadjust',[]]] - end - end - - def configure_core_tk8x(font, slot, value=None) - if JAPANIZED_TK - begin - padjust = tk_call('font', 'configure', font, '-pointadjust') - rescue - padjust = nil - end - else - padjust = nil - end - if slot.kind_of? Hash - if JAPANIZED_TK && (slot.key?('family') || slot.key?(:family)) - slot = _symbolkey2str(slot) - configure_core_tk8x(font, 'family', slot.delete('family')) - end - - if ((slot.key?('size') || slot.key?(:size)) && - padjust && !slot.key?('pointadjust') && !slot.key?(:pointadjust)) - tk_call('font', 'configure', font, - '-pointadjust', padjust, *hash_kv(slot)) - else - tk_call('font', 'configure', font, *hash_kv(slot)) - end - elsif (slot == 'size' || slot == :size) && padjust != nil - tk_call('font', 'configure', font, - "-#{slot}", value, '-pointadjust', padjust) - elsif JAPANIZED_TK && (slot == 'family' || slot == :family) - # coumpund font? - begin - compound = tk_split_simplelist(tk_call('font', 'configure', - font, '-compound')) - rescue - tk_call('font', 'configure', font, '-family', value) - return self - end - if compound == [] - tk_call('font', 'configure', font, '-family', value) - return self - end - ltn, knj = compound - - lfnt = tk_call('font', 'create', '-copy', ltn) - begin - tk_call('font', 'configure', lfnt, '-family', value) - latin_replace_core_tk8x(lfnt) - rescue RuntimeError => e - fail e if $DEBUG - ensure - tk_call('font', 'delete', lfnt) if lfnt != '' - end - - kfnt = tk_call('font', 'create', '-copy', knj) - begin - tk_call('font', 'configure', kfnt, '-family', value) - kanji_replace_core_tk8x(lfnt) - rescue RuntimeError => e - fail e if $DEBUG - ensure - tk_call('font', 'delete', kfnt) if kfnt != '' - end - - else - tk_call('font', 'configure', font, "-#{slot}", value) - end - self - end - - def configinfo_core_tk8x(font, option=nil) - if option == 'compound' - "" - elsif option - tk_call('font', 'configure', font, "-#{option}") - else - l = tk_split_simplelist(tk_call('font', 'configure', font)) - r = [] - while key=l.shift - if key == '-compound' - l.shift - else - r.push [key[1..-1], l.shift] - end - end - r - end - end - - def delete_core_tk4x - Tk_FontNameTBL.delete(@id) - Tk_FontUseTBL.delete_if{|key,value| value == self} - end - - def delete_core_tk8x - begin - tk_call('font', 'delete', @latinfont) - rescue - end - begin - tk_call('font', 'delete', @kanjifont) - rescue - end - begin - tk_call('font', 'delete', @compoundfont) - rescue - end - Tk_FontNameTBL.delete(@id) - Tk_FontUseTBL.delete_if{|key,value| value == self} - end - - def latin_replace_core_tk4x(ltn) - create_latinfont_tk4x(ltn) - @compoundfont[0] = [@latinfont] if JAPANIZED_TK - @fontslot['font'] = @latinfont - Tk_FontUseTBL.dup.each{|w, fobj| - if self == fobj - begin - if w.include?(';') - win, tag = w.split(';') - winobj = tk_tcl2ruby(win) -# winobj.tagfont_configure(tag, {'font'=>@latinfont}) - if winobj.kind_of? TkText - tk_call(win, 'tag', 'configure', tag, '-font', @latinfont) - elsif winobj.kind_of? TkCanvas - tk_call(win, 'itemconfigure', tag, '-font', @latinfont) - elsif winobj.kind_of? TkMenu - tk_call(win, 'entryconfigure', tag, '-font', @latinfont) - else - raise RuntimeError, "unknown widget type" - end - else -# tk_tcl2ruby(w).font_configure('font'=>@latinfont) - tk_call(w, 'configure', '-font', @latinfont) - end - rescue - Tk_FontUseTBL.delete(w) - end - end - } - self - end - - def kanji_replace_core_tk4x(knj) - return self unless JAPANIZED_TK - - create_kanjifont_tk4x(knj) - @compoundfont[1] = [@kanjifont] - @fontslot['kanjifont'] = @kanjifont - Tk_FontUseTBL.dup.each{|w, fobj| - if self == fobj - begin - if w.include?(';') - win, tag = w.split(';') - winobj = tk_tcl2ruby(win) -# winobj.tagfont_configure(tag, {'kanjifont'=>@kanjifont}) - if winobj.kind_of? TkText - tk_call(win, 'tag', 'configure', tag, '-kanjifont', @kanjifont) - elsif winobj.kind_of? TkCanvas - tk_call(win, 'itemconfigure', tag, '-kanjifont', @kanjifont) - elsif winobj.kind_of? TkMenu - tk_call(win, 'entryconfigure', tag, '-kanjifont', @latinfont) - else - raise RuntimeError, "unknown widget type" - end - else -# tk_tcl2ruby(w).font_configure('kanjifont'=>@kanjifont) - tk_call(w, 'configure', '-kanjifont', @kanjifont) - end - rescue - Tk_FontUseTBL.delete(w) - end - end - } - self - end - - def latin_replace_core_tk8x(ltn) - if JAPANIZED_TK - begin - tk_call('font', 'delete', '@font_tmp') - rescue - end - begin - fnt_bup = tk_call('font', 'create', '@font_tmp', '-copy', @latinfont) - rescue - #fnt_bup = '' - fnt_bup = DEFAULT_LATIN_FONT_NAME - end - end - - begin - tk_call('font', 'delete', @latinfont) - rescue - end - create_latinfont(ltn) - - if JAPANIZED_TK - keys = self.configinfo - tk_call('font', 'delete', @compoundfont) - begin - tk_call('font', 'create', @compoundfont, - '-compound', [@latinfont, @kanjifont], *hash_kv(keys)) -=begin - latinkeys = {} - begin - actual_core(@latinfont).each{|key,val| latinkeys[key] = val} - rescue - latinkeys {} - end - if latinkeys != {} - tk_call('font', 'configure', @compoundfont, *hash_kv(latinkeys)) - end -=end - rescue RuntimeError => e - tk_call('font', 'delete', @latinfont) - if fnt_bup && fnt_bup != '' - tk_call('font', 'create', @latinfont, '-copy', fnt_bup) - tk_call('font', 'create', @compoundfont, - '-compound', [@latinfont, @kanjifont], *hash_kv(keys)) - tk_call('font', 'delete', fnt_bup) - else - fail e - end - end - - else - latinkeys = {} - begin - actual_core(@latinfont).each{|key,val| latinkeys[key] = val} - rescue - latinkeys {} - end - if latinkeys != {} - tk_call('font', 'configure', @compoundfont, *hash_kv(latinkeys)) - end - end - self - end - - def kanji_replace_core_tk8x(knj) - if JAPANIZED_TK - begin - tk_call('font', 'delete', '@font_tmp') - rescue - end - begin - fnt_bup = tk_call('font', 'create', '@font_tmp', '-copy', @kanjifont) - rescue - #fnt_bup = '' - fnt_bup = DEFAULT_KANJI_FONT_NAME - end - end - - begin - tk_call('font', 'delete', @kanjifont) - rescue - end - create_kanjifont(knj) - - if JAPANIZED_TK - keys = self.configinfo - tk_call('font', 'delete', @compoundfont) - begin - tk_call('font', 'create', @compoundfont, - '-compound', [@latinfont, @kanjifont], *hash_kv(keys)) - rescue RuntimeError => e - tk_call('font', 'delete', @kanjifont) - if fnt_bup && fnt_bup != '' - tk_call('font', 'create', @kanjifont, '-copy', fnt_bup) - tk_call('font', 'create', @compoundfont, - '-compound', [@latinfont, @kanjifont], *hash_kv(keys)) - tk_call('font', 'delete', fnt_bup) - else - fail e - end - end - end - self - end - - def measure_core_tk4x(window, text) - 0 - end - - def measure_core_tk8x(window, text) - if window - number(tk_call('font', 'measure', @compoundfont, - '-displayof', window, text)) - else - number(tk_call('font', 'measure', @compoundfont, text)) - end - end - - def metrics_core_tk4x(font, window, option=nil) - # dummy - if option - "" - else - [['ascent',[]], ['descent',[]], ['linespace',[]], ['fixed',[]]] - end - end - - def metrics_core_tk8x(font, window, option=nil) - if option - if window - number(tk_call('font', 'metrics', font, - "-displayof", window, "-#{option}")) - else - number(tk_call('font', 'metrics', font, "-#{option}")) - end - else - l = tk_split_list(if window - tk_call('font','metrics',font,"-displayof",window) - else - tk_call('font','metrics',font) - end) - r = [] - while key=l.shift - r.push [key[1..-1], l.shift.to_i] - end - r - end - end - - ################################### - # private alias - ################################### - case (Tk::TK_VERSION) - when /^4\.*/ - alias create_latinfont create_latinfont_tk4x - alias create_kanjifont create_kanjifont_tk4x - alias create_compoundfont create_compoundfont_tk4x - alias actual_core actual_core_tk4x - alias configure_core configure_core_tk4x - alias configinfo_core configinfo_core_tk4x - alias delete_core delete_core_tk4x - alias latin_replace_core latin_replace_core_tk4x - alias kanji_replace_core kanji_replace_core_tk4x - alias measure_core measure_core_tk4x - alias metrics_core metrics_core_tk4x - - when /^8\.[0-4]/ - alias create_latinfont create_latinfont_tk8x - alias create_kanjifont create_kanjifont_tk8x - alias create_compoundfont create_compoundfont_tk8x - alias actual_core actual_core_tk8x - alias configure_core configure_core_tk8x - alias configinfo_core configinfo_core_tk8x - alias delete_core delete_core_tk8x - alias latin_replace_core latin_replace_core_tk8x - alias kanji_replace_core kanji_replace_core_tk8x - alias measure_core measure_core_tk8x - alias metrics_core metrics_core_tk8x - - when /^8\.*/ - alias create_latinfont create_latinfont_tk8x - alias create_kanjifont create_kanjifont_tk8x - alias create_compoundfont create_compoundfont_tk8x - alias actual_core actual_core_tk8x - alias configure_core configure_core_tk8x - alias configinfo_core configinfo_core_tk8x - alias delete_core delete_core_tk8x - alias latin_replace_core latin_replace_core_tk8x - alias kanji_replace_core kanji_replace_core_tk8x - alias measure_core measure_core_tk8x - alias metrics_core metrics_core_tk8x - - end - - ################################### - public - ################################### - def method_missing(id, *args) - name = id.id2name - case args.length - when 1 - configure name, args[0] - when 0 - begin - configinfo name - rescue - fail NameError, "undefined local variable or method `#{name}' for #{self.to_s}", error_at - end - else - fail NameError, "undefined method `#{name}' for #{self.to_s}", error_at - end - end - - def call_font_configure(path, *args) - args += hash_kv(args.pop.update(@fontslot)) - tk_call(*args) - Tk_FontUseTBL[path] = self - self - end - - def used - ret = [] - Tk_FontUseTBL.each{|key,value| - if key.include?(';') - win, tag = key.split(';') - winobj = tk_tcl2ruby(win) - if winobj.kind_of? TkText - ret.push([winobj, winobj.tagid2obj(tag)]) - elsif winobj.kind_of? TkCanvas - if (tagobj = TkcTag.id2obj(winobj, tag)).kind_of? TkcTag - ret.push([winobj, tagobj]) - elsif (tagobj = TkcItem.id2obj(tag)).kind_of? TkcItem - ret.push([winobj, tagobj]) - else - ret.push([winobj, tag]) - end - elsif winobj.kind_of? TkMenu - ret.push([winobj, tag]) - else - ret.push([win, tag]) - end - else - ret.push(tk_tcl2ruby(key)) if value == self - end - } - ret - end - - def id - @id - end - - def to_eval - font - end - - def font - @compoundfont - end - alias font_id font - - def latin_font_id - @latinfont - end - - def latin_font - # @latinfont - if @latin_descendant - @latin_descendant - else - @latin_descendant = DescendantFont.new(self, 'latin') - end - end - alias latinfont latin_font - - def kanji_font_id - @kanjifont - end - - def kanji_font - # @kanjifont - if @kanji_descendant - @kanji_descendant - else - @kanji_descendant = DescendantFont.new(self, 'kanji') - end - end - alias kanjifont kanji_font - - def actual(option=nil) - actual_core(@compoundfont, nil, option) - end - - def actual_displayof(window, option=nil) - window = '.' unless window - actual_core(@compoundfont, window, option) - end - - def latin_actual(option=nil) - actual_core(@latinfont, nil, option) - end - - def latin_actual_displayof(window, option=nil) - window = '.' unless window - actual_core(@latinfont, window, option) - end - - def kanji_actual(option=nil) - #if JAPANIZED_TK - if @kanjifont != "" - actual_core(@kanjifont, nil, option) - else - actual_core_tk4x(nil, nil, option) - end - end - - def kanji_actual_displayof(window, option=nil) - #if JAPANIZED_TK - if @kanjifont != "" - window = '.' unless window - actual_core(@kanjifont, window, option) - else - actual_core_tk4x(nil, window, option) - end - end - - def [](slot) - configinfo slot - end - - def []=(slot, val) - configure slot, val - end - - def configure(slot, value=None) - configure_core(@compoundfont, slot, value) - self - end - - def configinfo(slot=nil) - configinfo_core(@compoundfont, slot) - end - - def delete - delete_core - end - - def latin_configure(slot, value=None) - if JAPANIZED_TK - configure_core(@latinfont, slot, value) - else - configure(slot, value) - end - self - end - - def latin_configinfo(slot=nil) - if JAPANIZED_TK - configinfo_core(@latinfont, slot) - else - configinfo(slot) - end - end - - def kanji_configure(slot, value=None) - #if JAPANIZED_TK - if @kanjifont != "" - configure_core(@kanjifont, slot, value) - configure('size'=>configinfo('size')) # to reflect new configuration - else - #"" - configure(slot, value) - end - self - end - - def kanji_configinfo(slot=nil) - #if JAPANIZED_TK - if @kanjifont != "" - configinfo_core(@kanjifont, slot) - else - #[] - configinfo(slot) - end - end - - def replace(ltn, knj) - latin_replace(ltn) - kanji_replace(knj) - self - end - - def latin_replace(ltn) - latin_replace_core(ltn) - reset_pointadjust - self - end - - def kanji_replace(knj) - kanji_replace_core(knj) - reset_pointadjust - self - end - - def measure(text) - measure_core(nil, text) - end - - def measure_displayof(window, text) - window = '.' unless window - measure_core(window, text) - end - - def metrics(option=nil) - metrics_core(@compoundfont, nil, option) - end - - def metrics_displayof(window, option=nil) - window = '.' unless window - metrics_core(@compoundfont, window, option) - end - - def latin_metrics(option=nil) - metrics_core(@latinfont, nil, option) - end - - def latin_metrics_displayof(window, option=nil) - window = '.' unless window - metrics_core(@latinfont, window, option) - end - - def kanji_metrics(option=nil) - if JAPANIZED_TK - metrics_core(@kanjifont, nil, option) - else - metrics_core_tk4x(nil, nil, option) - end - end - - def kanji_metrics_displayof(window, option=nil) - if JAPANIZED_TK - window = '.' unless window - metrics_core(@kanjifont, window, option) - else - metrics_core_tk4x(nil, window, option) - end - end - - def reset_pointadjust - begin - if /^8\.*/ === Tk::TK_VERSION && JAPANIZED_TK - configure('pointadjust' => latin_actual.assoc('size')[1].to_f / - kanji_actual.assoc('size')[1].to_f ) - end - rescue - end - self - end - - ################################### - # public alias - ################################### - alias ascii_font latin_font - alias asciifont latinfont - alias create_asciifont create_latinfont - alias ascii_actual latin_actual - alias ascii_actual_displayof latin_actual_displayof - alias ascii_configure latin_configure - alias ascii_configinfo latin_configinfo - alias ascii_replace latin_replace - alias ascii_metrics latin_metrics - - ################################### - def dup - src = self - obj = super() - obj.instance_eval{ initialize(src) } - obj - end - def clone - src = self - obj = super() - obj.instance_eval{ initialize(src) } - obj - end -end - -module TkTreatTagFont - def font_configinfo - @parent.tagfont_configinfo(@id) - end -# alias font font_configinfo - - def font_configure(slot) - @parent.tagfont_configure(@id, slot) - self - end - - def latinfont_configure(ltn, keys=nil) - @parent.latintagfont_configure(@id, ltn, keys) - self - end - alias asciifont_configure latinfont_configure - - def kanjifont_configure(knj, keys=nil) - @parent.kanjitagfont_configure(@id, ltn, keys) - self - end - - def font_copy(window, wintag=nil) - @parent.tagfont_copy(@id, window, wintag) - self - end - - def latinfont_copy(window, wintag=nil) - @parent.latintagfont_copy(@id, window, wintag) - self - end - alias asciifont_copy latinfont_copy - - def kanjifont_copy(window, wintag=nil) - @parent.kanjitagfont_copy(@id, window, wintag) - self - end -end +require 'tk/font' diff --git a/ext/tk/lib/tkmacpkg.rb b/ext/tk/lib/tkmacpkg.rb index 3bac5e6c3..35560e78c 100644 --- a/ext/tk/lib/tkmacpkg.rb +++ b/ext/tk/lib/tkmacpkg.rb @@ -1,56 +1,4 @@ # -# tkmacpkg.rb : methods for Tcl/Tk packages for Macintosh -# 2000/11/22 by Hidetoshi Nagai +# tkmacpkg.rb - load tk/macpkg.rb # -# ATTENTION !! -# This is NOT TESTED. Because I have no test-environment. -# -# -require 'tk' - -module TkMacResource - extend Tk - extend TkMacResource - - TkCommandNames = ['resource'.freeze].freeze - - tk_call('package', 'require', 'resource') - - def close(rsrcRef) - tk_call('resource', 'close', rsrcRef) - end - - def delete(rsrcType, opts=nil) - tk_call('resource', 'delete', *(hash_kv(opts) + rsrcType)) - end - - def files(rsrcRef=nil) - if rsrcRef - tk_call('resource', 'files', rsrcRef) - else - tk_split_simplelist(tk_call('resource', 'files')) - end - end - - def list(rsrcType, rsrcRef=nil) - tk_split_simplelist(tk_call('resource', 'list', rsrcType, rsrcRef)) - end - - def open(fname, access=nil) - tk_call('resource', 'open', fname, access) - end - - def read(rsrcType, rsrcID, rsrcRef=nil) - tk_call('resource', 'read', rsrcType, rsrcID, rsrcRef) - end - - def types(rsrcRef=nil) - tk_split_simplelist(tk_call('resource', 'types', rsrcRef)) - end - - def write(rsrcType, data, opts=nil) - tk_call('resource', 'write', *(hash_kv(opts) + rsrcType + data)) - end - - module_function :close, :delete, :files, :list, :open, :read, :types, :write -end +require 'tk/macpkg' diff --git a/ext/tk/lib/tkmenubar.rb b/ext/tk/lib/tkmenubar.rb index 0d29571eb..70214fda1 100644 --- a/ext/tk/lib/tkmenubar.rb +++ b/ext/tk/lib/tkmenubar.rb @@ -1,143 +1,4 @@ # -# tkmenubar.rb +# tkmenubar.rb - load tk/menubar.rb # -# Copyright (C) 1998 maeda shugo. All rights reserved. -# This file can be distributed under the terms of the Ruby. - -# Usage: -# -# menu_spec = [ -# [['File', 0], -# ['Open', proc{puts('Open clicked')}, 0], -# '---', -# ['Quit', proc{exit}, 0]], -# [['Edit', 0], -# ['Cut', proc{puts('Cut clicked')}, 2], -# ['Copy', proc{puts('Copy clicked')}, 0], -# ['Paste', proc{puts('Paste clicked')}, 0]] -# ] -# menubar = TkMenubar.new(nil, menu_spec, -# 'tearoff'=>false, -# 'foreground'=>'grey40', -# 'activeforeground'=>'red', -# 'font'=>'-adobe-helvetica-bold-r-*--12-*-iso8859-1') -# menubar.pack('side'=>'top', 'fill'=>'x') -# -# -# OR -# -# -# menubar = TkMenubar.new -# menubar.add_menu([['File', 0], -# ['Open', proc{puts('Open clicked')}, 0], -# '---', -# ['Quit', proc{exit}, 0]]) -# menubar.add_menu([['Edit', 0], -# ['Cut', proc{puts('Cut clicked')}, 2], -# ['Copy', proc{puts('Copy clicked')}, 0], -# ['Paste', proc{puts('Paste clicked')}, 0]]) -# menubar.configure('tearoff', false) -# menubar.configure('foreground', 'grey40') -# menubar.configure('activeforeground', 'red') -# menubar.configure('font', '-adobe-helvetica-bold-r-*--12-*-iso8859-1') -# menubar.pack('side'=>'top', 'fill'=>'x') - -# The format of the menu_spec is: -# [ -# [ -# [button text, underline, accelerator], -# [menu label, command, underline, accelerator], -# '---', # separator -# ... -# ], -# ... -# ] - -# underline and accelerator are optional parameters. -# Hashes are OK instead of Arrays. - -# To use add_menu, configuration must be done by calling configure after -# adding all menus by add_menu, not by the constructor arguments. - -require "tk" - -class TkMenubar item_info) - end - end - - mbtn.menu(menu) - @menus.push([mbtn, menu]) - delegate('tearoff', menu) - delegate('foreground', mbtn, menu) - delegate('background', mbtn, menu) - delegate('disabledforeground', mbtn, menu) - delegate('activeforeground', mbtn, menu) - delegate('activebackground', mbtn, menu) - delegate('font', mbtn, menu) - delegate('kanjifont', mbtn, menu) - mbtn.pack('side' => 'left') - end - - def [](index) - return @menus[index] - end -end +require 'tk/menubar' diff --git a/ext/tk/lib/tkmngfocus.rb b/ext/tk/lib/tkmngfocus.rb index 461525009..fe70950e8 100644 --- a/ext/tk/lib/tkmngfocus.rb +++ b/ext/tk/lib/tkmngfocus.rb @@ -1,33 +1,4 @@ # -# tkmngfocus.rb : methods for Tcl/Tk standard library 'focus.tcl' -# by Hidetoshi Nagai +# tkmngfocus.rb - load tk/mngfocus.rb # -require 'tk' - -module TkManageFocus - extend Tk - - TkCommandNames = [ - 'tk_focusFollowMouse'.freeze, - 'tk_focusNext'.freeze, - 'tk_focusPrev'.freeze - ].freeze - - def TkManageFocus.followsMouse - tk_call 'tk_focusFollowsMouse' - end - - def TkManageFocus.next(window) - tk_tcl2ruby(tk_call('tk_focusNext', window)) - end - def focusNext - TkManageFocus.next(self) - end - - def TkManageFocus.prev(window) - tk_tcl2ruby(tk_call('tk_focusPrev', window)) - end - def focusPrev - TkManageFocus.prev(self) - end -end +require 'tk/mngfocus' diff --git a/ext/tk/lib/tkpalette.rb b/ext/tk/lib/tkpalette.rb index dc2fd47e5..56b203bbb 100644 --- a/ext/tk/lib/tkpalette.rb +++ b/ext/tk/lib/tkpalette.rb @@ -1,54 +1,4 @@ # -# tkpalette.rb : methods for Tcl/Tk standard library 'palette.tcl' -# 1998/06/21 by Hidetoshi Nagai +# tkpalette.rb - load tk/palette.rb # -require 'tk' - -module TkPalette - include Tk - extend Tk - - TkCommandNames = [ - 'tk_setPalette'.freeze, - 'tk_bisque'.freeze, - 'tkDarken'.freeze - ].freeze - - def TkPalette.set(*args) - args = args.to_a.flatten if args.kind_of? Hash - tk_call 'tk_setPalette', *args - end - def TkPalette.setPalette(*args) - TkPalette.set(*args) - end - - def TkPalette.bisque - tk_call 'tk_bisque' - end - - def TkPalette.darken(color, percent) - tk_call 'tkDarken', color, percent - end - - def TkPalette.recolorTree(window, colors) - if not colors.kind_of?(Hash) - fail "2nd arg need to be Hash" - end - - colors.each{|key, value| - begin - if window.cget(key) == tk_call('set', "tkPalette(#{key})") - window[key] = colors[key] - end - rescue - # ignore - end - } - - TkWinfo.children(window).each{|w| TkPalette.recolorTree(w, colors)} - end - - def recolorTree(colors) - TkPalette.recolorTree(self, colors) - end -end +require 'tk/palette' diff --git a/ext/tk/lib/tkscrollbox.rb b/ext/tk/lib/tkscrollbox.rb index 3f1191c74..6093b2e4e 100644 --- a/ext/tk/lib/tkscrollbox.rb +++ b/ext/tk/lib/tkscrollbox.rb @@ -1,30 +1,4 @@ # -# tkscrollbox.rb - Tk Listbox with Scrollbar -# as an example of Composite Widget -# $Date$ -# by Yukihiro Matsumoto - -require 'tk.rb' - -class TkScrollbox'left','fill'=>'both','expand'=>'yes' - scroll.configure 'command', list.path+" yview" - scroll.pack 'side'=>'right','fill'=>'y' - - delegate('DEFAULT', list) - delegate('foreground', list) - delegate('background', list, scroll) - delegate('borderwidth', @frame) - delegate('relief', @frame) - - configure keys if keys - end - private :initialize_composite -end +# tkscrollbox.rb - load tk/scrollbox.rb +# +require 'tk/scrollbox' diff --git a/ext/tk/lib/tktext.rb b/ext/tk/lib/tktext.rb index 2d37fb8c0..97ad62a3e 100644 --- a/ext/tk/lib/tktext.rb +++ b/ext/tk/lib/tktext.rb @@ -1,1356 +1,4 @@ # -# tktext.rb - Tk text classes -# $Date$ -# by Yukihiro Matsumoto - -require 'tk.rb' -require 'tkfont' - -module TkTreatTextTagFont - include TkTreatItemFont - - ItemCMD = ['tag'.freeze, 'configure'.freeze].freeze - def __conf_cmd(idx) - ItemCMD[idx] - end - - def __item_pathname(tagOrId) - if tagOrId.kind_of?(TkTextTag) - self.path + ';' + tagOrId.id - else - self.path + ';' + tagOrId - end - end - - private :__conf_cmd, :__item_pathname -end - -class TkText 0 - tags.shift.collect{|x|_get_eval_string(x)}.join(' ') # taglist - args << tags.shift if tags.size > 0 # chars - end - super index, *args - else - # single chars-taglist argument - super index, chars, tags.collect{|x|_get_eval_string(x)}.join(' ') - end - end - - def destroy - @tags = {} unless @tags - @tags.each_value do |t| - t.destroy - end - super - end - - def backspace - self.delete 'insert' - end - - def compare(idx1, op, idx2) - bool(tk_send('compare', idx1, op, idx2)) - end - - def debug - bool(tk_send('debug')) - end - def debug=(boolean) - tk_send 'debug', boolean - self - end - def bbox(index) - list(tk_send('bbox', index)) - end - - def dlineinfo(index) - list(tk_send('dlineinfo', index)) - end - - def modified? - bool(tk_send('edit', 'modified')) - end - def modified(mode) - tk_send('edit', 'modified', mode) - self - end - def edit_redo - tk_send('edit', 'redo') - self - end - def edit_reset - tk_send('edit', 'reset') - self - end - def edit_separator - tk_send('edit', 'separator') - self - end - def edit_undo - tk_send('edit', 'undo') - self - end - - def yview_pickplace(*what) - tk_send 'yview', '-pickplace', *what - self - end - - def xview_pickplace(*what) - tk_send 'xview', '-pickplace', *what - self - end - - def text_copy - # Tk8.4 feature - tk_call('tk_textCopy', @path) - end - - def text_cut - # Tk8.4 feature - tk_call('tk_textCut', @path) - end - - def text_paste - # Tk8.4 feature - tk_call('tk_textPaste', @path) - end - - def tag_add(tag, index1, index2=None) - tk_send 'tag', 'add', tag, index1, index2 - self - end - alias addtag tag_add - alias add_tag tag_add - - def tag_delete(*tags) - tk_send 'tag', 'delete', *tags - if TkTextTag::TTagID_TBL[@path] - tags.each{|tag| - if tag.kind_of? TkTextTag - TTagID_TBL[@path].delete(tag.id) - else - TTagID_TBL[@path].delete(tag) - end - } - end - self - end - alias deltag tag_delete - alias delete_tag tag_delete - - def tag_bind(tag, seq, cmd=Proc.new, args=nil) - _bind([@path, 'tag', 'bind', tag], seq, cmd, args) - self - end - - def tag_bind_append(tag, seq, cmd=Proc.new, args=nil) - _bind_append([@path, 'tag', 'bind', tag], seq, cmd, args) - self - end - - def tag_bind_remove(tag, seq) - _bind_remove([@path, 'tag', 'bind', tag], seq) - self - end - - def tag_bindinfo(tag, context=nil) - _bindinfo([@path, 'tag', 'bind', tag], context) - end - - def tag_cget(tag, key) - case key.to_s - when 'text', 'label', 'show', 'data', 'file' - tk_call(@path, 'tag', 'cget', tag, "-#{key}") - when 'font', 'kanjifont' - #fnt = tk_tcl2ruby(tk_send('tag', 'cget', tag, "-#{key}")) - fnt = tk_tcl2ruby(tk_send('tag', 'cget', tag, '-font')) - unless fnt.kind_of?(TkFont) - fnt = tagfontobj(tag, fnt) - end - if key.to_s == 'kanjifont' && JAPANIZED_TK && TK_VERSION =~ /^4\.*/ - # obsolete; just for compatibility - fnt.kanji_font - else - fnt - end - else - tk_tcl2ruby(tk_call(@path, 'tag', 'cget', tag, "-#{key}")) - end - end - - def tag_configure(tag, key, val=None) - if key.kind_of? Hash - key = _symbolkey2str(key) - if ( key['font'] || key['kanjifont'] \ - || key['latinfont'] || key['asciifont'] ) - tagfont_configure(tag, key) - else - tk_send 'tag', 'configure', tag, *hash_kv(key) - end - - else - if key == 'font' || key == :font || - key == 'kanjifont' || key == :kanjifont || - key == 'latinfont' || key == :latinfont || - key == 'asciifont' || key == :asciifont - if val == None - tagfontobj(tag) - else - tagfont_configure(tag, {key=>val}) - end - else - tk_send 'tag', 'configure', tag, "-#{key}", val - end - end - self - end - - def tag_configinfo(tag, key=nil) - if key - case key.to_s - when 'text', 'label', 'show', 'data', 'file' - conf = tk_split_simplelist(tk_send('tag','configure',tag,"-#{key}")) - when 'font', 'kanjifont' - conf = tk_split_simplelist(tk_send('tag','configure',tag,"-#{key}") ) - conf[4] = tagfont_configinfo(tag, conf[4]) - else - conf = tk_split_list(tk_send('tag','configure',tag,"-#{key}")) - end - conf[0] = conf[0][1..-1] - conf - else - ret = tk_split_simplelist(tk_send('tag', 'configure', - tag)).collect{|conflist| - conf = tk_split_simplelist(conflist) - conf[0] = conf[0][1..-1] - case conf[0] - when 'text', 'label', 'show', 'data', 'file' - else - if conf[3] - if conf[3].index('{') - conf[3] = tk_split_list(conf[3]) - else - conf[3] = tk_tcl2ruby(conf[3]) - end - end - if conf[4] - if conf[4].index('{') - conf[4] = tk_split_list(conf[4]) - else - conf[4] = tk_tcl2ruby(conf[4]) - end - end - end - conf - } - fontconf = ret.assoc('font') - if fontconf - ret.delete_if{|item| item[0] == 'font' || item[0] == 'kanjifont'} - fontconf[4] = tagfont_configinfo(tag, fontconf[4]) - ret.push(fontconf) - else - ret - end - end - end - - def tag_raise(tag, above=None) - tk_send 'tag', 'raise', tag, above - self - end - - def tag_lower(tag, below=None) - tk_send 'tag', 'lower', tag, below - self - end - - def tag_remove(tag, *index) - tk_send 'tag', 'remove', tag, *index - self - end - - def tag_ranges(tag) - l = tk_split_simplelist(tk_send('tag', 'ranges', tag)) - r = [] - while key=l.shift - r.push [key, l.shift] - end - r - end - - def tag_nextrange(tag, first, last=None) - tk_split_list(tk_send('tag', 'nextrange', tag, first, last)) - end - - def tag_prevrange(tag, first, last=None) - tk_split_list(tk_send('tag', 'prevrange', tag, first, last)) - end - - def window_cget(index, slot) - case slot.to_s - when 'text', 'label', 'show', 'data', 'file' - tk_send('window', 'cget', index, "-#{slot}") - when 'font', 'kanjifont' - #fnt = tk_tcl2ruby(tk_send('window', 'cget', index, "-#{slot}")) - fnt = tk_tcl2ruby(tk_send('window', 'cget', index, '-font')) - unless fnt.kind_of?(TkFont) - fnt = tagfontobj(index, fnt) - end - if slot.to_s == 'kanjifont' && JAPANIZED_TK && TK_VERSION =~ /^4\.*/ - # obsolete; just for compatibility - fnt.kanji_font - else - fnt - end - else - tk_tcl2ruby(tk_send('window', 'cget', index, "-#{slot}")) - end - end - - def window_configure(index, slot, value=None) - if index.kind_of? TkTextWindow - index.configure(slot, value) - else - if slot.kind_of? Hash - slot = _symbolkey2str(slot) - win = slot['window'] - slot['window'] = win.epath if win.kind_of?(TkWindow) - if slot['create'] - p_create = slot['create'] - if p_create.kind_of? Proc - slot['create'] = install_cmd(proc{ - id = p_create.call - if id.kind_of?(TkWindow) - id.epath - else - id - end - }) - end - end - tk_send('window', 'configure', index, *hash_kv(slot)) - else - if slot == 'window' || slot == :window - id = value - value = id.epath if id.kind_of?(TkWindow) - end - if slot == 'create' || slot == :create - p_create = value - if p_create.kind_of? Proc - value = install_cmd(proc{ - id = p_create.call - if id.kind_of?(TkWindow) - id.epath - else - id - end - }) - end - end - tk_send('window', 'configure', index, "-#{slot}", value) - end - end - self - end - - def window_configinfo(win, slot = nil) - if slot - case slot.to_s - when 'text', 'label', 'show', 'data', 'file' - conf = tk_split_simplelist(tk_send('window', 'configure', - win, "-#{slot}")) - else - conf = tk_split_list(tk_send('window', 'configure', - win, "-#{slot}")) - end - conf[0] = conf[0][1..-1] - conf - else - tk_split_simplelist(tk_send('window', 'configure', - win)).collect{|conflist| - conf = tk_split_simplelist(conflist) - conf[0] = conf[0][1..-1] - case conf[0] - when 'text', 'label', 'show', 'data', 'file' - else - if conf[3] - if conf[3].index('{') - conf[3] = tk_split_list(conf[3]) - else - conf[3] = tk_tcl2ruby(conf[3]) - end - end - if conf[4] - if conf[4].index('{') - conf[4] = tk_split_list(conf[4]) - else - conf[4] = tk_tcl2ruby(conf[4]) - end - end - end - conf - } - end - end - - def window_names - tk_split_simplelist(tk_send('window', 'names')).collect{|elt| - tagid2obj(elt) - } - end - - def _ktext_length(txt) - if $KCODE !~ /n/i - return txt.gsub(/[^\Wa-zA-Z_\d]/, ' ').length - end - - # $KCODE == 'NONE' - if JAPANIZED_TK - tk_call('kstring', 'length', txt).to_i - else - begin - tk_call('encoding', 'convertto', 'ascii', txt).length - rescue StandardError, NameError - # sorry, I have no plan - txt.length - end - end - end - private :_ktext_length - - def search_with_length(pat,start,stop=None) - pat = pat.chr if pat.kind_of? Integer - if stop != None - return ["", 0] if compare(start,'>=',stop) - txt = get(start,stop) - if (pos = txt.index(pat)) - match = $& - #pos = txt[0..(pos-1)].split('').length if pos > 0 - pos = _ktext_length(txt[0..(pos-1)]) if pos > 0 - if pat.kind_of? String - #return [index(start + " + #{pos} chars"), pat.split('').length] - return [index(start + " + #{pos} chars"), - _ktext_length(pat), pat.dup] - else - #return [index(start + " + #{pos} chars"), $&.split('').length] - return [index(start + " + #{pos} chars"), - _ktext_length(match), match] - end - else - return ["", 0] - end - else - txt = get(start,'end - 1 char') - if (pos = txt.index(pat)) - match = $& - #pos = txt[0..(pos-1)].split('').length if pos > 0 - pos = _ktext_length(txt[0..(pos-1)]) if pos > 0 - if pat.kind_of? String - #return [index(start + " + #{pos} chars"), pat.split('').length] - return [index(start + " + #{pos} chars"), - _ktext_length(pat), pat.dup] - else - #return [index(start + " + #{pos} chars"), $&.split('').length] - return [index(start + " + #{pos} chars"), - _ktext_length(match), match] - end - else - txt = get('1.0','end - 1 char') - if (pos = txt.index(pat)) - match = $& - #pos = txt[0..(pos-1)].split('').length if pos > 0 - pos = _ktext_length(txt[0..(pos-1)]) if pos > 0 - if pat.kind_of? String - #return [index("1.0 + #{pos} chars"), pat.split('').length] - return [index("1.0 + #{pos} chars"), - _ktext_length(pat), pat.dup] - else - #return [index("1.0 + #{pos} chars"), $&.split('').length] - return [index("1.0 + #{pos} chars"), _ktext_length(match), match] - end - else - return ["", 0] - end - end - end - end - - def search(pat,start,stop=None) - search_with_length(pat,start,stop)[0] - end - - def rsearch_with_length(pat,start,stop=None) - pat = pat.chr if pat.kind_of? Integer - if stop != None - return ["", 0] if compare(start,'<=',stop) - txt = get(stop,start) - if (pos = txt.rindex(pat)) - match = $& - #pos = txt[0..(pos-1)].split('').length if pos > 0 - pos = _ktext_length(txt[0..(pos-1)]) if pos > 0 - if pat.kind_of? String - #return [index(stop + " + #{pos} chars"), pat.split('').length] - return [index(stop + " + #{pos} chars"), _ktext_length(pat), pat.dup] - else - #return [index(stop + " + #{pos} chars"), $&.split('').length] - return [index(stop + " + #{pos} chars"), _ktext_length(match), match] - end - else - return ["", 0] - end - else - txt = get('1.0',start) - if (pos = txt.rindex(pat)) - match = $& - #pos = txt[0..(pos-1)].split('').length if pos > 0 - pos = _ktext_length(txt[0..(pos-1)]) if pos > 0 - if pat.kind_of? String - #return [index("1.0 + #{pos} chars"), pat.split('').length] - return [index("1.0 + #{pos} chars"), _ktext_length(pat), pat.dup] - else - #return [index("1.0 + #{pos} chars"), $&.split('').length] - return [index("1.0 + #{pos} chars"), _ktext_length(match), match] - end - else - txt = get('1.0','end - 1 char') - if (pos = txt.rindex(pat)) - match = $& - #pos = txt[0..(pos-1)].split('').length if pos > 0 - pos = _ktext_length(txt[0..(pos-1)]) if pos > 0 - if pat.kind_of? String - #return [index("1.0 + #{pos} chars"), pat.split('').length] - return [index("1.0 + #{pos} chars"), _ktext_length(pat), pat.dup] - else - #return [index("1.0 + #{pos} chars"), $&.split('').length] - return [index("1.0 + #{pos} chars"), _ktext_length(match), match] - end - else - return ["", 0] - end - end - end - end - - def rsearch(pat,start,stop=None) - rsearch_with_length(pat,start,stop)[0] - end - - def dump(type_info, *index, &block) - args = type_info.collect{|inf| '-' + inf} - args << '-command' << block if block - str = tk_send('dump', *(args + index)) - result = [] - sel = nil - i = 0 - while i < str.size - # retrieve key - idx = str.index(/ /, i) - result.push str[i..(idx-1)] - i = idx + 1 - - # retrieve value - case result[-1] - when 'text' - if str[i] == ?{ - # text formed as {...} - val, i = _retrieve_braced_text(str, i) - result.push val - else - # text which may contain backslahes - val, i = _retrieve_backslashed_text(str, i) - result.push val - end - else - idx = str.index(/ /, i) - val = str[i..(idx-1)] - case result[-1] - when 'mark' - case val - when 'insert' - result.push TkTextMarkInsert.new(self) - when 'current' - result.push TkTextMarkCurrent.new(self) - when 'anchor' - result.push TkTextMarkAnchor.new(self) - else - result.push tk_tcl2ruby(val) - end - when 'tagon' - if val == 'sel' - if sel - result.push sel - else - result.push TkTextTagSel.new(self) - end - else - result.push tk_tcl2ruby(val) - end - when 'tagoff' - result.push tk_tcl2ruby(val) - when 'window' - result.push tk_tcl2ruby(val) - end - i = idx + 1 - end - - # retrieve index - idx = str.index(/ /, i) - if idx - result.push str[i..(idx-1)] - i = idx + 1 - else - result.push str[i..-1] - break - end - end - - kvis = [] - until result.empty? - kvis.push [result.shift, result.shift, result.shift] - end - kvis # result is [[key1, value1, index1], [key2, value2, index2], ...] - end - - def _retrieve_braced_text(str, i) - cnt = 0 - idx = i - while idx < str.size - case str[idx] - when ?{ - cnt += 1 - when ?} - cnt -= 1 - if cnt == 0 - break - end - end - idx += 1 - end - return str[i+1..idx-1], idx + 2 - end - private :_retrieve_braced_text - - def _retrieve_backslashed_text(str, i) - j = i - idx = nil - loop { - idx = str.index(/ /, j) - if str[idx-1] == ?\\ - j += 1 - else - break - end - } - val = str[i..(idx-1)] - val.gsub!(/\\( |\{|\})/, '\1') - return val, idx + 1 - end - private :_retrieve_backslashed_text - - def dump_all(*index, &block) - dump(['all'], *index, &block) - end - def dump_mark(*index, &block) - dump(['mark'], *index, &block) - end - def dump_tag(*index, &block) - dump(['tag'], *index, &block) - end - def dump_text(*index, &block) - dump(['text'], *index, &block) - end - def dump_window(*index, &block) - dump(['window'], *index, &block) - end - def dump_image(*index, &block) - dump(['image'], *index, &block) - end -end - -class TkTextTag 0 - tk_call(@t.path, 'window', 'configure', @index, *hash_kv(slot)) - end - else - if slot == 'window' || slot == :window - @id = value - value = @id.epath if @id.kind_of?(TkWindow) - end - if slot == 'create' || slot == :create - self.create=value - else - tk_call(@t.path, 'window', 'configure', @index, "-#{slot}", value) - end - end - self - end - - def configinfo(slot = nil) - @t.window_configinfo(@index, slot) - end - - def window - @id - end - - def window=(value) - @id = value - value = @id.epath if @id.kind_of?(TkWindow) - tk_call @t.path, 'window', 'configure', @index, '-window', value - end - - def create - @p_create - end - - def create=(value) - @p_create = value - if @p_create.kind_of? Proc - value = install_cmd(proc{ - @id = @p_create.call - if @id.kind_of?(TkWindow) - @id.epath - else - @id - end - }) - end - tk_call @t.path, 'window', 'configure', @index, '-create', value - end -end - -class TkTextImage +# tkvirtevent.rb - load tk/virtevent.rb # -require 'tk' - -class TkVirtualEvent".freeze].freeze - TkVirtualEventTBL = TkCore::INTERP.create_table - - TkCore::INTERP.init_ip_env{ TkVirtualEventTBL.clear } - - class PreDefVirtEvent") - PreDefVirtEvent.new(event) - else - fail ArgumentError, "undefined virtual event '<#{event}>'" - end - end - end - - def TkVirtualEvent.info - tk_call('event', 'info').split(/\s+/).collect!{|seq| - TkVirtualEvent.getobj(seq[1..-2]) - } - end - - def initialize(*sequences) - @path = @id = TkVirtualEventID.join - TkVirtualEventID[1].succ! - add(*sequences) - end - - def add(*sequences) - if sequences != [] - tk_call('event', 'add', "<#{@id}>", - *(sequences.collect{|seq| "<#{tk_event_sequence(seq)}>"}) ) - TkVirtualEventTBL[@id] = self - end - self - end - - def delete(*sequences) - if sequences == [] - tk_call('event', 'delete', "<#{@id}>") - TkVirtualEventTBL.delete(@id) - else - tk_call('event', 'delete', "<#{@id}>", - *(sequences.collect{|seq| "<#{tk_event_sequence(seq)}>"}) ) - TkVirtualEventTBL.delete(@id) if info == [] - end - self - end - - def info - tk_call('event', 'info', "<#{@id}>").split(/\s+/).collect!{|seq| - l = seq.scan(/<*[^<>]+>*/).collect!{|subseq| - case (subseq) - when /^<<[^<>]+>>$/ - TkVirtualEvent.getobj(subseq[1..-2]) - when /^<[^<>]+>$/ - subseq[1..-2] - else - subseq.split('') - end - }.flatten - (l.size == 1) ? l[0] : l - } - end -end +require 'tk/virtevent' diff --git a/ext/tk/lib/tkwinpkg.rb b/ext/tk/lib/tkwinpkg.rb index 7762b3a59..83371c546 100644 --- a/ext/tk/lib/tkwinpkg.rb +++ b/ext/tk/lib/tkwinpkg.rb @@ -1,84 +1,4 @@ # -# tkwinpkg.rb : methods for Tcl/Tk packages for Microsoft Windows -# 2000/11/22 by Hidetoshi Nagai +# tkwinpkg.rb - load tk/winpkg.rb # -# ATTENTION !! -# This is NOT TESTED. Because I have no test-environment. -# -# -require 'tk' - -module TkWinDDE - extend Tk - extend TkWinDDE - - TkCommandNames = ['dde'.freeze].freeze - - tk_call('package', 'require', 'dde') - - def servername(topic=nil) - tk_call('dde', 'servername', topic) - end - - def execute(service, topic, data) - tk_call('dde', 'execute', service, topic, data) - end - - def async_execute(service, topic, data) - tk_call('dde', '-async', 'execute', service, topic, data) - end - - def poke(service, topic, item, data) - tk_call('dde', 'poke', service, topic, item, data) - end - - def request(service, topic, item) - tk_call('dde', 'request', service, topic, item) - end - - def services(service, topic) - tk_call('dde', 'services', service, topic) - end - - def eval(topic, cmd, *args) - tk_call('dde', 'eval', topic, cmd, *args) - end - - module_function :servername, :execute, :async_execute, - :poke, :request, :services, :eval -end - -module TkWinRegistry - extend Tk - extend TkWinRegistry - - TkCommandNames = ['registry'.freeze].freeze - - tk_call('package', 'require', 'registry') - - def delete(keynam, valnam=nil) - tk_call('registry', 'delete', keynam, valnam) - end - - def get(keynam, valnam) - tk_call('registry', 'get', keynam, valnam) - end - - def keys(keynam) - tk_split_simplelist(tk_call('registry', 'keys', keynam)) - end - - def set(keynam, valnam=nil, data=nil, dattype=nil) - tk_call('registry', 'set', keynam, valnam, data, dattype) - end - - def type(keynam, valnam) - tk_call('registry', 'type', keynam, valnam) - end - - def values(keynam) - tk_split_simplelist(tk_call('registry', 'values', keynam)) - end - - module_function :delete, :get, :keys, :set, :type, :values -end +require 'tk/winpkg' -- cgit