summaryrefslogtreecommitdiffstats
path: root/library/ttk/button.tcl
blob: 14460a28e43b382a20cd69861cc32b39fcdc0608 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#
# Bindings for Buttons, Checkbuttons, and Radiobuttons.
#
# Notes: <Button1-Leave>, <Button1-Enter> only control the "pressed"
# state; widgets remain "active" if the pointer is dragged out.
# This doesn't seem to be conventional, but it's a nice way
# to provide extra feedback while the grab is active.
# (If the button is released off the widget, the grab deactivates and
# we get a <Leave> event then, which turns off the "active" state)
#
# Normally, <ButtonRelease> and <ButtonN-Enter/Leave> events are
# delivered to the widget which received the initial <Button>
# event.  However, Tk [grab]s (#1223103) and menu interactions
# (#1222605) can interfere with this.  To guard against spurious
# <Button1-Enter> events, the <Button1-Enter> binding only sets
# the pressed state if the button is currently active.
#

namespace eval ttk::button {}

bind TButton <Enter> 		{ %W instate !disabled {%W state active} }
bind TButton <Leave>		{ %W state !active }
bind TButton <space>		{ ttk::button::activate %W }
bind TButton <<Invoke>> 	{ ttk::button::activate %W }

bind TButton <Button-1> \
    { %W instate !disabled { ttk::clickToFocus %W; %W state pressed } }
bind TButton <ButtonRelease-1> \
    { %W instate pressed { %W state !pressed; %W instate !disabled { %W invoke } } }
bind TButton <Button1-Leave> \
    { %W state !pressed }
bind TButton <Button1-Enter> \
    { %W instate {active !disabled} { %W state pressed } }

# Checkbuttons and Radiobuttons have the same bindings as Buttons:
#
ttk::copyBindings TButton TCheckbutton
ttk::copyBindings TButton TRadiobutton

# ...plus a few more:

bind TRadiobutton <Up>  		{ ttk::button::RadioTraverse %W -1 }
bind TRadiobutton <Down> 		{ ttk::button::RadioTraverse %W +1 }

# bind TCheckbutton <+> { %W select }
# bind TCheckbutton <minus> { %W deselect }

# activate --
#	Simulate a button press: temporarily set the state to 'pressed',
#	then invoke the button.
#
proc ttk::button::activate {w} {
    $w instate disabled { return }
    set oldState [$w state pressed]
    update idletasks; after 100	;# block event loop to avoid reentrancy
    $w state $oldState
    $w invoke
}

# RadioTraverse -- up/down keyboard traversal for radiobutton groups.
# 	Set focus to previous/next radiobutton in a group.
#	A radiobutton group consists of all the radiobuttons with
#	the same parent and -variable; this is a pretty good heuristic
#	that works most of the time.
#
proc ttk::button::RadioTraverse {w dir} {
    set group [list]
    foreach sibling [winfo children [winfo parent $w]] {
    	if {   [winfo class $sibling] eq "TRadiobutton"
	    && [$sibling cget -variable] eq [$w cget -variable]
	    && ![$sibling instate disabled]
	} {
	   lappend group $sibling
	}
    }

    if {![llength $group]} {	 # Shouldn't happen, but can.
    	return
    }

    set pos [expr {([lsearch -exact $group $w] + $dir) % [llength $group]}]
    tk::TabToWindow [lindex $group $pos]
}