-frontend: Refactored menu event handling and fixed a number of issues. (#8777)
* Moved common code for drawing about box, info viewer, and other text box menus to a base class; removed the last of the info viewer logic and the multi-line item hack from the base menu class. * Added previous/next group navigation for general inputs and plugin input selection menus. * Moved message catalog logic to lib/util, allowing osd and emu to use localised messages. * Made the base menu class use the UI manager’s feature for holding session state rather than a static map and mutex. * Improved menu event handling model, and fixed many issues, particularly with menus behaving badly when hidden/shown. * Added better support for menus that don’t participate in the usual menu stack, like the menuless sliders and the save/load state menus. * Made a number of menus refresh state when being shown after being hidden (fixes MT08121 among other issues). * Fixed indication of mounted slot option in the slot option details menu. * Improved appearance of background menus when emulation isn't running - draw all menus in the stack, and darken the background menus to make the edges of the active menu clearer. * Fixed locale issues in -listxml. -debugger: Made GUI debuggers more uniform. * Added new memory view features to Win32 debugger. * Fixed spelling of hexadecimal in Cocoa debugger and added decimal address option. * Fixed duplicate keyboard shortcut in Cocoa debugger (Shift-Cmd-D was both new device window and 64-bit float format). * Made keyboard shortcuts slightly more consistent across debuggers. -plugins: Moved input selection menu and sequence polling code to a common library. Fixed the issue that prevented keyboard inputs being mapped with -steadykey on. -docs: Started adding some documentation for MAME's internal UI, and updated the list of example front-ends. -Regenerated message catalog sources. For translators, the new strings are mostly: * The names of the inputs provided by the OS-dependent layer for things like fullscreen and video features. These show up in the user interface inputs menu. * The names for automatically generated views. These show up in the video options menu - test with a system with a lot of screens to see more variants. * The input macro plugin UI. * A few format strings for analog input assignments. * A few strings for the about box header.
This commit is contained in:
parent
cfffc54b61
commit
d64ea5331b
@ -16,6 +16,10 @@ To set the folders where the data plugin looks for supported files, choose
|
||||
**Configure Directories**, and then choose **DATs**. You can also set the
|
||||
``historypath`` option in your **ui.ini** file.
|
||||
|
||||
Loading large data files like **history.xml** can take quite a while, so please
|
||||
be patient the first time you start MAME after updating or adding new data
|
||||
files.
|
||||
|
||||
The following files are supported:
|
||||
|
||||
history.xml
|
||||
|
@ -436,6 +436,11 @@ ui:get_string_width(str)
|
||||
ui:set_aggressive_input_focus(enable)
|
||||
On some platforms, this controls whether MAME should accept input focus in
|
||||
more situations than when its windows have UI focus.
|
||||
ui:get_general_input_setting(type, [player])
|
||||
Gets a description of the configured input sequence for the specified input
|
||||
type and player suitable for using in prompts. The input type is an
|
||||
enumerated value. The player number is a zero-based index. If the player
|
||||
number is not supplied, it is assumed to be zero.
|
||||
|
||||
Properties
|
||||
^^^^^^^^^^
|
||||
|
@ -59,10 +59,11 @@ and saving/loading save states.
|
||||
Change current UI option setting when an arrow is present on it.
|
||||
**Right Arrow**
|
||||
Change current UI option setting when an arrow is present on it.
|
||||
**Home**
|
||||
Highlight first UI menu option.
|
||||
**End**
|
||||
Select last UI menu option.
|
||||
**Home**/**End**
|
||||
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).
|
||||
**Enter**/**Joystick 1 Button 1**
|
||||
Select currently highlighted UI menu option.
|
||||
**Space**
|
||||
|
@ -1,20 +1,45 @@
|
||||
.. _frontends:
|
||||
|
||||
Frontends
|
||||
=========
|
||||
Front-ends
|
||||
==========
|
||||
|
||||
There are a number of third party tools for MAME to make system and software selection simpler. These tools are called "Frontends", and there are far too many to list conclusively here. Some are free, some are commercial-- caveat emptor. Some older frontends predate the merging of MAME and MESS and do not support the additional console, handheld, etc functionality that MAME inherited from MESS.
|
||||
A number of third party tools for MAME to make system and software selection
|
||||
simpler are available. These tools are called “front-ends”, and there are far
|
||||
too many to list exhaustively here. Some are free, some are commercial –
|
||||
caveat emptor. Some older front-ends predate the merging of MAME and MESS and
|
||||
do not support the additional console, hand-held, and computer functionality
|
||||
inherited from MESS.
|
||||
|
||||
This following list is not an endorsement of any of these frontends by the MAME team, but simply showing a number of commonly used free frontends as a good starting point to begin from.
|
||||
This following list is not an endorsement of any of these front-ends by the MAME
|
||||
team. It simply shows a number of commonly used free front-ends to provide a
|
||||
starting point.
|
||||
|
||||
| QMC2 (multiple platforms)
|
||||
| Download: http://qmc2.batcom-it.net/
|
||||
|
|
||||
| IV/Play (Microsoft Windows)
|
||||
| Download: http://www.mameui.info/
|
||||
|
|
||||
| EmuLoader (Microsoft Windows)
|
||||
| Download: http://emuloader.mameworld.info/
|
||||
|
|
||||
`QMC2 <http://qmc2.batcom-it.net/>`__ (multiple platforms)
|
||||
Provides a graphical interface for configuring many of MAME’s settings and
|
||||
features. Also includes ROM management and media auditing features.
|
||||
Written in C++ using the Qt toolkit, the
|
||||
`source code is on SourceForge <https://sourceforge.net/projects/qmc2/>`__.
|
||||
`Negatron <http://negatron.net/>`__ (multiple platforms)
|
||||
Negatron emphasises features for configuring emulated computers and
|
||||
consoles. Written in Java, the
|
||||
`source code is on GitHub <https://github.com/xinyingho/Negatron>`__.
|
||||
`BletchMAME <https://www.bletchmame.org/>`__ (multiple platforms)
|
||||
BletchMAME takes advantage of MAME’s Lua scripting interface to integrate
|
||||
tightly and effectively replace MAME’s internal user interface. It has
|
||||
many useful features for home computer emulation. Written in C++, the
|
||||
`source code is on GitHub <https://github.com/npwoods/bletchmame>`__.
|
||||
`IV/Play <http://www.mameui.info/>`__ (Microsoft Windows)
|
||||
A simple Windows program for launching systems in MAME. Written in C#, the
|
||||
`souce code is on GitHub <https://github.com/Mataniko/IV-Play>`__.
|
||||
`EmuLoader <http://emuloader.mameworld.info/>`__ (Microsoft Windows)
|
||||
EmuLoader provides a Windows interface for launching systems in multiple
|
||||
emulators, including MAME, Supermodel and DEMUL. Written in Delphi Pascal,
|
||||
the source code is available
|
||||
`on the download page <https://emuloader.mameworld.info/downloads.htm>`__.
|
||||
`Retrofire <https://e2j.net/downloads/>`__ (Japanese, Microsoft Windows)
|
||||
Provides a Japanese-language graphical interface for launching systems or
|
||||
software in MAME.
|
||||
|
||||
The MAME team will not provide support for issues with frontends. For support, we suggest contacting the frontend author or trying any of the popular MAME-friendly forums on the internet.
|
||||
The MAME team will not provide support for issues with front-ends. For support,
|
||||
we suggest contacting the front-end author or asking on one of the popular
|
||||
MAME-friendly forums on the Internet.
|
||||
|
@ -1,16 +1,18 @@
|
||||
Basic MAME Usage and Configuration
|
||||
----------------------------------
|
||||
|
||||
This section describes general usage information about MAME. It is intended to cover aspects of using and configuring MAME that are common across all operating systems. For additional OS-specific options, please see the separate documentation for your platform of choice.
|
||||
This section describes general usage information about MAME. It is intended to
|
||||
cover aspects of using and configuring MAME that are common across all operating
|
||||
systems. For additional OS-specific options, please see the separate
|
||||
documentation for your platform of choice.
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
|
||||
usingmame
|
||||
defaultkeys
|
||||
mamemenus
|
||||
frontends
|
||||
aboutromsets
|
||||
commonissues
|
||||
|
||||
:titlesonly:
|
||||
|
||||
usingmame
|
||||
ui
|
||||
defaultkeys
|
||||
mamemenus
|
||||
frontends
|
||||
aboutromsets
|
||||
commonissues
|
||||
|
137
docs/source/usingmame/ui.rst
Normal file
137
docs/source/usingmame/ui.rst
Normal file
@ -0,0 +1,137 @@
|
||||
.. _ui:
|
||||
|
||||
MAME’s User Interface
|
||||
=====================
|
||||
|
||||
.. contents:: :local:
|
||||
|
||||
|
||||
.. _ui-intro:
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
MAME provides a simple user interface for selecting a system and software to
|
||||
run and changing settings while running an emulated system. MAME’s user
|
||||
interface is designed to be usable with a keyboard, game controller, or pointing
|
||||
device, but will require a keyboard for initial configuration.
|
||||
|
||||
The default settings for the most important controls to know when running an
|
||||
emulated system, and the settings they correspond to in case you want to change
|
||||
them, are as follows:
|
||||
|
||||
Scroll Lock, or Forward Delete on macOS (UI Toggle)
|
||||
For emulated systems with keyboard inputs, enable or disable UI controls.
|
||||
(MAME starts with UI controls disabled for systems with keyboard inputs
|
||||
unless the :ref:`ui_active option <mame-commandline-uiactive>` is on.)
|
||||
Tab (Config Menu)
|
||||
Show or hide the menu during emulation.
|
||||
Escape (UI Cancel)
|
||||
Return to the system selection menu, or exit if MAME was started with a
|
||||
system specified (from the command line or using an
|
||||
:ref:`external front-end <frontends>`).
|
||||
|
||||
|
||||
.. _ui-menus:
|
||||
|
||||
Navigating menus
|
||||
----------------
|
||||
|
||||
By default, MAME menus can be navigated using the keyboard cursor keys. All
|
||||
the UI controls can be changed by going to the **General Inputs** menu and then
|
||||
selecting **User Interface**. The default keyboard controls on a US ANSI QWERTY
|
||||
layout keyboard, and the settings they correspond to, are as follows:
|
||||
|
||||
Up Arrow (UI Up)
|
||||
Highlight the previous menu item, or the last item if the first item is
|
||||
highlighted.
|
||||
Down Arrow (UI Down)
|
||||
Highlight the next menu item, or the first item if the last item is
|
||||
highlighted.
|
||||
Left Arrow (UI Left)
|
||||
For menu items that are adjustable settings, reduce the value or select the
|
||||
previous setting (these menu items show left- and right-facing triangles
|
||||
beside the value).
|
||||
Right Arrow (UI Left)
|
||||
For menu items that are adjustable settings, increase the value or select
|
||||
the next setting (these menu items show left- and right-facing triangles
|
||||
beside the value).
|
||||
Return/Enter keypad Enter (UI Select)
|
||||
Select the highlighted menu item.
|
||||
Forward Delete, or Fn+Delete on some compact keyboards (UI Clear)
|
||||
Clear setting or reset to default value.
|
||||
Escape (UI Cancel)
|
||||
Close the menu, returning to the previous menu, or returning to the
|
||||
emulated machine for the main menu (there’s 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)
|
||||
Highlight the last menu item and scroll to the bottom of the menu.
|
||||
Page Up (UI Page Up)
|
||||
Scroll the menu up by one screen.
|
||||
Page Down (UI Page Down)
|
||||
Scroll the menu down by one screen.
|
||||
[ (UI Previous Group)
|
||||
Move to the previous group of items (not used by all menus).
|
||||
] (UI Next Group)
|
||||
Move to the next group of items (not used by all menus).
|
||||
|
||||
|
||||
.. _ui-menus-gamectrl:
|
||||
|
||||
Using a game controller
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
MAME supports navigating menus with a game controller or joystick, but only the
|
||||
most important UI controls have joystick assignments by default:
|
||||
|
||||
* Move the first joystick up or down in the Y axis to highlight the previous or
|
||||
next menu item.
|
||||
* Move the first joystick left or right in the X axis to adjust settings.
|
||||
* Press the first button on the first joystick to select the highlighted menu
|
||||
item.
|
||||
|
||||
If you want to be able to use MAME with a game controller without needing a
|
||||
keyboard, you’ll need to assign joystick buttons (or combinations of buttons) to
|
||||
these controls as well:
|
||||
|
||||
* **Config Menu** to show or dismiss the menu during emulation
|
||||
* **UI Cancel** to close menus, return to the system selection menu, or exit
|
||||
MAME
|
||||
* **UI Clear** isn’t essential for basic emulation, but it’s used to clear or
|
||||
reset some settings to defaults
|
||||
* **UI Home**, **UI End**, **UI Page Up**, **UI Page Down**, **UI Previous
|
||||
Group** and **UI Next Group** are not essential, but make navigating some
|
||||
menus easier
|
||||
|
||||
If you’re not using an external front-end to launch systems in MAME, you should
|
||||
assign joystick buttons (or combinations of buttons) to these controls to make
|
||||
full use of the system and software selection menus:
|
||||
|
||||
* **UI Focus Next**/**UI Focus Previous** to navigate between panes
|
||||
* **UI Add Remove favorite**, **UI Export List** and **UI Audit Media** if you
|
||||
want access to these features without using a keyboard or pointing device
|
||||
|
||||
|
||||
.. _ui-menus-mouse:
|
||||
|
||||
Using a mouse or trackball
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
MAME supports navigating menus using a mouse or trackball that works as a system
|
||||
pointing device:
|
||||
|
||||
* Click menu items to highlight them.
|
||||
* Double-click menu items to select them.
|
||||
* Click the left- or right-pointing triangle to adjust settings.
|
||||
* For menus with too many items to fit on the screen, click the upward- or
|
||||
downward-pointing triangle at the top or bottom to scroll up or down by one
|
||||
screen at a time.
|
||||
* Use vertical scrolling gestures to scroll menus or text boxes with too many
|
||||
items or lines to fit on the screen.
|
||||
* Click toolbar items to select them, or hover over them to see a description.
|
||||
|
||||
If you have enough additional mouse buttons, you may want to assign button
|
||||
combinations to the **Config Menu**, **Pause** and/or **UI Cancel** inputs to
|
||||
make it possible to use MAME without a keyboard.
|
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
@ -1,5 +1,8 @@
|
||||
local lib = {}
|
||||
|
||||
-- Common UI helper library
|
||||
local commonui
|
||||
|
||||
-- Set of all menus
|
||||
local MENU_TYPES = { MAIN = 0, EDIT = 1, ADD = 2, BUTTON = 3 }
|
||||
|
||||
@ -27,14 +30,17 @@ local configure_menu_active = false
|
||||
-- Saved selection on configure menu (to restore after button menu is dismissed)
|
||||
local configure_selection_save
|
||||
|
||||
-- Helper for polling for hotkeys
|
||||
local hotkey_poller
|
||||
|
||||
-- Button being created/edited
|
||||
local current_button = {}
|
||||
|
||||
-- Initial button to select when opening buttons menu
|
||||
local initial_input
|
||||
|
||||
-- Inputs that can be autofired (to list in BUTTON menu)
|
||||
local inputs
|
||||
-- Handler for BUTTON menu
|
||||
local input_menu
|
||||
|
||||
-- Returns the section (from MENU_SECTIONS) and the index within that section
|
||||
local function menu_section(index)
|
||||
@ -59,19 +65,14 @@ local function is_button_complete(button)
|
||||
return button.port and button.field and button.key and button.on_frames and button.off_frames and button.button and button.counter
|
||||
end
|
||||
|
||||
local function is_supported_input(ioport_field)
|
||||
-- IPT_BUTTON1 through IPT_BUTTON16 in ioport_type enum (ioport.h)
|
||||
return ioport_field.type >= 64 and ioport_field.type <= 79
|
||||
end
|
||||
|
||||
-- Main menu
|
||||
|
||||
local function populate_main_menu(buttons)
|
||||
local ioport = manager.machine.ioport
|
||||
local input = manager.machine.input
|
||||
local menu = {}
|
||||
menu[#menu + 1] = {_('Autofire buttons'), '', 'off'}
|
||||
menu[#menu + 1] = {string.format(_('Press %s to delete'), input:seq_name(ioport:type_seq(ioport:token_to_input_type('UI_CLEAR')))), '', 'off'}
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Autofire buttons'), '', 'off'}
|
||||
menu[#menu + 1] = {string.format(_p('plugin-autofire', 'Press %s to delete'), manager.ui:get_general_input_setting(ioport:token_to_input_type('UI_CLEAR'))), '', 'off'}
|
||||
menu[#menu + 1] = {'---', '', ''}
|
||||
header_height = #menu
|
||||
|
||||
@ -82,22 +83,26 @@ local function populate_main_menu(buttons)
|
||||
freq = 1 / screen.frame_period
|
||||
end
|
||||
|
||||
for index, button in ipairs(buttons) do
|
||||
-- Round rate to two decimal places
|
||||
local rate = freq / (button.on_frames + button.off_frames)
|
||||
rate = math.floor(rate * 100) / 100
|
||||
local text = string.format(_('%s [%g Hz]'), _p('input-name', button.button.name), rate)
|
||||
local subtext = input:seq_name(button.key)
|
||||
menu[#menu + 1] = {text, subtext, ''}
|
||||
if index == initial_button then
|
||||
main_selection_save = #menu
|
||||
if #buttons > 0 then
|
||||
for index, button in ipairs(buttons) do
|
||||
-- Round rate to two decimal places
|
||||
local rate = freq / (button.on_frames + button.off_frames)
|
||||
rate = math.floor(rate * 100) / 100
|
||||
local text = string.format(_p('plugin-autofire', '%s [%g Hz]'), _p('input-name', button.button.name), rate)
|
||||
local subtext = input:seq_name(button.key)
|
||||
menu[#menu + 1] = {text, subtext, ''}
|
||||
if index == initial_button then
|
||||
main_selection_save = #menu
|
||||
end
|
||||
end
|
||||
else
|
||||
menu[#menu + 1] = {_p('plugin-autofire', '[no autofire buttons]'), '', 'off'}
|
||||
end
|
||||
initial_button = nil
|
||||
content_height = #menu
|
||||
|
||||
menu[#menu + 1] = {'---', '', ''}
|
||||
menu[#menu + 1] = {_('Add autofire button'), '', ''}
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Add autofire button'), '', ''}
|
||||
|
||||
local selection = main_selection_save
|
||||
main_selection_save = nil
|
||||
@ -134,67 +139,53 @@ end
|
||||
-- Add/edit menus (mostly identical)
|
||||
|
||||
local function populate_configure_menu(menu)
|
||||
local button_name = current_button.button and _p('input-name', current_button.button.name) or _('NOT SET')
|
||||
local key_name = current_button.key and manager.machine.input:seq_name(current_button.key) or _('NOT SET')
|
||||
menu[#menu + 1] = {_('Input'), button_name, ''}
|
||||
local button_name = current_button.button and _p('input-name', current_button.button.name) or _p('plugin-autofire', '[not set]')
|
||||
local key_name = current_button.key and manager.machine.input:seq_name(current_button.key) or _p('plugin-autofire', '[not set]')
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Input'), button_name, ''}
|
||||
if not (configure_menu_active or configure_selection_save) then
|
||||
configure_selection_save = #menu
|
||||
end
|
||||
menu[#menu + 1] = {_('Hotkey'), key_name, ''}
|
||||
menu[#menu + 1] = {_('On frames'), current_button.on_frames, current_button.on_frames > 1 and 'lr' or 'r'}
|
||||
menu[#menu + 1] = {_('Off frames'), current_button.off_frames, current_button.off_frames > 1 and 'lr' or 'r'}
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Hotkey'), key_name, hotkey_poller and 'lr' or ''}
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'On frames'), current_button.on_frames, current_button.on_frames > 1 and 'lr' or 'r'}
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Off frames'), current_button.off_frames, current_button.off_frames > 1 and 'lr' or 'r'}
|
||||
configure_menu_active = true
|
||||
end
|
||||
|
||||
-- Borrowed from the cheat plugin
|
||||
local function poll_for_hotkey()
|
||||
local input = manager.machine.input
|
||||
local poller = input:switch_sequence_poller()
|
||||
manager.machine:popmessage(_('Press button for hotkey or wait to leave unchanged'))
|
||||
manager.machine.video:frame_update()
|
||||
poller:start()
|
||||
local time = os.clock()
|
||||
local clearmsg = true
|
||||
while (not poller:poll()) and (poller.modified or (os.clock() < time + 1)) do
|
||||
if poller.modified then
|
||||
if not poller.valid then
|
||||
manager.machine:popmessage(_('Invalid sequence entered'))
|
||||
clearmsg = false
|
||||
break
|
||||
end
|
||||
manager.machine:popmessage(input:seq_name(poller.sequence))
|
||||
manager.machine.video:frame_update()
|
||||
end
|
||||
end
|
||||
if clearmsg then
|
||||
manager.machine:popmessage()
|
||||
end
|
||||
return poller.valid and poller.sequence or nil
|
||||
end
|
||||
|
||||
local function handle_configure_menu(index, event)
|
||||
if hotkey_poller then
|
||||
-- special handling for polling for hotkey
|
||||
if hotkey_poller:poll() then
|
||||
if hotkey_poller.sequence then
|
||||
current_button.key = hotkey_poller.sequence
|
||||
end
|
||||
hotkey_poller = nil
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
if index == 1 then
|
||||
-- Input
|
||||
if event == 'select' then
|
||||
configure_selection_save = header_height + index
|
||||
table.insert(menu_stack, MENU_TYPES.BUTTON)
|
||||
if current_button.port and current_button.field then
|
||||
initial_input = {port_name = current_button.port, ioport_field = current_button.button}
|
||||
initial_input = current_button.button
|
||||
end
|
||||
return true
|
||||
end
|
||||
elseif index == 2 then
|
||||
-- Hotkey
|
||||
if event == 'select' then
|
||||
local keycode = poll_for_hotkey()
|
||||
if keycode then
|
||||
current_button.key = keycode
|
||||
return true
|
||||
if not commonui then
|
||||
commonui = require('commonui')
|
||||
end
|
||||
hotkey_poller = commonui.switch_polling_helper()
|
||||
return true
|
||||
end
|
||||
elseif index == 3 then
|
||||
-- On frames
|
||||
manager.machine:popmessage(_('Number of frames button will be pressed'))
|
||||
manager.machine:popmessage(_p('plugin-autofire', 'Number of frames button will be pressed'))
|
||||
if event == 'left' then
|
||||
current_button.on_frames = current_button.on_frames - 1
|
||||
return true
|
||||
@ -207,7 +198,7 @@ local function handle_configure_menu(index, event)
|
||||
end
|
||||
elseif index == 4 then
|
||||
-- Off frames
|
||||
manager.machine:popmessage(_('Number of frames button will be released'))
|
||||
manager.machine:popmessage(_p('plugin-autofire', 'Number of frames button will be released'))
|
||||
if event == 'left' then
|
||||
current_button.off_frames = current_button.off_frames - 1
|
||||
return true
|
||||
@ -224,7 +215,7 @@ end
|
||||
|
||||
local function populate_edit_menu()
|
||||
local menu = {}
|
||||
menu[#menu + 1] = {_('Edit autofire button'), '', 'off'}
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Edit autofire button'), '', 'off'}
|
||||
menu[#menu + 1] = {'---', '', ''}
|
||||
header_height = #menu
|
||||
|
||||
@ -232,17 +223,20 @@ local function populate_edit_menu()
|
||||
content_height = #menu
|
||||
|
||||
menu[#menu + 1] = {'---', '', ''}
|
||||
menu[#menu + 1] = {_('Done'), '', ''}
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Done'), '', ''}
|
||||
|
||||
local selection = configure_selection_save
|
||||
configure_selection_save = nil
|
||||
return menu, selection, 'lrrepeat'
|
||||
if hotkey_poller then
|
||||
return hotkey_poller:overlay(menu, selection, 'lrrepeat')
|
||||
else
|
||||
return menu, selection, 'lrrepeat'
|
||||
end
|
||||
end
|
||||
|
||||
local function handle_edit_menu(index, event, buttons)
|
||||
local section, adjusted_index = menu_section(index)
|
||||
if ((section == MENU_SECTIONS.FOOTER) and (event == 'select')) or (event == 'cancel') then
|
||||
inputs = nil
|
||||
configure_menu_active = false
|
||||
table.remove(menu_stack)
|
||||
return true
|
||||
@ -254,7 +248,7 @@ end
|
||||
|
||||
local function populate_add_menu()
|
||||
local menu = {}
|
||||
menu[#menu + 1] = {_('Add autofire button'), '', 'off'}
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Add autofire button'), '', 'off'}
|
||||
menu[#menu + 1] = {'---', '', ''}
|
||||
header_height = #menu
|
||||
|
||||
@ -263,20 +257,23 @@ local function populate_add_menu()
|
||||
|
||||
menu[#menu + 1] = {'---', '', ''}
|
||||
if is_button_complete(current_button) then
|
||||
menu[#menu + 1] = {_('Create'), '', ''}
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Create'), '', ''}
|
||||
else
|
||||
menu[#menu + 1] = {_('Cancel'), '', ''}
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Cancel'), '', ''}
|
||||
end
|
||||
|
||||
local selection = configure_selection_save
|
||||
configure_selection_save = nil
|
||||
return menu, selection, 'lrrepeat'
|
||||
if hotkey_poller then
|
||||
return hotkey_poller:overlay(menu, selection, 'lrrepeat')
|
||||
else
|
||||
return menu, selection, 'lrrepeat'
|
||||
end
|
||||
end
|
||||
|
||||
local function handle_add_menu(index, event, buttons)
|
||||
local section, adjusted_index = menu_section(index)
|
||||
if ((section == MENU_SECTIONS.FOOTER) and (event == 'select')) or (event == 'cancel') then
|
||||
inputs = nil
|
||||
configure_menu_active = false
|
||||
table.remove(menu_stack)
|
||||
if is_button_complete(current_button) and (event == 'select') then
|
||||
@ -293,103 +290,31 @@ end
|
||||
-- Button selection menu
|
||||
|
||||
local function populate_button_menu()
|
||||
local ioport = manager.machine.ioport
|
||||
menu = {}
|
||||
menu[#menu + 1] = {_('Select an input for autofire'), '', 'off'}
|
||||
menu[#menu + 1] = {'---', '', ''}
|
||||
header_height = #menu
|
||||
|
||||
if not inputs then
|
||||
inputs = {}
|
||||
|
||||
for port_key, port in pairs(ioport.ports) do
|
||||
for field_key, field in pairs(port.fields) do
|
||||
if is_supported_input(field) then
|
||||
inputs[#inputs + 1] = {
|
||||
port_name = port_key,
|
||||
field_name = field_key,
|
||||
ioport_field = field
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function compare(x, y)
|
||||
if x.ioport_field.device.tag < y.ioport_field.device.tag then
|
||||
return true
|
||||
elseif x.ioport_field.device.tag > y.ioport_field.device.tag then
|
||||
return false
|
||||
end
|
||||
groupx = ioport:type_group(x.ioport_field.type, x.ioport_field.player)
|
||||
groupy = ioport:type_group(y.ioport_field.type, y.ioport_field.player)
|
||||
if groupx < groupy then
|
||||
return true
|
||||
elseif groupx > groupy then
|
||||
return false
|
||||
elseif x.ioport_field.type < y.ioport_field.type then
|
||||
return true
|
||||
elseif x.ioport_field.type > y.ioport_field.type then
|
||||
return false
|
||||
else
|
||||
return x.ioport_field.name < y.ioport_field.name
|
||||
end
|
||||
end
|
||||
table.sort(inputs, compare)
|
||||
|
||||
local i = 1
|
||||
local prev
|
||||
while i <= #inputs do
|
||||
local current = inputs[i]
|
||||
if (not prev) or (prev.ioport_field.device.tag ~= current.ioport_field.device.tag) then
|
||||
table.insert(inputs, i, false)
|
||||
i = i + 2
|
||||
else
|
||||
i = i + 1
|
||||
end
|
||||
prev = current
|
||||
end
|
||||
local function is_supported_input(ioport_field)
|
||||
-- IPT_BUTTON1 through IPT_BUTTON16 in ioport_type enum (ioport.h)
|
||||
return ioport_field.type >= 64 and ioport_field.type <= 79
|
||||
end
|
||||
|
||||
local selection = header_height + 1
|
||||
for i, input in ipairs(inputs) do
|
||||
if input then
|
||||
menu[header_height + i] = { _p('input-name', input.ioport_field.name), '', '' }
|
||||
if initial_input and (initial_input.port_name == input.port_name) and (initial_input.ioport_field.mask == input.ioport_field.mask) and (initial_input.ioport_field.type == input.ioport_field.type) then
|
||||
selection = header_height + i
|
||||
initial_input = nil
|
||||
end
|
||||
else
|
||||
local device = inputs[i + 1].ioport_field.device
|
||||
if device.owner then
|
||||
menu[header_height + i] = {string.format(_('%s [root%s]'), device.name, device.tag), '', 'heading'}
|
||||
else
|
||||
menu[header_height + i] = {string.format(_('[root%s]'), device.tag), '', 'heading'}
|
||||
end
|
||||
local function action(field)
|
||||
if field then
|
||||
current_button.port = field.port.tag
|
||||
current_button.field = field.name
|
||||
current_button.button = field
|
||||
end
|
||||
initial_input = nil
|
||||
input_menu = nil
|
||||
table.remove(menu_stack)
|
||||
end
|
||||
content_height = #menu
|
||||
initial_input = nil
|
||||
|
||||
menu[#menu + 1] = {'---', '', ''}
|
||||
menu[#menu + 1] = {_('Cancel'), '', ''}
|
||||
|
||||
return menu, selection
|
||||
if not commonui then
|
||||
commonui = require('commonui')
|
||||
end
|
||||
input_menu = commonui.input_selection_menu(action, _p('plugin-autofire', 'Select an input for autofire'), is_supported_input)
|
||||
return input_menu:populate(initial_input)
|
||||
end
|
||||
|
||||
local function handle_button_menu(index, event)
|
||||
local section, adjusted_index = menu_section(index)
|
||||
if ((section == MENU_SECTIONS.FOOTER) and (event == 'select')) or (event == 'cancel') then
|
||||
table.remove(menu_stack)
|
||||
return true
|
||||
elseif (section == MENU_SECTIONS.CONTENT) and (event == 'select') then
|
||||
local selected_input = inputs[adjusted_index]
|
||||
current_button.port = selected_input.port_name
|
||||
current_button.field = selected_input.field_name
|
||||
current_button.button = selected_input.ioport_field
|
||||
table.remove(menu_stack)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
return input_menu:handle(index, event)
|
||||
end
|
||||
|
||||
function lib:init_menu(buttons)
|
||||
@ -397,7 +322,7 @@ function lib:init_menu(buttons)
|
||||
content_height = 0
|
||||
menu_stack = { MENU_TYPES.MAIN }
|
||||
current_button = {}
|
||||
inputs = nil
|
||||
input_menu = nil
|
||||
end
|
||||
|
||||
function lib:populate_menu(buttons)
|
||||
|
@ -100,14 +100,14 @@ function autofire.startplugin()
|
||||
if menu_handler then
|
||||
return menu_handler:populate_menu(buttons)
|
||||
else
|
||||
return {{_('Failed to load autofire menu'), '', ''}}
|
||||
return {{_p('plugin-autofire', 'Failed to load autofire menu'), '', 'off'}}
|
||||
end
|
||||
end
|
||||
|
||||
emu.register_frame_done(process_frame)
|
||||
emu.register_start(load_settings)
|
||||
emu.register_stop(save_settings)
|
||||
emu.register_menu(menu_callback, menu_populate, _('Autofire'))
|
||||
emu.register_menu(menu_callback, menu_populate, _p('plugin-autofire', 'Autofire'))
|
||||
end
|
||||
|
||||
return exports
|
||||
|
@ -597,58 +597,56 @@ function cheat.startplugin()
|
||||
|
||||
local hotkeymenu = false
|
||||
local hotkeylist = {}
|
||||
local commonui
|
||||
local poller
|
||||
|
||||
local function menu_populate()
|
||||
local menu = {}
|
||||
if hotkeymenu then
|
||||
local ioport = manager.machine.ioport
|
||||
local input = manager.machine.input
|
||||
|
||||
menu[1] = {_("Select cheat to set hotkey"), "", "off"}
|
||||
menu[2] = {string.format(_("Press %s to clear hotkey"), input:seq_name(ioport:type_seq(ioport:token_to_input_type("UI_CLEAR")))), "", "off"}
|
||||
menu[2] = {string.format(_("Press %s to clear hotkey"), manager.ui:get_general_input_setting(ioport:token_to_input_type("UI_CLEAR"))), "", "off"}
|
||||
menu[3] = {"---", "", "off"}
|
||||
hotkeylist = {}
|
||||
|
||||
local function hkcbfunc(cheat, event)
|
||||
if event == "clear" then
|
||||
cheat.hotkeys = nil
|
||||
return
|
||||
end
|
||||
|
||||
local poller = input:switch_sequence_poller()
|
||||
manager.machine:popmessage(_("Press button for hotkey or wait to leave unchanged"))
|
||||
manager.machine.video:frame_update()
|
||||
poller:start()
|
||||
local time = os.clock()
|
||||
local clearmsg = true
|
||||
while (not poller:poll()) and (poller.modified or (os.clock() < time + 1)) do
|
||||
if poller.modified then
|
||||
if not poller.valid then
|
||||
manager.machine:popmessage(_("Invalid sequence entered"))
|
||||
clearmsg = false
|
||||
break
|
||||
if poller then
|
||||
if poller:poll() then
|
||||
if poller.sequence then
|
||||
cheat.hotkeys = { pressed = false, keys = poller.sequence }
|
||||
end
|
||||
manager.machine:popmessage(input:seq_name(poller.sequence))
|
||||
manager.machine.video:frame_update()
|
||||
poller = nil
|
||||
return true
|
||||
end
|
||||
elseif event == "clear" then
|
||||
cheat.hotkeys = nil
|
||||
return true
|
||||
elseif event == "select" then
|
||||
if not commonui then
|
||||
commonui = require('commonui')
|
||||
end
|
||||
poller = commonui.switch_polling_helper()
|
||||
return true
|
||||
end
|
||||
if poller.modified and poller.valid then
|
||||
cheat.hotkeys = { pressed = false, keys = poller.sequence }
|
||||
end
|
||||
if clearmsg then
|
||||
manager.machine:popmessage()
|
||||
end
|
||||
manager.machine.video:frame_update()
|
||||
return false
|
||||
end
|
||||
|
||||
for num, cheat in ipairs(cheats) do
|
||||
if cheat.script then
|
||||
menu[#menu + 1] = {cheat.desc, cheat.hotkeys and input:seq_name(cheat.hotkeys.keys) or _("None"), ""}
|
||||
local setting = cheat.hotkeys and input:seq_name(cheat.hotkeys.keys) or _("None")
|
||||
menu[#menu + 1] = {cheat.desc, setting, ""}
|
||||
hotkeylist[#hotkeylist + 1] = function(event) return hkcbfunc(cheat, event) end
|
||||
end
|
||||
end
|
||||
menu[#menu + 1] = {"---", "", ""}
|
||||
menu[#menu + 1] = {_("Done"), "", ""}
|
||||
return menu
|
||||
if poller then
|
||||
return poller:overlay(menu)
|
||||
else
|
||||
return menu
|
||||
end
|
||||
end
|
||||
for num, cheat in ipairs(cheats) do
|
||||
menu[num] = {}
|
||||
@ -703,7 +701,10 @@ function cheat.startplugin()
|
||||
local function menu_callback(index, event)
|
||||
manager.machine:popmessage()
|
||||
if hotkeymenu then
|
||||
if event == "select" or event == "clear" then
|
||||
if event == "cancel" then
|
||||
hotkeymenu = false
|
||||
return true
|
||||
else
|
||||
index = index - 3
|
||||
if index >= 1 and index <= #hotkeylist then
|
||||
hotkeylist[index](event)
|
||||
@ -712,9 +713,6 @@ function cheat.startplugin()
|
||||
hotkeymenu = false
|
||||
return true
|
||||
end
|
||||
elseif event == "cancel" then
|
||||
hotkeymenu = false
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
214
plugins/commonui/init.lua
Normal file
214
plugins/commonui/init.lua
Normal file
@ -0,0 +1,214 @@
|
||||
-- license:BSD-3-Clause
|
||||
-- copyright-holders:Vas Crabb
|
||||
local exports = {
|
||||
name = 'commonui',
|
||||
version = '0.0.1',
|
||||
description = 'Common plugin UI helpers',
|
||||
license = 'BSD-3-Clause',
|
||||
author = { name = 'Vas Crabb' } }
|
||||
|
||||
|
||||
local commonui = exports
|
||||
|
||||
|
||||
function commonui.input_selection_menu(action, title, filter)
|
||||
menu = { }
|
||||
|
||||
local choices
|
||||
local index_first_choice
|
||||
local index_cancel
|
||||
|
||||
local function populate_choices()
|
||||
local ioport = manager.machine.ioport
|
||||
|
||||
local function compare(a, b)
|
||||
if a.device.tag < b.device.tag then
|
||||
return true
|
||||
elseif a.device.tag > b.device.tag then
|
||||
return false
|
||||
end
|
||||
groupa = ioport:type_group(a.type, a.player)
|
||||
groupb = ioport:type_group(b.type, b.player)
|
||||
if groupa < groupb then
|
||||
return true
|
||||
elseif groupa > groupb then
|
||||
return false
|
||||
elseif a.type < b.type then
|
||||
return true
|
||||
elseif a.type > b.type then
|
||||
return false
|
||||
else
|
||||
return a.name < b.name
|
||||
end
|
||||
end
|
||||
|
||||
choices = { }
|
||||
for tag, port in pairs(manager.machine.ioport.ports) do
|
||||
for name, field in pairs(port.fields) do
|
||||
if (not filter) or filter(field) then
|
||||
table.insert(choices, field)
|
||||
end
|
||||
end
|
||||
end
|
||||
table.sort(choices, compare)
|
||||
|
||||
local index = 1
|
||||
local prev
|
||||
while index <= #choices do
|
||||
local current = choices[index]
|
||||
if (not prev) or (prev.device.tag ~= current.device.tag) then
|
||||
table.insert(choices, index, false)
|
||||
index = index + 2
|
||||
else
|
||||
index = index + 1
|
||||
end
|
||||
prev = current
|
||||
end
|
||||
end
|
||||
|
||||
function menu:populate(initial_selection)
|
||||
if not choices then
|
||||
populate_choices()
|
||||
end
|
||||
|
||||
local items = { }
|
||||
|
||||
if title then
|
||||
table.insert(items, { title, '', 'off' })
|
||||
table.insert(items, { '---', '', '' })
|
||||
end
|
||||
|
||||
index_first_choice = #items + 1
|
||||
local selection = index_first_choice
|
||||
for index, field in ipairs(choices) do
|
||||
if field then
|
||||
table.insert(items, { _p('input-name', field.name), '', '' })
|
||||
if initial_selection and (field.port.tag == initial_selection.port.tag) and (field.mask == initial_selection.mask) and (field.type == initial_selection.type) then
|
||||
selection = #items
|
||||
initial_selection = nil
|
||||
end
|
||||
else
|
||||
local device = choices[index + 1].device
|
||||
if device.owner then
|
||||
table.insert(items, { string.format(_p('plugin-commonui', '%s [root%s]'), device.name, device.tag), '', 'heading' })
|
||||
else
|
||||
table.insert(items, { string.format(_p('plugin-commonui', '[root%s]'), device.tag), '', 'heading' })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(items, { '---', '', '' })
|
||||
table.insert(items, { _p('plugin-commonui', 'Cancel'), '', '' })
|
||||
index_cancel = #items
|
||||
|
||||
return items, selection
|
||||
end
|
||||
|
||||
function menu:handle(index, event)
|
||||
local selection
|
||||
if (event == 'cancel') or ((index == input_item_cancel) and (event == 'select')) then
|
||||
action(nil)
|
||||
return true
|
||||
elseif event == 'select' then
|
||||
local field = choices[index - index_first_choice + 1]
|
||||
if field then
|
||||
action(field)
|
||||
return true
|
||||
end
|
||||
elseif event == 'prevgroup' then
|
||||
local found_break = false
|
||||
while (index > index_first_choice) and (not selection) do
|
||||
index = index - 1
|
||||
if not choices[index - index_first_choice + 1] then
|
||||
if found_break then
|
||||
selection = index + 1
|
||||
else
|
||||
found_break = true
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif event == 'nextgroup' then
|
||||
while ((index - index_first_choice + 2) < #choices) and (not selection) do
|
||||
index = index + 1
|
||||
if not choices[index - index_first_choice + 1] then
|
||||
selection = index + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
return false, selection
|
||||
end
|
||||
|
||||
return menu
|
||||
end
|
||||
|
||||
|
||||
function commonui.switch_polling_helper(starting_sequence)
|
||||
helper = { }
|
||||
|
||||
local machine = manager.machine
|
||||
local cancel = machine.ioport:token_to_input_type('UI_CANCEL')
|
||||
local cancel_prompt = manager.ui:get_general_input_setting(cancel)
|
||||
local input = machine.input
|
||||
local uiinput = machine.uiinput
|
||||
local poller = input:switch_sequence_poller()
|
||||
local modified_ticks = 0
|
||||
|
||||
if starting_sequence then
|
||||
poller:start(starting_sequence)
|
||||
else
|
||||
poller:start()
|
||||
end
|
||||
|
||||
function helper:overlay(items, selection, flags)
|
||||
if flags then
|
||||
flags = flags .. " nokeys"
|
||||
else
|
||||
flags = "nokeys"
|
||||
end
|
||||
return items, selection, flags
|
||||
end
|
||||
|
||||
function helper:poll()
|
||||
-- prevent race condition between uiinput:pressed() and poll()
|
||||
if (modified_ticks == 0) and poller.modified then
|
||||
modified_ticks = emu.osd_ticks()
|
||||
end
|
||||
|
||||
if uiinput:pressed(cancel) then
|
||||
-- UI_CANCEL pressed, abort
|
||||
machine:popmessage()
|
||||
if (not poller.modified) or (modified_ticks == emu.osd_ticks()) then
|
||||
-- cancelled immediately
|
||||
self.sequence = nil
|
||||
return true -- TODO: communicate this better?
|
||||
else
|
||||
-- entered something before cancelling
|
||||
self.sequence = nil
|
||||
return true
|
||||
end
|
||||
elseif poller:poll() then
|
||||
if poller.valid then
|
||||
-- valid sequence entered
|
||||
machine:popmessage()
|
||||
self.sequence = poller.sequence
|
||||
return true
|
||||
else
|
||||
-- invalid sequence entered
|
||||
machine:popmessage(_p('plugin-commonui', 'Invalid sequence entered'))
|
||||
self.sequence = nil
|
||||
return true
|
||||
end
|
||||
else
|
||||
machine:popmessage(string.format(
|
||||
_p('plugin-commonui', 'Enter sequence or press %s to cancel\n%s'),
|
||||
cancel_prompt,
|
||||
input:seq_name(poller.sequence)))
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return helper
|
||||
end
|
||||
|
||||
|
||||
return exports
|
9
plugins/commonui/plugin.json
Normal file
9
plugins/commonui/plugin.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"plugin": {
|
||||
"name": "commonui",
|
||||
"description": "Common plugin UI helpers",
|
||||
"version": "0.0.1",
|
||||
"author": "Vas Crabb",
|
||||
"type": "library"
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ function dat.check(set, softlist)
|
||||
if not status or not info then
|
||||
return nil
|
||||
end
|
||||
return _("Command")
|
||||
return _p("plugin-data", "Command")
|
||||
end
|
||||
|
||||
function dat.get()
|
||||
|
@ -13,7 +13,7 @@ function dat.check(set, softlist)
|
||||
if not status or not info then
|
||||
return nil
|
||||
end
|
||||
return _("Gameinit")
|
||||
return _p("plugin-data", "Gameinit")
|
||||
end
|
||||
|
||||
function dat.get()
|
||||
|
@ -1217,7 +1217,7 @@ function dat.check(set, softlist)
|
||||
|
||||
if curset == set then
|
||||
if output then
|
||||
return _("High Scores")
|
||||
return _p("plugin-data", "High Scores")
|
||||
else
|
||||
return nil
|
||||
end
|
||||
@ -1265,7 +1265,7 @@ function dat.check(set, softlist)
|
||||
end
|
||||
end
|
||||
if output then
|
||||
return _("High Scores")
|
||||
return _p("plugin-data", "High Scores")
|
||||
else
|
||||
return nil
|
||||
end
|
||||
|
@ -169,7 +169,7 @@ function dat.check(set, softlist)
|
||||
info = stmt:get_value(0)
|
||||
end
|
||||
stmt:finalize()
|
||||
return info and _("History") or nil
|
||||
return info and _p("plugin-data", "History") or nil
|
||||
end
|
||||
|
||||
function dat.get()
|
||||
|
@ -15,9 +15,9 @@ function dat.check(set, softlist)
|
||||
local sourcefile = emu.driver_find(set).source_file:match("[^/\\]*$")
|
||||
status, drvinfo = pcall(datread, "drv", "info", sourcefile)
|
||||
if drvinfo then
|
||||
info = info .. _("\n\n--- DRIVER INFO ---\nDriver: ") .. sourcefile .. "\n\n" .. drvinfo
|
||||
info = info .. _p("plugin-data", "\n\n--- DRIVER INFO ---\nDriver: ") .. sourcefile .. "\n\n" .. drvinfo
|
||||
end
|
||||
return _("MAMEinfo")
|
||||
return _p("plugin-data", "MAMEinfo")
|
||||
end
|
||||
|
||||
function dat.get()
|
||||
|
@ -133,7 +133,7 @@ function dat.check(set, softlist)
|
||||
info = "#j2\n" .. stmt:get_value(0)
|
||||
end
|
||||
stmt:finalize()
|
||||
return info and _("MARPScore") or nil
|
||||
return info and _p("plugin-data", "MARPScore") or nil
|
||||
end
|
||||
|
||||
function dat.get()
|
||||
|
@ -16,9 +16,9 @@ function dat.check(set, softlist)
|
||||
local sourcefile = emu.driver_find(set).source_file:match("[^/\\]*$")
|
||||
status, drvinfo = pcall(datread, "drv", "info", sourcefile)
|
||||
if drvinfo then
|
||||
info = info .. _("\n\n--- DRIVER INFO ---\nDriver: ") .. sourcefile .. "\n\n" .. drvinfo
|
||||
info = info .. _p("plugin-data", "\n\n--- DRIVER INFO ---\nDriver: ") .. sourcefile .. "\n\n" .. drvinfo
|
||||
end
|
||||
return _("MESSinfo")
|
||||
return _p("plugin-data", "MESSinfo")
|
||||
end
|
||||
|
||||
function dat.get()
|
||||
|
@ -19,7 +19,7 @@ function dat.check(set, softlist)
|
||||
end
|
||||
end
|
||||
info = "#j2\n" .. table.concat(lines, "\n")
|
||||
return _("Mamescore")
|
||||
return _p("plugin-data", "Mamescore")
|
||||
end
|
||||
|
||||
function dat.get()
|
||||
|
@ -12,7 +12,7 @@ function dat.check(set, softlist)
|
||||
if not status or not info then
|
||||
return nil
|
||||
end
|
||||
return _("Sysinfo")
|
||||
return _p("plugin-data", "Sysinfo")
|
||||
end
|
||||
|
||||
function dat.get()
|
||||
|
@ -127,7 +127,7 @@ function inputmacro.startplugin()
|
||||
emu.register_frame_done(process_frame)
|
||||
emu.register_start(start)
|
||||
emu.register_stop(stop)
|
||||
emu.register_menu(menu_callback, menu_populate, _('Input Macros'))
|
||||
emu.register_menu(menu_callback, menu_populate, _p('plugin-inputmacro', 'Input Macros'))
|
||||
end
|
||||
|
||||
return exports
|
||||
|
@ -9,6 +9,7 @@ local MENU_TYPES = { MACROS = 0, ADD = 1, EDIT = 2, INPUT = 3 }
|
||||
|
||||
-- Globals
|
||||
|
||||
local commonui
|
||||
local macros
|
||||
local menu_stack
|
||||
|
||||
@ -51,118 +52,43 @@ end
|
||||
|
||||
-- Input menu
|
||||
|
||||
local input_action
|
||||
local input_menu
|
||||
local input_start_field
|
||||
local input_choices
|
||||
local input_item_first_choice
|
||||
local input_item_cancel
|
||||
|
||||
function handle_input(index, action)
|
||||
if (action == 'cancel') or ((index == input_item_cancel) and (action == 'select')) then
|
||||
table.remove(menu_stack)
|
||||
input_action = nil
|
||||
return true
|
||||
elseif action == 'select' then
|
||||
field = input_choices[index - input_item_first_choice + 1]
|
||||
if field then
|
||||
table.remove(menu_stack)
|
||||
input_action(field)
|
||||
input_action = nil
|
||||
function start_input_menu(handler, start_field)
|
||||
local function supported(f)
|
||||
if f.is_analog or f.is_toggle then
|
||||
return false
|
||||
elseif (f.type_class == 'config') or (f.type_class == 'dipswitch') then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
|
||||
local function action(field)
|
||||
if field then
|
||||
handler(field)
|
||||
end
|
||||
table.remove(menu_stack)
|
||||
input_menu = nil
|
||||
input_start_field = nil
|
||||
end
|
||||
|
||||
if not commonui then
|
||||
commonui = require('commonui')
|
||||
end
|
||||
input_menu = commonui.input_selection_menu(action, _p('plugin-inputmacro', 'Set Input'), supported)
|
||||
input_start_field = start_field
|
||||
table.insert(menu_stack, MENU_TYPES.INPUT)
|
||||
end
|
||||
|
||||
function handle_input(index, action)
|
||||
return input_menu:handle(index, action)
|
||||
end
|
||||
|
||||
function populate_input()
|
||||
local items = { }
|
||||
|
||||
items[#items + 1] = { _p('plugin-inputmacro', 'Set Input'), '', 'off' }
|
||||
items[#items + 1] = { '---', '', '' }
|
||||
|
||||
if not input_choices then
|
||||
local ioport = manager.machine.ioport
|
||||
|
||||
local function supported(f)
|
||||
if f.is_analog or f.is_toggle then
|
||||
return false
|
||||
elseif (f.type_class == 'config') or (f.type_class == 'dipswitch') then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local function compare(a, b)
|
||||
if a.device.tag < b.device.tag then
|
||||
return true
|
||||
elseif a.device.tag > b.device.tag then
|
||||
return false
|
||||
end
|
||||
groupa = ioport:type_group(a.type, a.player)
|
||||
groupb = ioport:type_group(b.type, b.player)
|
||||
if groupa < groupb then
|
||||
return true
|
||||
elseif groupa > groupb then
|
||||
return false
|
||||
elseif a.type < b.type then
|
||||
return true
|
||||
elseif a.type > b.type then
|
||||
return false
|
||||
else
|
||||
return a.name < b.name
|
||||
end
|
||||
end
|
||||
|
||||
input_choices = { }
|
||||
for tag, port in pairs(manager.machine.ioport.ports) do
|
||||
for name, field in pairs(port.fields) do
|
||||
if supported(field) then
|
||||
table.insert(input_choices, field)
|
||||
end
|
||||
end
|
||||
end
|
||||
table.sort(input_choices, compare)
|
||||
|
||||
local index = 1
|
||||
local prev
|
||||
while index <= #input_choices do
|
||||
local current = input_choices[index]
|
||||
if (not prev) or (prev.device.tag ~= current.device.tag) then
|
||||
table.insert(input_choices, index, false)
|
||||
index = index + 2
|
||||
else
|
||||
index = index + 1
|
||||
end
|
||||
prev = current
|
||||
end
|
||||
end
|
||||
|
||||
input_item_first_choice = #items + 1
|
||||
local selection = input_item_first_choice
|
||||
for index, field in ipairs(input_choices) do
|
||||
if field then
|
||||
items[#items + 1] = { _p('input-name', field.name), '', '' }
|
||||
if input_start_field and (field.port.tag == input_start_field.port.tag) and (field.mask == input_start_field.mask) and (field.type == input_start_field.type) then
|
||||
selection = #items
|
||||
input_start_field = nil
|
||||
end
|
||||
else
|
||||
local device = input_choices[index + 1].device
|
||||
if device.owner then
|
||||
items[#items + 1] = { string.format(_('plugin-inputmacro', '%s [root%s]'), device.name, device.tag), '', 'heading' }
|
||||
else
|
||||
items[#items + 1] = { string.format(_('plugin-inputmacro', '[root%s]'), device.tag), '', 'heading' }
|
||||
end
|
||||
end
|
||||
end
|
||||
input_start_field = nil
|
||||
|
||||
items[#items + 1] = { '---', '', '' }
|
||||
items[#items + 1] = { _p('plugin-inputmacro', 'Cancel'), '', '' }
|
||||
input_item_cancel = #items
|
||||
|
||||
return items, selection
|
||||
return input_menu:populate(input_start_field)
|
||||
end
|
||||
|
||||
|
||||
@ -176,6 +102,7 @@ local edit_insert_position
|
||||
local edit_name_buffer
|
||||
local edit_items
|
||||
local edit_item_exit
|
||||
local edit_switch_poller
|
||||
|
||||
local function current_macro_complete()
|
||||
if not edit_current_macro.binding then
|
||||
@ -188,36 +115,18 @@ local function current_macro_complete()
|
||||
return true
|
||||
end
|
||||
|
||||
local function set_binding()
|
||||
local input = manager.machine.input
|
||||
local poller = input:switch_sequence_poller()
|
||||
manager.machine:popmessage(_p('plugin-inputmacro', 'Enter activation sequence or wait to leave unchanged'))
|
||||
manager.machine.video:frame_update()
|
||||
poller:start()
|
||||
local time = os.clock()
|
||||
local clearmsg = true
|
||||
while (not poller:poll()) and (poller.modified or (os.clock() < (time + 1))) do
|
||||
if poller.modified then
|
||||
if not poller.valid then
|
||||
manager.machine:popmessage(_p('plugin-inputmacro', 'Invalid sequence entered'))
|
||||
clearmsg = false
|
||||
break
|
||||
end
|
||||
manager.machine:popmessage(input:seq_name(poller.sequence))
|
||||
manager.machine.video:frame_update()
|
||||
end
|
||||
end
|
||||
if clearmsg then
|
||||
manager.machine:popmessage()
|
||||
end
|
||||
if poller.valid then
|
||||
edit_current_macro.binding = poller.sequence
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function handle_edit_items(index, event)
|
||||
if edit_switch_poller then
|
||||
if edit_switch_poller:poll() then
|
||||
if edit_switch_poller.sequence then
|
||||
edit_current_macro.binding = edit_switch_poller.sequence
|
||||
end
|
||||
edit_switch_poller = nil
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local command = edit_items[index]
|
||||
|
||||
local namecancel = false
|
||||
@ -275,7 +184,11 @@ local function handle_edit_items(index, event)
|
||||
end
|
||||
elseif command.action == 'binding' then
|
||||
if event == 'select' then
|
||||
return set_binding()
|
||||
if not commonui then
|
||||
commonui = require('commonui')
|
||||
end
|
||||
edit_switch_poller = commonui.switch_polling_helper()
|
||||
return true
|
||||
end
|
||||
elseif command.action == 'releaseaction' then
|
||||
if (event == 'select') or (event == 'left') or (event == 'right') then
|
||||
@ -320,14 +233,13 @@ local function handle_edit_items(index, event)
|
||||
elseif command.action == 'input' then
|
||||
local inputs = edit_current_macro.steps[command.step].inputs
|
||||
if event == 'select' then
|
||||
input_action =
|
||||
local hanlder =
|
||||
function(field)
|
||||
inputs[command.input].port = field.port
|
||||
inputs[command.input].field = field
|
||||
end
|
||||
input_start_field = inputs[command.input].field
|
||||
start_input_menu(hanlder, inputs[command.input].field)
|
||||
edit_start_selection = index
|
||||
table.insert(menu_stack, MENU_TYPES.INPUT)
|
||||
return true
|
||||
elseif event == 'clear' then
|
||||
if #inputs > 1 then
|
||||
@ -338,14 +250,14 @@ local function handle_edit_items(index, event)
|
||||
elseif command.action == 'addinput' then
|
||||
if event == 'select' then
|
||||
local inputs = edit_current_macro.steps[command.step].inputs
|
||||
input_action =
|
||||
local handler =
|
||||
function(field)
|
||||
inputs[#inputs + 1] = {
|
||||
port = field.port,
|
||||
field = field }
|
||||
end
|
||||
start_input_menu(handler)
|
||||
edit_start_selection = index
|
||||
table.insert(menu_stack, MENU_TYPES.INPUT)
|
||||
return true
|
||||
end
|
||||
elseif command.action == 'deletestep' then
|
||||
@ -368,7 +280,7 @@ local function handle_edit_items(index, event)
|
||||
elseif command.action == 'addstep' then
|
||||
if event == 'select' then
|
||||
local steps = edit_current_macro.steps
|
||||
input_action =
|
||||
local handler =
|
||||
function(field)
|
||||
local newstep = {
|
||||
inputs = {
|
||||
@ -384,8 +296,8 @@ local function handle_edit_items(index, event)
|
||||
edit_start_step = edit_insert_position
|
||||
edit_insert_position = edit_insert_position + 1
|
||||
end
|
||||
start_input_menu(handler)
|
||||
edit_start_selection = index
|
||||
table.insert(menu_stack, MENU_TYPES.INPUT)
|
||||
return true
|
||||
elseif event == 'left' then
|
||||
edit_insert_position = edit_insert_position - 1
|
||||
@ -413,7 +325,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]')
|
||||
items[#items + 1] = { _p('plugin-inputmacro', 'Activation sequence'), activation, '' }
|
||||
items[#items + 1] = { _p('plugin-inputmacro', 'Activation sequence'), 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')
|
||||
@ -484,7 +396,6 @@ local function handle_add(index, event)
|
||||
if handle_edit_items(index, event) then
|
||||
return true
|
||||
elseif event == 'cancel' then
|
||||
input_choices = nil
|
||||
edit_current_macro = nil
|
||||
edit_menu_active = false
|
||||
edit_items = nil
|
||||
@ -495,7 +406,6 @@ local function handle_add(index, event)
|
||||
table.insert(macros, edit_current_macro)
|
||||
macros_start_macro = #macros
|
||||
end
|
||||
input_choices = nil
|
||||
edit_menu_active = false
|
||||
edit_current_macro = nil
|
||||
edit_items = nil
|
||||
@ -509,7 +419,6 @@ local function handle_edit(index, event)
|
||||
if handle_edit_items(index, event) then
|
||||
return true
|
||||
elseif (event == 'cancel') or ((index == edit_item_exit) and (event == 'select')) then
|
||||
input_choices = nil
|
||||
edit_current_macro = nil
|
||||
edit_menu_active = false
|
||||
edit_items = nil
|
||||
@ -537,7 +446,11 @@ local function populate_add()
|
||||
|
||||
local selection = edit_start_selection
|
||||
edit_start_selection = nil
|
||||
return items, selection, 'lrrepeat'
|
||||
if edit_switch_poller then
|
||||
return edit_switch_poller:overlay(items, selection, 'lrrepeat')
|
||||
else
|
||||
return items, selection, 'lrrepeat'
|
||||
end
|
||||
end
|
||||
|
||||
local function populate_edit()
|
||||
@ -554,7 +467,11 @@ local function populate_edit()
|
||||
|
||||
local selection = edit_start_selection
|
||||
edit_start_selection = nil
|
||||
return items, selection, 'lrrepeat'
|
||||
if edit_switch_poller then
|
||||
return edit_switch_poller:overlay(items, selection, 'lrrepeat')
|
||||
else
|
||||
return items, selection, 'lrrepeat'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -601,7 +518,7 @@ function populate_macros()
|
||||
local items = { }
|
||||
|
||||
items[#items + 1] = { _p('plugin-inputmacro', 'Input Macros'), '', 'off' }
|
||||
items[#items + 1] = { string.format(_p('plugin-inputmacro', 'Press %s to delete'), input:seq_name(ioport:type_seq(ioport:token_to_input_type('UI_CLEAR')))), '', 'off' }
|
||||
items[#items + 1] = { string.format(_p('plugin-inputmacro', 'Press %s to delete'), manager.ui:get_general_input_setting(ioport:token_to_input_type('UI_CLEAR'))), '', 'off' }
|
||||
items[#items + 1] = { '---', '', '' }
|
||||
|
||||
macros_item_first_macro = #items + 1
|
||||
|
@ -86,7 +86,7 @@ function timer.startplugin()
|
||||
local hrs = math.floor(time / 3600)
|
||||
local min = math.floor((time % 3600) / 60)
|
||||
local sec = time % 60
|
||||
return string.format("%03d:%02d:%02d", hrs, min, sec)
|
||||
return string.format(_p("plugin-timer", "%03d:%02d:%02d"), hrs, min, sec)
|
||||
end
|
||||
|
||||
local lastupdate
|
||||
@ -95,9 +95,9 @@ function timer.startplugin()
|
||||
lastupdate = os.time()
|
||||
local time = lastupdate - start_time
|
||||
return
|
||||
{{ _("Current time"), sectohms(time), "off" },
|
||||
{ _("Total time"), sectohms(total_time + time), "off" },
|
||||
{ _("Play Count"), play_count, "off" }},
|
||||
{{ _p("plugin-timer", "Current time"), sectohms(time), "off" },
|
||||
{ _p("plugin-timer", "Total time"), sectohms(total_time + time), "off" },
|
||||
{ _p("plugin-timer", "Play Count"), play_count, "off" }},
|
||||
nil,
|
||||
"idle"
|
||||
end
|
||||
@ -106,7 +106,7 @@ function timer.startplugin()
|
||||
return os.time() > lastupdate
|
||||
end
|
||||
|
||||
emu.register_menu(menu_callback, menu_populate, _("Timer"))
|
||||
emu.register_menu(menu_callback, menu_populate, _p("plugin-timer", "Timer"))
|
||||
end
|
||||
|
||||
return exports
|
||||
|
@ -89,6 +89,8 @@ end
|
||||
MAME_DIR .. "src/lib/util/ioprocsvec.h",
|
||||
MAME_DIR .. "src/lib/util/jedparse.cpp",
|
||||
MAME_DIR .. "src/lib/util/jedparse.h",
|
||||
MAME_DIR .. "src/lib/util/language.cpp",
|
||||
MAME_DIR .. "src/lib/util/language.h",
|
||||
MAME_DIR .. "src/lib/util/lrucache.h",
|
||||
MAME_DIR .. "src/lib/util/md5.cpp",
|
||||
MAME_DIR .. "src/lib/util/md5.h",
|
||||
|
@ -171,6 +171,8 @@ files {
|
||||
MAME_DIR .. "src/frontend/mame/ui/tapectrl.h",
|
||||
MAME_DIR .. "src/frontend/mame/ui/text.cpp",
|
||||
MAME_DIR .. "src/frontend/mame/ui/text.h",
|
||||
MAME_DIR .. "src/frontend/mame/ui/textbox.cpp",
|
||||
MAME_DIR .. "src/frontend/mame/ui/textbox.h",
|
||||
MAME_DIR .. "src/frontend/mame/ui/toolbar.ipp",
|
||||
MAME_DIR .. "src/frontend/mame/ui/ui.cpp",
|
||||
MAME_DIR .. "src/frontend/mame/ui/ui.h",
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "util/language.h"
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
BUILT-IN CORE MAPPINGS
|
||||
@ -15,12 +17,6 @@
|
||||
|
||||
namespace {
|
||||
|
||||
// can't get frontend/mame/language.h from here
|
||||
#ifndef N_p
|
||||
#define N_p(ctx, msg) (msg)
|
||||
#endif
|
||||
|
||||
|
||||
#define CORE_INPUT_TYPES_P1 \
|
||||
CORE_INPUT_TYPES_BEGIN(p1) \
|
||||
INPUT_PORT_DIGITAL_TYPE( 1, PLAYER1, JOYSTICK_UP, N_p("input-name", "P1 Up"), input_seq(KEYCODE_UP, input_seq::or_code, JOYCODE_Y_UP_SWITCH_INDEXED(0)) ) \
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include "ui/uimain.h"
|
||||
|
||||
#include "util/ioprocsfilter.h"
|
||||
#include "util/language.h"
|
||||
#include "util/path.h"
|
||||
#include "util/xmlfile.h"
|
||||
|
||||
@ -1693,6 +1694,8 @@ void render_target::load_layout_files(util::xml::data_node const &rootnode, bool
|
||||
|
||||
void render_target::load_additional_layout_files(const char *basename, bool have_artwork)
|
||||
{
|
||||
using util::lang_translate;
|
||||
|
||||
m_external_artwork = false;
|
||||
|
||||
// if override_artwork defined, load that and skip artwork other than default
|
||||
@ -1841,7 +1844,7 @@ void render_target::load_additional_layout_files(const char *basename, bool have
|
||||
viewnode->set_attribute(
|
||||
"name",
|
||||
util::string_format(
|
||||
"Screen %1$u Standard (%2$u:%3$u)",
|
||||
_("view-name", "Screen %1$u Standard (%2$u:%3$u)"),
|
||||
i, screens[i].physical_x(), screens[i].physical_y()).c_str());
|
||||
util::xml::data_node *const screennode(viewnode->add_child("screen", nullptr));
|
||||
if (!screennode)
|
||||
@ -1867,7 +1870,7 @@ void render_target::load_additional_layout_files(const char *basename, bool have
|
||||
viewnode->set_attribute(
|
||||
"name",
|
||||
util::string_format(
|
||||
"Screen %1$u Pixel Aspect (%2$u:%3$u)",
|
||||
_("view-name", "Screen %1$u Pixel Aspect (%2$u:%3$u)"),
|
||||
i, screens[i].native_x(), screens[i].native_y()).c_str());
|
||||
util::xml::data_node *const screennode(viewnode->add_child("screen", nullptr));
|
||||
if (!screennode)
|
||||
@ -1889,7 +1892,7 @@ void render_target::load_additional_layout_files(const char *basename, bool have
|
||||
util::xml::data_node *const viewnode(layoutnode->add_child("view", nullptr));
|
||||
if (!viewnode)
|
||||
throw emu_fatalerror("Couldn't create XML node??");
|
||||
viewnode->set_attribute("name", "Cocktail");
|
||||
viewnode->set_attribute("name", _("view-name", "Cocktail"));
|
||||
|
||||
util::xml::data_node *const mirrornode(viewnode->add_child("screen", nullptr));
|
||||
if (!mirrornode)
|
||||
@ -2009,10 +2012,10 @@ void render_target::load_additional_layout_files(const char *basename, bool have
|
||||
};
|
||||
|
||||
// generate linear views
|
||||
generate_view("Left-to-Right", screens.size(), false, [] (unsigned x, unsigned y) { return x; });
|
||||
generate_view("Left-to-Right (Gapless)", screens.size(), true, [] (unsigned x, unsigned y) { return x; });
|
||||
generate_view("Top-to-Bottom", 1U, false, [] (unsigned x, unsigned y) { return y; });
|
||||
generate_view("Top-to-Bottom (Gapless)", 1U, true, [] (unsigned x, unsigned y) { return y; });
|
||||
generate_view(_("view-name", "Left-to-Right"), screens.size(), false, [] (unsigned x, unsigned y) { return x; });
|
||||
generate_view(_("view-name", "Left-to-Right (Gapless)"), screens.size(), true, [] (unsigned x, unsigned y) { return x; });
|
||||
generate_view(_("view-name", "Top-to-Bottom"), 1U, false, [] (unsigned x, unsigned y) { return y; });
|
||||
generate_view(_("view-name", "Top-to-Bottom (Gapless)"), 1U, true, [] (unsigned x, unsigned y) { return y; });
|
||||
|
||||
// generate fake cocktail view for systems with two screens
|
||||
if (screens.size() == 2U)
|
||||
@ -2024,7 +2027,7 @@ void render_target::load_additional_layout_files(const char *basename, bool have
|
||||
util::xml::data_node *const viewnode(layoutnode->add_child("view", nullptr));
|
||||
if (!viewnode)
|
||||
throw emu_fatalerror("Couldn't create XML node??");
|
||||
viewnode->set_attribute("name", "Cocktail");
|
||||
viewnode->set_attribute("name", _("view-name", "Cocktail"));
|
||||
|
||||
util::xml::data_node *const mirrornode(viewnode->add_child("screen", nullptr));
|
||||
if (!mirrornode)
|
||||
@ -2063,7 +2066,7 @@ void render_target::load_additional_layout_files(const char *basename, bool have
|
||||
if (!remainder || (((majdim + 1) / 2) <= remainder))
|
||||
{
|
||||
generate_view(
|
||||
util::string_format("%1$u\xC3\x97%2$u Left-to-Right, Top-to-Bottom", majdim, mindim).c_str(),
|
||||
util::string_format(_("view-name", u8"%1$u×%2$u Left-to-Right, Top-to-Bottom"), majdim, mindim).c_str(),
|
||||
majdim,
|
||||
false,
|
||||
[&screens, majdim] (unsigned x, unsigned y)
|
||||
@ -2072,7 +2075,7 @@ void render_target::load_additional_layout_files(const char *basename, bool have
|
||||
return (screens.size() > i) ? int(i) : -1;
|
||||
});
|
||||
generate_view(
|
||||
util::string_format("%1$u\xC3\x97%2$u Left-to-Right, Top-to-Bottom (Gapless)", majdim, mindim).c_str(),
|
||||
util::string_format(_("view-name", u8"%1$u×%2$u Left-to-Right, Top-to-Bottom (Gapless)"), majdim, mindim).c_str(),
|
||||
majdim,
|
||||
true,
|
||||
[&screens, majdim] (unsigned x, unsigned y)
|
||||
@ -2081,7 +2084,7 @@ void render_target::load_additional_layout_files(const char *basename, bool have
|
||||
return (screens.size() > i) ? int(i) : -1;
|
||||
});
|
||||
generate_view(
|
||||
util::string_format("%1$u\xC3\x97%2$u Top-to-Bottom, Left-to-Right", mindim, majdim).c_str(),
|
||||
util::string_format(_("view-name", u8"%1$u×%2$u Top-to-Bottom, Left-to-Right"), mindim, majdim).c_str(),
|
||||
mindim,
|
||||
false,
|
||||
[&screens, majdim] (unsigned x, unsigned y)
|
||||
@ -2090,7 +2093,7 @@ void render_target::load_additional_layout_files(const char *basename, bool have
|
||||
return (screens.size() > i) ? int(i) : -1;
|
||||
});
|
||||
generate_view(
|
||||
util::string_format("%1$u\xC3\x97%2$u Top-to-Bottom, Left-to-Right (Gapless)", mindim, majdim).c_str(),
|
||||
util::string_format(_("view-name", u8"%1$u×%2$u Top-to-Bottom, Left-to-Right (Gapless)"), mindim, majdim).c_str(),
|
||||
mindim,
|
||||
true,
|
||||
[&screens, majdim] (unsigned x, unsigned y)
|
||||
|
@ -81,6 +81,7 @@
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
//**************************************************************************
|
||||
// COMMAND-LINE OPTIONS
|
||||
//**************************************************************************
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <future>
|
||||
#include <locale>
|
||||
#include <queue>
|
||||
#include <type_traits>
|
||||
#include <unordered_set>
|
||||
@ -100,6 +101,7 @@ private:
|
||||
typedef std::set<std::add_pointer_t<device_type>, device_type_compare> device_type_set;
|
||||
|
||||
std::string normalize_string(const char *string);
|
||||
std::string normalize_string(std::string_view string);
|
||||
|
||||
// internal helper
|
||||
void output_header(std::ostream &out, bool dtd);
|
||||
@ -440,6 +442,11 @@ void info_xml_creator::output(std::ostream &out, const std::function<bool(const
|
||||
device_type_set m_dev_set;
|
||||
};
|
||||
|
||||
// TODO: maybe not the best place for this as it affects the stream passed in
|
||||
// if the device part is threaded, the local streams used by the tasks can be
|
||||
// imbued and the stream passed in can be left alone
|
||||
out.imbue(std::locale::classic());
|
||||
|
||||
// prepare a driver enumerator and the queue
|
||||
driver_enumerator drivlist(m_lookup_options);
|
||||
device_filter devfilter(filter);
|
||||
@ -491,6 +498,7 @@ void info_xml_creator::output(std::ostream &out, const std::function<bool(const
|
||||
{
|
||||
prepared_info result;
|
||||
std::ostringstream stream;
|
||||
stream.imbue(std::locale::classic());
|
||||
|
||||
// output each of the drivers
|
||||
for (const game_driver &driver : drivers)
|
||||
@ -568,26 +576,30 @@ namespace
|
||||
|
||||
std::string normalize_string(const char *string)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
if (string)
|
||||
return normalize_string(std::string_view(string));
|
||||
else
|
||||
return std::string();
|
||||
}
|
||||
|
||||
if (string != nullptr)
|
||||
std::string normalize_string(std::string_view string)
|
||||
{
|
||||
std::string result;
|
||||
result.reserve(string.length());
|
||||
|
||||
for (char ch : string)
|
||||
{
|
||||
while (*string)
|
||||
switch (ch)
|
||||
{
|
||||
switch (*string)
|
||||
{
|
||||
case '\"': stream << """; break;
|
||||
case '&': stream << "&"; break;
|
||||
case '<': stream << "<"; break;
|
||||
case '>': stream << ">"; break;
|
||||
default:
|
||||
stream << *string;
|
||||
break;
|
||||
}
|
||||
++string;
|
||||
case '\"': result.append("""); break;
|
||||
case '&': result.append("&"); break;
|
||||
case '<': result.append("<"); break;
|
||||
case '>': result.append(">"); break;
|
||||
default: result.append(1, ch); break;
|
||||
}
|
||||
}
|
||||
return stream.str();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -647,7 +659,8 @@ void output_header(std::ostream &out, bool dtd)
|
||||
}
|
||||
|
||||
// top-level tag
|
||||
out << util::string_format("<%s build=\"%s\" debug=\""
|
||||
util::stream_format(out,
|
||||
"<%s build=\"%s\" debug=\""
|
||||
#ifdef MAME_DEBUG
|
||||
"yes"
|
||||
#else
|
||||
@ -667,7 +680,7 @@ void output_header(std::ostream &out, bool dtd)
|
||||
void output_footer(std::ostream &out)
|
||||
{
|
||||
// close the top level tag
|
||||
out << util::string_format("</%s>\n", XML_ROOT);
|
||||
util::stream_format(out, "</%s>\n", XML_ROOT);
|
||||
}
|
||||
|
||||
|
||||
@ -726,14 +739,14 @@ void output_one(std::ostream &out, driver_enumerator &drivlist, const game_drive
|
||||
}
|
||||
|
||||
// print the header and the machine name
|
||||
out << util::string_format("\t<%s name=\"%s\"", XML_TOP, normalize_string(driver.name));
|
||||
util::stream_format(out, "\t<%s name=\"%s\"", XML_TOP, normalize_string(driver.name));
|
||||
|
||||
// strip away any path information from the source_file and output it
|
||||
const char *start = strrchr(driver.type.source(), '/');
|
||||
if (!start)
|
||||
start = strrchr(driver.type.source(), '\\');
|
||||
start = start ? (start + 1) : driver.type.source();
|
||||
out << util::string_format(" sourcefile=\"%s\"", normalize_string(start));
|
||||
util::stream_format(out, " sourcefile=\"%s\"", normalize_string(start));
|
||||
|
||||
// append bios and runnable flags
|
||||
if (driver.flags & machine_flags::IS_BIOS_ROOT)
|
||||
@ -744,9 +757,9 @@ void output_one(std::ostream &out, driver_enumerator &drivlist, const game_drive
|
||||
// display clone information
|
||||
int clone_of = drivlist.find(driver.parent);
|
||||
if (clone_of != -1 && !(drivlist.driver(clone_of).flags & machine_flags::IS_BIOS_ROOT))
|
||||
out << util::string_format(" cloneof=\"%s\"", normalize_string(drivlist.driver(clone_of).name));
|
||||
util::stream_format(out, " cloneof=\"%s\"", normalize_string(drivlist.driver(clone_of).name));
|
||||
if (clone_of != -1)
|
||||
out << util::string_format(" romof=\"%s\"", normalize_string(drivlist.driver(clone_of).name));
|
||||
util::stream_format(out, " romof=\"%s\"", normalize_string(drivlist.driver(clone_of).name));
|
||||
|
||||
// display sample information and close the game tag
|
||||
output_sampleof(out, config.root_device());
|
||||
@ -754,15 +767,15 @@ void output_one(std::ostream &out, driver_enumerator &drivlist, const game_drive
|
||||
|
||||
// output game description
|
||||
if (driver.type.fullname() != nullptr)
|
||||
out << util::string_format("\t\t<description>%s</description>\n", normalize_string(driver.type.fullname()));
|
||||
util::stream_format(out, "\t\t<description>%s</description>\n", normalize_string(driver.type.fullname()));
|
||||
|
||||
// print the year only if is a number or another allowed character (? or +)
|
||||
if (driver.year != nullptr && strspn(driver.year, "0123456789?+") == strlen(driver.year))
|
||||
out << util::string_format("\t\t<year>%s</year>\n", normalize_string(driver.year));
|
||||
if (driver.year && strspn(driver.year, "0123456789?+") == strlen(driver.year))
|
||||
util::stream_format(out, "\t\t<year>%s</year>\n", normalize_string(driver.year));
|
||||
|
||||
// print the manufacturer information
|
||||
if (driver.manufacturer != nullptr)
|
||||
out << util::string_format("\t\t<manufacturer>%s</manufacturer>\n", normalize_string(driver.manufacturer));
|
||||
util::stream_format(out, "\t\t<manufacturer>%s</manufacturer>\n", normalize_string(driver.manufacturer));
|
||||
|
||||
// now print various additional information
|
||||
output_bios(out, config.root_device());
|
||||
@ -785,7 +798,7 @@ void output_one(std::ostream &out, driver_enumerator &drivlist, const game_drive
|
||||
output_ramoptions(out, config.root_device());
|
||||
|
||||
// close the topmost tag
|
||||
out << util::string_format("\t</%s>\n", XML_TOP);
|
||||
util::stream_format(out, "\t</%s>\n", XML_TOP);
|
||||
}
|
||||
|
||||
|
||||
@ -824,15 +837,16 @@ void output_one_device(std::ostream &out, machine_config &config, device_t &devi
|
||||
}
|
||||
|
||||
// start to output info
|
||||
out << util::string_format("\t<%s name=\"%s\"", XML_TOP, normalize_string(device.shortname()));
|
||||
util::stream_format(out, "\t<%s name=\"%s\"", XML_TOP, normalize_string(device.shortname()));
|
||||
std::string src(device.source());
|
||||
strreplace(src,"../", "");
|
||||
out << util::string_format(" sourcefile=\"%s\" isdevice=\"yes\" runnable=\"no\"", normalize_string(src.c_str()));
|
||||
util::stream_format(out, " sourcefile=\"%s\" isdevice=\"yes\" runnable=\"no\"", normalize_string(src));
|
||||
auto const parent(device.type().parent_rom_device_type());
|
||||
if (parent)
|
||||
out << util::string_format(" romof=\"%s\"", normalize_string(parent->shortname()));
|
||||
util::stream_format(out, " romof=\"%s\"", normalize_string(parent->shortname()));
|
||||
output_sampleof(out, device);
|
||||
out << ">\n" << util::string_format("\t\t<description>%s</description>\n", normalize_string(device.name()));
|
||||
out << ">\n";
|
||||
util::stream_format(out, "\t\t<description>%s</description>\n", normalize_string(device.name()));
|
||||
|
||||
output_bios(out, device);
|
||||
output_rom(out, config, nullptr, nullptr, device);
|
||||
@ -854,7 +868,7 @@ void output_one_device(std::ostream &out, machine_config &config, device_t &devi
|
||||
output_images(out, device, devtag);
|
||||
output_slots(out, config, device, devtag, nullptr);
|
||||
output_software_lists(out, device, devtag);
|
||||
out << util::string_format("\t</%s>\n", XML_TOP);
|
||||
util::stream_format(out, "\t</%s>\n", XML_TOP);
|
||||
}
|
||||
|
||||
|
||||
@ -909,7 +923,7 @@ void output_device_refs(std::ostream &out, device_t &root)
|
||||
{
|
||||
for (device_t &device : device_enumerator(root))
|
||||
if (&device != &root)
|
||||
out << util::string_format("\t\t<device_ref name=\"%s\"/>\n", normalize_string(device.shortname()));
|
||||
util::stream_format(out, "\t\t<device_ref name=\"%s\"/>\n", normalize_string(device.shortname()));
|
||||
}
|
||||
|
||||
|
||||
@ -926,7 +940,7 @@ void output_sampleof(std::ostream &out, device_t &device)
|
||||
samples_iterator sampiter(samples);
|
||||
if (sampiter.altbasename() != nullptr)
|
||||
{
|
||||
out << util::string_format(" sampleof=\"%s\"", normalize_string(sampiter.altbasename()));
|
||||
util::stream_format(out, " sampleof=\"%s\"", normalize_string(sampiter.altbasename()));
|
||||
|
||||
// must stop here, as there can only be one attribute of the same name
|
||||
return;
|
||||
@ -954,8 +968,8 @@ void output_bios(std::ostream &out, device_t const &device)
|
||||
{
|
||||
// output extracted name and descriptions'
|
||||
out << "\t\t<biosset";
|
||||
out << util::string_format(" name=\"%s\"", normalize_string(bios.get_name()));
|
||||
out << util::string_format(" description=\"%s\"", normalize_string(bios.get_description()));
|
||||
util::stream_format(out, " name=\"%s\"", normalize_string(bios.get_name()));
|
||||
util::stream_format(out, " description=\"%s\"", normalize_string(bios.get_description()));
|
||||
if (defaultname && !std::strcmp(defaultname, bios.get_name()))
|
||||
out << " default=\"yes\"";
|
||||
out << "/>\n";
|
||||
@ -1062,13 +1076,13 @@ void output_rom(std::ostream &out, machine_config &config, driver_enumerator *dr
|
||||
// add name, merge, bios, and size tags
|
||||
char const *const name(rom->name);
|
||||
if (name && name[0])
|
||||
out << util::string_format(" name=\"%s\"", normalize_string(name));
|
||||
util::stream_format(out, " name=\"%s\"", normalize_string(name));
|
||||
if (merge_name)
|
||||
out << util::string_format(" merge=\"%s\"", normalize_string(merge_name));
|
||||
util::stream_format(out, " merge=\"%s\"", normalize_string(merge_name));
|
||||
if (bios_name)
|
||||
out << util::string_format(" bios=\"%s\"", normalize_string(bios_name));
|
||||
util::stream_format(out, " bios=\"%s\"", normalize_string(bios_name));
|
||||
if (!is_disk)
|
||||
out << util::string_format(" size=\"%u\"", rom_file_size(rom));
|
||||
util::stream_format(out, " size=\"%u\"", rom_file_size(rom));
|
||||
|
||||
// dump checksum information only if there is a known dump
|
||||
if (!hashes.flag(util::hash_collection::FLAG_NO_DUMP))
|
||||
@ -1077,17 +1091,17 @@ void output_rom(std::ostream &out, machine_config &config, driver_enumerator *dr
|
||||
out << " status=\"nodump\"";
|
||||
|
||||
// append a region name
|
||||
out << util::string_format(" region=\"%s\"", region->name);
|
||||
util::stream_format(out, " region=\"%s\"", region->name);
|
||||
|
||||
if (!is_disk)
|
||||
{
|
||||
// for non-disk entries, print offset
|
||||
out << util::string_format(" offset=\"%x\"", ROM_GETOFFSET(rom));
|
||||
util::stream_format(out, " offset=\"%x\"", ROM_GETOFFSET(rom));
|
||||
}
|
||||
else
|
||||
{
|
||||
// for disk entries, add the disk index
|
||||
out << util::string_format(" index=\"%x\" writable=\"%s\"", DISK_GETINDEX(rom), DISK_ISREADONLY(rom) ? "no" : "yes");
|
||||
util::stream_format(out, " index=\"%x\" writable=\"%s\"", DISK_GETINDEX(rom), DISK_ISREADONLY(rom) ? "no" : "yes");
|
||||
}
|
||||
|
||||
// add optional flag
|
||||
@ -1120,7 +1134,7 @@ void output_sample(std::ostream &out, device_t &device)
|
||||
continue;
|
||||
|
||||
// output the sample name
|
||||
out << util::string_format("\t\t<sample name=\"%s\"/>\n", normalize_string(samplename));
|
||||
util::stream_format(out, "\t\t<sample name=\"%s\"/>\n", normalize_string(samplename));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1143,9 +1157,9 @@ void output_chips(std::ostream &out, device_t &device, const char *root_tag)
|
||||
|
||||
out << "\t\t<chip";
|
||||
out << " type=\"cpu\"";
|
||||
out << util::string_format(" tag=\"%s\"", normalize_string(newtag.c_str()));
|
||||
out << util::string_format(" name=\"%s\"", normalize_string(exec.device().name()));
|
||||
out << util::string_format(" clock=\"%d\"", exec.device().clock());
|
||||
util::stream_format(out, " tag=\"%s\"", normalize_string(newtag));
|
||||
util::stream_format(out, " name=\"%s\"", normalize_string(exec.device().name()));
|
||||
util::stream_format(out, " clock=\"%d\"", exec.device().clock());
|
||||
out << "/>\n";
|
||||
}
|
||||
}
|
||||
@ -1160,10 +1174,10 @@ void output_chips(std::ostream &out, device_t &device, const char *root_tag)
|
||||
|
||||
out << "\t\t<chip";
|
||||
out << " type=\"audio\"";
|
||||
out << util::string_format(" tag=\"%s\"", normalize_string(newtag.c_str()));
|
||||
out << util::string_format(" name=\"%s\"", normalize_string(sound.device().name()));
|
||||
util::stream_format(out, " tag=\"%s\"", normalize_string(newtag));
|
||||
util::stream_format(out, " name=\"%s\"", normalize_string(sound.device().name()));
|
||||
if (sound.device().clock() != 0)
|
||||
out << util::string_format(" clock=\"%d\"", sound.device().clock());
|
||||
util::stream_format(out, " clock=\"%d\"", sound.device().clock());
|
||||
out << "/>\n";
|
||||
}
|
||||
}
|
||||
@ -1185,7 +1199,7 @@ void output_display(std::ostream &out, device_t &device, machine_flags::type con
|
||||
std::string newtag(screendev.tag()), oldtag(":");
|
||||
newtag = newtag.substr(newtag.find(oldtag.append(root_tag)) + oldtag.length());
|
||||
|
||||
out << util::string_format("\t\t<display tag=\"%s\"", normalize_string(newtag.c_str()));
|
||||
util::stream_format(out, "\t\t<display tag=\"%s\"", normalize_string(newtag));
|
||||
|
||||
switch (screendev.screen_type())
|
||||
{
|
||||
@ -1229,12 +1243,12 @@ void output_display(std::ostream &out, device_t &device, machine_flags::type con
|
||||
if (screendev.screen_type() != SCREEN_TYPE_VECTOR)
|
||||
{
|
||||
const rectangle &visarea = screendev.visible_area();
|
||||
out << util::string_format(" width=\"%d\"", visarea.width());
|
||||
out << util::string_format(" height=\"%d\"", visarea.height());
|
||||
util::stream_format(out, " width=\"%d\"", visarea.width());
|
||||
util::stream_format(out, " height=\"%d\"", visarea.height());
|
||||
}
|
||||
|
||||
// output refresh rate
|
||||
out << util::string_format(" refresh=\"%f\"", ATTOSECONDS_TO_HZ(screendev.refresh_attoseconds()));
|
||||
util::stream_format(out, " refresh=\"%f\"", ATTOSECONDS_TO_HZ(screendev.refresh_attoseconds()));
|
||||
|
||||
// output raw video parameters only for games that are not vector
|
||||
// and had raw parameters specified
|
||||
@ -1242,13 +1256,13 @@ void output_display(std::ostream &out, device_t &device, machine_flags::type con
|
||||
{
|
||||
int pixclock = screendev.width() * screendev.height() * ATTOSECONDS_TO_HZ(screendev.refresh_attoseconds());
|
||||
|
||||
out << util::string_format(" pixclock=\"%d\"", pixclock);
|
||||
out << util::string_format(" htotal=\"%d\"", screendev.width());
|
||||
out << util::string_format(" hbend=\"%d\"", screendev.visible_area().min_x);
|
||||
out << util::string_format(" hbstart=\"%d\"", screendev.visible_area().max_x+1);
|
||||
out << util::string_format(" vtotal=\"%d\"", screendev.height());
|
||||
out << util::string_format(" vbend=\"%d\"", screendev.visible_area().min_y);
|
||||
out << util::string_format(" vbstart=\"%d\"", screendev.visible_area().max_y+1);
|
||||
util::stream_format(out, " pixclock=\"%d\"", pixclock);
|
||||
util::stream_format(out, " htotal=\"%d\"", screendev.width());
|
||||
util::stream_format(out, " hbend=\"%d\"", screendev.visible_area().min_x);
|
||||
util::stream_format(out, " hbstart=\"%d\"", screendev.visible_area().max_x+1);
|
||||
util::stream_format(out, " vtotal=\"%d\"", screendev.height());
|
||||
util::stream_format(out, " vbend=\"%d\"", screendev.visible_area().min_y);
|
||||
util::stream_format(out, " vbstart=\"%d\"", screendev.visible_area().max_y+1);
|
||||
}
|
||||
out << " />\n";
|
||||
}
|
||||
@ -1271,7 +1285,7 @@ void output_sound(std::ostream &out, device_t &device)
|
||||
if (snditer.first() == nullptr)
|
||||
speakers = 0;
|
||||
|
||||
out << util::string_format("\t\t<sound channels=\"%d\"/>\n", speakers);
|
||||
util::stream_format(out, "\t\t<sound channels=\"%d\"/>\n", speakers);
|
||||
}
|
||||
|
||||
|
||||
@ -1297,7 +1311,7 @@ void output_ioport_condition(std::ostream &out, const ioport_condition &conditio
|
||||
case ioport_condition::NOTLESSTHAN: rel = "ge"; break;
|
||||
}
|
||||
|
||||
out << util::string_format("<condition tag=\"%s\" mask=\"%u\" relation=\"%s\" value=\"%u\"/>\n", normalize_string(condition.tag()), condition.mask(), rel, condition.value());
|
||||
util::stream_format(out, "<condition tag=\"%s\" mask=\"%u\" relation=\"%s\" value=\"%u\"/>\n", normalize_string(condition.tag()), condition.mask(), rel, condition.value());
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
@ -1700,13 +1714,13 @@ void output_input(std::ostream &out, const ioport_list &portlist)
|
||||
// Output the input info
|
||||
// First basic info
|
||||
out << "\t\t<input";
|
||||
out << util::string_format(" players=\"%d\"", nplayer);
|
||||
util::stream_format(out, " players=\"%d\"", nplayer);
|
||||
if (ncoin != 0)
|
||||
out << util::string_format(" coins=\"%d\"", ncoin);
|
||||
util::stream_format(out, " coins=\"%d\"", ncoin);
|
||||
if (service)
|
||||
out << util::string_format(" service=\"yes\"");
|
||||
util::stream_format(out, " service=\"yes\"");
|
||||
if (tilt)
|
||||
out << util::string_format(" tilt=\"yes\"");
|
||||
util::stream_format(out, " tilt=\"yes\"");
|
||||
out << ">\n";
|
||||
|
||||
// Then controller specific ones
|
||||
@ -1716,21 +1730,21 @@ void output_input(std::ostream &out, const ioport_list &portlist)
|
||||
//printf("type %s - player %d - buttons %d\n", elem.type, elem.player, elem.nbuttons);
|
||||
if (elem.analog)
|
||||
{
|
||||
out << util::string_format("\t\t\t<control type=\"%s\"", normalize_string(elem.type));
|
||||
util::stream_format(out, "\t\t\t<control type=\"%s\"", normalize_string(elem.type));
|
||||
if (nplayer > 1)
|
||||
out << util::string_format(" player=\"%d\"", elem.player);
|
||||
util::stream_format(out, " player=\"%d\"", elem.player);
|
||||
if (elem.nbuttons > 0)
|
||||
{
|
||||
out << util::string_format(" buttons=\"%d\"", strcmp(elem.type, "stick") ? elem.nbuttons : elem.maxbuttons);
|
||||
util::stream_format(out, " buttons=\"%d\"", strcmp(elem.type, "stick") ? elem.nbuttons : elem.maxbuttons);
|
||||
if (elem.reqbuttons < elem.nbuttons)
|
||||
out << util::string_format(" reqbuttons=\"%d\"", elem.reqbuttons);
|
||||
util::stream_format(out, " reqbuttons=\"%d\"", elem.reqbuttons);
|
||||
}
|
||||
if (elem.min != 0 || elem.max != 0)
|
||||
out << util::string_format(" minimum=\"%d\" maximum=\"%d\"", elem.min, elem.max);
|
||||
util::stream_format(out, " minimum=\"%d\" maximum=\"%d\"", elem.min, elem.max);
|
||||
if (elem.sensitivity != 0)
|
||||
out << util::string_format(" sensitivity=\"%d\"", elem.sensitivity);
|
||||
util::stream_format(out, " sensitivity=\"%d\"", elem.sensitivity);
|
||||
if (elem.keydelta != 0)
|
||||
out << util::string_format(" keydelta=\"%d\"", elem.keydelta);
|
||||
util::stream_format(out, " keydelta=\"%d\"", elem.keydelta);
|
||||
if (elem.reverse)
|
||||
out << " reverse=\"yes\"";
|
||||
|
||||
@ -1742,14 +1756,14 @@ void output_input(std::ostream &out, const ioport_list &portlist)
|
||||
if (elem.helper[0] == 0 && elem.helper[1] != 0) { elem.helper[0] = elem.helper[1]; elem.helper[1] = 0; }
|
||||
if (elem.helper[1] == 0 && elem.helper[2] != 0) { elem.helper[1] = elem.helper[2]; elem.helper[2] = 0; }
|
||||
const char *joys = (elem.helper[2] != 0) ? "triple" : (elem.helper[1] != 0) ? "double" : "";
|
||||
out << util::string_format("\t\t\t<control type=\"%s%s\"", joys, normalize_string(elem.type));
|
||||
util::stream_format(out, "\t\t\t<control type=\"%s%s\"", joys, normalize_string(elem.type));
|
||||
if (nplayer > 1)
|
||||
out << util::string_format(" player=\"%d\"", elem.player);
|
||||
util::stream_format(out, " player=\"%d\"", elem.player);
|
||||
if (elem.nbuttons > 0)
|
||||
{
|
||||
out << util::string_format(" buttons=\"%d\"", strcmp(elem.type, "joy") ? elem.nbuttons : elem.maxbuttons);
|
||||
util::stream_format(out, " buttons=\"%d\"", strcmp(elem.type, "joy") ? elem.nbuttons : elem.maxbuttons);
|
||||
if (elem.reqbuttons < elem.nbuttons)
|
||||
out << util::string_format(" reqbuttons=\"%d\"", elem.reqbuttons);
|
||||
util::stream_format(out, " reqbuttons=\"%d\"", elem.reqbuttons);
|
||||
}
|
||||
for (int lp = 0; lp < 3 && elem.helper[lp] != 0; lp++)
|
||||
{
|
||||
@ -1759,7 +1773,7 @@ void output_input(std::ostream &out, const ioport_list &portlist)
|
||||
switch (elem.helper[lp] & (DIR_UP | DIR_DOWN | DIR_LEFT | DIR_RIGHT))
|
||||
{
|
||||
case DIR_UP | DIR_DOWN | DIR_LEFT | DIR_RIGHT:
|
||||
helper = string_format("%d", (elem.ways == 0) ? 8 : elem.ways);
|
||||
helper = util::string_format(std::locale::classic(), "%d", (elem.ways == 0) ? 8 : elem.ways);
|
||||
ways = helper.c_str();
|
||||
break;
|
||||
case DIR_LEFT | DIR_RIGHT:
|
||||
@ -1784,7 +1798,7 @@ void output_input(std::ostream &out, const ioport_list &portlist)
|
||||
ways = "strange2";
|
||||
break;
|
||||
}
|
||||
out << util::string_format(" ways%s=\"%s\"", plural, ways);
|
||||
util::stream_format(out, " ways%s=\"%s\"", plural, ways);
|
||||
}
|
||||
out << "/>\n";
|
||||
}
|
||||
@ -1811,15 +1825,15 @@ void output_switches(std::ostream &out, const ioport_list &portlist, const char
|
||||
|
||||
// output the switch name information
|
||||
std::string const normalized_field_name(normalize_string(field.name()));
|
||||
std::string const normalized_newtag(normalize_string(newtag.c_str()));
|
||||
out << util::string_format("\t\t<%s name=\"%s\" tag=\"%s\" mask=\"%u\">\n", outertag, normalized_field_name.c_str(), normalized_newtag.c_str(), field.mask());
|
||||
std::string const normalized_newtag(normalize_string(newtag));
|
||||
util::stream_format(out, "\t\t<%s name=\"%s\" tag=\"%s\" mask=\"%u\">\n", outertag, normalized_field_name, normalized_newtag, field.mask());
|
||||
if (!field.condition().none())
|
||||
output_ioport_condition(out, field.condition(), 3);
|
||||
|
||||
// loop over locations
|
||||
for (ioport_diplocation const &diploc : field.diplocations())
|
||||
{
|
||||
out << util::string_format("\t\t\t<%s name=\"%s\" number=\"%u\"", loctag, normalize_string(diploc.name()), diploc.number());
|
||||
util::stream_format(out, "\t\t\t<%s name=\"%s\" number=\"%u\"", loctag, normalize_string(diploc.name()), diploc.number());
|
||||
if (diploc.inverted())
|
||||
out << " inverted=\"yes\"";
|
||||
out << "/>\n";
|
||||
@ -1828,7 +1842,7 @@ void output_switches(std::ostream &out, const ioport_list &portlist, const char
|
||||
// loop over settings
|
||||
for (ioport_setting const &setting : field.settings())
|
||||
{
|
||||
out << util::string_format("\t\t\t<%s name=\"%s\" value=\"%u\"", innertag, normalize_string(setting.name()), setting.value());
|
||||
util::stream_format(out, "\t\t\t<%s name=\"%s\" value=\"%u\"", innertag, normalize_string(setting.name()), setting.value());
|
||||
if (setting.value() == field.defvalue())
|
||||
out << " default=\"yes\"";
|
||||
if (setting.condition().none())
|
||||
@ -1839,12 +1853,12 @@ void output_switches(std::ostream &out, const ioport_list &portlist, const char
|
||||
{
|
||||
out << ">\n";
|
||||
output_ioport_condition(out, setting.condition(), 4);
|
||||
out << util::string_format("\t\t\t</%s>\n", innertag);
|
||||
util::stream_format(out, "\t\t\t</%s>\n", innertag);
|
||||
}
|
||||
}
|
||||
|
||||
// terminate the switch entry
|
||||
out << util::string_format("\t\t</%s>\n", outertag);
|
||||
util::stream_format(out, "\t\t</%s>\n", outertag);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1857,13 +1871,13 @@ void output_ports(std::ostream &out, const ioport_list &portlist)
|
||||
// cycle through ports
|
||||
for (auto &port : portlist)
|
||||
{
|
||||
out << util::string_format("\t\t<port tag=\"%s\">\n", normalize_string(port.second->tag()));
|
||||
util::stream_format(out, "\t\t<port tag=\"%s\">\n", normalize_string(port.second->tag()));
|
||||
for (ioport_field const &field : port.second->fields())
|
||||
{
|
||||
if (field.is_analog())
|
||||
out << util::string_format("\t\t\t<analog mask=\"%u\"/>\n", field.mask());
|
||||
util::stream_format(out, "\t\t\t<analog mask=\"%u\"/>\n", field.mask());
|
||||
}
|
||||
out << util::string_format("\t\t</port>\n");
|
||||
util::stream_format(out, "\t\t</port>\n");
|
||||
}
|
||||
|
||||
}
|
||||
@ -1880,7 +1894,7 @@ void output_adjusters(std::ostream &out, const ioport_list &portlist)
|
||||
for (ioport_field const &field : port.second->fields())
|
||||
if (field.type() == IPT_ADJUSTER)
|
||||
{
|
||||
out << util::string_format("\t\t<adjuster name=\"%s\" default=\"%d\"/>\n", normalize_string(field.name()), field.defvalue());
|
||||
util::stream_format(out, "\t\t<adjuster name=\"%s\" default=\"%d\"/>\n", normalize_string(field.name()), field.defvalue());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1955,7 +1969,7 @@ void output_features(std::ostream &out, device_type type, device_t::feature_type
|
||||
{
|
||||
if (flags & feature.first)
|
||||
{
|
||||
out << util::string_format("\t\t<feature type=\"%s\"", feature.second);
|
||||
util::stream_format(out, "\t\t<feature type=\"%s\"", feature.second);
|
||||
if (type.unemulated_features() & feature.first)
|
||||
{
|
||||
out << " status=\"unemulated\"";
|
||||
@ -1991,11 +2005,11 @@ void output_images(std::ostream &out, device_t &device, const char *root_tag)
|
||||
newtag = newtag.substr(newtag.find(oldtag.append(root_tag)) + oldtag.length());
|
||||
|
||||
// print m_output device type
|
||||
out << util::string_format("\t\t<device type=\"%s\"", normalize_string(imagedev.image_type_name()));
|
||||
util::stream_format(out, "\t\t<device type=\"%s\"", normalize_string(imagedev.image_type_name()));
|
||||
|
||||
// does this device have a tag?
|
||||
if (imagedev.device().tag())
|
||||
out << util::string_format(" tag=\"%s\"", normalize_string(newtag.c_str()));
|
||||
util::stream_format(out, " tag=\"%s\"", normalize_string(newtag));
|
||||
|
||||
// is this device available as media switch?
|
||||
if (!loadable)
|
||||
@ -2006,7 +2020,7 @@ void output_images(std::ostream &out, device_t &device, const char *root_tag)
|
||||
out << " mandatory=\"1\"";
|
||||
|
||||
if (imagedev.image_interface() && imagedev.image_interface()[0])
|
||||
out << util::string_format(" interface=\"%s\"", normalize_string(imagedev.image_interface()));
|
||||
util::stream_format(out, " interface=\"%s\"", normalize_string(imagedev.image_interface()));
|
||||
|
||||
// close the XML tag
|
||||
out << ">\n";
|
||||
@ -2017,8 +2031,8 @@ void output_images(std::ostream &out, device_t &device, const char *root_tag)
|
||||
char const *const shortname = imagedev.brief_instance_name().c_str();
|
||||
|
||||
out << "\t\t\t<instance";
|
||||
out << util::string_format(" name=\"%s\"", normalize_string(name));
|
||||
out << util::string_format(" briefname=\"%s\"", normalize_string(shortname));
|
||||
util::stream_format(out, " name=\"%s\"", normalize_string(name));
|
||||
util::stream_format(out, " briefname=\"%s\"", normalize_string(shortname));
|
||||
out << "/>\n";
|
||||
|
||||
char const *extensions(imagedev.file_extensions());
|
||||
@ -2027,7 +2041,7 @@ void output_images(std::ostream &out, device_t &device, const char *root_tag)
|
||||
char const *end(extensions);
|
||||
while (*end && (',' != *end))
|
||||
++end;
|
||||
out << util::string_format("\t\t\t<extension name=\"%s\"/>\n", normalize_string(std::string(extensions, end).c_str()));
|
||||
util::stream_format(out, "\t\t\t<extension name=\"%s\"/>\n", normalize_string(std::string_view(extensions, end - extensions)));
|
||||
extensions = *end ? (end + 1) : nullptr;
|
||||
}
|
||||
}
|
||||
@ -2056,7 +2070,7 @@ void output_slots(std::ostream &out, machine_config &config, device_t &device, c
|
||||
|
||||
// print m_output device type
|
||||
if (listed)
|
||||
out << util::string_format("\t\t<slot name=\"%s\">\n", normalize_string(newtag.c_str()));
|
||||
util::stream_format(out, "\t\t<slot name=\"%s\">\n", normalize_string(newtag));
|
||||
|
||||
for (auto &option : slot.option_list())
|
||||
{
|
||||
@ -2071,9 +2085,9 @@ void output_slots(std::ostream &out, machine_config &config, device_t &device, c
|
||||
|
||||
if (listed && option.second->selectable())
|
||||
{
|
||||
out << util::string_format("\t\t\t<slotoption name=\"%s\"", normalize_string(option.second->name()));
|
||||
out << util::string_format(" devname=\"%s\"", normalize_string(dev->shortname()));
|
||||
if (slot.default_option() != nullptr && strcmp(slot.default_option(), option.second->name())==0)
|
||||
util::stream_format(out, "\t\t\t<slotoption name=\"%s\"", normalize_string(option.second->name()));
|
||||
util::stream_format(out, " devname=\"%s\"", normalize_string(dev->shortname()));
|
||||
if (slot.default_option() && !strcmp(slot.default_option(), option.second->name()))
|
||||
out << " default=\"yes\"";
|
||||
out << "/>\n";
|
||||
}
|
||||
@ -2106,10 +2120,10 @@ void output_software_lists(std::ostream &out, device_t &root, const char *root_t
|
||||
|
||||
std::string newtag(swlist.tag()), oldtag(":");
|
||||
newtag = newtag.substr(newtag.find(oldtag.append(root_tag)) + oldtag.length());
|
||||
out << util::string_format("\t\t<softwarelist tag=\"%s\" name=\"%s\" status=\"%s\"", normalize_string(newtag.c_str()), normalize_string(swlist.list_name().c_str()), swlist.is_original() ? "original" : "compatible");
|
||||
util::stream_format(out, "\t\t<softwarelist tag=\"%s\" name=\"%s\" status=\"%s\"", normalize_string(newtag), normalize_string(swlist.list_name()), swlist.is_original() ? "original" : "compatible");
|
||||
|
||||
if (swlist.filter())
|
||||
out << util::string_format(" filter=\"%s\"", normalize_string(swlist.filter()));
|
||||
util::stream_format(out, " filter=\"%s\"", normalize_string(swlist.filter()));
|
||||
out << "/>\n";
|
||||
}
|
||||
}
|
||||
@ -2135,15 +2149,15 @@ void output_ramoptions(std::ostream &out, device_t &root)
|
||||
{
|
||||
assert(!havedefault);
|
||||
havedefault = true;
|
||||
out << util::string_format("\t\t<ramoption name=\"%s\" default=\"yes\">%u</ramoption>\n", normalize_string(option.first.c_str()), option.second);
|
||||
util::stream_format(out, "\t\t<ramoption name=\"%s\" default=\"yes\">%u</ramoption>\n", normalize_string(option.first), option.second);
|
||||
}
|
||||
else
|
||||
{
|
||||
out << util::string_format("\t\t<ramoption name=\"%s\">%u</ramoption>\n", normalize_string(option.first.c_str()), option.second);
|
||||
util::stream_format(out, "\t\t<ramoption name=\"%s\">%u</ramoption>\n", normalize_string(option.first), option.second);
|
||||
}
|
||||
}
|
||||
if (!havedefault)
|
||||
out << util::string_format("\t\t<ramoption name=\"%s\" default=\"yes\">%u</ramoption>\n", ram.default_size_string(), defsize);
|
||||
util::stream_format(out, "\t\t<ramoption name=\"%s\" default=\"yes\">%u</ramoption>\n", ram.default_size_string(), defsize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -15,28 +15,12 @@
|
||||
|
||||
#include "corestr.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr u32 MO_MAGIC = 0x950412de;
|
||||
constexpr u32 MO_MAGIC_REVERSED = 0xde120495;
|
||||
|
||||
std::unique_ptr<u32 []> f_translation_data;
|
||||
std::unordered_map<std::string_view, std::pair<char const *, u32> > f_translation_map;
|
||||
|
||||
} // anonymous namespace
|
||||
#include <string>
|
||||
|
||||
|
||||
void load_translation(emu_options &m_options)
|
||||
{
|
||||
f_translation_data.reset();
|
||||
f_translation_map.clear();
|
||||
util::unload_translation();
|
||||
|
||||
std::string name = m_options.language();
|
||||
if (name.empty())
|
||||
@ -52,174 +36,6 @@ void load_translation(emu_options &m_options)
|
||||
return;
|
||||
}
|
||||
|
||||
u64 const size = file.size();
|
||||
if (20 > size)
|
||||
{
|
||||
file.close();
|
||||
osd_printf_error("Error reading translation file %s: %u-byte file is too small to contain translation data\n", name, size);
|
||||
return;
|
||||
}
|
||||
|
||||
f_translation_data.reset(new (std::nothrow) u32 [(size + 3) / 4]);
|
||||
if (!f_translation_data)
|
||||
{
|
||||
file.close();
|
||||
osd_printf_error("Failed to allocate %u bytes to load translation data file %s\n", size, name);
|
||||
return;
|
||||
}
|
||||
|
||||
auto const read = file.read(f_translation_data.get(), size);
|
||||
file.close();
|
||||
if (read != size)
|
||||
{
|
||||
osd_printf_error("Error reading translation file %s: requested %u bytes but got %u bytes\n", name, size, read);
|
||||
f_translation_data.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if ((f_translation_data[0] != MO_MAGIC) && (f_translation_data[0] != MO_MAGIC_REVERSED))
|
||||
{
|
||||
osd_printf_error("Error reading translation file %s: unrecognized magic number 0x%08X\n", name, f_translation_data[0]);
|
||||
f_translation_data.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
auto fetch_word =
|
||||
[reversed = f_translation_data[0] == MO_MAGIC_REVERSED, words = f_translation_data.get()] (size_t offset)
|
||||
{
|
||||
return reversed ? swapendian_int32(words[offset]) : words[offset];
|
||||
};
|
||||
|
||||
// FIXME: check major/minor version number
|
||||
|
||||
if ((fetch_word(3) % 4) || (fetch_word(4) % 4))
|
||||
{
|
||||
osd_printf_error("Error reading translation file %s: table offsets %u and %u are not word-aligned\n", name, fetch_word(3), fetch_word(4));
|
||||
f_translation_data.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
u32 const number_of_strings = fetch_word(2);
|
||||
u32 const original_table_offset = fetch_word(3) >> 2;
|
||||
u32 const translation_table_offset = fetch_word(4) >> 2;
|
||||
if ((4 * (original_table_offset + (u64(number_of_strings) * 2))) > size)
|
||||
{
|
||||
osd_printf_error("Error reading translation file %s: %u-entry original string table at offset %u extends past end of %u-byte file\n", name, number_of_strings, fetch_word(3), size);
|
||||
f_translation_data.reset();
|
||||
return;
|
||||
}
|
||||
if ((4 * (translation_table_offset + (u64(number_of_strings) * 2))) > size)
|
||||
{
|
||||
osd_printf_error("Error reading translation file %s: %u-entry translated string table at offset %u extends past end of %u-byte file\n", name, number_of_strings, fetch_word(4), size);
|
||||
f_translation_data.reset();
|
||||
return;
|
||||
}
|
||||
osd_printf_verbose("Reading translation file %s: %u strings, original table at word offset %u, translated table at word offset %u\n", name, number_of_strings, original_table_offset, translation_table_offset);
|
||||
|
||||
char const *const data = reinterpret_cast<char const *>(f_translation_data.get());
|
||||
for (u32 i = 1; number_of_strings > i; ++i)
|
||||
{
|
||||
u32 const original_length = fetch_word(original_table_offset + (2 * i));
|
||||
u32 const original_offset = fetch_word(original_table_offset + (2 * i) + 1);
|
||||
if ((original_length + original_offset) >= size)
|
||||
{
|
||||
osd_printf_error("Error reading translation file %s: %u-byte original string %u at offset %u extends past end of %u-byte file\n", name, original_length, i, original_offset, size);
|
||||
continue;
|
||||
}
|
||||
if (data[original_length + original_offset])
|
||||
{
|
||||
osd_printf_error("Error reading translation file %s: %u-byte original string %u at offset %u is not correctly NUL-terminated\n", name, original_length, i, original_offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
u32 const translation_length = fetch_word(translation_table_offset + (2 * i));
|
||||
u32 const translation_offset = fetch_word(translation_table_offset + (2 * i) + 1);
|
||||
if ((translation_length + translation_offset) >= size)
|
||||
{
|
||||
osd_printf_error("Error reading translation file %s: %u-byte translated string %u at offset %u extends past end of %u-byte file\n", name, translation_length, i, translation_offset, size);
|
||||
continue;
|
||||
}
|
||||
if (data[translation_length + translation_offset])
|
||||
{
|
||||
osd_printf_error("Error reading translation file %s: %u-byte translated string %u at offset %u is not correctly NUL-terminated\n", name, translation_length, i, translation_offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string_view const original(&data[original_offset], original_length);
|
||||
char const *const translation(&data[translation_offset]);
|
||||
auto const ins = f_translation_map.emplace(original, std::make_pair(translation, translation_length));
|
||||
if (!ins.second)
|
||||
{
|
||||
osd_printf_warning(
|
||||
"Loading translation file %s: translation %u '%s'='%s' conflicts with previous translation '%s'='%s'\n",
|
||||
name,
|
||||
i,
|
||||
original,
|
||||
translation,
|
||||
ins.first->first,
|
||||
ins.first->second.first);
|
||||
}
|
||||
}
|
||||
|
||||
osd_printf_verbose("Loaded %u translations from file %s\n", f_translation_map.size(), name);
|
||||
}
|
||||
|
||||
|
||||
char const *lang_translate(char const *message)
|
||||
{
|
||||
auto const found = f_translation_map.find(message);
|
||||
if (f_translation_map.end() != found)
|
||||
return found->second.first;
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
std::string_view lang_translate(std::string_view message)
|
||||
{
|
||||
auto const found = f_translation_map.find(message);
|
||||
if (f_translation_map.end() != found)
|
||||
return std::string_view(found->second.first, found->second.second);
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
char const *lang_translate(char const *context, char const *message)
|
||||
{
|
||||
if (!f_translation_map.empty())
|
||||
{
|
||||
auto const ctxlen(std::strlen(context));
|
||||
auto const msglen(std::strlen(message));
|
||||
std::string key;
|
||||
key.reserve(ctxlen + 1 + msglen);
|
||||
key.append(context, ctxlen);
|
||||
key.append(1, '\004');
|
||||
key.append(message, msglen);
|
||||
auto const found = f_translation_map.find(key);
|
||||
if (f_translation_map.end() != found)
|
||||
return found->second.first;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
std::string_view lang_translate(char const *context, std::string_view message)
|
||||
{
|
||||
return lang_translate(std::string_view(context), message);
|
||||
}
|
||||
|
||||
|
||||
std::string_view lang_translate(std::string_view context, std::string_view message)
|
||||
{
|
||||
if (!f_translation_map.empty())
|
||||
{
|
||||
std::string key;
|
||||
key.reserve(context.length() + 1 + message.length());
|
||||
key.append(context);
|
||||
key.append(1, '\004');
|
||||
key.append(message);
|
||||
auto const found = f_translation_map.find(key);
|
||||
if (f_translation_map.end() != found)
|
||||
return std::string_view(found->second.first, found->second.second);
|
||||
}
|
||||
return message;
|
||||
osd_printf_verbose("Loading translation file %s\n", file.fullpath());
|
||||
util::load_translation(file);
|
||||
}
|
||||
|
@ -12,25 +12,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
#include "util/language.h"
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// LOCALIZATION SUPPORT
|
||||
//**************************************************************************
|
||||
void load_translation(emu_options &options);
|
||||
|
||||
#define _(...) lang_translate(__VA_ARGS__)
|
||||
|
||||
#define N_(msg) (msg)
|
||||
#define N_p(ctx, msg) (msg)
|
||||
|
||||
void load_translation(emu_options &option);
|
||||
|
||||
char const *lang_translate(char const *message);
|
||||
std::string_view lang_translate(std::string_view message);
|
||||
|
||||
char const *lang_translate(char const *context, char const *message);
|
||||
std::string_view lang_translate(char const *context, std::string_view message);
|
||||
std::string_view lang_translate(std::string_view context, std::string_view message);
|
||||
using util::lang_translate;
|
||||
|
||||
#endif // MAME_FRONTEND_MAME_LANGUAGE_H
|
||||
|
@ -747,6 +747,8 @@ void lua_engine::initialize()
|
||||
emu["print_error"] = [] (const char *str) { osd_printf_error("%s\n", str); };
|
||||
emu["print_info"] = [] (const char *str) { osd_printf_info("%s\n", str); };
|
||||
emu["print_debug"] = [] (const char *str) { osd_printf_debug("%s\n", str); };
|
||||
emu["osd_ticks"] = &osd_ticks;
|
||||
emu["osd_ticks_per_second"] = &osd_ticks_per_second;
|
||||
emu["driver_find"] =
|
||||
[] (sol::this_state s, const char *driver) -> sol::object
|
||||
{
|
||||
@ -1737,6 +1739,10 @@ void lua_engine::initialize()
|
||||
ui_type["get_char_width"] = [] (mame_ui_manager &m, uint32_t utf8char) { return m.get_char_width(utf8char); };
|
||||
ui_type["get_string_width"] = &mame_ui_manager::get_string_width;
|
||||
ui_type["set_aggressive_input_focus"] = [](mame_ui_manager &m, bool aggressive_focus) { osd_set_aggressive_input_focus(aggressive_focus); };
|
||||
ui_type["get_general_input_setting"] = sol::overload(
|
||||
// TODO: overload with sequence type string - parser isn't available here
|
||||
[] (mame_ui_manager &ui, ioport_type type, int player) { return ui.get_general_input_setting(type, player, SEQ_TYPE_STANDARD); },
|
||||
[] (mame_ui_manager &ui, ioport_type type) { return ui.get_general_input_setting(type, 0, SEQ_TYPE_STANDARD); });
|
||||
ui_type["options"] = sol::property([] (mame_ui_manager &m) { return static_cast<core_options *>(&m.options()); });
|
||||
ui_type["line_height"] = sol::property(&mame_ui_manager::get_line_height);
|
||||
ui_type["menu_active"] = sol::property(&mame_ui_manager::is_menu_active);
|
||||
|
@ -12,12 +12,9 @@
|
||||
#include "ui/about.h"
|
||||
|
||||
#include "ui/ui.h"
|
||||
#include "ui/utils.h"
|
||||
|
||||
#include "mame.h"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
|
||||
namespace ui {
|
||||
|
||||
@ -38,21 +35,22 @@ namespace {
|
||||
//-------------------------------------------------
|
||||
|
||||
menu_about::menu_about(mame_ui_manager &mui, render_container &container)
|
||||
: menu(mui, container)
|
||||
: menu_textbox(mui, container)
|
||||
, m_header{
|
||||
util::string_format(
|
||||
#ifdef MAME_DEBUG
|
||||
_("%1$s %2$s (%3$s%4$sP%5$s, debug)"),
|
||||
_("about-header", "%1$s %2$s (%3$s%4$sP%5$s, debug)"),
|
||||
#else
|
||||
_("%1$s %2$s (%3$s%4$sP%5$s)"),
|
||||
_("about-header", "%1$s %2$s (%3$s%4$sP%5$s)"),
|
||||
#endif
|
||||
emulator_info::get_appname(),
|
||||
bare_build_version,
|
||||
(sizeof(int) == sizeof(void *)) ? "I" : "",
|
||||
(sizeof(long) == sizeof(void *)) ? "L" : (sizeof(long long) == sizeof(void *)) ? "LL" : "",
|
||||
sizeof(void *) * 8),
|
||||
util::string_format(_("Revision: %1$s"), bare_vcs_revision) }
|
||||
util::string_format(_("about-header", "Revision: %1$s"), bare_vcs_revision) }
|
||||
{
|
||||
set_process_flags(PROCESS_CUSTOM_NAV);
|
||||
}
|
||||
|
||||
|
||||
@ -81,136 +79,23 @@ void menu_about::custom_render(void *selectedref, float top, float bottom, float
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// draw - draw about
|
||||
// populate_text - populate the about box text
|
||||
//-------------------------------------------------
|
||||
|
||||
void menu_about::draw(uint32_t flags)
|
||||
void menu_about::populate_text(std::optional<text_layout> &layout, float &width, int &lines)
|
||||
{
|
||||
rgb_t const color = ui().colors().text_color();
|
||||
float const aspect = machine().render().ui_aspect(&container());
|
||||
float const line_height = ui().get_line_height();
|
||||
float const ud_arrow_width = line_height * aspect;
|
||||
float const gutter_width = 0.52f * line_height * aspect;
|
||||
float const visible_width = 1.0f - (2.0f * ui().box_lr_border() * aspect);
|
||||
float const visible_left = (1.0f - visible_width) * 0.5f;
|
||||
float const extra_height = 2.0f * line_height;
|
||||
float const visible_extra_menu_height = get_customtop() + get_custombottom() + extra_height;
|
||||
|
||||
// determine effective positions taking into account the hilighting arrows
|
||||
float const maximum_width = visible_width - 2.0f * gutter_width;
|
||||
|
||||
draw_background();
|
||||
map_mouse();
|
||||
|
||||
// account for extra space at the top and bottom
|
||||
float visible_main_menu_height = 1.0f - 2.0f * ui().box_tb_border() - visible_extra_menu_height;
|
||||
m_visible_lines = int(std::trunc(visible_main_menu_height / line_height));
|
||||
visible_main_menu_height = float(m_visible_lines) * line_height;
|
||||
|
||||
// compute top/left of inner menu area by centering, if the menu is at the bottom of the extra, adjust
|
||||
float const visible_top = ((1.0f - (visible_main_menu_height + visible_extra_menu_height)) * 0.5f) + get_customtop();
|
||||
|
||||
// lay out the text if necessary
|
||||
if (!m_layout || (m_layout->width() != maximum_width))
|
||||
if (!layout || (layout->width() != width))
|
||||
{
|
||||
m_layout.emplace(ui().create_layout(container(), maximum_width));
|
||||
rgb_t const color = ui().colors().text_color();
|
||||
layout.emplace(ui().create_layout(container(), width));
|
||||
for (char const *const *line = copying_text; *line; ++line)
|
||||
{
|
||||
m_layout->add_text(*line, color);
|
||||
m_layout->add_text("\n", color);
|
||||
layout->add_text(*line, color);
|
||||
layout->add_text("\n", color);
|
||||
}
|
||||
lines = layout->lines();
|
||||
}
|
||||
float const actual_width = m_layout->actual_width();
|
||||
|
||||
// compute text box size
|
||||
float const x1 = visible_left + ((maximum_width - actual_width) * 0.5f);
|
||||
float const y1 = visible_top - ui().box_tb_border();
|
||||
float const x2 = visible_left + visible_width - ((maximum_width - actual_width) * 0.5f);
|
||||
float const y2 = visible_top + visible_main_menu_height + ui().box_tb_border() + extra_height;
|
||||
float const effective_left = x1 + gutter_width;
|
||||
float const line_x0 = x1 + 0.5f * UI_LINE_WIDTH;
|
||||
float const line_x1 = x2 - 0.5f * UI_LINE_WIDTH;
|
||||
float const separator = visible_top + float(m_visible_lines) * line_height;
|
||||
|
||||
ui().draw_outlined_box(container(), x1, y1, x2, y2, ui().colors().background_color());
|
||||
|
||||
int const visible_items = m_layout->lines();
|
||||
m_visible_lines = (std::min)(visible_items, m_visible_lines);
|
||||
top_line = (std::max)(0, top_line);
|
||||
if (top_line + m_visible_lines >= visible_items)
|
||||
top_line = visible_items - m_visible_lines;
|
||||
|
||||
clear_hover();
|
||||
if (top_line)
|
||||
{
|
||||
// if we're on the top line, display the up arrow
|
||||
rgb_t fgcolor = ui().colors().text_color();
|
||||
if (mouse_in_rect(line_x0, visible_top, line_x1, visible_top + line_height))
|
||||
{
|
||||
fgcolor = ui().colors().mouseover_color();
|
||||
highlight(
|
||||
line_x0, visible_top,
|
||||
line_x1, visible_top + line_height,
|
||||
ui().colors().mouseover_bg_color());
|
||||
set_hover(HOVER_ARROW_UP);
|
||||
}
|
||||
draw_arrow(
|
||||
0.5f * (x1 + x2) - 0.5f * ud_arrow_width, visible_top + 0.25f * line_height,
|
||||
0.5f * (x1 + x2) + 0.5f * ud_arrow_width, visible_top + 0.75f * line_height,
|
||||
fgcolor, ROT0);
|
||||
}
|
||||
if ((top_line + m_visible_lines) < visible_items)
|
||||
{
|
||||
// if we're on the bottom line, display the down arrow
|
||||
float const line_y = visible_top + float(m_visible_lines - 1) * line_height;
|
||||
rgb_t fgcolor = ui().colors().text_color();
|
||||
if (mouse_in_rect(line_x0, line_y, line_x1, line_y + line_height))
|
||||
{
|
||||
fgcolor = ui().colors().mouseover_color();
|
||||
highlight(
|
||||
line_x0, line_y,
|
||||
line_x1, line_y + line_height,
|
||||
ui().colors().mouseover_bg_color());
|
||||
set_hover(HOVER_ARROW_DOWN);
|
||||
}
|
||||
draw_arrow(
|
||||
0.5f * (x1 + x2) - 0.5f * ud_arrow_width, line_y + 0.25f * line_height,
|
||||
0.5f * (x1 + x2) + 0.5f * ud_arrow_width, line_y + 0.75f * line_height,
|
||||
fgcolor, ROT0 ^ ORIENTATION_FLIP_Y);
|
||||
}
|
||||
|
||||
// return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow
|
||||
m_visible_items = m_visible_lines - (top_line ? 1 : 0) - (top_line + m_visible_lines != visible_items);
|
||||
m_layout->emit(
|
||||
container(),
|
||||
top_line ? (top_line + 1) : 0, m_visible_items,
|
||||
effective_left, visible_top + (top_line ? line_height : 0.0f));
|
||||
|
||||
// add visual separator before the "return to prevous menu" item
|
||||
container().add_line(
|
||||
x1, separator + (0.5f * line_height),
|
||||
x2, separator + (0.5f * line_height),
|
||||
UI_LINE_WIDTH, ui().colors().text_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
|
||||
|
||||
menu_item const &pitem = item(0);
|
||||
std::string_view const itemtext = pitem.text;
|
||||
float const line_y0 = separator + line_height;
|
||||
float const line_y1 = line_y0 + line_height;
|
||||
|
||||
if (mouse_in_rect(line_x0, line_y0, line_x1, line_y1) && is_selectable(pitem))
|
||||
set_hover(0);
|
||||
|
||||
highlight(line_x0, line_y0, line_x1, line_y1, ui().colors().selected_bg_color());
|
||||
ui().draw_text_full(
|
||||
container(), itemtext,
|
||||
effective_left, line_y0, actual_width,
|
||||
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE,
|
||||
mame_ui_manager::NORMAL,
|
||||
ui().colors().selected_color(), ui().colors().selected_bg_color(),
|
||||
nullptr, nullptr);
|
||||
|
||||
// if there is something special to add, do it by calling the virtual method
|
||||
custom_render(get_selection_ref(), get_customtop(), get_custombottom(), x1, y1, x2, y2);
|
||||
width = layout->actual_width();
|
||||
}
|
||||
|
||||
|
||||
@ -229,38 +114,10 @@ void menu_about::populate(float &customtop, float &custombottom)
|
||||
// handle - manages inputs in the about modal
|
||||
//-------------------------------------------------
|
||||
|
||||
void menu_about::handle()
|
||||
void menu_about::handle(event const *ev)
|
||||
{
|
||||
const event *event = process(PROCESS_CUSTOM_NAV);
|
||||
if (event)
|
||||
{
|
||||
switch (event->iptkey)
|
||||
{
|
||||
case IPT_UI_UP:
|
||||
--top_line;
|
||||
break;
|
||||
|
||||
case IPT_UI_DOWN:
|
||||
++top_line;
|
||||
break;
|
||||
|
||||
case IPT_UI_PAGE_UP:
|
||||
top_line -= m_visible_lines - 3;
|
||||
break;
|
||||
|
||||
case IPT_UI_PAGE_DOWN:
|
||||
top_line += m_visible_lines - 3;
|
||||
break;
|
||||
|
||||
case IPT_UI_HOME:
|
||||
top_line = 0;
|
||||
break;
|
||||
|
||||
case IPT_UI_END:
|
||||
top_line = m_layout->lines() - m_visible_lines;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ev)
|
||||
handle_key(ev->iptkey);
|
||||
}
|
||||
|
||||
};
|
||||
} // namespace ui
|
||||
|
@ -12,7 +12,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ui/menu.h"
|
||||
#include "ui/text.h"
|
||||
#include "ui/textbox.h"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
@ -21,7 +22,7 @@
|
||||
|
||||
namespace ui {
|
||||
|
||||
class menu_about : public menu
|
||||
class menu_about : public menu_textbox
|
||||
{
|
||||
public:
|
||||
menu_about(mame_ui_manager &mui, render_container &container);
|
||||
@ -30,13 +31,13 @@ public:
|
||||
protected:
|
||||
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
|
||||
|
||||
virtual void populate_text(std::optional<text_layout> &layout, float &width, int &lines) override;
|
||||
|
||||
private:
|
||||
virtual void draw(uint32_t flags) override;
|
||||
virtual void populate(float &customtop, float &custombottom) override;
|
||||
virtual void handle() override;
|
||||
virtual void handle(event const *ev) override;
|
||||
|
||||
std::vector<std::string> const m_header;
|
||||
std::optional<text_layout> m_layout;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
@ -52,6 +52,7 @@ menu_analog::menu_analog(mame_ui_manager &mui, render_container &container)
|
||||
, m_field_data()
|
||||
, m_visible_fields(0U)
|
||||
{
|
||||
set_process_flags(PROCESS_LR_REPEAT);
|
||||
}
|
||||
|
||||
|
||||
@ -121,18 +122,15 @@ void menu_analog::custom_render(void *selectedref, float top, float bottom, floa
|
||||
}
|
||||
|
||||
|
||||
void menu_analog::handle()
|
||||
void menu_analog::handle(event const *ev)
|
||||
{
|
||||
// process the menu
|
||||
event const *const menu_event(process(PROCESS_LR_REPEAT));
|
||||
|
||||
// handle events
|
||||
if (menu_event && menu_event->itemref)
|
||||
if (ev && ev->itemref)
|
||||
{
|
||||
item_data &data(*reinterpret_cast<item_data *>(menu_event->itemref));
|
||||
item_data &data(*reinterpret_cast<item_data *>(ev->itemref));
|
||||
int newval(data.cur);
|
||||
|
||||
switch (menu_event->iptkey)
|
||||
switch (ev->iptkey)
|
||||
{
|
||||
// if selected, reset to default value
|
||||
case IPT_UI_SELECT:
|
||||
|
@ -66,7 +66,7 @@ private:
|
||||
using field_data_vector = std::vector<field_data>;
|
||||
|
||||
virtual void populate(float &customtop, float &custombottom) override;
|
||||
virtual void handle() override;
|
||||
virtual void handle(event const *ev) override;
|
||||
|
||||
void find_fields();
|
||||
|
||||
|
@ -139,32 +139,28 @@ void menu_audit::populate(float &customtop, float &custombottom)
|
||||
custombottom = (ui().get_line_height() * 1.0f) + (ui().box_tb_border() * 3.0f);
|
||||
}
|
||||
|
||||
void menu_audit::handle()
|
||||
void menu_audit::handle(event const *ev)
|
||||
{
|
||||
switch (m_phase)
|
||||
{
|
||||
case phase::CONFIRMATION:
|
||||
if (ev && (IPT_UI_SELECT == ev->iptkey))
|
||||
{
|
||||
event const *const menu_event(process(0));
|
||||
if (menu_event && (IPT_UI_SELECT == menu_event->iptkey))
|
||||
if ((ITEMREF_START_FULL == ev->itemref) || (ITEMREF_START_FAST == ev->itemref))
|
||||
{
|
||||
if ((ITEMREF_START_FULL == menu_event->itemref) || (ITEMREF_START_FAST == menu_event->itemref))
|
||||
{
|
||||
m_phase = phase::AUDIT;
|
||||
m_fast = ITEMREF_START_FAST == menu_event->itemref;
|
||||
m_prompt = util::string_format(_("Press %1$s to cancel\n"), ui().get_general_input_setting(IPT_UI_CANCEL));
|
||||
m_future.resize(std::thread::hardware_concurrency());
|
||||
for (auto &future : m_future)
|
||||
future = std::async(std::launch::async, [this] () { return do_audit(); });
|
||||
}
|
||||
set_process_flags(PROCESS_CUSTOM_ONLY | PROCESS_NOINPUT);
|
||||
m_phase = phase::AUDIT;
|
||||
m_fast = ITEMREF_START_FAST == ev->itemref;
|
||||
m_prompt = util::string_format(_("Press %1$s to cancel\n"), ui().get_general_input_setting(IPT_UI_CANCEL));
|
||||
m_future.resize(std::thread::hardware_concurrency());
|
||||
for (auto &future : m_future)
|
||||
future = std::async(std::launch::async, [this] () { return do_audit(); });
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case phase::AUDIT:
|
||||
case phase::CANCELLATION:
|
||||
process(PROCESS_CUSTOM_ONLY | PROCESS_NOINPUT);
|
||||
|
||||
if ((m_next.load() >= m_availablesorted.size()) || m_cancel.load())
|
||||
{
|
||||
bool done(true);
|
||||
|
@ -36,7 +36,7 @@ private:
|
||||
enum class phase { CONFIRMATION, AUDIT, CANCELLATION };
|
||||
|
||||
virtual void populate(float &customtop, float &custombottom) override;
|
||||
virtual void handle() override;
|
||||
virtual void handle(event const *ev) override;
|
||||
|
||||
bool do_audit();
|
||||
void save_available_machines();
|
||||
|
@ -9,12 +9,14 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
|
||||
#include "ui/barcode.h"
|
||||
|
||||
#include "ui/ui.h"
|
||||
#include "ui/utils.h"
|
||||
|
||||
|
||||
namespace ui {
|
||||
|
||||
// itemrefs for key menu items
|
||||
#define ITEMREF_NEW_BARCODE ((void *) 0x0001)
|
||||
#define ITEMREF_ENTER_BARCODE ((void *) 0x0002)
|
||||
@ -35,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_process_flags(PROCESS_LR_REPEAT);
|
||||
}
|
||||
|
||||
|
||||
@ -86,29 +89,26 @@ void menu_barcode_reader::populate(float &customtop, float &custombottom)
|
||||
// handle - manages inputs in the barcode input menu
|
||||
//-------------------------------------------------
|
||||
|
||||
void menu_barcode_reader::handle()
|
||||
void menu_barcode_reader::handle(event const *ev)
|
||||
{
|
||||
// process the menu
|
||||
const event *event = process(PROCESS_LR_REPEAT);
|
||||
|
||||
// process the event
|
||||
if (event)
|
||||
if (ev)
|
||||
{
|
||||
// handle selections
|
||||
switch (event->iptkey)
|
||||
switch (ev->iptkey)
|
||||
{
|
||||
case IPT_UI_LEFT:
|
||||
if (event->itemref == ITEMREF_SELECT_READER)
|
||||
if (ev->itemref == ITEMREF_SELECT_READER)
|
||||
previous();
|
||||
break;
|
||||
|
||||
case IPT_UI_RIGHT:
|
||||
if (event->itemref == ITEMREF_SELECT_READER)
|
||||
if (ev->itemref == ITEMREF_SELECT_READER)
|
||||
next();
|
||||
break;
|
||||
|
||||
case IPT_UI_SELECT:
|
||||
if (event->itemref == ITEMREF_ENTER_BARCODE)
|
||||
if (ev->itemref == ITEMREF_ENTER_BARCODE)
|
||||
{
|
||||
std::string tmp_file(m_barcode_buffer);
|
||||
//printf("code %s\n", m_barcode_buffer);
|
||||
@ -135,7 +135,7 @@ void menu_barcode_reader::handle()
|
||||
case IPT_SPECIAL:
|
||||
if (get_selection_ref() == ITEMREF_NEW_BARCODE)
|
||||
{
|
||||
if (input_character(m_barcode_buffer, event->unichar, uchar_is_digit))
|
||||
if (input_character(m_barcode_buffer, ev->unichar, uchar_is_digit))
|
||||
reset(reset_options::REMEMBER_POSITION);
|
||||
}
|
||||
break;
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "ui/devctrl.h"
|
||||
|
||||
namespace ui {
|
||||
|
||||
class menu_barcode_reader : public menu_device_control<barcode_reader_device> {
|
||||
public:
|
||||
menu_barcode_reader(mame_ui_manager &mui, render_container &container, barcode_reader_device *device);
|
||||
@ -24,7 +25,7 @@ public:
|
||||
|
||||
private:
|
||||
virtual void populate(float &customtop, float &custombottom) override;
|
||||
virtual void handle() override;
|
||||
virtual void handle(event const *ev) override;
|
||||
|
||||
std::string m_barcode_buffer;
|
||||
};
|
||||
|
@ -9,12 +9,12 @@
|
||||
*********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "cheat.h"
|
||||
#include "mame.h"
|
||||
#include "ui/cheatopt.h"
|
||||
|
||||
#include "ui/ui.h"
|
||||
#include "ui/menu.h"
|
||||
#include "ui/cheatopt.h"
|
||||
|
||||
#include "cheat.h"
|
||||
#include "mame.h"
|
||||
|
||||
|
||||
namespace ui {
|
||||
@ -29,78 +29,73 @@ namespace ui {
|
||||
menu_cheat - handle the cheat menu
|
||||
-------------------------------------------------*/
|
||||
|
||||
void menu_cheat::handle()
|
||||
void menu_cheat::handle(event const *ev)
|
||||
{
|
||||
/* process the menu */
|
||||
const event *menu_event = process(PROCESS_LR_REPEAT);
|
||||
|
||||
|
||||
/* handle events */
|
||||
if (menu_event != nullptr && menu_event->itemref != nullptr)
|
||||
// handle events
|
||||
if (ev && ev->itemref)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
/* clear cheat comment on any movement or keypress */
|
||||
// clear cheat comment on any movement or keypress
|
||||
machine().popmessage();
|
||||
|
||||
/* handle reset all + reset all cheats for reload all option */
|
||||
if ((menu_event->itemref == ITEMREF_CHEATS_RESET_ALL || menu_event->itemref == ITEMREF_CHEATS_RELOAD_ALL) && menu_event->iptkey == IPT_UI_SELECT)
|
||||
if ((ev->itemref == ITEMREF_CHEATS_RESET_ALL || ev->itemref == ITEMREF_CHEATS_RELOAD_ALL) && ev->iptkey == IPT_UI_SELECT)
|
||||
{
|
||||
// handle reset all + reset all cheats for reload all option
|
||||
for (auto &curcheat : mame_machine_manager::instance()->cheat().entries())
|
||||
if (curcheat->select_default_state())
|
||||
changed = true;
|
||||
}
|
||||
|
||||
/* handle individual cheats */
|
||||
else if (menu_event->itemref >= ITEMREF_CHEATS_FIRST_ITEM)
|
||||
else if (ev->itemref >= ITEMREF_CHEATS_FIRST_ITEM)
|
||||
{
|
||||
cheat_entry *curcheat = reinterpret_cast<cheat_entry *>(menu_event->itemref);
|
||||
// handle individual cheats
|
||||
cheat_entry *curcheat = reinterpret_cast<cheat_entry *>(ev->itemref);
|
||||
const char *string;
|
||||
switch (menu_event->iptkey)
|
||||
switch (ev->iptkey)
|
||||
{
|
||||
/* if selected, activate a oneshot */
|
||||
// if selected, activate a oneshot
|
||||
case IPT_UI_SELECT:
|
||||
changed = curcheat->activate();
|
||||
break;
|
||||
|
||||
/* if cleared, reset to default value */
|
||||
// if cleared, reset to default value
|
||||
case IPT_UI_CLEAR:
|
||||
changed = curcheat->select_default_state();
|
||||
break;
|
||||
|
||||
/* left decrements */
|
||||
// left decrements
|
||||
case IPT_UI_LEFT:
|
||||
changed = curcheat->select_previous_state();
|
||||
break;
|
||||
|
||||
/* right increments */
|
||||
// right increments
|
||||
case IPT_UI_RIGHT:
|
||||
changed = curcheat->select_next_state();
|
||||
break;
|
||||
|
||||
/* bring up display comment if one exists */
|
||||
// bring up display comment if one exists
|
||||
case IPT_UI_DISPLAY_COMMENT:
|
||||
case IPT_UI_UP:
|
||||
case IPT_UI_DOWN:
|
||||
string = curcheat->comment();
|
||||
if (string != nullptr && string[0] != 0)
|
||||
if (string && *string)
|
||||
machine().popmessage(_("Cheat Comment:\n%s"), string);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* handle reload all */
|
||||
if (menu_event->itemref == ITEMREF_CHEATS_RELOAD_ALL && menu_event->iptkey == IPT_UI_SELECT)
|
||||
// handle reload all
|
||||
if (ev->itemref == ITEMREF_CHEATS_RELOAD_ALL && ev->iptkey == IPT_UI_SELECT)
|
||||
{
|
||||
/* re-init cheat engine and thus reload cheats/cheats have already been turned off by here */
|
||||
// re-init cheat engine and thus reload cheats/cheats have already been turned off by here
|
||||
mame_machine_manager::instance()->cheat().reload();
|
||||
|
||||
/* display the reloaded cheats */
|
||||
// display the reloaded cheats
|
||||
reset(reset_options::REMEMBER_REF);
|
||||
machine().popmessage(_("All cheats reloaded"));
|
||||
}
|
||||
|
||||
/* if things changed, update */
|
||||
// if things changed, update
|
||||
if (changed)
|
||||
reset(reset_options::REMEMBER_REF);
|
||||
}
|
||||
@ -113,6 +108,7 @@ void menu_cheat::handle()
|
||||
|
||||
menu_cheat::menu_cheat(mame_ui_manager &mui, render_container &container) : menu(mui, container)
|
||||
{
|
||||
set_process_flags(PROCESS_LR_REPEAT);
|
||||
}
|
||||
|
||||
void menu_cheat::populate(float &customtop, float &custombottom)
|
||||
|
@ -25,7 +25,7 @@ public:
|
||||
|
||||
private:
|
||||
virtual void populate(float &customtop, float &custombottom) override;
|
||||
virtual void handle() override;
|
||||
virtual void handle(event const *ev) override;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
@ -82,6 +82,13 @@ menu_confswitch::~menu_confswitch()
|
||||
}
|
||||
|
||||
|
||||
void menu_confswitch::menu_activated()
|
||||
{
|
||||
// switches can have input assignments, and scripts are a thing
|
||||
reset(reset_options::REMEMBER_REF);
|
||||
}
|
||||
|
||||
|
||||
void menu_confswitch::populate(float &customtop, float &custombottom)
|
||||
{
|
||||
// locate relevant fields if necessary
|
||||
@ -162,31 +169,28 @@ void menu_confswitch::populate(float &customtop, float &custombottom)
|
||||
}
|
||||
|
||||
item_append(menu_item_type::SEPARATOR);
|
||||
item_append(_("Reset"), 0, (void *)1);
|
||||
item_append(_("Reset Machine"), 0, (void *)1);
|
||||
}
|
||||
|
||||
|
||||
void menu_confswitch::handle()
|
||||
void menu_confswitch::handle(event const *ev)
|
||||
{
|
||||
// process the menu
|
||||
event const *const menu_event(process(0));
|
||||
|
||||
// handle events
|
||||
if (menu_event && menu_event->itemref)
|
||||
if (ev && ev->itemref)
|
||||
{
|
||||
if (uintptr_t(menu_event->itemref) == 1U)
|
||||
if (uintptr_t(ev->itemref) == 1U)
|
||||
{
|
||||
// reset
|
||||
if (menu_event->iptkey == IPT_UI_SELECT)
|
||||
if (ev->iptkey == IPT_UI_SELECT)
|
||||
machine().schedule_hard_reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
// actual settings
|
||||
ioport_field &field(*reinterpret_cast<ioport_field *>(menu_event->itemref));
|
||||
ioport_field &field(*reinterpret_cast<ioport_field *>(ev->itemref));
|
||||
bool changed(false);
|
||||
|
||||
switch (menu_event->iptkey)
|
||||
switch (ev->iptkey)
|
||||
{
|
||||
// if selected, reset to default value
|
||||
case IPT_UI_SELECT:
|
||||
|
@ -56,6 +56,7 @@ protected:
|
||||
|
||||
menu_confswitch(mame_ui_manager &mui, render_container &container, uint32_t type);
|
||||
|
||||
virtual void menu_activated() override;
|
||||
virtual void populate(float &customtop, float &custombottom) override;
|
||||
|
||||
field_vector const &fields() { return m_fields; }
|
||||
@ -63,7 +64,7 @@ protected:
|
||||
unsigned active_switch_groups() const { return m_active_switch_groups; }
|
||||
|
||||
private:
|
||||
virtual void handle() override;
|
||||
virtual void handle(event const *ev) override;
|
||||
|
||||
void find_fields();
|
||||
|
||||
|
@ -45,6 +45,7 @@ menu_custom_ui::menu_custom_ui(mame_ui_manager &mui, render_container &container
|
||||
, m_currlang(0)
|
||||
, m_currsysnames(0)
|
||||
{
|
||||
set_process_flags(PROCESS_LR_REPEAT);
|
||||
find_languages();
|
||||
find_sysnames();
|
||||
}
|
||||
@ -72,19 +73,17 @@ menu_custom_ui::~menu_custom_ui()
|
||||
// handle
|
||||
//-------------------------------------------------
|
||||
|
||||
void menu_custom_ui::handle()
|
||||
void menu_custom_ui::handle(event const *ev)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
// process the menu
|
||||
const event *menu_event = process(PROCESS_LR_REPEAT);
|
||||
|
||||
if (menu_event != nullptr && menu_event->itemref != nullptr)
|
||||
if (ev && ev->itemref)
|
||||
{
|
||||
switch ((uintptr_t)menu_event->itemref)
|
||||
switch ((uintptr_t)ev->itemref)
|
||||
{
|
||||
case FONT_MENU:
|
||||
if (menu_event->iptkey == IPT_UI_SELECT)
|
||||
if (ev->iptkey == IPT_UI_SELECT)
|
||||
menu::stack_push<menu_font_ui>(
|
||||
ui(),
|
||||
container(),
|
||||
@ -95,16 +94,16 @@ void menu_custom_ui::handle()
|
||||
});
|
||||
break;
|
||||
case COLORS_MENU:
|
||||
if (menu_event->iptkey == IPT_UI_SELECT)
|
||||
if (ev->iptkey == IPT_UI_SELECT)
|
||||
menu::stack_push<menu_colors_ui>(ui(), container());
|
||||
break;
|
||||
case HIDE_MENU:
|
||||
if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
|
||||
if (ev->iptkey == IPT_UI_LEFT || ev->iptkey == IPT_UI_RIGHT)
|
||||
{
|
||||
changed = true;
|
||||
(menu_event->iptkey == IPT_UI_RIGHT) ? ui_globals::panels_status++ : ui_globals::panels_status--;
|
||||
(ev->iptkey == IPT_UI_RIGHT) ? ui_globals::panels_status++ : ui_globals::panels_status--;
|
||||
}
|
||||
else if (menu_event->iptkey == IPT_UI_SELECT)
|
||||
else if (ev->iptkey == IPT_UI_SELECT)
|
||||
{
|
||||
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); });
|
||||
@ -118,15 +117,15 @@ void menu_custom_ui::handle()
|
||||
}
|
||||
break;
|
||||
case LANGUAGE_MENU:
|
||||
if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
|
||||
if (ev->iptkey == IPT_UI_LEFT || ev->iptkey == IPT_UI_RIGHT)
|
||||
{
|
||||
changed = true;
|
||||
if (menu_event->iptkey == IPT_UI_LEFT)
|
||||
if (ev->iptkey == IPT_UI_LEFT)
|
||||
m_currlang = (m_currlang ? m_currlang : m_languages.size())- 1;
|
||||
else if (++m_currlang >= m_languages.size())
|
||||
m_currlang = 0;
|
||||
}
|
||||
else if (menu_event->iptkey == IPT_UI_SELECT)
|
||||
else if (ev->iptkey == IPT_UI_SELECT)
|
||||
{
|
||||
// copying list of language names - expensive
|
||||
menu::stack_push<menu_selector>(
|
||||
@ -139,15 +138,15 @@ void menu_custom_ui::handle()
|
||||
}
|
||||
break;
|
||||
case SYSNAMES_MENU:
|
||||
if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
|
||||
if (ev->iptkey == IPT_UI_LEFT || ev->iptkey == IPT_UI_RIGHT)
|
||||
{
|
||||
changed = true;
|
||||
if (menu_event->iptkey == IPT_UI_LEFT)
|
||||
if (ev->iptkey == IPT_UI_LEFT)
|
||||
m_currsysnames = (m_currsysnames ? m_currsysnames : m_sysnames.size())- 1;
|
||||
else if (++m_currsysnames >= m_sysnames.size())
|
||||
m_currsysnames = 0;
|
||||
}
|
||||
else if (menu_event->iptkey == IPT_UI_SELECT)
|
||||
else if (ev->iptkey == IPT_UI_SELECT)
|
||||
{
|
||||
// copying list of file names - expensive
|
||||
menu::stack_push<menu_selector>(
|
||||
@ -308,6 +307,8 @@ menu_font_ui::menu_font_ui(mame_ui_manager &mui, render_container &container, st
|
||||
, m_changed(false)
|
||||
, m_actual(0U)
|
||||
{
|
||||
set_process_flags(PROCESS_LR_REPEAT);
|
||||
|
||||
std::string name(mui.machine().options().ui_font());
|
||||
list();
|
||||
|
||||
@ -374,41 +375,39 @@ menu_font_ui::~menu_font_ui()
|
||||
// handle
|
||||
//-------------------------------------------------
|
||||
|
||||
void menu_font_ui::handle()
|
||||
void menu_font_ui::handle(event const *ev)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
// process the menu
|
||||
const event *menu_event = process(PROCESS_LR_REPEAT);
|
||||
|
||||
if (menu_event && menu_event->itemref)
|
||||
if (ev && ev->itemref)
|
||||
{
|
||||
switch ((uintptr_t)menu_event->itemref)
|
||||
switch ((uintptr_t)ev->itemref)
|
||||
{
|
||||
case INFOS_SIZE:
|
||||
if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
|
||||
if (ev->iptkey == IPT_UI_LEFT || ev->iptkey == IPT_UI_RIGHT)
|
||||
{
|
||||
(menu_event->iptkey == IPT_UI_RIGHT) ? m_info_size += 0.05f : m_info_size -= 0.05f;
|
||||
(ev->iptkey == IPT_UI_RIGHT) ? m_info_size += 0.05f : m_info_size -= 0.05f;
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case FONT_SIZE:
|
||||
if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
|
||||
if (ev->iptkey == IPT_UI_LEFT || ev->iptkey == IPT_UI_RIGHT)
|
||||
{
|
||||
(menu_event->iptkey == IPT_UI_RIGHT) ? m_font_size++ : m_font_size--;
|
||||
(ev->iptkey == IPT_UI_RIGHT) ? m_font_size++ : m_font_size--;
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case MUI_FNT:
|
||||
if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
|
||||
if (ev->iptkey == IPT_UI_LEFT || ev->iptkey == IPT_UI_RIGHT)
|
||||
{
|
||||
(menu_event->iptkey == IPT_UI_RIGHT) ? m_actual++ : m_actual--;
|
||||
(ev->iptkey == IPT_UI_RIGHT) ? m_actual++ : m_actual--;
|
||||
changed = true;
|
||||
}
|
||||
else if (menu_event->iptkey == IPT_UI_SELECT)
|
||||
else if (ev->iptkey == IPT_UI_SELECT)
|
||||
{
|
||||
std::vector<std::string> display_names;
|
||||
display_names.reserve(m_fonts.size());
|
||||
@ -428,9 +427,9 @@ void menu_font_ui::handle()
|
||||
#ifdef UI_WINDOWS
|
||||
case MUI_BOLD:
|
||||
case MUI_ITALIC:
|
||||
if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT || menu_event->iptkey == IPT_UI_SELECT)
|
||||
if (ev->iptkey == IPT_UI_LEFT || ev->iptkey == IPT_UI_RIGHT || ev->iptkey == IPT_UI_SELECT)
|
||||
{
|
||||
((uintptr_t)menu_event->itemref == MUI_BOLD) ? m_bold = !m_bold : m_italic = !m_italic;
|
||||
((uintptr_t)ev->itemref == MUI_BOLD) ? m_bold = !m_bold : m_italic = !m_italic;
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
@ -551,17 +550,17 @@ menu_colors_ui::~menu_colors_ui()
|
||||
// handle
|
||||
//-------------------------------------------------
|
||||
|
||||
void menu_colors_ui::handle()
|
||||
void menu_colors_ui::handle(event const *ev)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
// process the menu
|
||||
const event *menu_event = process(0);
|
||||
|
||||
if (menu_event != nullptr && menu_event->itemref != nullptr && menu_event->iptkey == IPT_UI_SELECT)
|
||||
if (ev && ev->itemref && ev->iptkey == IPT_UI_SELECT)
|
||||
{
|
||||
if ((uintptr_t)menu_event->itemref != MUI_RESTORE)
|
||||
menu::stack_push<menu_rgb_ui>(ui(), container(), &m_color_table[(uintptr_t)menu_event->itemref].color, selected_item().text);
|
||||
if ((uintptr_t)ev->itemref != MUI_RESTORE)
|
||||
{
|
||||
menu::stack_push<menu_rgb_ui>(ui(), container(), &m_color_table[(uintptr_t)ev->itemref].color, selected_item().text);
|
||||
}
|
||||
else
|
||||
{
|
||||
changed = true;
|
||||
@ -767,6 +766,7 @@ menu_rgb_ui::menu_rgb_ui(mame_ui_manager &mui, render_container &container, rgb_
|
||||
m_lock_ref(0),
|
||||
m_title(_title)
|
||||
{
|
||||
set_process_flags(PROCESS_LR_REPEAT);
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
@ -781,26 +781,19 @@ menu_rgb_ui::~menu_rgb_ui()
|
||||
// handle
|
||||
//-------------------------------------------------
|
||||
|
||||
void menu_rgb_ui::handle()
|
||||
void menu_rgb_ui::handle(event const *ev)
|
||||
{
|
||||
// process the menu
|
||||
const event *menu_event;
|
||||
|
||||
if (!m_key_active)
|
||||
menu_event = process(PROCESS_LR_REPEAT);
|
||||
else
|
||||
menu_event = process(PROCESS_ONLYCHAR);
|
||||
|
||||
if (menu_event && menu_event->itemref != nullptr)
|
||||
if (ev && ev->itemref)
|
||||
{
|
||||
bool changed = false;
|
||||
switch (menu_event->iptkey)
|
||||
switch (ev->iptkey)
|
||||
{
|
||||
case IPT_UI_LEFT:
|
||||
case IPT_UI_RIGHT:
|
||||
{
|
||||
int updated = (IPT_UI_LEFT == menu_event->iptkey) ? -1 : 1;
|
||||
switch (uintptr_t(menu_event->itemref))
|
||||
int updated = (IPT_UI_LEFT == ev->iptkey) ? -1 : 1;
|
||||
switch (uintptr_t(ev->itemref))
|
||||
{
|
||||
case RGB_ALPHA:
|
||||
updated += m_color->a();
|
||||
@ -839,20 +832,20 @@ void menu_rgb_ui::handle()
|
||||
break;
|
||||
|
||||
case IPT_UI_SELECT:
|
||||
if (uintptr_t(menu_event->itemref) == PALETTE_CHOOSE)
|
||||
if (uintptr_t(ev->itemref) == PALETTE_CHOOSE)
|
||||
{
|
||||
menu::stack_push<menu_palette_sel>(ui(), container(), *m_color);
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case IPT_SPECIAL:
|
||||
switch (uintptr_t(menu_event->itemref))
|
||||
switch (uintptr_t(ev->itemref))
|
||||
{
|
||||
case RGB_ALPHA:
|
||||
case RGB_RED:
|
||||
case RGB_GREEN:
|
||||
case RGB_BLUE:
|
||||
inkey_special(menu_event);
|
||||
inkey_special(ev);
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
@ -1004,6 +997,7 @@ void menu_rgb_ui::inkey_special(const event *menu_event)
|
||||
if (menu_event->iptkey == IPT_UI_SELECT)
|
||||
{
|
||||
m_key_active = !m_key_active;
|
||||
set_process_flags(m_key_active ? PROCESS_ONLYCHAR : PROCESS_LR_REPEAT);
|
||||
m_lock_ref = (uintptr_t)menu_event->itemref;
|
||||
|
||||
if (!m_key_active)
|
||||
@ -1079,13 +1073,12 @@ menu_palette_sel::~menu_palette_sel()
|
||||
// handle
|
||||
//-------------------------------------------------
|
||||
|
||||
void menu_palette_sel::handle()
|
||||
void menu_palette_sel::handle(event const *ev)
|
||||
{
|
||||
// process the menu
|
||||
const event *menu_event = process(0);
|
||||
if (menu_event != nullptr && menu_event->itemref != nullptr)
|
||||
if (ev && ev->itemref)
|
||||
{
|
||||
if (menu_event->iptkey == IPT_UI_SELECT)
|
||||
if (ev->iptkey == IPT_UI_SELECT)
|
||||
{
|
||||
m_original = rgb_t(uint32_t(strtoul(selected_item().subtext.c_str(), nullptr, 16)));
|
||||
reset_parent(reset_options::SELECT_FIRST);
|
||||
|
@ -44,7 +44,7 @@ private:
|
||||
};
|
||||
|
||||
virtual void populate(float &customtop, float &custombottom) override;
|
||||
virtual void handle() override;
|
||||
virtual void handle(event const *ev) override;
|
||||
|
||||
void find_languages();
|
||||
void find_sysnames();
|
||||
@ -82,7 +82,7 @@ private:
|
||||
};
|
||||
|
||||
virtual void populate(float &customtop, float &custombottom) override;
|
||||
virtual void handle() override;
|
||||
virtual void handle(event const *ev) override;
|
||||
|
||||
void list();
|
||||
|
||||
@ -143,7 +143,7 @@ private:
|
||||
};
|
||||
|
||||
virtual void populate(float &customtop, float &custombottom) override;
|
||||
virtual void handle() override;
|
||||
virtual void handle(event const *ev) override;
|
||||
|
||||
s_color_table m_color_table[MUI_RESTORE];
|
||||
void restore_colors();
|
||||
@ -173,7 +173,7 @@ private:
|
||||
};
|
||||
|
||||
virtual void populate(float &customtop, float &custombottom) override;
|
||||
virtual void handle() override;
|
||||
virtual void handle(event const *ev) override;
|
||||
|
||||
void inkey_special(const event *menu_event);
|
||||
|
||||
@ -196,7 +196,7 @@ public:
|
||||
|
||||
private:
|
||||
virtual void populate(float &customtop, float &custombottom) override;
|
||||
virtual void handle() override;
|
||||
virtual void handle(event const *ev) override;
|
||||
|
||||
static std::pair<const char *, const char *> const s_palette[];
|
||||
rgb_t &m_original;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "uiinput.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <string_view>
|
||||
|
||||
|
||||
@ -34,14 +35,14 @@ namespace ui {
|
||||
//-------------------------------------------------
|
||||
|
||||
menu_dats_view::menu_dats_view(mame_ui_manager &mui, render_container &container, const ui_system_info *system)
|
||||
: menu(mui, container)
|
||||
: menu_textbox(mui, container)
|
||||
, m_system(!system ? &system_list::instance().systems()[driver_list::find(mui.machine().system().name)] : system)
|
||||
, m_swinfo(nullptr)
|
||||
, m_issoft(false)
|
||||
, m_layout()
|
||||
, m_actual(0)
|
||||
|
||||
{
|
||||
set_process_flags(PROCESS_LR_ALWAYS | PROCESS_CUSTOM_NAV);
|
||||
for (device_image_interface& image : image_interface_enumerator(mui.machine().root_device()))
|
||||
{
|
||||
if (image.filename())
|
||||
@ -71,11 +72,10 @@ menu_dats_view::menu_dats_view(mame_ui_manager &mui, render_container &container
|
||||
//-------------------------------------------------
|
||||
|
||||
menu_dats_view::menu_dats_view(mame_ui_manager &mui, render_container &container, const ui_software_info &swinfo)
|
||||
: menu(mui, container)
|
||||
: menu_textbox(mui, container)
|
||||
, m_system(nullptr)
|
||||
, m_swinfo(&swinfo)
|
||||
, m_issoft(true)
|
||||
, m_layout()
|
||||
, m_actual(0)
|
||||
, m_list(swinfo.listname)
|
||||
, m_short(swinfo.shortname)
|
||||
@ -83,6 +83,7 @@ menu_dats_view::menu_dats_view(mame_ui_manager &mui, render_container &container
|
||||
, m_parent(swinfo.parentname)
|
||||
|
||||
{
|
||||
set_process_flags(PROCESS_LR_ALWAYS | PROCESS_CUSTOM_NAV);
|
||||
if (!swinfo.infotext.empty())
|
||||
m_items_list.emplace_back(_("Software List Info"), 0, "");
|
||||
std::vector<std::string> lua_list;
|
||||
@ -165,18 +166,17 @@ void menu_dats_view::add_info_text(text_layout &layout, std::string_view text, r
|
||||
// handle
|
||||
//-------------------------------------------------
|
||||
|
||||
void menu_dats_view::handle()
|
||||
void menu_dats_view::handle(event const *ev)
|
||||
{
|
||||
event const *const menu_event = process(PROCESS_LR_ALWAYS | PROCESS_CUSTOM_NAV);
|
||||
if (menu_event)
|
||||
if (ev)
|
||||
{
|
||||
switch (menu_event->iptkey)
|
||||
switch (ev->iptkey)
|
||||
{
|
||||
case IPT_UI_LEFT:
|
||||
if (m_actual > 0)
|
||||
{
|
||||
m_actual--;
|
||||
reset(reset_options::SELECT_FIRST);
|
||||
reset_layout();
|
||||
}
|
||||
break;
|
||||
|
||||
@ -184,33 +184,12 @@ void menu_dats_view::handle()
|
||||
if ((m_actual + 1) < m_items_list.size())
|
||||
{
|
||||
m_actual++;
|
||||
reset(reset_options::SELECT_FIRST);
|
||||
reset_layout();
|
||||
}
|
||||
break;
|
||||
|
||||
case IPT_UI_UP:
|
||||
--top_line;
|
||||
break;
|
||||
|
||||
case IPT_UI_DOWN:
|
||||
++top_line;
|
||||
break;
|
||||
|
||||
case IPT_UI_PAGE_UP:
|
||||
top_line -= m_visible_lines - 3;
|
||||
break;
|
||||
|
||||
case IPT_UI_PAGE_DOWN:
|
||||
top_line += m_visible_lines - 3;
|
||||
break;
|
||||
|
||||
case IPT_UI_HOME:
|
||||
top_line = 0;
|
||||
break;
|
||||
|
||||
case IPT_UI_END:
|
||||
top_line = m_layout->lines() - m_visible_lines;
|
||||
break;
|
||||
default:
|
||||
handle_key(ev->iptkey);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -221,150 +200,8 @@ void menu_dats_view::handle()
|
||||
|
||||
void menu_dats_view::populate(float &customtop, float &custombottom)
|
||||
{
|
||||
bool paused = machine().paused();
|
||||
if (!paused)
|
||||
machine().pause();
|
||||
|
||||
m_layout = std::nullopt;
|
||||
|
||||
customtop = 2.0f * ui().get_line_height() + 4.0f * ui().box_tb_border();
|
||||
custombottom = ui().get_line_height() + 3.0f * ui().box_tb_border();
|
||||
|
||||
if (!paused)
|
||||
machine().resume();
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// draw - draw dats menu
|
||||
//-------------------------------------------------
|
||||
|
||||
void menu_dats_view::draw(uint32_t flags)
|
||||
{
|
||||
float const aspect = machine().render().ui_aspect(&container());
|
||||
float const line_height = ui().get_line_height();
|
||||
float const ud_arrow_width = line_height * aspect;
|
||||
float const gutter_width = 0.52f * line_height * aspect;
|
||||
float const visible_width = 1.0f - (2.0f * ui().box_lr_border() * aspect);
|
||||
float const visible_left = (1.0f - visible_width) * 0.5f;
|
||||
float const extra_height = 2.0f * line_height;
|
||||
float const visible_extra_menu_height = get_customtop() + get_custombottom() + extra_height;
|
||||
|
||||
// determine effective positions taking into account the hilighting arrows
|
||||
float const effective_width = visible_width - 2.0f * gutter_width;
|
||||
float const effective_left = visible_left + gutter_width;
|
||||
|
||||
draw_background();
|
||||
map_mouse();
|
||||
|
||||
// account for extra space at the top and bottom
|
||||
float visible_main_menu_height = 1.0f - 2.0f * ui().box_tb_border() - visible_extra_menu_height;
|
||||
m_visible_lines = int(std::trunc(visible_main_menu_height / line_height));
|
||||
visible_main_menu_height = float(m_visible_lines) * line_height;
|
||||
|
||||
// compute top/left of inner menu area by centering, if the menu is at the bottom of the extra, adjust
|
||||
float const visible_top = ((1.0f - (visible_main_menu_height + visible_extra_menu_height)) * 0.5f) + get_customtop();
|
||||
|
||||
// compute text box size
|
||||
float const x1 = visible_left;
|
||||
float const y1 = visible_top - ui().box_tb_border();
|
||||
float const x2 = x1 + visible_width;
|
||||
float const y2 = visible_top + visible_main_menu_height + ui().box_tb_border() + extra_height;
|
||||
float const line_x0 = x1 + 0.5f * UI_LINE_WIDTH;
|
||||
float const line_x1 = x2 - 0.5f * UI_LINE_WIDTH;
|
||||
float const separator = visible_top + float(m_visible_lines) * line_height;
|
||||
|
||||
ui().draw_outlined_box(container(), x1, y1, x2, y2, ui().colors().background_color());
|
||||
|
||||
if (!m_layout || (m_layout->width() != effective_width))
|
||||
{
|
||||
std::string buffer;
|
||||
if (!m_items_list.empty())
|
||||
{
|
||||
if (m_issoft)
|
||||
get_data_sw(buffer);
|
||||
else
|
||||
get_data(buffer);
|
||||
}
|
||||
m_layout.emplace(ui().create_layout(container(), effective_width));
|
||||
add_info_text(*m_layout, buffer, ui().colors().text_color());
|
||||
}
|
||||
int const visible_items = m_layout->lines();
|
||||
m_visible_lines = (std::min)(visible_items, m_visible_lines);
|
||||
top_line = (std::max)(0, top_line);
|
||||
if (top_line + m_visible_lines >= visible_items)
|
||||
top_line = visible_items - m_visible_lines;
|
||||
|
||||
clear_hover();
|
||||
if (top_line)
|
||||
{
|
||||
// if we're on the top line, display the up arrow
|
||||
rgb_t fgcolor = ui().colors().text_color();
|
||||
if (mouse_in_rect(line_x0, visible_top, line_x1, visible_top + line_height))
|
||||
{
|
||||
fgcolor = ui().colors().mouseover_color();
|
||||
highlight(
|
||||
line_x0, visible_top,
|
||||
line_x1, visible_top + line_height,
|
||||
ui().colors().mouseover_bg_color());
|
||||
set_hover(HOVER_ARROW_UP);
|
||||
}
|
||||
draw_arrow(
|
||||
0.5f * (x1 + x2) - 0.5f * ud_arrow_width, visible_top + 0.25f * line_height,
|
||||
0.5f * (x1 + x2) + 0.5f * ud_arrow_width, visible_top + 0.75f * line_height,
|
||||
fgcolor, ROT0);
|
||||
}
|
||||
if ((top_line + m_visible_lines) < visible_items)
|
||||
{
|
||||
// if we're on the bottom line, display the down arrow
|
||||
float const line_y = visible_top + float(m_visible_lines - 1) * line_height;
|
||||
rgb_t fgcolor = ui().colors().text_color();
|
||||
if (mouse_in_rect(line_x0, line_y, line_x1, line_y + line_height))
|
||||
{
|
||||
fgcolor = ui().colors().mouseover_color();
|
||||
highlight(
|
||||
line_x0, line_y,
|
||||
line_x1, line_y + line_height,
|
||||
ui().colors().mouseover_bg_color());
|
||||
set_hover(HOVER_ARROW_DOWN);
|
||||
}
|
||||
draw_arrow(
|
||||
0.5f * (x1 + x2) - 0.5f * ud_arrow_width, line_y + 0.25f * line_height,
|
||||
0.5f * (x1 + x2) + 0.5f * ud_arrow_width, line_y + 0.75f * line_height,
|
||||
fgcolor, ROT0 ^ ORIENTATION_FLIP_Y);
|
||||
}
|
||||
|
||||
// return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow
|
||||
m_visible_items = m_visible_lines - (top_line ? 1 : 0) - (top_line + m_visible_lines != visible_items);
|
||||
m_layout->emit(
|
||||
container(),
|
||||
top_line ? (top_line + 1) : 0, m_visible_items,
|
||||
effective_left, visible_top + (top_line ? line_height : 0.0f));
|
||||
|
||||
// add visual separator before the "return to prevous menu" item
|
||||
container().add_line(
|
||||
x1, separator + (0.5f * line_height),
|
||||
x2, separator + (0.5f * line_height),
|
||||
UI_LINE_WIDTH, ui().colors().text_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
|
||||
|
||||
menu_item const &pitem = item(0);
|
||||
std::string_view const itemtext = pitem.text;
|
||||
float const line_y0 = separator + line_height;
|
||||
float const line_y1 = line_y0 + line_height;
|
||||
|
||||
if (mouse_in_rect(line_x0, line_y0, line_x1, line_y1) && is_selectable(pitem))
|
||||
set_hover(0);
|
||||
|
||||
highlight(line_x0, line_y0, line_x1, line_y1, ui().colors().selected_bg_color());
|
||||
ui().draw_text_full(
|
||||
container(), itemtext,
|
||||
effective_left, line_y0, effective_width,
|
||||
text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE,
|
||||
mame_ui_manager::NORMAL,
|
||||
ui().colors().selected_color(), ui().colors().selected_bg_color(),
|
||||
nullptr, nullptr);
|
||||
|
||||
// if there is something special to add, do it by calling the virtual method
|
||||
custom_render(get_selection_ref(), get_customtop(), get_custombottom(), x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
@ -512,7 +349,7 @@ void menu_dats_view::custom_render(void *selectedref, float top, float bottom, f
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// load data from DATs
|
||||
// custom mouse click handling
|
||||
//-------------------------------------------------
|
||||
|
||||
bool menu_dats_view::custom_mouse_down()
|
||||
@ -532,6 +369,28 @@ bool menu_dats_view::custom_mouse_down()
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// populate selected DAT text
|
||||
//-------------------------------------------------
|
||||
|
||||
void menu_dats_view::populate_text(std::optional<text_layout> &layout, float &width, int &lines)
|
||||
{
|
||||
if (!layout || (layout->width() != width))
|
||||
{
|
||||
std::string buffer;
|
||||
if (!m_items_list.empty())
|
||||
{
|
||||
if (m_issoft)
|
||||
get_data_sw(buffer);
|
||||
else
|
||||
get_data(buffer);
|
||||
}
|
||||
layout.emplace(ui().create_layout(container(), width));
|
||||
add_info_text(*layout, buffer, ui().colors().text_color());
|
||||
lines = std::numeric_limits<int>::max();
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// load data from DATs
|
||||
//-------------------------------------------------
|
||||
|
@ -14,8 +14,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ui/menu.h"
|
||||
#include "ui/text.h"
|
||||
#include "ui/textbox.h"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
@ -33,7 +33,7 @@ namespace ui {
|
||||
// class dats menu
|
||||
//-------------------------------------------------
|
||||
|
||||
class menu_dats_view : public menu
|
||||
class menu_dats_view : public menu_textbox
|
||||
{
|
||||
public:
|
||||
menu_dats_view(mame_ui_manager &mui, render_container &container, const ui_software_info &swinfo);
|
||||
@ -46,6 +46,8 @@ protected:
|
||||
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
|
||||
virtual bool custom_mouse_down() override;
|
||||
|
||||
virtual void populate_text(std::optional<text_layout> &layout, float &width, int &lines) override;
|
||||
|
||||
private:
|
||||
struct list_items
|
||||
{
|
||||
@ -56,11 +58,8 @@ private:
|
||||
std::string revision;
|
||||
};
|
||||
|
||||
// draw dats menu
|
||||
virtual void draw(uint32_t flags) override;
|
||||
|
||||
virtual void populate(float &customtop, float &custombottom) override;
|
||||
virtual void handle() override;
|
||||
virtual void handle(event const *ev) override;
|
||||
|
||||
void get_data(std::string &buffer);
|
||||
void get_data_sw(std::string &buffer);
|
||||
@ -68,7 +67,6 @@ private:
|
||||
ui_system_info const *const m_system;
|
||||
ui_software_info const *const m_swinfo;
|
||||
bool const m_issoft;
|
||||
std::optional<text_layout> m_layout;
|
||||
int m_actual;
|
||||
std::string m_list, m_short, m_long, m_parent;
|
||||
std::vector<list_items> m_items_list;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user