diff options
Diffstat (limited to 'blt/library/treeview.tcl')
-rw-r--r-- | blt/library/treeview.tcl | 972 |
1 files changed, 972 insertions, 0 deletions
diff --git a/blt/library/treeview.tcl b/blt/library/treeview.tcl new file mode 100644 index 00000000000..9c602d9eb47 --- /dev/null +++ b/blt/library/treeview.tcl @@ -0,0 +1,972 @@ +# ====================================================================== +# +# treeview.tcl +# +# ---------------------------------------------------------------------- +# Bindings for the BLT treeview widget +# ---------------------------------------------------------------------- +# +# AUTHOR: George Howlett +# Bell Labs Innovations for Lucent Technologies +# gah@lucent.com +# http://www.tcltk.com/blt +# +# RCS: $Id$ +# +# ---------------------------------------------------------------------- +# Copyright (c) 1998 Lucent Technologies, Inc. +# ---------------------------------------------------------------------- +# +# Permission to use, copy, modify, and distribute this software and its +# documentation for any purpose and without fee is hereby granted, +# provided that the above copyright notice appear in all copies and that +# both that the copyright notice and warranty disclaimer appear in +# supporting documentation, and that the names of Lucent Technologies +# any of their entities not be used in advertising or publicity +# pertaining to distribution of the software without specific, written +# prior permission. +# +# Lucent Technologies disclaims all warranties with regard to this +# software, including all implied warranties of merchantability and +# fitness. In no event shall Lucent be liable for any special, indirect +# or consequential damages or any damages whatsoever resulting from loss +# of use, data or profits, whether in an action of contract, negligence +# or other tortuous action, arising out of or in connection with the use +# or performance of this software. +# +# ====================================================================== + +namespace eval blt::tv { + set afterId "" + set scroll 0 + set column "" + set space off + set x 0 + set y 0 +} + +image create photo blt::tv::normalCloseFolder -format gif -data { + R0lGODlhEAANAMIAAAAAAH9/f///////AL+/vwAA/wAAAAAAACH5BAEAAAUALAAAAAAQAA0A + AAM8WBrM+rAEQWmIb5KxiWjNInCkV32AJHRlGQBgDA7vdN4vUa8tC78qlrCWmvRKsJTquHkp + ZTKAsiCtWq0JADs= +} +image create photo blt::tv::normalOpenFolder -format gif -data { + R0lGODlhEAANAMIAAAAAAH9/f///////AL+/vwAA/wAAAAAAACH5BAEAAAUALAAAAAAQAA0A + AAM1WBrM+rAEMigJ8c3Kb3OSII6kGABhp1JnaK1VGwjwKwtvHqNzzd263M3H4n2OH1QBwGw6 + nQkAOw== +} +image create photo blt::tv::activeCloseFolder -format gif -data { + R0lGODlhEAANAMIAAAAAAH9/f/////+/AL+/vwAA/wAAAAAAACH5BAEAAAUALAAAAAAQAA0A + AAM8WBrM+rAEQWmIb5KxiWjNInCkV32AJHRlGQBgDA7vdN4vUa8tC78qlrCWmvRKsJTquHkp + ZTKAsiCtWq0JADs= +} +image create photo blt::tv::activeOpenFolder -format gif -data { + R0lGODlhEAANAMIAAAAAAH9/f/////+/AL+/vwAA/wAAAAAAACH5BAEAAAUALAAAAAAQAA0A + AAM1WBrM+rAEMigJ8c3Kb3OSII6kGABhp1JnaK1VGwjwKwtvHqNzzd263M3H4n2OH1QBwGw6 + nQkAOw== +} + +if { $tcl_platform(platform) == "windows" } { + if { $tk_version >= 8.3 } { + set cursor "@[file join $blt_library treeview.cur]" + } else { + set cursor "size_we" + } + option add *${className}.ResizeCursor [list $cursor] +} else { + option add *${className}.ResizeCursor \ + "@$blt_library/treeview.xbm $blt_library/treeview_m.xbm black white" +} + +# ---------------------------------------------------------------------- +# +# Initialize -- +# +# Invoked by internally by Treeview_Init routine. Initializes +# the default bindings for the treeview widget entries. These +# are local to the widget, so they can't be set through the +# widget's class bind tags. +# +# ---------------------------------------------------------------------- +proc blt::tv::Initialize { w } { + # + # Active entry bindings + # + $w bind Entry <Enter> { + %W entry highlight current + } + $w bind Entry <Leave> { + %W entry highlight "" + } + + # + # Button bindings + # + $w button bind all <ButtonRelease-1> { + %W see -anchor nw current + %W toggle current + } + $w button bind all <Enter> { + %W button highlight current + } + $w button bind all <Leave> { + %W button highlight "" + } + + # + # ButtonPress-1 + # + # Performs the following operations: + # + # 1. Clears the previous selection. + # 2. Selects the current entry. + # 3. Sets the focus to this entry. + # 4. Scrolls the entry into view. + # 5. Sets the selection anchor to this entry, just in case + # this is "multiple" mode. + # + + $w bind Entry <ButtonPress-1> { + blt::tv::SetSelectionAnchor %W current + set blt::tv::scroll 1 + } + + $w bind Entry <Double-ButtonPress-1> { + %W toggle current + } + + # + # B1-Motion + # + # For "multiple" mode only. Saves the current location of the + # pointer for auto-scrolling. Resets the selection mark. + # + $w bind Entry <B1-Motion> { + set blt::tv::x %x + set blt::tv::y %y + set index [%W nearest %x %y] + if { [%W cget -selectmode] == "multiple" } { + %W selection mark $index + } else { + blt::tv::SetSelectionAnchor %W $index + } + } + + # + # ButtonRelease-1 + # + # For "multiple" mode only. + # + $w bind Entry <ButtonRelease-1> { + if { [%W cget -selectmode] == "multiple" } { + %W selection anchor current + } + after cancel $blt::tv::afterId + set blt::tv::scroll 0 + } + + # + # Shift-ButtonPress-1 + # + # For "multiple" mode only. + # + + $w bind Entry <Shift-ButtonPress-1> { + if { [%W cget -selectmode] == "multiple" && [%W selection present] } { + if { [%W index anchor] == "" } { + %W selection anchor current + } + set index [%W index anchor] + %W selection clearall + %W selection set $index current + } else { + blt::tv::SetSelectionAnchor %W current + } + } + $w bind Entry <Shift-Double-ButtonPress-1> { + # do nothing + } + $w bind Entry <Shift-B1-Motion> { + # do nothing + } + $w bind Entry <Shift-ButtonRelease-1> { + after cancel $blt::tv::afterId + set blt::tv::scroll 0 + } + + # + # Control-ButtonPress-1 + # + # For "multiple" mode only. + # + $w bind Entry <Control-ButtonPress-1> { + if { [%W cget -selectmode] == "multiple" } { + set index [%W index current] + %W selection toggle $index + %W selection anchor $index + } else { + blt::tv::SetSelectionAnchor %W current + } + } + $w bind Entry <Control-Double-ButtonPress-1> { + # do nothing + } + $w bind Entry <Control-B1-Motion> { + # do nothing + } + $w bind Entry <Control-ButtonRelease-1> { + after cancel $blt::tv::afterId + set blt::tv::scroll 0 + } + + $w bind Entry <Control-Shift-ButtonPress-1> { + if { [%W cget -selectmode] == "multiple" && [%W selection present] } { + if { [%W index anchor] == "" } { + %W selection anchor current + } + if { [%W selection includes anchor] } { + %W selection set anchor current + } else { + %W selection clear anchor current + %W selection set current + } + } else { + blt::tv::SetSelectionAnchor %W current + } + } + $w bind Entry <Control-Shift-Double-ButtonPress-1> { + # do nothing + } + $w bind Entry <Control-Shift-B1-Motion> { + # do nothing + } + $w column bind all <Enter> { + %W column highlight [%W column current] + } + $w column bind all <Leave> { + %W column highlight "" + } + $w column bind Rule <Enter> { + %W column highlight [%W column current] + %W column resize activate [%W column current] + } + $w column bind Rule <Leave> { + %W column highlight "" + %W column resize activate "" + } + $w column bind Rule <ButtonPress-1> { + %W column resize anchor %x + } + $w column bind Rule <B1-Motion> { + %W column resize mark %x + } + $w column bind Rule <ButtonRelease-1> { + %W column configure [%W column current] -width [%W column resize set] + } + $w column bind all <ButtonRelease-1> { + set column [%W column nearest %x %y] + if { $column != "" } { + %W column invoke $column + } + } +} + +# ---------------------------------------------------------------------- +# +# AutoScroll -- +# +# Invoked when the user is selecting elements in a treeview +# widget and drags the mouse pointer outside of the widget. +# Scrolls the view in the direction of the pointer. +# +# ---------------------------------------------------------------------- +proc blt::tv::AutoScroll { w } { + if { ![winfo exists $w] } { + return + } + set x $blt::tv::x + set y $blt::tv::y + + set index [$w nearest $x $y] + + if {$y >= [winfo height $w]} { + $w yview scroll 1 units + set neighbor down + } elseif {$y < 0} { + $w yview scroll -1 units + set neighbor up + } else { + set neighbor $index + } + if { [$w cget -selectmode] == "single" } { + blt::tv::SetSelectionAnchor $w $neighbor + } else { + $w selection mark $index + } + set ::blt::tv::afterId [after 50 blt::tv::AutoScroll $w] +} + +proc blt::tv::SetSelectionAnchor { w tagOrId } { + set index [$w index $tagOrId] + # If the anchor hasn't changed, don't do anything + if { $index != [$w index anchor] } { + $w selection clearall + $w see $index + $w focus $index + $w selection set $index + $w selection anchor $index + } +} + +# ---------------------------------------------------------------------- +# +# MoveFocus -- +# +# Invoked by KeyPress bindings. Moves the active selection to +# the entry <where>, which is an index such as "up", "down", +# "prevsibling", "nextsibling", etc. +# +# ---------------------------------------------------------------------- +proc blt::tv::MoveFocus { w tagOrId } { + catch {$w focus $tagOrId} + if { [$w cget -selectmode] == "single" } { + $w selection clearall + $w selection set focus + $w selection anchor focus + } + $w see focus +} + +# ---------------------------------------------------------------------- +# +# MovePage -- +# +# Invoked by KeyPress bindings. Pages the current view up or +# down. The <where> argument should be either "top" or +# "bottom". +# +# ---------------------------------------------------------------------- +proc blt::tv::MovePage { w where } { + + # If the focus is already at the top/bottom of the window, we want + # to scroll a page. It's really one page minus an entry because we + # want to see the last entry on the next/last page. + if { [$w index focus] == [$w index view.$where] } { + if {$where == "top"} { + $w yview scroll -1 pages + $w yview scroll 1 units + } else { + $w yview scroll 1 pages + $w yview scroll -1 units + } + } + update + + # Adjust the entry focus and the view. Also activate the entry. + # just in case the mouse point is not in the widget. + $w entry highlight view.$where + $w focus view.$where + $w see view.$where + if { [$w cget -selectmode] == "single" } { + $w selection clearall + $w selection set focus + } +} + +# ---------------------------------------------------------------------- +# +# NextMatch -- +# +# Invoked by KeyPress bindings. Searches for an entry that +# starts with the letter <char> and makes that entry active. +# +# ---------------------------------------------------------------------- +proc blt::tv::NextMatch { w key } { + if {[string match {[ -~]} $key]} { + set last [$w index focus] + set next [$w index next] + while { $next != $last } { + set label [$w entry cget $next -label] + set label [string index $label 0] + if { [string tolower $label] == [string tolower $key] } { + break + } + set next [$w index -at $next next] + } + $w focus $next + if {[$w cget -selectmode] == "single"} { + $w selection clearall + $w selection set focus + } + $w see focus + } +} + +#------------------------------------------------------------------------ +# +# InsertText -- +# +# Inserts a text string into an entry at the insertion cursor. +# If there is a selection in the entry, and it covers the point +# of the insertion cursor, then delete the selection before +# inserting. +# +# Arguments: +# w Widget where to insert the text. +# text Text string to insert (usually just a single character) +# +#------------------------------------------------------------------------ +proc blt::tv::InsertText { w text } { + if { [string length $text] > 0 } { + set index [$w text index insert] + if { ($index >= [$w text index sel.first]) && + ($index <= [$w text index sel.last]) } { + $w text delete sel.first sel.last + } + $w text insert $index $text + } +} + +#------------------------------------------------------------------------ +# +# Transpose - +# +# This procedure implements the "transpose" function for entry +# widgets. It tranposes the characters on either side of the +# insertion cursor, unless the cursor is at the end of the line. +# In this case it transposes the two characters to the left of +# the cursor. In either case, the cursor ends up to the right +# of the transposed characters. +# +# Arguments: +# w The entry window. +# +#------------------------------------------------------------------------ +proc blt::tv::Transpose { w } { + set i [$w text index insert] + if {$i < [$w text index end]} { + incr i + } + set first [expr {$i-2}] + if {$first < 0} { + return + } + set new [string index [$w get] [expr {$i-1}]][string index [$w get] $first] + $w delete $first $i + $w insert insert $new +} + +#------------------------------------------------------------------------ +# +# GetSelection -- +# +# Returns the selected text of the entry with respect to the +# -show option. +# +# Arguments: +# w Entry window from which the text to get +# +#------------------------------------------------------------------------ + +proc blt::tv::GetSelection { w } { + set text [string range [$w get] [$w index sel.first] \ + [expr [$w index sel.last] - 1]] + if {[$w cget -show] != ""} { + regsub -all . $text [string index [$w cget -show] 0] text + } + return $text +} + +# +# ButtonPress assignments +# +# B1-Enter start auto-scrolling +# B1-Leave stop auto-scrolling +# ButtonPress-2 start scan +# B2-Motion adjust scan +# ButtonRelease-2 stop scan +# + +bind ${className} <ButtonPress-2> { + set blt::tv::cursor [%W cget -cursor] + %W configure -cursor hand1 + %W scan mark %x %y +} + +bind ${className} <B2-Motion> { + %W scan dragto %x %y +} + +bind ${className} <ButtonRelease-2> { + %W configure -cursor $blt::tv::cursor +} + +bind ${className} <B1-Leave> { + if { $blt::tv::scroll } { + blt::tv::AutoScroll %W + } +} + +bind ${className} <B1-Enter> { + after cancel $blt::tv::afterId +} + +# +# KeyPress assignments +# +# Up +# Down +# Shift-Up +# Shift-Down +# Prior (PageUp) +# Next (PageDn) +# Left +# Right +# space Start selection toggle of entry currently with focus. +# Return Start selection toggle of entry currently with focus. +# Home +# End +# F1 +# F2 +# ASCII char Go to next open entry starting with character. +# +# KeyRelease +# +# space Stop selection toggle of entry currently with focus. +# Return Stop selection toggle of entry currently with focus. + + +bind ${className} <KeyPress-Up> { + blt::tv::MoveFocus %W up + if { $blt::tv::space } { + %W selection toggle focus + } +} + +bind ${className} <KeyPress-Down> { + blt::tv::MoveFocus %W down + if { $blt::tv::space } { + %W selection toggle focus + } +} + +bind ${className} <Shift-KeyPress-Up> { + blt::tv::MoveFocus %W prevsibling +} + +bind ${className} <Shift-KeyPress-Down> { + blt::tv::MoveFocus %W nextsibling +} + +bind ${className} <KeyPress-Prior> { + blt::tv::MovePage %W top +} + +bind ${className} <KeyPress-Next> { + blt::tv::MovePage %W bottom +} + +bind ${className} <KeyPress-Left> { + %W close focus +} +bind ${className} <KeyPress-Right> { + %W open focus + %W see focus -anchor w +} + +bind ${className} <KeyPress-space> { + if { [%W cget -selectmode] == "single" } { + if { [%W selection includes focus] } { + %W selection clearall + } else { + %W selection clearall + %W selection set focus + } + } else { + %W selection toggle focus + } + set blt::tv::space on +} + +bind ${className} <KeyRelease-space> { + set blt::tv::space off +} + +bind ${className} <KeyPress-Return> { + blt::tv::MoveFocus %W focus + set blt::tv::space on +} + +bind ${className} <KeyRelease-Return> { + set blt::tv::space off +} + +bind ${className} <KeyPress> { + blt::tv::NextMatch %W %A +} + +bind ${className} <KeyPress-Home> { + blt::tv::MoveFocus %W top +} + +bind ${className} <KeyPress-End> { + blt::tv::MoveFocus %W bottom +} + +bind ${className} <KeyPress-F1> { + %W open -r root +} + +bind ${className} <KeyPress-F2> { + eval %W close -r [%W entry children root] +} + +# +# Differences between "current" and nearest. +# +# set index [$w index current] +# set index [$w nearest $x $y] +# +# o Nearest gives you the closest entry. +# o current is "" if +# 1) the pointer isn't over an entry. +# 2) the pointer is over a open/close button. +# 3) +# + +# +# Edit mode assignments +# +# ButtonPress-3 Enables/disables edit mode on entry. Sets focus to +# entry. +# +# KeyPress +# +# Left Move insertion position to previous. +# Right Move insertion position to next. +# Up Move insertion position up one line. +# Down Move insertion position down one line. +# Return End edit mode. +# Shift-Return Line feed. +# Home Move to first position. +# End Move to last position. +# ASCII char Insert character left of insertion point. +# Del Delete character right of insertion point. +# Delete Delete character left of insertion point. +# Ctrl-X Cut +# Ctrl-V Copy +# Ctrl-P Paste +# +# KeyRelease +# +# ButtonPress-1 Start selection if in entry, otherwise clear selection. +# B1-Motion Extend/reduce selection. +# ButtonRelease-1 End selection if in entry, otherwise use last +# selection. +# B1-Enter Disabled. +# B1-Leave Disabled. +# ButtonPress-2 Same as above. +# B2-Motion Same as above. +# ButtonRelease-2 Same as above. +# +# + +bind ${className} <ButtonPress-3> { + %W see current + set id [%W text get %x %y] + if { $id != -1 } { + focus %W.edit + grab set %W.edit + %W text selection range 0 end + } +} + + +# Standard Motif bindings: + +bind ${className}Editor <ButtonPress-1> { + %W text icursor @%x,%y + %W text selection clear +} + +bind ${className}Editor <Left> { + %W text icursor last + %W text selection clear +} + +bind ${className}Editor <Right> { + %W text icursor next + %W text selection clear +} + +bind ${className}Editor <Shift-Left> { + set new [expr {[%W text index insert] - 1}] + if {![%W text selection present]} { + %W text selection from insert + %W text selection to $new + } else { + %W text selection adjust $new + } + %W text icursor $new +} + +bind ${className}Editor <Shift-Right> { + set new [expr {[%W text index insert] + 1}] + if {![%W text selection present]} { + %W text selection from insert + %W text selection to $new + } else { + %W text selection adjust $new + } + %W text icursor $new +} + +bind ${className}Editor <Home> { + %W text icursor 0 + %W selection clear +} +bind ${className}Editor <Shift-Home> { + set new 0 + if {![%W text selection present]} { + %W text selection from insert + %W text selection to $new + } else { + %W text selection adjust $new + } + %W text icursor $new +} +bind ${className}Editor <End> { + %W text icursor end + %W selection clear +} +bind ${className}Editor <Shift-End> { + set new end + if {![%W text selection present]} { + %W text selection from insert + %W text selection to $new + } else { + %W text selection adjust $new + } + %W text icursor $new +} + +bind ${className}Editor <Delete> { + if { [%W text selection present]} { + %W text delete sel.first sel.last + } else { + %W text delete insert + } +} + +bind ${className}Editor <BackSpace> { + if { [%W text selection present] } { + %W text delete sel.first sel.last + } else { + set index [expr [%W text index insert] - 1] + if { $index >= 0 } { + %W text delete $index $index + } + } +} + +bind ${className}Editor <Control-space> { + %W text selection from insert +} + +bind ${className}Editor <Select> { + %W text selection from insert +} + +bind ${className}Editor <Control-Shift-space> { + %W text selection adjust insert +} + +bind ${className}Editor <Shift-Select> { + %W text selection adjust insert +} + +bind ${className}Editor <Control-slash> { + %W text selection range 0 end +} + +bind ${className}Editor <Control-backslash> { + %W text selection clear +} + +bind ${className}Editor <KeyPress> { + blt::tv::InsertText %W %A +} + +# Ignore all Alt, Meta, and Control keypresses unless explicitly bound. +# Otherwise, if a widget binding for one of these is defined, the +# <KeyPress> class binding will also fire and insert the character, +# which is wrong. Ditto for Escape, Return, and Tab. + +bind ${className}Editor <Alt-KeyPress> { + # nothing +} + +bind ${className}Editor <Meta-KeyPress> { + # nothing +} + +bind ${className}Editor <Control-KeyPress> { + # nothing +} + +bind ${className}Editor <Escape> { + %W text cancel + grab release %W +} + +bind ${className}Editor <Return> { + %W text apply + grab release %W +} + +bind ${className}Editor <Shift-Return> { + blt::tv::InsertText %W "\n" +} + +bind ${className}Editor <KP_Enter> { + # nothing +} + +bind ${className}Editor <Tab> { + # nothing +} + +if {![string compare $tcl_platform(platform) "macintosh"]} { + bind ${className}Editor <Command-KeyPress> { + # nothing + } +} + +# On Windows, paste is done using Shift-Insert. Shift-Insert already +# generates the <<Paste>> event, so we don't need to do anything here. +if { [string compare $tcl_platform(platform) "windows"] != 0 } { + bind ${className}Editor <Insert> { + catch {blt::tv::InsertText %W [selection get -displayof %W]} + } +} + +# Additional emacs-like bindings: +bind ${className}Editor <ButtonPress-3> { + grab release %W + %W text cancel + update + set id [%W text get -root %X %Y] + if { $id != -1 } { + focus %W + grab set %W + %W text selection range 0 end + } +} + +bind ${className}Editor <Control-a> { + %W text icursor 0 + %W text selection clear +} + +bind ${className}Editor <Control-b> { + %W text icursor [expr {[%W index insert] - 1}] + %W text selection clear +} + +bind ${className}Editor <Control-d> { + %W text delete insert +} + +bind ${className}Editor <Control-e> { + %W text icursor end + %W text selection clear +} + +bind ${className}Editor <Control-f> { + %W text icursor [expr {[%W index insert] + 1}] + %W text selection clear +} + +bind ${className}Editor <Control-h> { + if {[%W text selection present]} { + %W text delete sel.first sel.last + } else { + set index [expr [%W text index insert] - 1] + if { $index >= 0 } { + %W text delete $index $index + } + } +} + +bind ${className}Editor <Control-k> { + %W text delete insert end +} + +if 0 { + bind ${className}Editor <Control-t> { + blt::tv::Transpose %W + } + bind ${className}Editor <Meta-b> { + %W text icursor [blt::tv::PreviousWord %W insert] + %W text selection clear + } + bind ${className}Editor <Meta-d> { + %W delete insert [blt::tv::NextWord %W insert] + } + bind ${className}Editor <Meta-f> { + %W text icursor [blt::tv::NextWord %W insert] + %W text selection clear + } + bind ${className}Editor <Meta-BackSpace> { + %W delete [blt::tv::PreviousWord %W insert] insert + } + bind ${className}Editor <Meta-Delete> { + %W delete [blt::tv::PreviousWord %W insert] insert + } + # tkEntryNextWord -- Returns the index of the next word position + # after a given position in the entry. The next word is platform + # dependent and may be either the next end-of-word position or the + # next start-of-word position after the next end-of-word position. + # + # Arguments: + # w - The entry window in which the cursor is to move. + # start - Position at which to start search. + + if {![string compare $tcl_platform(platform) "windows"]} { + proc blt::tv::NextWord {w start} { + set pos [tcl_endOfWord [$w get] [$w index $start]] + if {$pos >= 0} { + set pos [tcl_startOfNextWord [$w get] $pos] + } + if {$pos < 0} { + return end + } + return $pos + } + } else { + proc blt::tv::NextWord {w start} { + set pos [tcl_endOfWord [$w get] [$w index $start]] + if {$pos < 0} { + return end + } + return $pos + } + } + + # PreviousWord -- + # + # Returns the index of the previous word position before a given + # position in the entry. + # + # Arguments: + # w - The entry window in which the cursor is to move. + # start - Position at which to start search. + + proc blt::tv::PreviousWord {w start} { + set pos [tcl_startOfPreviousWord [$w get] [$w index $start]] + if {$pos < 0} { + return 0 + } + return $pos + } +} |