summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authornagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2005-03-26 13:58:11 +0000
committernagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2005-03-26 13:58:11 +0000
commit334325f72a08589acaeca6d9ef5171af42dfbe60 (patch)
tree0fc4047f672a06b884dea107432fc345dffb7302 /ext
parente3c98febde12ce153bd07d29a9d7118d7ba8c58b (diff)
* ext/tk/lib/tk.rb (_callback_entry_class?): add for checking whether
a class is available for a callback entry. * ext/tk/lib/tk.rb (after_cancel): add Tk.after_cancel(afterID) method. * ext/tk/lib/tk.rb (array2tk_list): change from private module method of TkComm to public module method. * ext/tk/lib/tk.rb (cget): add check that slot argument is not empty string. * ext/tk/lib/tk.rb (configinfo): ditto. * ext/tk/lib/tk/itemconfig.rb (itemcget): add check that slot argument is not empty string. * ext/tk/lib/tk/itemconfig.rb (itemconfiginfo): ditto. * ext/tk/lib/tk/entry.rb: add TkEntry#icursor and icursor= (alias of cursor and cursor= method). * ext/tk/lib/tk/font.rb: improve font treatment when the font name is empty string. * ext/tk/lib/tk/variable.rb: add :variable, :window and :procedure type. * ext/tk/lib/tk/variable.rb: improve treatment of array-type tkvariable. * ext/tk/lib/tkextlib/blt.rb: add commands for zooming. * ext/tk/lib/tkextlib/blt/*: bug fix. * ext/tk/lib/tkextlib/treectrl/tktreectrl.rb: bug fix and add methods to call TreeCtrl commands for bindings. * ext/tk/sample/tkextlib/blt/*: new sample scritps. * ext/tk/sample/tkextlib/treectrl/*: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@8195 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext')
-rw-r--r--ext/tk/ChangeLog.tkextlib32
-rw-r--r--ext/tk/lib/tk.rb30
-rw-r--r--ext/tk/lib/tk/entry.rb2
-rw-r--r--ext/tk/lib/tk/font.rb113
-rw-r--r--ext/tk/lib/tk/itemconfig.rb16
-rw-r--r--ext/tk/lib/tk/variable.rb528
-rw-r--r--ext/tk/lib/tkextlib/SUPPORT_STATUS15
-rw-r--r--ext/tk/lib/tkextlib/blt.rb41
-rw-r--r--ext/tk/lib/tkextlib/blt/barchart.rb1
-rw-r--r--ext/tk/lib/tkextlib/blt/bitmap.rb35
-rw-r--r--ext/tk/lib/tkextlib/blt/busy.rb42
-rw-r--r--ext/tk/lib/tkextlib/blt/component.rb251
-rw-r--r--ext/tk/lib/tkextlib/blt/graph.rb1
-rw-r--r--ext/tk/lib/tkextlib/blt/htext.rb5
-rw-r--r--ext/tk/lib/tkextlib/blt/stripchart.rb1
-rw-r--r--ext/tk/lib/tkextlib/blt/table.rb17
-rw-r--r--ext/tk/lib/tkextlib/treectrl/tktreectrl.rb280
-rw-r--r--ext/tk/sample/tkextlib/blt/barchart5.rb101
-rw-r--r--ext/tk/sample/tkextlib/blt/graph7.rb40
-rw-r--r--ext/tk/sample/tkextlib/blt/graph7a.rb63
-rw-r--r--ext/tk/sample/tkextlib/blt/graph7b.rb41
-rw-r--r--ext/tk/sample/tkextlib/blt/graph7c.rb45
-rw-r--r--ext/tk/sample/tkextlib/blt/images/buckskin.gifbin0 -> 7561 bytes
-rw-r--r--ext/tk/sample/tkextlib/blt/images/qv100.t.gifbin0 -> 2694 bytes
-rw-r--r--ext/tk/sample/tkextlib/blt/images/sample.gifbin0 -> 186103 bytes
-rw-r--r--ext/tk/sample/tkextlib/blt/plot1.rb9
-rw-r--r--ext/tk/sample/tkextlib/blt/plot1b.rb10
-rw-r--r--ext/tk/sample/tkextlib/blt/readme.txt2
-rw-r--r--ext/tk/sample/tkextlib/blt/scripts/stipples.rb156
-rw-r--r--ext/tk/sample/tkextlib/blt/winop1.rb40
-rw-r--r--ext/tk/sample/tkextlib/blt/winop2.rb28
-rw-r--r--ext/tk/sample/tkextlib/treectrl/bitmaps.rb75
-rw-r--r--ext/tk/sample/tkextlib/treectrl/demo.rb1256
-rw-r--r--ext/tk/sample/tkextlib/treectrl/explorer.rb442
-rw-r--r--ext/tk/sample/tkextlib/treectrl/help.rb405
-rw-r--r--ext/tk/sample/tkextlib/treectrl/imovie.rb130
-rw-r--r--ext/tk/sample/tkextlib/treectrl/layout.rb159
-rw-r--r--ext/tk/sample/tkextlib/treectrl/mailwasher.rb269
-rw-r--r--ext/tk/sample/tkextlib/treectrl/outlook-folders.rb124
-rw-r--r--ext/tk/sample/tkextlib/treectrl/outlook-newgroup.rb447
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/big-dll.gifbin0 -> 437 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/big-exe.gifbin0 -> 368 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/big-file.gifbin0 -> 466 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/big-folder.gifbin0 -> 459 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/big-txt.gifbin0 -> 392 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/checked.gifbin0 -> 78 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/file.gifbin0 -> 279 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/folder-closed.gifbin0 -> 111 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/folder-open.gifbin0 -> 120 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/help-book-closed.gifbin0 -> 115 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/help-book-open.gifbin0 -> 128 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/help-page.gifbin0 -> 132 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/imovie-01.gifbin0 -> 5406 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/imovie-02.gifbin0 -> 5912 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/imovie-03.gifbin0 -> 4696 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/imovie-04.gifbin0 -> 5783 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/imovie-05.gifbin0 -> 3238 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/imovie-06.gifbin0 -> 3509 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/imovie-07.gifbin0 -> 2091 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/internet-check-off.gifbin0 -> 70 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/internet-check-on.gifbin0 -> 76 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/internet-print.gifbin0 -> 124 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/internet-radio-off.gifbin0 -> 68 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/internet-radio-on.gifbin0 -> 71 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/internet-search.gifbin0 -> 114 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/internet-security.gifbin0 -> 108 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/mac-collapse.gifbin0 -> 275 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/mac-expand.gifbin0 -> 277 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/outlook-arrow.gifbin0 -> 73 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/outlook-clip.gifbin0 -> 73 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/outlook-deleted.gifbin0 -> 138 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/outlook-draft.gifbin0 -> 134 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/outlook-folder.gifbin0 -> 133 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/outlook-group.gifbin0 -> 144 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/outlook-inbox.gifbin0 -> 133 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/outlook-local.gifbin0 -> 146 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/outlook-main.gifbin0 -> 174 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/outlook-outbox.gifbin0 -> 136 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/outlook-read-2.gifbin0 -> 343 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/outlook-read.gifbin0 -> 304 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/outlook-sent.gifbin0 -> 132 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/outlook-server.gifbin0 -> 163 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/outlook-unread.gifbin0 -> 303 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/outlook-watch.gifbin0 -> 98 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/sky.gifbin0 -> 6454 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/small-dll.gifbin0 -> 311 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/small-exe.gifbin0 -> 115 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/small-file.gifbin0 -> 338 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/small-folder.gifbin0 -> 307 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/small-txt.gifbin0 -> 302 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/pics/unchecked.gifbin0 -> 72 bytes
-rw-r--r--ext/tk/sample/tkextlib/treectrl/random.rb505
-rw-r--r--ext/tk/sample/tkextlib/treectrl/readme.txt2
-rw-r--r--ext/tk/sample/tkextlib/treectrl/www-options.rb303
94 files changed, 5854 insertions, 208 deletions
diff --git a/ext/tk/ChangeLog.tkextlib b/ext/tk/ChangeLog.tkextlib
index c27ada6d01..85fd938e3a 100644
--- a/ext/tk/ChangeLog.tkextlib
+++ b/ext/tk/ChangeLog.tkextlib
@@ -1,3 +1,35 @@
+2005-03-26 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * lib/tkextlib/blt.rb: add commands for zooming.
+
+ * lib/tkextlib/blt/bitmap.rb (new_with_name): add for using
+ given name.
+
+ * lib/tkextlib/blt/busy.rb: bug fix on Tk::BLT::Busy::Shild class.
+
+ * lib/tkextlib/blt/component.rb: typo fix.
+
+ * lib/tkextlib/blt/component.rb: fix lack of *_create methods
+
+ * lib/tkextlib/blt/component.rb: proper call on xaxis_* and so on.
+
+ * lib/tkextlib/blt/htext.rb: add TkVariable object to access
+ special Tcl variables.
+
+ * ext/tk/lib/tkextlib/treectrl/tktreectrl.rb: typo fix.
+
+ * ext/tk/lib/tkextlib/treectrl/tktreectrl.rb: proper treatment
+ of 'font' option of element_configure.
+
+ * ext/tk/lib/tkextlib/treectrl/tktreectrl.rb: bug fix on item_sort.
+
+ * ext/tk/lib/tkextlib/treectrl/tktreectrl.rb: add methods to
+ call TreeCtrl commands for bindings.
+
+ * ext/tk/sample/tkextlib/blt/*: add some sample scripts.
+
+ * ext/tk/sample/tkextlib/treectrl/*: add some sample scripts.
+
2005-03-18 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* lib/tkextlib/treectrl/tktreectrl.rb: bug fix and define some
diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb
index d246cd9a0c..61e76c29bc 100644
--- a/ext/tk/lib/tk.rb
+++ b/ext/tk/lib/tk.rb
@@ -448,7 +448,7 @@ end
private_class_method :tk_split_escstr, :tk_split_sublist
private_class_method :tk_split_list, :tk_split_simplelist
- private_class_method :array2tk_list
+# private_class_method :array2tk_list
=begin
### --> definition is moved to TkUtil module
@@ -583,6 +583,12 @@ end
private :_toUTF8, :_fromUTF8
module_function :_toUTF8, :_fromUTF8
+ def _callback_entry_class?(cls)
+ cls <= Proc || cls <= Method || cls <= TkCallbackEntry
+ end
+ private :_callback_entry_class?
+ module_function :_callback_entry_class?
+
def _callback_entry?(obj)
obj.kind_of?(Proc) || obj.kind_of?(Method) || obj.kind_of?(TkCallbackEntry)
end
@@ -1301,6 +1307,10 @@ module TkCore
tk_call_without_enc('after','idle',cmdid)
end
+ def after_cancel(afterId)
+ tk_call_without_enc('after','cancel',afterId)
+ end
+
def windowingsystem
tk_call_without_enc('tk', 'windowingsystem')
end
@@ -2612,7 +2622,12 @@ module TkConfigMethod
end
def cget(slot)
+ orig_slot = slot
slot = slot.to_s
+
+ if slot.length == 0
+ fail ArgumentError, "Invalid option `#{orig_slot.inspect}'"
+ end
if ( method = _symbolkey2str(__methodcall_optkeys)[slot] )
return self.__send__(method)
@@ -2698,7 +2713,12 @@ module TkConfigMethod
end
else
+ orig_slot = slot
slot = slot.to_s
+ if slot.length == 0
+ fail ArgumentError, "Invalid option `#{orig_slot.inspect}'"
+ end
+
if ( conf = __keyonly_optkeys.find{|k, v| k.to_s == slot} )
defkey, undefkey = conf
if value
@@ -2727,7 +2747,8 @@ module TkConfigMethod
def configinfo(slot = nil)
if TkComm::GET_CONFIGINFO_AS_ARRAY
- if (slot.to_s =~ /^(|latin|ascii|kanji)(#{__font_optkeys.join('|')})$/)
+ if (slot &&
+ slot.to_s =~ /^(|latin|ascii|kanji)(#{__font_optkeys.join('|')})$/)
fontkey = $2
conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{fontkey}"))))
conf[__configinfo_struct[:key]] =
@@ -2984,7 +3005,8 @@ module TkConfigMethod
end
else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
- if (slot.to_s =~ /^(|latin|ascii|kanji)(#{__font_optkeys.join('|')})$/)
+ if (slot &&
+ slot.to_s =~ /^(|latin|ascii|kanji)(#{__font_optkeys.join('|')})$/)
fontkey = $2
conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__confinfo_cmd << "-#{fontkey}"))))
conf[__configinfo_struct[:key]] =
@@ -4002,7 +4024,7 @@ end
#Tk.freeze
module Tk
- RELEASE_DATE = '2005-03-14'.freeze
+ RELEASE_DATE = '2005-03-26'.freeze
autoload :AUTO_PATH, 'tk/variable'
autoload :TCL_PACKAGE_PATH, 'tk/variable'
diff --git a/ext/tk/lib/tk/entry.rb b/ext/tk/lib/tk/entry.rb
index 0fe553d55c..63051979e6 100644
--- a/ext/tk/lib/tk/entry.rb
+++ b/ext/tk/lib/tk/entry.rb
@@ -27,11 +27,13 @@ class TkEntry<TkLabel
def cursor
number(tk_send_without_enc('index', 'insert'))
end
+ alias icursor cursor
def cursor=(index)
tk_send_without_enc('icursor', index)
#self
index
end
+ alias icursor= cursor=
def index(idx)
number(tk_send_without_enc('index', idx))
end
diff --git a/ext/tk/lib/tk/font.rb b/ext/tk/lib/tk/font.rb
index 389f001f44..8e63558cae 100644
--- a/ext/tk/lib/tk/font.rb
+++ b/ext/tk/lib/tk/font.rb
@@ -164,6 +164,7 @@ class TkFont
# class methods
###################################
def TkFont.actual(fnt, option=nil)
+ fnt = '{}' if fnt == ''
if fnt.kind_of?(TkFont)
fnt.actual(option)
else
@@ -172,6 +173,7 @@ class TkFont
end
def TkFont.actual_displayof(fnt, win, option=nil)
+ fnt = '{}' if fnt == ''
if fnt.kind_of?(TkFont)
fnt.actual_displayof(win, option)
else
@@ -206,6 +208,7 @@ class TkFont
end
def TkFont.measure(fnt, text)
+ fnt = '{}' if fnt == ''
if fnt.kind_of?(TkFont)
fnt.measure(text)
else
@@ -214,6 +217,7 @@ class TkFont
end
def TkFont.measure_displayof(fnt, win, text)
+ fnt = '{}' if fnt == ''
if fnt.kind_of?(TkFont)
fnt.measure_displayof(win, text)
else
@@ -223,6 +227,7 @@ class TkFont
end
def TkFont.metrics(fnt, option=nil)
+ fnt = '{}' if fnt == ''
if fnt.kind_of?(TkFont)
fnt.metrics(option)
else
@@ -231,6 +236,7 @@ class TkFont
end
def TkFont.metrics_displayof(fnt, win, option=nil)
+ fnt = '{}' if fnt == ''
if fnt.kind_of?(TkFont)
font.metrics_displayof(win, option=nil)
else
@@ -338,13 +344,17 @@ class TkFont
fnt = nil if fnt == [] || fnt == ""
unless fnt
- TkFont.new(nil, nil).call_font_configure([path, key], *args)
+ # create dummy
+ # TkFont.new(nil, nil).call_font_configure([path, key], *args)
+ dummy_fnt = TkFont.allocate
+ dummy_fnt.instance_eval{ init_dummy_fontobj() }
+ dummy_fnt
else
begin
compound = tk_split_simplelist(
Hash[*tk_split_simplelist(tk_call('font', 'configure',
- fnt))].collect{|key,value|
- [key[1..-1], value]
+ fnt))].collect{|k,v|
+ [k[1..-1], v]
}.assoc('compound')[1])
rescue
compound = []
@@ -381,7 +391,51 @@ class TkFont
###################################
private
###################################
+ def init_dummy_fontobj
+ @id = Tk_FontID.join(TkCore::INTERP._ip_id_)
+ Tk_FontID[1].succ!
+ Tk_FontNameTBL[@id] = self
+
+ @latin_desscendant = nil
+ @kanji_desscendant = nil
+
+ case (Tk::TK_VERSION)
+ when /^4\.*/
+ @latinfont = ""
+ @kanjifont = ""
+ if JAPANIZED_TK
+ @compoundfont = [[@latinfont], [@kanjifont]]
+ @fontslot = {'font'=>@latinfont, 'kanjifont'=>@kanjifont}
+ else
+ @compoundfont = @latinfont
+ @fontslot = {'font'=>@latinfont}
+ end
+ else
+ @latinfont = @id + 'l'
+ @kanjifont = @id + 'k'
+ @compoundfont = @id + 'c'
+
+ if JAPANIZED_TK
+ tk_call('font', 'create', @latinfont, '-charset', 'iso8859')
+ tk_call('font', 'create', @kanjifont, '-charset', 'jisx0208.1983')
+ tk_call('font', 'create', @compoundfont,
+ '-compound', [@latinfont, @kanjifont])
+ else
+ tk_call('font', 'create', @latinfont)
+ tk_call('font', 'create', @kanjifont)
+ tk_call('font', 'create', @compoundfont)
+ end
+
+ @fontslot = {'font'=>@compoundfont}
+ end
+
+ self
+ end
+
def initialize(ltn=nil, knj=nil, keys=nil)
+ ltn = '{}' if ltn == ''
+ knj = '{}' if knj == ''
+
# @id = Tk_FontID.join('')
@id = Tk_FontID.join(TkCore::INTERP._ip_id_)
Tk_FontID[1].succ!
@@ -657,10 +711,17 @@ class TkFont
end
def create_compoundfont_tk8x(ltn, knj, keys)
- create_latinfont(ltn)
- create_kanjifont(knj)
+ if knj
+ create_latinfont(ltn)
+ create_kanjifont(knj)
+ else
+ cfnt = ltn
+ create_kanjifont(cfnt)
+ create_latinfont(cfnt)
+ end
@compoundfont = @id + 'c'
+
if JAPANIZED_TK
unless keys
keys = {}
@@ -735,6 +796,7 @@ class TkFont
end
if knj
+ compoundkeys = nil
kanjikeys = {}
begin
actual_core(@kanjifont).each{|key,val| kanjikeys[key] = val}
@@ -746,6 +808,17 @@ class TkFont
end
end
+ if cfnt
+ if cfnt.kind_of?(Hash)
+ compoundkeys = cfnt.dup
+ else
+ compoundkeys = {}
+ actual_core(cfnt).each{|key,val| compoundkeys[key] = val}
+ end
+ compoundkeys.update(_symbolkey2str(keys))
+ keys = compoundkeys
+ end
+
@fontslot = {'font'=>@compoundfont}
tk_call('font', 'configure', @compoundfont, *hash_kv(keys))
end
@@ -754,11 +827,21 @@ class TkFont
###################################
public
###################################
+ def inspect
+ sprintf("#<%s:%0x:%s>", self.class.inspect, self.__id__, @compoundfont)
+ end
+
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]
+ args[0]
+ else
+ configure name, args[0]
+ self
+ end
when 0
begin
configinfo name
@@ -1099,6 +1182,7 @@ class TkFont
alias ascii_metrics latin_metrics
###################################
+=begin
def dup
src = self
obj = super()
@@ -1111,6 +1195,13 @@ class TkFont
obj.instance_eval{ initialize(src) }
obj
end
+=end
+ def dup
+ TkFont.new(self)
+ end
+ def clone
+ TkFont.new(self)
+ end
end
module TkFont::CoreMethods
@@ -1140,6 +1231,8 @@ module TkFont::CoreMethods
end
def actual_core_tk8x(font, win=nil, option=nil)
+ font = '{}' if font == ''
+
if option == 'compound' || option == :compound
""
elsif option
@@ -1465,6 +1558,8 @@ module TkFont::CoreMethods
end
def latin_replace_core_tk8x(ltn)
+ ltn = '{}' if ltn == ''
+
if JAPANIZED_TK
begin
tk_call('font', 'delete', '@font_tmp')
@@ -1528,6 +1623,8 @@ module TkFont::CoreMethods
end
def kanji_replace_core_tk8x(knj)
+ knj = '{}' if knj == ''
+
if JAPANIZED_TK
begin
tk_call('font', 'delete', '@font_tmp')
@@ -1573,6 +1670,8 @@ module TkFont::CoreMethods
end
def measure_core_tk8x(font, win, text)
+ font = '{}' if font == ''
+
if win
number(tk_call('font', 'measure', font,
'-displayof', win, text))
@@ -1591,6 +1690,8 @@ module TkFont::CoreMethods
end
def metrics_core_tk8x(font, win, option=nil)
+ font = '{}' if font == ''
+
if option
if win
number(tk_call('font', 'metrics', font,
diff --git a/ext/tk/lib/tk/itemconfig.rb b/ext/tk/lib/tk/itemconfig.rb
index f0f13e63bd..72225e7522 100644
--- a/ext/tk/lib/tk/itemconfig.rb
+++ b/ext/tk/lib/tk/itemconfig.rb
@@ -6,6 +6,8 @@ require 'tkutil'
require 'tk/itemfont.rb'
module TkItemConfigOptkeys
+ include TkUtil
+
def __item_numval_optkeys(id)
[]
end
@@ -119,8 +121,13 @@ module TkItemConfigMethod
################################################
def itemcget(tagOrId, option)
+ orig_opt = option
option = option.to_s
+ if option.length == 0
+ fail ArgumentError, "Invalid option `#{orig_opt.inspect}'"
+ end
+
if ( method = _symbolkey2str(__item_methodcall_optkeys(tagid(tagOrId)))[option] )
return self.__send__(method, tagOrId)
end
@@ -204,7 +211,12 @@ module TkItemConfigMethod
end
else
+ orig_slot = slot
slot = slot.to_s
+ if slot.length == 0
+ fail ArgumentError, "Invalid option `#{orig_slot.inspect}'"
+ end
+
if ( conf = __item_keyonly_optkeys(tagid(tagOrId)).find{|k, v| k.to_s == slot } )
defkey, undefkey = conf
if value
@@ -229,7 +241,7 @@ module TkItemConfigMethod
def itemconfiginfo(tagOrId, slot = nil)
if TkComm::GET_CONFIGINFO_AS_ARRAY
- if (slot.to_s =~ /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/)
+ if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/)
fontkey = $2
conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{fontkey}"))))
conf[__item_configinfo_struct(tagid(tagOrId))[:key]] =
@@ -487,7 +499,7 @@ module TkItemConfigMethod
end
else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
- if (slot.to_s =~ /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/)
+ if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/)
fontkey = $2
conf = tk_split_simplelist(_fromUTF8(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{fontkey}"))))
conf[__item_configinfo_struct(tagid(tagOrId))[:key]] =
diff --git a/ext/tk/lib/tk/variable.rb b/ext/tk/lib/tk/variable.rb
index e3a08dfdcf..982182c2a8 100644
--- a/ext/tk/lib/tk/variable.rb
+++ b/ext/tk/lib/tk/variable.rb
@@ -109,11 +109,12 @@ TkCore::INTERP.add_tk_procs('rb_var', 'args', <<-'EOL')
end
self
end
- def default_value=(val)
+ def set_default_value(val)
@def_default = :val
@default_val = val
self
end
+ alias default_value= set_default_value
def default_proc(cmd = Proc.new)
@def_default = :proc
@default_val = cmd
@@ -129,59 +130,111 @@ TkCore::INTERP.add_tk_procs('rb_var', 'args', <<-'EOL')
def default_value_type
@type
end
+ def default_element_value_type(idxs)
+ if idxs.kind_of?(Array)
+ index = idxs.collect{|idx| _get_eval_string(idx, true)}.join(',')
+ else
+ index = _get_eval_string(idxs, true)
+ end
+ @element_type[index]
+ end
- def default_value_type=(type)
+ def _set_default_value_type_core(type, idxs)
if type.kind_of?(Class)
if type == NilClass
- @type = nil
+ type = nil
elsif type == Numeric
- @type = :numeric
+ type = :numeric
elsif type == TrueClass || type == FalseClass
- @type = :bool
+ type = :bool
elsif type == String
- @type = :string
+ type = :string
elsif type == Symbol
- @type = :symbol
+ type = :symbol
elsif type == Array
- @type = :list
+ type = :list
+ elsif type <= TkVariable
+ type = :variable
+ elsif type <= TkWindow
+ type = :window
+ elsif TkComm._callback_entry_class?(type)
+ type = :procedure
else
- @type = nil
+ type = nil
end
else
case(type)
when nil
- @type = nil
+ type = nil
when :numeric, 'numeric'
- @type = :numeric
+ type = :numeric
when true, false, :bool, 'bool'
- @type = :bool
+ type = :bool
when :string, 'string'
- @type = :string
+ type = :string
when :symbol, 'symbol'
- @type = :symbol
+ type = :symbol
when :list, 'list'
- @type = :list
+ type = :list
when :numlist, 'numlist'
- @type = :numlist
+ type = :numlist
+ when :variable, 'variable'
+ type = :variable
+ when :window, 'window'
+ type = :window
+ when :procedure, 'procedure'
+ type = :procedure
else
- self.default_value_type = type.class
+ return _set_default_value_type_core(type.class, idxs)
end
end
- @type
+ if idxs
+ if idxs.kind_of?(Array)
+ index = idxs.collect{|idx| _get_eval_string(idx, true)}.join(',')
+ else
+ index = _get_eval_string(idxs, true)
+ end
+ @element_type[index] = type
+ else
+ @type = type
+ end
+ type
+ end
+ private :_set_default_value_type_core
+
+ def set_default_value_type(type)
+ _set_default_value_type_core(type, nil)
+ self
end
+ alias default_value_type= set_default_value_type
- def _to_default_type(val)
- return val unless @type
+ def set_default_element_value_type(idxs, type)
+ _set_default_value_type_core(type, idxs)
+ self
+ end
+
+ def _to_default_type(val, idxs = nil)
+ if idxs
+ if idxs.kind_of?(Array)
+ index = idxs.collect{|idx| _get_eval_string(idx, true)}.join(',')
+ else
+ index = _get_eval_string(idxs, true)
+ end
+ type = @element_type[index]
+ else
+ type = @type
+ end
+ return val unless type
if val.kind_of?(Hash)
- val.keys.each{|k| val[k] = _to_default_type(val[k]) }
+ val.keys.each{|k| val[k] = _to_default_type(val[k], idxs) }
val
else
begin
- case(@type)
+ case(type)
when :numeric
number(val)
when :bool
- TkComm
+ TkComm.bool(val)
when :string
val
when :symbol
@@ -190,6 +243,12 @@ TkCore::INTERP.add_tk_procs('rb_var', 'args', <<-'EOL')
tk_split_simplelist(val)
when :numlist
tk_split_simplelist(val).collect!{|v| number(v)}
+ when :variable
+ TkVarAccess.new(val)
+ when :window
+ TkComm.window(val)
+ when :procedure
+ TkComm.procedure(val)
else
val
end
@@ -200,6 +259,11 @@ TkCore::INTERP.add_tk_procs('rb_var', 'args', <<-'EOL')
end
private :_to_default_type
+ def _to_default_element_type(idxs, val)
+ _to_default_type(val, idxs)
+ end
+ private :_to_default_element_type
+
def initialize(val="", type=nil)
# @id = Tk_VARIABLE_ID.join('')
@id = Tk_VARIABLE_ID.join(TkCore::INTERP._ip_id_)
@@ -213,6 +277,10 @@ TkCore::INTERP.add_tk_procs('rb_var', 'args', <<-'EOL')
@trace_elem = nil
@trace_opts = nil
+ @type = nil
+ var = self
+ @element_type = Hash.new{|k,v| var.default_value_type }
+
self.default_value_type = type
begin
@@ -326,14 +394,15 @@ TkCore::INTERP.add_tk_procs('rb_var', 'args', <<-'EOL')
! is_hash?
end
- def exist?(idx = nil)
+ def exist?(*elems)
INTERP._invoke_without_enc('global', @id)
- if idx
+ if elems.empty?
+ TkComm.bool(tk_call('info', 'exist', @id))
+ else
# array
+ index = elems.collect{|idx| _get_eval_string(idx, true)}.join(',')
TkComm.bool(tk_call('info', 'exist', "#{@id}")) &&
- TkComm.bool(tk_call('info', 'exist', "#{@id}(#{idx})"))
- else
- TkComm.bool(tk_call('info', 'exist', @id))
+ TkComm.bool(tk_call('info', 'exist', "#{@id}(#{index})"))
end
end
@@ -389,6 +458,7 @@ if USE_TCLs_SET_VARIABLE_FUNCTIONS
end
def value=(val)
+ val = val._value if !@type && @type != :variable && val.kind_of?(TkVariable)
if val.kind_of?(Hash)
self.clear
val.each{|k, v|
@@ -418,11 +488,10 @@ if USE_TCLs_SET_VARIABLE_FUNCTIONS
end
end
- def [](*idxs)
+ def _element_value(*idxs)
index = idxs.collect{|idx| _get_eval_string(idx, true)}.join(',')
begin
- # _fromUTF8(INTERP._get_global_var2(@id, index))
- _to_default_type(_fromUTF8(INTERP._get_global_var2(@id, index)))
+ _fromUTF8(INTERP._get_global_var2(@id, index))
rescue => e
case @def_default
when :proc
@@ -440,6 +509,8 @@ if USE_TCLs_SET_VARIABLE_FUNCTIONS
def []=(*args)
val = args.pop
+ type = default_element_value_type(args)
+ val = val._value if !type && type != :variable && val.kind_of?(TkVariable)
index = args.collect{|idx| _get_eval_string(idx, true)}.join(',')
_fromUTF8(INTERP._set_global_var2(@id, index, _get_eval_string(val, true)))
#_fromUTF8(INTERP._set_global_var2(@id, _toUTF8(_get_eval_string(index)),
@@ -448,11 +519,12 @@ if USE_TCLs_SET_VARIABLE_FUNCTIONS
# _get_eval_string(val, true)))
end
- def unset(elem=nil)
- if elem
- INTERP._unset_global_var2(@id, _get_eval_string(elem, true))
- else
+ def unset(*elems)
+ if elems.empty?
INTERP._unset_global_var(@id)
+ else
+ index = elems.collect{|idx| _get_eval_string(idx, true)}.join(',')
+ INTERP._unset_global_var2(@id, index)
end
end
alias remove unset
@@ -481,6 +553,7 @@ else
end
def value=(val)
+ val = val._value if !@type && @type != :variable && val.kind_of?(TkVariable)
begin
#s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"'
s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"'
@@ -530,11 +603,10 @@ else
end
end
- def [](*idxs)
+ def _element_value(*idxs)
index = idxs.collect{|idx| _get_eval_string(idx)}.join(',')
begin
- # INTERP._eval(Kernel.format('global %s; set %s(%s)', @id, @id, index))
- _to_default_type(INTERP._eval(Kernel.format('global %s; set %s(%s)', @id, @id, index)))
+ INTERP._eval(Kernel.format('global %s; set %s(%s)', @id, @id, index))
rescue => e
case @def_default
when :proc
@@ -554,6 +626,8 @@ else
def []=(*args)
val = args.pop
+ type = default_element_value_type(args)
+ val = val._value if !type && type != :variable && val.kind_of?(TkVariable)
index = args.collect{|idx| _get_eval_string(idx)}.join(',')
INTERP._eval(Kernel.format('global %s; set %s(%s) %s', @id, @id,
index, _get_eval_string(val)))
@@ -565,37 +639,73 @@ else
# _get_eval_string(val))
end
- def unset(elem=nil)
- if elem
- INTERP._eval(Kernel.format('global %s; unset %s(%s)',
- @id, @id, _get_eval_string(elem)))
- #INTERP._eval(Kernel.format('unset %s(%s)', @id, tk_tcl2ruby(elem)))
- #INTERP._eval('unset ' + @id + '(' + _get_eval_string(elem) + ')')
- else
+ def unset(*elems)
+ if elems.empty?
INTERP._eval(Kernel.format('global %s; unset %s', @id, @id))
#INTERP._eval(Kernel.format('unset %s', @id))
#INTERP._eval('unset ' + @id)
+ else
+ index = elems.collect{|idx| _get_eval_string(idx, true)}.join(',')
+ INTERP._eval(Kernel.format('global %s; unset %s(%s)', @id, @id, index))
+ #INTERP._eval(Kernel.format('global %s; unset %s(%s)',
+ # @id, @id, _get_eval_string(elem)))
+ #INTERP._eval(Kernel.format('unset %s(%s)', @id, tk_tcl2ruby(elem)))
+ #INTERP._eval('unset ' + @id + '(' + _get_eval_string(elem) + ')')
end
end
alias remove unset
end
- protected :_value
+ protected :_value, :_element_value
def value
_to_default_type(_value)
end
- def value_type=(val)
- self.default_value_type = val
- self.value=(val)
+ def [](*idxs)
+ _to_default_element_type(idxs, _element_value(*idxs))
+ end
+
+ def set_value(val)
+ self.value = val
+ self
+ end
+
+ def set_element_value(idxs, val)
+ if idxs.kind_of?(Array)
+ self[*idxs]=val
+ else
+ self[idxs]=val
+ end
+ self
+ end
+
+ def set_value_type(val)
+ self.default_value_type = val.class
+ self.value = val
+ self
+ end
+
+ alias value_type= set_value_type
+
+ def set_element_value_type(idxs, val)
+ self.set_default_element_value_type(idxs, val.class)
+ if idxs.kind_of?(Array)
+ self[*idxs]=val
+ else
+ self[idxs]=val
+ end
+ self
end
def numeric
number(_value)
end
- def numeric=(val)
+ def numeric_element(*idxs)
+ number(_element_value(*idxs))
+ end
+ def set_numeric(val)
case val
when Numeric
self.value=(val)
@@ -604,14 +714,39 @@ end
else
raise ArgumentError, "Numeric is expected"
end
- val
+ self
+ end
+ alias numeric= set_numeric
+ def set_numeric_element(idxs, val)
+ case val
+ when Numeric
+ val
+ when TkVariable
+ val = val.numeric
+ else
+ raise ArgumentError, "Numeric is expected"
+ end
+ if idxs.kind_of?(Array)
+ self[*idxs]=val
+ else
+ self[idxs]=val
+ end
+ self
end
- def numeric_type=(val)
+ def set_numeric_type(val)
@type = :numeric
self.numeric=(val)
+ self
+ end
+ alias numeric_type= set_numeric_type
+ def set_numeric_element_type(idxs, val)
+ self.set_default_element_value_type(idxs, :numeric)
+ self.set_numeric_element(idxs, val)
end
def bool
+ TkComm.bool(_value)
+=begin
# see Tcl_GetBoolean man-page
case _value.downcase
when '0', 'false', 'no', 'off'
@@ -619,8 +754,12 @@ end
else
true
end
+=end
+ end
+ def bool_element(*idxs)
+ TkComm.bool(_element_value(*idxs))
end
- def bool=(val)
+ def set_bool(val)
if ! val
self.value = '0'
else
@@ -631,37 +770,216 @@ end
self.value = '1'
end
end
+ self
+ end
+ alias bool= set_bool
+ def set_bool_element(idxs, val)
+ if ! val
+ val = '0'
+ else
+ case val.to_s.downcase
+ when 'false', '0', 'no', 'off'
+ val = '0'
+ else
+ val = '1'
+ end
+ end
+ if idxs.kind_of?(Array)
+ self[*idxs]=val
+ else
+ self[idxs]=val
+ end
+ self
end
- def bool_type=(val)
+ def set_bool_type(val)
@type = :bool
self.bool=(val)
+ self
+ end
+ alias bool_type= set_bool_type
+ def set_bool_element_type(idxs, val)
+ self.set_default_element_value_type(idxs, :bool)
+ self.set_bool_element(idxs, val)
+ end
+
+ def variable
+ TkVarAccess.new(self._value)
+ end
+ def variable_element(*idxs)
+ TkVarAccess.new(_element_value(*idxs))
+ end
+ def set_variable(var)
+ var = var.id if var.kind_of?(TkVariable)
+ self.value = var
+ self
+ end
+ alias variable= set_variable
+ def set_variable_element(idxs, var)
+ var = var.id if var.kind_of?(TkVariable)
+ if idxs.kind_of?(Array)
+ self[*idxs]=var
+ else
+ self[idxs]=var
+ end
+ self
+ end
+ def set_variable_type(var)
+ @type = :variable
+ var = var.id if var.kind_of?(TkVariable)
+ self.value = var
+ self
+ end
+ alias variable_type= set_variable_type
+ def set_variable_element_type(idxs, var)
+ self.set_default_element_value_type(idxs, :variable)
+ self.set_variable_element(idxs, var)
+ end
+
+ def window
+ TkComm.window(self._value)
+ end
+ def window_element(*idxs)
+ TkComm.window(_element_value(*idxs))
+ end
+ def set_window(win)
+ win = win._value if win.kind_of?(TkVariable)
+ self.value = win
+ self
+ end
+ alias window= set_window
+ def set_window_element(idxs, win)
+ win = win._value if win.kind_of?(TkVariable)
+ if idxs.kind_of?(Array)
+ self[*idxs]=win
+ else
+ self[idxs]=win
+ end
+ self
+ end
+ def set_window_type(win)
+ @type = :window
+ self.window=(win)
+ self
+ end
+ alias window_type= set_window_type
+ def set_window_element_type(idxs, win)
+ self.set_default_element_value_type(idxs, :window)
+ self.set_window_element(idxs, win)
+ end
+
+ def procedure
+ TkComm.procedure(self._value)
+ end
+ def procedure_element(*idxs)
+ TkComm.procedure(_element_value(*idxs))
+ end
+ def set_procedure(cmd)
+ self.value = cmd
+ self
+ end
+ alias procedure= set_procedure
+ def set_procedure_element(idxs, cmd)
+ cmd = cmd._value if cmd.kind_of?(TkVariable)
+ if idxs.kind_of?(Array)
+ self[*idxs]=cmd
+ else
+ self[idxs]=cmd
+ end
+ self
+ end
+ def set_procedure_type(cmd)
+ @type = :procedure
+ self.procedure=(cmd)
+ self
+ end
+ alias procedure_type= set_procedure_type
+ def set_procedure_element_type(idxs, cmd)
+ self.set_default_element_value_type(idxs, :procedure)
+ self.set_proceure_element(idxs, cmd)
end
def to_i
number(_value).to_i
end
+ def element_to_i(*idxs)
+ number(_element_value(*idxs)).to_i
+ end
def to_f
number(_value).to_f
end
+ def element_to_f(*idxs)
+ number(_element_value(*idxs)).to_f
+ end
def to_s
#string(value).to_s
_value
end
- alias string= value=
- def string_type=(val)
+ def element_to_s(*idxs)
+ _element_value(*idxs)
+ end
+ def string_element(*idxs)
+ _element_value(*idxs)
+ end
+ def set_string(val)
+ val = val._value if val.kind_of?(TkVariable)
+ self.value=val
+ self
+ end
+ alias string= set_string
+ def set_string_element(idxs, val)
+ val = val._value if val.kind_of?(TkVariable)
+ if idxs.kind_of?(Array)
+ self[*idxs]=val
+ else
+ self[idxs]=val
+ end
+ self
+ end
+ def set_string_type(val)
@type = :string
- self.value=(val)
+ self.string=(val)
+ self
+ end
+ alias string_type= set_string_type
+ def set_string_element_type(idxs, val)
+ self.set_default_element_value_type(idxs, :string)
+ self.set_string_element(idxs, val)
end
def to_sym
_value.intern
end
- alias symbol= value=
- def symbol_type=(val)
+ alias symbol to_sym
+ def element_to_sym(*idxs)
+ _element_value(*idxs).intern
+ end
+ alias symbol_element element_to_sym
+ def set_symbol(val)
+ val = val._value if val.kind_of?(TkVariable)
+ self.value=val
+ self
+ end
+ alias symbol= set_symbol
+ def set_symbol_element(idxs, val)
+ val = val._value if val.kind_of?(TkVariable)
+ if idxs.kind_of?(Array)
+ self[*idxs]=val
+ else
+ self[idxs]=val
+ end
+ self
+ end
+ def set_symbol_type(val)
@type = :symbol
self.value=(val)
+ self
+ end
+ alias symbol_type= set_symbol_type
+ def set_symbol_element_type(idxs, val)
+ self.set_default_element_value_type(idxs, :symbol)
+ self.set_symbol_element(idxs, val)
end
def list
@@ -669,12 +987,19 @@ end
tk_split_simplelist(_value)
end
alias to_a list
+ def list_element(*idxs)
+ tk_split_simplelist(_element_value(*idxs))
+ end
+ alias element_to_a list_element
def numlist
list.collect!{|val| number(val)}
end
+ def numlist_element(*idxs)
+ list_element(*idxs).collect!{|val| number(val)}
+ end
- def list=(val)
+ def set_list(val)
case val
when Array
self.value=(val)
@@ -683,41 +1008,103 @@ end
else
raise ArgumentError, "Array is expected"
end
- val
+ self
end
- alias numlist= list=
+ alias list= set_list
+
+ alias set_numlist set_list
+ alias numlist= set_numlist
- def list_type=(val)
+ def set_list_element(idxs, val)
+ case val
+ when Array
+ val
+ when TkVariable
+ val = val.list
+ else
+ raise ArgumentError, "Array is expected"
+ end
+ if idxs.kind_of?(Array)
+ self[*idxs]=val
+ else
+ self[idxs]=val
+ end
+ self
+ end
+ alias set_numlist_element set_list_element
+
+ def set_list_type(val)
@type = :list
self.list=(val)
+ self
+ end
+ alias list_type= set_list_type
+ def set_list_element_type(idxs, val)
+ self.set_default_element_value_type(idxs, :list)
+ self.set_list_element(idxs, val)
end
- def numlist_type=(val)
+ def set_numlist_type(val)
@type = :numlist
self.numlist=(val)
+ self
+ end
+ alias numlist_type= set_numlist_type
+ def set_numlist_element_type(idxs, val)
+ self.set_default_element_value_type(idxs, :numlist)
+ self.set_numlist_element(idxs, val)
end
def lappend(*elems)
tk_call('lappend', @id, *elems)
self
end
+ def element_lappend(idxs, *elems)
+ if idxs.kind_of?(Array)
+ idxs = idxs.collect{|idx| _get_eval_string(idx, true)}.join(',')
+ end
+ tk_call('lappend', "#{@id}(#{idxs})", *elems)
+ self
+ end
def lindex(idx)
tk_call('lindex', self._value, idx)
end
alias lget lindex
+ def element_lindex(elem_idxs, idx)
+ if elem_idxs.kind_of?(Array)
+ val = _element_value(*elem_idxs)
+ else
+ val = _element_value(elem_idxs)
+ end
+ tk_call('lindex', val, idx)
+ end
+ alias element_lget element_lindex
def lget_i(idx)
number(lget(idx)).to_i
end
+ def element_lget_i(elem_idxs, idx)
+ number(element_lget(elem_idxs, idx)).to_i
+ end
def lget_f(idx)
number(lget(idx)).to_f
end
+ def element_lget_f(elem_idxs, idx)
+ number(element_lget(elem_idxs, idx)).to_f
+ end
def lset(idx, val)
tk_call('lset', @id, idx, val)
self
end
+ def element_lset(elem_idxs, idx, val)
+ if elem_idxs.kind_of?(Array)
+ idxs = elem_idxs.collect{|i| _get_eval_string(i, true)}.join(',')
+ end
+ tk_call('lset', "#{@id}(#{idxs})", idx, val)
+ self
+ end
def inspect
#Kernel.format "#<TkVariable: %s>", @id
@@ -823,7 +1210,8 @@ end
# false if self is not an assoc array
self._value == other
else
- false
+ # false
+ self._value == _get_eval_string(other)
end
end
@@ -842,13 +1230,14 @@ end
rescue
other = other._value
end
- end
- if other.kind_of?(Numeric)
+ elsif other.kind_of?(Numeric)
begin
return self.numeric <=> other
rescue
return self._value <=> other.to_s
end
+ elsif other.kind_of?(Array)
+ return self.list <=> other
else
return self._value <=> other
end
@@ -1107,7 +1496,6 @@ end
end
end
-
class TkVarAccess<TkVariable
def self.new(name, *args)
return TkVar_ID_TBL[name] if TkVar_ID_TBL[name]
@@ -1135,6 +1523,10 @@ class TkVarAccess<TkVariable
@trace_elem = nil
@trace_opts = nil
+ @type = nil
+ var = self
+ @element_type = Hash.new{|k,v| var.default_value_type }
+
# teach Tk-ip that @id is global var
INTERP._invoke_without_enc('global', @id)
diff --git a/ext/tk/lib/tkextlib/SUPPORT_STATUS b/ext/tk/lib/tkextlib/SUPPORT_STATUS
index 9cfc02d473..085de3bdf6 100644
--- a/ext/tk/lib/tkextlib/SUPPORT_STATUS
+++ b/ext/tk/lib/tkextlib/SUPPORT_STATUS
@@ -73,6 +73,14 @@ ICONS 1.0 http://www.satisoft.com/tcltk/icons/ ==> ICONS
TkImg 1.3 http://sf.net/projects/tkimg ==> tkimg
+BLT 2.4z http://sourceforge.net/projects/blt
+ * see also tcltk-ext library on RAA
+ (http://raa.ruby-lang.org/)
+ ==> blt
+
+TkTreeCtrl 1.1 http://tktreectrl.sourceforge.net/ ==> treectrl
+
+
===< support (may be alpha or beta quality) >=================================
@@ -84,19 +92,12 @@ TclX CVS/Hd(2005-02-07)
==> tclx (partial support; infox command and
XPG/3 message catalogs only)
-TkTreeCtrl 1.1 http://tktreectrl.sourceforge.net/ ==> treectrl
-
Tile 0.6 http://tktable.sourceforge.net/tile/ ==> tile
===< possibly available (not tested; alpha quality) >=========================
-BLT 2.4z http://sourceforge.net/projects/blt
- * see also tcltk-ext library on RAA
- (http://raa.ruby-lang.org/)
- ==> blt
-
winico CVS/Hd(2004-11-02)
http://tktable.sourceforge.net
==> winico (win32 only)
diff --git a/ext/tk/lib/tkextlib/blt.rb b/ext/tk/lib/tkextlib/blt.rb
index 965886762e..60ed39a0cf 100644
--- a/ext/tk/lib/tkextlib/blt.rb
+++ b/ext/tk/lib/tkextlib/blt.rb
@@ -105,6 +105,47 @@ module Tk
####################################################
+ def self.active_legend(graph)
+ tk_call_without_enc('Blt_ActiveLegend', graph)
+ end
+ def self.crosshairs(graph)
+ tk_call_without_enc('Blt_Crosshairs', graph)
+ end
+ def self.zoom_stack(graph)
+ tk_call_without_enc('Blt_ZoomStack', graph)
+ end
+ def self.print_key(graph)
+ tk_call_without_enc('Blt_PrintKey', graph)
+ end
+ def self.closest_point(graph)
+ tk_call_without_enc('Blt_ClosestPoint', graph)
+ end
+
+ module GraphCommand
+ def active_legend
+ tk_call_without_enc('Blt_ActiveLegend', @path)
+ self
+ end
+ def crosshairs
+ tk_call_without_enc('Blt_Crosshairs', @path)
+ self
+ end
+ def zoom_stack
+ tk_call_without_enc('Blt_ZoomStack', @path)
+ self
+ end
+ def print_key
+ tk_call_without_enc('Blt_PrintKey', @path)
+ self
+ end
+ def closest_point
+ tk_call_without_enc('Blt_ClosestPoint', @path)
+ self
+ end
+ end
+
+ ####################################################
+
autoload :PlotComponent,'tkextlib/blt/component.rb'
autoload :Barchart, 'tkextlib/blt/barchart.rb'
diff --git a/ext/tk/lib/tkextlib/blt/barchart.rb b/ext/tk/lib/tkextlib/blt/barchart.rb
index 624906b8bd..d8ecad834f 100644
--- a/ext/tk/lib/tkextlib/blt/barchart.rb
+++ b/ext/tk/lib/tkextlib/blt/barchart.rb
@@ -14,6 +14,7 @@ module Tk::BLT
WidgetClassNames[WidgetClassName] = self
include PlotComponent
+ include GraphCommand
def __boolval_optkeys
['bufferelements', 'invertxy']
diff --git a/ext/tk/lib/tkextlib/blt/bitmap.rb b/ext/tk/lib/tkextlib/blt/bitmap.rb
index 11ad5883d0..31cf8d4229 100644
--- a/ext/tk/lib/tkextlib/blt/bitmap.rb
+++ b/ext/tk/lib/tkextlib/blt/bitmap.rb
@@ -42,26 +42,41 @@ module Tk::BLT
alias _new new
def new(data, keys={})
- _new(:data, data, keys)
+ _new(:data, nil, data, keys)
end
alias define new
+ def new_with_name(name, data, keys={})
+ _new(:data, name, data, keys)
+ end
+ alias define_with_name new_with_name
+
def compose(text, keys={})
- _new(:text, text, keys)
+ _new(:text, nil, text, keys)
+ end
+
+ def compose_with_name(name, text, keys={})
+ _new(:text, name, text, keys)
end
end
- def initialize(type, data, keys = {})
- @id = BITMAP_ID.join(TkCore::INTERP._ip_id_)
- BITMAP_ID[1].succ!
- BITMAP_ID_TBL[@id] = self
+ def initialize(type, name, data, keys = {})
+ if name
+ @id = name
+ else
+ @id = BITMAP_ID.join(TkCore::INTERP._ip_id_)
+ BITMAP_ID[1].succ!
+ BITMAP_ID_TBL[@id] = self
+ end
@path = @id
- if type == :text
- tk_call('::blt::bitmap', 'compose', @id, *hash_kv(keys))
- else # :data
- tk_call('::blt::bitmap', 'define', @id, *hash_kv(keys))
+ unless bool(tk_call('::blt::bitmap', 'exists', @id))
+ if type == :text
+ tk_call('::blt::bitmap', 'compose', @id, data, *hash_kv(keys))
+ else # :data
+ tk_call('::blt::bitmap', 'define', @id, data, *hash_kv(keys))
+ end
end
end
diff --git a/ext/tk/lib/tkextlib/blt/busy.rb b/ext/tk/lib/tkextlib/blt/busy.rb
index c0740dc2d7..4726e466f4 100644
--- a/ext/tk/lib/tkextlib/blt/busy.rb
+++ b/ext/tk/lib/tkextlib/blt/busy.rb
@@ -13,6 +13,27 @@ module Tk::BLT
extend TkItemConfigMethod
TkCommandNames = ['::blt::busy'.freeze].freeze
+
+ ###########################
+
+ class Shield < TkWindow
+ def self.shield_path(win)
+ win = window(win) unless win.kind_of?(TkWindow)
+ if win.kind_of?(TkToplevel)
+ win.path + '._Busy'
+ else
+ win.path + '_Busy'
+ end
+ end
+
+ def initialize(win)
+ @path = self.class.shield_path(win)
+ end
+ end
+
+ def self.shield_path(win)
+ Tk::BLT::Busy::Shield.shield_path(win)
+ end
end
end
@@ -30,27 +51,6 @@ class << Tk::BLT::Busy
##################################
- class Shield < TkWindow
- def self.shield_path(win)
- win = window(win) unless win.kind_of?(TkWindow)
- if win.kind_of?(TkToplevel)
- win.path + '._Busy'
- else
- win.path + '_Busy'
- end
- end
-
- def initialize(win)
- @path = self.class.shield_path(win)
- end
- end
-
- def shield_path(win)
- Tk::BLT::Busy::Shield.shield_path(win)
- end
-
- ##################################
-
def hold(win, keys={})
tk_call('::blt::busy', 'hold', win, *hash_kv(keys))
end
diff --git a/ext/tk/lib/tkextlib/blt/component.rb b/ext/tk/lib/tkextlib/blt/component.rb
index 8e36946d0b..c5152ddab4 100644
--- a/ext/tk/lib/tkextlib/blt/component.rb
+++ b/ext/tk/lib/tkextlib/blt/component.rb
@@ -34,7 +34,7 @@ module Tk::BLT
end
private :__item_strval_optkeys
- def _item_listval_optkeys(id)
+ def __item_listval_optkeys(id)
['bindtags']
end
private :__item_listval_optkeys
@@ -266,8 +266,9 @@ module Tk::BLT
@cpath = @chart.path
Axis::OBJ_TBL[@cpath][@axis] = self
keys = _symbolkey2str(keys)
- unless keys.delete['without_creating']
- @chart.axis_create(@axis, keys)
+ unless keys.delete('without_creating')
+ # @chart.axis_create(@axis, keys)
+ tk_call(@chart, 'axis', 'create', @axis, keys)
end
end
@@ -420,8 +421,9 @@ module Tk::BLT
@cpath = @chart.path
Element::OBJ_TBL[@cpath][@element] = self
keys = _symbolkey2str(keys)
- unless keys.delete['without_creating']
- @chart.element_create(@element, keys)
+ unless keys.delete('without_creating')
+ # @chart.element_create(@element, keys)
+ tk_call(@chart, 'element', 'create', @element, keys)
end
end
@@ -623,8 +625,9 @@ module Tk::BLT
@cpath = @chart.path
Pen::OBJ_TBL[@cpath][@pen] = self
keys = _symbolkey2str(keys)
- unless keys.delete['without_creating']
- @chart.pen_create(@pen, keys)
+ unless keys.delete('without_creating')
+ # @chart.pen_create(@pen, keys)
+ tk_call(@chart, 'pen', 'create', @pen, keys)
end
end
@@ -784,6 +787,24 @@ module Tk::BLT
idnum.to_i # 'item id' is an integer number
end
+ def self.create_type(chart, type, keys={})
+ args, fontkeys = _parse_create_args(keys)
+ idnum = tk_call_without_enc(chart.path, 'create', type, *args)
+ chart.marker_configure(idnum, fontkeys) unless fontkeys.empty?
+ id = idnum.to_i # 'item id' is an integer number
+ obj = self.allocate
+ obj.instance_eval{
+ @parent = @chart = chart
+ @path = chart.path
+ @id = id
+ unless Tk::BLT::PlotComponent::MarkerID_TBL[@path]
+ Tk::BLT::PlotComponent::MarkerID_TBL[@path] = {}
+ end
+ Tk::BLT::PlotComponent::MarkerID_TBL[@path][@id] = self
+ }
+ obj
+ end
+
def initialize(parent, *args)
@parent = @chart = parent
@path = parent.path
@@ -980,12 +1001,10 @@ module Tk::BLT
###################
- def marker_create(type, *args)
- type.create(self, *args)
+ def axis_create(id=nil, keys={})
+ # tk_send('axis', 'create', tagid(id), keys)
+ Tk::BLT::PlotComponent::Axis.new(self, id, keys)
end
-
- ###################
-
def axis_delete(*ids)
tk_send('axis', 'delete', *(ids.collect{|id| tagid(id)}))
self
@@ -1033,6 +1052,10 @@ module Tk::BLT
###################
+ def element_create(id=nil, keys={})
+ # tk_send('element', 'create', tagid(id), keys)
+ Tk::BLT::PlotComponent::Element.new(self, id, keys)
+ end
def element_activate(id, *indices)
tk_send('element', 'activate', tagid(id), *indices)
self
@@ -1109,6 +1132,10 @@ module Tk::BLT
###################
+ def pen_create(id=nil, keys={})
+ # tk_send('pen', 'create', tagid(id), keys)
+ Tk::BLT::PlotComponent::Pen.new(self, id, keys)
+ end
def pen_delete(*ids)
tk_send('pen', 'delete', *(ids.collect{|id| tagid(id)}))
self
@@ -1137,6 +1164,28 @@ module Tk::BLT
###################
+ def marker_create(type, keys={})
+ case type
+ when :text, 'text'
+ Tk::BLT::PlotComponent::TextMarker.new(self, keys)
+ when :line, 'line'
+ Tk::BLT::PlotComponent::LineMarker.new(self, keys)
+ when :bitmap, 'bitmap'
+ Tk::BLT::PlotComponent::BitmapMarker.new(self, keys)
+ when :image, 'image'
+ Tk::BLT::PlotComponent::ImageMarker.new(self, keys)
+ when :polygon, 'polygon'
+ Tk::BLT::PlotComponent::PolygonMarker.new(self, keys)
+ when :window, 'window'
+ Tk::BLT::PlotComponent::WindowMarker.new(self, keys)
+ else
+ if type.kind_of?(Tk::BLT::PlotComponent::Marker)
+ type.new(self, keys)
+ else
+ Tk::BLT::PlotComponent::Marker.create_type(self, type, keys)
+ end
+ end
+ end
def marker_after(id, target=nil)
if target
tk_send_without_enc('marker', 'after', tagid(id), tagid(target))
@@ -1183,103 +1232,219 @@ module Tk::BLT
###################
def xaxis_cget(option)
- axis_cget('xaxis', option)
+ itemcget('xaxis', option)
end
def xaxis_configure(slot, value=None)
- axis_configure('xaxis', slot, value)
+ itemconfigure('xaxis', slot, value)
end
def xaxis_configinfo(slot=nil)
- axis_configinfo('xaxis', slot)
+ itemconfiginfo('xaxis', slot)
end
def current_xaxis_configinfo(slot=nil)
- current_axis_configinfo('xaxis', slot)
+ current_itemconfiginfo('xaxis', slot)
+ end
+ def xaxis_bind(context, *args)
+ if TkComm._callback_entry?(args[0]) || !block_given?
+ cmd = args.shift
+ else
+ cmd = Proc.new
+ end
+ _bind([path, 'xaxis', 'bind'], context, cmd, *args)
+ self
+ end
+ def xaxis_bind_append(context, *args)
+ if TkComm._callback_entry?(args[0]) || !block_given?
+ cmd = args.shift
+ else
+ cmd = Proc.new
+ end
+ _bind_append([path, 'xaxis', 'bind'], context, cmd, *args)
+ self
+ end
+ def xaxis_bind_remove(context)
+ _bind_remove([path, 'xaxis', 'bind'], context)
+ self
+ end
+ def xaxis_bindinfo(context=nil)
+ _bindinfo([path, 'xaxis', 'bind'], context)
end
def xaxis_invtransform(val)
- axis_invtransform('xaxis', val)
+ list(tk_send('xaxis', 'invtransform', val))
end
def xaxis_limits
- axis_limits('xaxis')
+ list(tk_send('xaxis', 'limits'))
end
def xaxis_transform(val)
- axis_transform('xaxis', val)
+ list(tk_send('xaxis', 'transform', val))
end
def xaxis_use(target=nil)
- axis_use('xaxis', target)
+ if target
+ Axis.id2obj(self, tk_send('xaxis', 'use', tagid(target)))
+ else
+ Axis.id2obj(self, tk_send('xaxis', 'use'))
+ end
end
def x2axis_cget(option)
- axis_cget('x2axis', option)
+ itemcget('x2axis', option)
end
def x2axis_configure(slot, value=None)
- axis_configure('x2axis', slot, value)
+ itemconfigure('x2axis', slot, value)
end
def x2axis_configinfo(slot=nil)
- axis_configinfo('x2axis', slot)
+ itemconfiginfo('x2axis', slot)
end
def current_x2axis_configinfo(slot=nil)
- current_axis_configinfo('x2axis', slot)
+ current_itemconfiginfo('x2axis', slot)
+ end
+ def x2axis_bind(context, *args)
+ if TkComm._callback_entry?(args[0]) || !block_given?
+ cmd = args.shift
+ else
+ cmd = Proc.new
+ end
+ _bind([path, 'x2axis', 'bind'], context, cmd, *args)
+ self
+ end
+ def x2axis_bind_append(context, *args)
+ if TkComm._callback_entry?(args[0]) || !block_given?
+ cmd = args.shift
+ else
+ cmd = Proc.new
+ end
+ _bind_append([path, 'x2axis', 'bind'], context, cmd, *args)
+ self
+ end
+ def x2axis_bind_remove(context)
+ _bind_remove([path, 'x2axis', 'bind'], context)
+ self
+ end
+ def x2axis_bindinfo(context=nil)
+ _bindinfo([path, 'x2axis', 'bind'], context)
end
def x2axis_invtransform(val)
- axis_invtransform('x2axis', val)
+ list(tk_send('x2axis', 'invtransform', val))
end
def x2axis_limits
- axis_limits('x2axis')
+ list(tk_send('x2axis', 'limits'))
end
def x2axis_transform(val)
- axis_transform('x2axis', val)
+ list(tk_send('x2axis', 'transform', val))
end
def x2axis_use(target=nil)
- axis_use('x2axis', target)
+ if target
+ Axis.id2obj(self, tk_send('x2axis', 'use', tagid(target)))
+ else
+ Axis.id2obj(self, tk_send('x2axis', 'use'))
+ end
end
def yaxis_cget(option)
- axis_cget('yaxis', option)
+ itemcget('yaxis', option)
end
def yaxis_configure(slot, value=None)
- axis_configure('yaxis', slot, value)
+ itemconfigure('yaxis', slot, value)
end
def yaxis_configinfo(slot=nil)
- axis_configinfo('yaxis', slot)
+ itemconfiginfo('yaxis', slot)
end
def current_yaxis_configinfo(slot=nil)
- current_axis_configinfo('yaxis', slot)
+ current_itemconfiginfo('yaxis', slot)
+ end
+ def yaxis_bind(context, *args)
+ if TkComm._callback_entry?(args[0]) || !block_given?
+ cmd = args.shift
+ else
+ cmd = Proc.new
+ end
+ _bind([path, 'yaxis', 'bind'], context, cmd, *args)
+ self
+ end
+ def yaxis_bind_append(context, *args)
+ if TkComm._callback_entry?(args[0]) || !block_given?
+ cmd = args.shift
+ else
+ cmd = Proc.new
+ end
+ _bind_append([path, 'yaxis', 'bind'], context, cmd, *args)
+ self
+ end
+ def yaxis_bind_remove(context)
+ _bind_remove([path, 'yaxis', 'bind'], context)
+ self
+ end
+ def yaxis_bindinfo(context=nil)
+ _bindinfo([path, 'yaxis', 'bind'], context)
end
def yaxis_invtransform(val)
- axis_invtransform('yaxis', val)
+ list(tk_send('yaxis', 'invtransform', val))
end
def yaxis_limits
- axis_limits('yaxis')
+ list(tk_send('yaxis', 'limits'))
end
def yaxis_transform(val)
- axis_transform('yaxis', val)
+ list(tk_send('yaxis', 'transform', val))
end
def yaxis_use(target=nil)
- axis_use('yaxis', target)
+ if target
+ Axis.id2obj(self, tk_send('yaxis', 'use', tagid(target)))
+ else
+ Axis.id2obj(self, tk_send('yaxis', 'use'))
+ end
end
def y2axis_cget(option)
- axis_cget('y2axis', option)
+ itemcget('y2axis', option)
end
def y2axis_configure(slot, value=None)
- axis_configure('y2axis', slot, value)
+ itemconfigure('y2axis', slot, value)
end
def y2axis_configinfo(slot=nil)
axis_configinfo('y2axis', slot)
end
def current_y2axis_configinfo(slot=nil)
- current_axis_configinfo('y2axis', slot)
+ current_itemconfiginfo('y2axis', slot)
+ end
+ def y2axis_bind(context, *args)
+ if TkComm._callback_entry?(args[0]) || !block_given?
+ cmd = args.shift
+ else
+ cmd = Proc.new
+ end
+ _bind([path, 'y2axis', 'bind'], context, cmd, *args)
+ self
+ end
+ def y2axis_bind_append(context, *args)
+ if TkComm._callback_entry?(args[0]) || !block_given?
+ cmd = args.shift
+ else
+ cmd = Proc.new
+ end
+ _bind_append([path, 'y2axis', 'bind'], context, cmd, *args)
+ self
+ end
+ def y2axis_bind_remove(context)
+ _bind_remove([path, 'y2axis', 'bind'], context)
+ self
+ end
+ def y2axis_bindinfo(context=nil)
+ _bindinfo([path, 'y2axis', 'bind'], context)
end
def y2axis_invtransform(val)
- axis_invtransform('y2axis', val)
+ list(tk_send('y2axis', 'invtransform', val))
end
def y2axis_limits
- axis_limits('y2axis')
+ list(tk_send('y2axis', 'limits'))
end
def y2axis_transform(val)
- axis_transform('y2axis', val)
+ list(tk_send('y2axis', 'transform', val))
end
def y2axis_use(target=nil)
- axis_use('y2axis', target)
+ if target
+ Axis.id2obj(self, tk_send('y2axis', 'use', tagid(target)))
+ else
+ Axis.id2obj(self, tk_send('y2axis', 'use'))
+ end
end
end
end
diff --git a/ext/tk/lib/tkextlib/blt/graph.rb b/ext/tk/lib/tkextlib/blt/graph.rb
index 0c49a70ec4..b16c72458a 100644
--- a/ext/tk/lib/tkextlib/blt/graph.rb
+++ b/ext/tk/lib/tkextlib/blt/graph.rb
@@ -14,6 +14,7 @@ module Tk::BLT
WidgetClassNames[WidgetClassName] = self
include PlotComponent
+ include GraphCommand
def __boolval_optkeys
['bufferelements', 'invertxy']
diff --git a/ext/tk/lib/tkextlib/blt/htext.rb b/ext/tk/lib/tkextlib/blt/htext.rb
index 29da9aa87f..3bc35b7e10 100644
--- a/ext/tk/lib/tkextlib/blt/htext.rb
+++ b/ext/tk/lib/tkextlib/blt/htext.rb
@@ -9,6 +9,11 @@ require 'tkextlib/blt.rb'
module Tk::BLT
class Htext<TkWindow
+ Htext_Var = TkVarAccess.new_hash('htext')
+ Htext_Widget = TkVarAccess.new('htext(widget)', :window)
+ Htext_File = TkVarAccess.new('htext(file)')
+ Htext_Line = TkVarAccess.new('htext(line)')
+
include TkItemConfigMethod
include Scrollable
diff --git a/ext/tk/lib/tkextlib/blt/stripchart.rb b/ext/tk/lib/tkextlib/blt/stripchart.rb
index faac8d830b..b8cbf8bc34 100644
--- a/ext/tk/lib/tkextlib/blt/stripchart.rb
+++ b/ext/tk/lib/tkextlib/blt/stripchart.rb
@@ -14,6 +14,7 @@ module Tk::BLT
WidgetClassNames[WidgetClassName] = self
include PlotComponent
+ include GraphCommand
def __boolval_optkeys
['bufferelements', 'buffergraph', 'invertxy']
diff --git a/ext/tk/lib/tkextlib/blt/table.rb b/ext/tk/lib/tkextlib/blt/table.rb
index c80e9ac55c..dc9cd0627e 100644
--- a/ext/tk/lib/tkextlib/blt/table.rb
+++ b/ext/tk/lib/tkextlib/blt/table.rb
@@ -256,11 +256,20 @@ class << Tk::BLT::Table
container
end
- def add(container, win=nil, *args)
- if win
- tk_call('::blt::table', container, _epath(win), *args)
- else
+ def add(container, *args)
+ if args.empty?
tk_call('::blt::table', container)
+ else
+ args = args.collect{|arg|
+ if arg.kind_of?(TkWindow)
+ _epath(arg)
+ elsif arg.kind_of?(Array) # index
+ arg.join(',')
+ else
+ arg
+ end
+ }
+ tk_call('::blt::table', container, *args)
end
end
diff --git a/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb b/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb
index 0e8fd86c0f..655ad87185 100644
--- a/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb
+++ b/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb
@@ -17,6 +17,8 @@ TkPackage.require('treectrl')
module Tk
class TreeCtrl < TkWindow
+ BindTag_FileList = TkBindTag.new_by_name('TreeCtrlFileList')
+
def self.package_version
begin
TkPackage.require('treectrl')
@@ -25,6 +27,9 @@ module Tk
end
end
+ HasColumnCreateCommand =
+ (TkPackage.vcompare(self.package_version, '1.1') >= 0)
+
# dummy ::
# pkgIndex.tcl of TreeCtrl-1.0 doesn't support auto_load for
# 'loupe' command (probably it is bug, I think).
@@ -146,7 +151,7 @@ module Tk::TreeCtrl::ConfigMethod
None
when 'dragimage'
- obj
+ None
when 'element'
obj
@@ -155,7 +160,7 @@ module Tk::TreeCtrl::ConfigMethod
obj
when 'marquee'
- obj
+ None
when 'notify'
obj
@@ -171,6 +176,10 @@ module Tk::TreeCtrl::ConfigMethod
def tagid(mixed_id)
if mixed_id == 'debug'
['debug', None]
+ elsif mixed_id == 'dragimage'
+ ['dragimage', None]
+ elsif mixed_id == 'marquee'
+ ['marquee', None]
elsif mixed_id.kind_of?(Array)
[mixed_id[0], treectrl_tagid(*mixed_id)]
else
@@ -237,6 +246,17 @@ module Tk::TreeCtrl::ConfigMethod
end
private :__item_configinfo_struct
+
+ def __item_font_optkeys(id)
+ if id.kind_of?(Array) && (id[0] == 'element' ||
+ (id[0].kind_of?(Array) && id[0][1] == 'element'))
+ []
+ else
+ ['font']
+ end
+ end
+ private :__item_font_optkeys
+
def __item_numstrval_optkeys(id)
if id == 'debug'
['displaydelay']
@@ -249,14 +269,28 @@ module Tk::TreeCtrl::ConfigMethod
def __item_boolval_optkeys(id)
if id == 'debug'
['data', 'display', 'enable']
+ elsif id == 'dragimage'
+ ['visible']
+ elsif id == 'marquee'
+ ['visible']
elsif id.kind_of?(Array)
case id[0]
+ when 'item'
+ ['button', 'visible']
when 'column'
['button', 'expand', 'squeeze', 'sunken', 'visible', 'widthhack']
when 'element'
['filled', 'showfocus']
+ when 'notify'
+ ['active']
+ when 'style'
+ ['detach']
else
- super(id)
+ if id[0].kind_of?(Array) && id[0][1] == 'element'
+ ['filled', 'showfocus']
+ else
+ super(id)
+ end
end
else
super(id)
@@ -280,8 +314,14 @@ module Tk::TreeCtrl::ConfigMethod
['itembackground']
when 'element'
['relief']
+ when 'style'
+ ['union']
else
- []
+ if id[0].kind_of?(Array) && id[0][1] == 'element'
+ ['relief']
+ else
+ []
+ end
end
else
[]
@@ -328,17 +368,17 @@ module Tk::TreeCtrl::ConfigMethod
current_itemconfiginfo('debug', slot)
end
- def dragimage_cget(tagOrId, option)
- itemcget(['dragimage', tagOrId], option)
+ def dragimage_cget(option)
+ itemcget('dragimage', option)
end
- def dragimage_configure(tagOrId, slot, value=None)
- itemconfigure(['dragimage', tagOrId], slot, value)
+ def dragimage_configure(slot, value=None)
+ itemconfigure('dragimage', slot, value)
end
- def dragimage_configinfo(tagOrId, slot=nil)
- itemconfiginfo(['dragimage', tagOrId], slot)
+ def dragimage_configinfo(slot=nil)
+ itemconfiginfo('dragimage', slot)
end
- def current_dragimage_configinfo(tagOrId, slot=nil)
- current_itemconfiginfo(['dragimage', tagOrId], slot)
+ def current_dragimage_configinfo(slot=nil)
+ current_itemconfiginfo('dragimage', slot)
end
def element_cget(tagOrId, option)
@@ -380,17 +420,17 @@ module Tk::TreeCtrl::ConfigMethod
current_itemconfiginfo([['item', 'element'], [item, column, elem]], slot)
end
- def marquee_cget(tagOrId, option)
- itemcget(['marquee', tagOrId], option)
+ def marquee_cget(option)
+ itemcget('marquee', option)
end
- def marquee_configure(tagOrId, slot, value=None)
- itemconfigure(['marquee', tagOrId], slot, value)
+ def marquee_configure(slot, value=None)
+ itemconfigure('marquee', slot, value)
end
- def marquee_configinfo(tagOrId, slot=nil)
- itemconfiginfo(['marquee', tagOrId], slot)
+ def marquee_configinfo(slot=nil)
+ itemconfiginfo('marquee', slot)
end
- def current_marquee_configinfo(tagOrId, slot=nil)
- current_itemconfiginfo(['marquee', tagOrId], slot)
+ def current_marquee_configinfo(slot=nil)
+ current_itemconfiginfo('marquee', slot)
end
def notify_cget(win, pattern, option)
@@ -757,17 +797,20 @@ class Tk::TreeCtrl
end
alias item_first_child item_firstchild
- def item_hashbutton(item, st=None)
+ def item_hasbutton(item, st=None)
if st == None
- bool(tk_send('item', 'hashbutton'))
+ bool(tk_send('item', 'hasbutton'))
else
- tk_send('item', 'hashbutton', st)
+ tk_send('item', 'hasbutton', st)
self
end
end
- def item_hashbutton?(item)
- item_hashbutton(item)
+ alias item_has_button item_hasbutton
+
+ def item_hasbutton?(item)
+ item_hasbutton(item)
end
+ alias item_has_button? item_hasbutton?
def item_index(item)
list(tk_send('item', 'index', item))
@@ -811,8 +854,8 @@ class Tk::TreeCtrl
end
alias item_next_sibling item_nextsibling
- def item_numchildren()
- number(tk_send('item', 'numchildren'))
+ def item_numchildren(item)
+ number(tk_send('item', 'numchildren', item))
end
alias item_num_children item_numchildren
alias item_children_size item_numchildren
@@ -850,10 +893,10 @@ class Tk::TreeCtrl
opts = opts.collect{|param|
if param.kind_of?(Hash)
param = _symbolkey2str(param)
- if param.key('column')
+ if param.key?('column')
key = '-column'
desc = param.delete('column')
- elsif param.key('element')
+ elsif param.key?('element')
key = '-element'
desc = param.delete('element')
else
@@ -863,7 +906,7 @@ class Tk::TreeCtrl
if param.empty?
param = None
else
- param = __conv_item_keyonly_opts(item, param).to_a
+ param = hash_kv(__conv_item_keyonly_opts(item, param))
end
if key
@@ -874,7 +917,7 @@ class Tk::TreeCtrl
elsif param.kind_of?(Array)
if param[2].kind_of?(Hash)
- param[2] = __conv_item_keyonly_opts(item, param[2]).to_a
+ param[2] = hash_kv(__conv_item_keyonly_opts(item, param[2]))
end
param
@@ -898,17 +941,15 @@ class Tk::TreeCtrl
end
private :_item_sort_core
- def item_sort_not_really(item, *opts)
- _item_sort_core(false, item, *opts)
- end
-
def item_sort(item, *opts)
_item_sort_core(true, item, *opts)
end
+ def item_sort_not_really(item, *opts)
+ _item_sort_core(false, item, *opts)
+ end
def item_state_forcolumn(item, column, *args)
tk_send('item', 'state', 'forcolumn', item, column, *args)
- self
end
alias item_state_for_column item_state_forcolumn
@@ -922,7 +963,6 @@ class Tk::TreeCtrl
def item_state_set(item, *args)
tk_send('item', 'state', 'set', item, *args)
- self
end
def item_style_elements(item, column)
@@ -1230,7 +1270,8 @@ class Tk::TreeCtrl
def _conv_style_layout_val(sty, val)
case sty.to_s
when 'padx', 'pady', 'ipadx', 'ipady'
- number(val)
+ lst = list(val)
+ (lst.size == 1)? lst[0]: lst
when 'detach'
bool(val)
when 'union'
@@ -1256,6 +1297,7 @@ class Tk::TreeCtrl
else
ret = Hash.new
Hash[*simplelist(tk_send('style', 'layout', style, elem))].each{|k, v|
+ k = k[1..-1]
ret[k] = _conv_style_layout_val(k, v)
}
ret
@@ -1599,18 +1641,20 @@ class Tk::TreeCtrl::Item < TkObject
end
alias first_child firstchild
- def hashbutton(st=None)
+ def hasbutton(st=None)
if st == None
- @tree.item_hashbutton(@id)
+ @tree.item_hasbutton(@id)
else
- @tree.item_hashbutton(@id, st)
+ @tree.item_hasbutton(@id, st)
self
end
end
+ alias has_button hasbutton
- def hashbutton?
- @tree.item_hashbutton(@id)
+ def hasbutton?
+ @tree.item_hasbutton(@id)
end
+ alias has_button? hasbutton?
def index
@tree.item_index(@id)
@@ -1685,6 +1729,10 @@ class Tk::TreeCtrl::Item < TkObject
def sort(*opts)
@tree.item_sort(@id, *opts)
end
+ def sort_not_really(*opts)
+ @tree.item_sort_not_really(@id, *opts)
+ self
+ end
def state_forcolumn(column, *args)
@tree.item_state_forcolumn(@id, column, *args)
@@ -1829,3 +1877,149 @@ class Tk::TreeCtrl::Style < TkObject
end
end
end
+
+module Tk::TreeCtrl::BindCallback
+ include Tk
+ extend Tk
+end
+
+class << Tk::TreeCtrl::BindCallback
+ def cursorCheck(w, x, y)
+ tk_call('::TreeCtrl::CursorCheck', w, x, y)
+ end
+ def cursorCheckAux(w)
+ tk_call('::TreeCtrl::CursorCheckAux', w)
+ end
+ def cursorCancel(w)
+ tk_call('::TreeCtrl::CursorCancel', w)
+ end
+ def buttonPress1(w, x, y)
+ tk_call('::TreeCtrl::ButtonPress1', w, x, y)
+ end
+ def doubleButton1(w, x, y)
+ tk_call('::TreeCtrl::DoubleButton1', w, x, y)
+ end
+ def motion1(w, x, y)
+ tk_call('::TreeCtrl::Motion1', w, x, y)
+ end
+ def leave1(w, x, y)
+ tk_call('::TreeCtrl::Leave1', w, x, y)
+ end
+ def release1(w, x, y)
+ tk_call('::TreeCtrl::Release1', w, x, y)
+ end
+ def beginSelect(w, el)
+ tk_call('::TreeCtrl::BeginSelect', w, el)
+ end
+ def motion(w, le)
+ tk_call('::TreeCtrl::Motion', w, el)
+ end
+ def beginExtend(w, el)
+ tk_call('::TreeCtrl::BeginExtend', w, el)
+ end
+ def beginToggle(w, el)
+ tk_call('::TreeCtrl::BeginToggle', w, el)
+ end
+ def cancelRepeat
+ tk_call('::TreeCtrl::CancelRepeat')
+ end
+ def autoScanCheck(w, x, y)
+ tk_call('::TreeCtrl::AutoScanCheck', w, x, y)
+ end
+ def autoScanCheckAux(w)
+ tk_call('::TreeCtrl::AutoScanCheckAux', w)
+ end
+ def autoScanCancel(w)
+ tk_call('::TreeCtrl::AutoScanCancel', w)
+ end
+ def up_down(w, n)
+ tk_call('::TreeCtrl::UpDown', w, n)
+ end
+ def left_right(w, n)
+ tk_call('::TreeCtrl::LeftRight', w, n)
+ end
+ def setActiveItem(w, idx)
+ tk_call('::TreeCtrl::SetActiveItem', w, idx)
+ end
+ def extendUpDown(w, amount)
+ tk_call('::TreeCtrl::ExtendUpDown', w, amount)
+ end
+ def dataExtend(w, el)
+ tk_call('::TreeCtrl::DataExtend', w, el)
+ end
+ def cancel(w)
+ tk_call('::TreeCtrl::Cancel', w)
+ end
+ def selectAll(w)
+ tk_call('::TreeCtrl::selectAll', w)
+ end
+ def marqueeBegin(w, x, y)
+ tk_call('::TreeCtrl::MarqueeBegin', w, x, y)
+ end
+ def marqueeUpdate(w, x, y)
+ tk_call('::TreeCtrl::MarqueeUpdate', w, x, y)
+ end
+ def marqueeEnd(w, x, y)
+ tk_call('::TreeCtrl::MarqueeEnd', w, x, y)
+ end
+ def scanMark(w, x, y)
+ tk_call('::TreeCtrl::ScanMark', w, x, y)
+ end
+ def scanDrag(w, x, y)
+ tk_call('::TreeCtrl::ScanDrag', w, x, y)
+ end
+
+ # filelist-bindings
+ def fileList_button1(w, x, y)
+ tk_call('::TreeCtrl::FileListButton1', w, x, y)
+ end
+ def fileList_motion1(w, x, y)
+ tk_call('::TreeCtrl::FileListMotion1', w, x, y)
+ end
+ def fileList_motion(w, x, y)
+ tk_call('::TreeCtrl::FileListMotion', w, x, y)
+ end
+ def fileList_leave1(w, x, y)
+ tk_call('::TreeCtrl::FileListLeave1', w, x, y)
+ end
+ def fileList_release1(w, x, y)
+ tk_call('::TreeCtrl::FileListRelease1', w, x, y)
+ end
+ def fileList_edit(w, i, s, e)
+ tk_call('::TreeCtrl::FileListEdit', w, i, s, e)
+ end
+ def fileList_editCancel(w)
+ tk_call('::TreeCtrl::FileListEditCancel', w)
+ end
+ def fileList_autoScanCheck(w, x, y)
+ tk_call('::TreeCtrl::FileListAutoScanCheck', w, x, y)
+ end
+ def fileList_autoScanCheckAux(w)
+ tk_call('::TreeCtrl::FileListAutoScanCheckAux', w)
+ end
+
+ def entryOpen(w, item, col, elem)
+ tk_call('::::TreeCtrl::EntryOpen', w, item, col, elem)
+ end
+ def entryExpanderOpen(w, item, col, elem)
+ tk_call('::TreeCtrl::EntryExpanderOpen', w, item, col, elem)
+ end
+ def entryClose(w, accept)
+ tk_call('::TreeCtrl::EntryClose', w, accept)
+ end
+ def entryExpanderKeypress(w)
+ tk_call('::TreeCtrl::EntryExpanderKeypress', w)
+ end
+ def textOpen(w, item, col, elem, width=0, height=0)
+ tk_call('::TreeCtrl::TextOpen', w, item, col, elem, width, height)
+ end
+ def textExpanderOpen(w, item, col, elem, width)
+ tk_call('::TreeCtrl::TextOpen', w, item, col, elem, width)
+ end
+ def textClose(w, accept)
+ tk_call('::TreeCtrl::TextClose', w, accept)
+ end
+ def textExpanderKeypress(w)
+ tk_call('::TreeCtrl::TextExpanderKeypress', w)
+ end
+end
diff --git a/ext/tk/sample/tkextlib/blt/barchart5.rb b/ext/tk/sample/tkextlib/blt/barchart5.rb
new file mode 100644
index 0000000000..db181d10ca
--- /dev/null
+++ b/ext/tk/sample/tkextlib/blt/barchart5.rb
@@ -0,0 +1,101 @@
+#!/usr/bin/env ruby
+require 'tk'
+require 'tkextlib/blt'
+
+load File.join(File.dirname(File.expand_path(__FILE__)),
+ 'scripts', 'stipples.rb')
+
+TkOption.add('*graph.x.Title', 'X Axis Label')
+TkOption.add('*graph.y.Title', 'Y Axis Label')
+TkOption.add('*graph.title', 'A Simple Barchart')
+TkOption.add('*graph.x.Font', 'Times 10')
+TkOption.add('*graph.Element.Relief', :raised)
+
+visual = Tk.root.winfo_screenvisual
+if visual != 'staticgray' && visual != 'grayscale'
+ TkOption.add('*graph.LineMarker.color', 'yellow')
+ TkOption.add('*graph.Element.Background', 'white')
+ TkOption.add('*graph.Legend.activeForeground', 'pink')
+ TkOption.add('*print.background', 'yellow')
+ TkOption.add('*quit.background', 'red')
+ TkOption.add('*graph.background', 'palegreen')
+ TkOption.add('*graph.plotBackground', 'lightblue')
+end
+
+htext = Tk::BLT::Htext.new(:widgetname=>'.htext', :text=><<EOD)
+ This is an example of the barchart widget. The barchart has
+ many components; x and y axis, legend, crosshairs, elements, etc.
+ To create a postscript file "bar.ps", press the %%
+
+ ruby {
+ b = TkButton.new(Tk::BLT::Htext::Htext_Widget.window,
+ :widgetname=>'print', :text=>'Print',
+ :command=>proc{
+ $graph.postsript(:output=>'bar.ps')
+ })
+ Tk::BLT::Htext::Htext_Widget.window.append(b)
+ }
+
+%% button.
+%%
+
+ ruby {
+ $graph = Tk::BLT::Barchart.new(:widgetname=>'.htext.graph',
+ :relief=>:raised, :borderwidth=>2)
+ $graph.xaxis_configure(:rotate=>90, :stepsize=>0)
+ Tk::BLT::Htext::Htext_Widget.window.append($graph,
+ :fill=>:both, :padx=>4)
+ }
+
+%%
+ Hit the %%
+
+ ruby {
+ b = TkButton.new(Tk::BLT::Htext::Htext_Widget.window,
+ :widgetname=>'quit', :text=>'Quit',
+ :command=>proc{ exit })
+ Tk::BLT::Htext::Htext_Widget.window.append(b)
+ }
+
+%% button when you've seen enough.%%
+
+ ruby {
+ l = TkLabel.new(Tk::BLT::Htext::Htext_Widget.window, :bitmap=>'BLT')
+ Tk::BLT::Htext::Htext_Widget.window.append(l, :padx=>20)
+ }
+
+%%
+EOD
+
+names = %w(One Two Three Four Five Six Seven Eight)
+if visual == 'staticgray' || visual == 'grayscale'
+ fgcolors = %w(white white white white white white white white)
+ bgcolors = %w(black black black black black black black black)
+else
+ fgcolors = %w(yellow orange red magenta purple blue cyan green)
+ bgcolors = %w(yellow4 orange4 red4 magenta4 purple4 blue4 cyan4 green4)
+end
+
+numColors = names.length
+
+Tk::TCL_PRECISION.value = 15
+
+x = Tk::BLT::Vector.new
+y = Tk::BLT::Vector.new
+x.seq(-5.0, 5.0, 0.2)
+y.expr("sin(#{x})")
+barWidth = 0.19
+
+$graph.element_create('sin', :relief=>:raised, :borderwidth=>1,
+ :x=>x, :y=>y, :barwidth=>barWidth)
+
+Tk::BLT::Table.add(Tk.root, htext, :fill=>:both)
+
+Tk.root.minsize(0, 0)
+
+Tk::BLT.zoom_stack($graph)
+Tk::BLT.crosshairs($graph)
+Tk::BLT.active_legend($graph)
+Tk::BLT.closest_point($graph)
+
+Tk.mainloop
diff --git a/ext/tk/sample/tkextlib/blt/graph7.rb b/ext/tk/sample/tkextlib/blt/graph7.rb
new file mode 100644
index 0000000000..27fbe53d97
--- /dev/null
+++ b/ext/tk/sample/tkextlib/blt/graph7.rb
@@ -0,0 +1,40 @@
+#!/usr/bin/env ruby
+require 'tk'
+require 'tkextlib/blt'
+
+length = 250000
+graph = Tk::BLT::Graph.new(:title=>"Scatter Plot\n#{length} points")
+graph.xaxis_configure(:loose=>false, :title=>'X Axis Label')
+graph.yaxis_configure(:title=>'Y Axis Label')
+graph.legend_configure(:activerelief=>:sunken, :background=>'')
+
+Tk::BLT::Table.add(Tk.root, graph, [0,0], :fill=>:both)
+
+v_x = Tk::BLT::Vector.new(length)
+v_y = Tk::BLT::Vector.new(length)
+v_x.expr("random(#{v_x})")
+v_y.expr("random(#{v_y})")
+v_x.sort(v_y)
+
+plot = Tk::BLT::PlotComponent::Element.new(graph, :symbol=>:square,
+ :color=>'green4', :fill=>'green2',
+ :linewidth=>0, :outlinewidth=>1,
+ :pixels=>4, :label=>'plot',
+ :xdata=>v_x, :ydata=>v_y)
+
+Tk.root.minsize(0, 0)
+
+#graph.zoom_stack
+#graph.crosshairs
+#graph.active_legend
+#graph.closest_point
+Tk::BLT.zoom_stack(graph)
+Tk::BLT.crosshairs(graph)
+Tk::BLT.active_legend(graph)
+Tk::BLT.closest_point(graph)
+
+Tk::BLT::Busy.hold(graph)
+Tk.update
+Tk::BLT::Busy.release(graph)
+
+Tk.mainloop
diff --git a/ext/tk/sample/tkextlib/blt/graph7a.rb b/ext/tk/sample/tkextlib/blt/graph7a.rb
new file mode 100644
index 0000000000..a014f72fc7
--- /dev/null
+++ b/ext/tk/sample/tkextlib/blt/graph7a.rb
@@ -0,0 +1,63 @@
+#!/usr/bin/env ruby
+require 'tk'
+require 'tkextlib/blt'
+
+file = File.join(File.dirname(File.expand_path(__FILE__)),
+ 'images', 'buckskin.gif')
+bgTexture = TkPhotoImage.new(:file=>file)
+
+TkOption.add('*Graph.Tile', bgTexture)
+TkOption.add('*Label.Tile', bgTexture)
+TkOption.add('*Frame.Tile', bgTexture)
+TkOption.add('*Htext.Tile', bgTexture)
+TkOption.add('*TileOffset', 0)
+TkOption.add('*HighlightThickness', 0)
+TkOption.add('*Element.ScaleSybols', false)
+TkOption.add('*Element.Smooth', :linear)
+TkOption.add('*activeLine.Color', 'yellow4')
+TkOption.add('*activeLine.Fill', 'yellow')
+TkOption.add('*activeLine.LineWidth', 0)
+TkOption.add('*Element.Pixels', 3)
+TkOption.add('*Graph.halo', '7i')
+
+if Tk.root.winfo_screenvisual != 'staticgray'
+ TkOption.add('*print.background', 'yellow')
+ TkOption.add('*quit.background', 'red')
+end
+
+length = 250000
+graph = Tk::BLT::Graph.new(:title=>"Scatter Plot\n#{length} points")
+graph.xaxis_configure(:loose=>false, :title=>'X Axis Label')
+graph.yaxis_configure(:title=>'Y Axis Label')
+graph.legend_configure(:activerelief=>:sunken, :background=>'')
+
+Tk::BLT::Table.add(Tk.root, graph, [0,0], :fill=>:both)
+
+v_x = Tk::BLT::Vector.new(length)
+v_y = Tk::BLT::Vector.new(length)
+v_x.expr("random(#{v_x})")
+v_y.expr("random(#{v_y})")
+v_x.sort(v_y)
+
+plot = Tk::BLT::PlotComponent::Element.new(graph, :symbol=>:square,
+ :color=>'green4', :fill=>'green2',
+ :linewidth=>0, :outlinewidth=>1,
+ :pixels=>4, :label=>'plot',
+ :xdata=>v_x, :ydata=>v_y)
+
+Tk.root.minsize(0, 0)
+
+#graph.zoom_stack
+#graph.crosshairs
+#graph.active_legend
+#graph.closest_point
+Tk::BLT.zoom_stack(graph)
+Tk::BLT.crosshairs(graph)
+Tk::BLT.active_legend(graph)
+Tk::BLT.closest_point(graph)
+
+Tk::BLT::Busy.hold(graph)
+Tk.update
+Tk::BLT::Busy.release(graph)
+
+Tk.mainloop
diff --git a/ext/tk/sample/tkextlib/blt/graph7b.rb b/ext/tk/sample/tkextlib/blt/graph7b.rb
new file mode 100644
index 0000000000..c589f18d86
--- /dev/null
+++ b/ext/tk/sample/tkextlib/blt/graph7b.rb
@@ -0,0 +1,41 @@
+#!/usr/bin/env ruby
+require 'tk'
+require 'tkextlib/blt'
+
+length = 250000
+graph = Tk::BLT::Graph.new(:title=>"Scatter Plot\n#{length} points")
+graph.xaxis_configure(:loose=>false, :title=>'X Axis Label')
+graph.yaxis_configure(:title=>'Y Axis Label')
+graph.legend_configure(:activerelief=>:sunken, :background=>'')
+
+Tk::BLT::Table.add(Tk.root, graph, [0,0], :fill=>:both)
+
+x = Array.new(length)
+y = Array.new(length)
+(0...length).each{|i|
+ x[i] = rand
+ y[i] = rand
+}
+
+plot = Tk::BLT::PlotComponent::Element.new(graph, :symbol=>:square,
+ :color=>'green4', :fill=>'green2',
+ :linewidth=>0, :outlinewidth=>1,
+ :pixels=>4, :label=>'plot',
+ :xdata=>x, :ydata=>y)
+
+Tk.root.minsize(0, 0)
+
+#graph.zoom_stack
+#graph.crosshairs
+#graph.active_legend
+#graph.closest_point
+Tk::BLT.zoom_stack(graph)
+Tk::BLT.crosshairs(graph)
+Tk::BLT.active_legend(graph)
+Tk::BLT.closest_point(graph)
+
+Tk::BLT::Busy.hold(graph)
+Tk.update
+Tk::BLT::Busy.release(graph)
+
+Tk.mainloop
diff --git a/ext/tk/sample/tkextlib/blt/graph7c.rb b/ext/tk/sample/tkextlib/blt/graph7c.rb
new file mode 100644
index 0000000000..495b66f4af
--- /dev/null
+++ b/ext/tk/sample/tkextlib/blt/graph7c.rb
@@ -0,0 +1,45 @@
+#!/usr/bin/env ruby
+require 'tk'
+require 'tkextlib/blt'
+
+length = 250000
+graph = Tk::BLT::Graph.new(:title=>"Scatter Plot\n#{length} points")
+graph.xaxis_configure(:loose=>false, :title=>'X Axis Label')
+graph.yaxis_configure(:title=>'Y Axis Label')
+graph.legend_configure(:activerelief=>:sunken, :background=>'')
+
+Tk::BLT::Table.add(Tk.root, graph, [0,0], :fill=>:both)
+
+v_x = Tk::BLT::Vector.new(length)
+v_y = Tk::BLT::Vector.new(length)
+x = Array.new(length)
+y = Array.new(length)
+(0...length).each{|i|
+ x[i] = rand
+ y[i] = rand
+}
+v_x.set(x)
+v_y.set(y)
+
+plot = Tk::BLT::PlotComponent::Element.new(graph, :symbol=>:square,
+ :color=>'green4', :fill=>'green2',
+ :linewidth=>0, :outlinewidth=>1,
+ :pixels=>4, :label=>'plot',
+ :xdata=>v_x, :ydata=>v_y)
+
+Tk.root.minsize(0, 0)
+
+#graph.zoom_stack
+#graph.crosshairs
+#graph.active_legend
+#graph.closest_point
+Tk::BLT.zoom_stack(graph)
+Tk::BLT.crosshairs(graph)
+Tk::BLT.active_legend(graph)
+Tk::BLT.closest_point(graph)
+
+Tk::BLT::Busy.hold(graph)
+Tk.update
+Tk::BLT::Busy.release(graph)
+
+Tk.mainloop
diff --git a/ext/tk/sample/tkextlib/blt/images/buckskin.gif b/ext/tk/sample/tkextlib/blt/images/buckskin.gif
new file mode 100644
index 0000000000..e2d7be9d62
--- /dev/null
+++ b/ext/tk/sample/tkextlib/blt/images/buckskin.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/blt/images/qv100.t.gif b/ext/tk/sample/tkextlib/blt/images/qv100.t.gif
new file mode 100644
index 0000000000..1e738ee86b
--- /dev/null
+++ b/ext/tk/sample/tkextlib/blt/images/qv100.t.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/blt/images/sample.gif b/ext/tk/sample/tkextlib/blt/images/sample.gif
new file mode 100644
index 0000000000..1d8a4010c3
--- /dev/null
+++ b/ext/tk/sample/tkextlib/blt/images/sample.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/blt/plot1.rb b/ext/tk/sample/tkextlib/blt/plot1.rb
new file mode 100644
index 0000000000..07dff48292
--- /dev/null
+++ b/ext/tk/sample/tkextlib/blt/plot1.rb
@@ -0,0 +1,9 @@
+#!/usr/bin/env ruby
+require 'tk'
+require 'tkextlib/blt'
+
+graph = Tk::BLT::Graph.new.pack
+plot = Tk::BLT::PlotComponent::Element.new(graph, :linewidth=>0, :label=>'foo')
+plot.data([[1.0, 3.4], [1.1, 2.8], [1.2, 3.1], [1.4, 2.9]].flatten)
+
+Tk.mainloop
diff --git a/ext/tk/sample/tkextlib/blt/plot1b.rb b/ext/tk/sample/tkextlib/blt/plot1b.rb
new file mode 100644
index 0000000000..eb41e361f9
--- /dev/null
+++ b/ext/tk/sample/tkextlib/blt/plot1b.rb
@@ -0,0 +1,10 @@
+#!/usr/bin/env ruby
+require 'tk'
+require 'tkextlib/blt'
+
+graph = Tk::BLT::Graph.new.pack
+plot = graph.element_create
+plot.configure(:linewidth=>0, :label=>'foo',
+ :data=>[[1.0, 3.4], [1.1, 2.8], [1.2, 3.1], [1.4, 2.9]].flatten)
+
+Tk.mainloop
diff --git a/ext/tk/sample/tkextlib/blt/readme.txt b/ext/tk/sample/tkextlib/blt/readme.txt
new file mode 100644
index 0000000000..fe12dd88a3
--- /dev/null
+++ b/ext/tk/sample/tkextlib/blt/readme.txt
@@ -0,0 +1,2 @@
+The scripts and image files in this directory are based on demo files
+of Tcl/Tk's BLT extention.
diff --git a/ext/tk/sample/tkextlib/blt/scripts/stipples.rb b/ext/tk/sample/tkextlib/blt/scripts/stipples.rb
new file mode 100644
index 0000000000..47f3c4d063
--- /dev/null
+++ b/ext/tk/sample/tkextlib/blt/scripts/stipples.rb
@@ -0,0 +1,156 @@
+$stipples = {} unless $stipples
+
+$stipples['bdiagonal1'] = Tk::BLT::Bitmap.new(<<EOD)
+#define bdiagonal1_width 8
+#define bdiagonal1_height 8
+static unsigned char bdiagonal1_bits[] = {
+ 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11};
+EOD
+
+$stipples['bdiagonal2'] = Tk::BLT::Bitmap.new(<<EOD)
+#define bdiagonal2_width 8
+#define bdiagonal2_height 8
+static unsigned char bdiagonal2_bits[] = {
+ 0x08, 0x04, 0x02, 0x01, 0x80, 0x40, 0x20, 0x10};
+EOD
+
+$stipples['checker2'] = Tk::BLT::Bitmap.new(<<EOD)
+#define checker2_width 8
+#define checker2_height 8
+static unsigned char checker2_bits[] = {
+ 0x33, 0x33, 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc};
+EOD
+
+
+$stipples['checker3'] = Tk::BLT::Bitmap.new(<<EOD)
+#define checker3_width 8
+#define checker3_height 8
+static unsigned char checker3_bits[] = {
+ 0x0f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0};
+EOD
+
+$stipples['cross1'] = Tk::BLT::Bitmap.new(<<EOD)
+#define cross1_width 8
+#define cross1_height 8
+static unsigned char cross_bits[] = {
+ 0xff, 0xaa, 0xff, 0xaa, 0xff, 0xaa, 0xff, 0xaa};
+EOD
+
+$stipples['cross2'] = Tk::BLT::Bitmap.new(<<EOD)
+#define cross2_width 8
+#define cross2_height 8
+static unsigned char cross2_bits[] = {
+ 0xff, 0x88, 0x88, 0x88, 0xff, 0x88, 0x88, 0x88};
+EOD
+
+$stipples['cross3'] = Tk::BLT::Bitmap.new(<<EOD)
+#define cross3_width 8
+#define cross3_height 8
+static unsigned char cross3_bits[] = {
+ 0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
+EOD
+
+$stipples['crossdiag'] = Tk::BLT::Bitmap.new(<<EOD)
+#define crossdiag_width 8
+#define crossdiag_height 8
+static unsigned char crossdiag2_bits[] = {
+ 0x18, 0x24, 0x42, 0x81, 0x81, 0x42, 0x24, 0x18};
+EOD
+
+$stipples['dot1'] = Tk::BLT::Bitmap.new(<<EOD)
+#define dot1_width 8
+#define dot1_height 8
+static unsigned char dot1_bits[] = {
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa};
+EOD
+
+$stipples['dot2'] = Tk::BLT::Bitmap.new(<<EOD)
+#define dot2_width 8
+#define dot2_height 8
+static unsigned char dot2_bits[] = {
+ 0x55, 0x00, 0x55, 0x00, 0x55, 0x00, 0x55, 0x00};
+EOD
+
+$stipples['dot3'] = Tk::BLT::Bitmap.new(<<EOD)
+#define dot3_width 8
+#define dot3_height 8
+static unsigned char dot3_bits[] = {
+ 0x11, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00};
+EOD
+
+$stipples['dot4'] = Tk::BLT::Bitmap.new(<<EOD)
+#define dot4_width 8
+#define dot4_height 8
+static unsigned char dot4_bits[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+EOD
+
+$stipples['fdiagonal1'] = Tk::BLT::Bitmap.new(<<EOD)
+#define fdiagonal1_width 8
+#define fdiagonal1_height 8
+static unsigned char fdiagonal1_bits[] = {
+ 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88};
+EOD
+
+$stipples['fdiagonal2'] = Tk::BLT::Bitmap.new(<<EOD)
+#define fdiagonal2_width 8
+#define fdiagonal2_height 8
+static unsigned char fdiagonal2_bits[] = {
+ 0x10, 0x20, 0x40, 0x80, 0x01, 0x02, 0x04, 0x08};
+EOD
+
+$stipples['hline1'] = Tk::BLT::Bitmap.new(<<EOD)
+#define hline1_width 8
+#define hline1_height 8
+static unsigned char hline1_bits[] = {
+ 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00};
+EOD
+
+$stipples['hline2'] = Tk::BLT::Bitmap.new(<<EOD)
+#define hline2_width 8
+#define hline2_height 8
+static unsigned char hline2_bits[] = {
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00};
+EOD
+
+$stipples['lbottom'] = Tk::BLT::Bitmap.new(<<EOD)
+#define lbottom_width 8
+#define lbottom_height 8
+static unsigned char lbottom_bits[] = {
+ 0x00, 0x11, 0x11, 0x77, 0x00, 0x11, 0x11, 0x77};
+EOD
+
+$stipples['ltop'] = Tk::BLT::Bitmap.new(<<EOD)
+#define ltop_width 8
+#define ltop_height 8
+static unsigned char ltop_bits[] = {
+ 0xee, 0x88, 0x88, 0x00, 0xee, 0x88, 0x88, 0x00};
+EOD
+
+$stipples['rbottom'] = Tk::BLT::Bitmap.new(<<EOD)
+#define rbottom_width 8
+#define rbottom_height 8
+static unsigned char rbottom_bits[] = {
+ 0x00, 0x88, 0x88, 0xee, 0x00, 0x88, 0x88, 0xee};
+EOD
+
+$stipples['rtop'] = Tk::BLT::Bitmap.new(<<EOD)
+#define rtop_width 8
+#define rtop_height 8
+static unsigned char rtop_bits[] = {
+ 0x77, 0x11, 0x11, 0x00, 0x77, 0x11, 0x11, 0x00};
+EOD
+
+$stipples['vline1'] = Tk::BLT::Bitmap.new(<<EOD)
+#define vline1_width 8
+#define vline1_height 8
+static unsigned char vline1_bits[] = {
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
+EOD
+
+$stipples['vline2'] = Tk::BLT::Bitmap.new(<<EOD)
+#define vline2_width 8
+#define vline2_height 8
+static unsigned char vline2_bits[] = {
+ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33};
+EOD
diff --git a/ext/tk/sample/tkextlib/blt/winop1.rb b/ext/tk/sample/tkextlib/blt/winop1.rb
new file mode 100644
index 0000000000..e94138cd94
--- /dev/null
+++ b/ext/tk/sample/tkextlib/blt/winop1.rb
@@ -0,0 +1,40 @@
+#!/usr/bin/env ruby
+require 'tk'
+require 'tkextlib/blt'
+
+file = File.join(File.dirname(File.expand_path(__FILE__)),
+ 'images', 'sample.gif')
+if File.exist?(file)
+ src = TkPhotoImage.new(:file=>file)
+else
+ fail RuntimeError, 'no image file'
+end
+
+width = src.width
+height = src.height
+
+TkOption.add('*Label.font', '*helvetica*10*')
+TkOption.add('*Label.background', 'white')
+
+l_img0 = TkLabel.new(:image=>src)
+l_hdr0 = TkLabel.new(:text=>"#{width} x #{height}")
+l_ftr0 = TkLabel.new(:text=>'100%')
+Tk.root.background('white')
+
+(2..10).each{|i|
+ iw = width/i
+ ih = height/i
+ r = '%6g'%(100.0/i)
+ dst = TkPhotoImage.new(:width=>iw, :height=>ih)
+ Tk::BLT::Winop.image_resample(src, dst, :sinc)
+ l_hdr = TkLabel.new(:text=>"#{iw} x #{ih}")
+ l_ftr = TkLabel.new(:text=>"#{r}%")
+ l_img = TkLabel.new(:image=>dst)
+ Tk::BLT::Table.add(Tk.root,
+ [0,i], l_hdr,
+ [1,i], l_img,
+ [2,i], l_ftr)
+ Tk.update
+}
+
+Tk.mainloop
diff --git a/ext/tk/sample/tkextlib/blt/winop2.rb b/ext/tk/sample/tkextlib/blt/winop2.rb
new file mode 100644
index 0000000000..1f674ee893
--- /dev/null
+++ b/ext/tk/sample/tkextlib/blt/winop2.rb
@@ -0,0 +1,28 @@
+#!/usr/bin/env ruby
+require 'tk'
+require 'tkextlib/blt'
+
+file = File.join(File.dirname(File.expand_path(__FILE__)),
+ 'images', 'qv100.t.gif')
+if File.exist?(file)
+ src = TkPhotoImage.new(:file=>file)
+else
+ fail RuntimeError, 'no image file'
+end
+
+width = src.width
+height = src.height
+
+TkOption.add('*Label.font', '*helvetica*10*')
+TkOption.add('*Label.background', 'white')
+
+[0, 90, 180, 270, 360, 45].each_with_index{|r, i|
+ dest = TkPhotoImage.new
+ Tk::BLT::Winop.image_rotate(src, dest, r)
+ l_txt = TkLabel.new(:text=>"#{r} degrees")
+ l_img = TkLabel.new(:image=>dest)
+ Tk::BLT::Table.add(Tk.root, [0,i], l_img, [1,i], l_txt)
+ Tk.update
+}
+
+Tk.mainloop
diff --git a/ext/tk/sample/tkextlib/treectrl/bitmaps.rb b/ext/tk/sample/tkextlib/treectrl/bitmaps.rb
new file mode 100644
index 0000000000..c621e61fdc
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/bitmaps.rb
@@ -0,0 +1,75 @@
+#
+# Demo: Bitmaps
+#
+def demoBitmaps(t)
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.configure(:showroot=>false, :showbuttons=>false, :showlines=>false,
+ :selectmode=>:browse, :orient=>:horizontal, :wrap=>'5 items',
+ :showheader=>false, :backgroundimage=>@images['sky'])
+ else
+ t.configure(:showroot=>false, :showbuttons=>false, :showlines=>false,
+ :selectmode=>:browse, :orient=>:horizontal, :wrap=>'5 items',
+ :showheader=>false)
+ end
+
+ if $HasColumnCreate
+ t.column_create(:itembackground=>['gray90', []])
+ else
+ t.column_configure(0, :itembackground=>['gray90', []])
+ end
+
+ t.element_create('elemTxt', :text,
+ :fill=>[@SystemHighlightText, ['selected', 'focus']])
+ t.element_create('elemSelTxt', :rect, :showfocus=>true,
+ :fill=>[@SystemHighlight, ['selected', 'focus']])
+ t.element_create('elemSelBmp', :rect, :outlinewidth=>4,
+ :outline=>[@SystemHighlight, ['selected', 'focus']])
+ t.element_create('elemBmp', :bitmap,
+ :foreground=>[@SystemHighlight, ['selected', 'focus']],
+ :background=>'linen',
+ :bitmap=>['question' ['selected']])
+
+ s = t.style_create('STYLE', :orient=>:vertical)
+ t.style_elements(s, ['elemSelBmp', 'elemBmp', 'elemSelTxt', 'elemTxt'])
+ t.style_layout(s, 'elemSelBmp', :union=>'elemBmp', :ipadx=>6, :ipady=>6)
+ t.style_layout(s, 'elemBmp', :pady=>[0, 6], :expand=>:we)
+ t.style_layout(s, 'elemSelTxt', :union=>'elemTxt', :ipadx=>2)
+ t.style_layout(s, 'elemTxt', :expand=>:we)
+
+ # Set default item style
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.defaultstyle = [s]
+ end
+
+ bitmap_names = %w(error gray75 gray50 gray25 gray12
+ hourglass info questhead question warning)
+
+ bitmap_names.each{|name|
+ i = t.item_create
+ unless (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.item_style_set(i, 0, s)
+ end
+ t.item_text(i, 0, name)
+ t.item_element_configure(i, 0, 'elemBmp', :bitmap=>name)
+ t.item_lastchild(:root, i)
+ }
+
+ bitmap_names.each{|name|
+ i = t.item_create
+ t.item_style_set(i, 0, s)
+ t.item_text(i, 0, name)
+ if true
+ t.item_element_configure(i, 0, 'elemBmp', :bitmap=>name,
+ :foreground=>['brown', ''],
+ :background=>['', ''])
+ else
+ t.item_element_configure(i, 0, 'elemBmp', :bitmap=>name,
+ :foreground=>[
+ @SystemHighlight, ['selected', 'focus'],
+ 'brown', []
+ ],
+ :background=>['', []])
+ end
+ t.item_lastchild(:root, i)
+ }
+end
diff --git a/ext/tk/sample/tkextlib/treectrl/demo.rb b/ext/tk/sample/tkextlib/treectrl/demo.rb
new file mode 100644
index 0000000000..1f822a6548
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/demo.rb
@@ -0,0 +1,1256 @@
+#!/usr/bin/env ruby
+
+require 'tk'
+require 'tkextlib/treectrl'
+
+$ScriptDir = File.dirname(File.expand_path(__FILE__))
+
+$HasColumnCreate = Tk::TreeCtrl::HasColumnCreateCommand
+
+class TkTreeCtrl_demo
+ def initialize(dir)
+ @ScriptDir = dir || '.'
+
+ @thisPlatform = Tk::PLATFORM['platform']
+ if @thisPlatform == 'unix' && Tk.windowingsystem == 'aqua'
+ @thisPlatform = 'macosx'
+ end
+
+ @RandomN = [500]
+
+ @images = Hash.new
+ @sel_images = Hash.new
+
+ @popup = Hash.new
+ @mTree = Hash.new
+ @mHeader = Hash.new
+
+ @non_clear_list = []
+
+ @demoCmd = Hash.new
+ @demoFile = Hash.new
+
+ # Get default colors
+ w = TkListbox.new
+ @SystemButtonFace = w[:highlightbackground]
+ @SystemHighlight = w[:selectbackground]
+ @SystemHighlightText = w[:selectforeground]
+ w.destroy
+
+ ####################
+
+ make_source_window()
+ make_menubar()
+ make_main_window()
+ make_list_popup()
+ make_header_popup()
+
+ init_pics('sky')
+
+ ####################
+
+ @tree2.bind('ButtonPress-3',
+ proc{|w, x, y, rootx, rooty|
+ show_list_popup(w, x, y, rootx, rooty)
+ }, '%W %x %y %X %Y')
+
+ # Allow "scan" bindings
+ if @thisPlatform == 'windows'
+ @tree2.bind_remove('Control-ButtonPress-3')
+ end
+
+ ####################
+
+ init_demo_scripts_module()
+ load_demo_scripts()
+ init_demo_list()
+
+ ####################
+
+ @tree1.notify_bind(@tree1, 'Selection',
+ proc{|c, t|
+ if c == 1
+ item = t.selection_get[0]
+ demo_set(@demoCmd[item], @demoFile[item])
+ end
+ }, '%c %T')
+
+ # When one item is selected in the demo list, display the styles in
+ # that item.
+ # See DemoClear for why the tag "DontDelete" is used
+ @tree2.notify_bind('DontDelete', 'Selection',
+ proc{|c, t|
+ display_styles_in_item(t.selection_get[0]) if c == 1
+ }, '%c %T')
+ end
+
+ ##########################
+
+ def init_pics(*args)
+ args.each{|pat|
+ pat = "#{pat}.gif"
+ unless TkImage.names.find{|img| (name = @images.key(img)) && File.fnmatch(pat, name)}
+ Dir.glob(File.join(@ScriptDir, 'pics', pat)).each{|file|
+ name = File.basename(file, '.gif')
+ img = TkPhotoImage.new(:file=>file)
+ @images[name] = img
+ @sel_images[name] = TkPhotoImage.new
+ @sel_images[name].copy(img)
+ Tk::TreeCtrl.image_tint(@sel_images[name], @SystemHighlight, 128)
+ }
+ end
+ }
+ end
+
+ ##########################
+
+ private
+
+ def make_menubar
+ menuspec = [
+ [['File']]
+ ]
+ if Tk::PLATFORM['platform'] != 'unix'
+ TkConsole.eval('.console conf -height 8')
+ menuspec[0] << ['Console', proc{
+ if TkComm.bool(TkConsole.eval('winfo ismapped .'))
+ TkConsole.hide
+ else
+ TkConsole.show
+ end
+ }]
+ end
+ menuspec[0] << ['View Source', proc{toggle_source_window()}]
+ menuspec[0] << ['Quit', proc{exit}]
+ Tk.root.add_menubar(menuspec)
+ end
+
+ def make_source_window
+ @src_top = TkToplevel.new
+ f = TkFrame.new(@src_top, :borderwidth=>0)
+ case @thisPlatform
+ when 'macintosh', 'macos'
+ font = TkFont.new(['Geneva', 9])
+ when 'unix'
+ font = TkFont.new(['Courier', -12])
+ else
+ font = TkFont.new(['Courier', 9])
+ end
+
+ @src_txt = TkText.new(f, :font=>font, :tabs=>font.measure('1234'),
+ :wrap=>:none)
+ xscr = @src_txt.xscrollbar(TkScrollbar.new(f))
+ yscr = @src_txt.yscrollbar(TkScrollbar.new(f))
+
+ f.pack(:expand=>true, :fill=>:both)
+ f.grid_columnconfigure(0, :weight=>1)
+ f.grid_rowconfigure(0, :weight=>1)
+ @src_txt.grid(:row=>0, :column=>0, :sticky=>:news)
+ xscr.grid(:row=>1, :column=>0, :sticky=>:we)
+ yscr.grid(:row=>0, :column=>1, :sticky=>:ns)
+
+ @src_top.protocol('WM_DELETE_WINDOW', proc{@src_top.withdraw})
+ @src_top.geometry('-0+0')
+ @src_top.withdraw
+ end
+
+ def show_source(file)
+ @src_top.title("Demo Source: #{file}")
+ @src_txt.value = IO.read(File.join(@ScriptDir, file))
+ @src_txt.set_insert('1.0')
+ end
+
+ def toggle_source_window
+ if @src_top.winfo_mapped?
+ @src_top.withdraw
+ else
+ @src_top.deiconify
+ end
+ end
+
+ def tree_plus_scrollbars_in_a_frame(parent, h, v)
+ f = TkFrame.new(parent, :borderwidth=>1, :relief=>:sunken)
+ case @thisPlatform
+ when 'macintosh'
+ font = TkFont.new(['Geneva', 9])
+ when 'macos'
+ font = TkFont.new(['Lucida Grande', 11])
+ when 'unix'
+ font = TkFont.new(['Helvetica', -12])
+ else
+ # There is a bug on my Win98 box with Tk_MeasureChars() and
+ # MS Sans Serif 8.
+ font = TkFont.new(['MS Sans', 8])
+ end
+
+ tree = Tk::TreeCtrl.new(f, :highlightthickness=>0,
+ :borderwidth=>0, :font=>font)
+ tree[:xscrollincrement] = 20
+ tree.debug_configure(:enable=>false, :display=>false)
+
+ if h
+ h_scr = TkScrollbar.new(f, :orient=>:horizontal,
+ :command=>proc{|*args| tree.xview(*args)})
+ tree.notify_bind(h_scr, 'Scroll-x',
+ proc{|w, l, u| w.set(l, u)}, '%W %l %u')
+ h_scr.bind('ButtonPress-1', proc{tree.set_focus})
+ end
+
+ if v
+ v_scr = TkScrollbar.new(f, :orient=>:vertical,
+ :command=>proc{|*args| tree.yview(*args)})
+ tree.notify_bind(v_scr, 'Scroll-y',
+ proc{|w, l, u| w.set(l, u)}, '%W %l %u')
+ v_scr.bind('ButtonPress-1', proc{tree.set_focus})
+ end
+
+ f.grid_columnconfigure(0, :weight=>1)
+ f.grid_rowconfigure(0, :weight=>1)
+ tree.grid(:row=>0, :column=>0, :sticky=>:news)
+ h_scr.grid(:row=>1, :column=>0, :sticky=>:we) if h
+ v_scr.grid(:row=>0, :column=>1, :sticky=>:ns) if v
+
+ [f, tree]
+ end
+
+ def make_main_window
+ Tk.root.title('Tk::TreeCtrl Demo')
+
+ case @thisPlatform
+ when 'macintosh', 'macosx'
+ Tk.root.geometry('+40+40')
+ else
+ Tk.root.geometry('+0+30')
+ end
+
+ pane1 = TkPanedWindow.new(:orient=>:vertical, :borderwidth=>0)
+ pane2 = TkPanedWindow.new(:orient=>:horizontal, :borderwidth=>0)
+
+ # Tree + scrollbar: demos
+ f1, @tree1 = tree_plus_scrollbars_in_a_frame(nil, false, true)
+ @tree1.configure(:showbuttons=>false, :showlines=>:false,
+ :showroot=>false, :height=>100)
+ if $HasColumnCreate
+ @tree1.column_create(:text=>'List of Demos',
+ :expand=>true, :button=>false)
+ else
+ @tree1.column_configure(0, :text=>'List of Demos',
+ :expand=>true, :button=>false)
+ end
+
+ # Tree + scrollbar: styles + elements in list
+ f4, @tree4 = tree_plus_scrollbars_in_a_frame(nil, false, true)
+ @tree4.configure(:showroot=>false, :height=>140)
+ if $HasColumnCreate
+ @tree4.column_create(:text=>'Elements and Styles',
+ :expand=>true, :button=>false)
+ else
+ @tree4.column_configure(0, :text=>'Elements and Styles',
+ :expand=>true, :button=>false)
+ end
+
+ # Tree + scrollbar: styles + elements in selected item
+ f3, @tree3 = tree_plus_scrollbars_in_a_frame(nil, false, true)
+ @tree3.configure(:showroot=>false)
+ if $HasColumnCreate
+ @tree3.column_create(:text=>'Styles in Item',
+ :expand=>true, :button=>false)
+ else
+ @tree3.column_configure(0, :text=>'Styles in Item',
+ :expand=>true, :button=>false)
+ end
+
+ pane1.add(f1, f4, f3, :height=>150)
+ pane1.pack(:expand=>true, :fill=>:both)
+
+ # Frame on right
+ f2_base = TkFrame.new
+
+ # Tree + scrollbars
+ f2, @tree2 = tree_plus_scrollbars_in_a_frame(f2_base, true, true)
+ @tree2.configure(:indent=>19)
+ @tree2.debug_configure(:enable=>false, :display=>true,
+ :erasecolor=>'pink', :displaydelay=>30)
+
+ # Give it a big border to debug drawing
+ @tree2.configure(:borderwidth=>6, :relief=>:ridge, :highlightthickness=>3)
+
+ f2_base.grid_columnconfigure(0, :weight=>1)
+ f2_base.grid_rowconfigure(0, :weight=>1)
+ f2.grid(:row=>0, :column=>0, :sticky=>:news, :pady=>0)
+
+ pane2.add(pane1, :width=>200)
+ pane2.add(f2_base, :width=>450)
+
+ pane2.pack(:expand=>true, :fill=>:both)
+
+ ###
+ # A treectrl widget can generate the following built-in events:
+ # <ActiveItem> called when the active item changes
+ # <Collapse-before> called before an item is closed
+ # <Collapse-after> called after an item is closed
+ # <Expand-before> called before an item is opened
+ # <Expand-after> called after an item is opened
+ # <Selection> called when items are added to or removed from the selection
+ # <Scroll-x> called when horizontal scroll position changes
+ # <Scroll-y> called when vertical scroll position changes
+ #
+ # The application programmer can define custom events to be
+ # generated by the "T notify generate" command. The following events
+ # are generated by the example bindings.
+
+ @tree2.notify_install_event('Header')
+ @tree2.notify_install_detail('Header', 'invoke')
+
+ @tree2.notify_install_event('Drag')
+ @tree2.notify_install_detail('Drag', 'begin')
+ @tree2.notify_install_detail('Drag', 'end')
+ @tree2.notify_install_detail('Drag', 'receive')
+
+ @tree2.notify_install_event('Edit')
+ @tree2.notify_install_detail('Edit', 'accept')
+ end
+
+ def make_list_popup
+ @popup[:bgimg] = TkVariable.new
+ @popup[:bgmode] = TkVariable.new
+ @popup[:debug] = Hash.new{|h, k| h[k] = TkVariable.new}
+ @popup[:doublebuffer] = TkVariable.new
+ @popup[:linestyle] = TkVariable.new
+ @popup[:orient] = TkVariable.new
+ @popup[:selectmode] = TkVariable.new
+ @popup[:show] = Hash.new{|h, k| h[k] = TkVariable.new}
+
+ menuspec = [
+ [ 'Collapse', [], nil, '', {:menu_config=>{:tearoff=>false}} ],
+
+ [ 'Expand', [], nil, '', {:menu_config=>{:tearoff=>false}} ]
+ ]
+
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ menuspec << \
+ [ 'Background Image',
+ [
+ [ 'none', [@popup[:bgimg], 'none'], nil, '',
+ {:command=>proc{@tree2.backgroundimage = ''}} ],
+ [ 'sky', [@popup[:bgimg], 'sky'], nil, '',
+ {:command=>proc{
+ @tree2.backgroundimage = @images[@popup[:bgimg].value]}} ]
+ ],
+ nil, '', {:menu_config=>{:tearoff=>false}}
+ ]
+ end
+
+ menuspec.concat([
+ [ 'Background Mode',
+ %w(column index row visindex).collect{|val|
+ [ val, [@popup[:bgmode], val] , nil, '',
+ {:command=>proc{@tree2.backgroundmode = @popup[:bgmode].value}} ]
+ },
+ nil, '', {:menu_config=>{:tearoff=>false}}
+ ],
+
+ [ 'Debug',
+ [
+ [ 'Data', @popup[:debug][:data], nil, '',
+ {:command=>proc{
+ @tree2.debug_configure(:data=>@popup[:debug][:data].value)
+ }
+ } ],
+ [ 'Display', @popup[:debug][:display], nil, '',
+ {:command=>proc{
+ @tree2.debug_configure(:display=>@popup[:debug][:display].value)
+ }
+ } ],
+ [ 'Enable', @popup[:debug][:enable], nil, '',
+ {:command=>proc{
+ @tree2.debug_configure(:enable=>@popup[:debug][:enable].value)
+ }
+ } ]
+ ],
+ nil, '', {:menu_config=>{:tearoff=>false}}
+ ],
+
+ [ 'Buffering',
+ [
+ [ 'none', [@popup[:doublebuffer], 'none'], nil, '',
+ {:command=>proc{
+ @tree2.doublebuffer = @popup[:doublebuffer].value
+ }
+ } ],
+ [ 'item', [@popup[:doublebuffer], 'item'], nil, '',
+ {:command=>proc{
+ @tree2.doublebuffer = @popup[:doublebuffer].value
+ }
+ } ],
+ [ 'window', [@popup[:doublebuffer], 'window'], nil, '',
+ {:command=>proc{
+ @tree2.doublebuffer = @popup[:doublebuffer].value
+ }
+ } ]
+ ],
+ nil, '', {:menu_config=>{:tearoff=>false}}
+ ],
+
+ [ 'Line style',
+ [
+ [ 'dot', [@popup[:linestyle], 'dot'], nil, '',
+ {:command=>proc{@tree2.linestyle = @popup[:linestyle].value}} ],
+ [ 'solid', [@popup[:linestyle], 'solid'], nil, '',
+ {:command=>proc{@tree2.linestyle = @popup[:linestyle].value}} ]
+ ],
+ nil, '', {:menu_config=>{:tearoff=>false}}
+ ],
+
+ [ 'Orient',
+ [
+ [ 'Horizontal', [@popup[:orient], 'horizontal'], nil, '',
+ {:command=>proc{@tree2.orient = @popup[:orient].value}} ],
+ [ 'Vertical', [@popup[:orient], 'vertical'], nil, '',
+ {:command=>proc{@tree2.orient = @popup[:orient].value}} ]
+ ],
+ nil, '', {:menu_config=>{:tearoff=>false}}
+ ],
+
+ [ 'Selectmode',
+ %w(list browse extended multiple single).collect{|val|
+ [ val, [@popup[:selectmode], val] , nil, '',
+ {:command=>proc{@tree2.selectmode = @popup[:selectmode].value}} ]
+ },
+ nil, '', {:menu_config=>{:tearoff=>false}}
+ ],
+
+ [ 'Show',
+ [
+ [ 'Buttons', @popup[:show][:buttons], nil, '',
+ {:command=>proc{
+ @tree2.showbuttons = @popup[:show][:buttons].value
+ }
+ } ],
+ [ 'Header', @popup[:show][:header], nil, '',
+ {:command=>proc{
+ @tree2.showheader = @popup[:show][:header].value
+ }
+ } ],
+ [ 'Lines', @popup[:show][:lines], nil, '',
+ {:command=>proc{
+ @tree2.showlines = @popup[:show][:lines].value
+ }
+ } ],
+ [ 'Root', @popup[:show][:root], nil, '',
+ {:command=>proc{
+ @tree2.showroot = @popup[:show][:root].value
+ }
+ } ],
+ [ 'Root Button', @popup[:show][:rootbutton], nil, '',
+ {:command=>proc{
+ @tree2.showrootbutton = @popup[:show][:rootbutton].value
+ }
+ } ]
+ ],
+ nil, '', {:menu_config=>{:tearoff=>false}}
+ ],
+
+ [ 'Visible', [], nil, '', {:menu_config=>{:tearoff=>false}} ]
+ ])
+
+ m = TkMenu.new_menuspec(menuspec, @tree2, false)
+ @non_clear_list << m
+ @mTree[@tree2] = m
+ end
+
+ def show_list_popup(w, x, y, rootx, rooty)
+ id = w.identify(x, y)
+ unless id.empty?
+ if id[0] == 'header'
+ col = id[1]
+ @popup[:column].value = col
+ @popup[:arrow].value = w.column_cget(col, :arrow)
+ @popup[:arrowside].value = w.column_cget(col, :arrowside)
+ @popup[:arrowgravity].value = w.column_cget(col, :arrowgravity)
+ @popup[:expand].value = w.column_cget(col, :expand)
+ @popup[:sqeeeze].value = w.column_cget(col, :squeeze)
+ @popup[:justify].value = w.column_cget(col, :justify)
+ @mHeader[w].popup(rootx, rooty)
+ return
+ end
+ end
+
+ m = @mTree[w].entrycget('Collapse', :menu)
+ m.delete(0, :end)
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ m.add_command(:label=>'All', :command=>proc{w.item_collapse(:all)})
+ else
+ m.add_command(:label=>'All', :command=>proc{w.collapse(:all)})
+ end
+ unless id.empty?
+ if id[0] == 'item'
+ item = id[1]
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ m.add_command(:label=>"Item #{item}",
+ :command=>proc{w.item_collapse(item)})
+ m.add_command(:label=>"Item #{item} (recurse)",
+ :command=>proc{w.item_collapse_recurse(item)})
+ else
+ m.add_command(:label=>"Item #{item}",
+ :command=>proc{w.collapse(item)})
+ m.add_command(:label=>"Item #{item} (recurse)",
+ :command=>proc{w.collapse_recurse(item)})
+ end
+ end
+ end
+
+ m = @mTree[w].entrycget('Expand', :menu)
+ m.delete(0, :end)
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ m.add_command(:label=>'All', :command=>proc{w.item_expand(:all)})
+ else
+ m.add_command(:label=>'All', :command=>proc{w.expand(:all)})
+ end
+ unless id.empty?
+ if id[0] == 'item'
+ item = id[1]
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ m.add_command(:label=>"Item #{item}",
+ :command=>proc{w.item_expand(item)})
+ m.add_command(:label=>"Item #{item} (recurse)",
+ :command=>proc{w.item_expand_recurse(item)})
+ else
+ m.add_command(:label=>"Item #{item}",
+ :command=>proc{w.expand(item)})
+ m.add_command(:label=>"Item #{item} (recurse)",
+ :command=>proc{w.expand_recurse(item)})
+ end
+ end
+ end
+
+ [:data, :display, :enable].each{|k|
+ @popup[:debug][k].value = w.debug_cget(k)
+ }
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ @popup[:bgimg].value = @images.key(w[:backgroundimage])
+ end
+ @popup[:bgmode].value = w[:backgroundmode]
+ @popup[:doublebuffer].value = w[:doublebuffer]
+ @popup[:linestyle].value = w[:linestyle]
+ @popup[:orient].value = w[:orient]
+ @popup[:selectmode].value = w[:selectmode]
+ @popup[:show][:buttons].value = w[:showbuttons]
+ @popup[:show][:header].value = w[:showheader]
+ @popup[:show][:lines].value = w[:showlines]
+ @popup[:show][:root].value = w[:showroot]
+ @popup[:show][:rootbutton].value = w[:showrootbutton]
+
+ m = @mTree[w].entrycget('Visible', :menu)
+ m.delete(0, :end)
+ @popup[:visible] = []
+ (0...(w.numcolumns)).each{|i|
+ @popup[:visible][i] = TkVariable.new(w.column_cget(i, :visible))
+ txt = w.column_cget(i, :text)
+ img_name = w.column_cget(i, :image)
+ img_name = @images.key(img_name) if img_name.kind_of?(TkImage)
+ m.add_checkbutton(:variable=>@popup[:visible][i],
+ :label=>"Column #{i} \"#{txt}\" [#{img_name}]",
+ :command=>proc{w.column_configure(i, :visible=>@popup[:visible][i].value)})
+ }
+
+ @mTree[w].popup(rootx, rooty)
+ end
+
+ def make_header_popup
+ @popup[:column] = TkVariable.new unless @popup[:column]
+ @popup[:arrow] = TkVariable.new
+ @popup[:arrowside] = TkVariable.new
+ @popup[:arrowgravity] = TkVariable.new
+ @popup[:expand] = TkVariable.new
+ @popup[:squeeze] = TkVariable.new
+ @popup[:justify] = TkVariable.new
+
+ menuspec = [
+ [ 'Arrow',
+ [
+ [ 'None', [@popup[:arrow], 'none'], nil, '',
+ {:command=>proc{
+ @tree2.column_configure(@popup[:column].value, :arrow=>:none)
+ }
+ } ],
+ [ 'Up', [@popup[:arrow], 'up'], nil, '',
+ {:command=>proc{
+ @tree2.column_configure(@popup[:column].value, :arrow=>:up)
+ }
+ } ],
+ [ 'Down', [@popup[:arrow], 'down'], nil, '',
+ {:command=>proc{
+ @tree2.column_configure(@popup[:column].value, :arrow=>:down)
+ }
+ } ],
+
+ '---',
+
+ [ 'Side Left', [@popup[:arrowside], 'left'], nil, '',
+ {:command=>proc{
+ @tree2.column_configure(@popup[:column].value,
+ :arrowside=>:left)
+ }
+ } ],
+ [ 'Side Right', [@popup[:arrowside], 'right'], nil, '',
+ {:command=>proc{
+ @tree2.column_configure(@popup[:column].value,
+ :arrowside=>:right)
+ }
+ } ],
+
+ '---',
+
+ [ 'Gravity Left', [@popup[:arrowgravity], 'left'], nil, '',
+ {:command=>proc{
+ @tree2.column_configure(@popup[:column].value,
+ :arrowgravity=>:left)
+ }
+ } ],
+ [ 'Gravity Right', [@popup[:arrowgravity], 'right'], nil, '',
+ {:command=>proc{
+ @tree2.column_configure(@popup[:column].value,
+ :arrowgravity=>:right)
+ }
+ } ],
+ ],
+ nil, '', {:menu_config=>{:tearoff=>false}} ],
+
+ [ 'Expand', @popup[:expand], nil, '',
+ {:command=>proc{
+ @tree2.column_configure(@popup[:column].value,
+ :expand=>@popup[:expand].value)
+ }
+ } ],
+
+ [ 'Squeeze', @popup[:squeeze], nil, '',
+ {:command=>proc{
+ @tree2.column_configure(@popup[:column].value,
+ :squeeze=>@popup[:squeeze].value)
+ }
+ } ],
+
+ [ 'Justify',
+ [
+ [ 'Left', [@popup[:justify], 'left'], nil, '',
+ {:command=>proc{
+ @tree2.column_configure(@popup[:column].value, :justify=>:left)
+ }
+ } ],
+ [ 'Center', [@popup[:justify], 'center'], nil, '',
+ {:command=>proc{
+ @tree2.column_configure(@popup[:column].value,
+ :justify=>:center)
+ }
+ } ],
+ [ 'Right', [@popup[:justify], 'right'], nil, '',
+ {:command=>proc{
+ @tree2.column_configure(@popup[:column].value,
+ :justify=>:right)
+ }
+ } ]
+ ],
+ nil, '', {:menu_config=>{:tearoff=>false}} ]
+ ]
+
+ m = TkMenu.new_menuspec(menuspec, @tree2, false)
+ @non_clear_list << m
+ @mHeader[@tree2] = m
+ end
+
+ ###########################
+
+ def init_demo_scripts_module
+ @demo_scripts = Module.new
+
+ master = self
+
+ scriptDir = @ScriptDir
+
+ thisPlatform = @thisPlatform
+
+ randomN = @RandomN
+
+ images = @images
+ sel_images = @sel_images
+
+ systemButtonFace = @SystemButtonFace
+ systemHighlight = @SystemHighlight
+ systemHighlightText = @SystemHighlightText
+
+ proc_disp_styles_in_item = proc{|item|
+ master.instance_eval{ display_styles_in_item(item) }
+ }
+
+ @demo_scripts.instance_eval{
+ @master = master
+
+ @display_styles_in_item = proc_disp_styles_in_item
+
+ @Priv = TkVarAccess.new('::TreeCtrl::Priv')
+
+ @ScriptDir = scriptDir
+
+ @thisPlatform = thisPlatform
+
+ @RandomN = randomN
+
+ @images = images
+ @sel_images = sel_images
+
+ @SystemButtonFace = systemButtonFace
+ @SystemHighlight = systemHighlight
+ @SystemHighlightText = systemHighlightText
+ }
+
+ class << @demo_scripts
+ def _get_binding
+ binding
+ end
+ private :_get_binding
+
+ def load_demo(file)
+ eval(IO.readlines(file).join, _get_binding())
+ end
+
+ def init_pics(*args)
+ @master.init_pics(*args)
+ end
+ end
+ end
+
+ def load_demo_scripts
+ # demo sources
+ [
+ 'bitmaps',
+ 'explorer',
+ 'help',
+ 'imovie',
+ 'layout',
+ 'mailwasher',
+ 'outlook-folders',
+ 'outlook-newgroup',
+ 'random',
+ 'www-options'
+ ].each{|f|
+ @demo_scripts.load_demo(File.join(@ScriptDir, "#{f}.rb"))
+ }
+ end
+
+ ###########################
+
+ def init_demo_list
+ @tree1.element_create('e1', :text,
+ :fill=>[@SystemHighlightText, ['selected', 'focus']])
+ @tree1.element_create('e2', :rect, :showfocus=>true,
+ :fill=>[
+ @SystemHighlight, ['selected', 'focus'],
+ 'gray', ['selected', '!focus'],
+ ])
+ @tree1.style_create('s1')
+ @tree1.style_elements('s1', ['e2', 'e1'])
+
+ # Tk listbox has linespace + 1 height
+ @tree1.style_layout('s1', 'e2', :union=>['e1'],
+ :ipadx=>2, :ipady=>[0, 1], :iexpand=>:e)
+
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ @tree1.defaultstyle = 's1'
+ end
+
+ ###
+ [
+ ["Random #{@RandomN[0]} Items", :demoRandom, 'random.rb'],
+ ["Random #{@RandomN[0]} Items, Button Images", :demoRandom2, 'random.rb'],
+ ["Outlook Express (Folders)", :demoOutlookFolders, 'outlook-folders.rb'],
+ ["Outlook Express (Newsgroup)", :demoOutlookNewsgroup, 'outlook-newgroup.rb'],
+ ["Explorer (Details)", :demoExplorerDetails, 'explorer.rb'],
+ ["Explorer (List)", :demoExplorerList, 'explorer.rb'],
+ ["Explorer (Large icons)", :demoExplorerLargeIcons, 'explorer.rb'],
+ ["Explorer (Small icons)", :demoExplorerSmallIcons, 'explorer.rb'],
+ ["Internet Options", :demoInternetOptions, 'www-options.rb'],
+ ["Help Contents", :demoHelpContents, 'help.rb'],
+ ["Layout", :demoLayout, 'layout.rb'],
+ ["MailWasher", :demoMailWasher, 'mailwasher.rb'],
+ ["Bitmaps", :demoBitmaps, 'bitmaps.rb'],
+ ["iMovie", :demoIMovie, 'imovie.rb']
+ ].each{|label, cmd, file|
+ item = @tree1.item_create
+ @tree1.item_lastchild(:root, item)
+ unless (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ @tree1.item_style_set(item, 0, 's1')
+ end
+ @tree1.item_text(item, 0, label)
+ @demoCmd[item] = cmd
+ @demoFile[item] = file
+ }
+
+ @tree1.yview_moveto(0.0)
+ end
+
+ def demo_set(cmd, file)
+ demo_clear()
+ clicks = Tk::Clock.clicks
+ @demo_scripts.__send__(cmd, @tree2)
+ clicks = Tk::Clock.clicks - clicks
+ puts "set list in #{'%.2g'%(clicks/1000000.0)} seconds (#{clicks} clicks)"
+ @tree2.xview_moveto(0)
+ @tree2.yview_moveto(0)
+ Tk.update
+ display_styles_in_list()
+ show_source(file)
+ end
+
+ def display_styles_in_list
+ # Create elements and styles the first time this is called
+ if @tree4.style_names.empty?
+ @tree4.element_create('e1', :text,
+ :fill=>[@SystemHighlightText,['selected','focus']])
+ @tree4.element_create('e2', :text,
+ :fill=>[
+ @SystemHighlightText, ['selected','focus'],
+ '', ['selected','!focus'],
+ 'blue', []
+ ])
+ @tree4.element_create('e3', :rect, :showfocus=>true,
+ :fill=>[
+ @SystemHighlight, ['selected','focus'],
+ 'gray', ['selected', '!focus']
+ ])
+
+ @tree4.style_create('s1')
+ @tree4.style_elements('s1', ['e3', 'e1'])
+ @tree4.style_layout('s1', 'e3', :union=>['e1'], :ipadx=>1, :ipady=>[0,1])
+
+ @tree4.style_create('s2')
+ @tree4.style_elements('s2', ['e3', 'e1', 'e2'])
+ @tree4.style_layout('s2', 'e1', :padx=>[0,4])
+ @tree4.style_layout('s2', 'e3', :union=>['e1', 'e2'],
+ :ipadx=>1, :ipady=>[0,1])
+ end
+
+ # Clear the list
+ @tree4.item_delete(:all)
+
+ # One item for each element in the demo list
+ @tree2.element_names.sort.each{|elem|
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ item = @tree4.item_create(:button=>true)
+ @tree4.item_collapse(item)
+ else
+ item = @tree4.item_create
+ @tree4.item_hasbutton(item, true)
+ @tree4.collapse(item)
+ end
+ @tree4.item_style_set(item, 0, 's1')
+ @tree4.item_text(item, 0,
+ "Element #{elem} (#{@tree2.element_type(elem)})")
+
+ # One item for each configuration option for this element
+ @tree2.element_configinfo(elem).each{|name, x, y, default, current|
+ item2 = @tree4.item_create
+
+ if default == current
+ @tree4.item_style_set(item2, 0, 's1')
+ @tree4.item_complex(item2, [
+ ['e1', {:text=>"#{name} #{current.inspect}"}]
+ ])
+ else
+ @tree4.item_style_set(item2, 0, 's2')
+ @tree4.item_complex(item2, [
+ ['e1', {:text=>name}],
+ ['e2', {:text=>current.inspect}]
+ ])
+ end
+
+ @tree4.item_lastchild(item, item2)
+ }
+
+ @tree4.item_lastchild(:root, item)
+ }
+
+ # One item for each style in the demo list
+ @tree2.style_names.sort.each{|sty|
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ item = @tree4.item_create(:button=>true)
+ @tree4.item_collapse(item)
+ else
+ item = @tree4.item_create
+ @tree4.item_hasbutton(item, true)
+ @tree4.collapse(item)
+ end
+ @tree4.item_style_set(item, 0, 's1')
+ @tree4.item_text(item, 0, "Style #{sty}")
+
+ # One item for each element in the style
+ @tree2.style_elements(sty).each{|elem|
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ item2 = @tree4.item_create(:button=>true)
+ @tree4.item_collapse(item2)
+ else
+ item2 = @tree4.item_create
+ @tree4.item_hasbutton(item2, true)
+ @tree4.collapse(item2)
+ end
+ @tree4.item_style_set(item2, 0, 's1')
+ @tree4.item_text(item2, 0,
+ "Element #{elem} (#{@tree2.element_type(elem)})")
+
+ # One item for each layout option for this element in this style
+ @tree2.style_layout(sty, elem).each{|k, v|
+ item3 = @tree4.item_create
+ unless (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ @tree4.item_hasbutton(item3, false)
+ end
+ @tree4.item_style_set(item3, 0, 's1')
+ @tree4.item_text(item3, 0, "#{k} #{v.inspect}")
+ @tree4.item_lastchild(item2, item3)
+ }
+
+ @tree4.item_lastchild(item, item2)
+ }
+
+ @tree4.item_lastchild(:root, item)
+ }
+
+ @tree4.xview_moveto(0)
+ @tree4.yview_moveto(0)
+ end
+
+ def display_styles_in_item(item)
+ @tree3.column_configure(0, :text=>"Styles in item #{@tree2.index(item)}")
+
+ # Create elements and styles the first time this is called
+ if @tree3.style_names.empty?
+ @tree3.element_create('e1', :text,
+ :fill=>[@SystemHighlightText,['selected','focus']])
+ @tree3.element_create('e2', :text,
+ :fill=>[
+ @SystemHighlightText, ['selected','focus'],
+ '', ['selected','!focus'],
+ 'blue', []
+ ])
+ @tree3.element_create('e3', :rect, :showfocus=>true,
+ :fill=>[
+ @SystemHighlight, ['selected','focus'],
+ 'gray', ['selected', '!focus']
+ ])
+
+ @tree3.style_create('s1')
+ @tree3.style_elements('s1', ['e3', 'e1'])
+ @tree3.style_layout('s1', 'e3', :union=>['e1'], :ipadx=>1, :ipady=>[0,1])
+
+ @tree3.style_create('s2')
+ @tree3.style_elements('s2', ['e3', 'e1', 'e2'])
+ @tree3.style_layout('s2', 'e1', :padx=>[0,4])
+ @tree3.style_layout('s2', 'e3', :union=>['e1', 'e2'],
+ :ipadx=>1, :ipady=>[0,1])
+ end
+ # Clear the list
+ @tree3.item_delete(:all)
+
+ # One item for each item-column
+ column = 0
+ @tree2.item_style_set(item).each{|sty|
+ item2 = @tree3.item_create
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ @tree3.item_collapse(item2)
+ else
+ @tree3.collapse(item2)
+ end
+ @tree3.item_style_set(item2, 0, 's1')
+ @tree3.item_element_configure(item2, 0, 'e1',
+ :text=>"Column #{column}: Style #{sty}")
+
+ button = false
+
+ # One item for each element in this style
+ unless sty.to_s.empty?
+ @tree2.item_style_elements(item, column).each{|elem|
+ button = true
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ item3 = @tree3.item_create(:button=>true)
+ else
+ item3 = @tree3.item_create
+ @tree3.item_hasbutton(item3, true)
+ end
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ @tree3.item_collapse(item3)
+ else
+ @tree3.collapse(item3)
+ end
+ @tree3.item_style_set(item3, 0, 's1')
+ @tree3.item_element_configure(item3, 0, 'e1',
+ :text=>"Element #{elem} (#{@tree2.element_type(elem)})")
+
+ # One item for each configuration option in this element
+ @tree2.item_element_configinfo(item, column, elem) \
+ .each{|name, x, y, default, current|
+ item4 = @tree3.item_create
+ masterDefault = @tree2.element_cget(elem, name)
+ sameAsMaster = (masterDefault == current)
+ if !sameAsMaster && current == ''
+ sameAsMaster = true
+ current = masterDefault
+ end
+
+ if sameAsMaster
+ @tree3.item_style_set(item4, 0, 's1')
+ @tree3.item_complex(item4, [
+ ['e1',
+ {:text=>"#{name} #{current.inspect}"}]
+ ])
+ else
+ @tree3.item_style_set(item4, 0, 's2')
+ @tree3.item_complex(item4, [
+ ['e1', {:text=>name}],
+ ['e2', {:text=>current.inspect}]
+ ])
+ end
+ @tree3.item_lastchild(item3, item4)
+ }
+ @tree3.item_lastchild(item2, item3)
+ }
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ @tree3.item_configure(item2, :button=>true) if button
+ else
+ @tree3.item_hasbutton(item2, true) if button
+ end
+ end
+ @tree3.item_lastchild(:root, item2)
+ column += 1
+ }
+
+ @tree3.xview_moveto(0)
+ @tree3.yview_moveto(0)
+ end
+
+ def demo_clear
+ # Clear the demo list
+ @tree2.item_delete(:all)
+
+ # Clear all bindings on the demo list added by the previous demo.
+ # This is why DontDelete is used for the <Selection> binding.
+ @tree2.notify_bindinfo(@tree2).each{|ev|
+ @tree2.notify_bind_remove(@tree2, ev)
+ }
+
+ # Clear all run-time states
+ @tree2.state_names.each{|st| @tree2.state_undefine(st) }
+
+ # Clear the styles-in-item list
+ @tree3.item_delete(:all)
+
+ # Delete columns in demo list
+ while (@tree2.numcolumns > 0)
+ @tree2.column_delete(0)
+ end
+
+ # Delete all styles in demo list
+ @tree2.style_delete(*(@tree2.style_names))
+
+ # Delete all elements in demo list
+ @tree2.element_delete(*(@tree2.element_names))
+
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ @tree2.item_configure(:root, :button=>false)
+ @tree2.item_expand(:root)
+ else
+ @tree2.item_hasbutton(:root, false)
+ @tree2.expand(:root)
+ end
+
+ # Restore some happy defaults to the demo list
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ @tree2.configure(:orient=>:vertical, :wrap=>'',
+ :xscrollincrement=>0, :yscrollincrement=>0,
+ :itemheight=>0, :showheader=>true,
+ :background=>'white', :scrollmargin=>0,
+ :xscrolldelay=>50, :yscrolldelay=>50,
+ :openbuttonimage=>'', :closedbuttonimage=>'',
+ :backgroundmode=>:row, :treecolumn=>0, :indent=>19,
+ :defaultstyle=>'', :backgroundimage=>'')
+ else
+ @tree2.configure(:orient=>:vertical, :wrap=>'',
+ :xscrollincrement=>0, :yscrollincrement=>0,
+ :itemheight=>0, :showheader=>true,
+ :background=>'white', :scrollmargin=>0,
+ :xscrolldelay=>50, :yscrolldelay=>50,
+ :openbuttonimage=>'', :closedbuttonimage=>'',
+ :backgroundmode=>:row, :treecolumn=>0, :indent=>19)
+ end
+
+ # Restore default bindings to the demo list
+ @tree2.bindtags = [ @tree2, Tk::TreeCtrl, @tree2.winfo_toplevel, :all ]
+
+ @tree2.winfo_children.each{|w|
+ w.destroy unless @non_clear_list.include?(w)
+ }
+ end
+end
+
+TkTreeCtrl_demo.new($ScriptDir)
+
+##############################################
+
+def cursor_window(top = nil)
+ top.destroy if top.kind_of?(TkWindow) && top.winfo_exist?
+ top = TkToplevel.new(:title=>'Cursor Window')
+
+ c = TkCanvas.new(top, :background=>'white',
+ :width=>50*10, :highlightthickness=>0,
+ :borderwidth=>0).pack(:expand=>true, :fill=>:both)
+ cursors = %w(
+ X_cursor
+ arrow
+ based_arrow_down
+ based_arrow_up
+ boat
+ bogosity
+ bottom_left_corner
+ bottom_right_corner
+ bottom_side
+ bottom_tee
+ box_spiral
+ center_ptr
+ circle
+ clock
+ coffee_mug
+ cross
+ cross_reverse
+ crosshair
+ diamond_cross
+ dot
+ dotbox
+ double_arrow
+ draft_large
+ draft_small
+ draped_box
+ exchange
+ fleur
+ gobbler
+ gumby
+ hand1
+ hand2
+ heart
+ icon
+ iron_cross
+ left_ptr
+ left_side
+ left_tee
+ leftbutton
+ ll_angle
+ lr_angle
+ man
+ middlebutton
+ mouse
+ pencil
+ pirate
+ plus
+ question_arrow
+ right_ptr
+ right_side
+ right_tee
+ rightbutton
+ rtl_logo
+ sailboat
+ sb_down_arrow
+ sb_h_double_arrow
+ sb_left_arrow
+ sb_right_arrow
+ sb_up_arrow
+ sb_v_double_arrow
+ shuttle
+ sizing
+ spider
+ spraycan
+ star
+ target
+ tcross
+ top_left_arrow
+ top_left_corner
+ top_right_corner
+ top_side
+ top_tee
+ trek
+ ul_angle
+ umbrella
+ ur_angle
+ watch
+ xterm
+ )
+
+ orig_cursor = c.cursor
+ col = 0
+ row = 0
+
+ cursors.each{|cur|
+ x = col * 50
+ y = row * 40
+
+ begin
+ c.cursor = cur
+
+ r = TkcRectangle.new(c, x, y, x+50, y+40,
+ :fill=>'gray90', :outline=>'black', :width=>2)
+ t = TkcText.new(c, x+50/2, y+4, :text=>cur, :anchor=>:n, :width=>42)
+
+ col += 1
+ if col >= 10
+ col = 0
+ row += 1
+ end
+
+ r.bind('Enter', proc{c.cursor = cur; r.fill = 'linen'})
+ r.bind('Leave', proc{c.cursor = ''; r.fill = 'gray90'})
+
+ t.bind('Enter', proc{c.cursor = cur})
+ t.bind('Leave', proc{c.cursor = ''})
+ rescue
+ c.cursor = orig_cursor
+ end
+ }
+
+ c.cursor = orig_cursor
+ c.height = (row + 1) * 40
+end
+
+cursor_window()
+
+##############################################
+
+# A little screen magnifier for X11
+if Tk::PLATFORM['platform'] == 'unix' && Tk.windowingsystem != 'aqua'
+ def show_loupe(setting=nil)
+ loupe = (setting.kind_of?(Hash))? setting: {}
+ loupe[:zoom] = 3 unless loupe[:zoom]
+ loupe[:x] = 0 unless loupe[:x]
+ loupe[:y] = 0 unless loupe[:y]
+ loupe[:auto] = true unless loupe[:auto]
+ loupe[:delay] = 500 unless loupe[:delay]
+ loupe[:image] =
+ TkPhotoImage.new(:width=>150, :height=>150) unless loupe[:image]
+
+ top = TkToplevel.new(:geometry=>'-0+30',
+ :title=>'A little screen magnifier for X11')
+ TkLabel.new(top, :image=>loupe[:image]).pack
+
+ TkTimer.new(proc{loupe[:delay]}, -1, proc{
+ x, y = TkWinfo.pointerxy(Tk.root)
+ if loupe[:auto] || loupe[:x] != x || loupe[:y] != y
+ w = loupe[:image].width
+ h = loupe[:image].height
+ Tk::TreeCtrl.loupe(loupe[:image], x, y, w, h, loupe[:zoom])
+ loupe[:x] = x
+ loupe[:y] = y
+ end
+ }).start
+ end
+
+ show_loupe()
+end
+
+##############################################
+
+Tk.mainloop
diff --git a/ext/tk/sample/tkextlib/treectrl/explorer.rb b/ext/tk/sample/tkextlib/treectrl/explorer.rb
new file mode 100644
index 0000000000..8ee002ef9e
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/explorer.rb
@@ -0,0 +1,442 @@
+
+def demoExplorerAux(t, dir_proc, file_proc)
+ base_dir = File.dirname(File.dirname(@ScriptDir))
+
+ clicks = Tk::Clock.clicks
+ globDirs = Dir.glob(File.join(base_dir, '*')).find_all{|file|
+ FileTest.directory?(file)
+ }
+ clickGlobDirs = Tk::Clock.clicks - clicks
+
+ clicks = Tk::Clock.clicks
+ list = globDirs.sort
+ clickSortDirs = Tk::Clock.clicks - clicks
+
+ clicks = Tk::Clock.clicks
+ list.each{|file| dir_proc.call(file)}
+ clickAddDirs = Tk::Clock.clicks - clicks
+
+ clicks = Tk::Clock.clicks
+ globFiles = Dir.glob(File.join(base_dir, '*')).find_all{|file|
+ FileTest.file?(file)
+ }
+ clickGlobFiles = Tk::Clock.clicks - clicks
+
+ clicks = Tk::Clock.clicks
+ list = globFiles.sort
+ clickSortFiles = Tk::Clock.clicks - clicks
+
+ clicks = Tk::Clock.clicks
+ list.each{|file| file_proc.call(file)}
+ clickAddFiles = Tk::Clock.clicks - clicks
+
+ gd = '%.2g' % (clickGlobDirs / 1000000.0)
+ sd = '%.2g' % (clickSortDirs / 1000000.0)
+ ad = '%.2g' % (clickAddDirs / 1000000.0)
+ gf = '%.2g' % (clickGlobFiles / 1000000.0)
+ sf = '%.2g' % (clickSortFiles / 1000000.0)
+ af = '%.2g' % (clickAddFiles / 1000000.0)
+
+ puts "dirs(#{globDirs.length}) glob/sort/add #{gd}/#{sd}/#{ad} files(#{globFiles.length}) glob/sort/add #{gf}/#{sf}/#{af}"
+
+ @Priv[:DirCnt, t] = globDirs.length
+end
+
+#
+# Demo: explorer files
+#
+def demoExplorerDetails(t)
+ height = t.font.metrics(:linespace) + 2
+ hehght = 18 if height < 18
+
+ t.configure(:showroot=>false, :showbuttons=>false, :showlines=>false,
+ :itemheight=>height, :selectmode=>:extended,
+ :xscrollincrement=>20, :scrollmargin=>16,
+ :xscrolldelay=>[500, 50], :yscrolldelay=>[500, 50])
+
+ init_pics('small-*')
+
+ if $HasColumnCreate
+ t.column_create(:text=>'Name', :tag=>'name',
+ :width=>200, :arrow=>:up, :arrowpad=>6)
+ t.column_create(:text=>'Size', :tag=>'size', :justify=>:right,
+ :width=>60, :arrowside=>:left, :arrowgravity=>:right)
+ t.column_create(:text=>'Type', :tag=>'type', :width=>120)
+ t.column_create(:text=>'Modified', :tag=>'modified', :width=>130)
+ else
+ t.column_configure(0, :text=>'Name', :tag=>'name',
+ :width=>200, :arrow=>:up, :arrowpad=>6)
+ t.column_configure(1, :text=>'Size', :tag=>'size', :justify=>:right,
+ :width=>60, :arrowside=>:left, :arrowgravity=>:right)
+ t.column_configure(2, :text=>'Type', :tag=>'type', :width=>120)
+ t.column_configure(3, :text=>'Modified', :tag=>'modified', :width=>130)
+ end
+
+ t.element_create('e1', :image,
+ :image=>[
+ @sel_images['small-folder'], ['selected'],
+ @images['small-folder'], []
+ ])
+ t.element_create('e2', :text, :lines=>1,
+ :fill=>[@SystemHighlightText, ['selected', 'focus']])
+ t.element_create('txtType', :text, :lines=>1)
+ t.element_create('txtSize', :text, :lines=>1,
+ :datatype=>:integer, :format=>'%dKB')
+ t.element_create('txtDate', :text, :lines=>1,
+ :datatype=>:time, :format=>'%d/%m/%y %I:%M %p')
+ t.element_create('e4', :rect, :showfocus=>true,
+ :fill=>[
+ @SystemHighlight, ['selected', 'focus'],
+ 'gray', ['selected', '!focus']
+ ])
+
+ # image + text
+ s = t.style_create('styName', :orient=>:horizontal)
+ t.style_elements(s, ['e4', 'e1', 'e2'])
+ t.style_layout(s, 'e1', :expand=>:ns)
+ t.style_layout(s, 'e2', :padx=>[2,0], :squeeze=>:x, :expand=>:ns)
+ t.style_layout(s, 'e4', :union=>['e2'], :iexpand=>:ns, :ipadx=>2)
+
+ # column 1: text
+ s = t.style_create('stySize')
+ t.style_elements(s, ['txtSize'])
+ t.style_layout(s, 'txtSize', :padx=>6, :squeeze=>:x, :expand=>:ns)
+
+ # column 2: text
+ s = t.style_create('styType')
+ t.style_elements(s, ['txtType'])
+ t.style_layout(s, 'txtType', :padx=>6, :squeeze=>:x, :expand=>:ns)
+
+ # column 3: text
+ s = t.style_create('styDate')
+ t.style_elements(s, ['txtDate'])
+ t.style_layout(s, 'txtDate', :padx=>6, :squeeze=>:x, :expand=>:ns)
+
+ @Priv[:edit, t] = ['e2']
+ @Priv[:sensitive, t] = [ ['name', 'styName', 'e1', 'e2'] ]
+ @Priv[:dragimage, t] = [ ['name', 'styName', 'e1', 'e2'] ]
+
+ t.notify_bind(t, 'Edit-accept',
+ proc{|w, i, tt| w.item_text(i, 0, tt)}, '%T %I %t')
+
+ dir_proc = proc{|file|
+ item = t.item_create
+ t.item_style_set(item, 0, 'styName', 2, 'styType', 3, 'styDate')
+ t.item_complex(item,
+ [['e2', {:text=>File.basename(file)}]],
+ [],
+ [['txtType', {:text=>'Folder'}]],
+ [['txtDate', {:data=>File.mtime(file).tv_sec}]])
+ t.item_lastchild(:root, item)
+ }
+
+ file_proc = proc{|file|
+ item = t.item_create
+ t.item_style_set(item, 0, 'styName', 1, 'stySize',
+ 2, 'styType', 3, 'styDate')
+
+ ext = File.extname(file)
+ case ext
+ when '.dll'
+ img = 'small-dll'
+ when '.exe'
+ img = 'small-exe'
+ when '.txt'
+ img = 'small-txt'
+ else
+ if FileTest.executable?(file)
+ img = 'small-exe'
+ else
+ img = 'small-file'
+ end
+ end
+
+ type = ext.upcase
+ type = type[1..-1] << ' ' unless type.empty?
+ type << 'File'
+
+ t.item_complex(item,
+ [
+ ['e1', {:image=>[@sel_images[img], ['selected'],
+ @images[img], []]}],
+ ['e2', {:text=>File.basename(file)}]
+ ],
+ [ ['txtSize', {:data=>File.size(file)/1024 + 1}] ],
+ [ ['txtType', {:text=>type}] ],
+ [ ['txtDate', {:data=>File.mtime(file).tv_sec}] ]
+ )
+ t.item_lastchild(:root, item)
+ }
+
+ demoExplorerAux(t, dir_proc, file_proc)
+
+ @SortColumn = 0
+ t.notify_bind(t, 'Header-invoke',
+ proc{|w, c| explorerHeaderInvoke(t, w, c)}, '%T %C')
+
+ t.bindtags = [ t, 'TreeCtrlFileList', Tk::TreeCtrl, t.winfo_toplevel, :all ]
+end
+
+def explorerHeaderInvoke(t, w, c)
+ if (c == @SortColumn)
+ if t.column_cget(@SortColumn, :arrow) == 'down'
+ order = :increasing
+ arrow = :up
+ else
+ order = :decreasing
+ arrow = :down
+ end
+ else
+ if t.column_cget(@SortColumn, :arrow) == 'down'
+ order = :decreasing
+ arrow = :down
+ else
+ order = :increasing
+ arrow = :up
+ end
+ t.column_configure(@SortColumn, :arrow=>:none)
+ @SortColumn = c
+ end
+
+ t.column_configure(c, :arrow=>arrow)
+ dirCount = TkComm.number(@Priv[:DirCnt, t])
+ lastDir = dirCount - 1
+ case t.column_cget(c, :tag)
+ when 'name'
+ if dirCount > 0
+ t.item_sort(:root, order, {:last=>"root child #{lastDir}"},
+ {:column=>c, :dictionary=>true})
+ end
+ if dirCount < t.numitems - 1
+ t.item_sort(:root, order, {:first=>"root child #{dirCount}"},
+ {:column=>c, :dictionary=>true})
+ end
+
+ when 'size'
+ if dirCount < t.numitems - 1
+ t.item_sort(:root, order, {:first=>"root child #{dirCount}"},
+ {:column=>c, :integer=>true},
+ {:column=>'name', :dictionary=>true})
+ end
+
+ when 'type'
+ if dirCount < t.numitems - 1
+ t.item_sort(:root, order, {:first=>"root child #{dirCount}"},
+ {:column=>c, :dictionary=>true},
+ {:column=>'name', :dictionary=>true})
+ end
+
+ when 'modified'
+ if dirCount > 0
+ t.item_sort(:root, order, {:last=>"root child #{lastDir}"},
+ {:column=>c, :integer=>true},
+ {:column=>'name', :dictionary=>true})
+ end
+ if dirCount < t.numitems - 1
+ t.item_sort(:root, order, {:first=>"root child #{dirCount}"},
+ {:column=>c, :integer=>true},
+ {:column=>'name', :dictionary=>true})
+ end
+
+ end
+end
+
+def demoExplorerLargeIcons(t)
+ # Item height is 32 for icon, 4 padding, 3 lines of text
+ itemHeight = 32 + 4 + t.font.metrics(:linespace) * 3
+
+ t.configure(:showroot=>false, :showbuttons=>false, :showlines=>false,
+ :selectmode=>:extended, :wrap=>:window, :orient=>:horizontal,
+ :itemheight=>itemHeight, :showheader=>false, :scrollmargin=>16,
+ :xscrolldelay=>[500, 50], :yscrolldelay=>[500, 50])
+
+ init_pics('big-*')
+
+ if $HasColumnCreate
+ t.column_create(:width=>75)
+ else
+ t.column_configure(0, :width=>75)
+ end
+
+ t.element_create('elemImg', :image,
+ :image=>[
+ @sel_images['big-folder'], ['selected'],
+ @images['big-folder'], []
+ ])
+ t.element_create('elemTxt', :text, :justify=>:center,
+ :lines=>1, :width=>71, :wrap=>:word,
+ :fill=>[@SystemHighlightText, ['selected', 'focus']])
+ t.element_create('elemSel', :rect, :showfocus=>true,
+ :fill=>[
+ @SystemHighlight, ['selected', 'focus'],
+ 'gray', ['selected']
+ ])
+
+ # image + text
+ s = t.style_create('STYLE', :orient=>:vertical)
+ t.style_elements(s, ['elemSel', 'elemImg', 'elemTxt'])
+ t.style_layout(s, 'elemImg', :expand=>:we)
+ t.style_layout(s, 'elemTxt',
+ :pady=>[4,0], :padx=>2, :squeeze=>:x, :expand=>:we)
+ t.style_layout(s, 'elemSel', :union=>['elemTxt'])
+
+ @Priv[:edit, t] = ['elemTxt']
+ @Priv[:sensitive, t] = [ [0, 'STYLE', 'elemImg', 'elemTxt'] ]
+ @Priv[:dragimage, t] = [ [0, 'STYLE', 'elemImg', 'elemTxt'] ]
+
+ t.notify_bind(t, 'Edit-accept',
+ proc{|w, i, tt| w.item_text(i, 0, tt)}, '%T %I %t')
+
+ dir_proc = proc{|file|
+ item = t.item_create
+ t.item_style_set(item, 0, 'STYLE')
+ t.item_text(item, 0, File.basename(file))
+ t.item_lastchild(:root, item)
+ }
+
+ file_proc = proc{|file|
+ item = t.item_create
+ t.item_style_set(item, 0, 'STYLE')
+
+ ext = File.extname(file)
+ case ext
+ when '.dll'
+ img = 'big-dll'
+ when '.exe'
+ img = 'big-exe'
+ when '.txt'
+ img = 'big-txt'
+ else
+ if FileTest.executable?(file)
+ img = 'big-exe'
+ else
+ img = 'big-file'
+ end
+ end
+
+ type = ext.upcase
+ type = type[1..-1] << ' ' unless type.empty?
+ type << 'File'
+
+ t.item_complex(item,
+ [
+ ['elemImg', {:image=>[@sel_images[img], ['selected'],
+ @images[img], []]}],
+ ['elemTxt', {:text=>File.basename(file)}]
+ ])
+ t.item_lastchild(:root, item)
+ }
+
+ demoExplorerAux(t, dir_proc, file_proc)
+
+ t.activate(t.index('root firstchild'))
+
+ t.notify_bind(t, 'ActiveItem',
+ proc{|w, a, c|
+ w.item_element_configure(a, 0, 'elemTxt', :lines=>'')
+ w.item_element_configure(c, 0, 'elemTxt', :lines=>3)
+ }, '%T %p %c')
+
+ t.bindtags = [ t, 'TreeCtrlFileList', Tk::TreeCtrl, t.winfo_toplevel, :all ]
+end
+
+# Tree is horizontal, wrapping occurs at right edge of window, each item
+# is as wide as the smallest needed multiple of 110 pixels
+def demoExplorerSmallIcons(t)
+ demoExplorerList(t)
+ t.configure(:orient=>:horizontal, :xscrollincrement=>0)
+ t.column_configure(0, :width=>'', :stepwidth=>110, :widthhack=>false)
+end
+
+# Tree is vertical, wrapping occurs at bottom of window, each range has the
+# same width (as wide as the longest item), xscrollincrement is by range
+def demoExplorerList(t)
+ height = t.font.metrics(:linespace) + 2
+ height = 18 if height < 18
+
+ t.configure(:showroot=>false, :showbuttons=>false, :showlines=>false,
+ :itemheight=>height, :selectmode=>:extended, :wrap=>:window,
+ :showheader=>false, :scrollmargin=>16,
+ :xscrolldelay=>[500, 50], :yscrolldelay=>[500, 50])
+
+ init_pics('small-*')
+
+ if $HasColumnCreate
+ t.column_create(:widthhack=>true)
+ else
+ t.column_configure(0, :widthhack=>true)
+ end
+
+ t.element_create('elemImg', :image,
+ :image=>[
+ @sel_images['small-folder'], ['selected'],
+ @images['small-folder'], []
+ ])
+ t.element_create('elemTxt', :text, :lines=>1,
+ :fill=>[@SystemHighlightText, ['selected', 'focus']])
+ t.element_create('elemSel', :rect, :showfocus=>true,
+ :fill=>[
+ @SystemHighlight, ['selected', 'focus'],
+ 'gray', ['selected', '!focus']
+ ])
+
+ # image + text
+ s = t.style_create('STYLE')
+ t.style_elements(s, ['elemSel', 'elemImg', 'elemTxt'])
+ t.style_layout(s, 'elemImg', :expand=>:ns)
+ t.style_layout(s, 'elemTxt', :squeeze=>:x, :expand=>:ns, :padx=>[2,0])
+ t.style_layout(s, 'elemSel', :union=>['elemTxt'], :iexpand=>:ns, :ipadx=>2)
+
+ @Priv[:edit, t] = ['elemTxt']
+ @Priv[:sensitive, t] = [ [0, 'STYLE', 'elemImg', 'elemTxt'] ]
+ @Priv[:dragimage, t] = [ [0, 'STYLE', 'elemImg', 'elemTxt'] ]
+
+ t.notify_bind(t, 'Edit-accept',
+ proc{|w, i, tt| w.item_text(i, 0, tt)}, '%T %I %t')
+
+ dir_proc = proc{|file|
+ item = t.item_create
+ t.item_style_set(item, 0, 'STYLE')
+ t.item_text(item, 0, File.basename(file))
+ t.item_lastchild(:root, item)
+ }
+
+ file_proc = proc{|file|
+ item = t.item_create
+ t.item_style_set(item, 0, 'STYLE')
+
+ ext = File.extname(file)
+ case ext
+ when '.dll'
+ img = 'small-dll'
+ when '.exe'
+ img = 'small-exe'
+ when '.txt'
+ img = 'small-txt'
+ else
+ if FileTest.executable?(file)
+ img = 'small-exe'
+ else
+ img = 'small-file'
+ end
+ end
+
+ type = ext.upcase
+ type = type[1..-1] << ' ' unless type.empty?
+ type << 'File'
+
+ t.item_complex(item,
+ [
+ ['elemImg', {:image=>[@sel_images[img], ['selected'],
+ @images[img], []]}],
+ ['elemTxt', {:text=>File.basename(file)}]
+ ])
+ t.item_lastchild(:root, item)
+ }
+
+ demoExplorerAux(t, dir_proc, file_proc)
+
+ t.activate(t.item_firstchild(:root))
+
+ t.bindtags = [ t, 'TreeCtrlFileList', Tk::TreeCtrl, t.winfo_toplevel, :all ]
+end
diff --git a/ext/tk/sample/tkextlib/treectrl/help.rb b/ext/tk/sample/tkextlib/treectrl/help.rb
new file mode 100644
index 0000000000..01e075bdf8
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/help.rb
@@ -0,0 +1,405 @@
+#
+# Demo: Help contents
+#
+def demoHelpContents(t)
+ height = t.font.metrics(:linespace) + 2
+ hehght = 18 if height < 18
+ t.configure(:showroot=>false, :showbuttons=>false, :showlines=>false,
+ :itemheight=>height, :selectmode=>:browse)
+
+ init_pics('help-*')
+
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.column_create(:text=>'Help Contents')
+ else # TreeCtrl 1.0
+ t.column_configure(0, :text=>'Help Contents')
+ end
+
+ # Define a new item state
+ t.state_define('mouseover')
+
+ t.element_create('e1', :image, :image=>@images['help-page'])
+ t.element_create('e2', :image, :image=>[
+ @images['help-book-open'], ['open'],
+ @images['help-book-closed'], [],
+ ])
+ t.element_create('e3', :text,
+ :font=>[t.font.dup.underline(true), ['mouseover']],
+ :fill=>[
+ @SystemHighlightText, ['selected', 'focus'],
+ 'blue', ['mouseover']
+ ])
+ t.element_create('e4', :rect, :showfocus=>true,
+ :fill=>[@SystemHighligh, ['selected', 'focus']])
+
+ # book
+ s = t.style_create('s1')
+ t.style_elements(s, ['e4', 'e1', 'e3'])
+ t.style_layout(s, 'e1', :padx=>[0,4], :expand=>:ns)
+ t.style_layout(s, 'e3', :expand=>:ns)
+ t.style_layout(s, 'e4', :union=>['e3'], :iexpand=>:ns, :ipadx=>2)
+
+ # page
+ s = t.style_create('s2')
+ t.style_elements(s, ['e4', 'e2', 'e3'])
+ t.style_layout(s, 'e2', :padx=>[0,4], :expand=>:ns)
+ t.style_layout(s, 'e3', :expand=>:ns)
+ t.style_layout(s, 'e4', :union=>['e3'], :iexpand=>:ns, :ipadx=>2)
+
+ parentList = [:root, '', '', '', '', '', '']
+ parent = :root
+ [
+ [0, 's1', "Welcome to Help"],
+ [0, 's2', "Introducing Windows 98"],
+ [1, 's2', "How to Use Help"],
+ [2, 's1', "Find a topic"],
+ [2, 's1', "Get more out of help"],
+ [1, 's2', "Register Your Software"],
+ [2, 's1', "Registering Windows 98 online"],
+ [1, 's2', "What's New in Windows 98"],
+ [2, 's1', "Innovative, easy-to-use features"],
+ [2, 's1', "Improved reliability"],
+ [2, 's1', "A faster operating system"],
+ [2, 's1', "True Web integration"],
+ [2, 's1', "More entertaining and fun"],
+ [1, 's2', "If You're New to Windows 98"],
+ [2, 's2', "Tips for Macintosh Users"],
+ [3, 's1', "Why does the mouse have two buttons?"]
+ ].each{|depth, style, text|
+ item = t.item_create
+ t.item_style_set(item, 0, style)
+ t.item_element_configure(item, 0, 'e3', :text=>text)
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.item_collapse(item)
+ else # TreeCtrl 1.0
+ t.collapse(item)
+ end
+ t.item_lastchild(parentList[depth], item)
+ depth += 1
+ parentList[depth] = item
+ }
+
+ treeCtrlHelp = TkBindTag.new
+
+ treeCtrlHelp.bind('Double-ButtonPress-1',
+ proc{|w, x, y|
+ if w.identify(x, y)[0] == 'header'
+ Tk::TreeCtrl::BindCallback.doubleButton1(w, x, y)
+ else
+ helpButton1(w, x, y)
+ end
+ Tk.callback_break
+ }, '%W %x %y')
+
+ treeCtrlHelp.bind('ButtonPress-1',
+ proc{|w, x, y|
+ helpButton1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+
+ treeCtrlHelp.bind('Button1-Motion',
+ proc{|w, x, y|
+ helpMotion1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+
+ treeCtrlHelp.bind('Button1-Leave',
+ proc{|w, x, y|
+ helpLeave1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+
+ treeCtrlHelp.bind('ButtonRelease-1',
+ proc{|w, x, y|
+ helpRelease1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+
+ treeCtrlHelp.bind('Motion', proc{|w, x, y| helpMotion(w, x, y) }, '%W %x %y')
+
+ treeCtrlHelp.bind('Leave', proc{|w, x, y| helpMotion(w, x, y) }, '%W %x %y')
+
+ treeCtrlHelp.bind('Button1-Motion',
+ proc{|w, x, y|
+ if w.selection_get.length == 1
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version,
+ '1.1') >= 0)
+ w.item_toggle(w.selection_get[0])
+ else # TreeCtrl 1.0
+ w.toggle(w.selection_get[0])
+ end
+ end
+ Tk.callback_break
+ }, '%W %x %y')
+
+ @Priv[:help, :prev] = ''
+
+ t.bindtags = [ t, treeCtrlHelp, Tk::TreeCtrl, t.winfo_toplevel, :all ]
+end
+
+# This is an alternate implementation that does not define a new item state
+# to change the appearance of the item under the cursor.
+def demoHelpContents2(t)
+ height = t.font.metrics(:linespace) + 2
+ hehght = 18 if height < 18
+ t.configure(:showroot=>false, :showbuttons=>false, :showlines=>false,
+ :itemheight=>height, :selectmode=>:browse)
+
+ init_pics('help-*')
+
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.column_create(:text=>'Help Contents')
+ else # TreeCtrl 1.0
+ t.column_configure(0, :text=>'Help Contents')
+ end
+
+ t.element_create('e1', :image, :image=>@images['help-page'])
+ t.element_create('e2', :image, :image=>[
+ @images['help-book-open'], ['open'],
+ @images['help-book-closed'], [],
+ ])
+ t.element_create('e3', :text,
+ :fill=>[
+ @SystemHighlightText, ['selected', 'focus'],
+ 'blue', []
+ ])
+ t.element_create('e4', :rect, :showfocus=>true,
+ :fill=>[@SystemHighligh, ['selected', 'focus']])
+ t.element_create('e5', :text, :font=>t.font.dup.underline(true),
+ :fill=>[
+ @SystemHighlightText, ['selected', 'focus'],
+ 'blue', []
+ ])
+
+ # book
+ s = t.style_create('s1')
+ t.style_elements(s, ['e4', 'e1', 'e3'])
+ t.style_layout(s, 'e1', :padx=>[0,4], :expand=>:ns)
+ t.style_layout(s, 'e3', :expand=>:ns)
+ t.style_layout(s, 'e4', :union=>['e3'], :iexpand=>:ns, :ipadx=>2)
+
+ # page
+ s = t.style_create('s2')
+ t.style_elements(s, ['e4', 'e2', 'e3'])
+ t.style_layout(s, 'e2', :padx=>[0,4], :expand=>:ns)
+ t.style_layout(s, 'e3', :expand=>:ns)
+ t.style_layout(s, 'e4', :union=>['e3'], :iexpand=>:ns, :ipadx=>2)
+
+ # book (focus)
+ s = t.style_create('s1.f')
+ t.style_elements(s, ['e4', 'e1', 'e5'])
+ t.style_layout(s, 'e1', :padx=>[0,4], :expand=>:ns)
+ t.style_layout(s, 'e5', :expand=>:ns)
+ t.style_layout(s, 'e4', :union=>['e5'], :iexpand=>:ns, :ipadx=>2)
+
+ # page (focus)
+ s = t.style_create('s2')
+ t.style_elements(s, ['e4', 'e2', 'e5'])
+ t.style_layout(s, 'e2', :padx=>[0,4], :expand=>:ns)
+ t.style_layout(s, 'e5', :expand=>:ns)
+ t.style_layout(s, 'e4', :union=>['e5'], :iexpand=>:ns, :ipadx=>2)
+
+ parentList = [:root, '', '', '', '', '', '']
+ parent = :root
+ [
+ [0, 's1', "Welcome to Help"],
+ [0, 's2', "Introducing Windows 98"],
+ [1, 's2', "How to Use Help"],
+ [2, 's1' "Find a topic"],
+ [2, 's1', "Get more out of help"],
+ [1, 's2', "Register Your Software"],
+ [2, 's1', "Registering Windows 98 online"],
+ [1, 's2', "What's New in Windows 98"],
+ [2, 's1', "Innovative, easy-to-use features"],
+ [2, 's1', "Improved reliability"],
+ [2, 's1', "A faster operating system"],
+ [2, 's1', "True Web integration"],
+ [2, 's1', "More entertaining and fun"],
+ [1, 's2', "If You're New to Windows 98"],
+ [2, 's2', "Tips for Macintosh Users"],
+ [3, 's1', "Why does the mouse have two buttons?"]
+ ].each{|depth, style, text|
+ item = t.item_create
+ t.item_style_set(item, 0, style)
+ t.item_element_configure(item, 0, 'e3', :text=>text)
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.item_collapse(item)
+ else # TreeCtrl 1.0
+ t.collapse(item)
+ end
+ t.item_lastchild(parentList[depth], item)
+ depth += 1
+ parentList[depth] = item
+ }
+
+ treeCtrlHelp = TkBindTag.new
+
+ treeCtrlHelp.bind('Double-ButtonPress-1',
+ proc{|w, x, y|
+ if w.identify(x, y)[0] == 'header'
+ Tk::TreeCtrl::BindCallback.doubleButton1(w, x, y)
+ else
+ helpButton1(w, x, y)
+ end
+ Tk.callback_break
+ }, '%W %x %y')
+
+ treeCtrlHelp.bind('ButtonPress-1',
+ proc{|w, x, y|
+ helpButton1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+
+ treeCtrlHelp.bind('Button1-Motion',
+ proc{|w, x, y|
+ helpMotion1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+
+ treeCtrlHelp.bind('Button1-Leave',
+ proc{|w, x, y|
+ helpLeave1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+
+ treeCtrlHelp.bind('ButtonRelease-1',
+ proc{|w, x, y|
+ helpRelease1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+
+ treeCtrlHelp.bind('Motion', proc{|w, x, y| helpMotion(w, x, y) }, '%W %x %y')
+
+ treeCtrlHelp.bind('Leave', proc{|w, x, y| helpMotion(w, x, y) }, '%W %x %y')
+
+ treeCtrlHelp.bind('Button1-Motion',
+ proc{|w, x, y|
+ if w.selection_get.length == 1
+ w.item_toggle(w.selection_get[0])
+ end
+ Tk.callback_break
+ }, '%W %x %y')
+
+ @Priv[:help, :prev] = ''
+
+ t.bindtags = [ t, treeCtrlHelp, Tk::TreeCtrl, t.winfo_toplevel, :all ]
+end
+
+def helpButton1(w, x, y)
+ w.set_focus
+ id = w.identify(x, y)
+ @Priv['buttonMode'] = ''
+ if id[0] == 'header'
+ Tk::TreeCtrl::BindCallback.buttonPress1(w, x, y)
+ elsif id[0] == 'item'
+ item = id[1]
+ # didn't click an element
+ return if id.length != 6
+ if w.selection_includes(item)
+ w.toggle(item)
+ return
+ end
+ if w.selection_get.length > 0
+ item2 = w.selection_get[0]
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ w.item_collapse(item2)
+ else # TreeCtrl 1.0
+ w.collapse(item2)
+ end
+ w.item_ancestors(item2).each{|i|
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ w.item_collapse(i) if w.compare(item, '!=', i)
+ else # TreeCtrl 1.0
+ w.collapse(i) if w.compare(item, '!=', i)
+ end
+ }
+ end
+ w.activate(item)
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ w.item_ancestors(item).each{|i|
+ w.item_expand(i)
+ }
+ w.item_toggle(item)
+ else # TreeCtrl 1.0
+ w.expand(*(w.item_ancestors(item)))
+ w.toggle(item)
+ end
+ w.selection_modify(item, :all)
+ end
+end
+
+def helpMotion1(w, x, y)
+ case @Priv['buttonMode']
+ when 'resize', 'header'
+ Tk::TreeCtrl::BindCallback.motion1(w, x, y)
+ end
+end
+
+def helpLeave1(w, x, y)
+ # This is called when I do ButtonPress-1 on Unix for some reason,
+ # and buttonMode is undefined.
+ return unless @Priv.exist?('buttonMode')
+ case @Priv['buttonMode']
+ when 'header'
+ w.column_configure(@Priv['column'], :sunken=>false)
+ end
+end
+
+def helpRelease1(w, x, y)
+ case @Priv['buttonMode']
+ when 'resize', 'header'
+ Tk::TreeCtrl::BindCallback.Release1(w, x, y)
+ end
+ @Priv['buttonMode'] = ''
+end
+
+def helpMotion(w, x, y)
+ id = w.identify(x, y)
+ if id.empty?
+ elsif id[0] == 'header'
+ elsif id[0] == 'item'
+ item = id[1]
+ if id.length == 6
+ if @Priv[:help, :prev] != TkComm._get_eval_string(item)
+ if @Priv[:help, :prev] != ''
+ w.item_state_set(@Priv[:help, :prev], '!mouseover')
+ end
+ w.item_state_set(item, 'mouseover')
+ @Priv[:help, :prev] = item
+ end
+ return
+ end
+ end
+ if @Priv[:help, :prev] != ''
+ w.item_state_set(@Priv[:help, :prev], '!mouseover')
+ @Priv[:help, :prev] = ''
+ end
+end
+
+# Alternate implementation doesn't rely on mouseover state
+def helpMotion2(w, x, y)
+ id = w.identify(x, y)
+ if id[0] == 'header'
+ elsif !id.empty?
+ item = id[1]
+ if id.kength == 6
+ if @Priv[:help, :prev] != TkComm._get_eval_string(item)
+ if @Priv[:help, :prev] != ''
+ style = w.item_style_set(@Priv[:help, :prev], 0)
+ style.sub!(/\.f$/, '')
+ w.item_style_map(@Priv[:help, :prev], 0, style, ['e5', 'e3'])
+ end
+ style = w.item_style_set(item, 0)
+ w.item_style_map(item, 0, style + '.f', ['e3', 'e5'])
+ @Priv[:help, :prev] = item
+ end
+ return
+ end
+ end
+ if @Priv[:help, :prev] != ''
+ style = w.item_style_set(@Priv[:help, :prev], 0)
+ style.sub!(/\.f$/, '')
+ w.item_style_map(@Priv[:help, :prev], 0, style, ['e5', 'e3'])
+ @Priv[:help, :prev] = ''
+ end
+end
diff --git a/ext/tk/sample/tkextlib/treectrl/imovie.rb b/ext/tk/sample/tkextlib/treectrl/imovie.rb
new file mode 100644
index 0000000000..3c394fa125
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/imovie.rb
@@ -0,0 +1,130 @@
+#
+# Demo: iMovie
+#
+def demoIMovie(t)
+ t.configure(:showroot=>false, :showbuttons=>false, :showlines=>false,
+ :selectmode=>:browse, :orient=>:horizontal, :wrap=>:window,
+ :showheader=>false, :background=>'#dcdcdc')
+
+ if $HasColumnCreate
+ t.column_create
+ end
+
+ init_pics('imovie-*')
+
+ case @thisPlatform
+ when 'macintosh', 'macosx'
+ font1 = TkFont.new(['Geneva', 9])
+ font2 = TkFont.new(['Geneva', 10])
+ when 'unix'
+ font1 = TkFont.new(['Helvetica', -12])
+ font2 = TkFont.new(['Helvetica', -14])
+ else
+ font1 = TkFont.new(['Helvetica', 8])
+ font2 = TkFont.new(['Helvetica', 10])
+ end
+
+ t.element_create('elemTime', :text, :font=>font1)
+ t.element_create('elemName', :text, :font=>font2, :lines=>1, :width=>80)
+ t.element_create('elemRect', :rect, :outline=>'#827878', :outlinewidth=>1,
+ :fill=>['#ffdc5a', ['selected'], 'white', []])
+ t.element_create('elemImg', :image)
+ t.element_create('elemShadow', :rect, :outline=>'gray', :outlinewidth=>1,
+ :open=>:wn)
+
+ s = t.style_create('STYLE', :orient=>:vertical)
+ t.style_elements(s, [
+ 'elemShadow', 'elemRect', 'elemTime',
+ 'elemImg', 'elemName'
+ ])
+ t.style_layout(s, 'elemShadow', :detach=>true,
+ :padx=>[1,2], :pady=>[1,2], :iexpand=>:es)
+ t.style_layout(s, 'elemTime', :padx=>[2,0])
+ t.style_layout(s, 'elemImg', :pady=>[0,1])
+ t.style_layout(s, 'elemName', :expand=>:we, :ipady=>[0,2], :padx=>[0,3],
+ :squeeze=>:x)
+ t.style_layout(s, 'elemRect', :union=>['elemTime', 'elemImg', 'elemName'],
+ :ipadx=>6, :padx=>[0,3], :pady=>[0,3])
+
+ # Set default item style
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.defaultstyle([s])
+ end
+
+ (0..4).each{|i|
+ [
+ ['15:20', 'Clip 1', @images['imovie-01']],
+ ['19:18', 'Clip 2', @images['imovie-02']],
+ ['07:20', 'Clip 3', @images['imovie-03']],
+ ['07:20', 'Clip 4', @images['imovie-04']],
+ ['07:20', 'Clip 5', @images['imovie-05']],
+ ['07:20', 'Clip 6', @images['imovie-06']],
+ ['07:20', 'Clip 7', @images['imovie-07']]
+ ].each{|time, name, image|
+ item = t.item_create
+ unless (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.item_style_set(item, 0, s)
+ end
+ t.item_element_configure(item, 0, 'elemTime', :text=>time)
+ t.item_element_configure(item, 0, 'elemName', :text=>name)
+ t.item_element_configure(item, 0, 'elemImg', :image=>image)
+ t.item_lastchild(:root, item)
+ }
+ }
+
+ t.notify_bind(t, 'Edit-accept', proc{|w, i, c, e, tt|
+ w.item_element_configure(i, c, e, :text=>tt)
+ }, '%T %I %C %E %t')
+
+ iMovie = TkBindTag.new
+ iMovie.bind('ButtonPress-1', proc{|w, x, y|
+ iMovieButton1(w, x, y)
+ }, '%W %x %y')
+
+ t.bindtags = [t, iMovie, Tk::TreeCtrl, t.winfo_toplevel, TkBindTag::ALL]
+end
+
+def iMovieButton1(w, x, y)
+ w.set_focus
+ id = w.identify(x,y)
+
+ if id.empty?
+ # Click outside any item
+
+ elsif id[0] == 'header'
+ # Click in header
+ Tk::TreeCtrl::BindCallback.buttonPress1(w, x, y)
+
+ elsif id[0] == 'item'
+ # Click in item
+ Tk::TreeCtrl::BindCallback.buttonPress1(w, x, y)
+ Tk.update
+ where, item, arg1, arg2, arg3, arg4 = id
+ case arg1
+ when 'column'
+ i = id[1]
+ if id.length == 6
+ e = id[-1]
+ if e == 'elemName'
+ exists = TkWinfo.exist?(w.path + '.entry')
+ Tk::TreeCtrl::BindCallback.entryOpen(w, i, 0, e)
+ ent = TkComm.window(w.path + '.entry')
+ unless exists
+ ent.configure(:borderwidth=>0, :justify=>:center,
+ :background=>'#ffdc5a')
+ x1, y1, x2, y2 = w.item_bbox(i, 0, e)
+ ent.place(:y=>y1 - 1)
+ end
+ ent.selection_clear
+ x1, y1, x2, y2 = t.item_bbox(i)
+ ent.place(:x=>x1 + 1, :width=>x2 - x1 - 5)
+ puts "@#{x - (x1 + 1)}"
+ # ent.icursor = ent.index("@#{x - (x1 + 1)}")
+ ent.icursor = ent.index(TkComm._at(x - (x1 + 1)))
+ end
+ end
+ end
+ end
+
+ Tk.callback_break
+end
diff --git a/ext/tk/sample/tkextlib/treectrl/layout.rb b/ext/tk/sample/tkextlib/treectrl/layout.rb
new file mode 100644
index 0000000000..0ab65ac243
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/layout.rb
@@ -0,0 +1,159 @@
+#
+# Demo: Layout
+#
+def demoLayout(t)
+ t.configure(:showroot=>false, :showrootbutton=>true, :showbuttons=>true,
+ :showlines=>true, :itemheight=>0, :selectmode=>:browse)
+
+ if $HasColumnCreate
+ t.column_create(:text=>'Layout')
+ else
+ t.column_configure(0, :text=>'Layout')
+ end
+
+ t.element_create('e1', :rect, :width=>30, :height=>30, :fill=>'gray20')
+ t.element_create('e2', :rect, :width=>30, :height=>30, :fill=>'gray40',
+ :outline=>'blue', :outlinewidth=>3)
+ t.element_create('e3', :rect, :fill=>'gray60')
+ t.element_create('e4', :rect, :showfocus=>true,
+ :fill=>[
+ @SystemHighlight, ['selected', 'focus'], 'gray80', []
+ ])
+ t.element_create('e5', :rect, :fill=>'{sky blue}', :width=>20, :height=>20)
+ t.element_create('e6', :rect, :fill=>'{sea green}', :width=>30, :height=>16)
+ t.element_create('e7', :rect, :fill=>'{sky blue}', :width=>30, :height=>16)
+ t.element_create('e8', :rect, :fill=>'gray70', :height=>1)
+
+ s = t.style_create('s1')
+ t.style_elements(s, ['e4', 'e3', 'e1', 'e2', 'e5', 'e6', 'e7'])
+ t.style_layout(s, 'e1', :padx=>[28, 4], :pady=>4)
+ t.style_layout(s, 'e2', :expand=>:es, :padx=>[0, 38])
+ t.style_layout(s, 'e3', :union=>['e1', 'e2'], :ipadx=>4, :ipady=>4, :pady=>2)
+ t.style_layout(s, 'e4', :detach=>true, :iexpand=>:es)
+ t.style_layout(s, 'e5', :detach=>true, :padx=>[2,0], :pady=>2, :iexpand=>:s)
+ t.style_layout(s, 'e6', :detach=>true, :expand=>:ws,
+ :padx=>[0,2], :pady=>[2,0])
+ t.style_layout(s, 'e7', :detach=>true, :expand=>:wn,
+ :padx=>[0,2], :pady=>[0,2])
+
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ i = t.item_create(:button=>true)
+ else
+ i = t.item_create
+ t.item_hasbutton(i, true)
+ end
+ t.item_style_set(i, 0, s)
+ t.item_lastchild(:root, i)
+ parent = i
+
+ i = t.item_create()
+ unless (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.item_hasbutton(i, false)
+ end
+ t.item_style_set(i, 0, s)
+ t.item_lastchild(parent, i)
+
+ ###
+
+ s = t.style_create('s2')
+ t.style_elements(s, ['e4', 'e3', 'e1'])
+ t.style_layout(s, 'e1', :padx=>8, :pady=>8, :iexpand=>:e)
+ t.style_layout(s, 'e3', :union=>['e1'], :ipadx=>[20,4], :ipady=>[4,12])
+ t.style_layout(s, 'e4', :detach=>true, :iexpand=>:es)
+
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ i = t.item_create(:button=>true)
+ else
+ i = t.item_create
+ t.item_hasbutton(i, true)
+ end
+ t.item_style_set(i, 0, s)
+ t.item_lastchild(:root, i)
+
+ i2 = t.item_create()
+ unless (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.item_hasbutton(i2, false)
+ end
+ t.item_style_set(i2, 0, s)
+ t.item_lastchild(i, i2)
+
+ ###
+
+ s = t.style_create('s3')
+ t.style_elements(s, ['e4', 'e3', 'e1', 'e5', 'e6'])
+ t.style_layout(s, 'e4', :union=>['e1', 'e6'], :ipadx=>8, :ipady=>[8,0])
+ t.style_layout(s, 'e3', :union=>['e1', 'e5'], :ipadx=>4, :ipady=>4)
+ t.style_layout(s, 'e5', :ipady=>[0,20])
+
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ i = t.item_create(:button=>true)
+ else
+ i = t.item_create
+ t.item_hasbutton(i, true)
+ end
+ t.item_style_set(i, 0, s)
+ t.item_lastchild(:root, i)
+
+ i2 = t.item_create()
+ unless (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.item_hasbutton(i2, false)
+ end
+ t.item_style_set(i2, 0, s)
+ t.item_lastchild(i, i2)
+
+ ###
+
+ t.element_create('eb', :border, :background=>@SystemButtonFace,
+ :relief=>[:sunken, ['selected'], :raised, []],
+ :thickness=>2, :filled=>true)
+ t.element_create('et', :text)
+
+ text = "Here is a text element surrounded by a border element.\nResize the column to watch me wrap."
+
+ s = t.style_create('e4')
+ t.style_elements(s, ['eb', 'et'])
+ t.style_layout(s, 'eb', :union=>['et'], :ipadx=>2, :ipady=>2)
+ t.style_layout(s, 'et', :squeeze=>:x)
+
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ i = t.item_create(:button=>true)
+ else
+ i = t.item_create
+ t.item_hasbutton(i, true)
+ end
+ t.item_style_set(i, 0, s)
+ t.item_text(i, 0, text)
+ t.item_lastchild(:root, i)
+ parent = i
+
+ i = t.item_create()
+ unless (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.item_hasbutton(i, false)
+ end
+ t.item_style_set(i, 0, s)
+ t.item_text(i, 0, text)
+ t.item_lastchild(parent, i)
+
+ ###
+
+ styleNum = 5
+ [
+ [:horizontal, [:s, :ns, :n]],
+ [:vertical, [:e, :we, :w]]
+ ].each{|orient, expandList|
+ expandList.each{|expand|
+ s = t.style_create("s#{styleNum}", :orient=>orient)
+ t.style_elements(s, ['e4', 'e8', 'e2', 'e5', 'e6'])
+ t.style_layout(s, 'e4', :detach=>true, :iexpand=>:es)
+ t.style_layout(s, 'e8', :detach=>true, :expand=>:n, :iexpand=>:e)
+ t.style_layout(s, 'e2', :expand=>expand)
+ t.style_layout(s, 'e5', :expand=>expand)
+ t.style_layout(s, 'e6', :expand=>expand)
+ styleNum += 1
+
+ i = t.item_create()
+ t.item_style_set(i, 0, s)
+ t.item_lastchild(:root, i)
+ }
+ }
+end
diff --git a/ext/tk/sample/tkextlib/treectrl/mailwasher.rb b/ext/tk/sample/tkextlib/treectrl/mailwasher.rb
new file mode 100644
index 0000000000..b695db5104
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/mailwasher.rb
@@ -0,0 +1,269 @@
+#
+# Demo: MailWasher
+#
+def demoMailWasher(t)
+ init_pics('*checked')
+
+ height = t.font.metrics(:linespace) + 2
+ height = 18 if height < 18
+
+ t.configure(:showroot=>false, :showrootbutton=>false, :showbuttons=>false,
+ :showlines=>false, :itemheight=>height, :selectmode=>:browse,
+ :xscrollincrement=>1)
+
+ pad = 4
+
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.column_create(:text=>'Delete', :textpadx=>pad, :tag=>'delete')
+ t.column_create(:text=>'Bounce', :textpadx=>pad, :tag=>'bounce')
+ t.column_create(:text=>'Status', :width=>80, :textpadx=>pad,
+ :tag=>'status')
+ t.column_create(:text=>'Size', :width=>40, :textpadx=>pad,
+ :justify=>:right, :tag=>'size')
+ t.column_create(:text=>'From', :width=>140, :textpadx=>pad, :tag=>'from')
+ t.column_create(:text=>'Subject', :width=>240, :textpadx=>pad,
+ :tag=>'subject')
+ t.column_create(:text=>'Received', :textpadx=>pad, :arrow=>:up,
+ :arrowpad=>[4,0], :tag=>'received')
+ t.column_create(:text=>'Attachments', :textpadx=>pad, :tag=>'attachments')
+
+ t.state_define('CHECK')
+
+ t.element_create('imgCheck', :image, :image=>[
+ @images['checked'], ['CHECK'], @images['unchecked'], []
+ ])
+
+ else # TreeCtrl 1.0
+ t.column_configure(0, :text=>'Delete', :textpadx=>pad, :tag=>'delete')
+ t.column_configure(1, :text=>'Bounce', :textpadx=>pad, :tag=>'bounce')
+ t.column_configure(2, :text=>'Status', :width=>80, :textpadx=>pad,
+ :tag=>'status')
+ t.column_configure(3, :text=>'Size', :width=>40, :textpadx=>pad,
+ :justify=>:right, :tag=>'size')
+ t.column_configure(4, :text=>'From', :width=>140, :textpadx=>pad,
+ :tag=>'from')
+ t.column_configure(5, :text=>'Subject', :width=>240, :textpadx=>pad,
+ :tag=>'subject')
+ t.column_configure(6, :text=>'Received', :textpadx=>pad, :arrow=>:up,
+ :arrowpad=>[4,0], :tag=>'received')
+ t.column_configure(7, :text=>'Attachments', :textpadx=>pad,
+ :tag=>'attachments')
+
+ t.element_create('imgOff', :image, :image=>@images['unchecked'])
+ t.element_create('imgOn', :image, :image=>@images['checked'])
+ end
+
+ t.element_create('border', :rect, :open=>:nw, :outline=>'gray',
+ :outlinewidth=>1, :fill=>[@SystemHighlight, ['selected']])
+ t.element_create('txtAny', :text, :lines=>1,
+ :fill=>[@SystemHighlightText, ['selected']])
+ t.element_create('txtNone', :text, :text=>'none', :lines=>1,
+ :fill=>[@SystemHighlightText, ['selected']])
+ t.element_create('txtYes', :text, :text=>'yes', :lines=>1,
+ :fill=>[@SystemHighlightText, ['selected']])
+ t.element_create('txtNormal', :text, :text=>'Normal', :lines=>1,
+ :fill=>[@SystemHighlightText, ['selected'], '#006800', []])
+ t.element_create('txtPossSpam', :text, :text=>'Possible Spam', :lines=>1,
+ :fill=>[@SystemHighlightText, ['selected'], '#787800', []])
+ t.element_create('txtProbSpam', :text, :text=>'Probably Spam', :lines=>1,
+ :fill=>[@SystemHighlightText, ['selected'], '#FF9000', []])
+ t.element_create('txtBlacklist', :text, :text=>'Blacklisted', :lines=>1,
+ :fill=>[@SystemHighlightText, ['selected'], '#FF5800', []])
+
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ s = t.style_create('styCheck')
+ t.style_elements(s, ['border', 'imgCheck'])
+ t.style_layout(s, 'border', :detach=>true, :iexpand=>:es)
+ t.style_layout(s, 'imgCheck', :expand=>:news)
+ else
+ ['Off', 'On'].each{|name|
+ s = t.style_create('sty' << name)
+ i = 'img' << name
+ t.style_elements(s, ['border', i])
+ t.style_layout(s, 'border', :detach=>true, :iexpand=>:es)
+ t.style_layout(s, i, :expand=>:news)
+ }
+ end
+
+ pad = 4
+
+ %w(Any None Yes Normal PossSpam ProbSpam Blacklist).each{|name|
+ s = t.style_create('sty' << name)
+ e = 'txt' << name
+ t.style_elements(s, ['border', e])
+ t.style_layout(s, 'border', :detach=>true, :iexpand=>:es)
+ t.style_layout(s, e, :padx=>pad, :squeeze=>:x, :expand=>:ns)
+ }
+
+ [
+ ['baldy@spammer.com', "Your hair is thinning"],
+ ['flat@spammer.com', "Your breasts are too small"],
+ ['tiny@spammer.com', "Your penis is too small"],
+ ['dumbass@spammer.com', "You are not very smart"],
+ ['bankrobber@spammer.com', "You need more money"],
+ ['loser@spammer.com', "You need better friends"],
+ ['gossip@spammer.com', "Find out what your coworkers think about you"],
+ ['whoami@spammer.com', "Find out what you think about yourself"],
+ ['downsized@spammer.com', "You need a better job"],
+ ['poorhouse@spammer.com', "Your mortgage is a joke"],
+ ['spam4ever@spammer.com' "You need more spam"]
+ ].each{|frm, subj|
+ item = t.item_create
+ status = ['styNormal','styPossSpam','styProbSpam','styBlacklist'][rand(4)]
+ attachments = ['styNone','styYes'][rand(2)]
+
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ delete = [false, true][rand(2)]
+ bounce = [false, true][rand(2)]
+ t.item_style_set(item,
+ 0, 'styCheck', 1, 'styCheck', 2, status, 3, 'styAny',
+ 4, 'styAny', 5, 'styAny', 6, 'styAny', 7, attachments)
+ t.item_state_forcolumn(item, 'delete', 'CHECK') if delete
+ t.item_state_forcolumn(item, 'bounce', 'CHECK') if bounce
+
+ else # TreeCtrl 1.0
+ delete = ['styOn', 'styOff'][rand(2)]
+ bounce = ['styOn', 'styOff'][rand(2)]
+ t.item_style_set(item,
+ 0, delete, 1, bounce, 2, status, 3, 'styAny',
+ 4, 'styAny', 5, 'styAny', 6, 'styAny', 7, attachments)
+ end
+
+ bytes = 512 + rand(1024 * 12)
+ size = "#{bytes / 1024 + 1}KB"
+ seconds = Tk::Clock.seconds - rand(100000)
+ received = Tk::Clock.format(seconds, '%d/%m/%y %I:%M %p')
+ t.item_text(item, 3, size, 4, frm, 5, subj, 6, received)
+ t.item_lastchild(:root, item)
+ }
+
+ sortColumn = 6
+ t.notify_bind(t, 'Header-invoke',
+ proc{|c, w|
+ if c == sortColumn
+ if w.column_cget(sortColumn, :arrow) == 'down'
+ order = :increasing
+ arrow = :up
+ else
+ order = :decreasing
+ arrow = :down
+ end
+ else
+ if w.column_cget(sortColumn, :arrow) == 'down'
+ order = :decreasing
+ arrow = :down
+ else
+ order = :increasing
+ arrow = :up
+ end
+ w.column_configure(sortColumn, :arrow=>:none)
+ sortColumn = c
+ end
+ w.column_configure(c, :arrow=>arrow)
+ case w.column_cget(c, :tag)
+ when 'bounce', 'delete'
+ w.item_sort(:root, order,
+ {
+ :column=>c,
+ :command=>proc{|item1, item2|
+ compareOnOff(w, c, item1, item2)
+ }
+ },
+ { :column=>'subject', :dictionary=>true })
+ when 'status'
+ w.item_sort(:root, order,
+ { :column=>c, :dictionary=>true })
+ when 'from'
+ w.item_sort(:root, order,
+ { :column=>c, :dictionary=>true },
+ { :column=>'subject', :dictionary=>true })
+ when 'subject'
+ w.item_sort(:root, order,
+ { :column=>c, :dictionary=>true })
+ when 'size'
+ w.item_sort(:root, order,
+ { :column=>c, :dictionary=>true },
+ { :column=>'subject', :dictionary=>true })
+ when 'received'
+ w.item_sort(:root, order,
+ { :column=>c, :dictionary=>true },
+ { :column=>'subject', :dictionary=>true })
+ when 'attachments'
+ w.item_sort(:root, order,
+ { :column=>c, :dictionary=>true },
+ { :column=>'subject', :dictionary=>true })
+ end
+ }, '%C %T')
+
+ mailWasher = TkBindTag.new
+
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ mailWasher.bind('ButtonPress-1',
+ proc{|w, x, y|
+ id = w.identify(x, y)
+ if id.empty?
+ elsif id[0] == 'header'
+ else
+ what, item, where, arg1, arg2, arg3 = id
+ if where == 'column'
+ tag = w.column_cget(arg1, :tag)
+ if tag == 'delete' || tag == 'bounce'
+ w.item_state_forcolumn(item, arg1, '~CHECK')
+ end
+ end
+ end
+ }, '%W %x %y')
+ else # TreeCtrl 1.0
+ mailWasher.bind('ButtonPress-1',
+ proc{|w, x, y|
+ id = w.identify(x, y)
+ if id.empty?
+ elsif id[0] == 'header'
+ else
+ what, item, where, arg1, arg2, arg3 = id
+ if where == 'column'
+ tag = w.column_cget(arg1, :tag)
+ if tag == 'delete' || tag == 'bounce'
+ style = w.item_style_set(item, arg1)
+ if style == 'styOn'
+ style = 'styOff'
+ else
+ style = 'styOn'
+ end
+ w.item_style_set(item, arg1, style)
+ @display_styles_in_item.call(item)
+ end
+ end
+ end
+ }, '%W %x %y')
+ end
+
+ t.bindtags = [t, mailWasher, Tk::TreeCtrl, t.winfo_toplevel, TkBindTag::ALL]
+end
+
+if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ def compareOnOff(w, c, item1, item2)
+ s1 = w.item_state_forcolumn(item1, c)
+ s2 = w.item_state_forcolumn(item2, c)
+ if (s1 == s2)
+ 0
+ elsif (s1 == 'CHECK')
+ -1
+ else
+ 1
+ end
+ end
+
+else # TreeCtrl 1.0
+ def compareOnOff(w, c, item1, item2)
+ s1 = w.item_style_set(item1, c)
+ s2 = w.item_style_set(item2, c)
+ if (s1 == s2)
+ 0
+ elsif (s1 == 'styOff')
+ -1
+ else
+ 1
+ end
+ end
+end
diff --git a/ext/tk/sample/tkextlib/treectrl/outlook-folders.rb b/ext/tk/sample/tkextlib/treectrl/outlook-folders.rb
new file mode 100644
index 0000000000..e56ba3f889
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/outlook-folders.rb
@@ -0,0 +1,124 @@
+#
+# Demo: Outlook Express folder list
+#
+def demoOutlookFolders(t)
+ init_pics('outlook-*')
+
+ height = t.font.metrics(:linespace) + 2
+ height = 18 if height < 18
+
+ t.configure(:itemheight=>height, :selectmode=>:browse, :showlines=>true,
+ :showroot=>true, :showrootbutton=>false, :showbuttons=>true)
+
+ if $HasColumnCreate
+ t.column_create(:text=>'Folders')
+ else
+ t.column_configure(0, :text=>'Folders')
+ end
+
+ t.element_create('e1', :image)
+ t.element_create('e2', :text, :lines=>1,
+ :fill=>[@SystemHighlightText, ['selected', 'focus']])
+ t.element_create('e3', :text, :lines=>1, :font=>t.font.dup.weight(:bold),
+ :fill=>[@SystemHighlightText, ['selected', 'focus']])
+ t.element_create('e4', :text, :fill=>'blue')
+ t.element_create('e5', :image, :image=>@images['outlook-folder'])
+ t.element_create('e6', :rect, :showfocus=>true,
+ :fill=>[
+ @SystemHighlight, ['selected', 'focus'],
+ 'gray', ['selected', '!focus']
+ ])
+
+ # image + text
+ s = t.style_create('s1')
+ t.style_elements(s, ['e6', 'e1', 'e2'])
+ t.style_layout(s, 'e1', :expand=>:ns)
+ t.style_layout(s, 'e2', :padx=>[4,0], :expand=>:ns, :squeeze=>:x)
+ t.style_layout(s, 'e6', :union=>['e2'], :iexpand=>:ns, :ipadx=>2)
+
+ # image + text + text
+ s = t.style_create('s2')
+ t.style_elements(s, ['e6', 'e1', 'e3', 'e4'])
+ t.style_layout(s, 'e1', :expand=>:ns)
+ t.style_layout(s, 'e3', :padx=>4, :expand=>:ns, :squeeze=>:x)
+ t.style_layout(s, 'e4', :expand=>:ns)
+ t.style_layout(s, 'e6', :union=>['e3'], :iexpand=>:ns, :ipadx=>2)
+
+ # folder + text
+ s = t.style_create('s3')
+ t.style_elements(s, ['e6', 'e5', 'e2'])
+ t.style_layout(s, 'e5', :expand=>:ns)
+ t.style_layout(s, 'e2', :padx=>[4,0], :expand=>:ns, :squeeze=>:x)
+ t.style_layout(s, 'e6', :union=>['e2'], :iexpand=>:ns, :ipadx=>2)
+
+ # folder + text + text
+ s = t.style_create('s4')
+ t.style_elements(s, ['e6', 'e5', 'e3', 'e4'])
+ t.style_layout(s, 'e5', :expand=>:ns)
+ t.style_layout(s, 'e3', :padx=>4, :expand=>:ns, :squeeze=>:x)
+ t.style_layout(s, 'e4', :expand=>:ns)
+ t.style_layout(s, 'e6', :union=>['e3'], :iexpand=>:ns, :ipadx=>2)
+
+ t.item_style_set(:root, 0, 's1')
+ t.item_complex(:root,
+ [
+ ['e1', {:image=>@images['outlook-main']}],
+ ['e2', {:text=>'Outlook Express'}]
+ ])
+
+ parentList = [:root, '', '', '', '', '', '']
+ parent = :root
+ [
+ [0, :local, "Local Folders", true, 0],
+ [1, :inbox, 'Inbox', false, 5],
+ [1, :outbox, 'Outbox', false, 0],
+ [1, :sent, "Sent Items", false, 0],
+ [1, :deleted, "Deleted Items", false, 50],
+ [1, :draft, 'Drafts', false, 0],
+ [1, :folder, "Messages to Dad", false, 0],
+ [1, :folder, "Messages to Sis", false, 0],
+ [1, :folder, "Messages to Me", false, 0],
+ [2, :folder, "2001", false, 0],
+ [2, :folder, "2000", false, 0],
+ [2, :folder, "1999", false, 0],
+ [0, :server, "news.gmane.org", true, 0],
+ [1, :group, "gmane.comp.lang.lua.general", false, 498]
+ ].each{|depth, img, text, button, unread|
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ item = t.item_create(:button=>button)
+ else
+ item = t.item_create
+ t.item_hasbutton(item, button)
+ end
+ if img == :folder
+ if unread != 0
+ t.item_style_set(item, 0, 's4')
+ t.item_complex(item,
+ [['e3', {:text=>text}], ['e4', {:text=>"(#{unread})"}]])
+ else
+ t.item_style_set(item, 0, 's3')
+ t.item_complex(item, [['e2', {:text=>text}]])
+ end
+ else
+ if unread != 0
+ t.item_style_set(item, 0, 's2')
+ t.item_complex(item,
+ [
+ ['e1', {:image=>@images["outlook-#{img}"]}],
+ ['e3', {:text=>text}],
+ ['e4', {:text=>"(#{unread})"}]
+ ])
+ else
+ t.item_style_set(item, 0, 's1')
+ t.item_complex(item,
+ [
+ ['e1', {:image=>@images["outlook-#{img}"]}],
+ ['e2', {:text=>text}]
+ ])
+ end
+ end
+ t.item_lastchild(parentList[depth], item)
+ depth += 1
+ parentList[depth] = item
+ }
+end
diff --git a/ext/tk/sample/tkextlib/treectrl/outlook-newgroup.rb b/ext/tk/sample/tkextlib/treectrl/outlook-newgroup.rb
new file mode 100644
index 0000000000..41b7fbb868
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/outlook-newgroup.rb
@@ -0,0 +1,447 @@
+#
+# Demo: Outlook Express newsgroup messages
+#
+def demoOutlookNewsgroup(t)
+ init_pics('outlook-*')
+
+ height = t.font.metrics(:linespace) + 2
+ hehght = 18 if height < 18
+ t.configure(:itemheight=>height, :selectmode=>:browse, :showlines=>false,
+ :showroot=>false, :showrootbutton=>false, :showbuttons=>true)
+
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.column_create(:image=>@images['outlook-clip'], :tag=>'clip')
+ t.column_create(:image=>@images['outlook-arrow'], :tag=>'arrow')
+ t.column_create(:image=>@images['outlook-watch'], :tag=>'watch')
+ t.column_create(:text=>'Subject', :width=>250, :tag=>'subject')
+ t.column_create(:text=>'From', :width=>150, :tag=>'from')
+ t.column_create(:text=>'Sent', :width=>150, :tag=>'sent')
+ t.column_create(:text=>'Size', :width=>60, :justify=>:right, :tag=>'size')
+ else # TreeCtrl 1.0
+ t.column_configure(0, :image=>@images['outlook-clip'], :tag=>'clip')
+ t.column_configure(1, :image=>@images['outlook-arrow'], :tag=>'arrow')
+ t.column_configure(2, :image=>@images['outlook-watch'], :tag=>'watch')
+ t.column_configure(3, :text=>'Subject', :width=>250, :tag=>'subject')
+ t.column_configure(4, :text=>'From', :width=>150, :tag=>'from')
+ t.column_configure(5, :text=>'Sent', :width=>150, :tag=>'sent')
+ t.column_configure(6, :text=>'Size', :width=>60, :justify=>:right,
+ :tag=>'size')
+ end
+
+ # Would be nice if I could specify a column -tag too
+ t.treecolumn = 3
+
+ # State for a read message
+ t.state_define('read')
+
+ # State for a message with unread descendants
+ t.state_define('unread')
+
+ t.element_create('elemImg', :image,
+ :image=>[
+ @images['outlook-read-2Sel'],
+ ['selected', 'read', 'unread', '!open'],
+ @images['outlook-read-2'], ['read', 'unread', '!open'],
+ @images['outlook-readSel'], ['selected', 'read'],
+ @images['outlook-read'], ['read'],
+ @images['outlook-unreadSel'], ['selected'],
+ @images['outlook-unread'], []
+ ])
+ t.element_create('elemTxt', :text, :lines=>1,
+ :fill=>[@SystemHighlightText, ['selected', 'focus']],
+ :font=>[
+ t.font.dup.weight(:bold), ['read', 'unread', '!open'],
+ t.font.dup.weight(:bold), ['!read']
+ ])
+ t.element_create('sel.e', :rect, :open=>:e, :showfocus=>true,
+ :fill=>[
+ @SystemHighlight, ['selected', 'focus'],
+ 'gray', ['selected', '!focus']
+ ])
+ t.element_create('sel.w', :rect, :open=>:w, :showfocus=>true,
+ :fill=>[
+ @SystemHighlight, ['selected', 'focus'],
+ 'gray', ['selected', '!focus']
+ ])
+ t.element_create('sel.we', :rect, :open=>:we, :showfocus=>true,
+ :fill=>[
+ @SystemHighlight, ['selected', 'focus'],
+ 'gray', ['selected', '!focus']
+ ])
+
+ # Image + text
+ s = t.style_create('s1')
+ t.style_elements(s, ['sel.e', 'elemImg', 'elemTxt'])
+ t.style_layout(s, 'elemImg', :expand=>:ns)
+ t.style_layout(s, 'elemTxt', :padx=>[2,6], :squeeze=>:x, :expand=>:ns)
+ t.style_layout(s, 'sel.e', :union=>['elemTxt'],
+ :iexpand=>:nes, :ipadx=>[2,0])
+
+ # Text
+ s = t.style_create('s2.we')
+ t.style_elements(s, ['sel.we', 'elemTxt'])
+ t.style_layout(s, 'elemTxt', :padx=>6, :squeeze=>:x, :expand=>:ns)
+ t.style_layout(s, 'sel.we', :detach=>true, :iexpand=>:es)
+
+ # Text
+ s = t.style_create('s2.w')
+ t.style_elements(s, ['sel.w', 'elemTxt'])
+ t.style_layout(s, 'elemTxt', :padx=>6, :squeeze=>:x, :expand=>:ns)
+ t.style_layout(s, 'sel.w', :detach=>true, :iexpand=>:es)
+
+ # Set default item style
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.defaultstyle = ['', '', '', 's1', 's2.we', 's2.we', 's2.w']
+ end
+
+ msgCnt = 100
+ thread = 0
+
+ @Message = Hash.new{|k, v| k[v] = Hash.new}
+ @Message[:count][0] = 0
+
+ items = [t.index(:root)]
+
+ (1...(msgCnt)).each{|i|
+ item_i = t.item_create
+ item_j = nil
+ j = nil
+ loop {
+ j = rand(i)
+ item_j = items[j]
+ break if j == 0
+ next if t.depth(item_j) == 5
+ next if @Message[:count][@Message[:thread][item_j]] == 15
+ break
+ }
+ t.item_lastchild(item_j, item_i)
+
+ @Message[:read][item_i] = (rand(2) == 0)
+ if j == 0
+ thread += 1
+ @Message[:thread][item_i] = thread
+ @Message[:seconds][item_i] = (Tk::Clock.seconds - rand(500000))
+ @Message[:seconds2][item_i] = @Message[:seconds][item_i]
+ @Message[:count][thread] = 1
+ else
+ @Message[:thread][item_i] = @Message[:thread][item_j]
+ @Message[:seconds][item_i] = (@Message[:seconds2][item_j] + rand(10000))
+ @Message[:seconds2][item_i] = @Message[:seconds][item_i]
+ @Message[:seconds2][item_j] = @Message[:seconds][item_i]
+ @Message[:count][@Message[:thread][item_j]] += 1
+ end
+ items << item_i
+ }
+
+ (1...(msgCnt)).each{|i|
+ item_i = items[i]
+ subject = "This is thread number #{@Message[:thread][item_i]}"
+ from = 'somebody@somewhere.net'
+ sent = Tk::Clock.format(@Message[:seconds][item_i], "%d/%m/%y %I:%M %p")
+ size = "#{1 + rand(10)}KB"
+
+ # This message has been read
+ t.item_state_set(item_i, 'read') if @Message[:read][item_i]
+
+ # This message has unread descendants
+ t.item_state_set(item_i, 'unread') if anyUnreadDescendants(t, item_i)
+
+ if t.item_numchildren(item_i) > 0
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.item_configure(item_i, :button=>true)
+ else # TreeCtrl 1.0
+ t.item_hasbutton(item_i, true)
+ end
+
+ # Collapse some messages
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.item_collapse(item_i) if rand(2) == 0
+ else # TreeCtrl 1.0
+ t.collapse(item_i) if rand(2) == 0
+ end
+ end
+
+ unless (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.item_style_set(item_i, 3, 's1', 4, 's2.we', 5, 's2.we', 6, 's2.w')
+ end
+ t.item_text(item_i, 3, subject, 4, from, 5, sent, 6, size)
+ }
+
+ # Do something when the selection changes
+ t.notify_bind(t, 'Selection',
+ proc{|w|
+ if w.selection_count == 1
+ # One item is selected
+ if @Message[:afterID][:id]
+ Tk.after_cancel(@Message[:afterID][:id])
+ end
+ @Message[:afterID][:item] = w.selection_get[0]
+ @Message[:afterID][:id] = Tk.after(500, proc{
+ messageReadDelayed(w)
+ })
+ end
+ }, '%T')
+end
+
+def messageReadDelayed(t)
+ @Message[:afterID].delete(:id)
+ i = @Message[:afterID][:item]
+ return unless t.selection_includes(i)
+
+ # This message is not read
+ unless @Message[:read][i]
+ # Read the message
+ t.item_state_set(i, 'read')
+ @Message[:read][i] = true
+
+ # Check ancestors (except root)
+ t.item_ancestors(i)[0..-2].each{|i2|
+ # This ancestor has no more unread descendants
+ t.item_state_set(i2, '!unread') unless anyUnreadDescendants(t, i2)
+ }
+ end
+end
+
+# Alternate implementation which does not rely on run-time states
+def demoOutlookNewsgroup2(t)
+ init_pics('outlook-*')
+
+ height = t.font.metrics(:linespace) + 2
+ hehght = 18 if height < 18
+ t.configure(:itemheight=>height, :selectmode=>:browse, :showlines=>false,
+ :showroot=>false, :showrootbutton=>false, :showbuttons=>true)
+
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.column_create(:image=>@images['outlook-clip'], :tag=>'clip')
+ t.column_create(:image=>@images['outlook-arrow'], :tag=>'arrow')
+ t.column_create(:image=>@images['outlook-watch'], :tag=>'watch')
+ t.column_create(:text=>'Subject', :width=>250, :tag=>'subject')
+ t.column_create(:text=>'From', :width=>150, :tag=>'from')
+ t.column_create(:text=>'Sent', :width=>150, :tag=>'sent')
+ t.column_create(:text=>'Size', :width=>60, :justify=>:right, :tag=>'size')
+ else # TreeCtrl 1.0
+ t.column_configure(0, :image=>@images['outlook-clip'], :tag=>'clip')
+ t.column_configure(1, :image=>@images['outlook-arrow'], :tag=>'arrow')
+ t.column_configure(2, :image=>@images['outlook-watch'], :tag=>'watch')
+ t.column_configure(3, :text=>'Subject', :width=>250, :tag=>'subject')
+ t.column_configure(4, :text=>'From', :width=>150, :tag=>'from')
+ t.column_configure(5, :text=>'Sent', :width=>150, :tag=>'sent')
+ t.column_configure(6, :text=>'Size', :width=>60, :justify=>:right,
+ :tag=>'size')
+ end
+
+ t.treecolumn = 3
+
+ t.element_create('image.unread', :image, :image=>@images['outlook-unread'])
+ t.element_create('image.read', :image, :image=>@images['outlook-read'])
+ t.element_create('image.read2', :image, :image=>@images['outlook-read-2'])
+ t.element_create('text.read', :text, :lines=>1,
+ :fill=>[@SystemHighlightText, ['selected', 'focus']])
+ t.element_create('text.unread', :text, :lines=>1,
+ :fill=>[@SystemHighlightText, ['selected', 'focus']],
+ :font=>t.font.dup.weight(:bold))
+ t.element_create('sel.e', :rect, :open=>:e, :showfocus=>true,
+ :fill=>[
+ @SystemHighlight, ['selected', 'focus'],
+ 'gray', ['selected', '!focus']
+ ])
+ t.element_create('sel.w', :rect, :open=>:w, :showfocus=>true,
+ :fill=>[
+ @SystemHighlight, ['selected', 'focus'],
+ 'gray', ['selected', '!focus']
+ ])
+ t.element_create('sel.we', :rect, :open=>:we, :showfocus=>true,
+ :fill=>[
+ @SystemHighlight, ['selected', 'focus'],
+ 'gray', ['selected', '!focus']
+ ])
+
+ # Image + text
+ s = t.style_create('unread')
+ t.style_elements(s, ['sel.e', 'image.unread', 'text.unread'])
+ t.style_layout(s, 'image.unread', :expand=>:ns)
+ t.style_layout(s, 'text.unread', :padx=>[2,6], :squeeze=>:x, :expand=>:ns)
+ t.style_layout(s, 'sel.e', :union=>['text.unread'],
+ :iexpand=>:nes, :ipadx=>[2,0])
+
+ # Image + text
+ s = t.style_create('read')
+ t.style_elements(s, ['sel.e', 'image.read', 'text.read'])
+ t.style_layout(s, 'image.read', :expand=>:ns)
+ t.style_layout(s, 'text.read', :padx=>[2,6], :squeeze=>:x, :expand=>:ns)
+ t.style_layout(s, 'sel.e', :union=>['text.read'],
+ :iexpand=>:nes, :ipadx=>[2,0])
+
+ # Image + text
+ s = t.style_create('read2')
+ t.style_elements(s, ['sel.e', 'image.read2', 'text.unread'])
+ t.style_layout(s, 'image.read2', :expand=>:ns)
+ t.style_layout(s, 'text.unread', :padx=>[2,6], :squeeze=>:x, :expand=>:ns)
+ t.style_layout(s, 'sel.e', :union=>['text.unread'],
+ :iexpand=>:nes, :ipadx=>[2,0])
+
+ # Text
+ s = t.style_create('unread.we')
+ t.style_elements(s, ['sel.we', 'text.unread'])
+ t.style_layout(s, 'text.unread', :padx=>6, :squeeze=>:x, :expand=>:ns)
+ t.style_layout(s, 'sel.we', :detach=>true, :iexpand=>:es)
+
+ # Text
+ s = t.style_create('read.we')
+ t.style_elements(s, ['sel.we', 'text.read'])
+ t.style_layout(s, 'text.read', :padx=>6, :squeeze=>:x, :expand=>:ns)
+ t.style_layout(s, 'sel.we', :detach=>true, :iexpand=>:es)
+
+ # Text
+ s = t.style_create('unread.w')
+ t.style_elements(s, ['sel.w', 'text.unread'])
+ t.style_layout(s, 'text.unread', :padx=>6, :squeeze=>:x, :expand=>:ns)
+ t.style_layout(s, 'sel.w', :detach=>true, :iexpand=>:es)
+
+ # Text
+ s = t.style_create('read.w')
+ t.style_elements(s, ['sel.w', 'text.read'])
+ t.style_layout(s, 'text.read', :padx=>6, :squeeze=>:x, :expand=>:ns)
+ t.style_layout(s, 'sel.w', :detach=>true, :iexpand=>:es)
+
+ msgCnt = 100
+ thread = 0
+
+ @Message = Hash.new{|k, v| k[v] = Hash.new}
+ @Message[:count][0] = 0
+
+ (1...(msgCnt)).each{|i|
+ t.item_create
+ j = nil
+ loop {
+ j = rand(i)
+ break if j == 0
+ next if t.depth(j) == 5
+ next if @Message[:count][@Message[:thread][j]] == 15
+ break
+ }
+ t.item_lastchild(j, i)
+
+ @Message[:read][i] = (rand(2) == 0)
+ if j == 0
+ thread += 1
+ @Message[:thread][i] = thread
+ @Message[:seconds][i] = (Tk::Clock.seconds - rand(500000))
+ @Message[:seconds2][i] = @Message[:seconds][i]
+ @Message[:count][thread] = 1
+ else
+ @Message[:thread][i] = @Message[:thread][j]
+ @Message[:seconds][i] = (@Message[:seconds2][j] + rand(10000))
+ @Message[:seconds2][i] = @Message[:seconds][i]
+ @Message[:seconds2][j] = @Message[:seconds][i]
+ @Message[:count][@Message[:thread][j]] += 1
+ end
+ }
+
+ (1...(msgCnt)).each{|i|
+ subject = "This is thread number #{@Message[:thread][i]}"
+ from = 'somebody@somewhere.net'
+ sent = Tk::Clock.format(@Message[:seconds][i], "%d/%m/%y %I:%M %p")
+ size = "#{1 + rand(10)}KB"
+ if @Message[:read][i]
+ style = 'read'
+ style2 = 'read2'
+ else
+ style = 'unread'
+ style2 = 'unread2'
+ end
+ t.item_style_set(i, 3, style, 4, "#{style2}.we", 5, "#{style2}.we",
+ 6, "#{style2}.w")
+ t.item_text(i, 3, subject, 4, from, 5, sent, 6, size)
+ if t.item_numchildren(i) > 0
+ t.item_configure(item_i, :button=>true)
+ end
+ }
+
+ # Do something when the selection changes
+ t.notify_bind(t, 'Selection',
+ proc{|w|
+ if w.selection_count == 1
+ i = t.selection_get[0]
+ unless @Message[:read][i]
+ if t.item_isopen(i) || !anyUnreadDescendants(t, i)
+ # unread -> read
+ t.item_style_map(i, 'subject', 'read',
+ ['text.unread', 'text.read'])
+ t.item_style_map(i, 'from', 'read.we',
+ ['text.unread', 'text.read'])
+ t.item_style_map(i, 'sent', 'read.we',
+ ['text.unread', 'text.read'])
+ t.item_style_map(i, 'size', 'read.w',
+ ['text.unread', 'text.read'])
+ else
+ # unread -> read2
+ t.item_style_map(i, 'subject', 'read2',
+ ['text.unread', 'text.unread'])
+ end
+
+ @Message[:read][i] = true
+ @display_styles_in_item.call(i)
+ end
+ end
+ }, '%T')
+
+ t.notify_bind(t, 'Expand-after',
+ proc{|w|
+ if @Messge[:read][i] && anyUnreadDescendants(t, i)
+ # read2 -> read
+ t.item_style_map(i, 'subject', 'read',
+ ['text.unread', 'text.read'])
+ # unread -> read
+ t.item_style_map(i, 'from', 'read.we',
+ ['text.unread', 'text.read'])
+ t.item_style_map(i, 'sent', 'read.we',
+ ['text.unread', 'text.read'])
+ t.item_style_map(i, 'size', 'read.w',
+ ['text.unread', 'text.read'])
+ end
+ }, '%T')
+
+ t.notify_bind(t, 'Collapse-after',
+ proc{|w|
+ if @Messge[:read][i] && anyUnreadDescendants(t, i)
+ # read -> read2
+ t.item_style_map(i, 'subject', 'read2',
+ ['text.read', 'text.unread'])
+ # read -> unread
+ t.item_style_map(i, 'from', 'unread.we',
+ ['text.read', 'text.unread'])
+ t.item_style_map(i, 'sent', 'unread.we',
+ ['text.read', 'text.unread'])
+ t.item_style_map(i, 'size', 'unread.w',
+ ['text.read', 'text.unread'])
+ end
+ }, '%T')
+
+ (1...(msgCnt)).each{|i|
+ if rand(2) == 0
+ if t.item_numchildren(i) > 0
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.item_collapse(i)
+ else # TreeCtrl 1.0
+ t.collapse(i)
+ end
+ end
+ end
+ }
+end
+
+def anyUnreadDescendants(t, i)
+ itemList = [ t.item_firstchild(i) ]
+ while(itemList.length > 0)
+ item = itemList.pop
+
+ return true unless @Message[:read][item]
+
+ item2 = t.item_nextsibling(item)
+ itemList.push(item2) if item2 != ''
+ item2 = t.item_firstchild(item)
+ itemList.push(item2) if item2 != ''
+ end
+ false
+end
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/big-dll.gif b/ext/tk/sample/tkextlib/treectrl/pics/big-dll.gif
new file mode 100644
index 0000000000..09170c0e26
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/big-dll.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/big-exe.gif b/ext/tk/sample/tkextlib/treectrl/pics/big-exe.gif
new file mode 100644
index 0000000000..e19aac1a2d
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/big-exe.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/big-file.gif b/ext/tk/sample/tkextlib/treectrl/pics/big-file.gif
new file mode 100644
index 0000000000..6c752312a3
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/big-file.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/big-folder.gif b/ext/tk/sample/tkextlib/treectrl/pics/big-folder.gif
new file mode 100644
index 0000000000..186c9749fd
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/big-folder.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/big-txt.gif b/ext/tk/sample/tkextlib/treectrl/pics/big-txt.gif
new file mode 100644
index 0000000000..a93492586e
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/big-txt.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/checked.gif b/ext/tk/sample/tkextlib/treectrl/pics/checked.gif
new file mode 100644
index 0000000000..3b9b176ab3
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/checked.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/file.gif b/ext/tk/sample/tkextlib/treectrl/pics/file.gif
new file mode 100644
index 0000000000..a64c2a06bd
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/file.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/folder-closed.gif b/ext/tk/sample/tkextlib/treectrl/pics/folder-closed.gif
new file mode 100644
index 0000000000..0a064376c9
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/folder-closed.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/folder-open.gif b/ext/tk/sample/tkextlib/treectrl/pics/folder-open.gif
new file mode 100644
index 0000000000..3fac27ffd9
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/folder-open.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/help-book-closed.gif b/ext/tk/sample/tkextlib/treectrl/pics/help-book-closed.gif
new file mode 100644
index 0000000000..0a0497bfa3
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/help-book-closed.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/help-book-open.gif b/ext/tk/sample/tkextlib/treectrl/pics/help-book-open.gif
new file mode 100644
index 0000000000..40656c5194
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/help-book-open.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/help-page.gif b/ext/tk/sample/tkextlib/treectrl/pics/help-page.gif
new file mode 100644
index 0000000000..e1ce1d72f5
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/help-page.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/imovie-01.gif b/ext/tk/sample/tkextlib/treectrl/pics/imovie-01.gif
new file mode 100644
index 0000000000..5fd9215551
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/imovie-01.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/imovie-02.gif b/ext/tk/sample/tkextlib/treectrl/pics/imovie-02.gif
new file mode 100644
index 0000000000..3d2d1c17c2
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/imovie-02.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/imovie-03.gif b/ext/tk/sample/tkextlib/treectrl/pics/imovie-03.gif
new file mode 100644
index 0000000000..9fccf12b51
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/imovie-03.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/imovie-04.gif b/ext/tk/sample/tkextlib/treectrl/pics/imovie-04.gif
new file mode 100644
index 0000000000..eff851c9bb
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/imovie-04.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/imovie-05.gif b/ext/tk/sample/tkextlib/treectrl/pics/imovie-05.gif
new file mode 100644
index 0000000000..ad00c827f6
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/imovie-05.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/imovie-06.gif b/ext/tk/sample/tkextlib/treectrl/pics/imovie-06.gif
new file mode 100644
index 0000000000..238bf162ac
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/imovie-06.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/imovie-07.gif b/ext/tk/sample/tkextlib/treectrl/pics/imovie-07.gif
new file mode 100644
index 0000000000..a9287e1b1c
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/imovie-07.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/internet-check-off.gif b/ext/tk/sample/tkextlib/treectrl/pics/internet-check-off.gif
new file mode 100644
index 0000000000..e64866a394
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/internet-check-off.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/internet-check-on.gif b/ext/tk/sample/tkextlib/treectrl/pics/internet-check-on.gif
new file mode 100644
index 0000000000..cf652beff2
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/internet-check-on.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/internet-print.gif b/ext/tk/sample/tkextlib/treectrl/pics/internet-print.gif
new file mode 100644
index 0000000000..7ac25b10e9
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/internet-print.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/internet-radio-off.gif b/ext/tk/sample/tkextlib/treectrl/pics/internet-radio-off.gif
new file mode 100644
index 0000000000..90ef62971f
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/internet-radio-off.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/internet-radio-on.gif b/ext/tk/sample/tkextlib/treectrl/pics/internet-radio-on.gif
new file mode 100644
index 0000000000..9de742c198
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/internet-radio-on.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/internet-search.gif b/ext/tk/sample/tkextlib/treectrl/pics/internet-search.gif
new file mode 100644
index 0000000000..1f9a047701
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/internet-search.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/internet-security.gif b/ext/tk/sample/tkextlib/treectrl/pics/internet-security.gif
new file mode 100644
index 0000000000..86d3943786
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/internet-security.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/mac-collapse.gif b/ext/tk/sample/tkextlib/treectrl/pics/mac-collapse.gif
new file mode 100644
index 0000000000..81302c80c1
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/mac-collapse.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/mac-expand.gif b/ext/tk/sample/tkextlib/treectrl/pics/mac-expand.gif
new file mode 100644
index 0000000000..0a2cd80040
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/mac-expand.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/outlook-arrow.gif b/ext/tk/sample/tkextlib/treectrl/pics/outlook-arrow.gif
new file mode 100644
index 0000000000..b1c2afd426
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/outlook-arrow.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/outlook-clip.gif b/ext/tk/sample/tkextlib/treectrl/pics/outlook-clip.gif
new file mode 100644
index 0000000000..8578132702
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/outlook-clip.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/outlook-deleted.gif b/ext/tk/sample/tkextlib/treectrl/pics/outlook-deleted.gif
new file mode 100644
index 0000000000..7cc8369b4b
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/outlook-deleted.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/outlook-draft.gif b/ext/tk/sample/tkextlib/treectrl/pics/outlook-draft.gif
new file mode 100644
index 0000000000..f19585050f
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/outlook-draft.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/outlook-folder.gif b/ext/tk/sample/tkextlib/treectrl/pics/outlook-folder.gif
new file mode 100644
index 0000000000..b3f733563b
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/outlook-folder.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/outlook-group.gif b/ext/tk/sample/tkextlib/treectrl/pics/outlook-group.gif
new file mode 100644
index 0000000000..29ad9b466e
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/outlook-group.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/outlook-inbox.gif b/ext/tk/sample/tkextlib/treectrl/pics/outlook-inbox.gif
new file mode 100644
index 0000000000..f41d804444
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/outlook-inbox.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/outlook-local.gif b/ext/tk/sample/tkextlib/treectrl/pics/outlook-local.gif
new file mode 100644
index 0000000000..0c74970d32
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/outlook-local.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/outlook-main.gif b/ext/tk/sample/tkextlib/treectrl/pics/outlook-main.gif
new file mode 100644
index 0000000000..92325fa85f
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/outlook-main.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/outlook-outbox.gif b/ext/tk/sample/tkextlib/treectrl/pics/outlook-outbox.gif
new file mode 100644
index 0000000000..c7e80527a0
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/outlook-outbox.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/outlook-read-2.gif b/ext/tk/sample/tkextlib/treectrl/pics/outlook-read-2.gif
new file mode 100644
index 0000000000..2f15a3af05
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/outlook-read-2.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/outlook-read.gif b/ext/tk/sample/tkextlib/treectrl/pics/outlook-read.gif
new file mode 100644
index 0000000000..a6f956207a
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/outlook-read.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/outlook-sent.gif b/ext/tk/sample/tkextlib/treectrl/pics/outlook-sent.gif
new file mode 100644
index 0000000000..963b56c4c9
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/outlook-sent.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/outlook-server.gif b/ext/tk/sample/tkextlib/treectrl/pics/outlook-server.gif
new file mode 100644
index 0000000000..c950845d62
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/outlook-server.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/outlook-unread.gif b/ext/tk/sample/tkextlib/treectrl/pics/outlook-unread.gif
new file mode 100644
index 0000000000..3df4b99439
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/outlook-unread.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/outlook-watch.gif b/ext/tk/sample/tkextlib/treectrl/pics/outlook-watch.gif
new file mode 100644
index 0000000000..87ec861312
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/outlook-watch.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/sky.gif b/ext/tk/sample/tkextlib/treectrl/pics/sky.gif
new file mode 100644
index 0000000000..b7fbf14a0a
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/sky.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/small-dll.gif b/ext/tk/sample/tkextlib/treectrl/pics/small-dll.gif
new file mode 100644
index 0000000000..d8875ec23f
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/small-dll.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/small-exe.gif b/ext/tk/sample/tkextlib/treectrl/pics/small-exe.gif
new file mode 100644
index 0000000000..69d30beacd
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/small-exe.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/small-file.gif b/ext/tk/sample/tkextlib/treectrl/pics/small-file.gif
new file mode 100644
index 0000000000..f340662879
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/small-file.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/small-folder.gif b/ext/tk/sample/tkextlib/treectrl/pics/small-folder.gif
new file mode 100644
index 0000000000..ad1b24da84
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/small-folder.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/small-txt.gif b/ext/tk/sample/tkextlib/treectrl/pics/small-txt.gif
new file mode 100644
index 0000000000..cdc7cbfe99
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/small-txt.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/pics/unchecked.gif b/ext/tk/sample/tkextlib/treectrl/pics/unchecked.gif
new file mode 100644
index 0000000000..833e48268b
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/pics/unchecked.gif
Binary files differ
diff --git a/ext/tk/sample/tkextlib/treectrl/random.rb b/ext/tk/sample/tkextlib/treectrl/random.rb
new file mode 100644
index 0000000000..05b6c21236
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/random.rb
@@ -0,0 +1,505 @@
+#
+def random_N
+ @RandomN[0] || 500
+end
+
+#
+# Demo: random N items
+#
+def demoRandom(t)
+ init_pics('folder-*', 'small-*')
+
+ height = t.font.metrics(:linespace) + 2
+ hehght = 18 if height < 18
+ t.configure(:itemheight=>height, :selectmode=>:extended,
+ :showroot=>true, :showrootbutton=>true, :showbuttons=>true,
+ :showlines=>true, :scrollmargin=>16,
+ :xscrolldelay=>[500, 50], :yscrolldelay=>[500, 50])
+
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.column_create(:expand=>true, :text=>'Item',
+ :itembackground=>['#e0e8f0', []], :tag=>'item')
+ t.column_create(:text=>'Parent', :justify=>:center,
+ :itembackground=>['gray90', []], :tag=>'parent')
+ t.column_create(:text=>'Depth', :justify=>:center,
+ :itembackground=>['linen', []], :tag=>'depth')
+ else # TreeCtrl 1.0
+ t.column_configure(0, :expand=>true, :text=>'Item',
+ :itembackground=>['#e0e8f0', []], :tag=>'item')
+ t.column_configure(1, :text=>'Parent', :justify=>:center,
+ :itembackground=>['gray90', []], :tag=>'parent')
+ t.column_configure(2, :text=>'Depth', :justify=>:center,
+ :itembackground=>['linen', []], :tag=>'depth')
+ end
+
+ t.element_create('e1', :image, :image=>[
+ @images['folder-open'], ['open'],
+ @images['folder-closed'], []
+ ])
+ t.element_create('e2', :image, :image=>@images['small-file'])
+ t.element_create('e3', :text,
+ :fill=>[@SystemHighlightText, ['selected', 'focus']])
+ t.element_create('e4', :text, :fill=>'blue')
+ t.element_create('e6', :text)
+ t.element_create('e5', :rect, :showfocus=>true,
+ :fill=>[
+ @SystemHighlight, ['selected', 'focus'],
+ 'gray', ['selected', '!focus']
+ ])
+
+ s = t.style_create('s1')
+ t.style_elements(s, ['e5', 'e1', 'e3', 'e4'])
+ t.style_layout(s, 'e1', :padx=>[0,4], :expand=>:ns)
+ t.style_layout(s, 'e3', :padx=>[0,4], :expand=>:ns)
+ t.style_layout(s, 'e4', :padx=>[0,6], :expand=>:ns)
+ t.style_layout(s, 'e5', :union=>['e3'], :iexpand=>:ns, :ipadx=>2)
+
+ s = t.style_create('s2')
+ t.style_elements(s, ['e5', 'e2', 'e3'])
+ t.style_layout(s, 'e2', :padx=>[0,4], :expand=>:ns)
+ t.style_layout(s, 'e3', :padx=>[0,4], :expand=>:ns)
+ t.style_layout(s, 'e5', :union=>['e3'], :iexpand=>:ns, :ipadx=>2)
+
+ s = t.style_create('s3')
+ t.style_elements(s, ['e6'])
+ t.style_layout(s, 'e6', :padx=>6, :expand=>:ns)
+
+ @Priv[:sensitive, t] = [
+ [:item, 's1', 'e5', 'e1', 'e3'],
+ [:item, 's2', 'e5', 'e2', 'e3']
+ ]
+ @Priv[:dragimage, t] = [
+ [:item, 's1', 'e1', 'e3'],
+ [:item, 's2', 'e2', 'e3']
+ ]
+
+ clicks = Tk::Clock.clicks
+ items = [ t.index(:root) ]
+ (1...(random_N())).each{|i|
+ item_i = t.item_create
+ item_j = nil
+ loop {
+ j = rand(i)
+ item_j = items[j]
+ break if t.depth(item_j) < 5
+ }
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.item_collapse(item_i) if rand(2) == 0
+ else # TreeCtrl 1.0
+ t.collapse(item_i) if rand(2) == 0
+ end
+ if rand(2) == 0
+ t.item_lastchild(item_j, item_i)
+ else
+ t.item_firstchild(item_j, item_i)
+ end
+ items << item_i
+ }
+ puts "created #{random_N() - 1} items in #{Tk::Clock.clicks - clicks} clicks"
+
+ clicks = Tk::Clock.clicks
+ (0...(random_N())).each{|i|
+ item_i = items[i]
+ item_j = nil
+ numChildren = t.item_numchildren(item_i)
+ if numChildren > 0
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.item_configure(item_i, :button=>true)
+ else # TreeCtrl 1.0
+ t.item_hasbutton(item_i, true)
+ end
+ t.item_style_set(item_i, 0, 's1', 1, 's3', 2, 's3')
+ t.item_complex(item_i,
+ [ ['e3', {:text=>"Item #{i}"}],
+ ['e4', {:text=>"(#{numChildren})"}] ],
+ [ ['e6', {:text=>"#{t.item_parent(item_i)}"}] ],
+ [ ['e6', {:text=>"#{t.depth(item_i)}"}] ])
+ else
+ t.item_style_set(item_i, 1, 's3', 2, 's3', 0, 's2')
+ t.item_complex(item_i,
+ [ ['e3', {:text=>"Item #{i}"}] ],
+ [ ['e6', {:text=>"#{t.item_parent(item_i)}"}] ],
+ [ ['e6', {:text=>"#{t.depth(item_i)}"}] ])
+ end
+ }
+ puts "configured #{random_N()} items in #{Tk::Clock.clicks - clicks} clicks"
+
+ treeCtrlRandom = TkBindTag.new
+
+ treeCtrlRandom.bind('Double-ButtonPress-1',
+ proc{|w, x, y|
+ Tk::TreeCtrl::BindCallback.doubleButton1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+
+ treeCtrlRandom.bind('Control-ButtonPress-1',
+ proc{|w, x, y|
+ @Priv['selectMode'] = :toggle
+ randomButton1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+
+ treeCtrlRandom.bind('Shift-ButtonPress-1',
+ proc{|w, x, y|
+ @Priv['selectMode'] = :add
+ randomButton1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+
+ treeCtrlRandom.bind('ButtonPress-1',
+ proc{|w, x, y|
+ @Priv['selectMode'] = :set
+ randomButton1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+
+ treeCtrlRandom.bind('Button1-Motion',
+ proc{|w, x, y|
+ randomMotion1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+
+ treeCtrlRandom.bind('Button1-Leave',
+ proc{|w, x, y|
+ randomLeave1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+
+ treeCtrlRandom.bind('ButtonRelease-1',
+ proc{|w, x, y|
+ randomRelease1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+
+ t.bindtags = [ t, treeCtrlRandom, Tk::TreeCtrl, t.winfo_toplevel, :all ]
+end
+
+def randomButton1(t, x, y)
+ t.set_focus
+ id = t.identify(x, y)
+ puts id.inspect
+ @Priv['buttonMode'] = ''
+ if id.empty?
+ # Click outside any item
+
+ elsif id[0] == 'header'
+ # Click in header
+ Tk::TreeCtrl::BindCallback.buttonPress1(w, x, y)
+
+ else
+ # Click in item
+ where, item, arg1, arg2, arg3, arg4 = id
+ case arg1
+ when 'button'
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.item_toggle(item)
+ else # TreeCtrl 1.0
+ t.toggle(item)
+ end
+
+ when 'line'
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.item_toggle(arg2)
+ else # TreeCtrl 1.0
+ t.toggle(arg2)
+ end
+
+ when 'column'
+ ok = false
+ # Clicked an element
+ if id.length == 6
+ column = id[3]
+ e = id[5]
+ @Priv.list_element(:sensitive, t).each{|lst|
+ c, s, *eList = TkComm.simplelist(lst)
+ next if column != t.column_index(c)
+ next if t.item_style_set(item, c) != s
+ next if eList.find{|le| le == e} == nil
+ ok = true
+ break
+ }
+ end
+ unless ok
+ t.selection_clear
+ return
+ end
+
+ @Priv[:drag, :motion] = 0
+ @Priv[:drag, :x] = t.canvasx(x)
+ @Priv[:drag, :y] = t.canvasy(y)
+ @Priv[:drop] = ''
+
+ if @Priv['selectMode'] == 'add'
+ Tk::TreeCtrl::BindCallback.beginExtend(t, item)
+ elsif @Priv['selectMode'] == 'toggle'
+ Tk::TreeCtrl::BindCallback.beginToggle(t, item)
+ elsif ! t.selection_includes(item)
+ Tk::TreeCtrl::BindCallback.beginSelect(t, item)
+ end
+ t.activate(item)
+
+ if t.selection_includes(item)
+ @Priv['buttonMode'] = 'drag'
+ end
+ end
+ end
+end
+
+def randomMotion1(t, x, y)
+ case @Priv['buttonMode']
+ when 'resize', 'header'
+ Tk::TreeCtrl::BindCallback.motion1(t, x, y)
+ when 'drag'
+ randomAutoScanCheck(t, x, y)
+ randomMotion(t, x, y)
+ end
+end
+
+def randomMotion(t, x, y)
+ case @Priv['buttonMode']
+ when 'resize', 'header'
+ Tk::TreeCtrl::BindCallback.motion1(t, x, y)
+
+ when 'drag'
+ # Detect initial mouse movement
+ unless @Priv.bool_element(:drag, :motion)
+ @Priv[:selection] = t.selection_get
+ @Priv[:drop] = ''
+ t.dragimage_clear
+ # For each selected item, add 2nd and 3rd elements of
+ # column "item" to the dragimage
+ @Priv.list_element(:selection).each{|i|
+ @Priv.list_element(:dragimage,t).each{|lst|
+ c, s, *eList = TkComm.simplelist(lst)
+ if t.item_style_set(i, c) == s
+ t.dragimage_add(i, c, *eList)
+ end
+ }
+ }
+ @Priv[:drag,:motion] = true
+ end
+
+ # Find the item under the cursor
+ cursor = 'X_cursor'
+ drop = ''
+ id = t.identify(x, y)
+ ok = false
+ if !id.empty? && id[0] == 'item' && id.length == 6
+ item = id[1]
+ column = id[3]
+ e = id[5]
+ @Priv.list_element(:sensitive,t).each{|lst|
+ c, s, *eList = TkComm.simplelist(lst)
+ next if column != t.column_index(c)
+ next if t.item_style_set(item, c) != s
+ next unless eList.find{|val| val == e}
+ ok = true
+ break
+ }
+ ok = true if @Priv.list_element(:sensitive,t).find{|val| TkComm.simplelist(val).index(e)}
+ end
+
+ if ok
+ # If the item is not in the pre-drag selection
+ # (i.e. not being dragged) see if we can drop on it
+ unless @Priv.list_element(:selection).find{|val| val == item}
+ drop = item
+ # We can drop if dragged item isn't an ancestor
+ @Priv.list_element(:selection).each{|item2|
+ if t.item_isancestor(item2, item)
+ drop = ''
+ break
+ end
+ }
+ if drop != ''
+ x1, y1, x2, y2 = t.item_bbox(drop)
+ if y < y1 + 3
+ cursor = 'top_side'
+ @Priv[:drop,:pos] = 'prevsibling'
+ elsif y >= y2 - 3
+ cursor = 'bottom_side'
+ @Priv[:drop,:pos] = 'nextsibling'
+ else
+ cursor = ''
+ @Priv[:drop,:pos] = 'lastchild'
+ end
+ end
+ end
+ end
+
+ t[:cursor] = cursor if t[:cursor] != cursor
+
+ # Select the item under the cursor (if any) and deselect
+ # the previous drop-item (if any)
+ t.selection_modify(drop, @Priv[:drop])
+ @Priv[:drop] = drop
+
+ # Show the dragimage in its new position
+ x = t.canvasx(x) - @Priv.numeric_element(:drag,:x)
+ y = t.canvasx(y) - @Priv.numeric_element(:drag,:y)
+ t.dragimage_offset(x, y)
+ t.dragimage_configure(:visible=>true)
+ end
+end
+
+def randomLeave1(t, x, y)
+ # This is called when I do ButtonPress-1 on Unix for some reason,
+ # and buttonMode is undefined.
+ return unless @Priv.exist?('buttonMode')
+ case @Priv['buttonMode']
+ when 'header'
+ Tk::TreeCtrl::BindCallback.leave1(t, x, y)
+ end
+end
+
+def randomRelease1(t, x, y)
+ case @Priv['buttonMode']
+ when 'resize', 'header'
+ Tk::TreeCtrl::BindCallback.release1(t, x, y)
+ when 'drag'
+ Tk::TreeCtrl::BindCallback.autoScanCancel(t)
+ t.dragimage_configure(:visible=>false)
+ t.selection_modify('', @Priv[:drop])
+ t[:cursor] = ''
+ if @Priv[:drop] != ''
+ randomDrop(t, @Priv[:drop], @Priv.list_element(:selection),
+ @Priv[:drop, :pos])
+ end
+ end
+ @Priv['buttonMode'] = ''
+end
+
+def randomDrop(t, target, src, pos)
+ parentList = []
+ case pos
+ when 'lastchild'
+ parent = target
+ when 'prevsibling'
+ parent = t.item_parent(target)
+ when 'nextsibling'
+ parent = t.item_parent(target)
+ end
+ src.each{|item|
+ # Ignore any item whose ancestor is also selected
+ ignore = false
+ t.item_ancestors(item).each{|ancestor|
+ if src.find{|val| val == ancestor}
+ ignore = true
+ break
+ end
+ }
+ next if ignore
+
+ # Update the old parent of this moved item later
+ unless parentList.find{|val| val == item}
+ parentList << t.item_parent(item)
+ end
+
+ # Add to target
+ t.__send__("item_#{pos}", target, item)
+
+ # Update text: parent
+ t.item_element_configure(item, 'parent', 'e6', :text=>parent)
+
+ # Update text: depth
+ t.item_element_configure(item, 'depth', 'e6', :text=>t.depth(item))
+
+ # Recursively update text: depth
+ itemList = [ t.item_firstchild(item) ]
+ while itemList.length > 0
+ item = itemList.pop
+
+ t.item_element_configure(item, 'depth', 'e6', :text=>t.depth(item))
+
+ item2 = t.item_nextsibling(item)
+ itemList << item2 if item2 != ''
+
+ item2 = t.item_firstchild(item)
+ itemList << item2 if item2 != ''
+ end
+ }
+
+ # Update items that lost some children
+ parentList.each{|item|
+ numChildren = t.item_numchildren(item)
+ if numChildren == 0
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.item_configure(item, :button=>false)
+ else # TreeCtrl 1.0
+ t.item_hasbutton(item, false)
+ end
+ t.item_style_map(item, 'item', 's2', ['e3', 'e3'])
+ else
+ t.item_element_configure(item, 'item', 'e4', :text=>"(#{numChildren})")
+ end
+ }
+
+ # Update the target that gained some children
+ if t.item_style_set(parent, 0) != 's1'
+ if (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
+ t.item_configure(parent, :button=>true)
+ else # TreeCtrl 1.0
+ t.item_hasbutton(parent, true)
+ end
+ t.item_style_map(parent, 'item', 's1', ['e3', 'e3'])
+ end
+ numChildren = t.item_numchildren(parent)
+ t.item_element_configure(parent, 'item', 'e4', :text=>"(#{numChildren})")
+end
+
+# Same as TreeCtrl::AutoScanCheck, but calls RandomMotion and
+# RandomAutoScanCheckAux
+def randomAutoScanCheck(t, x, y)
+ x1, y1, x2, y2 = t.contentbox
+ margin = t.winfo_pixels(t.scrollmargin)
+ if x < x1 + margin || x >= x2 - margin || y < y1 + margin || y >= y2 - margin
+ if ! @Priv.exist?(:auroscan, :afterID, t)
+ if y >= y2 - margin
+ t.yview(:scroll, 1, :units)
+ delay = t.yscrolldelay
+ elsif y < y1 + margin
+ t.yview(:scroll, -1, :units)
+ delay = t.yscrolldelay
+ elsif x >= x2 - margin
+ t.xview(:scroll, 1, :units)
+ delay = t.xscrolldelay
+ elsif x < x1 + margin
+ t.xview(:scroll, -1, :units)
+ delay = t.xscrolldelay
+ end
+ if @Priv.exist?(:autoscan, :scanning, t)
+ delay = delay[2] if delay.kind_of?(Array)
+ else
+ delay = delay[1] if delay.kind_of?(Array)
+ end
+ case @Priv['buttonMode']
+ when 'drag', 'marquee'
+ randomMotion(t, x, y)
+ end
+ @Priv[:autoscan, :scanning, t] =
+ Tk.after(delay, proc{ randomAutoScanCheckAux(t) })
+ end
+ return
+ end
+ Tk::TreeCtrl::BindCallback.autoScanCancel(t)
+end
+
+def randomAutoScanCheckAux(t)
+ @Priv.unset(:autoscan, :afterID, t)
+ x = t.winfo_pointerx - t.winfo_rootx
+ y = t.winfo_pointery - t.winfo_rooty
+ randomAutoScanCheck(t, x, y)
+end
+
+#
+# Demo: random N items, button images
+#
+def demoRandom2(t)
+ demoRandom(t)
+
+ init_pics('mac-*')
+
+ t.configure(:openbuttonimage=>@images['mac-collapse'],
+ :closedbuttonimage=>@images['mac-expand'],
+ :showlines=>false)
+end
diff --git a/ext/tk/sample/tkextlib/treectrl/readme.txt b/ext/tk/sample/tkextlib/treectrl/readme.txt
new file mode 100644
index 0000000000..9f26ac069c
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/readme.txt
@@ -0,0 +1,2 @@
+The scripts and image files in this directory are based on demo files
+of Tcl/Tk's TreeCtrl extention.
diff --git a/ext/tk/sample/tkextlib/treectrl/www-options.rb b/ext/tk/sample/tkextlib/treectrl/www-options.rb
new file mode 100644
index 0000000000..2b0f75e85e
--- /dev/null
+++ b/ext/tk/sample/tkextlib/treectrl/www-options.rb
@@ -0,0 +1,303 @@
+def demoInternetOptions (t)
+ @Option = TkVarAccess.new_hash('::Option')
+
+ height = t.font.metrics(:linespace) + 2
+ height = 18 if height < 18
+ t.configure(:showroot=>false, :showbuttons=>false, :showlines=>false,
+ :itemheight=>height, :selectmode=>:browse)
+
+ init_pics('internet-*')
+
+ if $HasColumnCreate
+ t.column_create(:text=>'Internet Options')
+ else
+ t.column_configure(0, :text=>'Internet Options')
+ end
+
+ t.state_define('check')
+ t.state_define('radio')
+ t.state_define('on')
+
+ t.element_create('e1', :image, :image=>[
+ @images['internet-check-on'], ['check', 'on'],
+ @images['internet-check-off'], ['check'],
+ @images['internet-radio-on'], ['radio', 'on'],
+ @images['internet-radio-off'], ['radio']
+ ])
+ t.element_create('e2', :text,
+ :fill=>[@SystemHighlightText, ['selected', 'focus']])
+ t.element_create('e3', :rect, :showfocus=>true,
+ :fill=>[@SystemHighlight, ['selected', 'focus']])
+
+ s = t.style_create('s1')
+ t.style_elements(s, ['e3', 'e1', 'e2'])
+ t.style_layout(s, 'e1', :padx=>[0,4], :expand=>:ns)
+ t.style_layout(s, 'e2', :expand=>:ns)
+ t.style_layout(s, 'e3', :union=>['e2'], :iexpand=>:ns, :ipadx=>2)
+
+ parentList = [:root, '', '', '', '', '', '']
+ parent = :root
+ [
+ [0, :print, "Printing", "", ""],
+ [1, :off, "Print background colors and images", "o1", ""],
+ [0, :search, "Search from Address bar", "", ""],
+ [1, :search, "When searching", "", ""],
+ [2, :off, "Display results, and go to the most likely sites",
+ "o2", "r1"],
+ [2, :off, "Do not search from the Address bar", "o3", "r1"],
+ [2, :off, "Just display the results in the main window",
+ "o4", "r1"],
+ [2, :on, "Just go to the most likely site", "o5", "r1"],
+ [0, :security, "Security", "", ""],
+ [1, :on, "Check for publisher's certificate revocation", "o5", ""],
+ [1, :off, "Check for server certificate revocation (requires restart)",
+ "o6", ""]
+ ].each{|depth, setting, text, option, group|
+ item = t.item_create()
+ t.item_style_set(item, 0, 's1')
+ t.item_element_configure(item, 0, 'e2', :text=>text)
+ @Option[:option, item] = option
+ @Option[:group, item] = group
+ if setting == :on || setting == :off
+ @Option[:setting, item] = setting
+ if group == ''
+ t.item_state_set(item, 'check')
+ if setting == :on
+ t.item_state_set(item, 'on')
+ end
+ else
+ if setting == :on
+ @Option[:current, group] = item
+ t.item_state_set(item, 'on')
+ end
+ t.item_state_set(item, 'radio')
+ end
+ else
+ t.item_element_configure(item, 0, 'e1',
+ :image=>@images["internet-#{setting}"])
+ end
+ t.item_lastchild(parentList[depth], item)
+ depth += 1
+ parentList[depth] = item
+ }
+
+ treeCtrlOption = TkBindTag.new
+ treeCtrlOption.bind('Double-ButtonPress-1', proc{|w, x, y|
+ Tk::TreeCtrl::BindCallback.doubleButton1(w, x, y)
+ }, '%W %x %y')
+ treeCtrlOption.bind('ButtonPress-1', proc{|w, x, y|
+ optionButton1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+ treeCtrlOption.bind('Button1-Motion', proc{|w, x, y|
+ optionMotion1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+ treeCtrlOption.bind('Button1-Leave', proc{|w, x, y|
+ optionLeave1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+ treeCtrlOption.bind('ButtonRelease-1', proc{|w, x, y|
+ optionRelease1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+
+ t.bindtags = [
+ t, treeCtrlOption, Tk::TreeCtrl, t.winfo_toplevel, TkBindTag::ALL
+ ]
+end
+
+def optionButton1(w, x, y)
+ w.set_focus
+ id = w.identify(x, y)
+ if id[0] == 'header'
+ Tk::TreeCtrl::BindCallback.buttonPress1(w, x, y)
+ elsif id.empty?
+ @Priv['buttonMode'] = ''
+ else
+ @Priv['buttonMode'] = ''
+ item = id[1]
+ w.selection_modify(item, :all)
+ w.activate(item)
+ return if @Option[:option, item] == ''
+ group = @Option[:group, item]
+ if group == ''
+ # a checkbutton
+ w.item_state_set(item, '~on')
+ if @Option[:setting, item] == 'on'
+ setting = :off
+ else
+ setting = :on
+ end
+ @Option[:setting, item] = setting
+ else
+ # a radiobutton
+ current = @Option[:current, group]
+ return if current == item.to_s
+ w.item_state_set(current, '!on')
+ w.item_state_set(item, 'on')
+ @Option[:setting, item] = :on
+ @Option[:current, group] = item
+ end
+ end
+end
+
+# Alternate implementation that doesn't rely on run-time styles
+def demoInternetOptions_2(t)
+ height = t.font.metrics(:linespace) + 2
+ height = 18 if height < 18
+ t.configure(:showroot=>false, :showbuttons=>false, :showlines=>false,
+ :itemheight=>height, :selectmode=>:browse)
+
+ init_pics('internet-*')
+
+ t.column_configure(0, :text=>'Internet Options')
+
+ t.element_create('e1', :image)
+ t.element_create('e2', :text,
+ :fill=>[@SystemHighlightText, ['selected', 'focus']])
+ t.element_create('e3', :rect, :showfocus=>true,
+ :fill=>[@SystemHighlight, ['selected', 'focus']])
+
+ s = t.style_create('s1')
+ t.style_elements('s1', ['e3', 'e1', 'e2'])
+ t.style_layout(s, 'e1', :padx=>[0,4], :expand=>:ns)
+ t.style_layout(s, 'e2', :expand=>:ns)
+ t.style_layout(s, 'e3', :union=>['e2'], :iexpand=>:ns, :ipadx=>2)
+
+ parentList = [:root, '', '', '', '', '', '']
+ parent = :root
+ [
+ [0, :print, "Printing", "", ""],
+ [1, :off, "Print background colors and images", "o1", ""],
+ [0, :search, "Search from Address bar", "", ""],
+ [1, :search, "When searching", "", ""],
+ [2, :off, "Display results, and go to the most likely sites",
+ "o2", "r1"],
+ [2, :off, "Do not search from the Address bar", "o3", "r1"],
+ [2, :off, "Just display the results in the main window",
+ "o4", "r1"],
+ [2, :on, "Just go to the most likely site", "o5", "r1"],
+ [0, :security, "Security", "", ""],
+ [1, :on, "Check for publisher's certificate revocation", "o5", ""],
+ [1, :off, "Check for server certificate revocation (requires restart)",
+ "o6", ""]
+ ].each{|depth, setting, text, option, group|
+ item = t.item_create()
+ t.item_style_set(item, 0, 's1')
+ t.item_element_configure(item, 0, 'e2', :text=>text)
+ @Option[:option, item] = option
+ @Option[:group, item] = group
+ if setting == :on || setting == :off
+ @Option[:setting, item] = setting
+ if group == ''
+ img = @images["internet-check-#{setting}"]
+ t.item_element_configure(item, 0, 'e1', :image=>img)
+ else
+ if setting == :on
+ @Option[:current, group] = item
+ end
+ img = @images["internet-radio-#{setting}"]
+ t.item_element_configure(item, 0, 'e1', :image=>img)
+ end
+ else
+ t.item_element_configure(item, 0, 'e1',
+ :image=>@images["internet-#{setting}"])
+ end
+ t.item_lastchild(parentList[depth], item)
+ depth += 1
+ parentList[depth] = item
+ }
+
+ treeCtrlOption = TkBindTag.new
+ treeCtrlOption.bind('Double-ButtonPress-1', proc{|w, x, y|
+ Tk::TreeCtrl::BindCallback.doubleButton1(w, x, y)
+ }, '%W %x %y')
+ treeCtrlOption.bind('ButtonPress-1', proc{|w, x, y|
+ optionButton1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+ treeCtrlOption.bind('Button1-Motion', proc{|w, x, y|
+ optionMotion1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+ treeCtrlOption.bind('Button1-Leave', proc{|w, x, y|
+ optionLeave1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+ treeCtrlOption.bind('ButtonRelease-1', proc{|w, x, y|
+ optionRelease1(w, x, y)
+ Tk.callback_break
+ }, '%W %x %y')
+
+ t.bindtags = [
+ t, treeCtrlOption, Tk::TreeCtrl, t.winfo_toplevel, TkBindTag::ALL
+ ]
+end
+
+def optionButton1_2(w, x, y)
+ w.set_focus
+ id = w.identify(x, y)
+ if id[0] == 'header'
+ Tk::TreeCtrl::BindCallback.buttonPress1(w, x, y)
+ elsif id.empty?
+ @Priv['buttonMode'] = ''
+ else
+ @Priv['buttonMode'] = ''
+ item = id[1]
+ w.selection_modify(item, :all)
+ w.activate(item)
+ return if @Option[:option, item] == ''
+ group = @Option[:group, item]
+ if group == ''
+ # a checkbutton
+ if @Option[:setting, item] == 'on'
+ setting = :off
+ else
+ setting = :on
+ end
+ w.item_element_configure(item, 0, 'e1',
+ :image=>@images["internet-check-#{setting}"])
+ @Option[:setting, item] = setting
+ else
+ # a radiobutton
+ current = @Option[:current, group]
+ return if current == item.to_s
+ w.item_element_configure(current, 0, 'e1',
+ :image=>@images["internet-radio-off"])
+ w.item_element_configure(item, 0, 'e1',
+ :image=>@images["internet-radio-on"])
+ @Option[:setting, item] = :on
+ @Option[:current, group] = item
+ end
+ end
+end
+
+def optionMotion1(w, x, y)
+ case @Priv['buttonMode']
+ when 'resize', 'header'
+ Tk::TreeCtrl::BindCallback.Motion1(w, x, y)
+ end
+end
+
+def optionLeave1(w, x, y)
+ # This is called when I do ButtonPress-1 on Unix for some reason,
+ # and buttonMode is undefined.
+ begin
+ mode = @Priv['buttonMode']
+ rescue
+ else
+ case mode
+ when 'header'
+ t.column_configure(@Priv['column'], :sunken=>false)
+ end
+ end
+end
+
+def optionRelease1(w, x, y)
+ case @Priv['buttonMode']
+ when 'resize', 'header'
+ Tk::TreeCtrl::BindCallback.Release1(w, x, y)
+ end
+ @Priv['buttonMode'] = ''
+end