# ====================================================================== # # 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: treeview.tcl,v 1.25 2002/08/06 05:08:24 ghowlett Exp $ # # ---------------------------------------------------------------------- # 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 { %W entry highlight current } $w bind Entry { %W entry highlight "" } # # Button bindings # $w button bind all { %W see -anchor nw current %W toggle current } $w button bind all { %W button highlight current } $w button bind all { %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 { blt::tv::SetSelectionAnchor %W current set blt::tv::scroll 1 } $w bind Entry { %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 { 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 { 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 { 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 { # do nothing } $w bind Entry { # do nothing } $w bind Entry { after cancel $blt::tv::afterId set blt::tv::scroll 0 } # # Control-ButtonPress-1 # # For "multiple" mode only. # $w bind Entry { 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 { # do nothing } $w bind Entry { # do nothing } $w bind Entry { after cancel $blt::tv::afterId set blt::tv::scroll 0 } $w bind Entry { 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 { # do nothing } $w bind Entry { # do nothing } $w bind Entry { blt::tv::EditColumn %W %X %Y } $w column bind all { %W column highlight [%W column current] } $w column bind all { %W column highlight "" } $w column bind Rule { %W column highlight [%W column current] %W column resize activate [%W column current] } $w column bind Rule { %W column highlight "" %W column resize activate "" } $w column bind Rule { %W column resize anchor %x } $w column bind Rule { %W column resize mark %x } $w column bind Rule { %W column configure [%W column current] -width [%W column resize set] } $w column bind all { set blt::tv::column [%W column current] %W column configure $blt::tv::column -titlerelief sunken } $w column bind all { set column [%W column current] if { $column != "" } { %W column invoke $column } %W column configure $blt::tv::column -titlerelief raised } $w bind TextBoxStyle { if { [%W edit -root -test %X %Y] } { break } } $w bind TextBoxStyle { if { [%W edit -root -test %X %Y] } { blt::tv::EditColumn %W %X %Y break } } $w bind CheckBoxStyle { set column [%W column current] if { [%W column cget $column -edit] } { %W style activate current $column } } $w bind CheckBoxStyle { %W style activate "" } $w bind CheckBoxStyle { set column [%W column current] if { [%W column cget $column -edit] } { break } } $w bind CheckBoxStyle { set column [%W column current] if { [%W column cget $column -edit] } { break } } $w bind CheckBoxStyle { if { [%W edit -root -test %X %Y] } { %W edit -root %X %Y break } } $w bind ComboBoxStyle { set column [%W column current] if { [%W column cget $column -edit] } { break } } $w bind ComboBoxStyle { if { [%W edit -root -test %X %Y] } { %W edit -root %X %Y break } } } # ---------------------------------------------------------------------- # # 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 , 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 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 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 index insert] if { ($index >= [$w index sel.first]) && ($index <= [$w index sel.last]) } { $w delete sel.first sel.last } $w 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 index insert] if {$i < [$w 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 } proc blt::tv::EditColumn { w x y } { $w see current if { [winfo exists $w.edit] } { destroy $w.edit } if { ![$w edit -root -test $x $y] } { return } $w edit -root $x $y update focus $w.edit $w.edit selection range 0 end grab set $w.edit tkwait window $w.edit grab release $w.edit } # # 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} { set blt::tv::cursor [%W cget -cursor] %W configure -cursor hand1 %W scan mark %x %y } bind ${className} { %W scan dragto %x %y } bind ${className} { %W configure -cursor $blt::tv::cursor } bind ${className} { if { $blt::tv::scroll } { blt::tv::AutoScroll %W } } bind ${className} { 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} { blt::tv::MoveFocus %W up if { $blt::tv::space } { %W selection toggle focus } } bind ${className} { blt::tv::MoveFocus %W down if { $blt::tv::space } { %W selection toggle focus } } bind ${className} { blt::tv::MoveFocus %W prevsibling } bind ${className} { blt::tv::MoveFocus %W nextsibling } bind ${className} { blt::tv::MovePage %W top } bind ${className} { blt::tv::MovePage %W bottom } bind ${className} { %W close focus } bind ${className} { %W open focus %W see focus -anchor w } bind ${className} { 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} { set blt::tv::space off } bind ${className} { blt::tv::MoveFocus %W focus set blt::tv::space on } bind ${className} { set blt::tv::space off } bind ${className} { blt::tv::NextMatch %W %A } bind ${className} { blt::tv::MoveFocus %W top } bind ${className} { blt::tv::MoveFocus %W bottom } bind ${className} { %W open -r root } bind ${className} { eval %W close -r [%W entry children root] } # # Differences between id "current" and operation 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. # # # Standard Motif bindings: bind ${className}Editor { %W icursor @%x,%y %W selection clear } bind ${className}Editor { %W icursor last %W selection clear } bind ${className}Editor { %W icursor next %W selection clear } bind ${className}Editor { set new [expr {[%W index insert] - 1}] if {![%W selection present]} { %W selection from insert %W selection to $new } else { %W selection adjust $new } %W icursor $new } bind ${className}Editor { set new [expr {[%W index insert] + 1}] if {![%W selection present]} { %W selection from insert %W selection to $new } else { %W selection adjust $new } %W icursor $new } bind ${className}Editor { %W icursor 0 %W selection clear } bind ${className}Editor { set new 0 if {![%W selection present]} { %W selection from insert %W selection to $new } else { %W selection adjust $new } %W icursor $new } bind ${className}Editor { %W icursor end %W selection clear } bind ${className}Editor { set new end if {![%W selection present]} { %W selection from insert %W selection to $new } else { %W selection adjust $new } %W icursor $new } bind ${className}Editor { if { [%W selection present]} { %W delete sel.first sel.last } else { %W delete insert } } bind ${className}Editor { if { [%W selection present] } { %W delete sel.first sel.last } else { set index [expr [%W index insert] - 1] if { $index >= 0 } { %W delete $index $index } } } bind ${className}Editor { %W selection from insert } bind ${className}Editor