1# 2def random_N 3 @RandomN[0] || 500 4end 5 6# 7# Demo: random N items 8# 9def demoRandom(t) 10 init_pics('folder-*', 'small-*') 11 12 height = t.font.metrics(:linespace) 13 height = 18 if height < 18 14 t.configure(:itemheight=>height, :selectmode=>:extended, 15 :showroot=>true, :showrootbutton=>true, :showbuttons=>true, 16 :showlines=>true, :scrollmargin=>16, 17 :xscrolldelay=>[500, 50], :yscrolldelay=>[500, 50]) 18 19 if $Version_1_1_OrLater 20 t.column_create(:expand=>true, :text=>'Item', 21 :itembackground=>['#e0e8f0', []], :tag=>'item') 22 t.column_create(:text=>'Parent', :justify=>:center, 23 :itembackground=>['gray90', []], :tag=>'parent') 24 t.column_create(:text=>'Depth', :justify=>:center, 25 :itembackground=>['linen', []], :tag=>'depth') 26 else # TreeCtrl 1.0 27 t.column_configure(0, :expand=>true, :text=>'Item', 28 :itembackground=>['#e0e8f0', []], :tag=>'item') 29 t.column_configure(1, :text=>'Parent', :justify=>:center, 30 :itembackground=>['gray90', []], :tag=>'parent') 31 t.column_configure(2, :text=>'Depth', :justify=>:center, 32 :itembackground=>['linen', []], :tag=>'depth') 33 end 34 35 t.element_create('e1', :image, :image=>[ 36 @images['folder-open'], ['open'], 37 @images['folder-closed'], [] 38 ]) 39 t.element_create('e2', :image, :image=>@images['small-file']) 40 t.element_create('e3', :text, 41 :fill=>[@SystemHighlightText, ['selected', 'focus']]) 42 t.element_create('e4', :text, :fill=>'blue') 43 t.element_create('e6', :text) 44 t.element_create('e5', :rect, :showfocus=>true, 45 :fill=>[ 46 @SystemHighlight, ['selected', 'focus'], 47 'gray', ['selected', '!focus'] 48 ]) 49 50 s = t.style_create('s1') 51 t.style_elements(s, ['e5', 'e1', 'e3', 'e4']) 52 t.style_layout(s, 'e1', :padx=>[0,4], :expand=>:ns) 53 t.style_layout(s, 'e3', :padx=>[0,4], :expand=>:ns) 54 t.style_layout(s, 'e4', :padx=>[0,6], :expand=>:ns) 55 t.style_layout(s, 'e5', :union=>['e3'], :iexpand=>:ns, :ipadx=>2) 56 57 s = t.style_create('s2') 58 t.style_elements(s, ['e5', 'e2', 'e3']) 59 t.style_layout(s, 'e2', :padx=>[0,4], :expand=>:ns) 60 t.style_layout(s, 'e3', :padx=>[0,4], :expand=>:ns) 61 t.style_layout(s, 'e5', :union=>['e3'], :iexpand=>:ns, :ipadx=>2) 62 63 s = t.style_create('s3') 64 t.style_elements(s, ['e6']) 65 t.style_layout(s, 'e6', :padx=>6, :expand=>:ns) 66 67 @Priv[:sensitive, t] = [ 68 [:item, 's1', 'e5', 'e1', 'e3'], 69 [:item, 's2', 'e5', 'e2', 'e3'] 70 ] 71 @Priv[:dragimage, t] = [ 72 [:item, 's1', 'e1', 'e3'], 73 [:item, 's2', 'e2', 'e3'] 74 ] 75 76 clicks = Tk::Clock.clicks 77 items = [ t.index(:root) ] 78 (1...(random_N())).each{|i| 79 item_i = t.item_create 80 item_j = nil 81 loop { 82 j = rand(i) 83 item_j = items[j] 84 break if t.depth(item_j) < 5 85 } 86 if $Version_1_1_OrLater 87 t.item_collapse(item_i) if rand(2) == 0 88 else # TreeCtrl 1.0 89 t.collapse(item_i) if rand(2) == 0 90 end 91 if rand(2) == 0 92 t.item_lastchild(item_j, item_i) 93 else 94 t.item_firstchild(item_j, item_i) 95 end 96 items << item_i 97 } 98 puts "created #{random_N() - 1} items in #{Tk::Clock.clicks - clicks} clicks" 99 100 clicks = Tk::Clock.clicks 101 (0...(random_N())).each{|i| 102 item_i = items[i] 103 numChildren = t.item_numchildren(item_i) 104 if numChildren > 0 105 if $Version_1_1_OrLater 106 t.item_configure(item_i, :button=>true) 107 else # TreeCtrl 1.0 108 t.item_hasbutton(item_i, true) 109 end 110 t.item_style_set(item_i, 0, 's1', 1, 's3', 2, 's3') 111 t.item_complex(item_i, 112 [ ['e3', {:text=>"Item #{i}"}], 113 ['e4', {:text=>"(#{numChildren})"}] ], 114 [ ['e6', {:text=>"#{t.item_parent(item_i)}"}] ], 115 [ ['e6', {:text=>"#{t.depth(item_i)}"}] ]) 116 else 117 t.item_style_set(item_i, 1, 's3', 2, 's3', 0, 's2') 118 t.item_complex(item_i, 119 [ ['e3', {:text=>"Item #{i}"}] ], 120 [ ['e6', {:text=>"#{t.item_parent(item_i)}"}] ], 121 [ ['e6', {:text=>"#{t.depth(item_i)}"}] ]) 122 end 123 } 124 puts "configured #{random_N()} items in #{Tk::Clock.clicks - clicks} clicks" 125 126 treeCtrlRandom = TkBindTag.new 127 128 treeCtrlRandom.bind('Double-ButtonPress-1', 129 proc{|w, x, y| 130 Tk::TreeCtrl::BindCallback.doubleButton1(w, x, y) 131 Tk.callback_break 132 }, '%W %x %y') 133 134 treeCtrlRandom.bind('Control-ButtonPress-1', 135 proc{|w, x, y| 136 @Priv['selectMode'] = :toggle 137 randomButton1(w, x, y) 138 Tk.callback_break 139 }, '%W %x %y') 140 141 treeCtrlRandom.bind('Shift-ButtonPress-1', 142 proc{|w, x, y| 143 @Priv['selectMode'] = :add 144 randomButton1(w, x, y) 145 Tk.callback_break 146 }, '%W %x %y') 147 148 treeCtrlRandom.bind('ButtonPress-1', 149 proc{|w, x, y| 150 @Priv['selectMode'] = :set 151 randomButton1(w, x, y) 152 Tk.callback_break 153 }, '%W %x %y') 154 155 treeCtrlRandom.bind('Button1-Motion', 156 proc{|w, x, y| 157 randomMotion1(w, x, y) 158 Tk.callback_break 159 }, '%W %x %y') 160 161 treeCtrlRandom.bind('Button1-Leave', 162 proc{|w, x, y| 163 randomLeave1(w, x, y) 164 Tk.callback_break 165 }, '%W %x %y') 166 167 treeCtrlRandom.bind('ButtonRelease-1', 168 proc{|w, x, y| 169 randomRelease1(w, x, y) 170 Tk.callback_break 171 }, '%W %x %y') 172 173 t.bindtags = [ t, treeCtrlRandom, Tk::TreeCtrl, t.winfo_toplevel, :all ] 174end 175 176def randomButton1(t, x, y) 177 t.set_focus 178 id = t.identify(x, y) 179 puts id.inspect 180 @Priv['buttonMode'] = '' 181 182 # Click outside any item 183 if id.empty? 184 t.selection_clear 185 186 # Click in header 187 elsif id[0] == 'header' 188 Tk::TreeCtrl::BindCallback.buttonPress1(t, x, y) 189 190 # Click in item 191 else 192 where, item, arg1, arg2, arg3, arg4 = id 193 case arg1 194 when 'button' 195 if $Version_1_1_OrLater 196 t.item_toggle(item) 197 else # TreeCtrl 1.0 198 t.toggle(item) 199 end 200 201 when 'line' 202 if $Version_1_1_OrLater 203 t.item_toggle(arg2) 204 else # TreeCtrl 1.0 205 t.toggle(arg2) 206 end 207 208 when 'column' 209 ok = false 210 # Clicked an element 211 if id.length == 6 212 column = id[3] 213 e = id[5] 214 @Priv.list_element(:sensitive, t).each{|lst| 215 c, s, *eList = TkComm.simplelist(lst) 216 next if column != t.column_index(c) 217 next if t.item_style_set(item, c) != s 218 next if eList.find{|le| le == e} == nil 219 ok = true 220 break 221 } 222 end 223 unless ok 224 t.selection_clear 225 return 226 end 227 228 @Priv[:drag, :motion] = 0 229 @Priv[:drag, :x] = t.canvasx(x) 230 @Priv[:drag, :y] = t.canvasy(y) 231 @Priv[:drop] = '' 232 233 if @Priv['selectMode'] == 'add' 234 Tk::TreeCtrl::BindCallback.beginExtend(t, item) 235 elsif @Priv['selectMode'] == 'toggle' 236 Tk::TreeCtrl::BindCallback.beginToggle(t, item) 237 elsif ! t.selection_includes(item) 238 Tk::TreeCtrl::BindCallback.beginSelect(t, item) 239 end 240 t.activate(item) 241 242 if t.selection_includes(item) 243 @Priv['buttonMode'] = 'drag' 244 end 245 end 246 end 247end 248 249def randomMotion1(t, x, y) 250 case @Priv['buttonMode'] 251 when 'resize', 'header' 252 Tk::TreeCtrl::BindCallback.motion1(t, x, y) 253 when 'drag' 254 randomAutoScanCheck(t, x, y) 255 randomMotion(t, x, y) 256 end 257end 258 259def randomMotion(t, x, y) 260 case @Priv['buttonMode'] 261 when 'resize', 'header' 262 Tk::TreeCtrl::BindCallback.motion1(t, x, y) 263 264 when 'drag' 265 # Detect initial mouse movement 266 unless @Priv.bool_element(:drag, :motion) 267 @Priv[:selection] = t.selection_get 268 @Priv[:drop] = '' 269 t.dragimage_clear 270 # For each selected item, add 2nd and 3rd elements of 271 # column "item" to the dragimage 272 @Priv.list_element(:selection).each{|i| 273 @Priv.list_element(:dragimage,t).each{|lst| 274 c, s, *eList = TkComm.simplelist(lst) 275 if t.item_style_set(i, c) == s 276 t.dragimage_add(i, c, *eList) 277 end 278 } 279 } 280 @Priv[:drag,:motion] = true 281 end 282 283 # Find the item under the cursor 284 cursor = 'X_cursor' 285 drop = '' 286 id = t.identify(x, y) 287 ok = false 288 if !id.empty? && id[0] == 'item' && id.length == 6 289 item = id[1] 290 column = id[3] 291 e = id[5] 292 @Priv.list_element(:sensitive,t).each{|lst| 293 c, s, *eList = TkComm.simplelist(lst) 294 next if column != t.column_index(c) 295 next if t.item_style_set(item, c) != s 296 next unless eList.find{|val| val.to_s == e.to_s} 297 ok = true 298 break 299 } 300 ok = true if @Priv.list_element(:sensitive,t).find{|val| TkComm.simplelist(val).index(e)} 301 end 302 303 if ok 304 # If the item is not in the pre-drag selection 305 # (i.e. not being dragged) see if we can drop on it 306 unless @Priv.list_element(:selection).find{|val| val.to_s == item.to_s} 307 drop = item 308 # We can drop if dragged item isn't an ancestor 309 @Priv.list_element(:selection).each{|item2| 310 if t.item_isancestor(item2, item) 311 drop = '' 312 break 313 end 314 } 315 if drop != '' 316 x1, y1, x2, y2 = t.item_bbox(drop) 317 if y < y1 + 3 318 cursor = 'top_side' 319 @Priv[:drop,:pos] = 'prevsibling' 320 elsif y >= y2 - 3 321 cursor = 'bottom_side' 322 @Priv[:drop,:pos] = 'nextsibling' 323 else 324 cursor = '' 325 @Priv[:drop,:pos] = 'lastchild' 326 end 327 end 328 end 329 end 330 331 t[:cursor] = cursor if t[:cursor] != cursor 332 333 # Select the item under the cursor (if any) and deselect 334 # the previous drop-item (if any) 335 t.selection_modify(drop, @Priv[:drop]) 336 @Priv[:drop] = drop 337 338 # Show the dragimage in its new position 339 x = t.canvasx(x) - @Priv.numeric_element(:drag,:x) 340 y = t.canvasx(y) - @Priv.numeric_element(:drag,:y) 341 t.dragimage_offset(x, y) 342 t.dragimage_configure(:visible=>true) 343 end 344end 345 346def randomLeave1(t, x, y) 347 # This is called when I do ButtonPress-1 on Unix for some reason, 348 # and buttonMode is undefined. 349 return unless @Priv.exist?('buttonMode') 350 case @Priv['buttonMode'] 351 when 'header' 352 Tk::TreeCtrl::BindCallback.leave1(t, x, y) 353 end 354end 355 356def randomRelease1(t, x, y) 357 case @Priv['buttonMode'] 358 when 'resize', 'header' 359 Tk::TreeCtrl::BindCallback.release1(t, x, y) 360 when 'drag' 361 Tk::TreeCtrl::BindCallback.autoScanCancel(t) 362 t.dragimage_configure(:visible=>false) 363 t.selection_modify('', @Priv[:drop]) 364 t[:cursor] = '' 365 if @Priv[:drop] != '' 366 randomDrop(t, @Priv[:drop], @Priv.list_element(:selection), 367 @Priv[:drop, :pos]) 368 end 369 end 370 @Priv['buttonMode'] = '' 371end 372 373def randomDrop(t, target, src, pos) 374 parentList = [] 375 case pos 376 when 'lastchild' 377 parent = target 378 when 'prevsibling' 379 parent = t.item_parent(target) 380 when 'nextsibling' 381 parent = t.item_parent(target) 382 end 383 src.each{|item| 384 # Ignore any item whose ancestor is also selected 385 ignore = false 386 t.item_ancestors(item).each{|ancestor| 387 if src.find{|val| val.to_s == ancestor.to_s} 388 ignore = true 389 break 390 end 391 } 392 next if ignore 393 394 # Update the old parent of this moved item later 395 unless parentList.find{|val| val.to_s == item.to_s} 396 parentList << t.item_parent(item) 397 end 398 399 # Add to target 400 t.__send__("item_#{pos}", target, item) 401 402 # Update text: parent 403 t.item_element_configure(item, 'parent', 'e6', :text=>parent) 404 405 # Update text: depth 406 t.item_element_configure(item, 'depth', 'e6', :text=>t.depth(item)) 407 408 # Recursively update text: depth 409 itemList = [] 410 item = t.item_firstchild(item) 411 itemList << item if item != '' 412 413 while item = itemList.pop 414 t.item_element_configure(item, 'depth', 'e6', :text=>t.depth(item)) 415 416 item2 = t.item_nextsibling(item) 417 itemList << item2 if item2 != '' 418 419 item2 = t.item_firstchild(item) 420 itemList << item2 if item2 != '' 421 end 422 } 423 424 # Update items that lost some children 425 parentList.each{|item| 426 numChildren = t.item_numchildren(item) 427 if numChildren == 0 428 if $Version_1_1_OrLater 429 t.item_configure(item, :button=>false) 430 else # TreeCtrl 1.0 431 t.item_hasbutton(item, false) 432 end 433 t.item_style_map(item, 'item', 's2', ['e3', 'e3']) 434 else 435 t.item_element_configure(item, 'item', 'e4', :text=>"(#{numChildren})") 436 end 437 } 438 439 # Update the target that gained some children 440 if t.item_style_set(parent, 0) != 's1' 441 if $Version_1_1_OrLater 442 t.item_configure(parent, :button=>true) 443 else # TreeCtrl 1.0 444 t.item_hasbutton(parent, true) 445 end 446 t.item_style_map(parent, 'item', 's1', ['e3', 'e3']) 447 end 448 numChildren = t.item_numchildren(parent) 449 t.item_element_configure(parent, 'item', 'e4', :text=>"(#{numChildren})") 450end 451 452# Same as TreeCtrl::AutoScanCheck, but calls RandomMotion and 453# RandomAutoScanCheckAux 454def randomAutoScanCheck(t, x, y) 455 x1, y1, x2, y2 = t.contentbox 456 margin = t.winfo_pixels(t.scrollmargin) 457 if x < x1 + margin || x >= x2 - margin || y < y1 + margin || y >= y2 - margin 458 if ! @Priv.exist?(:autoscan, :afterId, t) 459 if y >= y2 - margin 460 t.yview(:scroll, 1, :units) 461 delay = t.yscrolldelay 462 elsif y < y1 + margin 463 t.yview(:scroll, -1, :units) 464 delay = t.yscrolldelay 465 elsif x >= x2 - margin 466 t.xview(:scroll, 1, :units) 467 delay = t.xscrolldelay 468 elsif x < x1 + margin 469 t.xview(:scroll, -1, :units) 470 delay = t.xscrolldelay 471 end 472 if @Priv.exist?(:autoscan, :scanning, t) 473 delay = delay[1] if delay.kind_of?(Array) 474 else 475 delay = delay[0] if delay.kind_of?(Array) 476 @Priv[:autoscan, :scanning, t] = true 477 end 478 case @Priv['buttonMode'] 479 when 'drag', 'marquee' 480 randomMotion(t, x, y) 481 end 482 @Priv[:autoscan, :afterId, t] = 483 Tk.after(delay, proc{ randomAutoScanCheckAux(t) }) 484 end 485 return 486 end 487 Tk::TreeCtrl::BindCallback.autoScanCancel(t) 488end 489 490def randomAutoScanCheckAux(t) 491 @Priv.unset(:autoscan, :afterId, t) 492 x = t.winfo_pointerx - t.winfo_rootx 493 y = t.winfo_pointery - t.winfo_rooty 494 randomAutoScanCheck(t, x, y) 495end 496 497# 498# Demo: random N items, button images 499# 500def demoRandom2(t) 501 demoRandom(t) 502 503 init_pics('mac-*') 504 505 t.configure(:openbuttonimage=>@images['mac-collapse'], 506 :closedbuttonimage=>@images['mac-expand'], 507 :showlines=>false) 508end 509