2 # $Id: menubutton.tcl,v 1.1 2006/10/31 01:42:27 hobbs Exp $
4 # Bindings for Menubuttons.
6 # Menubuttons have three interaction modes:
8 # Pulldown: Press menubutton, drag over menu, release to activate menu entry
9 # Popdown: Click menubutton to post menu
10 # Keyboard: <Key-space> or accelerator key to post menu
12 # (In addition, when menu system is active, "dropdown" -- menu posts
13 # on mouse-over. Ttk menubuttons don't implement this).
15 # For keyboard and popdown mode, we hand off to tk_popup and let
16 # the built-in Tk bindings handle the rest of the interaction.
20 # Standard Tk menubuttons use a global grab on the menubutton.
21 # This won't work for Ttk menubuttons in pulldown mode,
22 # since we need to process the final <ButtonRelease> event,
23 # and this might be delivered to the menu. So instead we
24 # rely on the passive grab that occurs on <ButtonPress> events,
25 # and transition to popdown mode when the mouse is released
26 # or dragged outside the menubutton.
30 # I'm not sure what the hell is going on here. [$menu post] apparently
31 # sets up some kind of internal grab for native menus.
32 # On this platform, just use [tk_popup] for all menu actions.
36 # Same probably applies here.
40 namespace eval menubutton {
49 bind TMenubutton
<Enter
> { %W instate
!disabled
{%W state active
} }
50 bind TMenubutton
<Leave
> { %W state
!active
}
51 bind TMenubutton
<Key-space
> { ttk
::menubutton::Popdown %W
}
52 bind TMenubutton
<<Invoke
>> { ttk
::menubutton::Popdown %W
}
54 if {[tk windowingsystem
] eq
"x11"} {
55 bind TMenubutton
<ButtonPress-1
> { ttk
::menubutton::Pulldown %W
}
56 bind TMenubutton
<ButtonRelease-1
> { ttk
::menubutton::TransferGrab %W
}
57 bind TMenubutton
<B1-Leave
> { ttk
::menubutton::TransferGrab %W
}
59 bind TMenubutton
<ButtonPress-1
> \
60 { %W state pressed
; ttk
::menubutton::Popdown %W
}
61 bind TMenubutton
<ButtonRelease-1
> \
66 # Returns the x and y coordinates where the menu
67 # should be posted, based on the menubutton and menu size
68 # and -direction option.
70 # TODO: adjust menu width to be at least as wide as the button
71 # for -direction above, below.
73 proc ttk
::menubutton::PostPosition {mb
menu} {
74 set x
[winfo rootx
$mb]
75 set y
[winfo rooty
$mb]
76 set dir
[$mb cget
-direction]
78 set bw
[winfo width
$mb]
79 set bh
[winfo height
$mb]
80 set mw
[winfo reqwidth
$menu]
81 set mh
[winfo reqheight
$menu]
82 set sw
[expr {[winfo screenwidth
$menu] - $bw - $mw}]
83 set sh
[expr {[winfo screenheight
$menu] - $bh - $mh}]
86 above
{ if {$y >= $mh} { incr y
-$mh } { incr y
$bh } }
87 below
{ if {$y <= $sh} { incr y
$bh } { incr y
-$mh } }
88 left
{ if {$x >= $mw} { incr x
-$mw } { incr x
$bw } }
89 right
{ if {$x <= $sw} { incr x
$bw } { incr x
-$mw } }
91 # post menu atop menubutton.
92 # If there's a menu entry whose label matches the
93 # menubutton -text, assume this is an optionmenu
94 # and place that entry over the menubutton.
95 set index
[FindMenuEntry
$menu [$mb cget
-text]]
97 incr y
-[$menu yposition
$index]
106 # Post the menu and set a grab on the menu.
108 proc ttk
::menubutton::Popdown {mb
} {
109 if {[$mb instate disabled
] ||
[set menu [$mb cget
-menu]] eq
""} {
112 foreach {x y
} [PostPosition
$mb $menu] { break }
116 # Pulldown (X11 only) --
117 # Called when Button1 is pressed on a menubutton.
118 # Posts the menu; a subsequent ButtonRelease
119 # or Leave event will set a grab on the menu.
121 proc ttk
::menubutton::Pulldown {mb
} {
123 if {[$mb instate disabled
] ||
[set menu [$mb cget
-menu]] eq
""} {
126 foreach {x y
} [PostPosition
$mb $menu] { break }
127 set State
(pulldown
) 1
128 set State
(oldcursor
) [$mb cget
-cursor]
131 $mb configure
-cursor [$menu cget
-cursor]
133 tk_menuSetFocus $menu
136 # TransferGrab (X11 only) --
137 # Switch from pulldown mode (menubutton has an implicit grab)
138 # to popdown mode (menu has an explicit grab).
140 proc ttk
::menubutton::TransferGrab {mb
} {
142 if {$State(pulldown
)} {
143 $mb configure
-cursor $State(oldcursor
)
144 $mb state
{!pressed
!active
}
145 set State
(pulldown
) 0
147 set menu [$mb cget
-menu]
148 tk_popup $menu [winfo rootx
$menu] [winfo rooty
$menu]
153 # Hack to support tk_optionMenus.
154 # Returns the index of the menu entry with a matching -label,
157 proc ttk
::menubutton::FindMenuEntry {menu s
} {
158 set last
[$menu index last
]
159 if {$last eq
"none"} {
162 for {set i
0} {$i <= $last} {incr i
} {
163 if {![catch {$menu entrycget
$i -label} label]