Menus

PinballY's on-screen menu system is the workhorse of its UI, handling most user interactions. The menu system is functionally similar to conventional Windows mouse menus, but it's designed to be convenient to operate with just the basic pin cab buttons, and it's visually styled to look more like arcade graphics and with larger type for readability at a distance.

You can use the menu system from your Javascript code to create your own custom menus and display them whenever needed. You display a custom menu by calling mainWindow.showMenu(). This function lets you create a menu that looks and operates exactly like the built-in menus, and lets you populate it with standard system commands and/or your own custom commands.

The showMenu() function is called as follows:

mainWindow.showMenu(id, items, options);

id is a string giving an internal identifier for the menu. This can be any string you want; the system merely stores it, and reports it back to you via the .menuID property of the status object returned from mainWindow.getUIMode() while the menu is still being displayed.

items is an array of menu item descriptors. Each descriptor is an object with the following properties. The boolean flag properties are all optional; if omitted, they default to false.

The options object can be omitted, in which case the default settings are used. If present, options can have the following properties, all of which are optional and default to false or zero as appropriate:

Custom commands

When you create your own menu, you'll probably want to include some custom commands: that is, commands that aren't already provided by PinballY commands. To facilitate this, the system reserves the range of command IDs from command.UserFirst to command.UserLast specifically for your use in Javascript code. You can assign commands in this range as you see fit.

Implementing a custom menu command generally requires two Javascript elements:

Flow of control

When you call mainWindow.showMenu(), the system displays the menu, and the function immediately returns. It doesn't wait for the user to make a selection. Instead, the program continues running with the menu displayed. The program will interpret user input in the context of menu navigation, so the user will be able to navigate among the menu items. There's no need for your Javascript code to concern itself with any of the menu navigation, as that's handled automatically by the system. When the user selects an item from the menu, it will trigger a CommandEvent, with the command ID that you specified in the selected menu item stored in the event object. So the way you handle a command selected from your custom menu is to write a CommandEvent handler that responds to the custom command.

// Display a custom menu when the user presses the Insert key mainWindow.on("keydown", ev => { if (ev.code == "Insert") { mainWindow.showMenu("custom1", [ { title: "Custom Command", cmd: command.UserFirst }, { cmd: -1 }, { title: "Return", cmd: command.MenuReturn } ]); } }); // Handle our "Custom Command" command mainWindow.on("command", ev => { if (ev.id == command.UserFirst) { /* carry out the command here */; } });

Paged menus

In some cases, a menu might have too many items to fit into the available display space all at once. This is especially possible when a menu gets its items from a dynamic source, where you don't know in advance exactly how many items will be included, such as the list manufacturer filters.

To deal with menus that are known to be too large or that merely could be too large, depending on dynamic source data, the menu system can divide a menu into "pages" - groups of items that are displayed one page at a time. The user can switch between the pages using the "Next Page" and "Previous Page" buttons (typically assigned to the Magna save buttons on a pin cab) or by selecting up/down arrow items shown graphically in the menu.

Most paged menus have a section that's divided into pages, with some fixed items above and/or below the paged section. This lets you keep the options common to all pages (e.g., "Cancel", "Save") on the screen at all times.

To designate a section of a menu as paged, simply include an item with command ID command.MenuPageUp before the first paged item, and another item with command ID command.MenuPageDown after the last paged item. The Page Up and Page Down items don't need titles; they'll be displayed with up/down arrow graphics instead. The menu system will automatically measure the height of the menu and determine if the paged area actually has to be split up into multiple pages. If so, the menu will initially display the first page and will include the up/down arrows. If the full menu fits the available screen height without any page divisions, the up/down arrow items are simply omitted. So there's no need to figure out in advance whether or not the menu is "too big"; if there's any chance of that, you can simply include the page section markers and let the menu system figure out whether or not paging is necessary.

Menu events

When a menu opens or closes, the system fires a menuopen or menuclose event (respectively). See MenuEvent for details.

Customizing system menus

You can suppress, edit, or replace any system menu by taking advantage of the menuopen event. This event lets you intervene every time the system is about to display one of its own standard menus. You can use that opportunity to block a system menu entirely, make slight modifications (such as renaming items or adding your own custom items), or replace the system menu with your own entirely custom menu. See Overriding a system menu for details on how to accomplish these tricks.

System menus

Here's a list of the built-in menus generated by PinballY, and their menu IDs. The ID is the string reported in the .menuID property of the result object returned from mainWindow.getUIMode().