summaryrefslogtreecommitdiffstats
path: root/library
diff options
context:
space:
mode:
authortreectrl <treectrl>2002-12-17 05:04:00 (GMT)
committertreectrl <treectrl>2002-12-17 05:04:00 (GMT)
commit51219bf94e57870b142db498f63180828d6990d9 (patch)
tree2aaef21ae17c7dc8591f1fdf095fb4fbeeef8197 /library
downloadtktreectrl-51219bf94e57870b142db498f63180828d6990d9.zip
tktreectrl-51219bf94e57870b142db498f63180828d6990d9.tar.gz
tktreectrl-51219bf94e57870b142db498f63180828d6990d9.tar.bz2
Initial revision
Diffstat (limited to 'library')
-rw-r--r--library/filelist-bindings.tcl788
-rw-r--r--library/treectrl.tcl825
2 files changed, 1613 insertions, 0 deletions
diff --git a/library/filelist-bindings.tcl b/library/filelist-bindings.tcl
new file mode 100644
index 0000000..f58ef82
--- /dev/null
+++ b/library/filelist-bindings.tcl
@@ -0,0 +1,788 @@
+bind TreeCtrlFileList <Double-ButtonPress-1> {
+ TreeCtrl::FileListEditCancel %W
+ TreeCtrl::DoubleButton1 %W %x %y
+}
+bind TreeCtrlFileList <Control-ButtonPress-1> {
+ set TreeCtrl::Priv(selectMode) toggle
+ TreeCtrl::FileListButton1 %W %x %y
+ break
+}
+bind TreeCtrlFileList <Shift-ButtonPress-1> {
+ set TreeCtrl::Priv(selectMode) add
+ TreeCtrl::FileListButton1 %W %x %y
+ break
+}
+bind TreeCtrlFileList <ButtonPress-1> {
+ set TreeCtrl::Priv(selectMode) set
+ TreeCtrl::FileListButton1 %W %x %y
+ break
+}
+bind TreeCtrlFileList <Button1-Motion> {
+ TreeCtrl::FileListMotion1 %W %x %y
+ break
+}
+bind TreeCtrlFileList <Button1-Leave> {
+ TreeCtrl::FileListLeave1 %W %x %y
+ break
+}
+bind TreeCtrlFileList <ButtonRelease-1> {
+ TreeCtrl::FileListRelease1 %W %x %y
+ break
+}
+
+proc TreeCtrl::FileListButton1 {T x y} {
+ variable Priv
+ focus $T
+ set id [$T identify $x $y]
+ set marquee 0
+ set Priv(buttonMode) ""
+ FileListEditCancel $T
+ # Click outside any item
+ if {$id eq ""} {
+ set marquee 1
+
+ # Click in header
+ } elseif {[lindex $id 0] eq "header"} {
+ ButtonPress1 $T $x $y
+
+ # Click in item
+ } else {
+ foreach {where item arg1 arg2 arg3 arg4} $id {}
+ switch $arg1 {
+ button -
+ line {
+ ButtonPress1 $T $x $y
+ }
+ column {
+ # Clicked in column zero
+ if {$arg2 eq 0} {
+ set ok 0
+ # Clicked an element
+ if {[llength $id] == 6} {
+ set E [lindex $id 5]
+ if {[lsearch -exact $Priv(sensitive,$T) $E] != -1} {
+ set ok 1
+ }
+ }
+ if {$ok} {
+ set Priv(drag,motion) 0
+ set Priv(drag,x) [$T canvasx $x]
+ set Priv(drag,y) [$T canvasy $y]
+ set Priv(drop) ""
+ set Priv(drag,wasSel) [$T selection includes $item]
+ set Priv(drag,E) $E
+ $T activate $item
+ if {$Priv(selectMode) eq "add"} {
+ BeginExtend $T $item
+ } elseif {$Priv(selectMode) eq "toggle"} {
+ BeginToggle $T $item
+ } elseif {![$T selection includes $item]} {
+ BeginSelect $T $item
+ }
+
+ # Changing the selection might change the list
+ if {[$T index $item] eq ""} return
+
+ # Click selected item to drag
+ if {[$T selection includes $item]} {
+ set Priv(buttonMode) drag
+ }
+ # Clicked inside item, but outside elements
+ } else {
+ set marquee 1
+ }
+ # Clicked column > 0
+ } else {
+ set marquee 1
+ }
+ }
+ }
+ }
+ if {$marquee} {
+ set Priv(buttonMode) marquee
+ if {$Priv(selectMode) ne "set"} {
+ set Priv(selection) [$T selection get]
+ } else {
+ $T selection clear
+ set Priv(selection) {}
+ }
+ MarqueeBegin $T $x $y
+ }
+ return
+}
+proc TreeCtrl::FileListMotion1 {T x y} {
+ variable Priv
+ switch $Priv(buttonMode) {
+ "resize" -
+ "header" {
+ Motion1 $T $x $y
+ }
+ "drag" -
+ "marquee" {
+ FileListAutoScanCheck $T $x $y
+ FileListMotion $T $x $y
+ }
+ }
+}
+proc TreeCtrl::FileListMotion {T x y} {
+ variable Priv
+ switch $Priv(buttonMode) {
+ "resize" -
+ "header" {
+ Motion1 $T $x $y
+ }
+ "marquee" {
+ MarqueeUpdate $T $x $y
+ set select $Priv(selection)
+ set deselect {}
+
+ # Check items covered by the marquee
+ foreach list [$T marque identify] {
+ set item [lindex $list 0]
+
+ # Check covered columns in this item
+ foreach sublist [lrange $list 1 end] {
+ set column [lindex $sublist 0]
+ set ok 0
+ foreach E [lrange $sublist 1 end] {
+ if {[lsearch -exact $Priv(sensitive,$T) $E] != -1} {
+ set ok 1
+ break
+ }
+ }
+ # Some elements in column zero are covered
+ if {($column == 0) && $ok} {
+
+ # Toggle selected status
+ if {$Priv(selectMode) eq "toggle"} {
+ set i [lsearch -exact $Priv(selection) $item]
+ if {$i == -1} {
+ lappend select $item
+ } else {
+ set i [lsearch -exact $select $item]
+ set select [lreplace $select $i $i]
+ }
+ } else {
+ lappend select $item
+ }
+ }
+ break
+ }
+ }
+ $T selection modify $select all
+ }
+ "drag" {
+ # Detect initial mouse movement
+ if {!$Priv(drag,motion)} {
+ set Priv(selection) [$T selection get]
+ set Priv(drop) ""
+ $T dragimage clear
+ # For each selected item, add some elements to the dragimage
+ foreach I $Priv(selection) {
+ foreach list $Priv(dragimage,$T) {
+ set C [lindex $list 0]
+ set S [lindex $list 1]
+ if {[$T item style set $I $C] eq $S} {
+ eval $T dragimage add $I $C [lrange $list 2 end]
+ }
+ }
+ }
+ set Priv(drag,motion) 1
+ $T notify generate <Drag-begin> -T $T
+ }
+
+ # Find the element under the cursor
+ set drop ""
+ set id [$T identify $x $y]
+ set ok 0
+ if {($id ne "") && ([lindex $id 0] eq "item") && ([llength $id] == 6)} {
+ set E [lindex $id 5]
+ if {[lsearch -exact $Priv(sensitive,$T) $E] != -1} {
+ set ok 1
+ }
+ }
+ if {$ok} {
+ set item [lindex $id 1]
+ set column [lindex $id 3]
+ if {$column == 0} {
+ # If the item is not in the pre-drag selection
+ # (i.e. not being dragged) and it is a directory,
+ # see if we can drop on it
+ if {[lsearch -exact $Priv(selection) $item] == -1} {
+ if {[lindex [$T item index $item] 1] < $Priv(DirCnt,$T)} {
+ set drop $item
+ # We can drop if dragged item isn't an ancestor
+ foreach item2 $Priv(selection) {
+ if {[$T item isancestor $item2 $item]} {
+ set drop ""
+ break
+ }
+ }
+ }
+ }
+ }
+ }
+
+ # Select the directory under the cursor (if any) and deselect
+ # the previous drop-directory (if any)
+ $T selection modify $drop $Priv(drop)
+ set Priv(drop) $drop
+
+ # Show the dragimage in its new position
+ set x [expr {[$T canvasx $x] - $Priv(drag,x)}]
+ set y [expr {[$T canvasy $y] - $Priv(drag,y)}]
+ $T dragimage offset $x $y
+ $T dragimage visible yes
+ }
+ }
+ return
+}
+proc TreeCtrl::FileListLeave1 {T x y} {
+ variable Priv
+# This gets called when I click the mouse on Unix, and buttonMode is unset
+if {![info exists Priv(buttonMode)]} return
+ switch $Priv(buttonMode) {
+ "header" {
+ Leave1 $T $x $y
+ }
+ }
+ return
+}
+proc TreeCtrl::FileListRelease1 {T x y} {
+ variable Priv
+ switch $Priv(buttonMode) {
+ "resize" -
+ "header" {
+ Release1 $T $x $y
+ }
+ "marquee" {
+ AutoScanCancel $T
+ MarqueeEnd $T $x $y
+ }
+ "drag" {
+ AutoScanCancel $T
+
+ # Some dragging occurred
+ if {$Priv(drag,motion)} {
+ $T dragimage visible no
+ if {$Priv(drop) ne ""} {
+ $T selection modify {} $Priv(drop)
+ $T notify generate <Drag-receive> -T $T -I $Priv(drop) \
+ -l $Priv(selection)
+ }
+ $T notify generate <Drag-end> -T $T
+
+ } elseif {$Priv(selectMode) eq "toggle"} {
+ # don't rename
+
+ # Clicked/released a selected item, but didn't drag
+ } elseif {$Priv(drag,wasSel)} {
+ set I [$T index active]
+ set E $Priv(drag,E)
+ set S [$T item style set $I 0]
+ if {[lsearch -exact $Priv(edit,$T) $E] != -1} {
+ FileListEditCancel $T
+ set Priv(editId,$T) [after 900 [list ::TreeCtrl::FileListEdit $T $I $S $E]]
+ }
+ }
+ }
+ }
+ set Priv(buttonMode) ""
+ return
+}
+proc TreeCtrl::FileListEdit {T I S E} {
+ variable Priv
+ array unset Priv editId,$T
+ set lines [$T item element cget $I 0 $E -lines]
+ if {$lines eq ""} {
+ set lines [$T element cget $E -lines]
+ }
+
+ # Scroll item into view
+ $T see $I ; update
+
+ # Multi-line edit
+ if {$lines ne "1"} {
+ scan [$T item bbox $I 0] "%d %d %d %d" x1 y1 x2 y2
+ set padw [$T style layout $S $E -padw]
+ set pade [$T style layout $S $E -pade]
+ TextExpanderOpen $T $I 0 $E [expr {$x2 - $x1 - $padw - $pade}]
+
+ # Single-line edit
+ } else {
+ EntryExpanderOpen $T $I 0 $E
+ }
+ return
+}
+proc TreeCtrl::FileListEditCancel {T} {
+ variable Priv
+ if {[info exists Priv(editId,$T)]} {
+ after cancel $Priv(editId,$T)
+ array unset Priv editId,$T
+ }
+ return
+}
+
+# Same as TreeCtrl::AutoScanCheck, but calls FileListMotion and
+# FileListAutoScanCheckAux
+proc TreeCtrl::FileListAutoScanCheck {T x y} {
+ variable Priv
+ scan [$T contentbox] "%d %d %d %d" x1 y1 x2 y2
+ set margin [winfo pixels $T [$T cget -scrollmargin]]
+ if {($x < $x1 + $margin) || ($x >= $x2 - $margin) ||
+ ($y < $y1 + $margin) || ($y >= $y2 - $margin)} {
+ if {![info exists Priv(autoscan,afterId,$T)]} {
+ if {$y >= $y2 - $margin} {
+ $T yview scroll 1 units
+ set delay [$T cget -yscrolldelay]
+ } elseif {$y < $y1 + $margin} {
+ $T yview scroll -1 units
+ set delay [$T cget -yscrolldelay]
+ } elseif {$x >= $x2 - $margin} {
+ $T xview scroll 1 units
+ set delay [$T cget -xscrolldelay]
+ } elseif {$x < $x1 + $margin} {
+ $T xview scroll -1 units
+ set delay [$T cget -xscrolldelay]
+ }
+ set count [scan $delay "%d %d" d1 d2]
+ if {[info exists Priv(autoscan,scanning,$T)]} {
+ if {$count == 2} {
+ set delay $d2
+ }
+ } else {
+ if {$count == 2} {
+ set delay $d1
+ }
+ set Priv(autoscan,scanning,$T) 1
+ }
+ switch $Priv(buttonMode) {
+ "drag" -
+ "marquee" {
+ FileListMotion $T $x $y
+ }
+ }
+ set Priv(autoscan,afterId,$T) [after $delay [list TreeCtrl::FileListAutoScanCheckAux $T]]
+ }
+ return
+ }
+ AutoScanCancel $T
+ return
+}
+
+proc ::TreeCtrl::FileListAutoScanCheckAux {T} {
+ variable Priv
+ unset Priv(autoscan,afterId,$T)
+ set x [winfo pointerx $T]
+ set y [winfo pointery $T]
+ set x [expr {$x - [winfo rootx $T]}]
+ set y [expr {$y - [winfo rooty $T]}]
+ FileListAutoScanCheck $T $x $y
+ return
+}
+
+proc ::TreeCtrl::EntryOpen {T item column element} {
+
+ variable Priv
+
+ set Priv(entry,$T,item) $item
+ set Priv(entry,$T,column) $column
+ set Priv(entry,$T,element) $element
+ set Priv(entry,$T,focus) [focus]
+
+ # Get window coords of the Element
+ scan [$T item bbox $item $column $element] "%d %d" x y
+
+ # Get the font used by the Element
+ set font [$T item element actual $item $column $element -font]
+
+ # Get the text used by the Element. Could check master Element too.
+ set text [$T item element cget $item $column $element -text]
+
+ # Create the Entry widget if needed
+ if {[winfo exists $T.entry]} {
+ $T.entry delete 0 end
+ } else {
+ entry $T.entry -borderwidth 1 -highlightthickness 0 -relief solid
+
+ # Accept edit when we lose the focus
+ bind $T.entry <FocusOut> {
+ if {[winfo ismapped %W]} {
+ TreeCtrl::EntryClose [winfo parent %W] 1
+ }
+ }
+
+ # Accept edit on <Return>
+ bind $T.entry <KeyPress-Return> {
+ TreeCtrl::EntryClose [winfo parent %W] 1
+ focus $TreeCtrl::Priv(entry,[winfo parent %W],focus)
+ }
+
+ # Cancel edit on <Escape>
+ bind $T.entry <KeyPress-Escape> {
+ TreeCtrl::EntryClose [winfo parent %W] 0
+ focus $TreeCtrl::Priv(entry,[winfo parent %W],focus)
+ }
+ }
+
+ # Pesky MouseWheel
+ $T notify bind $T.entry <Scroll> {
+ TreeCtrl::EntryClose %T 0
+ focus $TreeCtrl::Priv(entry,%T,focus)
+ }
+
+ $T.entry configure -font $font
+ $T.entry insert end $text
+ $T.entry selection range 0 end
+
+ set ebw [$T.entry cget -borderwidth]
+ if 1 {
+ set ex [expr {$x - $ebw - 1}]
+ place $T.entry -x $ex -y [expr {$y - $ebw - 1}] \
+ -bordermode outside
+ } else {
+ set hw [$T cget -highlightthickness]
+ set bw [$T cget -borderwidth]
+ set ex [expr {$x - $bw - $hw - $ebw - 1}]
+ place $T.entry -x $ex -y [expr {$y - $bw - $hw - $ebw - 1}]
+ }
+
+ # Make the Entry as wide as the text plus "W" but keep it within the
+ # TreeCtrl borders
+ set width [font measure $font ${text}W]
+ set width [expr {$width + ($ebw + 1) * 2}]
+ scan [$T contentbox] "%d %d %d %d" left top right bottom
+ if {$ex + $width > $right} {
+ set width [expr {$right - $ex}]
+ }
+ scan [$T item bbox $item $column] "%d %d %d %d" left top right bottom
+ if {$ex + $width > $right} {
+ set width [expr {$right - $ex}]
+ }
+ place configure $T.entry -width $width
+
+ focus $T.entry
+
+ return
+}
+
+# Like EntryOpen, but Entry widget expands/shrinks during typing
+proc ::TreeCtrl::EntryExpanderOpen {T item column element} {
+
+ variable Priv
+
+ set Priv(entry,$T,item) $item
+ set Priv(entry,$T,column) $column
+ set Priv(entry,$T,element) $element
+ set Priv(entry,$T,focus) [focus]
+
+ # Get window coords of the Element
+ scan [$T item bbox $item $column $element] "%d %d" x y
+
+ # Get the font used by the Element
+ set font [$T item element actual $item $column $element -font]
+
+ set Priv(entry,$T,font) $font
+
+ # Get the text used by the Element. Could check master Element too.
+ set text [$T item element cget $item $column $element -text]
+
+ # Create the Entry widget if needed
+ if {[winfo exists $T.entry]} {
+ $T.entry delete 0 end
+ } else {
+ entry $T.entry -borderwidth 1 -highlightthickness 0 \
+ -selectborderwidth 0 -relief solid
+
+ # Accept edit when we lose the focus
+ bind $T.entry <FocusOut> {
+ if {[winfo ismapped %W]} {
+ TreeCtrl::EntryClose [winfo parent %W] 1
+ }
+ }
+
+ # Accept edit on <Return>
+ bind $T.entry <KeyPress-Return> {
+ TreeCtrl::EntryClose [winfo parent %W] 1
+ focus $TreeCtrl::Priv(entry,[winfo parent %W],focus)
+ }
+
+ # Cancel edit on <Escape>
+ bind $T.entry <KeyPress-Escape> {
+ TreeCtrl::EntryClose [winfo parent %W] 0
+ focus $TreeCtrl::Priv(entry,[winfo parent %W],focus)
+ }
+
+ # Resize as user types
+ bind $T.entry <KeyPress> {
+ after idle TreeCtrl::EntryExpanderKeypress [winfo parent %W]
+ }
+ }
+
+ # Pesky MouseWheel
+ $T notify bind $T.entry <Scroll> {
+ TreeCtrl::EntryClose %T 0
+ focus $TreeCtrl::Priv(entry,%T,focus)
+ }
+
+ $T.entry configure -font $font -background [$T cget -background]
+ $T.entry insert end $text
+ $T.entry selection range 0 end
+
+ set ebw [$T.entry cget -borderwidth]
+ set ex [expr {$x - $ebw - 1}]
+ place $T.entry -x $ex -y [expr {$y - $ebw - 1}] \
+ -bordermode outside
+
+ # Make the Entry as wide as the text plus "W" but keep it within the
+ # TreeCtrl borders
+ set width [font measure $font ${text}W]
+ set width [expr {$width + ($ebw + 1) * 2}]
+ scan [$T contentbox] "%d %d %d %d" left top right bottom
+ if {$ex + $width > $right} {
+ set width [expr {$right - $ex}]
+ }
+ place configure $T.entry -width $width
+
+ focus $T.entry
+
+ return
+}
+
+proc ::TreeCtrl::EntryClose {T accept} {
+
+ variable Priv
+
+ place forget $T.entry
+ update
+
+ if {$accept} {
+ $T notify generate <Edit-accept> -T $T -I $Priv(entry,$T,item) \
+ -C $Priv(entry,$T,column) -E $Priv(entry,$T,element) \
+ -t [$T.entry get]
+ }
+
+ $T notify bind $T.entry <Scroll> {}
+
+ return
+}
+
+proc ::TreeCtrl::EntryExpanderKeypress {T} {
+
+ variable Priv
+
+ set font $Priv(entry,$T,font)
+ set text [$T.entry get]
+ set ebw [$T.entry cget -borderwidth]
+ set ex [winfo x $T.entry]
+
+ set width [font measure $font ${text}W]
+ set width [expr {$width + ($ebw + 1) * 2}]
+
+ scan [$T contentbox] "%d %d %d %d" left top right bottom
+ if {$ex + $width > $right} {
+ set width [expr {$right - $ex}]
+ }
+
+ place configure $T.entry -width $width
+
+ return
+}
+
+proc ::TreeCtrl::TextOpen {T item column element {width 0} {height 0}} {
+
+ variable Priv
+
+ set Priv(text,$T,item) $item
+ set Priv(text,$T,column) $column
+ set Priv(text,$T,element) $element
+ set Priv(text,$T,focus) [focus]
+
+ # Get window coords of the Element
+ scan [$T item bbox $item $column $element] "%d %d %d %d" x1 y1 x2 y2
+
+ # Get the font used by the Element
+ set font [$T item element actual $item $column $element -font]
+
+ # Get the text used by the Element. Could check master Element too.
+ set text [$T item element cget $item $column $element -text]
+
+ # Create the Text widget if needed
+ if {[winfo exists $T.text]} {
+ $T.text delete 1.0 end
+ } else {
+ text $T.text -borderwidth 1 -highlightthickness 0 -relief solid
+
+ # Accept edit when we lose the focus
+ bind $T.text <FocusOut> {
+ if {[winfo ismapped %W]} {
+ TreeCtrl::TextClose [winfo parent %W] 1
+ }
+ }
+
+ # Accept edit on <Return>
+ bind $T.text <KeyPress-Return> {
+ TreeCtrl::TextClose [winfo parent %W] 1
+ focus $TreeCtrl::Priv(text,[winfo parent %W],focus)
+ break
+ }
+
+ # Cancel edit on <Escape>
+ bind $T.text <KeyPress-Escape> {
+ TreeCtrl::TextClose [winfo parent %W] 0
+ focus $TreeCtrl::Priv(text,[winfo parent %W],focus)
+ }
+ }
+
+ # Pesky MouseWheel
+ $T notify bind $T.text <Scroll> {
+ TreeCtrl::TextClose %T 0
+ focus $TreeCtrl::Priv(text,%T,focus)
+ }
+
+ $T.text tag configure TAG -justify [$T element cget $element -justify]
+ $T.text configure -font $font
+ $T.text insert end $text
+ $T.text tag add sel 1.0 end
+ $T.text tag add TAG 1.0 end
+
+ set tbw [$T.text cget -borderwidth]
+ set tx [expr {$x1 - $tbw - 1}]
+ place $T.text -x $tx -y [expr {$y1 - $tbw - 1}] \
+ -width [expr {$x2 - $x1 + ($tbw + 1) * 2}] \
+ -height [expr {$y2 - $y1 + ($tbw + 1) * 2}] \
+ -bordermode outside
+
+ focus $T.text
+
+ return
+}
+
+# Like TextOpen, but Text widget expands/shrinks during typing
+proc ::TreeCtrl::TextExpanderOpen {T item column element width} {
+
+ variable Priv
+
+ set Priv(text,$T,item) $item
+ set Priv(text,$T,column) $column
+ set Priv(text,$T,element) $element
+ set Priv(text,$T,focus) [focus]
+
+ # Get window coords of the Element
+ scan [$T item bbox $item $column $element] "%d %d %d %d" x1 y1 x2 y2
+
+ set Priv(text,$T,center) [expr {$x1 + ($x2 - $x1) / 2}]
+
+ # Get the font used by the Element
+ set font [$T item element actual $item $column $element -font]
+
+ # Get the text used by the Element. Could check master Element too.
+ set text [$T item element cget $item $column $element -text]
+
+ set justify [$T element cget $element -justify]
+
+ # Create the Text widget if needed
+ if {[winfo exists $T.text]} {
+ $T.text delete 1.0 end
+ } else {
+ text $T.text -borderwidth 1 -highlightthickness 0 \
+ -selectborderwidth 0 -relief solid
+
+ # Accept edit when we lose the focus
+ bind $T.text <FocusOut> {
+ if {[winfo ismapped %W]} {
+ TreeCtrl::TextClose [winfo parent %W] 1
+ }
+ }
+
+ # Accept edit on <Return>
+ bind $T.text <KeyPress-Return> {
+ TreeCtrl::TextClose [winfo parent %W] 1
+ focus $TreeCtrl::Priv(text,[winfo parent %W],focus)
+ break
+ }
+
+ # Cancel edit on <Escape>
+ bind $T.text <KeyPress-Escape> {
+ TreeCtrl::TextClose [winfo parent %W] 0
+ focus $TreeCtrl::Priv(text,[winfo parent %W],focus)
+ }
+
+ # Resize as user types
+ bind $T.text <KeyPress> {
+ after idle TreeCtrl::TextExpanderKeypress [winfo parent %W]
+ }
+ }
+
+ # Pesky MouseWheel
+ $T notify bind $T.text <Scroll> {
+ TreeCtrl::TextClose %T 0
+ focus $TreeCtrl::Priv(text,%T,focus)
+ }
+
+ $T.text tag configure TAG -justify $justify
+ $T.text configure -font $font -background [$T cget -background]
+ $T.text insert end $text
+ $T.text tag add sel 1.0 end
+ $T.text tag add TAG 1.0 end
+
+ set Priv(text,$T,font) $font
+ set Priv(text,$T,justify) $justify
+ set Priv(text,$T,width) $width
+
+ scan [textlayout $font $text -justify $justify -width $width] "%d %d" width height
+
+ set tbw [$T.text cget -borderwidth]
+ set tx [expr {$x1 - $tbw - 1}]
+ place $T.text -x $tx -y [expr {$y1 - $tbw - 1}] \
+ -width [expr {$width + ($tbw + 1) * 2}] \
+ -height [expr {$height + ($tbw + 1) * 2}] \
+ -bordermode outside
+
+ focus $T.text
+
+ return
+}
+
+proc ::TreeCtrl::TextClose {T accept} {
+
+ variable Priv
+
+ place forget $T.text
+ update
+
+ if {$accept} {
+ $T notify generate <Edit-accept> -T $T -I $Priv(text,$T,item) \
+ -C $Priv(text,$T,column) -E $Priv(text,$T,element) \
+ -t [$T.text get 1.0 end-1c]
+ }
+
+ $T notify bind $T.text <Scroll> {}
+
+ return
+}
+
+proc ::TreeCtrl::TextExpanderKeypress {T} {
+
+ variable Priv
+
+ set font $Priv(text,$T,font)
+ set justify $Priv(text,$T,justify)
+ set width $Priv(text,$T,width)
+ set center $Priv(text,$T,center)
+
+ set text [$T.text get 1.0 end-1c]
+
+ scan [textlayout $font $text -justify $justify -width $width] "%d %d" width height
+
+ set tbw [$T.text cget -borderwidth]
+ place configure $T.text \
+ -x [expr {$center - $width / 2 - $tbw - 1}] \
+ -width [expr {$width + ($tbw + 1) * 2}] \
+ -height [expr {$height + ($tbw + 1) * 2}]
+
+ $T.text tag add TAG 1.0 end
+
+ return
+}
+
diff --git a/library/treectrl.tcl b/library/treectrl.tcl
new file mode 100644
index 0000000..c973410
--- /dev/null
+++ b/library/treectrl.tcl
@@ -0,0 +1,825 @@
+bind TreeCtrl <Motion> {
+ TreeCtrl::CursorCheck %W %x %y
+}
+bind TreeCtrl <Leave> {
+ TreeCtrl::CursorCancel %W
+}
+
+bind TreeCtrl <ButtonPress-1> {
+ TreeCtrl::ButtonPress1 %W %x %y
+}
+
+bind TreeCtrl <Double-ButtonPress-1> {
+ TreeCtrl::DoubleButton1 %W %x %y
+}
+
+bind TreeCtrl <Button1-Motion> {
+ TreeCtrl::Motion1 %W %x %y
+}
+bind TreeCtrl <ButtonRelease-1> {
+ TreeCtrl::Release1 %W %x %y
+}
+bind TreeCtrl <Shift-ButtonPress-1> {
+ set TreeCtrl::Priv(buttonMode) normal
+ TreeCtrl::BeginExtend %W [%W index {nearest %x %y}]
+}
+bind TreeCtrl <Control-ButtonPress-1> {
+ set TreeCtrl::Priv(buttonMode) normal
+ TreeCtrl::BeginToggle %W [%W index {nearest %x %y}]
+}
+bind TreeCtrl <Button1-Leave> {
+ TreeCtrl::Leave1 %W %x %y
+}
+bind TreeCtrl <Button1-Enter> {}
+
+bind TreeCtrl <KeyPress-Up> {
+ TreeCtrl::SetActiveItem %W [TreeCtrl::UpDown %W -1]
+}
+bind TreeCtrl <Shift-KeyPress-Up> {
+ TreeCtrl::ExtendUpDown %W above
+}
+bind TreeCtrl <KeyPress-Down> {
+ TreeCtrl::SetActiveItem %W [TreeCtrl::UpDown %W 1]
+}
+bind TreeCtrl <Shift-KeyPress-Down> {
+ TreeCtrl::ExtendUpDown %W below
+}
+bind TreeCtrl <KeyPress-Left> {
+ TreeCtrl::SetActiveItem %W [TreeCtrl::LeftRight %W -1]
+}
+bind TreeCtrl <Shift-KeyPress-Left> {
+ TreeCtrl::ExtendUpDown %W left
+}
+bind TreeCtrl <Control-KeyPress-Left> {
+ %W xview scroll -1 pages
+}
+bind TreeCtrl <KeyPress-Right> {
+ TreeCtrl::SetActiveItem %W [TreeCtrl::LeftRight %W 1]
+}
+bind TreeCtrl <Shift-KeyPress-Right> {
+ TreeCtrl::ExtendUpDown %W right
+}
+bind TreeCtrl <Control-KeyPress-Right> {
+ %W xview scroll 1 pages
+}
+bind TreeCtrl <KeyPress-Prior> {
+ %W yview scroll -1 pages
+ %W activate {nearest 0 0}
+}
+bind TreeCtrl <KeyPress-Next> {
+ %W yview scroll 1 pages
+ %W activate {nearest 0 0}
+}
+bind TreeCtrl <Control-KeyPress-Prior> {
+ %W xview scroll -1 pages
+}
+bind TreeCtrl <Control-KeyPress-Next> {
+ %W xview scroll 1 pages
+}
+bind TreeCtrl <KeyPress-Home> {
+ %W xview moveto 0
+}
+bind TreeCtrl <KeyPress-End> {
+ %W xview moveto 1
+}
+bind TreeCtrl <Control-KeyPress-Home> {
+ %W activate {first visible}
+ %W see active
+ %W selection modify active all
+}
+bind TreeCtrl <Shift-Control-KeyPress-Home> {
+ TreeCtrl::DataExtend %W 0
+}
+bind TreeCtrl <Control-KeyPress-End> {
+ %W activate {last visible}
+ %W see active
+ %W selection modify active all
+}
+bind TreeCtrl <Shift-Control-KeyPress-End> {
+ TreeCtrl::DataExtend %W [%W index {last visible}]
+}
+bind TreeCtrl <<Copy>> {
+ if {[string equal [selection own -displayof %W] "%W"]} {
+ clipboard clear -displayof %W
+ clipboard append -displayof %W [selection get -displayof %W]
+ }
+}
+bind TreeCtrl <KeyPress-space> {
+ TreeCtrl::BeginSelect %W [%W index active]
+}
+bind TreeCtrl <KeyPress-Select> {
+ TreeCtrl::BeginSelect %W [%W index active]
+}
+bind TreeCtrl <Control-Shift-KeyPress-space> {
+ TreeCtrl::BeginExtend %W [%W index active]
+}
+bind TreeCtrl <Shift-KeyPress-Select> {
+ TreeCtrl::BeginExtend %W [%W index active]
+}
+bind TreeCtrl <KeyPress-Escape> {
+ TreeCtrl::Cancel %W
+}
+bind TreeCtrl <Control-KeyPress-slash> {
+ TreeCtrl::SelectAll %W
+}
+bind TreeCtrl <Control-KeyPress-backslash> {
+ if {[string compare [%W cget -selectmode] "browse"]} {
+ %W selection clear
+ }
+}
+
+bind TreeCtrl <KeyPress-plus> {
+ %W expand [%W index active]
+}
+bind TreeCtrl <KeyPress-minus> {
+ %W collapse [%W index active]
+}
+bind TreeCtrl <KeyPress-Return> {
+ %W toggle [%W index active]
+}
+
+
+# Additional Tk bindings that aren't part of the Motif look and feel:
+
+bind TreeCtrl <KeyPress-2> {
+ %W scan mark %x %y
+}
+bind TreeCtrl <Button2-Motion> {
+ %W scan dragto %x %y
+}
+
+# The MouseWheel will typically only fire on Windows. However,
+# someone could use the "event generate" command to produce one
+# on other platforms.
+
+bind TreeCtrl <MouseWheel> {
+ %W yview scroll [expr {- (%D / 120) * 4}] units
+}
+
+if {[string equal "unix" $tcl_platform(platform)]} {
+ # Support for mousewheels on Linux/Unix commonly comes through mapping
+ # the wheel to the extended buttons. If you have a mousewheel, find
+ # Linux configuration info at:
+ # http://www.inria.fr/koala/colas/mouse-wheel-scroll/
+ bind TreeCtrl <4> {
+ if {!$tk_strictMotif} {
+ %W yview scroll -5 units
+ }
+ }
+ bind TreeCtrl <5> {
+ if {!$tk_strictMotif} {
+ %W yview scroll 5 units
+ }
+ }
+}
+
+namespace eval ::TreeCtrl {
+ variable Priv
+ array set Priv {
+ prev {}
+ rnc {}
+ }
+}
+
+proc ::TreeCtrl::CursorCheck {w x y} {
+ variable Priv
+ set id [$w identify $x $y]
+ if {([llength $id] == 3) && ([lindex $id 0] eq "header")} {
+ set column [lindex $id 1]
+ set side [lindex $id 2]
+ set visCount 0
+ for {set i 0} {$i < [$w numcolumns]} {incr i} {
+ if {[$w column cget $i -visible]} {
+ lappend visColumns $i
+ if {$i eq $column} {
+ set columnIndex $visCount
+ }
+ incr visCount
+ }
+ }
+ lappend visColumns tail
+ if {$column eq "tail"} {
+ set columnIndex $visCount
+ }
+ if {$side eq "left"} {
+ if {$column eq [lindex $visColumns 0]} {
+ return
+ }
+ set column [lindex $visColumns [expr {$columnIndex - 1}]]
+ }
+ if {![info exists Priv(cursor,$w)]} {
+ set Priv(cursor,$w) [$w cget -cursor]
+ $w configure -cursor sb_h_double_arrow
+ if {[info exists Priv(cursor,afterId,$w)]} {
+ after cancel $Priv(cursor,afterId,$w)
+ }
+ set Priv(cursor,afterId,$w) [after 150 [list TreeCtrl::CursorCheckAux $w]]
+ }
+ return
+ }
+ CursorCancel $w
+ return
+}
+
+proc ::TreeCtrl::CursorCheckAux {w} {
+ variable Priv
+ set x [winfo pointerx $w]
+ set y [winfo pointery $w]
+ if {[info exists Priv(cursor,$w)]} {
+ set x [expr {$x - [winfo rootx $w]}]
+ set y [expr {$y - [winfo rooty $w]}]
+ CursorCheck $w $x $y
+ }
+ return
+}
+
+proc ::TreeCtrl::CursorCancel {w} {
+ variable Priv
+ if {[info exists Priv(cursor,$w)]} {
+ $w configure -cursor $Priv(cursor,$w)
+ unset Priv(cursor,$w)
+ }
+ if {[info exists Priv(cursor,afterId,$w)]} {
+ after cancel $Priv(cursor,afterId,$w)
+ unset Priv(cursor,afterId,$w)
+ }
+ return
+}
+
+proc ::TreeCtrl::ButtonPress1 {w x y} {
+ variable Priv
+ focus $w
+ set id [$w identify $x $y]
+ if {$id eq ""} {
+ return
+ }
+ if {[lindex $id 0] eq "item"} {
+ foreach {where item arg1 arg2} $id {}
+ if {$arg1 eq "button"} {
+ $w toggle $item
+ return
+ } elseif {$arg1 eq "line"} {
+ $w toggle $arg2
+ return
+ }
+ }
+ set Priv(buttonMode) ""
+ if {[lindex $id 0] eq "header"} {
+ set column [lindex $id 1]
+ set visCount 0
+ for {set i 0} {$i < [$w numcolumns]} {incr i} {
+ if {[$w column cget $i -visible]} {
+ lappend visColumns $i
+ if {$i eq $column} {
+ set columnIndex $visCount
+ }
+ incr visCount
+ }
+ }
+ lappend visColumns tail
+ if {$column eq "tail"} {
+ set columnIndex $visCount
+ }
+ if {[llength $id] == 3} {
+ set side [lindex $id 2]
+ if {$side == "left"} {
+ if {$column eq [lindex $visColumns 0]} {
+ return
+ }
+ set column [lindex $visColumns [expr {$columnIndex - 1}]]
+ }
+ set Priv(buttonMode) resize
+ set Priv(column) $column
+ set Priv(x) $x
+ set Priv(y) $y
+ set Priv(width) [$w column width $column]
+ return
+ }
+ if {$column eq "tail"} return
+ if {![$w column cget $column -button]} return
+ set Priv(buttonMode) header
+ set Priv(column) $column
+ $w column configure $column -sunken yes
+ return
+ }
+ set Priv(buttonMode) normal
+ BeginSelect $w [lindex $id 1]
+ return
+}
+
+# Double-click between columns to set default column width
+proc ::TreeCtrl::DoubleButton1 {w x y} {
+ set id [$w identify $x $y]
+ if {$id eq ""} {
+ return
+ }
+ if {[lindex $id 0] eq "header"} {
+ set column [lindex $id 1]
+ set visCount 0
+ for {set i 0} {$i < [$w numcolumns]} {incr i} {
+ if {[$w column cget $i -visible]} {
+ lappend visColumns $i
+ if {$i eq $column} {
+ set columnIndex $visCount
+ }
+ incr visCount
+ }
+ }
+ lappend visColumns tail
+ if {$column eq "tail"} {
+ set columnIndex $visCount
+ }
+ if {[llength $id] == 3} {
+ set side [lindex $id 2]
+ if {$side == "left"} {
+ if {$column eq [lindex $visColumns 0]} {
+ return
+ }
+ set column [lindex $visColumns [expr {$columnIndex - 1}]]
+ }
+ if {$column eq "tail"} return
+ $w column configure $column -width ""
+ }
+ }
+ return
+}
+
+proc ::TreeCtrl::Motion1 {w x y} {
+ variable Priv
+ if {![info exists Priv(buttonMode)]} return
+ switch $Priv(buttonMode) {
+ header {
+ set id [$w identify $x $y]
+ if {![string match "header $Priv(column)*" $id]} {
+ if {[$w column cget $Priv(column) -sunken]} {
+ $w column configure $Priv(column) -sunken no
+ }
+ } else {
+ if {![$w column cget $Priv(column) -sunken]} {
+ $w column configure $Priv(column) -sunken yes
+ }
+ }
+ }
+ normal {
+ set Priv(x) $x
+ set Priv(y) $y
+ Motion $w [$w index [list nearest $x $y]]
+ AutoScanCheck $w $x $y
+ }
+ resize {
+ set width [expr {$Priv(width) + $x - $Priv(x)}]
+ set minWidth [$w column cget $Priv(column) -minwidth]
+ if {$minWidth eq ""} {
+ set minWidth 0
+ }
+ if {$width < $minWidth} {
+ set width $minWidth
+ }
+ if {$width == 0} {
+ incr width
+ }
+ scan [$w column bbox $Priv(column)] "%d %d %d %d" x1 y1 x2 y2
+ # Use "ne" because -columnproxy could be ""
+ if {($x1 + $width - 1) ne [$w cget -columnproxy]} {
+ $w configure -columnproxy [expr {$x1 + $width - 1}]
+ }
+ }
+ }
+ return
+}
+
+proc ::TreeCtrl::Leave1 {w x y} {
+ variable Priv
+ if {![info exists Priv(buttonMode)]} return
+ switch $Priv(buttonMode) {
+ header {
+ if {[$w column cget $Priv(column) -sunken]} {
+ $w column configure $Priv(column) -sunken no
+ }
+ }
+ normal {
+ }
+ resize {}
+ }
+ return
+}
+
+proc ::TreeCtrl::Release1 {w x y} {
+ variable Priv
+ if {![info exists Priv(buttonMode)]} return
+ switch $Priv(buttonMode) {
+ header {
+ if {[$w column cget $Priv(column) -sunken]} {
+ $w column configure $Priv(column) -sunken no
+ $w notify generate <Header-invoke> -T $w -C $Priv(column)
+ }
+ }
+ normal {
+ AutoScanCancel $w
+ $w activate [$w index [list nearest $x $y]]
+ }
+ resize {
+ if {[$w cget -columnproxy] ne ""} {
+ scan [$w column bbox $Priv(column)] "%d %d %d %d" x1 y1 x2 y2
+ set width [expr {[$w cget -columnproxy] - $x1 + 1}]
+ $w configure -columnproxy {}
+ $w column configure $Priv(column) -width $width
+ CursorCheck $w $x $y
+ }
+ }
+ }
+ unset Priv(buttonMode)
+ return
+}
+
+# ::TreeCtrl::BeginSelect --
+#
+# This procedure is typically invoked on button-1 presses. It begins
+# the process of making a selection in the listbox. Its exact behavior
+# depends on the selection mode currently in effect for the listbox;
+# see the Motif documentation for details.
+#
+# Arguments:
+# w - The listbox widget.
+# el - The element for the selection operation (typically the
+# one under the pointer). Must be in numerical form.
+
+proc ::TreeCtrl::BeginSelect {w el} {
+ variable Priv
+ if {$el eq ""} return
+ if {[string equal [$w cget -selectmode] "multiple"]} {
+ if {[$w selection includes $el]} {
+ $w selection clear $el
+ } else {
+ $w selection add $el
+ }
+ } else {
+ $w selection anchor $el
+ $w selection modify $el all
+ set Priv(selection) {}
+ set Priv(prev) $el
+ }
+}
+
+# ::TreeCtrl::Motion --
+#
+# This procedure is called to process mouse motion events while
+# button 1 is down. It may move or extend the selection, depending
+# on the listbox's selection mode.
+#
+# Arguments:
+# w - The listbox widget.
+# el - The element under the pointer (must be a number).
+
+proc ::TreeCtrl::Motion {w el} {
+ variable Priv
+ if {$el eq $Priv(prev)} {
+ return
+ }
+ switch [$w cget -selectmode] {
+ browse {
+ $w selection modify $el all
+ set Priv(prev) $el
+ }
+ extended {
+ set i $Priv(prev)
+ if {$i eq ""} {
+ set i $el
+ $w selection add $el
+ }
+ if {[$w selection includes anchor]} {
+ $w selection clear $i $el
+ $w selection add anchor $el
+ } else {
+ $w selection clear $i $el
+ $w selection clear anchor $el
+ }
+ if {![info exists Priv(selection)]} {
+ set Priv(selection) [$w selection get]
+ }
+ while {[$w compare $i < $el] && [$w compare $i < anchor]} {
+ if {[lsearch $Priv(selection) $i] >= 0} {
+ $w selection add $i
+ }
+ set i [$w index "$i next visible"]
+ }
+ while {[$w compare $i > $el] && [$w compare $i > anchor]} {
+ if {[lsearch $Priv(selection) $i] >= 0} {
+ $w selection add $i
+ }
+ set i [$w index "$i prev visible"]
+ }
+ set Priv(prev) $el
+ }
+ }
+}
+
+# ::TreeCtrl::BeginExtend --
+#
+# This procedure is typically invoked on shift-button-1 presses. It
+# begins the process of extending a selection in the listbox. Its
+# exact behavior depends on the selection mode currently in effect
+# for the listbox; see the Motif documentation for details.
+#
+# Arguments:
+# w - The listbox widget.
+# el - The element for the selection operation (typically the
+# one under the pointer). Must be in numerical form.
+
+proc ::TreeCtrl::BeginExtend {w el} {
+ if {[string equal [$w cget -selectmode] "extended"]} {
+ if {[$w selection includes anchor]} {
+ Motion $w $el
+ } else {
+ # No selection yet; simulate the begin-select operation.
+ BeginSelect $w $el
+ }
+ }
+}
+
+# ::TreeCtrl::BeginToggle --
+#
+# This procedure is typically invoked on control-button-1 presses. It
+# begins the process of toggling a selection in the listbox. Its
+# exact behavior depends on the selection mode currently in effect
+# for the listbox; see the Motif documentation for details.
+#
+# Arguments:
+# w - The listbox widget.
+# el - The element for the selection operation (typically the
+# one under the pointer). Must be in numerical form.
+
+proc ::TreeCtrl::BeginToggle {w el} {
+ variable Priv
+ if {[string equal [$w cget -selectmode] "extended"]} {
+ set Priv(selection) [$w selection get]
+ set Priv(prev) $el
+ $w selection anchor $el
+ if {[$w selection includes $el]} {
+ $w selection clear $el
+ } else {
+ $w selection add $el
+ }
+ }
+}
+
+proc ::TreeCtrl::CancelRepeat {} {
+ variable Priv
+ if {[info exists Priv(afterId)]} {
+ after cancel $Priv(afterId)
+ unset Priv(afterId)
+ }
+}
+
+proc ::TreeCtrl::AutoScanCheck {w x y} {
+ variable Priv
+ scan [$w contentbox] "%d %d %d %d" x1 y1 x2 y2
+ set margin [winfo pixels $w [$w cget -scrollmargin]]
+ if {($x < $x1 + $margin) || ($x >= $x2 - $margin) ||
+ ($y < $y1 + $margin) || ($y >= $y2 - $margin)} {
+ if {![info exists Priv(autoscan,afterId,$w)]} {
+ if {$y >= $y2 - $margin} {
+ $w yview scroll 1 units
+ set delay [$w cget -yscrolldelay]
+ } elseif {$y < $y1 + $margin} {
+ $w yview scroll -1 units
+ set delay [$w cget -yscrolldelay]
+ } elseif {$x >= $x2 - $margin} {
+ $w xview scroll 1 units
+ set delay [$w cget -xscrolldelay]
+ } elseif {$x < $x1 + $margin} {
+ $w xview scroll -1 units
+ set delay [$w cget -xscrolldelay]
+ }
+ set count [scan $delay "%d %d" d1 d2]
+ if {[info exists Priv(autoscan,scanning,$w)]} {
+ if {$count == 2} {
+ set delay $d2
+ }
+ } else {
+ if {$count == 2} {
+ set delay $d1
+ }
+ set Priv(autoscan,scanning,$w) 1
+ }
+ Motion $w [$w index "nearest $x $y"]
+ set Priv(autoscan,afterId,$w) [after $delay [list TreeCtrl::AutoScanCheckAux $w]]
+ }
+ return
+ }
+ AutoScanCancel $w
+ return
+}
+
+proc ::TreeCtrl::AutoScanCheckAux {w} {
+ variable Priv
+ unset Priv(autoscan,afterId,$w)
+ set x [winfo pointerx $w]
+ set y [winfo pointery $w]
+ set x [expr {$x - [winfo rootx $w]}]
+ set y [expr {$y - [winfo rooty $w]}]
+ AutoScanCheck $w $x $y
+ return
+}
+
+proc ::TreeCtrl::AutoScanCancel {w} {
+ variable Priv
+ if {[info exists Priv(autoscan,afterId,$w)]} {
+ after cancel $Priv(autoscan,afterId,$w)
+ unset Priv(autoscan,afterId,$w)
+ }
+ unset -nocomplain Priv(autoscan,scanning,$w)
+ return
+}
+
+# ::TreeCtrl::UpDown --
+#
+# Moves the location cursor (active element) up or down by one element,
+# and changes the selection if we're in browse or extended selection
+# mode.
+#
+# Arguments:
+# w - The listbox widget.
+# amount - +1 to move down one item, -1 to move back one item.
+
+proc ::TreeCtrl::UpDown {w n} {
+ variable Priv
+ set rnc [$w item rnc active]
+ # active item isn't visible
+ if {$rnc eq ""} {
+ set rnc [$w item rnc first]
+ if {$rnc eq ""} return
+ }
+ scan $rnc "%d %d" row col
+ set Priv(row) [expr {$row + $n}]
+ if {$rnc ne $Priv(rnc)} {
+ set Priv(col) $col
+ }
+ set index [$w index "rnc $Priv(row) $Priv(col)"]
+ if {[$w compare active == $index]} {
+ set Priv(row) $row
+ } else {
+ set Priv(rnc) [$w item rnc $index]
+ }
+ return $index
+}
+
+proc ::TreeCtrl::LeftRight {w n} {
+ variable Priv
+ set rnc [$w item rnc active]
+ if {$rnc eq ""} {
+ set rnc [$w item rnc first]
+ if {$rnc eq ""} return
+ }
+ scan $rnc "%d %d" row col
+ set Priv(col) [expr {$col + $n}]
+ if {$rnc ne $Priv(rnc)} {
+ set Priv(row) $row
+ }
+ set index [$w index "rnc $Priv(row) $Priv(col)"]
+ if {[$w compare active == $index]} {
+ set Priv(col) $col
+ } else {
+ set Priv(rnc) [$w item rnc $index]
+ }
+ return $index
+}
+
+proc ::TreeCtrl::SetActiveItem {w index} {
+ if {$index eq ""} return
+ $w activate $index
+ $w see active
+ $w selection modify active all
+ switch [$w cget -selectmode] {
+ extended {
+ $w selection anchor active
+ set Priv(prev) [$w index active]
+ set Priv(selection) {}
+ }
+ }
+}
+
+# ::TreeCtrl::ExtendUpDown --
+#
+# Does nothing unless we're in extended selection mode; in this
+# case it moves the location cursor (active element) up or down by
+# one element, and extends the selection to that point.
+#
+# Arguments:
+# w - The listbox widget.
+# amount - +1 to move down one item, -1 to move back one item.
+
+proc ::TreeCtrl::ExtendUpDown {w amount} {
+ variable Priv
+ if {[string compare [$w cget -selectmode] "extended"]} {
+ return
+ }
+ set active [$w index active]
+ if {![info exists Priv(selection)]} {
+ $w selection add $active
+ set Priv(selection) [$w selection get]
+ }
+ set index [$w index "active $amount"]
+ if {$index eq ""} return
+ $w activate $index
+ $w see active
+ Motion $w [$w index active]
+}
+
+# ::TreeCtrl::DataExtend
+#
+# This procedure is called for key-presses such as Shift-KEndData.
+# If the selection mode isn't multiple or extend then it does nothing.
+# Otherwise it moves the active element to el and, if we're in
+# extended mode, extends the selection to that point.
+#
+# Arguments:
+# w - The listbox widget.
+# el - An integer element number.
+
+proc ::TreeCtrl::DataExtend {w el} {
+ set mode [$w cget -selectmode]
+ if {[string equal $mode "extended"]} {
+ $w activate $el
+ $w see $el
+ if {[$w selection includes anchor]} {
+ Motion $w $el
+ }
+ } elseif {[string equal $mode "multiple"]} {
+ $w activate $el
+ $w see $el
+ }
+}
+
+# ::TreeCtrl::Cancel
+#
+# This procedure is invoked to cancel an extended selection in
+# progress. If there is an extended selection in progress, it
+# restores all of the items between the active one and the anchor
+# to their previous selection state.
+#
+# Arguments:
+# w - The listbox widget.
+
+proc ::TreeCtrl::Cancel w {
+ variable Priv
+ if {[string compare [$w cget -selectmode] "extended"]} {
+ return
+ }
+ set first [$w index anchor]
+ set last $Priv(prev)
+ if { [string equal $last ""] } {
+ # Not actually doing any selection right now
+ return
+ }
+ if {[$w compare $first > $last]} {
+ set tmp $first
+ set first $last
+ set last $tmp
+ }
+ $w selection clear $first $last
+ while {[$w compare $first <= $last]} {
+ if {[lsearch $Priv(selection) $first] >= 0} {
+ $w selection add $first
+ }
+ set first [$w index "$first next visible"]
+ }
+}
+
+# ::TreeCtrl::SelectAll
+#
+# This procedure is invoked to handle the "select all" operation.
+# For single and browse mode, it just selects the active element.
+# Otherwise it selects everything in the widget.
+#
+# Arguments:
+# w - The listbox widget.
+
+proc ::TreeCtrl::SelectAll w {
+ set mode [$w cget -selectmode]
+ if {[string equal $mode "single"] || [string equal $mode "browse"]} {
+ $w selection modify active all
+ } else {
+ $w selection add all
+ }
+}
+
+proc ::TreeCtrl::MarqueeBegin {w x y} {
+ set x [$w canvasx $x]
+ set y [$w canvasy $y]
+ $w marquee coords $x $y $x $y
+ $w marquee visible yes
+ return
+}
+
+proc ::TreeCtrl::MarqueeUpdate {w x y} {
+ set x [$w canvasx $x]
+ set y [$w canvasy $y]
+ $w marquee corner $x $y
+ return
+}
+proc ::TreeCtrl::MarqueeEnd {w x y} {
+ $w marquee visible no
+ return
+}
+