123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- #
- # Bindings for Menubuttons.
- #
- # Menubuttons have three interaction modes:
- #
- # Pulldown: Press menubutton, drag over menu, release to activate menu entry
- # Popdown: Click menubutton to post menu
- # Keyboard: <space> or accelerator key to post menu
- #
- # (In addition, when menu system is active, "dropdown" -- menu posts
- # on mouse-over. Ttk menubuttons don't implement this).
- #
- # For keyboard and popdown mode, we hand off to tk_popup and let
- # the built-in Tk bindings handle the rest of the interaction.
- #
- # ON X11:
- #
- # Standard Tk menubuttons use a global grab on the menubutton.
- # This won't work for Ttk menubuttons in pulldown mode,
- # since we need to process the final <ButtonRelease> event,
- # and this might be delivered to the menu. So instead we
- # rely on the passive grab that occurs on <Button> events,
- # and transition to popdown mode when the mouse is released
- # or dragged outside the menubutton.
- #
- # ON WINDOWS:
- #
- # I'm not sure what the hell is going on here. [$menu post] apparently
- # sets up some kind of internal grab for native menus.
- # On this platform, just use [tk_popup] for all menu actions.
- #
- # ON MACOS:
- #
- # Same probably applies here.
- #
- namespace eval ttk {
- namespace eval menubutton {
- variable State
- array set State {
- pulldown 0
- oldcursor {}
- }
- }
- }
- bind TMenubutton <Enter> { %W instate !disabled {%W state active } }
- bind TMenubutton <Leave> { %W state !active }
- bind TMenubutton <space> { ttk::menubutton::Popdown %W }
- bind TMenubutton <<Invoke>> { ttk::menubutton::Popdown %W }
- if {[tk windowingsystem] eq "x11"} {
- bind TMenubutton <Button-1> { ttk::menubutton::Pulldown %W }
- bind TMenubutton <ButtonRelease-1> { ttk::menubutton::TransferGrab %W }
- bind TMenubutton <B1-Leave> { ttk::menubutton::TransferGrab %W }
- } else {
- bind TMenubutton <Button-1> \
- { %W state pressed ; ttk::menubutton::Popdown %W }
- bind TMenubutton <ButtonRelease-1> \
- { if {[winfo exists %W]} { %W state !pressed } }
- }
- # PostPosition --
- # Returns x and y coordinates and a menu item index.
- # If the index is not an empty string the menu should
- # be posted so that the upper left corner of the indexed
- # menu item is located at the point (x, y). Otherwise
- # the top left corner of the menu itself should be located
- # at that point.
- #
- # TODO: adjust menu width to be at least as wide as the button
- # for -direction above, below.
- #
- if {[tk windowingsystem] eq "aqua"} {
- proc ::ttk::menubutton::PostPosition {mb menu} {
- set menuPad 5
- set buttonPad 1
- set bevelPad 4
- set mh [winfo reqheight $menu]
- set bh [expr {[winfo height $mb]} + $buttonPad]
- set bbh [expr {[winfo height $mb]} + $bevelPad]
- set mw [winfo reqwidth $menu]
- set bw [winfo width $mb]
- set dF [expr {[winfo width $mb] - [winfo reqwidth $menu] - $menuPad}]
- set entry ""
- set entry [::tk::MenuFindName $menu [$mb cget -text]]
- if {$entry eq ""} {
- set entry 0
- }
- set x [winfo rootx $mb]
- set y [winfo rooty $mb]
- switch [$mb cget -direction] {
- above {
- set entry ""
- incr y [expr {-$mh + 2 * $menuPad}]
- }
- below {
- set entry ""
- incr y $bh
- }
- left {
- incr y $menuPad
- incr x -$mw
- }
- right {
- incr y $menuPad
- incr x $bw
- }
- default {
- incr y $bbh
- }
- }
- return [list $x $y $entry]
- }
- } else {
- proc ::ttk::menubutton::PostPosition {mb menu} {
- set mh [expr {[winfo reqheight $menu]}]
- set bh [expr {[winfo height $mb]}]
- set mw [expr {[winfo reqwidth $menu]}]
- set bw [expr {[winfo width $mb]}]
- set dF [expr {[winfo width $mb] - [winfo reqwidth $menu]}]
- if {[tk windowingsystem] eq "win32"} {
- incr mh 6
- incr mw 16
- }
- set entry {}
- set entry [::tk::MenuFindName $menu [$mb cget -text]]
- if {$entry eq {}} {
- set entry 0
- }
- set x [winfo rootx $mb]
- set y [winfo rooty $mb]
- switch [$mb cget -direction] {
- above {
- set entry {}
- incr y -$mh
- # if we go offscreen to the top, show as 'below'
- if {$y < [winfo vrooty $mb]} {
- set y [expr {[winfo vrooty $mb] + [winfo rooty $mb]\
- + [winfo reqheight $mb]}]
- }
- }
- below {
- set entry {}
- incr y $bh
- # if we go offscreen to the bottom, show as 'above'
- if {($y + $mh) > ([winfo vrooty $mb] + [winfo vrootheight $mb])} {
- set y [expr {[winfo vrooty $mb] + [winfo vrootheight $mb] \
- + [winfo rooty $mb] - $mh}]
- }
- }
- left {
- incr x -$mw
- }
- right {
- incr x $bw
- }
- default {
- if {[$mb cget -style] eq ""} {
- incr x [expr {([winfo width $mb] - \
- [winfo reqwidth $menu])/ 2}]
- } else {
- incr y $bh
- }
- }
- }
- return [list $x $y $entry]
- }
- }
- # Popdown --
- # Post the menu and set a grab on the menu.
- #
- proc ttk::menubutton::Popdown {mb} {
- if {[$mb instate disabled] || [set menu [$mb cget -menu]] eq ""} {
- return
- }
- foreach {x y entry} [PostPosition $mb $menu] { break }
- tk_popup $menu $x $y $entry
- }
- # Pulldown (X11 only) --
- # Called when Button1 is pressed on a menubutton.
- # Posts the menu; a subsequent ButtonRelease
- # or Leave event will set a grab on the menu.
- #
- proc ttk::menubutton::Pulldown {mb} {
- variable State
- if {[$mb instate disabled] || [set menu [$mb cget -menu]] eq ""} {
- return
- }
- set State(pulldown) 1
- set State(oldcursor) [$mb cget -cursor]
- $mb state pressed
- $mb configure -cursor [$menu cget -cursor]
- foreach {x y entry} [PostPosition $mb $menu] { break }
- if {$entry ne {}} {
- $menu post $x $y $entry
- } else {
- $menu post $x $y
- }
- tk_menuSetFocus $menu
- }
- # TransferGrab (X11 only) --
- # Switch from pulldown mode (menubutton has an implicit grab)
- # to popdown mode (menu has an explicit grab).
- #
- proc ttk::menubutton::TransferGrab {mb} {
- variable State
- if {$State(pulldown)} {
- $mb configure -cursor $State(oldcursor)
- $mb state {!pressed !active}
- set State(pulldown) 0
- set menu [$mb cget -menu]
- foreach {x y entry} [PostPosition $mb $menu] { break }
- tk_popup $menu [winfo rootx $menu] [winfo rooty $menu]
- }
- }
- # FindMenuEntry --
- # Hack to support tk_optionMenus.
- # Returns the index of the menu entry with a matching -label,
- # "" if not found.
- #
- proc ttk::menubutton::FindMenuEntry {menu s} {
- set last [$menu index last]
- if {$last eq "none" || $last eq ""} {
- return ""
- }
- for {set i 0} {$i <= $last} {incr i} {
- if {![catch {$menu entrycget $i -label} label]
- && ($label eq $s)} {
- return $i
- }
- }
- return ""
- }
- #*EOF*
|