summaryrefslogtreecommitdiffstatshomepage
path: root/src/frontend/mame/ui/inputmap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend/mame/ui/inputmap.cpp')
-rw-r--r--src/frontend/mame/ui/inputmap.cpp287
1 files changed, 200 insertions, 87 deletions
diff --git a/src/frontend/mame/ui/inputmap.cpp b/src/frontend/mame/ui/inputmap.cpp
index 8ac4b5943c8..d8a4d9656f4 100644
--- a/src/frontend/mame/ui/inputmap.cpp
+++ b/src/frontend/mame/ui/inputmap.cpp
@@ -26,13 +26,14 @@ namespace ui {
menu_input_groups::menu_input_groups(mame_ui_manager &mui, render_container &container) : menu(mui, container)
{
+ set_heading(_("Input Assignments (general)"));
}
menu_input_groups::~menu_input_groups()
{
}
-void menu_input_groups::populate(float &customtop, float &custombottom)
+void menu_input_groups::populate()
{
// build up the menu
item_append(_("User Interface"), 0, (void *)uintptr_t(IPG_UI + 1));
@@ -45,12 +46,18 @@ void menu_input_groups::populate(float &customtop, float &custombottom)
item_append(menu_item_type::SEPARATOR);
}
-void menu_input_groups::handle()
+bool menu_input_groups::handle(event const *ev)
{
- // process the menu
- const event *const menu_event = process(0);
- if (menu_event && menu_event->iptkey == IPT_UI_SELECT)
- menu::stack_push<menu_input_general>(ui(), container(), int(uintptr_t(menu_event->itemref) - 1));
+ if (ev && (ev->iptkey == IPT_UI_SELECT))
+ {
+ menu::stack_push<menu_input_general>(
+ ui(),
+ container(),
+ int(uintptr_t(ev->itemref) - 1),
+ util::string_format(_("Input Assignments (%1$s)"), ev->item->text()));
+ }
+
+ return false;
}
@@ -59,17 +66,24 @@ void menu_input_groups::handle()
input menu
-------------------------------------------------*/
-menu_input_general::menu_input_general(mame_ui_manager &mui, render_container &container, int _group)
+menu_input_general::menu_input_general(mame_ui_manager &mui, render_container &container, int _group, std::string &&heading)
: menu_input(mui, container)
, group(_group)
{
+ set_heading(std::move(heading));
}
menu_input_general::~menu_input_general()
{
}
-void menu_input_general::populate(float &customtop, float &custombottom)
+void menu_input_general::menu_activated()
+{
+ // scripts can change settings out from under us
+ reset(reset_options::REMEMBER_POSITION);
+}
+
+void menu_input_general::populate()
{
if (data.empty())
{
@@ -79,26 +93,30 @@ void menu_input_general::populate(float &customtop, float &custombottom)
for (const input_type_entry &entry : machine().ioport().types())
{
// add if we match the group and we have a valid name
- if ((entry.group() == group) && entry.name() && entry.name()[0])
+ if (entry.group() == group)
{
- // loop over all sequence types
- for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; ++seqtype)
+ std::string name = entry.name();
+ if (!name.empty())
{
- // build an entry for the standard sequence
- input_item_data &item(data.emplace_back());
- item.ref = &entry;
- item.seqtype = seqtype;
- item.seq = machine().ioport().type_seq(entry.type(), entry.player(), seqtype);
- item.defseq = &entry.defseq(seqtype);
- item.group = entry.group();
- item.type = ioport_manager::type_is_analog(entry.type()) ? (INPUT_TYPE_ANALOG + seqtype) : INPUT_TYPE_DIGITAL;
- item.is_optional = false;
- item.name = entry.name();
- item.owner = nullptr;
-
- // stop after one, unless we're analog
- if (item.type == INPUT_TYPE_DIGITAL)
- break;
+ // loop over all sequence types
+ for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; ++seqtype)
+ {
+ // build an entry for the standard sequence
+ input_item_data &item(data.emplace_back());
+ item.ref = &entry;
+ item.seqtype = seqtype;
+ item.seq = machine().ioport().type_seq(entry.type(), entry.player(), seqtype);
+ item.defseq = &entry.defseq(seqtype);
+ item.group = entry.group();
+ item.type = ioport_manager::type_is_analog(entry.type()) ? (INPUT_TYPE_ANALOG + seqtype) : INPUT_TYPE_DIGITAL;
+ item.is_optional = false;
+ item.name = name;
+ item.owner = nullptr;
+
+ // stop after one, unless we're analog
+ if (item.type == INPUT_TYPE_DIGITAL)
+ break;
+ }
}
}
}
@@ -113,13 +131,15 @@ void menu_input_general::populate(float &customtop, float &custombottom)
}
// populate the menu in a standard fashion
- populate_sorted(customtop, custombottom);
+ populate_sorted();
+ item_append(menu_item_type::SEPARATOR);
}
void menu_input_general::update_input(input_item_data &seqchangeditem)
{
const input_type_entry &entry = *reinterpret_cast<const input_type_entry *>(seqchangeditem.ref);
machine().ioport().set_type_seq(entry.type(), entry.player(), seqchangeditem.seqtype, seqchangeditem.seq);
+ seqchangeditem.seq = machine().ioport().type_seq(entry.type(), entry.player(), seqchangeditem.seqtype);
}
@@ -130,13 +150,22 @@ void menu_input_general::update_input(input_item_data &seqchangeditem)
menu_input_specific::menu_input_specific(mame_ui_manager &mui, render_container &container) : menu_input(mui, container)
{
+ set_heading(_("Input Assignments (this system)"));
}
menu_input_specific::~menu_input_specific()
{
}
-void menu_input_specific::populate(float &customtop, float &custombottom)
+void menu_input_specific::menu_activated()
+{
+ // scripts can change settings out from under us
+ assert(!pollingitem);
+ data.clear();
+ reset(reset_options::REMEMBER_POSITION);
+}
+
+void menu_input_specific::populate()
{
if (data.empty())
{
@@ -202,7 +231,7 @@ void menu_input_specific::populate(float &customtop, float &custombottom)
return true;
if (!codes2.empty() && (codes1.empty() || codes1[0] > codes2[0]))
return false;
- cmp = strcmp(i1.name, i2.name);
+ cmp = i1.name.compare(i2.name);
if (cmp < 0)
return true;
if (cmp > 0)
@@ -220,7 +249,12 @@ void menu_input_specific::populate(float &customtop, float &custombottom)
}
// populate the menu in a standard fashion
- populate_sorted(customtop, custombottom);
+ if (!data.empty())
+ populate_sorted();
+ else
+ item_append(_("[no assignable inputs are enabled]"), FLAG_DISABLE, nullptr);
+
+ item_append(menu_item_type::SEPARATOR);
}
void menu_input_specific::update_input(input_item_data &seqchangeditem)
@@ -228,15 +262,24 @@ void menu_input_specific::update_input(input_item_data &seqchangeditem)
ioport_field::user_settings settings;
// yeah, the const_cast is naughty, but we know we stored a non-const reference in it
- reinterpret_cast<const ioport_field *>(seqchangeditem.ref)->get_user_settings(settings);
+ ioport_field const &field(*reinterpret_cast<ioport_field const *>(seqchangeditem.ref));
+ field.get_user_settings(settings);
settings.seq[seqchangeditem.seqtype] = seqchangeditem.seq;
- reinterpret_cast<ioport_field *>(const_cast<void *>(seqchangeditem.ref))->set_user_settings(settings);
+ if (seqchangeditem.seq.is_default())
+ settings.cfg[seqchangeditem.seqtype].clear();
+ else if (!seqchangeditem.seq.length())
+ settings.cfg[seqchangeditem.seqtype] = "NONE";
+ else
+ settings.cfg[seqchangeditem.seqtype] = machine().input().seq_to_tokens(seqchangeditem.seq);
+ const_cast<ioport_field &>(field).set_user_settings(settings);
+ seqchangeditem.seq = field.seq(seqchangeditem.seqtype);
}
/*-------------------------------------------------
menu_input - display a menu for inputs
-------------------------------------------------*/
+
menu_input::menu_input(mame_ui_manager &mui, render_container &container)
: menu(mui, container)
, data()
@@ -248,12 +291,14 @@ menu_input::menu_input(mame_ui_manager &mui, render_container &container)
, record_next(false)
, modified_ticks(0)
{
+ set_process_flags(PROCESS_LR_ALWAYS);
}
menu_input::~menu_input()
{
}
+
/*-------------------------------------------------
toggle_none_default - toggle between "NONE"
and the default item
@@ -262,12 +307,22 @@ menu_input::~menu_input()
void menu_input::toggle_none_default(input_seq &selected_seq, input_seq &original_seq, const input_seq &selected_defseq)
{
if (original_seq.empty()) // if we used to be "none", toggle to the default value
- selected_seq = selected_defseq;
+ selected_seq.set_default();
else // otherwise, toggle to "none"
selected_seq.reset();
}
-void menu_input::custom_render(void *selectedref, float top, float bottom, float x1, float y1, float x2, float y2)
+
+void menu_input::recompute_metrics(uint32_t width, uint32_t height, float aspect)
+{
+ menu::recompute_metrics(width, height, aspect);
+
+ // leave space for showing the input sequence below the menu
+ set_custom_space(0.0F, 2.0F * line_height() + 3.0F * tb_border());
+}
+
+
+void menu_input::custom_render(uint32_t flags, void *selectedref, float top, float bottom, float x1, float y1, float x2, float y2)
{
if (pollingitem)
{
@@ -275,9 +330,9 @@ void menu_input::custom_render(void *selectedref, float top, float bottom, float
char const *const text[] = { seqname.c_str() };
draw_text_box(
std::begin(text), std::end(text),
- x1, x2, y2 + ui().box_tb_border(), y2 + bottom,
- ui::text_layout::CENTER, ui::text_layout::NEVER, false,
- ui().colors().text_color(), ui().colors().background_color(), 1.0f);
+ x1, x2, y2 + tb_border(), y2 + bottom,
+ text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, false,
+ ui().colors().text_color(), ui().colors().background_color());
}
else
{
@@ -292,9 +347,9 @@ void menu_input::custom_render(void *selectedref, float top, float bottom, float
char const *const text[] = { errormsg.c_str() };
draw_text_box(
std::begin(text), std::end(text),
- x1, x2, y2 + ui().box_tb_border(), y2 + bottom,
- ui::text_layout::CENTER, ui::text_layout::NEVER, false,
- ui().colors().text_color(), UI_RED_COLOR, 1.0f);
+ x1, x2, y2 + tb_border(), y2 + bottom,
+ text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, false,
+ ui().colors().text_color(), UI_RED_COLOR);
}
else if (selectedref)
{
@@ -304,9 +359,9 @@ void menu_input::custom_render(void *selectedref, float top, float bottom, float
char const *const text[] = { _("Pressed") };
draw_text_box(
std::begin(text), std::end(text),
- x1, x2, y2 + ui().box_tb_border(), y2 + bottom,
- ui::text_layout::CENTER, ui::text_layout::NEVER, false,
- ui().colors().text_color(), ui().colors().background_color(), 1.0f);
+ x1, x2, y2 + tb_border(), y2 + bottom,
+ text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, false,
+ ui().colors().text_color(), ui().colors().background_color());
}
else
{
@@ -315,21 +370,21 @@ void menu_input::custom_render(void *selectedref, float top, float bottom, float
(!item.seq.empty() || item.defseq->empty()) ? clearprompt.c_str() : defaultprompt.c_str() };
draw_text_box(
std::begin(text), std::end(text),
- x1, x2, y2 + ui().box_tb_border(), y2 + bottom,
- ui::text_layout::CENTER, ui::text_layout::NEVER, false,
- ui().colors().text_color(), ui().colors().background_color(), 1.0f);
+ x1, x2, y2 + tb_border(), y2 + bottom,
+ text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, false,
+ ui().colors().text_color(), ui().colors().background_color());
}
}
}
}
-void menu_input::handle()
+bool menu_input::handle(event const *ev)
{
input_item_data *seqchangeditem = nullptr;
bool invalidate = false;
+ bool redraw = false;
// process the menu
- const event *const menu_event = process((pollingitem != nullptr) ? PROCESS_NOKEYS : 0);
if (pollingitem)
{
// if we are polling, handle as a special case
@@ -341,25 +396,17 @@ void menu_input::handle()
if (machine().ui_input().pressed(IPT_UI_CANCEL))
{
- // if UI_CANCEL is pressed, abort
+ // if UI_CANCEL is pressed, abort and abandon changes
pollingitem = nullptr;
- if (!seq_poll->modified() || modified_ticks == osd_ticks())
- {
- // cancelled immediately - toggle between default and none
- record_next = false;
- toggle_none_default(item->seq, starting_seq, *item->defseq);
- seqchangeditem = item;
- }
- else
- {
- // entered something before cancelling - abandon change
- invalidate = true;
- }
+ set_process_flags(PROCESS_LR_ALWAYS);
+ invalidate = true;
seq_poll.reset();
+ machine().ui_input().reset();
}
else if (seq_poll->poll()) // poll again; if finished, update the sequence
{
pollingitem = nullptr;
+ set_process_flags(PROCESS_LR_ALWAYS);
if (seq_poll->valid())
{
record_next = true;
@@ -370,19 +417,27 @@ void menu_input::handle()
{
// entered invalid sequence - abandon change
invalidate = true;
- errormsg = _("Invalid sequence entered");
+ errormsg = _("Invalid combination entered");
erroritem = item;
}
seq_poll.reset();
+ machine().ui_input().reset();
+ }
+ else
+ {
+ // always redraw to ensure it updates as soon as possible in response to changes
+ redraw = true;
}
}
- else if (menu_event && menu_event->itemref)
+ else if (ev && ev->itemref)
{
// otherwise, handle the events
- input_item_data &item = *reinterpret_cast<input_item_data *>(menu_event->itemref);
- switch (menu_event->iptkey)
+ input_item_data &item = *reinterpret_cast<input_item_data *>(ev->itemref);
+ input_item_data *newsel = &item;
+ switch (ev->iptkey)
{
case IPT_UI_SELECT: // an item was selected: begin polling
+ set_process_flags(PROCESS_NOKEYS);
errormsg.clear();
erroritem = nullptr;
modified_ticks = 0;
@@ -407,10 +462,59 @@ void menu_input::handle()
record_next = false;
seqchangeditem = &item;
break;
+
+ case IPT_UI_PREV_GROUP:
+ {
+ auto current = std::distance(data.data(), &item);
+ bool found_break = false;
+ while (0 < current)
+ {
+ if (!found_break)
+ {
+ if (data[--current].owner != item.owner)
+ found_break = true;
+ }
+ else if (data[current].owner != data[current - 1].owner)
+ {
+ newsel = &data[current];
+ set_selection(newsel);
+ set_top_line(selected_index() - 1);
+ break;
+ }
+ else
+ {
+ --current;
+ }
+ if (found_break && !current)
+ {
+ newsel = &data[current];
+ set_selection(newsel);
+ set_top_line(selected_index() - 1);
+ break;
+ }
+ }
+ }
+ break;
+
+ case IPT_UI_NEXT_GROUP:
+ {
+ auto current = std::distance(data.data(), &item);
+ while (data.size() > ++current)
+ {
+ if (data[current].owner != item.owner)
+ {
+ newsel = &data[current];
+ set_selection(newsel);
+ set_top_line(selected_index() - 1);
+ break;
+ }
+ }
+ }
+ break;
}
// if the selection changed, reset the "record next" flag
- if (&item != lastitem)
+ if (newsel != lastitem)
{
if (erroritem)
{
@@ -419,6 +523,23 @@ void menu_input::handle()
}
record_next = false;
lastitem = &item;
+ redraw = true;
+ }
+
+ // flip between set and append
+ // not very discoverable, but with the prompt it isn't completely opaque
+ if ((IPT_UI_LEFT == ev->iptkey) || (IPT_UI_RIGHT == ev->iptkey))
+ {
+ if (erroritem)
+ {
+ errormsg.clear();
+ erroritem = nullptr;
+ }
+ else if (record_next || !item.seq.empty())
+ {
+ record_next = !record_next;
+ }
+ redraw = true;
}
}
@@ -434,6 +555,8 @@ void menu_input::handle()
// if the menu is invalidated, clear it now
if (invalidate)
reset(reset_options::REMEMBER_POSITION);
+
+ return redraw && !invalidate;
}
@@ -443,20 +566,19 @@ void menu_input::handle()
// menu from them
//-------------------------------------------------
-void menu_input::populate_sorted(float &customtop, float &custombottom)
+void menu_input::populate_sorted()
{
const char *nameformat[INPUT_TYPE_TOTAL] = { nullptr };
// create a mini lookup table for name format based on type
- nameformat[INPUT_TYPE_DIGITAL] = "%s";
- nameformat[INPUT_TYPE_ANALOG] = "%s Analog";
- nameformat[INPUT_TYPE_ANALOG_INC] = "%s Analog Inc";
- nameformat[INPUT_TYPE_ANALOG_DEC] = "%s Analog Dec";
+ nameformat[INPUT_TYPE_DIGITAL] = "%1$s";
+ nameformat[INPUT_TYPE_ANALOG] = _("input-name", "%1$s Analog");
+ nameformat[INPUT_TYPE_ANALOG_INC] = _("input-name", "%1$s Analog Inc");
+ nameformat[INPUT_TYPE_ANALOG_DEC] = _("input-name", "%1$s Analog Dec");
// build the menu
std::string text, subtext;
const device_t *prev_owner = nullptr;
- bool first_entry = true;
for (input_item_data &item : data)
{
// generate the name of the item itself, based off the base name and the type
@@ -464,14 +586,10 @@ void menu_input::populate_sorted(float &customtop, float &custombottom)
if (item.owner && (item.owner != prev_owner))
{
- if (first_entry)
- first_entry = false;
- else
- item_append(menu_item_type::SEPARATOR);
if (item.owner->owner())
- item_append(string_format(_("%1$s [root%2$s]"), item.owner->type().fullname(), item.owner->tag()), 0, nullptr);
+ item_append(string_format(_("%1$s [root%2$s]"), item.owner->type().fullname(), item.owner->tag()), FLAG_UI_HEADING | FLAG_DISABLE, nullptr);
else
- item_append(string_format(_("[root%1$s]"), item.owner->tag()), 0, nullptr);
+ item_append(string_format(_("[root%1$s]"), item.owner->tag()), FLAG_UI_HEADING | FLAG_DISABLE, nullptr);
prev_owner = item.owner;
}
@@ -497,16 +615,11 @@ void menu_input::populate_sorted(float &customtop, float &custombottom)
item_append(std::move(text), std::move(subtext), flags, &item);
}
- item_append(menu_item_type::SEPARATOR);
-
// pre-format messages
- assignprompt = util::string_format(_("Press %1$s to set\n"), machine().input().seq_name(machine().ioport().type_seq(IPT_UI_SELECT)));
- appendprompt = util::string_format(_("Press %1$s to append\n"), machine().input().seq_name(machine().ioport().type_seq(IPT_UI_SELECT)));
- clearprompt = util::string_format(_("Press %1$s to clear\n"), machine().input().seq_name(machine().ioport().type_seq(IPT_UI_CLEAR)));
- defaultprompt = util::string_format(_("Press %1$s to restore default\n"), machine().input().seq_name(machine().ioport().type_seq(IPT_UI_CLEAR)));
-
- // leave space for showing the input sequence below the menu
- custombottom = 2.0f * ui().get_line_height() + 3.0f * ui().box_tb_border();
+ assignprompt = util::string_format(_("Press %1$s to set\n"), ui().get_general_input_setting(IPT_UI_SELECT));
+ appendprompt = util::string_format(_("Press %1$s to append\n"), ui().get_general_input_setting(IPT_UI_SELECT));
+ clearprompt = util::string_format(_("Press %1$s to clear\n"), ui().get_general_input_setting(IPT_UI_CLEAR));
+ defaultprompt = util::string_format(_("Press %1$s to restore default\n"), ui().get_general_input_setting(IPT_UI_CLEAR));
}
} // namespace ui