3 # This file defines the default bindings for Tk entry widgets and provides
4 # procedures that help in implementing those bindings.
6 # Copyright (c) 1992-1994 The Regents of the University of California.
7 # Copyright (c) 1994-1997 Sun Microsystems, Inc.
9 # See the file "license.terms" for information on usage and redistribution
10 # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 #-------------------------------------------------------------------------
14 # Elements of tk::Priv that are used in this file:
16 # afterId - If non-null, it means that auto-scanning is underway
17 # and it gives the "after" id for the next auto-scan
18 # command to be executed.
19 # mouseMoved - Non-zero means the mouse has moved a significant
20 # amount since the button went down (so, for example,
21 # start dragging out a selection).
22 # pressX - X-coordinate at which the mouse button was pressed.
23 # selectMode - The style of selection currently underway:
24 # char, word, or line.
25 # x, y - Last known mouse coordinates for scanning
27 # data - Used for Cut and Copy
28 #-------------------------------------------------------------------------
30 #-------------------------------------------------------------------------
31 # The code below creates the default class bindings for entries.
32 #-------------------------------------------------------------------------
34 if {![catch {tk::EntryGetSelection %W
} tk::Priv(data
)]} {
35 clipboard clear
-displayof %W
36 clipboard append -displayof %W
$tk::Priv(data
)
37 %W delete sel.first sel.last
42 if {![catch {tk::EntryGetSelection %W
} tk::Priv(data
)]} {
43 clipboard clear
-displayof %W
44 clipboard append -displayof %W
$tk::Priv(data
)
48 bind Entry
<<Paste
>> {
51 if {[tk windowingsystem
] ne
"x11"} {
53 %W delete sel.first sel.last
56 %W insert insert
[::tk::GetSelection %W CLIPBOARD
]
60 bind Entry
<<Clear
>> {
61 # ignore if there is no selection
62 catch { %W delete sel.first sel.last
}
64 bind Entry
<<PasteSelection
>> {
65 if {$tk_strictMotif ||
![info exists
tk::Priv(mouseMoved
)]
66 ||
!$tk::Priv(mouseMoved
)} {
71 bind Entry
<<TraverseIn
>> {
72 %W
selection range
0 end
76 # Standard Motif bindings:
79 tk::EntryButton1 %W
%x
82 bind Entry
<B1-Motion
> {
84 tk::EntryMouseSelect %W
%x
86 bind Entry
<Double-1
> {
87 set tk::Priv(selectMode
) word
88 tk::EntryMouseSelect %W
%x
89 catch {%W icursor sel.last
}
91 bind Entry
<Triple-1
> {
92 set tk::Priv(selectMode
) line
93 tk::EntryMouseSelect %W
%x
94 catch {%W icursor sel.last
}
96 bind Entry
<Shift-1
> {
97 set tk::Priv(selectMode
) char
98 %W
selection adjust
@%x
100 bind Entry
<Double-Shift-1
> {
101 set tk::Priv(selectMode
) word
102 tk::EntryMouseSelect %W
%x
104 bind Entry
<Triple-Shift-1
> {
105 set tk::Priv(selectMode
) line
106 tk::EntryMouseSelect %W
%x
108 bind Entry
<B1-Leave
> {
112 bind Entry
<B1-Enter
> {
115 bind Entry
<ButtonRelease-1
> {
118 bind Entry
<Control-1
> {
123 tk::EntrySetCursor %W
[expr {[%W index insert
] - 1}]
126 tk::EntrySetCursor %W
[expr {[%W index insert
] + 1}]
128 bind Entry
<Shift-Left
> {
129 tk::EntryKeySelect %W
[expr {[%W index insert
] - 1}]
130 tk::EntrySeeInsert %W
132 bind Entry
<Shift-Right
> {
133 tk::EntryKeySelect %W
[expr {[%W index insert
] + 1}]
134 tk::EntrySeeInsert %W
136 bind Entry
<Control-Left
> {
137 tk::EntrySetCursor %W
[tk::EntryPreviousWord %W insert
]
139 bind Entry
<Control-Right
> {
140 tk::EntrySetCursor %W
[tk::EntryNextWord %W insert
]
142 bind Entry
<Shift-Control-Left
> {
143 tk::EntryKeySelect %W
[tk::EntryPreviousWord %W insert
]
144 tk::EntrySeeInsert %W
146 bind Entry
<Shift-Control-Right
> {
147 tk::EntryKeySelect %W
[tk::EntryNextWord %W insert
]
148 tk::EntrySeeInsert %W
151 tk::EntrySetCursor %W
0
153 bind Entry
<Shift-Home
> {
154 tk::EntryKeySelect %W
0
155 tk::EntrySeeInsert %W
158 tk::EntrySetCursor %W end
160 bind Entry
<Shift-End
> {
161 tk::EntryKeySelect %W end
162 tk::EntrySeeInsert %W
165 bind Entry
<Delete
> {
166 if {[%W
selection present
]} {
167 %W delete sel.first sel.last
172 bind Entry
<BackSpace
> {
173 tk::EntryBackspace %W
176 bind Entry
<Control-space
> {
177 %W
selection from insert
179 bind Entry
<Select
> {
180 %W
selection from insert
182 bind Entry
<Control-Shift-space
> {
183 %W
selection adjust insert
185 bind Entry
<Shift-Select
> {
186 %W
selection adjust insert
188 bind Entry
<Control-slash
> {
189 %W
selection range
0 end
191 bind Entry
<Control-backslash
> {
194 bind Entry
<KeyPress
> {
196 tk::EntryInsert %W
%A
199 # Ignore all Alt, Meta, and Control keypresses unless explicitly bound.
200 # Otherwise, if a widget binding for one of these is defined, the
201 # <KeyPress> class binding will also fire and insert the character,
202 # which is wrong. Ditto for Escape, Return, and Tab.
204 bind Entry
<Alt-KeyPress
> {# nothing}
205 bind Entry
<Meta-KeyPress
> {# nothing}
206 bind Entry
<Control-KeyPress
> {# nothing}
207 bind Entry
<Escape
> {# nothing}
208 bind Entry
<Return
> {# nothing}
209 bind Entry
<KP_Enter
> {# nothing}
210 bind Entry
<Tab
> {# nothing}
211 if {[tk windowingsystem
] eq
"aqua"} {
212 bind Entry
<Command-KeyPress
> {# nothing}
215 # On Windows, paste is done using Shift-Insert. Shift-Insert already
216 # generates the <<Paste>> event, so we don't need to do anything here.
217 if {[tk windowingsystem
] ne
"win32"} {
218 bind Entry
<Insert
> {
219 catch {tk::EntryInsert %W
[::tk::GetSelection %W PRIMARY
]}
223 # Additional emacs-like bindings:
225 bind Entry
<Control-a
> {
226 if {!$tk_strictMotif} {
227 tk::EntrySetCursor %W
0
230 bind Entry
<Control-b
> {
231 if {!$tk_strictMotif} {
232 tk::EntrySetCursor %W
[expr {[%W index insert
] - 1}]
235 bind Entry
<Control-d
> {
236 if {!$tk_strictMotif} {
240 bind Entry
<Control-e
> {
241 if {!$tk_strictMotif} {
242 tk::EntrySetCursor %W end
245 bind Entry
<Control-f
> {
246 if {!$tk_strictMotif} {
247 tk::EntrySetCursor %W
[expr {[%W index insert
] + 1}]
250 bind Entry
<Control-h
> {
251 if {!$tk_strictMotif} {
252 tk::EntryBackspace %W
255 bind Entry
<Control-k
> {
256 if {!$tk_strictMotif} {
260 bind Entry
<Control-t
> {
261 if {!$tk_strictMotif} {
262 tk::EntryTranspose %W
265 bind Entry
<Meta-b
> {
266 if {!$tk_strictMotif} {
267 tk::EntrySetCursor %W
[tk::EntryPreviousWord %W insert
]
270 bind Entry
<Meta-d
> {
271 if {!$tk_strictMotif} {
272 %W delete insert
[tk::EntryNextWord %W insert
]
275 bind Entry
<Meta-f
> {
276 if {!$tk_strictMotif} {
277 tk::EntrySetCursor %W
[tk::EntryNextWord %W insert
]
280 bind Entry
<Meta-BackSpace
> {
281 if {!$tk_strictMotif} {
282 %W delete
[tk::EntryPreviousWord %W insert
] insert
285 bind Entry
<Meta-Delete
> {
286 if {!$tk_strictMotif} {
287 %W delete
[tk::EntryPreviousWord %W insert
] insert
291 # A few additional bindings of my own.
294 if {!$tk_strictMotif} {
295 ::tk::EntryScanMark %W
%x
298 bind Entry
<B2-Motion
> {
299 if {!$tk_strictMotif} {
300 ::tk::EntryScanDrag %W
%x
304 # ::tk::EntryClosestGap --
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 ::tk::EntryClosestGap {w x
} {
314 set pos
[$w index
@$x]
315 set bbox
[$w bbox
$pos]
316 if {($x - [lindex $bbox 0]) < ([lindex $bbox 2]/2)} {
322 # ::tk::EntryButton1 --
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 ::tk::EntryButton1 {w x
} {
334 set Priv
(selectMode
) char
335 set Priv
(mouseMoved
) 0
337 $w icursor
[EntryClosestGap
$w $x]
338 $w selection from insert
339 if {"disabled" ne
[$w cget
-state]} {
344 # ::tk::EntryMouseSelect --
345 # This procedure is invoked when dragging out a selection with
346 # the mouse. Depending on the selection mode (character, word,
347 # line) it selects in different-sized units. This procedure
348 # ignores mouse motions initially until the mouse has moved from
349 # one character to another or until there have been multiple clicks.
352 # w - The entry window in which the button was pressed.
353 # x - The x-coordinate of the mouse.
355 proc ::tk::EntryMouseSelect {w x
} {
358 set cur
[EntryClosestGap
$w $x]
359 set anchor
[$w index anchor
]
360 if {($cur != $anchor) ||
(abs
($Priv(pressX
) - $x) >= 3)} {
361 set Priv
(mouseMoved
) 1
363 switch $Priv(selectMode
) {
365 if {$Priv(mouseMoved
)} {
366 if {$cur < $anchor} {
367 $w selection range
$cur $anchor
368 } elseif
{$cur > $anchor} {
369 $w selection range
$anchor $cur
376 if {$cur < [$w index anchor
]} {
377 set before
[tcl_wordBreakBefore [$w get
] $cur]
378 set after [tcl_wordBreakAfter [$w get
] [expr {$anchor-1}]]
380 set before
[tcl_wordBreakBefore [$w get
] $anchor]
381 set after [tcl_wordBreakAfter [$w get
] [expr {$cur - 1}]]
389 $w selection range
$before $after
392 $w selection range
0 end
395 if {$Priv(mouseMoved
)} {
401 # ::tk::EntryPaste --
402 # This procedure sets the insertion cursor to the current mouse position,
403 # pastes the selection there, and sets the focus to the window.
406 # w - The entry window.
407 # x - X position of the mouse.
409 proc ::tk::EntryPaste {w x
} {
410 $w icursor
[EntryClosestGap
$w $x]
411 catch {$w insert insert
[::tk::GetSelection $w PRIMARY
]}
412 if {"disabled" ne
[$w cget
-state]} {
417 # ::tk::EntryAutoScan --
418 # This procedure is invoked when the mouse leaves an entry window
419 # with button 1 down. It scrolls the window left or right,
420 # depending on where the mouse is, and reschedules itself as an
421 # "after" command so that the window continues to scroll until the
422 # mouse moves back into the window or the mouse button is released.
425 # w - The entry window.
427 proc ::tk::EntryAutoScan {w
} {
430 if {![winfo exists
$w]} {
433 if {$x >= [winfo width
$w]} {
434 $w xview scroll
2 units
435 EntryMouseSelect
$w $x
437 $w xview scroll
-2 units
438 EntryMouseSelect
$w $x
440 set Priv
(afterId
) [after 50 [list tk::EntryAutoScan $w]]
443 # ::tk::EntryKeySelect --
444 # This procedure is invoked when stroking out selections using the
445 # keyboard. It moves the cursor to a new position, then extends
446 # the selection to that position.
449 # w - The entry window.
450 # new - A new position for the insertion cursor (the cursor hasn't
451 # actually been moved to this position yet).
453 proc ::tk::EntryKeySelect {w new
} {
454 if {![$w selection present
]} {
455 $w selection from insert
458 $w selection adjust
$new
463 # ::tk::EntryInsert --
464 # Insert a string into an entry at the point of the insertion cursor.
465 # If there is a selection in the entry, and it covers the point of the
466 # insertion cursor, then delete the selection before inserting.
469 # w - The entry window in which to insert the string
470 # s - The string to insert (usually just a single character)
472 proc ::tk::EntryInsert {w s
} {
477 set insert
[$w index insert
]
478 if {([$w index sel.first
] <= $insert)
479 && ([$w index sel.last
] >= $insert)} {
480 $w delete sel.first sel.last
487 # ::tk::EntryBackspace --
488 # Backspace over the character just before the insertion cursor.
489 # If backspacing would move the cursor off the left edge of the
490 # window, reposition the cursor at about the middle of the window.
493 # w - The entry window in which to backspace.
495 proc ::tk::EntryBackspace w
{
496 if {[$w selection present
]} {
497 $w delete sel.first sel.last
499 set x
[expr {[$w index insert
] - 1}]
503 if {[$w index
@0] >= [$w index insert
]} {
505 set left
[lindex $range 0]
506 set right
[lindex $range 1]
507 $w xview moveto
[expr {$left - ($right - $left)/2.0}]
512 # ::tk::EntrySeeInsert --
513 # Make sure that the insertion cursor is visible in the entry window.
514 # If not, adjust the view so that it is.
517 # w - The entry window.
519 proc ::tk::EntrySeeInsert w
{
520 set c
[$w index insert
]
521 if {($c < [$w index
@0]) ||
($c > [$w index
@[winfo width
$w]])} {
526 # ::tk::EntrySetCursor -
527 # Move the insertion cursor to a given position in an entry. Also
528 # clears the selection, if there is one in the entry, and makes sure
529 # that the insertion cursor is visible.
532 # w - The entry window.
533 # pos - The desired new position for the cursor in the window.
535 proc ::tk::EntrySetCursor {w pos
} {
541 # ::tk::EntryTranspose -
542 # This procedure implements the "transpose" function for entry widgets.
543 # It tranposes the characters on either side of the insertion cursor,
544 # unless the cursor is at the end of the line. In this case it
545 # transposes the two characters to the left of the cursor. In either
546 # case, the cursor ends up to the right of the transposed characters.
549 # w - The entry window.
551 proc ::tk::EntryTranspose w
{
552 set i
[$w index insert
]
553 if {$i < [$w index end
]} {
556 set first
[expr {$i-2}]
561 set new
[string index
$data [expr {$i-1}]][string index
$data $first]
563 $w insert insert
$new
567 # ::tk::EntryNextWord --
568 # Returns the index of the next word position after a given position in the
569 # entry. The next word is platform dependent and may be either the next
570 # end-of-word position or the next start-of-word position after the next
571 # end-of-word position.
574 # w - The entry window in which the cursor is to move.
575 # start - Position at which to start search.
577 if {[tk windowingsystem
] eq
"win32"} {
578 proc ::tk::EntryNextWord {w start
} {
579 set pos
[tcl_endOfWord [$w get
] [$w index
$start]]
581 set pos
[tcl_startOfNextWord [$w get
] $pos]
589 proc ::tk::EntryNextWord {w start
} {
590 set pos
[tcl_endOfWord [$w get
] [$w index
$start]]
598 # ::tk::EntryPreviousWord --
600 # Returns the index of the previous word position before a given
601 # position in the entry.
604 # w - The entry window in which the cursor is to move.
605 # start - Position at which to start search.
607 proc ::tk::EntryPreviousWord {w start
} {
608 set pos
[tcl_startOfPreviousWord [$w get
] [$w index
$start]]
615 # ::tk::EntryScanMark --
617 # Marks the start of a possible scan drag operation
620 # w - The entry window from which the text to get
621 # x - x location on screen
623 proc ::tk::EntryScanMark {w x
} {
626 set ::tk::Priv(y
) 0 ; # not used
627 set ::tk::Priv(mouseMoved
) 0
630 # ::tk::EntryScanDrag --
632 # Marks the start of a possible scan drag operation
635 # w - The entry window from which the text to get
636 # x - x location on screen
638 proc ::tk::EntryScanDrag {w x
} {
639 # Make sure these exist, as some weird situations can trigger the
640 # motion binding without the initial press. [Bug #220269]
641 if {![info exists
::tk::Priv(x
)]} { set ::tk::Priv(x
) $x }
643 if {abs
($x-$::tk::Priv(x
)) > 2} {
644 set ::tk::Priv(mouseMoved
) 1
649 # ::tk::EntryGetSelection --
651 # Returns the selected text of the entry with respect to the -show option.
654 # w - The entry window from which the text to get
656 proc ::tk::EntryGetSelection {w
} {
657 set entryString
[string range
[$w get
] [$w index sel.first
] \
658 [expr {[$w index sel.last
] - 1}]]
659 if {[$w cget
-show] ne
""} {
660 return [string repeat
[string index
[$w cget
-show] 0] \
661 [string length
$entryString]]