# MenuEvent

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

- menuopen: Fires when a system menu is about to be displayed. No event is fired when a user menu is opened via mainWindow.showMenu().

  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.

- menuclose: Fires when any menu (including both system menus and user menus) has just been closed. This event is fired after the fact, so it's not possible to prevent the menu from being closed.

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 modify 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:

- id: a string with the menu ID of the menu that's about to be opened or that just closed. See system menus for list of IDs strings for the standard menus.
- items: for the menuopen event, an array of objects describing the items in the menu that's about to be opened. The list is in the same format as the items argument in mainWindow.showMenu(), so you can pass this as an argument to that function to show a menu with the same contents. Modifying the list has no effect on the menu displayed if you allow the menuopen to proceed to the system handling, but you can cancel the event to prevent this menu from showing, and call showMenu() with your own item list instead. This property isn't present for menuclose events.
- menuUpdated: undefined by default; set this to true to signal that you've changed the id, items, and/or options properties to reflect a modified version of the menu that want to display instead of the original. See Overriding a system menu above for more details.
- options: for the menuopen event, an object with properties describing the menu options, in the same format as the options argument to mainWindow.showMenu(). Modifying the object has no effect on the menu displayed if you allow the menuopen event to proceed to the system handling, but you can cancel the event to prevent this menu from showing, and call showMenu() with your own options instead. This property isn't present for menuclose events.