1# RCS: @(#) $Id: treectrl.tcl,v 1.41 2009/04/18 20:39:54 treectrl Exp $ 2 3bind TreeCtrl <Motion> { 4 TreeCtrl::CursorCheck %W %x %y 5 TreeCtrl::MotionInHeader %W %x %y 6} 7bind TreeCtrl <Leave> { 8 TreeCtrl::CursorCancel %W 9 TreeCtrl::MotionInHeader %W 10} 11bind TreeCtrl <ButtonPress-1> { 12 TreeCtrl::ButtonPress1 %W %x %y 13} 14bind TreeCtrl <Double-ButtonPress-1> { 15 TreeCtrl::DoubleButton1 %W %x %y 16} 17bind TreeCtrl <Button1-Motion> { 18 TreeCtrl::Motion1 %W %x %y 19} 20bind TreeCtrl <ButtonRelease-1> { 21 TreeCtrl::Release1 %W %x %y 22} 23bind TreeCtrl <Shift-ButtonPress-1> { 24 set TreeCtrl::Priv(buttonMode) normal 25 TreeCtrl::BeginExtend %W [%W item id {nearest %x %y}] 26} 27# Command-click should provide a discontinuous selection on OSX 28switch -- [tk windowingsystem] { 29 "aqua" { set modifier Command } 30 default { set modifier Control } 31} 32bind TreeCtrl <$modifier-ButtonPress-1> { 33 set TreeCtrl::Priv(buttonMode) normal 34 TreeCtrl::BeginToggle %W [%W item id {nearest %x %y}] 35} 36bind TreeCtrl <Button1-Leave> { 37 TreeCtrl::Leave1 %W %x %y 38} 39bind TreeCtrl <Button1-Enter> { 40 TreeCtrl::Enter1 %W %x %y 41} 42 43bind TreeCtrl <KeyPress-Up> { 44 TreeCtrl::SetActiveItem %W [TreeCtrl::UpDown %W active -1] 45} 46bind TreeCtrl <Shift-KeyPress-Up> { 47 TreeCtrl::Extend %W above 48} 49bind TreeCtrl <KeyPress-Down> { 50 TreeCtrl::SetActiveItem %W [TreeCtrl::UpDown %W active 1] 51} 52bind TreeCtrl <Shift-KeyPress-Down> { 53 TreeCtrl::Extend %W below 54} 55bind TreeCtrl <KeyPress-Left> { 56 if {[%W cget -orient] eq "vertical" && [%W cget -wrap] eq ""} { 57 %W item collapse [%W item id active] 58 } else { 59 TreeCtrl::SetActiveItem %W [TreeCtrl::LeftRight %W active -1] 60 } 61} 62bind TreeCtrl <Shift-KeyPress-Left> { 63 TreeCtrl::Extend %W left 64} 65bind TreeCtrl <Control-KeyPress-Left> { 66 %W xview scroll -1 pages 67} 68bind TreeCtrl <KeyPress-Right> { 69 if {[%W cget -orient] eq "vertical" && [%W cget -wrap] eq ""} { 70 %W item expand [%W item id active] 71 } else { 72 TreeCtrl::SetActiveItem %W [TreeCtrl::LeftRight %W active 1] 73 } 74} 75bind TreeCtrl <Shift-KeyPress-Right> { 76 TreeCtrl::Extend %W right 77} 78bind TreeCtrl <Control-KeyPress-Right> { 79 %W xview scroll 1 pages 80} 81bind TreeCtrl <KeyPress-Prior> { 82 %W yview scroll -1 pages 83 if {[%W item id {nearest 0 0}] ne ""} { 84 %W activate {nearest 0 0} 85 } 86} 87bind TreeCtrl <KeyPress-Next> { 88 %W yview scroll 1 pages 89 if {[%W item id {nearest 0 0}] ne ""} { 90 %W activate {nearest 0 0} 91 } 92} 93bind TreeCtrl <Control-KeyPress-Prior> { 94 %W xview scroll -1 pages 95} 96bind TreeCtrl <Control-KeyPress-Next> { 97 %W xview scroll 1 pages 98} 99bind TreeCtrl <KeyPress-Home> { 100 %W xview moveto 0 101} 102bind TreeCtrl <KeyPress-End> { 103 %W xview moveto 1 104} 105bind TreeCtrl <Control-KeyPress-Home> { 106 TreeCtrl::SetActiveItem %W [%W item id {first visible state enabled}] 107} 108bind TreeCtrl <Shift-Control-KeyPress-Home> { 109 TreeCtrl::DataExtend %W [%W item id {first visible state enabled}] 110} 111bind TreeCtrl <Control-KeyPress-End> { 112 TreeCtrl::SetActiveItem %W [%W item id {last visible state enabled}] 113} 114bind TreeCtrl <Shift-Control-KeyPress-End> { 115 TreeCtrl::DataExtend %W [%W item id {last visible state enabled}] 116} 117bind TreeCtrl <<Copy>> { 118 if {[string equal [selection own -displayof %W] "%W"]} { 119 clipboard clear -displayof %W 120 clipboard append -displayof %W [selection get -displayof %W] 121 } 122} 123bind TreeCtrl <KeyPress-space> { 124 TreeCtrl::BeginSelect %W [%W item id active] 125} 126bind TreeCtrl <KeyPress-Select> { 127 TreeCtrl::BeginSelect %W [%W item id active] 128} 129bind TreeCtrl <Control-Shift-KeyPress-space> { 130 TreeCtrl::BeginExtend %W [%W item id active] 131} 132bind TreeCtrl <Shift-KeyPress-Select> { 133 TreeCtrl::BeginExtend %W [%W item id active] 134} 135bind TreeCtrl <KeyPress-Escape> { 136 TreeCtrl::Cancel %W 137} 138bind TreeCtrl <Control-KeyPress-slash> { 139 TreeCtrl::SelectAll %W 140} 141bind TreeCtrl <Control-KeyPress-backslash> { 142 if {[string compare [%W cget -selectmode] "browse"]} { 143 %W selection clear 144 } 145} 146 147bind TreeCtrl <KeyPress-plus> { 148 %W item expand [%W item id active] 149} 150bind TreeCtrl <KeyPress-minus> { 151 %W item collapse [%W item id active] 152} 153bind TreeCtrl <KeyPress-Return> { 154 %W item toggle [%W item id active] 155} 156 157 158# Additional Tk bindings that aren't part of the Motif look and feel: 159 160bind TreeCtrl <ButtonPress-2> { 161 TreeCtrl::ScanMark %W %x %y 162} 163bind TreeCtrl <Button2-Motion> { 164 TreeCtrl::ScanDrag %W %x %y 165} 166 167if {$tcl_platform(platform) eq "windows"} { 168 bind TreeCtrl <Control-ButtonPress-3> { 169 TreeCtrl::ScanMark %W %x %y 170 } 171 bind TreeCtrl <Control-Button3-Motion> { 172 TreeCtrl::ScanDrag %W %x %y 173 } 174} 175 176# MouseWheel 177if {[string equal "x11" [tk windowingsystem]]} { 178 # Support for mousewheels on Linux/Unix commonly comes through mapping 179 # the wheel to the extended buttons. If you have a mousewheel, find 180 # Linux configuration info at: 181 # http://www.inria.fr/koala/colas/mouse-wheel-scroll/ 182 bind TreeCtrl <4> { 183 if {!$tk_strictMotif} { 184 %W yview scroll -5 units 185 } 186 } 187 bind TreeCtrl <5> { 188 if {!$tk_strictMotif} { 189 %W yview scroll 5 units 190 } 191 } 192} elseif {[string equal [tk windowingsystem] "aqua"]} { 193 bind TreeCtrl <MouseWheel> { 194 %W yview scroll [expr {- (%D)}] units 195 } 196} else { 197 bind TreeCtrl <MouseWheel> { 198 %W yview scroll [expr {- (%D / 120) * 4}] units 199 } 200} 201 202namespace eval ::TreeCtrl { 203 variable Priv 204 array set Priv { 205 prev {} 206 } 207 208 if {[info procs ::lassign] eq ""} { 209 proc lassign {values args} { 210 uplevel 1 [list foreach $args [linsert $values end {}] break] 211 lrange $values [llength $args] end 212 } 213 } 214} 215 216# Retrieve filelist bindings from this dir 217source [file join [file dirname [info script]] filelist-bindings.tcl] 218 219# ::TreeCtrl::ColumnCanResizeLeft -- 220# 221# Return 1 if the given column should be resized by the left edge. 222# 223# Arguments: 224# w The treectrl widget. 225# column The column. 226 227proc ::TreeCtrl::ColumnCanResizeLeft {w column} { 228 if {[$w column cget $column -lock] eq "right"} { 229 if {[$w column compare $column == "first visible lock right"]} { 230 return 1 231 } 232 if {[$w column compare $column == "last visible lock right"]} { 233 return 1 234 } 235 } 236 return 0 237} 238 239# ::TreeCtrl::ColumnCanMoveHere -- 240# 241# Return 1 if the given column can be moved before another. 242# 243# Arguments: 244# w The treectrl widget. 245# column The column. 246# before The column to place 'column' before. 247 248proc ::TreeCtrl::ColumnCanMoveHere {w column before} { 249 if {[$w column compare $column == $before] || 250 ([$w column order $column] == [$w column order $before] - 1)} { 251 return 0 252 } 253 set lock [$w column cget $column -lock] 254 return [expr {[$w column compare $before >= "first lock $lock"] && 255 [$w column compare $before <= "last lock $lock next"]}] 256} 257 258# ::TreeCtrl::ColumnsBbox -- 259# 260# Returns the bounding box of an area of the header. The [bbox] command 261# can't be used if the items area is completely obscured. [BUG 2355369] 262# 263# Arguments: 264# w The treectrl widget. 265# area left, content or right 266 267proc ::TreeCtrl::ColumnsBbox {w area} { 268 if {[$w bbox header] eq ""} return 269 scan [$w bbox header] "%d %d %d %d" x1 y1 x2 y2 270 271 # If the items area is not obscured then use the [bbox] command. 272 if {[$w bbox $area] ne ""} { 273 scan [$w bbox $area] "%d %d %d %d" x1 dummy x2 dummy 274 return "$x1 $y1 $x2 $y2" 275 } 276 277 set contentLeft $x1 278 if {[$w column id "last visible lock left"] ne ""} { 279 scan [$w column bbox "last visible lock left"] "%d %d %d %d" a b c d 280 set contentLeft $c 281 } elseif {$area eq "left"} { 282 return "" 283 } 284 285 set contentRight $x2 286 if {[$w column id "first visible lock right"] ne ""} { 287 scan [$w column bbox "first visible lock right"] "%d %d %d %d" a b c d 288 set contentRight $a 289 } elseif {$area eq "right"} { 290 return "" 291 } 292 293 switch -- $area { 294 left { set result "$x1 $y1 $contentLeft $y2" } 295 content { set result "$contentLeft $y1 $contentRight $y2" } 296 right { set result "$contentRight $y1 $x2 $y2" } 297 } 298 return $result 299} 300 301# ::TreeCtrl::ColumnDragFindBefore -- 302# 303# This is called when dragging a column header. The result is 1 if the given 304# coordinates are near a column header before which the dragged column can 305# be moved. 306# 307# Arguments: 308# w The treectrl widget. 309# x Window x-coord. 310# y Window y-coord. 311# dragColumn The column being dragged. 312# indColumn_ Out: what to set -indicatorcolumn to. 313# indSide_ Out: what to set -indicatorside to. 314 315proc ::TreeCtrl::ColumnDragFindBefore {w x y dragColumn indColumn_ indSide_} { 316 upvar $indColumn_ indColumn 317 upvar $indSide_ indSide 318 319 switch -- [$w column cget $dragColumn -lock] { 320 left {set area left} 321 none {set area content} 322 right {set area right} 323 } 324 325# BUG 2355369 326# scan [$w bbox $area] "%d %d %d %d" minX y1 maxX y2 327 scan [ColumnsBbox $w $area] "%d %d %d %d" minX y1 maxX y2 328 if {$x < $minX} { 329 set x $minX 330 } 331 if {$x >= $maxX} { 332 set x [expr {$maxX - 1}] 333 } 334 set id [$w identify $x $y] 335 if {[lindex $id 0] ne "header"} { 336 return 0 337 } 338 set indColumn [lindex $id 1] 339 set before $indColumn 340 set prev [$w column id "$dragColumn prev visible"] 341 set next [$w column id "$dragColumn next visible"] 342 if {[$w column compare $indColumn == "tail"]} { 343 set indSide left 344 } elseif {$prev ne "" && [$w column compare $prev == $indColumn]} { 345 set indSide left 346 } elseif {$next ne "" && [$w column compare $next == $indColumn]} { 347 set before [$w column id "$indColumn next visible"] 348 set indSide right 349 } else { 350 scan [$w column bbox $indColumn] "%d %d %d %d" x1 y1 x2 y2 351 if {$x < $x1 + ($x2 - $x1) / 2} { 352 set indSide left 353 } else { 354 set before [$w column id "$indColumn next visible"] 355 set indSide right 356 } 357 } 358 return [ColumnCanMoveHere $w $dragColumn $before] 359} 360 361# ::TreeCtrl::CursorAction -- 362# 363# If the given point is at the left or right edge of a resizable column, the 364# result is "column resize C". If the given point is in a header with -button 365# TRUE, the result is "column button C". 366# 367# Arguments: 368# w The treectrl widget. 369# x Window coord of pointer. 370# y Window coord of pointer. 371 372proc ::TreeCtrl::CursorAction {w x y} { 373 variable Priv 374 set id [$w identify $x $y] 375 376 if {[lindex $id 0] eq "header"} { 377 set column [lindex $id 1] 378 set side [lindex $id 2] 379 if {$side eq "left"} { 380 if {[$w column compare $column == tail]} { 381 set column2 [$w column id "last visible lock none"] 382 if {$column2 ne "" && [$w column cget $column2 -resize]} { 383 return "column resize $column2" 384 } 385 # Can't -resize or -button the tail column 386 return "" 387 } 388 if {[ColumnCanResizeLeft $w $column]} { 389 if {[$w column cget $column -resize]} { 390 return "column resize $column" 391 } 392 } else { 393 # Resize the previous column 394 set lock [$w column cget $column -lock] 395 if {[$w column compare $column != "first visible lock $lock"]} { 396 set column2 [$w column id "$column prev visible"] 397 if {[$w column cget $column2 -resize]} { 398 return "column resize $column2" 399 } 400 } 401 } 402 } elseif {$side eq "right"} { 403 if {![ColumnCanResizeLeft $w $column]} { 404 if {[$w column cget $column -resize]} { 405 return "column resize $column" 406 } 407 } 408 } 409 if {[$w column compare $column == "tail"]} { 410 # nothing 411 } elseif {[$w column cget $column -button]} { 412 return "column button $column" 413 } 414 } 415 return "" 416} 417 418# ::TreeCtrl::CursorCheck -- 419# 420# Sees if the given pointer coordinates are near the edge of a resizable 421# column in the header. If so and the treectrl's cursor is not already 422# set to sb_h_double_arrow, then the current cursor is saved and changed 423# to sb_h_double_arrow, and an [after] callback to CursorCheckAux is 424# scheduled. 425# 426# Arguments: 427# w The treectrl widget. 428# x Window coord of pointer. 429# y Window coord of pointer. 430 431proc ::TreeCtrl::CursorCheck {w x y} { 432 variable Priv 433 set action [CursorAction $w $x $y] 434 if {[lindex $action 1] ne "resize"} { 435 CursorCancel $w 436 return 437 } 438 set cursor sb_h_double_arrow 439 if {$cursor ne [$w cget -cursor]} { 440 if {![info exists Priv(cursor,$w)]} { 441 set Priv(cursor,$w) [$w cget -cursor] 442 } 443 $w configure -cursor $cursor 444 } 445 if {[info exists Priv(cursor,afterId,$w)]} { 446 after cancel $Priv(cursor,afterId,$w) 447 } 448 set Priv(cursor,afterId,$w) [after 150 [list TreeCtrl::CursorCheckAux $w]] 449 return 450} 451 452# ::TreeCtrl::CursorCheckAux -- 453# 454# Get's the location of the pointer and calls CursorCheck if the treectrl's 455# cursor was previously set to sb_h_double_arrow. 456# 457# Arguments: 458# w The treectrl widget. 459 460proc ::TreeCtrl::CursorCheckAux {w} { 461 variable Priv 462 set x [winfo pointerx $w] 463 set y [winfo pointery $w] 464 if {[info exists Priv(cursor,$w)]} { 465 set x [expr {$x - [winfo rootx $w]}] 466 set y [expr {$y - [winfo rooty $w]}] 467 CursorCheck $w $x $y 468 } 469 return 470} 471 472# ::TreeCtrl::CursorCancel -- 473# 474# Restores the treectrl's cursor if it was changed to sb_h_double_arrow. 475# Cancels any pending [after] callback to CursorCheckAux. 476# 477# Arguments: 478# w The treectrl widget. 479 480proc ::TreeCtrl::CursorCancel {w} { 481 variable Priv 482 if {[info exists Priv(cursor,$w)]} { 483 $w configure -cursor $Priv(cursor,$w) 484 unset Priv(cursor,$w) 485 } 486 if {[info exists Priv(cursor,afterId,$w)]} { 487 after cancel $Priv(cursor,afterId,$w) 488 unset Priv(cursor,afterId,$w) 489 } 490 return 491} 492 493# ::TreeCtrl::MotionInHeader -- 494# 495# This procedure updates the active/normal states of columns as the pointer 496# moves in and out of column headers. Typically this results in visual 497# feedback by changing the appearance of the headers. 498# 499# Arguments: 500# w The treectrl widget. 501# args x y coords if the pointer is in the window, or an empty list. 502 503proc ::TreeCtrl::MotionInHeader {w args} { 504 variable Priv 505 if {[llength $args]} { 506 set x [lindex $args 0] 507 set y [lindex $args 1] 508 set action [CursorAction $w $x $y] 509 } else { 510 set action "" 511 } 512 if {[info exists Priv(inheader,$w)]} { 513 set prevColumn $Priv(inheader,$w) 514 } else { 515 set prevColumn "" 516 } 517 set column "" 518 if {[lindex $action 0] eq "column"} { 519 set column [lindex $action 2] 520 } 521 if {$column ne $prevColumn} { 522 if {$prevColumn ne ""} { 523 $w column configure $prevColumn -state normal 524 } 525 if {$column ne ""} { 526 $w column configure $column -state active 527 set Priv(inheader,$w) $column 528 } else { 529 unset Priv(inheader,$w) 530 } 531 } 532 return 533} 534 535# ::TreeCtrl::ButtonPress1 -- 536# 537# Handle <ButtonPress-1> event. 538# 539# Arguments: 540# w The treectrl widget. 541# x Window x coord. 542# y Window y coord. 543 544proc ::TreeCtrl::ButtonPress1 {w x y} { 545 variable Priv 546 focus $w 547 548 set id [$w identify $x $y] 549 if {$id eq ""} { 550 return 551 } 552 553 if {[lindex $id 0] eq "item"} { 554 lassign $id where item arg1 arg2 555 if {$arg1 eq "button"} { 556 $w item toggle $item 557 return 558 } elseif {$arg1 eq "line"} { 559 $w item toggle $arg2 560 return 561 } 562 } 563 set Priv(buttonMode) "" 564 if {[lindex $id 0] eq "header"} { 565 set action [CursorAction $w $x $y] 566 if {[lindex $action 1] eq "resize"} { 567 set column [lindex $action 2] 568 set Priv(buttonMode) resize 569 set Priv(column) $column 570 set Priv(x) $x 571 set Priv(y) $y 572 set Priv(width) [$w column width $column] 573 return 574 } 575 set column [lindex $id 1] 576 if {[lindex $action 1] eq "button"} { 577 set Priv(buttonMode) header 578 $w column configure $column -state pressed 579 } else { 580 if {[$w column compare $column == "tail"]} return 581 if {![$w column dragcget -enable]} return 582 set Priv(buttonMode) dragColumnWait 583 } 584 set Priv(column) $column 585 set Priv(columnDrag,x) $x 586 set Priv(columnDrag,y) $y 587 return 588 } 589 set item [lindex $id 1] 590 if {![$w item enabled $item]} { 591 return 592 } 593 594 # If the initial mouse-click is in a locked column, restrict scrolling 595 # to the vertical. 596 scan [$w contentbox] "%d %d %d %d" x1 y1 x2 y2 597 if {$x >= $x1 && $x < $x2} { 598 set Priv(autoscan,direction,$w) xy 599 } else { 600 set Priv(autoscan,direction,$w) y 601 } 602 603 set Priv(buttonMode) normal 604 BeginSelect $w $item 605 return 606} 607 608# ::TreeCtrl::DoubleButtonPress1 -- 609# 610# Handle <Double-ButtonPress-1> event. 611# 612# Arguments: 613# w The treectrl widget. 614# x Window x coord. 615# y Window y coord. 616 617proc ::TreeCtrl::DoubleButton1 {w x y} { 618 619 set id [$w identify $x $y] 620 if {$id eq ""} { 621 return 622 } 623 if {[lindex $id 0] eq "item"} { 624 lassign $id where item arg1 arg2 625 if {$arg1 eq "button"} { 626 $w item toggle $item 627 return 628 } elseif {$arg1 eq "line"} { 629 $w item toggle $arg2 630 return 631 } 632 } 633 if {[lindex $id 0] eq "header"} { 634 set action [CursorAction $w $x $y] 635 # Double-click between columns to set default column width 636 if {[lindex $action 1] eq "resize"} { 637 set column [lindex $action 2] 638 $w column configure $column -width "" 639 CursorCheck $w $x $y 640 MotionInHeader $w $x $y 641 } else { 642 ButtonPress1 $w $x $y 643 } 644 } 645 return 646} 647 648# ::TreeCtrl::Motion1 -- 649# 650# Handle <Button1-Motion> event. 651# 652# Arguments: 653# w The treectrl widget. 654# x Window x coord. 655# y Window y coord. 656 657proc ::TreeCtrl::Motion1 {w x y} { 658 variable Priv 659 if {![info exists Priv(buttonMode)]} return 660 switch $Priv(buttonMode) { 661 header { 662 set id [$w identify $x $y] 663 if {![string match "header $Priv(column)*" $id]} { 664 if {[$w column cget $Priv(column) -state] eq "pressed"} { 665 $w column configure $Priv(column) -state normal 666 } 667 } else { 668 if {[$w column cget $Priv(column) -state] ne "pressed"} { 669 $w column configure $Priv(column) -state pressed 670 } 671 if {[$w column dragcget -enable] && 672 (abs($Priv(columnDrag,x) - $x) > 4)} { 673 $w column dragconfigure \ 674 -imagecolumn $Priv(column) \ 675 -imageoffset [expr {$x - $Priv(columnDrag,x)}] 676 set Priv(buttonMode) dragColumn 677 TryEvent $w ColumnDrag begin [list C $Priv(column)] 678 } 679 } 680 } 681 dragColumnWait { 682 if {(abs($Priv(columnDrag,x) - $x) > 4)} { 683 $w column dragconfigure \ 684 -imagecolumn $Priv(column) \ 685 -imageoffset [expr {$x - $Priv(columnDrag,x)}] 686 set Priv(buttonMode) dragColumn 687 TryEvent $w ColumnDrag begin [list C $Priv(column)] 688 } 689 } 690 dragColumn { 691 scan [$w bbox header] "%d %d %d %d" x1 y1 x2 y2 692 if {$y < $y1 - 30 || $y >= $y2 + 30} { 693 set inside 0 694 } else { 695 set inside 1 696 } 697 if {$inside && ([$w column dragcget -imagecolumn] eq "")} { 698 $w column dragconfigure -imagecolumn $Priv(column) 699 } elseif {!$inside && ([$w column dragcget -imagecolumn] ne "")} { 700 $w column dragconfigure -imagecolumn "" -indicatorcolumn "" 701 } 702 if {$inside} { 703 $w column dragconfigure -imageoffset [expr {$x - $Priv(columnDrag,x)}] 704 if {[ColumnDragFindBefore $w $x $Priv(columnDrag,y) $Priv(column) indColumn indSide]} { 705 $w column dragconfigure -indicatorcolumn $indColumn \ 706 -indicatorside $indSide 707 } else { 708 $w column dragconfigure -indicatorcolumn "" 709 } 710 } 711 if {[$w column cget $Priv(column) -lock] eq "none"} { 712 ColumnDragScrollCheck $w $x $y 713 } 714 } 715 normal { 716 set Priv(x) $x 717 set Priv(y) $y 718 SelectionMotion $w [$w item id [list nearest $x $y]] 719 set Priv(autoscan,command,$w) {SelectionMotion %T [%T item id "nearest %x %y"]} 720 AutoScanCheck $w $x $y 721 } 722 resize { 723 if {[ColumnCanResizeLeft $w $Priv(column)]} { 724 set width [expr {$Priv(width) + $Priv(x) - $x}] 725 } else { 726 set width [expr {$Priv(width) + $x - $Priv(x)}] 727 } 728 set minWidth [$w column cget $Priv(column) -minwidth] 729 set maxWidth [$w column cget $Priv(column) -maxwidth] 730 if {$minWidth eq ""} { 731 set minWidth 0 732 } 733 if {$width < $minWidth} { 734 set width $minWidth 735 } 736 if {($maxWidth ne "") && ($width > $maxWidth)} { 737 set width $maxWidth 738 } 739 if {$width == 0} { 740 incr width 741 } 742 switch -- [$w cget -columnresizemode] { 743 proxy { 744 scan [$w column bbox $Priv(column)] "%d %d %d %d" x1 y1 x2 y2 745 if {[ColumnCanResizeLeft $w $Priv(column)]} { 746 # Use "ne" because -columnproxy could be "" 747 if {$x ne [$w cget -columnproxy]} { 748 $w configure -columnproxy $x 749 } 750 } else { 751 if {($x1 + $width - 1) ne [$w cget -columnproxy]} { 752 $w configure -columnproxy [expr {$x1 + $width - 1}] 753 } 754 } 755 } 756 realtime { 757 if {[$w column cget $Priv(column) -width] != $width} { 758 $w column configure $Priv(column) -width $width 759 } 760 } 761 } 762 } 763 } 764 return 765} 766 767# ::TreeCtrl::Leave1 -- 768# 769# Handle <Button1-Leave> event. 770# 771# Arguments: 772# w The treectrl widget. 773# x Window x coord. 774# y Window y coord. 775 776proc ::TreeCtrl::Leave1 {w x y} { 777 variable Priv 778 if {![info exists Priv(buttonMode)]} return 779 switch $Priv(buttonMode) { 780 header { 781 if {[$w column cget $Priv(column) -state] eq "pressed"} { 782 $w column configure $Priv(column) -state normal 783 } 784 } 785 } 786 return 787} 788 789# ::TreeCtrl::Enter1 -- 790# 791# Handle <Button1-Enter> event. 792# 793# Arguments: 794# w The treectrl widget. 795# x Window x coord. 796# y Window y coord. 797 798proc ::TreeCtrl::Enter1 {w x y} { 799 variable Priv 800 if {![info exists Priv(buttonMode)]} return 801 switch $Priv(buttonMode) { 802 default {} 803 } 804 return 805} 806 807# ::TreeCtrl::Release1 -- 808# 809# Handle <ButtonRelease-1> event. 810# 811# Arguments: 812# w The treectrl widget. 813# x Window x coord. 814# y Window y coord. 815 816proc ::TreeCtrl::Release1 {w x y} { 817 variable Priv 818 if {![info exists Priv(buttonMode)]} return 819 switch $Priv(buttonMode) { 820 header { 821 if {[$w column cget $Priv(column) -state] eq "pressed"} { 822 $w column configure $Priv(column) -state active 823 TryEvent $w Header invoke [list C $Priv(column)] 824 } 825 } 826 dragColumn { 827 AutoScanCancel $w 828 $w column configure $Priv(column) -state normal 829 if {[$w column dragcget -imagecolumn] ne ""} { 830 set visible 1 831 } else { 832 set visible 0 833 } 834 set column [$w column dragcget -indicatorcolumn] 835 $w column dragconfigure -imagecolumn "" -indicatorcolumn "" 836 if {$visible && ($column ne "")} { 837 set side [$w column dragcget -indicatorside] 838 if {$side eq "right"} { 839 set column [$w column id "$column next visible"] 840 } 841 TryEvent $w ColumnDrag receive [list C $Priv(column) b $column] 842 } 843 set id [$w identify $x $y] 844 if {[lindex $id 0] eq "header"} { 845 set column [lindex $id 1] 846 if {($column ne "") && [$w column compare $column != "tail"]} { 847 if {[$w column cget $column -button]} { 848 $w column configure $column -state active 849 } 850 } 851 } 852 TryEvent $w ColumnDrag end [list C $Priv(column)] 853 } 854 normal { 855 AutoScanCancel $w 856 set nearest [$w item id [list nearest $x $y]] 857 if {$nearest ne ""} { 858 $w activate $nearest 859 } 860set Priv(prev) "" 861 } 862 resize { 863 if {[$w cget -columnproxy] ne ""} { 864 scan [$w column bbox $Priv(column)] "%d %d %d %d" x1 y1 x2 y2 865 if {[ColumnCanResizeLeft $w $Priv(column)]} { 866 set width [expr {$x2 - [$w cget -columnproxy]}] 867 } else { 868 set width [expr {[$w cget -columnproxy] - $x1 + 1}] 869 } 870 $w configure -columnproxy {} 871 $w column configure $Priv(column) -width $width 872 } 873 CursorCheck $w $x $y 874 } 875 } 876 unset Priv(buttonMode) 877 return 878} 879 880# ::TreeCtrl::BeginSelect -- 881# 882# This procedure is typically invoked on button-1 presses. It begins 883# the process of making a selection in the treectrl. Its exact behavior 884# depends on the selection mode currently in effect for the treectrl. 885# 886# Arguments: 887# w The treectrl widget. 888# item The item for the selection operation (typically the 889# one under the pointer). 890 891proc ::TreeCtrl::BeginSelect {w item} { 892 variable Priv 893 if {$item eq ""} return 894 if {[string equal [$w cget -selectmode] "multiple"]} { 895 if {[$w selection includes $item]} { 896 $w selection clear $item 897 } else { 898 $w selection add $item 899 } 900 } else { 901 $w selection anchor $item 902 $w selection modify $item all 903 set Priv(selection) {} 904 set Priv(prev) $item 905 } 906 return 907} 908 909# ::TreeCtrl::SelectionMotion -- 910# 911# This procedure is called to process mouse motion events while 912# button 1 is down. It may move or extend the selection, depending 913# on the treectrl's selection mode. 914# 915# Arguments: 916# w The treectrl widget. 917# item- The item under the pointer. 918 919proc ::TreeCtrl::SelectionMotion {w item} { 920 variable Priv 921 922 if {$item eq ""} return 923 if {$item eq $Priv(prev)} return 924 if {![$w item enabled $item]} return 925 926 switch [$w cget -selectmode] { 927 browse { 928 $w selection modify $item all 929 set Priv(prev) $item 930 } 931 extended { 932 set i $Priv(prev) 933 set select {} 934 set deselect {} 935 if {$i eq ""} { 936 set i $item 937 lappend select $item 938 set hack [$w item compare $item == anchor] 939 } else { 940 set hack 0 941 } 942 if {[$w selection includes anchor] || $hack} { 943 set deselect [concat $deselect [$w item range $i $item]] 944 set select [concat $select [$w item range anchor $item]] 945 } else { 946 set deselect [concat $deselect [$w item range $i $item]] 947 set deselect [concat $deselect [$w item range anchor $item]] 948 } 949 if {![info exists Priv(selection)]} { 950 set Priv(selection) [$w selection get] 951 } 952 while {[$w item compare $i < $item] && [$w item compare $i < anchor]} { 953 if {[lsearch $Priv(selection) $i] >= 0} { 954 lappend select $i 955 } 956 set i [$w item id "$i next visible"] 957 } 958 while {[$w item compare $i > $item] && [$w item compare $i > anchor]} { 959 if {[lsearch $Priv(selection) $i] >= 0} { 960 lappend select $i 961 } 962 set i [$w item id "$i prev visible"] 963 } 964 set Priv(prev) $item 965 $w selection modify $select $deselect 966 } 967 } 968 return 969} 970 971# ::TreeCtrl::BeginExtend -- 972# 973# This procedure is typically invoked on shift-button-1 presses. It 974# begins the process of extending a selection in the treectrl. Its 975# exact behavior depends on the selection mode currently in effect 976# for the treectrl. 977# 978# Arguments: 979# w The treectrl widget. 980# item- The item for the selection operation (typically the 981# one under the pointer). 982 983proc ::TreeCtrl::BeginExtend {w item} { 984 if {[string equal [$w cget -selectmode] "extended"]} { 985 if {[$w selection includes anchor]} { 986 SelectionMotion $w $item 987 } else { 988 # No selection yet; simulate the begin-select operation. 989 BeginSelect $w $item 990 } 991 } 992 return 993} 994 995# ::TreeCtrl::BeginToggle -- 996# 997# This procedure is typically invoked on control-button-1 presses. It 998# begins the process of toggling a selection in the treectrl. Its 999# exact behavior depends on the selection mode currently in effect 1000# for the treectrl. 1001# 1002# Arguments: 1003# w The treectrl widget. 1004# item The item for the selection operation (typically the 1005# one under the pointer). 1006 1007proc ::TreeCtrl::BeginToggle {w item} { 1008 variable Priv 1009 if {$item eq ""} return 1010 if {[string equal [$w cget -selectmode] "extended"]} { 1011 set Priv(selection) [$w selection get] 1012 set Priv(prev) $item 1013 $w selection anchor $item 1014 if {[$w selection includes $item]} { 1015 $w selection clear $item 1016 } else { 1017 $w selection add $item 1018 } 1019 } 1020 return 1021} 1022 1023# ::TreeCtrl::AutoScanCheck -- 1024# 1025# Sees if the given pointer coords are outside the content area of the 1026# treectrl (ie, not including borders or column headers) or within 1027# -scrollmargin distance of the edges of the content area. If so and 1028# auto-scanning is not already in progress, then the window is scrolled 1029# and an [after] callback to AutoScanCheckAux is scheduled. 1030# 1031# Arguments: 1032# w The treectrl widget. 1033# x Window x coord. 1034# y Window y coord. 1035 1036proc ::TreeCtrl::AutoScanCheck {w x y} { 1037 variable Priv 1038 scan [$w contentbox] "%d %d %d %d" x1 y1 x2 y2 1039 set margin [winfo pixels $w [$w cget -scrollmargin]] 1040 if {![info exists Priv(autoscan,direction,$w)]} { 1041 set Priv(autoscan,direction,$w) xy 1042 } 1043 set scrollX [string match *x* $Priv(autoscan,direction,$w)] 1044 set scrollY [string match *y* $Priv(autoscan,direction,$w)] 1045 if {($scrollX && (($x < $x1 + $margin) || ($x >= $x2 - $margin))) || 1046 ($scrollY && (($y < $y1 + $margin) || ($y >= $y2 - $margin)))} { 1047 if {[info exists Priv(autoscan,afterId,$w)]} return 1048 if {$scrollY && $y >= $y2 - $margin} { 1049 $w yview scroll 1 units 1050 set delay [$w cget -yscrolldelay] 1051 } elseif {$scrollY && $y < $y1 + $margin} { 1052 $w yview scroll -1 units 1053 set delay [$w cget -yscrolldelay] 1054 } elseif {$scrollX && $x >= $x2 - $margin} { 1055 $w xview scroll 1 units 1056 set delay [$w cget -xscrolldelay] 1057 } elseif {$scrollX && $x < $x1 + $margin} { 1058 $w xview scroll -1 units 1059 set delay [$w cget -xscrolldelay] 1060 } 1061 set count [scan $delay "%d %d" d1 d2] 1062 if {[info exists Priv(autoscan,scanning,$w)]} { 1063 if {$count == 2} { 1064 set delay $d2 1065 } 1066 } else { 1067 if {$count == 2} { 1068 set delay $d1 1069 } 1070 set Priv(autoscan,scanning,$w) 1 1071 } 1072 if {$Priv(autoscan,command,$w) ne ""} { 1073 set command [string map [list %T $w %x $x %y $y] $Priv(autoscan,command,$w)] 1074 eval $command 1075 } 1076 set Priv(autoscan,afterId,$w) [after $delay [list TreeCtrl::AutoScanCheckAux $w]] 1077 return 1078 } 1079 AutoScanCancel $w 1080 return 1081} 1082 1083# ::TreeCtrl::AutoScanCheckAux -- 1084# 1085# Gets the location of the pointer and calls AutoScanCheck. 1086# 1087# Arguments: 1088# w The treectrl widget. 1089 1090proc ::TreeCtrl::AutoScanCheckAux {w} { 1091 variable Priv 1092 # Not quite sure how this can happen 1093 if {![info exists Priv(autoscan,afterId,$w)]} return 1094 unset Priv(autoscan,afterId,$w) 1095 set x [winfo pointerx $w] 1096 set y [winfo pointery $w] 1097 set x [expr {$x - [winfo rootx $w]}] 1098 set y [expr {$y - [winfo rooty $w]}] 1099 AutoScanCheck $w $x $y 1100 return 1101} 1102 1103# ::TreeCtrl::AutoScanCancel -- 1104# 1105# Cancels any pending [after] callback to AutoScanCheckAux. 1106# 1107# Arguments: 1108# w The treectrl widget. 1109 1110proc ::TreeCtrl::AutoScanCancel {w} { 1111 variable Priv 1112 if {[info exists Priv(autoscan,afterId,$w)]} { 1113 after cancel $Priv(autoscan,afterId,$w) 1114 unset Priv(autoscan,afterId,$w) 1115 } 1116 unset -nocomplain Priv(autoscan,scanning,$w) 1117 return 1118} 1119 1120# ::TreeCtrl::ColumnDragScrollCheck -- 1121# 1122# Sees if the given pointer coords are outside the left or right edges of 1123# the content area of the treectrl (ie, not including borders). If so and 1124# auto-scanning is not already in progress, then the window is scrolled 1125# horizontally and the column drag-image is repositioned, and an [after] 1126# callback to ColumnDragScrollCheckAux is scheduled. 1127# 1128# Arguments: 1129# w The treectrl widget. 1130# x Window coord of pointer. 1131# y Window coord of pointer. 1132 1133proc ::TreeCtrl::ColumnDragScrollCheck {w x y} { 1134 variable Priv 1135 1136# BUG 2355369 1137# scan [$w contentbox] "%d %d %d %d" x1 y1 x2 y2 1138 scan [ColumnsBbox $w content] "%d %d %d %d" x1 y1 x2 y2 1139 1140 if {($x < $x1) || ($x >= $x2)} { 1141 if {![info exists Priv(autoscan,afterId,$w)]} { 1142 set bbox1 [$w column bbox $Priv(column)] 1143 if {$x >= $x2} { 1144 $w xview scroll 1 units 1145 } else { 1146 $w xview scroll -1 units 1147 } 1148 set bbox2 [$w column bbox $Priv(column)] 1149 if {[lindex $bbox1 0] != [lindex $bbox2 0]} { 1150 incr Priv(columnDrag,x) [expr {[lindex $bbox2 0] - [lindex $bbox1 0]}] 1151 $w column dragconfigure -imageoffset [expr {$x - $Priv(columnDrag,x)}] 1152 1153 if {[ColumnDragFindBefore $w $x $Priv(columnDrag,y) $Priv(column) indColumn indSide]} { 1154 $w column dragconfigure -indicatorcolumn $indColumn \ 1155 -indicatorside $indSide 1156 } else { 1157 $w column dragconfigure -indicatorcolumn "" 1158 } 1159 } 1160 set Priv(autoscan,afterId,$w) [after 50 [list TreeCtrl::ColumnDragScrollCheckAux $w]] 1161 } 1162 return 1163 } 1164 AutoScanCancel $w 1165 return 1166} 1167 1168# ::TreeCtrl::ColumnDragScrollCheckAux -- 1169# 1170# Gets the location of the pointer and calls ColumnDragScrollCheck. 1171# 1172# Arguments: 1173# w The treectrl widget. 1174 1175proc ::TreeCtrl::ColumnDragScrollCheckAux {w} { 1176 variable Priv 1177 # Not quite sure how this can happen 1178 if {![info exists Priv(autoscan,afterId,$w)]} return 1179 unset Priv(autoscan,afterId,$w) 1180 set x [winfo pointerx $w] 1181 set y [winfo pointery $w] 1182 set x [expr {$x - [winfo rootx $w]}] 1183 set y [expr {$y - [winfo rooty $w]}] 1184 ColumnDragScrollCheck $w $x $y 1185 return 1186} 1187 1188# ::TreeCtrl::UpDown -- 1189# 1190# Returns the id of an item above or below the given item that the active 1191# item could be set to. If the given item isn't visible, the first visible 1192# enabled item is returned. An attempt is made to choose an item in the 1193# same column over repeat calls; this gives a better result if some rows 1194# have less items than others. Only enabled items are considered. 1195# 1196# Arguments: 1197# w The treectrl widget. 1198# item Item to move from, typically the active item. 1199# n +1 to move down, -1 to move up. 1200 1201proc ::TreeCtrl::UpDown {w item n} { 1202 variable Priv 1203 set rnc [$w item rnc $item] 1204 if {$rnc eq ""} { 1205 return [$w item id {first visible state enabled}] 1206 } 1207 scan $rnc "%d %d" row col 1208 set Priv(keyNav,row,$w) [expr {$row + $n}] 1209 if {![info exists Priv(keyNav,rnc,$w)] || $rnc ne $Priv(keyNav,rnc,$w)} { 1210 set Priv(keyNav,col,$w) $col 1211 } 1212 set item2 [$w item id "rnc $Priv(keyNav,row,$w) $Priv(keyNav,col,$w)"] 1213 if {[$w item compare $item == $item2]} { 1214 set Priv(keyNav,row,$w) $row 1215 if {![$w item enabled $item2]} { 1216 return "" 1217 } 1218 } else { 1219 set Priv(keyNav,rnc,$w) [$w item rnc $item2] 1220 if {![$w item enabled $item2]} { 1221 return [UpDown $w $item2 $n] 1222 } 1223 } 1224 return $item2 1225} 1226 1227# ::TreeCtrl::LeftRight -- 1228# 1229# Returns the id of an item left or right of the given item that the active 1230# item could be set to. If the given item isn't visible, the first visible 1231# enabled item is returned. An attempt is made to choose an item in the 1232# same row over repeat calls; this gives a better result if some columns 1233# have less items than others. Only enabled items are considered. 1234# 1235# Arguments: 1236# w The treectrl widget. 1237# item Item to move from, typically the active item. 1238# n +1 to move right, -1 to move left. 1239 1240proc ::TreeCtrl::LeftRight {w item n} { 1241 variable Priv 1242 set rnc [$w item rnc $item] 1243 if {$rnc eq ""} { 1244 return [$w item id {first visible state enabled}] 1245 } 1246 scan $rnc "%d %d" row col 1247 set Priv(keyNav,col,$w) [expr {$col + $n}] 1248 if {![info exists Priv(keyNav,rnc,$w)] || $rnc ne $Priv(keyNav,rnc,$w)} { 1249 set Priv(keyNav,row,$w) $row 1250 } 1251 set item2 [$w item id "rnc $Priv(keyNav,row,$w) $Priv(keyNav,col,$w)"] 1252 if {[$w item compare $item == $item2]} { 1253 set Priv(keyNav,col,$w) $col 1254 if {![$w item enabled $item2]} { 1255 return "" 1256 } 1257 } else { 1258 set Priv(keyNav,rnc,$w) [$w item rnc $item2] 1259 if {![$w item enabled $item2]} { 1260 return [LeftRight $w $item2 $n] 1261 } 1262 } 1263 return $item2 1264} 1265 1266# ::TreeCtrl::SetActiveItem -- 1267# 1268# Sets the active item, scrolls it into view, and makes it the only selected 1269# item. If -selectmode is extended, makes the active item the anchor of any 1270# future extended selection. 1271# 1272# Arguments: 1273# w The treectrl widget. 1274# item The new active item, or "". 1275 1276proc ::TreeCtrl::SetActiveItem {w item} { 1277 if {$item eq ""} return 1278 $w activate $item 1279 $w see active 1280 $w selection modify active all 1281 switch [$w cget -selectmode] { 1282 extended { 1283 $w selection anchor active 1284 set Priv(prev) [$w item id active] 1285 set Priv(selection) {} 1286 } 1287 } 1288 return 1289} 1290 1291# ::TreeCtrl::Extend -- 1292# 1293# Does nothing unless we're in extended selection mode; in this 1294# case it moves the location cursor (active item) up, down, left or 1295# right, and extends the selection to that point. 1296# 1297# Arguments: 1298# w The treectrl widget. 1299# dir up, down, left or right 1300 1301proc ::TreeCtrl::Extend {w dir} { 1302 variable Priv 1303 if {[string compare [$w cget -selectmode] "extended"]} { 1304 return 1305 } 1306 if {![info exists Priv(selection)]} { 1307 $w selection add active 1308 set Priv(selection) [$w selection get] 1309 } 1310 switch -- $dir { 1311 above { set item [UpDown $w active -1] } 1312 below { set item [UpDown $w active 1] } 1313 left { set item [LeftRight $w active -1] } 1314 right { set item [LeftRight $w active 1] } 1315 } 1316 if {$item eq ""} return 1317 $w activate $item 1318 $w see active 1319 SelectionMotion $w [$w item id active] 1320 return 1321} 1322 1323# ::TreeCtrl::DataExtend 1324# 1325# This procedure is called for key-presses such as Shift-KEndData. 1326# If the selection mode isn't multiple or extended then it does nothing. 1327# Otherwise it moves the active item and, if we're in 1328# extended mode, extends the selection to that point. 1329# 1330# Arguments: 1331# w The treectrl widget. 1332# item Item to become new active item. 1333 1334proc ::TreeCtrl::DataExtend {w item} { 1335 if {$item eq ""} return 1336 set mode [$w cget -selectmode] 1337 if {[string equal $mode "extended"]} { 1338 $w activate $item 1339 $w see $item 1340 if {[$w selection includes anchor]} { 1341 SelectionMotion $w $item 1342 } 1343 } elseif {[string equal $mode "multiple"]} { 1344 $w activate $item 1345 $w see $item 1346 } 1347 return 1348} 1349 1350# ::TreeCtrl::Cancel 1351# 1352# This procedure is invoked to cancel an extended selection in 1353# progress. If there is an extended selection in progress, it 1354# restores all of the items between the active one and the anchor 1355# to their previous selection state. 1356# 1357# Arguments: 1358# w The treectrl widget. 1359 1360proc ::TreeCtrl::Cancel w { 1361 variable Priv 1362 if {[string compare [$w cget -selectmode] "extended"]} { 1363 return 1364 } 1365 set first [$w item id anchor] 1366 set last $Priv(prev) 1367 if { [string equal $last ""] } { 1368 # Not actually doing any selection right now 1369 return 1370 } 1371 if {[$w item compare $first > $last]} { 1372 set tmp $first 1373 set first $last 1374 set last $tmp 1375 } 1376 $w selection clear $first $last 1377 while {[$w item compare $first <= $last]} { 1378 if {[lsearch $Priv(selection) $first] >= 0} { 1379 $w selection add $first 1380 } 1381 set first [$w item id "$first next visible"] 1382 } 1383 return 1384} 1385 1386# ::TreeCtrl::SelectAll 1387# 1388# This procedure is invoked to handle the "select all" operation. 1389# For single and browse mode, it just selects the active item. 1390# Otherwise it selects everything in the widget. 1391# 1392# Arguments: 1393# w The treectrl widget. 1394 1395proc ::TreeCtrl::SelectAll w { 1396 set mode [$w cget -selectmode] 1397 if {[string equal $mode "single"] || [string equal $mode "browse"]} { 1398 $w selection modify active all 1399 } else { 1400 $w selection add all 1401 } 1402 return 1403} 1404 1405# ::TreeCtrl::MarqueeBegin -- 1406# 1407# Shows the selection rectangle at the given coords. 1408# 1409# Arguments: 1410# w The treectrl widget. 1411# x Window coord of pointer. 1412# y Window coord of pointer. 1413 1414proc ::TreeCtrl::MarqueeBegin {w x y} { 1415 set x [$w canvasx $x] 1416 set y [$w canvasy $y] 1417 $w marquee coords $x $y $x $y 1418 $w marquee configure -visible yes 1419 return 1420} 1421 1422# ::TreeCtrl::MarqueeUpdate -- 1423# 1424# Resizes the selection rectangle. 1425# 1426# Arguments: 1427# w The treectrl widget. 1428# x Window coord of pointer. 1429# y Window coord of pointer. 1430 1431proc ::TreeCtrl::MarqueeUpdate {w x y} { 1432 set x [$w canvasx $x] 1433 set y [$w canvasy $y] 1434 $w marquee corner $x $y 1435 return 1436} 1437 1438# ::TreeCtrl::MarqueeEnd -- 1439# 1440# Hides the selection rectangle. 1441# 1442# Arguments: 1443# w The treectrl widget. 1444# x Window coord of pointer. 1445# y Window coord of pointer. 1446 1447proc ::TreeCtrl::MarqueeEnd {w x y} { 1448 $w marquee configure -visible no 1449 return 1450} 1451 1452# ::TreeCtrl::ScanMark -- 1453# 1454# Marks the start of a possible scan drag operation. 1455# 1456# Arguments: 1457# w The treectrl widget. 1458# x Window coord of pointer. 1459# y Window coord of pointer. 1460 1461proc ::TreeCtrl::ScanMark {w x y} { 1462 variable Priv 1463 $w scan mark $x $y 1464 set Priv(x) $x 1465 set Priv(y) $y 1466 set Priv(mouseMoved) 0 1467 return 1468} 1469 1470# ::TreeCtrl::ScanDrag -- 1471# 1472# Performs a scan drag if the mouse moved. 1473# 1474# Arguments: 1475# w The treectrl widget. 1476# x Window coord of pointer. 1477# y Window coord of pointer. 1478 1479proc ::TreeCtrl::ScanDrag {w x y} { 1480 variable Priv 1481 if {![info exists Priv(x)]} { set Priv(x) $x } 1482 if {![info exists Priv(y)]} { set Priv(y) $y } 1483 if {($x != $Priv(x)) || ($y != $Priv(y))} { 1484 set Priv(mouseMoved) 1 1485 } 1486 if {[info exists Priv(mouseMoved)] && $Priv(mouseMoved)} { 1487 $w scan dragto $x $y 1488 } 1489 return 1490} 1491 1492# ::TreeCtrl::TryEvent -- 1493# 1494# This procedure is used to cause a treectrl to generate a dynamic event. 1495# If the treectrl doesn't have the event defined (because you didn't call 1496# the [notify install] command) nothing happens. TreeCtrl::PercentsCmd is 1497# used to perform %-substitution on any scripts bound to the event. 1498# 1499# Arguments: 1500# T The treectrl widget. 1501# event Name of event. 1502# detail Name of detail or "". 1503# charMap %-char substitution list (even number of elements). 1504 1505proc ::TreeCtrl::TryEvent {T event detail charMap} { 1506 if {[lsearch -exact [$T notify eventnames] $event] == -1} return 1507 if {$detail ne ""} { 1508 if {[lsearch -exact [$T notify detailnames $event] $detail] == -1} return 1509 $T notify generate <$event-$detail> $charMap "::TreeCtrl::PercentsCmd $T" 1510 } else { 1511 $T notify generate <$event> $charMap "::TreeCtrl::PercentsCmd $T" 1512 } 1513 return 1514} 1515 1516# ::TreeCtrl::PercentsCmd -- 1517# 1518# This command is passed to [notify generate] to perform %-substitution on 1519# scripts bound to dynamic events. It supports the same set of substitution 1520# characters as the built-in static events (plus any event-specific chars). 1521# 1522# Arguments: 1523# T The treectrl widget. 1524# char %-char to be replaced in bound scripts. 1525# object Same arg passed to [notify bind]. 1526# event Name of event. 1527# detail Name of detail or "". 1528# charMap %-char substitution list (even number of elements). 1529 1530proc ::TreeCtrl::PercentsCmd {T char object event detail charMap} { 1531 if {$detail ne ""} { 1532 set pattern <$event-$detail> 1533 } else { 1534 set pattern <$event> 1535 } 1536 switch -- $char { 1537 d { return $detail } 1538 e { return $event } 1539 P { return $pattern } 1540 W { return $object } 1541 T { return $T } 1542 ? { 1543 array set map $charMap 1544 array set map [list T $T W $object P $pattern e $event d $detail] 1545 return [array get map] 1546 } 1547 default { 1548 array set map [list $char $char] 1549 array set map $charMap 1550 return $map($char) 1551 } 1552 } 1553 return 1554} 1555 1556namespace eval TreeCtrl { 1557catch { 1558 foreach theme [ttk::style theme names] { 1559 ttk::style theme settings $theme { 1560 ttk::style configure TreeCtrlHeading -relief raised -font TkHeadingFont 1561 ttk::style map TreeCtrlHeading -relief { 1562 pressed sunken 1563 } 1564 } 1565 } 1566} 1567} 1568