1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* ext/tk/lib/tk/itemconfig.rb: bug fix on 'itemconfiginfo' method, and

modify to make it easy to override 'itemconfiginfo' method.
* ext/tk/lib/tkextlib/tile/treeview.rb : support Tile 0.7.8.
* ext/tk/lib/tkextlib/version.rb : [new] add Tk::Tkextlib_RELEASE_DATE
  to get the information from scripts.
* ext/tk/lib/tk.rb: load 'tkextlib/version.rb', and update RELEASE_DATE.
* ext/tk/lib/tkextlib/SUPPORT_STATUS: update.
* ext/tk/sample/editable_listbox.rb: [new] the listbox with editable
  items. It's one of the example about usage of Place geometry manager.
* ext/tk/sample/tktextio.rb: improve the functions of TkTextIO class.
  Those are required by 'irbtkw.rbw'.
* ext/tk/sample/irbtkw.rbw: [new] IRB on Ruby/Tk. It doesn't need any
  real console. IRB works on a text widget without I/O blocking. That
  is, thread switching on IRB will work properly, even if on Windows.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11283 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nagai 2006-11-06 06:56:37 +00:00
parent ced53248ff
commit 2ec88c167b
10 changed files with 1692 additions and 206 deletions

View file

@ -1,3 +1,28 @@
Mon Nov 6 15:41:55 2006 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* ext/tk/lib/tk/itemconfig.rb: ext/tk/lib/tk/itemconfig.rb: bug
fix on 'itemconfiginfo' method, and modify to make it easy to
override 'itemconfiginfo' method.
* ext/tk/lib/tkextlib/tile/treeview.rb : support Tile 0.7.8.
* ext/tk/lib/tkextlib/version.rb : [new] add Tk::Tkextlib_RELEASE_DATE
to get the information from scripts.
* ext/tk/lib/tk.rb: load 'tkextlib/version.rb', and update RELEASE_DATE
* ext/tk/lib/tkextlib/SUPPORT_STATUS: update.
* ext/tk/sample/editable_listbox.rb: [new] the listbox with editable
items. It's one of the example about usage of Place geometry manager.
* ext/tk/sample/tktextio.rb: improve the functions of TkTextIO class.
Those are required by 'irbtkw.rbw'.
* ext/tk/sample/irbtkw.rbw: [new] IRB on Ruby/Tk. It doesn't need any
real console. IRB works on a text widget without I/O blocking. That
is, thread switching on IRB will work properly, even if on Windows.
Mon Nov 6 00:42:05 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
* parse.y (arg_dup_check): vid may be nameless internal id.

View file

@ -1,3 +1,11 @@
2006-11-06 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* lib/tkextlib/version.rb: keep release date of tkextlib on
"Tk::Tkextlib_RELEASE_DATE".
* lib/tkextlib/tile/treeview.rb : support Tile 0.7.8.
Now, you can handle tree items as objects.
2006-10-04 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* lib/tkextlib/tile.rb, lib/tkextlib/tile/* : support Tile 0.7.6.

View file

@ -4597,7 +4597,7 @@ end
#Tk.freeze
module Tk
RELEASE_DATE = '2006-09-01'.freeze
RELEASE_DATE = '2006-11-06'.freeze
autoload :AUTO_PATH, 'tk/variable'
autoload :TCL_PACKAGE_PATH, 'tk/variable'
@ -4609,6 +4609,7 @@ end
# call setup script for Tk extension libraries (base configuration)
begin
require 'tkextlib/version.rb'
require 'tkextlib/setup.rb'
rescue LoadError
# ignore

View file

@ -289,7 +289,7 @@ module TkItemConfigMethod
self
end
def itemconfiginfo(tagOrId, slot = nil)
def __itemconfiginfo_core(tagOrId, slot = nil)
if TkComm::GET_CONFIGINFO_AS_ARRAY
if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/)
fontkey = $2
@ -594,7 +594,7 @@ module TkItemConfigMethod
if v.empty?
conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = nil
else
conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = TkVarAccess.new
conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = TkVarAccess.new(v)
end
end
@ -1020,13 +1020,18 @@ module TkItemConfigMethod
end
end
end
private :__itemconfiginfo_core
def itemconfiginfo(tagOrId, slot = nil)
__itemconfiginfo_core(tagOrId, slot)
end
def current_itemconfiginfo(tagOrId, slot = nil)
if TkComm::GET_CONFIGINFO_AS_ARRAY
if slot
org_slot = slot
begin
conf = itemconfiginfo(tagOrId, slot)
conf = __itemconfiginfo_core(tagOrId, slot)
if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \
|| conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 )
return {conf[0] => conf[-1]}
@ -1037,7 +1042,7 @@ module TkItemConfigMethod
"there is a configure alias loop about '#{org_slot}'"
else
ret = {}
itemconfiginfo(tagOrId).each{|conf|
__itemconfiginfo_core(tagOrId).each{|conf|
if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \
|| conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 )
ret[conf[0]] = conf[-1]
@ -1047,7 +1052,7 @@ module TkItemConfigMethod
end
else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
ret = {}
itemconfiginfo(slot).each{|key, conf|
itemconfiginfo(tagOrId, slot).each{|key, conf|
ret[key] = conf[-1] if conf.kind_of?(Array)
}
ret

View file

@ -1,7 +1,7 @@
[ current support status of Tcl/Tk extensions ]
*******<<< RELEASE_DATE of the libraries : 2006/10/04 >>>*******
*** RELEASE_DATE of the libraries => see 'tkextlib/version.rb' ***
The following list shows *CURRENT* status when this file was modifyed
at last. If you want to add other Tcl/Tk extensions to the planed list
@ -83,7 +83,7 @@ BLT 2.4z http://sourceforge.net/projects/blt
TkTreeCtrl CVS/Hd(2005-12-02)
http://sourceforge.net/projects/tktreectrl ==> treectrl
Tile CVS/Hd(2006-10-01)
Tile 0.7.8
http://sourceforge.net/projects/tktable ==> tile

View file

@ -9,10 +9,360 @@ module Tk
module Tile
class Treeview < TkWindow
end
end
end
module TreeviewConfig
module Tk::Tile::TreeviewConfig
include TkItemConfigMethod
def __item_configinfo_struct(id)
# maybe need to override
{:key=>0, :alias=>nil, :db_name=>nil, :db_class=>nil,
:default_value=>nil, :current_value=>1}
end
private :__item_configinfo_struct
def __itemconfiginfo_core(tagOrId, slot = nil)
if TkComm::GET_CONFIGINFO_AS_ARRAY
if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/)
fontkey = $2
return [slot.to_s, tagfontobj(tagid(tagOrId), fontkey)]
else
if slot
slot = slot.to_s
case slot
when /^(#{__tile_specific_item_optkeys(tagid(tagOrId)).join('|')})$/
begin
# On tile-0.7.{2-8}, 'state' options has no '-' at its head.
val = tk_call(*(__item_confinfo_cmd(tagid(tagOrId)) << slot))
rescue
# Maybe, 'state' option has '-' in future.
val = tk_call(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
end
return [slot, val]
when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/
method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[slot]
optval = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
begin
val = method.call(tagOrId, optval)
rescue => e
warn("Warning:: #{e.message} (when #{method}lcall(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG
val = optval
end
return [slot, val]
when /^(#{__item_methodcall_optkeys(tagid(tagOrId)).keys.join('|')})$/
method = _symbolkey2str(__item_methodcall_optkeys(tagid(tagOrId)))[slot]
return [slot, self.__send__(method, tagOrId)]
when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/
begin
val = number(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
rescue
val = nil
end
return [slot, val]
when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/
val = num_or_str(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
return [slot, val]
when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/
begin
val = bool(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
rescue
val = nil
end
return [slot, val]
when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/
val = simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
return [slot, val]
when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/
val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
if val =~ /^[0-9]/
return [slot, list(val)]
else
return [slot, val]
end
when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/
val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
return [slot, val]
when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/
val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
if val.empty?
return [slot, nil]
else
return [slot, TkVarAccess.new(val)]
end
else
val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
if val.index('{')
return [slot, tk_split_list(val)]
else
return [slot, tk_tcl2ruby(val)]
end
end
else # ! slot
ret = Hash[*(tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)))), false, false))].to_a.collect{|conf|
conf[0] = conf[0][1..-1] if conf[0][0] == ?-
case conf[0]
when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/
method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[conf[0]]
optval = conf[1]
begin
val = method.call(tagOrId, optval)
rescue => e
warn("Warning:: #{e.message} (when #{method}.call(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG
val = optval
end
conf[1] = val
when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/
# do nothing
when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/
begin
conf[1] = number(conf[1])
rescue
conf[1] = nil
end
when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/
conf[1] = num_or_str(conf[1])
when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/
begin
conf[1] = bool(conf[1])
rescue
conf[1] = nil
end
when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/
conf[1] = simplelist(conf[1])
when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/
if conf[1] =~ /^[0-9]/
conf[1] = list(conf[1])
end
when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/
if conf[1].empty?
conf[1] = nil
else
conf[1] = TkVarAccess.new(conf[1])
end
else
if conf[1].index('{')
conf[1] = tk_split_list(conf[1])
else
conf[1] = tk_tcl2ruby(conf[1])
end
end
conf
}
__item_font_optkeys(tagid(tagOrId)).each{|optkey|
optkey = optkey.to_s
fontconf = ret.assoc(optkey)
if fontconf
ret.delete_if{|inf| inf[0] =~ /^(|latin|ascii|kanji)#{optkey}$/}
fontconf[1] = tagfontobj(tagid(tagOrId), optkey)
ret.push(fontconf)
end
}
__item_methodcall_optkeys(tagid(tagOrId)).each{|optkey, method|
ret << [optkey.to_s, self.__send__(method, tagOrId)]
}
ret
end
end
else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/)
fontkey = $2
return {slot.to_s => tagfontobj(tagid(tagOrId), fontkey)}
else
if slot
slot = slot.to_s
case slot
when /^(#{__tile_specific_item_optkeys(tagid(tagOrId)).join('|')})$/
begin
# On tile-0.7.{2-8}, 'state' option has no '-' at its head.
val = tk_call(*(__item_confinfo_cmd(tagid(tagOrId)) << slot))
rescue
# Maybe, 'state' option has '-' in future.
val = tk_call(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
end
return {slot => val}
when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/
method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[slot]
optval = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
begin
val = method.call(tagOrId, optval)
rescue => e
warn("Warning:: #{e.message} (when #{method}lcall(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG
val = optval
end
return {slot => val}
when /^(#{__item_methodcall_optkeys(tagid(tagOrId)).keys.join('|')})$/
method = _symbolkey2str(__item_methodcall_optkeys(tagid(tagOrId)))[slot]
return {slot => self.__send__(method, tagOrId)}
when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/
begin
val = number(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
rescue
val = nil
end
return {slot => val}
when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/
val = num_or_str(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
return {slot => val}
when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/
begin
val = bool(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
rescue
val = nil
end
return {slot => val}
when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/
val = simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
return {slot => val}
when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/
val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
if val =~ /^[0-9]/
return {slot => list(val)}
else
return {slot => val}
end
when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/
val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
return {slot => val}
when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/
val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
if val.empty?
return {slot => nil}
else
return {slot => TkVarAccess.new(val)}
end
else
val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
if val.index('{')
return {slot => tk_split_list(val)}
else
return {slot => tk_tcl2ruby(val)}
end
end
else # ! slot
ret = {}
ret = Hash[*(tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)))), false, false))].to_a.collect{|conf|
conf[0] = conf[0][1..-1] if conf[0][0] == ?-
optkey = conf[0]
case optkey
when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/
method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[optkey]
optval = conf[1]
begin
val = method.call(tagOrId, optval)
rescue => e
warn("Warning:: #{e.message} (when #{method}.call(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG
val = optval
end
conf[1] = val
when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/
# do nothing
when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/
begin
conf[1] = number(conf[1])
rescue
conf[1] = nil
end
when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/
conf[1] = num_or_str(conf[1])
when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/
begin
conf[1] = bool(conf[1])
rescue
conf[1] = nil
end
when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/
conf[1] = simplelist(conf[1])
when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/
if conf[1] =~ /^[0-9]/
conf[1] = list(conf[1])
end
when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/
if conf[1].empty?
conf[1] = nil
else
conf[1] = TkVarAccess.new(conf[1])
end
else
if conf[1].index('{')
return [slot, tk_split_list(conf[1])]
else
return [slot, tk_tcl2ruby(conf[1])]
end
end
ret[conf[0]] = conf[1]
}
__item_font_optkeys(tagid(tagOrId)).each{|optkey|
optkey = optkey.to_s
fontconf = ret[optkey]
if fontconf.kind_of?(Array)
ret.delete(optkey)
ret.delete('latin' << optkey)
ret.delete('ascii' << optkey)
ret.delete('kanji' << optkey)
fontconf[1] = tagfontobj(tagid(tagOrId), optkey)
ret[optkey] = fontconf
end
}
__item_methodcall_optkeys(tagid(tagOrId)).each{|optkey, method|
ret[optkey.to_s] = self.__send__(method, tagOrId)
}
ret
end
end
end
end
###################
def __item_cget_cmd(id)
[self.path, id[0], id[1]]
end
@ -29,8 +379,12 @@ module Tk
['width']
when :column, 'column'
super(id[1])
when :tag, 'tag'
super(id[1])
when :heading, 'heading'
super(id[1])
else
super(id[1])
end
end
private :__item_numstrval_optkeys
@ -41,8 +395,12 @@ module Tk
super(id) + ['id']
when :column, 'column'
super(id[1])
when :tag, 'tag'
super(id[1])
when :heading, 'heading'
super(id[1])
else
super(id[1])
end
end
private :__item_strval_optkeys
@ -53,6 +411,8 @@ module Tk
['open']
when :column, 'column'
super(id[1])
when :tag, 'tag'
super(id[1])
when :heading, 'heading'
super(id[1])
end
@ -67,10 +427,83 @@ module Tk
[]
when :heading, 'heading'
[]
else
[]
end
end
private :__item_listval_optkeys
def __item_val2ruby_optkeys(id)
case id[0]
when :item, 'item'
{
'tags'=>proc{|arg_id, val|
simplelist(val).collect{|tag|
Tk::Tile::Treeview::Tag.id2obj(self, tag)
}
}
}
when :column, 'column'
{}
when :heading, 'heading'
{}
else
{}
end
end
private :__item_val2ruby_optkeys
def __tile_specific_item_optkeys(id)
case id[0]
when :item, 'item'
[]
when :column, 'column'
[]
when :heading, 'heading'
['state'] # On tile-0.7.{2-8}, 'state' options has no '-' at its head.
else
[]
end
end
private :__item_val2ruby_optkeys
def itemconfiginfo(tagOrId, slot = nil)
__itemconfiginfo_core(tagOrId, slot)
end
def current_itemconfiginfo(tagOrId, slot = nil)
if TkComm::GET_CONFIGINFO_AS_ARRAY
if slot
org_slot = slot
begin
conf = __itemconfiginfo_core(tagOrId, slot)
if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \
|| conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 )
return {conf[0] => conf[-1]}
end
slot = conf[__item_configinfo_struct(tagid(tagOrId))[:alias]]
end while(org_slot != slot)
fail RuntimeError,
"there is a configure alias loop about '#{org_slot}'"
else
ret = {}
__itemconfiginfo_core(tagOrId).each{|conf|
if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \
|| conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 )
ret[conf[0]] = conf[-1]
end
}
ret
end
else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
ret = {}
itemconfiginfo(tagOrId, slot).each{|key, conf|
ret[key] = conf[-1] if conf.kind_of?(Array)
}
ret
end
end
alias __itemcget itemcget
alias __itemconfigure itemconfigure
alias __itemconfiginfo itemconfiginfo
@ -113,11 +546,40 @@ module Tk
# Treeview Heading
def headingcget(tagOrId, option)
if __tile_specific_item_optkeys([:heading, tagOrId]).index(option.to_s)
begin
# On tile-0.7.{2-8}, 'state' options has no '-' at its head.
tk_call(*(__item_cget_cmd([:heading, tagOrId]) << option.to_s))
rescue
# Maybe, 'state' option has '-' in future.
tk_call(*(__item_cget_cmd([:heading, tagOrId]) << "-#{option}"))
end
else
__itemcget([:heading, tagOrId], option)
end
end
def headingconfigure(tagOrId, slot, value=None)
if slot.kind_of?(Hash)
slot = _symbolkey2str(slot)
sp_kv = []
__tile_specific_item_optkeys([:heading, tagOrId]).each{|k|
sp_kv << k << _get_eval_string(slot.delete(k)) if slot.has_key?(k)
}
tk_call(*(__item_config_cmd([:heading, tagOrId]).concat(sp_kv)))
tk_call(*(__item_config_cmd([:heading, tagOrId]).concat(hash_kv(slot))))
elsif __tile_specific_item_optkeys([:heading, tagOrId]).index(slot.to_s)
begin
# On tile-0.7.{2-8}, 'state' options has no '-' at its head.
tk_call(*(__item_cget_cmd([:heading, tagOrId]) << slot.to_s << value))
rescue
# Maybe, 'state' option has '-' in future.
tk_call(*(__item_cget_cmd([:heading, tagOrId]) << "-#{slot}" << value))
end
else
__itemconfigure([:heading, tagOrId], slot, value)
end
self
end
def headingconfiginfo(tagOrId, slot=nil)
__itemconfiginfo([:heading, tagOrId], slot)
end
@ -128,10 +590,317 @@ module Tk
alias heading_configure headingconfigure
alias heading_configinfo headingconfiginfo
alias current_heading_configinfo current_headingconfiginfo
# Treeview Tag
def tagcget(tagOrId, option)
__itemcget([:tag, tagOrId], option)
end
def tagconfigure(tagOrId, slot, value=None)
__itemconfigure([:tag, tagOrId], slot, value)
end
def tagconfiginfo(tagOrId, slot=nil)
__itemconfiginfo([:tag, tagOrId], slot)
end
def current_tagconfiginfo(tagOrId, slot=nil)
__current_itemconfiginfo([:tag, tagOrId], slot)
end
alias tag_cget tagcget
alias tag_configure tagconfigure
alias tag_configinfo tagconfiginfo
alias current_tag_configinfo current_tagconfiginfo
end
########################
class Tk::Tile::Treeview::Item < TkObject
ItemID_TBL = TkCore::INTERP.create_table
TkCore::INTERP.init_ip_env{ Tk::Tile::Treeview::Item::ItemID_TBL.clear }
def self.id2obj(tree, id)
tpath = tree.path
return id unless Tk::Tile::Treeview::Item::ItemID_TBL[tpath]
(Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id])? \
Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id]: id
end
def self.assign(tree, id)
tpath = tree.path
if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] &&
Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id]
return Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id]
end
obj = self.allocate
obj.instance_eval{
@parent = @t = tree
@tpath = tpath
@path = @id = id
}
ItemID_TBL[tpath] = {} unless ItemID_TBL[tpath]
Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] = obj
obj
end
def _insert_item(tree, parent_item, idx, keys={})
keys = _symbolkey2str(keys)
id = keys.delete('id')
if id
num_or_str(tk_call(tree, 'insert',
parent_item, idx, '-id', id, *hash_kv(keys)))
else
num_or_str(tk_call(tree, 'insert', parent_item, idx, *hash_kv(keys)))
end
end
private :_insert_item
def initialize(tree, parent_item = '', idx = 'end', keys = {})
if parent_item.kind_of?(Hash)
keys = parent_item
idx = 'end'
parent_item = ''
elsif idx.kind_of?(Hash)
keys = idx
idx = 'end'
end
@parent = @t = tree
@tpath = tree.path
@path = @id = _insert_item(@t, parent_item, idx, keys)
ItemID_TBL[@tpath] = {} unless ItemID_TBL[@tpath]
ItemID_TBL[@tpath][@id] = self
end
def id
@id
end
def cget(option)
@t.itemcget(@id, option)
end
def configure(key, value=None)
@t.itemconfigure(@id, key, value)
self
end
def configinfo(key=nil)
@t.itemconfiginfo(@id, key)
end
def current_configinfo(key=nil)
@t.current_itemconfiginfo(@id, key)
end
def open?
cget('open')
end
def open
configure('open', true)
self
end
def close
configure('open', false)
self
end
def bbox(column=None)
@t.bbox(@id, column)
end
def children
@t.children(@id)
end
def set_children(*items)
@t.set_children(@id, *items)
self
end
def delete
@t.delete(@id)
self
end
def detach
@t.detach(@id)
self
end
def exist?
@t.exist?(@id)
end
def focus
@t.focus_item(@id)
end
def index
@t.index(@id)
end
def insert(idx='end', keys={})
@t.insert(@id, idx, keys)
end
def move(parent, idx)
@t.move(@id, parent, idx)
self
end
def next_item
@t.next_item(@id)
end
def parent_item
@t.parent_item(@id)
end
def prev_item
@t.prev_item(@id)
end
def see
@t.see(@id)
self
end
def selection_add
@t.selection_add(@id)
self
end
def selection_remove
@t.selection_remove(@id)
self
end
def selection_set
@t.selection_set(@id)
self
end
def selection_toggle
@t.selection_toggle(@id)
self
end
def get_directory
@t.get_directory(@id)
end
alias get_dictionary get_directory
def get(col)
@t.get(@id, col)
end
def set(col, value)
@t.set(@id, col, value)
end
end
########################
class Tk::Tile::Treeview::Root < Tk::Tile::Treeview::Item
def self.new(tree, keys = {})
tpath = tree.path
if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] &&
Tk::Tile::Treeview::Item::ItemID_TBL[tpath]['']
Tk::Tile::Treeview::Item::ItemID_TBL[tpath]['']
else
super(tree, keys)
end
end
def initialize(tree, keys = {})
@parent = @t = tree
@tpath = tree.path
@path = @id = ''
unless Tk::Tile::Treeview::Item::ItemID_TBL[@tpath]
Tk::Tile::Treeview::Item::ItemID_TBL[@tpath] = {}
end
Tk::Tile::Treeview::Item::ItemID_TBL[@tpath][@id] = self
end
end
########################
class Tk::Tile::Treeview::Tag < TkObject
include TkTreatTagFont
TagID_TBL = TkCore::INTERP.create_table
Tag_ID = ['tile_treeview_tag'.freeze, '00000'.taint].freeze
TkCore::INTERP.init_ip_env{ Tk::Tile::Treeview::Tag::TagID_TBL.clear }
def self.id2obj(tree, id)
tpath = tree.path
return id unless Tk::Tile::Treeview::Tag::TagID_TBL[tpath]
(Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id])? \
Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id]: id
end
def initialize(tree, keys=nil)
@parent = @t = tree
@tpath = tree.path
@path = @id = Tag_ID.join(TkCore::INTERP._ip_id_)
TagID_TBL[@tpath] = {} unless TagID_TBL[@tpath]
TagID_TBL[@tpath][@id] = self
Tag_ID[1].succ!
if keys && keys != None
tk_call_without_enc(@tpath, 'tag', 'configure', *hash_kv(keys, true))
end
end
def id
@id
end
def bind(seq, *args)
if TkComm._callback_entry?(args[0]) || !block_given?
cmd = args.shift
else
cmd = Proc.new
end
@t.tag_bind(@id, seq, cmd, *args)
self
end
def bind_append(seq, *args)
if TkComm._callback_entry?(args[0]) || !block_given?
cmd = args.shift
else
cmd = Proc.new
end
@t.tag_bind_append(@id, seq, cmd, *args)
self
end
def bind_remove(seq)
@t.tag_bind_remove(@id, seq)
self
end
def bindinfo(seq=nil)
@t.tag_bindinfo(@id, seq)
end
def cget(option)
@t.tagcget(@id, option)
end
def configure(key, value=None)
@t.tagconfigure(@id, key, value)
self
end
def configinfo(key=nil)
@t.tagconfiginfo(@id, key)
end
def current_configinfo(key=nil)
@t.current_tagconfiginfo(@id, key)
end
end
########################
class Tk::Tile::Treeview < TkWindow
include Tk::Tile::TileWidget
include Scrollable
@ -146,24 +915,38 @@ class Tk::Tile::Treeview < TkWindow
WidgetClassName = 'Treeview'.freeze
WidgetClassNames[WidgetClassName] = self
def __destroy_hook__
Tk::Tile::Treeview::Item::ItemID_TBL.delete(@path)
Tk::Tile::Treeview::Tag::ItemID_TBL.delete(@path)
end
def self.style(*args)
[self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.')
end
def tagid(id)
if id.kind_of?(Array)
if id.kind_of?(Tk::Tile::Treeview::Item) ||
id.kind_of?(Tk::Tile::Treeview::Tag)
id.id
elsif id.kind_of?(Array)
[id[0], _get_eval_string(id[1])]
else
_get_eval_string(id)
end
end
def root
Tk::Tile::Treeview::Root.new(self)
end
def bbox(item, column=None)
list(tk_send('item', 'bbox', item, column))
end
def children(item)
simplelist(tk_send_without_enc('children', item))
simplelist(tk_send_without_enc('children', item)).collect{|id|
Tk::Tile::Treeview::Item.id2obj(self, id)
}
end
def set_children(item, *items)
tk_send_without_enc('children', item,
@ -185,21 +968,33 @@ class Tk::Tile::Treeview < TkWindow
bool(tk_send_without_enc('exists', _get_eval_enc_str(item)))
end
def focus_item(item = None)
def focus_item(item = nil)
if item
tk_send('focus', item)
item
else
id = tk_send('focus')
(id.empty?)? nil: Tk::Tile::Treeview::Item.id2obj(self, id)
end
end
def identify(x, y)
# tile-0.7.2 or previous
ret = simplelist(tk_send('identify', x, y))
case ret[0]
when 'heading', 'separator', 'cell'
when 'heading', 'separator'
ret[-1] = num_or_str(ret[-1])
when 'cell'
ret[1] = Tk::Tile::Treeview::Item.id2obj(self, ret[1])
ret[-1] = num_or_str(ret[-1])
when 'item', 'row'
ret[1] = Tk::Tile::Treeview::Item.id2obj(self, ret[1])
end
end
def row_identify(x, y)
tk_send('identify', 'row', x, y)
id = tk_send('identify', 'row', x, y)
(id.empty?)? nil: Tk::Tile::Treeview::Item.id2obj(self, id)
end
def column_identify(x, y)
@ -210,38 +1005,47 @@ class Tk::Tile::Treeview < TkWindow
number(tk_send('index', item))
end
def insert(parent, idx, keys={})
keys = _symbolkey2str(keys)
id = keys.delete('id')
if id
num_or_str(tk_send('insert', parent, idx, '-id', id, *hash_kv(keys)))
else
num_or_str(tk_send('insert', parent, idx, *hash_kv(keys)))
end
# def insert(parent, idx='end', keys={})
# keys = _symbolkey2str(keys)
# id = keys.delete('id')
# if id
# num_or_str(tk_send('insert', parent, idx, '-id', id, *hash_kv(keys)))
# else
# num_or_str(tk_send('insert', parent, idx, *hash_kv(keys)))
# end
# end
def insert(parent, idx='end', keys={})
Tk::Tile::Treeview::Item.new(self, parent, idx, keys)
end
def instate(spec, cmd=Proc.new)
tk_send('instate', spec, cmd)
end
def state(spec=None)
tk_send('state', spec)
end
# def instate(spec, cmd=Proc.new)
# tk_send('instate', spec, cmd)
# end
# def state(spec=None)
# tk_send('state', spec)
# end
def move(item, parent, idx)
tk_send('move', item, parent, idx)
self
end
def next(item)
tk_send('next', item)
def next_item(item)
id = tk_send('next', item)
(id.empty?)? nil: Tk::Tile::Treeview::Item.id2obj(self, id)
end
def parent(item)
tk_send('parent', item)
def parent_item(item)
if (id = tk_send('parent', item)).empty?
Tk::Tile::Treeview::Root.new(self)
else
Tk::Tile::Treeview::Item.id2obj(self, id)
end
end
def prev(item)
tk_send('prev', item)
def prev_item(item)
id = tk_send('prev', item)
(id.empty?)? nil: Tk::Tile::Treeview::Item.id2obj(self, id)
end
def see(item)
@ -250,7 +1054,9 @@ class Tk::Tile::Treeview < TkWindow
end
def selection
simplelist(tk_send('selection'))
simplelist(tk_send('selection')).collect{|id|
Tk::Tile::Treeview::Item.id2obj(self, id)
}
end
alias selection_get selection

View file

@ -0,0 +1,6 @@
#
# release date of tkextlib
#
module Tk
Tkextlib_RELEASE_DATE = '2006-11-06'.freeze
end

View file

@ -0,0 +1,69 @@
#
# Editable_TkListbox class
#
# When "DoubleClick-1" on a listbox item, the entry box is opend on the
# item. And when hit "Return" key on the entry box after modifying the
# text, the entry box is closed and the item is changed. Or when hit
# "Escape" key, the entry box is closed without modification.
#
# by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
#
require 'tk'
class Editable_TkListbox < TkListbox
def _ebox_placer(coord_y)
idx = self.nearest(coord_y)
x, y, w, h = self.bbox(idx)
@ebox.place(:x => 0, :relwidth => 1.0,
:y => y - self.selectborderwidth,
:height => h + 2 * self.selectborderwidth)
@ebox.pos = idx
@ebox.value = self.listvariable.list[idx]
@ebox.focus
end
private :_ebox_placer
def create_self(keys)
super(keys)
unless self.listvariable
self.listvariable = TkVariable.new(self.get(0, :end))
end
@ebox = TkEntry.new(self){
@pos = -1
def self.pos; @pos; end
def self.pos=(idx); @pos = idx; end
}
@ebox.bind('Return'){
list = self.listvariable.list
list[@ebox.pos] = @ebox.value
self.listvariable.value = list
@ebox.place_forget
@ebox.pos = -1
}
@ebox.bind('Escape'){
@ebox.place_forget
@ebox.pos = -1
}
self.bind('Double-1', '%y'){|y| _ebox_placer(y) }
end
end
if $0 == __FILE__
scr = TkScrollbar.new.pack(:side=>:right, :fill=>:y)
lbox1 = Editable_TkListbox.new.pack(:side=>:left)
lbox2 = Editable_TkListbox.new.pack(:side=>:left)
scr.assign(lbox1, lbox2)
lbox1.insert(:end, *%w(a b c d e f g h i j k l m n))
lbox2.insert(:end, 0,1,2,3,4,5,6,7,8,9,0,1,2,3)
Tk.mainloop
end

119
ext/tk/sample/irbtkw.rbw Normal file
View file

@ -0,0 +1,119 @@
#!/usr/bin/env ruby
#
# irbtkw.rb : IRB console with Ruby/Tk
#
# by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
#
release = '2006/11/06'
require 'tk'
begin
require 'tktextio'
rescue LoadError
require File.join(File.dirname(File.expand_path(__FILE__)), 'tktextio.rb')
end
require 'irb'
# console setup
top = TkToplevel.new(:title=>'IRB console')
top.protocol(:WM_DELETE_WINDOW){ Tk.exit }
console = TkTextIO.new(top, :mode=>:console,
:width=>80).pack(:side=>:left,
:expand=>true, :fill=>:both)
console.yscrollbar(TkScrollbar.new(top, :width=>10).pack(:before=>console,
:side=>:right,
:expand=>false,
:fill=>:y))
ev_loop = Thread.new{Tk.mainloop}
# window position control
root = Tk.root
r_x = root.winfo_rootx
r_y = root.winfo_rooty
r_w = root.winfo_width
t_x = top.winfo_rootx
t_y = top.winfo_rooty
t_w = top.winfo_width
delta = 10
ratio = 0.8
s_w = (ratio * root.winfo_screenwidth).to_i
if r_x < t_x
r_x, t_x = t_x, r_x
end
if t_x + t_w + r_w + delta < s_w
r_x = t_x + t_w + delta
elsif t_w + r_w + delta < s_w
r_x = s_w - r_w
t_x = r_x - t_w
else
r_x = s_w - r_w
t_x = 0
end
root.geometry("+#{r_x}+#{r_y}")
top.geometry("+#{t_x}+#{t_y}")
root.raise
console.focus
# I/O setup
$stdin = console
$stdout = console
$stderr = console
# dummy for rubyw.exe on Windows
def STDIN.tty?
true
end
# IRB setup
IRB.init_config(nil)
IRB.conf[:USE_READLINE] = false
IRB.init_error
irb = IRB::Irb.new
IRB.conf[:MAIN_CONTEXT] = irb.context
class IRB::StdioInputMethod
def gets
prompt = "\n" << @prompt
$stdin.instance_eval{
flush
@prompt = prompt
_set_console_line
@prompt = nil
_see_pos
}
@line[@line_no += 1] = $stdin.gets
end
end
# IRB start
$stdout.print("*** IRB console on Ruby/Tk (#{release}) ")
irb_thread = Thread.new{
catch(:IRB_EXIT){
loop {
begin
irb.eval_input
rescue Exception
end
}
}
}
console.bind('Control-c'){
console.insert('end', "^C\n")
irb_thread.raise RubyLex::TerminateLineInput
}
irb_thread.join
# exit
Tk.exit

View file

@ -1,7 +1,7 @@
#!/usr/bin/env ruby
#
# sample class of handling I/O stream on a TkText widget
# by Hidetoshi NAGAI
# TkTextIO class :: handling I/O stream on a TkText widget
# by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
#
# NOTE: TkTextIO supports 'character' (not 'byte') access only.
# So, for example, TkTextIO#getc returns a character, TkTextIO#pos
@ -14,68 +14,375 @@
# TkTextIO.
#
require 'tk'
require 'tk/text'
require 'tk/textmark'
require 'thread'
class TkTextIO < TkText
def create_self(keys)
mode = nil
ovwt = false
text = nil
wrap = 'char'
show = :pos
# keep safe level
@@create_queues = proc{ [Queue.new, Mutex.new, Queue.new, Mutex.new] }
if keys.kind_of?(Hash)
mode = keys.delete('mode')
ovwt = keys.delete('overwrite')
text = keys.delete('text')
show = keys.delete('show') if keys.has_key?('show')
wrap = keys.delete('wrap') || 'char'
end
OPT_DEFAULTS = {
'mode' => nil,
'overwrite' => false,
'text' => nil,
'show' => :pos,
'wrap' => 'char',
'sync' => true,
'prompt' => nil,
'prompt_cmd' => nil,
'hist_size' => 1000,
}
def create_self(keys)
opts = _get_io_params((keys.kind_of?(Hash))? keys: {})
super(keys)
self['wrap'] = wrap
insert('1.0', text)
@count_var = TkVariable.new
@write_buffer = ''
@read_buffer = ''
@buf_size = 0
@buf_max = 1024
@write_buf_queue, @write_buf_mutex,
@read_buf_queue, @read_buf_mutex = @@create_queues.call
@idle_flush = TkTimer.new(:idle, 1, proc{ @flusher.run rescue nil })
@timer_flush = TkTimer.new(250, -1, proc{ @flusher.run rescue nil })
@flusher = Thread.new{ loop { Thread.stop; flush() } }
@receiver = Thread.new{
begin
loop {
str = @write_buf_queue.deq
@write_buf_mutex.synchronize { @write_buffer << str }
@idle_flush.start
}
ensure
@flusher.kill
end
}
@timer_flush.start
_setup_io(opts)
end
private :create_self
def destroy
@flusher.kill rescue nil
@idle_flush.stop rescue nil
@timer_flush.stop rescue nil
@receiver.kill rescue nil
super()
end
####################################
def _get_io_params(keys)
opts = {}
self.class.const_get(:OPT_DEFAULTS).each{|k, v|
if keys.has_key?(k)
opts[k] = keys.delete(k)
else
opts[k] = v
end
}
opts
end
def _setup_io(opts)
unless defined? @txtpos
@txtpos = TkTextMark.new(self, '1.0')
else
@txtpos.set('1.0')
end
@txtpos.gravity = :left
self.show_mode = show
@sync = true
@overwrite = (ovwt)? true: false
@lineno = 0
@line_offset = 0
@count_var = TkVariable.new
@hist_max = opts['hist_size']
@hist_index = 0
@history = Array.new(@hist_max)
@history[0] = ''
self['wrap'] = wrap
self.show_mode = opts['show']
self.value = opts['text'] if opts['text']
@overwrite = (opts['overwrite'])? true: false
@sync = opts['sync']
@prompt = opts['prompt']
@prompt_cmd = opts['prompt_cmd']
@open = {:r => true, :w => true} # default is 'r+'
case mode
when 'r'
@console_mode = false
@end_of_stream = false
@console_buffer = nil
case opts['mode']
when nil
# do nothing
when :console, 'console'
@console_mode = true
# @console_buffer = TkTextIO.new(:mode=>'r')
@console_buffer = self.class.new(:mode=>'r')
self.show_mode = :insert
when 'r', 'rb'
@open[:r] = true; @open[:w] = nil
when 'r+'
when 'r+', 'rb+', 'r+b'
@open[:r] = true; @open[:w] = true
when 'w'
when 'w', 'wb'
@open[:r] = nil; @open[:w] = true
self.value=''
when 'w+'
when 'w+', 'wb+', 'w+b'
@open[:r] = true; @open[:w] = true
self.value=''
when 'a'
when 'a', 'ab'
@open[:r] = nil; @open[:w] = true
@txtpos = TkTextMark.new(self, 'end - 1 char')
@txtpos.set('end - 1 char')
@txtpos.gravity = :right
when 'a+'
when 'a+', 'ab+', 'a+b'
@open[:r] = true; @open[:w] = true
@txtpos = TkTextMark.new(self, 'end - 1 char')
@txtpos.set('end - 1 char')
@txtpos.gravity = :right
else
fail ArgumentError, "unknown mode `#{opts['mode']}'"
end
unless defined? @ins_head
@ins_head = TkTextMark.new(self, 'insert')
@ins_head.gravity = :left
end
unless defined? @ins_tail
@ins_tail = TkTextMark.new(self, 'insert')
@ins_tail.gravity = :right
end
unless defined? @tmp_mark
@tmp_mark = TkTextMark.new(self, 'insert')
@tmp_mark.gravity = :left
end
if @console_mode
_set_console_line
_setup_console_bindings
end
end
private :_get_io_params, :_setup_io
def _set_console_line
@tmp_mark.set(@ins_tail)
mark_set('insert', 'end')
prompt = ''
prompt << @prompt_cmd.call if @prompt_cmd
prompt << @prompt if @prompt
insert(@tmp_mark, prompt)
@ins_head.set(@ins_tail)
@ins_tail.set('insert')
@txtpos.set(@tmp_mark)
_see_pos
end
def _replace_console_line(str)
self.delete(@ins_head, @ins_tail)
self.insert(@ins_head, str)
end
def _get_console_line
@tmp_mark.set(@ins_tail)
s = self.get(@ins_head, @tmp_mark)
_set_console_line
s
end
private :_set_console_line, :_replace_console_line, :_get_console_line
def _cb_up
@history[@hist_index].replace(self.get(@ins_head, @ins_tail))
@hist_index += 1
@hist_index -= 1 if @hist_index >= @hist_max || !@history[@hist_index]
_replace_console_line(@history[@hist_index]) if @history[@hist_index]
Tk.callback_break
end
def _cb_down
@history[@hist_index].replace(self.get(@ins_head, @ins_tail))
@hist_index -= 1
@hist_index = 0 if @hist_index < 0
_replace_console_line(@history[@hist_index]) if @history[@hist_index]
Tk.callback_break
end
def _cb_left
if @console_mode && compare('insert', '<=', @ins_head)
mark_set('insert', @ins_head)
Tk.callback_break
end
end
def _cb_backspace
if @console_mode && compare('insert', '<=', @ins_head)
Tk.callback_break
end
end
def _cb_ctrl_a
if @console_mode
mark_set('insert', @ins_head)
Tk.callback_break
end
end
private :_cb_up, :_cb_down, :_cb_left, :_cb_backspace, :_cb_ctrl_a
def _setup_console_bindings
@bindtag = TkBindTag.new
tags = self.bindtags
tags[tags.index(self)+1, 0] = @bindtag
self.bindtags = tags
@bindtag.bind('Return'){
insert('end - 1 char', "\n")
if (str = _get_console_line)
@read_buf_queue.push(str)
@history[0].replace(str.chomp)
@history.pop
@history.unshift('')
@hist_index = 0
end
Tk.update
Tk.callback_break
}
@bindtag.bind('Alt-Return'){
Tk.callback_continue
}
@bindtag.bind('FocusIn'){
if @console_mode
mark_set('insert', @ins_tail)
Tk.callback_break
end
}
ins_mark = TkTextMark.new(self, 'insert')
@bindtag.bind('ButtonPress'){
if @console_mode
ins_mark.set('insert')
end
}
@bindtag.bind('ButtonRelease-1'){
if @console_mode && compare('insert', '<=', @ins_head)
mark_set('insert', ins_mark)
Tk.callback_break
end
}
@bindtag.bind('ButtonRelease-2', '%x %y'){|x, y|
if @console_mode
# paste a text at 'insert' only
x1, y1, x2, y2 = bbox(ins_mark)
unless x == x1 && y == y1
Tk.event_generate(self, 'ButtonRelease-2', :x=>x1, :y=>y1)
Tk.callback_break
end
end
}
@bindtag.bind('Up'){ _cb_up }
@bindtag.bind('Control-p'){ _cb_up }
@bindtag.bind('Down'){ _cb_down }
@bindtag.bind('Control-n'){ _cb_down }
@bindtag.bind('Left'){ _cb_left }
@bindtag.bind('Control-b'){ _cb_left }
@bindtag.bind('BackSpace'){ _cb_backspace }
@bindtag.bind('Control-h'){ _cb_backspace }
@bindtag.bind('Home'){ _cb_ctrl_a }
@bindtag.bind('Control-a'){ _cb_ctrl_a }
end
private :_setup_console_bindings
def _block_read(size = nil, ret = '', block_mode = true)
return '' if size == 0
return nil if ! @read_buf_queue && @read_buffer.empty?
ret = '' unless ret.kind_of?(String)
ret.replace('') unless ret.empty?
if block_mode == nil # partial
if @read_buffer.empty?
ret << @read_buffer.slice!(0..-1)
return ret
end
end
if size.kind_of?(Numeric)
loop{
@read_buf_mutex.synchronize {
buf_len = @read_buffer.length
if buf_len >= size
ret << @read_buffer.slice!(0, size)
return ret
else
ret << @read_buffer.slice!(0..-1)
size -= buf_len
return ret unless @read_buf_queue
end
}
@read_buffer << @read_buf_queue.pop
}
else # readline
rs = (size)? size: $/
rs = rs.to_s if rs.kind_of?(Regexp)
loop{
@read_buf_mutex.synchronize {
if (str = @read_buffer.slice!(/\A(.*)(#{rs})/m))
ret << str
return ret
else
ret << @read_buffer.slice!(0..-1)
return ret unless @read_buf_queue
end
}
@read_buffer << @read_buf_queue.pop
}
end
end
def _block_write
###### currently, not support
end
private :_block_read, :_block_write
####################################
def <<(obj)
_write(obj)
@ -107,14 +414,15 @@ class TkTextIO < TkText
nil
end
def closed?
close_read? && close_write?
end
def closed_read?
def closed?(dir=nil)
case dir
when :r, 'r'
!@open[:r]
end
def closed_write?
when :w, 'w'
!@open[:w]
else
!@open[:r] && !@open[:w]
end
end
def _check_readable
@ -129,7 +437,7 @@ class TkTextIO < TkText
def each_line(rs = $/)
_check_readable
while(s = gets)
while(s = self.gets(rs))
yield(s)
end
self
@ -138,7 +446,7 @@ class TkTextIO < TkText
def each_char
_check_readable
while(c = getc)
while(c = self.getc)
yield(c)
end
self
@ -151,7 +459,7 @@ class TkTextIO < TkText
alias eof eof?
def fcntl(*args)
fail NotImplementedError, 'fcntl is not implemented on TkTextIO'
fail NotImplementedError, "fcntl is not implemented on #{self.class}"
end
def fsync
@ -163,11 +471,19 @@ class TkTextIO < TkText
end
def flush
Tk.update if @open[:w] && @sync
Thread.pass
if @open[:w] || ! @write_buffer.empty?
@write_buf_mutex.synchronize {
_sync_write_buf(@write_buffer)
@write_buffer[0..-1] = ''
}
end
self
end
def getc
return _block_read(1) if @console_mode
_check_readable
return nil if eof?
c = get(@txtpos)
@ -177,6 +493,8 @@ class TkTextIO < TkText
end
def gets(rs = $/)
return _block_read(rs) if @console_mode
_check_readable
return nil if eof?
_readline(rs)
@ -233,7 +551,6 @@ class TkTextIO < TkText
alias tell pos
def pos=(idx)
# @txtpos.set((idx.kind_of?(Numeric))? "1.0 + #{idx} char": idx)
seek(idx, IO::SEEK_SET)
idx
end
@ -306,6 +623,8 @@ class TkTextIO < TkText
private :_read
def read(len=nil, buf=nil)
return _block_read(len, buf) if @console_mode
_check_readable
if len
return "" if len == 0
@ -321,6 +640,8 @@ class TkTextIO < TkText
end
def readchar
return _block_read(1) if @console_mode
_check_readable
fail EOFError if eof?
c = get(@txtpos)
@ -334,6 +655,7 @@ class TkTextIO < TkText
s = get(@txtpos, 'end - 1 char')
@txtpos.set('end - 1 char')
elsif rs == ''
@count_var.value # make it global
idx = tksearch_with_count([:regexp], @count_var,
"\n(\n)+", @txtpos, 'end - 1 char')
if idx
@ -345,6 +667,7 @@ class TkTextIO < TkText
@txtpos.set('end - 1 char')
end
else
@count_var.value # make it global
idx = tksearch_with_count(@count_var, rs, @txtpos, 'end - 1 char')
if idx
s = get(@txtpos, "#{idx} + #{@count_var.value} char")
@ -363,12 +686,22 @@ class TkTextIO < TkText
private :_readline
def readline(rs = $/)
return _block_readline(rs) if @console_mode
_check_readable
fail EOFError if eof?
_readline(rs)
end
def readlines(rs = $/)
if @console_mode
lines = []
while (line = _block_readline(rs))
lines << line
end
return lines
end
_check_readable
lines = []
until(eof?)
@ -379,7 +712,11 @@ class TkTextIO < TkText
end
def readpartial(maxlen, buf=nil)
#return @console_buffer.readpartial(maxlen, buf) if @console_mode
return _block_read(maxlen, buf, nil) if @console_mode
_check_readable
fail EOFError if eof?
s = _read(maxlen)
buf.replace(s) if buf.kind_of?(String)
s
@ -471,6 +808,8 @@ class TkTextIO < TkText
end
def sysread(len, buf=nil)
return _block_read(len, buf) if @console_mode
_check_readable
fail EOFError if eof?
s = _read(len)
@ -492,6 +831,13 @@ class TkTextIO < TkText
end
def ungetc(c)
if @console_mode
@read_buf_mutex.synchronize {
@read_buffer[0,0] = c.chr
}
return nil
end
_check_readable
c = c.chr if c.kind_of?(Fixnum)
if compare(@txtpos, '>', '1.0')
@ -506,8 +852,10 @@ class TkTextIO < TkText
nil
end
=begin
def _write(obj)
s = _get_eval_string(obj)
#s = _get_eval_string(obj)
s = (obj.kind_of?(String))? obj: obj.to_s
n = number(tk_call('string', 'length', s))
delete(@txtpos, @txtpos + "#{n} char") if @overwrite
self.insert(@txtpos, s)
@ -518,6 +866,37 @@ class TkTextIO < TkText
n
end
private :_write
=end
#=begin
def _sync_write_buf(s)
if (n = number(tk_call('string', 'length', s))) > 0
delete(@txtpos, @txtpos + "#{n} char") if @overwrite
self.insert(@txtpos, s)
#Tk.update
@txtpos.set(@txtpos + "#{n} char")
@txtpos.set('end - 1 char') if compare(@txtpos, '>=', :end)
@ins_head.set(@txtpos) if compare(@txtpos, '>', @ins_head)
_see_pos
end
self
end
private :_sync_write_buf
def _write(obj)
s = (obj.kind_of?(String))? obj: obj.to_s
n = number(tk_call('string', 'length', s))
@write_buf_queue.enq(s)
if @sync
Thread.pass
Tk.update
end
n
end
private :_write
#=end
def write(obj)
_check_writable
@ -529,13 +908,19 @@ end
# TEST
####################
if __FILE__ == $0
ev_loop = Thread.new{Tk.mainloop}
f = TkFrame.new.pack
tio = TkTextIO.new(f, :show=>:pos,
#tio = TkTextIO.new(f, :show=>:nil,
#tio = TkTextIO.new(f, :show=>:pos,
tio = TkTextIO.new(f, :show=>:insert,
:text=>">>> This is an initial text line. <<<\n\n"){
yscrollbar(TkScrollbar.new(f).pack(:side=>:right, :fill=>:y))
# yscrollbar(TkScrollbar.new(f).pack(:side=>:right, :fill=>:y))
pack(:side=>:left, :fill=>:both, :expand=>true)
}
Tk.update
$stdin = tio
$stdout = tio
$stderr = tio
@ -599,5 +984,67 @@ if __FILE__ == $0
tio.seek(0, IO::SEEK_END)
Tk.mainloop
STDOUT.print("tio.sync == #{tio.sync}\n")
# tio.sync = false
# STDOUT.print("tio.sync == #{tio.sync}\n")
(0..10).each{|i|
STDOUT.print("#{i}\n")
s = ''
(0..1000).each{ s << '*' }
print(s)
}
print("\n")
print("\n=========================================================\n\n")
s = ''
timer = TkTimer.new(:idle, -1, proc{
#STDOUT.print("idle call\n")
unless s.empty?
print(s)
s = ''
end
}).start
(0..10).each{|i|
STDOUT.print("#{i}\n")
(0..1000).each{ s << '*' }
}
# timer.stop
until s.empty?
sleep 0.1
end
timer.stop
=begin
tio.sync = false
print("\n")
#(0..10000).each{ putc('*') }
(0..10).each{|i|
STDOUT.print("#{i}\n")
(0..1000).each{ putc('*') }
}
(0..10).each{|i|
STDOUT.print("#{i}\n")
s = ''
(0..1000).each{ s << '*' }
print(s)
}
=end
num = 0
# io = TkTextIO.new(:mode=>:console, :prompt=>'').pack
#=begin
io = TkTextIO.new(:mode=>:console,
:prompt_cmd=>proc{
s = "[#{num}]"
num += 1
s
},
:prompt=>'-> ').pack
#=end
Thread.new{loop{sleep 2; io.puts 'hoge'}}
Thread.new{loop{p io.gets}}
ev_loop.join
end