summaryrefslogtreecommitdiffstats
path: root/ext/tk/sample/tkextlib/treectrl/random.rb
diff options
context:
space:
mode:
Diffstat (limited to 'ext/tk/sample/tkextlib/treectrl/random.rb')
-rw-r--r--ext/tk/sample/tkextlib/treectrl/random.rb505
1 files changed, 505 insertions, 0 deletions
diff --git a/ext/tk/sample/tkextlib/treectrl/random.rb b/ext/tk/sample/tkextlib/treectrl/random.rb
new file mode 100644
index 000000000..05b6c2123
--- /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