Article
Difficulty Rating
1
Doing Menus in MetaCard

.

.

.

Menus are really very simple to do in MetaCard. However, they often prove to be one of the more difficult concepts to get to grips with if you are just starting out. The important thing to understand is that menus in MetaCard are really just buttons with a few fancy properties set. This even applies to the MacOS version of MetaCard - editing the menu bar is just a case of moving around buttons on the stack to which the menus are "attached". Even if you are an old hand with menus, you'll want to check out our scrolling menus stack, which is available for download (see the bottom of this document).

MetaCard supports two different methods of doing menus. The first method is known as a button contents menu. Use it to construct simple menus which use only the normal set of options - radio buttons, check boxes, dividers and enabled or disabled items and hierarchical (or pull right) menus. The second, the menu panel, is used for doing more complex menus that support any kind of scripting or control. Use these to make pop up palettes, menus with graphics, images, icons, or any other complex type of menu.

Button Contents Menus

We'll start off by looking at button contents menus. Button contents menus are buttons, with their text property set to contain a list of items to pop up. Use the properties palette to create a button, then set its style to pulldown. Then, put the name of each menu item on a separate line in the menu contents field. Try out that button: clicking on it will cause the menu to open. If you want to dynamically alter the contents of the menu before display, use a mouseDown handler in the button to set the text property of the button to whatever you want. Use this technique to add, delete, check, uncheck, enable or disable items.

To make an item...

Do the following...

a dividing line

use "-" as the name of the item.

disabled

place a "(" at the start of the item name.

a hilited checkbox

place a "!c" at the start of the item name.

an unhilited checkbox

use "!n" at the start of the item name.

a hilited radio button

place a "!r" at the start of the item name.

an unhilited radio button

place a "!u" at the start of the item name.

 

Example:

Item 1
(Item 2
-
!cFourth item
Fifth item
-
Seventh Item
Eight item
(!rItem nine

Button contents menus on Windows and the MacOS.

MetaCard can use HyperCard compatible syntax for menu operations. Here's a sample script to disable an item (in this case, item 5):

on mouseDown
disable menuItem 5 of me
end mouseDown

And a few more HyperCard compatible examples:

disable menu "Style"
enable menuItem 3 of menu "Style"
hilite menuItem 1 of menu "Font"
                                    

MetaCard's native way of handling menus is actually a little harder to use. The following script does the same as the first example above, disabling menu item 5:

on mouseDown
  get the text of me
  if char 1 of line 5 of it is not "(" then put "(" before line 5 of it
  set the text of me to it
end mouseDown
                                    

You may need to use this method to control some MetaCard specific features, such as placing checkboxes before menu items.

When an item gets chosen, it sends a "menuPick" message to the button. The menuPick message is sent with the name of the item chosen. Here is an example script:

on menuPick pWhichItemPicked
switch pWhichItemPicked
case "Item 1"
--do something to handle the first item picked
break
case "Second item"
--do something to handle the second item getting picked
break
... etc...
end switch
end menuPick

Tip: If you prefer to work with item numbers instead of names, use the menuHistory property. It contains the number of the item last chosen, instead of the name. Use a switch statement:

switch the menuHistory of me

Button contents menus can also be used to do option style menus, and comboBox style menus. Use an option menu to create a list of items. Use a comboBox to create a scrolling list of items where the user has the option to type the name of the item in instead of choose it from a list. Use the menuLines property to set how many lines in a comboBox are visible at one time. Note that disabling items, checkboxes, dividers, etc. are not supported in this type of menu.

ComboBoxes on Windows and the MacOS. The menuLines has been set to 5.

When an item is chosen, the label property of the button is automatically set to the name of the item chosen. In option menus, when you re-open the menu, it will be positioned with the item most recently chosen over the mouse. You can get and set this using the menuHistory property of the button.

Option menus on Windows and the MacOS.

 

The final type of button contents menu is the tabbed button. This type of menu can be used to display a tabbed interface, often used for doing program Preferences screens. The tab items are set as contents in the normal way. Like option menus and comboBoxes, using dividers, disabling items and other such features are not supported.

When a tab is chosen, a menuPick message is sent to the button. In this case it is sent with two parameters, the name of the tab chosen, and the name of the tab previously chosen. The most common use for this is to hide and show a group of controls.

If you want to set which tab is currently active, you can set the menuHistory property of the button to the number of the tab, e.g.:

set the menuHistory of btn "tabbed
example" to 2
                                             

Note that setting the menuHistory causes a menuPick message to be sent to the button, just as if one of the tabs had been pressed with the mouse.

Menu panel menus

Menu Panels are very different from button contents menus. They are actual MetaCard stacks, as opposed to a property attached to a single button. This means you can open them in multiple places throughout an application without having to duplicate anything. It also means that you have to draw out the panel yourself, and you can place any standard MetaCard control in it if you wish.

To create a menu panel, it is simplest to clone the existing menu panel structure found in MetaCard. Type:

clone stack "MC SelectedObject Menu"
                                             

to create an editable copy of the MetaCard object selection menu. You'll find that all the buttons in the stack have mouseUp scripts, instead of menuPick handlers. You can use mouseUp messages attached to each button in the menu, or use a single menuPick handler like in button contents. In addition, normal messages are sent to controls in a panel stack. This means you can use the messages mouseEnter, mouseLeave, etc. to provide additional functionality if you wish.

To display a menu panel, create a button on the stack you want to display it. Set the style to either pulldown or popup, and then set the menuName property to the name of the stack you've created. You can do all of these operations using the button properties palette. For example, you could create a button to pop up the MetaCard object selection menu in anywhere - simply create a new button, set the style to pulldown and the menuName to "MC SelectedObject Menu".

If you need to display a panel by script, rather than attached to a button, you can open the menu stack using a command in a mouseDown handler. For example:

popup "myStackMenu"
                                             

will open the stack "myStackMenu" as a popup menu under the position of the cursor.

Tip:If you only want your panel to open on a button when a particular mouse button is used, set the menuMouseButton property. For example, select a pulldown panel button and type:

set the menuMouseButton of the selobj to 3
                                             

The button will now only display the menu if you use the third mouse button. Note that the third mouse button is actually the second mouse button on Windows systems, and the mouse-Control key combination on the Mac.

  Sub-menus (or "pull right" menus)

If you want to create menus inside menus, you can use either contents menus with tabs inserted, or create the first menu as a menu panel. Note that sub-menus inside button contents menus are only supported in 2.2.1B1 or above, previous versions require you to use panel menus.

For button contents menus, place tabs before the menu items that you want to be displayed in a sub-menu. The number of tabs can be used to indicate the number of levels deep an item is.

For panel menus, the item where you want the second menu to be displayed should have its style set to cascade. You can either set the button contents of that button to form a button-contents sub-menu, or set the menuName property to display a panel inside the panel. The sub-menu will be displayed automatically when the mouse moves over the item. Note that you can't use the cascade style menu in a normal stack - you must use it inside a menu panel.

Menu Bars

A menu bar is made from a group of buttons. To create a menu bar, create buttons corresponding to each menu and, using the Button Properties dialogue, set the style of the buttons to pulldown menu. If you're using Windows, set the text and font to the Windows standard (MS Sans Serif). If you're using the MacOS, you don't need to set the font - the system font will be used when MetaCard places your buttons into the MacOS standard menu bar at the top of the screen.

Set the menu contents of each button to the menu items you require. Arrange the buttons as a menu bar and group them. Name the group. To display a menu bar as the system menu bar on MacOS, use the Stack Properties dialog in the Edit menu to set the menubar property of the stack to the name of the group. Whenever the stack is active that group will be used for the system menu bar.

IMPORTANT: On MacOS when you set the menubar property of a stack to a group which exists in the same stack, the whole stack is scrolled so that the menu bar group and everything above it disappears from the window. The height of the stack is actually decreased by the height of the menu bar group and everything above it. This is a useful time saver for cross-platform projects because the same menu bar appears inside the window in Windows and UNIX, and on the system menubar in MacOS. However, if you want the group to remain in the stack window where it is editable on MacOS systems, set the editMenus property of the stack to true.

A good example of an existing menu bar you can take apart and examine is the MetaCard standard menu bar. The entire MetaCard interface is written in MetaCard. The menus you see while using MetaCard are a MetaCard group. The menubar of stack "Home" is set to the group "MetaCard Menu Bar". If you want to see this group type the following into the Message Box:

toplevel "MetaCard Menu Bar"-- stack name happens to be group name
                                             

Select the group named "MetaCard Menu Bar" inside this stack. These are the actual menus MetaCard displays in its editor. Be cautious as editing this group will alter the MetaCard interface.

Menu bars on MacOS systems

The menu bar includes the MacOS standard Help menu with the Apple default items (usually Show Balloons, About Balloon Help). The righter-most menu button in the menubar group always operates as the Help menu (and is named Help, regardless of what you call it). The last item in the menu contents of the righter-most button is used as the About... menu item in the Apple menu. To capture a user selection of that item, place a menuPick message handler in the group containing the menu bar.

If you want to update the contents of the menu bar before displaying the menus, place a mouseDown message in the group containing the menus. Note that the mouseDown message is only sent to the group, not the individual menus. This is a limitation of the MacOS. Another limitation for the 2.2 release of MetaCard is that you can't use menu panels in the Mac menu bar. All Mac menu bar menus must be standard button contents menus (cascade and option styles are not supported either). If you want to do sub-menus, these must be done using the sub-menu button contents properties in the 2.2.1B1 release or above.

If any of the subStacks in your project don't have a menu bar, but you want one to be displayed set the defaultMenuBar global property to the one you want displayed. That menu bar will then be displayed for stacks without a menu bar.

Important Note:

Make sure that the buttons in any menu bar you create don't overlap. If they do, it may cause strange behavior - including multiple panels being displayed at once. If you're having problems with a menu bar, check to see that the buttons aren't overlapping.

  Scrolling Menus

One limitation of MetaCard is that you can't do scrolling menus, except as the comboBox type. There are plans to add scrolling menu support to the MetaCard engine. In the mean time, Cross Worlds has produced a free utility for creating menu panel menus, which includes full support for scrolling. Fully compatible with MetaCard on any platform, you can use it to create menus with greater ease than producing even button contents menus. The panels created can easily also be edited easily by script on the fly - just like button contents menus. This stack comes complete with support for doing cascade (sub-menu) style menus inside the scrolling menu, with support for scrolling sub-menus inside sub-menus. (Of course, actually doing this in your program would make it just about impossible to navigate :-) Download it here as a Stuffit archive, or here as a zip archive.

Did you find this article useful? Have any ideas for future topics? Email Us!