diff options
author | 2021-11-02 07:53:18 +1100 | |
---|---|---|
committer | 2021-11-02 07:53:18 +1100 | |
commit | 8ab63e2072f6cfe19b8f8e2acfbd29754d282c79 (patch) | |
tree | 5e05b0a71e44d3b5466a28e9232b32252a96d620 /src/frontend/mame/ui/analogipt.cpp | |
parent | 782359169952d8fd7bf737ff45a0c3650ca12c7e (diff) |
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.
Diffstat (limited to 'src/frontend/mame/ui/analogipt.cpp')
-rw-r--r-- | src/frontend/mame/ui/analogipt.cpp | 269 |
1 files changed, 207 insertions, 62 deletions
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 <algorithm> +#include <iterator> #include <string> #include <utility> @@ -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<int>(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<item_data *>(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<item_data *>(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<item_data *>(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; + switch (ev->iptkey) + { + 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; + } + } + else if (ev->itemref) + { + item_data &data(*reinterpret_cast<item_data *>(ev->itemref)); + int newval(data.cur); - // 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; + // 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; } - data.field.get().set_user_settings(settings); - // rebuild the menu - reset(reset_options::REMEMBER_POSITION); + // 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(); } |