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.
- title: a string giving the title of the item, or an empty string to display
a separator bar instead of a named item
- cmd: an integer giving the command number (see Commands),
or -1 if this item can't be selected as a command item
- selected: true if the item is pre-selected when the menu opens, as though the user
had navigated to this item already. Only one item can be selected at a time, so if
multiple items have this flag, the last one with the flag is the one that's actually
selected.
- checked: true if the item should be displayed with a checkmark
- radio: true if the item should be displayed with a radio button bullet (this is
mutually exclusive with "checked", as only one type of mark can be displayed)
- hasSubmenu: true if the item should be displayed with an arrow indicating that
it has a sub-menu
- stayOpen: true if the menu should stay open when the item is selected. This can
be used for items that update a setting in place and leave the menu open for further
selections.
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:
- isExitMenu: true if this should be treated as an "Exit" menu. The special
feature of an Exit menu is that the Exit button acts like the Select button within
the menu, if that behavior is configured in the user's option settings. The rationale
for this behavior is that some people find it more intuitive to make selections in a
menu with the same button that opened the menu, so a menu that's opened with the Exit
button should also use the Exit button to make selections.
- noAnimation: true if you want to skip the normal menu opening animation and
just display the menu instantly. This is useful when you're updating a menu in
place in response to a command, such as toggling a checkmark in a "stay open" item.
If this is a paged menu, you'll probably also want to specify pageNo: "same",
to maintain the same page location in the refreshed menu.
- dialogStyle: true to display a "dialog style" menu. This style is designed to
accommodate a long-ish message at the top of the menu, followed by the usual
complement of menu options below. Dialog menus are displayed at a slightly wider
size than regular menus, and the first item in the menu is displayed with a
slightly smaller font than regular menu items, to pack more text into the available
space. The first item is also word-wrapped onto multiple lines if necessary
(normal menu items are forced onto one line and clipped if they're
too wide). The first item in a dialog menu is
by convention a static (non-selectable) message only, so it should have "cmd"
set to -1 in its item descriptor. It also usually looks best to use a separator
bar as the second item, to visually reinforce the dialog styling. The remaining
items are ordinary menu items.
- pageNo: a number specifying the "page" to show initially (see Paged Menus below).
The page number starts at zero for the first page. You can also set this to
the string "same" to display the same page previously shown; this is
useful when re-displaying a menu after a stayOpen item was selected,
such as to update the check-mark status of some items.
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:
- First, you have to make the command accessible to the user, by
adding it to some menu. One way to do this is to
add it to one of the existing system menus, which you can do by setting
up a handler for the menuopen event that
intercepts the system menu of interest and customizes it with your
additional command(s). Another way is to create your own entirely
custom menu, and display it in response to an appropriate event, such
as when the user presses a special key that you select as the custom
menu key. You could also use a command
event handler to display a custom menu whenever the user selects one of
the standard system commands.
- Second, create a command event
handler that processes the command. The event handler should check the
command ID in the event object, and when it matches the ID you selected
(from the command.UserFirst...command.UserLast range), carry out the
custom action for the command.
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().
- "approve elevation": prompt to confirm privilege elevation for launching a game that
can only run in Admin Mode
- "batch capture disposition": batch capture file disposition selection menu (lists the media
types selected for the batch capture, with options for what to do about existing files for each
type)
- "batch capture games": batch capture game selection menu
- "batch capture media": batch capture media type selection menu (basically the same menu as
"capture", but shown during the batch capture setup workflow)
- "batch capture ready": final step of the batch capture workflow, showing a summary of the
proposed capture, with options to view details or launch the capture
- "capture layout message": shown at the start of a capture to explain how the screen recording area is determined
- "capture needs gameinfo": shown when the user attempts a Capture command on a game that
doesn't have an XML database entry; offers an option to set up the game information entry now
- "capture": single-game capture setup menu, with options for which media types to capture
- "confirm delete gameinfo": confirmation menu for deleting the current game's XML database entry
- "confirm delete media": confirmation menu for deleting a media file from the media file viewer
- "elevation required": prompt to allow restarting the program with the Admin Host enabled,
triggered when the user tries to launch a game requiring Admin Mode and the Admin Host isn't
already running
- "exit": the exit menu, shown when the user presses the Exit button from the main wheel UI
- "filter by category": filter submenu for selecting a category filter
- "filter by era": filter submenu for selecting an era filter
- "filter by manuf": filter submenu for selecting a manufacturer filter
- "filter by rating": filter submenu for selecting a star rating filter
- "filter by system": filter submenu for selecting a player system filter
- "filter by when added": filter submenu for selecting a recently-added filter
- "filter by when played": filter submenu for selecting a recently-played filter
- "game categories": menu for editing the category tags assigned to the current game
- "game setup": the game setup options menu
- "main": the main menu, shown when the user presses the Select button from the main wheel UI
- "media drop confirm replace": confirmation menu asking if a dropped media file should
replace an existing file
- "media drop confirm": confirmation menu shown when a media drop is ready to go, to confirm
that it should proceed
- "media drop needs gameinfo": shown when the user attempts to drop media files onto a game that
doesn't have an XML database entry; offers an option to set up the game information entry now
- "media drop rename": confirmation menu shown when dropped media files don't match the current
game's name, to warn that the wrong files might have been dropped
- "media search": media search confirmation menu (options to proceed with the search or cancel it)
- "operator": the operator menu
- "pause game": shown when the user presses the Pause Game button while a game is running;
PinballY tries to bring its window to the foreground, and then displays this menu
- "play pick system": system selection menu, displayed when the user tries to launch a game that
doesn't have a database entry and has multiple systems associated with its file type
- "power off": system shutdown confirmation menu, shown when the user selects "Power Off" from the
exit menu
- "swf error": displayed when an error occurs loading an .swf (Shockwave Flash file); provides
options to disable .swf files or ignore .swf errors for the current session (note: Flash Player
is no longer used as of PinballY 1.1 Beta 5, so this menu is essentially obsolete)
- Your custom ID: if the menu is a custom menu that you displayed via showMenu(),
the ID string that you provided when creating the menu is used.