1# tree.rb --
2#
3# This demonstration script creates a toplevel window containing a Ttk
4# tree widget.
5#
6# based on "Id: tree.tcl,v 1.4 2007/12/13 15:27:07 dgp Exp"
7
8if defined?($tree_demo) && $tree_demo
9  $tree_demo.destroy
10  $tree_demo = nil
11end
12
13$tree_demo = TkToplevel.new {|w|
14  title("Directory Browser")
15  iconname("tree")
16  positionWindow(w)
17}
18
19base_frame = TkFrame.new($tree_demo).pack(:fill=>:both, :expand=>true)
20
21## Explanatory text
22Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i',
23               :justify=>:left, :anchor=>'n', :padding=>[10, 2, 10, 6],
24               :text=><<EOL).pack(:fill=>:x)
25Ttk is the new Tk themed widget set. \
26One of the widgets it includes is a tree widget, \
27which allows the user to browse a hierarchical data-set such as a filesystem. \
28The tree widget not only allows for the tree part itself, \
29but it also supports an arbitrary number of additional columns \
30which can show additional data (in this case, the size of the files \
31found in your filesystem). \
32You can also change the width of the columns \
33by dragging the boundary between them.
34EOL
35
36## See Code / Dismiss
37Ttk::Frame.new(base_frame) {|frame|
38  sep = Ttk::Separator.new(frame)
39  Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
40  TkGrid('x',
41         Ttk::Button.new(frame, :text=>'See Code',
42                         :image=>$image['view'], :compound=>:left,
43                         :command=>proc{showCode 'tree'}),
44         Ttk::Button.new(frame, :text=>'Dismiss',
45                         :image=>$image['delete'], :compound=>:left,
46                         :command=>proc{
47                           $tree_demo.destroy
48                           $tree_demo = nil
49                         }),
50         :padx=>4, :pady=>4)
51  grid_columnconfigure(0, :weight=>1)
52  pack(:side=>:bottom, :fill=>:x)
53}
54
55## Code to populate the roots of the tree (can be more than one on Windows)
56def populate_roots(tree)
57  TkComm.simplelist(Tk.tk_call('file', 'volumes')).sort.each{|dir|
58    populate_tree(tree, tree.insert(nil, :end, :text=>dir,
59                                    :values=>[dir, 'directory']))
60  }
61end
62
63## Code to populate a node of the tree
64def populate_tree(tree, node)
65  return if tree.get(node, :type) != 'directory'
66
67  path = tree.get(node, :fullpath)
68  tree.delete(tree.children(node))
69  Dir.glob("#{path}/*").sort.each{|f|
70    type = File.ftype(f) rescue nil
71    id = tree.insert(node, :end,
72                     :text=>File.basename(f), :values=>[f, type]).id
73    if type == 'directory'
74      ## Make it so that this node is openable
75      tree.insert(id, 0, :text=>'dummy')
76      tree.itemconfigure(id, :text=>File.basename(f))
77    elsif type == 'file'
78      size = File.size(f)
79      if size >= 1024*1024*1024
80        size = '%.1f GB' % (size.to_f/1024/1024/1024)
81      elsif size >= 1024*1024
82        size = '%.1f MB' % (size.to_f/1024/1024)
83      elsif size >= 1024
84        size = '%.1f KB' % (size.to_f/1024)
85      else
86        size = '%.1f bytes' % (size.to_f/1024)
87      end
88      tree.set(id, :size, size)
89    end
90  }
91
92  # Stop this code from rerunning on the current node
93  tree.set(node, :type, 'processed_directory')
94end
95
96## Create the tree and set it up
97tree = Ttk::Treeview.new(base_frame, :columns=>%w(fullpath type size),
98                         :displaycolumns=>['size'])
99if Tk.windowingsystem != 'aqua'
100  vsb = tree.yscrollbar(Ttk::Scrollbar.new(base_frame))
101  hsb = tree.xscrollbar(Ttk::Scrollbar.new(base_frame))
102else
103  vsb = tree.yscrollbar(Tk::Scrollbar.new(base_frame))
104  hsb = tree.xscrollbar(Tk::Scrollbar.new(base_frame))
105end
106
107tree.heading_configure('#0', :text=>'Directory Structure')
108tree.heading_configure('size', :text=>'File Size')
109tree.column_configure('size', :stretch=>0, :width=>70)
110populate_roots(tree)
111tree.bind('<TreeviewOpen>', '%W'){|w| populate_tree(w, w.focus_item)}
112
113## Arrange the tree and its scrollbars in the toplevel
114container = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true)
115container.lower
116Tk.grid(tree, vsb, :in=>container, :sticky=>'nsew')
117Tk.grid(hsb,       :in=>container, :sticky=>'nsew')
118container.grid_columnconfigure(0, :weight=>1)
119container.grid_rowconfigure(0, :weight=>1)
120