Skip to content
Cecil edited this page Jun 3, 2018 · 1 revision

Menus, menuitems and a menubar

This a future enhancement to Shoes if all the wrinkles can be smoothed.

This was never part of the original philosophy of Shoes or the design goals. However, it appears possible to get some minimal menus implemented. As anyone who has used osx and linux (or windows) knows, OSX is different. It has one menubar for all the windows in your application. If you think about it harder it becomes even more difficult to figure out how Shoes could emulate one model on the other system because there's more got-cha tricks in those competing models that you first appreciate.

Menus are totally optional - you have to ask for them.

First simplification

If you need menus for your application and you want to be cross platform then you won't spawn new Shoes.apps or Windows and put menus on those sub windows/app. In other words you'll use the one menubar model. It's not that much of design constraint.

Second simplification

Shoes doesn't allow submenus (yet). We don't have icons in the menus (yet) or mnemonics (yet). We do have accelerators and separators.

Third Simplification

Not everything that could be done has to be done.

Definition

Shoes defines things this way. These definitions(widgets) will differ from what you know in OSX and Gtk3 even though some names are shared.

menubar

The menubar is a horizontal strip of graphic real estate. In OSX it's on the top of the screen. In Linux and Windows it is a strip across the Window(s) The menubar has menus. In Shoes there will be a default menu already setup up. You should think three times before changing it and one of those rethinks will be done with OSX.

menu

A menu is a vertical stripe of dropdown space. A menu contains menuitems. A menu has a title like "Help". The title is shown in the menubar. A menu also has a position in the menubar (0 that "Shoes" menu)

A menu contains menuitems.

menuitem

A menuitem has a title, shown in the menu, an optional accelerator key like ^h and a Shoes block that will be called when the menuitem is selected.

Simple example

Let add a Help menu to the menubar with an About menuitem and and a Cobbler menuitem

Shoes.app menus: true, width: 300, height: 200 do  
  mb = menubar
  helpmenu = menu "Help"
  @aboutitem =  menuitem "About", key: "control_h" do
    alert "This is a menu test", title: "About"
  end
  helpmenu << @aboutitem
  cobbleritem = menuitem "Cobbler" do Shoes.cobbler end
  helpmenu << cobbleritem
  mb << helpmenu
end

We get the current menubar, there will be one. We don't know if were are running osx or linux or windows so this script doesn't know what's in the Shoes menu so we'll append the help menu to the menubar. But first we have to build the helpmenu object and then build all the menuitem objects and attach them to the menu. Then we can update the menubar.

That's it. In real life, that do..end block could to be tricky to write for your application. It's a lot like a Shoes button.

API

This should be in the manual but I'll rough it out here.

menubar methods

menubar >> menubar object

This gets the global menubar (OSX) or current menubar object for the Shoes 'app' window. Design your application so they are the same.

menubar.menus >> an array

Returns a ruby array of menu objects.

menubar[x] >> menu object

Shoes does something fun here. [x] could be an integer like [1] or it could be a string like ["Help"]. If the string does exist in the menubar's menus titles or the integer is out of range then nil is returned. You might get an exception on the log window too.

menubar << menu >> nothing useful.

Same as append.

menubar.append menu >> nothing useful

Append the new menu object to the end of the menubar and two the menus array in the menubar object.

Returns nothing useful

menubar.insert menu, pos >> nothing useful

Insert the menu object at pos position. If pos is a string, it will used to search thru the menus for a matching title. menus start at 0. Inserting at 1 will push 1...n-1 down (visually to the right). Only dare-devils would insert at 0.

Returns nothing useful.

menubar.remove pos >> nothing useful

Delete the menu at pos from the menubar. Pos maybe a integer or a String that matches a menu title.

menu methods

A few more methods than menubar but there is pattern.

menu title >> menu object

Creates a new menu object with the given title string. A new menu object has no menuitems attached. Returns the new menuitem object

menu.title >> string

Returns the string of the menu's title. Not particularly useful.

menu.items >> an array of menuitems

Returns the list (array) of menuitems contained in this menu object.

menu[x] >> menuitem

Returns the menuitem at position [x]. X maybe an integer [3] or a string ["About"] matching the title of the first menuitem contained in the menu.

menu.index string >> integer

Returns the index of the menuitem title that matches the string Like all ruby array indices, it start with 0.

menu << menuitem

see append

menu.append menuitem

Adds the menuitem to the end of the list (array) of menuitems contained in the menu. Visually, this the bottom of drop down column.

menu.insert menuitem, pos

Inserts the new menuitem at pos, pushing anything at or beyond pos down. pos may be an integer or a String that matches a menuitem title. If pos is less that 0 (or nonexistent) it behaves as append.

menu.remove pos

Delete the menuitem at pos from the menu's list. pos may be an integer or a string. If a string it will delete the first matching menuitem with a matching title.

menuitem API

menuitem title [,key: string] [block] >> menuitem

Creates a new menuitem with the given title string (shown in the containing menu drop down list); A hash of {:key "string"} is optional. The block argument is also optional. Like Button widgets, the syntax for a menuitem block is a bit odd. The block will be called it the menuitem is selected by the user.

NOTE: If the title starts with 3 hyphens "---" the menuitem will display as a separator and can not be selected or trigger a call to a block.

The optional :key => string hash (or key: string) requires the string to be in a certain form: For example "control_h" will be converted to ^H on Linux/Windows and that apple-fan-h on OSX. 'shift_control_x' would be shift control X (shift_apple_X).

Caution: alt_, and alt_shift_control_ and variants like control_alt_ may work for some people, sometimes. Rule of thumb: Don't use alt if you care about other people.

menuitem.title >> string

Returns the title string of the menuitem

menuitem.title = string

Changes the menuitem title to string

menuitem.enable = boolean

By default all menuitems except the "---" separators are enabled: They can be selected and the associated block will trigger. You can disable with a menuitem.enable = false and re-enable with menuitem.enable = true

menuitem.block = proc

You can replace (or set) a block on a menu item. This example might help.

Shoes.app menus: true, width: 300, height: 200 do  
  mb = menubar
  helpmenu = menu "Help"
  @aboutitem =  menuitem "About", key: "control_h" do
    alert "This is a menu test", title: "About"
  end
  helpmenu << @aboutitem
  cobbleritem = menuitem "Cobbler" do Shoes.cobbler end
  helpmenu << cobbleritem
  mb << helpmenu
  button "change About" do
    @aboutitem.title = "Info"
    @aboutitem.block = proc {
      if confirm "The block is changed, disable menuitem?"
        @aboutitem.enable = false
      end
    }
  end
end

Note that it demonstrates setting title and enable.

Menu

In This Section:

Clone this wiki locally