From bb68893deb460b1247b3dfa15d3d190bfec5a083 Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Sun, 17 Nov 2019 02:01:39 +1100 Subject: UI updates: * Cleaned up memory management in some more menus * Don't walk the directory every time the crosshair menu is refreshed * Sort crosshair pictures * Show a selector menu when crosshair picture item is selected --- src/frontend/mame/ui/menu.cpp | 1 - src/frontend/mame/ui/miscmenu.cpp | 402 +++++++++++++++++++++----------------- src/frontend/mame/ui/miscmenu.h | 24 ++- src/frontend/mame/ui/swlist.cpp | 34 ++-- src/frontend/mame/ui/swlist.h | 8 +- 5 files changed, 258 insertions(+), 211 deletions(-) (limited to 'src/frontend') diff --git a/src/frontend/mame/ui/menu.cpp b/src/frontend/mame/ui/menu.cpp index 69e08b5489d..bb56497f32a 100644 --- a/src/frontend/mame/ui/menu.cpp +++ b/src/frontend/mame/ui/menu.cpp @@ -317,7 +317,6 @@ void menu::reset(reset_options options) else item_append(_("Return to Previous Menu"), "", 0, nullptr); } - } diff --git a/src/frontend/mame/ui/miscmenu.cpp b/src/frontend/mame/ui/miscmenu.cpp index b7a52f2a4e5..e91f289b6e9 100644 --- a/src/frontend/mame/ui/miscmenu.cpp +++ b/src/frontend/mame/ui/miscmenu.cpp @@ -9,6 +9,13 @@ *********************************************************************/ #include "emu.h" +#include "ui/miscmenu.h" + +#include "ui/inifile.h" +#include "ui/selector.h" +#include "ui/submenu.h" +#include "ui/ui.h" + #include "mame.h" #include "osdnet.h" #include "mameopts.h" @@ -18,14 +25,14 @@ #include "romload.h" #include "uiinput.h" -#include "ui/ui.h" -#include "ui/menu.h" -#include "ui/miscmenu.h" + #include "../info.h" -#include "ui/inifile.h" -#include "ui/submenu.h" +#include +#include #include +#include + namespace ui { @@ -271,93 +278,99 @@ void menu_bookkeeping::populate(float &customtop, float &custombottom) void menu_crosshair::handle() { - /* process the menu */ - const event *menu_event = process(PROCESS_LR_REPEAT); + // process the menu + event const *const menu_event(process(PROCESS_LR_REPEAT)); - /* handle events */ - if (menu_event != nullptr && menu_event->itemref != nullptr) + // handle events + if (menu_event && menu_event->itemref) { - crosshair_item_data *data = (crosshair_item_data *)menu_event->itemref; - bool changed = false; - //int set_def = false; - int newval = data->cur; - - /* retreive the user settings */ - render_crosshair &crosshair = machine().crosshair().get_crosshair(data->player); + crosshair_item_data &data(*reinterpret_cast(menu_event->itemref)); + bool changed(false); + int newval(data.cur); switch (menu_event->iptkey) { - /* if selected, reset to default value */ - case IPT_UI_SELECT: - newval = data->defvalue; - //set_def = true; - break; + // if selected, reset to default value + case IPT_UI_SELECT: + newval = data.defvalue; + break; - /* left decrements */ - case IPT_UI_LEFT: - newval -= machine().input().code_pressed(KEYCODE_LSHIFT) ? 10 : 1; - break; + // left decrements + case IPT_UI_LEFT: + newval -= machine().input().code_pressed(KEYCODE_LSHIFT) ? 10 : 1; + break; - /* right increments */ - case IPT_UI_RIGHT: - newval += machine().input().code_pressed(KEYCODE_LSHIFT) ? 10 : 1; - break; + // right increments + case IPT_UI_RIGHT: + newval += machine().input().code_pressed(KEYCODE_LSHIFT) ? 10 : 1; + break; } - /* clamp to range */ - if (newval < data->min) - newval = data->min; - if (newval > data->max) - newval = data->max; + // clamp to range + if (newval < data.min) + newval = data.min; + if (newval > data.max) + newval = data.max; - /* if things changed, update */ - if (newval != data->cur) + // if things changed, update + if (newval != data.cur) { - switch (data->type) + switch (data.type) { - /* visibility state */ - case CROSSHAIR_ITEM_VIS: - crosshair.set_mode(newval); - // set visibility as specified by mode - auto mode starts with visibility off - crosshair.set_visible(newval == CROSSHAIR_VISIBILITY_ON); - changed = true; - break; - - /* auto time */ - case CROSSHAIR_ITEM_AUTO_TIME: - machine().crosshair().set_auto_time(newval); - changed = true; - break; + // visibility state + case CROSSHAIR_ITEM_VIS: + data.crosshair->set_mode(newval); + // set visibility as specified by mode - auto mode starts with visibility off + data.crosshair->set_visible(newval == CROSSHAIR_VISIBILITY_ON); + changed = true; + break; + + // auto time + case CROSSHAIR_ITEM_AUTO_TIME: + machine().crosshair().set_auto_time(newval); + changed = true; + break; } } - /* crosshair graphic name */ - if (data->type == CROSSHAIR_ITEM_PIC) + // crosshair graphic name + if (data.type == CROSSHAIR_ITEM_PIC) { switch (menu_event->iptkey) { - case IPT_UI_SELECT: - crosshair.set_default_bitmap(); - changed = true; - break; - - case IPT_UI_LEFT: - crosshair.set_bitmap_name(data->last_name); - changed = true; - break; - - case IPT_UI_RIGHT: - crosshair.set_bitmap_name(data->next_name); - changed = true; - break; + case IPT_UI_SELECT: + { + std::vector sel; + sel.reserve(m_pics.size() + 1); + sel.push_back("DEFAULT"); + std::copy(m_pics.begin(), m_pics.end(), std::back_inserter(sel)); + menu::stack_push( + ui(), container(), std::move(sel), data.cur, + [this, &data] (int selection) + { + if (!selection) + data.crosshair->set_default_bitmap(); + else + data.crosshair->set_bitmap_name(m_pics[selection - 1].c_str()); + reset(reset_options::REMEMBER_REF); + }); + } + break; + + case IPT_UI_LEFT: + data.crosshair->set_bitmap_name(data.last_name.c_str()); + changed = true; + break; + + case IPT_UI_RIGHT: + data.crosshair->set_bitmap_name(data.next_name.c_str()); + changed = true; + break; } } if (changed) - { - /* rebuild the menu */ - reset(reset_options::REMEMBER_POSITION); - } + reset(reset_options::REMEMBER_REF); // rebuild the menu } } @@ -373,142 +386,165 @@ menu_crosshair::menu_crosshair(mame_ui_manager &mui, render_container &container void menu_crosshair::populate(float &customtop, float &custombottom) { - crosshair_item_data *data; - char temp_text[16]; - int player; - uint8_t use_auto = false; - uint32_t flags = 0; + if (m_data.empty()) + { + // loop over player and add the manual items + for (int player = 0; player < MAX_PLAYERS; player++) + { + // get the user settings + render_crosshair &crosshair(machine().crosshair().get_crosshair(player)); + + // add menu items for usable crosshairs + if (crosshair.is_used()) + { + // CROSSHAIR_ITEM_VIS - allocate a data item and fill it + crosshair_item_data &visdata(*m_data.emplace(m_data.end())); + visdata.crosshair = &crosshair; + visdata.type = CROSSHAIR_ITEM_VIS; + visdata.player = player; + visdata.min = CROSSHAIR_VISIBILITY_OFF; + visdata.max = CROSSHAIR_VISIBILITY_AUTO; + visdata.defvalue = CROSSHAIR_VISIBILITY_DEFAULT; + + // CROSSHAIR_ITEM_PIC - allocate a data item and fill it + crosshair_item_data &picdata(*m_data.emplace(m_data.end())); + picdata.crosshair = &crosshair; + picdata.type = CROSSHAIR_ITEM_PIC; + picdata.player = player; + // other data item not used by this menu + } + } + + // CROSSHAIR_ITEM_AUTO_TIME - allocate a data item and fill it + crosshair_item_data &timedata(*m_data.emplace(m_data.end())); + timedata.type = CROSSHAIR_ITEM_AUTO_TIME; + timedata.min = CROSSHAIR_VISIBILITY_AUTOTIME_MIN; + timedata.max = CROSSHAIR_VISIBILITY_AUTOTIME_MAX; + timedata.defvalue = CROSSHAIR_VISIBILITY_AUTOTIME_DEFAULT; + } - /* loop over player and add the manual items */ - for (player = 0; player < MAX_PLAYERS; player++) + if (m_pics.empty()) { - /* get the user settings */ - render_crosshair &crosshair = machine().crosshair().get_crosshair(player); + // open a path to the crosshairs + file_enumerator path(machine().options().crosshair_path()); + for (osd::directory::entry const *dir = path.next(); dir; dir = path.next()) + { + // look for files ending in .png + size_t const length(std::strlen(dir->name)); + if ((length > 4) && core_filename_ends_with(dir->name, ".png")) + m_pics.emplace_back(dir->name, length - 4); + } + std::stable_sort( + m_pics.begin(), + m_pics.end(), + [] (std::string const &a, std::string const &b) { return 0 > core_stricmp(a.c_str(), b.c_str()); }); + } + + // Make sure to keep these matched to the CROSSHAIR_VISIBILITY_xxx types + static char const *const vis_text[] = { "Off", "On", "Auto" }; - /* add menu items for usable crosshairs */ - if (crosshair.is_used()) + bool use_auto = false; + for (crosshair_item_data &data : m_data) + { + switch (data.type) { - /* Make sure to keep these matched to the CROSSHAIR_VISIBILITY_xxx types */ - static const char *const vis_text[] = { "Off", "On", "Auto" }; - - /* track if we need the auto time menu */ - if (crosshair.mode() == CROSSHAIR_VISIBILITY_AUTO) use_auto = true; - - /* CROSSHAIR_ITEM_VIS - allocate a data item and fill it */ - data = (crosshair_item_data *)m_pool_alloc(sizeof(*data)); - data->type = CROSSHAIR_ITEM_VIS; - data->player = player; - data->min = CROSSHAIR_VISIBILITY_OFF; - data->max = CROSSHAIR_VISIBILITY_AUTO; - data->defvalue = CROSSHAIR_VISIBILITY_DEFAULT; - data->cur = crosshair.mode(); - - /* put on arrows */ - if (data->cur > data->min) - flags |= FLAG_LEFT_ARROW; - if (data->cur < data->max) - flags |= FLAG_RIGHT_ARROW; - - /* add CROSSHAIR_ITEM_VIS menu */ - sprintf(temp_text, "P%d Visibility", player + 1); - item_append(temp_text, vis_text[crosshair.mode()], flags, data); - - /* CROSSHAIR_ITEM_PIC - allocate a data item and fill it */ - data = (crosshair_item_data *)m_pool_alloc(sizeof(*data)); - data->type = CROSSHAIR_ITEM_PIC; - data->player = player; - data->last_name[0] = 0; - /* other data item not used by this menu */ - - /* search for crosshair graphics */ - - /* open a path to the crosshairs */ - file_enumerator path(machine().options().crosshair_path()); - const osd::directory::entry *dir; - /* reset search flags */ - bool using_default = false; - bool finished = false; - bool found = false; - - /* if we are using the default, then we just need to find the first in the list */ - if (*crosshair.bitmap_name() == '\0') - using_default = true; - - /* look for the current name, then remember the name before */ - /* and find the next name */ - while (((dir = path.next()) != nullptr) && !finished) + case CROSSHAIR_ITEM_VIS: { - int length = strlen(dir->name); + // track if we need the auto time menu + if (data.crosshair->mode() == CROSSHAIR_VISIBILITY_AUTO) + use_auto = true; - /* look for files ending in .png with a name not larger then 9 chars*/ - if ((length > 4) && (length <= CROSSHAIR_PIC_NAME_LENGTH + 4) && core_filename_ends_with(dir->name, ".png")) - { - /* remove .png from length */ - length -= 4; + data.cur = data.crosshair->mode(); + + // put on arrows + uint32_t flags(0U); + if (data.cur > data.min) + flags |= FLAG_LEFT_ARROW; + if (data.cur < data.max) + flags |= FLAG_RIGHT_ARROW; + // add CROSSHAIR_ITEM_VIS menu */ + item_append(util::string_format(_("P%d Visibility"), data.player + 1), vis_text[data.crosshair->mode()], flags, &data); + } + break; + + case CROSSHAIR_ITEM_PIC: + // search for crosshair graphics + { + // reset search flags + bool const using_default(*data.crosshair->bitmap_name() == '\0'); + bool finished(false); + bool found(false); + data.cur = using_default ? 0U : 1U; + data.last_name.clear(); + data.next_name.clear(); + + // look for the current name, then remember the name before and find the next name + for (auto it = m_pics.begin(); it != m_pics.end() && !finished; ++it) + { + // if we are using the default, then we just need to find the first in the list if (found || using_default) { - /* get the next name */ - strncpy(data->next_name, dir->name, length); - data->next_name[length] = 0; + // get the next name + data.next_name = *it; finished = true; } - else if (!strncmp(dir->name, crosshair.bitmap_name(), length)) + else if (data.crosshair->bitmap_name() == *it) { - /* we found the current name */ - /* so loop once more to find the next name */ + // we found the current name so loop once more to find the next name found = true; } else - /* remember last name */ - /* we will do it here in case files get added to the directory */ { - strncpy(data->last_name, dir->name, length); - data->last_name[length] = 0; + // remember last name - we will do it here in case files get added to the directory + ++data.cur; + data.last_name = *it; } } + + // if name not found then next item is DEFAULT + if (!found && !using_default) + { + data.cur = 0U; + data.next_name.clear(); + finished = true; + } + + // set up the selection flags + uint32_t flags(0U); + if (finished) + flags |= FLAG_RIGHT_ARROW; + if (found) + flags |= FLAG_LEFT_ARROW; + + // add CROSSHAIR_ITEM_PIC menu + item_append(util::string_format(_("P%d Crosshair"), data.player + 1), using_default ? "DEFAULT" : data.crosshair->bitmap_name(), flags, &data); } - /* if name not found then next item is DEFAULT */ - if (!found && !using_default) + break; + + case CROSSHAIR_ITEM_AUTO_TIME: + if (use_auto) { - data->next_name[0] = 0; - finished = true; + data.cur = machine().crosshair().auto_time(); + + // put on arrows in visible menu + uint32_t flags(0U); + if (data.cur > data.min) + flags |= FLAG_LEFT_ARROW; + if (data.cur < data.max) + flags |= FLAG_RIGHT_ARROW; + + // add CROSSHAIR_ITEM_AUTO_TIME menu + item_append(_("Visible Delay"), util::string_format("%d", data.cur), flags, &data); } - /* setup the selection flags */ - flags = 0; - if (finished) - flags |= FLAG_RIGHT_ARROW; - if (found) - flags |= FLAG_LEFT_ARROW; - - /* add CROSSHAIR_ITEM_PIC menu */ - sprintf(temp_text, "P%d Crosshair", player + 1); - item_append(temp_text, using_default ? "DEFAULT" : crosshair.bitmap_name(), flags, data); + else + { + // leave a blank filler line when not in auto time so size does not rescale + //item_append("", "", nullptr, nullptr); + } + break; } } - if (use_auto) - { - /* CROSSHAIR_ITEM_AUTO_TIME - allocate a data item and fill it */ - data = (crosshair_item_data *)m_pool_alloc(sizeof(*data)); - data->type = CROSSHAIR_ITEM_AUTO_TIME; - data->min = CROSSHAIR_VISIBILITY_AUTOTIME_MIN; - data->max = CROSSHAIR_VISIBILITY_AUTOTIME_MAX; - data->defvalue = CROSSHAIR_VISIBILITY_AUTOTIME_DEFAULT; - data->cur = machine().crosshair().auto_time(); - - /* put on arrows in visible menu */ - if (data->cur > data->min) - flags |= FLAG_LEFT_ARROW; - if (data->cur < data->max) - flags |= FLAG_RIGHT_ARROW; - - /* add CROSSHAIR_ITEM_AUTO_TIME menu */ - sprintf(temp_text, "%d", machine().crosshair().auto_time()); - item_append(_("Visible Delay"), temp_text, flags, data); - } -// else -// /* leave a blank filler line when not in auto time so size does not rescale */ -// item_append("", "", nullptr, nullptr); } menu_crosshair::~menu_crosshair() diff --git a/src/frontend/mame/ui/miscmenu.h b/src/frontend/mame/ui/miscmenu.h index 4df94c60a78..acff544dee6 100644 --- a/src/frontend/mame/ui/miscmenu.h +++ b/src/frontend/mame/ui/miscmenu.h @@ -13,12 +13,15 @@ #pragma once +#include "ui/menu.h" + #include "crsshair.h" #include "emuopts.h" #include #include + namespace ui { class menu_keyboard_mode : public menu @@ -69,23 +72,24 @@ private: CROSSHAIR_ITEM_AUTO_TIME }; - // FIXME: use std::string instead of fixed-length arrays - constexpr static int CROSSHAIR_PIC_NAME_LENGTH = 12; - /* internal crosshair menu item data */ struct crosshair_item_data { - uint8_t type; - uint8_t player; - uint8_t min, max; - uint8_t cur; - uint8_t defvalue; - char last_name[CROSSHAIR_PIC_NAME_LENGTH + 1]; - char next_name[CROSSHAIR_PIC_NAME_LENGTH + 1]; + render_crosshair *crosshair = nullptr; + uint8_t type = 0U; + uint8_t player = 0U; + uint8_t min = 0U, max = 0U; + uint32_t cur = 0U; + uint8_t defvalue = 0U; + std::string last_name; + std::string next_name; }; virtual void populate(float &customtop, float &custombottom) override; virtual void handle() override; + + std::vector m_data; + std::vector m_pics; }; class menu_quit_game : public menu diff --git a/src/frontend/mame/ui/swlist.cpp b/src/frontend/mame/ui/swlist.cpp index dc0e98407fe..b0dba549efc 100644 --- a/src/frontend/mame/ui/swlist.cpp +++ b/src/frontend/mame/ui/swlist.cpp @@ -75,38 +75,40 @@ menu_software_parts::~menu_software_parts() void menu_software_parts::populate(float &customtop, float &custombottom) { + m_entries.clear(); + if (m_other_opt) { - software_part_menu_entry *entry1 = (software_part_menu_entry *) m_pool_alloc(sizeof(*entry1)); - entry1->type = result::EMPTY; - entry1->part = nullptr; - item_append(_("[empty slot]"), "", 0, entry1); + software_part_menu_entry &entry1(*m_entries.emplace(m_entries.end())); + entry1.type = result::EMPTY; + entry1.part = nullptr; + item_append(_("[empty slot]"), "", 0, &entry1); - software_part_menu_entry *entry2 = (software_part_menu_entry *) m_pool_alloc(sizeof(*entry2)); - entry2->type = result::FMGR; - entry2->part = nullptr; - item_append(_("[file manager]"), "", 0, entry2); + software_part_menu_entry &entry2(*m_entries.emplace(m_entries.end())); + entry2.type = result::FMGR; + entry2.part = nullptr; + item_append(_("[file manager]"), "", 0, &entry2); - software_part_menu_entry *entry3 = (software_part_menu_entry *) m_pool_alloc(sizeof(*entry3)); - entry3->type = result::SWLIST; - entry3->part = nullptr; - item_append(_("[software list]"), "", 0, entry3); + software_part_menu_entry &entry3(*m_entries.emplace(m_entries.end())); + entry3.type = result::SWLIST; + entry3.part = nullptr; + item_append(_("[software list]"), "", 0, &entry3); } for (const software_part &swpart : m_info->parts()) { if (swpart.matches_interface(m_interface)) { - software_part_menu_entry *entry = (software_part_menu_entry *) m_pool_alloc(sizeof(*entry)); + software_part_menu_entry &entry(*m_entries.emplace(m_entries.end())); // check if the available parts have specific part_id to be displayed (e.g. "Map Disc", "Bonus Disc", etc.) // if not, we simply display "part_name"; if yes we display "part_name (part_id)" std::string menu_part_name(swpart.name()); if (swpart.feature("part_id") != nullptr) menu_part_name.append(" (").append(swpart.feature("part_id")).append(")"); - entry->type = result::ENTRY; - entry->part = &swpart; - item_append(m_info->shortname(), menu_part_name, 0, entry); + entry.type = result::ENTRY; + entry.part = &swpart; + item_append(m_info->shortname(), menu_part_name, 0, &entry); } } } diff --git a/src/frontend/mame/ui/swlist.h b/src/frontend/mame/ui/swlist.h index d0239c2c389..a9947cd8daf 100644 --- a/src/frontend/mame/ui/swlist.h +++ b/src/frontend/mame/ui/swlist.h @@ -13,8 +13,11 @@ #include "ui/menu.h" +#include + namespace ui { + // ======================> menu_software_parts class menu_software_parts : public menu @@ -33,15 +36,18 @@ public: virtual ~menu_software_parts() override; private: - struct software_part_menu_entry { + struct software_part_menu_entry + { result type; const software_part *part; }; + using entry_list = std::list; virtual void populate(float &customtop, float &custombottom) override; virtual void handle() override; // variables + entry_list m_entries; const software_info * m_info; const char * m_interface; const software_part ** m_selected_part; -- cgit v1.2.3