2 # ======================================================================
6 # ----------------------------------------------------------------------
7 # Bindings for the BLT treeview widget
8 # ----------------------------------------------------------------------
10 # AUTHOR: George Howlett
11 # Bell Labs Innovations for Lucent Technologies
13 # http://www.tcltk.com/blt
15 # RCS: $Id: treeview.tcl,v 1.25 2002/08/06 05:08:24 ghowlett Exp $
17 # ----------------------------------------------------------------------
18 # Copyright (c) 1998 Lucent Technologies, Inc.
19 # ----------------------------------------------------------------------
21 # Permission to use, copy, modify, and distribute this software and its
22 # documentation for any purpose and without fee is hereby granted,
23 # provided that the above copyright notice appear in all copies and that
24 # both that the copyright notice and warranty disclaimer appear in
25 # supporting documentation, and that the names of Lucent Technologies
26 # any of their entities not be used in advertising or publicity
27 # pertaining to distribution of the software without specific, written
30 # Lucent Technologies disclaims all warranties with regard to this
31 # software, including all implied warranties of merchantability and
32 # fitness. In no event shall Lucent be liable for any special, indirect
33 # or consequential damages or any damages whatsoever resulting from loss
34 # of use, data or profits, whether in an action of contract, negligence
35 # or other tortuous action, arising out of or in connection with the use
36 # or performance of this software.
38 # ======================================================================
40 namespace eval blt::tv {
49 image create photo blt::tv::normalCloseFolder -format gif -data {
50 R0lGODlhEAANAMIAAAAAAH9/f///////AL+/vwAA/wAAAAAAACH5BAEAAAUALAAAAAAQAA0A
51 AAM8WBrM+rAEQWmIb5KxiWjNInCkV32AJHRlGQBgDA7vdN4vUa8tC78qlrCWmvRKsJTquHkp
54 image create photo blt::tv::normalOpenFolder -format gif -data {
55 R0lGODlhEAANAMIAAAAAAH9/f///////AL+/vwAA/wAAAAAAACH5BAEAAAUALAAAAAAQAA0A
56 AAM1WBrM+rAEMigJ8c3Kb3OSII6kGABhp1JnaK1VGwjwKwtvHqNzzd263M3H4n2OH1QBwGw6
59 image create photo blt::tv::activeCloseFolder -format gif -data {
60 R0lGODlhEAANAMIAAAAAAH9/f/////+/AL+/vwAA/wAAAAAAACH5BAEAAAUALAAAAAAQAA0A
61 AAM8WBrM+rAEQWmIb5KxiWjNInCkV32AJHRlGQBgDA7vdN4vUa8tC78qlrCWmvRKsJTquHkp
64 image create photo blt::tv::activeOpenFolder -format gif -data {
65 R0lGODlhEAANAMIAAAAAAH9/f/////+/AL+/vwAA/wAAAAAAACH5BAEAAAUALAAAAAAQAA0A
66 AAM1WBrM+rAEMigJ8c3Kb3OSII6kGABhp1JnaK1VGwjwKwtvHqNzzd263M3H4n2OH1QBwGw6
70 if { $tcl_platform(platform) == "windows" } {
71 if { $tk_version >= 8.3 } {
72 set cursor "@[file join $blt_library treeview.cur]"
76 option add *${className}.ResizeCursor [list $cursor]
78 option add *${className}.ResizeCursor \
79 "@$blt_library/treeview.xbm $blt_library/treeview_m.xbm black white"
82 # ----------------------------------------------------------------------
86 # Invoked by internally by Treeview_Init routine. Initializes
87 # the default bindings for the treeview widget entries. These
88 # are local to the widget, so they can't be set through the
89 # widget's class bind tags.
91 # ----------------------------------------------------------------------
92 proc blt::tv::Initialize { w } {
94 # Active entry bindings
96 $w bind Entry <Enter> {
97 %W entry highlight current
99 $w bind Entry <Leave> {
100 %W entry highlight ""
106 $w button bind all <ButtonRelease-1> {
107 %W see -anchor nw current
110 $w button bind all <Enter> {
111 %W button highlight current
113 $w button bind all <Leave> {
114 %W button highlight ""
120 # Performs the following operations:
122 # 1. Clears the previous selection.
123 # 2. Selects the current entry.
124 # 3. Sets the focus to this entry.
125 # 4. Scrolls the entry into view.
126 # 5. Sets the selection anchor to this entry, just in case
127 # this is "multiple" mode.
130 $w bind Entry <ButtonPress-1> {
131 blt::tv::SetSelectionAnchor %W current
132 set blt::tv::scroll 1
135 $w bind Entry <Double-ButtonPress-1> {
142 # For "multiple" mode only. Saves the current location of the
143 # pointer for auto-scrolling. Resets the selection mark.
145 $w bind Entry <B1-Motion> {
148 set index [%W nearest %x %y]
149 if { [%W cget -selectmode] == "multiple" } {
150 %W selection mark $index
152 blt::tv::SetSelectionAnchor %W $index
159 # For "multiple" mode only.
161 $w bind Entry <ButtonRelease-1> {
162 if { [%W cget -selectmode] == "multiple" } {
163 %W selection anchor current
165 after cancel $blt::tv::afterId
166 set blt::tv::scroll 0
170 # Shift-ButtonPress-1
172 # For "multiple" mode only.
175 $w bind Entry <Shift-ButtonPress-1> {
176 if { [%W cget -selectmode] == "multiple" && [%W selection present] } {
177 if { [%W index anchor] == "" } {
178 %W selection anchor current
180 set index [%W index anchor]
181 %W selection clearall
182 %W selection set $index current
184 blt::tv::SetSelectionAnchor %W current
187 $w bind Entry <Shift-Double-ButtonPress-1> {
190 $w bind Entry <Shift-B1-Motion> {
193 $w bind Entry <Shift-ButtonRelease-1> {
194 after cancel $blt::tv::afterId
195 set blt::tv::scroll 0
199 # Control-ButtonPress-1
201 # For "multiple" mode only.
203 $w bind Entry <Control-ButtonPress-1> {
204 if { [%W cget -selectmode] == "multiple" } {
205 set index [%W index current]
206 %W selection toggle $index
207 %W selection anchor $index
209 blt::tv::SetSelectionAnchor %W current
212 $w bind Entry <Control-Double-ButtonPress-1> {
215 $w bind Entry <Control-B1-Motion> {
218 $w bind Entry <Control-ButtonRelease-1> {
219 after cancel $blt::tv::afterId
220 set blt::tv::scroll 0
223 $w bind Entry <Control-Shift-ButtonPress-1> {
224 if { [%W cget -selectmode] == "multiple" && [%W selection present] } {
225 if { [%W index anchor] == "" } {
226 %W selection anchor current
228 if { [%W selection includes anchor] } {
229 %W selection set anchor current
231 %W selection clear anchor current
232 %W selection set current
235 blt::tv::SetSelectionAnchor %W current
238 $w bind Entry <Control-Shift-Double-ButtonPress-1> {
241 $w bind Entry <Control-Shift-B1-Motion> {
245 $w bind Entry <Shift-ButtonPress-3> {
246 blt::tv::EditColumn %W %X %Y
249 $w column bind all <Enter> {
250 %W column highlight [%W column current]
252 $w column bind all <Leave> {
253 %W column highlight ""
255 $w column bind Rule <Enter> {
256 %W column highlight [%W column current]
257 %W column resize activate [%W column current]
259 $w column bind Rule <Leave> {
260 %W column highlight ""
261 %W column resize activate ""
263 $w column bind Rule <ButtonPress-1> {
264 %W column resize anchor %x
266 $w column bind Rule <B1-Motion> {
267 %W column resize mark %x
269 $w column bind Rule <ButtonRelease-1> {
270 %W column configure [%W column current] -width [%W column resize set]
272 $w column bind all <ButtonPress-1> {
273 set blt::tv::column [%W column current]
274 %W column configure $blt::tv::column -titlerelief sunken
276 $w column bind all <ButtonRelease-1> {
277 set column [%W column current]
278 if { $column != "" } {
279 %W column invoke $column
281 %W column configure $blt::tv::column -titlerelief raised
283 $w bind TextBoxStyle <ButtonPress-3> {
284 if { [%W edit -root -test %X %Y] } {
288 $w bind TextBoxStyle <ButtonRelease-3> {
289 if { [%W edit -root -test %X %Y] } {
290 blt::tv::EditColumn %W %X %Y
294 $w bind CheckBoxStyle <Enter> {
295 set column [%W column current]
296 if { [%W column cget $column -edit] } {
297 %W style activate current $column
300 $w bind CheckBoxStyle <Leave> {
303 $w bind CheckBoxStyle <ButtonPress-1> {
304 set column [%W column current]
305 if { [%W column cget $column -edit] } {
309 $w bind CheckBoxStyle <B1-Motion> {
310 set column [%W column current]
311 if { [%W column cget $column -edit] } {
315 $w bind CheckBoxStyle <ButtonRelease-1> {
316 if { [%W edit -root -test %X %Y] } {
321 $w bind ComboBoxStyle <ButtonPress-1> {
322 set column [%W column current]
323 if { [%W column cget $column -edit] } {
327 $w bind ComboBoxStyle <ButtonRelease-1> {
328 if { [%W edit -root -test %X %Y] } {
335 # ----------------------------------------------------------------------
339 # Invoked when the user is selecting elements in a treeview
340 # widget and drags the mouse pointer outside of the widget.
341 # Scrolls the view in the direction of the pointer.
343 # ----------------------------------------------------------------------
344 proc blt::tv::AutoScroll { w } {
345 if { ![winfo exists $w] } {
351 set index [$w nearest $x $y]
353 if {$y >= [winfo height $w]} {
354 $w yview scroll 1 units
357 $w yview scroll -1 units
362 if { [$w cget -selectmode] == "single" } {
363 blt::tv::SetSelectionAnchor $w $neighbor
365 $w selection mark $index
367 set ::blt::tv::afterId [after 50 blt::tv::AutoScroll $w]
370 proc blt::tv::SetSelectionAnchor { w tagOrId } {
371 set index [$w index $tagOrId]
372 # If the anchor hasn't changed, don't do anything
373 if { $index != [$w index anchor] } {
374 $w selection clearall
377 $w selection set $index
378 $w selection anchor $index
382 # ----------------------------------------------------------------------
386 # Invoked by KeyPress bindings. Moves the active selection to
387 # the entry <where>, which is an index such as "up", "down",
388 # "prevsibling", "nextsibling", etc.
390 # ----------------------------------------------------------------------
391 proc blt::tv::MoveFocus { w tagOrId } {
392 catch {$w focus $tagOrId}
393 if { [$w cget -selectmode] == "single" } {
394 $w selection clearall
395 $w selection set focus
396 $w selection anchor focus
401 # ----------------------------------------------------------------------
405 # Invoked by KeyPress bindings. Pages the current view up or
406 # down. The <where> argument should be either "top" or
409 # ----------------------------------------------------------------------
410 proc blt::tv::MovePage { w where } {
412 # If the focus is already at the top/bottom of the window, we want
413 # to scroll a page. It's really one page minus an entry because we
414 # want to see the last entry on the next/last page.
415 if { [$w index focus] == [$w index view.$where] } {
416 if {$where == "top"} {
417 $w yview scroll -1 pages
418 $w yview scroll 1 units
420 $w yview scroll 1 pages
421 $w yview scroll -1 units
426 # Adjust the entry focus and the view. Also activate the entry.
427 # just in case the mouse point is not in the widget.
428 $w entry highlight view.$where
431 if { [$w cget -selectmode] == "single" } {
432 $w selection clearall
433 $w selection set focus
437 # ----------------------------------------------------------------------
441 # Invoked by KeyPress bindings. Searches for an entry that
442 # starts with the letter <char> and makes that entry active.
444 # ----------------------------------------------------------------------
445 proc blt::tv::NextMatch { w key } {
446 if {[string match {[ -~]} $key]} {
447 set last [$w index focus]
448 set next [$w index next]
449 while { $next != $last } {
450 set label [$w entry cget $next -label]
451 set label [string index $label 0]
452 if { [string tolower $label] == [string tolower $key] } {
455 set next [$w index -at $next next]
458 if {[$w cget -selectmode] == "single"} {
459 $w selection clearall
460 $w selection set focus
466 #------------------------------------------------------------------------
470 # Inserts a text string into an entry at the insertion cursor.
471 # If there is a selection in the entry, and it covers the point
472 # of the insertion cursor, then delete the selection before
476 # w Widget where to insert the text.
477 # text Text string to insert (usually just a single character)
479 #------------------------------------------------------------------------
480 proc blt::tv::InsertText { w text } {
481 if { [string length $text] > 0 } {
482 set index [$w index insert]
483 if { ($index >= [$w index sel.first]) &&
484 ($index <= [$w index sel.last]) } {
485 $w delete sel.first sel.last
487 $w insert $index $text
491 #------------------------------------------------------------------------
495 # This procedure implements the "transpose" function for entry
496 # widgets. It tranposes the characters on either side of the
497 # insertion cursor, unless the cursor is at the end of the line.
498 # In this case it transposes the two characters to the left of
499 # the cursor. In either case, the cursor ends up to the right
500 # of the transposed characters.
503 # w The entry window.
505 #------------------------------------------------------------------------
506 proc blt::tv::Transpose { w } {
507 set i [$w index insert]
508 if {$i < [$w index end]} {
511 set first [expr {$i-2}]
515 set new [string index [$w get] [expr {$i-1}]][string index [$w get] $first]
517 $w insert insert $new
520 #------------------------------------------------------------------------
524 # Returns the selected text of the entry with respect to the
528 # w Entry window from which the text to get
530 #------------------------------------------------------------------------
532 proc blt::tv::GetSelection { w } {
533 set text [string range [$w get] [$w index sel.first] \
534 [expr [$w index sel.last] - 1]]
535 if {[$w cget -show] != ""} {
536 regsub -all . $text [string index [$w cget -show] 0] text
541 proc blt::tv::EditColumn { w x y } {
543 if { [winfo exists $w.edit] } {
546 if { ![$w edit -root -test $x $y] } {
552 $w.edit selection range 0 end
554 tkwait window $w.edit
559 # ButtonPress assignments
561 # B1-Enter start auto-scrolling
562 # B1-Leave stop auto-scrolling
563 # ButtonPress-2 start scan
564 # B2-Motion adjust scan
565 # ButtonRelease-2 stop scan
568 bind ${className} <ButtonPress-2> {
569 set blt::tv::cursor [%W cget -cursor]
570 %W configure -cursor hand1
574 bind ${className} <B2-Motion> {
578 bind ${className} <ButtonRelease-2> {
579 %W configure -cursor $blt::tv::cursor
582 bind ${className} <B1-Leave> {
583 if { $blt::tv::scroll } {
584 blt::tv::AutoScroll %W
588 bind ${className} <B1-Enter> {
589 after cancel $blt::tv::afterId
593 # KeyPress assignments
603 # space Start selection toggle of entry currently with focus.
604 # Return Start selection toggle of entry currently with focus.
609 # ASCII char Go to next open entry starting with character.
613 # space Stop selection toggle of entry currently with focus.
614 # Return Stop selection toggle of entry currently with focus.
617 bind ${className} <KeyPress-Up> {
618 blt::tv::MoveFocus %W up
619 if { $blt::tv::space } {
620 %W selection toggle focus
624 bind ${className} <KeyPress-Down> {
625 blt::tv::MoveFocus %W down
626 if { $blt::tv::space } {
627 %W selection toggle focus
631 bind ${className} <Shift-KeyPress-Up> {
632 blt::tv::MoveFocus %W prevsibling
635 bind ${className} <Shift-KeyPress-Down> {
636 blt::tv::MoveFocus %W nextsibling
639 bind ${className} <KeyPress-Prior> {
640 blt::tv::MovePage %W top
643 bind ${className} <KeyPress-Next> {
644 blt::tv::MovePage %W bottom
647 bind ${className} <KeyPress-Left> {
650 bind ${className} <KeyPress-Right> {
652 %W see focus -anchor w
655 bind ${className} <KeyPress-space> {
656 if { [%W cget -selectmode] == "single" } {
657 if { [%W selection includes focus] } {
658 %W selection clearall
660 %W selection clearall
661 %W selection set focus
664 %W selection toggle focus
666 set blt::tv::space on
669 bind ${className} <KeyRelease-space> {
670 set blt::tv::space off
673 bind ${className} <KeyPress-Return> {
674 blt::tv::MoveFocus %W focus
675 set blt::tv::space on
678 bind ${className} <KeyRelease-Return> {
679 set blt::tv::space off
682 bind ${className} <KeyPress> {
683 blt::tv::NextMatch %W %A
686 bind ${className} <KeyPress-Home> {
687 blt::tv::MoveFocus %W top
690 bind ${className} <KeyPress-End> {
691 blt::tv::MoveFocus %W bottom
694 bind ${className} <KeyPress-F1> {
698 bind ${className} <KeyPress-F2> {
699 eval %W close -r [%W entry children root]
703 # Differences between id "current" and operation nearest.
705 # set index [$w index current]
706 # set index [$w nearest $x $y]
708 # o Nearest gives you the closest entry.
710 # 1) the pointer isn't over an entry.
711 # 2) the pointer is over a open/close button.
716 # Edit mode assignments
718 # ButtonPress-3 Enables/disables edit mode on entry. Sets focus to
723 # Left Move insertion position to previous.
724 # Right Move insertion position to next.
725 # Up Move insertion position up one line.
726 # Down Move insertion position down one line.
727 # Return End edit mode.
728 # Shift-Return Line feed.
729 # Home Move to first position.
730 # End Move to last position.
731 # ASCII char Insert character left of insertion point.
732 # Del Delete character right of insertion point.
733 # Delete Delete character left of insertion point.
740 # ButtonPress-1 Start selection if in entry, otherwise clear selection.
741 # B1-Motion Extend/reduce selection.
742 # ButtonRelease-1 End selection if in entry, otherwise use last
746 # ButtonPress-2 Same as above.
747 # B2-Motion Same as above.
748 # ButtonRelease-2 Same as above.
753 # Standard Motif bindings:
755 bind ${className}Editor <ButtonPress-1> {
760 bind ${className}Editor <Left> {
765 bind ${className}Editor <Right> {
770 bind ${className}Editor <Shift-Left> {
771 set new [expr {[%W index insert] - 1}]
772 if {![%W selection present]} {
773 %W selection from insert
776 %W selection adjust $new
781 bind ${className}Editor <Shift-Right> {
782 set new [expr {[%W index insert] + 1}]
783 if {![%W selection present]} {
784 %W selection from insert
787 %W selection adjust $new
792 bind ${className}Editor <Home> {
796 bind ${className}Editor <Shift-Home> {
798 if {![%W selection present]} {
799 %W selection from insert
802 %W selection adjust $new
806 bind ${className}Editor <End> {
810 bind ${className}Editor <Shift-End> {
812 if {![%W selection present]} {
813 %W selection from insert
816 %W selection adjust $new
821 bind ${className}Editor <Delete> {
822 if { [%W selection present]} {
823 %W delete sel.first sel.last
829 bind ${className}Editor <BackSpace> {
830 if { [%W selection present] } {
831 %W delete sel.first sel.last
833 set index [expr [%W index insert] - 1]
835 %W delete $index $index
840 bind ${className}Editor <Control-space> {
841 %W selection from insert
844 bind ${className}Editor <Select> {
845 %W selection from insert
848 bind ${className}Editor <Control-Shift-space> {
849 %W selection adjust insert
852 bind ${className}Editor <Shift-Select> {
853 %W selection adjust insert
856 bind ${className}Editor <Control-slash> {
857 %W selection range 0 end
860 bind ${className}Editor <Control-backslash> {
864 bind ${className}Editor <KeyPress> {
865 blt::tv::InsertText %W %A
868 # Ignore all Alt, Meta, and Control keypresses unless explicitly bound.
869 # Otherwise, if a widget binding for one of these is defined, the
870 # <KeyPress> class binding will also fire and insert the character,
871 # which is wrong. Ditto for Escape, Return, and Tab.
873 bind ${className}Editor <Alt-KeyPress> {
877 bind ${className}Editor <Meta-KeyPress> {
881 bind ${className}Editor <Control-KeyPress> {
885 bind ${className}Editor <Escape> {
889 bind ${className}Editor <Return> {
893 bind ${className}Editor <Shift-Return> {
894 blt::tv::InsertText %W "\n"
897 bind ${className}Editor <KP_Enter> {
901 bind ${className}Editor <Tab> {
905 if {![string compare $tcl_platform(platform) "macintosh"]} {
906 bind ${className}Editor <Command-KeyPress> {
911 # On Windows, paste is done using Shift-Insert. Shift-Insert already
912 # generates the <<Paste>> event, so we don't need to do anything here.
913 if { [string compare $tcl_platform(platform) "windows"] != 0 } {
914 bind ${className}Editor <Insert> {
915 catch {blt::tv::InsertText %W [selection get -displayof %W]}
919 # Additional emacs-like bindings:
920 bind ${className}Editor <ButtonPress-3> {
921 set parent [winfo parent %W]
924 blt::tv::EditColumn $parent %X %Y
928 bind ${className}Editor <Control-a> {
933 bind ${className}Editor <Control-b> {
934 %W icursor [expr {[%W index insert] - 1}]
938 bind ${className}Editor <Control-d> {
942 bind ${className}Editor <Control-e> {
947 bind ${className}Editor <Control-f> {
948 %W icursor [expr {[%W index insert] + 1}]
952 bind ${className}Editor <Control-h> {
953 if {[%W selection present]} {
954 %W delete sel.first sel.last
956 set index [expr [%W index insert] - 1]
958 %W delete $index $index
963 bind ${className}Editor <Control-k> {
968 bind ${className}Editor <Control-t> {
969 blt::tv::Transpose %W
971 bind ${className}Editor <Meta-b> {
972 %W icursor [blt::tv::PreviousWord %W insert]
975 bind ${className}Editor <Meta-d> {
976 %W delete insert [blt::tv::NextWord %W insert]
978 bind ${className}Editor <Meta-f> {
979 %W icursor [blt::tv::NextWord %W insert]
982 bind ${className}Editor <Meta-BackSpace> {
983 %W delete [blt::tv::PreviousWord %W insert] insert
985 bind ${className}Editor <Meta-Delete> {
986 %W delete [blt::tv::PreviousWord %W insert] insert
988 # tkEntryNextWord -- Returns the index of the next word position
989 # after a given position in the entry. The next word is platform
990 # dependent and may be either the next end-of-word position or the
991 # next start-of-word position after the next end-of-word position.
994 # w - The entry window in which the cursor is to move.
995 # start - Position at which to start search.
997 if {![string compare $tcl_platform(platform) "windows"]} {
998 proc blt::tv::NextWord {w start} {
999 set pos [tcl_endOfWord [$w get] [$w index $start]]
1001 set pos [tcl_startOfNextWord [$w get] $pos]
1009 proc blt::tv::NextWord {w start} {
1010 set pos [tcl_endOfWord [$w get] [$w index $start]]
1020 # Returns the index of the previous word position before a given
1021 # position in the entry.
1024 # w - The entry window in which the cursor is to move.
1025 # start - Position at which to start search.
1027 proc blt::tv::PreviousWord {w start} {
1028 set pos [tcl_startOfPreviousWord [$w get] [$w index $start]]