summaryrefslogtreecommitdiffstats
path: root/src/frontend/mame/ui/analogipt.cpp
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2021-11-02 07:53:18 +1100
committer Vas Crabb <vas@vastheman.com>2021-11-02 07:53:18 +1100
commit8ab63e2072f6cfe19b8f8e2acfbd29754d282c79 (patch)
tree5e05b0a71e44d3b5466a28e9232b32252a96d620 /src/frontend/mame/ui/analogipt.cpp
parent782359169952d8fd7bf737ff45a0c3650ca12c7e (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.cpp269
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();
}