From 8ab63e2072f6cfe19b8f8e2acfbd29754d282c79 Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Tue, 2 Nov 2021 07:53:18 +1100 Subject: [PATCH] Fix various usability issues: frontend: Made it so you can press UI On Screen Display to hide the Analog Controls menu and see the response to your inputs without the risk of changing settings, and see more axes at once and scroll them for systems with very large number of axes. Also ensure the axis being configured is visible when the menu is visible, and made the menu behave a bit more like the system input assignments menu (including previous/next group navigation). frontend: Allow Lua to draw to the UI container - this addresses the main complaint in #7475. Note that drawing to the UI container will draw over any UI elements, including menus. Plugins can check menu_active to avoid drawing over menus. Also removed some unnecessary use of sol::overload. frontend: Improved info/image box navigation on the system/softwre selection menus, and cleaned up some leftover code that came from the copy/pasted event handling functions. frontend: Fixed sliders menu not handling Alt+Shift as intended (thanks Coverity). Fixed a couple of harmless Coverity errors, too. emu/inpttype.ipp: Made the default assignment for Save State recognise right shift. plugins: Added next/previous group navigation to input macro edit menu. docs: Added basic description of the system and software selection menus, and corrected a couple of errors in the Lua reference. --- docs/source/techspecs/luareference.rst | 119 ++++++++--- docs/source/usingmame/ui.rst | 131 +++++++++++- plugins/inputmacro/inputmacro_menu.lua | 49 +++-- src/emu/inpttype.ipp | 8 +- src/emu/video.cpp | 28 ++- src/frontend/mame/luaengine.cpp | 143 +++++++------ src/frontend/mame/luaengine_render.cpp | 65 ++++++ src/frontend/mame/ui/analogipt.cpp | 271 +++++++++++++++++++------ src/frontend/mame/ui/analogipt.h | 3 + src/frontend/mame/ui/mainmenu.cpp | 4 +- src/frontend/mame/ui/menu.cpp | 4 - src/frontend/mame/ui/pluginopt.cpp | 12 +- src/frontend/mame/ui/selgame.cpp | 19 +- src/frontend/mame/ui/selmenu.cpp | 46 +++-- src/frontend/mame/ui/selsoft.cpp | 5 +- src/frontend/mame/ui/simpleselgame.cpp | 1 + src/frontend/mame/ui/sliders.cpp | 38 ++-- src/frontend/mame/ui/textbox.cpp | 8 +- 18 files changed, 686 insertions(+), 268 deletions(-) diff --git a/docs/source/techspecs/luareference.rst b/docs/source/techspecs/luareference.rst index 38ae1476b3a..623d4738407 100644 --- a/docs/source/techspecs/luareference.rst +++ b/docs/source/techspecs/luareference.rst @@ -804,12 +804,12 @@ screen:pixels() screen:draw_box(left, top, right, bottom, [line], [fill]) Draws an outlined rectangle with edges at the specified positions. - Coordinates are floating-point numbers in units of screen pixels, with the - origin at (0, 0). Note that screen pixels often aren’t square. The - coordinate system is rotated if the screen is rotated, which is usually the - case for vertical-format screens. Before rotation, the origin is at the top - left, and coordinates increase to the right and downwards. Coordinates are - limited to the screen area. + Coordinates are floating-point numbers in units of emulated screen pixels, + with the origin at (0, 0). Note that emulated screen pixels often aren’t + square. The coordinate system is rotated if the screen is rotated, which is + usually the case for vertical-format screens. Before rotation, the origin + is at the top left, and coordinates increase to the right and downwards. + Coordinates are limited to the screen area. The fill and line colours are in alpha/red/green/blue (ARGB) format. Channel values are in the range 0 (transparent or off) to 255 (opaque or @@ -822,12 +822,12 @@ screen:draw_box(left, top, right, bottom, [line], [fill]) screen:draw_line(x1, y1, x2, y2, bottom, [color]) Draws a line from (x1, y1) to (x2, y2). - Coordinates are floating-point numbers in units of screen pixels, with the - origin at (0, 0). Note that screen pixels often aren’t square. The - coordinate system is rotated if the screen is rotated, which is usually the - case for vertical-format screens. Before rotation, the origin is at the top - left, and coordinates increase to the right and downwards. Coordinates are - limited to the screen area. + Coordinates are floating-point numbers in units of emulated screen pixels, + with the origin at (0, 0). Note that emulated screen pixels often aren’t + square. The coordinate system is rotated if the screen is rotated, which is + usually the case for vertical-format screens. Before rotation, the origin + is at the top left, and coordinates increase to the right and downwards. + Coordinates are limited to the screen area. The line colour is in alpha/red/green/blue (ARGB) format. Channel values are in the range 0 (transparent or off) to 255 (opaque or full intensity), @@ -847,21 +847,21 @@ screen:draw_text(x|justify, y, text, [foreground], [background]) right-aligned at the right edge of the screen, respectively. The second argument specifies the Y coordinate of the maximum ascent of the text. - Coordinates are floating-point numbers in units of screen pixels, with the - origin at (0, 0). Note that screen pixels often aren’t square. The - coordinate system is rotated if the screen is rotated, which is usually the - case for vertical-format screens. Before rotation, the origin is at the top - left, and coordinates increase to the right and downwards. Coordinates are - limited to the screen area. + Coordinates are floating-point numbers in units of emulated screen pixels, + with the origin at (0, 0). Note that emulated screen pixels often aren’t + square. The coordinate system is rotated if the screen is rotated, which is + usually the case for vertical-format screens. Before rotation, the origin + is at the top left, and coordinates increase to the right and downwards. + Coordinates are limited to the screen area. - The foreground and background colours is in alpha/red/green/blue (ARGB) - format. Channel values are in the range 0 (transparent or off) to 255 (opaque or full intensity), - inclusive. Colour channel values are not pre-multiplied by the alpha value. - The channel values must be packed into the bytes of a 32-bit unsigned - integer, in the order alpha, red, green, blue from most-significant to - least-significant byte. If the foreground colour is not provided, the UI - text colour is used; if the background colour is not provided, the UI - background colour is used. + The foreground and background colours are in alpha/red/green/blue (ARGB) + format. Channel values are in the range 0 (transparent or off) to 255 + (opaque or full intensity), inclusive. Colour channel values are not + pre-multiplied by the alpha value. The channel values must be packed into + the bytes of a 32-bit unsigned integer, in the order alpha, red, green, blue + from most-significant to least-significant byte. If the foreground colour + is not provided, the UI text colour is used; if the background colour is not + provided, it is fully transparent. Properties ^^^^^^^^^^ @@ -2412,6 +2412,73 @@ manager.machine.render.ui_container manager.machine.screens[tag].container Gets the render container used to draw a given screen. +Methods +^^^^^^^ + +container:draw_box(left, top, right, bottom, [line], [fill]) + Draws an outlined rectangle with edges at the specified positions. + + Coordinates are floating-point numbers in the range of 0 (zero) to 1 (one), + with (0, 0) at the top left and (1, 1) at the bottom right of the window or + screen that showss the user interface. Note that the aspect ratio is + usually not square. Coordinates are limited to the window or screen area. + + The fill and line colours are in alpha/red/green/blue (ARGB) format. + Channel values are in the range 0 (transparent or off) to 255 (opaque or + full intensity), inclusive. Colour channel values are not pre-multiplied by + the alpha value. The channel values must be packed into the bytes of a + 32-bit unsigned integer, in the order alpha, red, green, blue from + most-significant to least-significant byte. If the line colour is not + provided, the UI text colour is used; if the fill colour is not provided, + the UI background colour is used. +container:draw_line(x1, y1, x2, y2, bottom, [color]) + Draws a line from (x1, y1) to (x2, y2). + + Coordinates are floating-point numbers in the range of 0 (zero) to 1 (one), + with (0, 0) at the top left and (1, 1) at the bottom right of the window or + screen that showss the user interface. Note that the aspect ratio is + usually not square. Coordinates are limited to the window or screen area. + + Coordinates are floating-point numbers in units of screen pixels, with the + origin at (0, 0). Note that screen pixels often aren’t square. The + coordinate system is rotated if the screen is rotated, which is usually the + case for vertical-format screens. Before rotation, the origin is at the top + left, and coordinates increase to the right and downwards. Coordinates are + limited to the screen area. + + The line colour is in alpha/red/green/blue (ARGB) format. Channel values + are in the range 0 (transparent or off) to 255 (opaque or full intensity), + inclusive. Colour channel values are not pre-multiplied by the alpha value. + The channel values must be packed into the bytes of a 32-bit unsigned + integer, in the order alpha, red, green, blue from most-significant to + least-significant byte. If the line colour is not provided, the UI text + colour is used. +container:draw_text(x|justify, y, text, [foreground], [background]) + Draws text at the specified position. If the screen is rotated the text + will be rotated. + + If the first argument is a number, the text will be left-aligned at this X + coordinate. If the first argument is a string, it must be ``"left"``, + ``"center"`` or ``"right"`` to draw the text left-aligned at the + left edge of the window or screen, horizontally centred in the window or + screen, or right-aligned at the right edge of the window or screen, + respectively. The second argument specifies the Y coordinate of the maximum + ascent of the text. + + Coordinates are floating-point numbers in the range of 0 (zero) to 1 (one), + with (0, 0) at the top left and (1, 1) at the bottom right of the window or + screen that showss the user interface. Note that the aspect ratio is + usually not square. Coordinates are limited to the window or screen area. + + The foreground and background colours are in alpha/red/green/blue (ARGB) + format. Channel values are in the range 0 (transparent or off) to 255 + (opaque or full intensity), inclusive. Colour channel values are not + pre-multiplied by the alpha value. The channel values must be packed into + the bytes of a 32-bit unsigned integer, in the order alpha, red, green, blue + from most-significant to least-significant byte. If the foreground colour + is not provided, the UI text colour is used; if the background colour is not + provided, it is fully transparent. + Properties ^^^^^^^^^^ diff --git a/docs/source/usingmame/ui.rst b/docs/source/usingmame/ui.rst index 38b0e5bc7cc..c764ef56688 100644 --- a/docs/source/usingmame/ui.rst +++ b/docs/source/usingmame/ui.rst @@ -61,9 +61,9 @@ Return/Enter keypad Enter (UI Select) 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). + Clear the search if searching the menu, otherwise close the menu, returning + to the previous menu, or returning to the emulated machine for the main menu + (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) @@ -110,7 +110,7 @@ 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 +* **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 @@ -135,3 +135,126 @@ pointing device: 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. + + +.. _ui-selmenu: + +The system and software selection menus +--------------------------------------- + +If you start MAME without specifying a system on the command line, the system +selection menu will be shown (assuming the +:ref:`ui option ` is set to **cabinet**). The system +selection menu is also shown if you select **Select New Machine** from the main +menu during emulation. Selecting a system that uses software lists shows the +similar software selection menu. + +The system and software selection menus have the following parts: + +* The heading area at the top, showing the emulator name and version, the number + of systems or software items in the menu, and the current search text. The + software selection menu also shows the name of the selected system. +* The toolbar immediately below the heading area. The exact toolbar buttons + shown depend on the menu. Hover the mouse pointer over a button to see a + description. Click a button to select it. + + Toolbar buttons are add/remove highlighted system/software from favourites + (star), export displayed list to file (diskette), audit media (magnifying + glass), show info viewer (“i” emblazoned on blue circle), return to previous + menu (bent arrow on blue), and exit (cross on red). +* The list of systems or software in the centre. For the system selection menu, + there are configuration options below the list of systems. Clones are shown + with a different text colour (grey by default). You can right-click a system + name as a shortcut to show the machine configuration options for the system. + + Systems or software items are sorted by full name or description, keeping + clones immediately below their parents. This may appear confusing if your + filter settings cause a parent system or software item to be hidden while one + or more of its clones are visible. +* The info panel at the bottom, showing summary information about the + highlighted system or software. The background colour changes depending on + the emulation status: green for working, amber for imperfectly emulated + features or known issues, or red for more serious issues. + + A yellow star is show at the top left of the info panel if the highlighted + system or software is in your favourites list. +* The collapsible list of filter options on the left. Click a filter to apply + it to the list of systems/software. Some filters show a menu with additional + options (e.g. specifying the manufacturer for the **Manufacturer** filter, or + specifying a file and group for the **Category** filter). + + Click **Unfiltered** to display all items. Click **Custom Filter** to combine + multiple filters. Click the strip between the list of filters and the list of + systems/software to show or hide the list of filters. Be aware that filters + still apply when the list of filters is hidden. +* The collapsible info viewer on the right. This has two tabs for showing + images and information. Click a tab to switch tabs; click the left- or + right-facing triangles next to the image/info title to switch between images + or information sources. + + Emulation information is automatically shown for systems, and information from + the software list is shown for software items. Additional information from + external files can be shown using the :ref:`Data plugin `. + +You can type to search the displayed list of systems or software. Systems are +searched by full name, manufacturer and full name, and short name. If you are +using localised system names, phonetic names will also be searched if present. +Software items are searched by description, alternate titles (``alt_title`` +info elements in the software lists), and short name. **UI Cancel** (Escape by +default) will clear the search if currently searching. + + +.. _ui-selmenu-nav: + +Navigation controls +~~~~~~~~~~~~~~~~~~~ + +In addition to the usual :ref:`menu navigation controls `, the system +and software selection menus have additional configurable controls for +navigating the multi-pane layout, and providing alternatives to toolbar buttons +if you don’t want to use a pointing device. The default additional controls (on +a US ANSI QWERTY keyboard), and the settings they correspond to, are: + +Tab (UI Focus Next) + Move focus to the next area. The order is system/software list, + configuration options (if visible), filter list (if visible), info/image + tabs (if visible), info/image source (if visible). +Shift+Tab (UI Focus Previous) + Move focus to the previous area. +Alt+D (UI External DAT View) + Show the full-size info viewer. +Alt+F (UI Add/Remove favorite) + Add or remove the highlighted system or software item from the favourites + list. +F1 (UI Audit Media) + Audit ROMs and/or disk images for systems. The results are saved for use + with the **Available** and **Unavailable** filters. + +When focus is on the filter list, you can use the menu navigation controls (up, +down, home and end) to highlight a filter, and **UI Select** (Return/Enter by +default) apply it. + +When focus is on any area besides the info/image tabs, you can change the image +or info source with left/right. When focus is on the info/image tabs, +left/right switch between tabs. When focus is on the image/info tabs or source, +you can scroll the info using up, down, page up, page down, home and end. + + +.. _ui-simpleselmenu: + +The simple system selection menu +-------------------------------- + +If you start MAME without specifying a system on the command line (or choose +**Select New Machine** from the main menu during emulation) with the +:ref:`ui option ` set to **simple**, the simple system +selection menu will be shown. The simple system selection menu shows fifteen +randomly selected systems that have ROM sets present in your configured +:ref:`ROM folder(s) `. You can type to search for a +system. Clearing the search causes fifteen systems to be randomly selected +again. + +The info panel below the menu shows summary information about the highlighted +system. The background colour changes depending on the emulation status: green +for working, amber for imperfectly emulated features or known issues, or red for +more serious issues. diff --git a/plugins/inputmacro/inputmacro_menu.lua b/plugins/inputmacro/inputmacro_menu.lua index b6b8c9413c0..944361c88fe 100644 --- a/plugins/inputmacro/inputmacro_menu.lua +++ b/plugins/inputmacro/inputmacro_menu.lua @@ -308,7 +308,30 @@ local function handle_edit_items(index, event) end end - return namecancel + local selection + if command.step then + if event == 'prevgroup' then + if command.step > 1 then + local found_break = false + selection = index - 1 + while (not edit_items[selection]) or (edit_items[selection].step == command.step) do + selection = selection - 1 + end + local step = edit_items[selection].step + while edit_items[selection - 1] and (edit_items[selection - 1].step == step) do + selection = selection - 1 + end + end + elseif event == 'nextgroup' then + if command.step < #edit_current_macro.steps then + selection = index + 1 + while (not edit_items[selection]) or (edit_items[selection].step == command.step) do + selection = selection + 1 + end + end + end + end + return namecancel, selection end local function add_edit_items(items) @@ -393,14 +416,15 @@ local function add_edit_items(items) end local function handle_add(index, event) - if handle_edit_items(index, event) then - return true + local handled, selection = handle_edit_items(index, event) + if handled then + return true, selection elseif event == 'cancel' then edit_current_macro = nil edit_menu_active = false edit_items = nil table.remove(menu_stack) - return true + return true, selection elseif (index == edit_item_exit) and (event == 'select') then if current_macro_complete() then table.insert(macros, edit_current_macro) @@ -410,22 +434,23 @@ local function handle_add(index, event) edit_current_macro = nil edit_items = nil table.remove(menu_stack) - return true + return true, selection end - return false + return false, selection end local function handle_edit(index, event) - if handle_edit_items(index, event) then - return true + local handled, selection = handle_edit_items(index, event) + if handled then + return true, selection elseif (event == 'cancel') or ((index == edit_item_exit) and (event == 'select')) then edit_current_macro = nil edit_menu_active = false edit_items = nil table.remove(menu_stack) - return true + return true, selection end - return false + return false, selection end local function populate_add() @@ -449,7 +474,7 @@ local function populate_add() if edit_switch_poller then return edit_switch_poller:overlay(items, selection, 'lrrepeat') else - return items, selection, 'lrrepeat' + return items, selection, 'lrrepeat' .. (edit_name_buffer and ' ignorepause' or '') end end @@ -470,7 +495,7 @@ local function populate_edit() if edit_switch_poller then return edit_switch_poller:overlay(items, selection, 'lrrepeat') else - return items, selection, 'lrrepeat' + return items, selection, 'lrrepeat' .. (edit_name_buffer and ' ignorepause' or '') end end diff --git a/src/emu/inpttype.ipp b/src/emu/inpttype.ipp index 235f1c421d5..9ae468cbe96 100644 --- a/src/emu/inpttype.ipp +++ b/src/emu/inpttype.ipp @@ -848,14 +848,14 @@ namespace { INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TOGGLE_UI, N_p("input-name", "UI Toggle"), input_seq(KEYCODE_SCRLOCK, input_seq::not_code, KEYCODE_LSHIFT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RELEASE_POINTER, N_p("input-name", "UI Release Pointer"), input_seq(KEYCODE_RCONTROL, KEYCODE_RALT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PASTE, N_p("input-name", "UI Paste Text"), input_seq(KEYCODE_SCRLOCK, KEYCODE_LSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SAVE_STATE, N_p("input-name", "Save State"), input_seq(KEYCODE_F7, KEYCODE_LSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_LOAD_STATE, N_p("input-name", "Load State"), input_seq(KEYCODE_F7, input_seq::not_code, KEYCODE_LSHIFT) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TAPE_START, N_p("input-name", "UI (First) Tape Start"), input_seq(KEYCODE_F2, input_seq::not_code, KEYCODE_LSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SAVE_STATE, N_p("input-name", "Save State"), input_seq(KEYCODE_F7, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_F7, KEYCODE_RSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_LOAD_STATE, N_p("input-name", "Load State"), input_seq(KEYCODE_F7, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TAPE_START, N_p("input-name", "UI (First) Tape Start"), input_seq(KEYCODE_F2, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TAPE_STOP, N_p("input-name", "UI (First) Tape Stop"), input_seq(KEYCODE_F2, KEYCODE_LSHIFT) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_DATS, N_p("input-name", "UI External DAT View"), input_seq(KEYCODE_LALT, KEYCODE_D) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_FAVORITES, N_p("input-name", "UI Add/Remove favorite"), input_seq(KEYCODE_LALT, KEYCODE_F) ) \ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_EXPORT, N_p("input-name", "UI Export List"), input_seq(KEYCODE_LALT, KEYCODE_E) ) \ - INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_AUDIT, N_p("input-name", "UI Audit Media"), input_seq(KEYCODE_F1, input_seq::not_code, KEYCODE_LSHIFT) ) \ + INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_AUDIT, N_p("input-name", "UI Audit Media"), input_seq(KEYCODE_F1, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \ CORE_INPUT_TYPES_END() #define CORE_INPUT_TYPES_OSD \ diff --git a/src/emu/video.cpp b/src/emu/video.cpp index 9ab18b03f4d..520eed492f9 100644 --- a/src/emu/video.cpp +++ b/src/emu/video.cpp @@ -213,22 +213,23 @@ void video_manager::frame_update(bool from_debugger) // only render sound and video if we're in the running phase machine_phase const phase = machine().phase(); bool skipped_it = m_skipping_this_frame; - if (phase == machine_phase::RUNNING && (!machine().paused() || machine().options().update_in_pause())) - { - bool anything_changed = finish_screen_updates(); - - // if none of the screens changed and we haven't skipped too many frames in a row, - // mark this frame as skipped to prevent throttling; this helps for games that - // don't update their screen at the monitor refresh rate - if (!anything_changed && !m_auto_frameskip && m_frameskip_level == 0 && m_empty_skip_count++ < 3) - skipped_it = true; - else - m_empty_skip_count = 0; - } + bool const update_screens = (phase == machine_phase::RUNNING) && (!machine().paused() || machine().options().update_in_pause()); + bool anything_changed = update_screens && finish_screen_updates(); // draw the user interface emulator_info::draw_user_interface(machine()); + // let plugins draw over the UI + anything_changed = emulator_info::frame_hook() || anything_changed; + + // if none of the screens changed and we haven't skipped too many frames in a row, + // mark this frame as skipped to prevent throttling; this helps for games that + // don't update their screen at the monitor refresh rate + if (!anything_changed && !m_auto_frameskip && (m_frameskip_level == 0) && (m_empty_skip_count++ < 3)) + skipped_it = true; + else + m_empty_skip_count = 0; + // if we're throttling, synchronize before rendering attotime current_time = machine().time(); if (!from_debugger && !skipped_it && phase > machine_phase::INIT && !m_low_latency && effective_throttle()) @@ -649,9 +650,6 @@ bool video_manager::finish_screen_updates() if (screen.update_quads()) anything_changed = true; - // draw HUD from LUA callback (if any) - anything_changed |= emulator_info::frame_hook(); - // update our movie recording and burn-in state if (!machine().paused()) { diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp index 6954116283c..0680fb4c391 100644 --- a/src/frontend/mame/luaengine.cpp +++ b/src/frontend/mame/luaengine.cpp @@ -59,63 +59,6 @@ struct lua_engine::devenum namespace { -void do_draw_box(screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t fgcolor, uint32_t bgcolor) -{ - float const sc_width(sdev.visible_area().width()); - float const sc_height(sdev.visible_area().height()); - x1 = std::clamp(x1, 0.0f, sc_width) / sc_width; - y1 = std::clamp(y1, 0.0f, sc_height) / sc_height; - x2 = std::clamp(x2, 0.0f, sc_width) / sc_width; - y2 = std::clamp(y2, 0.0f, sc_height) / sc_height; - mame_machine_manager::instance()->ui().draw_outlined_box(sdev.container(), x1, y1, x2, y2, fgcolor, bgcolor); -} - -void do_draw_line(screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t color) -{ - float const sc_width(sdev.visible_area().width()); - float const sc_height(sdev.visible_area().height()); - x1 = std::clamp(x1, 0.0f, sc_width) / sc_width; - y1 = std::clamp(y1, 0.0f, sc_height) / sc_height; - x2 = std::clamp(x2, 0.0f, sc_width) / sc_width; - y2 = std::clamp(y2, 0.0f, sc_height) / sc_height; - sdev.container().add_line(x1, y1, x2, y2, UI_LINE_WIDTH, rgb_t(color), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); -} - -void do_draw_text(lua_State *L, screen_device &sdev, sol::object &xobj, float y, const char *msg, rgb_t fgcolor, rgb_t bgcolor) -{ - float const sc_width(sdev.visible_area().width()); - float const sc_height(sdev.visible_area().height()); - auto justify = ui::text_layout::text_justify::LEFT; - float x = 0; - if (xobj.is()) - { - x = std::clamp(xobj.as(), 0.0f, sc_width) / sc_width; - } - else if (xobj.is()) - { - char const *const justifystr(xobj.as()); - if (!strcmp(justifystr, "left")) - justify = ui::text_layout::text_justify::LEFT; - else if (!strcmp(justifystr, "right")) - justify = ui::text_layout::text_justify::RIGHT; - else if (!strcmp(justifystr, "center")) - justify = ui::text_layout::text_justify::CENTER; - } - else - { - luaL_error(L, "Error in param 1 to draw_text"); - return; - } - y = std::clamp(y, 0.0f, sc_height) / sc_height; - mame_machine_manager::instance()->ui().draw_text_full( - sdev.container(), - msg, - x, y, (1.0f - x), - justify, ui::text_layout::word_wrapping::WORD, - mame_ui_manager::OPAQUE_, fgcolor, bgcolor); -} - - struct image_interface_formats { image_interface_formats(device_image_interface &i) : image(i) { } @@ -1444,24 +1387,74 @@ void lua_engine::initialize() "screen_dev", sol::no_constructor, sol::base_classes, sol::bases()); - screen_dev_type["draw_box"] = sol::overload( - [] (screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t fgcolor, uint32_t bgcolor) - { do_draw_box(sdev, x1, y1, x2, y2, fgcolor, bgcolor); }, - [] (screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t fgcolor) - { do_draw_box(sdev, x1, y1, x2, y2, fgcolor, mame_machine_manager::instance()->ui().colors().background_color()); }, - [] (screen_device &sdev, float x1, float y1, float x2, float y2) - { auto const &colors(mame_machine_manager::instance()->ui().colors()); do_draw_box(sdev, x1, y1, x2, y2, colors.text_color(), colors.background_color()); }); - screen_dev_type["draw_line"] = sol::overload( - &do_draw_line, - [] (screen_device &sdev, float x1, float y1, float x2, float y2) - { do_draw_line(sdev, x1, y1, x2, y2, mame_machine_manager::instance()->ui().colors().text_color()); }); - screen_dev_type["draw_text"] = sol::overload( - [this] (screen_device &sdev, sol::object xobj, float y, const char *msg, uint32_t fgcolor, uint32_t bgcolor) - { do_draw_text(m_lua_state, sdev, xobj, y, msg, fgcolor, bgcolor); }, - [this] (screen_device &sdev, sol::object xobj, float y, const char *msg, uint32_t fgcolor) - { do_draw_text(m_lua_state, sdev, xobj, y, msg, fgcolor, 0); }, - [this] (screen_device &sdev, sol::object xobj, float y, const char *msg) - { do_draw_text(m_lua_state, sdev, xobj, y, msg, mame_machine_manager::instance()->ui().colors().text_color(), 0); }); + screen_dev_type["draw_box"] = + [] (screen_device &sdev, float x1, float y1, float x2, float y2, std::optional fgcolor, std::optional bgcolor) + { + float const sc_width(sdev.visible_area().width()); + float const sc_height(sdev.visible_area().height()); + x1 = std::clamp(x1, 0.0f, sc_width) / sc_width; + y1 = std::clamp(y1, 0.0f, sc_height) / sc_height; + x2 = std::clamp(x2, 0.0f, sc_width) / sc_width; + y2 = std::clamp(y2, 0.0f, sc_height) / sc_height; + mame_ui_manager &ui(mame_machine_manager::instance()->ui()); + if (!fgcolor) + fgcolor = ui.colors().text_color(); + if (!bgcolor) + bgcolor = ui.colors().background_color(); + ui.draw_outlined_box(sdev.container(), x1, y1, x2, y2, *fgcolor, *bgcolor); + }; + screen_dev_type["draw_line"] = + [] (screen_device &sdev, float x1, float y1, float x2, float y2, std::optional color) + { + float const sc_width(sdev.visible_area().width()); + float const sc_height(sdev.visible_area().height()); + x1 = std::clamp(x1, 0.0f, sc_width) / sc_width; + y1 = std::clamp(y1, 0.0f, sc_height) / sc_height; + x2 = std::clamp(x2, 0.0f, sc_width) / sc_width; + y2 = std::clamp(y2, 0.0f, sc_height) / sc_height; + if (!color) + color = mame_machine_manager::instance()->ui().colors().text_color(); + sdev.container().add_line(x1, y1, x2, y2, UI_LINE_WIDTH, rgb_t(*color), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + }; + screen_dev_type["draw_text"] = + [this] (screen_device &sdev, sol::object xobj, float y, char const *msg, std::optional fgcolor, std::optional bgcolor) + { + float const sc_width(sdev.visible_area().width()); + float const sc_height(sdev.visible_area().height()); + auto justify = ui::text_layout::text_justify::LEFT; + float x = 0; + if (xobj.is()) + { + x = std::clamp(xobj.as(), 0.0f, sc_width) / sc_width; + } + else if (xobj.is()) + { + char const *const justifystr(xobj.as()); + if (!strcmp(justifystr, "left")) + justify = ui::text_layout::text_justify::LEFT; + else if (!strcmp(justifystr, "right")) + justify = ui::text_layout::text_justify::RIGHT; + else if (!strcmp(justifystr, "center")) + justify = ui::text_layout::text_justify::CENTER; + } + else + { + luaL_error(m_lua_state, "Error in param 1 to draw_text"); + return; + } + y = std::clamp(y, 0.0f, sc_height) / sc_height; + mame_ui_manager &ui(mame_machine_manager::instance()->ui()); + if (!fgcolor) + fgcolor = ui.colors().text_color(); + if (!bgcolor) + bgcolor = 0; + ui.draw_text_full( + sdev.container(), + msg, + x, y, (1.0f - x), + justify, ui::text_layout::word_wrapping::WORD, + mame_ui_manager::OPAQUE_, *fgcolor, *bgcolor); + }; screen_dev_type["orientation"] = [] (screen_device &sdev) { diff --git a/src/frontend/mame/luaengine_render.cpp b/src/frontend/mame/luaengine_render.cpp index 2cf8cc6878d..ea40a34c02a 100644 --- a/src/frontend/mame/luaengine_render.cpp +++ b/src/frontend/mame/luaengine_render.cpp @@ -11,6 +11,9 @@ #include "emu.h" #include "luaengine.ipp" +#include "mame.h" +#include "ui/ui.h" + #include "render.h" #include "rendlay.h" @@ -351,6 +354,68 @@ void lua_engine::initialize_render(sol::table &emu) auto render_container_type = sol().registry().new_usertype("render_container", sol::no_constructor); + render_container_type["draw_box"] = + [] (render_container &ctnr, float x1, float y1, float x2, float y2, std::optional fgcolor, std::optional bgcolor) + { + x1 = std::clamp(x1, 0.0f, 1.0f); + y1 = std::clamp(y1, 0.0f, 1.0f); + x2 = std::clamp(x2, 0.0f, 1.0f); + y2 = std::clamp(y2, 0.0f, 1.0f); + mame_ui_manager &ui(mame_machine_manager::instance()->ui()); + if (!fgcolor) + fgcolor = ui.colors().text_color(); + if (!bgcolor) + bgcolor = ui.colors().background_color(); + ui.draw_outlined_box(ctnr, x1, y1, x2, y2, *fgcolor, *bgcolor); + }; + render_container_type["draw_line"] = + [] (render_container &ctnr, float x1, float y1, float x2, float y2, std::optional color) + { + x1 = std::clamp(x1, 0.0f, 1.0f); + y1 = std::clamp(y1, 0.0f, 1.0f); + x2 = std::clamp(x2, 0.0f, 1.0f); + y2 = std::clamp(y2, 0.0f, 1.0f); + if (!color) + color = mame_machine_manager::instance()->ui().colors().text_color(); + ctnr.add_line(x1, y1, x2, y2, UI_LINE_WIDTH, rgb_t(*color), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + }; + render_container_type["draw_text"] = + [this] (render_container &ctnr, sol::object xobj, float y, char const *msg, std::optional fgcolor, std::optional bgcolor) + { + auto justify = ui::text_layout::text_justify::LEFT; + float x = 0; + if (xobj.is()) + { + x = std::clamp(xobj.as(), 0.0f, 1.0f); + } + else if (xobj.is()) + { + char const *const justifystr(xobj.as()); + if (!strcmp(justifystr, "left")) + justify = ui::text_layout::text_justify::LEFT; + else if (!strcmp(justifystr, "right")) + justify = ui::text_layout::text_justify::RIGHT; + else if (!strcmp(justifystr, "center")) + justify = ui::text_layout::text_justify::CENTER; + } + else + { + luaL_error(m_lua_state, "Error in param 1 to draw_text"); + return; + } + y = std::clamp(y, 0.0f, 1.0f); + mame_ui_manager &ui(mame_machine_manager::instance()->ui()); + if (!fgcolor) + fgcolor = ui.colors().text_color(); + if (!bgcolor) + bgcolor = 0; + ui.draw_text_full( + ctnr, + msg, + x, y, (1.0f - x), + justify, ui::text_layout::word_wrapping::WORD, + mame_ui_manager::OPAQUE_, *fgcolor, *bgcolor); + }; render_container_type["user_settings"] = sol::property(&render_container::get_user_settings, &render_container::set_user_settings); render_container_type["orientation"] = sol::property( &render_container::orientation, diff --git a/src/frontend/mame/ui/analogipt.cpp b/src/frontend/mame/ui/analogipt.cpp index 209a84b4f06..3cc732cb82c 100644 --- a/src/frontend/mame/ui/analogipt.cpp +++ b/src/frontend/mame/ui/analogipt.cpp @@ -12,6 +12,7 @@ #include "ui/analogipt.h" #include +#include #include #include @@ -50,7 +51,10 @@ menu_analog::menu_analog(mame_ui_manager &mui, render_container &container) : menu(mui, container) , m_item_data() , m_field_data() + , m_prompt() , m_visible_fields(0U) + , m_top_field(0) + , m_hide_menu(false) { set_process_flags(PROCESS_LR_REPEAT); } @@ -71,29 +75,96 @@ void menu_analog::custom_render(void *selectedref, float top, float bottom, floa for (field_data &data : m_field_data) namewidth = (std::min)((std::max)(ui().get_string_width(data.field.get().name()), namewidth), nameavail); - // make a box + // make a box or two + rgb_t const fgcolor(ui().colors().text_color()); + float const lineheight(ui().get_line_height()); + float const border(ui().box_tb_border()); float const boxleft((1.0f - namewidth - extrawidth) / 2.0f); float const boxright(boxleft + namewidth + extrawidth); - ui().draw_outlined_box(container(), boxleft, y2 + ui().box_tb_border(), boxright, y2 + bottom, ui().colors().background_color()); + float boxtop; + float boxbottom; + float firstliney; + int visible_fields; + if (m_hide_menu) + { + if (m_prompt.empty()) + m_prompt = util::string_format(_("Press %s to show menu"), ui().get_general_input_setting(IPT_UI_ON_SCREEN_DISPLAY)); + draw_text_box( + &m_prompt, &m_prompt + 1, + boxleft, boxright, y - top, y - top + lineheight + (border * 2.0f), + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, + fgcolor, ui().colors().background_color(), 1.0f); + boxtop = y - top + lineheight + (border * 3.0f); + firstliney = y - top + lineheight + (border * 4.0f); + visible_fields = std::min(m_field_data.size(), int((y2 + bottom - border - firstliney) / lineheight)); + boxbottom = firstliney + (lineheight * visible_fields) + border; + } + else + { + boxtop = y2 + border; + boxbottom = y2 + bottom; + firstliney = y2 + (border * 2.0f); + visible_fields = m_visible_fields; + } + ui().draw_outlined_box(container(), boxleft, boxtop, boxright, boxbottom, ui().colors().background_color()); + + // force the field being configured to be visible + ioport_field *const selfield(selectedref ? &reinterpret_cast(selectedref)->field.get() : nullptr); + if (!m_hide_menu && selfield) + { + auto const found( + std::find_if( + m_field_data.begin(), + m_field_data.end(), + [selfield] (field_data const &d) { return &d.field.get() == selfield; })); + if (m_field_data.end() != found) + { + auto const i(std::distance(m_field_data.begin(), found)); + if (m_top_field > i) + m_top_field = i; + if ((m_top_field + visible_fields) <= i) + m_top_field = i - m_visible_fields + 1; + } + } + if (0 > m_top_field) + m_top_field = 0; + if ((m_top_field + visible_fields) > m_field_data.size()) + m_top_field = m_field_data.size() - visible_fields; // show live fields - namewidth += ui().get_line_height() * aspect; - unsigned line(0U); + namewidth += lineheight * aspect; float const nameleft(boxleft + (ui().box_lr_border() * aspect)); float const indleft(nameleft + namewidth); float const indright(indleft + 0.4f); - ioport_field *const selfield(selectedref ? &reinterpret_cast(selectedref)->field.get() : nullptr); - for (field_data &data : m_field_data) + for (unsigned line = 0; visible_fields > line; ++line) { + // draw arrows if scrolling is possible and menu is hidden + float const liney(firstliney + (lineheight * line)); + if (m_hide_menu) + { + bool const uparrow(!line && m_top_field); + bool const downarrow(((visible_fields - 1) == line) && ((m_field_data.size() - 1) > (line + m_top_field))); + if (uparrow || downarrow) + { + float const arrowwidth = lineheight * aspect; + draw_arrow( + 0.5f * (nameleft + indright - arrowwidth), liney + (0.25f * lineheight), + 0.5f * (nameleft + indright + arrowwidth), liney + (0.75f * lineheight), + fgcolor, line ? (ROT0 ^ ORIENTATION_FLIP_Y) : ROT0); + continue; + } + } + + // draw the field name, using the selected colour if it's being configured + field_data &data(m_field_data[line + m_top_field]); bool const selected(&data.field.get() == selfield); - rgb_t const fgcolor(selected ? ui().colors().selected_color() : ui().colors().text_color()); - float const liney(y2 + (ui().box_tb_border() * 2.0f) + (ui().get_line_height() * line)); + rgb_t const fieldcolor(selected ? ui().colors().selected_color() : fgcolor); ui().draw_text_full( container(), data.field.get().name(), nameleft, liney, namewidth, text_layout::text_justify::LEFT, text_layout::word_wrapping::NEVER, - mame_ui_manager::NORMAL, fgcolor, ui().colors().text_bg_color()); + mame_ui_manager::NORMAL, fieldcolor, ui().colors().text_bg_color()); ioport_value cur(0U); data.field.get().live().analog->read(cur); @@ -102,8 +173,8 @@ void menu_analog::custom_render(void *selectedref, float top, float bottom, floa if (data.field.get().analog_reverse()) fill = 1.0f - fill; - float const indtop(liney + (ui().get_line_height() * 0.2f)); - float const indbottom(liney + (ui().get_line_height() * 0.8f)); + float const indtop(liney + (lineheight * 0.2f)); + float const indbottom(liney + (lineheight * 0.8f)); if (data.origin > fill) container().add_rect(indleft + (fill * 0.4f), indtop, indleft + (data.origin * 0.4f), indbottom, fgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); else @@ -114,10 +185,6 @@ void menu_analog::custom_render(void *selectedref, float top, float bottom, floa container().add_line(indleft, indbottom, indleft, indtop, UI_LINE_WIDTH, fgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); if (data.show_neutral) container().add_line(indleft + (data.neutral * 0.4f), indtop, indleft + (data.neutral * 0.4f), indbottom, UI_LINE_WIDTH, fgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); - - // TODO: ensure field being configured is visible - if (++line >= m_visible_fields) - break; } } @@ -125,53 +192,133 @@ void menu_analog::custom_render(void *selectedref, float top, float bottom, floa void menu_analog::handle(event const *ev) { // handle events - if (ev && ev->itemref) + if (ev) { - item_data &data(*reinterpret_cast(ev->itemref)); - int newval(data.cur); - - switch (ev->iptkey) + if (IPT_UI_ON_SCREEN_DISPLAY == ev->iptkey) { - // if selected, reset to default value - case IPT_UI_SELECT: - newval = data.defvalue; - break; - - // left decrements - case IPT_UI_LEFT: - newval -= machine().input().code_pressed(KEYCODE_LSHIFT) ? 10 : 1; - break; - - // right increments - case IPT_UI_RIGHT: - newval += machine().input().code_pressed(KEYCODE_LSHIFT) ? 10 : 1; - break; + m_hide_menu = !m_hide_menu; + set_process_flags(PROCESS_LR_REPEAT | (m_hide_menu ? (PROCESS_CUSTOM_NAV | PROCESS_CUSTOM_ONLY) : 0)); } - - // clamp to range - if (newval < data.min) - newval = data.min; - if (newval > data.max) - newval = data.max; - - // if things changed, update - if (newval != data.cur) + else if (m_hide_menu) { - ioport_field::user_settings settings; - - // get the settings and set the new value - data.field.get().get_user_settings(settings); - switch (data.type) + switch (ev->iptkey) { - case ANALOG_ITEM_KEYSPEED: settings.delta = newval; break; - case ANALOG_ITEM_CENTERSPEED: settings.centerdelta = newval; break; - case ANALOG_ITEM_REVERSE: settings.reverse = newval; break; - case ANALOG_ITEM_SENSITIVITY: settings.sensitivity = newval; break; + case IPT_UI_UP: + --m_top_field; + break; + case IPT_UI_DOWN: + ++m_top_field; + break; + case IPT_UI_HOME: + m_top_field = 0; + break; + case IPT_UI_END: + m_top_field = m_field_data.size(); + break; } - data.field.get().set_user_settings(settings); + } + else if (ev->itemref) + { + item_data &data(*reinterpret_cast(ev->itemref)); + int newval(data.cur); - // rebuild the menu - reset(reset_options::REMEMBER_POSITION); + switch (ev->iptkey) + { + // if selected, reset to default value + case IPT_UI_SELECT: + newval = data.defvalue; + break; + + // left decrements + case IPT_UI_LEFT: + newval -= machine().input().code_pressed(KEYCODE_LSHIFT) ? 10 : 1; + break; + + // right increments + case IPT_UI_RIGHT: + newval += machine().input().code_pressed(KEYCODE_LSHIFT) ? 10 : 1; + break; + + // move to first item for previous device + case IPT_UI_PREV_GROUP: + { + auto current = std::distance(m_item_data.data(), &data); + device_t const *dev(&data.field.get().device()); + bool found_break = false; + while (0 < current) + { + if (!found_break) + { + device_t const *prev(&m_item_data[--current].field.get().device()); + if (prev != dev) + { + dev = prev; + found_break = true; + } + } + else if (&m_item_data[current - 1].field.get().device() != dev) + { + set_selection(&m_item_data[current]); + set_top_line(selected_index() - 1); + break; + } + else + { + --current; + } + if (found_break && !current) + { + set_selection(&m_item_data[current]); + set_top_line(selected_index() - 1); + break; + } + } + } + break; + + // move to first item for next device + case IPT_UI_NEXT_GROUP: + { + auto current = std::distance(m_item_data.data(), &data); + device_t const *const dev(&data.field.get().device()); + while (m_item_data.size() > ++current) + { + if (&m_item_data[current].field.get().device() != dev) + { + set_selection(&m_item_data[current]); + set_top_line(selected_index() - 1); + break; + } + } + } + break; + } + + // clamp to range + if (newval < data.min) + newval = data.min; + if (newval > data.max) + newval = data.max; + + // if things changed, update + if (newval != data.cur) + { + ioport_field::user_settings settings; + + // get the settings and set the new value + data.field.get().get_user_settings(settings); + switch (data.type) + { + case ANALOG_ITEM_KEYSPEED: settings.delta = newval; break; + case ANALOG_ITEM_CENTERSPEED: settings.centerdelta = newval; break; + case ANALOG_ITEM_REVERSE: settings.reverse = newval; break; + case ANALOG_ITEM_SENSITIVITY: settings.sensitivity = newval; break; + } + data.field.get().set_user_settings(settings); + + // rebuild the menu + reset(reset_options::REMEMBER_POSITION); + } } } } @@ -184,7 +331,6 @@ void menu_analog::populate(float &customtop, float &custombottom) find_fields(); device_t *prev_owner(nullptr); - bool first_entry(true); ioport_field *field(nullptr); ioport_field::user_settings settings; @@ -202,11 +348,10 @@ void menu_analog::populate(float &customtop, float &custombottom) if (&field->device() != prev_owner) { prev_owner = &field->device(); - if (first_entry) - first_entry = false; + if (prev_owner->owner()) + item_append(string_format(_("%1$s [root%2$s]"), prev_owner->type().fullname(), prev_owner->tag()), FLAG_UI_HEADING | FLAG_DISABLE, nullptr); else - item_append(menu_item_type::SEPARATOR); - item_append(string_format("[root%s]", prev_owner->tag()), 0, nullptr); + item_append(string_format(_("[root%1$s]"), prev_owner->tag()), FLAG_UI_HEADING | FLAG_DISABLE, nullptr); } } @@ -304,9 +449,9 @@ void menu_analog::find_fields() } } - // restrict live display to 60% height plus borders - if ((ui().get_line_height() * m_field_data.size()) > 0.6f) - m_visible_fields = unsigned(0.6f / ui().get_line_height()); + // restrict live display to 40% height plus borders + if ((ui().get_line_height() * m_field_data.size()) > 0.4f) + m_visible_fields = unsigned(0.4f / ui().get_line_height()); else m_visible_fields = m_field_data.size(); } diff --git a/src/frontend/mame/ui/analogipt.h b/src/frontend/mame/ui/analogipt.h index 36ab7906ee3..b4baa6bfa88 100644 --- a/src/frontend/mame/ui/analogipt.h +++ b/src/frontend/mame/ui/analogipt.h @@ -72,7 +72,10 @@ private: item_data_vector m_item_data; field_data_vector m_field_data; + std::string m_prompt; unsigned m_visible_fields; + int m_top_field; + bool m_hide_menu; }; } // namespace ui diff --git a/src/frontend/mame/ui/mainmenu.cpp b/src/frontend/mame/ui/mainmenu.cpp index 132902b8f81..0de7d7ca4d3 100644 --- a/src/frontend/mame/ui/mainmenu.cpp +++ b/src/frontend/mame/ui/mainmenu.cpp @@ -87,7 +87,9 @@ enum : unsigned { menu_main constructor/destructor -------------------------------------------------*/ -menu_main::menu_main(mame_ui_manager &mui, render_container &container) : menu(mui, container) +menu_main::menu_main(mame_ui_manager &mui, render_container &container) + : menu(mui, container) + , m_phase(machine_phase::PREINIT) { set_needs_prev_menu_item(false); } diff --git a/src/frontend/mame/ui/menu.cpp b/src/frontend/mame/ui/menu.cpp index 4df4731cb4f..f42b927091b 100644 --- a/src/frontend/mame/ui/menu.cpp +++ b/src/frontend/mame/ui/menu.cpp @@ -1013,10 +1013,6 @@ void menu::handle_keys(uint32_t flags, int &iptkey) return; if (!ignoreright && exclusive_input_pressed(iptkey, IPT_UI_RIGHT, (flags & PROCESS_LR_REPEAT) ? 6 : 0)) return; - if (exclusive_input_pressed(iptkey, IPT_UI_PREV_GROUP, 0)) - return; - if (exclusive_input_pressed(iptkey, IPT_UI_NEXT_GROUP, 0)) - return; // up backs up by one item if (exclusive_input_pressed(iptkey, IPT_UI_UP, 6)) diff --git a/src/frontend/mame/ui/pluginopt.cpp b/src/frontend/mame/ui/pluginopt.cpp index f21511f1645..6f6a980d871 100644 --- a/src/frontend/mame/ui/pluginopt.cpp +++ b/src/frontend/mame/ui/pluginopt.cpp @@ -162,6 +162,8 @@ void menu_plugin_opt::populate(float &customtop, float &custombottom) item_flags_or |= FLAG_INVERT; else if (flag == "heading") item_flags_or |= FLAG_DISABLE | FLAG_UI_HEADING; + else + osd_printf_info("menu_plugin_opt: unknown flag '%s' for item %d (%s)\n", flag, i, text); } if (text == "---") @@ -189,16 +191,20 @@ void menu_plugin_opt::populate(float &customtop, float &custombottom) mflags.remove_prefix(flag.length()); flag_start = mflags.find_first_not_of(' '); - if (flag == "lralways") + if (flag == "nokeys") + process_flags |= PROCESS_NOKEYS; + else if (flag == "lralways") process_flags |= PROCESS_LR_ALWAYS; else if (flag == "lrrepeat") process_flags |= PROCESS_LR_REPEAT; else if (flag == "customnav") process_flags |= PROCESS_CUSTOM_NAV; + else if (flag == "ignorepause") + process_flags |= PROCESS_IGNOREPAUSE; else if (flag == "idle") m_need_idle = true; - else if (flag == "nokeys") - process_flags |= PROCESS_NOKEYS; + else + osd_printf_info("menu_plugin_opt: unknown processing flag '%s'\n", flag); } if (process_flags & PROCESS_NOKEYS) m_need_idle = true; diff --git a/src/frontend/mame/ui/selgame.cpp b/src/frontend/mame/ui/selgame.cpp index 0572b1dcf86..5fceddc1b3e 100644 --- a/src/frontend/mame/ui/selgame.cpp +++ b/src/frontend/mame/ui/selgame.cpp @@ -43,12 +43,6 @@ extern const char UI_VERSION_TAG[]; namespace ui { -namespace { - -constexpr uint32_t FLAGS_UI = ui::menu::FLAG_LEFT_ARROW | ui::menu::FLAG_RIGHT_ARROW; - -} // anonymous namespace - bool menu_select_game::s_first_start = true; @@ -398,7 +392,7 @@ void menu_select_game::populate(float &customtop, float &custombottom) if (old_item_selected == -1 && elem.driver->name == reselect_last::driver()) old_item_selected = curitem; - item_append(elem.description, elem.is_clone ? (FLAGS_UI | FLAG_INVERT) : FLAGS_UI, (void *)&elem); + item_append(elem.description, elem.is_clone ? FLAG_INVERT : 0, (void *)&elem); curitem++; } } @@ -423,14 +417,13 @@ void menu_select_game::populate(float &customtop, float &custombottom) cloneof = false; } - item_append(info.longname, cloneof ? (FLAGS_UI | FLAG_INVERT) : FLAGS_UI, (void *)&info); + item_append(info.longname, cloneof ? FLAG_INVERT : 0, (void *)&info); } else { if (old_item_selected == -1 && info.shortname == reselect_last::driver()) old_item_selected = curitem; - item_append(info.longname, info.devicetype, - info.parentname.empty() ? FLAGS_UI : (FLAG_INVERT | FLAGS_UI), (void *)&info); + item_append(info.longname, info.devicetype, info.parentname.empty() ? 0 : FLAG_INVERT, (void *)&info); } curitem++; }); @@ -439,9 +432,9 @@ void menu_select_game::populate(float &customtop, float &custombottom) // add special items if (stack_has_special_main_menu()) { - item_append(menu_item_type::SEPARATOR, FLAGS_UI); - item_append(_("Configure Options"), FLAGS_UI, (void *)(uintptr_t)CONF_OPTS); - item_append(_("Configure Machine"), FLAGS_UI, (void *)(uintptr_t)CONF_MACHINE); + item_append(menu_item_type::SEPARATOR, 0); + item_append(_("Configure Options"), 0, (void *)(uintptr_t)CONF_OPTS); + item_append(_("Configure Machine"), 0, (void *)(uintptr_t)CONF_MACHINE); skip_main_items = 3; } else diff --git a/src/frontend/mame/ui/selmenu.cpp b/src/frontend/mame/ui/selmenu.cpp index d55009623e8..29bec4fe639 100644 --- a/src/frontend/mame/ui/selmenu.cpp +++ b/src/frontend/mame/ui/selmenu.cpp @@ -1449,26 +1449,36 @@ void menu_select_launch::handle_keys(uint32_t flags, int &iptkey) validate_selection(1); // swallow left/right keys if they are not appropriate - bool const ignoreleft = ((selected_item().flags & FLAG_LEFT_ARROW) == 0); - bool const ignoreright = ((selected_item().flags & FLAG_RIGHT_ARROW) == 0); bool const leftclose = (ui_globals::panels_status == HIDE_BOTH || ui_globals::panels_status == HIDE_LEFT_PANEL); bool const rightclose = (ui_globals::panels_status == HIDE_BOTH || ui_globals::panels_status == HIDE_RIGHT_PANEL); // accept left/right keys as-is with repeat - if (!ignoreleft && exclusive_input_pressed(iptkey, IPT_UI_LEFT, (flags & PROCESS_LR_REPEAT) ? 6 : 0)) + if (exclusive_input_pressed(iptkey, IPT_UI_LEFT, (flags & PROCESS_LR_REPEAT) ? 6 : 0)) { - // Swap the right panel if (m_focus == focused_menu::RIGHTTOP) + { + // Swap the right panel and swallow it ui_globals::rpanel = RP_IMAGES; - return; + iptkey = IPT_INVALID; + } + else + { + return; + } } - if (!ignoreright && exclusive_input_pressed(iptkey, IPT_UI_RIGHT, (flags & PROCESS_LR_REPEAT) ? 6 : 0)) + if (exclusive_input_pressed(iptkey, IPT_UI_RIGHT, (flags & PROCESS_LR_REPEAT) ? 6 : 0)) { - // Swap the right panel if (m_focus == focused_menu::RIGHTTOP) + { + // Swap the right panel and swallow it ui_globals::rpanel = RP_INFOS; - return; + iptkey = IPT_INVALID; + } + else + { + return; + } } // up backs up by one item @@ -1478,7 +1488,7 @@ void menu_select_launch::handle_keys(uint32_t flags, int &iptkey) { return; } - else if (!rightclose && m_focus == focused_menu::RIGHTBOTTOM) + else if (!rightclose && ((m_focus == focused_menu::RIGHTTOP) || (m_focus == focused_menu::RIGHTBOTTOM))) { m_topline_datsview--; return; @@ -1501,7 +1511,7 @@ void menu_select_launch::handle_keys(uint32_t flags, int &iptkey) { return; } - else if (!rightclose && m_focus == focused_menu::RIGHTBOTTOM) + else if (!rightclose && ((m_focus == focused_menu::RIGHTTOP) || (m_focus == focused_menu::RIGHTBOTTOM))) { m_topline_datsview++; return; @@ -1520,7 +1530,7 @@ void menu_select_launch::handle_keys(uint32_t flags, int &iptkey) if (exclusive_input_pressed(iptkey, IPT_UI_PAGE_UP, 6)) { // Infos - if (!rightclose && m_focus == focused_menu::RIGHTBOTTOM) + if (!rightclose && ((m_focus == focused_menu::RIGHTTOP) || (m_focus == focused_menu::RIGHTBOTTOM))) { m_topline_datsview -= m_right_visible_lines - 3; return; @@ -1538,7 +1548,7 @@ void menu_select_launch::handle_keys(uint32_t flags, int &iptkey) if (exclusive_input_pressed(iptkey, IPT_UI_PAGE_DOWN, 6)) { // Infos - if (!rightclose && m_focus == focused_menu::RIGHTBOTTOM) + if (!rightclose && ((m_focus == focused_menu::RIGHTTOP) || (m_focus == focused_menu::RIGHTBOTTOM))) { m_topline_datsview += m_right_visible_lines - 3; return; @@ -1559,7 +1569,7 @@ void menu_select_launch::handle_keys(uint32_t flags, int &iptkey) { return; } - else if (!rightclose && m_focus == focused_menu::RIGHTBOTTOM) + else if (!rightclose && ((m_focus == focused_menu::RIGHTTOP) || (m_focus == focused_menu::RIGHTBOTTOM))) { m_topline_datsview = 0; return; @@ -1576,7 +1586,7 @@ void menu_select_launch::handle_keys(uint32_t flags, int &iptkey) { return; } - else if (!rightclose && m_focus == focused_menu::RIGHTBOTTOM) + else if (!rightclose && ((m_focus == focused_menu::RIGHTTOP) || (m_focus == focused_menu::RIGHTBOTTOM))) { m_topline_datsview = m_total_lines; return; @@ -1618,14 +1628,6 @@ void menu_select_launch::handle_keys(uint32_t flags, int &iptkey) case IPT_UI_FOCUS_PREV: case IPT_UI_PAUSE: continue; - case IPT_UI_LEFT: - if (ignoreleft) - continue; - break; - case IPT_UI_RIGHT: - if (ignoreright) - continue; - break; } if (exclusive_input_pressed(iptkey, code, 0)) diff --git a/src/frontend/mame/ui/selsoft.cpp b/src/frontend/mame/ui/selsoft.cpp index e0d3023050a..e129b1c064e 100644 --- a/src/frontend/mame/ui/selsoft.cpp +++ b/src/frontend/mame/ui/selsoft.cpp @@ -508,7 +508,6 @@ void menu_select_software::populate(float &customtop, float &custombottom) for (auto &icon : m_data->icons()) // TODO: why is this here? maybe better on resize or setting change? icon.second.texture.reset(); - uint32_t flags_ui = FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW; int old_software = -1; // start with an empty list @@ -521,7 +520,7 @@ void menu_select_software::populate(float &customtop, float &custombottom) // add an item to start empty or let the user use the file manager item_append( m_data->has_empty_start() ? _("[Start empty]") : _("[Use file manager]"), - flags_ui, + 0, (void *)&m_data->swinfo()[0]); if (!flt) @@ -561,7 +560,7 @@ void menu_select_software::populate(float &customtop, float &custombottom) item_append( m_displaylist[curitem].get().longname, m_displaylist[curitem].get().devicetype, - m_displaylist[curitem].get().parentname.empty() ? flags_ui : (FLAG_INVERT | flags_ui), (void *)&m_displaylist[curitem].get()); + m_displaylist[curitem].get().parentname.empty() ? 0 : FLAG_INVERT, (void *)&m_displaylist[curitem].get()); } // configure the custom rendering diff --git a/src/frontend/mame/ui/simpleselgame.cpp b/src/frontend/mame/ui/simpleselgame.cpp index 4803b390247..82fde5bae79 100644 --- a/src/frontend/mame/ui/simpleselgame.cpp +++ b/src/frontend/mame/ui/simpleselgame.cpp @@ -205,6 +205,7 @@ void simple_menu_select_game::inkey_cancel() if (!m_search.empty()) { m_search.clear(); + m_rerandomize = true; reset(reset_options::SELECT_FIRST); } } diff --git a/src/frontend/mame/ui/sliders.cpp b/src/frontend/mame/ui/sliders.cpp index e26b76e2302..4dbb69baa1a 100644 --- a/src/frontend/mame/ui/sliders.cpp +++ b/src/frontend/mame/ui/sliders.cpp @@ -41,9 +41,23 @@ void menu_sliders::handle(event const *ev) // process the menu if (ev) { - // handle keys if there is a valid item selected - if (ev->itemref && (ev->type == menu_item_type::SLIDER)) + if (ev->iptkey == IPT_UI_ON_SCREEN_DISPLAY) { + // toggle visibility + if (m_menuless_mode) + { + stack_pop(); + } + else + { + m_hidden = !m_hidden; + set_process_flags(PROCESS_LR_REPEAT | (m_hidden ? PROCESS_CUSTOM_ONLY : 0)); + } + + } + else if (ev->itemref && (ev->type == menu_item_type::SLIDER)) + { + // handle keys if there is a valid item selected const slider_state *slider = (const slider_state *)ev->itemref; int32_t curvalue = slider->update(nullptr, SLIDER_NOCHANGE); int32_t increment = 0; @@ -53,24 +67,11 @@ void menu_sliders::handle(event const *ev) switch (ev->iptkey) { - // toggle visibility - case IPT_UI_ON_SCREEN_DISPLAY: - if (m_menuless_mode) - { - stack_pop(); - } - else - { - m_hidden = !m_hidden; - set_process_flags(PROCESS_LR_REPEAT | (m_hidden ? PROCESS_CUSTOM_ONLY : 0)); - } - break; - // decrease value case IPT_UI_LEFT: if (alt_pressed && shift_pressed) increment = -1; - if (alt_pressed) + else if (alt_pressed) increment = -(curvalue - slider->minval); else if (shift_pressed) increment = (slider->incval > 10) ? -(slider->incval / 10) : -1; @@ -84,7 +85,7 @@ void menu_sliders::handle(event const *ev) case IPT_UI_RIGHT: if (alt_pressed && shift_pressed) increment = 1; - if (alt_pressed) + else if (alt_pressed) increment = slider->maxval - curvalue; else if (shift_pressed) increment = (slider->incval > 10) ? (slider->incval / 10) : 1; @@ -116,10 +117,9 @@ void menu_sliders::handle(event const *ev) reset(reset_options::REMEMBER_REF); } } - - // if we are selecting an invalid item and we are hidden, skip to the next one else if (m_hidden) { + // if we are selecting an invalid item and we are hidden, skip to the next one if (ev->iptkey == IPT_UI_UP || ev->iptkey == IPT_UI_PAGE_UP) { // if we got here via up or page up, select the previous item diff --git a/src/frontend/mame/ui/textbox.cpp b/src/frontend/mame/ui/textbox.cpp index 177f39a0f53..9761491bf78 100644 --- a/src/frontend/mame/ui/textbox.cpp +++ b/src/frontend/mame/ui/textbox.cpp @@ -178,8 +178,8 @@ void menu_textbox::draw(uint32_t flags) 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, + 0.5f * (x1 + x2 - ud_arrow_width), visible_top + (0.25f * line_height), + 0.5f * (x1 + x2 + ud_arrow_width), visible_top + (0.75f * line_height), fgcolor, ROT0); } if ((m_top_line + m_window_lines) < visible_items) @@ -197,8 +197,8 @@ void menu_textbox::draw(uint32_t flags) 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, + 0.5f * (x1 + x2 - ud_arrow_width), line_y + (0.25f * line_height), + 0.5f * (x1 + x2 + ud_arrow_width), line_y + (0.75f * line_height), fgcolor, ROT0 ^ ORIENTATION_FLIP_Y); }