summaryrefslogtreecommitdiffstatshomepage
path: root/src/frontend/mame/ui
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2023-02-05 04:50:30 +1100
committer Vas Crabb <vas@vastheman.com>2023-02-05 05:01:40 +1100
commitb98fb7c98e5e44d436808eac46c927d3d0dc1f3f (patch)
treecd411d4fe24cd36862c78165723833e42de27303 /src/frontend/mame/ui
parent519554c8464ba8e8641e474bc949a2a0beae77ae (diff)
Small batch of input refactoring:
emu/input.cpp: Fixed regression in display of some joystick inputs. osd/interface: Split up interface classes into a few more files to reduce where the input device interface class needs to be included. Made OSD independent of concrete input_device class. osd/modules/input, emu/inputdev.cpp, emu/ioport.cpp: Allow input devices to provide tokens for controls without standard item types and additional default input assignments. Fixes issues assigning Yen and Backslash on Japanese keyboards. ui/textbox.cpp: Added a fixed-content text box menu class for future use. Got main.h out of emu.h as it’s only used in a very small number of places, mostly for getting the application name. Added eminline.h to attotime.h as it's used without emu.h. Cleaned up forward declarations in emufwd.h a little.
Diffstat (limited to 'src/frontend/mame/ui')
-rw-r--r--src/frontend/mame/ui/analogipt.cpp7
-rw-r--r--src/frontend/mame/ui/inputdevices.cpp4
-rw-r--r--src/frontend/mame/ui/inputtoggle.cpp11
-rw-r--r--src/frontend/mame/ui/textbox.cpp217
-rw-r--r--src/frontend/mame/ui/textbox.h26
5 files changed, 211 insertions, 54 deletions
diff --git a/src/frontend/mame/ui/analogipt.cpp b/src/frontend/mame/ui/analogipt.cpp
index d8bbbae5eb6..ed0daf0b152 100644
--- a/src/frontend/mame/ui/analogipt.cpp
+++ b/src/frontend/mame/ui/analogipt.cpp
@@ -246,8 +246,13 @@ void menu_analog::handle(event const *ev)
switch (ev->iptkey)
{
- // if selected, reset to default value
+ // flip toggles when selected
case IPT_UI_SELECT:
+ if (ANALOG_ITEM_REVERSE == data.type)
+ newval = newval ? 0 : 1;
+ break;
+
+ // if cleared, reset to default value
case IPT_UI_CLEAR:
newval = data.defvalue;
break;
diff --git a/src/frontend/mame/ui/inputdevices.cpp b/src/frontend/mame/ui/inputdevices.cpp
index 71d09a0b280..4890b1ac724 100644
--- a/src/frontend/mame/ui/inputdevices.cpp
+++ b/src/frontend/mame/ui/inputdevices.cpp
@@ -89,12 +89,12 @@ protected:
s32 const value = (input.itemclass() == ITEM_CLASS_ABSOLUTE) ? input.read_as_absolute(ITEM_MODIFIER_NONE) : input.read_as_relative(ITEM_MODIFIER_NONE);
if (0 < value)
{
- float const fillright = indcentre + (float(value) / float(osd::INPUT_ABSOLUTE_MAX) * (indright - indcentre));
+ float const fillright = indcentre + (float(value) / float(osd::input_device::ABSOLUTE_MAX) * (indright - indcentre));
container().add_rect(indcentre, indtop, (std::min)(fillright, indright), indbottom, fgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
}
else if (0 > value)
{
- float const fillleft = indcentre - (float(value) / float(osd::INPUT_ABSOLUTE_MIN) * (indcentre - indleft));
+ float const fillleft = indcentre - (float(value) / float(osd::input_device::ABSOLUTE_MIN) * (indcentre - indleft));
container().add_rect((std::max)(fillleft, indleft), indtop, indcentre, indbottom, fgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
}
container().add_line(indleft, indtop, indright, indtop, UI_LINE_WIDTH, fgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
diff --git a/src/frontend/mame/ui/inputtoggle.cpp b/src/frontend/mame/ui/inputtoggle.cpp
index e86d41b7031..172ae16b141 100644
--- a/src/frontend/mame/ui/inputtoggle.cpp
+++ b/src/frontend/mame/ui/inputtoggle.cpp
@@ -119,14 +119,13 @@ void menu_input_toggles::handle(event const *ev)
bool invalidate = false;
switch (ev->iptkey)
{
- case IPT_UI_SELECT: // toggle regular items, set multi-value items to default
+ case IPT_UI_SELECT: // toggle regular items, cycle multi-value items
if (field.settings().empty())
- {
field.live().value ^= field.mask();
- invalidate = true;
- break;
- }
- [[fallthrough]];
+ else
+ field.select_next_setting();
+ invalidate = true;
+ break;
case IPT_UI_CLEAR: // set to default
if (field.defvalue() != field.live().value)
diff --git a/src/frontend/mame/ui/textbox.cpp b/src/frontend/mame/ui/textbox.cpp
index 9c6dfded606..e3cb88cdd36 100644
--- a/src/frontend/mame/ui/textbox.cpp
+++ b/src/frontend/mame/ui/textbox.cpp
@@ -15,19 +15,73 @@
#include "ui/utils.h"
#include <string_view>
+#include <utility>
namespace ui {
+namespace {
+
+inline std::string_view split_column(std::string_view &line)
+{
+ auto const split = line.find('\t');
+ if (std::string::npos == split)
+ {
+ return std::exchange(line, std::string_view());
+ }
+ else
+ {
+ std::string_view result = line.substr(0, split);
+ line.remove_prefix(split + 1);
+ return result;
+ }
+}
+
+
+template <typename T, typename U, typename V>
+void populate_three_column_layout(std::string_view text, T &&l, U &&c, V &&r)
+{
+ while (!text.empty())
+ {
+ // pop a line from the front
+ auto const eol = text.find('\n');
+ std::string_view line = (std::string_view::npos != eol)
+ ? text.substr(0, eol + 1)
+ : text;
+ text.remove_prefix(line.length());
+
+ // left-justify up to the first tab
+ std::string_view const lcol = split_column(line);
+ if (!lcol.empty())
+ l(lcol);
+
+ // centre up to the second tab
+ if (!line.empty())
+ {
+ std::string_view const ccol = split_column(line);
+ if (!ccol.empty())
+ c(ccol);
+ }
+
+ // right-justify the rest
+ if (!line.empty())
+ r(line);
+ }
+}
+
+} // anonymous namespace
+
+
+
//-------------------------------------------------
-// constructor
+// menu_textbox - base text box menu class
//-------------------------------------------------
menu_textbox::menu_textbox(mame_ui_manager &mui, render_container &container)
: menu(mui, container)
, m_layout()
- , m_layout_width(-1.0f)
- , m_desired_width(-1.0f)
+ , m_layout_width(-1.0F)
+ , m_desired_width(-1.0F)
, m_desired_lines(-1)
, m_window_lines(0)
, m_top_line(0)
@@ -35,31 +89,19 @@ menu_textbox::menu_textbox(mame_ui_manager &mui, render_container &container)
}
-//-------------------------------------------------
-// destructor
-//-------------------------------------------------
-
menu_textbox::~menu_textbox()
{
}
-//-------------------------------------------------
-// reset_layout - force repopulate and scroll to
-// top
-//-------------------------------------------------
-
void menu_textbox::reset_layout()
{
+ // force recompute and scroll to top
m_layout = std::nullopt;
m_top_line = 0;
}
-//-------------------------------------------------
-// handle_key - handle basic navigation keys
-//-------------------------------------------------
-
void menu_textbox::handle_key(int key)
{
switch (key)
@@ -91,10 +133,6 @@ void menu_textbox::handle_key(int key)
}
-//-------------------------------------------------
-// recompute_metrics - recompute metrics
-//-------------------------------------------------
-
void menu_textbox::recompute_metrics(uint32_t width, uint32_t height, float aspect)
{
menu::recompute_metrics(width, height, aspect);
@@ -103,10 +141,6 @@ void menu_textbox::recompute_metrics(uint32_t width, uint32_t height, float aspe
}
-//-------------------------------------------------
-// custom_mouse_scroll - handle scroll events
-//-------------------------------------------------
-
bool menu_textbox::custom_mouse_scroll(int lines)
{
m_top_line += lines;
@@ -114,25 +148,21 @@ bool menu_textbox::custom_mouse_scroll(int lines)
}
-//-------------------------------------------------
-// draw - draw the menu
-//-------------------------------------------------
-
void menu_textbox::draw(uint32_t flags)
{
- float const visible_width = 1.0f - (2.0f * lr_border());
- float const visible_left = (1.0f - visible_width) * 0.5f;
- float const extra_height = 2.0f * line_height();
+ float const visible_width = 1.0F - (2.0F * lr_border());
+ 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
- float const maximum_width = visible_width - (2.0f * gutter_width());
+ float const maximum_width = visible_width - (2.0F * gutter_width());
draw_background();
map_mouse();
// account for extra space at the top and bottom and the separator/item for closing
- float visible_main_menu_height = 1.0f - 2.0f * tb_border() - visible_extra_menu_height;
+ float visible_main_menu_height = 1.0F - 2.0F * tb_border() - visible_extra_menu_height;
m_window_lines = int(std::trunc(visible_main_menu_height / line_height()));
// lay out the text if necessary
@@ -146,7 +176,7 @@ void menu_textbox::draw(uint32_t flags)
visible_main_menu_height = float(m_window_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();
+ float const visible_top = ((1.0F - (visible_main_menu_height + visible_extra_menu_height)) * 0.5F) + get_customtop();
// get width required to draw the sole menu item
menu_item const &pitem = item(0);
@@ -155,13 +185,13 @@ void menu_textbox::draw(uint32_t flags)
float const draw_width = std::min(maximum_width, std::max(itemwidth, m_desired_width));
// compute text box size
- float const x1 = visible_left + ((maximum_width - draw_width) * 0.5f);
+ float const x1 = visible_left + ((maximum_width - draw_width) * 0.5F);
float const y1 = visible_top - tb_border();
- float const x2 = visible_left + visible_width - ((maximum_width - draw_width) * 0.5f);
+ float const x2 = visible_left + visible_width - ((maximum_width - draw_width) * 0.5F);
float const y2 = visible_top + visible_main_menu_height + 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 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_window_lines) * line_height();
ui().draw_outlined_box(container(), x1, y1, x2, y2, ui().colors().background_color());
@@ -187,8 +217,8 @@ void menu_textbox::draw(uint32_t flags)
set_hover(HOVER_ARROW_UP);
}
draw_arrow(
- 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()),
+ 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)
@@ -206,8 +236,8 @@ void menu_textbox::draw(uint32_t flags)
set_hover(HOVER_ARROW_DOWN);
}
draw_arrow(
- 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()),
+ 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);
}
@@ -216,12 +246,12 @@ void menu_textbox::draw(uint32_t flags)
m_layout->emit(
container(),
m_top_line ? (m_top_line + 1) : 0, text_lines,
- effective_left, visible_top + (m_top_line ? line_height() : 0.0f));
+ effective_left, visible_top + (m_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()),
+ x1, separator + (0.5F * line_height()),
+ x2, separator + (0.5F * line_height()),
UI_LINE_WIDTH, ui().colors().text_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
float const line_y0 = separator + line_height();
@@ -244,4 +274,101 @@ void menu_textbox::draw(uint32_t flags)
custom_render(get_selection_ref(), get_customtop(), get_custombottom(), x1, y1, x2, y2);
}
+
+
+//-------------------------------------------------
+// menu_fixed_textbox - text box with three-
+// column content supplied at construction
+//-------------------------------------------------
+
+menu_fixed_textbox::menu_fixed_textbox(
+ mame_ui_manager &mui,
+ render_container &container,
+ std::string &&heading,
+ std::string &&content)
+ : menu_textbox(mui, container)
+ , m_heading(std::move(heading))
+ , m_content(std::move(content))
+{
+}
+
+
+menu_fixed_textbox::~menu_fixed_textbox()
+{
+}
+
+
+void menu_fixed_textbox::recompute_metrics(uint32_t width, uint32_t height, float aspect)
+{
+ menu_textbox::recompute_metrics(width, height, aspect);
+
+ set_custom_space(line_height() + 3.0F * tb_border(), 0.0F);
+}
+
+
+void menu_fixed_textbox::custom_render(void *selectedref, float top, float bottom, float x1, float y1, float x2, float y2)
+{
+ std::string_view const toptext[] = { m_heading };
+ draw_text_box(
+ std::begin(toptext), std::end(toptext),
+ x1, x2, y1 - top, y1 - tb_border(),
+ text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, false,
+ ui().colors().text_color(), UI_GREEN_COLOR);
+}
+
+
+void menu_fixed_textbox::populate_text(
+ std::optional<text_layout> &layout,
+ float &width,
+ int &lines)
+{
+ // ugly - use temporary layouts to compute required width
+ {
+ text_layout l(create_layout(width));
+ text_layout c(create_layout(width));
+ text_layout r(create_layout(width));
+ populate_three_column_layout(
+ m_content,
+ [&l] (std::string_view s)
+ {
+ l.add_text(s, text_layout::text_justify::LEFT);
+ if (s.back() != '\n')
+ l.add_text("\n", text_layout::text_justify::LEFT);
+ },
+ [&c] (std::string_view s) {
+ c.add_text(s, text_layout::text_justify::LEFT);
+ if (s.back() != '\n')
+ c.add_text("\n", text_layout::text_justify::LEFT);
+ },
+ [&r] (std::string_view s) {
+ r.add_text(s, text_layout::text_justify::LEFT);
+ if (s.back() != '\n')
+ r.add_text("\n", text_layout::text_justify::LEFT);
+ });
+ width = (std::min)(l.actual_width() + c.actual_width() + r.actual_width(), width);
+ }
+
+ // now do it for real
+ layout.emplace(create_layout(width));
+ rgb_t const color = ui().colors().text_color();
+ populate_three_column_layout(
+ m_content,
+ [&layout, color] (std::string_view s) { layout->add_text(s, text_layout::text_justify::LEFT, color); },
+ [&layout, color] (std::string_view s) { layout->add_text(s, text_layout::text_justify::CENTER, color); },
+ [&layout, color] (std::string_view s) { layout->add_text(s, text_layout::text_justify::RIGHT, color); });
+ lines = layout->lines();
+}
+
+
+void menu_fixed_textbox::populate()
+{
+}
+
+
+void menu_fixed_textbox::handle(event const *ev)
+{
+ if (ev)
+ handle_key(ev->iptkey);
+}
+
} // namespace ui
diff --git a/src/frontend/mame/ui/textbox.h b/src/frontend/mame/ui/textbox.h
index 724134a482b..f7993f79121 100644
--- a/src/frontend/mame/ui/textbox.h
+++ b/src/frontend/mame/ui/textbox.h
@@ -14,6 +14,7 @@
#include "ui/text.h"
#include <optional>
+#include <string>
namespace ui {
@@ -45,6 +46,31 @@ private:
int m_top_line;
};
+
+class menu_fixed_textbox : public menu_textbox
+{
+public:
+ menu_fixed_textbox(
+ mame_ui_manager &mui,
+ render_container &container,
+ std::string &&headig,
+ std::string &&content);
+ virtual ~menu_fixed_textbox() override;
+
+protected:
+ virtual void recompute_metrics(uint32_t width, uint32_t height, float aspect) override;
+ 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 populate() override;
+ virtual void handle(event const *ev) override;
+
+ std::string const m_heading;
+ std::string const m_content;
+};
+
} // namespace ui
#endif // MAME_FRONTEND_UI_TEXTBOX_H