ui, docs: Added menus to fill a couple of gaps, improved consistency. (#9915)

Added menus for controlling toggle inputs, and showing recognised input
devices and control state.  Moved input menu options off main menu to a
submenu, as there are a lot of them now.

Moved menu heading drawing into base class, added headings to more
menus, and made headings more consistent with the menu items used to
reach them.  Also made terminology more consistent.

Changed the default names for buttons and hat switches/D-pads to use
1-based numbering.  DirectInput still returns 0-based button numbers for
some devices.

Removed local copy of MinGW xaudio2.h as it’s now included in the MSYS2
package.  Also fixed building the DirectSound sound output module with
the SDL OSD on Windows - the Windows headers are sensitive to include
order.

Started adding documentation for menus, to hopefully help people find
menus they remember seeing but can't recall how to access.

For translators, this makes terminology more consistent.  In particular:
* "Settings" is preferred over "configuration" in a number of places, as
  the latter can be construed as referring specifically to settings
  stored in .cfg files in the cfg_directory folder.  Also, references to
  saving machine configuration could be interpreted as relating to the
  settings on the "Machine Configuration" menu.
* The controls on host input devices (e.g. keys, buttons, joystick axes)
  are referred to as "controls", while emulated inputs are referred to
  as "inputs".
* The menus for assigning host controls to emulated inputs are called
  "input assignments" menus to distinguish them from other input
  settings menus.
* Combinations of controls that can be assigned to emulated inputs are
  referred to as "combinations" rather than "sequences".
* The potentially confusing term "ROM set" has been removed altogether.
  Use "short name" to refer to a device or system's identifier.
* "System" is used in almost places to refer to a complete, runnable
  system rather than "Machine".
* "Driver" is now only used to refer to source files where systems or
  devices are defined - it is no longer used to refer to individual
  systems.
* A few more menus have message context for the messages.  This makes it
  a bit easier to guess where the messages are used.  It also means you
  can use different translations in different places if necessary (e.g.
  if the same English text should be translated differently as an item
  in one menu and as a heading in another).
This commit is contained in:
Vas Crabb 2022-06-11 21:47:19 +10:00 committed by GitHub
parent 5214d7f31c
commit f47f9c3db3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
121 changed files with 84412 additions and 68493 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
MAME is a registered trademark of Gregory Ember.
MAME is a registered trademark of Gregory Ember. Other trademarks are
property of their respective owners.
MAME as a whole is made available under the terms of the GNU General
Public License. Individual source files may be made available under

View File

@ -41,8 +41,9 @@ Basic structure
Controller configuration files follow a similar format to the system
configuration files that MAME uses to save things like input settings and
bookkeeping data. This example shows the overall structure of a controller
configuration file:
bookkeeping data (created in the folder specified using the
:ref:`cfg_directory option <mame-commandline-cfgdirectory>`). This example
shows the overall structure of a controller configuration file:
.. code-block:: XML
@ -127,21 +128,21 @@ left and right arrows will be replaced with the numeric 8, 2, 4 and 6 keys on
the numeric keypad, respectively.
Note that substitutions specified using ``remap`` elements only apply to inputs
that use MAMEs default assignment for the control type. That is, they only
apply to default assignments for control types set in the “Inputs (general)”
menu. They *do not* apply to default input assignments set in driver/device I/O
port definitions (using the ``PORT_CODE`` macro).
that use MAMEs default assignment for the input type. That is, they only apply
to default assignments for control types set in the “Input Assignments
(general)” menus. They *do not* apply to default control assignments set in
driver/device I/O port definitions (using the ``PORT_CODE`` macro).
MAME applies ``remap`` elements found inside any applicable ``system`` element.
.. _ctrlrcfg-typeoverride:
Overriding defaults by control type
-----------------------------------
Overriding defaults by input type
---------------------------------
Use ``port`` elements with ``type`` attributes but without ``tag`` attributes to
override the default host input assignments for a controls:
override the default control assignments for emulated inputs by type:
.. code-block:: XML
@ -183,10 +184,10 @@ P1 Button 4 (Player 1 Controls)
X key, or joystick 1 button 4
Note that this will only apply for inputs that use MAMEs default assignment for
the control type. That is, ``port`` elements without ``tag`` attributes only
override default assignments for control types set in the “Inputs (general)”
menu. They *do not* override default input assignments set in driver/device I/O
port definitions (using the ``PORT_CODE`` macro).
the input type. That is, ``port`` elements without ``tag`` attributes only
override default assignments for control types set in the “Input Assignments
(general)” menus. They *do not* override default control assignments set in
driver/device I/O port definitions (using the ``PORT_CODE`` macro).
MAME applies ``port`` elements without ``tag`` attributes found inside any
applicable ``system`` element.
@ -194,22 +195,22 @@ applicable ``system`` element.
.. _ctrlrcfg-ctrloverride:
Overriding defaults for specific controls
-----------------------------------------
Overriding defaults for specific inputs
---------------------------------------
Use ``port`` elements with ``tag``, ``type``, ``mask`` and ``defvalue``
attributes to override defaults for specific controls. These ``port`` elements
attributes to override defaults for specific inputs. These ``port`` elements
should only occur inside ``system`` elements that apply to particular systems or
source files (i.e. they should not occur inside ``system`` elements where the
``name`` attribute has the value ``default``). The default host input
assignments can be overridden, as well as the toggle setting for digital
controls.
``name`` attribute has the value ``default``). The default control assignments
can be overridden, as well as the toggle setting for digital inputs.
The ``tag``, ``type``, ``mask`` and ``defvalue`` are used to identify the
affected input. You can find out the values to use for a particular input by
changing its assigned host input, exiting MAME, and checking the values in the
system configuration file. Note that these values are not guaranteed to be
stable, and may change between MAME versions.
changing its control assignment, exiting MAME, and checking the values in the
system configuration file (created in the folder specified using the
:ref:`cfg_directory option <mame-commandline-cfgdirectory>`). Note that these
values are not guaranteed to be stable, and may change between MAME versions.
Heres an example that overrides defaults for 280-ZZZAP:
@ -225,5 +226,5 @@ Heres an example that overrides defaults for 280-ZZZAP:
</input>
</system>
This sets the host inputs to steer left and right to the K and J keys,
This sets the controls to steer left and right to the K and J keys,
respectively, and disables the toggle setting for the gear shift input.

View File

@ -63,9 +63,9 @@ copyright = u'1997-2022, MAMEdev and contributors'
# built documents.
#
# The short X.Y version.
version = '0.244'
version = '0.245'
# The full version, including alpha/beta/rc tags.
release = '0.244'
release = '0.245'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View File

@ -546,6 +546,21 @@ Examples:
Back to :ref:`debugger-general-list`
.. _debugger-command-time:
time
----
Prints the total elapsed emulated time to the debugger console.
Examples:
``time``
Prints the elapsed emulated time.
Back to :ref:`debugger-general-list`
.. _debugger-command-quit:
quit

View File

@ -50,9 +50,9 @@ Button 1* or the equivalent for another player, but it might have have a
different name. On Konamis Gradius games, *P1 Button 2* is the primary fire
button.
Select **Hotkey** to set the input combination youll use to activate the
autofire button. This can be any combination that MAME supports for activating
a digital input.
Select **Hotkey** to set the control (or combination of controls) youll use to
activate the autofire button. This can be any combination that MAME supports
for activating a digital input.
**On frames** and **Off frames** are the number of consecutive emulated video
frames that the emulated button will be held and released for, respectively.
@ -81,10 +81,10 @@ immediately.
Notes and potential pitfalls
----------------------------
Autofire buttons act as if theyre wired in parallel with MAMEs regular inputs.
This means that if you set the activation hotkey for an autofire button to a
button or key thats also assigned to one of the emulated inputs directly, you
may get unexpected results. Using Gradius as an example:
Autofire buttons act as if theyre wired in parallel with MAMEs regular
controls. This means that if you set the activation hotkey for an autofire
button to a button or key thats also assigned to one of the emulated inputs
directly, you may get unexpected results. Using Gradius as an example:
* Suppose you set button 1 on your controller to fire, and set an autofire
hotkey to button 1 as well. Holding the button down to shoot will not trigger
@ -97,8 +97,8 @@ may get unexpected results. Using Gradius as an example:
powerup because the powerup button is also being held down along with the
autofire button.
It is suggested you choose input combinations for autofire hotkeys that are not
assigned to any other emulated inputs in the system.
It is recommended that you choose control combinations for autofire hotkeys that
are not assigned to any other emulated inputs in the system.
Autofire is not necessarily desirable in all situations. For example using
autofire in Super-X with the blue “lightning” weapon equipped at high power

View File

@ -57,10 +57,10 @@ whole:
press the UI Clear key to type a new name. Press the UI Select key before
moving to another menu item to save the new name; press the UI Cancel key
(Escape/Esc on the keyboard by default) to change discard the new name.
* Select **Activation sequence** to set the key or button combination you want
to use to activate the macro. Keep in mind that regular input settings still
apply, so you probably want to use a combination that isnt being used for any
other emulated input in the system.
* Select **Activation combination** to set the control (or combination of
controls) you want to use to activate the macro. Keep in mind that regular
input assignments still apply, so you will probably want to use a combination
that isnt being used for any other emulated input in the system.
* Set **On release** to specify what should happen if the activation sequence is
released before the macro completes. When set to *Stop immediately*, any
emulated inputs activated by the macro will be released immediately, and no
@ -133,7 +133,7 @@ thing could be achieved using the :ref:`plugins-autofire`, but this demonstrates
a simple looping macro:
* **Name**: P1 Autofire
* **Activation sequence**: Kbd Space
* **Activation combination**: Kbd Space
* **On release**: Stop immediately
* **When held**: Loop to step 2
* **Step 1**:
@ -159,7 +159,7 @@ This allows you to run in Konami Track & Field by holding a single button. This
takes most of the skill (and fun) out of the game:
* **Name**: P1 Sprint
* **Activation sequence**: Kbd Shift
* **Activation combination**: Kbd Shift
* **On release**: Stop immediately
* **When held**: Loop to step 2
* **Step 1**:
@ -188,7 +188,7 @@ This macro allows you to perform a right-facing Shōryūken (Dragon Punch) by
pressing a single key:
* **Name**: 1P Shoryuken LP
* **Activation sequence**: Kbd M
* **Activation combination**: Kbd M
* **On release**: Complete macro
* **When held**: Prolong step 6
* **Step 1**:

View File

@ -126,7 +126,8 @@ A memory share can be created if it doesnt exist in a memory map
through that creator class. If it already exists it is just
retrieved. That class behaves like a pointer but also has the
``target()``, ``length()``, ``bytes()``, ``endianness()``,
``bitwidth()`` and ``bytewidth()`` methods for share information.
``bitwidth()`` and ``bytewidth()`` methods for share information. The
desired size is specified in bytes.
.. code-block:: C++
@ -154,12 +155,17 @@ A memory bank is a named memory zone indirection that can be mapped in
address spaces. It points to ``nullptr`` when created.
``configure_entry`` associates an entry number and a base pointer.
``configure_entries`` does the same for multiple consecutive entries
spanning a memory zone. Alternatively ``set_base`` sets the base for
entry 0 and selects it.
spanning a memory zone.
``set_entry`` allows to dynamically and efficiently select the current
active entry, ``entry()`` gets that selection back, and ``base()`` gets
the associated base pointer.
``set_base`` sets the base address for the active entry. If there are
no entries, entry 0 (zero) is automatically created and selected. Use
of ``set_base`` should be avoided in favour of pre-configured entries
unless there are an impractically large number of possible base
addresses.
``set_entry`` dynamically and efficiently selects the active entry,
``entry()`` returns the active entry number, and ``base()`` gets the
associated base pointer.
.. code-block:: C++

View File

@ -309,7 +309,7 @@ You can try changing the
:ref:`lightgunprovider <mame-commandline-lightgunprovider>` setting (depending
on which kind of device youre having issues with) from ``rawinput`` to one of
the other options such as ``dinput`` or ``win32``. See
:ref:`osd-commandline-options` for details on input provider options
:ref:`mame-commandline-osdoptions` for details on input provider options
.. _ExternalOPL:

View File

@ -63,7 +63,8 @@ and saving/loading save states.
Highlight first or last UI menu option.
**[** **]**
Move to previous or next group in UI menus that support it (e.g. move to the
inputs for the previous or next device in the Input (this Machine) menu).
inputs for the previous or next device in the **Input Assignments (this
System)** menu).
**Enter**/**Joystick 1 Button 1**
Select currently highlighted UI menu option.
**Space**
@ -706,8 +707,8 @@ All the keys below are fully configurable in the user interface. This list shows
the standard keyboard configuration.
Note that controls can vary widely by computer type, so not all keys are shown
here. See the “Input (this Machine)” section of MAMEs configuration menu for
details for the machine you are currently using.
here. See the **Input Assignments (this system)** section of MAMEs Input
Settings menu for details for the machine you are currently using.
**Tab**
@ -742,5 +743,5 @@ All the keys are fully configurable in the user interface.
Note that controls can vary widely by machine type, so default keys are not
shown here and defaults will vary considerably based on the manufacturer and
style. See the “Input (this Machine)” section of MAMEs configuration menu for
details for the machine you are currently using.
style. See the **Input Assignments (this system)** section of MAMEs Input
Settings menu for details for the machine you are currently using.

View File

@ -1,9 +1,283 @@
.. _menus:
MAME Menus
==========
If you started MAME without any command line parameters, you'll be shown the
system selection menu immediately. While the keys listed above will let you
navigate the menus, you can also use a mouse.
.. contents:: :local:
[todo: This needs SERIOUS expansion. Waiting on answer to a few questions..]
.. _menus-intro:
Introduction
------------
To show the :ref:`main menu <menus-main>` while running an emulated system in
MAME, press the **Config Menu** key or button (**Tab** by default). If the
emulated system has keyboard inputs, you may need to press the **UI Toggle** key
or button (**Scroll Lock**, or **Forward Delete** on macOS, by default) to
enable user interface controls first. You can dismiss a menu by pressing the
**UI Cancel** key or button (**Escape** by default). Dismissing a menu will
return to its parent menu, or to the running system in the case of the main
menu.
You can hide a menu and return to the running system by pressing the **Config
Menu** key or button. Pressing the **Config Menu** key or button again will
jump back to the same menu. This is useful when testing changes to settings.
Emulated system inputs are ignored while menus are displayed. You can still
pause or resume the running system while most menus are displayed by pressing
the **Pause** key or button (**P** on the keyboard by default).
If you start MAME without specifying a system on the command line, the system
selection menu will be shown (assuming the
:ref:`ui option <mame-commandline-ui>` is set to **cabinet**). The system
selection menu is also shown if you select **Select New System** from the main
menu during emulation.
For more information on navigating menus, :ref:`see the relevant section
<ui-menus>`.
.. _menus-main:
Main menu
---------
The main menu is shown when you press the **Config Menu** key or button while
running an emulated system or while the system information screen is displayed.
It provides access to menus used to change settings, control various features,
and show information about the running system and MAME itself.
If you press the **Config Menu** key or button to show the main menu while the
system information screen is displayed, the emulated system will not start until
the main menu is dismissed (either by selecting **Start System**, pressing the
**UI Cancel** key or button, or pressing the **Config Menu** key or button).
This can be useful for mounting media images or changing DIP switches and
machine configuration settings before the emulated system starts.
Input Settings
Shows the :ref:`Input Settings <menus-inputopts>` menu, where you can assign
controls to emulated inputs, adjust analog control settings, control toggle
inputs, and test input devices.
DIP Switches
Shows the DIP Switches menu, where configuration switches for the running
system can be changed. This item is not shown if the running system has no
DIP switches.
Machine Configuration
Shows the Machine Configuration menu, where various settings specific to the
emulated system can be changed. This item is not shown if the running
system has no configuration settings.
Bookkeeping
Shows uptime, coin counter and ticket dispenser statistics (if relevant) for
the running system.
System Information
Shows information about the running system as emulated in MAME, including
CPU, sound and video devices.
Warning Information
Shows information about imperfectly emulated features of the running system.
This item is not shown if there are no relevant warnings.
Media Image Information
Shows information about mounted media images (if any). This item is only
shown if the running system has one or more media devices (e.g. floppy disk
drives or memory card slots).
File Manager
Shows the File Manager menu, where you can mount new or existing media image
files, or unmount currently mounted media images. This item is only shown
if the running system has one or more media devices (e.g. floppy disk
drives or memory card slots).
Tape Control
Shows the Tape Control menu, where you can control emulated cassette tape
mechanisms. This item is only shown for systems that use cassette tape
media.
Pseudo Terminals
Shows the status of any pseudo terminal devices in the running system (used
to connect the emulated system to host pseudo terminals, for example via
emulated serial ports). This item is not shown if there are no pseudo
terminal devices in the running system.
BIOS Selection
Shows the BIOS Selection menu, where you can select the BIOS/boot
ROM/firmware for the system and slot cards it contains. This item is not
shown if no BIOS options are available.
Slot Devices
Shows the Slot Devices menu, where you can choose between emulated
peripherals. This item is not shown for systems that have no slot devices.
Barcode Reader
Shows the Barcode Reader menu, where you can simulate scanning barcodes with
emulated barcode readers. This item is not shown if there are no barcode
readers in the running system.
Network Devices
Shows the Network Devices menu, where you can set up emulated network
adapters that support bridging to a host network. This item is not shown if
there are no network adaptors that support bridging in the running system.
Slider Controls
Shows the Slider Controls menu, where you can adjust various settings,
including video adjustments and individual sound channel levels.
Video Options
Shows the Video Options menu, where you can change the view for each
screen/window, as well as for screenshots.
Crosshair Options
Shows the Crosshair Options menu, where you can adjust the appearance of
crosshairs used to show the location of emulated light guns and other
absolute pointer inputs. This item is not shown if the emulated system has
has no absolute pointer inputs.
Cheat
Shows the Cheat menu, for controlling the built-in cheat engine. This item
is only shown if the built-in chat engine is enabled. Note that the cheat
plugins menu is accessed via the Plugin Options menu.
Plugin Options
Shows the Plugin Options menu, where you can access settings for enabled
plugins. This item is not shown if no plugins are enabled, or if the main
menu is shown before the emulated system starts (by pressing the Config Menu
key/button while the system information screen is displayed).
External DAT View
Shows the info viewer, which displays information loaded from various
external support files. This item is not shown if the :ref:`data plugin
<plugins-data>` is not enabled, or if the main menu is shown before the
emulated system starts (by pressing the Config Menu key/button while the
system information screen is displayed).
Add To Favorites/Remove From Favorites
Adds the running system to the favourites list, or removes it if its
already in the favourites list. The favourites list can be used as a
filter for the system selection menu.
About MAME
Shows the emulator version, data model, and copyright license information.
Select New System
Shows the system selection menu, where you can select a system to start a
new emulation session. This item is not shown if the main menu is shown
before the emulated system starts (by pressing the Config Menu key/button
while the system information screen is displayed).
Close Menu/Start System
Closes the main menu, returning control of the running system. Shows
**Start System** if the main menu is shown before the emulated system
starts (by pressing the Config Menu key/button while the system information
screen is displayed).
.. _menus-inputopts:
Input Settings menu
-------------------
The Input Settings provides options for assigning controls to emulated inputs,
adjusting analog control settings, controlling toggle inputs, and testing input
devices. You can reach the Input Settings menu by selecting **Input Settings**
from the :ref:`main menu <menus-main>`. The items shown on this menu depend on
available emulated inputs for the running system. Available emulated inputs may
depend on slot options, machine configuration settings and DIP switch settings.
Input Assignments (general)
Lets you select assign user interface controls, or assign default controls
for all emulated systems. See the section on :ref:`configuring inputs
<ui-inptcfg>` for more details.
Input Assignments (this system)
Lets you select assign controls to emulated inputs for the running system.
See the section on :ref:`configuring inputs <ui-inptcfg>` for more details.
This item is not shown if the running system has no enabled inputs that can
be assigned controls.
Analog Input Adjustments
Shows the Analog Input Adjustments menu, where you can adjust sensitivity,
auto-centring speed and inversion settings for emulated analog inputs, and
see how the emulated analog inputs respond to controls with your settings.
For more details, see the :ref:`analog input settings <ui-inptcfg-analog>`
section for more details. This item is not shown if the running system has
no enabled analog inputs.
Keyboard Selection
Shows the :ref:`Keyboard Selection menu <menus-keyboard>`, where you can
select between emulated and natural keyboard modes, and enable and disable
keyboard and keypad inputs for individual emulated devices. This item is
not shown if the running system has no keyboard or keypad inputs.
Toggle Inputs
Shows the :ref:`Toggle Inputs menu <menus-inputtoggle>`, where you can view
and adjust the state of multi-position or toggle inputs. This item is not
shown if the running system has no enabled toggle inputs.
Input Devices
Shows the :ref:`Input Devices menu <menus-inputdevices>`, which lists the
input devices recognised by MAME.
.. _menus-inputtoggle:
Toggle Inputs menu
------------------
The Toggle Inputs menu shows the current state of multi-position or toggle
inputs. Common examples include mechanically locking Caps Lock keys on
computers, and two-position gear shit levers on driving games. You can reach
the Toggle Inputs menu by selecting **Toggle Inputs** from the :ref:`Input
Settings menu <menus-inputopts>`. Note that available emulated inputs may
depend on slot options, machine configuration settings and DIP switch settings.
Inputs are grouped by the emulated device they belong to. You can move between
devices using the **Next Group** and **Previous Group** keys or buttons. Names
of inputs are shown on the left, and the current settings are shown on the
right.
To change the state of an input, highlight it and use the **UI Left** and **UI
Right** keys or buttons, or click the arrows beside the current setting.
.. _menus-keyboard:
Keyboard Selection menu
-----------------------
The Keyboard Selection menu lets your switch between emulated and natural
keyboard modes, and enable or disable keyboard inputs for individual emulated
devices. You can reach the Keyboard Selection menu by selecting **Keyboard
Selection** from the :ref:`Input Settings menu <menus-inputopts>`.
In emulated keyboard mode, keyboard and keypad inputs behave like any other
digital inputs, responding to their assigned controls. In natural keyboard
mode, MAME attempts to translate typed characters to emulated keystrokes. The
initial keyboard mode is set using the :ref:`natural option
<mame-commandline-natural>`.
There are a number of unavoidable limitations in natural keyboard mode:
* The emulated system must to support it.
* The selected keyboard *must* match the keyboard layout selected in the
emulated software.
* Keystrokes that dont produce characters cant be translated. (e.g. pressing a
modifier key on its own, such as **Shift** or **Control**).
* Holding a key until the character repeats will cause the emulated key to be
pressed repeatedly as opposed to being held down.
* Dead key sequences are cumbersome to use at best.
* Complex input methods will not work at all (e.g. for Chinese/Japanese/Korean).
Each emulated device in the system that has keyboard and/or keypad inputs is
listed on the menu, allowing keyboard/keypad inputs to be enabled or disabled
for individual devices. By default, keyboard/keypad inputs are enabled for the
first device with keyboard inputs (if any), and for all other devices that have
keypad inputs but no keyboard inputs. The enabled keyboard/keypad inputs are
automatically saved to the configuration file for the system when the emulation
session ends.
.. _menus-inputdevices:
Input Devices menu
------------------
The Input Devices menu lists input devices recognised by MAME and enabled with
your current settings. Recognised input devices depend on the
:ref:`keyboardprovider <mame-commandline-keyboardprovider>`, :ref:`mouseprovider
<mame-commandline-mouseprovider>`, :ref:`lightgunprovider
<mame-commandline-lightgunprovider>` and :ref:`joystickprovider
<mame-commandline-joystickprovider>` options. Classes of input devices can be
enabled or disabled using the :ref:`mouse <mame-commandline-nomouse>`,
:ref:`lightgun <mame-commandline-nolightgun>` and :ref:`joystick
<mame-commandline-nojoystick>` options. You can reach the Input Devices menu by
selecting **Input Devices** from the :ref:`main menu <menus-main>` or the
General Settings menu.
Input devices are grouped by device class (for example keyboards or light guns).
You can move between device classes using the **Next Group** and **Previous
Group** keys or buttons. For each device, the device number (within its class)
is shown on the left, and the name is shown on the right.
Select a device to show the supported controls for the device. The name of
each control is displayed on the left and its current state is shown on the
right. When an analog axis control is highlighted, its state is also shown in
graphical form below the menu. Digital control states are either zero
(inactive) or one (active). Analog axis input states range from -65,536 to
65,536 with the neutral position at zero.

View File

@ -11,7 +11,7 @@ MAMEs User Interface
Introduction
------------
MAME provides a simple user interface for selecting a system and software to
MAME provides a simple user interface for selecting the system and software to
run and changing settings while running an emulated system. MAMEs user
interface is designed to be usable with a keyboard, game controller, or pointing
device, but will require a keyboard for initial configuration.
@ -62,8 +62,9 @@ Forward Delete, or Fn+Delete on some compact keyboards (UI Clear)
Clear setting or reset to default value.
Escape (UI Cancel)
Clear the search if searching the menu, otherwise close the menu, returning
to the previous menu, or returning to the emulated machine for the main menu
(theres usually an item at the bottom of the menu for the same purpose).
to the previous menu, or returning to the emulated system in the case of the
main menu (theres usually an item at the bottom of the menu for the same
purpose).
Home (UI Home)
Highlight the first menu item and scroll to the top of the menu.
End (UI End)
@ -92,6 +93,10 @@ most important UI controls have joystick assignments by default:
* Press the first button on the first joystick to select the highlighted menu
item.
For gamepad-style controllers, the left analog thumb stick usually controls UI
navigation. You may find it convenient to assign directional pad controls to UI
navigation in addition to or in place of the left thumb stick.
If you want to be able to use MAME with a game controller without needing a
keyboard, youll need to assign joystick buttons (or combinations of buttons) to
these controls as well:
@ -145,26 +150,31 @@ Configuring inputs
MAME needs a flexible input system to support the control schemes of the vast
array of systems it emulates. In MAME, inputs that only have two distinct
states, on and off or active and inactive, are called *digital inputs*, and all
other inputs are called *analog inputs*, even if this is not strictly true.
other inputs are called *analog inputs*, even if this is not strictly true (for
example multi-position switches are called analog inputs in MAME).
To assign MAMEs user interface controls or the default inputs for all systems,
select **Input (general)** from the main menu during emulation, or select
**Configure Options** from the system selection menu and then select **General
Inputs**. From there, select a category.
select **Input Settings** from the main menu during emulation and then select
**Input Assignments (general)** from the Input Settings menu, or select
**General Settings** from the system selection menu and then select **Input
Assignments** from the General Settings menu. From there, select a category.
To assign inputs for the currently running machine, select **Input (this
Machine)** from the main menu during emulation. Inputs are grouped by device
and sorted by type. You can move between devices with the next group and
previous group keys/buttons (**[** and **]** on the keyboard by default).
To assign inputs for the currently running system, select **Input Settings**
from the main menu during emulation and then select **Input Assignments (this
system)** from the Input Settings menu. Inputs are grouped by device and sorted
by type. You can move between devices with the next group and previous group
keys/buttons (opening/closing brackets **[** and **]** on the keyboard by
default).
The input assignment menus show the name of the emulated input or user interface
control on the left, and the input (or combination of inputs) assigned to it on
the right.
control on the left, and the controls (or combination of controls) assigned to
it on the right.
To adjust the sensitivity, auto-centre speed and inversion settings, or to see
how emulated analog controls react to your inputs, select **Analog Controls**
from the main menu during emulation. (This item only appears on the main menu
for systems with analog controls.)
how emulated analog controls react to your inputs, select **Input Settings**
from the main menu during emulation, and then select **Analog Input
Adjustments** from the Input Settings Menu (this item only appears on the Input
Settings menu for systems with analog controls).
.. _ui-inptcfg-digital:
@ -173,7 +183,7 @@ Digital input settings
~~~~~~~~~~~~~~~~~~~~~~
Each emulated digital input has a single assignment setting. For flexibility,
MAME can combine host inputs (keys, buttons and joystick axes) using logical
MAME can combine controls (keys, buttons and joystick axes) using logical
**and**, **not** and **or** operations. This is best illustrated with some
examples:
@ -195,11 +205,12 @@ Kbd P Kbd Shift or Kbd P Kbd Right Shift
(In technical terms, MAME uses Boolean sum of products logic to combine inputs.)
When a digital input setting is highlighted, the prompt below the menu shows
whether selecting it will set the assignment or append an **or** operation to
it. Press **UI Left/Right** before selecting the setting to switch between
setting or appending an **or** operation. Press **UI Clear** (**Delete** or
**Forward Delete** by default) to clear the setting or restore the default
assignment.
whether selecting it will replace the current assignment or append an **or**
operation to it. Press **UI Left/Right** before selecting the setting to switch
between replacing the assignment or appending an **or** operation to it. Press
**UI Clear** (**Delete** or **Forward Delete** by default) to clear the
highlighted setting, or restore the default assignment if it is currently
cleared.
When you select a digital input setting, MAME will wait for you to enter an
input or a combination of inputs for a logical **and** operation:
@ -211,7 +222,7 @@ input or a combination of inputs for a logical **and** operation:
analog control additional times toggles the **not** on and off.
* Pressing **UI Cancel** (**Escape** by default) *before* activating any other
controls clears the setting or restores the default assignment.
* Pressing **UI Cancel** *after* activating another control leaves the setting
* Press **UI Cancel** *after* activating another control to leave the setting
unchanged.
* The new setting is shown below the menu. Wait one second after activating an
input to accept the new setting.
@ -242,14 +253,14 @@ Each emulated analog input has three assignment settings:
input. The axis setting uses the name of the input with the suffix “Analog”.
For example the axis setting for the steering wheel in Ridge Racer is called
**Steering Wheel Analog**.
* Use the *increment setting* assign an input (or combination of inputs) to
* Use the *increment setting* assign a control (or combination of controls) to
increase the value of the emulated analog input. The increment setting uses
the name of the input with the suffix “Analog Inc”. For example the increment
setting for the steering wheel in Ridge Racer is called **Steering Wheel
Analog Inc**. This is a digital input setting if an analog axis is
assigned to it, MAME will not increase the emulated input value at a
proportional speed.
* Use the *decrement setting* assign an input (or combination of inputs) to
* Use the *decrement setting* assign a control (or combination of controls) to
decrease the value of the emulated analog input. The decrement setting uses
the name of the input with the suffix “Analog Dec”. For example the decrement
setting for the steering wheel in Ridge Racer is called **Steering Wheel
@ -272,12 +283,12 @@ You can assign one or more analog axes to the axis setting for an emulated
analog input. When multiple axes are assigned to an axis setting, they will be
added together, but absolute position controls will override relative position
controls. For example suppose for Arkanoid you assign the **Dial Analog** axis
setting to **Mouse X or Joy 1 LSX or Joy 1 RSX** on a mouse Xbox-style
setting to **Mouse X or Joy 1 LSX or Joy 1 RSX** on a mouse and Xbox-style
controller. You will be able to control the paddle with the mouse or either
analog stick, but the mouse will only take effect if both analog sticks are in
the neutral position (centred) on the X axis. If either analog stick is *not*
centred on the X axis, the mouse will have no effect, because a mouse is a
relative position control while a joystick is an absolute position control.
relative position control while joysticks are absolute position controls.
For absolute position controls like joysticks and pedals, MAME allows you to
assign either the full range of an axis or the range on one side of the neutral
@ -311,10 +322,10 @@ Mouse X or Joy 1 LT or Joy 1 RT Reverse
direction to the left trigger.
Joy 1 LB Joy 1 LSX
Use horizontal movement of the left analog stick to control the emulated
input, but *only* while holding the left shoulder button. If the right
input, but *only* while holding the left shoulder button. If the left
shoulder button is released while the left analog stick is not centred
horizontally, the emulated input will hold its value until the right
shoulder button is pressed again (a “sticky” control).
horizontally, the emulated input will hold its value until the left shoulder
button is pressed again (a “sticky” control).
not Joy 1 RB Joy 1 RSX or Joy 1 RB Joy 1 RSX Reverse
Use horizontal movement of the right analog stick to control the emulated
input, but invert the control if the right shoulder button is held.
@ -341,15 +352,16 @@ When you select an axis setting, MAME will wait for you to enter an input:
analog control to accept the new setting.
To adjust sensitivity, auto-centring speed and inversion settings for emulated
analog inputs, or to see how they respond to your settings, select **Analog
Controls** from the main menu during emulation. Settings for emulated analog
analog inputs, or to see how they respond to controls with your settings, select
**Input Settings** from the main menu during emulation, and then select **Analog
Input Adjustments** from the Input Settings Menu. Settings for emulated analog
inputs are grouped by device and sorted by type. You can move between devices
with the next group and previous group keys/buttons (**[** and **]** on the
keyboard by default). The state of the emulated analog inputs is shown below
the menu, and reacts in real time. Press the **On Screen Display** key or
button (the backtick/tilde key by default on a US ANSI QWERTY keyboard) to hide
the menu to make it easier to test without changing settings. Press the same
key or button to show the menu again.
with the next group and previous group keys/buttons (opening/closing brackets
**[** and **]** on the keyboard by default). The state of the emulated analog
inputs is shown below the menu, and reacts in real time. Press the **On Screen
Display** key or button (the backtick/tilde key by default on a US ANSI QWERTY
keyboard) to hide the menu to make it easier to test without changing settings.
Press the same key or button to show the menu again.
Each emulated input has four settings on the **Analog Controls** menu:
@ -387,7 +399,7 @@ The system and software selection menus
If you start MAME without specifying a system on the command line, the system
selection menu will be shown (assuming the
:ref:`ui option <mame-commandline-ui>` is set to **cabinet**). The system
selection menu is also shown if you select **Select New Machine** from the main
selection menu is also shown if you select **Select New System** from the main
menu during emulation. Selecting a system that uses software lists shows the
similar software selection menu.
@ -407,7 +419,7 @@ The system and software selection menus have the following parts:
* The list of systems or software in the centre. For the system selection menu,
there are configuration options below the list of systems. Clones are shown
with a different text colour (grey by default). You can right-click a system
name as a shortcut to show the machine configuration options for the system.
name as a shortcut to show the System Settings menu for the system.
Systems or software items are sorted by full name or description, keeping
clones immediately below their parents. This may appear confusing if your
@ -454,8 +466,8 @@ Navigation controls
In addition to the usual :ref:`menu navigation controls <ui-menus>`, the system
and software selection menus have additional configurable controls for
navigating the multi-pane layout, and providing alternatives to toolbar buttons
if you dont want to use a pointing device. The default additional controls (on
a US ANSI QWERTY keyboard), and the settings they correspond to, are:
if you dont want to use a pointing device. The default additional controls
(with a US ANSI QWERTY keyboard), and the settings they correspond to, are:
Tab (UI Focus Next)
Move focus to the next area. The order is system/software list,
@ -488,7 +500,7 @@ The simple system selection menu
--------------------------------
If you start MAME without specifying a system on the command line (or choose
**Select New Machine** from the main menu during emulation) with the
**Select New System** from the main menu during emulation) with the
:ref:`ui option <mame-commandline-ui>` set to **simple**, the simple system
selection menu will be shown. The simple system selection menu shows fifteen
randomly selected systems that have ROM sets present in your configured

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -194,13 +194,13 @@ function commonui.switch_polling_helper(starting_sequence)
return true
else
-- invalid sequence entered
machine:popmessage(_p('plugin-commonui', 'Invalid sequence entered'))
machine:popmessage(_p('plugin-commonui', 'Invalid combination entered'))
self.sequence = nil
return true
end
else
machine:popmessage(string.format(
_p('plugin-commonui', 'Enter sequence or press %s to cancel\n%s'),
_p('plugin-commonui', 'Enter combination or press %s to cancel\n%s'),
cancel_prompt,
input:seq_name(poller.sequence)))
return false

View File

@ -356,7 +356,7 @@ local function add_edit_items(items)
local binding = edit_current_macro.binding
local activation = binding and input:seq_name(binding) or _p('plugin-inputmacro', '[not set]')
table.insert(items, { _p('plugin-inputmacro', 'Activation sequence'), activation, edit_switch_poller and 'lr' or '' })
table.insert(items, { _p('plugin-inputmacro', 'Activation combination'), activation, edit_switch_poller and 'lr' or '' })
edit_items[#items] = { action = 'binding' }
local releaseaction = edit_current_macro.earlycancel and _p('plugin-inputmacro', 'Stop immediately') or _p('plugin-inputmacro', 'Complete macro')

View File

@ -125,8 +125,14 @@ files {
MAME_DIR .. "src/frontend/mame/ui/info_pty.h",
MAME_DIR .. "src/frontend/mame/ui/inifile.cpp",
MAME_DIR .. "src/frontend/mame/ui/inifile.h",
MAME_DIR .. "src/frontend/mame/ui/inputdevices.cpp",
MAME_DIR .. "src/frontend/mame/ui/inputdevices.h",
MAME_DIR .. "src/frontend/mame/ui/inputmap.cpp",
MAME_DIR .. "src/frontend/mame/ui/inputmap.h",
MAME_DIR .. "src/frontend/mame/ui/inputopts.cpp",
MAME_DIR .. "src/frontend/mame/ui/inputopts.h",
MAME_DIR .. "src/frontend/mame/ui/inputtoggle.cpp",
MAME_DIR .. "src/frontend/mame/ui/inputtoggle.h",
MAME_DIR .. "src/frontend/mame/ui/keyboard.cpp",
MAME_DIR .. "src/frontend/mame/ui/keyboard.h",
MAME_DIR .. "src/frontend/mame/ui/mainmenu.cpp",

View File

@ -865,14 +865,15 @@ float render_font::string_width(float height, float aspect, std::string_view str
char32_t schar;
// loop over characters
while (!string.empty())
int scharcount;
while ((scharcount = uchar_from_utf8(&schar, string)) != 0)
{
int scharcount = uchar_from_utf8(&schar, string);
if (0 > scharcount)
schar = 0xfffd;
string.remove_prefix((0 > scharcount) ? 1 : scharcount);
totwidth += get_char(schar).width;
string.remove_prefix(scharcount);
}
// scale the final result based on height
return float(totwidth) * m_scale * height * aspect;
}

View File

@ -57,6 +57,7 @@ menu_analog::menu_analog(mame_ui_manager &mui, render_container &container)
, m_hide_menu(false)
{
set_process_flags(PROCESS_LR_REPEAT);
set_heading(_("Analog Input Adjustments"));
}
@ -192,6 +193,8 @@ void menu_analog::custom_render(void *selectedref, float top, float bottom, floa
void menu_analog::menu_activated()
{
// scripts could have changed something in the mean time
m_item_data.clear();
m_field_data.clear();
reset(reset_options::REMEMBER_POSITION);
}
@ -394,6 +397,10 @@ void menu_analog::populate(float &customtop, float &custombottom)
&data);
}
// display a message if there are toggle inputs enabled
if (!prev_owner)
item_append(_("[no analog inputs are enabled]"), FLAG_DISABLE, nullptr);
item_append(menu_item_type::SEPARATOR);
// space for live display

View File

@ -56,6 +56,8 @@ menu_audit::menu_audit(mame_ui_manager &mui, render_container &container)
, m_phase(phase::CONFIRMATION)
, m_fast(true)
{
set_heading(_("Audit Media"));
std::string filename(emulator_info::get_configname());
filename += "_avail.ini";
m_prompt = util::string_format(_("Results will be saved to %1$s"), filename);
@ -96,7 +98,7 @@ void menu_audit::custom_render(void *selectedref, float top, float bottom, float
std::size_t const total(m_fast ? m_unavailable : m_availablesorted.size());
std::ostringstream text;
util::stream_format(text,
_("Auditing media for machine %2$u of %3$u...\n%1$s"),
_("Auditing media for system %2$u of %3$u...\n%1$s"),
system ? std::string_view(system->description) : std::string_view(),
(std::min)(audited + 1, total),
total);
@ -134,8 +136,8 @@ bool menu_audit::custom_ui_cancel()
void menu_audit::populate(float &customtop, float &custombottom)
{
if (m_unavailable && (m_availablesorted.size() != m_unavailable))
item_append(util::string_format(_("Audit media for %1$u machines marked unavailable"), m_unavailable), 0, ITEMREF_START_FAST);
item_append(util::string_format(_("Audit media for all %1$u machines"), m_availablesorted.size()), 0, ITEMREF_START_FULL);
item_append(util::string_format(_("Audit media for %1$u systems marked unavailable"), m_unavailable), 0, ITEMREF_START_FAST);
item_append(util::string_format(_("Audit media for all %1$u systems"), m_availablesorted.size()), 0, ITEMREF_START_FULL);
item_append(menu_item_type::SEPARATOR, 0);
custombottom = (ui().get_line_height() * 1.0f) + (ui().box_tb_border() * 3.0f);
}

View File

@ -37,6 +37,7 @@ namespace ui {
menu_barcode_reader::menu_barcode_reader(mame_ui_manager &mui, render_container &container, barcode_reader_device *device)
: menu_device_control<barcode_reader_device>(mui, container, device)
{
set_heading(_("Barcode Reader"));
set_process_flags(PROCESS_LR_REPEAT);
}
@ -61,7 +62,7 @@ void menu_barcode_reader::populate(float &customtop, float &custombottom)
const char *new_barcode;
// selected device
item_append(current_display_name(), current_display_flags(), ITEMREF_SELECT_READER);
item_append(std::string(current_display_name()), std::string(current_device()->tag() + 1), current_display_flags(), ITEMREF_SELECT_READER);
// append the "New Barcode" item
if (get_selection_ref() == ITEMREF_NEW_BARCODE)
@ -79,8 +80,6 @@ void menu_barcode_reader::populate(float &customtop, float &custombottom)
// finish up the menu
item_append(_("Enter Code"), 0, ITEMREF_ENTER_BARCODE);
item_append(menu_item_type::SEPARATOR);
customtop = ui().get_line_height() + 3.0f * ui().box_tb_border();
}
}

View File

@ -167,7 +167,7 @@ void menu_confswitch::populate(float &customtop, float &custombottom)
}
item_append(menu_item_type::SEPARATOR);
item_append(_("Reset Machine"), 0, (void *)1);
item_append(_("Reset System"), 0, (void *)1);
}
@ -311,6 +311,7 @@ menu_settings_dip_switches::menu_settings_dip_switches(mame_ui_manager &mui, ren
, m_first_nub(0.0f)
, m_clickable_height(0.0f)
{
set_heading(_("DIP Switches"));
}
@ -504,11 +505,11 @@ void menu_settings_dip_switches::populate(float &customtop, float &custombottom)
menu_settings_machine_config::menu_settings_machine_config(mame_ui_manager &mui, render_container &container) : menu_confswitch(mui, container, IPT_CONFIG)
{
set_heading(_("Machine Configuration"));
}
menu_settings_machine_config::~menu_settings_machine_config()
{
}
} // namespace ui

View File

@ -79,6 +79,8 @@ menu_custom_ui::menu_custom_ui(mame_ui_manager &mui, render_container &container
, m_currsysnames(0)
{
set_process_flags(PROCESS_LR_REPEAT);
set_heading(_("Customize UI"));
find_languages();
find_sysnames();
}
@ -137,7 +139,7 @@ void menu_custom_ui::handle(event const *ev)
{
// copying list of language names - expensive
menu::stack_push<menu_selector>(
ui(), container(), std::vector<std::string>(m_languages), m_currlang,
ui(), container(), _("UI Language"), std::vector<std::string>(m_languages), m_currlang,
[this, item = ev->item] (int selection)
{
m_currlang = selection;
@ -162,7 +164,7 @@ void menu_custom_ui::handle(event const *ev)
{
// copying list of file names - expensive
menu::stack_push<menu_selector>(
ui(), container(), std::vector<std::string>(m_sysnames), m_currsysnames,
ui(), container(), _("System Names"), std::vector<std::string>(m_sysnames), m_currsysnames,
[this, item = ev->item] (int selection)
{
m_currsysnames = selection;
@ -188,7 +190,7 @@ void menu_custom_ui::handle(event const *ev)
std::vector<std::string> s_sel(std::size(HIDE_STATUS));
std::transform(std::begin(HIDE_STATUS), std::end(HIDE_STATUS), s_sel.begin(), [](auto &s) { return _(s); });
menu::stack_push<menu_selector>(
ui(), container(), std::move(s_sel), ui_globals::panels_status,
ui(), container(), _("Show Side Panels"), std::move(s_sel), ui_globals::panels_status,
[item = ev->item] (int selection)
{
ui_globals::panels_status = selection;
@ -218,24 +220,9 @@ void menu_custom_ui::populate(float &customtop, float &custombottom)
item_append(_("System Names"), m_sysnames[m_currsysnames], arrow_flags, (void *)(uintptr_t)SYSNAMES_MENU);
arrow_flags = get_arrow_flags<uint16_t>(0, HIDE_BOTH, ui_globals::panels_status);
item_append(_("Show side panels"), _(HIDE_STATUS[ui_globals::panels_status]), arrow_flags, (void *)(uintptr_t)HIDE_MENU);
item_append(_("Show Side Panels"), _(HIDE_STATUS[ui_globals::panels_status]), arrow_flags, (void *)(uintptr_t)HIDE_MENU);
item_append(menu_item_type::SEPARATOR);
customtop = ui().get_line_height() + 3.0f * ui().box_tb_border();
}
//-------------------------------------------------
// perform our special rendering
//-------------------------------------------------
void menu_custom_ui::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{
char const *const text[] = { _("UI Customization Settings") };
draw_text_box(
std::begin(text), std::end(text),
origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(),
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false,
ui().colors().text_color(), UI_GREEN_COLOR, 1.0f);
}
//-------------------------------------------------
@ -344,6 +331,7 @@ menu_font_ui::menu_font_ui(mame_ui_manager &mui, render_container &container, st
, m_actual(0U)
{
set_process_flags(PROCESS_LR_REPEAT);
set_heading(_("UI Fonts"));
std::string name(mui.machine().options().ui_font());
list();
@ -467,7 +455,7 @@ void menu_font_ui::handle(event const *ev)
for (auto const &font : m_fonts)
display_names.emplace_back(font.second);
menu::stack_push<menu_selector>(
ui(), container(), std::move(display_names), m_actual,
ui(), container(), _("UI Font"), std::move(display_names), m_actual,
[this] (int selection)
{
m_changed = true;
@ -527,7 +515,7 @@ void menu_font_ui::populate(float &customtop, float &custombottom)
item_append(menu_item_type::SEPARATOR);
custombottom = customtop = ui().get_line_height() + 3.0f * ui().box_tb_border();
custombottom = ui().get_line_height() + 3.0f * ui().box_tb_border();
}
//-------------------------------------------------
@ -536,14 +524,6 @@ void menu_font_ui::populate(float &customtop, float &custombottom)
void menu_font_ui::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{
// top text
char const *const toptext[] = { _("UI Fonts Settings") };
draw_text_box(
std::begin(toptext), std::end(toptext),
origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(),
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false,
ui().colors().text_color(), UI_GREEN_COLOR, 1.0f);
if (uintptr_t(selectedref) == INFOS_SIZE)
{
char const *const bottomtext[] = { _("Sample text - Lorem ipsum dolor sit amet, consectetur adipiscing elit.") };
@ -562,6 +542,8 @@ void menu_font_ui::custom_render(void *selectedref, float top, float bottom, flo
menu_colors_ui::menu_colors_ui(mame_ui_manager &mui, render_container &container) : menu(mui, container)
{
set_heading(_("UI Colors"));
SET_COLOR_UI(m_color_table, UI_BACKGROUND_COLOR);
SET_COLOR_UI(m_color_table, UI_BORDER_COLOR);
SET_COLOR_UI(m_color_table, UI_CLONE_COLOR);
@ -644,7 +626,7 @@ void menu_colors_ui::populate(float &customtop, float &custombottom)
item_append(_("Restore default colors"), 0, (void *)(uintptr_t)MUI_RESTORE);
custombottom = customtop = ui().get_line_height() + 3.0f * ui().box_tb_border();
custombottom = ui().get_line_height() + 3.0f * ui().box_tb_border();
}
//-------------------------------------------------
@ -653,15 +635,6 @@ void menu_colors_ui::populate(float &customtop, float &custombottom)
void menu_colors_ui::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{
// top text
char const *const toptext[] = { _("UI Color Settings") };
draw_text_box(
std::begin(toptext), std::end(toptext),
origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(),
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false,
ui().colors().text_color(), UI_GREEN_COLOR, 1.0f);
// bottom text
// get the text for 'UI Select'
std::string const bottomtext[] = { util::string_format(_("Double-click or press %1$s to change color"), ui().get_general_input_setting(IPT_UI_SELECT)) };
draw_text_box(
@ -810,9 +783,9 @@ menu_rgb_ui::menu_rgb_ui(mame_ui_manager &mui, render_container &container, rgb_
, m_search()
, m_key_active(false)
, m_lock_ref(0)
, m_title(std::move(title))
{
set_process_flags(PROCESS_LR_REPEAT);
set_heading(std::move(title));
}
//-------------------------------------------------
@ -942,7 +915,7 @@ void menu_rgb_ui::populate(float &customtop, float &custombottom)
item_append(_("Choose from palette"), 0, (void *)(uintptr_t)PALETTE_CHOOSE);
item_append(menu_item_type::SEPARATOR);
custombottom = customtop = ui().get_line_height() + 3.0f * ui().box_tb_border();
custombottom = ui().get_line_height() + 3.0f * ui().box_tb_border();
}
//-------------------------------------------------
@ -951,42 +924,11 @@ void menu_rgb_ui::populate(float &customtop, float &custombottom)
void menu_rgb_ui::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{
float width, maxwidth = origx2 - origx1;
// top text
ui().draw_text_full(
container(),
m_title,
0.0f, 0.0f, 1.0f,
text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER,
mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), &width);
const float lr_border = ui().box_lr_border() * machine().render().ui_aspect(&container());
width += 2 * lr_border;
maxwidth = std::max(maxwidth, width);
// compute our bounds
float x1 = 0.5f - 0.5f * maxwidth;
float x2 = x1 + maxwidth;
float y1 = origy1 - top;
float y2 = origy1 - ui().box_tb_border();
// draw a box
ui().draw_outlined_box(container(), x1, y1, x2, y2, UI_GREEN_COLOR);
// take off the borders
x1 += lr_border;
x2 -= lr_border;
y1 += ui().box_tb_border();
// draw the text within it
ui().draw_text_full(
container(),
m_title,
x1, y1, x2 - x1,
text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER,
mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color());
float maxwidth = origx2 - origx1;
std::string sampletxt(_("Color preview:"));
float width;
ui().draw_text_full(
container(),
sampletxt,
@ -998,10 +940,10 @@ void menu_rgb_ui::custom_render(void *selectedref, float top, float bottom, floa
maxwidth = std::max(origx2 - origx1, width);
// compute our bounds
x1 = 0.5f - 0.5f * maxwidth;
x2 = x1 + maxwidth;
y1 = origy2 + ui().box_tb_border();
y2 = origy2 + bottom;
float x1 = 0.5f - 0.5f * maxwidth;
float x2 = x1 + maxwidth;
float y1 = origy2 + ui().box_tb_border();
float y2 = origy2 + bottom;
// draw a box - force black to ensure the text is legible
ui().draw_outlined_box(container(), x1, y1, x2, y2, rgb_t::black());

View File

@ -30,7 +30,6 @@ public:
menu_custom_ui(mame_ui_manager &mui, render_container &container, std::function<void ()> &&handler);
protected:
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
virtual void menu_dismissed() override;
private:

View File

@ -29,8 +29,8 @@ namespace ui {
namespace {
static int ADDING = 1;
static int CHANGE = 2;
constexpr int ADDING = 1;
constexpr int CHANGE = 2;
struct folders_entry
{
@ -39,7 +39,7 @@ struct folders_entry
const int action;
};
static const folders_entry s_folders[] =
const folders_entry f_folders[] =
{
{ N_p("path-option", "ROMs"), OPTION_MEDIAPATH, ADDING },
{ N_p("path-option", "Software Media"), OPTION_SWPATH, CHANGE },
@ -74,167 +74,132 @@ static const folders_entry s_folders[] =
{ N_p("path-option", "Covers"), OPTION_COVER_PATH, ADDING }
};
} // anonymous namespace
/**************************************************
MENU DIRECTORY
MENU REMOVE FOLDER
**************************************************/
class menu_remove_folder : public menu
{
public:
menu_remove_folder(mame_ui_manager &mui, render_container &container, int ref);
private:
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle(event const *ev) override;
std::string m_searchpath;
int const m_ref;
std::vector<std::string> m_folders;
};
//-------------------------------------------------
// ctor / dtor
//-------------------------------------------------
menu_directory::menu_directory(mame_ui_manager &mui, render_container &container) : menu(mui, container)
menu_remove_folder::menu_remove_folder(mame_ui_manager &mui, render_container &container, int ref)
: menu(mui, container)
, m_ref(ref)
{
}
set_heading(util::string_format(_("Remove %1$s Folder"), _("path-option", f_folders[m_ref].name)));
menu_directory::~menu_directory()
{
ui().save_ui_options();
ui_globals::reset = true;
}
//-------------------------------------------------
// handle
//-------------------------------------------------
void menu_directory::handle(event const *ev)
{
// process the menu
if (ev && ev->itemref && ev->iptkey == IPT_UI_SELECT)
menu::stack_push<menu_display_actual>(ui(), container(), selected_index());
}
//-------------------------------------------------
// populate
//-------------------------------------------------
void menu_directory::populate(float &customtop, float &custombottom)
{
for (auto & elem : s_folders)
item_append(_("path-option", elem.name), 0, (void *)(uintptr_t)elem.action);
item_append(menu_item_type::SEPARATOR);
customtop = ui().get_line_height() + 3.0f * ui().box_tb_border();
}
//-------------------------------------------------
// perform our special rendering
//-------------------------------------------------
void menu_directory::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{
char const *const toptext[] = { _("Folders Setup") };
draw_text_box(
std::begin(toptext), std::end(toptext),
origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(),
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false,
ui().colors().text_color(), UI_GREEN_COLOR, 1.0f);
}
/**************************************************
MENU DISPLAY PATH
**************************************************/
//-------------------------------------------------
// ctor / dtor
//-------------------------------------------------
menu_display_actual::menu_display_actual(mame_ui_manager &mui, render_container &container, int ref)
: menu(mui, container), m_ref(ref)
{
}
menu_display_actual::~menu_display_actual()
{
}
//-------------------------------------------------
// handle
//-------------------------------------------------
void menu_display_actual::handle(event const *ev)
{
// process the menu
if (ev && ev->itemref && ev->iptkey == IPT_UI_SELECT)
switch ((uintptr_t)ev->itemref)
{
case REMOVE:
menu::stack_push<menu_remove_folder>(ui(), container(), m_ref);
break;
case ADD_CHANGE:
menu::stack_push<menu_add_change_folder>(ui(), container(), m_ref);
break;
}
}
//-------------------------------------------------
// populate
//-------------------------------------------------
void menu_display_actual::populate(float &customtop, float &custombottom)
{
m_heading[0] = string_format(_("Current %1$s Folders"), _("path-option", s_folders[m_ref].name));
if (ui().options().exists(s_folders[m_ref].option))
m_searchpath.assign(ui().options().value(s_folders[m_ref].option));
if (mui.options().exists(f_folders[m_ref].option))
m_searchpath.assign(mui.options().value(f_folders[m_ref].option));
else
m_searchpath.assign(machine().options().value(s_folders[m_ref].option));
m_searchpath.assign(mui.machine().options().value(f_folders[m_ref].option));
path_iterator path(m_searchpath);
std::string curpath;
m_folders.clear();
while (path.next(curpath))
m_folders.push_back(curpath);
}
item_append((s_folders[m_ref].action == CHANGE) ? _("Change Folder") : _("Add Folder"), 0, (void *)ADD_CHANGE);
//-------------------------------------------------
// handle
//-------------------------------------------------
if (m_folders.size() > 1)
item_append(_("Remove Folder"), 0, (void *)REMOVE);
void menu_remove_folder::handle(event const *ev)
{
// process the menu
if (ev && ev->itemref && ev->iptkey == IPT_UI_SELECT)
{
std::string tmppath, error_string;
m_folders.erase(m_folders.begin() + selected_index());
for (int x = 0; x < m_folders.size(); ++x)
{
tmppath.append(m_folders[x]);
if (x < m_folders.size() - 1)
tmppath.append(";");
}
if (ui().options().exists(f_folders[m_ref].option))
ui().options().set_value(f_folders[m_ref].option, tmppath, OPTION_PRIORITY_CMDLINE);
else if (machine().options().value(f_folders[m_ref].option) != tmppath)
{
machine().options().set_value(f_folders[m_ref].option, tmppath, OPTION_PRIORITY_CMDLINE);
}
reset_parent(reset_options::REMEMBER_REF);
stack_pop();
}
}
//-------------------------------------------------
// populate menu
//-------------------------------------------------
void menu_remove_folder::populate(float &customtop, float &custombottom)
{
int folders_count = 0;
for (auto & elem : m_folders)
item_append(elem, 0, (void *)(uintptr_t)++folders_count);
item_append(menu_item_type::SEPARATOR);
customtop = (m_folders.size() + 1) * ui().get_line_height() + 6.0f * ui().box_tb_border();
}
//-------------------------------------------------
// perform our special rendering
//-------------------------------------------------
void menu_display_actual::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{
float const lineheight(ui().get_line_height());
float const maxwidth(draw_text_box(
std::begin(m_folders), std::end(m_folders),
origx1, origx2, origy1 - (3.0f * ui().box_tb_border()) - (m_folders.size() * lineheight), origy1 - ui().box_tb_border(),
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false,
ui().colors().text_color(), ui().colors().background_color(), 1.0f));
draw_text_box(
std::begin(m_heading), std::end(m_heading),
0.5f * (1.0f - maxwidth), 0.5f * (1.0f + maxwidth), origy1 - top, origy1 - top + lineheight + (2.0f * ui().box_tb_border()),
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false,
ui().colors().text_color(), UI_GREEN_COLOR, 1.0f);
}
/**************************************************
MENU ADD FOLDER
MENU ADD FOLDER
**************************************************/
//-------------------------------------------------
// ctor / dtor
//-------------------------------------------------
menu_add_change_folder::menu_add_change_folder(mame_ui_manager &mui, render_container &container, int ref) : menu(mui, container)
class menu_add_change_folder : public menu
{
m_ref = ref;
m_change = (s_folders[ref].action == CHANGE);
m_search.clear();
public:
menu_add_change_folder(mame_ui_manager &mui, render_container &container, int ref);
protected:
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
virtual bool custom_ui_cancel() override { return !m_search.empty(); }
private:
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle(event const *ev) override;
int const m_ref;
std::string m_current_path;
std::string m_search;
bool const m_change;
std::vector<std::string> m_folders;
};
//-------------------------------------------------
// ctor
//-------------------------------------------------
menu_add_change_folder::menu_add_change_folder(mame_ui_manager &mui, render_container &container, int ref)
: menu(mui, container)
, m_ref(ref)
, m_change(f_folders[ref].action == CHANGE)
{
// configure the starting path
osd_get_full_path(m_current_path, ".");
std::string searchpath;
if (mui.options().exists(s_folders[m_ref].option))
searchpath = mui.options().value(s_folders[m_ref].option);
if (mui.options().exists(f_folders[m_ref].option))
searchpath = mui.options().value(f_folders[m_ref].option);
else
searchpath = mui.machine().options().value(s_folders[m_ref].option);
searchpath = mui.machine().options().value(f_folders[m_ref].option);
path_iterator path(searchpath);
std::string curpath;
@ -242,10 +207,6 @@ menu_add_change_folder::menu_add_change_folder(mame_ui_manager &mui, render_cont
m_folders.push_back(curpath);
}
menu_add_change_folder::~menu_add_change_folder()
{
}
//-------------------------------------------------
// handle
//-------------------------------------------------
@ -290,10 +251,10 @@ void menu_add_change_folder::handle(event const *ev)
std::string error_string;
if (m_change)
{
if (ui().options().exists(s_folders[m_ref].option))
ui().options().set_value(s_folders[m_ref].option, m_current_path, OPTION_PRIORITY_CMDLINE);
else if (machine().options().value(s_folders[m_ref].option) != m_current_path)
machine().options().set_value(s_folders[m_ref].option, m_current_path, OPTION_PRIORITY_CMDLINE);
if (ui().options().exists(f_folders[m_ref].option))
ui().options().set_value(f_folders[m_ref].option, m_current_path, OPTION_PRIORITY_CMDLINE);
else if (machine().options().value(f_folders[m_ref].option) != m_current_path)
machine().options().set_value(f_folders[m_ref].option, m_current_path, OPTION_PRIORITY_CMDLINE);
}
else
{
@ -306,10 +267,10 @@ void menu_add_change_folder::handle(event const *ev)
tmppath.append(";");
}
if (ui().options().exists(s_folders[m_ref].option))
ui().options().set_value(s_folders[m_ref].option, tmppath, OPTION_PRIORITY_CMDLINE);
else if (machine().options().value(s_folders[m_ref].option) != tmppath)
machine().options().set_value(s_folders[m_ref].option, tmppath, OPTION_PRIORITY_CMDLINE);
if (ui().options().exists(f_folders[m_ref].option))
ui().options().set_value(f_folders[m_ref].option, tmppath, OPTION_PRIORITY_CMDLINE);
else if (machine().options().value(f_folders[m_ref].option) != tmppath)
machine().options().set_value(f_folders[m_ref].option, tmppath, OPTION_PRIORITY_CMDLINE);
}
reset_parent(reset_options::SELECT_FIRST);
@ -429,7 +390,7 @@ void menu_add_change_folder::custom_render(void *selectedref, float top, float b
std::string const toptext[] = {
util::string_format(
m_change ? _("Change %1$s Folder - Search: %2$s_") : _("Add %1$s Folder - Search: %2$s_"),
_("path-option", s_folders[m_ref].name),
_("path-option", f_folders[m_ref].name),
m_search),
m_current_path };
draw_text_box(
@ -447,87 +408,150 @@ void menu_add_change_folder::custom_render(void *selectedref, float top, float b
ui().colors().text_color(), ui().colors().background_color(), 1.0f);
}
/**************************************************
MENU REMOVE FOLDER
MENU DISPLAY PATH
**************************************************/
//-------------------------------------------------
// ctor / dtor
//-------------------------------------------------
menu_remove_folder::menu_remove_folder(mame_ui_manager &mui, render_container &container, int ref) : menu(mui, container)
class menu_display_actual : public menu
{
m_ref = ref;
if (mui.options().exists(s_folders[m_ref].option))
m_searchpath.assign(mui.options().value(s_folders[m_ref].option));
else
m_searchpath.assign(mui.machine().options().value(s_folders[m_ref].option));
public:
menu_display_actual(mame_ui_manager &mui, render_container &container, int selectedref)
: menu(mui, container)
, m_heading{ util::string_format((f_folders[selectedref].action == ADDING) ? _("%1$s Folders") : _("%1$s Folder"), _("path-option", f_folders[selectedref].name)) }
, m_ref(selectedref)
{
}
path_iterator path(m_searchpath);
std::string curpath;
while (path.next(curpath))
m_folders.push_back(curpath);
}
protected:
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
menu_remove_folder::~menu_remove_folder()
{
}
private:
enum
{
ADD_CHANGE = 1,
REMOVE,
};
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle(event const *ev) override;
std::string const m_heading[1];
std::string m_searchpath;
std::vector<std::string> m_folders;
int const m_ref;
};
//-------------------------------------------------
// handle
//-------------------------------------------------
void menu_remove_folder::handle(event const *ev)
void menu_display_actual::handle(event const *ev)
{
// process the menu
if (ev && ev->itemref && ev->iptkey == IPT_UI_SELECT)
{
std::string tmppath, error_string;
m_folders.erase(m_folders.begin() + selected_index());
for (int x = 0; x < m_folders.size(); ++x)
switch ((uintptr_t)ev->itemref)
{
tmppath.append(m_folders[x]);
if (x < m_folders.size() - 1)
tmppath.append(";");
}
case REMOVE:
menu::stack_push<menu_remove_folder>(ui(), container(), m_ref);
break;
if (ui().options().exists(s_folders[m_ref].option))
ui().options().set_value(s_folders[m_ref].option, tmppath, OPTION_PRIORITY_CMDLINE);
else if (machine().options().value(s_folders[m_ref].option) != tmppath)
{
machine().options().set_value(s_folders[m_ref].option, tmppath, OPTION_PRIORITY_CMDLINE);
case ADD_CHANGE:
menu::stack_push<menu_add_change_folder>(ui(), container(), m_ref);
break;
}
reset_parent(reset_options::REMEMBER_REF);
stack_pop();
}
}
//-------------------------------------------------
// populate menu
// populate
//-------------------------------------------------
void menu_remove_folder::populate(float &customtop, float &custombottom)
void menu_display_actual::populate(float &customtop, float &custombottom)
{
int folders_count = 0;
for (auto & elem : m_folders)
item_append(elem, 0, (void *)(uintptr_t)++folders_count);
if (ui().options().exists(f_folders[m_ref].option))
m_searchpath.assign(ui().options().value(f_folders[m_ref].option));
else
m_searchpath.assign(machine().options().value(f_folders[m_ref].option));
path_iterator path(m_searchpath);
std::string curpath;
m_folders.clear();
while (path.next(curpath))
m_folders.push_back(curpath);
item_append((f_folders[m_ref].action == CHANGE) ? _("Change Folder") : _("Add Folder"), 0, (void *)ADD_CHANGE);
if (m_folders.size() > 1)
item_append(_("Remove Folder"), 0, (void *)REMOVE);
item_append(menu_item_type::SEPARATOR);
customtop = ui().get_line_height() + 3.0f * ui().box_tb_border();
customtop = (m_folders.size() + 1) * ui().get_line_height() + 6.0f * ui().box_tb_border();
}
//-------------------------------------------------
// perform our special rendering
//-------------------------------------------------
void menu_remove_folder::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
void menu_display_actual::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{
std::string const toptext[] = {string_format(_("Remove %1$s Folder"), _("path-option", s_folders[m_ref].name)) };
float const lineheight(ui().get_line_height());
float const maxwidth(draw_text_box(
std::begin(m_folders), std::end(m_folders),
origx1, origx2, origy1 - (3.0f * ui().box_tb_border()) - (m_folders.size() * lineheight), origy1 - ui().box_tb_border(),
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false,
ui().colors().text_color(), ui().colors().background_color(), 1.0f));
draw_text_box(
std::begin(toptext), std::end(toptext),
origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(),
std::begin(m_heading), std::end(m_heading),
0.5f * (1.0f - maxwidth), 0.5f * (1.0f + maxwidth), origy1 - top, origy1 - top + lineheight + (2.0f * ui().box_tb_border()),
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false,
ui().colors().text_color(), UI_GREEN_COLOR, 1.0f);
}
} // anonymous namespace
/**************************************************
MENU DIRECTORY
**************************************************/
//-------------------------------------------------
// ctor / dtor
//-------------------------------------------------
menu_directory::menu_directory(mame_ui_manager &mui, render_container &container) : menu(mui, container)
{
set_heading(_("Configure Folders"));
}
menu_directory::~menu_directory()
{
ui().save_ui_options();
ui_globals::reset = true;
}
//-------------------------------------------------
// handle
//-------------------------------------------------
void menu_directory::handle(event const *ev)
{
// process the menu
if (ev && ev->itemref && ev->iptkey == IPT_UI_SELECT)
menu::stack_push<menu_display_actual>(ui(), container(), selected_index());
}
//-------------------------------------------------
// populate
//-------------------------------------------------
void menu_directory::populate(float &customtop, float &custombottom)
{
for (auto & elem : f_folders)
item_append(_("path-option", elem.name), 0, (void *)(uintptr_t)elem.action);
item_append(menu_item_type::SEPARATOR);
}
} // namespace ui

View File

@ -8,11 +8,11 @@
***************************************************************************/
#pragma once
#ifndef MAME_FRONTEND_UI_DIRMENU_H
#define MAME_FRONTEND_UI_DIRMENU_H
#pragma once
#include "ui/menu.h"
#include <string>
@ -30,90 +30,11 @@ public:
menu_directory(mame_ui_manager &mui, render_container &container);
virtual ~menu_directory() override;
protected:
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
private:
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle(event const *ev) override;
};
//-------------------------------------------------
// class directory specific menu
//-------------------------------------------------
class menu_display_actual : public menu
{
public:
menu_display_actual(mame_ui_manager &mui, render_container &container, int selectedref);
virtual ~menu_display_actual() override;
protected:
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
private:
enum
{
ADD_CHANGE = 1,
REMOVE,
};
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle(event const *ev) override;
std::string m_heading[1], m_searchpath;
std::vector<std::string> m_folders;
int m_ref;
};
//-------------------------------------------------
// class remove folder menu
//-------------------------------------------------
class menu_remove_folder : public menu
{
public:
menu_remove_folder(mame_ui_manager &mui, render_container &container, int ref);
virtual ~menu_remove_folder() override;
protected:
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
private:
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle(event const *ev) override;
std::string m_searchpath;
int m_ref;
std::vector<std::string> m_folders;
};
//-------------------------------------------------
// class add / change folder menu
//-------------------------------------------------
class menu_add_change_folder : public menu
{
public:
menu_add_change_folder(mame_ui_manager &mui, render_container &container, int ref);
virtual ~menu_add_change_folder() override;
protected:
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
virtual bool custom_ui_cancel() override { return !m_search.empty(); }
private:
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle(event const *ev) override;
int m_ref;
std::string m_current_path;
std::string m_search;
bool m_change;
std::vector<std::string> m_folders;
};
} // namespace ui
#endif // MAME_FRONTEND_UI_DIRMENU_H

View File

@ -40,6 +40,7 @@ menu_file_manager::menu_file_manager(mame_ui_manager &mui, render_container &con
{
// The warning string is used when accessing from the force_file_manager call, i.e.
// when the file manager is loaded top front in the case of mandatory image devices
set_heading(_("File Manager"));
}
@ -150,7 +151,7 @@ void menu_file_manager::populate(float &customtop, float &custombottom)
item_append(menu_item_type::SEPARATOR);
if (m_warnings.empty() || !missing_mandatory)
item_append(m_warnings.empty() ? _("Reset Machine") : _("Start Machine"), 0, (void *)1);
item_append(m_warnings.empty() ? _("Reset System") : _("Start System"), 0, (void *)1);
custombottom = ui().get_line_height() + 3.0f * ui().box_tb_border();
}

View File

@ -64,7 +64,7 @@ void get_general_warnings(std::ostream &buf, running_machine &machine, machine_f
if (machine.rom_load().warnings() > 0)
{
bad_roms = true;
buf << _("One or more ROMs/CHDs for this machine are incorrect. The machine may not run correctly.\n");
buf << _("One or more ROMs/disk images for this system are incorrect. The system may not run correctly.\n");
}
if (!machine.rom_load().software_load_warnings_message().empty())
{
@ -77,12 +77,12 @@ void get_general_warnings(std::ostream &buf, running_machine &machine, machine_f
{
if (bad_roms)
buf << '\n';
buf << _("There are known problems with this machine\n\n");
buf << _("There are known problems with this system\n\n");
}
// add a warning if any ROMs are flagged BAD_DUMP/NO_DUMP
if (machine.rom_load().knownbad() > 0)
buf << _("One or more ROMs/CHDs for this machine have not been correctly dumped.\n");
buf << _("One or more ROMs/disk images for this system have not been correctly dumped.\n");
}
void get_device_warnings(std::ostream &buf, device_t::feature_type unemulated, device_t::feature_type imperfect)
@ -129,17 +129,17 @@ void get_system_warnings(std::ostream &buf, running_machine &machine, machine_fl
if (flags & ::machine_flags::NO_COCKTAIL)
buf << _("Screen flipping in cocktail mode is not supported.\n");
if (flags & ::machine_flags::REQUIRES_ARTWORK)
buf << _("This machine requires external artwork files.\n");
buf << _("This system requires external artwork files.\n");
if (flags & ::machine_flags::IS_INCOMPLETE)
buf << _("This machine was never completed. It may exhibit strange behavior or missing elements that are not bugs in the emulation.\n");
buf << _("This system was never completed. It may exhibit strange behavior or missing elements that are not bugs in the emulation.\n");
if (flags & ::machine_flags::NO_SOUND_HW)
buf << _("This machine has no sound hardware, MAME will produce no sounds, this is expected behaviour.\n");
buf << _("This system has no sound hardware, MAME will produce no sounds, this is expected behaviour.\n");
// these are more severe warnings
if (flags & ::machine_flags::NOT_WORKING)
buf << _("\nTHIS MACHINE DOESN'T WORK. The emulation for this machine is not yet complete. There is nothing you can do to fix this problem except wait for the developers to improve the emulation.\n");
buf << _("\nTHIS SYSTEM DOESN'T WORK. The emulation for this system is not yet complete. There is nothing you can do to fix this problem except wait for the developers to improve the emulation.\n");
if (flags & ::machine_flags::MECHANICAL)
buf << _("\nElements of this machine cannot be emulated as they require physical interaction or consist of mechanical devices. It is not possible to fully experience this machine.\n");
buf << _("\nElements of this system cannot be emulated as they require physical interaction or consist of mechanical devices. It is not possible to fully experience this system.\n");
if ((flags & MACHINE_ERRORS) || ((machine.system().type.unemulated_features() | machine.system().type.imperfect_features()) & device_t::feature::PROTECTION))
{
@ -161,7 +161,7 @@ void get_system_warnings(std::ostream &buf, running_machine &machine, machine_fl
{
// this one works, add a header and display the name of the clone
if (!foundworking)
util::stream_format(buf, _("\n\nThere are working clones of this machine: %s"), driver.name);
util::stream_format(buf, _("\n\nThere are working clones of this system: %s"), driver.name);
else
util::stream_format(buf, _(", %s"), driver.name);
foundworking = true;
@ -615,6 +615,7 @@ void menu_warn_info::handle(event const *ev)
menu_image_info::menu_image_info(mame_ui_manager &mui, render_container &container) : menu(mui, container)
{
set_heading(_("Media Image Information"));
}
menu_image_info::~menu_image_info()
@ -628,10 +629,6 @@ void menu_image_info::menu_activated()
void menu_image_info::populate(float &customtop, float &custombottom)
{
ui_system_info const &system(system_list::instance().systems()[driver_list::find(machine().system().name)]);
item_append(system.description, FLAG_DISABLE, nullptr);
item_append(std::string(), FLAG_DISABLE, nullptr);
for (device_image_interface &image : image_interface_enumerator(machine().root_device()))
image_info(&image);
}
@ -680,7 +677,7 @@ void menu_image_info::image_info(device_image_interface *image)
{
item_append(image->brief_instance_name(), _("[empty]"), 0, nullptr);
}
item_append(std::string(), FLAG_DISABLE, nullptr);
item_append(menu_item_type::SEPARATOR);
}
} // namespace ui

View File

@ -19,6 +19,7 @@ namespace ui {
menu_pty_info::menu_pty_info(mame_ui_manager &mui, render_container &container) :
menu(mui, container)
{
set_heading(_("Pseudo Terminals"));
}
menu_pty_info::~menu_pty_info()
@ -27,9 +28,6 @@ menu_pty_info::~menu_pty_info()
void menu_pty_info::populate(float &customtop, float &custombottom)
{
item_append(_("Pseudo terminals"), FLAG_DISABLE, nullptr);
item_append(std::string(), FLAG_DISABLE, nullptr);
for (device_pty_interface &pty : pty_interface_enumerator(machine().root_device()))
{
const char *port_name = pty.device().owner()->tag() + 1;

View File

@ -0,0 +1,258 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/***************************************************************************
ui/inputdevices.cpp
Input devices menu.
***************************************************************************/
#include "emu.h"
#include "inputdevices.h"
#include "inputdev.h"
namespace ui {
namespace {
class menu_input_device : public menu
{
public:
menu_input_device(mame_ui_manager &mui, render_container &container, input_device &device)
: menu(mui, container)
, m_device(device)
{
set_heading(
util::string_format(_("menu-inputdev", "%1$s (%2$s %3$d)"),
device.name(),
machine().input().device_class(device.devclass()).name(),
device.devindex() + 1));
}
protected:
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override
{
if (selectedref)
{
input_device_item &input = *reinterpret_cast<input_device_item *>(selectedref);
switch (input.itemclass())
{
case ITEM_CLASS_ABSOLUTE:
case ITEM_CLASS_RELATIVE:
{
// draw the outer box
ui().draw_outlined_box(container(), x, y2 + ui().box_tb_border(), x2, y2 + bottom, ui().colors().background_color());
// draw the indicator
rgb_t const fgcolor(ui().colors().text_color());
float const border = ui().box_lr_border() * machine().render().ui_aspect(&container());
float const lineheight = ui().get_line_height();
float const indleft = x + border;
float const indright = x2 - border;
float const indtop = y2 + (ui().box_tb_border() * 2.0F) + (lineheight * 0.2F);
float const indbottom = y2 + (ui().box_tb_border() * 2.0F) + (lineheight * 0.8F);
float const indcentre = (x + x2) * 0.5F;
s32 const value = (input.itemclass() == ITEM_CLASS_ABSOLUTE) ? input.read_as_absolute(ITEM_MODIFIER_NONE) : input.read_as_relative(ITEM_MODIFIER_NONE);
if (0 < value)
{
float const fillright = indcentre + (float(value) / float(INPUT_ABSOLUTE_MAX) * (indright - indcentre));
container().add_rect(indcentre, indtop, (std::min)(fillright, indright), indbottom, fgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
}
else if (0 > value)
{
float const fillleft = indcentre - (float(value) / float(INPUT_ABSOLUTE_MIN) * (indcentre - indleft));
container().add_rect((std::max)(fillleft, indleft), indtop, indcentre, indbottom, fgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
}
container().add_line(indleft, indtop, indright, indtop, UI_LINE_WIDTH, fgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
container().add_line(indright, indtop, indright, indbottom, UI_LINE_WIDTH, fgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
container().add_line(indright, indbottom, indleft, indbottom, UI_LINE_WIDTH, fgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
container().add_line(indleft, indbottom, indleft, indtop, UI_LINE_WIDTH, fgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
container().add_line(indcentre, indtop, indcentre, indbottom, UI_LINE_WIDTH, fgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
}
break;
default:
break;
}
}
}
private:
virtual void populate(float &customtop, float &custombottom) override
{
bool haveanalog = false;
for (input_item_id itemid = ITEM_ID_FIRST_VALID; m_device.maxitem() >= itemid; ++itemid)
{
input_device_item *const input = m_device.item(itemid);
if (input)
{
switch (input->itemclass())
{
case ITEM_CLASS_ABSOLUTE:
case ITEM_CLASS_RELATIVE:
haveanalog = true;
break;
default:
break;
}
item_append(input->name(), format_value(*input), 0U, input);
}
}
item_append(menu_item_type::SEPARATOR);
if (haveanalog)
custombottom = ui().get_line_height() + (ui().box_tb_border() * 3.0F);
}
virtual void handle(event const *ev) override
{
for (int i = 0; item_count() > i; ++i)
{
void *const ref(item(i).ref());
if (ref)
{
input_device_item &input = *reinterpret_cast<input_device_item *>(ref);
item(i).set_subtext(format_value(input));
}
}
}
static std::string format_value(input_device_item &input)
{
switch (input.itemclass())
{
default:
case ITEM_CLASS_SWITCH:
return util::string_format("%d", input.read_as_switch(ITEM_MODIFIER_NONE));
case ITEM_CLASS_ABSOLUTE:
return util::string_format("%d", input.read_as_absolute(ITEM_MODIFIER_NONE));
case ITEM_CLASS_RELATIVE:
return util::string_format("%d", input.read_as_relative(ITEM_MODIFIER_NONE));
}
}
input_device &m_device;
};
} // anonymous namespace
menu_input_devices::menu_input_devices(mame_ui_manager &mui, render_container &container)
: menu(mui, container)
{
set_heading(_("menu-inputdev", "Input Devices"));
}
menu_input_devices::~menu_input_devices()
{
}
void menu_input_devices::populate(float &customtop, float &custombottom)
{
// iterate input device classes and devices within each class
bool found = false;
for (input_device_class classno = DEVICE_CLASS_FIRST_VALID; DEVICE_CLASS_LAST_VALID >= classno; ++classno)
{
input_class &devclass = machine().input().device_class(classno);
if (devclass.enabled())
{
bool first = true;
for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum)
{
input_device *const device = devclass.device(devnum);
if (device)
{
// add a device class heading
found = true;
if (first)
{
first = false;
item_append(devclass.name(), FLAG_UI_HEADING | FLAG_DISABLE, nullptr);
}
// add the item for the device itself
item_append(util::string_format("%d", device->devindex() + 1), device->name(), 0U, device);
}
}
}
}
// highly unlikely - at least one keyboard or mouse will be enabled in almost all cases
if (!found)
item_append(_("menu-inputdev", "[no input devices are enabled]"), FLAG_DISABLE, nullptr);
item_append(menu_item_type::SEPARATOR);
}
void menu_input_devices::handle(event const *ev)
{
if (ev && ev->itemref)
{
input_device &dev = *reinterpret_cast<input_device *>(ev->itemref);
switch (ev->iptkey)
{
case IPT_UI_SELECT:
stack_push<menu_input_device>(ui(), container(), dev);
break;
case IPT_UI_PREV_GROUP:
{
auto group = dev.devclass();
bool found_break = false;
int target = 0;
for (auto i = selected_index(); 0 < i--; )
{
input_device *const candidate = reinterpret_cast<input_device *>(item(i).ref());
if (candidate)
{
if (candidate->devclass() == group)
{
target = i;
}
else if (!found_break)
{
group = candidate->devclass();
found_break = true;
target = i;
}
else
{
set_selected_index(target);
break;
}
}
if (!i && found_break)
{
set_selected_index(target);
break;
}
}
}
break;
case IPT_UI_NEXT_GROUP:
{
auto const group = dev.devclass();
for (auto i = selected_index(); item_count() > ++i; )
{
input_device *const candidate = reinterpret_cast<input_device *>(item(i).ref());
if (candidate && (candidate->devclass() != group))
{
set_selected_index(i);
break;
}
}
}
break;
}
}
}
} // namespace ui

View File

@ -0,0 +1,34 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/***************************************************************************
ui/inputdevices.h
Input devices menu.
***************************************************************************/
#ifndef MAME_FRONTEND_UI_INPUTDEVICES_H
#define MAME_FRONTEND_UI_INPUTDEVICES_H
#pragma once
#include "ui/menu.h"
namespace ui {
class menu_input_devices : public menu
{
public:
menu_input_devices(mame_ui_manager &mui, render_container &container);
virtual ~menu_input_devices();
private:
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle(event const *ev) override;
};
} // namespace ui
#endif // MAME_FRONTEND_UI_INPUTDEVICES_H

View File

@ -26,6 +26,7 @@ namespace ui {
menu_input_groups::menu_input_groups(mame_ui_manager &mui, render_container &container) : menu(mui, container)
{
set_heading(_("Input Assignments (general)"));
}
menu_input_groups::~menu_input_groups()
@ -49,7 +50,13 @@ void menu_input_groups::handle(event const *ev)
{
// process the menu
if (ev && (ev->iptkey == IPT_UI_SELECT))
menu::stack_push<menu_input_general>(ui(), container(), int(uintptr_t(ev->itemref) - 1));
{
menu::stack_push<menu_input_general>(
ui(),
container(),
int(uintptr_t(ev->itemref) - 1),
util::string_format(_("Input Assignments (%1$s)"), ev->item->text()));
}
}
@ -58,16 +65,23 @@ void menu_input_groups::handle(event const *ev)
input menu
-------------------------------------------------*/
menu_input_general::menu_input_general(mame_ui_manager &mui, render_container &container, int _group)
menu_input_general::menu_input_general(mame_ui_manager &mui, render_container &container, int _group, std::string &&heading)
: menu_input(mui, container)
, group(_group)
{
set_heading(std::move(heading));
}
menu_input_general::~menu_input_general()
{
}
void menu_input_general::menu_activated()
{
// scripts can change settings out from under us
reset(reset_options::REMEMBER_POSITION);
}
void menu_input_general::populate(float &customtop, float &custombottom)
{
if (data.empty())
@ -135,12 +149,21 @@ void menu_input_general::update_input(input_item_data &seqchangeditem)
menu_input_specific::menu_input_specific(mame_ui_manager &mui, render_container &container) : menu_input(mui, container)
{
set_heading(_("Input Assignments (this system)"));
}
menu_input_specific::~menu_input_specific()
{
}
void menu_input_specific::menu_activated()
{
// scripts can change settings out from under us
assert(!pollingitem);
data.clear();
reset(reset_options::REMEMBER_POSITION);
}
void menu_input_specific::populate(float &customtop, float &custombottom)
{
if (data.empty())
@ -228,7 +251,7 @@ void menu_input_specific::populate(float &customtop, float &custombottom)
if (!data.empty())
populate_sorted(customtop, custombottom);
else
item_append(_("This machine has no configurable inputs."), FLAG_DISABLE, nullptr);
item_append(_("[no assignable inputs are enabled]"), FLAG_DISABLE, nullptr);
item_append(menu_item_type::SEPARATOR);
}
@ -274,12 +297,6 @@ menu_input::~menu_input()
{
}
void menu_input::menu_activated()
{
// scripts can change settings out from under us
reset(reset_options::REMEMBER_POSITION);
}
/*-------------------------------------------------
toggle_none_default - toggle between "NONE"
@ -398,7 +415,7 @@ void menu_input::handle(event const *ev)
{
// entered invalid sequence - abandon change
invalidate = true;
errormsg = _("Invalid sequence entered");
errormsg = _("Invalid combination entered");
erroritem = item;
}
seq_poll.reset();

View File

@ -64,8 +64,6 @@ protected:
menu_input(mame_ui_manager &mui, render_container &container);
virtual void menu_activated() override;
void populate_sorted(float &customtop, float &custombottom);
void toggle_none_default(input_seq &selected_seq, input_seq &original_seq, const input_seq &selected_defseq);
@ -92,9 +90,12 @@ private:
class menu_input_general : public menu_input
{
public:
menu_input_general(mame_ui_manager &mui, render_container &container, int group);
menu_input_general(mame_ui_manager &mui, render_container &container, int group, std::string &&heading);
virtual ~menu_input_general() override;
protected:
virtual void menu_activated() override;
private:
virtual void populate(float &customtop, float &custombottom) override;
virtual void update_input(input_item_data &seqchangeditem) override;
@ -109,6 +110,9 @@ public:
menu_input_specific(mame_ui_manager &mui, render_container &container);
virtual ~menu_input_specific() override;
protected:
virtual void menu_activated() override;
private:
virtual void populate(float &customtop, float &custombottom) override;
virtual void update_input(input_item_data &seqchangeditem) override;

View File

@ -0,0 +1,141 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/***************************************************************************
ui/inputopts.cpp
Input options submenu.
***************************************************************************/
#include "emu.h"
#include "ui/inputopts.h"
#include "ui/analogipt.h"
#include "ui/inputdevices.h"
#include "ui/inputmap.h"
#include "ui/inputtoggle.h"
#include "ui/keyboard.h"
#include "natkeyboard.h"
namespace ui {
namespace {
enum : unsigned
{
INPUTMAP_GENERAL = 1,
INPUTMAP_MACHINE,
ANALOG,
KEYBOARD,
TOGGLES,
INPUTDEV
};
void scan_inputs(running_machine &machine, bool &inputmap, bool &analog, bool &toggle)
{
inputmap = analog = toggle = false;
for (auto &port : machine.ioport().ports())
{
for (ioport_field &field : port.second->fields())
{
if (field.enabled())
{
switch (field.type_class())
{
case INPUT_CLASS_CONTROLLER:
case INPUT_CLASS_MISC:
case INPUT_CLASS_KEYBOARD:
inputmap = true;
if (field.live().toggle)
toggle = true;
break;
default:
break;
}
if (field.is_analog())
analog = true;
if (inputmap && analog && toggle)
return;
}
}
}
}
} // anonymous namespace
menu_input_options::menu_input_options(mame_ui_manager &mui, render_container &container)
: menu(mui, container)
{
set_heading(_("menu-inputopts", "Input Settings"));
}
menu_input_options::~menu_input_options()
{
}
void menu_input_options::menu_activated()
{
reset(reset_options::REMEMBER_REF);
}
void menu_input_options::populate(float &customtop, float &custombottom)
{
bool inputmap, analog, toggle;
scan_inputs(machine(), inputmap, analog, toggle);
item_append(_("menu-inputopts", "Input Assignments (general)"), 0, (void *)INPUTMAP_GENERAL);
if (inputmap)
item_append(_("menu-inputopts", "Input Assignments (this system)"), 0, (void *)INPUTMAP_MACHINE);
if (analog)
item_append(_("menu-inputopts", "Analog Input Adjustments"), 0, (void *)ANALOG);
if (machine().natkeyboard().keyboard_count())
item_append(_("menu-inputopts", "Keyboard Selection"), 0, (void *)KEYBOARD);
if (toggle)
item_append(_("menu-inputopts", "Toggle Inputs"), 0, (void *)TOGGLES);
item_append(menu_item_type::SEPARATOR);
item_append(_("menu-inputopts", "Input Devices"), 0, (void *)INPUTDEV);
item_append(menu_item_type::SEPARATOR);
}
void menu_input_options::handle(event const *ev)
{
if (ev && (IPT_UI_SELECT == ev->iptkey))
{
switch (uintptr_t(ev->itemref))
{
case INPUTMAP_GENERAL:
stack_push<menu_input_groups>(ui(), container());
break;
case INPUTMAP_MACHINE:
stack_push<menu_input_specific>(ui(), container());
break;
case ANALOG:
stack_push<menu_analog>(ui(), container());
break;
case KEYBOARD:
stack_push<menu_keyboard_mode>(ui(), container());
break;
case TOGGLES:
stack_push<menu_input_toggles>(ui(), container());
break;
case INPUTDEV:
stack_push<menu_input_devices>(ui(), container());
break;
}
}
}
} // namespace ui

View File

@ -0,0 +1,37 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/***************************************************************************
ui/inputopts.h
Input options submenu.
***************************************************************************/
#ifndef MAME_FRONTEND_UI_INPUTOPTS_H
#define MAME_FRONTEND_UI_INPUTOPTS_H
#pragma once
#include "ui/menu.h"
namespace ui {
class menu_input_options : public menu
{
public:
menu_input_options(mame_ui_manager &mui, render_container &container);
virtual ~menu_input_options();
protected:
virtual void menu_activated() override;
private:
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle(event const *ev) override;
};
} // namespace ui
#endif // MAME_FRONTEND_UI_INPUTOPTS_H

View File

@ -0,0 +1,219 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/***************************************************************************
ui/inputtoggle.cpp
Toggle inputs menu.
***************************************************************************/
#include "emu.h"
#include "ui/inputtoggle.h"
#include <iterator>
namespace ui {
menu_input_toggles::menu_input_toggles(mame_ui_manager &mui, render_container &container)
: menu(mui, container)
{
set_heading(_("menu-inputtoggle", "Toggle Inputs"));
}
menu_input_toggles::~menu_input_toggles()
{
}
void menu_input_toggles::menu_activated()
{
// enabled inputs and state of inputs can change while menu is inactive
reset(reset_options::REMEMBER_REF);
}
void menu_input_toggles::populate(float &customtop, float &custombottom)
{
// find toggle fields
if (m_fields.empty())
{
for (auto &port : machine().ioport().ports())
{
for (ioport_field &field : port.second->fields())
{
switch (field.type_class())
{
case INPUT_CLASS_CONTROLLER:
case INPUT_CLASS_MISC:
case INPUT_CLASS_KEYBOARD:
if (field.live().toggle)
m_fields.emplace_back(field);
break;
default:
break;
}
}
}
}
// create corresponding items for enabled fields
device_t *prev_owner = nullptr;
for (auto &field : m_fields)
{
if (field.get().enabled())
{
// add a device heading if necessary
if (&field.get().device() != prev_owner)
{
prev_owner = &field.get().device();
if (prev_owner->owner())
item_append(string_format(_("%1$s [root%2$s]"), prev_owner->type().fullname(), prev_owner->tag()), FLAG_UI_HEADING | FLAG_DISABLE, nullptr);
else
item_append(string_format(_("[root%1$s]"), prev_owner->tag()), FLAG_UI_HEADING | FLAG_DISABLE, nullptr);
}
// choose the display name for the value
char const *setting;
u32 flags = 0U;
if (!field.get().settings().empty())
{
setting = field.get().setting_name();
if (field.get().has_previous_setting())
flags |= FLAG_LEFT_ARROW;
if (field.get().has_next_setting())
flags |= FLAG_RIGHT_ARROW;
}
else if (field.get().defvalue() == field.get().live().value)
{
setting = _("Off");
flags = FLAG_RIGHT_ARROW;
}
else
{
setting = _("On");
flags = FLAG_LEFT_ARROW;
}
// actually create the item
item_append(field.get().name(), setting, flags, &field);
}
}
// display a message if there are toggle inputs enabled
if (!prev_owner)
item_append(_("menu-inputtoggle", "[no toggle inputs are enabled]"), FLAG_DISABLE, nullptr);
item_append(menu_item_type::SEPARATOR);
}
void menu_input_toggles::handle(event const *ev)
{
if (ev && ev->itemref)
{
auto const ref = reinterpret_cast<std::reference_wrapper<ioport_field> *>(ev->itemref);
ioport_field &field = ref->get();
bool invalidate = false;
switch (ev->iptkey)
{
case IPT_UI_SELECT: // toggle regular items, set multi-value items to default
if (field.settings().empty())
{
field.live().value ^= field.mask();
invalidate = true;
break;
}
[[fallthrough]];
case IPT_UI_CLEAR: // set to default
if (field.defvalue() != field.live().value)
{
field.live().value = field.defvalue();
invalidate = true;
}
break;
case IPT_UI_LEFT: // toggle or select previous setting
if (field.settings().empty())
field.live().value ^= field.mask();
else
field.select_previous_setting();
invalidate = true;
break;
case IPT_UI_RIGHT: // toggle or select next setting
if (field.settings().empty())
field.live().value ^= field.mask();
else
field.select_next_setting();
invalidate = true;
break;
case IPT_UI_PREV_GROUP: // previous device if any
{
auto current = std::distance(m_fields.data(), ref);
device_t const *dev = &field.device();
bool found_break = false;
void *candidate = nullptr;
while (0 < current)
{
if (!found_break)
{
if (m_fields[--current].get().enabled())
{
device_t const *prev = &m_fields[current].get().device();
if (prev != dev)
{
dev = prev;
found_break = true;
candidate = &m_fields[current];
}
}
}
else if (&m_fields[--current].get().device() != dev)
{
set_selection(candidate);
set_top_line(selected_index() - 1);
break;
}
else if (m_fields[current].get().enabled())
{
candidate = &m_fields[current];
}
if (found_break && !current)
{
set_selection(candidate);
set_top_line(selected_index() - 1);
break;
}
}
}
break;
case IPT_UI_NEXT_GROUP: // next device if any
{
auto current = std::distance(m_fields.data(), ref);
device_t const *const dev = &field.device();
while (m_fields.size() > ++current)
{
if (m_fields[current].get().enabled() && (&m_fields[current].get().device() != dev))
{
set_selection(&m_fields[current]);
set_top_line(selected_index() - 1);
break;
}
}
}
break;
}
// changing value can enable or disable other fields
if (invalidate)
reset(reset_options::REMEMBER_REF);
}
}
} // namespace ui

View File

@ -0,0 +1,42 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/***************************************************************************
ui/inputtoggle.h
Toggle inputs menu.
***************************************************************************/
#ifndef MAME_FRONTEND_UI_INPUTTOGGLE_H
#define MAME_FRONTEND_UI_INPUTTOGGLE_H
#pragma once
#include "ui/menu.h"
#include <functional>
#include <vector>
namespace ui {
class menu_input_toggles : public menu
{
public:
menu_input_toggles(mame_ui_manager &mui, render_container &container);
virtual ~menu_input_toggles();
protected:
virtual void menu_activated() override;
private:
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle(event const *ev) override;
std::vector<std::reference_wrapper<ioport_field> > m_fields;
};
} // namespace ui
#endif // MAME_FRONTEND_UI_INPUTTOGGLE_H

View File

@ -26,6 +26,7 @@ constexpr uintptr_t ITEM_KBDEV_FIRST = 0x00000200;
menu_keyboard_mode::menu_keyboard_mode(mame_ui_manager &mui, render_container &container) : menu(mui, container)
{
set_heading(_("menu-keyboard", "Keyboard Selection"));
}
void menu_keyboard_mode::menu_activated()
@ -42,8 +43,8 @@ void menu_keyboard_mode::populate(float &customtop, float &custombottom)
{
bool const natmode(natkbd.in_use());
item_append(
_("Keyboard Mode"),
natmode ? _("Natural") : _("Emulated"),
_("menu-keyboard", "Keyboard Mode"),
natmode ? _("menu-keyboard", "Natural") : _("menu-keyboard", "Emulated"),
natmode ? FLAG_LEFT_ARROW : FLAG_RIGHT_ARROW,
reinterpret_cast<void *>(ITEM_KBMODE));
item_append(menu_item_type::SEPARATOR);
@ -88,7 +89,7 @@ void menu_keyboard_mode::handle(event const *ev)
if ((left || right) && (natkbd.in_use() != right))
{
natkbd.set_in_use(right);
ev->item->set_subtext(right ? _("Natural") : _("Emulated"));
ev->item->set_subtext(right ? _("menu-keyboard", "Natural") : _("menu-keyboard", "Emulated"));
ev->item->set_flags(right ? FLAG_LEFT_ARROW : FLAG_RIGHT_ARROW);
}
}

View File

@ -12,7 +12,6 @@
#include "ui/mainmenu.h"
#include "ui/about.h"
#include "ui/analogipt.h"
#include "ui/barcode.h"
#include "ui/cheatopt.h"
#include "ui/confswitch.h"
@ -21,8 +20,7 @@
#include "ui/info.h"
#include "ui/info_pty.h"
#include "ui/inifile.h"
#include "ui/inputmap.h"
#include "ui/keyboard.h"
#include "ui/inputopts.h"
#include "ui/miscmenu.h"
#include "ui/pluginopt.h"
#include "ui/selgame.h"
@ -35,23 +33,20 @@
#include "mame.h"
#include "luaengine.h"
#include "machine/bcreader.h"
#include "imagedev/cassette.h"
#include "machine/bcreader.h"
#include "crsshair.h"
#include "dipty.h"
#include "emuopts.h"
#include "natkeyboard.h"
namespace ui {
enum : unsigned {
INPUT_GROUPS,
INPUT_SPECIFIC,
INPUT_OPTIONS,
SETTINGS_DIP_SWITCHES,
SETTINGS_DRIVER_CONFIG,
ANALOG,
BOOKKEEPING,
GAME_INFO,
WARN_INFO,
@ -60,10 +55,8 @@ enum : unsigned {
TAPE_CONTROL,
SLOT_DEVICES,
NETWORK_DEVICES,
KEYBOARD_MODE,
SLIDERS,
VIDEO_TARGETS,
VIDEO_OPTIONS,
CROSSHAIR,
CHEAT,
PLUGINS,
@ -118,99 +111,92 @@ void menu_main::populate(float &customtop, float &custombottom)
{
m_phase = machine().phase();
item_append(_("Input (general)"), 0, (void *)INPUT_GROUPS);
item_append(_("menu-main", "Input Settings"), 0, (void *)INPUT_OPTIONS);
item_append(_("Input (this machine)"), 0, (void *)INPUT_SPECIFIC);
if (ui().machine_info().has_analog())
item_append(_("Analog Controls"), 0, (void *)ANALOG);
if (ui().machine_info().has_dips())
item_append(_("DIP Switches"), 0, (void *)SETTINGS_DIP_SWITCHES);
item_append(_("menu-main", "DIP Switches"), 0, (void *)SETTINGS_DIP_SWITCHES);
if (ui().machine_info().has_configs())
item_append(_("Machine Configuration"), 0, (void *)SETTINGS_DRIVER_CONFIG);
item_append(_("menu-main", "Machine Configuration"), 0, (void *)SETTINGS_DRIVER_CONFIG);
item_append(_("Bookkeeping Info"), 0, (void *)BOOKKEEPING);
item_append(_("menu-main", "Bookkeeping Info"), 0, (void *)BOOKKEEPING);
item_append(_("Machine Information"), 0, (void *)GAME_INFO);
item_append(_("menu-main", "System Information"), 0, (void *)GAME_INFO);
if (ui().found_machine_warnings())
item_append(_("Warning Information"), 0, (void *)WARN_INFO);
item_append(_("menu-main", "Warning Information"), 0, (void *)WARN_INFO);
for (device_image_interface &image : image_interface_enumerator(machine().root_device()))
{
if (image.user_loadable())
{
item_append(_("Image Information"), 0, (void *)IMAGE_MENU_IMAGE_INFO);
item_append(_("menu-main", "Media Image Information"), 0, (void *)IMAGE_MENU_IMAGE_INFO);
item_append(_("File Manager"), 0, (void *)IMAGE_MENU_FILE_MANAGER);
item_append(_("menu-main", "File Manager"), 0, (void *)IMAGE_MENU_FILE_MANAGER);
break;
}
}
if (cassette_device_enumerator(machine().root_device()).first() != nullptr)
item_append(_("Tape Control"), 0, (void *)TAPE_CONTROL);
item_append(_("menu-main", "Tape Control"), 0, (void *)TAPE_CONTROL);
if (pty_interface_enumerator(machine().root_device()).first() != nullptr)
item_append(_("Pseudo Terminals"), 0, (void *)PTY_INFO);
item_append(_("menu-main", "Pseudo Terminals"), 0, (void *)PTY_INFO);
if (ui().machine_info().has_bioses())
item_append(_("BIOS Selection"), 0, (void *)BIOS_SELECTION);
item_append(_("menu-main", "BIOS Selection"), 0, (void *)BIOS_SELECTION);
if (slot_interface_enumerator(machine().root_device()).first() != nullptr)
item_append(_("Slot Devices"), 0, (void *)SLOT_DEVICES);
item_append(_("menu-main", "Slot Devices"), 0, (void *)SLOT_DEVICES);
if (barcode_reader_device_enumerator(machine().root_device()).first() != nullptr)
item_append(_("Barcode Reader"), 0, (void *)BARCODE_READ);
item_append(_("menu-main", "Barcode Reader"), 0, (void *)BARCODE_READ);
if (network_interface_enumerator(machine().root_device()).first() != nullptr)
item_append(_("Network Devices"), 0, (void*)NETWORK_DEVICES);
item_append(_("menu-main", "Network Devices"), 0, (void*)NETWORK_DEVICES);
if (machine().natkeyboard().keyboard_count())
item_append(_("Keyboard Mode"), 0, (void *)KEYBOARD_MODE);
item_append(_("menu-main", "Slider Controls"), 0, (void *)SLIDERS);
item_append(_("Slider Controls"), 0, (void *)SLIDERS);
item_append(_("Video Options"), 0, (void *)VIDEO_TARGETS);
item_append(_("menu-main", "Video Options"), 0, (void *)VIDEO_TARGETS);
if (machine().crosshair().get_usage())
item_append(_("Crosshair Options"), 0, (void *)CROSSHAIR);
item_append(_("menu-main", "Crosshair Options"), 0, (void *)CROSSHAIR);
if (machine().options().cheat())
item_append(_("Cheat"), 0, (void *)CHEAT);
item_append(_("menu-main", "Cheat"), 0, (void *)CHEAT);
if (machine_phase::RESET <= m_phase)
{
if (machine().options().plugins() && !mame_machine_manager::instance()->lua()->get_menu().empty())
item_append(_("Plugin Options"), 0, (void *)PLUGINS);
item_append(_("menu-main", "Plugin Options"), 0, (void *)PLUGINS);
if (mame_machine_manager::instance()->lua()->call_plugin_check<const char *>("data_list", "", true))
item_append(_("External DAT View"), 0, (void *)EXTERNAL_DATS);
item_append(_("menu-main", "External DAT View"), 0, (void *)EXTERNAL_DATS);
}
item_append(menu_item_type::SEPARATOR);
if (!mame_machine_manager::instance()->favorite().is_favorite(machine()))
item_append(_("Add To Favorites"), 0, (void *)ADD_FAVORITE);
item_append(_("menu-main", "Add To Favorites"), 0, (void *)ADD_FAVORITE);
else
item_append(_("Remove From Favorites"), 0, (void *)REMOVE_FAVORITE);
item_append(_("menu-main", "Remove From Favorites"), 0, (void *)REMOVE_FAVORITE);
item_append(menu_item_type::SEPARATOR);
item_append(string_format(_("About %1$s"), emulator_info::get_appname()), 0, (void *)ABOUT);
item_append(string_format(_("menu-main", "About %1$s"), emulator_info::get_appname()), 0, (void *)ABOUT);
item_append(menu_item_type::SEPARATOR);
// item_append(_("Quit from Machine"), 0, (void *)QUIT_GAME);
// item_append(_("menu-main", "Quit from System"), 0, (void *)QUIT_GAME);
if (machine_phase::INIT == m_phase)
{
item_append(_("Start Machine"), 0, (void *)DISMISS);
item_append(_("menu-main", "Start System"), 0, (void *)DISMISS);
}
else
{
item_append(_("Select New Machine"), 0, (void *)SELECT_GAME);
item_append(_("Return to Machine"), 0, (void *)DISMISS);
item_append(_("menu-main", "Select New System"), 0, (void *)SELECT_GAME);
item_append(_("menu-main", "Close Menu"), 0, (void *)DISMISS);
}
}
@ -226,12 +212,8 @@ void menu_main::handle(event const *ev)
{
switch (uintptr_t(ev->itemref))
{
case INPUT_GROUPS:
menu::stack_push<menu_input_groups>(ui(), container());
break;
case INPUT_SPECIFIC:
menu::stack_push<menu_input_specific>(ui(), container());
case INPUT_OPTIONS:
menu::stack_push<menu_input_options>(ui(), container());
break;
case SETTINGS_DIP_SWITCHES:
@ -242,10 +224,6 @@ void menu_main::handle(event const *ev)
menu::stack_push<menu_settings_machine_config>(ui(), container());
break;
case ANALOG:
menu::stack_push<menu_analog>(ui(), container());
break;
case BOOKKEEPING:
menu::stack_push<menu_bookkeeping>(ui(), container());
break;
@ -282,10 +260,6 @@ void menu_main::handle(event const *ev)
menu::stack_push<menu_network_devices>(ui(), container());
break;
case KEYBOARD_MODE:
menu::stack_push<menu_keyboard_mode>(ui(), container());
break;
case SLIDERS:
menu::stack_push<menu_sliders>(ui(), container(), false);
break;
@ -294,10 +268,6 @@ void menu_main::handle(event const *ev)
menu::stack_push<menu_video_targets>(ui(), container());
break;
case VIDEO_OPTIONS:
menu::stack_push<menu_video_options>(ui(), container(), *machine().render().first_target(), false);
break;
case CROSSHAIR:
menu::stack_push<menu_crosshair>(ui(), container());
break;

View File

@ -28,7 +28,6 @@
#include <algorithm>
#include <cassert>
#include <cmath>
#include <utility>
namespace ui {
@ -236,7 +235,9 @@ menu::menu(mame_ui_manager &mui, render_container &container)
, m_ui(mui)
, m_container(container)
, m_parent()
, m_heading()
, m_items()
, m_rebuilding(false)
, m_process_flags(0)
, m_selected(0)
, m_hover(1)
@ -245,14 +246,14 @@ menu::menu(mame_ui_manager &mui, render_container &container)
, m_needs_prev_menu_item(true)
, m_active(false)
, m_event()
, m_customtop(0.0f)
, m_custombottom(0.0f)
, m_customtop(0.0F)
, m_custombottom(0.0F)
, m_resetpos(0)
, m_resetref(nullptr)
, m_mouse_hit(false)
, m_mouse_button(false)
, m_mouse_x(-1.0f)
, m_mouse_y(-1.0f)
, m_mouse_x(-1.0F)
, m_mouse_y(-1.0F)
{
reset(reset_options::SELECT_FIRST);
@ -321,6 +322,8 @@ void menu::item_append(menu_item_type type, uint32_t flags)
void menu::item_append(std::string &&text, std::string &&subtext, uint32_t flags, void *ref, menu_item_type type)
{
assert(m_rebuilding);
// allocate a new item and populate it
menu_item pitem(type, ref, flags);
pitem.set_text(std::move(text));
@ -386,7 +389,7 @@ const menu::event *menu::process()
return true;
};
if (draw_parent(draw_parent, m_parent.get()))
container().add_rect(0.0f, 0.0f, 1.0f, 1.0f, rgb_t(114, 0, 0, 0), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
container().add_rect(0.0F, 0.0F, 1.0F, 1.0F, rgb_t(114, 0, 0, 0), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
// draw the menu proper
draw(m_process_flags);
@ -447,12 +450,13 @@ void menu::set_selection(void *selected_itemref)
void menu::draw(uint32_t flags)
{
// first draw the FPS counter
// FIXME: provide a way to do this in the UI manager itself while menus are on-screen
if (ui().show_fps_counter())
{
ui().draw_text_full(
container(),
machine().video().speed_text(),
0.0f, 0.0f, 1.0f,
0.0F, 0.0F, 1.0F,
text_layout::text_justify::RIGHT, text_layout::word_wrapping::WORD,
mame_ui_manager::OPAQUE_, rgb_t::white(), rgb_t::black(),
nullptr, nullptr);
@ -462,10 +466,11 @@ void menu::draw(uint32_t flags)
bool const noinput = (flags & PROCESS_NOINPUT);
float const aspect = machine().render().ui_aspect(&container());
float const line_height = ui().get_line_height();
float const lr_arrow_width = 0.4f * line_height * aspect;
float const lr_arrow_width = 0.4F * line_height * aspect;
float const ud_arrow_width = line_height * aspect;
float const gutter_width = lr_arrow_width * 1.3f;
float const gutter_width = 0.5F * line_height * aspect;
float const lr_border = ui().box_lr_border() * aspect;
float const max_width = 1.0F - ((lr_border + (aspect * UI_LINE_WIDTH)) * 2.0F);
if (is_special_main_menu())
draw_background();
@ -480,38 +485,46 @@ void menu::draw(uint32_t flags)
// add in width of right hand side
if (!pitem.subtext().empty())
total_width += 2.0f * gutter_width + ui().get_string_width(pitem.subtext());
total_width += 2.0F * gutter_width + ui().get_string_width(pitem.subtext());
else if (pitem.flags() & FLAG_UI_HEADING)
total_width += 4.0f * ud_arrow_width;
total_width += 4.0F * ud_arrow_width;
// track the maximum
if (total_width > visible_width)
visible_width = total_width;
visible_width = std::max(total_width, visible_width);
// track the height as well
visible_main_menu_height += line_height;
}
// lay out the heading if present
std::optional<text_layout> heading_layout;
if (m_heading)
{
heading_layout.emplace(ui().create_layout(container(), max_width - (gutter_width * 2.0F), text_layout::text_justify::CENTER));
heading_layout->add_text(*m_heading, ui().colors().text_color());
}
// account for extra space at the top and bottom
float const visible_extra_menu_height = m_customtop + m_custombottom;
float const top_extra_menu_height = m_customtop + (heading_layout ? (heading_layout->actual_height() + (ui().box_tb_border() * 3.0F)) : 0.0F);
float const visible_extra_menu_height = top_extra_menu_height + m_custombottom;
// add a little bit of slop for rounding
visible_width += 0.01f;
visible_main_menu_height += 0.01f;
visible_width += 0.01F;
visible_main_menu_height += 0.01F;
// if we are too wide or too tall, clamp it down
visible_width = std::min(visible_width, 1.0f - ((lr_border + (aspect * UI_LINE_WIDTH)) * 2.0f));
visible_width = std::min(visible_width, max_width);
// if the menu and extra menu won't fit, take away part of the regular menu, it will scroll
if (visible_main_menu_height + visible_extra_menu_height + 2.0f * ui().box_tb_border() > 1.0f)
visible_main_menu_height = 1.0f - 2.0f * ui().box_tb_border() - visible_extra_menu_height;
if (visible_main_menu_height + visible_extra_menu_height + 2.0F * ui().box_tb_border() > 1.0F)
visible_main_menu_height = 1.0F - 2.0F * ui().box_tb_border() - visible_extra_menu_height;
m_visible_lines = std::min(int(std::floor(visible_main_menu_height / line_height)), int(unsigned(m_items.size())));
visible_main_menu_height = float(m_visible_lines) * line_height;
// compute top/left of inner menu area by centering
float const visible_left = (1.0f - visible_width) * 0.5f;
float const visible_top = ((1.0f - visible_main_menu_height - visible_extra_menu_height) * 0.5f) + m_customtop;
float const visible_left = (1.0F - visible_width) * 0.5F;
float const visible_top = ((1.0F - visible_main_menu_height - visible_extra_menu_height) * 0.5F) + top_extra_menu_height;
// first add us a box
float const x1 = visible_left - lr_border;
@ -519,7 +532,26 @@ void menu::draw(uint32_t flags)
float const x2 = visible_left + visible_width + lr_border;
float const y2 = visible_top + visible_main_menu_height + ui().box_tb_border();
if (!customonly)
ui().draw_outlined_box(container(), x1, y1, x2, y2, ui().colors().background_color());
{
if (heading_layout)
{
float const heading_width = heading_layout->actual_width();
float const heading_left = (1.0F - heading_width) * 0.5F;
float const hx1 = std::min(x1, heading_left - gutter_width - lr_border);
float const hx2 = std::max(x2, heading_left + heading_width + gutter_width + lr_border);
ui().draw_outlined_box(
container(),
hx1, y1 - top_extra_menu_height,
hx2, y1 - m_customtop - ui().box_tb_border(),
UI_GREEN_COLOR);
heading_layout->emit(container(), (1.0F - heading_layout->width()) * 0.5F, y1 - top_extra_menu_height + ui().box_tb_border());
}
ui().draw_outlined_box(
container(),
x1, y1,
x2, y2,
ui().colors().background_color());
}
if ((m_selected >= (top_line + m_visible_lines)) || (m_selected < (top_line + 1)))
top_line = m_selected - (m_visible_lines / 2);
@ -538,7 +570,7 @@ void menu::draw(uint32_t flags)
m_visible_items = m_visible_lines - (show_top_arrow ? 1 : 0) - (show_bottom_arrow ? 1 : 0);
// determine effective positions taking into account the hilighting arrows
float const effective_width = visible_width - 2.0f * gutter_width;
float const effective_width = visible_width - 2.0F * gutter_width;
float const effective_left = visible_left + gutter_width;
// locate mouse
@ -550,8 +582,8 @@ void menu::draw(uint32_t flags)
// loop over visible lines
m_hover = m_items.size() + 1;
bool selected_subitem_too_big = false;
float const line_x0 = x1 + 0.5f * UI_LINE_WIDTH;
float const line_x1 = x2 - 0.5f * UI_LINE_WIDTH;
float const line_x0 = x1 + 0.5F * UI_LINE_WIDTH;
float const line_x1 = x2 - 0.5F * UI_LINE_WIDTH;
if (!customonly)
{
for (int linenum = 0; linenum < m_visible_lines; linenum++)
@ -603,10 +635,10 @@ void menu::draw(uint32_t flags)
{
// if we're on the top line, display the up arrow
draw_arrow(
0.5f * (x1 + x2) - 0.5f * ud_arrow_width,
line_y0 + 0.25f * line_height,
0.5f * (x1 + x2) + 0.5f * ud_arrow_width,
line_y0 + 0.75f * line_height,
0.5F * (x1 + x2) - 0.5F * ud_arrow_width,
line_y0 + 0.25F * line_height,
0.5F * (x1 + x2) + 0.5F * ud_arrow_width,
line_y0 + 0.75F * line_height,
fgcolor,
ROT0);
}
@ -614,17 +646,17 @@ void menu::draw(uint32_t flags)
{
// if we're on the bottom line, display the down arrow
draw_arrow(
0.5f * (x1 + x2) - 0.5f * ud_arrow_width,
line_y0 + 0.25f * line_height,
0.5f * (x1 + x2) + 0.5f * ud_arrow_width,
line_y0 + 0.75f * line_height,
0.5F * (x1 + x2) - 0.5F * ud_arrow_width,
line_y0 + 0.25F * line_height,
0.5F * (x1 + x2) + 0.5F * ud_arrow_width,
line_y0 + 0.75F * line_height,
fgcolor,
ROT0 ^ ORIENTATION_FLIP_Y);
}
else if (pitem.type() == menu_item_type::SEPARATOR)
{
// if we're just a divider, draw a line
container().add_line(visible_left, line_y0 + 0.5f * line_height, visible_left + visible_width, line_y0 + 0.5f * line_height, UI_LINE_WIDTH, ui().colors().border_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
container().add_line(visible_left, line_y0 + 0.5F * line_height, visible_left + visible_width, line_y0 + 0.5F * line_height, UI_LINE_WIDTH, ui().colors().border_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
}
else if (pitem.subtext().empty())
{
@ -632,8 +664,8 @@ void menu::draw(uint32_t flags)
if (pitem.flags() & FLAG_UI_HEADING)
{
float heading_width = ui().get_string_width(itemtext);
container().add_line(visible_left, line_y0 + 0.5f * line_height, visible_left + ((visible_width - heading_width) / 2) - lr_border, line_y0 + 0.5f * line_height, UI_LINE_WIDTH, ui().colors().border_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
container().add_line(visible_left + visible_width - ((visible_width - heading_width) / 2) + lr_border, line_y0 + 0.5f * line_height, visible_left + visible_width, line_y0 + 0.5f * line_height, UI_LINE_WIDTH, ui().colors().border_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
container().add_line(visible_left, line_y0 + 0.5F * line_height, visible_left + ((visible_width - heading_width) / 2) - lr_border, line_y0 + 0.5F * line_height, UI_LINE_WIDTH, ui().colors().border_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
container().add_line(visible_left + visible_width - ((visible_width - heading_width) / 2) + lr_border, line_y0 + 0.5F * line_height, visible_left + visible_width, line_y0 + 0.5F * line_height, UI_LINE_WIDTH, ui().colors().border_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
}
ui().draw_text_full(
container(),
@ -667,8 +699,8 @@ void menu::draw(uint32_t flags)
ui().draw_outlined_box(
container(),
effective_left + effective_width - subitem_width, line_y0 + (UI_LINE_WIDTH * 2.0f),
effective_left + effective_width, line_y1 - (UI_LINE_WIDTH * 2.0f),
effective_left + effective_width - subitem_width, line_y0 + (UI_LINE_WIDTH * 2.0F),
effective_left + effective_width, line_y1 - (UI_LINE_WIDTH * 2.0F),
color);
}
else
@ -676,7 +708,7 @@ void menu::draw(uint32_t flags)
std::string_view subitem_text(pitem.subtext());
// give 2 spaces worth of padding
item_width += 2.0f * gutter_width;
item_width += 2.0F * gutter_width;
// if the subitem doesn't fit here, display dots
if (ui().get_string_width(subitem_text) > effective_width - item_width)
@ -712,10 +744,10 @@ void menu::draw(uint32_t flags)
float const l = effective_left + effective_width - subitem_width - gutter_width;
float const r = l + lr_arrow_width;
draw_arrow(
l, line_y0 + 0.1f * line_height, r, line_y0 + 0.9f * line_height,
l, line_y0 + 0.1F * line_height, r, line_y0 + 0.9F * line_height,
fgcolor,
ROT90 ^ ORIENTATION_FLIP_X);
if (mouse_in_rect(l, line_y0 + 0.1f * line_height, r, line_y0 + 0.9f * line_height))
if (mouse_in_rect(l, line_y0 + 0.1F * line_height, r, line_y0 + 0.9F * line_height))
m_hover = HOVER_UI_LEFT;
}
if (is_selected(itemnum) && (pitem.flags() & FLAG_RIGHT_ARROW))
@ -723,10 +755,10 @@ void menu::draw(uint32_t flags)
float const r = effective_left + effective_width + gutter_width;
float const l = r - lr_arrow_width;
draw_arrow(
l, line_y0 + 0.1f * line_height, r, line_y0 + 0.9f * line_height,
l, line_y0 + 0.1F * line_height, r, line_y0 + 0.9F * line_height,
fgcolor,
ROT90);
if (mouse_in_rect(l, line_y0 + 0.1f * line_height, r, line_y0 + 0.9f * line_height))
if (mouse_in_rect(l, line_y0 + 0.1F * line_height, r, line_y0 + 0.9F * line_height))
m_hover = HOVER_UI_RIGHT;
}
}
@ -746,7 +778,7 @@ void menu::draw(uint32_t flags)
ui().draw_text_full(
container(),
pitem.subtext(),
0, 0, visible_width * 0.75f,
0, 0, visible_width * 0.75F,
text_layout::text_justify::RIGHT, text_layout::word_wrapping::WORD,
mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(),
&target_width, &target_height);
@ -809,8 +841,8 @@ void menu::ignore_mouse()
{
m_mouse_hit = false;
m_mouse_button = false;
m_mouse_x = -1.0f;
m_mouse_y = -1.0f;
m_mouse_x = -1.0F;
m_mouse_y = -1.0F;
}
@ -1193,12 +1225,23 @@ void menu::do_handle()
{
if (m_items.empty())
{
// add an item to return - this is a really hacky way of doing this
if (m_needs_prev_menu_item)
item_append(_("Return to Previous Menu"), 0, nullptr);
m_rebuilding = true;
try
{
// add an item to return - this is a really hacky way of doing this
if (m_needs_prev_menu_item)
item_append(_("Return to Previous Menu"), 0, nullptr);
// let implementation add other items
populate(m_customtop, m_custombottom);
// let implementation add other items
populate(m_customtop, m_custombottom);
}
catch (...)
{
m_items.clear();
m_rebuilding = false;
throw;
}
m_rebuilding = false;
}
handle(process());
}
@ -1274,7 +1317,7 @@ void menu::draw_background()
{
// draw background image if available
if (ui().options().use_background_image() && m_global_state.bgrnd_bitmap() && m_global_state.bgrnd_bitmap()->valid())
container().add_quad(0.0f, 0.0f, 1.0f, 1.0f, rgb_t::white(), m_global_state.bgrnd_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
container().add_quad(0.0F, 0.0F, 1.0F, 1.0F, rgb_t::white(), m_global_state.bgrnd_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
}
@ -1290,7 +1333,7 @@ void menu::extra_text_position(float origx1, float origx2, float origy, float ys
float maxwidth = std::max(width, origx2 - origx1);
// compute our bounds
x1 = 0.5f - 0.5f * maxwidth;
x1 = 0.5F - (0.5F * maxwidth);
x2 = x1 + maxwidth;
y1 = origy + (yspan * direction);
y2 = origy + (ui().box_tb_border() * direction);

View File

@ -23,7 +23,9 @@
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <string_view>
#include <utility>
#include <vector>
@ -49,6 +51,16 @@ public:
virtual ~menu();
// setting menu heading
template <typename... T>
void set_heading(T &&... args)
{
if (!m_heading)
m_heading.emplace(std::forward<T>(args)...);
else
m_heading->assign(std::forward<T>(args)...);
}
// append a new item to the end of the menu
void item_append(const std::string &text, uint32_t flags, void *ref, menu_item_type type = menu_item_type::UNKNOWN) { item_append(std::string(text), std::string(), flags, ref, type); }
void item_append(const std::string &text, const std::string &subtext, uint32_t flags, void *ref, menu_item_type type = menu_item_type::UNKNOWN) { item_append(std::string(text), std::string(subtext), flags, ref, type); }
@ -348,14 +360,14 @@ private:
// to be implemented in derived classes
virtual void handle(event const *ev) = 0;
// push a new menu onto the stack
static void stack_push(std::unique_ptr<menu> &&menu) { menu->m_global_state.stack_push(std::move(menu)); }
void extra_text_draw_box(float origx1, float origx2, float origy, float yspan, std::string_view text, int direction);
bool first_item_visible() const { return top_line <= 0; }
bool last_item_visible() const { return (top_line + m_visible_lines) >= m_items.size(); }
// push a new menu onto the stack
static void stack_push(std::unique_ptr<menu> &&menu) { menu->m_global_state.stack_push(std::move(menu)); }
static global_state &get_global_state(mame_ui_manager &ui);
protected: // TODO: remove need to expose these - only used here and in selmenu.cpp
@ -369,7 +381,9 @@ private:
render_container &m_container; // render_container we render to
std::unique_ptr<menu> m_parent; // pointer to parent menu in the stack
std::optional<std::string> m_heading; // menu heading
std::vector<menu_item> m_items; // array of items
bool m_rebuilding; // ensure items are only added during rebuild
uint32_t m_process_flags; // event processing options
int m_selected; // which item is selected

View File

@ -49,6 +49,7 @@ namespace ui {
menu_bios_selection::menu_bios_selection(mame_ui_manager &mui, render_container &container) : menu(mui, container)
{
set_heading(_("BIOS Selection"));
}
void menu_bios_selection::populate(float &customtop, float &custombottom)
@ -70,7 +71,7 @@ void menu_bios_selection::populate(float &customtop, float &custombottom)
val = rom->hashdata;
}
if (val)
item_append(!parent ? "driver" : (device.tag() + 1), val, FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, (void *)&device);
item_append(!parent ? _("System") : (device.tag() + 1), val, FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, (void *)&device);
}
}
}
@ -144,6 +145,7 @@ void menu_bios_selection::handle(event const *ev)
menu_network_devices::menu_network_devices(mame_ui_manager &mui, render_container &container) : menu(mui, container)
{
set_heading(_("Network Devices"));
}
menu_network_devices::~menu_network_devices()
@ -349,10 +351,10 @@ void menu_crosshair::handle(event const *ev)
{
std::vector<std::string> sel;
sel.reserve(m_pics.size() + 1);
sel.push_back("DEFAULT");
sel.push_back(_("menu-crosshair", "[built-in]"));
std::copy(m_pics.begin(), m_pics.end(), std::back_inserter(sel));
menu::stack_push<menu_selector>(
ui(), container(), std::move(sel), data.cur,
ui(), container(), std::string(ev->item->text()), std::move(sel), data.cur,
[this, &data] (int selection)
{
if (!selection)
@ -390,6 +392,7 @@ void menu_crosshair::handle(event const *ev)
menu_crosshair::menu_crosshair(mame_ui_manager &mui, render_container &container) : menu(mui, container)
{
set_process_flags(PROCESS_LR_REPEAT);
set_heading(_("menu-crosshair", "Crosshair Options"));
}
void menu_crosshair::populate(float &customtop, float &custombottom)
@ -449,7 +452,10 @@ void menu_crosshair::populate(float &customtop, float &custombottom)
}
// Make sure to keep these matched to the CROSSHAIR_VISIBILITY_xxx types
static char const *const vis_text[] = { "Off", "On", "Auto" };
static char const *const vis_text[] = {
N_p("menu-crosshair", "Always"),
N_p("menu-crosshair", "Never"),
N_p("menu-crosshair", "When moved") };
bool use_auto = false;
for (crosshair_item_data &data : m_data)
@ -472,7 +478,11 @@ void menu_crosshair::populate(float &customtop, float &custombottom)
flags |= FLAG_RIGHT_ARROW;
// add CROSSHAIR_ITEM_VIS menu */
item_append(util::string_format(_("P%d Visibility"), data.player + 1), vis_text[data.crosshair->mode()], flags, &data);
item_append(
util::string_format(_("menu-crosshair", "P%1$d Visibility"), data.player + 1),
_("menu-crosshair", vis_text[data.crosshair->mode()]),
flags,
&data);
}
break;
@ -526,7 +536,12 @@ void menu_crosshair::populate(float &customtop, float &custombottom)
flags |= FLAG_LEFT_ARROW;
// add CROSSHAIR_ITEM_PIC menu
item_append(util::string_format(_("P%d Crosshair"), data.player + 1), using_default ? "DEFAULT" : data.crosshair->bitmap_name(), flags, &data);
item_append(
util::string_format(_("menu-crosshair", "P%1$d Crosshair"), data.player + 1),
using_default ? _("menu-crosshair", "[built-in]") : data.crosshair->bitmap_name(),
flags,
&data);
item_append(menu_item_type::SEPARATOR);
}
break;
@ -543,18 +558,16 @@ void menu_crosshair::populate(float &customtop, float &custombottom)
flags |= FLAG_RIGHT_ARROW;
// add CROSSHAIR_ITEM_AUTO_TIME menu
item_append(_("Visible Delay"), util::string_format("%d", data.cur), flags, &data);
}
else
{
// leave a blank filler line when not in auto time so size does not rescale
//item_append("", "", nullptr, nullptr);
item_append(
_("menu-crosshair", "Auto-Hide Delay"),
util::string_format(_("menu-crosshair", "%1$d s"), data.cur),
flags,
&data);
item_append(menu_item_type::SEPARATOR);
}
break;
}
}
item_append(menu_item_type::SEPARATOR);
}
menu_crosshair::~menu_crosshair()
@ -568,6 +581,7 @@ menu_crosshair::~menu_crosshair()
menu_export::menu_export(mame_ui_manager &mui, render_container &container, std::vector<const game_driver *> &&drvlist)
: menu(mui, container), m_list(std::move(drvlist))
{
set_heading(_("Export Displayed List to File"));
}
menu_export::~menu_export()
@ -708,6 +722,7 @@ menu_machine_configure::menu_machine_configure(
osd_setup_osd_specific_emu_options(m_opts);
mame_options::parse_standard_inis(m_opts, error, m_sys.driver);
setup_bios();
set_heading(util::string_format(_("System Settings:\n%1$s"), m_sys.description));
}
menu_machine_configure::~menu_machine_configure()
@ -746,7 +761,7 @@ void menu_machine_configure::handle(event const *ev)
{
std::string inistring = m_opts.output_ini();
file.puts(inistring);
ui().popup_time(2, "%s", _("\n Configuration saved \n\n"));
ui().popup_time(2, "%s", _("\n Settings saved \n\n"));
}
}
break;
@ -758,14 +773,14 @@ void menu_machine_configure::handle(event const *ev)
m_want_favorite = false;
reset(reset_options::REMEMBER_POSITION);
break;
case CONTROLLER:
if (ev->iptkey == IPT_UI_SELECT)
menu::stack_push<submenu>(ui(), container(), submenu::control_options(), m_sys.driver, &m_opts);
break;
case VIDEO:
if (ev->iptkey == IPT_UI_SELECT)
menu::stack_push<submenu>(ui(), container(), submenu::video_options(), m_sys.driver, &m_opts);
break;
case CONTROLLER:
if (ev->iptkey == IPT_UI_SELECT)
menu::stack_push<submenu>(ui(), container(), submenu::control_options(), m_sys.driver, &m_opts);
break;
case ADVANCED:
if (ev->iptkey == IPT_UI_SELECT)
menu::stack_push<submenu>(ui(), container(), submenu::advanced_options(), m_sys.driver, &m_opts);
@ -794,10 +809,10 @@ void menu_machine_configure::populate(float &customtop, float &custombottom)
if (!m_bios.empty())
{
uint32_t arrows = get_arrow_flags(std::size_t(0), m_bios.size() - 1, m_curbios);
item_append(_("Driver"), m_bios[m_curbios].first, arrows, (void *)(uintptr_t)BIOS);
item_append(_("System"), m_bios[m_curbios].first, arrows, (void *)(uintptr_t)BIOS);
}
else
item_append(_("This machine has no BIOS."), FLAG_DISABLE, nullptr);
item_append(_("[this system has no BIOS settings]"), FLAG_DISABLE, nullptr);
item_append(menu_item_type::SEPARATOR);
item_append(_(submenu::advanced_options()[0].description), 0, (void *)(uintptr_t)ADVANCED);
@ -811,25 +826,13 @@ void menu_machine_configure::populate(float &customtop, float &custombottom)
item_append(_("Remove From Favorites"), 0, (void *)DELFAV);
item_append(menu_item_type::SEPARATOR);
item_append(_("Save Machine Configuration"), 0, (void *)(uintptr_t)SAVE);
customtop = 2.0f * ui().get_line_height() + 3.0f * ui().box_tb_border();
item_append(_("Save System Settings"), 0, (void *)(uintptr_t)SAVE);
}
//-------------------------------------------------
// perform our special rendering
//-------------------------------------------------
void menu_machine_configure::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{
char const *const text[] = { _("Configure Machine:"), m_sys.description.c_str() };
draw_text_box(
std::begin(text), std::end(text),
origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(),
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false,
ui().colors().text_color(), UI_GREEN_COLOR, 1.0f);
}
void menu_machine_configure::setup_bios()
{
if (!m_sys.driver->rom)
@ -850,7 +853,7 @@ void menu_machine_configure::setup_bios()
u32 const bios_flags(bios.get_value());
std::string const bios_number(std::to_string(bios_flags - 1));
// check biosnumber and name
// check BIOS number and name
if ((bios_number == specbios) || (specbios == bios.get_name()))
m_curbios = bios_count;
@ -873,6 +876,7 @@ void menu_machine_configure::setup_bios()
menu_plugins_configure::menu_plugins_configure(mame_ui_manager &mui, render_container &container)
: menu(mui, container)
{
set_heading(_("Plugins"));
}
menu_plugins_configure::~menu_plugins_configure()
@ -932,23 +936,8 @@ void menu_plugins_configure::populate(float &customtop, float &custombottom)
}
}
if (first)
item_append(_("No plugins found"), 0, nullptr);
item_append(_("No plugins found"), FLAG_DISABLE, nullptr);
item_append(menu_item_type::SEPARATOR);
customtop = ui().get_line_height() + (3.0f * ui().box_tb_border());
}
//-------------------------------------------------
// perform our special rendering
//-------------------------------------------------
void menu_plugins_configure::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{
char const *const toptext[] = { _("Plugins") };
draw_text_box(
std::begin(toptext), std::end(toptext),
origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(),
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false,
ui().colors().text_color(), UI_GREEN_COLOR, 1.0f);
}
} // namespace ui

View File

@ -133,9 +133,6 @@ public:
std::function<void (bool, bool)> &&handler = nullptr);
virtual ~menu_machine_configure();
protected:
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
private:
using s_bios = std::vector<std::pair<std::string, int>>;
@ -144,8 +141,8 @@ private:
ADDFAV = 1,
DELFAV,
SAVE,
CONTROLLER,
VIDEO,
CONTROLLER,
BIOS,
ADVANCED,
LAST = ADVANCED
@ -179,8 +176,6 @@ public:
protected:
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle(event const *ev) override;
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
};
} // namespace ui

View File

@ -13,6 +13,7 @@
#include "ui/custui.h"
#include "ui/dirmenu.h"
#include "ui/inputdevices.h"
#include "ui/inputmap.h"
#include "ui/miscmenu.h"
#include "ui/selector.h"
@ -41,6 +42,7 @@ menu_simple_game_options::menu_simple_game_options(
, m_handler(std::move(handler))
{
set_process_flags(PROCESS_LR_REPEAT);
set_heading(_("General Settings"));
}
//-------------------------------------------------
@ -75,15 +77,16 @@ void menu_simple_game_options::populate(float &customtop, float &custombottom)
item_append(_("Sound Options"), 0, (void *)(uintptr_t)SOUND_MENU);
item_append(_(submenu::misc_options()[0].description), 0, (void *)(uintptr_t)MISC_MENU);
item_append(_(submenu::control_options()[0].description), 0, (void *)(uintptr_t)CONTROLLER_MENU);
item_append(_("General Inputs"), 0, (void *)(uintptr_t)CGI_MENU);
item_append(_("Input Assignments"), 0, (void *)(uintptr_t)INPUTASSIGN_MENU);
item_append(_(submenu::advanced_options()[0].description), 0, (void *)(uintptr_t)ADVANCED_MENU);
if (machine().options().plugins())
item_append(_("Plugins"), 0, (void *)(uintptr_t)PLUGINS_MENU);
item_append(menu_item_type::SEPARATOR);
item_append(_("Save Configuration"), 0, (void *)(uintptr_t)SAVE_CONFIG);
item_append(_("Input Devices"), 0, (void *)(uintptr_t)INPUTDEV_MENU);
item_append(menu_item_type::SEPARATOR);
item_append(_("Save Settings"), 0, (void *)(uintptr_t)SAVE_CONFIG);
custombottom = 2.0f * ui().get_line_height() + 3.0f * ui().box_tb_border();
customtop = ui().get_line_height() + 3.0f * ui().box_tb_border();
}
//-------------------------------------------------
@ -92,69 +95,45 @@ void menu_simple_game_options::populate(float &customtop, float &custombottom)
void menu_simple_game_options::handle_item_event(event const &menu_event)
{
switch ((uintptr_t)menu_event.itemref)
if (IPT_UI_SELECT == menu_event.iptkey)
{
case MISC_MENU:
if (menu_event.iptkey == IPT_UI_SELECT)
switch ((uintptr_t)menu_event.itemref)
{
case MISC_MENU:
menu::stack_push<submenu>(ui(), container(), submenu::misc_options());
ui_globals::reset = true;
}
break;
case SOUND_MENU:
if (menu_event.iptkey == IPT_UI_SELECT)
{
break;
case SOUND_MENU:
menu::stack_push<menu_sound_options>(ui(), container());
ui_globals::reset = true;
}
break;
case DISPLAY_MENU:
if (menu_event.iptkey == IPT_UI_SELECT)
{
break;
case DISPLAY_MENU:
menu::stack_push<submenu>(ui(), container(), submenu::video_options());
ui_globals::reset = true;
}
break;
case CONTROLLER_MENU:
if (menu_event.iptkey == IPT_UI_SELECT)
break;
case CONTROLLER_MENU:
menu::stack_push<submenu>(ui(), container(), submenu::control_options());
break;
case CGI_MENU:
if (menu_event.iptkey == IPT_UI_SELECT)
break;
case INPUTASSIGN_MENU:
menu::stack_push<menu_input_groups>(ui(), container());
break;
case ADVANCED_MENU:
if (menu_event.iptkey == IPT_UI_SELECT)
{
break;
case ADVANCED_MENU:
menu::stack_push<submenu>(ui(), container(), submenu::advanced_options());
ui_globals::reset = true;
}
break;
case PLUGINS_MENU:
if (menu_event.iptkey == IPT_UI_SELECT)
break;
case PLUGINS_MENU:
menu::stack_push<menu_plugins_configure>(ui(), container());
break;
case SAVE_CONFIG:
if (menu_event.iptkey == IPT_UI_SELECT)
break;
case INPUTDEV_MENU:
menu::stack_push<menu_input_devices>(ui(), container());
break;
case SAVE_CONFIG:
ui().save_main_option();
break;
break;
}
}
}
//-------------------------------------------------
// perform our special rendering
//-------------------------------------------------
void menu_simple_game_options::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{
char const *const toptext[] = { _("Settings") };
draw_text_box(
std::begin(toptext), std::end(toptext),
origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(),
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false,
ui().colors().text_color(), UI_GREEN_COLOR, 1.0f);
}
//-------------------------------------------------
// ctor
@ -169,7 +148,6 @@ menu_game_options::menu_game_options(
, m_filter_data(filter_data)
, m_main_filter(filter_data.get_current_filter_type())
{
set_process_flags(PROCESS_LR_REPEAT);
}
//-------------------------------------------------
@ -204,7 +182,7 @@ void menu_game_options::populate(float &customtop, float &custombottom)
// add filter item
uint32_t arrow_flags = get_arrow_flags<uint16_t>(machine_filter::FIRST, machine_filter::LAST, m_main_filter);
machine_filter &active_filter(m_filter_data.get_filter(m_main_filter));
item_append(_("Filter"), active_filter.display_name(), arrow_flags, (void *)(uintptr_t)FILTER_MENU);
item_append(_("System Filter"), active_filter.display_name(), arrow_flags, (void *)(uintptr_t)FILTER_MENU);
// add subitem if the filter wants it
if (active_filter.wants_adjuster())
@ -217,7 +195,7 @@ void menu_game_options::populate(float &customtop, float &custombottom)
// add options items
item_append(_("Customize UI"), 0, (void *)(uintptr_t)CUSTOM_MENU);
item_append(_("Configure Directories"), 0, (void *)(uintptr_t)CONF_DIR);
item_append(_("Configure Folders"), 0, (void *)(uintptr_t)CONF_DIR);
// add the options that don't relate to the UI
menu_simple_game_options::populate(customtop, custombottom);
@ -246,7 +224,7 @@ void menu_game_options::handle_item_event(event const &menu_event)
s_sel[index] = machine_filter::display_name(machine_filter::type(index));
menu::stack_push<menu_selector>(
ui(), container(), std::move(s_sel), m_main_filter,
ui(), container(), _("System Filter"), std::move(s_sel), m_main_filter,
[this] (int selection)
{
m_main_filter = machine_filter::type(selection);

View File

@ -28,7 +28,6 @@ public:
virtual ~menu_simple_game_options() override;
protected:
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
virtual void handle(event const *ev) override;
virtual void populate(float &customtop, float &custombottom) override;
@ -41,9 +40,10 @@ private:
SOUND_MENU,
MISC_MENU,
CONTROLLER_MENU,
CGI_MENU,
INPUTASSIGN_MENU,
ADVANCED_MENU,
PLUGINS_MENU,
INPUTDEV_MENU,
SAVE_CONFIG
};

View File

@ -32,6 +32,7 @@ menu_plugin::menu_plugin(mame_ui_manager &mui, render_container &container) :
menu(mui, container),
m_plugins(mame_machine_manager::instance()->lua()->get_menu())
{
set_heading(_("Plugin Options"));
}
void menu_plugin::populate(float &customtop, float &custombottom)

View File

@ -27,10 +27,12 @@ namespace ui {
menu_selector::menu_selector(
mame_ui_manager &mui,
render_container &container,
std::string &&title,
std::vector<std::string> &&sel,
int initial,
std::function<void (int)> &&handler)
: menu(mui, container)
, m_title(std::move(title))
, m_search()
, m_str_items(std::move(sel))
, m_handler(std::move(handler))
@ -50,30 +52,36 @@ menu_selector::~menu_selector()
void menu_selector::handle(event const *ev)
{
// process the menu
if (ev && ev->itemref)
if (ev)
{
if (ev->iptkey == IPT_UI_SELECT)
switch (ev->iptkey)
{
int selection(-1);
for (size_t idx = 0; (m_str_items.size() > idx) && (0 > selection); ++idx)
if ((void*)&m_str_items[idx] == ev->itemref)
selection = int(unsigned(idx));
case IPT_UI_SELECT:
if (ev->itemref)
{
int selection(-1);
for (size_t idx = 0; (m_str_items.size() > idx) && (0 > selection); ++idx)
if ((void*)&m_str_items[idx] == ev->itemref)
selection = int(unsigned(idx));
m_handler(selection);
m_handler(selection);
stack_pop();
}
break;
stack_pop();
}
else if (ev->iptkey == IPT_SPECIAL)
{
case IPT_SPECIAL:
if (input_character(m_search, ev->unichar, uchar_is_printable))
reset(reset_options::SELECT_FIRST);
}
break;
// escape pressed with non-empty text clears the text
else if (ev->iptkey == IPT_UI_CANCEL && !m_search.empty())
{
m_search.clear();
reset(reset_options::SELECT_FIRST);
case IPT_UI_CANCEL:
if (!m_search.empty())
{
// escape pressed with non-empty search text clears the search text
m_search.clear();
reset(reset_options::SELECT_FIRST);
}
break;
}
}
}
@ -84,12 +92,17 @@ void menu_selector::handle(event const *ev)
void menu_selector::populate(float &customtop, float &custombottom)
{
set_heading(util::string_format(_("menu-selector", "%1$s - Search: %2$s_"), m_title, m_search));
if (!m_search.empty())
{
find_matches(m_search.c_str());
for (int curitem = 0; m_searchlist[curitem]; ++curitem)
int curitem;
for (curitem = 0; m_searchlist[curitem]; ++curitem)
item_append(*m_searchlist[curitem], 0, (void *)m_searchlist[curitem]);
if (!curitem)
item_append(_("menu-selector", "[no matches]"), FLAG_DISABLE, nullptr);
}
else
{
@ -100,10 +113,13 @@ void menu_selector::populate(float &customtop, float &custombottom)
item_append(m_str_items[index], 0, (void *)&m_str_items[index]);
}
if (m_str_items.empty())
item_append(_("menu-selector", "[no choices]"), FLAG_DISABLE, nullptr); // the caller was probably being dumb
}
item_append(menu_item_type::SEPARATOR);
customtop = custombottom = ui().get_line_height() + 3.0f * ui().box_tb_border();
custombottom = ui().get_line_height() + 3.0f * ui().box_tb_border();
m_initial = -1;
}
@ -113,15 +129,8 @@ void menu_selector::populate(float &customtop, float &custombottom)
void menu_selector::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{
std::string tempbuf[1] = { std::string(_("Selection List - Search: ")).append(m_search).append("_") };
draw_text_box(
std::begin(tempbuf), std::end(tempbuf),
origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(),
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false,
ui().colors().text_color(), UI_GREEN_COLOR, 1.0f);
// get the text for 'UI Select'
tempbuf[0] = string_format(_("Double-click or press %1$s to select"), ui().get_general_input_setting(IPT_UI_SELECT));
std::string const tempbuf[] = { util::string_format(_("menu-selector", "Double-click or press %1$s to select"), ui().get_general_input_setting(IPT_UI_SELECT)) };
draw_text_box(
std::begin(tempbuf), std::end(tempbuf),
origx1, origx2, origy2 + ui().box_tb_border(), origy2 + bottom,
@ -137,7 +146,7 @@ void menu_selector::find_matches(const char *str)
{
// allocate memory to track the penalty value
m_ucs_items.reserve(m_str_items.size());
std::vector<double> penalty(VISIBLE_GAMES_IN_SEARCH, 1.0);
std::vector<double> penalty(VISIBLE_SEARCH_ITEMS, 2.0); // impossibly high penalty for unpopulated slots
std::u32string const search(ustr_from_utf8(normalize_unicode(str, unicode_normalization_form::D, true)));
int index = 0;
@ -149,14 +158,14 @@ void menu_selector::find_matches(const char *str)
double const curpenalty(util::edit_distance(search, m_ucs_items[index]));
// insert into the sorted table of matches
for (int matchnum = VISIBLE_GAMES_IN_SEARCH - 1; matchnum >= 0; --matchnum)
for (int matchnum = VISIBLE_SEARCH_ITEMS - 1; matchnum >= 0; --matchnum)
{
// stop if we're worse than the current entry
if (curpenalty >= penalty[matchnum])
break;
// as long as this isn't the last entry, bump this one down
if (matchnum < VISIBLE_GAMES_IN_SEARCH - 1)
if (matchnum < VISIBLE_SEARCH_ITEMS - 1)
{
penalty[matchnum + 1] = penalty[matchnum];
m_searchlist[matchnum + 1] = m_searchlist[matchnum];
@ -166,7 +175,7 @@ void menu_selector::find_matches(const char *str)
penalty[matchnum] = curpenalty;
}
}
(index < VISIBLE_GAMES_IN_SEARCH) ? m_searchlist[index] = nullptr : m_searchlist[VISIBLE_GAMES_IN_SEARCH] = nullptr;
(index < VISIBLE_SEARCH_ITEMS) ? m_searchlist[index] = nullptr : m_searchlist[VISIBLE_SEARCH_ITEMS] = nullptr;
}
} // namespace ui

View File

@ -12,9 +12,12 @@
#pragma once
#include "ui/menu.h"
#include <functional>
#include <string>
#include <vector>
namespace ui {
@ -28,6 +31,7 @@ public:
menu_selector(
mame_ui_manager &mui,
render_container &container,
std::string &&title,
std::vector<std::string> &&sel,
int initial,
std::function<void (int)> &&handler);
@ -38,21 +42,22 @@ protected:
virtual bool custom_ui_cancel() override { return !m_search.empty(); }
private:
enum { VISIBLE_GAMES_IN_SEARCH = 200 };
enum { VISIBLE_SEARCH_ITEMS = 200 };
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle(event const *ev) override;
void find_matches(const char *str);
std::string const m_title;
std::string m_search;
std::vector<std::string> m_str_items;
std::function<void (int)> m_handler;
std::vector<std::u32string> m_ucs_items;
int m_initial;
std::string *m_searchlist[VISIBLE_GAMES_IN_SEARCH + 1];
std::string *m_searchlist[VISIBLE_SEARCH_ITEMS + 1];
};
} // namespace ui
#endif /* MAME_FRONTEND_UI_SELECTOR_H */
#endif // MAME_FRONTEND_UI_SELECTOR_H

View File

@ -438,8 +438,8 @@ void menu_select_game::populate(float &customtop, float &custombottom)
if (stack_has_special_main_menu())
{
item_append(menu_item_type::SEPARATOR, 0);
item_append(_("Configure Options"), 0, (void *)(uintptr_t)CONF_OPTS);
item_append(_("Configure Machine"), 0, (void *)(uintptr_t)CONF_MACHINE);
item_append(_("General Settings"), 0, (void *)(uintptr_t)CONF_OPTS);
item_append(_("System Settings"), 0, (void *)(uintptr_t)CONF_MACHINE);
skip_main_items = 3;
if (m_prev_selected && !have_prev_selected)
@ -1055,7 +1055,7 @@ void menu_select_game::get_selection(ui_software_info const *&software, ui_syste
void menu_select_game::make_topbox_text(std::string &line0, std::string &line1, std::string &line2) const
{
line0 = string_format(_("%1$s %2$s ( %3$d / %4$d machines (%5$d BIOS) )"),
line0 = string_format(_("%1$s %2$s ( %3$d / %4$d systems (%5$d BIOS) )"),
emulator_info::get_appname(),
bare_build_version,
m_available_items,

View File

@ -167,9 +167,6 @@ public:
software_parts(mame_ui_manager &mui, render_container &container, s_parts &&parts, ui_software_info const &ui_info);
virtual ~software_parts() override;
protected:
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
private:
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle(event const *ev) override;
@ -185,9 +182,6 @@ public:
bios_selection(mame_ui_manager &mui, render_container &container, s_bios &&biosname, ui_software_info const &swinfo, bool inlist);
virtual ~bios_selection() override;
protected:
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
private:
bios_selection(mame_ui_manager &mui, render_container &container, s_bios &&biosname, void const *driver, bool software, bool inlist);
@ -263,6 +257,7 @@ menu_select_launch::software_parts::software_parts(mame_ui_manager &mui, render_
, m_uiinfo(ui_info)
, m_parts(std::move(parts))
{
set_heading(_("Select Software Package Part"));
}
//-------------------------------------------------
@ -288,7 +283,6 @@ void menu_select_launch::software_parts::populate(float &customtop, float &custo
item_append(elem->first, elem->second, 0, (void *)&*elem);
item_append(menu_item_type::SEPARATOR);
customtop = ui().get_line_height() + (3.0f * ui().box_tb_border());
}
//-------------------------------------------------
@ -311,20 +305,6 @@ void menu_select_launch::software_parts::handle(event const *ev)
}
}
//-------------------------------------------------
// perform our special rendering
//-------------------------------------------------
void menu_select_launch::software_parts::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{
char const *const text[] = { _("Software part selection:") };
draw_text_box(
std::begin(text), std::end(text),
origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(),
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false,
ui().colors().text_color(), UI_GREEN_COLOR, 1.0f);
}
//-------------------------------------------------
// ctor
@ -347,6 +327,7 @@ menu_select_launch::bios_selection::bios_selection(mame_ui_manager &mui, render_
, m_inlist(inlist)
, m_bios(std::move(biosname))
{
set_heading(_("Select System BIOS"));
}
//-------------------------------------------------
@ -363,11 +344,10 @@ menu_select_launch::bios_selection::~bios_selection()
void menu_select_launch::bios_selection::populate(float &customtop, float &custombottom)
{
for (auto & elem : m_bios)
for (auto &elem : m_bios)
item_append(elem.first, 0, (void *)&elem.first);
item_append(menu_item_type::SEPARATOR);
customtop = ui().get_line_height() + (3.0f * ui().box_tb_border());
}
//-------------------------------------------------
@ -416,20 +396,6 @@ void menu_select_launch::bios_selection::handle(event const *ev)
}
}
//-------------------------------------------------
// perform our special rendering
//-------------------------------------------------
void menu_select_launch::bios_selection::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{
char const *const text[] = { _("BIOS selection:") };
draw_text_box(
std::begin(text), std::end(text),
origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(),
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false,
ui().colors().text_color(), UI_GREEN_COLOR, 1.0f);
}
menu_select_launch::cache::cache(running_machine &machine)
: m_snapx_bitmap(std::make_unique<bitmap_argb32>(0, 0))
@ -712,11 +678,11 @@ void menu_select_launch::custom_render(void *selectedref, float top, float botto
int cloneof = driver_list::non_bios_clone(driver);
if (0 > cloneof)
tempbuf[1] = _("Driver is parent");
tempbuf[1] = _("System is parent");
else if (system)
tempbuf[1] = string_format(_("Driver is clone of: %1$s"), system->parent);
tempbuf[1] = string_format(_("System is clone of: %1$s"), system->parent);
else
tempbuf[1] = string_format(_("Driver is clone of: %1$s"), driver_list::driver(cloneof).type.fullname());
tempbuf[1] = string_format(_("System is clone of: %1$s"), driver_list::driver(cloneof).type.fullname());
// next line is overall driver status
system_flags const &flags(get_system_flags(driver));
@ -869,9 +835,10 @@ void menu_select_launch::inkey_dats()
void menu_select_launch::draw_common_arrow(float origx1, float origy1, float origx2, float origy2, int current, int dmin, int dmax, float title_size)
{
auto line_height = ui().get_line_height();
auto lr_arrow_width = 0.4f * line_height * machine().render().ui_aspect(&container());
auto gutter_width = lr_arrow_width * 1.3f;
float const aspect = machine().render().ui_aspect(&container());
float const line_height = ui().get_line_height();
float const lr_arrow_width = 0.4f * line_height * aspect;
float const gutter_width = 0.5f * line_height * aspect;
// set left-right arrows dimension
float const ar_x0 = 0.5f * (origx2 + origx1) + 0.5f * title_size + gutter_width - lr_arrow_width;
@ -2894,7 +2861,7 @@ void menu_select_launch::general_info(ui_system_info const *system, game_driver
str << driver.type.fullname();
str << "\t\n\n";
util::stream_format(str, _("Romset\t%1$s\n"), driver.name);
util::stream_format(str, _("Short Name\t%1$s\n"), driver.name);
util::stream_format(str, _("Year\t%1$s\n"), driver.year);
util::stream_format(str, _("Manufacturer\t%1$s\n"), driver.manufacturer);
@ -2903,12 +2870,12 @@ void menu_select_launch::general_info(ui_system_info const *system, game_driver
{
util::stream_format(
str,
_("Driver is Clone of\t%1$s\n"),
_("System is Clone of\t%1$s\n"),
system ? std::string_view(system->parent) : std::string_view(driver_list::driver(cloneof).type.fullname()));
}
else
{
str << _("Driver is Parent\t\n");
str << _("System is Parent\t\n");
}
if (flags.has_analog())
@ -3028,12 +2995,12 @@ void menu_select_launch::general_info(ui_system_info const *system, game_driver
else if (flags.imperfect_features() & device_t::feature::TIMING)
str << _("Timing\tImperfect\n");
str << ((flags.machine_flags() & machine_flags::MECHANICAL) ? _("Mechanical Machine\tYes\n") : _("Mechanical Machine\tNo\n"));
str << ((flags.machine_flags() & machine_flags::MECHANICAL) ? _("Mechanical System\tYes\n") : _("Mechanical System\tNo\n"));
str << ((flags.machine_flags() & machine_flags::REQUIRES_ARTWORK) ? _("Requires Artwork\tYes\n") : _("Requires Artwork\tNo\n"));
str << ((flags.machine_flags() & machine_flags::CLICKABLE_ARTWORK) ? _("Requires Clickable Artwork\tYes\n") : _("Requires Clickable Artwork\tNo\n"));
if (flags.machine_flags() & machine_flags::NO_COCKTAIL)
str << _("Support Cocktail\tNo\n");
str << ((flags.machine_flags() & machine_flags::IS_BIOS_ROOT) ? _("Driver is BIOS\tYes\n") : _("Driver is BIOS\tNo\n"));
str << ((flags.machine_flags() & machine_flags::IS_BIOS_ROOT) ? _("System is BIOS\tYes\n") : _("System is BIOS\tNo\n"));
str << ((flags.machine_flags() & machine_flags::SUPPORTS_SAVE) ? _("Support Save\tYes\n") : _("Support Save\tNo\n"));
str << ((flags.machine_flags() & ORIENTATION_SWAP_XY) ? _("Screen Orientation\tVertical\n") : _("Screen Orientation\tHorizontal\n"));
bool found = false;

Some files were not shown because too many files have changed in this diff Show More