#!/usr/bin/env ruby require 'tk' require 'tkextlib/treectrl' $ScriptDir = File.dirname(File.expand_path(__FILE__)) $HasColumnCreate = Tk::TreeCtrl::HasColumnCreateCommand $Version_1_1_OrLater = (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0) if Hash.instance_methods.include?('key') # probably ruby 1.9.x --> use Hash#key # Because Hash#index show warning "Hash#index is deprecated; use Hash#key". else # probably ruby 1.8.x --> use Hash#index class Hash alias key index end end 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() if $Version_1_1_OrLater begin @tree2[:backgroundimage] @has_bgimg = true rescue @has_bgimg = false end else @has_bgimg = false end #################### 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| unless TkImage.names.find{|img| (name = @images.key(img)) && File.fnmatch(pat, name)} Dir.glob(File.join(@ScriptDir, 'pics', "#{pat}.gif")).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.create 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: # called when the active item changes # called before an item is closed # called after an item is closed # called before an item is opened # called after an item is opened # called when items are added to or removed from the selection # called when horizontal scroll position changes # 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 $Version_1_1_OrLater if @has_bgimg 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[:squeeze].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 $Version_1_1_OrLater 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 $Version_1_1_OrLater 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 $Version_1_1_OrLater 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 $Version_1_1_OrLater 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 $Version_1_1_OrLater if @has_bgimg @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 has_bgimg = @has_bgimg scriptDir = @ScriptDir thisPlatform = @thisPlatform randomN = @RandomN images = @images sel_images = @sel_images systemButtonFace = @SystemButtonFace systemHighlight = @SystemHighlight systemHighlightText = @SystemHighlightText def master._pub_display_styles_in_item(item) display_styles_in_item(item) end proc_disp_styles_in_item = proc{|item| master._pub_display_styles_in_item(item) } @demo_scripts.instance_eval{ @master = master @has_bgimg = has_bgimg @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) puts "load \"#{file}\"" if $DEBUG begin eval(IO.readlines(file).join, _get_binding()) rescue Exception => e bt = e.backtrace if bt[0] =~ /^([^:]+):(\d+):/ errline = $2.to_i else raise e end if bt[1] =~ /^([^:]+):(\d+):/ bt.unshift("#{file}:#{errline - $2.to_i + 1}") raise e else raise e end end 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 $Version_1_1_OrLater @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 $Version_1_1_OrLater @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 $Version_1_1_OrLater 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 $Version_1_1_OrLater 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 $Version_1_1_OrLater 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 $Version_1_1_OrLater @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 $Version_1_1_OrLater @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 $Version_1_1_OrLater item3 = @tree3.item_create(:button=>true) else item3 = @tree3.item_create @tree3.item_hasbutton(item3, true) end if $Version_1_1_OrLater @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 $Version_1_1_OrLater @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 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 $Version_1_1_OrLater @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 $Version_1_1_OrLater if @has_bgimg @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