diff options
Diffstat (limited to 'ext/tk')
238 files changed, 23147 insertions, 10395 deletions
diff --git a/ext/tk/MANIFEST b/ext/tk/MANIFEST index 503adaabb7..32d8029de1 100644 --- a/ext/tk/MANIFEST +++ b/ext/tk/MANIFEST @@ -1,5 +1,6 @@ MANIFEST README.1st +README.fork extconf.rb depend tkutil.c @@ -22,6 +23,77 @@ lib/tkscrollbox.rb lib/tktext.rb lib/tkvirtevent.rb lib/tkwinpkg.rb +lib/tk/after.rb +lib/tk/autoload.rb +lib/tk/bgerror.rb +lib/tk/bindtag.rb +lib/tk/button.rb +lib/tk/canvas.rb +lib/tk/canvastag.rb +lib/tk/checkbutton.rb +lib/tk/clipboard.rb +lib/tk/clock.rb +lib/tk/composite.rb +lib/tk/console.rb +lib/tk/dialog.rb +lib/tk/encodedstr.rb +lib/tk/entry.rb +lib/tk/event.rb +lib/tk/font.rb +lib/tk/frame.rb +lib/tk/grid.rb +lib/tk/image.rb +lib/tk/itemfont.rb +lib/tk/kinput.rb +lib/tk/label.rb +lib/tk/labelframe.rb +lib/tk/listbox.rb +lib/tk/macpkg.rb +lib/tk/menu.rb +lib/tk/menubar.rb +lib/tk/message.rb +lib/tk/mngfocus.rb +lib/tk/msgcat.rb +lib/tk/namespace.rb +lib/tk/optiondb.rb +lib/tk/pack.rb +lib/tk/package.rb +lib/tk/palette.rb +lib/tk/panedwindow.rb +lib/tk/place.rb +lib/tk/radiobutton.rb +lib/tk/root.rb +lib/tk/scale.rb +lib/tk/scrollable.rb +lib/tk/scrollbar.rb +lib/tk/scrollbox.rb +lib/tk/selection.rb +lib/tk/spinbox.rb +lib/tk/tagfont.rb +lib/tk/text.rb +lib/tk/textimage.rb +lib/tk/textmark.rb +lib/tk/texttag.rb +lib/tk/textwindow.rb +lib/tk/timer.rb +lib/tk/toplevel.rb +lib/tk/txtwin_abst.rb +lib/tk/validation.rb +lib/tk/variable.rb +lib/tk/virtevent.rb +lib/tk/winfo.rb +lib/tk/winpkg.rb +lib/tk/wm.rb +lib/tk/xim.rb +sample/binding_sample.rb +sample/bindtag_sample.rb +sample/binstr_usage.rb +sample/btn_with_frame.rb +sample/encstr_usage.rb +sample/iso2022-kr.txt +sample/propagate.rb +sample/resource.en +sample/resource.ja sample/safe-tk.rb sample/tkalignbox.rb sample/tkballoonhelp.rb @@ -33,20 +105,22 @@ sample/tkfrom.rb sample/tkhello.rb sample/tkline.rb sample/tkmenubutton.rb +sample/tkmsgcat-load_rb.rb +sample/tkmsgcat-load_rb2.rb +sample/tkmsgcat-load_tk.rb sample/tkmulticolumnlist.rb sample/tkmultilistbox.rb sample/tkmultilistframe.rb sample/tkoptdb-safeTk.rb sample/tkoptdb.rb sample/tktextframe.rb -sample/resource.ja -sample/resource.en sample/tktimer.rb sample/tktimer2.rb sample/tktimer3.rb sample/demos-en/ChangeLog sample/demos-en/ChangeLog.prev sample/demos-en/README +sample/demos-en/README.1st sample/demos-en/README.tkencoding sample/demos-en/arrow.rb sample/demos-en/bind.rb @@ -55,6 +129,7 @@ sample/demos-en/browse1 sample/demos-en/browse2 sample/demos-en/button.rb sample/demos-en/check.rb +sample/demos-en/check2.rb sample/demos-en/clrpick.rb sample/demos-en/colors.rb sample/demos-en/cscroll.rb @@ -71,6 +146,7 @@ sample/demos-en/entry2.rb sample/demos-en/entry3.rb sample/demos-en/filebox.rb sample/demos-en/floor.rb +sample/demos-en/floor2.rb sample/demos-en/form.rb sample/demos-en/hello sample/demos-en/hscale.rb @@ -78,19 +154,6 @@ sample/demos-en/icon.rb sample/demos-en/image1.rb sample/demos-en/image2.rb sample/demos-en/image3.rb -sample/demos-en/images/earth.gif -sample/demos-en/images/earthris.gif -sample/demos-en/images/face.xbm -sample/demos-en/images/flagdown.xbm -sample/demos-en/images/flagup.xbm -sample/demos-en/images/gray25.xbm -sample/demos-en/images/grey.25 -sample/demos-en/images/grey.5 -sample/demos-en/images/letters.xbm -sample/demos-en/images/noletter.xbm -sample/demos-en/images/pattern.xbm -sample/demos-en/images/tcllogo.gif -sample/demos-en/images/teapot.ppm sample/demos-en/items.rb sample/demos-en/ixset sample/demos-en/ixset2 @@ -107,6 +170,7 @@ sample/demos-en/plot.rb sample/demos-en/puzzle.rb sample/demos-en/radio.rb sample/demos-en/radio2.rb +sample/demos-en/radio3.rb sample/demos-en/rmt sample/demos-en/rolodex sample/demos-en/rolodex-j @@ -123,6 +187,7 @@ sample/demos-en/text.rb sample/demos-en/timer sample/demos-en/tkencoding.rb sample/demos-en/twind.rb +sample/demos-en/twind2.rb sample/demos-en/unicodeout.rb sample/demos-en/vscale.rb sample/demos-en/widget @@ -134,6 +199,7 @@ sample/demos-jp/browse1 sample/demos-jp/browse2 sample/demos-jp/button.rb sample/demos-jp/check.rb +sample/demos-jp/check2.rb sample/demos-jp/clrpick.rb sample/demos-jp/colors.rb sample/demos-jp/cscroll.rb @@ -150,6 +216,7 @@ sample/demos-jp/entry2.rb sample/demos-jp/entry3.rb sample/demos-jp/filebox.rb sample/demos-jp/floor.rb +sample/demos-jp/floor2.rb sample/demos-jp/form.rb sample/demos-jp/hello sample/demos-jp/hscale.rb @@ -157,19 +224,6 @@ sample/demos-jp/icon.rb sample/demos-jp/image1.rb sample/demos-jp/image2.rb sample/demos-jp/image3.rb -sample/demos-jp/images/earth.gif -sample/demos-jp/images/earthris.gif -sample/demos-jp/images/face.bmp -sample/demos-jp/images/flagdown.bmp -sample/demos-jp/images/flagup.bmp -sample/demos-jp/images/gray25.bmp -sample/demos-jp/images/grey.25 -sample/demos-jp/images/grey.5 -sample/demos-jp/images/letters.bmp -sample/demos-jp/images/noletter.bmp -sample/demos-jp/images/pattern.bmp -sample/demos-jp/images/tcllogo.gif -sample/demos-jp/images/teapot.ppm sample/demos-jp/items.rb sample/demos-jp/ixset sample/demos-jp/ixset2 @@ -186,6 +240,7 @@ sample/demos-jp/plot.rb sample/demos-jp/puzzle.rb sample/demos-jp/radio.rb sample/demos-jp/radio2.rb +sample/demos-jp/radio3.rb sample/demos-jp/rmt sample/demos-jp/rolodex sample/demos-jp/rolodex-j @@ -200,6 +255,51 @@ sample/demos-jp/tcolor sample/demos-jp/text.rb sample/demos-jp/timer sample/demos-jp/twind.rb +sample/demos-jp/twind2.rb sample/demos-jp/unicodeout.rb sample/demos-jp/vscale.rb sample/demos-jp/widget +sample/images/earth.gif +sample/images/earthris.gif +sample/images/face.xbm +sample/images/flagdown.xbm +sample/images/flagup.xbm +sample/images/gray25.xbm +sample/images/grey.25 +sample/images/grey.5 +sample/images/letters.xbm +sample/images/noletter.xbm +sample/images/pattern.xbm +sample/images/tcllogo.gif +sample/images/teapot.ppm +sample/msgs_rb/README +sample/msgs_rb/cs.msg +sample/msgs_rb/de.msg +sample/msgs_rb/el.msg +sample/msgs_rb/en.msg +sample/msgs_rb/en_gb.msg +sample/msgs_rb/eo.msg +sample/msgs_rb/es.msg +sample/msgs_rb/fr.msg +sample/msgs_rb/it.msg +sample/msgs_rb/ja.msg +sample/msgs_rb/nl.msg +sample/msgs_rb/pl.msg +sample/msgs_rb/ru.msg +sample/msgs_rb2/README +sample/msgs_rb2/de.msg +sample/msgs_rb2/ja.msg +sample/msgs_tk/README +sample/msgs_tk/cs.msg +sample/msgs_tk/de.msg +sample/msgs_tk/el.msg +sample/msgs_tk/en.msg +sample/msgs_tk/en_gb.msg +sample/msgs_tk/eo.msg +sample/msgs_tk/es.msg +sample/msgs_tk/fr.msg +sample/msgs_tk/it.msg +sample/msgs_tk/ja.msg +sample/msgs_tk/nl.msg +sample/msgs_tk/pl.msg +sample/msgs_tk/ru.msg diff --git a/ext/tk/README.fork b/ext/tk/README.fork new file mode 100644 index 0000000000..cda89b003c --- /dev/null +++ b/ext/tk/README.fork @@ -0,0 +1,29 @@ +Ruby/Tk does NOT support forking the process on which Tk interpreter +is running (unless NEVER control Tk interpreter under the forked child +process). In the library 'tk.rb', a Tk interpreter is initialized. +Therefore, if you want running Tk under a child process, please call +"require 'tk'" in the child process. + +For example, the following sample1 will NOT work, and sample2 will +work properly. + +---<sample1: NOT work>--------------------------------------- +require 'tk' ## init Tk interpreter under parent process + +exit! if fork ## exit parent process + +## child process +TkButton.new(:text=>'QUIT', :command=>proc{exit}).pack +Tk.mainloop +------------------------------------------------------------- + +---<sample2: will work>-------------------------------------- +exit! if fork ## exit main process + +## child process +require 'tk' ## init Tk interpreter under child process +TkButton.new(:text=>'QUIT', :command=>proc{exit}).pack +Tk.mainloop +------------------------------------------------------------- + + 2004/04/20 Hidetoshi NAGAI diff --git a/ext/tk/extconf.rb b/ext/tk/extconf.rb index f769b06e30..4f87d527ae 100644 --- a/ext/tk/extconf.rb +++ b/ext/tk/extconf.rb @@ -1,2 +1,3 @@ require 'mkmf' +$preload = ["tcltklib"] create_makefile("tkutil") diff --git a/ext/tk/lib/multi-tk.rb b/ext/tk/lib/multi-tk.rb index c2dcb4f971..a3cd3857a0 100644 --- a/ext/tk/lib/multi-tk.rb +++ b/ext/tk/lib/multi-tk.rb @@ -3,6 +3,7 @@ # by Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp> 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 f098772a28..36a9e54f2e 100644 --- a/ext/tk/lib/tk.rb +++ b/ext/tk/lib/tk.rb @@ -4,17 +4,30 @@ # by Yukihiro Matsumoto <matz@netlab.jp> # 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,10 +110,16 @@ 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] + #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)} @@ -110,10 +144,76 @@ module TkComm 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 = [] @@ -201,7 +301,7 @@ module TkComm if c == '\\' && !escape escape = true token = (token || "") << c if brace > 0 - next + next end brace += 1 if c == '{' && !escape brace -= 1 if c == '}' && !escape @@ -216,78 +316,74 @@ module TkComm list << token.gsub(/^\{(.*)\}$/, '\1') if token list end -=begin - 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 - escape = false - brace = 1 - str.each_byte {|c| - i += 1 - brace += 1 if c == ?{ && !escape - brace -= 1 if c == ?} && !escape - escape = (c == ?\\) - break if brace == 0 - } - if i == 0 - list.push '' - elsif str[0, i] == ' ' - list.push ' ' - else - #list.push str[0..i-1] - list.push(str[0..i-1].gsub(/\\(\{|\})/, '\1')) - end - list += tk_split_simplelist(str[i+1..-1]) - list + def array2tk_list(ary) + ary.collect{|e| + if e.kind_of? Array + "{#{array2tk_list(e)}}" + elsif e.kind_of? Hash + "{#{e.to_a.collect{|ee| array2tk_list(ee)}.join(' ')}}" + else + s = _get_eval_string(e) + (s.index(/\s/) || s.size == 0)? "{#{s}}": s + end + }.join(" ") end -=end +end + + private :tk_split_escstr, :tk_split_sublist + private :tk_split_list, :tk_split_simplelist + private :array2tk_list - private :tk_tcl2ruby, :tk_split_escstr, - :tk_split_sublist, :tk_split_list, :tk_split_simplelist + 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 - def hash_kv(keys) - conf = [] +=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 - for k, v in keys - conf.push("-#{k}") - conf.push(v) - end + 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 - conf end private :hash_kv module_function :hash_kv +=end - def array2tk_list(ary) - ary.collect{|e| - if e.kind_of? Array - "{#{array2tk_list(e)}}" - elsif e.kind_of? Hash - "{#{e.to_a.collect{|ee| array2tk_list(ee)}.join(' ')}}" - else - s = _get_eval_string(e) - (s.index(/\s/) || s.size == 0)? "{#{s}}": s - end - }.join(" ") - end - private :array2tk_list - module_function :array2tk_list - +=begin + ### --> definition is moved to TkUtil module def bool(val) case val when "1", 1, 'yes', 'true' @@ -296,6 +392,7 @@ module TkComm false end end + def number(val) case val when /^-?\d+$/ @@ -303,8 +400,7 @@ 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) @@ -316,6 +412,15 @@ module TkComm 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 @@ -331,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] @@ -342,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 @@ -365,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 - def ruby2tcl(v) +=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 + +=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]) @@ -405,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]) @@ -436,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) @@ -443,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 @@ -624,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 @@ -640,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] @@ -654,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 /^<<[^<>]+>>$/ @@ -709,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 @@ -764,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("#<Class(TkCallbackEntry):%0x>", self.__id__) + end + alias to_s inspect + end + def initialize(ip, cmd) @ip = ip @cmd = cmd @@ -773,9 +854,16 @@ module TkCore def call(*args) @ip.cb_eval(@cmd, *args) end - } + def inspect + sprintf("#<cb_entry:%0x>", 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 @@ -783,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 @@ -790,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) @@ -821,16 +919,64 @@ module TkCore end end + WIDGET_DESTROY_HOOK = '<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 "\\{" 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 @@ -842,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)) @@ -875,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 @@ -893,69 +1072,25 @@ module TkCore def after_idle(cmd=Proc.new) myid = _curr_cmd_id cmdid = install_cmd(cmd) - tk_call('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 - end - - def clock_format(clk, form=nil) - if form - tk_call('clock','format',clk,'-format',form).to_i - else - tk_call('clock','format',clk).to_i - end - end - - def clock_formatGMT(clk, form=nil) - if form - tk_call('clock','format',clk,'-format',form,'-gmt','1').to_i - else - tk_call('clock','format',clk,'-gmt','1').to_i - 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 - 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 + tk_call_without_enc('after','idle',cmdid) end def windowingsystem - tk_call('tk', 'windowingsystem') + tk_call_without_enc('tk', 'windowingsystem') end def scaling(scale=nil) if scale - tk_call('tk', 'scaling', scale) + tk_call_without_enc('tk', 'scaling', scale) else - Float(number(tk_call('tk', 'scaling'))) + Float(number(tk_call_without_enc('tk', 'scaling'))) end end def scaling_displayof(win, scale=nil) if scale - tk_call('tk', 'scaling', '-displayof', win, scale) + tk_call_without_enc('tk', 'scaling', '-displayof', win, scale) else - Float(number(tk_call('tk', '-displayof', win, 'scaling'))) + Float(number(tk_call_without_enc('tk', '-displayof', win, 'scaling'))) end end @@ -1049,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 + private :_tk_call_core - 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 - - 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) @@ -1209,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'))] @@ -1226,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' @@ -1254,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.current_grabs - tk_split_list(tk_call('grab', 'current')) + 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(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) @@ -1303,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') @@ -1336,286 +1553,12 @@ 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) - 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 - end - - module Wm - include TkComm - - TkCommandNames = ['wm'.freeze].freeze - - 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 - else - tk_call 'wm', 'focusmodel', path - end - end - def frame - tk_call('wm', 'frame', path) - end - def geometry(geom=nil) - if geom - tk_call('wm', 'geometry', path, geom) - self - else - tk_call('wm', 'geometry', path) - end - end - def grid(*args) - w = tk_call('wm', 'grid', path, *args) - if args.size == 0 - list(w) - else - self - end - end - def group(*args) - w = tk_call('wm', 'group', path, *args) - if args.size == 0 - window(w) - else - self - end - end - def iconbitmap(bmp=nil) - if bmp - tk_call 'wm', 'iconbitmap', path, bmp - self - else - tk_call 'wm', 'iconbitmap', path - end - end - def iconify(ex = true) - tk_call('wm', 'iconify', path) if ex - self - end - def iconmask(bmp=nil) - if bmp - tk_call 'wm', 'iconmask', path, bmp - self - else - tk_call 'wm', 'iconmask', path - end - end - def iconname(name=nil) - if name - tk_call 'wm', 'iconname', path, name - self - else - tk_call 'wm', 'iconname', path - end - end - def iconposition(*args) - w = tk_call('wm', 'iconposition', path, *args) - if args.size == 0 - list(w) - else - self - end - end - def iconwindow(*args) - w = tk_call('wm', 'iconwindow', path, *args) - if args.size == 0 - window(w) - else - self - end - end - def maxsize(*args) - w = tk_call('wm', 'maxsize', path, *args) - if args.size == 0 - list(w) - else - self - end - end - def minsize(*args) - w = tk_call('wm', 'minsize', path, *args) - if args.size == 0 - list(w) - else - self - end - end - def overrideredirect(bool=None) - if bool == None - bool(tk_call('wm', 'overrideredirect', path)) - else - tk_call 'wm', 'overrideredirect', path, bool - self - 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 - 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)) - 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 + def Tk.fromUTF8(str, encoding = nil) + _fromUTF8(str, encoding) end end @@ -1623,46 +1566,20 @@ end # string with Tcl's encoding ########################################### module Tk - class EncodedString < String - @@enc_buf = '__rb_encoding_buffer__' - - def self.tk_escape(str) - s = '"' + str.gsub(/[\[\]$"]/, '\\\\\&') + '"' - #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 + def Tk.subst_utf_backslash(str) + Tk::EncodedString.subst_utf_backslash(str) end - def Tk.EncodedString(str, enc = Tk.encoding_system) - Tk::EncodedString.new(str, enc) + def Tk.subst_tk_backslash(str) + Tk::EncodedString.subst_tk_backslash(str) 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 + def Tk.utf_to_backslash_sequence(str) + Tk::EncodedString.utf_to_backslash_sequence(str) end - def Tk.UTF8_String(str) - Tk::UTF8_String.new(str) + 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 @@ -1670,20 +1587,96 @@ end ########################################### # convert kanji string to/from utf-8 ########################################### -if /^8\.[1-9]/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK +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 + alias __eval _eval alias __invoke _invoke - - attr_accessor :encoding - + + 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 + encoding = __invoke('encoding', 'system') + end + + # convert + case encoding + when 'utf-8', 'binary' + str + else + __toUTF8(str, encoding) + end + end + + def _fromUTF8(str, encoding = nil) + unless encoding + if defined?(@encoding) && @encoding != nil + encoding = @encoding.to_s + else + encoding = __invoke('encoding', 'system') + end + end + + 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 + __fromUTF8(str, encoding) + end + end +=end + + def _eval(cmd) + _fromUTF8(__eval(_toUTF8(cmd))) + end + + def _invoke(*cmds) + _fromUTF8(__invoke(*(cmds.collect{|cmd| _toUTF8(cmd)}))) + end + + alias _eval_with_enc _eval + alias _invoke_with_enc _invoke + +=begin def _eval(cmd) - if defined? @encoding - if cmd.kind_of?(Tk::EncodedString) - _fromUTF8(__eval(_toUTF8(cmd, cmd.encoding)), @encoding) + 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(__eval(_toUTF8(cmd, @encoding)), @encoding) + _fromUTF8(ret, @encoding) end else __eval(cmd) @@ -1691,19 +1684,32 @@ if /^8\.[1-9]/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK end def _invoke(*cmds) - if defined? @encoding + if defined?(@encoding) && @encoding != 'utf-8' cmds = cmds.collect{|cmd| if cmd.kind_of?(Tk::EncodedString) - _toUTF8(cmd, cmd.encoding) + 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 } - _fromUTF8(__invoke(*cmds), @encoding) + ret = __invoke(*cmds) + if ret.kind_of?(String) && ret.instance_variable_get(:@encoding) == 'binary' + ret + else + _fromUTF8(ret, @encoding) + end else __invoke(*cmds) end end +=end end module Tk @@ -1767,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 @@ -1799,1723 +1808,9 @@ 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) - end -end - -class TkBindTag - include TkBindCore - - #BTagID_TBL = {} - BTagID_TBL = TkCore::INTERP.create_table - Tk_BINDTAG_ID = ["btag".freeze, "00000".taint].freeze - - TkCore::INTERP.init_ip_env{ BTagID_TBL.clear } - - def TkBindTag.id2obj(id) - BTagID_TBL[id]? BTagID_TBL[id]: id - end - - 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 - - def initialize(*args, &b) - @id = Tk_BINDTAG_ID.join - Tk_BINDTAG_ID[1].succ! - BTagID_TBL[@id] = self - bind(*args, &b) if args != [] - end - - ALL = self.new_by_name('all') - - def name - @id - end - - def to_eval - @id - end - - def inspect - Kernel.format "#<TkBindTag: %s>", @id - end -end - -class TkBindTagAll<TkBindTag - def TkBindTagAll.new(*args, &b) - $stderr.puts "Warning: TkBindTagALL is obsolete. Use TkBindTag::ALL\n" - - TkBindTag::ALL.bind(*args, &b) if args != [] - TkBindTag::ALL - end -end - -class TkDatabaseClass<TkBindTag - def self.new(name, *args, &b) - return BTagID_TBL[name] if BTagID_TBL[name] - super(name, *args, &b) - end - - def initialize(name, *args, &b) - @id = name - BTagID_TBL[@id] = self - bind(*args, &b) if args != [] - end - - def inspect - Kernel.format "#<TkDatabaseClass: %s>", @id - 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) - name1,name2,op = tk_split_simplelist(args) - if TkVar_CB_TBL[name1] - _get_eval_string(TkVar_CB_TBL[name1].trace_callback(name2,op)) - else - '' - end - 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(/[\[\]$"]/, '\\\\\&') + '"' - 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(/[\[\]$"]/, '\\\\\&') + '"' - 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(/[\[\]$"]/, '\\\\\&') + '"' - 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(/[\[\]$"]/, '\\\\\&') + '"' - 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(/[\[\]$"]/, '\\\\\&') + '"' - 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(/[\[\]$"]/, '\\\\\&') + '"' - 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(/[\[\]$"]/, '\\\\\&') + '"' - 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(/[\[\]$"]/, '\\\\\&') + '"' - 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 - value - 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 "#<TkVariable: %s>", @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<TkVariable - def self.new(name, *args) - return TkVar_ID_TBL[name] if TkVar_ID_TBL[name] - super(name, *args) - end - - def initialize(varname, val=nil) - @id = varname - TkVar_ID_TBL[@id] = self - if val - #s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"' #" - s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"' #" - INTERP._eval(Kernel.format('global %s; set %s %s', @id, @id, s)) - end - end -end - -module Tk - begin - auto_path = INTERP._invoke('set', 'auto_path') - rescue - begin - auto_path = INTERP._invoke('set', 'env(TCLLIBPATH)') - rescue - auto_path = Tk::LIBRARY - end - end - - AUTO_PATH = TkVarAccess.new('auto_path', auto_path) - -=begin - AUTO_OLDPATH = tk_split_simplelist(INTERP._invoke('set', 'auto_oldpath')) - AUTO_OLDPATH.each{|s| s.freeze} - AUTO_OLDPATH.freeze -=end - - TCL_PACKAGE_PATH = TkVarAccess.new('tcl_pkgPath') - PACKAGE_PATH = TCL_PACKAGE_PATH - - TCL_LIBRARY_PATH = TkVarAccess.new('tcl_libPath') - LIBRARY_PATH = TCL_LIBRARY_PATH - - TCL_PRECISION = TkVarAccess.new('tcl_precision') -end - -module TkSelection - include Tk - extend Tk - - TkCommandNames = ['selection'.freeze].freeze - - def self.clear(sel=nil) - if sel - tk_call 'selection', 'clear', '-selection', sel - else - tk_call 'selection', 'clear' - end - end - def self.clear_on_display(win, sel=nil) - if sel - tk_call 'selection', 'clear', '-displayof', win, '-selection', sel - else - tk_call 'selection', 'clear', '-displayof', win - end - end - def clear(sel=nil) - TkSelection.clear_on_display(self, sel) - self - end - - def self.get(keys=nil) - tk_call 'selection', 'get', *hash_kv(keys) - end - def self.get_on_display(win, keys=nil) - tk_call 'selection', 'get', '-displayof', win, *hash_kv(keys) - end - def get(keys=nil) - TkSelection.get_on_display(self, sel) - end - - def self.handle(win, func=Proc.new, keys=nil, &b) - if func.kind_of?(Hash) && keys == nil - keys = func - func = Proc.new(&b) - end - args = ['selection', 'handle'] - args += hash_kv(keys) - args += [win, func] - tk_call(*args) - end - def handle(func=Proc.new, keys=nil, &b) - TkSelection.handle(self, func, keys, &b) - end - - def self.get_owner(sel=nil) - if sel - window(tk_call('selection', 'own', '-selection', sel)) - else - window(tk_call('selection', 'own')) - end - end - def self.get_owner_on_display(win, sel=nil) - if sel - window(tk_call('selection', 'own', '-displayof', win, '-selection', sel)) - else - window(tk_call('selection', 'own', '-displayof', win)) - end - end - def get_owner(sel=nil) - TkSelection.get_owner_on_display(self, sel) - self - end - - def self.set_owner(win, keys=nil) - tk_call('selection', 'own', *(hash_kv(keys) << win)) - end - def set_owner(keys=nil) - TkSelection.set_owner(self, keys) - self - end -end - -module TkKinput - include Tk - extend Tk - - TkCommandNames = [ - 'kinput_start'.freeze, - 'kinput_send_spot'.freeze, - 'kanjiInput'.freeze - ].freeze - - def TkKinput.start(window, style=None) - tk_call 'kinput_start', window.path, style - end - def kinput_start(style=None) - TkKinput.start(self, style) - end - - def TkKinput.send_spot(window) - tk_call 'kinput_send_spot', window.path - end - def kinput_send_spot - TkKinput.send_spot(self) - end - - def TkKinput.input_start(window, keys=nil) - tk_call 'kanjiInput', 'start', window.path, *hash_kv(keys) - end - def kanji_input_start(keys=nil) - TkKinput.input_start(self, keys) - end - - def TkKinput.attribute_config(window, slot, value=None) - if slot.kind_of? Hash - tk_call 'kanjiInput', 'attribute', window.path, *hash_kv(slot) - else - tk_call 'kanjiInput', 'attribute', window.path, "-#{slot}", value - end - end - def kinput_attribute_config(slot, value=None) - TkKinput.attribute_config(self, slot, value) - end - - def TkKinput.attribute_info(window, slot=nil) - if slot - conf = tk_split_list(tk_call('kanjiInput', 'attribute', - window.path, "-#{slot}")) - conf[0] = conf[0][1..-1] - conf - else - tk_split_list(tk_call('kanjiInput', 'attribute', - window.path)).collect{|conf| - conf[0] = conf[0][1..-1] - conf - } - end - end - def kinput_attribute_info(slot=nil) - TkKinput.attribute_info(self, slot) - end - - def TkKinput.input_end(window) - tk_call 'kanjiInput', 'end', window.path - end - def kanji_input_end - TkKinput.input_end(self) - end -end - -module TkXIM - include Tk - extend Tk - - TkCommandNames = ['imconfigure'.freeze].freeze - - def TkXIM.useinputmethods(window=nil, value=nil) - if window - if value - tk_call 'tk', 'useinputmethods', '-displayof', window.path, value - else - tk_call 'tk', 'useinputmethods', '-displayof', window.path - end - else - if value - tk_call 'tk', 'useinputmethods', value - else - tk_call 'tk', 'useinputmethods' - end - end - end - - def TkXIM.caret(window, keys=nil) - if keys - tk_call('tk', 'caret', window, *hash_kv(keys)) - self - else - lst = tk_split_list(tk_call('tk', 'caret', window)) - info = {} - while key = lst.shift - info[key[1..-1]] = lst.shift - end - info - end - end - - def TkXIM.configure(window, slot, value=None) - begin - if /^8\.*/ === Tk::TK_VERSION && JAPANIZED_TK - if slot.kind_of? Hash - tk_call 'imconfigure', window.path, *hash_kv(slot) - else - tk_call 'imconfigure', window.path, "-#{slot}", value - end - end - rescue - end - end - - def TkXIM.configinfo(window, slot=nil) - begin - if /^8\.*/ === Tk::TK_VERSION && JAPANIZED_TK - if slot - conf = tk_split_list(tk_call('imconfigure', window.path, "-#{slot}")) - conf[0] = conf[0][1..-1] - conf - else - tk_split_list(tk_call('imconfigure', window.path)).collect{|conf| - conf[0] = conf[0][1..-1] - conf - } - end - else - [] - end - rescue - [] - end - end - - def useinputmethods(value=nil) - TkXIM.useinputmethods(self, value) - end - - def caret(keys=nil) - TkXIM.caret(self, keys=nil) - end - - def imconfigure(slot, value=None) - TkXIM.configinfo(self, slot, value) - end - - def imconfiginfo(slot=nil) - TkXIM.configinfo(self, slot) - end -end - -module TkWinfo - include Tk - extend Tk - - TkCommandNames = ['winfo'.freeze].freeze - - def TkWinfo.atom(name, win=nil) - if win - number(tk_call('winfo', 'atom', '-displayof', win, name)) - else - number(tk_call('winfo', 'atom', name)) - end - end - def winfo_atom(name) - TkWinfo.atom(name, self) - end - - def TkWinfo.atomname(id, win=nil) - if win - tk_call('winfo', 'atomname', '-displayof', win, id) - else - tk_call('winfo', 'atomname', id) - end - end - def winfo_atomname(id) - TkWinfo.atomname(id, self) - end - - def TkWinfo.cells(window) - number(tk_call('winfo', 'cells', window.path)) - end - def winfo_cells - TkWinfo.cells self - end - - def TkWinfo.children(window) - c = tk_call('winfo', 'children', window.path) - list(c) - end - def winfo_children - TkWinfo.children self - end - - def TkWinfo.classname(window) - tk_call 'winfo', 'class', window.path - end - def winfo_classname - TkWinfo.classname self - end - alias winfo_class winfo_classname - - def TkWinfo.colormapfull(window) - bool(tk_call('winfo', 'colormapfull', window.path)) - end - def winfo_colormapfull - TkWinfo.colormapfull self - end - - def TkWinfo.containing(rootX, rootY, win=nil) - if win - window(tk_call('winfo', 'containing', '-displayof', win, rootX, rootY)) - else - window(tk_call('winfo', 'containing', rootX, rootY)) - end - end - def winfo_containing(x, y) - TkWinfo.containing(x, y, self) - end - - def TkWinfo.depth(window) - number(tk_call('winfo', 'depth', window.path)) - end - def winfo_depth - TkWinfo.depth self - end - - def TkWinfo.exist?(window) - bool(tk_call('winfo', 'exists', window.path)) - end - def winfo_exist? - TkWinfo.exist? self - end - - def TkWinfo.fpixels(window, dist) - number(tk_call('winfo', 'fpixels', window.path, dist)) - end - def winfo_fpixels(dist) - TkWinfo.fpixels self, dist - end - - def TkWinfo.geometry(window) - tk_call('winfo', 'geometry', window.path) - end - def winfo_geometry - TkWinfo.geometry self - end - - def TkWinfo.height(window) - number(tk_call('winfo', 'height', window.path)) - end - def winfo_height - TkWinfo.height self - end - - def TkWinfo.id(window) - tk_call('winfo', 'id', window.path) - end - def winfo_id - TkWinfo.id self - end - - def TkWinfo.interps(window=nil) - if window - tk_split_simplelist(tk_call('winfo', 'interps', - '-displayof', window.path)) - else - tk_split_simplelist(tk_call('winfo', 'interps')) - end - end - def winfo_interps - TkWinfo.interps self - end - - def TkWinfo.mapped?(window) - bool(tk_call('winfo', 'ismapped', window.path)) - end - def winfo_mapped? - TkWinfo.mapped? self - end - - def TkWinfo.manager(window) - tk_call('winfo', 'manager', window.path) - end - def winfo_manager - TkWinfo.manager self - end - - def TkWinfo.appname(window) - tk_call('winfo', 'name', window.path) - end - def winfo_appname - TkWinfo.appname self - end - - def TkWinfo.parent(window) - window(tk_call('winfo', 'parent', window.path)) - end - def winfo_parent - TkWinfo.parent self - end - - def TkWinfo.widget(id, win=nil) - if win - window(tk_call('winfo', 'pathname', '-displayof', win, id)) - else - window(tk_call('winfo', 'pathname', id)) - end - end - def winfo_widget(id) - TkWinfo.widget id, self - end - - def TkWinfo.pixels(window, dist) - number(tk_call('winfo', 'pixels', window.path, dist)) - end - def winfo_pixels(dist) - TkWinfo.pixels self, dist - end - - def TkWinfo.reqheight(window) - number(tk_call('winfo', 'reqheight', window.path)) - end - def winfo_reqheight - TkWinfo.reqheight self - end - - def TkWinfo.reqwidth(window) - number(tk_call('winfo', 'reqwidth', window.path)) - end - def winfo_reqwidth - TkWinfo.reqwidth self - end - - def TkWinfo.rgb(window, color) - list(tk_call('winfo', 'rgb', window.path, color)) - end - def winfo_rgb(color) - TkWinfo.rgb self, color - end - - def TkWinfo.rootx(window) - number(tk_call('winfo', 'rootx', window.path)) - end - def winfo_rootx - TkWinfo.rootx self - end - - def TkWinfo.rooty(window) - number(tk_call('winfo', 'rooty', window.path)) - end - def winfo_rooty - TkWinfo.rooty self - end - - def TkWinfo.screen(window) - tk_call 'winfo', 'screen', window.path - end - def winfo_screen - TkWinfo.screen self - end - - def TkWinfo.screencells(window) - number(tk_call('winfo', 'screencells', window.path)) - end - def winfo_screencells - TkWinfo.screencells self - end - - def TkWinfo.screendepth(window) - number(tk_call('winfo', 'screendepth', window.path)) - end - def winfo_screendepth - TkWinfo.screendepth self - end - - def TkWinfo.screenheight (window) - number(tk_call('winfo', 'screenheight', window.path)) - end - def winfo_screenheight - TkWinfo.screenheight self - end - - def TkWinfo.screenmmheight(window) - number(tk_call('winfo', 'screenmmheight', window.path)) - end - def winfo_screenmmheight - TkWinfo.screenmmheight self - end - - def TkWinfo.screenmmwidth(window) - number(tk_call('winfo', 'screenmmwidth', window.path)) - end - def winfo_screenmmwidth - TkWinfo.screenmmwidth self - end - - def TkWinfo.screenvisual(window) - tk_call('winfo', 'screenvisual', window.path) - end - def winfo_screenvisual - TkWinfo.screenvisual self - end - - def TkWinfo.screenwidth(window) - number(tk_call('winfo', 'screenwidth', window.path)) - end - def winfo_screenwidth - TkWinfo.screenwidth self - end - - def TkWinfo.server(window) - tk_call 'winfo', 'server', window.path - end - def winfo_server - TkWinfo.server self - end - - def TkWinfo.toplevel(window) - window(tk_call('winfo', 'toplevel', window.path)) - end - def winfo_toplevel - TkWinfo.toplevel self - end - - def TkWinfo.visual(window) - tk_call('winfo', 'visual', window.path) - end - def winfo_visual - TkWinfo.visual self - end - - def TkWinfo.visualid(window) - tk_call('winfo', 'visualid', window.path) - end - def winfo_visualid - TkWinfo.visualid self - end - - def TkWinfo.visualsavailable(window, includeids=false) - if includeids - list(tk_call('winfo', 'visualsavailable', window.path, "includeids")) - else - list(tk_call('winfo', 'visualsavailable', window.path)) - end - end - def winfo_visualsavailable(includeids=false) - TkWinfo.visualsavailable self, includeids - end - - def TkWinfo.vrootheight(window) - number(tk_call('winfo', 'vrootheight', window.path)) - end - def winfo_vrootheight - TkWinfo.vrootheight self - end - - def TkWinfo.vrootwidth(window) - number(tk_call('winfo', 'vrootwidth', window.path)) - end - def winfo_vrootwidth - TkWinfo.vrootwidth self - end - - def TkWinfo.vrootx(window) - number(tk_call('winfo', 'vrootx', window.path)) - end - def winfo_vrootx - TkWinfo.vrootx self - end - - def TkWinfo.vrooty(window) - number(tk_call('winfo', 'vrooty', window.path)) - end - def winfo_vrooty - TkWinfo.vrooty self - end - - def TkWinfo.width(window) - number(tk_call('winfo', 'width', window.path)) - end - def winfo_width - TkWinfo.width self - end - - def TkWinfo.x(window) - number(tk_call('winfo', 'x', window.path)) - end - def winfo_x - TkWinfo.x self - end - - def TkWinfo.y(window) - number(tk_call('winfo', 'y', window.path)) - end - def winfo_y - TkWinfo.y self - end - - def TkWinfo.viewable(window) - bool(tk_call('winfo', 'viewable', window.path)) - end - def winfo_viewable - TkWinfo.viewable self - end - - def TkWinfo.pointerx(window) - number(tk_call('winfo', 'pointerx', window.path)) - end - def winfo_pointerx - TkWinfo.pointerx self - end - - def TkWinfo.pointery(window) - number(tk_call('winfo', 'pointery', window.path)) - end - def winfo_pointery - TkWinfo.pointery self - end - - def TkWinfo.pointerxy(window) - list(tk_call('winfo', 'pointerxy', window.path)) - end - def winfo_pointerxy - TkWinfo.pointerxy self - end -end - -module TkPack - include Tk - extend Tk - - TkCommandNames = ['pack'.freeze].freeze - - def configure(win, *args) - if args[-1].kind_of?(Hash) - keys = args.pop - end - wins = [win.epath] - for i in args - wins.push i.epath - end - tk_call "pack", 'configure', *(wins+hash_kv(keys)) end - - def forget(*args) - tk_call 'pack', 'forget' *args - end - - def info(slave) - ilist = list(tk_call('pack', 'info', slave.epath)) - info = {} - while key = ilist.shift - info[key[1..-1]] = ilist.shift - end - return info - end - - def propagate(master, bool=None) - if bool == None - bool(tk_call('pack', 'propagate', master.epath)) - else - tk_call('pack', 'propagate', master.epath, bool) - end - end - - def slaves(master) - list(tk_call('pack', 'slaves', master.epath)) - end - - module_function :configure, :forget, :info, :propagate, :slaves end -module TkGrid - include Tk - extend Tk - - TkCommandNames = ['grid'.freeze].freeze - - def bbox(*args) - list(tk_call('grid', 'bbox', *args)) - end - - def configure(widget, *args) - if args[-1].kind_of?(Hash) - keys = args.pop - end - wins = [] - args.unshift(widget) - for i in args - case i - when '-', 'x', '^' # RELATIVE PLACEMENT - wins.push(i) - else - wins.push(i.epath) - end - end - tk_call "grid", 'configure', *(wins+hash_kv(keys)) - end - - def columnconfigure(master, index, args) - tk_call "grid", 'columnconfigure', master, index, *hash_kv(args) - end - - def rowconfigure(master, index, args) - tk_call "grid", 'rowconfigure', master, index, *hash_kv(args) - end - - def columnconfiginfo(master, index, slot=nil) - if slot - tk_call('grid', 'columnconfigure', master, index, "-#{slot}").to_i - else - ilist = list(tk_call('grid', 'columnconfigure', master, index)) - info = {} - while key = ilist.shift - info[key[1..-1]] = ilist.shift - end - info - end - end - - def rowconfiginfo(master, index, slot=nil) - if slot - tk_call('grid', 'rowconfigure', master, index, "-#{slot}").to_i - else - ilist = list(tk_call('grid', 'rowconfigure', master, index)) - info = {} - while key = ilist.shift - info[key[1..-1]] = ilist.shift - end - info - end - end - - def add(widget, *args) - configure(widget, *args) - end - - def forget(*args) - tk_call 'grid', 'forget', *args - end - - def info(slave) - list(tk_call('grid', 'info', slave)) - end - - def location(master, x, y) - list(tk_call('grid', 'location', master, x, y)) - end - - def propagate(master, bool=None) - if bool == None - bool(tk_call('grid', 'propagate', master.epath)) - else - tk_call('grid', 'propagate', master.epath, bool) - end - end - - def remove(*args) - tk_call 'grid', 'remove', *args - end - - def size(master) - list(tk_call('grid', 'size', master)) - end - - def slaves(master, args) - list(tk_call('grid', 'slaves', master, *hash_kv(args))) - end - - module_function :bbox, :forget, :propagate, :info - module_function :remove, :size, :slaves, :location - module_function :configure, :columnconfigure, :rowconfigure - module_function :columnconfiginfo, :rowconfiginfo -end - -module TkPlace - include Tk - extend Tk - - TkCommandNames = ['place'.freeze].freeze - - def configure(win, slot, value=None) - if slot.kind_of? Hash - tk_call 'place', 'configure', win.epath, *hash_kv(slot) - else - tk_call 'place', 'configure', win.epath, "-#{slot}", value - end - end - - def configinfo(win, slot = nil) - # for >= 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) @@ -3666,198 +1961,37 @@ module TkTreatFont 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, {}) +module TkBindCore + def bind(context, cmd=Proc.new, args=nil) + Tk.bind(self, context, cmd, args) 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, {}) + def bind_append(context, cmd=Proc.new, args=nil) + Tk.bind_append(self, context, cmd, args) 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 + def bind_remove(context) + Tk.bind_remove(self, context) 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 + def bindinfo(context=nil) + Tk.bindinfo(self, context) end end + class TkObject<TkKernel include Tk include TkTreatFont include TkBindCore def path - return @path + @path end def epath - return @path + @path end def to_eval @@ -3865,18 +1999,28 @@ class TkObject<TkKernel end def tk_send(cmd, *rest) - tk_call path, cmd, *rest + tk_call(path, cmd, *rest) + end + def tk_send_without_enc(cmd, *rest) + tk_call_without_enc(path, cmd, *rest) end - private :tk_send + def tk_send_with_enc(cmd, *rest) + tk_call_with_enc(path, cmd, *rest) + end + private :tk_send, :tk_send_without_enc, :tk_send_with_enc def method_missing(id, *args) name = id.id2name case args.length when 1 - configure name, args[0] + if name[-1] == ?= + configure name[0..-2], args[0] + else + configure name, args[0] + end when 0 begin - cget name + cget(name) rescue fail NameError, "undefined local variable or method `#{name}' for #{self.to_s}", @@ -3888,20 +2032,23 @@ class TkObject<TkKernel end def [](id) - cget id + cget(id) end def []=(id, val) - configure id, val + configure(id, val) + val end def cget(slot) case slot.to_s when 'text', 'label', 'show', 'data', 'file' - tk_call path, 'cget', "-#{slot}" + #tk_call(path, 'cget', "-#{slot}") + _fromUTF8(tk_call_without_enc(path, 'cget', "-#{slot}")) when 'font', 'kanjifont' #fnt = tk_tcl2ruby(tk_call(path, 'cget', "-#{slot}")) - fnt = tk_tcl2ruby(tk_call(path, 'cget', "-font")) + #fnt = tk_tcl2ruby(tk_call(path, 'cget', "-font")) + fnt = tk_tcl2ruby(tk_call_without_enc(path, 'cget', "-font"), true) unless fnt.kind_of?(TkFont) fnt = fontobj(fnt) end @@ -3912,7 +2059,7 @@ class TkObject<TkKernel fnt end else - tk_tcl2ruby tk_call(path, 'cget', "-#{slot}") + tk_tcl2ruby(tk_call_without_enc(path, 'cget', "-#{slot}"), true) end end @@ -3924,7 +2071,7 @@ class TkObject<TkKernel slot['asciifont'] || slot[:asciifont] ) font_configure(slot) elsif slot.size > 0 - tk_call path, 'configure', *hash_kv(slot) + tk_call(path, 'configure', *hash_kv(slot)) end else @@ -3938,93 +2085,177 @@ class TkObject<TkKernel font_configure({slot=>value}) end else - tk_call path, 'configure', "-#{slot}", value + tk_call(path, 'configure', "-#{slot}", value) end end self end def configure_cmd(slot, value) - configure slot, install_cmd(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 + 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] + conf[4] = fontobj(conf[4]) 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] + if slot + case slot.to_s when 'text', 'label', 'show', 'data', 'file' + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('configure', "-#{slot}"))) else - if conf[3] - if conf[3].index('{') - conf[3] = tk_split_list(conf[3]) - else - conf[3] = tk_tcl2ruby(conf[3]) + conf = tk_split_list(_fromUTF8(tk_send_without_enc('configure', "-#{slot}"))) + end + conf[0] = conf[0][1..-1] + conf + else + 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 + 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[4] - if conf[4].index('{') - conf[4] = tk_split_list(conf[4]) - else - conf[4] = tk_tcl2ruby(conf[4]) + 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 - 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) + 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 + 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 + 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 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 + def event_generate(context, keys=nil) if keys - tk_call('event', 'generate', path, - "<#{tk_event_sequence(context)}>", *hash_kv(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('event', 'generate', path, "<#{tk_event_sequence(context)}>") + tk_call_without_enc('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)) + fail(ArgumentError, "type error (#{v.class}); must be TkVariable object") end v end private :tk_trace_variable def destroy - # tk_call 'trace', 'vdelete', @tk_vn, 'w', @var_id if @var_id + tk_call 'trace', 'vdelete', @tk_vn, 'w', @var_id if @var_id end end + class TkWindow<TkObject include TkWinfo extend TkBindCore @@ -4086,6 +2317,10 @@ class TkWindow<TkObject end private :create_self + def exist? + TkWinfo.exist?(self) + end + def bind_class @db_class || self.class() end @@ -4109,7 +2344,12 @@ class TkWindow<TkObject end def pack(keys = nil) - tk_call 'pack', epath, *hash_kv(keys) + #tk_call_without_enc('pack', epath, *hash_kv(keys, true)) + if keys + TkPack.configure(self, keys) + else + TkPack.configure(self) + end self end @@ -4120,48 +2360,68 @@ class TkWindow<TkObject else keys = {'in'=>target} end - tk_call 'pack', epath, *hash_kv(keys) + #tk_call 'pack', epath, *hash_kv(keys) + TkPack.configure(self, keys) self end - def unpack - tk_call 'pack', 'forget', epath + def pack_forget + #tk_call_without_enc('pack', 'forget', epath) + TkPack.forget(self) self end - alias pack_forget unpack + 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 - tk_call 'pack', 'configure', epath, *hash_kv(slot) + TkPack.configure(self, slot) else - tk_call 'pack', 'configure', epath, "-#{slot}", value + TkPack.configure(self, 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 + #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 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 - bool(tk_call('pack', 'propagate', epath)) + TkPack.propagate(self) else - tk_call('pack', 'propagate', epath, mode) + TkPack.propagate(self, mode) self end end def pack_slaves() - list(tk_call('pack', 'slaves', epath)) + #list(tk_call('pack', 'slaves', epath)) + TkPack.slaves(self) end def grid(keys = nil) - tk_call 'grid', epath, *hash_kv(keys) + #tk_call 'grid', epath, *hash_kv(keys) + if keys + TkGrid.configure(self, keys) + else + TkGrid.configure(self) + end self end @@ -4172,94 +2432,120 @@ class TkWindow<TkObject else keys = {'in'=>target} end - tk_call 'grid', epath, *hash_kv(keys) + #tk_call 'grid', epath, *hash_kv(keys) + TkGrid.configure(self, keys) self end - def ungrid - tk_call 'grid', 'forget', epath + def grid_forget + #tk_call('grid', 'forget', epath) + TkGrid.forget(self) self end - alias grid_forget ungrid + alias ungrid grid_forget def grid_bbox(*args) - list(tk_call('grid', 'bbox', epath, *args)) + #list(tk_call('grid', 'bbox', epath, *args)) + TkGrid.bbox(self, *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 if slot.kind_of? Hash - tk_call 'grid', 'configure', epath, *hash_kv(slot) + TkGrid.configure(self, slot) else - tk_call 'grid', 'configure', epath, "-#{slot}", value + TkGrid.configure(self, slot=>value) end end def grid_columnconfig(index, keys) - tk_call('grid', 'columnconfigure', epath, index, *hash_kv(keys)) + #tk_call('grid', 'columnconfigure', epath, index, *hash_kv(keys)) + TkGrid.columnconfigure(self, index, keys) end + alias grid_columnconfigure grid_columnconfig def grid_rowconfig(index, keys) - tk_call('grid', 'rowconfigure', epath, index, *hash_kv(keys)) + #tk_call('grid', 'rowconfigure', epath, index, *hash_kv(keys)) + TkGrid.rowconfigure(self, index, keys) end + alias grid_rowconfigure grid_rowconfig 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 + #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 + TkGrid.columnconfiginfo(self, index, slot) 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 + #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 + TkGrid.rowconfiginfo(self, index, slot) end def grid_info() - list(tk_call('grid', 'info', epath)) + #list(tk_call('grid', 'info', epath)) + TkGrid.info(self) end def grid_location(x, y) - list(tk_call('grid', 'location', epath, x, y)) + #list(tk_call('grid', 'location', epath, x, y)) + TkGrid.location(self, 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 if mode == None - bool(tk_call('grid', 'propagate', epath)) + TkGrid.propagete(self) else - tk_call('grid', 'propagate', epath, mode) + TkGrid.propagete(self, mode) self end end def grid_remove() - tk_call 'grid', 'remove', epath + #tk_call 'grid', 'remove', epath + TkGrid.remove(self) self end def grid_size() - list(tk_call('grid', 'size', epath)) + #list(tk_call('grid', 'size', epath)) + TkGrid.size(self) end def grid_slaves(args) - list(tk_call('grid', 'slaves', epath, *hash_kv(args))) + #list(tk_call('grid', 'slaves', epath, *hash_kv(args))) + TkGrid.slaves(self, args) end - def place(keys = nil) - tk_call 'place', epath, *hash_kv(keys) + def place(keys) + #tk_call 'place', epath, *hash_kv(keys) + TkPlace.configure(self, keys) self end @@ -4270,88 +2556,90 @@ class TkWindow<TkObject else keys = {'in'=>target} end - tk_call 'place', epath, *hash_kv(keys) + #tk_call 'place', epath, *hash_kv(keys) + TkPlace.configure(self, keys) self end - def unplace - tk_call 'place', 'forget', epath + def place_forget + #tk_call 'place', 'forget', epath + TkPlace.forget(self) self end - alias place_forget unplace + 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 + #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 + #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 place_info() - ilist = list(tk_call('place', 'info', epath)) - info = {} - while key = ilist.shift - info[key[1..-1]] = ilist.shift - end - return 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 place_slaves() - list(tk_call('place', 'slaves', epath)) + #list(tk_call('place', 'slaves', epath)) + TkPlace.slaves(self) end - def focus(force=false) + def set_focus(force=false) if force - tk_call 'focus', '-force', path + tk_call_without_enc('focus', '-force', path) else - tk_call 'focus', path + tk_call_without_enc('focus', path) end self end + alias focus set_focus - 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 + 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 - fail ArgumentError, 'wrong # of args' + return tk_call_without_enc('grab', args[0], path) end end @@ -4372,20 +2660,30 @@ class TkWindow<TkObject end def lower(below=None) + # below = below.epath if below.kind_of?(TkObject) + below = _epath(below) tk_call 'lower', epath, below self end def raise(above=None) + #above = above.epath if above.kind_of?(TkObject) + above = _epath(above) tk_call 'raise', epath, above self end - def command(cmd=Proc.new) - configure_cmd 'command', cmd + def command(cmd=nil, &b) + if cmd + configure_cmd('command', cmd) + elsif b + configure_cmd('command', Proc.new(&b)) + else + cget('command') + end end - def colormodel model=None - tk_call 'tk', 'colormodel', path, model + def colormodel(model=None) + tk_call('tk', 'colormodel', path, model) self end @@ -4416,7 +2714,7 @@ class TkWindow<TkObject } begin - tk_call 'destroy', epath + tk_call_without_enc('destroy', epath) rescue end uninstall_win @@ -4426,6 +2724,7 @@ class TkWindow<TkObject 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 @@ -4451,6 +2750,7 @@ class TkWindow<TkObject if $SAFE >= 4 fail SecurityError, "can't wait destroy at $SAFE >= 4" end + on_thread &= (Thread.list.size != 1) if on_thread INTERP._thread_tkwait('window', epath) else @@ -4491,6 +2791,7 @@ class TkWindow<TkObject def bindtags=(taglist) bindtags(taglist) + taglist end def bindtags_shift @@ -4505,1499 +2806,6 @@ class TkWindow<TkObject end end -class TkRoot<TkWindow - include Wm - -=begin - ROOT = [] - def TkRoot.new(keys=nil) - if ROOT[0] - Tk_WINDOWS["."] = ROOT[0] - return ROOT[0] - end - new = super(:without_creating=>true, :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 TkToplevel<TkWindow - include Wm - - TkCommandNames = ['toplevel'.freeze].freeze - WidgetClassName = 'Toplevel'.freeze - WidgetClassNames[WidgetClassName] = self - -################# old version -# def initialize(parent=nil, screen=nil, classname=nil, keys=nil) -# if screen.kind_of? Hash -# keys = screen.dup -# else -# @screen = screen -# end -# @classname = classname -# if keys.kind_of? Hash -# keys = keys.dup -# @classname = keys.delete('classname') if keys.key?('classname') -# @colormap = keys.delete('colormap') if keys.key?('colormap') -# @container = keys.delete('container') if keys.key?('container') -# @screen = keys.delete('screen') if keys.key?('screen') -# @use = keys.delete('use') if keys.key?('use') -# @visual = keys.delete('visual') if keys.key?('visual') -# end -# super(parent, keys) -# end -# -# def create_self -# s = [] -# s << "-class" << @classname if @classname -# s << "-colormap" << @colormap if @colormap -# s << "-container" << @container if @container -# s << "-screen" << @screen if @screen -# s << "-use" << @use if @use -# s << "-visual" << @visual if @visual -# tk_call 'toplevel', @path, *s -# end -################# - - def _wm_command_option_chk(keys) - keys = {} unless keys - new_keys = {} - wm_cmds = {} - keys.each{|k,v| - if Wm.method_defined?(k) - case k - when 'screen','class','colormap','container','use','visual' - new_keys[k] = v - else - case self.method(k).arity - when -1,1 - wm_cmds[k] = v - else - new_keys[k] = v - end - end - else - new_keys[k] = v - end - } - [new_keys, wm_cmds] - end - private :_wm_command_option_chk - - def initialize(parent=nil, screen=nil, classname=nil, keys=nil) - my_class_name = nil - if self.class < WidgetClassNames[WidgetClassName] - my_class_name = self.class.name - my_class_name = nil if my_class_name == '' - end - if parent.kind_of? Hash - keys = _symbolkey2str(parent) - if keys.key?('classname') - keys['class'] = keys.delete('classname') - end - @classname = keys['class'] - @colormap = keys['colormap'] - @container = keys['container'] - @screen = keys['screen'] - @use = keys['use'] - @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 - keys, cmds = _wm_command_option_chk(keys) - super(keys) - cmds.each{|k,v| - if v.kind_of? Array - self.send(k,*v) - else - self.send(k,v) - end - } - return - end - - if screen.kind_of? Hash - keys = screen - else - @screen = screen - if classname.kind_of? Hash - keys = classname - else - @classname = classname - end - end - if keys.kind_of? Hash - keys = _symbolkey2str(keys) - if keys.key?('classname') - keys['class'] = keys.delete('classname') - end - @classname = keys['class'] unless @classname - @colormap = keys['colormap'] - @container = keys['container'] - @screen = keys['screen'] unless @screen - @use = keys['use'] - @visual = keys['visual'] - else - keys = {} - end - 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 - keys, cmds = _wm_command_option_chk(keys) - super(parent, keys) - cmds.each{|k,v| - if v.kind_of? Array - self.send(k,*v) - else - self.send(k,v) - end - } - end - - def create_self(keys) - if keys and keys != None - tk_call 'toplevel', @path, *hash_kv(keys) - else - tk_call 'toplevel', @path - end - end - private :create_self - - def specific_class - @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 TkFrame<TkWindow - TkCommandNames = ['frame'.freeze].freeze - WidgetClassName = 'Frame'.freeze - WidgetClassNames[WidgetClassName] = self - -################# old version -# def initialize(parent=nil, keys=nil) -# if keys.kind_of? Hash -# keys = keys.dup -# @classname = keys.delete('classname') if keys.key?('classname') -# @colormap = keys.delete('colormap') if keys.key?('colormap') -# @container = keys.delete('container') if keys.key?('container') -# @visual = keys.delete('visual') if keys.key?('visual') -# end -# super(parent, keys) -# end -# -# def create_self -# s = [] -# s << "-class" << @classname if @classname -# s << "-colormap" << @colormap if @colormap -# s << "-container" << @container if @container -# s << "-visual" << @visual if @visual -# tk_call 'frame', @path, *s -# end -################# - - def initialize(parent=nil, keys=nil) - my_class_name = nil - if self.class < WidgetClassNames[WidgetClassName] - my_class_name = self.class.name - my_class_name = nil if my_class_name == '' - end - if parent.kind_of? Hash - keys = _symbolkey2str(parent) - else - if keys - keys = _symbolkey2str(keys) - keys['parent'] = parent - else - keys = {'parent'=>parent} - 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 TkLabelFrame<TkFrame - TkCommandNames = ['labelframe'.freeze].freeze - WidgetClassName = 'Labelframe'.freeze - WidgetClassNames[WidgetClassName] = self - def create_self(keys) - if keys and keys != None - tk_call 'labelframe', @path, *hash_kv(keys) - else - tk_call 'labelframe', @path - end - end - private :create_self -end -TkLabelframe = TkLabelFrame - -class TkPanedWindow<TkWindow - TkCommandNames = ['panedwindow'.freeze].freeze - WidgetClassName = 'Panedwindow'.freeze - WidgetClassNames[WidgetClassName] = self - def create_self(keys) - if keys and keys != None - tk_call 'panedwindow', @path, *hash_kv(keys) - else - tk_call 'panedwindow', @path - end - end - private :create_self - - def add(*args) - keys = args.pop - fail ArgumentError, "no window in arguments" unless keys - if keys && keys.kind_of?(Hash) - fail ArgumentError, "no window in arguments" if args == [] - args = args.collect{|w| w.epath} - args.push(hash_kv(keys)) - else - args.push(keys) if keys - args = args.collect{|w| w.epath} - end - tk_send('add', *args) - self - end - - def forget(win, *wins) - tk_send('forget', win.epath, *(wins.collect{|w| w.epath})) - self - end - alias del forget - alias delete forget - alias remove forget - - def identify(x, y) - list(tk_send('identify', x, y)) - end - - def proxy_coord - list(tk_send('proxy', 'coord')) - end - def proxy_forget - tk_send('proxy', 'forget') - self - end - def proxy_place(x, y) - tk_send('proxy', 'place', x, y) - self - end - - def sash_coord(index) - list(tk_send('sash', 'coord', index)) - end - def sash_dragto(index) - tk_send('sash', 'dragto', index, x, y) - self - end - def sash_mark(index, x, y) - tk_send('sash', 'mark', index, x, y) - self - end - def sash_place(index, x, y) - tk_send('sash', 'place', index, x, y) - self - end - - def panecget(win, key) - tk_tcl2ruby(tk_send('panecget', win.epath, "-#{key}")) - end - - def paneconfigure(win, key, value=nil) - if key.kind_of? Hash - tk_send('paneconfigure', win.epath, *hash_kv(key)) - else - tk_send('paneconfigure', win.epath, "-#{key}", value) - end - self - end - alias pane_config paneconfigure - - def paneconfiginfo(win, key=nil) - if key - conf = tk_split_list(tk_send('paneconfigure', win.epath, "-#{key}")) - conf[0] = conf[0][1..-1] - conf - else - tk_split_simplelist(tk_send('paneconfigure', - win.epath)).collect{|conflist| - conf = tk_split_simplelist(conflist) - conf[0] = conf[0][1..-1] - 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 - conf - } - end - end - alias pane_configinfo paneconfiginfo - - def panes - list(tk_send('panes')) - end -end -TkPanedwindow = TkPanedWindow - -class TkLabel<TkWindow - TkCommandNames = ['label'.freeze].freeze - WidgetClassName = 'Label'.freeze - WidgetClassNames[WidgetClassName] = self - def create_self(keys) - if keys and keys != None - tk_call 'label', @path, *hash_kv(keys) - else - tk_call 'label', @path - end - end - private :create_self - - def textvariable(v) - configure 'textvariable', tk_trace_variable(v) - end -end - -class TkButton<TkLabel - TkCommandNames = ['button'.freeze].freeze - WidgetClassName = 'Button'.freeze - WidgetClassNames[WidgetClassName] = self - def create_self(keys) - if keys and keys != None - tk_call 'button', @path, *hash_kv(keys) - else - tk_call 'button', @path - end - end - private :create_self - - def invoke - tk_send 'invoke' - end - def flash - tk_send 'flash' - self - end -end - -class TkRadioButton<TkButton - TkCommandNames = ['radiobutton'.freeze].freeze - WidgetClassName = 'Radiobutton'.freeze - WidgetClassNames[WidgetClassName] = self - def create_self(keys) - if keys and keys != None - tk_call 'radiobutton', @path, *hash_kv(keys) - else - tk_call 'radiobutton', @path - end - end - private :create_self - - def deselect - tk_send 'deselect' - self - end - def select - tk_send 'select' - self - end - def variable(v) - configure 'variable', tk_trace_variable(v) - end -end -TkRadiobutton = TkRadioButton - -class TkCheckButton<TkRadioButton - TkCommandNames = ['checkbutton'.freeze].freeze - WidgetClassName = 'Checkbutton'.freeze - WidgetClassNames[WidgetClassName] = self - def create_self(keys) - if keys and keys != None - tk_call 'checkbutton', @path, *hash_kv(keys) - else - tk_call 'checkbutton', @path - end - end - private :create_self - - def toggle - tk_send 'toggle' - self - end -end -TkCheckbutton = TkCheckButton - -class TkMessage<TkLabel - TkCommandNames = ['message'.freeze].freeze - WidgetClassName = 'Message'.freeze - WidgetClassNames[WidgetClassName] = self - def create_self(keys) - if keys and keys != None - tk_call 'message', @path, *hash_kv(keys) - else - tk_call 'message', @path - end - end - private :create_self -end - -class TkScale<TkWindow - TkCommandNames = ['scale'.freeze].freeze - WidgetClassName = 'Scale'.freeze - WidgetClassNames[WidgetClassName] = self - - def create_self(keys) - if keys and keys != None - if keys.key?('command') - cmd = keys.delete('command') - keys['command'] = proc{|val| cmd.call(val.to_f)} - end - tk_call 'scale', @path, *hash_kv(keys) - else - tk_call 'scale', @path - end - end - private :create_self - - def _wrap_command_arg(cmd) - proc{|val| - if val.kind_of?(String) - cmd.call(number(val)) - else - cmd.call(val) - end - } - end - private :_wrap_command_arg - - def configure_cmd(slot, value) - configure(slot=>value) - 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<TkWindow - TkCommandNames = ['scrollbar'.freeze].freeze - WidgetClassName = 'Scrollbar'.freeze - WidgetClassNames[WidgetClassName] = self - - def create_self(keys) - @assigned = [] - @scroll_proc = proc{|*args| - if self.orient == 'horizontal' - @assigned.each{|w| w.xview(*args)} - else # 'vertical' - @assigned.each{|w| w.yview(*args)} - end - } - - if keys and keys != None - tk_call 'scrollbar', @path, *hash_kv(keys) - else - tk_call 'scrollbar', @path - end - end - private :create_self - - def assign(*wins) - begin - self.command(@scroll_proc) if self.cget('command').cmd != @scroll_proc - rescue Exception - self.command(@scroll_proc) - end - orient = self.orient - wins.each{|w| - @assigned << w unless @assigned.index(w) - if orient == 'horizontal' - w.xscrollcommand proc{|first, last| self.set(first, last)} - else # 'vertical' - w.yscrollcommand proc{|first, last| self.set(first, last)} - end - } - self - end - - def assigned_list - begin - return @assigned.dup if self.cget('command').cmd == @scroll_proc - rescue Exception - end - fail RuntimeError, "not depend on the assigned_list" - end - - def delta(deltax=None, deltay=None) - number(tk_send('delta', deltax, deltay)) - end - - def fraction(x=None, y=None) - number(tk_send('fraction', x, y)) - end - - def identify(x, y) - tk_send('identify', x, y) - end - - def get - ary1 = tk_send('get').split - ary2 = [] - for i in ary1 - ary2.push number(i) - end - ary2 - end - - def set(first, last) - tk_send "set", first, last - self - end - - def activate(element=None) - tk_send('activate', element) - end -end - -class TkXScrollbar<TkScrollbar - def create_self(keys) - keys = {} unless keys - keys['orient'] = 'horizontal' - super(keys) - end - private :create_self -end - -class TkYScrollbar<TkScrollbar - def create_self(keys) - keys = {} unless keys - keys['orient'] = 'vertical' - super(keys) - end - private :create_self -end - -class TkTextWin<TkWindow - def create_self - fail RuntimeError, "TkTextWin is an abstract class" - end - private :create_self - - def bbox(index) - list(tk_send('bbox', index)) - end - def delete(first, last=None) - tk_send 'delete', first, last - self - end - def get(*index) - tk_send 'get', *index - end - def insert(index, *args) - tk_send 'insert', index, *args - 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 see(index) - tk_send 'see', index - self - end -end - -module TkTreatListItemFont - include TkTreatItemFont - - ItemCMD = ['itemconfigure'.freeze, TkComm::None].freeze - def __conf_cmd(idx) - ItemCMD[idx] - end - - def __item_pathname(tagOrId) - self.path + ';' + tagOrId.to_s - end - - private :__conf_cmd, :__item_pathname -end - -class TkListbox<TkTextWin - include TkTreatListItemFont - include Scrollable - - TkCommandNames = ['listbox'.freeze].freeze - WidgetClassName = 'Listbox'.freeze - WidgetClassNames[WidgetClassName] = self - - def create_self(keys) - if keys and keys != None - tk_call 'listbox', @path, *hash_kv(keys) - else - tk_call 'listbox', @path - end - end - private :create_self - - def activate(y) - tk_send 'activate', y - self - end - def curselection - list(tk_send('curselection')) - end - def get(*index) - v = tk_send('get', *index) - if index.size == 1 - v - else - tk_split_simplelist(v) - end - end - def nearest(y) - tk_send('nearest', y).to_i - end - def size - tk_send('size').to_i - end - def selection_anchor(index) - tk_send 'selection', 'anchor', index - self - end - def selection_clear(first, last=None) - tk_send 'selection', 'clear', first, last - self - end - def selection_includes(index) - bool(tk_send('selection', 'includes', index)) - end - def selection_set(first, last=None) - tk_send 'selection', 'set', first, last - self - end - - def index(index) - tk_send('index', index).to_i - end - - def itemcget(index, key) - case key.to_s - when 'text', 'label', 'show' - tk_send('itemcget', index, "-#{key}") - when 'font', 'kanjifont' - #fnt = tk_tcl2ruby(tk_send('itemcget', index, "-#{key}")) - fnt = tk_tcl2ruby(tk_send('itemcget', 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 - else - tk_tcl2ruby(tk_send('itemcget', index, "-#{key}")) - end - end - def itemconfigure(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 'itemconfigure', index, *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(index) - else - tagfont_configure(index, {key=>val}) - end - else - tk_call 'itemconfigure', index, "-#{key}", val - 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) - 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 - } - 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) - else - ret - end - end - end -end - -module TkTreatMenuEntryFont - include TkTreatItemFont - - ItemCMD = ['entryconfigure'.freeze, TkComm::None].freeze - def __conf_cmd(idx) - ItemCMD[idx] - end - - def __item_pathname(tagOrId) - self.path + ';' + tagOrId.to_s - end - - private :__conf_cmd, :__item_pathname -end - -class TkMenu<TkWindow - include TkTreatMenuEntryFont - - TkCommandNames = ['menu'.freeze].freeze - WidgetClassName = 'Menu'.freeze - WidgetClassNames[WidgetClassName] = self - - def create_self(keys) - if keys and keys != None - tk_call 'menu', @path, *hash_kv(keys) - else - tk_call 'menu', @path - end - end - private :create_self - - def activate(index) - tk_send 'activate', index - self - end - def add(type, keys=nil) - tk_send 'add', type, *hash_kv(keys) - self - end - def add_cascade(keys=nil) - add('cascade', keys) - end - def add_checkbutton(keys=nil) - add('checkbutton', keys) - end - def add_command(keys=nil) - add('command', keys) - end - def add_radiobutton(keys=nil) - add('radiobutton', keys) - end - def add_separator(keys=nil) - add('separator', keys) - end - def index(index) - ret = tk_send('index', index) - (ret == 'none')? nil: number(ret) - end - def invoke(index) - tk_send 'invoke', index - end - def insert(index, type, keys=nil) - tk_send 'insert', index, type, *hash_kv(keys) - self - end - def delete(index, last=None) - tk_send 'delete', index, last - self - end - def popup(x, y, index=None) - tk_call('tk_popup', path, x, y, index) - self - end - def post(x, y) - tk_send 'post', x, y - self - end - def postcascade(index) - tk_send 'postcascade', index - self - end - def postcommand(cmd=Proc.new) - configure_cmd 'postcommand', cmd - self - end - def set_focus - tk_call('tk_menuSetFocus', path) - end - def tearoffcommand(cmd=Proc.new) - configure_cmd 'tearoffcommand', cmd - self - end - def menutype(index) - tk_send 'type', index - end - def unpost - tk_send 'unpost' - end - def yposition(index) - number(tk_send('yposition', index)) - 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 - else - tk_tcl2ruby(tk_send('entrycget', index, "-#{key}")) - end - 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 - - 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 - end - 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 - end -end - -class TkMenuClone<TkMenu - def initialize(parent, type=None) - widgetname = nil - if parent.kind_of? Hash - keys = _symbolkey2str(parent) - parent = keys.delete('parent') - widgetname = keys.delete('widgetname') - type = keys.delete('type'); type = None unless type - end - unless parent.kind_of?(TkMenu) - fail ArgumentError, "parent must be TkMenu" - end - @parent = parent - install_win(@parent.path, widgetname) - tk_call @parent.path, 'clone', @path, type - end -end - -module TkSystemMenu - def initialize(parent, keys=nil) - if parent.kind_of? Hash - keys = _symbolkey2str(parent) - parent = keys.delete('parent') - end - unless parent.kind_of? TkMenu - fail ArgumentError, "parent must be a TkMenu object" - end - @path = Kernel.format("%s.%s", parent.path, self.class::SYSMENU_NAME) - #TkComm::Tk_WINDOWS[@path] = self - TkCore::INTERP.tk_windows[@path] = self - if self.method(:create_self).arity == 0 - p 'create_self has no arg' if $DEBUG - create_self - configure(keys) if keys - else - p 'create_self has an arg' if $DEBUG - create_self(keys) - end - end -end - -class TkSysMenu_Help<TkMenu - # for all platform - include TkSystemMenu - SYSMENU_NAME = 'help' -end - -class TkSysMenu_System<TkMenu - # for Windows - include TkSystemMenu - SYSMENU_NAME = 'system' -end - -class TkSysMenu_Apple<TkMenu - # for Machintosh - include TkSystemMenu - SYSMENU_NAME = 'apple' -end - -class TkMenubutton<TkLabel - TkCommandNames = ['menubutton'.freeze].freeze - WidgetClassName = 'Menubutton'.freeze - WidgetClassNames[WidgetClassName] = self - def create_self(keys) - if keys and keys != None - tk_call 'menubutton', @path, *hash_kv(keys) - else - tk_call 'menubutton', @path - end - end - private :create_self -end - -class TkOptionMenubutton<TkMenubutton - TkCommandNames = ['tk_optionMenu'.freeze].freeze - - class OptionMenu<TkMenu - def initialize(path) #==> return value of tk_optionMenu - @path = path - #TkComm::Tk_WINDOWS[@path] = self - TkCore::INTERP.tk_windows[@path] = self - end - 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)) - end - - def value - @variable.value - end - - def activate(index) - @menu.activate(index) - self - end - def add(value) - @menu.add('radiobutton', 'variable'=>@variable, - 'label'=>value, 'value'=>value) - self - end - def index(index) - @menu.index(index) - end - def invoke(index) - @menu.invoke(index) - end - def insert(index, value) - @menu.add(index, 'radiobutton', 'variable'=>@variable, - 'label'=>value, 'value'=>value) - self - end - def delete(index, last=None) - @menu.delete(index, last) - self - end - def yposition(index) - @menu.yposition(index) - end - def menu - @menu - end - def menucget(key) - @menu.cget(key) - end - def menuconfigure(key, val=None) - @menu.configure(key, val) - self - end - def menuconfiginfo(key=nil) - @menu.configinfo(key) - end - def entrycget(index, key) - @menu.entrycget(index, key) - end - def entryconfigure(index, key, val=None) - @menu.entryconfigure(index, key, val) - self - end - def entryconfiginfo(index, key=nil) - @menu.entryconfiginfo(index, key) - 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) - else - @frame = TkFrame.new(parent) - @delegates['DEFAULT'] = @frame - @path = @epath = @frame.path - initialize_composite(*args) - end - end - - def epath - @epath - end - - def initialize_composite(*args) end - private :initialize_composite - - def delegate(option, *wins) - if @delegates[option].kind_of?(Array) - for i in wins - @delegates[option].push(i) - 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 - end - last - else - super - end - end - 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 - else - tk_call 'clipboard', 'clear' - end - end - def self.clear_on_display(win) - tk_call 'clipboard', 'clear', '-displayof', win - end - - def self.get(type=nil) - if type - tk_call 'clipboard', 'get', '-type', type - else - tk_call 'clipboard', 'get' - end - end - def self.get_on_display(win, type=nil) - if type - tk_call 'clipboard', 'get', '-displayof', win, '-type', type - else - tk_call 'clipboard', 'get', '-displayof', win - end - end - - def self.set(data, keys=nil) - clear - append(data, keys) - end - def self.set_on_display(win, data, keys=nil) - clear(win) - append_on_display(win, data, keys) - end - - 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) - end - - def clear - TkClipboard.clear_on_display(self) - self - end - def get(type=nil) - TkClipboard.get_on_display(self, type) - end - def set(data, keys=nil) - TkClipboard.set_on_display(self, data, keys) - self - end - def append(data, keys=nil) - TkClipboard.append_on_display(self, data, keys) - self - 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 @@ -6009,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/tk/after.rb b/ext/tk/lib/tk/after.rb new file mode 100644 index 0000000000..8c58210331 --- /dev/null +++ b/ext/tk/lib/tk/after.rb @@ -0,0 +1,6 @@ +# +# tk/after.rb : methods for Tcl/Tk after command +# +# $Id$ +# +require 'tk/timer' diff --git a/ext/tk/lib/tk/autoload.rb b/ext/tk/lib/tk/autoload.rb new file mode 100644 index 0000000000..0a8251af8b --- /dev/null +++ b/ext/tk/lib/tk/autoload.rb @@ -0,0 +1,181 @@ +# +# autoload +# + +####################### +# geometry manager +autoload :TkGrid, 'tk/grid' +def TkGrid(*args); TkGrid.configure(*args); end + +autoload :TkPack, 'tk/pack' +def TkPack(*args); TkPack.configure(*args); end + +autoload :TkPlace, 'tk/place' +def TkPlace(*args); TkPlace.configure(*args); end + + +####################### +# others +autoload :TkBgError, 'tk/bgerror' + +autoload :TkBindTag, 'tk/bindtag' +autoload :TkBindTagAll, 'tk/bindtag' +autoload :TkDatabaseClass, 'tk/bindtag' + +autoload :TkButton, 'tk/button' + +autoload :TkConsole, 'tk/console' + +autoload :TkCanvas, 'tk/canvas' + +autoload :TkcTagAccess, 'tk/canvastag' +autoload :TkcTag, 'tk/canvastag' +autoload :TkcTagString, 'tk/canvastag' +autoload :TkcNamedTag, 'tk/canvastag' +autoload :TkcTagAll, 'tk/canvastag' +autoload :TkcTagCurrent, 'tk/canvastag' +autoload :TkcTagGroup, 'tk/canvastag' + +autoload :TkCheckButton, 'tk/checkbutton' +autoload :TkCheckbutton, 'tk/checkbutton' + +autoload :TkClipboard, 'tk/clipboard' + +autoload :TkComposite, 'tk/composite' + +autoload :TkConsole, 'tk/console' + +autoload :TkDialog, 'tk/dialog' +autoload :TkDialog2, 'tk/dialog' +autoload :TkWarning, 'tk/dialog' +autoload :TkWarning2, 'tk/dialog' + +autoload :TkEntry, 'tk/entry' + +autoload :TkEvent, 'tk/event' + +autoload :TkFont, 'tk/font' +autoload :TkTreatTagFont, 'tk/font' + +autoload :TkFrame, 'tk/frame' + +autoload :TkImage, 'tk/image' +autoload :TkBitmapImage, 'tk/image' +autoload :TkPhotoImage, 'tk/image' + +autoload :TkTreatItemFont, 'tk/itemfont' + +autoload :TkKinput, 'tk/kinput' + +autoload :TkLabel, 'tk/label' + +autoload :TkLabelFrame, 'tk/labelframe' +autoload :TkLabelframe, 'tk/labelframe' + +autoload :TkListbox, 'tk/listbox' + +autoload :TkMacResource, 'tk/macpkg' + +autoload :TkMenu, 'tk/menu' +autoload :TkMenuClone, 'tk/menu' +autoload :TkSystemMenu, 'tk/menu' +autoload :TkSysMenu_Help, 'tk/menu' +autoload :TkSysMenu_System, 'tk/menu' +autoload :TkSysMenu_Apple, 'tk/menu' +autoload :TkMenubutton, 'tk/menu' +autoload :TkOptionMenubutton, 'tk/menu' + +autoload :TkMenubar, 'tk/menubar' + +autoload :TkMessage, 'tk/message' + +autoload :TkManageFocus, 'tk/mngfocus' + +autoload :TkMsgCatalog, 'tk/msgcat' +autoload :TkMsgCat, 'tk/msgcat' + +autoload :TkNamespace, 'tk/namespace' + +autoload :TkOptionDB, 'tk/optiondb' +autoload :TkOption, 'tk/optiondb' +autoload :TkResourceDB, 'tk/optiondb' + +autoload :TkPackage, 'tk/package' + +autoload :TkPalette, 'tk/palette' + +autoload :TkPanedWindow, 'tk/panedwindow' +autoload :TkPanedwindow, 'tk/panedwindow' + +autoload :TkRadioButton, 'tk/radiobutton' +autoload :TkRadiobutton, 'tk/radiobutton' + +autoload :TkRoot, 'tk/root' + +autoload :TkScale, 'tk/scale' + +autoload :TkScrollbar, 'tk/scrollbar' +autoload :TkXScrollbar, 'tk/scrollbar' +autoload :TkYScrollbar, 'tk/scrollbar' + +autoload :TkScrollbox, 'tk/scrollbox' + +autoload :TkSelection, 'tk/selection' + +autoload :TkSpinbox, 'tk/spinbox' + +autoload :TkTreatTagFont, 'tk/tagfont' + +autoload :TkText, 'tk/text' + +autoload :TkTextImage, 'tk/textimage' + +autoload :TkTextMark, 'tk/textmark' +autoload :TkTextNamedMark, 'tk/textmark' +autoload :TkTextMarkInsert, 'tk/textmark' +autoload :TkTextMarkCurrent, 'tk/textmark' +autoload :TkTextMarkAnchor, 'tk/textmark' + +autoload :TkTextTag, 'tk/texttag' +autoload :TkTextNamedTag, 'tk/texttag' +autoload :TkTextTagSel, 'tk/texttag' + +autoload :TkTextWindow, 'tk/textwindow' + +autoload :TkAfter, 'tk/timer' +autoload :TkTimer, 'tk/timer' + +autoload :TkToplevel, 'tk/toplevel' + +autoload :TkTextWin, 'tk/txtwin_abst' + +autoload :TkValidation, 'tk/validation' +autoload :TkVariable, 'tk/variable' +autoload :TkVarAccess, 'tk/variable' + +autoload :TkVirtualEvent, 'tk/virtevent' + +autoload :TkWinfo, 'tk/winfo' + +autoload :TkWinDDE, 'tk/winpkg' +autoload :TkWinRegistry, 'tk/winpkg' + +autoload :TkXIM, 'tk/xim' + + +####################### +# sub-module of Tk +module Tk + autoload :Clock, 'tk/clock' + autoload :Scrollable, 'tk/scrollable' + autoload :Wm, 'tk/wm' + + autoload :EncodedString, 'tk/encodedstr' + def Tk.EncodedString(str, enc = nil); Tk::EncodedString.new(str, enc); end + + autoload :BinaryString, 'tk/encodedstr' + def Tk.BinaryString(str); Tk::BinaryString.new(str); end + + autoload :UTF8_String, 'tk/encodedstr' + def Tk.UTF8_String(str); Tk::UTF8_String.new(str); end +end diff --git a/ext/tk/lib/tk/bgerror.rb b/ext/tk/lib/tk/bgerror.rb new file mode 100644 index 0000000000..c82a8e046b --- /dev/null +++ b/ext/tk/lib/tk/bgerror.rb @@ -0,0 +1,29 @@ +# +# tkbgerror -- bgerror ( tkerror ) module +# 1998/07/16 by Hidetoshi Nagai <nagai@ai.kyutech.ac.jp> +# +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 diff --git a/ext/tk/lib/tk/bindtag.rb b/ext/tk/lib/tk/bindtag.rb new file mode 100644 index 0000000000..d309ea6423 --- /dev/null +++ b/ext/tk/lib/tk/bindtag.rb @@ -0,0 +1,78 @@ +# +# tk/bind.rb : control event binding +# +require 'tk' + +class TkBindTag + include TkBindCore + + #BTagID_TBL = {} + BTagID_TBL = TkCore::INTERP.create_table + Tk_BINDTAG_ID = ["btag".freeze, "00000".taint].freeze + + TkCore::INTERP.init_ip_env{ BTagID_TBL.clear } + + def TkBindTag.id2obj(id) + BTagID_TBL[id]? BTagID_TBL[id]: id + end + + 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 + + def initialize(*args, &b) + @id = Tk_BINDTAG_ID.join('') + Tk_BINDTAG_ID[1].succ! + BTagID_TBL[@id] = self + bind(*args, &b) if args != [] + end + + ALL = self.new_by_name('all') + + def name + @id + end + + def to_eval + @id + end + + def inspect + #Kernel.format "#<TkBindTag: %s>", @id + '#<TkBindTag: ' + @id + '>' + end +end + + +class TkBindTagAll<TkBindTag + def TkBindTagAll.new(*args, &b) + $stderr.puts "Warning: TkBindTagALL is obsolete. Use TkBindTag::ALL\n" + + TkBindTag::ALL.bind(*args, &b) if args != [] + TkBindTag::ALL + end +end + + +class TkDatabaseClass<TkBindTag + def self.new(name, *args, &b) + return BTagID_TBL[name] if BTagID_TBL[name] + super(name, *args, &b) + end + + def initialize(name, *args, &b) + @id = name + BTagID_TBL[@id] = self + bind(*args, &b) if args != [] + end + + def inspect + #Kernel.format "#<TkDatabaseClass: %s>", @id + '#<TkDatabaseClass: ' + @id + '>' + end +end diff --git a/ext/tk/lib/tk/button.rb b/ext/tk/lib/tk/button.rb new file mode 100644 index 0000000000..15e87c300d --- /dev/null +++ b/ext/tk/lib/tk/button.rb @@ -0,0 +1,27 @@ +# +# tk/button.rb : treat button widget +# +require 'tk' +require 'tk/label' + +class TkButton<TkLabel + TkCommandNames = ['button'.freeze].freeze + WidgetClassName = 'Button'.freeze + WidgetClassNames[WidgetClassName] = self + def create_self(keys) + if keys and keys != None + tk_call_without_enc('button', @path, *hash_kv(keys, true)) + else + tk_call_without_enc('button', @path) + end + end + private :create_self + + def invoke + _fromUTF8(tk_send_without_enc('invoke')) + end + def flash + tk_send_without_enc('flash') + self + end +end diff --git a/ext/tk/lib/tk/canvas.rb b/ext/tk/lib/tk/canvas.rb new file mode 100644 index 0000000000..7defecdfe4 --- /dev/null +++ b/ext/tk/lib/tk/canvas.rb @@ -0,0 +1,697 @@ +# +# tk/canvas.rb - Tk canvas classes +# $Date$ +# by Yukihiro Matsumoto <matz@caelum.co.jp> +# $Date$ +# by Hidetoshi Nagai <nagai@ai.kyutech.ac.jp> +# +require 'tk' +require 'tk/canvastag' +require 'tk/itemfont' +require 'tk/scrollable' + +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 TkCanvas<TkWindow + include TkTreatCItemFont + include Scrollable + + TkCommandNames = ['canvas'.freeze].freeze + WidgetClassName = 'Canvas'.freeze + WidgetClassNames[WidgetClassName] = self + + def __destroy_hook__ + TkcItem::CItemID_TBL.delete(@path) + end + + def create_self(keys) + if keys and keys != None + tk_call_without_enc('canvas', @path, *hash_kv(keys, true)) + else + tk_call_without_enc('canvas', @path) + end + end + private :create_self + + def tagid(tag) + if tag.kind_of?(TkcItem) || tag.kind_of?(TkcTag) + tag.id + else + tag + end + end + private :tagid + + + def create(type, *args) + # create a canvas item without creating a TkcItem object + if type.kind_of?(TkcItem) + fail ArgumentError, 'TkcItem class expected for 1st argument' + end + type.create(@path, *args) + end + + + def addtag(tag, mode, *args) + tk_send_without_enc('addtag', tagid(tag), mode, *args) + self + end + def addtag_above(tagOrId, target) + addtag(tagOrId, 'above', tagid(target)) + end + def addtag_all(tagOrId) + addtag(tagOrId, 'all') + end + def addtag_below(tagOrId, target) + addtag(tagOrId, 'below', tagid(target)) + end + def addtag_closest(tagOrId, x, y, halo=None, start=None) + addtag(tagOrId, 'closest', x, y, halo, start) + end + def addtag_enclosed(tagOrId, x1, y1, x2, y2) + addtag(tagOrId, 'enclosed', x1, y1, x2, y2) + end + def addtag_overlapping(tagOrId, x1, y1, x2, y2) + addtag(tagOrId, 'overlapping', x1, y1, x2, y2) + end + def addtag_withtag(tagOrId, tag) + addtag(tagOrId, 'withtag', tagid(tag)) + end + + def bbox(tagOrId, *tags) + list(tk_send_without_enc('bbox', tagid(tagOrId), + *tags.collect{|t| tagid(t)})) + end + + def itembind(tag, context, cmd=Proc.new, args=nil) + _bind([path, "bind", tagid(tag)], context, cmd, args) + self + end + + def itembind_append(tag, context, cmd=Proc.new, args=nil) + _bind_append([path, "bind", tagid(tag)], context, cmd, args) + self + end + + def itembind_remove(tag, context) + _bind_remove([path, "bind", tagid(tag)], context) + self + end + + def itembindinfo(tag, context=nil) + _bindinfo([path, "bind", tagid(tag)], context) + end + + def canvasx(screen_x, *args) + #tk_tcl2ruby(tk_send_without_enc('canvasx', screen_x, *args)) + number(tk_send_without_enc('canvasx', screen_x, *args)) + end + def canvasy(screen_y, *args) + #tk_tcl2ruby(tk_send_without_enc('canvasy', screen_y, *args)) + number(tk_send_without_enc('canvasy', screen_y, *args)) + end + + def coords(tag, *args) + if args == [] + tk_split_list(tk_send_without_enc('coords', tagid(tag))) + else + tk_send_without_enc('coords', tagid(tag), *(args.flatten)) + end + end + + def dchars(tag, first, last=None) + tk_send_without_enc('dchars', tagid(tag), + _get_eval_enc_str(first), _get_eval_enc_str(last)) + self + end + + def delete(*args) + if TkcItem::CItemID_TBL[self.path] + find('withtag', *args).each{|item| + TkcItem::CItemID_TBL[self.path].delete(item.id) + } + end + tk_send_without_enc('delete', *args.collect{|t| tagid(t)}) + self + end + alias remove delete + + def dtag(tag, tag_to_del=None) + tk_send_without_enc('dtag', tagid(tag), tag_to_del) + self + end + + def find(mode, *args) + list(tk_send_without_enc('find', mode, *args)).collect!{|id| + TkcItem.id2obj(self, id) + } + end + def find_above(target) + find('above', tagid(target)) + end + def find_all + find('all') + end + def find_below(target) + find('below', tagid(target)) + end + def find_closest(x, y, halo=None, start=None) + find('closest', x, y, halo, start) + end + def find_enclosed(x1, y1, x2, y2) + find('enclosed', x1, y1, x2, y2) + end + def find_overlapping(x1, y1, x2, y2) + find('overlapping', x1, y1, x2, y2) + end + def find_withtag(tag) + find('withtag', tag) + end + + def itemfocus(tagOrId=nil) + if tagOrId + tk_send_without_enc('focus', tagid(tagOrId)) + self + else + ret = tk_send_without_enc('focus') + if ret == "" + nil + else + TkcItem.id2obj(self, ret) + end + end + end + + def gettags(tagOrId) + list(tk_send_without_enc('gettags', tagid(tagOrId))).collect{|tag| + TkcTag.id2obj(self, tag) + } + end + + def icursor(tagOrId, index) + tk_send_without_enc('icursor', tagid(tagOrId), index) + self + end + + def index(tagOrId, index) + number(tk_send_without_enc('index', tagid(tagOrId), index)) + end + + def insert(tagOrId, index, string) + tk_send_without_enc('insert', tagid(tagOrId), index, + _get_eval_enc_str(string)) + self + end + + def itemcget(tagOrId, option) + case option.to_s + when 'dash', 'activedash', 'disableddash' + conf = tk_send_without_enc('itemcget', tagid(tagOrId), "-#{option}") + if conf =~ /^[0-9]/ + list(conf) + else + conf + end + when 'text', 'label', 'show', 'data', 'file', 'maskdata', 'maskfile' + _fromUTF8(tk_send_without_enc('itemcget', tagid(tagOrId), "-#{option}")) + when 'font', 'kanjifont' + #fnt = tk_tcl2ruby(tk_send('itemcget', tagid(tagOrId), "-#{option}")) + fnt = tk_tcl2ruby(_fromUTF8(tk_send_with_enc('itemcget', tagid(tagOrId), '-font'))) + unless fnt.kind_of?(TkFont) + fnt = tagfontobj(tagid(tagOrId), fnt) + end + if option.to_s == 'kanjifont' && JAPANIZED_TK && TK_VERSION =~ /^4\.*/ + # obsolete; just for compatibility + fnt.kanji_font + else + fnt + end + else + tk_tcl2ruby(_fromUTF8(tk_send_without_enc('itemcget', tagid(tagOrId), + "-#{option}"))) + end + end + + def itemconfigure(tagOrId, key, value=None) + if key.kind_of? Hash + key = _symbolkey2str(key) + if ( key['font'] || key['kanjifont'] \ + || key['latinfont'] || key['asciifont'] ) + tagfont_configure(tagid(tagOrId), key.dup) + else + _fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId), + *hash_kv(key, true))) + end + + else + if ( key == 'font' || key == :font || + key == 'kanjifont' || key == :kanjifont || + key == 'latinfont' || key == :latinfont || + key == 'asciifont' || key == :asciifont ) + if value == None + tagfontobj(tagid(tagOrId)) + else + tagfont_configure(tagid(tagOrId), {key=>value}) + end + else + _fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId), + "-#{key}", _get_eval_enc_str(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 TkComm::GET_CONFIGINFO_AS_ARRAY + if key + case key.to_s + when 'dash', 'activedash', 'disableddash' + conf = tk_split_simplelist(tk_send_without_enc('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(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId), "-#{key}"))) + when 'font', 'kanjifont' + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId),"-#{key}"))) + conf[4] = tagfont_configinfo(tagid(tagOrId), conf[4]) + else + conf = tk_split_list(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId), "-#{key}"))) + end + conf[0] = conf[0][1..-1] + conf + else + ret = tk_split_simplelist(_fromUTF8(tk_send_without_enc('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[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] = tagfont_configinfo(tagid(tagOrId), fontconf[4]) + ret.push(fontconf) + else + ret + end + end + else # ! TkComm::GET_CONFIGINFO_AS_ARRAY + if key + case key.to_s + when 'dash', 'activedash', 'disableddash' + conf = tk_split_simplelist(tk_send_without_enc('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(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId), "-#{key}"))) + when 'font', 'kanjifont' + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId),"-#{key}"))) + conf[4] = tagfont_configinfo(tagid(tagOrId), conf[4]) + else + conf = tk_split_list(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId), "-#{key}"))) + end + key = conf.shift[1..-1] + { key => conf } + else + ret = {} + tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId)))).each{|conflist| + conf = tk_split_simplelist(conflist) + key = conf.shift[1..-1] + case key + when 'text', 'label', 'show', 'data', 'file', 'maskdata', 'maskfile' + when 'dash', 'activedash', 'disableddash' + if conf[2] && conf[2] =~ /^[0-9]/ + conf[2] = list(conf[2]) + end + if conf[3] && conf[3] =~ /^[0-9]/ + conf[3] = list(conf[3]) + end + 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 + ret[key] = conf + end + } + fontconf = ret['font'] + if fontconf + ret.delete('font') + ret.delete('kanjifont') + fontconf[3] = tagfont_configinfo(tagid(tagOrId), fontconf[3]) + ret['font'] = fontconf + end + ret + end + end + end + + def current_itemconfiginfo(tagOrId, key=nil) + if TkComm::GET_CONFIGINFO_AS_ARRAY + if key + conf = itemconfiginfo(tagOrId, key) + {conf[0] => conf[4]} + else + ret = {} + itemconfiginfo(tagOrId).each{|conf| + ret[conf[0]] = conf[4] if conf.size > 2 + } + ret + end + else # ! TkComm::GET_CONFIGINFO_AS_ARRAY + ret = {} + itemconfiginfo(tagOrId, key).each{|k, conf| + ret[k] = conf[-1] if conf.kind_of?(Array) + } + ret + end + end + + def lower(tag, below=nil) + if below + tk_send_without_enc('lower', tagid(tag), tagid(below)) + else + tk_send_without_enc('lower', tagid(tag)) + end + self + end + + def move(tag, x, y) + tk_send_without_enc('move', tagid(tag), x, y) + self + end + + def postscript(keys) + tk_send("postscript", *hash_kv(keys)) + end + + def raise(tag, above=nil) + if above + tk_send_without_enc('raise', tagid(tag), tagid(above)) + else + tk_send_without_enc('raise', tagid(tag)) + end + self + end + + def scale(tag, x, y, xs, ys) + tk_send_without_enc('scale', tagid(tag), x, y, xs, ys) + self + end + + def scan_mark(x, y) + tk_send_without_enc('scan', 'mark', x, y) + self + end + def scan_dragto(x, y) + tk_send_without_enc('scan', 'dragto', x, y) + self + end + + def select(mode, *args) + r = tk_send_without_enc('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 + +class TkcItem<TkObject + extend Tk + include TkcTagAccess + + CItemTypeToClass = {} + CItemID_TBL = TkCore::INTERP.create_table + + TkCore::INTERP.init_ip_env{ CItemID_TBL.clear } + + def TkcItem.type2class(type) + CItemTypeToClass[type] + end + + def TkcItem.id2obj(canvas, id) + cpath = canvas.path + return id unless CItemID_TBL[cpath] + CItemID_TBL[cpath][id]? CItemID_TBL[cpath][id]: id + end + + ######################################## + def self.create(canvas, *args) + fail RuntimeError, "TkcItem is an abstract class" + end + ######################################## + + def initialize(parent, *args) + unless parent.kind_of?(TkCanvas) + fail ArguemntError, "expect TkCanvas for 1st argument" + end + @parent = @c = parent + @path = parent.path + fontkeys = {} + if args.size == 1 && args[0].kind_of?(Hash) + args[0] = _symbolkey2str(args[0]) + coords = args[0].delete('coords') + unless coords.kind_of?(Array) + fail "coords parameter must be given by an Array" + end + args[0,0] = coords.flatten + end + if args[-1].kind_of? Hash + keys = _symbolkey2str(args.pop) + ['font', 'kanjifont', 'latinfont', 'asciifont'].each{|key| + fontkeys[key] = keys.delete(key) if keys.key?(key) + } + args.concat(hash_kv(keys)) + end + @id = create_self(*args).to_i ;# 'canvas item id' is integer number + CItemID_TBL[@path] = {} unless CItemID_TBL[@path] + CItemID_TBL[@path][@id] = self + configure(fontkeys) unless fontkeys.empty? + +######## old version +# if args[-1].kind_of? Hash +# keys = args.pop +# end +# @id = create_self(*args).to_i ;# 'canvas item id' is integer number +# CItemID_TBL[@path] = {} unless CItemID_TBL[@path] +# CItemID_TBL[@path][@id] = self +# if keys +# # tk_call @path, 'itemconfigure', @id, *hash_kv(keys) +# configure(keys) if keys +# end +######## + end + def create_self(*args) + self.class.create(@path, *args) + end + private :create_self + + def id + @id + end + + def delete + @c.delete @id + CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] + self + end + alias remove delete + alias destroy delete +end + +class TkcArc<TkcItem + CItemTypeToClass['arc'] = self + def self.create(path, *args) + if args[-1].kind_of?(Hash) + keys = args.pop + args.concat(hash_kv(keys)) + end + tk_call_without_enc(path, 'create', 'arc', *args) + end +end + +class TkcBitmap<TkcItem + CItemTypeToClass['bitmap'] = self + def self.create(path, *args) + if args[-1].kind_of?(Hash) + keys = args.pop + args.concat(hash_kv(keys)) + end + tk_call_without_enc(path, 'create', 'bitmap', *args) + end +end + +class TkcImage<TkcItem + CItemTypeToClass['image'] = self + def self.create(path, *args) + if args[-1].kind_of?(Hash) + keys = args.pop + args.concat(hash_kv(keys)) + end + tk_call_without_enc(path, 'create', 'image', *args) + end +end + +class TkcLine<TkcItem + CItemTypeToClass['line'] = self + def self.create(path, *args) + if args[-1].kind_of?(Hash) + keys = args.pop + args.concat(hash_kv(keys)) + end + tk_call_without_enc(path, 'create', 'line', *args) + end +end + +class TkcOval<TkcItem + CItemTypeToClass['oval'] = self + def self.create(path, *args) + if args[-1].kind_of?(Hash) + keys = args.pop + args.concat(hash_kv(keys)) + end + tk_call_without_enc(path, 'create', 'oval', *args) + end +end + +class TkcPolygon<TkcItem + CItemTypeToClass['polygon'] = self + def self.create(path, *args) + if args[-1].kind_of?(Hash) + keys = args.pop + args.concat(hash_kv(keys)) + end + tk_call_without_enc(path, 'create', 'polygon', *args) + end +end + +class TkcRectangle<TkcItem + CItemTypeToClass['rectangle'] = self + def self.create(path, *args) + if args[-1].kind_of?(Hash) + keys = args.pop + args.concat(hash_kv(keys)) + end + tk_call_without_enc(path, 'create', 'rectangle', *args) + end +end + +class TkcText<TkcItem + CItemTypeToClass['text'] = self + def self.create(path, *args) + if args[-1].kind_of?(Hash) + keys = args.pop + args.concat(hash_kv(keys)) + end + #tk_call_without_enc(path, 'create', 'text', + # *(args.each{|arg| _get_eval_enc_str(arg)})) + tk_call(path, 'create', 'text', *args) + end +end + +class TkcWindow<TkcItem + CItemTypeToClass['window'] = self + def self.create(path, *args) + if args[-1].kind_of?(Hash) + keys = _symbolkey2str(args.pop) + win = keys['window'] + # keys['window'] = win.epath if win.kind_of?(TkWindow) + keys['window'] = _epath(win) if win + args.concat(hash_kv(keys)) + end + tk_call_without_enc(path, 'create', 'window', *args) + end +end diff --git a/ext/tk/lib/tk/canvastag.rb b/ext/tk/lib/tk/canvastag.rb new file mode 100644 index 0000000000..962e08b6e0 --- /dev/null +++ b/ext/tk/lib/tk/canvastag.rb @@ -0,0 +1,337 @@ +# +# tk/canvastag.rb - methods for treating canvas tags +# +require 'tk' +require 'tk/canvas' +require 'tk/tagfont' + +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 current_configinfo(key=nil) + @c.current_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 TkcTag<TkObject + include TkcTagAccess + + CTagID_TBL = TkCore::INTERP.create_table + Tk_CanvasTag_ID = ['ctag'.freeze, '00000'.taint].freeze + + TkCore::INTERP.init_ip_env{ CTagID_TBL.clear } + + def TkcTag.id2obj(canvas, id) + cpath = canvas.path + return id unless CTagID_TBL[cpath] + CTagID_TBL[cpath][id]? CTagID_TBL[cpath][id]: id + end + + def initialize(parent, mode=nil, *args) + unless parent.kind_of?(TkCanvas) + fail ArguemntError, "expect TkCanvas for 1st argument" + end + @c = parent + @cpath = parent.path + @path = @id = Tk_CanvasTag_ID.join('') + CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] + CTagID_TBL[@cpath][@id] = self + Tk_CanvasTag_ID[1].succ! + if mode + tk_call_without_enc(@c.path, "addtag", @id, mode, *args) + end + end + def id + @id + end + + def delete + @c.delete @id + CTagID_TBL[@cpath].delete(@id) if CTagID_TBL[@cpath] + self + end + alias remove delete + alias destroy delete + + def set_to_above(target) + @c.addtag_above(@id, target) + self + end + alias above set_to_above + + def set_to_all + @c.addtag_all(@id) + self + end + alias all set_to_all + + def set_to_below(target) + @c.addtag_below(@id, target) + self + end + alias below set_to_below + + def set_to_closest(x, y, halo=None, start=None) + @c.addtag_closest(@id, x, y, halo, start) + self + end + alias closest set_to_closest + + def set_to_enclosed(x1, y1, x2, y2) + @c.addtag_enclosed(@id, x1, y1, x2, y2) + self + end + alias enclosed set_to_enclosed + + def set_to_overlapping(x1, y1, x2, y2) + @c.addtag_overlapping(@id, x1, y1, x2, y2) + self + end + alias overlapping set_to_overlapping + + def set_to_withtag(target) + @c.addtag_withtag(@id, target) + self + end + alias withtag set_to_withtag +end + +class TkcTagString<TkcTag + def self.new(parent, name, *args) + if CTagID_TBL[parent.path] && CTagID_TBL[parent.path][name] + return CTagID_TBL[parent.path][name] + else + super(parent, name, *args) + end + end + + def initialize(parent, name, mode=nil, *args) + unless parent.kind_of?(TkCanvas) + fail ArguemntError, "expect TkCanvas for 1st argument" + end + @c = parent + @cpath = parent.path + @path = @id = name + CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] + CTagID_TBL[@cpath][@id] = self + if mode + tk_call_without_enc(@c.path, "addtag", @id, mode, *args) + end + end +end +TkcNamedTag = TkcTagString + +class TkcTagAll<TkcTag + def initialize(parent) + unless parent.kind_of?(TkCanvas) + fail ArguemntError, "expect TkCanvas for 1st argument" + end + @c = parent + @cpath = parent.path + @path = @id = 'all' + CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] + CTagID_TBL[@cpath][@id] = self + end +end + +class TkcTagCurrent<TkcTag + def initialize(parent) + unless parent.kind_of?(TkCanvas) + fail ArguemntError, "expect TkCanvas for 1st argument" + end + @c = parent + @cpath = parent.path + @path = @id = 'current' + CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] + CTagID_TBL[@cpath][@id] = self + end +end + +class TkcGroup<TkcTag + Tk_cGroup_ID = ['tkcg'.freeze, '00000'.taint].freeze + def create_self(parent, *args) + unless parent.kind_of?(TkCanvas) + fail ArguemntError, "expect TkCanvas for 1st argument" + end + @c = parent + @cpath = parent.path + @path = @id = Tk_cGroup_ID.join('') + CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath] + CTagID_TBL[@cpath][@id] = self + Tk_cGroup_ID[1].succ! + add(*args) if args != [] + end + private :create_self + + def include(*tags) + for i in tags + i.addtag @id + end + self + end + + def exclude(*tags) + for i in tags + i.delete @id + end + self + end +end diff --git a/ext/tk/lib/tk/checkbutton.rb b/ext/tk/lib/tk/checkbutton.rb new file mode 100644 index 0000000000..a1ee5e8764 --- /dev/null +++ b/ext/tk/lib/tk/checkbutton.rb @@ -0,0 +1,25 @@ +# +# tk/checkbutton.rb : treat checkbutton widget +# +require 'tk' +require 'tk/radiobutton' + +class TkCheckButton<TkRadioButton + TkCommandNames = ['checkbutton'.freeze].freeze + WidgetClassName = 'Checkbutton'.freeze + WidgetClassNames[WidgetClassName] = self + def create_self(keys) + if keys and keys != None + tk_call_without_enc('checkbutton', @path, *hash_kv(keys, true)) + else + tk_call_without_enc('checkbutton', @path) + end + end + private :create_self + + def toggle + tk_send_without_enc('toggle') + self + end +end +TkCheckbutton = TkCheckButton diff --git a/ext/tk/lib/tk/clipboard.rb b/ext/tk/lib/tk/clipboard.rb new file mode 100644 index 0000000000..d4205a5c28 --- /dev/null +++ b/ext/tk/lib/tk/clipboard.rb @@ -0,0 +1,75 @@ +# +# tk/clipboard.rb : methods to treat clipboard +# +require 'tk' + +module TkClipboard + include Tk + extend Tk + + TkCommandNames = ['clipboard'.freeze].freeze + + def self.clear(win=nil) + if win + tk_call_without_enc('clipboard', 'clear', '-displayof', win) + else + tk_call_without_enc('clipboard', 'clear') + end + end + def self.clear_on_display(win) + tk_call_without_enc('clipboard', 'clear', '-displayof', win) + end + + def self.get(type=nil) + if type + tk_call_without_enc('clipboard', 'get', '-type', type) + else + tk_call_without_enc('clipboard', 'get') + end + end + def self.get_on_display(win, type=nil) + if type + tk_call_without_enc('clipboard', 'get', '-displayof', win, '-type', type) + else + tk_call_without_enc('clipboard', 'get', '-displayof', win) + end + end + + def self.set(data, keys=nil) + clear + append(data, keys) + end + def self.set_on_display(win, data, keys=nil) + clear(win) + append_on_display(win, data, keys) + end + + def self.append(data, keys=nil) + args = ['clipboard', 'append'] + args.concat(hash_kv(keys)) + args.concat(['--', data]) + tk_call(*args) + end + def self.append_on_display(win, data, keys=nil) + args = ['clipboard', 'append', '-displayof', win] + args.concat(hash_kv(keys)) + args.concat(['--', data]) + tk_call(*args) + end + + def clear + TkClipboard.clear_on_display(self) + self + end + def get(type=nil) + TkClipboard.get_on_display(self, type) + end + def set(data, keys=nil) + TkClipboard.set_on_display(self, data, keys) + self + end + def append(data, keys=nil) + TkClipboard.append_on_display(self, data, keys) + self + end +end diff --git a/ext/tk/lib/tk/clock.rb b/ext/tk/lib/tk/clock.rb new file mode 100644 index 0000000000..88b66129ea --- /dev/null +++ b/ext/tk/lib/tk/clock.rb @@ -0,0 +1,57 @@ +# +# tk/clock.rb : methods for clock command +# +require 'tk' + +module Tk + module Clock + def self.clicks(ms=nil) + case ms + when nil + tk_call_without_enc('clock','clicks').to_i + when /^mic/ + tk_call_without_enc('clock','clicks','-microseconds').to_i + when /^mil/ + tk_call_without_enc('clock','clicks','-milliseconds').to_i + else + tk_call_without_enc('clock','clicks','-milliseconds').to_i + end + end + + def self.format(clk, form=nil) + if form + tk_call('clock','format',clk,'-format',form) + else + tk_call('clock','format',clk) + end + end + + def self.formatGMT(clk, form=nil) + if form + tk_call('clock','format',clk,'-format',form,'-gmt','1') + else + tk_call('clock','format',clk,'-gmt','1') + end + end + + def self.scan(str, base=nil) + if base + tk_call('clock','scan',str,'-base',base).to_i + else + tk_call('clock','scan',str).to_i + end + end + + def self.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 self.seconds + tk_call_without_enc('clock','seconds').to_i + end + end +end diff --git a/ext/tk/lib/tk/composite.rb b/ext/tk/lib/tk/composite.rb new file mode 100644 index 0000000000..ed7796aafb --- /dev/null +++ b/ext/tk/lib/tk/composite.rb @@ -0,0 +1,64 @@ +# +# tk/composite.rb : +# +require 'tk' + +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) + else + @frame = TkFrame.new(parent) + @delegates['DEFAULT'] = @frame + @path = @epath = @frame.path + initialize_composite(*args) + end + end + + def epath + @epath + end + + def initialize_composite(*args) end + private :initialize_composite + + def delegate(option, *wins) + if @delegates[option].kind_of?(Array) + for i in wins + @delegates[option].push(i) + 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 + end + last + else + super + end + end + end +end diff --git a/ext/tk/lib/tk/console.rb b/ext/tk/lib/tk/console.rb new file mode 100644 index 0000000000..855ee6a94f --- /dev/null +++ b/ext/tk/lib/tk/console.rb @@ -0,0 +1,29 @@ +# +# tk/console.rb : control the console on system without a real console +# +require 'tk' + +module TkConsole + include Tk + extend Tk + + TkCommandNames = ['console'.freeze].freeze + + def self.title(str=None) + tk_call 'console', str + end + def self.hide + tk_call_without_enc('console', 'hide') + end + def self.show + tk_call_without_enc('console', 'show') + end + def self.eval(tcl_script) + # + # supports a Tcl script only + # I have no idea to support a Ruby script seamlessly. + # + _fromUTF8(tk_call_without_enc('console', 'eval', + _get_eval_enc_str(tcl_script))) + end +end diff --git a/ext/tk/lib/tk/dialog.rb b/ext/tk/lib/tk/dialog.rb new file mode 100644 index 0000000000..30521e126a --- /dev/null +++ b/ext/tk/lib/tk/dialog.rb @@ -0,0 +1,290 @@ +# +# tk/dialog.rb : create dialog boxes +# +require 'tk' + +class TkDialog2 < TkWindow + extend Tk + + TkCommandNames = ['tk_dialog'.freeze].freeze + + def self.show(*args) + dlog = self.new(*args) + dlog.show + dlog + end + + def _set_button_config(configs) + set_config = proc{|c,i| + if $VERBOSE && (c.has_key?('command') || c.has_key?(:command)) + STDERR.print("Warning: cannot give a command option " + + "to the dialog button#{i}. It was removed.\n") + end + c.delete('command'); c.delete(:command) + # @config << Kernel.format("%s.button%s configure %s; ", + # @path, i, hash_kv(c).join(' ')) + @config << @path+'.button'+i.to_s+'configure '+hash_kv(c).join(' ')+'; ' + } + case configs + when Proc + @buttons.each_index{|i| + if (c = configs.call(i)).kind_of? Hash + set_config.call(c,i) + end + } + + when Array + @buttons.each_index{|i| + if (c = configs[i]).kind_of? Hash + set_config.call(c,i) + end + } + + when Hash + @buttons.each_with_index{|s,i| + if (c = configs[s]).kind_of? Hash + set_config.call(c,i) + end + } + end + @config = 'after idle {' + @config + '};' if @config != "" + end + private :_set_button_config + + # initialize tk_dialog + def create_self(keys) + #@var = TkVariable.new + @val = nil + + @title = title + + @message = message + @message_config = message_config + @msgframe_config = msgframe_config + + @bitmap = bitmap + @bitmap_config = message_config + + @default_button = default_button + + @buttons = buttons + @button_configs = proc{|num| button_configs(num)} + @btnframe_config = btnframe_config + + #@config = "puts [winfo children .w0000];" + @config = "" + + @command = nil + + if keys.kind_of? Hash + @title = keys['title'] if keys.key? 'title' + @message = keys['message'] if keys.key? 'message' + @bitmap = keys['bitmap'] if keys.key? 'bitmap' + @bitmap = '{}' if @bitmap == nil || @bitmap == "" + @default_button = keys['default'] if keys.key? 'default' + @buttons = keys['buttons'] if keys.key? 'buttons' + + @command = keys['prev_command'] + + @message_config = keys['message_config'] if keys.key? 'message_config' + @msgframe_config = keys['msgframe_config'] if keys.key? 'msgframe_config' + @bitmap_config = keys['bitmap_config'] if keys.key? 'bitmap_config' + @button_configs = keys['button_configs'] if keys.key? 'button_configs' + @btnframe_config = keys['btnframe_config'] if keys.key? 'btnframe_config' + end + + if @title.include? ?\s + @title = '{' + @title + '}' + end + + if @buttons.kind_of? Array + _set_button_config(@buttons.collect{|cfg| + (cfg.kind_of? Array)? cfg[1]: nil}) + @buttons = @buttons.collect{|cfg| (cfg.kind_of? Array)? cfg[0]: cfg} + end + if @buttons.kind_of? Hash + _set_button_config(@buttons) + @buttons = @buttons.keys + end + @buttons = tk_split_simplelist(@buttons) if @buttons.kind_of? String + @buttons = @buttons.collect{|s| + if s.kind_of? Array + s = s.join(' ') + end + if s.include? ?\s + '{' + s + '}' + else + s + end + } + + if @message_config.kind_of? Hash + # @config << Kernel.format("%s.msg configure %s;", + # @path, hash_kv(@message_config).join(' ')) + @config << @path+'.msg configure '+hash_kv(@message_config).join(' ')+';' + end + + if @msgframe_config.kind_of? Hash + # @config << Kernel.format("%s.top configure %s;", + # @path, hash_kv(@msgframe_config).join(' ')) + @config << @path+'.top configure '+hash_kv(@msgframe_config).join(' ')+';' + end + + if @btnframe_config.kind_of? Hash + # @config << Kernel.format("%s.bot configure %s;", + # @path, hash_kv(@btnframe_config).join(' ')) + @config << @path+'.bot configure '+hash_kv(@btnframe_config).join(' ')+';' + end + + if @bitmap_config.kind_of? Hash + # @config << Kernel.format("%s.bitmap configure %s;", + # @path, hash_kv(@bitmap_config).join(' ')) + @config << @path+'.bitmap configure '+hash_kv(@bitmap_config).join(' ')+';' + end + + _set_button_config(@button_configs) if @button_configs + + if @command.kind_of? Proc + @command.call(self) + end + end + private :create_self + + def show + if @default_button.kind_of? String + default_button = @buttons.index(@default_button) + else + default_button = @default_button + end + default_button = '{}' if default_button == nil + #Tk.ip_eval('eval {global '+@var.id+';'+@config+ + # 'set '+@var.id+' [tk_dialog '+ + # @path+" "+@title+" {#{@message}} "+@bitmap+" "+ + # String(default_button)+" "+@buttons.join(' ')+']}') + Tk.ip_eval(@config) + @val = Tk.ip_eval('tk_dialog ' + @path + ' ' + @title + + ' {' + @message + '} ' + @bitmap + ' ' + + String(default_button) + ' ' + @buttons.join(' ')).to_i + end + + def value + # @var.value.to_i + @val + end + ###################################################### + # # + # these methods must be overridden for each dialog # + # # + ###################################################### + private + + def title + # returns a title string of the dialog window + return "DIALOG" + end + def message + # returns a message text to display on the dialog + return "MESSAGE" + end + def message_config + # returns a Hash {option=>value, ...} 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 +# +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 diff --git a/ext/tk/lib/tk/encodedstr.rb b/ext/tk/lib/tk/encodedstr.rb new file mode 100644 index 0000000000..5eb989f420 --- /dev/null +++ b/ext/tk/lib/tk/encodedstr.rb @@ -0,0 +1,107 @@ +# +# tk/encodedstr.rb : Tk::EncodedString class +# +require 'tk' + +########################################### +# string with Tcl's encoding +########################################### +module Tk + class EncodedString < String + Encoding = nil + + def self.subst_utf_backslash(str) + # str.gsub(/\\u([0-9A-Fa-f]{1,4})/){[$1.hex].pack('U')} + TclTkLib._subst_UTF_backslash(str) + end + def self.utf_backslash(str) + self.subst_utf_backslash(str) + end + + def self.subst_tk_backslash(str) + TclTkLib._subst_Tcl_backslash(str) + end + + def self.utf_to_backslash_sequence(str) + str.unpack('U*').collect{|c| + if c <= 0xFF # ascii character + c.chr + else + format('\u%X', c) + end + }.join('') + end + def self.utf_to_backslash(str) + self.utf_to_backslash_sequence(str) + end + + def self.to_backslash_sequence(str) + str.unpack('U*').collect{|c| + if c <= 0x1F # control character + case c + when 0x07; '\a' + when 0x08; '\b' + when 0x09; '\t' + when 0x0a; '\n' + when 0x0b; '\v' + when 0x0c; '\f' + when 0x0d; '\r' + else + format('\x%02X', c) + end + elsif c <= 0xFF # ascii character + c.chr + else + format('\u%X', c) + end + }.join('') + end + + def self.new_with_utf_backslash(str, enc = nil) + self.new('', enc).replace(self.subst_utf_backslash(str)) + end + + def self.new_without_utf_backslash(str, enc = nil) + self.new('', enc).replace(str) + end + + def initialize(str, enc = nil) + super(str) + @encoding = ( enc || + ((self.class::Encoding)? + self.class::Encoding : Tk.encoding_system) ) + end + + attr_reader :encoding + end + # def Tk.EncodedString(str, enc = nil) + # Tk::EncodedString.new(str, enc) + # end + + ################################## + + class BinaryString < EncodedString + Encoding = 'binary'.freeze + end + # def Tk.BinaryString(str) + # Tk::BinaryString.new(str) + # end + + ################################## + + class UTF8_String < EncodedString + Encoding = 'utf-8'.freeze + def self.new(str) + super(self.subst_utf_backslash(str)) + end + + def to_backslash_sequence + Tk::EncodedString.utf_to_backslash_sequence(self) + end + alias to_backslash to_backslash_sequence + end + # def Tk.UTF8_String(str) + # Tk::UTF8_String.new(str) + # end + +end diff --git a/ext/tk/lib/tk/entry.rb b/ext/tk/lib/tk/entry.rb new file mode 100644 index 0000000000..2077c1e9e4 --- /dev/null +++ b/ext/tk/lib/tk/entry.rb @@ -0,0 +1,114 @@ +# +# tk/entry.rb - Tk entry classes +# $Date$ +# by Yukihiro Matsumoto <matz@caelum.co.jp> + +require 'tk' +require 'tk/label' +require 'tk/scrollable' +require 'tk/validation' + +class TkEntry<TkLabel + include Scrollable + include TkValidation + + TkCommandNames = ['entry'.freeze].freeze + WidgetClassName = 'Entry'.freeze + WidgetClassNames[WidgetClassName] = self + + + def create_self(keys) + tk_call_without_enc('entry', @path) + if keys and keys != None + configure(keys) + end + end + private :create_self + + def bbox(index) + list(tk_send_without_enc('bbox', index)) + end + def cursor + number(tk_send_without_enc('index', 'insert')) + end + def cursor=(index) + tk_send_without_enc('icursor', index) + #self + index + end + def index(index) + number(tk_send_without_enc('index', index)) + end + def insert(pos,text) + tk_send_without_enc('insert', pos, _get_eval_enc_str(text)) + self + end + def delete(first, last=None) + tk_send_without_enc('delete', first, last) + self + end + def mark(pos) + tk_send_without_enc('scan', 'mark', pos) + self + end + def dragto(pos) + tk_send_without_enc('scan', 'dragto', pos) + self + end + def selection_adjust(index) + tk_send_without_enc('selection', 'adjust', index) + self + end + def selection_clear + tk_send_without_enc('selection', 'clear') + self + end + def selection_from(index) + tk_send_without_enc('selection', 'from', index) + self + end + def selection_present() + bool(tk_send_without_enc('selection', 'present')) + end + def selection_range(s, e) + tk_send_without_enc('selection', 'range', s, e) + self + end + def selection_to(index) + tk_send_without_enc('selection', 'to', index) + self + end + + def invoke_validate + bool(tk_send_without_enc('validate')) + end + def validate(mode = nil) + if mode + configure 'validate', mode + else + invoke_validate + end + end + + def value + _fromUTF8(tk_send_without_enc('get')) + end + def value= (val) + tk_send_without_enc('delete', 0, 'end') + tk_send_without_enc('insert', 0, _get_eval_enc_str(val)) + val + end + alias get value + alias set value= + + def [](*args) + self.value[*args] + end + def []=(*args) + val = args.pop + str = self.value + str[*args] = val + self.value = str + val + end +end diff --git a/ext/tk/lib/tk/event.rb b/ext/tk/lib/tk/event.rb new file mode 100644 index 0000000000..b85c456d41 --- /dev/null +++ b/ext/tk/lib/tk/event.rb @@ -0,0 +1,142 @@ +# +# tk/event.rb - module for event +# +require 'tk' + +module TkEvent + class Event < TkUtil::CallbackSubst + 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 + + # [ <'%' subst-key char>, <proc type char>, <instance var (accessor) name>] + key_tbl = [ + [ ?#, ?n, :serial ], + [ ?a, ?s, :above ], + [ ?b, ?n, :num ], + [ ?c, ?n, :count ], + [ ?d, ?s, :detail ], + [ ?f, ?b, :focus ], + [ ?h, ?n, :height ], + [ ?i, ?s, :win_hex ], + [ ?k, ?n, :keycode ], + [ ?m, ?s, :mode ], + [ ?o, ?b, :override ], + [ ?p, ?s, :place ], + [ ?s, ?x, :state ], + [ ?t, ?n, :time ], + [ ?w, ?n, :width ], + [ ?x, ?n, :x ], + [ ?y, ?n, :y ], + [ ?A, ?s, :char ], + [ ?B, ?n, :borderwidth ], + [ ?D, ?n, :wheel_delta ], + [ ?E, ?b, :send_event ], + [ ?K, ?s, :keysym ], + [ ?N, ?n, :keysym_num ], + [ ?R, ?s, :rootwin_id ], + [ ?S, ?s, :subwindow ], + [ ?T, ?n, :type ], + [ ?W, ?w, :widget ], + [ ?X, ?n, :x_root ], + [ ?Y, ?n, :y_root ], + nil + ] + + # [ <proc type char>, <proc/method to convert tcl-str to ruby-obj>] + proc_tbl = [ + [ ?n, TkComm.method(:num_or_str) ], + [ ?s, TkComm.method(:string) ], + [ ?b, TkComm.method(:bool) ], + [ ?w, TkComm.method(:window) ], + + [ ?x, proc{|val| + begin + TkComm::number(val) + rescue ArgumentError + val + end + } + ], + + nil + ] + + # setup tables to be used by scan_args, _get_subst_key, _get_all_subst_keys + # + # _get_subst_key() and _get_all_subst_keys() generates key-string + # which describe how to convert callback arguments to ruby objects. + # When binding parameters are given, use _get_subst_key(). + # But when no parameters are given, use _get_all_subst_keys() to + # create a Event class object as a callback parameter. + # + # scan_args() is used when doing callback. It convert arguments + # ( which are Tcl strings ) to ruby objects based on the key string + # that is generated by _get_subst_key() or _get_all_subst_keys(). + # + _setup_subst_table(key_tbl, proc_tbl); + end + + def install_bind(cmd, *args) + if args.compact.size > 0 + args = args.join(' ') + keys = Event._get_subst_key(args) + + if cmd.kind_of?(String) + id = cmd + elsif cmd.kind_of?(TkCallbackEntry) + id = install_cmd(cmd) + else + id = install_cmd(proc{|*arg| + TkUtil.eval_cmd(cmd, *Event.scan_args(keys, arg)) + }) + end + id + ' ' + args + else + keys, args = Event._get_all_subst_keys + + if cmd.kind_of?(String) + id = cmd + elsif cmd.kind_of?(TkCallbackEntry) + id = install_cmd(cmd) + else + id = install_cmd(proc{|*arg| + TkUtil.eval_cmd(cmd, Event.new(*Event.scan_args(keys, arg))) + }) + end + id + ' ' + args + end + end +end diff --git a/ext/tk/lib/tk/font.rb b/ext/tk/lib/tk/font.rb new file mode 100644 index 0000000000..b8f7f1b991 --- /dev/null +++ b/ext/tk/lib/tk/font.rb @@ -0,0 +1,1407 @@ +# +# tk/font.rb - the class to treat fonts on Ruby/Tk +# +# by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) +# +require 'tk' + +class TkFont + include Tk + extend TkCore + + TkCommandNames = ['font'.freeze].freeze + + Tk_FontID = ["@font".freeze, "00000".taint].freeze + Tk_FontNameTBL = TkCore::INTERP.create_table + Tk_FontUseTBL = TkCore::INTERP.create_table + + TkCore::INTERP.init_ip_env{ + Tk_FontNameTBL.clear + Tk_FontUseTBL.clear + } + + # set default font + case Tk::TK_VERSION + when /^4\.*/ + DEFAULT_LATIN_FONT_NAME = 'a14'.freeze + DEFAULT_KANJI_FONT_NAME = 'k14'.freeze + + when /^8\.*/ + if JAPANIZED_TK + begin + fontnames = tk_call('font', 'names') + case fontnames + when /defaultgui/ + # Tcl/Tk-JP for Windows + ltn = 'defaultgui' + knj = 'defaultgui' + when /Mincho:Helvetica-Bold-12/ + # Tcl/Tk-JP for UNIX/X + ltn, knj = tk_split_simplelist(tk_call('font', 'configure', + 'Mincho:Helvetica-Bold-12', + '-compound')) + else + # unknown Tcl/Tk-JP + 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 + 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) + @compound.__send__(@type + '_configure', slot, value) + 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 + if TkComm::GET_CONFIGINFOwoRES_AS_ARRAY + keys = {} + font.configinfo.each{|key,value| keys[key] = value } + TkFont.new(font.latin_font_id, font.kanji_font_id, keys) + else # ! TkComm::GET_CONFIGINFOwoRES_AS_ARRAY + TkFont.new(font.latin_font_id, font.kanji_font_id, font.configinfo) + end + 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 + if JAPANIZED_TK && !knj + if Tk::TK_VERSION =~ /^4.*/ + knj = DEFAULT_KANJI_FONT_NAME + else + knj = ltn + end + end + 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 TkComm::GET_CONFIGINFOwoRES_AS_ARRAY + if option + "" + else + [['family',[]], ['size',[]], ['weight',[]], ['slant',[]], + ['underline',[]], ['overstrike',[]], ['charset',[]], + ['pointadjust',[]]] + end + else # ! TkComm::GET_CONFIGINFOwoRES_AS_ARRAY + current_configinfo_core_tk4x(font, option) + end + end + + def current_configinfo_core_tk4x(font, option=nil) + 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 TkComm::GET_CONFIGINFOwoRES_AS_ARRAY + 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 + else # ! TkComm::GET_CONFIGINFOwoRES_AS_ARRAY + current_configinfo_core_tk8x(font, option) + end + end + + def current_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[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 current_configinfo_core current_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-5]/ + 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 current_configinfo_core current_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 + + else + 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 current_configinfo_core current_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) + keys = args.pop.update(@fontslot) + args.concat(hash_kv(keys)) + 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 + val + end + + def configure(slot, value=None) + configure_core(@compoundfont, slot, value) + self + end + + def configinfo(slot=nil) + configinfo_core(@compoundfont, slot) + end + + def current_configinfo(slot=nil) + current_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 diff --git a/ext/tk/lib/tk/frame.rb b/ext/tk/lib/tk/frame.rb new file mode 100644 index 0000000000..6598ceb55c --- /dev/null +++ b/ext/tk/lib/tk/frame.rb @@ -0,0 +1,123 @@ +# +# tk/frame.rb : treat frame widget +# +require 'tk' + +class TkFrame<TkWindow + TkCommandNames = ['frame'.freeze].freeze + WidgetClassName = 'Frame'.freeze + WidgetClassNames[WidgetClassName] = self + +################# old version +# def initialize(parent=nil, keys=nil) +# if keys.kind_of? Hash +# keys = keys.dup +# @classname = keys.delete('classname') if keys.key?('classname') +# @colormap = keys.delete('colormap') if keys.key?('colormap') +# @container = keys.delete('container') if keys.key?('container') +# @visual = keys.delete('visual') if keys.key?('visual') +# end +# super(parent, keys) +# end +# +# def create_self +# s = [] +# s << "-class" << @classname if @classname +# s << "-colormap" << @colormap if @colormap +# s << "-container" << @container if @container +# s << "-visual" << @visual if @visual +# tk_call 'frame', @path, *s +# end +################# + + def initialize(parent=nil, keys=nil) + my_class_name = nil + if self.class < WidgetClassNames[WidgetClassName] + my_class_name = self.class.name + my_class_name = nil if my_class_name == '' + end + if parent.kind_of? Hash + keys = _symbolkey2str(parent) + else + if keys + keys = _symbolkey2str(keys) + keys['parent'] = parent + else + keys = {'parent'=>parent} + 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_without_enc('frame', @path, *hash_kv(keys)) + else + tk_call_without_enc( '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 diff --git a/ext/tk/lib/tk/grid.rb b/ext/tk/lib/tk/grid.rb new file mode 100644 index 0000000000..1516aef4bf --- /dev/null +++ b/ext/tk/lib/tk/grid.rb @@ -0,0 +1,182 @@ +# +# tk/grid.rb : control grid geometry manager +# +require 'tk' + +module TkGrid + include Tk + extend Tk + + TkCommandNames = ['grid'.freeze].freeze + + def anchor(master, anchor=None) + # master = master.epath if master.kind_of?(TkObject) + master = _epath(master) + tk_call_without_enc('grid', 'anchor', master, anchor) + end + + def bbox(master, *args) + # master = master.epath if master.kind_of?(TkObject) + master = _epath(master) + args.unshift(master) + list(tk_call_without_enc('grid', 'bbox', *args)) + end + + def configure(win, *args) + if args[-1].kind_of?(Hash) + opts = args.pop + else + opts = {} + end + params = [] + params.push(_epath(win)) + args.each{|win| + case win + when '-', 'x', '^' # RELATIVE PLACEMENT + params.push(win) + else + params.push(_epath(win)) + end + } + opts.each{|k, v| + params.push("-#{k}") + params.push((v.kind_of?(TkObject))? v.epath: v) + } + tk_call_without_enc("grid", 'configure', *params) + end + + def columnconfigure(master, index, args) + # master = master.epath if master.kind_of?(TkObject) + master = _epath(master) + tk_call_without_enc("grid", 'columnconfigure', + master, index, *hash_kv(args)) + end + + def rowconfigure(master, index, args) + # master = master.epath if master.kind_of?(TkObject) + master = _epath(master) + tk_call_without_enc("grid", 'rowconfigure', master, index, *hash_kv(args)) + end + + def columnconfiginfo(master, index, slot=nil) + # master = master.epath if master.kind_of?(TkObject) + master = _epath(master) + if slot + num_or_str(tk_call_without_enc('grid', 'columnconfigure', + master, index, "-#{slot}")) + else + ilist = list(tk_call_without_enc('grid','columnconfigure',master,index)) + info = {} + while key = ilist.shift + info[key[1..-1]] = ilist.shift + end + info + end + end + + def rowconfiginfo(master, index, slot=nil) + # master = master.epath if master.kind_of?(TkObject) + master = _epath(master) + if slot + num_or_str(tk_call_without_enc('grid', 'rowconfigure', + master, index, "-#{slot}")) + else + ilist = list(tk_call_without_enc('grid', 'rowconfigure', master, index)) + info = {} + while key = ilist.shift + info[key[1..-1]] = ilist.shift + end + info + end + end + + def add(widget, *args) + configure(widget, *args) + end + + def forget(*args) + return '' if args.size == 0 + wins = args.collect{|win| + # (win.kind_of?(TkObject))? win.epath: win + _epath(win) + } + tk_call_without_enc('grid', 'forget', *wins) + end + + def info(slave) + # slave = slave.epath if slave.kind_of?(TkObject) + slave = _epath(slave) + ilist = list(tk_call_without_enc('grid', 'info', slave)) + info = {} + while key = ilist.shift + info[key[1..-1]] = ilist.shift + end + return info + end + + def location(master, x, y) + # master = master.epath if master.kind_of?(TkObject) + master = _epath(master) + list(tk_call_without_enc('grid', 'location', master, x, y)) + end + + def propagate(master, bool=None) + # master = master.epath if master.kind_of?(TkObject) + master = _epath(master) + if bool == None + bool(tk_call_without_enc('grid', 'propagate', master)) + else + tk_call_without_enc('grid', 'propagate', master, bool) + end + end + + def remove(*args) + return '' if args.size == 0 + wins = args.collect{|win| + # (win.kind_of?(TkObject))? win.epath: win + _epath(win) + } + tk_call_without_enc('grid', 'remove', *wins) + end + + def size(master) + # master = master.epath if master.kind_of?(TkObject) + master = _epath(master) + list(tk_call_without_enc('grid', 'size', master)) + end + + def slaves(master, args) + # master = master.epath if master.kind_of?(TkObject) + master = _epath(master) + list(tk_call_without_enc('grid', 'slaves', master, *hash_kv(args))) + end + + module_function :bbox, :forget, :propagate, :info + module_function :remove, :size, :slaves, :location + module_function :configure, :columnconfigure, :rowconfigure + module_function :columnconfiginfo, :rowconfiginfo +end +=begin +def TkGrid(win, *args) + if args[-1].kind_of?(Hash) + opts = args.pop + else + opts = {} + end + params = [] + params.push((win.kind_of?(TkObject))? win.epath: win) + args.each{|win| + case win + when '-', 'x', '^' # RELATIVE PLACEMENT + params.push(win) + else + params.push((win.kind_of?(TkObject))? win.epath: win) + end + } + opts.each{|k, v| + params.push("-#{k}") + params.push((v.kind_of?(TkObject))? v.epath: v) + } + tk_call_without_enc("grid", *params) +end +=end diff --git a/ext/tk/lib/tk/image.rb b/ext/tk/lib/tk/image.rb new file mode 100644 index 0000000000..70dd096434 --- /dev/null +++ b/ext/tk/lib/tk/image.rb @@ -0,0 +1,185 @@ +# +# tk/image.rb : treat Tk image objects +# + +require 'tk' + +class TkImage<TkObject + include Tk + + TkCommandNames = ['image'.freeze].freeze + + Tk_IMGTBL = TkCore::INTERP.create_table + Tk_Image_ID = ['i'.freeze, '00000'.taint].freeze + + TkCore::INTERP.init_ip_env{ Tk_IMGTBL.clear } + + def initialize(keys=nil) + @path = Tk_Image_ID.join('') + Tk_Image_ID[1].succ! + tk_call_without_enc('image', 'create', @type, @path, *hash_kv(keys, true)) + Tk_IMGTBL[@path] = self + end + + def delete + Tk_IMGTBL.delete(@id) if @id + tk_call_without_enc('image', 'delete', @path) + self + end + def height + number(tk_call_without_enc('image', 'height', @path)) + end + def inuse + bool(tk_call_without_enc('image', 'inuse', @path)) + end + def itemtype + tk_call_without_enc('image', 'type', @path) + end + def width + number(tk_call_without_enc('image', 'width', @path)) + end + + def TkImage.names + Tk.tk_call_without_enc('image', 'names').split.collect!{|id| + (Tk_IMGTBL[id])? Tk_IMGTBL[id] : id + } + end + + def TkImage.types + Tk.tk_call_without_enc('image', 'types').split + end +end + +class TkBitmapImage<TkImage + def initialize(*args) + @type = 'bitmap' + super + end +end + +class TkPhotoImage<TkImage + NullArgOptionKeys = [ "shrink", "grayscale" ] + + def _photo_hash_kv(keys) + keys = _symbolkey2str(keys) + NullArgOptionKeys.collect{|opt| + if keys[opt] + keys[opt] = None + else + keys.delete(opt) + end + } + hash_kv(keys).flatten + end + private :_photo_hash_kv + + def initialize(*args) + @type = 'photo' + super + end + + def blank + tk_send_without_enc('blank') + self + end + + def cget(option) + case option.to_s + when 'data', 'file' + tk_send 'cget', option + else + tk_tcl2ruby(tk_send('cget', option)) + end + end + + def copy(src, *opts) + if opts.size == 0 + tk_send('copy', src) + elsif opts.size == 1 && opts[0].kind_of?(Hash) + tk_send('copy', src, *_photo_hash_kv(opts[0])) + else + # for backward compatibility + args = opts.collect{|term| + if term.kind_of?(String) && term.include?(?\s) + term.split + else + term + end + }.flatten + tk_send('copy', source, *args) + end + self + end + + def data(keys={}) + #tk_send('data', *_photo_hash_kv(keys)) + tk_split_list(tk_send('data', *_photo_hash_kv(keys))) + end + + def get(x, y) + tk_send('get', x, y).split.collect{|n| n.to_i} + end + + def put(data, *opts) + if opts == [] + tk_send('put', data) + elsif opts.size == 1 && opts[0].kind_of?(Hash) + tk_send('put', data, *_photo_hash_kv(opts[0])) + else + # for backward compatibility + tk_send('put', data, '-to', *opts) + end + self + end + + def read(file, *opts) + if opts.size == 0 + tk_send('read', file) + elsif opts.size == 1 && opts[0].kind_of?(Hash) + tk_send('read', file, *_photo_hash_kv(opts[0])) + else + # for backward compatibility + args = opts.collect{|term| + if term.kind_of?(String) && term.include?(?\s) + term.split + else + term + end + }.flatten + tk_send('read', file, *args) + end + self + end + + def redither + tk_send 'redither' + self + end + + def get_transparency(x, y) + bool(tk_send('transparency', 'get', x, y)) + end + def set_transparency(x, y, st) + tk_send('transparency', 'set', x, y, st) + self + end + + def write(file, *opts) + if opts.size == 0 + tk_send('write', file) + elsif opts.size == 1 && opts[0].kind_of?(Hash) + tk_send('write', file, *_photo_hash_kv(opts[0])) + else + # for backward compatibility + args = opts.collect{|term| + if term.kind_of?(String) && term.include?(?\s) + term.split + else + term + end + }.flatten + tk_send('write', file, *args) + end + self + end +end diff --git a/ext/tk/lib/tk/itemfont.rb b/ext/tk/lib/tk/itemfont.rb new file mode 100644 index 0000000000..6e92fc001c --- /dev/null +++ b/ext/tk/lib/tk/itemfont.rb @@ -0,0 +1,185 @@ +# +# tk/itemfont.rb : control font of widget items +# +require 'tk' + +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 diff --git a/ext/tk/lib/tk/kinput.rb b/ext/tk/lib/tk/kinput.rb new file mode 100644 index 0000000000..418b3aec47 --- /dev/null +++ b/ext/tk/lib/tk/kinput.rb @@ -0,0 +1,71 @@ +# +# tk/kinput.rb : control kinput +# +require 'tk' + +module TkKinput + include Tk + extend Tk + + TkCommandNames = [ + 'kinput_start'.freeze, + 'kinput_send_spot'.freeze, + 'kanjiInput'.freeze + ].freeze + + def TkKinput.start(window, style=None) + tk_call('kinput_start', window, style) + end + def kinput_start(style=None) + TkKinput.start(self, style) + end + + def TkKinput.send_spot(window) + tk_call('kinput_send_spot', window) + end + def kinput_send_spot + TkKinput.send_spot(self) + end + + def TkKinput.input_start(window, keys=nil) + tk_call('kanjiInput', 'start', window, *hash_kv(keys)) + end + def kanji_input_start(keys=nil) + TkKinput.input_start(self, keys) + end + + def TkKinput.attribute_config(window, slot, value=None) + if slot.kind_of? Hash + tk_call('kanjiInput', 'attribute', window, *hash_kv(slot)) + else + tk_call('kanjiInput', 'attribute', window, "-#{slot}", value) + end + end + def kinput_attribute_config(slot, value=None) + TkKinput.attribute_config(self, slot, value) + end + + def TkKinput.attribute_info(window, slot=nil) + if slot + conf = tk_split_list(tk_call('kanjiInput', 'attribute', + window, "-#{slot}")) + conf[0] = conf[0][1..-1] + conf + else + tk_split_list(tk_call('kanjiInput', 'attribute', window)).collect{|conf| + conf[0] = conf[0][1..-1] + conf + } + end + end + def kinput_attribute_info(slot=nil) + TkKinput.attribute_info(self, slot) + end + + def TkKinput.input_end(window) + tk_call('kanjiInput', 'end', window) + end + def kanji_input_end + TkKinput.input_end(self) + end +end diff --git a/ext/tk/lib/tk/label.rb b/ext/tk/lib/tk/label.rb new file mode 100644 index 0000000000..fe2640958d --- /dev/null +++ b/ext/tk/lib/tk/label.rb @@ -0,0 +1,22 @@ +# +# tk/label.rb : treat label widget +# +require 'tk' + +class TkLabel<TkWindow + TkCommandNames = ['label'.freeze].freeze + WidgetClassName = 'Label'.freeze + WidgetClassNames[WidgetClassName] = self + def create_self(keys) + if keys and keys != None + tk_call_without_enc('label', @path, *hash_kv(keys, true)) + else + tk_call_without_enc('label', @path) + end + end + private :create_self + + def textvariable(v) + configure 'textvariable', tk_trace_variable(v) + end +end diff --git a/ext/tk/lib/tk/labelframe.rb b/ext/tk/lib/tk/labelframe.rb new file mode 100644 index 0000000000..fa658848c8 --- /dev/null +++ b/ext/tk/lib/tk/labelframe.rb @@ -0,0 +1,20 @@ +# +# tk/labelframe.rb : treat labelframe widget +# +require 'tk' +require 'tk/frame' + +class TkLabelFrame<TkFrame + TkCommandNames = ['labelframe'.freeze].freeze + WidgetClassName = 'Labelframe'.freeze + WidgetClassNames[WidgetClassName] = self + def create_self(keys) + if keys and keys != None + tk_call_without_enc('labelframe', @path, *hash_kv(keys, true)) + else + tk_call_without_enc('labelframe', @path) + end + end + private :create_self +end +TkLabelframe = TkLabelFrame diff --git a/ext/tk/lib/tk/listbox.rb b/ext/tk/lib/tk/listbox.rb new file mode 100644 index 0000000000..611226682a --- /dev/null +++ b/ext/tk/lib/tk/listbox.rb @@ -0,0 +1,252 @@ +# +# tk/listbox.rb : treat listbox widget +# +require 'tk' +require 'tk/scrollable' +require 'tk/txtwin_abst' + +module TkTreatListItemFont + include TkTreatItemFont + + ItemCMD = ['itemconfigure'.freeze, TkComm::None].freeze + def __conf_cmd(idx) + ItemCMD[idx] + end + + def __item_pathname(tagOrId) + self.path + ';' + tagOrId.to_s + end + + private :__conf_cmd, :__item_pathname +end + + +class TkListbox<TkTextWin + include TkTreatListItemFont + include Scrollable + + TkCommandNames = ['listbox'.freeze].freeze + WidgetClassName = 'Listbox'.freeze + WidgetClassNames[WidgetClassName] = self + + def create_self(keys) + if keys and keys != None + tk_call_without_enc('listbox', @path, *hash_kv(keys, true)) + else + tk_call_without_enc('listbox', @path) + end + end + private :create_self + + def activate(y) + tk_send_without_enc('activate', y) + self + end + def curselection + list(tk_send_without_enc('curselection')) + end + def get(first, last=nil) + if last + tk_split_simplelist(_fromUTF8(tk_send_without_enc('get', first, last))) + else + _fromUTF8(tk_send_without_enc('get', first)) + end + end + def nearest(y) + tk_send_without_enc('nearest', y).to_i + end + def size + tk_send_without_enc('size').to_i + end + def selection_anchor(index) + tk_send_without_enc('selection', 'anchor', index) + self + end + def selection_clear(first, last=None) + tk_send_without_enc('selection', 'clear', first, last) + self + end + def selection_includes(index) + bool(tk_send_without_enc('selection', 'includes', index)) + end + def selection_set(first, last=None) + tk_send_without_enc('selection', 'set', first, last) + self + end + + def index(index) + tk_send_without_enc('index', index).to_i + end + + def itemcget(index, key) + case key.to_s + when 'text', 'label', 'show' + _fromUTF8(tk_send_without_enc('itemcget', index, "-#{key}")) + when 'font', 'kanjifont' + #fnt = tk_tcl2ruby(tk_send('itemcget', index, "-#{key}")) + fnt = tk_tcl2ruby(_fromUTF8(tk_send_without_enc('itemcget', 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 + else + tk_tcl2ruby(_fromUTF8(tk_send_without_enc('itemcget', index, "-#{key}"))) + end + end + def itemconfigure(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_without_enc('itemconfigure', index, *hash_kv(key, true)) + end + + 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('itemconfigure', index, "-#{key}", val) + end + end + self + end + + def itemconfiginfo(index, key=nil) + if TkComm::GET_CONFIGINFO_AS_ARRAY + if key + case key.to_s + when 'text', 'label', 'show' + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure',index,"-#{key}"))) + when 'font', 'kanjifont' + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure',index,"-#{key}"))) + conf[4] = tagfont_configinfo(index, conf[4]) + else + conf = tk_split_list(_fromUTF8(tk_send_without_enc('itemconfigure',index,"-#{key}"))) + end + conf[0] = conf[0][1..-1] + conf + else + ret = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure', 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[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] = tagfont_configinfo(index, fontconf[4]) + ret.push(fontconf) + else + ret + end + end + else # ! TkComm::GET_CONFIGINFO_AS_ARRAY + if key + case key.to_s + when 'text', 'label', 'show' + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure',index,"-#{key}"))) + when 'font', 'kanjifont' + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure',index,"-#{key}"))) + conf[4] = tagfont_configinfo(index, conf[4]) + else + conf = tk_split_list(_fromUTF8(tk_send_without_enc('itemconfigure',index,"-#{key}"))) + end + key = conf.shift[1..-1] + { key => conf } + else + ret = {} + tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure', index))).each{|conflist| + conf = tk_split_simplelist(conflist) + key = conf.shift[1..-1] + case key + when 'text', 'label', 'show' + 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 + ret[key] = conf + end + } + fontconf = ret['font'] + if fontconf + ret.delete('font') + ret.delete('kanjifont') + fontconf[3] = tagfont_configinfo(index, fontconf[3]) + ret['font'] = fontconf + end + ret + end + end + end + + def current_itemconfiginfo(index, key=nil) + if TkComm::GET_CONFIGINFO_AS_ARRAY + if key + conf = itemconfiginfo(index, key) + {conf[0] => conf[4]} + else + ret = {} + itemconfiginfo(index).each{|conf| + ret[conf[0]] = conf[4] if conf.size > 2 + } + ret + end + else # ! TkComm::GET_CONFIGINFO_AS_ARRAY + ret = {} + itemconfiginfo(index, key).each{|k, conf| + ret[k] = conf[-1] if conf.kind_of?(Array) + } + ret + end + end +end diff --git a/ext/tk/lib/tk/macpkg.rb b/ext/tk/lib/tk/macpkg.rb new file mode 100644 index 0000000000..d67a19745b --- /dev/null +++ b/ext/tk/lib/tk/macpkg.rb @@ -0,0 +1,68 @@ +# +# tk/macpkg.rb : methods for Tcl/Tk packages for Macintosh +# 2000/11/22 by Hidetoshi Nagai <nagai@ai.kyutech.ac.jp> +# +# ATTENTION !! +# This is NOT TESTED. Because I have no test-environment. +# +# +require 'tk' + +module Tk + def Tk.load_tclscript_rsrc(resource_name, file=None) + # Mac only + tk_call('source', '-rsrc', resource_name, file) + end + + def Tk.load_tclscript_rsrcid(resource_id, file=None) + # Mac only + tk_call('source', '-rsrcid', resource_id, file) + end +end + +module TkMacResource + extend Tk + extend TkMacResource + + TkCommandNames = ['resource'.freeze].freeze + + tk_call_without_enc('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 diff --git a/ext/tk/lib/tk/menu.rb b/ext/tk/lib/tk/menu.rb new file mode 100644 index 0000000000..9c34741b1b --- /dev/null +++ b/ext/tk/lib/tk/menu.rb @@ -0,0 +1,460 @@ +# +# tk/menu.rb : treat menu and menubutton +# +require 'tk' + +module TkTreatMenuEntryFont + include TkTreatItemFont + + ItemCMD = ['entryconfigure'.freeze, TkComm::None].freeze + def __conf_cmd(idx) + ItemCMD[idx] + end + + def __item_pathname(tagOrId) + self.path + ';' + tagOrId.to_s + end + + private :__conf_cmd, :__item_pathname +end + +class TkMenu<TkWindow + include TkTreatMenuEntryFont + + TkCommandNames = ['menu'.freeze].freeze + WidgetClassName = 'Menu'.freeze + WidgetClassNames[WidgetClassName] = self + + def create_self(keys) + if keys and keys != None + tk_call_without_enc('menu', @path, *hash_kv(keys, true)) + else + tk_call_without_enc('menu', @path) + end + end + private :create_self + + def activate(index) + tk_send_without_enc('activate', _get_eval_enc_str(index)) + self + end + def add(type, keys=nil) + tk_send_without_enc('add', type, *hash_kv(keys, true)) + self + end + def add_cascade(keys=nil) + add('cascade', keys) + end + def add_checkbutton(keys=nil) + add('checkbutton', keys) + end + def add_command(keys=nil) + add('command', keys) + end + def add_radiobutton(keys=nil) + add('radiobutton', keys) + end + def add_separator(keys=nil) + add('separator', keys) + end + def index(index) + ret = tk_send_without_enc('index', _get_eval_enc_str(index)) + (ret == 'none')? nil: number(ret) + end + def invoke(index) + _fromUTF8(tk_send_without_enc('invoke', _get_eval_enc_str(index))) + end + def insert(index, type, keys=nil) + tk_send_without_enc('insert', _get_eval_enc_str(index), + type, *hash_kv(keys, true)) + self + end + def delete(first, last=nil) + if last + tk_send_without_enc('delete', _get_eval_enc_str(first), + _get_eval_enc_str(last)) + else + tk_send_without_enc('delete', _get_eval_enc_str(first)) + end + self + end + def popup(x, y, index=nil) + if index + tk_call_without_enc('tk_popup', path, x, y, + _get_eval_enc_str(index)) + else + tk_call_without_enc('tk_popup', path, x, y) + end + self + end + def post(x, y) + _fromUTF8(tk_send_without_enc('post', x, y)) + end + def postcascade(index) + tk_send_without_enc('postcascade', _get_eval_enc_str(index)) + self + end + def postcommand(cmd=Proc.new) + configure_cmd 'postcommand', cmd + self + end + def set_focus + tk_call_without_enc('tk_menuSetFocus', path) + self + end + def tearoffcommand(cmd=Proc.new) + configure_cmd 'tearoffcommand', cmd + self + end + def menutype(index) + tk_send_without_enc('type', _get_eval_enc_str(index)) + end + def unpost + tk_send_without_enc('unpost') + self + end + def yposition(index) + number(tk_send_without_enc('yposition', _get_eval_enc_str(index))) + end + def entrycget(index, key) + case key.to_s + when 'text', 'label', 'show' + _fromUTF8(tk_send_without_enc('entrycget', + _get_eval_enc_str(index), "-#{key}")) + when 'font', 'kanjifont' + #fnt = tk_tcl2ruby(tk_send('entrycget', index, "-#{key}")) + fnt = tk_tcl2ruby(_fromUTF8(tk_send_without_enc('entrycget', _get_eval_enc_str(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 + else + tk_tcl2ruby(_fromUTF8(tk_send_without_enc('entrycget', _get_eval_enc_str(index), "-#{key}"))) + end + 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_without_enc('entryconfigure', _get_eval_enc_str(index), + *hash_kv(key, true)) + end + + 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 + end + self + end + + def entryconfiginfo(index, key=nil) + if TkComm::GET_CONFIGINFO_AS_ARRAY + if key + case key.to_s + when 'text', 'label', 'show' + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('entryconfigure',_get_eval_enc_str(index),"-#{key}"))) + when 'font', 'kanjifont' + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('entryconfigure',_get_eval_enc_str(index),"-#{key}"))) + conf[4] = tagfont_configinfo(index, conf[4]) + else + conf = tk_split_list(_fromUTF8(tk_send_without_enc('entryconfigure',_get_eval_enc_str(index),"-#{key}"))) + end + conf[0] = conf[0][1..-1] + conf + else + ret = tk_split_simplelist(_fromUTF8(tk_send_without_enc('entryconfigure', _get_eval_enc_str(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[1] = conf[1][1..-1] if conf.size == 2 # alias info + 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 + else # ! TkComm::GET_CONFIGINFO_AS_ARRAY + if key + case key.to_s + when 'text', 'label', 'show' + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('entryconfigure',_get_eval_enc_str(index),"-#{key}"))) + when 'font', 'kanjifont' + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('entryconfigure',_get_eval_enc_str(index),"-#{key}"))) + conf[4] = tagfont_configinfo(index, conf[4]) + else + conf = tk_split_list(_fromUTF8(tk_send_without_enc('entryconfigure',_get_eval_enc_str(index),"-#{key}"))) + end + key = conf.shift[1..-1] + { key => conf } + else + ret = {} + tk_split_simplelist(_fromUTF8(tk_send_without_enc('entryconfigure', _get_eval_enc_str(index)))).each{|conflist| + conf = tk_split_simplelist(conflist) + key = conf.shift[1..-1] + case key + when 'text', 'label', 'show' + 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 + ret[key] = conf + end + } + fontconf = ret['font'] + if fontconf + ret.delete('font') + ret.delete('kanjifont') + fontconf[3] = tagfont_configinfo(index, fontconf[3]) + ret['font'] = fontconf + end + ret + end + end + end + + def current_entryconfiginfo(index, key=nil) + if TkComm::GET_CONFIGINFO_AS_ARRAY + if key + conf = entryconfiginfo(index, key) + {conf[0] => conf[4]} + else + ret = {} + entryconfiginfo(index).each{|conf| + ret[conf[0]] = conf[4] if conf.size > 2 + } + ret + end + else # ! TkComm::GET_CONFIGINFO_AS_ARRAY + ret = {} + entryconfiginfo(index, key).each{|k, conf| + ret[k] = conf[-1] if conf.kind_of?(Array) + } + ret + end + end +end + + +class TkMenuClone<TkMenu + def initialize(parent, type=None) + widgetname = nil + if parent.kind_of? Hash + keys = _symbolkey2str(parent) + parent = keys.delete('parent') + widgetname = keys.delete('widgetname') + type = keys.delete('type'); type = None unless type + end + unless parent.kind_of?(TkMenu) + fail ArgumentError, "parent must be TkMenu" + end + @parent = parent + install_win(@parent.path, widgetname) + tk_call_without_enc(@parent.path, 'clone', @path, type) + end +end + + +module TkSystemMenu + def initialize(parent, keys=nil) + if parent.kind_of? Hash + keys = _symbolkey2str(parent) + parent = keys.delete('parent') + end + unless parent.kind_of? TkMenu + fail ArgumentError, "parent must be a TkMenu object" + end + # @path = Kernel.format("%s.%s", parent.path, self.class::SYSMENU_NAME) + @path = parent_path + '.' + self.class::SYSMENU_NAME + #TkComm::Tk_WINDOWS[@path] = self + TkCore::INTERP.tk_windows[@path] = self + if self.method(:create_self).arity == 0 + p 'create_self has no arg' if $DEBUG + create_self + configure(keys) if keys + else + p 'create_self has an arg' if $DEBUG + create_self(keys) + end + end +end + + +class TkSysMenu_Help<TkMenu + # for all platform + include TkSystemMenu + SYSMENU_NAME = 'help' +end + + +class TkSysMenu_System<TkMenu + # for Windows + include TkSystemMenu + SYSMENU_NAME = 'system' +end + + +class TkSysMenu_Apple<TkMenu + # for Machintosh + include TkSystemMenu + SYSMENU_NAME = 'apple' +end + + +class TkMenubutton<TkLabel + TkCommandNames = ['menubutton'.freeze].freeze + WidgetClassName = 'Menubutton'.freeze + WidgetClassNames[WidgetClassName] = self + def create_self(keys) + if keys and keys != None + tk_call_without_enc('menubutton', @path, *hash_kv(keys, true)) + else + tk_call_without_enc('menubutton', @path) + end + end + private :create_self +end + + +class TkOptionMenubutton<TkMenubutton + TkCommandNames = ['tk_optionMenu'.freeze].freeze + + class OptionMenu<TkMenu + def initialize(path) #==> return value of tk_optionMenu + @path = path + #TkComm::Tk_WINDOWS[@path] = self + TkCore::INTERP.tk_windows[@path] = self + end + 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)) + end + + def value + @variable.value + end + + def activate(index) + @menu.activate(index) + self + end + def add(value) + @menu.add('radiobutton', 'variable'=>@variable, + 'label'=>value, 'value'=>value) + self + end + def index(index) + @menu.index(index) + end + def invoke(index) + @menu.invoke(index) + end + def insert(index, value) + @menu.add(index, 'radiobutton', 'variable'=>@variable, + 'label'=>value, 'value'=>value) + self + end + def delete(index, last=None) + @menu.delete(index, last) + self + end + def yposition(index) + @menu.yposition(index) + end + def menu + @menu + end + def menucget(key) + @menu.cget(key) + end + def menuconfigure(key, val=None) + @menu.configure(key, val) + self + end + def menuconfiginfo(key=nil) + @menu.configinfo(key) + end + def current_menuconfiginfo(key=nil) + @menu.current_configinfo(key) + end + def entrycget(index, key) + @menu.entrycget(index, key) + end + def entryconfigure(index, key, val=None) + @menu.entryconfigure(index, key, val) + self + end + def entryconfiginfo(index, key=nil) + @menu.entryconfiginfo(index, key) + end + def current_entryconfiginfo(index, key=nil) + @menu.current_entryconfiginfo(index, key) + end +end diff --git a/ext/tk/lib/tk/menubar.rb b/ext/tk/lib/tk/menubar.rb new file mode 100644 index 0000000000..2c2846e9b6 --- /dev/null +++ b/ext/tk/lib/tk/menubar.rb @@ -0,0 +1,144 @@ +# +# 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' +require 'tk/frame' + +class TkMenubar<TkFrame + + include TkComposite + + def initialize(parent = nil, spec = nil, options = nil) + if parent.kind_of? Hash + options = _symbolkey2str(parent) + spec = options.delete('spec') + super(options) + else + super(parent, options) + end + + @menus = [] + + if spec + for menu_info in spec + add_menu(menu_info) + end + end + + if options + for key, value in options + configure(key, value) + end + end + end + + def add_menu(menu_info) + btn_info = menu_info.shift + mbtn = TkMenubutton.new(@frame) + + if btn_info.kind_of?(Hash) + for key, value in btn_info + mbtn.configure(key, value) + end + elsif btn_info.kind_of?(Array) + mbtn.configure('text', btn_info[0]) if btn_info[0] + mbtn.configure('underline', btn_info[1]) if btn_info[1] + mbtn.configure('accelerator', btn_info[2]) if btn_info[2] + else + mbtn.configure('text', btn_info) + end + + menu = TkMenu.new(mbtn) + + for item_info in menu_info + if item_info.kind_of?(Hash) + menu.add('command', item_info) + elsif item_info.kind_of?(Array) + options = {} + options['label'] = item_info[0] if item_info[0] + options['command'] = item_info[1] if item_info[1] + options['underline'] = item_info[2] if item_info[2] + options['accelerator'] = item_info[3] if item_info[3] + menu.add('command', options) + elsif /^-+$/ =~ item_info + menu.add('sep') + else + menu.add('command', 'label' => 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 diff --git a/ext/tk/lib/tk/message.rb b/ext/tk/lib/tk/message.rb new file mode 100644 index 0000000000..b359800142 --- /dev/null +++ b/ext/tk/lib/tk/message.rb @@ -0,0 +1,19 @@ +# +# tk/message.rb : treat message widget +# +require 'tk' +require 'tk/label' + +class TkMessage<TkLabel + TkCommandNames = ['message'.freeze].freeze + WidgetClassName = 'Message'.freeze + WidgetClassNames[WidgetClassName] = self + def create_self(keys) + if keys and keys != None + tk_call_without_enc('message', @path, *hash_kv(keys, true)) + else + tk_call_without_enc('message', @path) + end + end + private :create_self +end diff --git a/ext/tk/lib/tk/mngfocus.rb b/ext/tk/lib/tk/mngfocus.rb new file mode 100644 index 0000000000..a0f18233be --- /dev/null +++ b/ext/tk/lib/tk/mngfocus.rb @@ -0,0 +1,33 @@ +# +# tk/mngfocus.rb : methods for Tcl/Tk standard library 'focus.tcl' +# by Hidetoshi Nagai <nagai@ai.kyutech.ac.jp> +# +require 'tk' + +module TkManageFocus + extend Tk + + TkCommandNames = [ + 'tk_focusFollowMouse'.freeze, + 'tk_focusNext'.freeze, + 'tk_focusPrev'.freeze + ].freeze + + def TkManageFocus.followsMouse + tk_call_without_enc('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 diff --git a/ext/tk/lib/tk/msgcat.rb b/ext/tk/lib/tk/msgcat.rb new file mode 100644 index 0000000000..6c46542faf --- /dev/null +++ b/ext/tk/lib/tk/msgcat.rb @@ -0,0 +1,268 @@ +# +# tk/msgcat.rb : methods for Tcl message catalog +# by Hidetoshi Nagai <nagai@ai.kyutech.ac.jp> +# +require 'tk' + +#class TkMsgCatalog +class TkMsgCatalog < TkObject + include TkCore + extend Tk + #extend TkMsgCatalog + + TkCommandNames = [ + '::msgcat::mc'.freeze, + '::msgcat::mcmax'.freeze, + '::msgcat::mclocale'.freeze, + '::msgcat::mcpreferences'.freeze, + '::msgcat::mcload'.freeze, + '::msgcat::mcset'.freeze, + '::msgcat::mcmset'.freeze, + '::msgcat::mcunknown'.freeze + ].freeze + + tk_call_without_enc('package', 'require', 'Tcl', '8.2') + + if self.const_defined? :FORCE_VERSION + tk_call_without_enc('package', 'require', 'msgcat', FORCE_VERSION) + else + tk_call_without_enc('package', 'require', 'msgcat') + end + + MSGCAT_EXT = '.msg' + + UNKNOWN_CBTBL = Hash.new{|hash,key| hash[key] = {}}.taint + + TkCore::INTERP.add_tk_procs('::msgcat::mcunknown', 'args', <<-'EOL') + if {[set st [catch {eval {ruby_cmd TkMsgCatalog callback} [namespace current] $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 + + def self.callback(namespace, locale, src_str) + cmd_tbl = TkMsgCatalog::UNKNOWN_CBTBL[TkCore::INTERP.__getip] + cmd = cmd_tbl[namespace] + cmd = cmd_tbl['::'] unless cmd # use global scope as interp default + return src_str unless cmd # no cmd -> return src-str (default action) + begin + cmd.call(locale, src_str) + rescue Exception => e + begin + 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 + + def initialize(namespace = nil) + if namespace.kind_of?(TkNamespace) + @namespace = namespace + elsif namespace == nil + @namespace = TkNamespace.new('::') # global namespace + else + @namespace = TkNamespace.new(namespace) + end + @path = @namespace.path + + @msgcat_ext = '.msg' + end + attr_accessor :msgcat_ext + + def method_missing(id, *args) + # locale(src, trans) ==> set_translation(locale, src, trans) + loc = id.id2name + case args.length + when 0 # set locale + self.locale=(loc) + + when 1 # src only, or trans_list + if args[0].kind_of?(Array) + # trans_list + #list = args[0].collect{|src, trans| + # [ Tk::UTF8_String.new(src), Tk::UTF8_String.new(trans) ] + #} + self.set_translation_list(loc, args[0]) + else + # src + #self.set_translation(loc, Tk::UTF8_String.new(args[0])) + self.set_translation(loc, args[0]) + end + + when 2 # src and trans, or, trans_list and enc + if args[0].kind_of?(Array) + else + #self.set_translation(loc, args[0], Tk::UTF8_String.new(args[1])) + self.set_translation(loc, *args) + end + + when 3 # src and trans and enc + self.set_translation(loc, *args) + + else + fail NameError, "undefined method `#{name}' for #{self.to_s}", error_at + + end + end + + # *args ::= form, arg, arg, ... + def self.translate(*args) + dst = args.collect{|src| + tk_call_without_enc('::msgcat::mc', _get_eval_string(src, true)) + } + Tk.UTF8_String(sprintf(*dst)) + end + class << self + alias mc translate + alias [] translate + end + def translate(*args) + dst = args.collect{|src| + @namespace.eval{tk_call_without_enc('::msgcat::mc', + _get_eval_string(src, true))} + } + Tk.UTF8_String(sprintf(*dst)) + end + alias mc translate + alias [] translate + + def self.maxlen(*src_strings) + tk_call('::msgcat::mcmax', *src_strings).to_i + end + def maxlen(*src_strings) + @namespace.eval{tk_call('::msgcat::mcmax', *src_strings).to_i} + end + + def self.locale + tk_call('::msgcat::mclocale') + end + def locale + @namespace.eval{tk_call('::msgcat::mclocale')} + end + + def self.locale=(locale) + tk_call('::msgcat::mclocale', locale) + end + def locale=(locale) + @namespace.eval{tk_call('::msgcat::mclocale', locale)} + end + + def self.preferences + tk_split_simplelist(tk_call('::msgcat::mcpreferences')) + end + def preferences + tk_split_simplelist(@namespace.eval{tk_call('::msgcat::mcpreferences')}) + end + + def self.load_tk(dir) + number(tk_call('::msgcat::mcload', dir)) + end + + def self.load_rb(dir) + count = 0 + preferences().each{|loc| + file = File.join(dir, loc + self::MSGCAT_EXT) + if File.readable?(file) + count += 1 + eval(open(file){|f| f.read}) + end + } + count + end + + def load_tk(dir) + number(@namespace.eval{tk_call('::msgcat::mcload', dir)}) + end + + def load_rb(dir) + count = 0 + preferences().each{|loc| + file = File.join(dir, loc + @msgcat_ext) + if File.readable?(file) + count += 1 + @namespace.eval(open(file){|f| f.read}) + end + } + count + end + + def self.load(dir) + self.load_rb(dir) + end + alias load load_rb + + def self.set_translation(locale, src_str, trans_str=None, enc='utf-8') + trans_str = Tk.UTF8_String(_toUTF8(trans_str, enc)) if trans_str != None + Tk.UTF8_String(tk_call_without_enc('::msgcat::mcset', + locale, + _get_eval_string(src_str, true), + trans_str)) + end + def set_translation(locale, src_str, trans_str=None, enc='utf-8') + trans_str = Tk.UTF8_String(_toUTF8(trans_str, enc)) if trans_str != None + Tk.UTF8_String(@namespace.eval{ + tk_call_without_enc('::msgcat::mcset', + locale, + _get_eval_string(src_str, true), + trans_str) + }) + end + + def self.set_translation_list(locale, trans_list, enc='utf-8') + # trans_list ::= [ [src, trans], [src, trans], ... ] + list = [] + trans_list.each{|src, trans| + if trans && trans != None + list << _get_eval_string(src, true) + list << Tk.UTF8_Stirng(_toUTF8(trans, enc)) + else + list << _get_eval_string(src, true) << '' + end + } + number(tk_call_without_enc('::msgcat::mcmset', locale, list)) + end + def set_translation_list(locale, trans_list, enc='utf-8') + # trans_list ::= [ [src, trans], [src, trans], ... ] + list = [] + trans_list.each{|src, trans| + if trans && trans != None + list << _get_eval_string(src, true) + list << Tk.UTF8_String(_toUTF8(trans, enc)) + else + list << _get_eval_string(src, true) << '' + end + } + number(@namespace.eval{ + tk_call_without_enc('::msgcat::mcmset', locale, list) + }) + end + + def self.def_unknown_proc(cmd=Proc.new) + TkMsgCatalog::UNKNOWN_CBTBL[TkCore::INTERP.__getip]['::'] = cmd + end + def def_unknown_proc(cmd=Proc.new) + TkMsgCatalog::UNKNOWN_CBTBL[TkCore::INTERP.__getip][@namespace.path] = cmd + end +end + +TkMsgCat = TkMsgCatalog diff --git a/ext/tk/lib/tk/namespace.rb b/ext/tk/lib/tk/namespace.rb new file mode 100644 index 0000000000..72e9500a49 --- /dev/null +++ b/ext/tk/lib/tk/namespace.rb @@ -0,0 +1,293 @@ +# +# tk/namespace.rb : methods to manipulate Tcl/Tk namespace +# by Hidetoshi Nagai <nagai@ai.kyutech.ac.jp> +# +require 'tk' + +class TkNamespace < TkObject + extend Tk + + TkCommandNames = [ + 'namespace'.freeze, + ].freeze + + Tk_Namespace_ID_TBL = TkCore::INTERP.create_table + Tk_Namespace_ID = ["ns".freeze, "00000".taint].freeze + + class ScopeArgs < Array + include Tk + + # alias __tk_call tk_call + # alias __tk_call_without_enc tk_call_without_enc + # alias __tk_call_with_enc tk_call_with_enc + def tk_call(*args) + #super('namespace', 'eval', @namespace, *args) + args = args.collect{|arg| (s = _get_eval_string(arg))? s: ''} + super('namespace', 'eval', @namespace, + TkCore::INTERP._merge_tklist(*args)) + end + def tk_call_without_enc(*args) + #super('namespace', 'eval', @namespace, *args) + args = args.collect{|arg| (s = _get_eval_string(arg))? s: ''} + super('namespace', 'eval', @namespace, + TkCore::INTERP._merge_tklist(*args)) + end + def tk_call_with_enc(*args) + #super('namespace', 'eval', @namespace, *args) + args = args.collect{|arg| (s = _get_eval_string(arg))? s: ''} + super('namespace', 'eval', @namespace, + TkCore::INTERP._merge_tklist(*args)) + end + + def initialize(namespace, *args) + @namespace = namespace + super(args.size) + self.replace(args) + end + end + + class NsCode < TkObject + def initialize(scope) + @scope = scope + ' ' + end + def path + @scope + end + def to_eval + @scope + end + def call(*args) + TkCore::INTERP._eval_without_enc(@scope + array2tk_list(args)) + end + end + + alias __tk_call tk_call + alias __tk_call_without_enc tk_call_without_enc + alias __tk_call_with_enc tk_call_with_enc + def tk_call(*args) + #super('namespace', 'eval', @fullname, *args) + args = args.collect{|arg| (s = _get_eval_string(arg))? s: ''} + super('namespace', 'eval', @fullname, + TkCore::INTERP._merge_tklist(*args)) + end + def tk_call_without_enc(*args) + #super('namespace', 'eval', @fullname, *args) + args = args.collect{|arg| (s = _get_eval_string(arg))? s: ''} + super('namespace', 'eval', @fullname, + TkCore::INTERP._merge_tklist(*args)) + end + def tk_call_with_enc(*args) + #super('namespace', 'eval', @fullname, *args) + args = args.collect{|arg| (s = _get_eval_string(arg))? s: ''} + super('namespace', 'eval', @fullname, + TkCore::INTERP._merge_tklist(*args)) + end + alias ns_tk_call tk_call + alias ns_tk_call_without_enc tk_call_without_enc + alias ns_tk_call_with_enc tk_call_with_enc + + def initialize(name = nil, parent = nil) + unless name + name = Tk_Namespace_ID.join('') + Tk_Namespace_ID[1].succ! + end + name = __tk_call('namespace', 'current') if name == '' + if parent + if parent =~ /^::/ + if name =~ /^::/ + @fullname = parent + name + else + @fullname = parent +'::'+ name + end + else + ancestor = __tk_call('namespace', 'current') + ancestor = '' if ancestor == '::' + if name =~ /^::/ + @fullname = ancestor + '::' + parent + name + else + @fullname = ancestor + '::'+ parent +'::'+ name + end + end + else # parent == nil + ancestor = __tk_call('namespace', 'current') + ancestor = '' if ancestor == '::' + if name =~ /^::/ + @fullname = name + else + @fullname = ancestor + '::' + name + end + end + @path = @fullname + @parent = __tk_call('namespace', 'qualifiers', @fullname) + @name = __tk_call('namespace', 'tail', @fullname) + + # create namespace + __tk_call('namespace', 'eval', @fullname, '') + + Tk_Namespace_ID_TBL[@fullname] = self + end + + def self.children(*args) + # args ::= [<namespace>] [<pattern>] + # <pattern> must be glob-style pattern + tk_split_simplelist(tk_call('namespace', 'children', *args)).collect{|ns| + # ns is fullname + if Tk_Namesapce_ID.key?(ns) + Tk_Namesapce_ID[ns] + else + ns + end + } + end + def children(pattern=None) + TkNamespace.children(@fullname, pattern) + end + + def self.code(script = Proc.new) + TkNamespace.new('').code(script) + end + def code(script = Proc.new) + if script.kind_of?(String) + cmd = proc{|*args| ScopeArgs.new(@fullname,*args).instance_eval(script)} + elsif script.kind_of?(Proc) + cmd = proc{|*args| ScopeArgs.new(@fullname,*args).instance_eval(&script)} + else + fail ArgumentError, "String or Proc is expected" + end + TkNamespace::NsCode.new(tk_call_without_enc('namespace', 'code', + _get_eval_string(cmd, false))) + end + + def self.current + tk_call('namespace', 'current') + end + def current_namespace + # ns_tk_call('namespace', 'current') + @fullname + end + alias current current_namespace + + def self.delete(*ns_list) + tk_call('namespace', 'delete', *ns_list) + end + def delete + TkNamespece.delete(@fullname) + end + + def self.ensemble_create(*keys) + tk_call('namespace', 'ensemble', 'create', *hash_kv(keys)) + end + def self.ensemble_configure(cmd, slot, value=None) + if slot.kind_of?(Hash) + tk_call('namespace', 'ensemble', 'configure', cmd, *hash_kv(slot)) + else + tk_call('namespace', 'ensemble', 'configure', cmd, '-'+slot.to_s, value) + end + end + def self.ensemble_configinfo(cmd, slot = nil) + if slot + tk_call('namespace', 'ensemble', 'configure', cmd, '-' + slot.to_s) + else + inf = {} + Hash(*tk_split_simplelist(tk_call('namespace', 'ensemble', 'configure', cmd))).each{|k, v| inf[k[1..-1]] = v} + inf + end + end + def self.ensemble_exist?(cmd) + bool(tk_call('namespace', 'ensemble', 'exists', cmd)) + end + + def self.eval(namespace, cmd = Proc.new, *args) + #tk_call('namespace', 'eval', namespace, cmd, *args) + TkNamespace.new(namespece).eval(cmd, *args) + end + def eval(cmd = Proc.new, *args) + #TkNamespace.eval(@fullname, cmd, *args) + #ns_tk_call(cmd, *args) + code_obj = code(cmd) + ret = code_obj.call(*args) + uninstall_cmd(TkCore::INTERP._split_tklist(code_obj.path)[-1]) + ret + end + + def self.exist?(ns) + bool(tk_call('namespace', 'exists', ns)) + end + def exist? + TkNamespece.delete(@fullname) + end + + def self.export(*patterns) + tk_call('namespace', 'export', *patterns) + end + def self.export_with_clear(*patterns) + tk_call('namespace', 'export', '-clear', *patterns) + end + def export + TkNamespace.export(@fullname) + end + def export_with_clear + TkNamespace.export_with_clear(@fullname) + end + + def self.forget(*patterns) + tk_call('namespace', 'forget', *patterns) + end + def forget + TkNamespace.forget(@fullname) + end + + def self.import(*patterns) + tk_call('namespace', 'import', *patterns) + end + def self.force_import(*patterns) + tk_call('namespace', 'import', '-force', *patterns) + end + def import + TkNamespace.import(@fullname) + end + def force_import + TkNamespace.force_import(@fullname) + end + + def self.inscope(namespace, script, *args) + tk_call('namespace', 'inscope', namespace, script, *args) + end + def inscope(script, *args) + TkNamespace(@fullname, script, *args) + end + + def self.origin(cmd) + tk_call('namespace', 'origin', cmd) + end + + def self.parent(namespace=None) + ns = tk_call('namespace', 'parent', namespace) + if Tk_Namesapce_ID.key?(ns) + Tk_Namesapce_ID[ns] + else + ns + end + end + def parent + tk_call('namespace', 'parent', @fullname) + end + + def self.qualifiers(str) + tk_call('namespace', 'qualifiers', str) + end + + def self.tail(str) + tk_call('namespace', 'tail', str) + end + + def self.which(name) + tk_call('namespace', 'which', name) + end + def self.which_command(name) + tk_call('namespace', 'which', '-command', name) + end + def self.which_variable(name) + tk_call('namespace', 'which', '-variable', name) + end +end diff --git a/ext/tk/lib/tk/optiondb.rb b/ext/tk/lib/tk/optiondb.rb new file mode 100644 index 0000000000..588c946440 --- /dev/null +++ b/ext/tk/lib/tk/optiondb.rb @@ -0,0 +1,297 @@ +# +# tk/optiondb.rb : treat option database +# +require 'tk' + +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_without_enc('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 /^\s*(!|#)/ # coment + cline = '' + next + when /^([^:]+):(.*)$/ + pat = $1.strip + val = $2.lstrip + 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 + read_entries(file, f_enc).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 /^\s*!/ # 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 + +=begin + 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 + private :__closed_block_check__ +=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, proc_str = self::METHOD_TBL[id] + + proc_source = TkOptionDB.get(self::CARRIER, id.id2name, '').strip + res_proc = nil if proc_str != proc_source # resource is changed + + 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 = proc_source + 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 = proc{ + begin + eval("$SAFE = #{self::SAFE_MODE};\nProc.new" + proc_str) + rescue SyntaxError=>err + raise SyntaxError, + TkCore::INTERP._toUTF8(err.message.gsub(/\(eval\):\d:/, + "(#{id.id2name}):")) + end + }.call + self::METHOD_TBL[id] = [res_proc, proc_source] + end + res_proc.call(*args) + end + + private :__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_without_enc('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 diff --git a/ext/tk/lib/tk/pack.rb b/ext/tk/lib/tk/pack.rb new file mode 100644 index 0000000000..79f4d19d82 --- /dev/null +++ b/ext/tk/lib/tk/pack.rb @@ -0,0 +1,89 @@ +# +# tk/pack.rb : control pack geometry manager +# +require 'tk' + +module TkPack + include Tk + extend Tk + + TkCommandNames = ['pack'.freeze].freeze + + def configure(win, *args) + if args[-1].kind_of?(Hash) + opts = args.pop + else + opts = {} + end + params = [] + # params.push((win.kind_of?(TkObject))? win.epath: win) + params.push(_epath(win)) + args.each{|win| + # params.push((win.kind_of?(TkObject))? win.epath: win) + params.push(_epath(win)) + } + opts.each{|k, v| + params.push("-#{k}") + # params.push((v.kind_of?(TkObject))? v.epath: v) + params.push(_epath(v)) + } + tk_call_without_enc("pack", 'configure', *params) + end + + def forget(*args) + return '' if args.size == 0 + wins = args.collect{|win| + # (win.kind_of?(TkObject))? win.epath: win + _epath(win) + } + tk_call_without_enc('pack', 'forget', *wins) + end + + def info(slave) + # slave = slave.epath if slave.kind_of?(TkObject) + slave = _epath(slave) + ilist = list(tk_call_without_enc('pack', 'info', slave)) + info = {} + while key = ilist.shift + info[key[1..-1]] = ilist.shift + end + return info + end + + def propagate(master, bool=None) + # master = master.epath if master.kind_of?(TkObject) + master = _epath(master) + if bool == None + bool(tk_call_without_enc('pack', 'propagate', master)) + else + tk_call_without_enc('pack', 'propagate', master, bool) + end + end + + def slaves(master) + # master = master.epath if master.kind_of?(TkObject) + master = _epath(master) + list(tk_call_without_enc('pack', 'slaves', master)) + end + + module_function :configure, :forget, :info, :propagate, :slaves +end +=begin +def TkPack(win, *args) + if args[-1].kind_of?(Hash) + opts = args.pop + else + opts = {} + end + params = [] + params.push((win.kind_of?(TkObject))? win.epath: win) + args.each{|win| + params.push((win.kind_of?(TkObject))? win.epath: win) + } + opts.each{|k, v| + params.push("-#{k}") + params.push((v.kind_of?(TkObject))? v.epath: v) + } + tk_call_without_enc("pack", *params) +end +=end diff --git a/ext/tk/lib/tk/package.rb b/ext/tk/lib/tk/package.rb new file mode 100644 index 0000000000..8768bf1c79 --- /dev/null +++ b/ext/tk/lib/tk/package.rb @@ -0,0 +1,61 @@ +# +# tk/package.rb : package command +# +require 'tk' + +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 + + def versions(package) + tk_split_simplelist(tk_call('package', 'versions', package)) + end + + def vcompare(version1, version2) + number(tk_call('package', 'vcompare', version1, version2)) + end + + def vsatisfies(version1, version2) + bool(tk_call('package', 'vsatisfies', version1, version2)) + end +end diff --git a/ext/tk/lib/tk/palette.rb b/ext/tk/lib/tk/palette.rb new file mode 100644 index 0000000000..abcafcfb3a --- /dev/null +++ b/ext/tk/lib/tk/palette.rb @@ -0,0 +1,54 @@ +# +# tk/palette.rb : methods for Tcl/Tk standard library 'palette.tcl' +# 1998/06/21 by Hidetoshi Nagai <nagai@ai.kyutech.ac.jp> +# +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 diff --git a/ext/tk/lib/tk/panedwindow.rb b/ext/tk/lib/tk/panedwindow.rb new file mode 100644 index 0000000000..1cfc7bad7a --- /dev/null +++ b/ext/tk/lib/tk/panedwindow.rb @@ -0,0 +1,204 @@ +# +# tk/panedwindow.rb : treat panedwindow +# +require 'tk' + +class TkPanedWindow<TkWindow + TkCommandNames = ['panedwindow'.freeze].freeze + WidgetClassName = 'Panedwindow'.freeze + WidgetClassNames[WidgetClassName] = self + def create_self(keys) + if keys and keys != None + tk_call_without_enc('panedwindow', @path, *hash_kv(keys, true)) + else + tk_call_without_enc('panedwindow', @path) + end + end + private :create_self + + def add(*args) + keys = args.pop + fail ArgumentError, "no window in arguments" unless keys + if keys && keys.kind_of?(Hash) + fail ArgumentError, "no window in arguments" if args == [] + # args = args.collect{|w| (w.kind_of?(TkObject))? w.epath: w } + args = args.collect{|w| _epath(w) } + #args.push(hash_kv(keys)) + args.concat(hash_kv(keys)) + else + args.push(keys) if keys + # args = args.collect{|w| (w.kind_of?(TkObject))? w.epath: w } + args = args.collect{|w| _epath(w) } + end + tk_send_without_enc('add', *args) + self + end + + def forget(win, *wins) + wins.unshift(win) + # tk_send_without_enc('forget', *((w.kind_of?(TkObject))? w.epath: w)) + tk_send_without_enc('forget', *(wins.collect{|w| _epath(w)})) + self + end + alias del forget + alias delete forget + alias remove forget + + def identify(x, y) + list(tk_send_without_enc('identify', x, y)) + end + + def proxy_coord + list(tk_send_without_enc('proxy', 'coord')) + end + def proxy_forget + tk_send_without_enc('proxy', 'forget') + self + end + def proxy_place(x, y) + tk_send_without_enc('proxy', 'place', x, y) + self + end + + def sash_coord(index) + list(tk_send('sash', 'coord', index)) + end + def sash_dragto(index) + tk_send('sash', 'dragto', index, x, y) + self + end + def sash_mark(index, x, y) + tk_send('sash', 'mark', index, x, y) + self + end + def sash_place(index, x, y) + tk_send('sash', 'place', index, x, y) + self + end + + def panecget(win, key) + # win = win.epath if win.kind_of?(TkObject) + win = _epath(win) + tk_tcl2ruby(tk_send_without_enc('panecget', win, "-#{key}")) + end + + def paneconfigure(win, key, value=nil) + # win = win.epath if win.kind_of?(TkObject) + win = _epath(win) + if key.kind_of? Hash + params = [] + key.each{|k, v| + params.push("-#{k}") + # params.push((v.kind_of?(TkObject))? v.epath: v) + params.push(_epath(v)) + } + tk_send_without_enc('paneconfigure', win, *params) + else + # value = value.epath if value.kind_of?(TkObject) + value = _epath(value) + tk_send_without_enc('paneconfigure', win, "-#{key}", value) + end + self + end + alias pane_config paneconfigure + + def paneconfiginfo(win, key=nil) + if TkComm::GET_CONFIGINFO_AS_ARRAY + # win = win.epath if win.kind_of?(TkObject) + win = _epath(win) + if key + conf = tk_split_list(tk_send_without_enc('paneconfigure', + win, "-#{key}")) + conf[0] = conf[0][1..-1] + conf + else + tk_split_simplelist(tk_send_without_enc('paneconfigure', + win)).collect{|conflist| + conf = tk_split_simplelist(conflist) + conf[0] = conf[0][1..-1] + 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 + conf[1] = conf[1][1..-1] if conf.size == 2 # alias info + conf + } + end + else # ! TkComm::GET_CONFIGINFO_AS_ARRAY + # win = win.epath if win.kind_of?(TkObject) + win = _epath(win) + if key + conf = tk_split_list(tk_send_without_enc('paneconfigure', + win, "-#{key}")) + key = conf.shift[1..-1] + { key => conf } + else + ret = {} + tk_split_simplelist(tk_send_without_enc('paneconfigure', + win)).each{|conflist| + conf = tk_split_simplelist(conflist) + key = conf.shift[1..-1] + if key + 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 + if conf.size == 1 + ret[key] = conf[0][1..-1] # alias info + else + ret[key] = conf + end + } + ret + end + end + end + alias pane_configinfo paneconfiginfo + + def current_paneconfiginfo(win, key=nil) + if TkComm::GET_CONFIGINFO_AS_ARRAY + if key + conf = paneconfiginfo(win, key) + {conf[0] => conf[4]} + else + ret = {} + paneconfiginfo(win).each{|conf| + ret[conf[0]] = conf[4] if conf.size > 2 + } + ret + end + else # ! TkComm::GET_CONFIGINFO_AS_ARRAY + ret = {} + paneconfiginfo(win, key).each{|k, conf| + ret[k] = conf[-1] if conf.kind_of?(Array) + } + ret + end + end + + alias current_pane_configinfo current_paneconfiginfo + + def panes + list(tk_send_without_enc('panes')) + end +end +TkPanedwindow = TkPanedWindow diff --git a/ext/tk/lib/tk/place.rb b/ext/tk/lib/tk/place.rb new file mode 100644 index 0000000000..5c2f890e07 --- /dev/null +++ b/ext/tk/lib/tk/place.rb @@ -0,0 +1,110 @@ +# +# tk/place.rb : control place geometry manager +# +require 'tk' + +module TkPlace + include Tk + extend Tk + + TkCommandNames = ['place'.freeze].freeze + + def configure(win, slot, value=None) + # for >= Tk8.4a2 ? + # win = win.epath if win.kind_of?(TkObject) + win = _epath(win) + if slot.kind_of? Hash + params = [] + slot.each{|k, v| + params.push("-#{k}") + # params.push((v.kind_of?(TkObject))? v.epath: v) + params.push(_epath(v)) + } + tk_call_without_enc('place', 'configure', win, *params) + else + # value = value.epath if value.kind_of?(TkObject) + value = _epath(value) + tk_call_without_enc('place', 'configure', win, "-#{slot}", value) + end + end + + def configinfo(win, slot = nil) + # for >= Tk8.4a2 ? + if TkComm::GET_CONFIGINFOwoRES_AS_ARRAY + # win = win.epath if win.kind_of?(TkObject) + win = _epath(win) + if slot + conf = tk_split_list(tk_call_without_enc('place', 'configure', + win, "-#{slot}") ) + conf[0] = conf[0][1..-1] + conf + else + tk_split_simplelist(tk_call_without_enc('place', 'configure', + win)).collect{|conflist| + conf = list(conflist) + conf[0] = conf[0][1..-1] + conf + } + end + else # ! TkComm::GET_CONFIGINFOwoRES_AS_ARRAY + current_configinfo(win, slot) + end + end + + def current_configinfo(win, slot = nil) + # win = win.epath if win.kind_of?(TkObject) + win = _epath(win) + if slot + conf = tk_split_list(tk_call_without_enc('place', 'configure', + win, "-#{slot}") ) + { conf[0][1..-1] => conf[1] } + else + ret = {} + tk_split_list(tk_call_without_enc('place','configure',win)).each{|conf| + ret[conf[0][1..-1]] = conf[1] + } + ret + end + end + + def forget(win) + # win = win.epath if win.kind_of?(TkObject) + win = _epath(win) + tk_call_without_enc('place', 'forget', win) + end + + def info(win) + # win = win.epath if win.kind_of?(TkObject) + win = _epath(win) + ilist = list(tk_call_without_enc('place', 'info', win)) + info = {} + while key = ilist.shift + info[key[1..-1]] = ilist.shift + end + return info + end + + def slaves(master) + # master = master.epath if master.kind_of?(TkObject) + master = _epath(master) + list(tk_call('place', 'slaves', master)) + end + + module_function :configure, :configinfo, :forget, :info, :slaves +end +=begin +def TkPlace(win, slot, value=None) + win = win.epath if win.kind_of?(TkObject) + if slot.kind_of? Hash + params = [] + slot.each{|k, v| + params.push("-#{k}") + params.push((v.kind_of?(TkObject))? v.epath: v) + } + tk_call_without_enc('place', win, *params) + else + value = value.epath if value.kind_of?(TkObject) + tk_call_without_enc('place', win, "-#{slot}", value) + end +end +=end diff --git a/ext/tk/lib/tk/radiobutton.rb b/ext/tk/lib/tk/radiobutton.rb new file mode 100644 index 0000000000..e00f0a03eb --- /dev/null +++ b/ext/tk/lib/tk/radiobutton.rb @@ -0,0 +1,32 @@ +# +# tk/radiobutton.rb : treat radiobutton widget +# +require 'tk' +require 'tk/button' + +class TkRadioButton<TkButton + TkCommandNames = ['radiobutton'.freeze].freeze + WidgetClassName = 'Radiobutton'.freeze + WidgetClassNames[WidgetClassName] = self + def create_self(keys) + if keys and keys != None + tk_call_without_enc('radiobutton', @path, *hash_kv(keys, true)) + else + tk_call_without_enc('radiobutton', @path) + end + end + private :create_self + + def deselect + tk_send_without_enc('deselect') + self + end + def select + tk_send_without_enc('select') + self + end + def variable(v) + configure 'variable', tk_trace_variable(v) + end +end +TkRadiobutton = TkRadioButton diff --git a/ext/tk/lib/tk/root.rb b/ext/tk/lib/tk/root.rb new file mode 100644 index 0000000000..487eb78fef --- /dev/null +++ b/ext/tk/lib/tk/root.rb @@ -0,0 +1,65 @@ +# +# tk/root.rb : treat root widget +# +require 'tk' +require 'tk/wm' + +class TkRoot<TkWindow + include Wm + +=begin + ROOT = [] + def TkRoot.new(keys=nil) + if ROOT[0] + Tk_WINDOWS["."] = ROOT[0] + return ROOT[0] + end + new = super(:without_creating=>true, :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 diff --git a/ext/tk/lib/tk/scale.rb b/ext/tk/lib/tk/scale.rb new file mode 100644 index 0000000000..9398a6cd52 --- /dev/null +++ b/ext/tk/lib/tk/scale.rb @@ -0,0 +1,78 @@ +# +# tk/scale.rb : treat scale widget +# +require 'tk' + +class TkScale<TkWindow + TkCommandNames = ['scale'.freeze].freeze + WidgetClassName = 'Scale'.freeze + WidgetClassNames[WidgetClassName] = self + + def create_self(keys) + if keys and keys != None + if keys.key?('command') + cmd = keys.delete('command') + keys['command'] = proc{|val| cmd.call(val.to_f)} + end + tk_call_without_enc('scale', @path, *hash_kv(keys, true)) + else + tk_call_without_enc('scale', @path) + end + end + private :create_self + + def _wrap_command_arg(cmd) + proc{|val| + if val.kind_of?(String) + cmd.call(number(val)) + else + cmd.call(val) + end + } + end + private :_wrap_command_arg + + def configure_cmd(slot, value) + configure(slot=>value) + 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_without_enc('get', x, y)) + end + + def coords(val=None) + tk_split_list(tk_send_without_enc('coords', val)) + end + + def identify(x, y) + tk_send_without_enc('identify', x, y) + end + + def set(val) + tk_send_without_enc('set', val) + end + + def value + get + end + + def value= (val) + set(val) + val + end +end diff --git a/ext/tk/lib/tk/scrollable.rb b/ext/tk/lib/tk/scrollable.rb new file mode 100644 index 0000000000..e591a299ab --- /dev/null +++ b/ext/tk/lib/tk/scrollable.rb @@ -0,0 +1,49 @@ +# +# tk/scrollable.rb : module for scrollable widget +# +require 'tk' + +module Tk + 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) + if index.size == 0 + list(tk_send_without_enc('xview')) + else + tk_send_without_enc('xview', *index) + self + end + end + def yview(*index) + if index.size == 0 + list(tk_send_without_enc('yview')) + else + tk_send_without_enc('yview', *index) + self + end + 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 + end +end diff --git a/ext/tk/lib/tk/scrollbar.rb b/ext/tk/lib/tk/scrollbar.rb new file mode 100644 index 0000000000..0ee4423c9a --- /dev/null +++ b/ext/tk/lib/tk/scrollbar.rb @@ -0,0 +1,105 @@ +# +# tk/scrollbar.rb : treat scrollbar widget +# +require 'tk' + +class TkScrollbar<TkWindow + TkCommandNames = ['scrollbar'.freeze].freeze + WidgetClassName = 'Scrollbar'.freeze + WidgetClassNames[WidgetClassName] = self + + def create_self(keys) + @assigned = [] + @scroll_proc = proc{|*args| + if self.orient == 'horizontal' + @assigned.each{|w| w.xview(*args)} + else # 'vertical' + @assigned.each{|w| w.yview(*args)} + end + } + + if keys and keys != None + tk_call_without_enc('scrollbar', @path, *hash_kv(keys, true)) + else + tk_call_without_enc('scrollbar', @path) + end + end + private :create_self + + def assign(*wins) + begin + self.command(@scroll_proc) if self.cget('command').cmd != @scroll_proc + rescue Exception + self.command(@scroll_proc) + end + orient = self.orient + wins.each{|w| + @assigned << w unless @assigned.index(w) + if orient == 'horizontal' + w.xscrollcommand proc{|first, last| self.set(first, last)} + else # 'vertical' + w.yscrollcommand proc{|first, last| self.set(first, last)} + end + } + self + end + + def assigned_list + begin + return @assigned.dup if self.cget('command').cmd == @scroll_proc + rescue Exception + end + fail RuntimeError, "not depend on the assigned_list" + end + + #def delta(deltax=None, deltay=None) + def delta(deltax, deltay) + number(tk_send_without_enc('delta', deltax, deltay)) + end + + #def fraction(x=None, y=None) + def fraction(x, y) + number(tk_send_without_enc('fraction', x, y)) + end + + def identify(x, y) + tk_send_without_enc('identify', x, y) + end + + def get + #ary1 = tk_send('get').split + #ary2 = [] + #for i in ary1 + # ary2.push number(i) + #end + #ary2 + list(tk_send_without_enc('get')) + end + + def set(first, last) + tk_send_without_enc('set', first, last) + self + end + + def activate(element=None) + tk_send_without_enc('activate', element) + end +end + +class TkXScrollbar<TkScrollbar + def create_self(keys) + keys = {} unless keys + keys['orient'] = 'horizontal' + super(keys) + end + private :create_self +end + +class TkYScrollbar<TkScrollbar + def create_self(keys) + keys = {} unless keys + keys['orient'] = 'vertical' + super(keys) + end + private :create_self +end diff --git a/ext/tk/lib/tk/scrollbox.rb b/ext/tk/lib/tk/scrollbox.rb new file mode 100644 index 0000000000..f0fdece260 --- /dev/null +++ b/ext/tk/lib/tk/scrollbox.rb @@ -0,0 +1,31 @@ +# +# tk/scrollbox.rb - Tk Listbox with Scrollbar +# as an example of Composite Widget +# $Date$ +# by Yukihiro Matsumoto <matz@netlab.co.jp> +# +require 'tk' +require 'tk/listbox' + +class TkScrollbox<TkListbox + include TkComposite + def initialize_composite(keys=nil) + list = TkListbox.new(@frame) + scroll = TkScrollbar.new(@frame) + @path = list.path + + list.configure 'yscroll', scroll.path+" set" + list.pack 'side'=>'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 diff --git a/ext/tk/lib/tk/selection.rb b/ext/tk/lib/tk/selection.rb new file mode 100644 index 0000000000..970c3faa80 --- /dev/null +++ b/ext/tk/lib/tk/selection.rb @@ -0,0 +1,86 @@ +# +# tk/selection.rb : control selection +# +require 'tk' + +module TkSelection + include Tk + extend Tk + + TkCommandNames = ['selection'.freeze].freeze + + def self.clear(sel=nil) + if sel + tk_call_without_enc('selection', 'clear', '-selection', sel) + else + tk_call_without_enc('selection', 'clear') + end + end + def self.clear_on_display(win, sel=nil) + if sel + tk_call_without_enc('selection', 'clear', + '-displayof', win, '-selection', sel) + else + tk_call_without_enc('selection', 'clear', '-displayof', win) + end + end + def clear(sel=nil) + TkSelection.clear_on_display(self, sel) + self + end + + def self.get(keys=nil) + #tk_call('selection', 'get', *hash_kv(keys)) + _fromUTF8(tk_call_without_enc('selection', 'get', *hash_kv(keys))) + end + def self.get_on_display(win, keys=nil) + #tk_call('selection', 'get', '-displayof', win, *hash_kv(keys)) + _fromUTF8(tk_call_without_enc('selection', 'get', '-displayof', + win, *hash_kv(keys))) + end + def get(keys=nil) + TkSelection.get_on_display(self, sel) + end + + def self.handle(win, func=Proc.new, keys=nil, &b) + if func.kind_of?(Hash) && keys == nil + keys = func + func = Proc.new(&b) + end + args = ['selection', 'handle'] + args.concat(hash_kv(keys)) + args.concat([win, func]) + tk_call_without_enc(*args) + end + def handle(func=Proc.new, keys=nil, &b) + TkSelection.handle(self, func, keys, &b) + end + + def self.get_owner(sel=nil) + if sel + window(tk_call_without_enc('selection', 'own', '-selection', sel)) + else + window(tk_call_without_enc('selection', 'own')) + end + end + def self.get_owner_on_display(win, sel=nil) + if sel + window(tk_call_without_enc('selection', 'own', + '-displayof', win, '-selection', sel)) + else + window(tk_call_without_enc('selection', 'own', '-displayof', win)) + end + end + def get_owner(sel=nil) + TkSelection.get_owner_on_display(self, sel) + self + end + + def self.set_owner(win, keys=nil) + tk_call_without_enc('selection', 'own', *(hash_kv(keys) << win)) + end + def set_owner(keys=nil) + TkSelection.set_owner(self, keys) + self + end +end diff --git a/ext/tk/lib/tk/spinbox.rb b/ext/tk/lib/tk/spinbox.rb new file mode 100644 index 0000000000..1c58f9199b --- /dev/null +++ b/ext/tk/lib/tk/spinbox.rb @@ -0,0 +1,39 @@ +# +# tk/spinbox.rb - Tk spinbox classes +# $Date$ +# by Yukihiro Matsumoto <matz@caelum.co.jp> +# +require 'tk' +require 'tk/entry' + +class TkSpinbox<TkEntry + TkCommandNames = ['spinbox'.freeze].freeze + WidgetClassName = 'Spinbox'.freeze + WidgetClassNames[WidgetClassName] = self + + def create_self(keys) + tk_call_without_enc('spinbox', @path) + if keys and keys != None + configure(keys) + end + end + private :create_self + + def identify(x, y) + tk_send_without_enc('identify', x, y) + end + + def spinup + tk_send_without_enc('invoke', 'spinup') + self + end + + def spindown + tk_send_without_enc('invoke', 'spindown') + self + end + + def set(str) + _freomUTF8(tk_send_without_enc('set', _get_eval_enc_str(str))) + end +end diff --git a/ext/tk/lib/tk/tagfont.rb b/ext/tk/lib/tk/tagfont.rb new file mode 100644 index 0000000000..a106f814be --- /dev/null +++ b/ext/tk/lib/tk/tagfont.rb @@ -0,0 +1,43 @@ +# +# tk/tagfont.rb : control font of tags +# +require 'tk' + +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 diff --git a/ext/tk/lib/tk/text.rb b/ext/tk/lib/tk/text.rb new file mode 100644 index 0000000000..b1e671e1e0 --- /dev/null +++ b/ext/tk/lib/tk/text.rb @@ -0,0 +1,1179 @@ +# +# tk/text.rb - Tk text classes +# $Date$ +# by Yukihiro Matsumoto <matz@caelum.co.jp> +require 'tk' +require 'tk/itemfont' +require 'tk/scrollable' +require 'tk/txtwin_abst' + +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<TkTextWin + ItemConfCMD = ['tag'.freeze, 'configure'.freeze].freeze + include TkTreatTextTagFont + include Scrollable + + TkCommandNames = ['text'.freeze].freeze + WidgetClassName = 'Text'.freeze + WidgetClassNames[WidgetClassName] = self + + def self.new(*args, &block) + obj = super(*args){} + obj.init_instance_variable + obj.instance_eval(&block) if defined? yield + obj + end + + def init_instance_variable + @cmdtbl = [] + @tags = {} + end + + def __destroy_hook__ + TTagID_TBL.delete(@path) + TMarkID_TBL.delete(@path) + end + + def create_self(keys) + if keys and keys != None + tk_call_without_enc('text', @path, *hash_kv(keys, true)) + else + tk_call_without_enc('text', @path) + end + init_instance_variable + end + private :create_self + + def index(index) + tk_send_without_enc('index', _get_eval_enc_str(index)) + end + + def value + _fromUTF8(tk_send_without_enc('get', "1.0", "end - 1 char")) + end + + def value= (val) + tk_send_without_enc('delete', "1.0", 'end') + tk_send_without_enc('insert', "1.0", _get_eval_enc_str(val)) + val + end + + def _addcmd(cmd) + @cmdtbl.push cmd + end + + def _addtag(name, obj) + @tags[name] = obj + end + + def tagid2obj(tagid) + if @tags[tagid] + @tags[tagid] + else + tagid + end + end + + def tag_names(index=None) + tk_split_simplelist(_fromUTF8(tk_send_without_enc('tag', 'names', _get_eval_enc_str(index)))).collect{|elt| + tagid2obj(elt) + } + end + + def mark_names + tk_split_simplelist(_fromUTF8(tk_send_without_enc('mark', 'names'))).collect{|elt| + tagid2obj(elt) + } + end + + def mark_gravity(mark, direction=nil) + if direction + tk_send_without_enc('mark', 'gravity', + _get_eval_enc_str(mark), direction) + self + else + tk_send_without_enc('mark', 'gravity', _get_eval_enc_str(mark)) + end + end + + def mark_set(mark, index) + tk_send_without_enc('mark', 'set', _get_eval_enc_str(mark), + _get_eval_enc_str(index)) + self + end + alias set_mark mark_set + + def mark_unset(*marks) + tk_send_without_enc('mark', 'unset', + *(marks.collect{|mark| _get_eval_enc_str(mark)})) + self + end + alias unset_mark mark_unset + + def mark_next(index) + tagid2obj(_fromUTF8(tk_send_without_enc('mark', 'next', + _get_eval_enc_str(index)))) + end + alias next_mark mark_next + + def mark_previous(index) + tagid2obj(_fromUTF8(tk_send_without_enc('mark', 'previous', + _get_eval_enc_str(index)))) + end + alias previous_mark mark_previous + + def image_cget(index, slot) + case slot.to_s + when 'text', 'label', 'show', 'data', 'file' + _fromUTF8(tk_send_without_enc('image', 'cget', + _get_eval_enc_str(index), "-#{slot}")) + else + tk_tcl2ruby(_fromUTF8(tk_send_without_enc('image', 'cget', + _get_eval_enc_str(index), + "-#{slot}"))) + end + end + + def image_configure(index, slot, value=None) + if slot.kind_of? Hash + _fromUTF8(tk_send_without_enc('image', 'configure', + _get_eval_enc_str(index), + *hash_kv(slot, true))) + else + _fromUTF8(tk_send_without_enc('image', 'configure', + _get_eval_enc_str(index), + "-#{slot}", + _get_eval_enc_str(value))) + end + self + end + + def image_configinfo(index, slot = nil) + if TkComm::GET_CONFIGINFO_AS_ARRAY + if slot + case slot.to_s + when 'text', 'label', 'show', 'data', 'file' + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"))) + else + conf = tk_split_list(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"))) + end + conf[0] = conf[0][1..-1] + conf + else + tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index)))).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[1] = conf[1][1..-1] if conf.size == 2 # alias info + conf + } + end + else # ! TkComm::GET_CONFIGINFO_AS_ARRAY + if slot + case slot.to_s + when 'text', 'label', 'show', 'data', 'file' + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"))) + else + conf = tk_split_list(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index), "-#{slot}"))) + end + key = conf.shift[1..-1] + { key => conf } + else + ret = {} + tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'configure', _get_eval_enc_str(index)))).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 + ret[key] = conf + end + } + ret + end + end + end + + def current_image_configinfo(index, slot = nil) + if TkComm::GET_CONFIGINFO_AS_ARRAY + if slot + conf = image_configinfo(index, slot) + {conf[0] => conf[4]} + else + ret = {} + image_configinfo(index).each{|conf| + ret[conf[0]] = conf[4] if conf.size > 2 + } + ret + end + else # ! TkComm::GET_CONFIGINFO_AS_ARRAY + ret = {} + image_configinfo(index, slot).each{|k, conf| + ret[k] = conf[-1] if conf.kind_of?(Array) + } + ret + end + end + + def image_names + tk_split_simplelist(_fromUTF8(tk_send_without_enc('image', 'names'))).collect{|elt| + tagid2obj(elt) + } + end + + def set_insert(index) + tk_send_without_enc('mark','set','insert', _get_eval_enc_str(index)) + self + end + + def set_current(index) + tk_send_without_enc('mark','set','current', _get_eval_enc_str(index)) + self + end + + def insert(index, chars, *tags) + if tags[0].kind_of? Array + # multiple chars-taglist argument :: str, [tag,...], str, [tag,...], ... + args = [chars] + while tags.size > 0 + args << 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 :: str, tag, tag, ... + if tags.size == 0 + super index, chars + else + super index, chars, tags.collect{|x|_get_eval_string(x)}.join(' ') + end + end + end + + def destroy + @tags = {} unless @tags + @tags.each_value do |t| + t.destroy + end + super + end + + def backspace + self.delete 'insert' + end + + def bbox(index) + list(tk_send_without_enc('bbox', _get_eval_enc_str(index))) + end + + def compare(idx1, op, idx2) + bool(tk_send_without_enc('compare', _get_eval_enc_str(idx1), + op, _get_eval_enc_str(idx2))) + end + + def count(idx1, idx2, *opts) + opts = opts.collect{|opt| '-' + opt.to_s} + number(tk_send_without_enc('count', _get_eval_enc_str(idx1), + _get_eval_enc_str(idx2), *opts)) + end + + def replace(idx1, idx2, *opts) + tk_send('replace', idx1, idx2, *opts) + self + end + + def debug + bool(tk_send_without_enc('debug')) + end + def debug=(boolean) + tk_send_without_enc('debug', boolean) + #self + boolean + end + + def dlineinfo(index) + list(tk_send_without_enc('dlineinfo', _get_eval_enc_str(index))) + end + + def modified? + bool(tk_send_without_enc('edit', 'modified')) + end + def modified(mode) + tk_send_without_enc('edit', 'modified', mode) + self + end + def modified=(mode) + modified(mode) + mode + end + + def edit_redo + tk_send_without_enc('edit', 'redo') + self + end + def edit_reset + tk_send_without_enc('edit', 'reset') + self + end + def edit_separator + tk_send_without_enc('edit', 'separator') + self + end + def edit_undo + tk_send_without_enc('edit', 'undo') + self + end + + def xview_pickplace(index) + tk_send_without_enc('xview', '-pickplace', _get_eval_enc_str(index)) + self + end + + def yview_pickplace(index) + tk_send_without_enc('yview', '-pickplace', _get_eval_enc_str(index)) + self + end + + def text_copy + # Tk8.4 feature + tk_call_without_enc('tk_textCopy', @path) + self + end + + def text_cut + # Tk8.4 feature + tk_call_without_enc('tk_textCut', @path) + self + end + + def text_paste + # Tk8.4 feature + tk_call_without_enc('tk_textPaste', @path) + self + end + + def tag_add(tag, index1, index2=None) + tk_send_without_enc('tag', 'add', _get_eval_enc_str(tag), + _get_eval_enc_str(index1), + _get_eval_enc_str(index2)) + self + end + alias addtag tag_add + alias add_tag tag_add + + def tag_delete(*tags) + tk_send_without_enc('tag', 'delete', + *(tags.collect{|tag| _get_eval_enc_str(tag)})) + 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_without_enc(@path, 'tag', 'cget', + _get_eval_enc_str(tag), "-#{key}") + when 'font', 'kanjifont' + #fnt = tk_tcl2ruby(tk_send('tag', 'cget', tag, "-#{key}")) + fnt = tk_tcl2ruby(_fromUTF8(tk_send_without_enc('tag','cget',_get_eval_enc_str(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(_fromUTF8(tk_call_without_enc(@path,'tag','cget',_get_eval_enc_str(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_without_enc('tag', 'configure', _get_eval_enc_str(tag), + *hash_kv(key, true)) + 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_without_enc('tag', 'configure', _get_eval_enc_str(tag), + "-#{key}", _get_eval_enc_str(val)) + end + end + self + end + + def tag_configinfo(tag, key=nil) + if TkComm::GET_CONFIGINFO_AS_ARRAY + if key + case key.to_s + when 'text', 'label', 'show', 'data', 'file' + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('tag','configure',_get_eval_enc_str(tag),"-#{key}"))) + when 'font', 'kanjifont' + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('tag','configure',_get_eval_enc_str(tag),"-#{key}"))) + conf[4] = tagfont_configinfo(tag, conf[4]) + else + conf = tk_split_list(_fromUTF8(tk_send_without_enc('tag','configure',_get_eval_enc_str(tag),"-#{key}"))) + end + conf[0] = conf[0][1..-1] + conf + else + ret = tk_split_simplelist(_fromUTF8(tk_send('tag','configure',_get_eval_enc_str(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[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] = tagfont_configinfo(tag, fontconf[4]) + ret.push(fontconf) + else + ret + end + end + else # ! TkComm::GET_CONFIGINFO_AS_ARRAY + if key + case key.to_s + when 'text', 'label', 'show', 'data', 'file' + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('tag','configure',_get_eval_enc_str(tag),"-#{key}"))) + when 'font', 'kanjifont' + conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('tag','configure',_get_eval_enc_str(tag),"-#{key}"))) + conf[4] = tagfont_configinfo(tag, conf[4]) + else + conf = tk_split_list(_fromUTF8(tk_send_without_enc('tag','configure',_get_eval_enc_str(tag),"-#{key}"))) + end + key = conf.shift[1..-1] + { key => conf } + else + ret = {} + tk_split_simplelist(_fromUTF8(tk_send('tag','configure',_get_eval_enc_str(tag)))).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 + ret[key] = conf + end + } + fontconf = ret['font'] + if fontconf + ret.delete('font') + ret.delete('kanjifont') + fontconf[3] = tagfont_configinfo(tag, fontconf[3]) + ret['font'] = fontconf + end + ret + end + end + end + + def current_tag_configinfo(tag, key=nil) + if TkComm::GET_CONFIGINFO_AS_ARRAY + if key + conf = tag_configinfo(tag, key) + {conf[0] => conf[4]} + else + ret = {} + tag_configinfo(tag).each{|conf| + ret[conf[0]] = conf[4] if conf.size > 2 + } + ret + end + else # ! TkComm::GET_CONFIGINFO_AS_ARRAY + ret = {} + tag_configinfo(tag, key).each{|k, conf| + ret[k] = conf[-1] if conf.kind_of?(Array) + } + ret + end + end + + def tag_raise(tag, above=None) + tk_send_without_enc('tag', 'raise', _get_eval_enc_str(tag), + _get_eval_enc_str(above)) + self + end + + def tag_lower(tag, below=None) + tk_send_without_enc('tag', 'lower', _get_eval_enc_str(tag), + _get_eval_enc_str(below)) + self + end + + def tag_remove(tag, *indices) + tk_send_without_enc('tag', 'remove', _get_eval_enc_str(tag), + *(indces.collect{|idx| _get_eval_enc_str(idx)})) + self + end + + def tag_ranges(tag) + l = tk_split_simplelist(tk_send_without_enc('tag', 'ranges', + _get_eval_enc_str(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_without_enc('tag', 'nextrange', + _get_eval_enc_str(tag), + _get_eval_enc_str(first), + _get_eval_enc_str(last))) + end + + def tag_prevrange(tag, first, last=None) + tk_split_list(tk_send_without_enc('tag', 'prevrange', + _get_eval_enc_str(tag), + _get_eval_enc_str(first), + _get_eval_enc_str(last))) + end + + def window_cget(index, slot) + case slot.to_s + when 'text', 'label', 'show', 'data', 'file' + _fromUTF8(tk_send_without_enc('window', 'cget', + _get_eval_enc_str(index), "-#{slot}")) + when 'font', 'kanjifont' + #fnt = tk_tcl2ruby(tk_send('window', 'cget', index, "-#{slot}")) + fnt = tk_tcl2ruby(_fromUTF8(tk_send_without_enc('window', 'cget', _get_eval_enc_str(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(_fromUTF8(tk_send_without_enc('window', 'cget', _get_eval_enc_str(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) + slot['window'] = _epath(win) if win + if slot['create'] + p_create = slot['create'] + if p_create.kind_of? Proc +=begin + slot['create'] = install_cmd(proc{ + id = p_create.call + if id.kind_of?(TkWindow) + id.epath + else + id + end + }) +=end + slot['create'] = install_cmd(proc{_epath(p_create.call)}) + end + end + tk_send_without_enc('window', 'configure', + _get_eval_enc_str(index), + *hash_kv(slot, true)) + else + if slot == 'window' || slot == :window + # id = value + # value = id.epath if id.kind_of?(TkWindow) + value = _epath(value) + end + if slot == 'create' || slot == :create + p_create = value + if p_create.kind_of? Proc +=begin + value = install_cmd(proc{ + id = p_create.call + if id.kind_of?(TkWindow) + id.epath + else + id + end + }) +=end + value = install_cmd(proc{_epath(p_create.call)}) + end + end + tk_send_without_enc('window', 'configure', + _get_eval_enc_str(index), + "-#{slot}", _get_eval_enc_str(value)) + end + end + self + end + + def window_configinfo(win, slot = nil) + if TkComm::GET_CONFIGINFO_AS_ARRAY + if slot + case slot.to_s + when 'text', 'label', 'show', 'data', 'file' + conf = tk_split_simplelist(_fromUTF8(tk_send('window', 'configure', _get_eval_enc_str(win), "-#{slot}"))) + else + conf = tk_split_list(_fromUTF8(tk_send('window', 'configure', _get_eval_enc_str(win), "-#{slot}"))) + end + conf[0] = conf[0][1..-1] + conf + else + tk_split_simplelist(_fromUTF8(tk_send('window', 'configure', _get_eval_enc_str(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[1] = conf[1][1..-1] if conf.size == 2 # alias info + conf + } + end + else # ! TkComm::GET_CONFIGINFO_AS_ARRAY + if slot + case slot.to_s + when 'text', 'label', 'show', 'data', 'file' + conf = tk_split_simplelist(_fromUTF8(tk_send('window', 'configure', _get_eval_enc_str(win), "-#{slot}"))) + else + conf = tk_split_list(_fromUTF8(tk_send('window', 'configure', _get_eval_enc_str(win), "-#{slot}"))) + end + key = conf.shift[1..-1] + { key => conf } + else + ret = {} + tk_split_simplelist(_fromUTF8(tk_send('window', 'configure', _get_eval_enc_str(win)))).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 + ret[key] = conf + end + } + ret + end + end + end + + def current_window_configinfo(win, slot = nil) + if TkComm::GET_CONFIGINFO_AS_ARRAY + if slot + conf = window_configinfo(win, slot) + {conf[0] => conf[4]} + else + ret = {} + window_configinfo(win).each{|conf| + ret[conf[0]] = conf[4] if conf.size > 2 + } + ret + end + else # ! TkComm::GET_CONFIGINFO_AS_ARRAY + ret = {} + window_configinfo(win, slot).each{|k, conf| + ret[k] = conf[-1] if conf.kind_of?(Array) + } + ret + end + end + + def window_names + tk_split_simplelist(_fromUTF8(tk_send_without_enc('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_without_enc('kstring', 'length', + _get_eval_enc_str(txt)).to_i + else + begin + tk_call_without_enc('encoding', 'convertto', 'ascii', + _get_eval_enc_str(txt)).length + rescue StandardError, NameError + # sorry, I have no plan + txt.length + end + end + end + private :_ktext_length + + def tksearch(*args) + # call 'search' subcommand of text widget + # args ::= [<array_of_opts>] <pattern> <start_index> [<stop_index>] + # <pattern> must be a regular expression of Tcl + all_mode = false + opts = args.shift + if opts.kind_of?(Array) + opts = opts.collect{|opt| + opt = opt.to_s + all_mode = true if opt == 'all' + opt + } + else + args.unshift(opts) + opts = [] + end + + opts << '--' + + if all_mode + tk_split_simplelist(tk_send(*(opts + args))) + else + tk_send(*(opts + args)) + end + end + + def tksearch_with_count(*args) + # call 'search' subcommand of text widget + # args ::= [<array_of_opts>] <var> <pattern> <start_index> [<stop_index>] + # <pattern> must be a regular expression of Tcl + all_mode = false + opts = args.shift + if opts.kind_of?(Array) + opts = opts.collect{|opt| + opt = opt.to_s + all_mode = true if opt == 'all' + opt + } + var = args.shift + else + var = opts + opts = [] + end + + opts << '-count' << var << '--' + + if all_mode + tk_split_simplelist(tk_send(*(opts + args))) + else + tk_send(*(opts + args)) + end + end + + 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 diff --git a/ext/tk/lib/tk/textimage.rb b/ext/tk/lib/tk/textimage.rb new file mode 100644 index 0000000000..444d91b0a5 --- /dev/null +++ b/ext/tk/lib/tk/textimage.rb @@ -0,0 +1,72 @@ +# +# tk/textimage.rb - treat Tk text image object +# +require 'tk' +require 'tk/text' + +class TkTextImage<TkObject + def initialize(parent, index, keys) + unless parent.kind_of?(TkText) + fail ArguemntError, "expect TkText for 1st argument" + end + @t = parent + if index == 'end' + @path = TkTextMark.new(@t, tk_call(@t.path, 'index', 'end - 1 chars')) + elsif index.kind_of? TkTextMark + if tk_call_without_enc(@t.path,'index',index.path) == tk_call_without_enc(@t.path,'index','end') + @path = TkTextMark.new(@t, tk_call_without_enc(@t.path, 'index', + 'end - 1 chars')) + else + @path = TkTextMark.new(@t, tk_call_without_enc(@t.path, 'index', + index.path)) + end + else + @path = TkTextMark.new(@t, tk_call_without_enc(@t.path, 'index', + _get_eval_enc_str(index))) + end + @path.gravity = 'left' + @index = @path.path + @id = tk_call_without_enc(@t.path, 'image', 'create', @index, + *hash_kv(keys, true)) + end + + def [](slot) + cget(slot) + end + def []=(slot, value) + configure(slot, value) + value + end + + def cget(slot) + @t.image_cget(@index, slot) + end + + def configure(slot, value=None) + @t.image_configure(@index, slot, value) + self + end +# def configure(slot, value) +# tk_call @t.path, 'image', 'configure', @index, "-#{slot}", value +# end + + def configinfo(slot = nil) + @t.image_configinfo(@index, slot) + end + + def current_configinfo(slot = nil) + @t.current_image_configinfo(@index, slot) + end + + def image + img = tk_call_without_enc(@t.path, 'image', 'configure', @index, '-image') + TkImage::Tk_IMGTBL[img]? TkImage::Tk_IMGTBL[img] : img + end + + def image=(value) + tk_call_without_enc(@t.path, 'image', 'configure', @index, '-image', + _get_eval_enc_str(value)) + #self + value + end +end diff --git a/ext/tk/lib/tk/textmark.rb b/ext/tk/lib/tk/textmark.rb new file mode 100644 index 0000000000..faf19b7a62 --- /dev/null +++ b/ext/tk/lib/tk/textmark.rb @@ -0,0 +1,126 @@ +# +# tk/textmark.rb - methods for treating text marks +# +require 'tk' +require 'tk/text' + +class TkTextMark<TkObject + TMarkID_TBL = TkCore::INTERP.create_table + Tk_TextMark_ID = ['mark'.freeze, '00000'.taint].freeze + + TkCore::INTERP.init_ip_env{ TMarkID_TBL.clear } + + def TkTextMark.id2obj(text, id) + tpath = text.path + return id unless TMarkID_TBL[tpath] + TMarkID_TBL[tpath][id]? TMarkID_TBL[tpath][id]: id + end + + def initialize(parent, index) + unless parent.kind_of?(TkText) + fail ArguemntError, "expect TkText for 1st argument" + end + @parent = @t = parent + @tpath = parent.path + @path = @id = Tk_TextMark_ID.join('') + TMarkID_TBL[@id] = self + TMarkID_TBL[@tpath] = {} unless TMarkID_TBL[@tpath] + TMarkID_TBL[@tpath][@id] = self + Tk_TextMark_ID[1].succ! + tk_call_without_enc(@t.path, 'mark', 'set', @id, + _get_eval_enc_str(index)) + @t._addtag id, self + end + + def id + @id + end + + def +(mod) + @id + ' + ' + mod + end + def -(mod) + @id + ' - ' + mod + end + + def set(where) + tk_call_without_enc(@t.path, 'mark', 'set', @id, + _get_eval_enc_str(where)) + self + end + + def unset + tk_call_without_enc(@t.path, 'mark', 'unset', @id) + self + end + alias destroy unset + + def gravity + tk_call_without_enc(@t.path, 'mark', 'gravity', @id) + end + + def gravity=(direction) + tk_call_without_enc(@t.path, 'mark', 'gravity', @id, direction) + #self + direction + end + + def next(index = nil) + if index + @t.tagid2obj(_fromUTF8(tk_call_without_enc(@t.path, 'mark', 'next', _get_eval_enc_str(index)))) + else + @t.tagid2obj(_fromUTF8(tk_call_without_enc(@t.path, 'mark', 'next', @id))) + end + end + + def previous(index = nil) + if index + @t.tagid2obj(_fromUTF8(tk_call_without_enc(@t.path, 'mark', 'previous', _get_eval_enc_str(index)))) + else + @t.tagid2obj(_fromUTF8(tk_call_without_enc(@t.path, 'mark', 'previous', @id))) + end + end +end + +class TkTextNamedMark<TkTextMark + def self.new(parent, name, *args) + if TMarkID_TBL[parent.path] && TMarkID_TBL[parent.path][name] + return TMarkID_TBL[parent.path][name] + else + super(parent, name, *args) + end + end + + def initialize(parent, name, index=nil) + unless parent.kind_of?(TkText) + fail ArguemntError, "expect TkText for 1st argument" + end + @parent = @t = parent + @tpath = parent.path + @path = @id = name + TMarkID_TBL[@id] = self + TMarkID_TBL[@tpath] = {} unless TMarkID_TBL[@tpath] + TMarkID_TBL[@tpath][@id] = self unless TMarkID_TBL[@tpath][@id] + tk_call_without_enc(@t.path, 'mark', 'set', @id, + _get_eval_enc_str(index)) if index + @t._addtag id, self + end +end + +class TkTextMarkInsert<TkTextNamedMark + def self.new(parent,*args) + super(parent, 'insert', *args) + end +end + +class TkTextMarkCurrent<TkTextMark + def self.new(parent,*args) + super(parent, 'current', *args) + end +end + +class TkTextMarkAnchor<TkTextMark + def self.new(parent,*args) + super(parent, 'anchor', *args) + end +end diff --git a/ext/tk/lib/tk/texttag.rb b/ext/tk/lib/tk/texttag.rb new file mode 100644 index 0000000000..c08dffd66f --- /dev/null +++ b/ext/tk/lib/tk/texttag.rb @@ -0,0 +1,239 @@ +# +# tk/texttag.rb - methods for treating text tags +# +require 'tk' +require 'tk/text' +require 'tk/tagfont' + +class TkTextTag<TkObject + include TkTreatTagFont + + TTagID_TBL = TkCore::INTERP.create_table + Tk_TextTag_ID = ['tag'.freeze, '00000'.taint].freeze + + TkCore::INTERP.init_ip_env{ TTagID_TBL.clear } + + def TkTextTag.id2obj(text, id) + tpath = text.path + return id unless TTagID_TBL[tpath] + TTagID_TBL[tpath][id]? TTagID_TBL[tpath][id]: id + end + + def initialize(parent, *args) + unless parent.kind_of?(TkText) + fail ArguemntError, "expect TkText for 1st argument" + end + @parent = @t = parent + @tpath = parent.path + @path = @id = Tk_TextTag_ID.join('') + TTagID_TBL[@id] = self + TTagID_TBL[@tpath] = {} unless TTagID_TBL[@tpath] + TTagID_TBL[@tpath][@id] = self + Tk_TextTag_ID[1].succ! + #tk_call @t.path, "tag", "configure", @id, *hash_kv(keys) + if args != [] then + keys = args.pop + if keys.kind_of? Hash then + add(*args) if args != [] + configure(keys) + else + args.push keys + add(*args) + end + end + @t._addtag id, self + end + + def id + @id + end + + def first + @id + '.first' + end + + def last + @id + '.last' + end + + def add(*indices) + tk_call_without_enc(@t.path, 'tag', 'add', @id, + *(indices.collect{|idx| _get_eval_enc_str(idx)})) + self + end + + def remove(*indices) + tk_call_without_enc(@t.path, 'tag', 'remove', @id, + *(indices.collect{|idx| _get_eval_enc_str(idx)})) + self + end + + def ranges + l = tk_split_simplelist(tk_call_without_enc(@t.path, 'tag', 'ranges', @id)) + r = [] + while key=l.shift + r.push [key, l.shift] + end + r + end + + def nextrange(first, last=None) + tk_split_list(tk_call_without_enc(@t.path, 'tag', 'nextrange', @id, + _get_eval_enc_str(first), + _get_eval_enc_str(last))) + end + + def prevrange(first, last=None) + tk_split_list(tk_call_without_enc(@t.path, 'tag', 'prevrange', @id, + _get_eval_enc_str(first), + _get_eval_enc_str(last))) + end + + def [](key) + cget key + end + + def []=(key,val) + configure key, val + val + end + + def cget(key) + case key.to_s + when 'text', 'label', 'show', 'data', 'file' + _fromUTF8(tk_call_without_enc(@t.path, 'tag', 'cget', @id, "-#{key}")) + when 'font', 'kanjifont' + #fnt = tk_tcl2ruby(tk_call(@t.path, 'tag', 'cget', @id, "-#{key}")) + fnt = tk_tcl2ruby(_fromUTF8(tk_call_without_enc(@t.path, 'tag', 'cget', + @id, '-font'))) + unless fnt.kind_of?(TkFont) + fnt = tagfontobj(@id, 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(_fromUTF8(tk_call_without_enc(@t.path, 'tag', 'cget', + @id, "-#{key}"))) + end + end + + def configure(key, val=None) + @t.tag_configure @id, key, val + end +# def configure(key, val=None) +# if key.kind_of? Hash +# tk_call @t.path, 'tag', 'configure', @id, *hash_kv(key) +# else +# tk_call @t.path, 'tag', 'configure', @id, "-#{key}", val +# end +# end +# def configure(key, value) +# if value == FALSE +# value = "0" +# elsif value.kind_of? Proc +# value = install_cmd(value) +# end +# tk_call @t.path, 'tag', 'configure', @id, "-#{key}", value +# end + + def configinfo(key=nil) + @t.tag_configinfo @id, key + end + + def current_configinfo(key=nil) + @t.current_tag_configinfo @id, key + end + + def bind(seq, cmd=Proc.new, args=nil) + _bind([@t.path, 'tag', 'bind', @id], seq, cmd, args) + self + end + + def bind_append(seq, cmd=Proc.new, args=nil) + _bind_append([@t.path, 'tag', 'bind', @id], seq, cmd, args) + self + end + + def bind_remove(seq) + _bind_remove([@t.path, 'tag', 'bind', @id], seq) + self + end + + def bindinfo(context=nil) + _bindinfo([@t.path, 'tag', 'bind', @id], context) + end + + def raise(above=None) + tk_call_without_enc(@t.path, 'tag', 'raise', @id, + _get_eval_enc_str(above)) + self + end + + def lower(below=None) + tk_call_without_enc(@t.path, 'tag', 'lower', @id, + _get_eval_enc_str(below)) + self + end + + def destroy + tk_call_without_enc(@t.path, 'tag', 'delete', @id) + TTagID_TBL[@tpath].delete(@id) if TTagID_TBL[@tpath] + self + end +end + +class TkTextNamedTag<TkTextTag + def self.new(parent, name, *args) + if TTagID_TBL[parent.path] && TTagID_TBL[parent.path][name] + tagobj = TTagID_TBL[parent.path][name] + if args != [] then + keys = args.pop + if keys.kind_of? Hash then + tagobj.add(*args) if args != [] + tagobj.configure(keys) + else + args.push keys + tagobj.add(*args) + end + end + return tagobj + else + super(parent, name, *args) + end + end + + def initialize(parent, name, *args) + unless parent.kind_of?(TkText) + fail ArguemntError, "expect TkText for 1st argument" + end + @parent = @t = parent + @tpath = parent.path + @path = @id = name + TTagID_TBL[@tpath] = {} unless TTagID_TBL[@tpath] + TTagID_TBL[@tpath][@id] = self unless TTagID_TBL[@tpath][@id] + #if mode + # tk_call @t.path, "addtag", @id, *args + #end + if args != [] then + keys = args.pop + if keys.kind_of? Hash then + add(*args) if args != [] + configure(keys) + else + args.push keys + add(*args) + end + end + @t._addtag id, self + end +end + +class TkTextTagSel<TkTextNamedTag + def self.new(parent, *args) + super(parent, 'sel', *args) + end +end diff --git a/ext/tk/lib/tk/textwindow.rb b/ext/tk/lib/tk/textwindow.rb new file mode 100644 index 0000000000..6f609ee5e7 --- /dev/null +++ b/ext/tk/lib/tk/textwindow.rb @@ -0,0 +1,137 @@ +# +# tk/textwindow.rb - treat Tk text window object +# +require 'tk' +require 'tk/text' + +class TkTextWindow<TkObject + def initialize(parent, index, keys) + unless parent.kind_of?(TkText) + fail ArguemntError, "expect TkText for 1st argument" + end + @t = parent + if index == 'end' + @path = TkTextMark.new(@t, tk_call_without_enc(@t.path, 'index', + 'end - 1 chars')) + elsif index.kind_of? TkTextMark + if tk_call_without_enc(@t.path,'index',index.path) == tk_call_without_enc(@t.path,'index','end') + @path = TkTextMark.new(@t, tk_call_without_enc(@t.path, 'index', + 'end - 1 chars')) + else + @path = TkTextMark.new(@t, tk_call_without_enc(@t.path, 'index', + index.path)) + end + else + @path = TkTextMark.new(@t, tk_call_without_enc(@t.path, 'index', _get_eval_enc_str(index))) + end + @path.gravity = 'left' + @index = @path.path + keys = _symbolkey2str(keys) + @id = keys['window'] + # keys['window'] = @id.epath if @id.kind_of?(TkWindow) + keys['window'] = _epath(@id) if @id + if keys['create'] + @p_create = keys['create'] + if @p_create.kind_of? Proc +=begin + keys['create'] = install_cmd(proc{ + @id = @p_create.call + if @id.kind_of?(TkWindow) + @id.epath + else + @id + end + }) +=end + keys['create'] = install_cmd(proc{@id = @p_create.call; _epath(@id)}) + end + end + tk_call_without_enc(@t.path, 'window', 'create', @index, + *hash_kv(keys, true)) + end + + def [](slot) + cget(slot) + end + def []=(slot, value) + configure(slot, value) + value + end + + def cget(slot) + @t.window_cget(@index, slot) + end + + def configure(slot, value=None) + if slot.kind_of? Hash + slot = _symbolkey2str(slot) + if slot['window'] + @id = slot['window'] + # slot['window'] = @id.epath if @id.kind_of?(TkWindow) + slot['window'] = _epath(@id) if @id + end + if slot['create'] + self.create=slot.delete('create') + end + if slot.size > 0 + tk_call_without_enc(@t.path, 'window', 'configure', @index, + *hash_kv(slot, true)) + end + else + if slot == 'window' || slot == :window + @id = value + # value = @id.epath if @id.kind_of?(TkWindow) + value = _epath(@id) if @id + end + if slot == 'create' || slot == :create + self.create=value + else + tk_call_without_enc(@t.path, 'window', 'configure', @index, + "-#{slot}", _get_eval_enc_str(value)) + end + end + self + end + + def configinfo(slot = nil) + @t.window_configinfo(@index, slot) + end + + def current_configinfo(slot = nil) + @t.current_window_configinfo(@index, slot) + end + + def window + @id + end + + def window=(value) + @id = value + # value = @id.epath if @id.kind_of?(TkWindow) + value = _epath(@id) if @id + tk_call_without_enc(@t.path, 'window', 'configure', @index, + '-window', _get_eval_enc_str(value)) + 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_without_enc(@t.path, 'window', 'configure', @index, + '-create', _get_eval_enc_str(value)) + value + end +end diff --git a/ext/tk/lib/tk/timer.rb b/ext/tk/lib/tk/timer.rb new file mode 100644 index 0000000000..c53e67682d --- /dev/null +++ b/ext/tk/lib/tk/timer.rb @@ -0,0 +1,441 @@ +# +# tk/timer.rb : methods for Tcl/Tk after command +# +# $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 {eval {ruby_cmd TkTimer callback} $id} ret]] != 0} { + return -code $st $ret + } { + return $ret + } + EOL + + DEFAULT_IGNORE_EXCEPTIONS = [ NameError, RuntimeError ].freeze + + ############################### + # 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(obj = nil) + if obj + if obj.kind_of?(TkTimer) + if obj.after_id + inf = tk_split_list(tk_call_without_enc('after','info',obj.after_id)) + [Tk_CBTBL[inf[0][1]], inf[1]] + else + nil + end + else + fail ArgumentError, "TkTimer object is expected" + end + else + tk_call_without_enc('after', 'info').split(' ').collect!{|id| + ret = Tk_CBTBL.find{|key,val| val.after_id == id} + (ret == nil)? id: ret[1] + } + end + end + + ############################### + # instance methods + ############################### + def do_callback + @in_callback = true + begin + @return_value = @current_proc.call(self) + rescue Exception => e + if @cancel_on_exception && + @cancel_on_exception.find{|exc| e.kind_of?(exc)} + 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_without_enc('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 = DEFAULT_IGNORE_EXCEPTIONS + # Unless @cancel_on_exception, Ruby/Tk shows an error dialog box when + # an excepsion is raised on TkTimer callback procedure. + # If @cancel_on_exception is an array of exception classes and the raised + # exception is included in the array, Ruby/Tk cancels executing TkTimer + # callback procedures silently (TkTimer#cancel is called and no dialog is + # shown). + + 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) + if mode.kind_of?(Array) + @cancel_on_exception = mode + elsif mode + @cancel_on_exception = DEFAULT_IGNORE_EXCEPTIONS + else + @cancel_on_exception = false + end + #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 ArguemntError, "expect Integer or Proc for 1st argument" + 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 ArguemntError, "expect Integer for 2nd argument" + 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 ArguemntError, "expect Integer or 'idle' for 1st argument" + 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 ArguemntError, "expect Integer or 'idle' for 1st argument" + 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 ArgumentError, "Argument '#{@init_proc}' need to be Proc" + 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 + unless wait.kind_of? Integer + fail ArguemntError, "expect Integer for 1st argument" + end + sleep = wait + end + Tk_CBTBL[@id] = self + @running = true + @after_id = tk_call_without_enc('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_without_enc('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 diff --git a/ext/tk/lib/tk/toplevel.rb b/ext/tk/lib/tk/toplevel.rb new file mode 100644 index 0000000000..f8b0f77936 --- /dev/null +++ b/ext/tk/lib/tk/toplevel.rb @@ -0,0 +1,211 @@ +# +# tk/toplevel.rb : treat toplevel widget +# +require 'tk' +require 'tk/wm' + +class TkToplevel<TkWindow + include Wm + + TkCommandNames = ['toplevel'.freeze].freeze + WidgetClassName = 'Toplevel'.freeze + WidgetClassNames[WidgetClassName] = self + +################# old version +# def initialize(parent=nil, screen=nil, classname=nil, keys=nil) +# if screen.kind_of? Hash +# keys = screen.dup +# else +# @screen = screen +# end +# @classname = classname +# if keys.kind_of? Hash +# keys = keys.dup +# @classname = keys.delete('classname') if keys.key?('classname') +# @colormap = keys.delete('colormap') if keys.key?('colormap') +# @container = keys.delete('container') if keys.key?('container') +# @screen = keys.delete('screen') if keys.key?('screen') +# @use = keys.delete('use') if keys.key?('use') +# @visual = keys.delete('visual') if keys.key?('visual') +# end +# super(parent, keys) +# end +# +# def create_self +# s = [] +# s << "-class" << @classname if @classname +# s << "-colormap" << @colormap if @colormap +# s << "-container" << @container if @container +# s << "-screen" << @screen if @screen +# s << "-use" << @use if @use +# s << "-visual" << @visual if @visual +# tk_call 'toplevel', @path, *s +# end +################# + + def _wm_command_option_chk(keys) + keys = {} unless keys + new_keys = {} + wm_cmds = {} + keys.each{|k,v| + if Wm.method_defined?(k) + case k + when 'screen','class','colormap','container','use','visual' + new_keys[k] = v + else + case self.method(k).arity + when -1,1 + wm_cmds[k] = v + else + new_keys[k] = v + end + end + else + new_keys[k] = v + end + } + [new_keys, wm_cmds] + end + private :_wm_command_option_chk + + def initialize(parent=nil, screen=nil, classname=nil, keys=nil) + my_class_name = nil + if self.class < WidgetClassNames[WidgetClassName] + my_class_name = self.class.name + my_class_name = nil if my_class_name == '' + end + if parent.kind_of? Hash + keys = _symbolkey2str(parent) + if keys.key?('classname') + keys['class'] = keys.delete('classname') + end + @classname = keys['class'] + @colormap = keys['colormap'] + @container = keys['container'] + @screen = keys['screen'] + @use = keys['use'] + @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 + keys, cmds = _wm_command_option_chk(keys) + super(keys) + cmds.each{|k,v| + if v.kind_of? Array + self.send(k,*v) + else + self.send(k,v) + end + } + return + end + + if screen.kind_of? Hash + keys = screen + else + @screen = screen + if classname.kind_of? Hash + keys = classname + else + @classname = classname + end + end + if keys.kind_of? Hash + keys = _symbolkey2str(keys) + if keys.key?('classname') + keys['class'] = keys.delete('classname') + end + @classname = keys['class'] unless @classname + @colormap = keys['colormap'] + @container = keys['container'] + @screen = keys['screen'] unless @screen + @use = keys['use'] + @visual = keys['visual'] + else + keys = {} + end + 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 + keys, cmds = _wm_command_option_chk(keys) + super(parent, keys) + cmds.each{|k,v| + if v.kind_of? Array + self.send(k,*v) + else + self.send(k,v) + end + } + end + + def create_self(keys) + if keys and keys != None + tk_call_without_enc('toplevel', @path, *hash_kv(keys, true)) + else + tk_call_without_enc('toplevel', @path) + end + end + private :create_self + + def specific_class + @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 diff --git a/ext/tk/lib/tk/txtwin_abst.rb b/ext/tk/lib/tk/txtwin_abst.rb new file mode 100644 index 0000000000..63da9da11d --- /dev/null +++ b/ext/tk/lib/tk/txtwin_abst.rb @@ -0,0 +1,38 @@ +# +# tk/txtwin_abst.rb : TkTextWin abstruct class +# +require 'tk' + +class TkTextWin<TkWindow + def create_self + fail RuntimeError, "TkTextWin is an abstract class" + end + private :create_self + + def bbox(index) + list(tk_send_without_enc('bbox', index)) + end + def delete(first, last=None) + tk_send_without_enc('delete', first, last) + self + end + def get(*index) + _fromUTF8(tk_send_without_enc('get', *index)) + end + def insert(index, *args) + tk_send('insert', index, *args) + self + end + def scan_mark(x, y) + tk_send_without_enc('scan', 'mark', x, y) + self + end + def scan_dragto(x, y) + tk_send_without_enc('scan', 'dragto', x, y) + self + end + def see(index) + tk_send_without_enc('see', index) + self + end +end diff --git a/ext/tk/lib/tk/validation.rb b/ext/tk/lib/tk/validation.rb new file mode 100644 index 0000000000..70e84e6cbf --- /dev/null +++ b/ext/tk/lib/tk/validation.rb @@ -0,0 +1,166 @@ +# +# tk/validation.rb - validation support module for entry, spinbox, and so on +# +require 'tk' + +module TkValidation + class ValidateCmd + include TkComm + + module Action + Insert = 1 + Delete = 0 + Others = -1 + Focus = -1 + Forced = -1 + Textvariable = -1 + TextVariable = -1 + end + + class ValidateArgs < TkUtil::CallbackSubst + key_tbl = [ + [ ?d, ?n, :action ], + [ ?i, ?x, :index ], + [ ?s, ?e, :current ], + [ ?v, ?s, :type ], + [ ?P, ?e, :value ], + [ ?S, ?e, :string ], + [ ?V, ?s, :triggered ], + [ ?W, ?w, :widget ], + nil + ] + + proc_tbl = [ + [ ?n, TkComm.method(:number) ], + [ ?s, TkComm.method(:string) ], + [ ?w, TkComm.method(:window) ], + + [ ?e, proc{|val| + enc = Tk.encoding + if enc + Tk.fromUTF8(TkComm::string(val), enc) + else + TkComm::string(val) + end + } + ], + + [ ?x, proc{|val| + idx = TkComm::number(val) + if idx < 0 + nil + else + idx + end + } + ], + + nil + ] + + _setup_subst_table(key_tbl, proc_tbl); + end + + def initialize(cmd = Proc.new, *args) + if args.compact.size > 0 + args = args.join(' ') + keys = ValidateArgs._get_subst_key(args) + if cmd.kind_of?(String) + id = cmd + elsif cmd.kind_of?(TkCallbackEntry) + @id = install_cmd(cmd) + else + @id = install_cmd(proc{|*arg| + (cmd.call(*ValidateArgs.scan_args(keys, arg)))? '1':'0' + }) + ' ' + args + end + else + keys, args = ValidateArgs._get_all_subst_keys + if cmd.kind_of?(String) + id = cmd + elsif cmd.kind_of?(TkCallbackEntry) + @id = install_cmd(cmd) + else + @id = install_cmd(proc{|*arg| + (cmd.call( + ValidateArgs.new(*ValidateArgs.scan_args(keys,arg))) + )? '1': '0' + }) + ' ' + args + end + end + end + + def to_eval + @id + end + end + + ##################################### + + def configure(slot, value=TkComm::None) + if slot.kind_of? Hash + slot = _symbolkey2str(slot) + if slot['vcmd'].kind_of? Array + cmd, *args = slot['vcmd'] + slot['vcmd'] = ValidateCmd.new(cmd, args.join(' ')) + elsif slot['vcmd'].kind_of? Proc + slot['vcmd'] = ValidateCmd.new(slot['vcmd']) + end + if slot['validatecommand'].kind_of? Array + cmd, *args = slot['validatecommand'] + slot['validatecommand'] = ValidateCmd.new(cmd, args.join(' ')) + elsif slot['validatecommand'].kind_of? Proc + slot['validatecommand'] = ValidateCmd.new(slot['validatecommand']) + end + if slot['invcmd'].kind_of? Array + cmd, *args = slot['invcmd'] + slot['invcmd'] = ValidateCmd.new(cmd, args.join(' ')) + elsif slot['invcmd'].kind_of? Proc + slot['invcmd'] = ValidateCmd.new(slot['invcmd']) + end + if slot['invalidcommand'].kind_of? Array + cmd, *args = slot['invalidcommand'] + slot['invalidcommand'] = ValidateCmd.new(cmd, args.join(' ')) + elsif slot['invalidcommand'].kind_of? Proc + slot['invalidcommand'] = ValidateCmd.new(slot['invalidcommand']) + end + super(slot) + else + if (slot == 'vcmd' || slot == :vcmd || + slot == 'validatecommand' || slot == :validatecommand || + slot == 'invcmd' || slot == :invcmd || + slot == 'invalidcommand' || slot == :invalidcommand) + if value.kind_of? Array + cmd, *args = value + value = ValidateCmd.new(cmd, args.join(' ')) + elsif value.kind_of? Proc + value = ValidateCmd.new(value) + end + end + super(slot, value) + end + self + end + + def validatecommand(cmd = Proc.new, args = nil) + if cmd.kind_of?(ValidateCmd) + configure('validatecommand', cmd) + elsif args + configure('validatecommand', [cmd, args]) + else + configure('validatecommand', cmd) + end + end + alias vcmd validatecommand + + def invalidcommand(cmd = Proc.new, args = nil) + if cmd.kind_of?(ValidateCmd) + configure('invalidcommand', cmd) + elsif args + configure('invalidcommand', [cmd, args]) + else + configure('invalidcommand', cmd) + end + end + alias invcmd invalidcommand +end diff --git a/ext/tk/lib/tk/variable.rb b/ext/tk/lib/tk/variable.rb new file mode 100644 index 0000000000..c4ec91741d --- /dev/null +++ b/ext/tk/lib/tk/variable.rb @@ -0,0 +1,847 @@ +# +# tk/variable.rb : treat Tk variable object +# +require 'tk' + +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]") +TkCore::INTERP.add_tk_procs('rb_var', 'args', <<-'EOL') + if {[set st [catch {eval {ruby_cmd TkVariable callback} $args} ret]] != 0} { + set idx [string first "\n\n" $ret] + if {$idx > 0} { + global errorInfo + set tcl_backtrace $errorInfo + set errorInfo [string range $ret [expr $idx + 2] \ + [string length $ret]] + append errorInfo "\n" $tcl_backtrace + bgerror [string range $ret 0 [expr $idx - 1]] + } else { + bgerror $ret + } + return "" + #return -code $st $ret + } else { + return $ret + } + EOL + + #def TkVariable.callback(args) + def TkVariable.callback(name1, name2, op) + #name1,name2,op = tk_split_list(args) + #name1,name2,op = tk_split_simplelist(args) + if TkVar_CB_TBL[name1] + #_get_eval_string(TkVar_CB_TBL[name1].trace_callback(name2,op)) + begin + _get_eval_string(TkVar_CB_TBL[name1].trace_callback(name2, op)) + rescue Exception => e + begin + 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 +=begin + begin + raise 'check backtrace' + rescue + # ignore backtrace before 'callback' + pos = -($!.backtrace.size) + end + begin + _get_eval_string(TkVar_CB_TBL[name1].trace_callback(name2,op)) + rescue + trace = $!.backtrace + raise $!, "\n#{trace[0]}: #{$!.message} (#{$!.class})\n" + + "\tfrom #{trace[1..pos].join("\n\tfrom ")}" + end +=end + else + '' + end + 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 + INTERP._unset_global_var(@id) + rescue + end + + # teach Tk-ip that @id is global var + INTERP._invoke_without_enc('global', @id) + #INTERP._invoke('global', @id) + + self.value = val + +=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(/[\[\]$"]/, '\\\\\&') + '"' + 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(/[\[\]$"]/, '\\\\\&') + '"' + 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(/[\[\]$"]/, '\\\\\&') + '"' + s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"' + INTERP._eval(format('global %s; set %s %s', @id, @id, s)) + end +=end +=begin + if val.kind_of?(Hash) + #s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\ + # .gsub(/[\[\]$"]/, '\\\\\&') + '"' + 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(/[\[\]$"]/, '\\\\\&') + '"' + s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"' + INTERP._eval(Kernel.format('global %s; set %s %s', @id, @id, s)) + end +=end + end + + def wait(on_thread = false, check_root = false) + if $SAFE >= 4 + fail SecurityError, "can't wait variable at $SAFE >= 4" + end + on_thread &= (Thread.list.size != 1) + if on_thread + if check_root + INTERP._thread_tkwait('variable', @id) + else + INTERP._thread_vwait(@id) + end + else + if check_root + INTERP._invoke_without_enc('tkwait', 'variable', @id) + else + INTERP._invoke_without_enc('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 is_hash? + #ITNERP._eval("global #{@id}; array exist #{@id}") == '1' + ITNERP._invoke_without_enc('array', 'exist', @id) == '1' + end + + def is_scalar? + ! is_hash? + end + + def keys + if (is_scalar?) + fail RuntimeError, 'cannot get keys from a scalar variable' + end + #tk_split_simplelist(INTERP._eval("global #{@id}; array get #{@id}")) + tk_split_simplelist(INTERP._fromUTF8(INTERP._invoke_without_enc('array', 'get', @id))) + end + + +unless const_defined?(:USE_TCLs_SET_VARIABLE_FUNCTIONS) + USE_TCLs_SET_VARIABLE_FUNCTIONS = true +end + +if USE_TCLs_SET_VARIABLE_FUNCTIONS + ########################################################################### + # use Tcl function version of set tkvariable + ########################################################################### + + def value + #if INTERP._eval("global #{@id}; array exist #{@id}") == '1' + if INTERP._invoke('array', 'exist', @id) == '1' + #Hash[*tk_split_simplelist(INTERP._eval("global #{@id}; array get #{@id}"))] + Hash[*tk_split_simplelist(INTERP._invoke('array', 'get', @id))] + else + _fromUTF8(INTERP._get_global_var(@id)) + end + end + + def value=(val) + if val.kind_of?(Hash) + val.each{|k, v| + #INTERP._set_global_var2(@id, _toUTF8(_get_eval_string(k)), + # _toUTF8(_get_eval_string(v))) + INTERP._set_global_var2(@id, __get_eval_string(k, true), + _get_eval_string(v, true)) + } + self.value + elsif val.kind_of?(Array) + INTERP._set_global_var(@id, '') + val.each{|v| + #INTERP._set_variable(@id, _toUTF8(_get_eval_string(v)), + INTERP._set_variable(@id, _get_eval_string(v, true), + TclTkLib::VarAccessFlag::GLOBAL_ONLY | + TclTkLib::VarAccessFlag::LEAVE_ERR_MSG | + TclTkLib::VarAccessFlag::APPEND_VALUE | + TclTkLib::VarAccessFlag::LIST_ELEMENT) + } + self.value + else + #_fromUTF8(INTERP._set_global_var(@id, _toUTF8(_get_eval_string(val)))) + _fromUTF8(INTERP._set_global_var(@id, _get_eval_string(val, true))) + end + end + + def [](index) + #_fromUTF8(INTERP._get_global_var2(@id, _toUTF8(_get_eval_string(index)))) + _fromUTF8(INTERP._get_global_var2(@id, _get_eval_string(index, true))) + end + + def []=(index,val) + #_fromUTF8(INTERP._set_global_var2(@id, _toUTF8(_get_eval_string(index)), + # _toUTF8(_get_eval_string(val)))) + _fromUTF8(INTERP._set_global_var2(@id, _get_eval_string(index, true), + _get_eval_string(val, true))) + end + + def unset(elem=nil) + if elem + INTERP._unset_global_var2(@id, tk_tcl2ruby(elem)) + else + INTERP._unset_global_var(@id) + end + end + alias remove unset + +else + ########################################################################### + # use Ruby script version of set tkvariable (traditional methods) + ########################################################################### + + def value + begin + INTERP._eval(Kernel.format('global %s; set %s', @id, @id)) + #INTERP._eval(Kernel.format('set %s', @id)) + #INTERP._invoke_without_enc('set', @id) + rescue + if INTERP._eval(Kernel.format('global %s; array exists %s', + @id, @id)) != "1" + #if INTERP._eval(Kernel.format('array exists %s', @id)) != "1" + #if INTERP._invoke_without_enc('array', 'exists', @id) != "1" + fail + else + Hash[*tk_split_simplelist(INTERP._eval(Kernel.format('global %s; array get %s', @id, @id)))] + #Hash[*tk_split_simplelist(_fromUTF8(INTERP._invoke_without_enc('array', 'get', @id)))] + end + end + end + + def value=(val) + begin + #s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"' + s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"' + INTERP._eval(Kernel.format('global %s; set %s %s', @id, @id, s)) + #INTERP._eval(Kernel.format('set %s %s', @id, s)) + #_fromUTF8(INTERP._invoke_without_enc('set', @id, _toUTF8(s))) + rescue + if INTERP._eval(Kernel.format('global %s; array exists %s', + @id, @id)) != "1" + #if INTERP._eval(Kernel.format('array exists %s', @id)) != "1" + #if INTERP._invoke_without_enc('array', 'exists', @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)) + #INTERP._eval(Kernel.format('unset %s; set %s(0) 0; unset %s(0)', + # @id, @id, @id)) + #INTERP._invoke_without_enc('unset', @id) + #INTERP._invoke_without_enc('set', @id+'(0)', 0) + #INTERP._invoke_without_enc('unset', @id+'(0)') + elsif val.kind_of?(Array) + a = [] + val.each_with_index{|e,i| a.push(i); a.push(array2tk_list(e))} + #s = '"' + a.join(" ").gsub(/[\[\]$"]/, '\\\\\&') + '"' + s = '"' + a.join(" ").gsub(/[\[\]$"\\]/, '\\\\\&') + '"' + INTERP._eval(Kernel.format('global %s; unset %s; array set %s %s', + @id, @id, @id, s)) + #INTERP._eval(Kernel.format('unset %s; array set %s %s', + # @id, @id, s)) + #INTERP._invoke_without_enc('unset', @id) + #_fromUTF8(INTERP._invoke_without_enc('array','set', @id, _toUTF8(s))) + elsif val.kind_of?(Hash) + #s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\ + # .gsub(/[\[\]$"]/, '\\\\\&') + '"' + 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)) + #INTERP._eval(Kernel.format('unset %s; array set %s %s', + # @id, @id, s)) + #INTERP._invoke_without_enc('unset', @id) + #_fromUTF8(INTERP._invoke_without_enc('array','set', @id, _toUTF8(s))) + else + fail + end + end + end + end + + def [](index) + INTERP._eval(Kernel.format('global %s; set %s(%s)', + @id, @id, _get_eval_string(index))) + #INTERP._eval(Kernel.format('set %s(%s)', @id, _get_eval_string(index))) + #INTERP._eval('set ' + @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))) + #INTERP._eval(Kernel.format('set %s(%s) %s', @id, + # _get_eval_string(index), _get_eval_string(val))) + #INTERP._eval('set ' + @id + '(' + _get_eval_string(index) + ') ' + + # _get_eval_string(val)) + end + + def unset(elem=nil) + if elem + INTERP._eval(Kernel.format('global %s; unset %s(%s)', + @id, @id, tk_tcl2ruby(elem))) + #INTERP._eval(Kernel.format('unset %s(%s)', @id, tk_tcl2ruby(elem))) + #INTERP._eval('unset ' + @id + '(' + _get_eval_string(elem) + ')') + else + INTERP._eval(Kernel.format('global %s; unset %s', @id, @id)) + #INTERP._eval(Kernel.format('unset %s', @id)) + #INTERP._eval('unset ' + @id) + end + end + alias remove unset + +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 + val + end + + def to_i + number(value).to_i + end + + def to_f + number(value).to_f + end + + def to_s + #string(value).to_s + value + end + + def to_sym + value.intern + end + + def list + #tk_split_list(value) + tk_split_simplelist(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 + val + end + + def inspect + #Kernel.format "#<TkVariable: %s>", @id + '#<TkVariable: ' + @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 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) && elem != '' + if @trace_elem.kind_of?(Hash) && @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 = Proc.new) + @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.dup + Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, 'rb_var') +=begin + if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION + # TCL_VERSION >= 8.4 + Tk.tk_call_without_enc('trace', 'add', 'variable', + @id, @trace_opts, 'rb_var') + else + # TCL_VERSION <= 8.3 + Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, 'rb_var') + end +=end + else + newopts = @trace_opts.dup + opts.each_byte{|c| newopts += c.chr unless newopts.index(c)} + if newopts != @trace_opts + Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts, 'rb_var') + @trace_opts.replace(newopts) + Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, 'rb_var') +=begin + if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION + # TCL_VERSION >= 8.4 + Tk.tk_call_without_enc('trace', 'remove', 'variable', + @id, @trace_opts, 'rb_var') + @trace_opts.replace(newopts) + Tk.tk_call_without_enc('trace', 'add', 'variable', + @id, @trace_opts, 'rb_var') + else + # TCL_VERSION <= 8.3 + Tk.tk_call_without_enc('trace', 'vdelete', + @id, @trace_opts, 'rb_var') + @trace_opts.replace(newopts) + Tk.tk_call_without_enc('trace', 'variable', + @id, @trace_opts, 'rb_var') + end +=end + end + end + self + end + + def trace_element(elem, opts, cmd = Proc.new) + @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.dup + Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, 'rb_var') +=begin + if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION + # TCL_VERSION >= 8.4 + Tk.tk_call_without_enc('trace', 'add', 'variable', + @id, @trace_opts, 'rb_var') + else + # TCL_VERSION <= 8.3 + Tk.tk_call_without_enc('trace', 'variable', + @id, @trace_opts, 'rb_var') + end +=end + else + newopts = @trace_opts.dup + opts.each_byte{|c| newopts += c.chr unless newopts.index(c)} + if newopts != @trace_opts + Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts, 'rb_var') + @trace_opts.replace(newopts) + Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, 'rb_var') +=begin + if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION + # TCL_VERSION >= 8.4 + Tk.tk_call_without_enc('trace', 'remove', 'variable', + @id, @trace_opts, 'rb_var') + @trace_opts.replace(newopts) + Tk.tk_call_without_enc('trace', 'add', 'variable', + @id, @trace_opts, 'rb_var') + else + # TCL_VERSION <= 8.3 + Tk.tk_call_without_enc('trace', 'vdelete', + @id, @trace_opts, 'rb_var') + @trace_opts.replace(newopts) + Tk.tk_call_without_enc('trace', 'variable', + @id, @trace_opts, 'rb_var') + end +=end + end + end + self + 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 self 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 self + 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_without_enc('trace', 'vdelete', @id, @trace_opts, 'rb_var') +=begin + if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION + # TCL_VERSION >= 8.4 + Tk.tk_call_without_enc('trace', 'remove', 'variable', + @id, @trace_opts, 'rb_var') + else + # TCL_VERSION <= 8.3 + Tk.tk_call_without_enc('trace', 'vdelete', + @id, @trace_opts, 'rb_var') + end +=end + @trace_opts.replace(newopts) + if @trace_opts != '' + Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, 'rb_var') +=begin + if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION + # TCL_VERSION >= 8.4 + Tk.tk_call_without_enc('trace', 'add', 'variable', + @id, @trace_opts, 'rb_var') + else + # TCL_VERSION <= 8.3 + Tk.tk_call_without_enc('trace', 'variable', + @id, @trace_opts, 'rb_var') + end +=end + end + end + + self + end + + def trace_vdelete_for_element(elem,opts,cmd) + return self unless @trace_elem.kind_of? Hash + return self 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 self + 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_without_enc('trace', 'vdelete', @id, @trace_opts, 'rb_var') +=begin + if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION + # TCL_VERSION >= 8.4 + Tk.tk_call_without_enc('trace', 'remove', 'variable', + @id, @trace_opts, 'rb_var') + else + # TCL_VERSION <= 8.3 + Tk.tk_call_without_enc('trace', 'vdelete', + @id, @trace_opts, 'rb_var') + end +=end + @trace_opts.replace(newopts) + if @trace_opts != '' + Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, 'rb_var') +=begin + if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION + # TCL_VERSION >= 8.4 + Tk.tk_call_without_enc('trace', 'add', 'variable', + @id, @trace_opts, 'rb_var') + else + # TCL_VERSION <= 8.3 + Tk.tk_call_without_enc('trace', 'variable', @id, + @trace_opts, 'rb_var') + end +=end + end + end + + self + end +end + + +class TkVarAccess<TkVariable + def self.new(name, *args) + return TkVar_ID_TBL[name] if TkVar_ID_TBL[name] + super(name, *args) + end + + def initialize(varname, val=nil) + @id = varname + TkVar_ID_TBL[@id] = self + + # teach Tk-ip that @id is global var + INTERP._invoke_without_enc('global', @id) + + if val + #s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"' #" + #s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"' #" + #INTERP._eval(Kernel.format('global %s; set %s %s', @id, @id, s)) + #INTERP._set_global_var(@id, _toUTF8(_get_eval_string(val))) + self.value = val + end + end +end + + +module Tk + begin + auto_path = INTERP._invoke('set', 'auto_path') + rescue + begin + auto_path = INTERP._invoke('set', 'env(TCLLIBPATH)') + rescue + auto_path = Tk::LIBRARY + end + end + + AUTO_PATH = TkVarAccess.new('auto_path', auto_path) + +=begin + AUTO_OLDPATH = tk_split_simplelist(INTERP._invoke('set', 'auto_oldpath')) + AUTO_OLDPATH.each{|s| s.freeze} + AUTO_OLDPATH.freeze +=end + + TCL_PACKAGE_PATH = TkVarAccess.new('tcl_pkgPath') + PACKAGE_PATH = TCL_PACKAGE_PATH + + TCL_LIBRARY_PATH = TkVarAccess.new('tcl_libPath') + LIBRARY_PATH = TCL_LIBRARY_PATH + + TCL_PRECISION = TkVarAccess.new('tcl_precision') +end diff --git a/ext/tk/lib/tk/virtevent.rb b/ext/tk/lib/tk/virtevent.rb new file mode 100644 index 0000000000..bb95ed2421 --- /dev/null +++ b/ext/tk/lib/tk/virtevent.rb @@ -0,0 +1,89 @@ +# +# tk/virtevent.rb : treats virtual events +# 1998/07/16 by Hidetoshi Nagai <nagai@ai.kyutech.ac.jp> +# +require 'tk' + +class TkVirtualEvent<TkObject + extend Tk + + TkCommandNames = ['event'.freeze].freeze + + TkVirtualEventID = ["<VirtEvent".freeze, "00000".taint, ">".freeze].freeze + TkVirtualEventTBL = TkCore::INTERP.create_table + + TkCore::INTERP.init_ip_env{ TkVirtualEventTBL.clear } + + class PreDefVirtEvent<self + def initialize(event) + @path = @id = event + TkVirtualEvent::TkVirtualEventTBL[@id] = self + end + end + + def TkVirtualEvent.getobj(event) + obj = TkVirtualEventTBL[event] + if obj + obj + else + if tk_call_without_enc('event', 'info').index("<#{event}>") + PreDefVirtEvent.new(event) + else + fail ArgumentError, "undefined virtual event '<#{event}>'" + end + end + end + + def TkVirtualEvent.info + tk_call_without_enc('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_without_enc('event', 'add', "<#{@id}>", + *(sequences.collect{|seq| + "<#{tk_event_sequence(seq)}>" + }) ) + TkVirtualEventTBL[@id] = self + end + self + end + + def delete(*sequences) + if sequences == [] + tk_call_without_enc('event', 'delete', "<#{@id}>") + TkVirtualEventTBL.delete(@id) + else + tk_call_without_enc('event', 'delete', "<#{@id}>", + *(sequences.collect{|seq| + "<#{tk_event_sequence(seq)}>" + }) ) + TkVirtualEventTBL.delete(@id) if info == [] + end + self + end + + def info + tk_call_without_enc('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 diff --git a/ext/tk/lib/tk/winfo.rb b/ext/tk/lib/tk/winfo.rb new file mode 100644 index 0000000000..a3ce2b2cd2 --- /dev/null +++ b/ext/tk/lib/tk/winfo.rb @@ -0,0 +1,384 @@ +# +# tk/winfo.rb : methods for winfo command +# +require 'tk' + +module TkWinfo + include Tk + extend Tk + + TkCommandNames = ['winfo'.freeze].freeze + + def TkWinfo.atom(name, win=nil) + if win + number(tk_call_without_enc('winfo', 'atom', '-displayof', win, + _get_eval_enc_str(name))) + else + number(tk_call_without_enc('winfo', 'atom', _get_eval_enc_str(name))) + end + end + def winfo_atom(name) + TkWinfo.atom(name, self) + end + + def TkWinfo.atomname(id, win=nil) + if win + _fromUTF8(tk_call_without_enc('winfo', 'atomname', + '-displayof', win, id)) + else + _fromUTF8(tk_call_without_enc('winfo', 'atomname', id)) + end + end + def winfo_atomname(id) + TkWinfo.atomname(id, self) + end + + def TkWinfo.cells(window) + number(tk_call_without_enc('winfo', 'cells', window)) + end + def winfo_cells + TkWinfo.cells self + end + + def TkWinfo.children(window) + list(tk_call_without_enc('winfo', 'children', window)) + end + def winfo_children + TkWinfo.children self + end + + def TkWinfo.classname(window) + tk_call_without_enc('winfo', 'class', window) + end + def winfo_classname + TkWinfo.classname self + end + alias winfo_class winfo_classname + + def TkWinfo.colormapfull(window) + bool(tk_call_without_enc('winfo', 'colormapfull', window)) + end + def winfo_colormapfull + TkWinfo.colormapfull self + end + + def TkWinfo.containing(rootX, rootY, win=nil) + if win + window(tk_call_without_enc('winfo', 'containing', + '-displayof', win, rootX, rootY)) + else + window(tk_call_without_enc('winfo', 'containing', rootX, rootY)) + end + end + def winfo_containing(x, y) + TkWinfo.containing(x, y, self) + end + + def TkWinfo.depth(window) + number(tk_call_without_enc('winfo', 'depth', window)) + end + def winfo_depth + TkWinfo.depth self + end + + def TkWinfo.exist?(window) + bool(tk_call_without_enc('winfo', 'exists', window)) + end + def winfo_exist? + TkWinfo.exist? self + end + + def TkWinfo.fpixels(window, dist) + number(tk_call_without_enc('winfo', 'fpixels', window, dist)) + end + def winfo_fpixels(dist) + TkWinfo.fpixels self, dist + end + + def TkWinfo.geometry(window) + tk_call_without_enc('winfo', 'geometry', window) + end + def winfo_geometry + TkWinfo.geometry self + end + + def TkWinfo.height(window) + number(tk_call_without_enc('winfo', 'height', window)) + end + def winfo_height + TkWinfo.height self + end + + def TkWinfo.id(window) + tk_call_without_enc('winfo', 'id', window) + end + def winfo_id + TkWinfo.id self + end + + def TkWinfo.interps(window=nil) + if window + tk_split_simplelist(tk_call_without_enc('winfo', 'interps', + '-displayof', window)) + else + tk_split_simplelist(tk_call_without_enc('winfo', 'interps')) + end + end + def winfo_interps + TkWinfo.interps self + end + + def TkWinfo.mapped?(window) + bool(tk_call_without_enc('winfo', 'ismapped', window)) + end + def winfo_mapped? + TkWinfo.mapped? self + end + + def TkWinfo.manager(window) + tk_call_without_enc('winfo', 'manager', window) + end + def winfo_manager + TkWinfo.manager self + end + + def TkWinfo.appname(window) + tk_call('winfo', 'name', window) + end + def winfo_appname + TkWinfo.appname self + end + + def TkWinfo.parent(window) + window(tk_call_without_enc('winfo', 'parent', window)) + end + def winfo_parent + TkWinfo.parent self + end + + def TkWinfo.widget(id, win=nil) + if win + window(tk_call_without_enc('winfo', 'pathname', '-displayof', win, id)) + else + window(tk_call_without_enc('winfo', 'pathname', id)) + end + end + def winfo_widget(id) + TkWinfo.widget id, self + end + + def TkWinfo.pixels(window, dist) + number(tk_call_without_enc('winfo', 'pixels', window, dist)) + end + def winfo_pixels(dist) + TkWinfo.pixels self, dist + end + + def TkWinfo.reqheight(window) + number(tk_call_without_enc('winfo', 'reqheight', window)) + end + def winfo_reqheight + TkWinfo.reqheight self + end + + def TkWinfo.reqwidth(window) + number(tk_call_without_enc('winfo', 'reqwidth', window)) + end + def winfo_reqwidth + TkWinfo.reqwidth self + end + + def TkWinfo.rgb(window, color) + list(tk_call_without_enc('winfo', 'rgb', window, color)) + end + def winfo_rgb(color) + TkWinfo.rgb self, color + end + + def TkWinfo.rootx(window) + number(tk_call_without_enc('winfo', 'rootx', window)) + end + def winfo_rootx + TkWinfo.rootx self + end + + def TkWinfo.rooty(window) + number(tk_call_without_enc('winfo', 'rooty', window)) + end + def winfo_rooty + TkWinfo.rooty self + end + + def TkWinfo.screen(window) + tk_call('winfo', 'screen', window) + end + def winfo_screen + TkWinfo.screen self + end + + def TkWinfo.screencells(window) + number(tk_call_without_enc('winfo', 'screencells', window)) + end + def winfo_screencells + TkWinfo.screencells self + end + + def TkWinfo.screendepth(window) + number(tk_call_without_enc('winfo', 'screendepth', window)) + end + def winfo_screendepth + TkWinfo.screendepth self + end + + def TkWinfo.screenheight (window) + number(tk_call_without_enc('winfo', 'screenheight', window)) + end + def winfo_screenheight + TkWinfo.screenheight self + end + + def TkWinfo.screenmmheight(window) + number(tk_call_without_enc('winfo', 'screenmmheight', window)) + end + def winfo_screenmmheight + TkWinfo.screenmmheight self + end + + def TkWinfo.screenmmwidth(window) + number(tk_call_without_enc('winfo', 'screenmmwidth', window)) + end + def winfo_screenmmwidth + TkWinfo.screenmmwidth self + end + + def TkWinfo.screenvisual(window) + tk_call_without_enc('winfo', 'screenvisual', window) + end + def winfo_screenvisual + TkWinfo.screenvisual self + end + + def TkWinfo.screenwidth(window) + number(tk_call_without_enc('winfo', 'screenwidth', window)) + end + def winfo_screenwidth + TkWinfo.screenwidth self + end + + def TkWinfo.server(window) + tk_call('winfo', 'server', window) + end + def winfo_server + TkWinfo.server self + end + + def TkWinfo.toplevel(window) + window(tk_call_without_enc('winfo', 'toplevel', window)) + end + def winfo_toplevel + TkWinfo.toplevel self + end + + def TkWinfo.visual(window) + tk_call_without_enc('winfo', 'visual', window) + end + def winfo_visual + TkWinfo.visual self + end + + def TkWinfo.visualid(window) + tk_call_without_enc('winfo', 'visualid', window) + end + def winfo_visualid + TkWinfo.visualid self + end + + def TkWinfo.visualsavailable(window, includeids=false) + if includeids + list(tk_call_without_enc('winfo', 'visualsavailable', + window, "includeids")) + else + list(tk_call_without_enc('winfo', 'visualsavailable', window)) + end + end + def winfo_visualsavailable(includeids=false) + TkWinfo.visualsavailable self, includeids + end + + def TkWinfo.vrootheight(window) + number(tk_call_without_enc('winfo', 'vrootheight', window)) + end + def winfo_vrootheight + TkWinfo.vrootheight self + end + + def TkWinfo.vrootwidth(window) + number(tk_call_without_enc('winfo', 'vrootwidth', window)) + end + def winfo_vrootwidth + TkWinfo.vrootwidth self + end + + def TkWinfo.vrootx(window) + number(tk_call_without_enc('winfo', 'vrootx', window)) + end + def winfo_vrootx + TkWinfo.vrootx self + end + + def TkWinfo.vrooty(window) + number(tk_call_without_enc('winfo', 'vrooty', window)) + end + def winfo_vrooty + TkWinfo.vrooty self + end + + def TkWinfo.width(window) + number(tk_call_without_enc('winfo', 'width', window)) + end + def winfo_width + TkWinfo.width self + end + + def TkWinfo.x(window) + number(tk_call_without_enc('winfo', 'x', window)) + end + def winfo_x + TkWinfo.x self + end + + def TkWinfo.y(window) + number(tk_call_without_enc('winfo', 'y', window)) + end + def winfo_y + TkWinfo.y self + end + + def TkWinfo.viewable(window) + bool(tk_call_without_enc('winfo', 'viewable', window)) + end + def winfo_viewable + TkWinfo.viewable self + end + + def TkWinfo.pointerx(window) + number(tk_call_without_enc('winfo', 'pointerx', window)) + end + def winfo_pointerx + TkWinfo.pointerx self + end + + def TkWinfo.pointery(window) + number(tk_call_without_enc('winfo', 'pointery', window)) + end + def winfo_pointery + TkWinfo.pointery self + end + + def TkWinfo.pointerxy(window) + list(tk_call_without_enc('winfo', 'pointerxy', window)) + end + def winfo_pointerxy + TkWinfo.pointerxy self + end +end diff --git a/ext/tk/lib/tk/winpkg.rb b/ext/tk/lib/tk/winpkg.rb new file mode 100644 index 0000000000..1d7d473387 --- /dev/null +++ b/ext/tk/lib/tk/winpkg.rb @@ -0,0 +1,136 @@ +# +# tk/winpkg.rb : methods for Tcl/Tk packages for Microsoft Windows +# 2000/11/22 by Hidetoshi Nagai <nagai@ai.kyutech.ac.jp> +# +# ATTENTION !! +# This is NOT TESTED. Because I have no test-environment. +# +require 'tk' + +module TkWinDDE + extend Tk + extend TkWinDDE + + TkCommandNames = ['dde'.freeze].freeze + + if self.const_defined? :FORCE_VERSION + tk_call_without_enc('package', 'require', 'dde', FORCE_VERSION) + else + tk_call_without_enc('package', 'require', 'dde') + end + + def servername(topic=None) + tk_call('dde', 'servername', topic) + end + def servername(*args) + if args.size == 0 + tk_call('dde', 'servername') + else + if args[-1].kind_of?(Hash) + keys = _symbolkey2str(args.pop) + force = (keys.delete('force'))? '-force': None + exact = (keys.delete('exact'))? '-exact': None + if keys.size == 0 + tk_call('dde', 'servername', force, exact) + elsif args.size == 0 + tk_call('dde', 'servername', force, exact, *hash_kv(keys)) + else + tk_call('dde', 'servername', force, exact, + *((hash_kv(keys) << '--') + args)) + end + end + end + 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 binary_request(service, topic, item) + tk_call('dde', 'request', '-binary', 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 + + def async_eval(topic, cmd, *args) + tk_call('dde', 'eval', -async, 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 + + if self.const_defined? :FORCE_VERSION + tk_call('package', 'require', 'registry', FORCE_VERSION) + else + tk_call('package', 'require', 'registry') + end + + def broadcast(keynam, timeout=nil) + if timeout + tk_call('registry', 'broadcast', keynam, '-timeout', timeout) + else + tk_call('registry', 'broadcast', keynam) + end + end + + def delete(keynam, valnam=None) + tk_call('registry', 'delete', keynam, valnam) + end + + def get(keynam, valnam) + tk_call('registry', 'get', keynam, valnam) + end + + def keys(keynam, pattern=nil) + lst = tk_split_simplelist(tk_call('registry', 'keys', keynam)) + if pattern + lst.find_all{|key| key =~ pattern} + else + lst + end + end + + def set(keynam, valnam=None, data=None, dattype=None) + tk_call('registry', 'set', keynam, valnam, data, dattype) + end + + def type(keynam, valnam) + tk_call('registry', 'type', keynam, valnam) + end + + def values(keynam, pattern=nil) + lst = tk_split_simplelist(tk_call('registry', 'values', keynam)) + if pattern + lst.find_all{|val| val =~ pattern} + else + lst + end + end + + module_function :delete, :get, :keys, :set, :type, :values +end diff --git a/ext/tk/lib/tk/wm.rb b/ext/tk/lib/tk/wm.rb new file mode 100644 index 0000000000..2467656837 --- /dev/null +++ b/ext/tk/lib/tk/wm.rb @@ -0,0 +1,247 @@ +# +# tk/wm.rb : methods for wm command +# +require 'tk' + +module Tk + module Wm + include TkComm + + TkCommandNames = ['wm'.freeze].freeze + + def aspect(*args) + if args.length == 0 + list(tk_call_without_enc('wm', 'aspect', path)) + else + tk_call('wm', 'aspect', path, *args) + 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) + if args.size == 0 + list(tk_call_without_enc('wm', 'colormapwindows', path)) + else + tk_call_without_enc('wm', 'colormapwindows', path, *args) + self + end + end + def wm_command(value=nil) + if value + tk_call('wm', 'command', path, value) + self + else + #procedure(tk_call('wm', 'command', path)) + tk_call('wm', 'command', path) + end + end + def deiconify(ex = true) + tk_call_without_enc('wm', 'deiconify', path) if ex + self + end + def focusmodel(mode = nil) + if mode + tk_call_without_enc('wm', 'focusmodel', path, mode) + self + else + tk_call_without_enc('wm', 'focusmodel', path) + end + end + def frame + tk_call_without_enc('wm', 'frame', path) + end + def geometry(geom=nil) + if geom + tk_call_without_enc('wm', 'geometry', path, geom) + self + else + tk_call_without_enc('wm', 'geometry', path) + end + end + def wm_grid(*args) + if args.size == 0 + list(tk_call_without_enc('wm', 'grid', path)) + else + tk_call_without_enc('wm', 'grid', path, *args) + self + end + end + def group(leader = nil) + if leader + tk_call('wm', 'group', path, leader) + self + else + window(tk_call('wm', 'group', path)) + end + end + def iconbitmap(bmp=nil) + if bmp + tk_call_without_enc('wm', 'iconbitmap', path, bmp) + self + else + image_obj(tk_call_without_enc('wm', 'iconbitmap', path)) + end + end + def iconify(ex = true) + tk_call_without_enc('wm', 'iconify', path) if ex + self + end + def iconmask(bmp=nil) + if bmp + tk_call_without_enc('wm', 'iconmask', path, bmp) + self + else + image_obj(tk_call_without_enc('wm', 'iconmask', path)) + end + end + def iconname(name=nil) + if name + tk_call('wm', 'iconname', path, name) + self + else + tk_call('wm', 'iconname', path) + end + end + def iconposition(*args) + if args.size == 0 + list(tk_call_without_enc('wm', 'iconposition', path)) + else + tk_call_without_enc('wm', 'iconposition', path, *args) + self + end + end + def iconwindow(win = nil) + if win + tk_call_without_enc('wm', 'iconwindow', path, win) + self + else + w = tk_call_without_enc('wm', 'iconwindow', path) + (w == '')? nil: window(w) + end + end + def maxsize(*args) + if args.size == 0 + list(tk_call_without_enc('wm', 'maxsize', path)) + else + tk_call_without_enc('wm', 'maxsize', path, *args) + self + end + end + def minsize(*args) + if args.size == 0 + list(tk_call_without_enc('wm', 'minsize', path)) + else + tk_call_without_enc('wm', 'minsize', path, *args) + self + end + end + def overrideredirect(bool=None) + if bool == None + bool(tk_call_without_enc('wm', 'overrideredirect', path)) + else + tk_call_without_enc('wm', 'overrideredirect', path, bool) + self + end + end + def positionfrom(who=None) + if who == None + r = tk_call_without_enc('wm', 'positionfrom', path) + (r == "")? nil: r + else + tk_call_without_enc('wm', 'positionfrom', path, who) + self + end + end + def protocol(name=nil, cmd=nil) + if cmd + tk_call_without_enc('wm', 'protocol', path, name, cmd) + self + elsif name + result = tk_call_without_enc('wm', 'protocol', path, name) + (result == "")? nil : tk_tcl2ruby(result) + else + tk_split_simplelist(tk_call_without_enc('wm', 'protocol', path)) + end + end + def resizable(*args) + if args.length == 0 + list(tk_call_without_enc('wm', 'resizable', path)).collect{|e| bool(e)} + else + tk_call_without_enc('wm', 'resizable', path, *args) + self + end + end + def sizefrom(who=None) + if who == None + r = tk_call_without_enc('wm', 'sizefrom', path) + (r == "")? nil: r + else + tk_call_without_enc('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_without_enc('wm', 'state', path, state) + self + else + tk_call_without_enc('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_without_enc('wm', 'transient', path, master) + self + else + window(tk_call_without_enc('wm', 'transient', path)) + end + end + def withdraw(ex = true) + tk_call_without_enc('wm', 'withdraw', path) if ex + self + end + end +end diff --git a/ext/tk/lib/tk/xim.rb b/ext/tk/lib/tk/xim.rb new file mode 100644 index 0000000000..b4dacdc331 --- /dev/null +++ b/ext/tk/lib/tk/xim.rb @@ -0,0 +1,122 @@ +# +# tk/xim.rb : control imput_method +# +require 'tk' + +module TkXIM + include Tk + extend Tk + + TkCommandNames = ['imconfigure'.freeze].freeze + + def TkXIM.useinputmethods(value = None, window = nil) + if value == None + if window + bool(tk_call_without_enc('tk', 'useinputmethods', + '-displayof', window)) + else + bool(tk_call_without_enc('tk', 'useinputmethods')) + end + else + if window + bool(tk_call_without_enc('tk', 'useinputmethods', + '-displayof', window, value)) + else + bool(tk_call_without_enc('tk', 'useinputmethods', value)) + end + end + end + + def TkXIM.useinputmethods_displayof(window, value = None) + TkXIM.useinputmethods(value, window) + end + + def TkXIM.caret(window, keys=nil) + if keys + tk_call_without_enc('tk', 'caret', window, *hash_kv(keys)) + self + else + lst = tk_split_list(tk_call_without_enc('tk', 'caret', window)) + info = {} + while key = lst.shift + info[key[1..-1]] = lst.shift + end + info + end + end + + def TkXIM.configure(window, slot, value=None) + begin + if /^8\.*/ === Tk::TK_VERSION && JAPANIZED_TK + if slot.kind_of? Hash + tk_call('imconfigure', window, *hash_kv(slot)) + else + tk_call('imconfigure', window, "-#{slot}", value) + end + end + rescue + end + end + + def TkXIM.configinfo(window, slot=nil) + if TkComm::GET_CONFIGINFOwoRES_AS_ARRAY + begin + if /^8\.*/ === Tk::TK_VERSION && JAPANIZED_TK + if slot + conf = tk_split_list(tk_call('imconfigure', window, "-#{slot}")) + conf[0] = conf[0][1..-1] + conf + else + tk_split_list(tk_call('imconfigure', window)).collect{|conf| + conf[0] = conf[0][1..-1] + conf + } + end + else + [] + end + rescue + [] + end + else # ! TkComm::GET_CONFIGINFOwoRES_AS_ARRAY + TkXIM.current_configinfo(window, slot) + end + end + + def TkXIM.current_configinfo(window, slot=nil) + begin + if /^8\.*/ === Tk::TK_VERSION && JAPANIZED_TK + if slot + conf = tk_split_list(tk_call('imconfigure', window, "-#{slot}")) + { conf[0][1..-1] => conf[1] } + else + ret = {} + tk_split_list(tk_call('imconfigure', window)).each{|conf| + ret[conf[0][1..-1]] = conf[1] + } + ret + end + else + {} + end + rescue + {} + end + end + + def useinputmethods(value=None) + TkXIM.useinputmethods(value, self) + end + + def caret(keys=nil) + TkXIM.caret(self, keys=nil) + end + + def imconfigure(slot, value=None) + TkXIM.configure(self, slot, value) + end + + def imconfiginfo(slot=nil) + TkXIM.configinfo(self, slot) + end +end diff --git a/ext/tk/lib/tkafter.rb b/ext/tk/lib/tkafter.rb index 53e78b8808..f65945884c 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) - pro |