Gnocl MenuButton

WJG (08/01/19) Gnocl has a wide range of buttons, choosers and menu functionality but there is not a simple menu button. There is the toolbar menu button but this is a megawidget comprised of two buttons and geared more towards offering a recent choices type pulldown menu enhancement to a basic file open button. A menubar could be used, but this would ruin the style of the layout which, as a button, should look like a button and not a menu label. Working with popups is the best solution here. The gnocl::menuButton command below is simply a wrap around the standard gnocl::button plus the addition a unique option, -menu. The creation and packing of a menu into a popup window is achieved with the menu popup command. The trick but is making sure that the popup behaves like pulldown appearing beneath its parent widget rather than placed under the mouse pointer.

#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"

if { [catch { package present Gnocl } ] } { package require Gnocl }


## display menuButton menu, adjust positionsing for right-edge/bottom of screen
#/param w button widget-id
#/param d menu widget-id
#/returns none
proc gnocl::mbPopup { w d } {
        
        lassign [gnocl::winfo geometry $w] x y w h                             
        lassign [gnocl::winfo geometry $d] mx my mw mh
        lassign [gnocl::screen geometry] sw sh
                                
        if { [expr ($y+$h+$mh) > $sh ] } { 
                set y [expr $y - $mh] 
        } else {
                set y [expr $y + $h]
        }

        if { [expr ($x+$mw) > $sw ] } { set x [expr $sw - $mw] } 
        
        $d popup $x $y

}

## implement widget commands
#/param args standard series of options for gnocl::button, plus -menu
#/returns menu button widget-id
proc gnocl::menuButton { args } {
        
        # extract -menu option and discard -onClicked
        array set tmp $args
        set menu $tmp(-menu)
        array unset tmp -menu 
        array unset tmp -onClicked
                
        set res [gnocl::button {*}[array get tmp]]
        $res configure -onClicked "gnocl::mbPopup $res $menu"
        
        return $res
}


## Demonstrate menuButton
proc main { args } {

        # create menu
        set ::app(languages) [list {"Sanskrit (D)" sk} {"Sanskrit (I)" sk} {"Pali (I)" pa} {"Pali (D)" pa} {Chinese zh} {"Tibetan (U)" bo} {"Tibetan (W)" bo} ]

        set menu [gnocl::menu -title "menu" -tearoff 0]
        foreach item $::app(languages) {
                $menu add [gnocl::menuCheckItem -text [lindex $item 0] -onToggled {puts "load item 1"}]
        }        

        # create menuButton and attach to a window
        gnocl::window -title MB -child [gnocl::menuButton -menu $menu -icon %#Preferences -text "Click Me"] -width 100 -height 100

}


main