Like most applications, yours may rely on menus and toolbars as part of the basic user interface. Menus and toolbars are common, multipurpose widgets that are familiar to most users. Menus often appear as part of a menu bar that organizes all of the capabilities of the program, or they can be single menus for presenting a simple list of choices. Buttons provide quick access to the most commonly used tasks and help get information back from the user. Beyond these basics, however, XUL provides widgets for creating almost any kind of interface (and the flexibility of Mozilla's presentation layer means you can make even the most prosaic menus look any way you want).
As your applications grow in complexity and provide more services to the user, the toolbox can be a good way to organize menus, toolbars, and other widgets. A <toolbox> is a special container for holding one or more toolbars and/or menu bars. A Mozilla toolbar implements a toolbargrippy and a box that contains children. The toolbargrippy is a bar on the lefthand side used for collapsing and expanding the bar. This useful method allows users to control the space that is available to them onscreen.
The <toolbar> element shown in Example 3-4 contains buttons used to carry out various application functions. Buttons are the most common children of a toolbar, but they are by no means the only widgets or content you can put in there.
Example 3-4. Toolbar with buttons and spacing
<toolbox> <toolbar id="fixed-toolbar" class="toolbar-primary" tbautostretch="always" persist="collapsed"> <toolbarbutton id="newfileBtn" label="New" oncommand="doNew( );" /> <toolbarseparator /> <toolbarbutton id="openfileBtn" label="Open" oncommand="doOpen( );" /> <spacer flex="1" /> </toolbar> </toolbox>
To apply spacing between elements, the <spacer> element can be used. In Example 3-4, all space that remains after the buttons are drawn goes after the buttons because the spacer there is flexible and the buttons are not. Space added elsewhere with other <spacer> elements is determined by ratio of the flex values on the elements competing for layout space. Extending the toolbar in Example 3-4, you can add a print button on the far right:
<toolbarbutton id="newfileBtn" label="New" oncommand="doNew( );" /> <toolbarseparator /> <toolbarbutton id="openfileBtn" label="Open" oncommand="doOpen( );" /> <spacer flex="1" /> <toolbarbutton id="printBtn" label="Print" oncommand="doPrint( );" />
The <toolbarseparator> element does not create additional spacing between the first two toolbarbuttons, but there is space between them and the print button, which is pushed to the far right because the flex attribute of the spacer in between is set to 1.
Among the other most common nested elements within a toolbox is a XUL <menubar>. <menubar> is a container much like the toolbar that has one or more menus as its children.
<menubar id="fixed-menubar"> <menu label="Quantity" /> <menu label="Color" /> </menubar>
//FIXME did we loose content here?
There is one caveat in menubar behavior that you should be aware of. On the Mac OS, application menu bars appear at the top of the screen. If you have any nonmenu elements contained in your menu bar widget, they are ignored because the OS does not know how to display them there.
As Example 3-5 illustrates, it's easy to build up a simple application menu and get the intrinsic look and collapsibility of a menu bar with a few simple lines of code:
Example 3-5. Application menu bar
<?xml version="1.0"?> <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <menubar id="appbar"> <menu label="File"> <menupopup> <menuitem label="New"/> <menuitem label="Open"/> </menupopup> </menu> <menu label="Edit" /> </menubar> </window>
There are a number of ways to create lists in Mozilla. This section provides three alternative ways of presenting the same choices to the user. The options are illustrated in Figure 3-3. The one thing these three selection list widgets -- menus, pop ups, and menu lists -- have in common is they all use menu items to display individual choices:
<menuitem label="Tachinidae" oncommand="changeF(1)"/> <menuitem label="Tanyderidae" oncommand="changeF(2)"/> <menuitem label="Tipulidae" oncommand="changeF(3)"/> <menuitem label="Syrphidae" oncommand="changeF(4)"/> <menuitem label="Tephritidae" oncommand="changeF(5)"/>
When you wrap the menuitem elements above in a menu, a menu list, and a pop-up window, you see the variations in Figure 3-3.
Menus are much more flexible than they first appear to be. They can appear anywhere in the UI, for one thing, and needn't be stuck at the top of the window. They can be in buttons, trees, or just out on their own. Example 3-6 shows the basic structure of a menu.
Example 3-6. A sample menu
<menu label="Quantity"> <menupopup> <!-- menuitems here --> </menupopup> </menu>
There is a rigid ordering of nesting in a menu. A menu contains a <menupopup>, which in turn contains one or more menu items. Optionally, you can segregate groups of menu items by using a <menuseparator> in the pop up, which draws a thin line between items.
The pop up manifests as either a <menupopup> or a <popup> element. The latter can be used in a number of different ways, but Example 3-7 focuses on its common use in context menus.
Example 3-7. Context menu using pop up
<popup id="FlyContext" onpopupshowing="return doThis( );" onpopuphiding=" return doThat( );"> <!-- menuitems here --> </popup>
A couple of extra steps are needed to prepare a context pop up for activation. First, you must attach the popup element to a widget in the UI by using the id of the pop up that must correspond to the context of the widget:
<toolbar id="main-toolbar" context="FlyContext" />
When the toolbar is clicked, the pop up that corresponds to that value appears. You can have some script execute when you show and/or hide the pop up by using the onpopupshowing and onpopuphiding methods, as when you show and hide items in a dynamic menu.
The second step includes the pop up in a set of pop ups, enclosed in a <popupset> element. Though not strictly necessary as a container for pop ups, the pop-up set helps organize the free-floating pop-up windows in your application and makes it easy to overlay them or overlay into them as the situation requires.
Another manifestation of the pop up is in the use of menu lists. A menu list is a choice of options presented to solicit a single choice, usually in the form of a drop-down menu, for which XUL provides the <menulist> element. Example 3-8 presents a straightforward menu list with a selection of items to choose from. As in the other pop-up examples, selecting an item executes the code defined in the oncommand event handler for that item (e.g., changeF(1) for the menu item "Tachinidae").
Example 3-8. XUL menu list
<menulist id="FlyInput"> <menupopup> <!-- menuitems here --> </menupopup> </menulist>
The menulist widget provides functionality beyond that of a regular menu. The menu list can be made editable when the user should be allowed to enter a value not represented in the menu items. In this case, the menulist element definition in Example 3-8 would change to something such as:
<menulist id="FlyInput" editable="true" oninput="onInputFly( );" onchange="onChangeFly( );">
A true value on the editable attribute allows input in the list. Input can be validated immediately by using the oninput attribute. The addition of the onchange attribute can be used to carry out an extra script when a new selection is made.
Free-floating because their location in the interface is not determined by their position in the XUL markup, as it usually is for items like menus and buttons.