3 # This file defines the default bindings for Tk label, button,
4 # checkbutton, and radiobutton widgets and provides procedures
5 # that help in implementing those bindings.
7 # RCS: @(#) $Id: button.tcl,v 1.19.4.1 2009/10/24 00:12:03 dkf Exp $
9 # Copyright (c) 1992-1994 The Regents of the University of California.
10 # Copyright (c) 1994-1996 Sun Microsystems, Inc.
11 # Copyright (c) 2002 ActiveState Corporation.
13 # See the file "license.terms" for information on usage and redistribution
14 # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
17 #-------------------------------------------------------------------------
18 # The code below creates the default class bindings for buttons.
19 #-------------------------------------------------------------------------
21 if {[tk windowingsystem
] eq
"aqua"} {
22 bind Radiobutton
<Enter
> {
25 bind Radiobutton
<1> {
28 bind Radiobutton
<ButtonRelease-1
> {
31 bind Checkbutton
<Enter
> {
34 bind Checkbutton
<1> {
37 bind Checkbutton
<ButtonRelease-1
> {
40 bind Checkbutton
<Leave
> {
44 if {"windows" eq
$tcl_platform(platform
)} {
45 bind Checkbutton
<equal
> {
46 tk::CheckRadioInvoke %W select
48 bind Checkbutton
<plus
> {
49 tk::CheckRadioInvoke %W select
51 bind Checkbutton
<minus
> {
52 tk::CheckRadioInvoke %W deselect
54 bind Checkbutton
<1> {
57 bind Checkbutton
<ButtonRelease-1
> {
60 bind Checkbutton
<Enter
> {
61 tk::CheckRadioEnter %W
63 bind Checkbutton
<Leave
> {
67 bind Radiobutton
<1> {
70 bind Radiobutton
<ButtonRelease-1
> {
73 bind Radiobutton
<Enter
> {
74 tk::CheckRadioEnter %W
77 if {"x11" eq
[tk windowingsystem
]} {
78 bind Checkbutton
<Return
> {
79 if {!$tk_strictMotif} {
83 bind Radiobutton
<Return
> {
84 if {!$tk_strictMotif} {
85 tk::CheckRadioInvoke %W
88 bind Checkbutton
<1> {
91 bind Radiobutton
<1> {
92 tk::CheckRadioInvoke %W
94 bind Checkbutton
<Enter
> {
97 bind Radiobutton
<Enter
> {
100 bind Checkbutton
<Leave
> {
105 bind Button
<space
> {
108 bind Checkbutton
<space
> {
109 tk::CheckRadioInvoke %W
111 bind Radiobutton
<space
> {
112 tk::CheckRadioInvoke %W
115 bind Button
<FocusIn
> {}
116 bind Button
<Enter
> {
119 bind Button
<Leave
> {
125 bind Button
<ButtonRelease-1
> {
129 bind Checkbutton
<FocusIn
> {}
131 bind Radiobutton
<FocusIn
> {}
132 bind Radiobutton
<Leave
> {
136 if {"windows" eq
$tcl_platform(platform
)} {
138 #########################
139 # Windows implementation
140 #########################
142 # ::tk::ButtonEnter --
143 # The procedure below is invoked when the mouse pointer enters a
144 # button widget. It records the button we're in and changes the
145 # state of the button to active unless the button is disabled.
148 # w - The name of the widget.
150 proc ::tk::ButtonEnter w
{
152 if {[$w cget
-state] ne
"disabled"} {
154 # If the mouse button is down, set the relief to sunken on entry.
155 # Overwise, if there's an -overrelief value, set the relief to that.
157 set Priv
($w,relief
) [$w cget
-relief]
158 if {$Priv(buttonWindow
) eq
$w} {
159 $w configure
-relief sunken
-state active
160 set Priv
($w,prelief
) sunken
161 } elseif
{[set over
[$w cget
-overrelief]] ne
""} {
162 $w configure
-relief $over
163 set Priv
($w,prelief
) $over
169 # ::tk::ButtonLeave --
170 # The procedure below is invoked when the mouse pointer leaves a
171 # button widget. It changes the state of the button back to inactive.
172 # Restore any modified relief too.
175 # w - The name of the widget.
177 proc ::tk::ButtonLeave w
{
179 if {[$w cget
-state] ne
"disabled"} {
180 $w configure
-state normal
183 # Restore the original button relief if it was changed by Tk.
184 # That is signaled by the existence of Priv($w,prelief).
186 if {[info exists Priv
($w,relief
)]} {
187 if {[info exists Priv
($w,prelief
)] && \
188 $Priv($w,prelief
) eq
[$w cget
-relief]} {
189 $w configure
-relief $Priv($w,relief
)
191 unset -nocomplain Priv
($w,relief
) Priv
($w,prelief
)
197 # ::tk::ButtonDown --
198 # The procedure below is invoked when the mouse button is pressed in
199 # a button widget. It records the fact that the mouse is in the button,
200 # saves the button's relief so it can be restored later, and changes
201 # the relief to sunken.
204 # w - The name of the widget.
206 proc ::tk::ButtonDown w
{
209 # Only save the button's relief if it does not yet exist. If there
210 # is an overrelief setting, Priv($w,relief) will already have been set,
211 # and the current value of the -relief option will be incorrect.
213 if {![info exists Priv
($w,relief
)]} {
214 set Priv
($w,relief
) [$w cget
-relief]
217 if {[$w cget
-state] ne
"disabled"} {
218 set Priv
(buttonWindow
) $w
219 $w configure
-relief sunken
-state active
220 set Priv
($w,prelief
) sunken
222 # If this button has a repeatdelay set up, get it going with an after
223 after cancel
$Priv(afterId
)
224 set delay
[$w cget
-repeatdelay]
227 set Priv
(afterId
) [after $delay [list tk::ButtonAutoInvoke $w]]
233 # The procedure below is invoked when the mouse button is released
234 # in a button widget. It restores the button's relief and invokes
235 # the command as long as the mouse hasn't left the button.
238 # w - The name of the widget.
240 proc ::tk::ButtonUp w
{
242 if {$Priv(buttonWindow
) eq
$w} {
243 set Priv
(buttonWindow
) ""
245 # Restore the button's relief if it was cached.
247 if {[info exists Priv
($w,relief
)]} {
248 if {[info exists Priv
($w,prelief
)] && \
249 $Priv($w,prelief
) eq
[$w cget
-relief]} {
250 $w configure
-relief $Priv($w,relief
)
252 unset -nocomplain Priv
($w,relief
) Priv
($w,prelief
)
255 # Clean up the after event from the auto-repeater
256 after cancel
$Priv(afterId
)
258 if {$Priv(window
) eq
$w && [$w cget
-state] ne
"disabled"} {
259 $w configure
-state normal
261 # Only invoke the command if it wasn't already invoked by the
262 # auto-repeater functionality
263 if { $Priv(repeated
) == 0 } {
264 uplevel #0 [list $w invoke]
270 # ::tk::CheckRadioEnter --
271 # The procedure below is invoked when the mouse pointer enters a
272 # checkbutton or radiobutton widget. It records the button we're in
273 # and changes the state of the button to active unless the button is
277 # w - The name of the widget.
279 proc ::tk::CheckRadioEnter w
{
281 if {[$w cget
-state] ne
"disabled"} {
282 if {$Priv(buttonWindow
) eq
$w} {
283 $w configure
-state active
285 if {[set over
[$w cget
-overrelief]] ne
""} {
286 set Priv
($w,relief
) [$w cget
-relief]
287 set Priv
($w,prelief
) $over
288 $w configure
-relief $over
294 # ::tk::CheckRadioDown --
295 # The procedure below is invoked when the mouse button is pressed in
296 # a button widget. It records the fact that the mouse is in the button,
297 # saves the button's relief so it can be restored later, and changes
298 # the relief to sunken.
301 # w - The name of the widget.
303 proc ::tk::CheckRadioDown w
{
305 if {![info exists Priv
($w,relief
)]} {
306 set Priv
($w,relief
) [$w cget
-relief]
308 if {[$w cget
-state] ne
"disabled"} {
309 set Priv
(buttonWindow
) $w
311 $w configure
-state active
317 if {"x11" eq
[tk windowingsystem
]} {
319 #####################
320 # Unix implementation
321 #####################
323 # ::tk::ButtonEnter --
324 # The procedure below is invoked when the mouse pointer enters a
325 # button widget. It records the button we're in and changes the
326 # state of the button to active unless the button is disabled.
329 # w - The name of the widget.
331 proc ::tk::ButtonEnter {w
} {
333 if {[$w cget
-state] ne
"disabled"} {
334 # On unix the state is active just with mouse-over
335 $w configure
-state active
337 # If the mouse button is down, set the relief to sunken on entry.
338 # Overwise, if there's an -overrelief value, set the relief to that.
340 set Priv
($w,relief
) [$w cget
-relief]
341 if {$Priv(buttonWindow
) eq
$w} {
342 $w configure
-relief sunken
343 set Priv
($w,prelief
) sunken
344 } elseif
{[set over
[$w cget
-overrelief]] ne
""} {
345 $w configure
-relief $over
346 set Priv
($w,prelief
) $over
352 # ::tk::ButtonLeave --
353 # The procedure below is invoked when the mouse pointer leaves a
354 # button widget. It changes the state of the button back to inactive.
355 # Restore any modified relief too.
358 # w - The name of the widget.
360 proc ::tk::ButtonLeave w
{
362 if {[$w cget
-state] ne
"disabled"} {
363 $w configure
-state normal
366 # Restore the original button relief if it was changed by Tk.
367 # That is signaled by the existence of Priv($w,prelief).
369 if {[info exists Priv
($w,relief
)]} {
370 if {[info exists Priv
($w,prelief
)] && \
371 $Priv($w,prelief
) eq
[$w cget
-relief]} {
372 $w configure
-relief $Priv($w,relief
)
374 unset -nocomplain Priv
($w,relief
) Priv
($w,prelief
)
380 # ::tk::ButtonDown --
381 # The procedure below is invoked when the mouse button is pressed in
382 # a button widget. It records the fact that the mouse is in the button,
383 # saves the button's relief so it can be restored later, and changes
384 # the relief to sunken.
387 # w - The name of the widget.
389 proc ::tk::ButtonDown w
{
392 # Only save the button's relief if it does not yet exist. If there
393 # is an overrelief setting, Priv($w,relief) will already have been set,
394 # and the current value of the -relief option will be incorrect.
396 if {![info exists Priv
($w,relief
)]} {
397 set Priv
($w,relief
) [$w cget
-relief]
400 if {[$w cget
-state] ne
"disabled"} {
401 set Priv
(buttonWindow
) $w
402 $w configure
-relief sunken
403 set Priv
($w,prelief
) sunken
405 # If this button has a repeatdelay set up, get it going with an after
406 after cancel
$Priv(afterId
)
407 set delay
[$w cget
-repeatdelay]
410 set Priv
(afterId
) [after $delay [list tk::ButtonAutoInvoke $w]]
416 # The procedure below is invoked when the mouse button is released
417 # in a button widget. It restores the button's relief and invokes
418 # the command as long as the mouse hasn't left the button.
421 # w - The name of the widget.
423 proc ::tk::ButtonUp w
{
425 if {$w eq
$Priv(buttonWindow
)} {
426 set Priv
(buttonWindow
) ""
428 # Restore the button's relief if it was cached.
430 if {[info exists Priv
($w,relief
)]} {
431 if {[info exists Priv
($w,prelief
)] && \
432 $Priv($w,prelief
) eq
[$w cget
-relief]} {
433 $w configure
-relief $Priv($w,relief
)
435 unset -nocomplain Priv
($w,relief
) Priv
($w,prelief
)
438 # Clean up the after event from the auto-repeater
439 after cancel
$Priv(afterId
)
441 if {$Priv(window
) eq
$w && [$w cget
-state] ne
"disabled"} {
442 # Only invoke the command if it wasn't already invoked by the
443 # auto-repeater functionality
444 if { $Priv(repeated
) == 0 } {
445 uplevel #0 [list $w invoke]
453 if {[tk windowingsystem
] eq
"aqua"} {
459 # ::tk::ButtonEnter --
460 # The procedure below is invoked when the mouse pointer enters a
461 # button widget. It records the button we're in and changes the
462 # state of the button to active unless the button is disabled.
465 # w - The name of the widget.
467 proc ::tk::ButtonEnter {w
} {
469 if {[$w cget
-state] ne
"disabled"} {
471 # If there's an -overrelief value, set the relief to that.
473 if {$Priv(buttonWindow
) eq
$w} {
474 $w configure
-state active
475 } elseif
{[set over
[$w cget
-overrelief]] ne
""} {
476 set Priv
($w,relief
) [$w cget
-relief]
477 set Priv
($w,prelief
) $over
478 $w configure
-relief $over
484 # ::tk::ButtonLeave --
485 # The procedure below is invoked when the mouse pointer leaves a
486 # button widget. It changes the state of the button back to
487 # inactive. If we're leaving the button window with a mouse button
488 # pressed (Priv(buttonWindow) == $w), restore the relief of the
492 # w - The name of the widget.
494 proc ::tk::ButtonLeave w
{
496 if {$w eq
$Priv(buttonWindow
)} {
497 $w configure
-state normal
500 # Restore the original button relief if it was changed by Tk.
501 # That is signaled by the existence of Priv($w,prelief).
503 if {[info exists Priv
($w,relief
)]} {
504 if {[info exists Priv
($w,prelief
)] && \
505 $Priv($w,prelief
) eq
[$w cget
-relief]} {
506 $w configure
-relief $Priv($w,relief
)
508 unset -nocomplain Priv
($w,relief
) Priv
($w,prelief
)
514 # ::tk::ButtonDown --
515 # The procedure below is invoked when the mouse button is pressed in
516 # a button widget. It records the fact that the mouse is in the button,
517 # saves the button's relief so it can be restored later, and changes
518 # the relief to sunken.
521 # w - The name of the widget.
523 proc ::tk::ButtonDown w
{
526 if {[$w cget
-state] ne
"disabled"} {
527 set Priv
(buttonWindow
) $w
528 $w configure
-state active
530 # If this button has a repeatdelay set up, get it going with an after
531 after cancel
$Priv(afterId
)
533 if { ![catch {$w cget
-repeatdelay} delay
] } {
535 set Priv
(afterId
) [after $delay [list tk::ButtonAutoInvoke $w]]
542 # The procedure below is invoked when the mouse button is released
543 # in a button widget. It restores the button's relief and invokes
544 # the command as long as the mouse hasn't left the button.
547 # w - The name of the widget.
549 proc ::tk::ButtonUp w
{
551 if {$Priv(buttonWindow
) eq
$w} {
552 set Priv
(buttonWindow
) ""
553 $w configure
-state normal
555 # Restore the button's relief if it was cached.
557 if {[info exists Priv
($w,relief
)]} {
558 if {[info exists Priv
($w,prelief
)] && \
559 $Priv($w,prelief
) eq
[$w cget
-relief]} {
560 $w configure
-relief $Priv($w,relief
)
562 unset -nocomplain Priv
($w,relief
) Priv
($w,prelief
)
565 # Clean up the after event from the auto-repeater
566 after cancel
$Priv(afterId
)
568 if {$Priv(window
) eq
$w && [$w cget
-state] ne
"disabled"} {
569 # Only invoke the command if it wasn't already invoked by the
570 # auto-repeater functionality
571 if { $Priv(repeated
) == 0 } {
572 uplevel #0 [list $w invoke]
584 # ::tk::ButtonInvoke --
585 # The procedure below is called when a button is invoked through
586 # the keyboard. It simulate a press of the button via the mouse.
589 # w - The name of the widget.
591 proc ::tk::ButtonInvoke w
{
592 if {[$w cget
-state] ne
"disabled"} {
593 set oldRelief
[$w cget
-relief]
594 set oldState
[$w cget
-state]
595 $w configure
-state active
-relief sunken
598 $w configure
-state $oldState -relief $oldRelief
599 uplevel #0 [list $w invoke]
603 # ::tk::ButtonAutoInvoke --
605 # Invoke an auto-repeating button, and set it up to continue to repeat.
608 # w button to invoke.
614 # May create an after event to call ::tk::ButtonAutoInvoke.
616 proc ::tk::ButtonAutoInvoke {w
} {
618 after cancel
$Priv(afterId
)
619 set delay
[$w cget
-repeatinterval]
620 if {$Priv(window
) eq
$w} {
622 uplevel #0 [list $w invoke]
625 set Priv
(afterId
) [after $delay [list tk::ButtonAutoInvoke $w]]
629 # ::tk::CheckRadioInvoke --
630 # The procedure below is invoked when the mouse button is pressed in
631 # a checkbutton or radiobutton widget, or when the widget is invoked
632 # through the keyboard. It invokes the widget if it
636 # w - The name of the widget.
637 # cmd - The subcommand to invoke (one of invoke, select, or deselect).
639 proc ::tk::CheckRadioInvoke {w
{cmd invoke
}} {
640 if {[$w cget
-state] ne
"disabled"} {
641 uplevel #0 [list $w $cmd]
645 # Special versions of the handlers for checkbuttons on Unix that do the magic
646 # to make things work right when the checkbutton indicator is hidden;
647 # radiobuttons don't need this complexity.
649 # ::tk::CheckInvoke --
650 # The procedure below invokes the checkbutton, like ButtonInvoke, but handles
651 # what to do when the checkbutton indicator is missing. Only used on Unix.
654 # w - The name of the widget.
656 proc ::tk::CheckInvoke {w
} {
658 if {[$w cget
-state] ne
"disabled"} {
659 # Additional logic to switch the "selected" colors around if necessary
660 # (when we're indicator-less).
662 if {![$w cget
-indicatoron]} {
663 if {[$w cget
-selectcolor] eq
$Priv($w,aselectcolor
)} {
664 $w configure
-selectcolor $Priv($w,selectcolor
)
666 $w configure
-selectcolor $Priv($w,aselectcolor
)
669 uplevel #0 [list $w invoke]
673 # ::tk::CheckEnter --
674 # The procedure below enters the checkbutton, like ButtonEnter, but handles
675 # what to do when the checkbutton indicator is missing. Only used on Unix.
678 # w - The name of the widget.
680 proc ::tk::CheckEnter {w
} {
682 if {[$w cget
-state] ne
"disabled"} {
683 # On unix the state is active just with mouse-over
684 $w configure
-state active
686 # If the mouse button is down, set the relief to sunken on entry.
687 # Overwise, if there's an -overrelief value, set the relief to that.
689 set Priv
($w,relief
) [$w cget
-relief]
690 if {$Priv(buttonWindow
) eq
$w} {
691 $w configure
-relief sunken
692 set Priv
($w,prelief
) sunken
693 } elseif
{[set over
[$w cget
-overrelief]] ne
""} {
694 $w configure
-relief $over
695 set Priv
($w,prelief
) $over
698 # Compute what the "selected and active" color should be.
700 if {![$w cget
-indicatoron]} {
701 set Priv
($w,selectcolor
) [$w cget
-selectcolor]
702 lassign
[winfo rgb
$w [$w cget
-selectcolor]] r1 g1 b1
703 lassign
[winfo rgb
$w [$w cget
-activebackground]] r2 g2 b2
704 set Priv
($w,aselectcolor
) \
705 [format "#%04x%04x%04x" [expr {($r1+$r2)/2}] \
706 [expr {($g1+$g2)/2}] [expr {($b1+$b2)/2}]]
707 if {[set ::[$w cget
-variable]] eq
[$w cget
-onvalue]} {
708 $w configure
-selectcolor $Priv($w,aselectcolor
)
715 # ::tk::CheckLeave --
716 # The procedure below leaves the checkbutton, like ButtonLeave, but handles
717 # what to do when the checkbutton indicator is missing. Only used on Unix.
720 # w - The name of the widget.
722 proc ::tk::CheckLeave {w
} {
724 if {[$w cget
-state] ne
"disabled"} {
725 $w configure
-state normal
728 # Restore the original button "selected" color; assume that the user
729 # wasn't monkeying around with things too much.
731 if {![$w cget
-indicatoron] && [info exist Priv
($w,selectcolor
)]} {
732 $w configure
-selectcolor $Priv($w,selectcolor
)
734 unset -nocomplain Priv
($w,selectcolor
) Priv
($w,aselectcolor
)
736 # Restore the original button relief if it was changed by Tk. That is
737 # signaled by the existence of Priv($w,prelief).
739 if {[info exists Priv
($w,relief
)]} {
740 if {[info exists Priv
($w,prelief
)] && \
741 $Priv($w,prelief
) eq
[$w cget
-relief]} {
742 $w configure
-relief $Priv($w,relief
)
744 unset -nocomplain Priv
($w,relief
) Priv
($w,prelief
)