3 # This file defines the default bindings for Tk listbox widgets
4 # and provides procedures that help in implementing those bindings.
6 # RCS: @(#) $Id: listbox.tcl,v 1.11 2000/03/24 19:38:57 ericm Exp $
8 # Copyright (c) 1994 The Regents of the University of California.
9 # Copyright (c) 1994-1995 Sun Microsystems, Inc.
10 # Copyright (c) 1998 by Scriptics Corporation.
12 # See the file "license.terms" for information on usage and redistribution
13 # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15 #--------------------------------------------------------------------------
16 # tkPriv elements used in this file:
18 # afterId - Token returned by "after" for autoscanning.
19 # listboxPrev - The last element to be selected or deselected
20 # during a selection operation.
21 # listboxSelection - All of the items that were selected before the
22 # current selection operation (such as a mouse
23 # drag) started; used to cancel an operation.
24 #--------------------------------------------------------------------------
26 #-------------------------------------------------------------------------
27 # The code below creates the default class bindings for listboxes.
28 #-------------------------------------------------------------------------
30 # Note: the check for existence of %W below is because this binding
31 # is sometimes invoked after a window has been deleted (e.g. because
32 # there is a double-click binding on the widget that deletes it). Users
33 # can put "break"s in their bindings to avoid the error, but this check
34 # makes that unnecessary.
37 if {[winfo exists %W]} {
38 tkListboxBeginSelect %W [%W index @%x,%y]
42 # Ignore double clicks so that users can define their own behaviors.
43 # Among other things, this prevents errors if the user deletes the
44 # listbox on a double click.
46 bind Listbox <Double-1> {
50 bind Listbox <B1-Motion> {
53 tkListboxMotion %W [%W index @%x,%y]
55 bind Listbox <ButtonRelease-1> {
59 bind Listbox <Shift-1> {
60 tkListboxBeginExtend %W [%W index @%x,%y]
62 bind Listbox <Control-1> {
63 tkListboxBeginToggle %W [%W index @%x,%y]
65 bind Listbox <B1-Leave> {
70 bind Listbox <B1-Enter> {
77 bind Listbox <Shift-Up> {
78 tkListboxExtendUpDown %W -1
83 bind Listbox <Shift-Down> {
84 tkListboxExtendUpDown %W 1
87 %W xview scroll -1 units
89 bind Listbox <Control-Left> {
90 %W xview scroll -1 pages
92 bind Listbox <Right> {
93 %W xview scroll 1 units
95 bind Listbox <Control-Right> {
96 %W xview scroll 1 pages
98 bind Listbox <Prior> {
99 %W yview scroll -1 pages
102 bind Listbox <Next> {
103 %W yview scroll 1 pages
106 bind Listbox <Control-Prior> {
107 %W xview scroll -1 pages
109 bind Listbox <Control-Next> {
110 %W xview scroll 1 pages
112 bind Listbox <Home> {
118 bind Listbox <Control-Home> {
121 %W selection clear 0 end
123 event generate %W <<ListboxSelect>>
125 bind Listbox <Shift-Control-Home> {
126 tkListboxDataExtend %W 0
128 bind Listbox <Control-End> {
131 %W selection clear 0 end
133 event generate %W <<ListboxSelect>>
135 bind Listbox <Shift-Control-End> {
136 tkListboxDataExtend %W [%W index end]
138 bind Listbox <<Copy>> {
139 if {[string equal [selection own -displayof %W] "%W"]} {
140 clipboard clear -displayof %W
141 clipboard append -displayof %W [selection get -displayof %W]
144 bind Listbox <space> {
145 tkListboxBeginSelect %W [%W index active]
147 bind Listbox <Select> {
148 tkListboxBeginSelect %W [%W index active]
150 bind Listbox <Control-Shift-space> {
151 tkListboxBeginExtend %W [%W index active]
153 bind Listbox <Shift-Select> {
154 tkListboxBeginExtend %W [%W index active]
156 bind Listbox <Escape> {
159 bind Listbox <Control-slash> {
160 tkListboxSelectAll %W
162 bind Listbox <Control-backslash> {
163 if {[string compare [%W cget -selectmode] "browse"]} {
164 %W selection clear 0 end
165 event generate %W <<ListboxSelect>>
169 # Additional Tk bindings that aren't part of the Motif look and feel:
174 bind Listbox <B2-Motion> {
178 # The MouseWheel will typically only fire on Windows. However,
179 # someone could use the "event generate" command to produce one
180 # on other platforms.
182 bind Listbox <MouseWheel> {
183 %W yview scroll [expr {- (%D / 120) * 4}] units
186 if {[string equal "unix" $tcl_platform(platform)]} {
187 # Support for mousewheels on Linux/Unix commonly comes through mapping
188 # the wheel to the extended buttons. If you have a mousewheel, find
189 # Linux configuration info at:
190 # http://www.inria.fr/koala/colas/mouse-wheel-scroll/
192 if {!$tk_strictMotif} {
193 %W yview scroll -5 units
197 if {!$tk_strictMotif} {
198 %W yview scroll 5 units
203 # tkListboxBeginSelect --
205 # This procedure is typically invoked on button-1 presses. It begins
206 # the process of making a selection in the listbox. Its exact behavior
207 # depends on the selection mode currently in effect for the listbox;
208 # see the Motif documentation for details.
211 # w - The listbox widget.
212 # el - The element for the selection operation (typically the
213 # one under the pointer). Must be in numerical form.
215 proc tkListboxBeginSelect {w el} {
217 if {[string equal [$w cget -selectmode] "multiple"]} {
218 if {[$w selection includes $el]} {
219 $w selection clear $el
224 $w selection clear 0 end
226 $w selection anchor $el
227 set tkPriv(listboxSelection) {}
228 set tkPriv(listboxPrev) $el
230 event generate $w <<ListboxSelect>>
235 # This procedure is called to process mouse motion events while
236 # button 1 is down. It may move or extend the selection, depending
237 # on the listbox's selection mode.
240 # w - The listbox widget.
241 # el - The element under the pointer (must be a number).
243 proc tkListboxMotion {w el} {
245 if {$el == $tkPriv(listboxPrev)} {
248 set anchor [$w index anchor]
249 switch [$w cget -selectmode] {
251 $w selection clear 0 end
253 set tkPriv(listboxPrev) $el
254 event generate $w <<ListboxSelect>>
257 set i $tkPriv(listboxPrev)
258 if {[string equal {} $i]} {
262 if {[$w selection includes anchor]} {
263 $w selection clear $i $el
264 $w selection set anchor $el
266 $w selection clear $i $el
267 $w selection clear anchor $el
269 if {![info exists tkPriv(listboxSelection)]} {
270 set tkPriv(listboxSelection) [$w curselection]
272 while {($i < $el) && ($i < $anchor)} {
273 if {[lsearch $tkPriv(listboxSelection) $i] >= 0} {
278 while {($i > $el) && ($i > $anchor)} {
279 if {[lsearch $tkPriv(listboxSelection) $i] >= 0} {
284 set tkPriv(listboxPrev) $el
285 event generate $w <<ListboxSelect>>
290 # tkListboxBeginExtend --
292 # This procedure is typically invoked on shift-button-1 presses. It
293 # begins the process of extending a selection in the listbox. Its
294 # exact behavior depends on the selection mode currently in effect
295 # for the listbox; see the Motif documentation for details.
298 # w - The listbox widget.
299 # el - The element for the selection operation (typically the
300 # one under the pointer). Must be in numerical form.
302 proc tkListboxBeginExtend {w el} {
303 if {[string equal [$w cget -selectmode] "extended"]} {
304 if {[$w selection includes anchor]} {
305 tkListboxMotion $w $el
307 # No selection yet; simulate the begin-select operation.
308 tkListboxBeginSelect $w $el
313 # tkListboxBeginToggle --
315 # This procedure is typically invoked on control-button-1 presses. It
316 # begins the process of toggling a selection in the listbox. Its
317 # exact behavior depends on the selection mode currently in effect
318 # for the listbox; see the Motif documentation for details.
321 # w - The listbox widget.
322 # el - The element for the selection operation (typically the
323 # one under the pointer). Must be in numerical form.
325 proc tkListboxBeginToggle {w el} {
327 if {[string equal [$w cget -selectmode] "extended"]} {
328 set tkPriv(listboxSelection) [$w curselection]
329 set tkPriv(listboxPrev) $el
330 $w selection anchor $el
331 if {[$w selection includes $el]} {
332 $w selection clear $el
336 event generate $w <<ListboxSelect>>
340 # tkListboxAutoScan --
341 # This procedure is invoked when the mouse leaves an entry window
342 # with button 1 down. It scrolls the window up, down, left, or
343 # right, depending on where the mouse left the window, and reschedules
344 # itself as an "after" command so that the window continues to scroll until
345 # the mouse moves back into the window or the mouse button is released.
348 # w - The entry window.
350 proc tkListboxAutoScan {w} {
352 if {![winfo exists $w]} return
355 if {$y >= [winfo height $w]} {
356 $w yview scroll 1 units
358 $w yview scroll -1 units
359 } elseif {$x >= [winfo width $w]} {
360 $w xview scroll 2 units
362 $w xview scroll -2 units
366 tkListboxMotion $w [$w index @$x,$y]
367 set tkPriv(afterId) [after 50 [list tkListboxAutoScan $w]]
372 # Moves the location cursor (active element) up or down by one element,
373 # and changes the selection if we're in browse or extended selection
377 # w - The listbox widget.
378 # amount - +1 to move down one item, -1 to move back one item.
380 proc tkListboxUpDown {w amount} {
382 $w activate [expr {[$w index active] + $amount}]
384 switch [$w cget -selectmode] {
386 $w selection clear 0 end
387 $w selection set active
388 event generate $w <<ListboxSelect>>
391 $w selection clear 0 end
392 $w selection set active
393 $w selection anchor active
394 set tkPriv(listboxPrev) [$w index active]
395 set tkPriv(listboxSelection) {}
396 event generate $w <<ListboxSelect>>
401 # tkListboxExtendUpDown --
403 # Does nothing unless we're in extended selection mode; in this
404 # case it moves the location cursor (active element) up or down by
405 # one element, and extends the selection to that point.
408 # w - The listbox widget.
409 # amount - +1 to move down one item, -1 to move back one item.
411 proc tkListboxExtendUpDown {w amount} {
412 if {[string compare [$w cget -selectmode] "extended"]} {
415 set active [$w index active]
416 if {![info exists tkPriv(listboxSelection)]} {
418 $w selection set $active
419 set tkPriv(listboxSelection) [$w curselection]
421 $w activate [expr {$active + $amount}]
423 tkListboxMotion $w [$w index active]
426 # tkListboxDataExtend
428 # This procedure is called for key-presses such as Shift-KEndData.
429 # If the selection mode isn't multiple or extend then it does nothing.
430 # Otherwise it moves the active element to el and, if we're in
431 # extended mode, extends the selection to that point.
434 # w - The listbox widget.
435 # el - An integer element number.
437 proc tkListboxDataExtend {w el} {
438 set mode [$w cget -selectmode]
439 if {[string equal $mode "extended"]} {
442 if {[$w selection includes anchor]} {
443 tkListboxMotion $w $el
445 } elseif {[string equal $mode "multiple"]} {
453 # This procedure is invoked to cancel an extended selection in
454 # progress. If there is an extended selection in progress, it
455 # restores all of the items between the active one and the anchor
456 # to their previous selection state.
459 # w - The listbox widget.
461 proc tkListboxCancel w {
463 if {[string compare [$w cget -selectmode] "extended"]} {
466 set first [$w index anchor]
467 set last $tkPriv(listboxPrev)
468 if { [string equal $last ""] } {
469 # Not actually doing any selection right now
472 if {$first > $last} {
477 $w selection clear $first $last
478 while {$first <= $last} {
479 if {[lsearch $tkPriv(listboxSelection) $first] >= 0} {
480 $w selection set $first
484 event generate $w <<ListboxSelect>>
489 # This procedure is invoked to handle the "select all" operation.
490 # For single and browse mode, it just selects the active element.
491 # Otherwise it selects everything in the widget.
494 # w - The listbox widget.
496 proc tkListboxSelectAll w {
497 set mode [$w cget -selectmode]
498 if {[string equal $mode "single"] || [string equal $mode "browse"]} {
499 $w selection clear 0 end
500 $w selection set active
502 $w selection set 0 end
504 event generate $w <<ListboxSelect>>