diff options
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 |
commit | b98fb7c98e5e44d436808eac46c927d3d0dc1f3f (patch) | |
tree | cd411d4fe24cd36862c78165723833e42de27303 /src/frontend/mame/ui | |
parent | 519554c8464ba8e8641e474bc949a2a0beae77ae (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.cpp | 7 | ||||
-rw-r--r-- | src/frontend/mame/ui/inputdevices.cpp | 4 | ||||
-rw-r--r-- | src/frontend/mame/ui/inputtoggle.cpp | 11 | ||||
-rw-r--r-- | src/frontend/mame/ui/textbox.cpp | 217 | ||||
-rw-r--r-- | src/frontend/mame/ui/textbox.h | 26 |
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 |