Upgrade to Tcl/Tk 8.5b2
[msysgit.git] / mingw / lib / tk8.5 / entry.tcl
blob32b197380ab6bacdb971e2cd7ece4a0ae6fb97ac
1 # entry.tcl --
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.24 2005/07/25 09:06:00 dkf 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
28 # and auto-scanning.
29 # data - Used for Cut and Copy
30 #-------------------------------------------------------------------------
32 #-------------------------------------------------------------------------
33 # The code below creates the default class bindings for entries.
34 #-------------------------------------------------------------------------
35 bind Entry <<Cut>> {
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
40 unset tk::Priv(data)
43 bind Entry <<Copy>> {
44 if {![catch {tk::EntryGetSelection %W} tk::Priv(data)]} {
45 clipboard clear -displayof %W
46 clipboard append -displayof %W $tk::Priv(data)
47 unset tk::Priv(data)
50 bind Entry <<Paste>> {
51 global tcl_platform
52 catch {
53 if {[tk windowingsystem] ne "x11"} {
54 catch {
55 %W delete sel.first sel.last
58 %W insert insert [::tk::GetSelection %W CLIPBOARD]
59 tk::EntrySeeInsert %W
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)} {
68 tk::EntryPaste %W %x
72 bind Entry <<TraverseIn>> {
73 %W selection range 0 end
74 %W icursor end
77 # Standard Motif bindings:
79 bind Entry <1> {
80 tk::EntryButton1 %W %x
81 %W selection clear
83 bind Entry <B1-Motion> {
84 set tk::Priv(x) %x
85 tk::EntryMouseSelect %W %x
87 bind Entry <Double-1> {
88 set tk::Priv(selectMode) word
89 tk::EntryMouseSelect %W %x
90 catch {%W icursor sel.last}
92 bind Entry <Triple-1> {
93 set tk::Priv(selectMode) line
94 tk::EntryMouseSelect %W %x
95 catch {%W icursor sel.last}
97 bind Entry <Shift-1> {
98 set tk::Priv(selectMode) char
99 %W selection adjust @%x
101 bind Entry <Double-Shift-1> {
102 set tk::Priv(selectMode) word
103 tk::EntryMouseSelect %W %x
105 bind Entry <Triple-Shift-1> {
106 set tk::Priv(selectMode) line
107 tk::EntryMouseSelect %W %x
109 bind Entry <B1-Leave> {
110 set tk::Priv(x) %x
111 tk::EntryAutoScan %W
113 bind Entry <B1-Enter> {
114 tk::CancelRepeat
116 bind Entry <ButtonRelease-1> {
117 tk::CancelRepeat
119 bind Entry <Control-1> {
120 %W icursor @%x
123 bind Entry <Left> {
124 tk::EntrySetCursor %W [expr {[%W index insert] - 1}]
126 bind Entry <Right> {
127 tk::EntrySetCursor %W [expr {[%W index insert] + 1}]
129 bind Entry <Shift-Left> {
130 tk::EntryKeySelect %W [expr {[%W index insert] - 1}]
131 tk::EntrySeeInsert %W
133 bind Entry <Shift-Right> {
134 tk::EntryKeySelect %W [expr {[%W index insert] + 1}]
135 tk::EntrySeeInsert %W
137 bind Entry <Control-Left> {
138 tk::EntrySetCursor %W [tk::EntryPreviousWord %W insert]
140 bind Entry <Control-Right> {
141 tk::EntrySetCursor %W [tk::EntryNextWord %W insert]
143 bind Entry <Shift-Control-Left> {
144 tk::EntryKeySelect %W [tk::EntryPreviousWord %W insert]
145 tk::EntrySeeInsert %W
147 bind Entry <Shift-Control-Right> {
148 tk::EntryKeySelect %W [tk::EntryNextWord %W insert]
149 tk::EntrySeeInsert %W
151 bind Entry <Home> {
152 tk::EntrySetCursor %W 0
154 bind Entry <Shift-Home> {
155 tk::EntryKeySelect %W 0
156 tk::EntrySeeInsert %W
158 bind Entry <End> {
159 tk::EntrySetCursor %W end
161 bind Entry <Shift-End> {
162 tk::EntryKeySelect %W end
163 tk::EntrySeeInsert %W
166 bind Entry <Delete> {
167 if {[%W selection present]} {
168 %W delete sel.first sel.last
169 } else {
170 %W delete insert
173 bind Entry <BackSpace> {
174 tk::EntryBackspace %W
177 bind Entry <Control-space> {
178 %W selection from insert
180 bind Entry <Select> {
181 %W selection from insert
183 bind Entry <Control-Shift-space> {
184 %W selection adjust insert
186 bind Entry <Shift-Select> {
187 %W selection adjust insert
189 bind Entry <Control-slash> {
190 %W selection range 0 end
192 bind Entry <Control-backslash> {
193 %W selection clear
195 bind Entry <KeyPress> {
196 tk::CancelRepeat
197 tk::EntryInsert %W %A
200 # Ignore all Alt, Meta, and Control keypresses unless explicitly bound.
201 # Otherwise, if a widget binding for one of these is defined, the
202 # <KeyPress> class binding will also fire and insert the character,
203 # which is wrong. Ditto for Escape, Return, and Tab.
205 bind Entry <Alt-KeyPress> {# nothing}
206 bind Entry <Meta-KeyPress> {# nothing}
207 bind Entry <Control-KeyPress> {# nothing}
208 bind Entry <Escape> {# nothing}
209 bind Entry <Return> {# nothing}
210 bind Entry <KP_Enter> {# nothing}
211 bind Entry <Tab> {# nothing}
212 if {[tk windowingsystem] eq "aqua"} {
213 bind Entry <Command-KeyPress> {# nothing}
216 # On Windows, paste is done using Shift-Insert. Shift-Insert already
217 # generates the <<Paste>> event, so we don't need to do anything here.
218 if {$tcl_platform(platform) ne "windows"} {
219 bind Entry <Insert> {
220 catch {tk::EntryInsert %W [::tk::GetSelection %W PRIMARY]}
224 # Additional emacs-like bindings:
226 bind Entry <Control-a> {
227 if {!$tk_strictMotif} {
228 tk::EntrySetCursor %W 0
231 bind Entry <Control-b> {
232 if {!$tk_strictMotif} {
233 tk::EntrySetCursor %W [expr {[%W index insert] - 1}]
236 bind Entry <Control-d> {
237 if {!$tk_strictMotif} {
238 %W delete insert
241 bind Entry <Control-e> {
242 if {!$tk_strictMotif} {
243 tk::EntrySetCursor %W end
246 bind Entry <Control-f> {
247 if {!$tk_strictMotif} {
248 tk::EntrySetCursor %W [expr {[%W index insert] + 1}]
251 bind Entry <Control-h> {
252 if {!$tk_strictMotif} {
253 tk::EntryBackspace %W
256 bind Entry <Control-k> {
257 if {!$tk_strictMotif} {
258 %W delete insert end
261 bind Entry <Control-t> {
262 if {!$tk_strictMotif} {
263 tk::EntryTranspose %W
266 bind Entry <Meta-b> {
267 if {!$tk_strictMotif} {
268 tk::EntrySetCursor %W [tk::EntryPreviousWord %W insert]
271 bind Entry <Meta-d> {
272 if {!$tk_strictMotif} {
273 %W delete insert [tk::EntryNextWord %W insert]
276 bind Entry <Meta-f> {
277 if {!$tk_strictMotif} {
278 tk::EntrySetCursor %W [tk::EntryNextWord %W insert]
281 bind Entry <Meta-BackSpace> {
282 if {!$tk_strictMotif} {
283 %W delete [tk::EntryPreviousWord %W insert] insert
286 bind Entry <Meta-Delete> {
287 if {!$tk_strictMotif} {
288 %W delete [tk::EntryPreviousWord %W insert] insert
292 # A few additional bindings of my own.
294 bind Entry <2> {
295 if {!$tk_strictMotif} {
296 ::tk::EntryScanMark %W %x
299 bind Entry <B2-Motion> {
300 if {!$tk_strictMotif} {
301 ::tk::EntryScanDrag %W %x
305 # ::tk::EntryClosestGap --
306 # Given x and y coordinates, this procedure finds the closest boundary
307 # between characters to the given coordinates and returns the index
308 # of the character just after the boundary.
310 # Arguments:
311 # w - The entry window.
312 # x - X-coordinate within the window.
314 proc ::tk::EntryClosestGap {w x} {
315 set pos [$w index @$x]
316 set bbox [$w bbox $pos]
317 if {($x - [lindex $bbox 0]) < ([lindex $bbox 2]/2)} {
318 return $pos
320 incr pos
323 # ::tk::EntryButton1 --
324 # This procedure is invoked to handle button-1 presses in entry
325 # widgets. It moves the insertion cursor, sets the selection anchor,
326 # and claims the input focus.
328 # Arguments:
329 # w - The entry window in which the button was pressed.
330 # x - The x-coordinate of the button press.
332 proc ::tk::EntryButton1 {w x} {
333 variable ::tk::Priv
335 set Priv(selectMode) char
336 set Priv(mouseMoved) 0
337 set Priv(pressX) $x
338 $w icursor [EntryClosestGap $w $x]
339 $w selection from insert
340 if {"disabled" ne [$w cget -state]} {
341 focus $w
345 # ::tk::EntryMouseSelect --
346 # This procedure is invoked when dragging out a selection with
347 # the mouse. Depending on the selection mode (character, word,
348 # line) it selects in different-sized units. This procedure
349 # ignores mouse motions initially until the mouse has moved from
350 # one character to another or until there have been multiple clicks.
352 # Arguments:
353 # w - The entry window in which the button was pressed.
354 # x - The x-coordinate of the mouse.
356 proc ::tk::EntryMouseSelect {w x} {
357 variable ::tk::Priv
359 set cur [EntryClosestGap $w $x]
360 set anchor [$w index anchor]
361 if {($cur != $anchor) || (abs($Priv(pressX) - $x) >= 3)} {
362 set Priv(mouseMoved) 1
364 switch $Priv(selectMode) {
365 char {
366 if {$Priv(mouseMoved)} {
367 if {$cur < $anchor} {
368 $w selection range $cur $anchor
369 } elseif {$cur > $anchor} {
370 $w selection range $anchor $cur
371 } else {
372 $w selection clear
376 word {
377 if {$cur < [$w index anchor]} {
378 set before [tcl_wordBreakBefore [$w get] $cur]
379 set after [tcl_wordBreakAfter [$w get] [expr {$anchor-1}]]
380 } else {
381 set before [tcl_wordBreakBefore [$w get] $anchor]
382 set after [tcl_wordBreakAfter [$w get] [expr {$cur - 1}]]
384 if {$before < 0} {
385 set before 0
387 if {$after < 0} {
388 set after end
390 $w selection range $before $after
392 line {
393 $w selection range 0 end
396 if {$Priv(mouseMoved)} {
397 $w icursor $cur
399 update idletasks
402 # ::tk::EntryPaste --
403 # This procedure sets the insertion cursor to the current mouse position,
404 # pastes the selection there, and sets the focus to the window.
406 # Arguments:
407 # w - The entry window.
408 # x - X position of the mouse.
410 proc ::tk::EntryPaste {w x} {
411 $w icursor [EntryClosestGap $w $x]
412 catch {$w insert insert [::tk::GetSelection $w PRIMARY]}
413 if {"disabled" ne [$w cget -state]} {
414 focus $w
418 # ::tk::EntryAutoScan --
419 # This procedure is invoked when the mouse leaves an entry window
420 # with button 1 down. It scrolls the window left or right,
421 # depending on where the mouse is, and reschedules itself as an
422 # "after" command so that the window continues to scroll until the
423 # mouse moves back into the window or the mouse button is released.
425 # Arguments:
426 # w - The entry window.
428 proc ::tk::EntryAutoScan {w} {
429 variable ::tk::Priv
430 set x $Priv(x)
431 if {![winfo exists $w]} {
432 return
434 if {$x >= [winfo width $w]} {
435 $w xview scroll 2 units
436 EntryMouseSelect $w $x
437 } elseif {$x < 0} {
438 $w xview scroll -2 units
439 EntryMouseSelect $w $x
441 set Priv(afterId) [after 50 [list tk::EntryAutoScan $w]]
444 # ::tk::EntryKeySelect --
445 # This procedure is invoked when stroking out selections using the
446 # keyboard. It moves the cursor to a new position, then extends
447 # the selection to that position.
449 # Arguments:
450 # w - The entry window.
451 # new - A new position for the insertion cursor (the cursor hasn't
452 # actually been moved to this position yet).
454 proc ::tk::EntryKeySelect {w new} {
455 if {![$w selection present]} {
456 $w selection from insert
457 $w selection to $new
458 } else {
459 $w selection adjust $new
461 $w icursor $new
464 # ::tk::EntryInsert --
465 # Insert a string into an entry at the point of the insertion cursor.
466 # If there is a selection in the entry, and it covers the point of the
467 # insertion cursor, then delete the selection before inserting.
469 # Arguments:
470 # w - The entry window in which to insert the string
471 # s - The string to insert (usually just a single character)
473 proc ::tk::EntryInsert {w s} {
474 if {$s eq ""} {
475 return
477 catch {
478 set insert [$w index insert]
479 if {([$w index sel.first] <= $insert)
480 && ([$w index sel.last] >= $insert)} {
481 $w delete sel.first sel.last
484 $w insert insert $s
485 EntrySeeInsert $w
488 # ::tk::EntryBackspace --
489 # Backspace over the character just before the insertion cursor.
490 # If backspacing would move the cursor off the left edge of the
491 # window, reposition the cursor at about the middle of the window.
493 # Arguments:
494 # w - The entry window in which to backspace.
496 proc ::tk::EntryBackspace w {
497 if {[$w selection present]} {
498 $w delete sel.first sel.last
499 } else {
500 set x [expr {[$w index insert] - 1}]
501 if {$x >= 0} {
502 $w delete $x
504 if {[$w index @0] >= [$w index insert]} {
505 set range [$w xview]
506 set left [lindex $range 0]
507 set right [lindex $range 1]
508 $w xview moveto [expr {$left - ($right - $left)/2.0}]
513 # ::tk::EntrySeeInsert --
514 # Make sure that the insertion cursor is visible in the entry window.
515 # If not, adjust the view so that it is.
517 # Arguments:
518 # w - The entry window.
520 proc ::tk::EntrySeeInsert w {
521 set c [$w index insert]
522 if {($c < [$w index @0]) || ($c > [$w index @[winfo width $w]])} {
523 $w xview $c
527 # ::tk::EntrySetCursor -
528 # Move the insertion cursor to a given position in an entry. Also
529 # clears the selection, if there is one in the entry, and makes sure
530 # that the insertion cursor is visible.
532 # Arguments:
533 # w - The entry window.
534 # pos - The desired new position for the cursor in the window.
536 proc ::tk::EntrySetCursor {w pos} {
537 $w icursor $pos
538 $w selection clear
539 EntrySeeInsert $w
542 # ::tk::EntryTranspose -
543 # This procedure implements the "transpose" function for entry widgets.
544 # It tranposes the characters on either side of the insertion cursor,
545 # unless the cursor is at the end of the line. In this case it
546 # transposes the two characters to the left of the cursor. In either
547 # case, the cursor ends up to the right of the transposed characters.
549 # Arguments:
550 # w - The entry window.
552 proc ::tk::EntryTranspose w {
553 set i [$w index insert]
554 if {$i < [$w index end]} {
555 incr i
557 set first [expr {$i-2}]
558 if {$first < 0} {
559 return
561 set data [$w get]
562 set new [string index $data [expr {$i-1}]][string index $data $first]
563 $w delete $first $i
564 $w insert insert $new
565 EntrySeeInsert $w
568 # ::tk::EntryNextWord --
569 # Returns the index of the next word position after a given position in the
570 # entry. The next word is platform dependent and may be either the next
571 # end-of-word position or the next start-of-word position after the next
572 # end-of-word position.
574 # Arguments:
575 # w - The entry window in which the cursor is to move.
576 # start - Position at which to start search.
578 if {$tcl_platform(platform) eq "windows"} {
579 proc ::tk::EntryNextWord {w start} {
580 set pos [tcl_endOfWord [$w get] [$w index $start]]
581 if {$pos >= 0} {
582 set pos [tcl_startOfNextWord [$w get] $pos]
584 if {$pos < 0} {
585 return end
587 return $pos
589 } else {
590 proc ::tk::EntryNextWord {w start} {
591 set pos [tcl_endOfWord [$w get] [$w index $start]]
592 if {$pos < 0} {
593 return end
595 return $pos
599 # ::tk::EntryPreviousWord --
601 # Returns the index of the previous word position before a given
602 # position in the entry.
604 # Arguments:
605 # w - The entry window in which the cursor is to move.
606 # start - Position at which to start search.
608 proc ::tk::EntryPreviousWord {w start} {
609 set pos [tcl_startOfPreviousWord [$w get] [$w index $start]]
610 if {$pos < 0} {
611 return 0
613 return $pos
616 # ::tk::EntryScanMark --
618 # Marks the start of a possible scan drag operation
620 # Arguments:
621 # w - The entry window from which the text to get
622 # x - x location on screen
624 proc ::tk::EntryScanMark {w x} {
625 $w scan mark $x
626 set ::tk::Priv(x) $x
627 set ::tk::Priv(y) 0 ; # not used
628 set ::tk::Priv(mouseMoved) 0
631 # ::tk::EntryScanDrag --
633 # Marks the start of a possible scan drag operation
635 # Arguments:
636 # w - The entry window from which the text to get
637 # x - x location on screen
639 proc ::tk::EntryScanDrag {w x} {
640 # Make sure these exist, as some weird situations can trigger the
641 # motion binding without the initial press. [Bug #220269]
642 if {![info exists ::tk::Priv(x)]} { set ::tk::Priv(x) $x }
643 # allow for a delta
644 if {abs($x-$::tk::Priv(x)) > 2} {
645 set ::tk::Priv(mouseMoved) 1
647 $w scan dragto $x
650 # ::tk::EntryGetSelection --
652 # Returns the selected text of the entry with respect to the -show option.
654 # Arguments:
655 # w - The entry window from which the text to get
657 proc ::tk::EntryGetSelection {w} {
658 set entryString [string range [$w get] [$w index sel.first] \
659 [expr {[$w index sel.last] - 1}]]
660 if {[$w cget -show] ne ""} {
661 return [string repeat [string index [$w cget -show] 0] \
662 [string length $entryString]]
664 return $entryString