MenuEvent

This event class is fired when a system menu is displayed or any menu is closed. There are two subtypes:

The event target for this event type is the mainWindow object.

Overriding a system menu

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:

mainWindow.on("menuopen", ev => { if (ev.id == "exit") ev.preventDefault(); });

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.

mainWindow.on("menuopen", ev => { if (ev.id == "main") ev.addMenuItem(command.MenuReturn, { title: "Quit", cmd: command.Quit }); });

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!):

mainWindow.on("menuopen", ev => { if (ev.id == "main") { ev.deleteMenuItem(command.PlayGame); ev.tidyMenu(); } });

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:

mainWindow.on("menuopen", (ev) => { if (ev.id = "main") { // edit the menu items ev.items.forEach(i => { if (i.cmd == command.PlayGame) i.title = "Run Game"; }); // tell the system to apply our updates ev.menuUpdated = true; } });

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.

Timing of open/close events

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.

Properties

This event type has all of the standard event properties and methods (see the Event class), plus the following additional items:

Methods