This event class is fired when a system menu is displayed or any menu is closed. There are two subtypes:
The menu display can be stopped entirely by calling preventDefault() on the event object (passed as a parameter to your event handler).
Alternatively, you can modify the menu that's about to be displayed by event object's property menuUpdated to true, and changing the id, items, and options properties to reflect the menu you want to display instead of the standard system menu. See Overriding a system menu below for more details.
The event target for this event type is the mainWindow object.
You can use the menuopen event to prevent any system menu from displaying, to add or remove items from the default system menu, or to display your own entirely custom menu in place of a system menu. In all cases, you do this by canceling the default system handling of the menuopen event, which would otherwise proceed by showing the standard system menu, and then optionally displaying your own menu via mainWindow.showMenu().
To suppress a system menu: simply cancel the menuopen event when that menu is about to be opened. For example, this will prevent the Exit menu from ever showing:
To add new items to a system menu: The most common sort of change that you'll probably want to make to a system menu is to add a new custom item or items. You can do this by directly manipulating the array in the items property of the event object, but the MenuEvent object provides a convenience method that makes this a little bit easier: event.addMenuItem(). You can read the full details on that below. Here's how you could add a "Quit PinballY" command to the main menu, just before the Cancel item at the bottom of the normal menu.
To delete an item in a system menu: There's also a convenience method to delete items from a menu, event.deleteMenuItem(). For example, here's how you could delete the Play command from the main menu (not that you'd ever really want to do that!):
Note that it's a good idea to call event.tidyMenu() after deleting items, since a deletion could potentially leave an empty "group" in the menu, where two separator bars are shown with no commands in between. There's no real harm in that, but it looks awkward, so it's nice to clean those up, which is what tidyMenu() does.
To modify items in a system menu: You can modify any system menu, by taking advantage of the items property of the menuopen event object, which gives you the complete contents of the menu that the system is about to display. The items array uses exactly the same format that mainWindow.showMenu() uses to describe a custom menu, so it has all of the information you'd need to build an identical custom menu of your own. You can use the items array as a starting point to do things like inserting custom menu items, removing items that the system menu would normally show, or changing the displayed names on the system's menu items.
You can also change the id and options properties in the event object to reflect any changes you want to make to those.
After making any changes to the menu items, ID, or options, you must set the menuUpdated property of the event object to true. This property is undefined by default. When the event processing is complete, the system checks this property of the event object, and if it hasn't been changed, the system assumes that you haven't made any changes to the menu setup and goes ahead with the standard menu layout. So if you want to apply changes, you must set menuUpdated to true.
For example, if you want to change the name of the "Play" command on the main menu to "Run Game", you could do something like this:
This approach is designed so that multiple event handlers can make their own edits to the same system menus, without having to know about one another. This is useful for combining your own scripts with add-in modules written by other people. Remember that the event system allows you to create any number of listeners for each event, and calls each listener in sequence when the event occurs. So if you have multiple menuopen listeners, each one gets a chance to inspect and edit the items array before the final menu is displayed.
To replace a system menu with an entirely custom menu: This is just like editing a system menu, as in the example above, except that you'd ignore the original items list in the event and build your own from scratch, with your desired list of custom menu items.
The sequencing of the menuopen and menuclose events can be a little confusing when switching straight from one menu to another, such as when navigating into a submenu. The thing that's confusing is that the menuopen for the new menu will fire before the menuclose for the old menu fires.
To understand why, we have to look at the timing of the open/close events individually. The menuopen event is sent before the new menu is displayed. This is important because it gives you a chance to intervene, by canceling the new menu display entirely or by altering its contents. The menuclose event is sent after the old menu is removed. This event represents a fait accompli; it's not possible to prevent the menu from being closed, since it's already gone by the time the event occurs.
Now, putting those two bits of timing together, we can see what happens when the user does something that switches directly from one menu to another. The menuopen event for the new menu occurs first, before the menuclose event for the old menu is fired. That's a necessary consequence of the menuopen handler's ability to intervene in the new menu setup, because the display of the new menu is what actually triggers the removal of the old menu. If your menuopen handler cancels the new menu before it's been opened, any old menu will remain displayed, so a menuclose event for the old menu before the menopen event for the new menu would have been premature.
The reason we point this out is that it might seem reasonable to think that a menuclose event means that a menu is no longer being displayed. It doesn't actually mean that, though, because the outgoing menu could have been replaced with a new menu by the time the close event fired.
This event type has all of the standard event properties and methods (see the Event class), plus the following additional items:
newItem can be a single menu item descriptor object, of the same sort that you can use with mainWindow.showMenu(), or it can be an array of such objects if you wish to insert several items in one go. The new item or items are inserted at the location specified by the where. If no match is found for the where argument, the new items are inserted at the default location, meaning at the very top of the menu (before the first existing item) for a "before" condition, or the very end of the menu (after the last existing item) for an "after" condition.
If you pass an items array as an argument, the method edits that array and returns it as the result. If you don't pass an argument, the method edits the items property of the event object itself, and also sets the menuUpdated of the event property to true to reflect the change.
If you pass an items array as an argument, the method edits that array and returns it as the result. If you don't pass an argument, the method edits the items property of the event object itself, and also sets the menuUpdated of the event property to true to reflect the change.
If you pass an items array as an argument, the method tidies up that array and returns the result. If you don't pass an argument at all, the method tidies up the array in the items property of the event object itself, and also sets the menuUpdated property of the event to true to reflect the change.