summaryrefslogtreecommitdiffstatshomepage
path: root/src/frontend/mame/ui/inputtoggle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend/mame/ui/inputtoggle.cpp')
-rw-r--r--src/frontend/mame/ui/inputtoggle.cpp220
1 files changed, 220 insertions, 0 deletions
diff --git a/src/frontend/mame/ui/inputtoggle.cpp b/src/frontend/mame/ui/inputtoggle.cpp
new file mode 100644
index 00000000000..7a307c01c66
--- /dev/null
+++ b/src/frontend/mame/ui/inputtoggle.cpp
@@ -0,0 +1,220 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ ui/inputtoggle.cpp
+
+ Toggle inputs menu.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "ui/inputtoggle.h"
+
+#include <iterator>
+
+
+namespace ui {
+
+menu_input_toggles::menu_input_toggles(mame_ui_manager &mui, render_container &container)
+ : menu(mui, container)
+{
+ set_heading(_("menu-inputtoggle", "Toggle Inputs"));
+}
+
+
+menu_input_toggles::~menu_input_toggles()
+{
+}
+
+
+void menu_input_toggles::menu_activated()
+{
+ // enabled inputs and state of inputs can change while menu is inactive
+ reset(reset_options::REMEMBER_REF);
+}
+
+
+void menu_input_toggles::populate()
+{
+ // find toggle fields
+ if (m_fields.empty())
+ {
+ for (auto &port : machine().ioport().ports())
+ {
+ for (ioport_field &field : port.second->fields())
+ {
+ switch (field.type_class())
+ {
+ case INPUT_CLASS_CONTROLLER:
+ case INPUT_CLASS_MISC:
+ case INPUT_CLASS_KEYBOARD:
+ if (field.live().toggle)
+ m_fields.emplace_back(field);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ // create corresponding items for enabled fields
+ device_t *prev_owner = nullptr;
+ for (auto &field : m_fields)
+ {
+ if (field.get().enabled())
+ {
+ // add a device heading if necessary
+ if (&field.get().device() != prev_owner)
+ {
+ prev_owner = &field.get().device();
+ 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(string_format(_("[root%1$s]"), prev_owner->tag()), FLAG_UI_HEADING | FLAG_DISABLE, nullptr);
+ }
+
+ // choose the display name for the value
+ char const *setting;
+ u32 flags = 0U;
+ if (!field.get().settings().empty())
+ {
+ setting = field.get().setting_name();
+ if (field.get().has_previous_setting())
+ flags |= FLAG_LEFT_ARROW;
+ if (field.get().has_next_setting())
+ flags |= FLAG_RIGHT_ARROW;
+ }
+ else if (field.get().defvalue() == field.get().live().value)
+ {
+ setting = _("Off");
+ flags = FLAG_RIGHT_ARROW;
+ }
+ else
+ {
+ setting = _("On");
+ flags = FLAG_LEFT_ARROW;
+ }
+
+ // actually create the item
+ item_append(field.get().name(), setting, flags, &field);
+ }
+ }
+
+ // display a message if there are toggle inputs enabled
+ if (!prev_owner)
+ item_append(_("menu-inputtoggle", "[no toggle inputs are enabled]"), FLAG_DISABLE, nullptr);
+
+ item_append(menu_item_type::SEPARATOR);
+}
+
+
+bool menu_input_toggles::handle(event const *ev)
+{
+ if (!ev || !ev->itemref)
+ return false;
+
+ auto const ref = reinterpret_cast<std::reference_wrapper<ioport_field> *>(ev->itemref);
+ ioport_field &field = ref->get();
+ bool invalidate = false;
+ switch (ev->iptkey)
+ {
+ case IPT_UI_SELECT: // toggle regular items, cycle multi-value items
+ if (field.settings().empty())
+ field.live().value ^= field.mask();
+ else
+ field.select_next_setting();
+ invalidate = true;
+ break;
+
+ case IPT_UI_CLEAR: // set to default
+ if (field.defvalue() != field.live().value)
+ {
+ field.live().value = field.defvalue();
+ invalidate = true;
+ }
+ break;
+
+ case IPT_UI_LEFT: // toggle or select previous setting
+ if (field.settings().empty())
+ field.live().value ^= field.mask();
+ else
+ field.select_previous_setting();
+ invalidate = true;
+ break;
+
+ case IPT_UI_RIGHT: // toggle or select next setting
+ if (field.settings().empty())
+ field.live().value ^= field.mask();
+ else
+ field.select_next_setting();
+ invalidate = true;
+ break;
+
+ case IPT_UI_PREV_GROUP: // previous device if any
+ {
+ auto current = std::distance(m_fields.data(), ref);
+ device_t const *dev = &field.device();
+ bool found_break = false;
+ void *candidate = nullptr;
+ while (0 < current)
+ {
+ if (!found_break)
+ {
+ if (m_fields[--current].get().enabled())
+ {
+ device_t const *prev = &m_fields[current].get().device();
+ if (prev != dev)
+ {
+ dev = prev;
+ found_break = true;
+ candidate = &m_fields[current];
+ }
+ }
+ }
+ else if (&m_fields[--current].get().device() != dev)
+ {
+ set_selection(candidate);
+ set_top_line(selected_index() - 1);
+ return true;
+ }
+ else if (m_fields[current].get().enabled())
+ {
+ candidate = &m_fields[current];
+ }
+ if (found_break && !current)
+ {
+ set_selection(candidate);
+ set_top_line(selected_index() - 1);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case IPT_UI_NEXT_GROUP: // next device if any
+ {
+ auto current = std::distance(m_fields.data(), ref);
+ device_t const *const dev = &field.device();
+ while (m_fields.size() > ++current)
+ {
+ if (m_fields[current].get().enabled() && (&m_fields[current].get().device() != dev))
+ {
+ set_selection(&m_fields[current]);
+ set_top_line(selected_index() - 1);
+ return true;
+ }
+ }
+ }
+ break;
+ }
+
+ // changing value can enable or disable other fields
+ if (invalidate)
+ reset(reset_options::REMEMBER_REF);
+
+ return false;
+}
+
+} // namespace ui