**Toolbutton with optional menu** Sometimes it's useful in a toolbar, to have a button which an optional popdown menu. For example, in an IDE you could have a "Compile" button but occasionally the user wants to "Clean & Compile" or "Compile docs". "optionbuttion" is a crossover between a regular pushbutton and a menubutton. When clicking, it executes the command as a pushbutton. When holding the button down for longer than a 0.5 s (adjustable delay), a menu appears. The menu entries execute the callback with an index corresponding to the selected entry. The menu can also be displayed with a right button click, like context menus. Code: ====== # Copyright (c) 2021 Christian Gollwitzer # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. package require Tk package require snit snit::widgetadaptor optionbutton { # a toolbutton that opens a menu upon # longer click delegate option * to hull except -command delegate method * to hull # delay before opening the options menu option -delay -default 500 # values for display option -values -default {} -configuremethod setvalues option -headline -default {} # callback before menu opens option -optcallback -default {} # callback after press / select option -command -default {} component optmenu variable afterid {} constructor {args} { installhull using ttk::menubutton -style Toolbutton install optmenu using menu $win.m $hull configure -menu $optmenu $self configurelist $args # replace bindings bind $self [mymethod LeftBPress] bind $self [mymethod LeftBRelease] bind $self [mymethod RightBPress] } destructor { if {$afterid ne {}} { catch [after cancel $afterid] } } method LeftBPress {} { $hull state pressed set afterid [after $options(-delay) [mymethod openmenu]] return -code break } method LeftBRelease {} { if {$afterid ne {}} { # the delay for the popdown menu is not passes after cancel $afterid set afterid {} uplevel #0 $options(-command) } $hull state !pressed return -code break } method RightBPress {} { $self openmenu return -code break } method openmenu {} { set afterid {} uplevel #0 $options(-optcallback) $hull state !pressed ttk::menubutton::Popdown $win } method selected {i} { uplevel #0 [linsert $options(-command) end $i] } method setvalues {opt val} { set options($opt) $val $optmenu delete 0 end if {$options(-headline) ne {}} { $optmenu add command -label $options(-headline) -state disabled $optmenu add separator } set i 0 foreach lbl $val { $optmenu add command -label $lbl -command [mymethod selected $i] incr i } } } ====== Test: ====== proc echo args { puts $args } pack [optionbutton .b -text "Compile" -values {"Compile" "Clean & Compile" "Compile docs"} -command {echo called}] # fill the values just before the menu appears pack [optionbutton .c -text "I'm dynamic!" -values {1 2 3} -command {echo called} -optcallback {shuffle .c} -headline "Select number"] proc shuffle {w} { $w configure -values [list [expr rand()] [clock scan now] [clock format [clock scan now]]] } ======