3 # This file defines the default bindings for Tk entry widgets and provides
4 # procedures that help in implementing those bindings.
6 # RCS: @(#) $Id: entry.tcl,v 1.21.2.1 2006/01/25 18:21:41 dgp Exp $
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 tk::Priv 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 {tk::EntryGetSelection %W
} tk::Priv(data
)]} {
37 clipboard clear
-displayof %W
38 clipboard append -displayof %W
$tk::Priv(data
)
39 %W delete sel.first sel.last
44 if {![catch {tk::EntryGetSelection %W
} tk::Priv(data
)]} {
45 clipboard clear
-displayof %W
46 clipboard append -displayof %W
$tk::Priv(data
)
50 bind Entry
<<Paste
>> {
53 if {[tk windowingsystem
] ne
"x11"} {
55 %W delete sel.first sel.last
58 %W insert insert
[::tk::GetSelection %W CLIPBOARD
]
62 bind Entry
<<Clear
>> {
63 %W delete sel.first sel.last
65 bind Entry
<<PasteSelection
>> {
66 if {$tk_strictMotif ||
![info exists
tk::Priv(mouseMoved
)]
67 ||
!$tk::Priv(mouseMoved
)} {
72 # Standard Motif bindings:
75 tk::EntryButton1 %W
%x
78 bind Entry
<B1-Motion
> {
80 tk::EntryMouseSelect %W
%x
82 bind Entry
<Double-1
> {
83 set tk::Priv(selectMode
) word
84 tk::EntryMouseSelect %W
%x
85 catch {%W icursor sel.last
}
87 bind Entry
<Triple-1
> {
88 set tk::Priv(selectMode
) line
89 tk::EntryMouseSelect %W
%x
90 catch {%W icursor sel.last
}
92 bind Entry
<Shift-1
> {
93 set tk::Priv(selectMode
) char
94 %W
selection adjust
@%x
96 bind Entry
<Double-Shift-1
> {
97 set tk::Priv(selectMode
) word
98 tk::EntryMouseSelect %W
%x
100 bind Entry
<Triple-Shift-1
> {
101 set tk::Priv(selectMode
) line
102 tk::EntryMouseSelect %W
%x
104 bind Entry
<B1-Leave
> {
108 bind Entry
<B1-Enter
> {
111 bind Entry
<ButtonRelease-1
> {
114 bind Entry
<Control-1
> {
119 tk::EntrySetCursor %W
[expr {[%W index insert
] - 1}]
122 tk::EntrySetCursor %W
[expr {[%W index insert
] + 1}]
124 bind Entry
<Shift-Left
> {
125 tk::EntryKeySelect %W
[expr {[%W index insert
] - 1}]
126 tk::EntrySeeInsert %W
128 bind Entry
<Shift-Right
> {
129 tk::EntryKeySelect %W
[expr {[%W index insert
] + 1}]
130 tk::EntrySeeInsert %W
132 bind Entry
<Control-Left
> {
133 tk::EntrySetCursor %W
[tk::EntryPreviousWord %W insert
]
135 bind Entry
<Control-Right
> {
136 tk::EntrySetCursor %W
[tk::EntryNextWord %W insert
]
138 bind Entry
<Shift-Control-Left
> {
139 tk::EntryKeySelect %W
[tk::EntryPreviousWord %W insert
]
140 tk::EntrySeeInsert %W
142 bind Entry
<Shift-Control-Right
> {
143 tk::EntryKeySelect %W
[tk::EntryNextWord %W insert
]
144 tk::EntrySeeInsert %W
147 tk::EntrySetCursor %W
0
149 bind Entry
<Shift-Home
> {
150 tk::EntryKeySelect %W
0
151 tk::EntrySeeInsert %W
154 tk::EntrySetCursor %W end
156 bind Entry
<Shift-End
> {
157 tk::EntryKeySelect %W end
158 tk::EntrySeeInsert %W
161 bind Entry
<Delete
> {
162 if {[%W
selection present
]} {
163 %W delete sel.first sel.last
168 bind Entry
<BackSpace
> {
169 tk::EntryBackspace %W
172 bind Entry
<Control-space
> {
173 %W
selection from insert
175 bind Entry
<Select
> {
176 %W
selection from insert
178 bind Entry
<Control-Shift-space
> {
179 %W
selection adjust insert
181 bind Entry
<Shift-Select
> {
182 %W
selection adjust insert
184 bind Entry
<Control-slash
> {
185 %W
selection range
0 end
187 bind Entry
<Control-backslash
> {
190 bind Entry
<KeyPress
> {
192 tk::EntryInsert %W
%A
195 # Ignore all Alt, Meta, and Control keypresses unless explicitly bound.
196 # Otherwise, if a widget binding for one of these is defined, the
197 # <KeyPress> class binding will also fire and insert the character,
198 # which is wrong. Ditto for Escape, Return, and Tab.
200 bind Entry
<Alt-KeyPress
> {# nothing}
201 bind Entry
<Meta-KeyPress
> {# nothing}
202 bind Entry
<Control-KeyPress
> {# nothing}
203 bind Entry
<Escape
> {# nothing}
204 bind Entry
<Return
> {# nothing}
205 bind Entry
<KP_Enter
> {# nothing}
206 bind Entry
<Tab
> {# nothing}
207 if {[tk windowingsystem
] eq
"classic" ||
[tk windowingsystem
] eq
"aqua"} {
208 bind Entry
<Command-KeyPress
> {# nothing}
211 # On Windows, paste is done using Shift-Insert. Shift-Insert already
212 # generates the <<Paste>> event, so we don't need to do anything here.
213 if {$tcl_platform(platform
) ne
"windows"} {
214 bind Entry
<Insert
> {
215 catch {tk::EntryInsert %W
[::tk::GetSelection %W PRIMARY
]}
219 # Additional emacs-like bindings:
221 bind Entry
<Control-a
> {
222 if {!$tk_strictMotif} {
223 tk::EntrySetCursor %W
0
226 bind Entry
<Control-b
> {
227 if {!$tk_strictMotif} {
228 tk::EntrySetCursor %W
[expr {[%W index insert
] - 1}]
231 bind Entry
<Control-d
> {
232 if {!$tk_strictMotif} {
236 bind Entry
<Control-e
> {
237 if {!$tk_strictMotif} {
238 tk::EntrySetCursor %W end
241 bind Entry
<Control-f
> {
242 if {!$tk_strictMotif} {
243 tk::EntrySetCursor %W
[expr {[%W index insert
] + 1}]
246 bind Entry
<Control-h
> {
247 if {!$tk_strictMotif} {
248 tk::EntryBackspace %W
251 bind Entry
<Control-k
> {
252 if {!$tk_strictMotif} {
256 bind Entry
<Control-t
> {
257 if {!$tk_strictMotif} {
258 tk::EntryTranspose %W
261 bind Entry
<Meta-b
> {
262 if {!$tk_strictMotif} {
263 tk::EntrySetCursor %W
[tk::EntryPreviousWord %W insert
]
266 bind Entry
<Meta-d
> {
267 if {!$tk_strictMotif} {
268 %W delete insert
[tk::EntryNextWord %W insert
]
271 bind Entry
<Meta-f
> {
272 if {!$tk_strictMotif} {
273 tk::EntrySetCursor %W
[tk::EntryNextWord %W insert
]
276 bind Entry
<Meta-BackSpace
> {
277 if {!$tk_strictMotif} {
278 %W delete
[tk::EntryPreviousWord %W insert
] insert
281 bind Entry
<Meta-Delete
> {
282 if {!$tk_strictMotif} {
283 %W delete
[tk::EntryPreviousWord %W insert
] insert
287 # A few additional bindings of my own.
290 if {!$tk_strictMotif} {
291 ::tk::EntryScanMark %W
%x
294 bind Entry
<B2-Motion
> {
295 if {!$tk_strictMotif} {
296 ::tk::EntryScanDrag %W
%x
300 # ::tk::EntryClosestGap --
301 # Given x and y coordinates, this procedure finds the closest boundary
302 # between characters to the given coordinates and returns the index
303 # of the character just after the boundary.
306 # w - The entry window.
307 # x - X-coordinate within the window.
309 proc ::tk::EntryClosestGap {w x
} {
310 set pos
[$w index
@$x]
311 set bbox
[$w bbox
$pos]
312 if {($x - [lindex $bbox 0]) < ([lindex $bbox 2]/2)} {
318 # ::tk::EntryButton1 --
319 # This procedure is invoked to handle button-1 presses in entry
320 # widgets. It moves the insertion cursor, sets the selection anchor,
321 # and claims the input focus.
324 # w - The entry window in which the button was pressed.
325 # x - The x-coordinate of the button press.
327 proc ::tk::EntryButton1 {w x
} {
330 set Priv
(selectMode
) char
331 set Priv
(mouseMoved
) 0
333 $w icursor
[EntryClosestGap
$w $x]
334 $w selection from insert
335 if {"disabled" ne
[$w cget
-state]} {focus $w}
338 # ::tk::EntryMouseSelect --
339 # This procedure is invoked when dragging out a selection with
340 # the mouse. Depending on the selection mode (character, word,
341 # line) it selects in different-sized units. This procedure
342 # ignores mouse motions initially until the mouse has moved from
343 # one character to another or until there have been multiple clicks.
346 # w - The entry window in which the button was pressed.
347 # x - The x-coordinate of the mouse.
349 proc ::tk::EntryMouseSelect {w x
} {
352 set cur
[EntryClosestGap
$w $x]
353 set anchor
[$w index anchor
]
354 if {($cur != $anchor) ||
(abs
($Priv(pressX
) - $x) >= 3)} {
355 set Priv
(mouseMoved
) 1
357 switch $Priv(selectMode
) {
359 if {$Priv(mouseMoved
)} {
360 if {$cur < $anchor} {
361 $w selection range
$cur $anchor
362 } elseif
{$cur > $anchor} {
363 $w selection range
$anchor $cur
370 if {$cur < [$w index anchor
]} {
371 set before
[tcl_wordBreakBefore [$w get
] $cur]
372 set after [tcl_wordBreakAfter [$w get
] [expr {$anchor-1}]]
374 set before
[tcl_wordBreakBefore [$w get
] $anchor]
375 set after [tcl_wordBreakAfter [$w get
] [expr {$cur - 1}]]
383 $w selection range
$before $after
386 $w selection range
0 end
389 if {$Priv(mouseMoved
)} {
395 # ::tk::EntryPaste --
396 # This procedure sets the insertion cursor to the current mouse position,
397 # pastes the selection there, and sets the focus to the window.
400 # w - The entry window.
401 # x - X position of the mouse.
403 proc ::tk::EntryPaste {w x
} {
404 $w icursor
[EntryClosestGap
$w $x]
405 catch {$w insert insert
[::tk::GetSelection $w PRIMARY
]}
406 if {"disabled" ne
[$w cget
-state]} {focus $w}
409 # ::tk::EntryAutoScan --
410 # This procedure is invoked when the mouse leaves an entry window
411 # with button 1 down. It scrolls the window left or right,
412 # depending on where the mouse is, and reschedules itself as an
413 # "after" command so that the window continues to scroll until the
414 # mouse moves back into the window or the mouse button is released.
417 # w - The entry window.
419 proc ::tk::EntryAutoScan {w
} {
422 if {![winfo exists
$w]} return
423 if {$x >= [winfo width
$w]} {
424 $w xview scroll
2 units
425 EntryMouseSelect
$w $x
427 $w xview scroll
-2 units
428 EntryMouseSelect
$w $x
430 set Priv
(afterId
) [after 50 [list tk::EntryAutoScan $w]]
433 # ::tk::EntryKeySelect --
434 # This procedure is invoked when stroking out selections using the
435 # keyboard. It moves the cursor to a new position, then extends
436 # the selection to that position.
439 # w - The entry window.
440 # new - A new position for the insertion cursor (the cursor hasn't
441 # actually been moved to this position yet).
443 proc ::tk::EntryKeySelect {w new
} {
444 if {![$w selection present
]} {
445 $w selection from insert
448 $w selection adjust
$new
453 # ::tk::EntryInsert --
454 # Insert a string into an entry at the point of the insertion cursor.
455 # If there is a selection in the entry, and it covers the point of the
456 # insertion cursor, then delete the selection before inserting.
459 # w - The entry window in which to insert the string
460 # s - The string to insert (usually just a single character)
462 proc ::tk::EntryInsert {w s
} {
467 set insert
[$w index insert
]
468 if {([$w index sel.first
] <= $insert)
469 && ([$w index sel.last
] >= $insert)} {
470 $w delete sel.first sel.last
477 # ::tk::EntryBackspace --
478 # Backspace over the character just before the insertion cursor.
479 # If backspacing would move the cursor off the left edge of the
480 # window, reposition the cursor at about the middle of the window.
483 # w - The entry window in which to backspace.
485 proc ::tk::EntryBackspace w
{
486 if {[$w selection present
]} {
487 $w delete sel.first sel.last
489 set x
[expr {[$w index insert
] - 1}]
490 if {$x >= 0} {$w delete
$x}
491 if {[$w index
@0] >= [$w index insert
]} {
493 set left
[lindex $range 0]
494 set right
[lindex $range 1]
495 $w xview moveto
[expr {$left - ($right - $left)/2.0}]
500 # ::tk::EntrySeeInsert --
501 # Make sure that the insertion cursor is visible in the entry window.
502 # If not, adjust the view so that it is.
505 # w - The entry window.
507 proc ::tk::EntrySeeInsert w
{
508 set c
[$w index insert
]
509 if {($c < [$w index
@0]) ||
($c > [$w index
@[winfo width
$w]])} {
514 # ::tk::EntrySetCursor -
515 # Move the insertion cursor to a given position in an entry. Also
516 # clears the selection, if there is one in the entry, and makes sure
517 # that the insertion cursor is visible.
520 # w - The entry window.
521 # pos - The desired new position for the cursor in the window.
523 proc ::tk::EntrySetCursor {w pos
} {
529 # ::tk::EntryTranspose -
530 # This procedure implements the "transpose" function for entry widgets.
531 # It tranposes the characters on either side of the insertion cursor,
532 # unless the cursor is at the end of the line. In this case it
533 # transposes the two characters to the left of the cursor. In either
534 # case, the cursor ends up to the right of the transposed characters.
537 # w - The entry window.
539 proc ::tk::EntryTranspose w
{
540 set i
[$w index insert
]
541 if {$i < [$w index end
]} {
544 set first
[expr {$i-2}]
549 set new
[string index
$data [expr {$i-1}]][string index
$data $first]
551 $w insert insert
$new
555 # ::tk::EntryNextWord --
556 # Returns the index of the next word position after a given position in the
557 # entry. The next word is platform dependent and may be either the next
558 # end-of-word position or the next start-of-word position after the next
559 # end-of-word position.
562 # w - The entry window in which the cursor is to move.
563 # start - Position at which to start search.
565 if {$tcl_platform(platform
) eq
"windows"} {
566 proc ::tk::EntryNextWord {w start
} {
567 set pos
[tcl_endOfWord [$w get
] [$w index
$start]]
569 set pos
[tcl_startOfNextWord [$w get
] $pos]
577 proc ::tk::EntryNextWord {w start
} {
578 set pos
[tcl_endOfWord [$w get
] [$w index
$start]]
586 # ::tk::EntryPreviousWord --
588 # Returns the index of the previous word position before a given
589 # position in the entry.
592 # w - The entry window in which the cursor is to move.
593 # start - Position at which to start search.
595 proc ::tk::EntryPreviousWord {w start
} {
596 set pos
[tcl_startOfPreviousWord [$w get
] [$w index
$start]]
603 # ::tk::EntryScanMark --
605 # Marks the start of a possible scan drag operation
608 # w - The entry window from which the text to get
609 # x - x location on screen
611 proc ::tk::EntryScanMark {w x
} {
614 set ::tk::Priv(y
) 0 ; # not used
615 set ::tk::Priv(mouseMoved
) 0
618 # ::tk::EntryScanDrag --
620 # Marks the start of a possible scan drag operation
623 # w - The entry window from which the text to get
624 # x - x location on screen
626 proc ::tk::EntryScanDrag {w x
} {
627 # Make sure these exist, as some weird situations can trigger the
628 # motion binding without the initial press. [Bug #220269]
629 if {![info exists
::tk::Priv(x
)]} { set ::tk::Priv(x
) $x }
631 if {abs
($x-$::tk::Priv(x
)) > 2} {
632 set ::tk::Priv(mouseMoved
) 1
637 # ::tk::EntryGetSelection --
639 # Returns the selected text of the entry with respect to the -show option.
642 # w - The entry window from which the text to get
644 proc ::tk::EntryGetSelection {w
} {
645 set entryString
[string range
[$w get
] [$w index sel.first
] \
646 [expr {[$w index sel.last
] - 1}]]
647 if {[$w cget
-show] ne
""} {
648 return [string repeat
[string index
[$w cget
-show] 0] \
649 [string length
$entryString]]