3 # This file defines the default bindings for Tk entry widgets and provides
4 # procedures that help in implementing those bindings.
8 # Copyright (c) 1992-1994 The Regents of the University of California.
9 # Copyright (c) 1994-1997 Sun Microsystems, Inc.
11 # See the file "license.terms" for information on usage and redistribution
12 # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15 #-------------------------------------------------------------------------
16 # Elements of tkPriv that are used in this file:
18 # afterId - If non-null, it means that auto-scanning is underway
19 # and it gives the "after" id for the next auto-scan
20 # command to be executed.
21 # mouseMoved - Non-zero means the mouse has moved a significant
22 # amount since the button went down (so, for example,
23 # start dragging out a selection).
24 # pressX - X-coordinate at which the mouse button was pressed.
25 # selectMode - The style of selection currently underway:
26 # char, word, or line.
27 # x, y - Last known mouse coordinates for scanning
29 # data - Used for Cut and Copy
30 #-------------------------------------------------------------------------
32 #-------------------------------------------------------------------------
33 # The code below creates the default class bindings for entries.
34 #-------------------------------------------------------------------------
36 if {![catch {tkEntryGetSelection %W} tkPriv(data)]} {
37 clipboard clear -displayof %W
38 clipboard append -displayof %W $tkPriv(data)
39 %W delete sel.first sel.last
44 if {![catch {tkEntryGetSelection %W} tkPriv(data)]} {
45 clipboard clear -displayof %W
46 clipboard append -displayof %W $tkPriv(data)
50 bind Entry <<Paste>> {
53 if {[string compare $tcl_platform(platform) "unix"]} {
55 %W delete sel.first sel.last
58 %W insert insert [selection get -displayof %W -selection CLIPBOARD]
62 bind Entry <<Clear>> {
63 %W delete sel.first sel.last
65 bind Entry <<PasteSelection>> {
66 if {!$tkPriv(mouseMoved) || $tk_strictMotif} {
71 # Standard Motif bindings:
77 bind Entry <B1-Motion> {
79 tkEntryMouseSelect %W %x
81 bind Entry <Double-1> {
82 set tkPriv(selectMode) word
83 tkEntryMouseSelect %W %x
84 catch {%W icursor sel.first}
86 bind Entry <Triple-1> {
87 set tkPriv(selectMode) line
88 tkEntryMouseSelect %W %x
91 bind Entry <Shift-1> {
92 set tkPriv(selectMode) char
93 %W selection adjust @%x
95 bind Entry <Double-Shift-1> {
96 set tkPriv(selectMode) word
97 tkEntryMouseSelect %W %x
99 bind Entry <Triple-Shift-1> {
100 set tkPriv(selectMode) line
101 tkEntryMouseSelect %W %x
103 bind Entry <B1-Leave> {
107 bind Entry <B1-Enter> {
110 bind Entry <ButtonRelease-1> {
113 bind Entry <Control-1> {
118 tkEntrySetCursor %W [expr {[%W index insert] - 1}]
121 tkEntrySetCursor %W [expr {[%W index insert] + 1}]
123 bind Entry <Shift-Left> {
124 tkEntryKeySelect %W [expr {[%W index insert] - 1}]
127 bind Entry <Shift-Right> {
128 tkEntryKeySelect %W [expr {[%W index insert] + 1}]
131 bind Entry <Control-Left> {
132 tkEntrySetCursor %W [tkEntryPreviousWord %W insert]
134 bind Entry <Control-Right> {
135 tkEntrySetCursor %W [tkEntryNextWord %W insert]
137 bind Entry <Shift-Control-Left> {
138 tkEntryKeySelect %W [tkEntryPreviousWord %W insert]
141 bind Entry <Shift-Control-Right> {
142 tkEntryKeySelect %W [tkEntryNextWord %W insert]
146 tkEntrySetCursor %W 0
148 bind Entry <Shift-Home> {
149 tkEntryKeySelect %W 0
153 tkEntrySetCursor %W end
155 bind Entry <Shift-End> {
156 tkEntryKeySelect %W end
160 bind Entry <Delete> {
161 if {[%W selection present]} {
162 %W delete sel.first sel.last
167 bind Entry <BackSpace> {
171 bind Entry <Control-space> {
172 %W selection from insert
174 bind Entry <Select> {
175 %W selection from insert
177 bind Entry <Control-Shift-space> {
178 %W selection adjust insert
180 bind Entry <Shift-Select> {
181 %W selection adjust insert
183 bind Entry <Control-slash> {
184 %W selection range 0 end
186 bind Entry <Control-backslash> {
189 bind Entry <KeyPress> {
193 # Ignore all Alt, Meta, and Control keypresses unless explicitly bound.
194 # Otherwise, if a widget binding for one of these is defined, the
195 # <KeyPress> class binding will also fire and insert the character,
196 # which is wrong. Ditto for Escape, Return, and Tab.
198 bind Entry <Alt-KeyPress> {# nothing}
199 bind Entry <Meta-KeyPress> {# nothing}
200 bind Entry <Control-KeyPress> {# nothing}
201 bind Entry <Escape> {# nothing}
202 bind Entry <Return> {# nothing}
203 bind Entry <KP_Enter> {# nothing}
204 bind Entry <Tab> {# nothing}
205 if {[string equal $tcl_platform(platform) "macintosh"]} {
206 bind Entry <Command-KeyPress> {# nothing}
209 # On Windows, paste is done using Shift-Insert. Shift-Insert already
210 # generates the <<Paste>> event, so we don't need to do anything here.
211 if {[string compare $tcl_platform(platform) "windows"]} {
212 bind Entry <Insert> {
213 catch {tkEntryInsert %W [selection get -displayof %W]}
217 # Additional emacs-like bindings:
219 bind Entry <Control-a> {
220 if {!$tk_strictMotif} {
221 tkEntrySetCursor %W 0
224 bind Entry <Control-b> {
225 if {!$tk_strictMotif} {
226 tkEntrySetCursor %W [expr {[%W index insert] - 1}]
229 bind Entry <Control-d> {
230 if {!$tk_strictMotif} {
234 bind Entry <Control-e> {
235 if {!$tk_strictMotif} {
236 tkEntrySetCursor %W end
239 bind Entry <Control-f> {
240 if {!$tk_strictMotif} {
241 tkEntrySetCursor %W [expr {[%W index insert] + 1}]
244 bind Entry <Control-h> {
245 if {!$tk_strictMotif} {
249 bind Entry <Control-k> {
250 if {!$tk_strictMotif} {
254 bind Entry <Control-t> {
255 if {!$tk_strictMotif} {
259 bind Entry <Meta-b> {
260 if {!$tk_strictMotif} {
261 tkEntrySetCursor %W [tkEntryPreviousWord %W insert]
264 bind Entry <Meta-d> {
265 if {!$tk_strictMotif} {
266 %W delete insert [tkEntryNextWord %W insert]
269 bind Entry <Meta-f> {
270 if {!$tk_strictMotif} {
271 tkEntrySetCursor %W [tkEntryNextWord %W insert]
274 bind Entry <Meta-BackSpace> {
275 if {!$tk_strictMotif} {
276 %W delete [tkEntryPreviousWord %W insert] insert
279 bind Entry <Meta-Delete> {
280 if {!$tk_strictMotif} {
281 %W delete [tkEntryPreviousWord %W insert] insert
285 # A few additional bindings of my own.
288 if {!$tk_strictMotif} {
292 set tkPriv(mouseMoved) 0
295 bind Entry <B2-Motion> {
296 if {!$tk_strictMotif} {
297 if {abs(%x-$tkPriv(x)) > 2} {
298 set tkPriv(mouseMoved) 1
304 # tkEntryClosestGap --
305 # Given x and y coordinates, this procedure finds the closest boundary
306 # between characters to the given coordinates and returns the index
307 # of the character just after the boundary.
310 # w - The entry window.
311 # x - X-coordinate within the window.
313 proc tkEntryClosestGap {w x} {
314 set pos [$w index @$x]
315 set bbox [$w bbox $pos]
316 if {($x - [lindex $bbox 0]) < ([lindex $bbox 2]/2)} {
323 # This procedure is invoked to handle button-1 presses in entry
324 # widgets. It moves the insertion cursor, sets the selection anchor,
325 # and claims the input focus.
328 # w - The entry window in which the button was pressed.
329 # x - The x-coordinate of the button press.
331 proc tkEntryButton1 {w x} {
334 set tkPriv(selectMode) char
335 set tkPriv(mouseMoved) 0
336 set tkPriv(pressX) $x
337 $w icursor [tkEntryClosestGap $w $x]
338 $w selection from insert
339 if {[string equal [$w cget -state] "normal"]} {focus $w}
342 # tkEntryMouseSelect --
343 # This procedure is invoked when dragging out a selection with
344 # the mouse. Depending on the selection mode (character, word,
345 # line) it selects in different-sized units. This procedure
346 # ignores mouse motions initially until the mouse has moved from
347 # one character to another or until there have been multiple clicks.
350 # w - The entry window in which the button was pressed.
351 # x - The x-coordinate of the mouse.
353 proc tkEntryMouseSelect {w x} {
356 set cur [tkEntryClosestGap $w $x]
357 set anchor [$w index anchor]
358 if {($cur != $anchor) || (abs($tkPriv(pressX) - $x) >= 3)} {
359 set tkPriv(mouseMoved) 1
361 switch $tkPriv(selectMode) {
363 if {$tkPriv(mouseMoved)} {
364 if {$cur < $anchor} {
365 $w selection range $cur $anchor
366 } elseif {$cur > $anchor} {
367 $w selection range $anchor $cur
374 if {$cur < [$w index anchor]} {
375 set before [tcl_wordBreakBefore [$w get] $cur]
376 set after [tcl_wordBreakAfter [$w get] [expr {$anchor-1}]]
378 set before [tcl_wordBreakBefore [$w get] $anchor]
379 set after [tcl_wordBreakAfter [$w get] [expr {$cur - 1}]]
387 $w selection range $before $after
390 $w selection range 0 end
397 # This procedure sets the insertion cursor to the current mouse position,
398 # pastes the selection there, and sets the focus to the window.
401 # w - The entry window.
402 # x - X position of the mouse.
404 proc tkEntryPaste {w x} {
407 $w icursor [tkEntryClosestGap $w $x]
408 catch {$w insert insert [selection get -displayof $w]}
409 if {[string equal [$w cget -state] "normal"]} {focus $w}
413 # This procedure is invoked when the mouse leaves an entry window
414 # with button 1 down. It scrolls the window left or right,
415 # depending on where the mouse is, and reschedules itself as an
416 # "after" command so that the window continues to scroll until the
417 # mouse moves back into the window or the mouse button is released.
420 # w - The entry window.
422 proc tkEntryAutoScan {w} {
425 if {![winfo exists $w]} return
426 if {$x >= [winfo width $w]} {
427 $w xview scroll 2 units
428 tkEntryMouseSelect $w $x
430 $w xview scroll -2 units
431 tkEntryMouseSelect $w $x
433 set tkPriv(afterId) [after 50 [list tkEntryAutoScan $w]]
436 # tkEntryKeySelect --
437 # This procedure is invoked when stroking out selections using the
438 # keyboard. It moves the cursor to a new position, then extends
439 # the selection to that position.
442 # w - The entry window.
443 # new - A new position for the insertion cursor (the cursor hasn't
444 # actually been moved to this position yet).
446 proc tkEntryKeySelect {w new} {
447 if {![$w selection present]} {
448 $w selection from insert
451 $w selection adjust $new
457 # Insert a string into an entry at the point of the insertion cursor.
458 # If there is a selection in the entry, and it covers the point of the
459 # insertion cursor, then delete the selection before inserting.
462 # w - The entry window in which to insert the string
463 # s - The string to insert (usually just a single character)
465 proc tkEntryInsert {w s} {
466 if {[string equal $s ""]} {
470 set insert [$w index insert]
471 if {([$w index sel.first] <= $insert)
472 && ([$w index sel.last] >= $insert)} {
473 $w delete sel.first sel.last
480 # tkEntryBackspace --
481 # Backspace over the character just before the insertion cursor.
482 # If backspacing would move the cursor off the left edge of the
483 # window, reposition the cursor at about the middle of the window.
486 # w - The entry window in which to backspace.
488 proc tkEntryBackspace w {
489 if {[$w selection present]} {
490 $w delete sel.first sel.last
492 set x [expr {[$w index insert] - 1}]
493 if {$x >= 0} {$w delete $x}
494 if {[$w index @0] >= [$w index insert]} {
496 set left [lindex $range 0]
497 set right [lindex $range 1]
498 $w xview moveto [expr {$left - ($right - $left)/2.0}]
503 # tkEntrySeeInsert --
504 # Make sure that the insertion cursor is visible in the entry window.
505 # If not, adjust the view so that it is.
508 # w - The entry window.
510 proc tkEntrySeeInsert w {
511 set c [$w index insert]
512 if {($c < [$w index @0]) || ($c > [$w index @[winfo width $w]])} {
518 # Move the insertion cursor to a given position in an entry. Also
519 # clears the selection, if there is one in the entry, and makes sure
520 # that the insertion cursor is visible.
523 # w - The entry window.
524 # pos - The desired new position for the cursor in the window.
526 proc tkEntrySetCursor {w pos} {
533 # This procedure implements the "transpose" function for entry widgets.
534 # It tranposes the characters on either side of the insertion cursor,
535 # unless the cursor is at the end of the line. In this case it
536 # transposes the two characters to the left of the cursor. In either
537 # case, the cursor ends up to the right of the transposed characters.
540 # w - The entry window.
542 proc tkEntryTranspose w {
543 set i [$w index insert]
544 if {$i < [$w index end]} {
547 set first [expr {$i-2}]
551 set new [string index [$w get] [expr {$i-1}]][string index [$w get] $first]
553 $w insert insert $new
558 # Returns the index of the next word position after a given position in the
559 # entry. The next word is platform dependent and may be either the next
560 # end-of-word position or the next start-of-word position after the next
561 # end-of-word position.
564 # w - The entry window in which the cursor is to move.
565 # start - Position at which to start search.
567 if {[string equal $tcl_platform(platform) "windows"]} {
568 proc tkEntryNextWord {w start} {
569 set pos [tcl_endOfWord [$w get] [$w index $start]]
571 set pos [tcl_startOfNextWord [$w get] $pos]
579 proc tkEntryNextWord {w start} {
580 set pos [tcl_endOfWord [$w get] [$w index $start]]
588 # tkEntryPreviousWord --
590 # Returns the index of the previous word position before a given
591 # position in the entry.
594 # w - The entry window in which the cursor is to move.
595 # start - Position at which to start search.
597 proc tkEntryPreviousWord {w start} {
598 set pos [tcl_startOfPreviousWord [$w get] [$w index $start]]
604 # tkEntryGetSelection --
606 # Returns the selected text of the entry with respect to the -show option.
609 # w - The entry window from which the text to get
611 proc tkEntryGetSelection {w} {
612 set entryString [string range [$w get] [$w index sel.first] \
613 [expr {[$w index sel.last] - 1}]]
614 if {[string compare [$w cget -show] ""]} {
615 regsub -all . $entryString [string index [$w cget -show] 0] entryString