From 9e2601c56b315eef4689811610b0f1451ed5a06d Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Sat, 16 Nov 2019 15:16:15 +1100 Subject: UI updates: * Made DIP switch display scale with UI font and improved layout * Improved analog control display giving an indication of neutral position * Fixed menu heading sizes not being recalculated after font is changed --- src/frontend/mame/ui/analogipt.cpp | 39 ++-- src/frontend/mame/ui/analogipt.h | 10 +- src/frontend/mame/ui/confswitch.cpp | 414 ++++++++++++++++++++++++++++++++++++ src/frontend/mame/ui/confswitch.h | 97 +++++++++ src/frontend/mame/ui/custui.cpp | 82 ++++--- src/frontend/mame/ui/custui.h | 20 +- src/frontend/mame/ui/inputmap.cpp | 319 --------------------------- src/frontend/mame/ui/inputmap.h | 47 ---- src/frontend/mame/ui/mainmenu.cpp | 3 +- src/frontend/mame/ui/miscmenu.cpp | 1 + src/frontend/mame/ui/optsmenu.cpp | 2 +- 11 files changed, 615 insertions(+), 419 deletions(-) create mode 100644 src/frontend/mame/ui/confswitch.cpp create mode 100644 src/frontend/mame/ui/confswitch.h (limited to 'src/frontend') diff --git a/src/frontend/mame/ui/analogipt.cpp b/src/frontend/mame/ui/analogipt.cpp index f70e62d9de0..d63f6afc490 100644 --- a/src/frontend/mame/ui/analogipt.cpp +++ b/src/frontend/mame/ui/analogipt.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods +// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods, Vas Crabb /********************************************************************* ui/analogipt.cpp @@ -12,11 +12,13 @@ #include "ui/analogipt.h" #include +#include +#include namespace ui { -inline menu_analog::item_data::item_data(ioport_field &f, int t) +inline menu_analog::item_data::item_data(ioport_field &f, int t) noexcept : field(f) , type(t) , min((ANALOG_ITEM_SENSITIVITY == t) ? 1 : 0) @@ -32,9 +34,12 @@ inline menu_analog::item_data::item_data(ioport_field &f, int t) } -inline menu_analog::field_data::field_data(ioport_field &f) +inline menu_analog::field_data::field_data(ioport_field &f) noexcept : field(f) , range(f.maxval() - f.minval()) + , neutral(float(f.analog_reverse() ? (f.maxval() - f.defvalue()) : (f.defvalue() - f.minval())) / range) + , origin((f.analog_wraps() && (f.defvalue() != f.minval()) && (f.defvalue() != f.maxval())) ? 0.0f : neutral) + , show_neutral((f.defvalue() != f.minval()) && (f.defvalue() != f.maxval())) { } @@ -56,8 +61,9 @@ menu_analog::~menu_analog() void menu_analog::custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) { // work out how much space to use for field names - float const extrawidth(0.4f + (ui().box_lr_border() * 2.0f) + (ui().get_line_height() * machine().render().ui_aspect())); - float const nameavail(1.0f - (ui().box_lr_border() * 2.0f) - extrawidth); + float const aspect(machine().render().ui_aspect(&container())); + float const extrawidth(0.4f + (((ui().box_lr_border() * 2.0f) + ui().get_line_height()) * aspect)); + float const nameavail(1.0f - (ui().box_lr_border() * 2.0f * aspect) - extrawidth); float namewidth(0.0f); for (field_data &data : m_field_data) namewidth = (std::min)((std::max)(ui().get_string_width(data.field.get().name()), namewidth), nameavail); @@ -68,9 +74,9 @@ void menu_analog::custom_render(void *selectedref, float top, float bottom, floa ui().draw_outlined_box(container(), boxleft, y2 + ui().box_tb_border(), boxright, y2 + bottom, ui().colors().background_color()); // show live fields - namewidth += ui().get_line_height() * machine().render().ui_aspect(); + namewidth += ui().get_line_height() * aspect; unsigned line(0U); - float const nameleft(boxleft + ui().box_lr_border()); + 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); @@ -82,7 +88,7 @@ void menu_analog::custom_render(void *selectedref, float top, float bottom, floa ui().draw_text_full( container(), data.field.get().name(), - nameleft, liney, namewidth, ui::text_layout::LEFT, ui::text_layout::TRUNCATE, + nameleft, liney, namewidth, ui::text_layout::LEFT, ui::text_layout::NEVER, mame_ui_manager::NORMAL, fgcolor, ui().colors().text_bg_color()); ioport_value cur(0U); @@ -94,11 +100,16 @@ void menu_analog::custom_render(void *selectedref, float top, float bottom, floa float const indtop(liney + (ui().get_line_height() * 0.2f)); float const indbottom(liney + (ui().get_line_height() * 0.8f)); - container().add_rect(indleft, indtop, indleft + (fill * 0.4f), indbottom, fgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + if (data.origin > fill) + container().add_rect(indleft + (fill * 0.4f), indtop, indleft + (data.origin * 0.4f), indbottom, fgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + else + container().add_rect(indleft + (data.origin * 0.4f), indtop, indleft + (fill * 0.4f), indbottom, fgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); container().add_line(indleft, indtop, indright, indtop, UI_LINE_WIDTH, fgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); container().add_line(indright, indtop, indright, indbottom, UI_LINE_WIDTH, fgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); container().add_line(indright, indbottom, indleft, indbottom, UI_LINE_WIDTH, fgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); 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) @@ -228,7 +239,7 @@ void menu_analog::populate(float &customtop, float &custombottom) } // put on arrows - uint32_t flags = 0; + uint32_t flags(0U); if (data.cur > data.min) flags |= FLAG_LEFT_ARROW; if (data.cur < data.max) @@ -245,6 +256,8 @@ void menu_analog::populate(float &customtop, float &custombottom) void menu_analog::find_fields() { + assert(m_field_data.empty()); + // collect analog fields for (auto &port : machine().ioport().ports()) { @@ -288,9 +301,9 @@ void menu_analog::find_fields() } } - // 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()); + // 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()); 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 b71cc095cc0..40c76602af5 100644 --- a/src/frontend/mame/ui/analogipt.h +++ b/src/frontend/mame/ui/analogipt.h @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods +// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods, Vas Crabb /*************************************************************************** ui/analogipt.h @@ -7,7 +7,6 @@ Analog inputs menu. ***************************************************************************/ - #ifndef MAME_FRONTEND_UI_ANALOGIPT_H #define MAME_FRONTEND_UI_ANALOGIPT_H @@ -42,7 +41,7 @@ private: struct item_data { - item_data(ioport_field &f, int t); + item_data(ioport_field &f, int t) noexcept; std::reference_wrapper field; int type; @@ -53,10 +52,13 @@ private: struct field_data { - field_data(ioport_field &f); + field_data(ioport_field &f) noexcept; std::reference_wrapper field; float range; + float neutral; + float origin; + bool show_neutral; }; using item_data_vector = std::vector; diff --git a/src/frontend/mame/ui/confswitch.cpp b/src/frontend/mame/ui/confswitch.cpp new file mode 100644 index 00000000000..82eec967b08 --- /dev/null +++ b/src/frontend/mame/ui/confswitch.cpp @@ -0,0 +1,414 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods +/********************************************************************* + + ui/confswitch.cpp + + Configuration/DIP switches menu. + +*********************************************************************/ + +#include "emu.h" +#include "ui/confswitch.h" + +#include +#include + + +namespace ui { + +namespace { + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +// DIP switch rendering parameters in terms of line height +constexpr float DIP_SWITCH_HEIGHT = 1.6f; +constexpr float DIP_SWITCH_SPACING = DIP_SWITCH_HEIGHT / 5.0f; +constexpr float SINGLE_TOGGLE_SWITCH_FIELD_WIDTH = DIP_SWITCH_HEIGHT / 2.0f; +constexpr float SINGLE_TOGGLE_SWITCH_WIDTH = SINGLE_TOGGLE_SWITCH_FIELD_WIDTH * 0.8f; +// make the switch nub 80% of the width space and 1/2 of the switch height +constexpr float SINGLE_TOGGLE_SWITCH_HEIGHT = (DIP_SWITCH_HEIGHT / 2.0f) * 0.8f; + +} // anonymous namespace + + + +/*------------------------------------------------- + menu_confswitch +-------------------------------------------------*/ + +menu_confswitch::field_descriptor::field_descriptor(ioport_field &f) noexcept + : field(f) +{ +} + + +menu_confswitch::switch_group_descriptor::switch_group_descriptor(ioport_field const &f, ioport_diplocation const &loc) noexcept + : name(loc.name()) + , owner(f.device()) + , mask(0U) + , state(0U) +{ +} + + +inline bool menu_confswitch::switch_group_descriptor::matches(ioport_field const &f, ioport_diplocation const &loc) const noexcept +{ + return (&owner.get() == &f.device()) && !strcmp(loc.name(), name); +} + + +inline unsigned menu_confswitch::switch_group_descriptor::switch_count() const noexcept +{ + return (sizeof(mask) * 8) - count_leading_zeros(mask); +} + + +menu_confswitch::menu_confswitch(mame_ui_manager &mui, render_container &container, uint32_t type) + : menu(mui, container) + , m_fields() + , m_switch_groups() + , m_active_switch_groups(0U) + , m_type(type) +{ +} + + +menu_confswitch::~menu_confswitch() +{ +} + + +void menu_confswitch::populate(float &customtop, float &custombottom) +{ + // locate relevant fields if necessary + if (m_fields.empty()) + find_fields(); + + // reset switch group masks + m_active_switch_groups = 0U; + for (switch_group_descriptor &group : m_switch_groups) + group.mask = group.state = 0U; + + // loop over input ports and set up the current values + device_t *prev_owner(nullptr); + bool first_entry(true); + for (field_descriptor &desc : m_fields) + { + ioport_field &field(desc.field); + if (field.enabled()) + { + if (!field.settings().empty()) + { + // add a device heading if necessary + if (&field.device() != prev_owner) + { + prev_owner = &field.device(); + if (first_entry) + first_entry = false; + else + item_append(menu_item_type::SEPARATOR); + item_append(string_format("[root%s]", prev_owner->tag()), "", 0, nullptr); + } + + // set the left/right flags appropriately + uint32_t flags(0U); + if (field.has_previous_setting()) + flags |= FLAG_LEFT_ARROW; + if (field.has_next_setting()) + flags |= FLAG_RIGHT_ARROW; + + // add the menu item + item_append(field.name(), field.setting_name(), flags, &field); + } + + // track switch groups + if (!field.diplocations().empty()) + { + // get current settings + ioport_field::user_settings settings; + field.get_user_settings(settings); + + // iterate over each bit in the field + ioport_value accummask(field.mask()); + for (ioport_diplocation const &loc : field.diplocations()) + { + // find the matching switch group + switch_group_descriptor &group( + *std::find_if( + m_switch_groups.begin(), + m_switch_groups.end(), [&field, &loc] (switch_group_descriptor const &sw) { return sw.matches(field, loc); })); + + // count if this is the first switch in the group + if (!group.mask) + ++m_active_switch_groups; + + // apply the bits + group.mask |= uint32_t(1) << (loc.number() - 1); + ioport_value const mask(accummask & ~(accummask - 1)); + if (((settings.value & mask) && !loc.inverted()) || (!(settings.value & mask) && loc.inverted())) + group.state |= uint32_t(1) << (loc.number() - 1); + + // clear the relevant bit in the accumulated mask + accummask &= ~mask; + } + } + } + } + + item_append(menu_item_type::SEPARATOR); + item_append(_("Reset"), "", 0, (void *)1); +} + + +void menu_confswitch::handle() +{ + // process the menu + event const *const menu_event(process(0)); + + // handle events + if (menu_event && menu_event->itemref) + { + if (uintptr_t(menu_event->itemref) == 1U) + { + // reset + if (menu_event->iptkey == IPT_UI_SELECT) + machine().schedule_hard_reset(); + } + else + { + // actual settings + ioport_field &field(*reinterpret_cast(menu_event->itemref)); + bool changed(false); + + switch (menu_event->iptkey) + { + // if selected, reset to default value + case IPT_UI_SELECT: + { + ioport_field::user_settings settings; + field.get_user_settings(settings); + settings.value = field.defvalue(); + field.set_user_settings(settings); + } + changed = true; + break; + + // left goes to previous setting + case IPT_UI_LEFT: + field.select_previous_setting(); + changed = true; + break; + + // right goes to next setting + case IPT_UI_RIGHT: + field.select_next_setting(); + changed = true; + break; + } + + // if anything changed, rebuild the menu, trying to stay on the same field + if (changed) + reset(reset_options::REMEMBER_REF); + } + } +} + + +void menu_confswitch::find_fields() +{ + assert(m_fields.empty()); + assert(m_switch_groups.empty()); + + // find relevant input ports + for (auto &port : machine().ioport().ports()) + { + for (ioport_field &field : port.second->fields()) + { + if (field.type() == m_type) + { + m_fields.emplace_back(field); + + // iterate over locations + for (ioport_diplocation const &loc : field.diplocations()) + { + auto const found( + std::find_if( + m_switch_groups.begin(), + m_switch_groups.end(), [&field, &loc] (switch_group_descriptor const &sw) { return sw.matches(field, loc); })); + if (m_switch_groups.end() == found) + m_switch_groups.emplace_back(field, loc); + } + } + } + } +} + + + +/*------------------------------------------------- + menu_settings_dip_switches +-------------------------------------------------*/ + +menu_settings_dip_switches::menu_settings_dip_switches(mame_ui_manager &mui, render_container &container) + : menu_confswitch(mui, container, IPT_DIPSWITCH) + , m_visible_switch_groups(0U) +{ +} + + +menu_settings_dip_switches::~menu_settings_dip_switches() +{ +} + + +void menu_settings_dip_switches::custom_render(void *selectedref, float top, float bottom, float x1, float y1, float x2, float y2) +{ + // catch if no diploc has to be drawn + if (!m_visible_switch_groups) + return; + + // calculate optimal width + float const aspect(machine().render().ui_aspect(&container())); + float const lineheight(ui().get_line_height()); + float const singlewidth(lineheight * SINGLE_TOGGLE_SWITCH_FIELD_WIDTH * aspect); + float const maxwidth(1.0f - (ui().box_lr_border() * 2.0f * aspect)); + float width(0.0f); + unsigned maxswitches(0U); + for (switch_group_descriptor const &group : switch_groups()) + { + if (group.mask) + { + maxswitches = (std::max)(group.switch_count(), maxswitches); + float const namewidth(ui().get_string_width(group.name)); + float const switchwidth(singlewidth * maxswitches); + width = (std::min)((std::max)(namewidth + switchwidth + (lineheight * aspect), width), maxwidth); + } + } + + // draw extra menu area + float const boxwidth((std::max)(width + (ui().box_lr_border() * 2.0f * aspect), x2 - x1)); + float const boxleft((1.0f - boxwidth) / 2.0f); + ui().draw_outlined_box(container(), boxleft, y2 + ui().box_tb_border(), boxleft + boxwidth, y2 + bottom, ui().colors().background_color()); + + // calculate centred layout + float const nameleft((1.0f - width) / 2.0f); + float const switchleft(nameleft + width - (singlewidth * maxswitches)); + float const namewidth(width - (singlewidth * maxswitches) - (lineheight * aspect)); + + // iterate over switch groups + ioport_field *const field((uintptr_t(selectedref) != 1U) ? reinterpret_cast(selectedref) : nullptr); + float const nubheight(lineheight * SINGLE_TOGGLE_SWITCH_HEIGHT); + float const nubwidth(lineheight * SINGLE_TOGGLE_SWITCH_WIDTH * aspect); + float const ygap(lineheight * ((DIP_SWITCH_HEIGHT / 2) - SINGLE_TOGGLE_SWITCH_HEIGHT) / 2); + float const xgap((singlewidth + (UI_LINE_WIDTH / 2) - nubwidth) / 2); + unsigned line(0U); + for (switch_group_descriptor const &group : switch_groups()) + { + if (group.mask) + { + // determine the mask of selected bits + uint32_t selectedmask(0U); + if (field) + { + for (ioport_diplocation const &loc : field->diplocations()) + if (group.matches(*field, loc)) + selectedmask |= uint32_t(1) << (loc.number() - 1); + } + + // draw the name + float const liney(y2 + (ui().box_tb_border() * 2.0f) + (lineheight * (DIP_SWITCH_HEIGHT + DIP_SWITCH_SPACING) * line)); + ui().draw_text_full( + container(), + group.name, + nameleft, liney + (lineheight * (DIP_SWITCH_HEIGHT - 1.0f) / 2.0f), namewidth, + ui::text_layout::RIGHT, ui::text_layout::NEVER, + mame_ui_manager::NORMAL, ui().colors().text_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + + // draw the group outline + float const switchbottom(liney + (DIP_SWITCH_HEIGHT * lineheight)); + unsigned const cnt(group.switch_count()); + ui().draw_outlined_box( + container(), + switchleft, liney, switchleft + (singlewidth * cnt), switchbottom, + ui().colors().background_color()); + for (unsigned i = 1; cnt > i; ++i) + { + container().add_line( + switchleft + (singlewidth * i), liney, switchleft + (singlewidth * i), switchbottom, + UI_LINE_WIDTH, ui().colors().text_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + } + + // compute top and bottom for on and off positions + float const yoff(liney + UI_LINE_WIDTH + ygap); + float const yon(switchbottom - UI_LINE_WIDTH - ygap - nubheight); + + // draw the switch nubs + for (unsigned toggle = 0; cnt > toggle; ++toggle) + { + float const nubleft(switchleft + (singlewidth * toggle) + xgap); + if (BIT(group.mask, toggle)) + { + float const nubtop(BIT(group.state, toggle) ? yon : yoff); + container().add_rect( + nubleft, nubtop, nubleft + nubwidth, nubtop + nubheight, + BIT(selectedmask, toggle) ? ui().colors().dipsw_color() : ui().colors().text_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + } + else + { + container().add_rect( + nubleft, yoff, nubleft + nubwidth, yon + nubheight, + ui().colors().unavailable_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + } + } + + // limit the number of visible switch groups + if (++line >= m_visible_switch_groups) + break; + } + } +} + + +void menu_settings_dip_switches::populate(float &customtop, float &custombottom) +{ + // let the base class add items + menu_confswitch::populate(customtop, custombottom); + + // use up to about 70% of height for DIP switch display + if (active_switch_groups()) + { + float const lineheight(ui().get_line_height()); + float const groupheight(DIP_SWITCH_HEIGHT * lineheight); + float const groupspacing(DIP_SWITCH_SPACING * lineheight); + if ((active_switch_groups() * (groupheight + groupspacing)) > 0.7f) + m_visible_switch_groups = unsigned(0.7f / (groupheight + groupspacing)); + else + m_visible_switch_groups = active_switch_groups(); + custombottom = (m_visible_switch_groups * groupheight) + ((m_visible_switch_groups - 1) * groupspacing) + (ui().box_tb_border() * 3.0f); + } + else + { + m_visible_switch_groups = 0U; + custombottom = 0.0f; + } +} + + + +/*------------------------------------------------- + menu_settings_machine_config +-------------------------------------------------*/ + +menu_settings_machine_config::menu_settings_machine_config(mame_ui_manager &mui, render_container &container) : menu_confswitch(mui, container, IPT_CONFIG) +{ +} + +menu_settings_machine_config::~menu_settings_machine_config() +{ +} + + +} // namespace ui diff --git a/src/frontend/mame/ui/confswitch.h b/src/frontend/mame/ui/confswitch.h new file mode 100644 index 00000000000..35dac6d75d9 --- /dev/null +++ b/src/frontend/mame/ui/confswitch.h @@ -0,0 +1,97 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods +/*************************************************************************** + + ui/confswitch.h + + Configuration/DIP switches menu. + +***************************************************************************/ +#ifndef MAME_FRONTEND_UI_CONFSWITCH_H +#define MAME_FRONTEND_UI_CONFSWITCH_H + +#include "ui/menu.h" + +#include +#include + + +namespace ui { + +class menu_confswitch : public menu +{ +public: + virtual ~menu_confswitch() override; + +protected: + struct field_descriptor + { + field_descriptor(ioport_field &f) noexcept; + + std::reference_wrapper field; + }; + + struct switch_group_descriptor + { + switch_group_descriptor(ioport_field const &f, ioport_diplocation const &loc) noexcept; + + bool matches(ioport_field const &f, ioport_diplocation const &loc) const noexcept; + unsigned switch_count() const noexcept; + + char const *name; + std::reference_wrapper owner; + uint32_t mask; + uint32_t state; + }; + + using field_vector = std::vector; + using switch_group_vector = std::vector; + + menu_confswitch(mame_ui_manager &mui, render_container &container, uint32_t type); + + virtual void populate(float &customtop, float &custombottom) override; + + field_vector const &fields() { return m_fields; } + switch_group_vector const &switch_groups() { return m_switch_groups; } + unsigned active_switch_groups() const { return m_active_switch_groups; } + + int m_dipcount; + +private: + virtual void handle() override; + + void find_fields(); + + field_vector m_fields; + switch_group_vector m_switch_groups; + unsigned m_active_switch_groups; + int const m_type; +}; + + +class menu_settings_dip_switches : public menu_confswitch +{ +public: + menu_settings_dip_switches(mame_ui_manager &mui, render_container &container); + virtual ~menu_settings_dip_switches() override; + +protected: + virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override; + +private: + virtual void populate(float &customtop, float &custombottom) override; + + unsigned m_visible_switch_groups; +}; + + +class menu_settings_machine_config : public menu_confswitch +{ +public: + menu_settings_machine_config(mame_ui_manager &mui, render_container &container); + virtual ~menu_settings_machine_config(); +}; + +} // namespace ui + +#endif // MAME_FRONTEND_UI_CONFSWITCH_H diff --git a/src/frontend/mame/ui/custui.cpp b/src/frontend/mame/ui/custui.cpp index 65b1ad2fa5e..5eec6d1c6ba 100644 --- a/src/frontend/mame/ui/custui.cpp +++ b/src/frontend/mame/ui/custui.cpp @@ -37,7 +37,9 @@ const char *const menu_custom_ui::HIDE_STATUS[] = { // ctor //------------------------------------------------- -menu_custom_ui::menu_custom_ui(mame_ui_manager &mui, render_container &container) : menu(mui, container) +menu_custom_ui::menu_custom_ui(mame_ui_manager &mui, render_container &container, std::function &&handler) + : menu(mui, container) + , m_handler(std::move(handler)) { // load languages file_enumerator path(mui.machine().options().language_path()); @@ -72,6 +74,9 @@ menu_custom_ui::~menu_custom_ui() load_translation(machine().options()); } ui_globals::reset = true; + + if (m_handler) + m_handler(); } //------------------------------------------------- @@ -91,7 +96,14 @@ void menu_custom_ui::handle() { case FONT_MENU: if (menu_event->iptkey == IPT_UI_SELECT) - menu::stack_push(ui(), container()); + menu::stack_push( + ui(), + container(), + [this] (bool changed) + { + if (changed) + reset(reset_options::REMEMBER_REF); + }); break; case COLORS_MENU: if (menu_event->iptkey == IPT_UI_SELECT) @@ -182,9 +194,19 @@ void menu_custom_ui::custom_render(void *selectedref, float top, float bottom, f // ctor //------------------------------------------------- -menu_font_ui::menu_font_ui(mame_ui_manager &mui, render_container &container) : menu(mui, container) +menu_font_ui::menu_font_ui(mame_ui_manager &mui, render_container &container, std::function &&handler) + : menu(mui, container) + , m_handler(std::move(handler)) + , m_fonts() + , m_font_min(atof(mui.options().get_entry(OPTION_FONT_ROWS)->minimum())) + , m_font_max(atof(mui.options().get_entry(OPTION_FONT_ROWS)->maximum())) + , m_font_size(mui.options().font_rows()) + , m_info_min(atof(mui.options().get_entry(OPTION_INFOS_SIZE)->minimum())) + , m_info_max(atof(mui.options().get_entry(OPTION_INFOS_SIZE)->maximum())) + , m_info_size(mui.options().infos_size()) + , m_changed(false) + , m_actual(0U) { - ui_options &moptions = mui.options(); std::string name(mui.machine().options().ui_font()); list(); @@ -192,7 +214,6 @@ menu_font_ui::menu_font_ui(mame_ui_manager &mui, render_container &container) : m_bold = (strreplace(name, "[B]", "") + strreplace(name, "[b]", "") > 0); m_italic = (strreplace(name, "[I]", "") + strreplace(name, "[i]", "") > 0); #endif - m_actual = 0; for (std::size_t index = 0; index < m_fonts.size(); index++) { @@ -202,13 +223,6 @@ menu_font_ui::menu_font_ui(mame_ui_manager &mui, render_container &container) : break; } } - - m_info_size = moptions.infos_size(); - m_font_size = moptions.font_rows(); - m_info_max = atof(moptions.get_entry(OPTION_INFOS_SIZE)->maximum()); - m_info_min = atof(moptions.get_entry(OPTION_INFOS_SIZE)->minimum()); - m_font_max = atof(moptions.get_entry(OPTION_FONT_ROWS)->maximum()); - m_font_min = atof(moptions.get_entry(OPTION_FONT_ROWS)->minimum()); } //------------------------------------------------- @@ -229,25 +243,30 @@ void menu_font_ui::list() menu_font_ui::~menu_font_ui() { - std::string error_string; - ui_options &moptions = ui().options(); + if (m_changed) + { + ui_options &moptions = ui().options(); - std::string name(m_fonts[m_actual].first); + std::string name(m_fonts[m_actual].first); #ifdef UI_WINDOWS - if (name != "default") - { - if (m_italic) - name.insert(0, "[I]"); - if (m_bold) - name.insert(0, "[B]"); - } + if (name != "default") + { + if (m_italic) + name.insert(0, "[I]"); + if (m_bold) + name.insert(0, "[B]"); + } #endif - machine().options().set_value(OPTION_UI_FONT, name, OPTION_PRIORITY_CMDLINE); - moptions.set_value(OPTION_INFOS_SIZE, m_info_size, OPTION_PRIORITY_CMDLINE); - moptions.set_value(OPTION_FONT_ROWS, m_font_size, OPTION_PRIORITY_CMDLINE); + machine().options().set_value(OPTION_UI_FONT, name, OPTION_PRIORITY_CMDLINE); + moptions.set_value(OPTION_INFOS_SIZE, m_info_size, OPTION_PRIORITY_CMDLINE); + moptions.set_value(OPTION_FONT_ROWS, m_font_size, OPTION_PRIORITY_CMDLINE); + + // OPTION_FONT_ROWS was changed; update the font info + ui().update_target_font_height(); + } - // OPTION_FONT_ROWS was changed; update the font info - ui().update_target_font_height(); + if (m_handler) + m_handler(m_changed); } //------------------------------------------------- @@ -261,7 +280,8 @@ void menu_font_ui::handle() // process the menu const event *menu_event = process(PROCESS_LR_REPEAT); - if (menu_event != nullptr && menu_event->itemref != nullptr) + if (menu_event && menu_event->itemref) + { switch ((uintptr_t)menu_event->itemref) { case INFOS_SIZE: @@ -297,10 +317,10 @@ void menu_font_ui::handle() ui(), container(), std::move(display_names), m_actual, [this] (int selection) { + m_changed = true; m_actual = selection; reset(reset_options::REMEMBER_REF); }); - changed = true; } break; @@ -315,9 +335,13 @@ void menu_font_ui::handle() break; #endif } + } if (changed) + { + m_changed = true; reset(reset_options::REMEMBER_REF); + } } //------------------------------------------------- diff --git a/src/frontend/mame/ui/custui.h b/src/frontend/mame/ui/custui.h index a419e424375..2da5cfd132b 100644 --- a/src/frontend/mame/ui/custui.h +++ b/src/frontend/mame/ui/custui.h @@ -15,7 +15,11 @@ #include "ui/menu.h" +#include + + namespace ui { + //------------------------------------------------- // Custom UI menu //------------------------------------------------- @@ -23,7 +27,7 @@ namespace ui { class menu_custom_ui : public menu { public: - menu_custom_ui(mame_ui_manager &mui, render_container &container); + menu_custom_ui(mame_ui_manager &mui, render_container &container, std::function &&handler); virtual ~menu_custom_ui() override; protected: @@ -43,6 +47,7 @@ private: static const char *const HIDE_STATUS[]; + std::function m_handler; std::vector m_lang; std::uint16_t m_currlang; }; @@ -54,7 +59,7 @@ private: class menu_font_ui : public menu { public: - menu_font_ui(mame_ui_manager &mui, render_container &container); + menu_font_ui(mame_ui_manager &mui, render_container &container, std::function &&handler); virtual ~menu_font_ui() override; protected: @@ -75,14 +80,19 @@ private: void list(); + std::function m_handler; + std::vector > m_fonts; + const int m_font_min, m_font_max; + int m_font_size; + const float m_info_min, m_info_max; + float m_info_size; + bool m_changed; + std::uint16_t m_actual; - std::vector > m_fonts; #ifdef UI_WINDOWS bool m_bold, m_italic; #endif - float m_info_min, m_info_max, m_info_size; - int m_font_min, m_font_max, m_font_size; }; //------------------------------------------------- diff --git a/src/frontend/mame/ui/inputmap.cpp b/src/frontend/mame/ui/inputmap.cpp index cc91e92766e..182a2201d83 100644 --- a/src/frontend/mame/ui/inputmap.cpp +++ b/src/frontend/mame/ui/inputmap.cpp @@ -19,25 +19,6 @@ namespace ui { -/*************************************************************************** - CONSTANTS -***************************************************************************/ - -#define MAX_PHYSICAL_DIPS 10 -#define MAX_INPUT_PORTS 32 -#define MAX_BITS_PER_PORT 32 - -/* DIP switch rendering parameters */ -#define DIP_SWITCH_HEIGHT 0.05f -#define DIP_SWITCH_SPACING 0.01f -#define SINGLE_TOGGLE_SWITCH_FIELD_WIDTH 0.025f -#define SINGLE_TOGGLE_SWITCH_WIDTH 0.020f -/* make the switch 80% of the width space and 1/2 of the switch height */ -#define PERCENTAGE_OF_HALF_FIELD_USED 0.80f -#define SINGLE_TOGGLE_SWITCH_HEIGHT ((DIP_SWITCH_HEIGHT / 2) * PERCENTAGE_OF_HALF_FIELD_USED) - - - /*------------------------------------------------- menu_input_groups_populate - populate the input groups menu @@ -440,304 +421,4 @@ void menu_input::populate_sorted(std::vector &&itemarray) } } - -/*------------------------------------------------- - menu_settings_dip_switches - handle the DIP - switches menu --------------------------------------------------*/ - -menu_settings_dip_switches::menu_settings_dip_switches(mame_ui_manager &mui, render_container &container) : menu_settings(mui, container, IPT_DIPSWITCH) -{ -} - -menu_settings_dip_switches::~menu_settings_dip_switches() -{ -} - -/*------------------------------------------------- - menu_settings_driver_config - handle the - driver config menu --------------------------------------------------*/ - -menu_settings_driver_config::menu_settings_driver_config(mame_ui_manager &mui, render_container &container) : menu_settings(mui, container, IPT_CONFIG) -{ -} - -menu_settings_driver_config::~menu_settings_driver_config() -{ -} - -/*------------------------------------------------- - menu_settings_common - handle one of the - switches menus --------------------------------------------------*/ - -void menu_settings::handle() -{ - // process the menu - const event *menu_event = process(0); - - // handle events - if (menu_event != nullptr && menu_event->itemref != nullptr) - { - // reset - if ((uintptr_t)menu_event->itemref == 1) - { - if (menu_event->iptkey == IPT_UI_SELECT) - machine().schedule_hard_reset(); - } - // actual settings - else - { - ioport_field *field = (ioport_field *)menu_event->itemref; - ioport_field::user_settings settings; - int changed = false; - - switch (menu_event->iptkey) - { - /* if selected, reset to default value */ - case IPT_UI_SELECT: - field->get_user_settings(settings); - settings.value = field->defvalue(); - field->set_user_settings(settings); - changed = true; - break; - - /* left goes to previous setting */ - case IPT_UI_LEFT: - field->select_previous_setting(); - changed = true; - break; - - /* right goes to next setting */ - case IPT_UI_RIGHT: - field->select_next_setting(); - changed = true; - break; - } - - /* if anything changed, rebuild the menu, trying to stay on the same field */ - if (changed) - reset(reset_options::REMEMBER_REF); - } - } -} - - -/*------------------------------------------------- - menu_settings_populate - populate one of the - switches menus --------------------------------------------------*/ - -menu_settings::menu_settings(mame_ui_manager &mui, render_container &container, uint32_t _type) : menu(mui, container), diplist(nullptr), dipcount(0) -{ - type = _type; -} - -void menu_settings::populate(float &customtop, float &custombottom) -{ - dip_descriptor **diplist_tailptr; - std::string prev_owner; - bool first_entry = true; - - /* reset the dip switch tracking */ - dipcount = 0; - diplist = nullptr; - diplist_tailptr = &diplist; - - /* loop over input ports and set up the current values */ - for (auto &port : machine().ioport().ports()) - for (ioport_field &field : port.second->fields()) - if (field.type() == type && field.enabled()) - { - if (!field.settings().empty()) - { - uint32_t flags = 0; - - /* set the left/right flags appropriately */ - if (field.has_previous_setting()) - flags |= FLAG_LEFT_ARROW; - if (field.has_next_setting()) - flags |= FLAG_RIGHT_ARROW; - - /* add the menu item */ - if (strcmp(field.device().tag(), prev_owner.c_str()) != 0) - { - if (first_entry) - first_entry = false; - else - item_append(menu_item_type::SEPARATOR); - string_format("[root%s]", field.device().tag()); - item_append(string_format("[root%s]", field.device().tag()), "", 0, nullptr); - prev_owner.assign(field.device().tag()); - } - - item_append(field.name(), field.setting_name(), flags, (void *)&field); - } - - /* for DIP switches, build up the model */ - if (type == IPT_DIPSWITCH && !field.diplocations().empty()) - { - ioport_field::user_settings settings; - uint32_t accummask = field.mask(); - - /* get current settings */ - field.get_user_settings(settings); - - /* iterate over each bit in the field */ - for (const ioport_diplocation &diploc : field.diplocations()) - { - uint32_t mask = accummask & ~(accummask - 1); - dip_descriptor *dip; - - /* find the matching switch name */ - for (dip = diplist; dip != nullptr; dip = dip->next) - if (dip->owner == &field.device() && strcmp(dip->name, diploc.name()) == 0) - break; - - /* allocate new if none */ - if (dip == nullptr) - { - dip = (dip_descriptor *)m_pool_alloc(sizeof(*dip)); - dip->next = nullptr; - dip->name = diploc.name(); - dip->owner = &field.device(); - dip->mask = dip->state = 0; - *diplist_tailptr = dip; - diplist_tailptr = &dip->next; - dipcount++; - } - - /* apply the bits */ - dip->mask |= 1 << (diploc.number() - 1); - if (((settings.value & mask) != 0 && !diploc.inverted()) || ((settings.value & mask) == 0 && diploc.inverted())) - dip->state |= 1 << (diploc.number() - 1); - - /* clear the relevant bit in the accumulated mask */ - accummask &= ~mask; - } - } - } - if (type == IPT_DIPSWITCH) - custombottom = dipcount ? dipcount * (DIP_SWITCH_HEIGHT + DIP_SWITCH_SPACING) + DIP_SWITCH_SPACING : 0; - - item_append(menu_item_type::SEPARATOR); - item_append(_("Reset"), "", 0, (void *)1); -} - -menu_settings::~menu_settings() -{ -} - -/*------------------------------------------------- - menu_settings_custom_render - perform our special - rendering --------------------------------------------------*/ - -void menu_settings_dip_switches::custom_render(void *selectedref, float top, float bottom, float x1, float y1, float x2, float y2) -{ - // catch if no diploc has to be drawn - if (bottom == 0) - return; - - // add borders - y1 = y2 + ui().box_tb_border(); - y2 = y1 + bottom; - - // draw extra menu area - ui().draw_outlined_box(container(), x1, y1, x2, y2, ui().colors().background_color()); - y1 += (float)DIP_SWITCH_SPACING; - - // iterate over DIP switches - for (dip_descriptor *dip = diplist; dip != nullptr; dip = dip->next) - { - uint32_t selectedmask = 0; - - // determine the mask of selected bits - if ((uintptr_t)selectedref != 1) - { - ioport_field *field = (ioport_field *)selectedref; - - if (field != nullptr && !field->diplocations().empty()) - for (const ioport_diplocation &diploc : field->diplocations()) - if (dip->owner == &field->device() && strcmp(dip->name, diploc.name()) == 0) - selectedmask |= 1 << (diploc.number() - 1); - } - - // draw one switch - custom_render_one(x1, y1, x2, y1 + DIP_SWITCH_HEIGHT, dip, selectedmask); - y1 += (float)(DIP_SWITCH_SPACING + DIP_SWITCH_HEIGHT); - } -} - - -/*------------------------------------------------- - menu_settings_custom_render_one - draw a single - DIP switch --------------------------------------------------*/ - -void menu_settings_dip_switches::custom_render_one(float x1, float y1, float x2, float y2, const dip_descriptor *dip, uint32_t selectedmask) -{ - float switch_field_width = SINGLE_TOGGLE_SWITCH_FIELD_WIDTH * container().manager().ui_aspect(); - float switch_width = SINGLE_TOGGLE_SWITCH_WIDTH * container().manager().ui_aspect(); - int numtoggles, toggle; - float switch_toggle_gap; - float y1_off, y1_on; - - /* determine the number of toggles in the DIP */ - numtoggles = 32 - count_leading_zeros(dip->mask); - - /* center based on the number of switches */ - x1 += (x2 - x1 - numtoggles * switch_field_width) / 2; - - /* draw the dip switch name */ - ui().draw_text_full(container(), - dip->name, - 0, - y1 + (DIP_SWITCH_HEIGHT - ui().target_font_height()) / 2, - x1 - ui().get_string_width(" "), - ui::text_layout::RIGHT, - ui::text_layout::NEVER, - mame_ui_manager::NORMAL, - ui().colors().text_color(), - PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA), - nullptr , - nullptr); - - /* compute top and bottom for on and off positions */ - switch_toggle_gap = ((DIP_SWITCH_HEIGHT/2) - SINGLE_TOGGLE_SWITCH_HEIGHT)/2; - y1_off = y1 + UI_LINE_WIDTH + switch_toggle_gap; - y1_on = y1 + DIP_SWITCH_HEIGHT/2 + switch_toggle_gap; - - /* iterate over toggles */ - for (toggle = 0; toggle < numtoggles; toggle++) - { - float innerx1; - - /* first outline the switch */ - ui().draw_outlined_box(container(), x1, y1, x1 + switch_field_width, y2, ui().colors().background_color()); - - /* compute x1/x2 for the inner filled in switch */ - innerx1 = x1 + (switch_field_width - switch_width) / 2; - - /* see if the switch is actually used */ - if (dip->mask & (1 << toggle)) - { - float innery1 = (dip->state & (1 << toggle)) ? y1_on : y1_off; - container().add_rect(innerx1, innery1, innerx1 + switch_width, innery1 + SINGLE_TOGGLE_SWITCH_HEIGHT, - (selectedmask & (1 << toggle)) ? ui().colors().dipsw_color() : ui().colors().text_color(), - PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); - } - else - { - container().add_rect(innerx1, y1_off, innerx1 + switch_width, y1_on + SINGLE_TOGGLE_SWITCH_HEIGHT, - ui().colors().unavailable_color(), - PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); - } - - /* advance to the next switch */ - x1 += switch_field_width; - } -} - } // namespace ui diff --git a/src/frontend/mame/ui/inputmap.h b/src/frontend/mame/ui/inputmap.h index d0ffc4ec12c..bfb6dbcec17 100644 --- a/src/frontend/mame/ui/inputmap.h +++ b/src/frontend/mame/ui/inputmap.h @@ -7,7 +7,6 @@ Internal menus for input mappings. ***************************************************************************/ - #ifndef MAME_FRONTEND_UI_INPUTMAP_H #define MAME_FRONTEND_UI_INPUTMAP_H @@ -99,52 +98,6 @@ private: virtual void update_input(struct input_item_data *seqchangeditem) override; }; -class menu_settings : public menu -{ -public: - menu_settings(mame_ui_manager &mui, render_container &container, uint32_t type); - virtual ~menu_settings() override; - -protected: - /* DIP switch descriptor */ - struct dip_descriptor - { - dip_descriptor * next; - const char * name; - device_t * owner; - uint32_t mask; - uint32_t state; - }; - - dip_descriptor * diplist; - int dipcount; - int type; - -private: - virtual void populate(float &customtop, float &custombottom) override; - virtual void handle() override; -}; - -class menu_settings_dip_switches : public menu_settings -{ -public: - menu_settings_dip_switches(mame_ui_manager &mui, render_container &container); - virtual ~menu_settings_dip_switches() override; - -protected: - virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override; - -private: - void custom_render_one(float x1, float y1, float x2, float y2, const dip_descriptor *dip, uint32_t selectedmask); -}; - -class menu_settings_driver_config : public menu_settings -{ -public: - menu_settings_driver_config(mame_ui_manager &mui, render_container &container); - virtual ~menu_settings_driver_config(); -}; - } // namespace ui #endif // MAME_FRONTEND_UI_INPUTMAP_H diff --git a/src/frontend/mame/ui/mainmenu.cpp b/src/frontend/mame/ui/mainmenu.cpp index 10cbced036d..c6052ae2fd6 100644 --- a/src/frontend/mame/ui/mainmenu.cpp +++ b/src/frontend/mame/ui/mainmenu.cpp @@ -14,6 +14,7 @@ #include "ui/analogipt.h" #include "ui/barcode.h" #include "ui/cheatopt.h" +#include "ui/confswitch.h" #include "ui/datmenu.h" #include "ui/filemngr.h" #include "ui/info.h" @@ -163,7 +164,7 @@ void menu_main::handle() break; case SETTINGS_DRIVER_CONFIG: - menu::stack_push(ui(), container()); + menu::stack_push(ui(), container()); break; case ANALOG: diff --git a/src/frontend/mame/ui/miscmenu.cpp b/src/frontend/mame/ui/miscmenu.cpp index 0c263e2b875..b7a52f2a4e5 100644 --- a/src/frontend/mame/ui/miscmenu.cpp +++ b/src/frontend/mame/ui/miscmenu.cpp @@ -28,6 +28,7 @@ #include namespace ui { + /*************************************************************************** MENU HANDLERS ***************************************************************************/ diff --git a/src/frontend/mame/ui/optsmenu.cpp b/src/frontend/mame/ui/optsmenu.cpp index 497d527e6cf..17dddd10c67 100644 --- a/src/frontend/mame/ui/optsmenu.cpp +++ b/src/frontend/mame/ui/optsmenu.cpp @@ -282,7 +282,7 @@ void menu_game_options::handle_item_event(event const &menu_event) break; case CUSTOM_MENU: if (menu_event.iptkey == IPT_UI_SELECT) - menu::stack_push(ui(), container()); + menu::stack_push(ui(), container(), [this] () { reset(reset_options::REMEMBER_REF); }); break; default: menu_simple_game_options::handle_item_event(menu_event); -- cgit v1.2.3