summaryrefslogtreecommitdiffstatshomepage
path: root/src/frontend
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2017-08-09 23:22:19 +1000
committer Vas Crabb <vas@vastheman.com>2017-08-09 23:27:30 +1000
commit651d8ee692ca08541953f73d455663434f50ba02 (patch)
treed8d6c06c19a026d69c8aab92aa19227843545c86 /src/frontend
parentba14f72569be7f283602f4e5aacda566ef6995b9 (diff)
Polymorphic machine/software list filters:
* Localisable filter names * Uniform interface for most filters without far less special-casing * Stacking year/manufacturer/etc. does OR rather than useless AND * Prevent stacking contradictory filters (e.g. parents and clones) * Fix alignment of filter list * Removed most of the lambdas added the other day * There's no longer an implicit "not BIOS" filter * Can't add (un)available to custom machine filter (will address)
Diffstat (limited to 'src/frontend')
-rw-r--r--src/frontend/mame/ui/custmenu.cpp591
-rw-r--r--src/frontend/mame/ui/custmenu.h79
-rw-r--r--src/frontend/mame/ui/optsmenu.cpp380
-rw-r--r--src/frontend/mame/ui/optsmenu.h13
-rw-r--r--src/frontend/mame/ui/selgame.cpp502
-rw-r--r--src/frontend/mame/ui/selgame.h2
-rw-r--r--src/frontend/mame/ui/selsoft.cpp459
-rw-r--r--src/frontend/mame/ui/selsoft.h9
-rw-r--r--src/frontend/mame/ui/utils.cpp1220
-rw-r--r--src/frontend/mame/ui/utils.h236
10 files changed, 1760 insertions, 1731 deletions
diff --git a/src/frontend/mame/ui/custmenu.cpp b/src/frontend/mame/ui/custmenu.cpp
index 45d981174d1..ea5562a0d9e 100644
--- a/src/frontend/mame/ui/custmenu.cpp
+++ b/src/frontend/mame/ui/custmenu.cpp
@@ -11,571 +11,108 @@
#include "emu.h"
#include "ui/custmenu.h"
-#include "ui/ui.h"
-#include "ui/selector.h"
-#include "ui/inifile.h"
-
-#include "rendfont.h"
+#include <algorithm>
namespace ui {
-/**************************************************
- MENU CUSTOM FILTER
-**************************************************/
-//-------------------------------------------------
-// ctor / dtor
-//-------------------------------------------------
-menu_custom_filter::menu_custom_filter(mame_ui_manager &mui, render_container &container, bool _single_menu)
- : menu(mui, container)
- , m_single_menu(_single_menu)
- , m_added(false)
-{
-}
-
-menu_custom_filter::~menu_custom_filter()
-{
- if (m_single_menu)
- reset_topmost(reset_options::SELECT_FIRST);
- save_custom_filters();
-}
-
-//-------------------------------------------------
-// handle
-//-------------------------------------------------
-void menu_custom_filter::handle()
-{
- bool changed = false;
- m_added = false;
-
- // process the menu
- const event *menu_event = process(PROCESS_LR_REPEAT);
- if (menu_event != nullptr && menu_event->itemref != nullptr)
- {
- switch ((uintptr_t)menu_event->itemref)
- {
- case MAIN_FILTER:
- if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
- {
- (menu_event->iptkey == IPT_UI_RIGHT) ? custfltr::main++ : custfltr::main--;
- changed = true;
- }
- break;
+namespace {
- case ADD_FILTER:
- if (menu_event->iptkey == IPT_UI_SELECT)
- {
- custfltr::numother++;
- custfltr::other[custfltr::numother] = machine_filter::UNAVAILABLE;
- ++custfltr::other[custfltr::numother];
- m_added = true;
- }
- break;
+constexpr char const *region_lists[] = {
+ "arab", "arg", "asia", "aus", "aut",
+ "bel", "blr", "bra",
+ "can", "chi", "chn", "cze",
+ "den",
+ "ecu", "esp", "euro",
+ "fin", "fra",
+ "gbr", "ger", "gre",
+ "hkg", "hun",
+ "irl", "isr", "isv", "ita",
+ "jpn",
+ "kaz", "kor",
+ "lat", "lux",
+ "mex",
+ "ned", "nld", "nor", "nzl",
+ "pol",
+ "rus",
+ "slo", "spa", "sui", "swe",
+ "tha", "tpe", "tw",
+ "uk", "ukr", "usa" };
- case REMOVE_FILTER:
- if (menu_event->iptkey == IPT_UI_SELECT)
- {
- custfltr::other[custfltr::numother] = machine_filter::UNAVAILABLE;
- ++custfltr::other[custfltr::numother];
- custfltr::numother--;
- changed = true;
- }
- break;
- }
-
- if ((uintptr_t)menu_event->itemref >= OTHER_FILTER && (uintptr_t)menu_event->itemref < OTHER_FILTER + MAX_CUST_FILTER)
- {
- int pos = (int)((uintptr_t)menu_event->itemref - OTHER_FILTER);
- if (menu_event->iptkey == IPT_UI_LEFT && custfltr::other[pos] > machine_filter::UNAVAILABLE + 1)
- {
- custfltr::other[pos]--;
- for ( ; custfltr::other[pos] > machine_filter::UNAVAILABLE && (custfltr::other[pos] == machine_filter::CATEGORY
- || custfltr::other[pos] == machine_filter::FAVORITE); custfltr::other[pos]--) { };
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_RIGHT && custfltr::other[pos] < machine_filter::LAST - 1)
- {
- custfltr::other[pos]++;
- for ( ; custfltr::other[pos] < machine_filter::LAST && (custfltr::other[pos] == machine_filter::CATEGORY
- || custfltr::other[pos] == machine_filter::FAVORITE); custfltr::other[pos]++) { };
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_SELECT)
- {
- std::vector<machine_filter::type> types;
- std::vector<std::string> names;
- types.reserve(machine_filter::COUNT);
- names.reserve(machine_filter::COUNT);
- int sel(-1);
- for (machine_filter::type index = machine_filter::FIRST; index < machine_filter::COUNT; ++index)
- {
- if ((index > machine_filter::UNAVAILABLE) && (index != machine_filter::CATEGORY) && (index != machine_filter::FAVORITE) && (index != machine_filter::CUSTOM))
- {
- if (custfltr::other[pos] == index)
- sel = types.size();
- types.emplace_back(index);
- names.emplace_back(machine_filter::display_name(index));
- }
- }
- menu::stack_push<menu_selector>(ui(), container(), std::move(names), sel, [this, pos, t = std::move(types)] (int selection) { custfltr::other[pos] = t[selection]; reset(reset_options::REMEMBER_REF); });
- }
- }
- else if ((uintptr_t)menu_event->itemref >= YEAR_FILTER && (uintptr_t)menu_event->itemref < YEAR_FILTER + MAX_CUST_FILTER)
- {
- int pos = (int)((uintptr_t)menu_event->itemref - YEAR_FILTER);
- if (menu_event->iptkey == IPT_UI_LEFT && custfltr::year[pos] > 0)
- {
- custfltr::year[pos]--;
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_RIGHT && custfltr::year[pos] < c_year::ui.size() - 1)
- {
- custfltr::year[pos]++;
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_SELECT)
- {
- menu::stack_push<menu_selector>(ui(), container(), std::vector<std::string>(c_year::ui), custfltr::year[pos], [this, pos] (int selection) { custfltr::year[pos] = selection; reset(reset_options::REMEMBER_REF); });
- }
- }
- else if ((uintptr_t)menu_event->itemref >= MNFCT_FILTER && (uintptr_t)menu_event->itemref < MNFCT_FILTER + MAX_CUST_FILTER)
- {
- int pos = (int)((uintptr_t)menu_event->itemref - MNFCT_FILTER);
- if (menu_event->iptkey == IPT_UI_LEFT && custfltr::mnfct[pos] > 0)
- {
- custfltr::mnfct[pos]--;
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_RIGHT && custfltr::mnfct[pos] < c_mnfct::ui.size() - 1)
- {
- custfltr::mnfct[pos]++;
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_SELECT)
- {
- menu::stack_push<menu_selector>(ui(), container(), std::vector<std::string>(c_mnfct::ui), custfltr::mnfct[pos], [this, pos] (int selection) { custfltr::mnfct[pos] = selection; reset(reset_options::REMEMBER_REF); });
- }
- }
- }
-
- if (changed)
- reset(reset_options::REMEMBER_REF);
- else if (m_added)
- reset(reset_options::SELECT_FIRST);
-}
+} // anonymous namespace
//-------------------------------------------------
-// populate
+// set software regions
//-------------------------------------------------
-void menu_custom_filter::populate(float &customtop, float &custombottom)
-{
- // add main filter
- uint32_t arrow_flags = get_arrow_flags<uint16_t>(machine_filter::ALL, machine_filter::UNAVAILABLE, custfltr::main);
- item_append(_("Main filter"), machine_filter::display_name(custfltr::main), arrow_flags, (void *)(uintptr_t)MAIN_FILTER);
-
- // add other filters
- for (int x = 1; x <= custfltr::numother; x++)
- {
- item_append(menu_item_type::SEPARATOR);
-
- // add filter items
- arrow_flags = get_arrow_flags<uint16_t>(machine_filter::UNAVAILABLE + 1, machine_filter::LAST - 1, custfltr::other[x]);
- item_append(_("Other filter"), machine_filter::display_name(custfltr::other[x]), arrow_flags, (void *)(uintptr_t)(OTHER_FILTER + x));
-
- if (m_added)
- selected = item.size() - 2;
-
- // add manufacturer subitem
- if (custfltr::other[x] == machine_filter::MANUFACTURER && c_mnfct::ui.size() > 0)
- {
- arrow_flags = get_arrow_flags<uint16_t>(0, c_mnfct::ui.size() - 1, custfltr::mnfct[x]);
- std::string fbuff(_("^!Manufacturer"));
- convert_command_glyph(fbuff);
- item_append(fbuff, c_mnfct::ui[custfltr::mnfct[x]], arrow_flags, (void *)(uintptr_t)(MNFCT_FILTER + x));
- }
-
- // add year subitem
- else if (custfltr::other[x] == machine_filter::YEAR && c_year::ui.size() > 0)
- {
- arrow_flags = get_arrow_flags<uint16_t>(0, c_year::ui.size() - 1, custfltr::year[x]);
- std::string fbuff(_("^!Year"));
- convert_command_glyph(fbuff);
- item_append(fbuff, c_year::ui[custfltr::year[x]], arrow_flags, (void *)(uintptr_t)(YEAR_FILTER + x));
- }
- }
-
- item_append(menu_item_type::SEPARATOR);
- if (custfltr::numother > 0)
- item_append(_("Remove last filter"), "", 0, (void *)(uintptr_t)REMOVE_FILTER);
-
- if (custfltr::numother < MAX_CUST_FILTER - 2)
- item_append(_("Add filter"), "", 0, (void *)(uintptr_t)ADD_FILTER);
-
- item_append(menu_item_type::SEPARATOR);
- customtop = ui().get_line_height() + 3.0f * UI_BOX_TB_BORDER;
-}
-
-//-------------------------------------------------
-// perform our special rendering
-//-------------------------------------------------
-void menu_custom_filter::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
+void c_sw_region::set(std::string &str)
{
- char const *const text[] = { _("Select custom filters:") };
- draw_text_box(
- std::begin(text), std::end(text),
- origx1, origx2, origy1 - top, origy1 - UI_BOX_TB_BORDER,
- ui::text_layout::CENTER, ui::text_layout::NEVER, false,
- UI_TEXT_COLOR, UI_GREEN_COLOR, 1.0f);
+ std::string name(getname(str));
+ std::vector<std::string>::iterator const pos(std::lower_bound(ui.begin(), ui.end(), name));
+ if ((ui.end() == pos) || (*pos != str))
+ ui.emplace(pos, std::move(name));
}
-//-------------------------------------------------
-// save custom filters info to file
-//-------------------------------------------------
-
-void menu_custom_filter::save_custom_filters()
+std::string c_sw_region::getname(std::string const &str) const
{
- // attempt to open the output file
- emu_file file(ui().options().ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
- if (file.open("custom_", emulator_info::get_configname(), "_filter.ini") == osd_file::error::NONE)
+ std::string fullname(str);
+ strmakelower(fullname);
+ size_t found = fullname.find("(");
+
+ if (found != std::string::npos)
{
- // generate custom filters info
- std::ostringstream cinfo;
- util::stream_format(cinfo, "Total filters = %d\n", (custfltr::numother + 1));
- util::stream_format(cinfo, "Main filter = %s\n", machine_filter::config_name(custfltr::main));
+ size_t ends = fullname.find_first_not_of("abcdefghijklmnopqrstuvwxyz", found + 1);
+ std::string temp(fullname.substr(found + 1, ends - found - 1));
- for (int x = 1; x <= custfltr::numother; x++)
- {
- util::stream_format(cinfo, "Other filter = %s\n", machine_filter::config_name(custfltr::other[x]));
- if (custfltr::other[x] == machine_filter::MANUFACTURER)
- util::stream_format(cinfo, " Manufacturer filter = %s\n", c_mnfct::ui[custfltr::mnfct[x]]);
- else if (custfltr::other[x] == machine_filter::YEAR)
- util::stream_format(cinfo, " Year filter = %s\n", c_year::ui[custfltr::year[x]]);
- }
- file.puts(cinfo.str().c_str());
- file.close();
+ for (auto & elem : region_lists)
+ if (temp == elem)
+ return (str.substr(found + 1, ends - found - 1));
}
+ return std::string("<none>");
}
-/**************************************************
- MENU CUSTOM SOFTWARE FILTER
-**************************************************/
//-------------------------------------------------
-// ctor / dtor
+// set software device type
//-------------------------------------------------
-menu_swcustom_filter::menu_swcustom_filter(mame_ui_manager &mui, render_container &container, const game_driver *_driver, s_filter &_filter)
- : menu(mui, container)
- , m_added(false)
- , m_filter(_filter)
- , m_driver(_driver)
-{
-}
-menu_swcustom_filter::~menu_swcustom_filter()
+void c_sw_type::set(std::string &str)
{
- reset_topmost(reset_options::SELECT_FIRST);
- save_sw_custom_filters();
+ std::vector<std::string>::iterator const pos(std::lower_bound(ui.begin(), ui.end(), str));
+ if ((ui.end() == pos) || (*pos != str))
+ ui.emplace(pos, str);
}
//-------------------------------------------------
-// handle
+// set software years
//-------------------------------------------------
-void menu_swcustom_filter::handle()
-{
- bool changed = false;
- m_added = false;
-
- // process the menu
- const event *menu_event = process(PROCESS_LR_REPEAT);
- if (menu_event != nullptr && menu_event->itemref != nullptr)
- {
- switch ((uintptr_t)menu_event->itemref)
- {
- case MAIN_FILTER:
- if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
- {
- (menu_event->iptkey == IPT_UI_RIGHT) ? sw_custfltr::main++ : sw_custfltr::main--;
- changed = true;
- }
- break;
-
- case ADD_FILTER:
- if (menu_event->iptkey == IPT_UI_SELECT)
- {
- sw_custfltr::numother++;
- sw_custfltr::other[sw_custfltr::numother] = software_filter::UNAVAILABLE;
- ++sw_custfltr::other[sw_custfltr::numother];
- m_added = true;
- }
- break;
-
- case REMOVE_FILTER:
- if (menu_event->iptkey == IPT_UI_SELECT)
- {
- sw_custfltr::other[sw_custfltr::numother] = software_filter::UNAVAILABLE;
- ++sw_custfltr::other[sw_custfltr::numother];
- sw_custfltr::numother--;
- changed = true;
- }
- break;
- }
-
- if ((uintptr_t)menu_event->itemref >= OTHER_FILTER && (uintptr_t)menu_event->itemref < OTHER_FILTER + MAX_CUST_FILTER)
- {
- int pos = (int)((uintptr_t)menu_event->itemref - OTHER_FILTER);
- if (menu_event->iptkey == IPT_UI_LEFT && sw_custfltr::other[pos] > software_filter::UNAVAILABLE + 1)
- {
- sw_custfltr::other[pos]--;
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_RIGHT && sw_custfltr::other[pos] < software_filter::LAST - 1)
- {
- sw_custfltr::other[pos]++;
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_SELECT)
- {
- std::vector<software_filter::type> types;
- std::vector<std::string> names;
- types.reserve(software_filter::COUNT);
- names.reserve(software_filter::COUNT);
- uint16_t sel(0);
- for (software_filter::type index = software_filter::FIRST; index < software_filter::COUNT; ++index)
- {
- if ((index >= software_filter::UNAVAILABLE) && (index != software_filter::CUSTOM))
- {
- if (sw_custfltr::other[pos] == index)
- sel = types.size();
- types.emplace_back(index);
- names.emplace_back(software_filter::display_name(index));
- }
- }
- menu::stack_push<menu_selector>(ui(), container(), std::move(names), sel, [this, pos, t = std::move(types)] (int selection) { sw_custfltr::other[pos] = t[selection]; reset(reset_options::REMEMBER_REF); });
- }
- }
- else if ((uintptr_t)menu_event->itemref >= YEAR_FILTER && (uintptr_t)menu_event->itemref < YEAR_FILTER + MAX_CUST_FILTER)
- {
- int pos = (int)((uintptr_t)menu_event->itemref - YEAR_FILTER);
- if (menu_event->iptkey == IPT_UI_LEFT && sw_custfltr::year[pos] > 0)
- {
- sw_custfltr::year[pos]--;
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_RIGHT && sw_custfltr::year[pos] < m_filter.year.ui.size() - 1)
- {
- sw_custfltr::year[pos]++;
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_SELECT)
- {
- menu::stack_push<menu_selector>(ui(), container(), std::vector<std::string>(m_filter.year.ui), sw_custfltr::year[pos], [this, pos] (int selection) { sw_custfltr::year[pos] = selection; reset(reset_options::REMEMBER_REF); });
- }
- }
- else if ((uintptr_t)menu_event->itemref >= TYPE_FILTER && (uintptr_t)menu_event->itemref < TYPE_FILTER + MAX_CUST_FILTER)
- {
- int pos = (int)((uintptr_t)menu_event->itemref - TYPE_FILTER);
- if (menu_event->iptkey == IPT_UI_LEFT && sw_custfltr::type[pos] > 0)
- {
- sw_custfltr::type[pos]--;
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_RIGHT && sw_custfltr::type[pos] < m_filter.type.ui.size() - 1)
- {
- sw_custfltr::type[pos]++;
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_SELECT)
- {
- menu::stack_push<menu_selector>(ui(), container(), std::vector<std::string>(m_filter.type.ui), sw_custfltr::type[pos], [this, pos] (int selection) { sw_custfltr::type[pos] = selection; reset(reset_options::REMEMBER_REF); });
- }
- }
- else if ((uintptr_t)menu_event->itemref >= MNFCT_FILTER && (uintptr_t)menu_event->itemref < MNFCT_FILTER + MAX_CUST_FILTER)
- {
- int pos = (int)((uintptr_t)menu_event->itemref - MNFCT_FILTER);
- if (menu_event->iptkey == IPT_UI_LEFT && sw_custfltr::mnfct[pos] > 0)
- {
- sw_custfltr::mnfct[pos]--;
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_RIGHT && sw_custfltr::mnfct[pos] < m_filter.publisher.ui.size() - 1)
- {
- sw_custfltr::mnfct[pos]++;
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_SELECT)
- {
- menu::stack_push<menu_selector>(ui(), container(), std::vector<std::string>(m_filter.publisher.ui), sw_custfltr::mnfct[pos], [this, pos] (int selection) { sw_custfltr::mnfct[pos] = selection; reset(reset_options::REMEMBER_REF); });
- }
- }
- else if ((uintptr_t)menu_event->itemref >= REGION_FILTER && (uintptr_t)menu_event->itemref < REGION_FILTER + MAX_CUST_FILTER)
- {
- int pos = (int)((uintptr_t)menu_event->itemref - REGION_FILTER);
- if (menu_event->iptkey == IPT_UI_LEFT && sw_custfltr::region[pos] > 0)
- {
- sw_custfltr::region[pos]--;
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_RIGHT && sw_custfltr::region[pos] < m_filter.region.ui.size() - 1)
- {
- sw_custfltr::region[pos]++;
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_SELECT)
- {
- menu::stack_push<menu_selector>(ui(), container(), std::vector<std::string>(m_filter.region.ui), sw_custfltr::region[pos], [this, pos] (int selection) { sw_custfltr::region[pos] = selection; reset(reset_options::REMEMBER_REF); });
- }
- }
- else if ((uintptr_t)menu_event->itemref >= LIST_FILTER && (uintptr_t)menu_event->itemref < LIST_FILTER + MAX_CUST_FILTER)
- {
- int pos = (int)((uintptr_t)menu_event->itemref - LIST_FILTER);
- if (menu_event->iptkey == IPT_UI_LEFT && sw_custfltr::list[pos] > 0)
- {
- sw_custfltr::list[pos]--;
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_RIGHT && sw_custfltr::list[pos] < m_filter.swlist.name.size() - 1)
- {
- sw_custfltr::list[pos]++;
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_SELECT)
- {
- menu::stack_push<menu_selector>(ui(), container(), std::vector<std::string>(m_filter.swlist.description), sw_custfltr::list[pos], [this, pos] (int selection) { sw_custfltr::list[pos] = selection; reset(reset_options::REMEMBER_REF); });
- }
- }
- }
-
- if (changed)
- reset(reset_options::REMEMBER_REF);
- else if (m_added)
- reset(reset_options::SELECT_FIRST);
-}
-//-------------------------------------------------
-// populate
-//-------------------------------------------------
-void menu_swcustom_filter::populate(float &customtop, float &custombottom)
+void c_sw_year::set(std::string &str)
{
- // add main filter
- uint32_t arrow_flags = get_arrow_flags<uint16_t>(software_filter::ALL, software_filter::UNAVAILABLE, sw_custfltr::main);
- item_append(_("Main filter"), software_filter::display_name(sw_custfltr::main), arrow_flags, (void *)(uintptr_t)MAIN_FILTER);
-
- // add other filters
- for (int x = 1; x <= sw_custfltr::numother; x++)
- {
- item_append(menu_item_type::SEPARATOR);
-
- // add filter items
- arrow_flags = get_arrow_flags<uint16_t>(software_filter::UNAVAILABLE + 1, software_filter::LAST - 1, sw_custfltr::other[x]);
- item_append(_("Other filter"), software_filter::display_name(sw_custfltr::other[x]), arrow_flags, (void *)(uintptr_t)(OTHER_FILTER + x));
-
- if (m_added)
- selected = item.size() - 2;
-
- // add publisher subitem
- if (sw_custfltr::other[x] == software_filter::PUBLISHERS && m_filter.publisher.ui.size())
- {
- arrow_flags = get_arrow_flags<uint16_t>(0, m_filter.publisher.ui.size() - 1, sw_custfltr::mnfct[x]);
- std::string fbuff(_("^!Publisher"));
- convert_command_glyph(fbuff);
- item_append(fbuff, m_filter.publisher.ui[sw_custfltr::mnfct[x]], arrow_flags, (void *)(uintptr_t)(MNFCT_FILTER + x));
- }
-
- // add year subitem
- else if (sw_custfltr::other[x] == software_filter::YEARS && m_filter.year.ui.size())
- {
- arrow_flags = get_arrow_flags<uint16_t>(0, m_filter.year.ui.size() - 1, sw_custfltr::year[x]);
- std::string fbuff(_("^!Year"));
- convert_command_glyph(fbuff);
- item_append(fbuff, m_filter.year.ui[sw_custfltr::year[x]], arrow_flags, (void *)(uintptr_t)(YEAR_FILTER + x));
- }
-
- // add year subitem
- else if (sw_custfltr::other[x] == software_filter::LIST && m_filter.swlist.name.size())
- {
- arrow_flags = get_arrow_flags<uint16_t>(0, m_filter.swlist.name.size() - 1, sw_custfltr::list[x]);
- std::string fbuff(_("^!Software List"));
- convert_command_glyph(fbuff);
- item_append(fbuff, m_filter.swlist.description[sw_custfltr::list[x]], arrow_flags, (void *)(uintptr_t)(LIST_FILTER + x));
- }
-
- // add device type subitem
- else if (sw_custfltr::other[x] == software_filter::DEVICE_TYPE && m_filter.type.ui.size())
- {
- arrow_flags = get_arrow_flags<uint16_t>(0, m_filter.type.ui.size() - 1, sw_custfltr::type[x]);
- std::string fbuff(_("^!Device type"));
- convert_command_glyph(fbuff);
- item_append(fbuff, m_filter.type.ui[sw_custfltr::type[x]], arrow_flags, (void *)(uintptr_t)(TYPE_FILTER + x));
- }
-
- // add region subitem
- else if (sw_custfltr::other[x] == software_filter::REGION && m_filter.region.ui.size())
- {
- arrow_flags = get_arrow_flags<uint16_t>(0, m_filter.region.ui.size() - 1, sw_custfltr::region[x]);
- std::string fbuff(_("^!Region"));
- convert_command_glyph(fbuff);
- item_append(fbuff, m_filter.region.ui[sw_custfltr::region[x]], arrow_flags, (void *)(uintptr_t)(REGION_FILTER + x));
- }
- }
-
- item_append(menu_item_type::SEPARATOR);
-
- if (sw_custfltr::numother > 0)
- item_append(_("Remove last filter"), "", 0, (void *)(uintptr_t)REMOVE_FILTER);
-
- if (sw_custfltr::numother < MAX_CUST_FILTER - 2)
- item_append(_("Add filter"), "", 0, (void *)(uintptr_t)ADD_FILTER);
-
- item_append(menu_item_type::SEPARATOR);
-
- customtop = ui().get_line_height() + 3.0f * UI_BOX_TB_BORDER;
+ std::vector<std::string>::iterator const pos(std::lower_bound(ui.begin(), ui.end(), str));
+ if ((ui.end() == pos) || (*pos != str))
+ ui.emplace(pos, str);
}
//-------------------------------------------------
-// perform our special rendering
+// set software publishers
//-------------------------------------------------
-void menu_swcustom_filter::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
+
+void c_sw_publisher::set(std::string &str)
{
- char const *const text[] = { _("Select custom filters:") };
- draw_text_box(
- std::begin(text), std::end(text),
- origx1, origx2, origy1 - top, origy1 - UI_BOX_TB_BORDER,
- ui::text_layout::CENTER, ui::text_layout::NEVER, false,
- UI_TEXT_COLOR, UI_GREEN_COLOR, 1.0f);
+ std::string name(getname(str));
+ std::vector<std::string>::iterator const pos(std::lower_bound(ui.begin(), ui.end(), name));
+ if ((ui.end() == pos) || (*pos != str))
+ ui.emplace(pos, std::move(name));
}
-//-------------------------------------------------
-// save custom filters info to file
-//-------------------------------------------------
-
-void menu_swcustom_filter::save_sw_custom_filters()
+std::string c_sw_publisher::getname(std::string const &str) const
{
- // attempt to open the output file
- emu_file file(ui().options().ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
- if (file.open("custom_", m_driver->name, "_filter.ini") == osd_file::error::NONE)
- {
- // generate custom filters info
- std::ostringstream cinfo;
- util::stream_format(cinfo, "Total filters = %d\n", (sw_custfltr::numother + 1));
- util::stream_format(cinfo, "Main filter = %s\n", software_filter::config_name(sw_custfltr::main));
+ size_t found = str.find("(");
- for (int x = 1; x <= sw_custfltr::numother; x++)
- {
- util::stream_format(cinfo, "Other filter = %s\n", software_filter::config_name(sw_custfltr::other[x]));
- if (sw_custfltr::other[x] == software_filter::PUBLISHERS)
- util::stream_format(cinfo, " Manufacturer filter = %s\n", m_filter.publisher.ui[sw_custfltr::mnfct[x]]);
- else if (sw_custfltr::other[x] == software_filter::LIST)
- util::stream_format(cinfo, " Software List filter = %s\n", m_filter.swlist.name[sw_custfltr::list[x]]);
- else if (sw_custfltr::other[x] == software_filter::YEARS)
- util::stream_format(cinfo, " Year filter = %s\n", m_filter.year.ui[sw_custfltr::year[x]]);
- else if (sw_custfltr::other[x] == software_filter::DEVICE_TYPE)
- util::stream_format(cinfo, " Type filter = %s\n", m_filter.type.ui[sw_custfltr::type[x]]);
- else if (sw_custfltr::other[x] == software_filter::REGION)
- util::stream_format(cinfo, " Region filter = %s\n", m_filter.region.ui[sw_custfltr::region[x]]);
- }
- file.puts(cinfo.str().c_str());
- file.close();
- }
+ if (found != std::string::npos)
+ return (str.substr(0, found - 1));
+ else
+ return str;
}
} // namespace ui
diff --git a/src/frontend/mame/ui/custmenu.h b/src/frontend/mame/ui/custmenu.h
index 77a470cf621..09911a50787 100644
--- a/src/frontend/mame/ui/custmenu.h
+++ b/src/frontend/mame/ui/custmenu.h
@@ -14,33 +14,29 @@
#pragma once
-#include "ui/menu.h"
-#include "ui/utils.h"
namespace ui {
+
// Software region
struct c_sw_region
{
std::vector<std::string> ui;
- uint16_t actual;
void set(std::string &str);
- std::string getname(std::string &str);
+ std::string getname(std::string const &str) const;
};
// Software publishers
struct c_sw_publisher
{
std::vector<std::string> ui;
- uint16_t actual;
void set(std::string &str);
- std::string getname(std::string &str);
+ std::string getname(std::string const &str) const;
};
// Software device type
struct c_sw_type
{
std::vector<std::string> ui;
- uint16_t actual;
void set(std::string &str);
};
@@ -49,14 +45,12 @@ struct c_sw_list
{
std::vector<std::string> name;
std::vector<std::string> description;
- uint16_t actual;
};
// Software years
struct c_sw_year
{
std::vector<std::string> ui;
- uint16_t actual;
void set(std::string &str);
};
@@ -69,73 +63,6 @@ struct s_filter
c_sw_list swlist;
};
-//-------------------------------------------------
-// custom software filter menu class
-//-------------------------------------------------
-class menu_swcustom_filter : public menu
-{
-public:
- menu_swcustom_filter(mame_ui_manager &mui, render_container &container, const game_driver *_driver, s_filter &_filter);
- virtual ~menu_swcustom_filter() override;
-
-protected:
- virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
-
-private:
- enum
- {
- MAIN_FILTER = 1,
- ADD_FILTER,
- REMOVE_FILTER,
- MNFCT_FILTER,
- YEAR_FILTER = MNFCT_FILTER + MAX_CUST_FILTER + 1,
- REGION_FILTER = YEAR_FILTER + MAX_CUST_FILTER + 1,
- TYPE_FILTER = REGION_FILTER + MAX_CUST_FILTER + 1,
- LIST_FILTER = TYPE_FILTER + MAX_CUST_FILTER + 1,
- OTHER_FILTER = LIST_FILTER + MAX_CUST_FILTER + 1
- };
-
- virtual void populate(float &customtop, float &custombottom) override;
- virtual void handle() override;
-
- void save_sw_custom_filters();
-
- bool m_added;
- s_filter &m_filter;
- const game_driver *m_driver;
-};
-
-//-------------------------------------------------
-// custom filter menu class
-//-------------------------------------------------
-class menu_custom_filter : public menu
-{
-public:
- menu_custom_filter(mame_ui_manager &mui, render_container &container, bool _single_menu = false);
- virtual ~menu_custom_filter() override;
-
-protected:
- virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
-
-private:
- enum
- {
- MAIN_FILTER = 1,
- ADD_FILTER,
- REMOVE_FILTER,
- MNFCT_FILTER,
- YEAR_FILTER = MNFCT_FILTER + MAX_CUST_FILTER + 1,
- SCREEN_FILTER = YEAR_FILTER + MAX_CUST_FILTER + 1,
- OTHER_FILTER = SCREEN_FILTER + MAX_CUST_FILTER + 1
- };
- virtual void populate(float &customtop, float &custombottom) override;
- virtual void handle() override;
-
- void save_custom_filters();
-
- bool m_single_menu, m_added;
-};
-
} // namespace ui
#endif /* MAME_FRONTEND_UI_CUSTMENU_H */
diff --git a/src/frontend/mame/ui/optsmenu.cpp b/src/frontend/mame/ui/optsmenu.cpp
index ffeca417473..c25f4df62bc 100644
--- a/src/frontend/mame/ui/optsmenu.cpp
+++ b/src/frontend/mame/ui/optsmenu.cpp
@@ -42,7 +42,7 @@ menu_game_options::menu_game_options(mame_ui_manager &mui, render_container &con
menu_game_options::~menu_game_options()
{
- main_filters::actual = machine_filter::type(m_main);
+ main_filters::actual = m_main;
reset_topmost(reset_options::SELECT_FIRST);
ui().save_ui_options();
ui_globals::switch_image = true;
@@ -71,180 +71,163 @@ void menu_game_options::handle()
if (menu_event != nullptr && menu_event->itemref != nullptr)
switch ((uintptr_t)menu_event->itemref)
{
- case FILTER_MENU:
+ case FILTER_MENU:
+ if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
{
- if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
- {
- (menu_event->iptkey == IPT_UI_RIGHT) ? ++m_main : --m_main;
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_SELECT)
- {
- std::vector<std::string> s_sel(machine_filter::COUNT);
- for (unsigned index = 0; index < s_sel.size(); ++index)
- s_sel[index] = machine_filter::display_name(machine_filter::type(index));
-
- menu::stack_push<menu_selector>(
- ui(), container(), std::move(s_sel), m_main,
- [this] (int selection)
- {
- m_main = selection;
- reset(reset_options::REMEMBER_REF);
- });
- }
- break;
+ (menu_event->iptkey == IPT_UI_RIGHT) ? ++m_main : --m_main;
+ changed = true;
}
- case FILE_CATEGORY_FILTER:
+ else if (menu_event->iptkey == IPT_UI_SELECT)
{
- if (menu_event->iptkey == IPT_UI_LEFT)
- {
- mame_machine_manager::instance()->inifile().move_file(-1);
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_RIGHT)
- {
- mame_machine_manager::instance()->inifile().move_file(1);
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_SELECT)
- {
- inifile_manager &ifile = mame_machine_manager::instance()->inifile();
- int total = ifile.total();
- std::vector<std::string> s_sel(total);
- mame_machine_manager::instance()->inifile().set_cat(0);
- for (size_t index = 0; index < total; ++index)
- s_sel[index] = ifile.get_file(index);
-
- menu::stack_push<menu_selector>(
- ui(), container(), std::move(s_sel), ifile.cur_file(),
- [this] (int selection)
- {
- mame_machine_manager::instance()->inifile().set_file(selection);
- mame_machine_manager::instance()->inifile().set_cat(0);
- reset(reset_options::REMEMBER_REF);
- });
- }
- break;
+ std::vector<std::string> s_sel(machine_filter::COUNT);
+ for (unsigned index = 0; index < s_sel.size(); ++index)
+ s_sel[index] = machine_filter::display_name(machine_filter::type(index));
+
+ menu::stack_push<menu_selector>(
+ ui(), container(), std::move(s_sel), m_main,
+ [this] (int selection)
+ {
+ m_main = machine_filter::type(selection);
+ reset(reset_options::REMEMBER_REF);
+ });
}
- case CATEGORY_FILTER:
+ break;
+ case FILE_CATEGORY_FILTER:
+ if (menu_event->iptkey == IPT_UI_LEFT)
{
- if (menu_event->iptkey == IPT_UI_LEFT)
- {
- mame_machine_manager::instance()->inifile().move_cat(-1);
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_RIGHT)
- {
- mame_machine_manager::instance()->inifile().move_cat(1);
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_SELECT)
- {
- inifile_manager &ifile = mame_machine_manager::instance()->inifile();
- int total = ifile.cat_total();
- std::vector<std::string> s_sel(total);
- for (int index = 0; index < total; ++index)
- s_sel[index] = ifile.get_category(index);
-
- menu::stack_push<menu_selector>(
- ui(), container(), std::move(s_sel), ifile.cur_cat(),
- [this] (int selection)
- {
- mame_machine_manager::instance()->inifile().cur_cat() = selection;
- mame_machine_manager::instance()->inifile().set_cat(selection);
- reset(reset_options::REMEMBER_REF);
- });
- }
- break;
+ mame_machine_manager::instance()->inifile().move_file(-1);
+ changed = true;
}
- case MANUFACT_CAT_FILTER:
- if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
- {
- (menu_event->iptkey == IPT_UI_RIGHT) ? c_mnfct::actual++ : c_mnfct::actual--;
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_SELECT)
- {
- menu::stack_push<menu_selector>(
- ui(), container(), std::vector<std::string>(c_mnfct::ui), c_mnfct::actual,
- [this] (int selection)
- {
- c_mnfct::actual = selection;
- reset(reset_options::REMEMBER_REF);
- });
- }
-
- break;
- case YEAR_CAT_FILTER:
- if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
- {
- (menu_event->iptkey == IPT_UI_RIGHT) ? c_year::actual++ : c_year::actual--;
- changed = true;
- }
- else if (menu_event->iptkey == IPT_UI_SELECT)
- {
- menu::stack_push<menu_selector>(
- ui(), container(), std::vector<std::string>(c_year::ui), c_year::actual,
- [this] (int selection)
+ else if (menu_event->iptkey == IPT_UI_RIGHT)
+ {
+ mame_machine_manager::instance()->inifile().move_file(1);
+ changed = true;
+ }
+ else if (menu_event->iptkey == IPT_UI_SELECT)
+ {
+ inifile_manager &ifile = mame_machine_manager::instance()->inifile();
+ int total = ifile.total();
+ std::vector<std::string> s_sel(total);
+ mame_machine_manager::instance()->inifile().set_cat(0);
+ for (size_t index = 0; index < total; ++index)
+ s_sel[index] = ifile.get_file(index);
+
+ menu::stack_push<menu_selector>(
+ ui(), container(), std::move(s_sel), ifile.cur_file(),
+ [this] (int selection)
+ {
+ mame_machine_manager::instance()->inifile().set_file(selection);
+ mame_machine_manager::instance()->inifile().set_cat(0);
+ reset(reset_options::REMEMBER_REF);
+ });
+ }
+ break;
+ case CATEGORY_FILTER:
+ if (menu_event->iptkey == IPT_UI_LEFT)
+ {
+ mame_machine_manager::instance()->inifile().move_cat(-1);
+ changed = true;
+ }
+ else if (menu_event->iptkey == IPT_UI_RIGHT)
+ {
+ mame_machine_manager::instance()->inifile().move_cat(1);
+ changed = true;
+ }
+ else if (menu_event->iptkey == IPT_UI_SELECT)
+ {
+ inifile_manager &ifile = mame_machine_manager::instance()->inifile();
+ int total = ifile.cat_total();
+ std::vector<std::string> s_sel(total);
+ for (int index = 0; index < total; ++index)
+ s_sel[index] = ifile.get_category(index);
+
+ menu::stack_push<menu_selector>(
+ ui(), container(), std::move(s_sel), ifile.cur_cat(),
+ [this] (int selection)
+ {
+ mame_machine_manager::instance()->inifile().cur_cat() = selection;
+ mame_machine_manager::instance()->inifile().set_cat(selection);
+ reset(reset_options::REMEMBER_REF);
+ });
+ }
+ break;
+ case FILTER_ADJUST:
+ if (menu_event->iptkey == IPT_UI_LEFT)
+ {
+ changed = main_filters::filters.find(m_main)->second->adjust_left();
+ }
+ else if (menu_event->iptkey == IPT_UI_RIGHT)
+ {
+ changed = main_filters::filters.find(m_main)->second->adjust_right();
+ }
+ else if (menu_event->iptkey == IPT_UI_SELECT)
+ {
+ main_filters::filters.find(m_main)->second->show_ui(
+ ui(),
+ container(),
+ [this] (machine_filter &filter)
+ {
+ if (machine_filter::CUSTOM == filter.get_type())
{
- c_year::actual = selection;
- reset(reset_options::REMEMBER_REF);
- });
- }
-
- break;
- case CONF_DIR:
- if (menu_event->iptkey == IPT_UI_SELECT)
- menu::stack_push<menu_directory>(ui(), container());
- break;
- case MISC_MENU:
- if (menu_event->iptkey == IPT_UI_SELECT)
- {
- menu::stack_push<submenu>(ui(), container(), submenu::misc_options);
- ui_globals::reset = true;
- }
- break;
- case SOUND_MENU:
- if (menu_event->iptkey == IPT_UI_SELECT)
- {
- menu::stack_push<menu_sound_options>(ui(), container());
- ui_globals::reset = true;
- }
- break;
- case DISPLAY_MENU:
- if (menu_event->iptkey == IPT_UI_SELECT)
- {
- menu::stack_push<submenu>(ui(), container(), submenu::video_options);
- ui_globals::reset = true;
- }
- break;
- case CUSTOM_MENU:
- if (menu_event->iptkey == IPT_UI_SELECT)
- menu::stack_push<menu_custom_ui>(ui(), container());
- break;
- case CONTROLLER_MENU:
- if (menu_event->iptkey == IPT_UI_SELECT)
- menu::stack_push<submenu>(ui(), container(), submenu::control_options);
- break;
- case CGI_MENU:
- if (menu_event->iptkey == IPT_UI_SELECT)
- menu::stack_push<menu_input_groups>(ui(), container());
- break;
- case CUSTOM_FILTER:
- if (menu_event->iptkey == IPT_UI_SELECT)
- menu::stack_push<menu_custom_filter>(ui(), container());
- break;
- case ADVANCED_MENU:
- if (menu_event->iptkey == IPT_UI_SELECT)
- {
- menu::stack_push<submenu>(ui(), container(), submenu::advanced_options);
- ui_globals::reset = true;
- }
- break;
- case SAVE_CONFIG:
- if (menu_event->iptkey == IPT_UI_SELECT)
- ui().save_main_option();
- break;
+ emu_file file(ui().options().ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
+ if (file.open("custom_", emulator_info::get_configname(), "_filter.ini") == osd_file::error::NONE)
+ {
+ filter.save_ini(file, 0);
+ file.close();
+ }
+ }
+ reset_options::REMEMBER_REF;
+ });
+ }
+ break;
+ case CONF_DIR:
+ if (menu_event->iptkey == IPT_UI_SELECT)
+ menu::stack_push<menu_directory>(ui(), container());
+ break;
+ case MISC_MENU:
+ if (menu_event->iptkey == IPT_UI_SELECT)
+ {
+ menu::stack_push<submenu>(ui(), container(), submenu::misc_options);
+ ui_globals::reset = true;
+ }
+ break;
+ case SOUND_MENU:
+ if (menu_event->iptkey == IPT_UI_SELECT)
+ {
+ menu::stack_push<menu_sound_options>(ui(), container());
+ ui_globals::reset = true;
+ }
+ break;
+ case DISPLAY_MENU:
+ if (menu_event->iptkey == IPT_UI_SELECT)
+ {
+ menu::stack_push<submenu>(ui(), container(), submenu::video_options);
+ ui_globals::reset = true;
+ }
+ break;
+ case CUSTOM_MENU:
+ if (menu_event->iptkey == IPT_UI_SELECT)
+ menu::stack_push<menu_custom_ui>(ui(), container());
+ break;
+ case CONTROLLER_MENU:
+ if (menu_event->iptkey == IPT_UI_SELECT)
+ menu::stack_push<submenu>(ui(), container(), submenu::control_options);
+ break;
+ case CGI_MENU:
+ if (menu_event->iptkey == IPT_UI_SELECT)
+ menu::stack_push<menu_input_groups>(ui(), container());
+ break;
+ case ADVANCED_MENU:
+ if (menu_event->iptkey == IPT_UI_SELECT)
+ {
+ menu::stack_push<submenu>(ui(), container(), submenu::advanced_options);
+ ui_globals::reset = true;
+ }
+ break;
+ case SAVE_CONFIG:
+ if (menu_event->iptkey == IPT_UI_SELECT)
+ ui().save_main_option();
+ break;
}
if (changed)
@@ -264,45 +247,38 @@ void menu_game_options::populate(float &customtop, float &custombottom)
// add filter item
uint32_t arrow_flags = get_arrow_flags<uint16_t>(machine_filter::FIRST, machine_filter::LAST, m_main);
- item_append(_("Filter"), machine_filter::display_name(machine_filter::type(m_main)), arrow_flags, (void *)(uintptr_t)FILTER_MENU);
-
- // add category subitem
- if (m_main == machine_filter::CATEGORY && mame_machine_manager::instance()->inifile().total() > 0)
+ if (machine_filter::CATEGORY == m_main)
{
- inifile_manager &inif = mame_machine_manager::instance()->inifile();
+ item_append(_("Filter"), machine_filter::display_name(m_main), arrow_flags, (void *)(uintptr_t)FILTER_MENU);
+ if (mame_machine_manager::instance()->inifile().total() > 0)
+ {
+ inifile_manager &inif = mame_machine_manager::instance()->inifile();
- arrow_flags = get_arrow_flags(uint16_t(0), uint16_t(inif.total() - 1), inif.cur_file());
- fbuff = _(" ^!File");
- convert_command_glyph(fbuff);
- item_append(fbuff, inif.get_file(), arrow_flags, (void *)(uintptr_t)FILE_CATEGORY_FILTER);
+ arrow_flags = get_arrow_flags(uint16_t(0), uint16_t(inif.total() - 1), inif.cur_file());
+ fbuff = _(" ^!File");
+ convert_command_glyph(fbuff);
+ item_append(fbuff, inif.get_file(), arrow_flags, (void *)(uintptr_t)FILE_CATEGORY_FILTER);
- arrow_flags = get_arrow_flags(uint16_t(0), uint16_t(inif.cat_total() - 1), inif.cur_cat());
- fbuff = _(" ^!Category");
- convert_command_glyph(fbuff);
- item_append(fbuff, inif.get_category(), arrow_flags, (void *)(uintptr_t)CATEGORY_FILTER);
- }
- // add manufacturer subitem
- else if (m_main == machine_filter::MANUFACTURER && c_mnfct::ui.size() > 0)
- {
- arrow_flags = get_arrow_flags(uint16_t(0), uint16_t(c_mnfct::ui.size() - 1), c_mnfct::actual);
- fbuff = _("^!Manufacturer");
- convert_command_glyph(fbuff);
- item_append(fbuff, c_mnfct::ui[c_mnfct::actual], arrow_flags, (void *)(uintptr_t)MANUFACT_CAT_FILTER);
- }
- // add year subitem
- else if (m_main == machine_filter::YEAR && c_year::ui.size() > 0)
- {
- arrow_flags = get_arrow_flags(uint16_t(0), uint16_t(c_year::ui.size() - 1), c_year::actual);
- fbuff.assign(_("^!Year"));
- convert_command_glyph(fbuff);
- item_append(fbuff, c_year::ui[c_year::actual], arrow_flags, (void *)(uintptr_t)YEAR_CAT_FILTER);
+ arrow_flags = get_arrow_flags(uint16_t(0), uint16_t(inif.cat_total() - 1), inif.cur_cat());
+ fbuff = _(" ^!Category");
+ convert_command_glyph(fbuff);
+ item_append(fbuff, inif.get_category(), arrow_flags, (void *)(uintptr_t)CATEGORY_FILTER);
+ }
}
- // add custom subitem
- else if (m_main == machine_filter::CUSTOM)
+ else
{
- fbuff = _("^!Setup custom filter");
- convert_command_glyph(fbuff);
- item_append(fbuff, "", 0, (void *)(uintptr_t)CUSTOM_FILTER);
+ auto active_filter(main_filters::filters.find(m_main));
+ if (main_filters::filters.end() == active_filter)
+ active_filter = main_filters::filters.emplace(m_main, machine_filter::create(m_main)).first;
+ item_append(_("Filter"), active_filter->second->display_name(), arrow_flags, (void *)(uintptr_t)FILTER_MENU);
+
+ // add subitem if the filter wants it
+ if (active_filter->second->wants_adjuster())
+ {
+ std::string name("^!");
+ convert_command_glyph(name);
+ item_append(name, active_filter->second->adjust_text(), active_filter->second->arrow_flags(), (void *)(FILTER_ADJUST));
+ }
}
item_append(menu_item_type::SEPARATOR);
diff --git a/src/frontend/mame/ui/optsmenu.h b/src/frontend/mame/ui/optsmenu.h
index 769d0aa9ecf..2ef9d2969c8 100644
--- a/src/frontend/mame/ui/optsmenu.h
+++ b/src/frontend/mame/ui/optsmenu.h
@@ -7,13 +7,14 @@
UI main options menu manager.
***************************************************************************/
-
-#pragma once
-
#ifndef MAME_FRONTEND_UI_OPTSMENU_H
#define MAME_FRONTEND_UI_OPTSMENU_H
+#pragma once
+
#include "ui/menu.h"
+#include "ui/utils.h"
+
namespace ui {
class menu_game_options : public menu
@@ -30,8 +31,7 @@ private:
{
FILTER_MENU = 1,
FILE_CATEGORY_FILTER,
- MANUFACT_CAT_FILTER,
- YEAR_CAT_FILTER,
+ FILTER_ADJUST,
CATEGORY_FILTER,
CONF_DIR,
DISPLAY_MENU,
@@ -42,14 +42,13 @@ private:
ADVANCED_MENU,
SAVE_OPTIONS,
CGI_MENU,
- CUSTOM_FILTER,
SAVE_CONFIG
};
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle() override;
- uint16_t m_main;
+ machine_filter::type m_main;
};
} // namespace ui
diff --git a/src/frontend/mame/ui/selgame.cpp b/src/frontend/mame/ui/selgame.cpp
index aa3d1580e6f..1e504bb858f 100644
--- a/src/frontend/mame/ui/selgame.cpp
+++ b/src/frontend/mame/ui/selgame.cpp
@@ -74,49 +74,40 @@ menu_select_game::menu_select_game(mame_ui_manager &mui, render_container &conta
if (!load_available_machines())
build_available_list();
- // load custom filter
- load_custom_filters();
-
if (first_start)
{
reselect_last::set_driver(moptions.last_used_machine());
+
std::string tmp(moptions.last_used_filter());
- std::size_t found = tmp.find_first_of(",");
+ std::size_t const found = tmp.find_first_of(",");
+ std::string fake_ini;
if (found == std::string::npos)
- last_filter = tmp;
+ {
+ fake_ini = util::string_format("%s = 1\n", tmp);
+ }
else
{
- last_filter = tmp.substr(0, found);
- sub_filter = tmp.substr(found + 1);
+ std::string const sub_filter(tmp.substr(found + 1));
+ tmp.resize(found);
+ fake_ini = util::string_format("%s = %s\n", tmp, sub_filter);
}
- main_filters::actual = machine_filter::ALL;
- for (machine_filter::type ind = machine_filter::FIRST; ind < machine_filter::COUNT; ++ind)
+ emu_file file(ui().options().ui_path(), OPEN_FLAG_READ);
+ if (file.open_ram(fake_ini.c_str(), fake_ini.size()) == osd_file::error::NONE)
{
- if (last_filter == machine_filter::config_name(ind))
+ machine_filter::ptr flt(machine_filter::create(file));
+ if (flt)
{
- main_filters::actual = ind;
- break;
+ main_filters::actual = flt->get_type();
+ main_filters::filters.emplace(main_filters::actual, std::move(flt));
}
+ file.close();
}
-
- if (main_filters::actual == machine_filter::CATEGORY)
- main_filters::actual = machine_filter::ALL;
- else if (main_filters::actual == machine_filter::MANUFACTURER)
- {
- for (size_t id = 0; id < c_mnfct::ui.size(); ++id)
- if (sub_filter == c_mnfct::ui[id])
- c_mnfct::actual = id;
- }
- else if (main_filters::actual == machine_filter::YEAR)
- {
- for (size_t id = 0; id < c_year::ui.size(); ++id)
- if (sub_filter == c_year::ui[id])
- c_year::actual = id;
- }
- first_start = false;
}
+ // do this after processing the last used filter setting so it overwrites the placeholder
+ load_custom_filters();
+
if (!moptions.remember_last())
reselect_last::reset();
@@ -151,11 +142,17 @@ menu_select_game::~menu_select_game()
else if (swinfo && m_prev_selected)
last_driver = reinterpret_cast<ui_software_info *>(m_prev_selected)->shortname;
- std::string filter(machine_filter::config_name(main_filters::actual));
- if (main_filters::actual == machine_filter::MANUFACTURER)
- filter.append(",").append(c_mnfct::ui[c_mnfct::actual]);
- else if (main_filters::actual == machine_filter::YEAR)
- filter.append(",").append(c_year::ui[c_year::actual]);
+ std::string filter;
+ auto const active_filter(main_filters::filters.find(main_filters::actual));
+ if (main_filters::filters.end() != active_filter)
+ {
+ char const *val(active_filter->second->filter_text());
+ filter = val ? util::string_format("%s,%s", active_filter->second->config_name(), val) : active_filter->second->config_name();
+ }
+ else
+ {
+ filter = machine_filter::config_name(main_filters::actual);
+ }
ui_options &mopt = ui().options();
mopt.set_value(OPTION_LAST_USED_FILTER, filter.c_str(), OPTION_PRIORITY_CMDLINE);
@@ -423,43 +420,38 @@ void menu_select_game::handle()
if (check_filter)
{
m_search.clear();
- if (l_hover == machine_filter::CATEGORY)
+ switch (l_hover)
{
+ case machine_filter::CATEGORY:
+ // FIXME: this should be unified with the other filters
main_filters::actual = machine_filter::type(l_hover);
menu::stack_push<menu_game_options>(ui(), container());
- }
- else if (l_hover == machine_filter::CUSTOM)
- {
- main_filters::actual = machine_filter::type(l_hover);
- menu::stack_push<menu_custom_filter>(ui(), container(), true);
- }
- else if (l_hover == machine_filter::MANUFACTURER)
- {
- menu::stack_push<menu_selector>(
- ui(), container(), std::vector<std::string>(c_mnfct::ui), c_mnfct::actual,
- [this] (int selection)
- {
- c_mnfct::actual = selection;
- main_filters::actual = machine_filter::type(l_hover);
- reset(reset_options::SELECT_FIRST);
- });
- }
- else if (l_hover == machine_filter::YEAR)
- {
- menu::stack_push<menu_selector>(
- ui(), container(), std::vector<std::string>(c_year::ui), c_year::actual,
- [this] (int selection)
- {
- c_year::actual = selection;
- main_filters::actual = machine_filter::type(l_hover);
- reset(reset_options::SELECT_FIRST);
- });
- }
- else
- {
+ break;
+ default:
if (l_hover >= machine_filter::ALL)
- main_filters::actual = machine_filter::type(l_hover);
- reset(reset_options::SELECT_FIRST);
+ {
+ auto it(main_filters::filters.find(machine_filter::type(l_hover)));
+ if (main_filters::filters.end() == it)
+ it = main_filters::filters.emplace(machine_filter::type(l_hover), machine_filter::create(machine_filter::type(l_hover))).first;
+ it->second->show_ui(
+ ui(),
+ container(),
+ [this] (machine_filter &filter)
+ {
+ machine_filter::type const new_type(filter.get_type());
+ if (machine_filter::CUSTOM == new_type)
+ {
+ emu_file file(ui().options().ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
+ if (file.open("custom_", emulator_info::get_configname(), "_filter.ini") == osd_file::error::NONE)
+ {
+ filter.save_ini(file, 0);
+ file.close();
+ }
+ }
+ main_filters::actual = new_type;
+ reset(reset_options::SELECT_FIRST);
+ });
+ }
}
}
}
@@ -479,7 +471,9 @@ void menu_select_game::populate(float &customtop, float &custombottom)
{
// if search is not empty, find approximate matches
if (!m_search.empty())
+ {
populate_search();
+ }
else
{
// reset search string
@@ -489,21 +483,27 @@ void menu_select_game::populate(float &customtop, float &custombottom)
// if filter is set on category, build category list
switch (main_filters::actual)
{
- case machine_filter::CATEGORY:
- build_category();
+ case machine_filter::ALL:
+ m_displaylist = m_sortedlist;
break;
- case machine_filter::MANUFACTURER:
- build_list(c_mnfct::ui[c_mnfct::actual].c_str());
+ case machine_filter::AVAILABLE:
+ m_displaylist = m_availsortedlist;
break;
- case machine_filter::YEAR:
- build_list(c_year::ui[c_year::actual].c_str());
+ case machine_filter::UNAVAILABLE:
+ m_displaylist = m_unavailsortedlist;
break;
- case machine_filter::CUSTOM:
- build_custom();
+ case machine_filter::CATEGORY:
+ build_category();
break;
default:
- build_list();
- break;
+ {
+ auto const it(main_filters::filters.find(main_filters::actual));
+ std::copy_if(
+ m_sortedlist.begin(),
+ m_sortedlist.end(),
+ std::back_inserter(m_displaylist),
+ [&flt = *it->second] (game_driver const *drv) { return flt.apply(*drv); });
+ }
}
// iterate over entries
@@ -907,139 +907,6 @@ void menu_select_game::inkey_special(const event *menu_event)
//-------------------------------------------------
-// build list
-//-------------------------------------------------
-
-void menu_select_game::build_list(const char *filter_text, int filter, bool bioscheck, std::vector<const game_driver *> s_drivers)
-{
- if (s_drivers.empty())
- {
- filter = main_filters::actual;
- if (filter == machine_filter::AVAILABLE)
- s_drivers = m_availsortedlist;
- else if (filter == machine_filter::UNAVAILABLE)
- s_drivers = m_unavailsortedlist;
- else
- s_drivers = m_sortedlist;
- }
-
- for (auto & s_driver : s_drivers)
- {
- if (!bioscheck && filter != machine_filter::BIOS && (s_driver->flags & machine_flags::IS_BIOS_ROOT) != 0)
- continue;
-
- switch (filter)
- {
- case machine_filter::ALL:
- case machine_filter::AVAILABLE:
- case machine_filter::UNAVAILABLE:
- m_displaylist.push_back(s_driver);
- break;
-
- case machine_filter::WORKING:
- if (!(s_driver->flags & machine_flags::NOT_WORKING))
- m_displaylist.push_back(s_driver);
- break;
-
- case machine_filter::NOT_MECHANICAL:
- if (!(s_driver->flags & machine_flags::MECHANICAL))
- m_displaylist.push_back(s_driver);
- break;
-
- case machine_filter::BIOS:
- if (s_driver->flags & machine_flags::IS_BIOS_ROOT)
- m_displaylist.push_back(s_driver);
- break;
-
- case machine_filter::PARENT:
- case machine_filter::CLONES:
- {
- bool cloneof = strcmp(s_driver->parent, "0");
- if (cloneof)
- {
- auto cx = driver_list::find(s_driver->parent);
- if (cx != -1 && ((driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT) != 0))
- cloneof = false;
- }
-
- if (filter == machine_filter::CLONES && cloneof)
- m_displaylist.push_back(s_driver);
- else if (filter == machine_filter::PARENT && !cloneof)
- m_displaylist.push_back(s_driver);
- }
- break;
- case machine_filter::NOT_WORKING:
- if (s_driver->flags & machine_flags::NOT_WORKING)
- m_displaylist.push_back(s_driver);
- break;
-
- case machine_filter::MECHANICAL:
- if (s_driver->flags & machine_flags::MECHANICAL)
- m_displaylist.push_back(s_driver);
- break;
-
- case machine_filter::SAVE:
- if (s_driver->flags & machine_flags::SUPPORTS_SAVE)
- m_displaylist.push_back(s_driver);
- break;
-
- case machine_filter::NOSAVE:
- if (!(s_driver->flags & machine_flags::SUPPORTS_SAVE))
- m_displaylist.push_back(s_driver);
- break;
-
- case machine_filter::YEAR:
- if (!core_stricmp(filter_text, s_driver->year))
- m_displaylist.push_back(s_driver);
- break;
-
- case machine_filter::VERTICAL:
- if (s_driver->flags & ORIENTATION_SWAP_XY)
- m_displaylist.push_back(s_driver);
- break;
-
- case machine_filter::HORIZONTAL:
- if (!(s_driver->flags & ORIENTATION_SWAP_XY))
- m_displaylist.push_back(s_driver);
- break;
-
- case machine_filter::MANUFACTURER:
- {
- std::string name = c_mnfct::getname(s_driver->manufacturer);
- if (!core_stricmp(filter_text, name.c_str()))
- m_displaylist.push_back(s_driver);
- }
- break;
- case machine_filter::CHD:
- {
- auto entries = rom_build_entries(s_driver->rom);
- for (const rom_entry &rom : entries)
- if (ROMENTRY_ISREGION(&rom) && ROMREGION_ISDISKDATA(&rom))
- {
- m_displaylist.push_back(s_driver);
- break;
- }
- }
- break;
- case machine_filter::NOCHD:
- {
- auto entries = rom_build_entries(s_driver->rom);
- bool found = false;
- for (const rom_entry &rom : entries)
- if (ROMENTRY_ISREGION(&rom) && ROMREGION_ISDISKDATA(&rom))
- {
- found = true;
- break;
- }
- if (!found)
- m_displaylist.push_back(s_driver);
- }
- break;
- }
- }
-}
-
-//-------------------------------------------------
// change what's displayed in the info box
//-------------------------------------------------
@@ -1075,55 +942,6 @@ void menu_select_game::change_info_pane(int delta)
}
//-------------------------------------------------
-// build custom display list
-//-------------------------------------------------
-
-void menu_select_game::build_custom()
-{
- std::vector<const game_driver *> s_drivers;
- bool bioscheck = false;
-
- if (custfltr::main == machine_filter::AVAILABLE)
- s_drivers = m_availsortedlist;
- else if (custfltr::main == machine_filter::UNAVAILABLE)
- s_drivers = m_unavailsortedlist;
- else
- s_drivers = m_sortedlist;
-
- for (auto & elem : s_drivers)
- {
- m_displaylist.push_back(elem);
- }
-
- for (int count = 1; count <= custfltr::numother; ++count)
- {
- int filter = custfltr::other[count];
- if (filter == machine_filter::BIOS)
- bioscheck = true;
- }
-
- for (int count = 1; count <= custfltr::numother; ++count)
- {
- int filter = custfltr::other[count];
- s_drivers = m_displaylist;
- m_displaylist.clear();
-
- switch (filter)
- {
- case machine_filter::YEAR:
- build_list(c_year::ui[custfltr::year[count]].c_str(), filter, bioscheck, s_drivers);
- break;
- case machine_filter::MANUFACTURER:
- build_list(c_mnfct::ui[custfltr::mnfct[count]].c_str(), filter, bioscheck, s_drivers);
- break;
- default:
- build_list(nullptr, filter, bioscheck, s_drivers);
- break;
- }
- }
-}
-
-//-------------------------------------------------
// build category list
//-------------------------------------------------
@@ -1378,24 +1196,27 @@ void menu_select_game::init_sorted_list()
return;
// generate full list
+ std::unordered_set<std::string> manufacturers, years;
for (int x = 0; x < driver_list::total(); ++x)
{
- const game_driver *driver = &driver_list::driver(x);
- if (driver == &GAME_NAME(___empty))
- continue;
- if (driver->flags & machine_flags::IS_BIOS_ROOT)
- m_isabios++;
-
- m_sortedlist.push_back(driver);
- c_mnfct::set(driver->manufacturer);
- c_year::set(driver->year);
- }
+ game_driver const &driver(driver_list::driver(x));
+ if (&driver != &GAME_NAME(___empty))
+ {
+ if (driver.flags & machine_flags::IS_BIOS_ROOT)
+ m_isabios++;
- for (auto & e : c_mnfct::uimap)
- c_mnfct::ui.emplace_back(e.first);
+ m_sortedlist.push_back(&driver);
+ manufacturers.emplace(c_mnfct::getname(driver.manufacturer));
+ years.emplace(driver.year);
+ }
+ }
// sort manufacturers - years and driver
- std::stable_sort(c_mnfct::ui.begin(), c_mnfct::ui.end());
+ for (auto it = manufacturers.begin(); manufacturers.end() != it; it = manufacturers.erase(it))
+ c_mnfct::ui.emplace_back(*it);
+ std::sort(c_mnfct::ui.begin(), c_mnfct::ui.end(), [] (std::string const &x, std::string const &y) { return 0 > core_stricmp(x.c_str(), y.c_str()); });
+ for (auto it = years.begin(); years.end() != it; it = years.erase(it))
+ c_year::ui.emplace_back(*it);
std::stable_sort(c_year::ui.begin(), c_year::ui.end());
std::stable_sort(m_sortedlist.begin(), m_sortedlist.end(), sorted_game_list);
}
@@ -1457,60 +1278,12 @@ bool menu_select_game::load_available_machines()
void menu_select_game::load_custom_filters()
{
- // attempt to open the output file
emu_file file(ui().options().ui_path(), OPEN_FLAG_READ);
if (file.open("custom_", emulator_info::get_configname(), "_filter.ini") == osd_file::error::NONE)
{
- char buffer[MAX_CHAR_INFO];
-
- // get number of filters
- file.gets(buffer, MAX_CHAR_INFO);
- char *pb = strchr(buffer, '=');
- custfltr::numother = atoi(++pb) - 1;
-
- // get main filter
- file.gets(buffer, MAX_CHAR_INFO);
- pb = strchr(buffer, '=') + 2;
-
- for (machine_filter::type y = machine_filter::FIRST; y < machine_filter::COUNT; ++y)
- {
- char const *const name(machine_filter::config_name(y));
- if (!strncmp(pb, name, strlen(name)))
- {
- custfltr::main = y;
- break;
- }
- }
-
- for (int x = 1; x <= custfltr::numother; ++x)
- {
- file.gets(buffer, MAX_CHAR_INFO);
- char *cb = strchr(buffer, '=') + 2;
- for (machine_filter::type y = machine_filter::FIRST; y < machine_filter::COUNT; ++y)
- {
- char const *const name(machine_filter::config_name(y));
- if (!strncmp(cb, name, strlen(name)))
- {
- custfltr::other[x] = y;
- if (y == machine_filter::MANUFACTURER)
- {
- file.gets(buffer, MAX_CHAR_INFO);
- char *ab = strchr(buffer, '=') + 2;
- for (size_t z = 0; z < c_mnfct::ui.size(); ++z)
- if (!strncmp(ab, c_mnfct::ui[z].c_str(), c_mnfct::ui[z].length()))
- custfltr::mnfct[x] = z;
- }
- else if (y == machine_filter::YEAR)
- {
- file.gets(buffer, MAX_CHAR_INFO);
- char *db = strchr(buffer, '=') + 2;
- for (size_t z = 0; z < c_year::ui.size(); ++z)
- if (!strncmp(db, c_year::ui[z].c_str(), c_year::ui[z].length()))
- custfltr::year[x] = z;
- }
- }
- }
- }
+ machine_filter::ptr flt(machine_filter::create(file));
+ if (flt)
+ main_filters::filters[flt->get_type()] = std::move(flt); // not emplace/insert - could replace bogus filter from ui.ini line
file.close();
}
@@ -1527,13 +1300,13 @@ float menu_select_game::draw_left_panel(float x1, float y1, float x2, float y2)
if (ui_globals::panels_status == SHOW_PANELS || ui_globals::panels_status == HIDE_RIGHT_PANEL)
{
+ auto const active_filter(main_filters::filters.find(main_filters::actual));
float origy1 = y1;
float origy2 = y2;
float text_size = ui().options().infos_size();
float line_height_max = line_height * text_size;
float left_width = 0.0f;
int line_count = machine_filter::COUNT;
- int afilter = main_filters::actual;
int phover = HOVER_FILTER_FIRST;
float sc = y2 - y1 - (2.0f * UI_BOX_TB_BORDER);
@@ -1544,7 +1317,9 @@ float menu_select_game::draw_left_panel(float x1, float y1, float x2, float y2)
line_height_max = line_height * text_size;
}
- float text_sign = ui().get_string_width("_# ", text_size);
+ std::string tmp("_# ");
+ convert_command_glyph(tmp);
+ float text_sign = ui().get_string_width(tmp.c_str(), text_size);
for (machine_filter::type x = machine_filter::FIRST; x < machine_filter::COUNT; ++x)
{
float total_width;
@@ -1569,7 +1344,21 @@ float menu_select_game::draw_left_panel(float x1, float y1, float x2, float y2)
for (machine_filter::type filter = machine_filter::FIRST; filter < machine_filter::COUNT; ++filter)
{
- std::string str(machine_filter::display_name(filter));
+ std::string str;
+ if (main_filters::filters.end() != active_filter)
+ {
+ str = active_filter->second->adorned_display_name(filter);
+ }
+ else
+ {
+ if (main_filters::actual == filter)
+ {
+ str = std::string("_> ") + str;
+ convert_command_glyph(str);
+ }
+ str.append(machine_filter::display_name(filter));
+ }
+
rgb_t bgcolor = UI_TEXT_BG_COLOR;
rgb_t fgcolor = UI_TEXT_COLOR;
@@ -1589,35 +1378,7 @@ float menu_select_game::draw_left_panel(float x1, float y1, float x2, float y2)
hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1));
}
- float x1t = x1 + text_sign;
- if (afilter == machine_filter::CUSTOM)
- {
- if (filter == custfltr::main)
- {
- str = std::string("@custom1 ") + str;
- x1t -= text_sign;
- }
- else
- {
- for (int count = 1; count <= custfltr::numother; ++count)
- {
- int cfilter = custfltr::other[count];
- if (cfilter == filter)
- {
- str = string_format("@custom%d %s", count + 1, str);
- x1t -= text_sign;
- break;
- }
- }
- }
- convert_command_glyph(str);
- }
- else if (filter == main_filters::actual)
- {
- str = std::string("_> ") + str;
- x1t -= text_sign;
- convert_command_glyph(str);
- }
+ float const x1t = x1 + ((str == machine_filter::display_name(filter)) ? text_sign : 0.0f);
ui().draw_text_full(container(), str.c_str(), x1t, y1, x2 - x1, ui::text_layout::LEFT, ui::text_layout::NEVER,
mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr, text_size);
@@ -1705,33 +1466,28 @@ void menu_select_game::make_topbox_text(std::string &line0, std::string &line1,
(driver_list::total() - 1),
m_isabios);
- std::string filtered;
- if (main_filters::actual == machine_filter::CATEGORY && inifile.total() > 0)
+ if (isfavorite())
{
- filtered = string_format(_("%1$s (%2$s - %3$s) - "),
- machine_filter::display_name(main_filters::actual),
- inifile.get_file(),
- inifile.get_category());
+ line1.clear();
}
- else if (main_filters::actual == machine_filter::MANUFACTURER)
+ if (main_filters::actual == machine_filter::CATEGORY && inifile.total() > 0)
{
- filtered = string_format(_("%1$s (%2$s) - "),
+ line1 = string_format(_("%1$s (%2$s - %3$s) - Search: %4$s_"),
machine_filter::display_name(main_filters::actual),
- c_mnfct::ui[c_mnfct::actual]);
+ inifile.get_file(),
+ inifile.get_category(),
+ m_search);
}
- else if (main_filters::actual == machine_filter::YEAR)
+ else
{
- filtered = string_format(_("%1$s (%2$s) - "),
- machine_filter::display_name(main_filters::actual),
- c_year::ui[c_year::actual]);
+ auto const it(main_filters::filters.find(main_filters::actual));
+ char const *const filter((main_filters::filters.end() != it) ? it->second->filter_text() : nullptr);
+ if (filter)
+ line1 = string_format(_("%1$s: %2$s - Search: %3$s_"), it->second->display_name(), filter, m_search);
+ else
+ line1 = string_format(_("Search: %1$s_"), m_search);
}
- // display the current typeahead
- if (isfavorite())
- line1.clear();
- else
- line1 = string_format(_("%1$s Search: %2$s_"), filtered, m_search);
-
line2.clear();
}
diff --git a/src/frontend/mame/ui/selgame.h b/src/frontend/mame/ui/selgame.h
index fc8801bbab5..344713188ff 100644
--- a/src/frontend/mame/ui/selgame.h
+++ b/src/frontend/mame/ui/selgame.h
@@ -69,10 +69,8 @@ private:
// internal methods
void change_info_pane(int delta);
- void build_custom();
void build_category();
void build_available_list();
- void build_list(const char *filter_text = nullptr, int filter = 0, bool bioscheck = false, std::vector<const game_driver *> vec = {});
bool isfavorite() const;
void populate_search();
diff --git a/src/frontend/mame/ui/selsoft.cpp b/src/frontend/mame/ui/selsoft.cpp
index c58a6a0fbc8..03a7c69cd7a 100644
--- a/src/frontend/mame/ui/selsoft.cpp
+++ b/src/frontend/mame/ui/selsoft.cpp
@@ -29,11 +29,6 @@
namespace ui {
-static const char *region_lists[] = { "arab", "arg", "asia", "aus", "aut", "bel", "blr", "bra", "can", "chi", "chn", "cze", "den",
- "ecu", "esp", "euro", "fin", "fra", "gbr", "ger", "gre", "hkg", "hun", "irl", "isr",
- "isv", "ita", "jpn", "kaz", "kor", "lat", "lux", "mex", "ned", "nld", "nor", "nzl",
- "pol", "rus", "slo", "spa", "sui", "swe", "tha", "tpe", "tw", "uk", "ukr", "usa" };
-
//-------------------------------------------------
// compares two items in the software list and
// sort them by parent-clone
@@ -269,41 +264,28 @@ void menu_select_software::handle()
if (check_filter)
{
m_search.clear();
- auto handler =
- [this] (uint16_t &actual, int selection)
+
+ filter_map::const_iterator it(m_filters.find(software_filter::type(l_sw_hover)));
+ if (m_filters.end() == it)
+ it = m_filters.emplace(software_filter::type(l_sw_hover), software_filter::create(software_filter::type(l_sw_hover), m_filter_data)).first;
+ it->second->show_ui(
+ ui(),
+ container(),
+ [this, driver = m_driver] (software_filter &filter)
{
- actual = selection;
- m_filter_type = software_filter::type(l_sw_hover);
+ software_filter::type const new_type(filter.get_type());
+ if (software_filter::CUSTOM == new_type)
+ {
+ emu_file file(ui().options().ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
+ if (file.open("custom_", driver->name, "_filter.ini") == osd_file::error::NONE)
+ {
+ filter.save_ini(file, 0);
+ file.close();
+ }
+ }
+ m_filter_type = new_type;
reset(reset_options::SELECT_FIRST);
- };
-
- using std::placeholders::_1;
- switch (l_sw_hover)
- {
- case software_filter::REGION:
- menu::stack_push<menu_selector>(ui(), container(), std::vector<std::string>(m_filter.region.ui), m_filter.region.actual, std::bind(handler, std::ref(m_filter.region.actual), _1));
- break;
- case software_filter::YEARS:
- menu::stack_push<menu_selector>(ui(), container(), std::vector<std::string>(m_filter.year.ui), m_filter.year.actual, std::bind(handler, std::ref(m_filter.year.actual), _1));
- break;
- case software_filter::LIST:
- menu::stack_push<menu_selector>(ui(), container(), std::vector<std::string>(m_filter.swlist.description), m_filter.swlist.actual, std::bind(handler, std::ref(m_filter.swlist.actual), _1));
- break;
- case software_filter::DEVICE_TYPE:
- menu::stack_push<menu_selector>(ui(), container(), std::vector<std::string>(m_filter.type.ui), m_filter.type.actual, std::bind(handler, std::ref(m_filter.type.actual), _1));
- break;
- case software_filter::PUBLISHERS:
- menu::stack_push<menu_selector>(ui(), container(), std::vector<std::string>(m_filter.publisher.ui), m_filter.publisher.actual, std::bind(handler, std::ref(m_filter.publisher.actual), _1));
- break;
- case software_filter::CUSTOM:
- m_filter_type = software_filter::type(l_sw_hover);
- menu::stack_push<menu_swcustom_filter>(ui(), container(), m_driver, m_filter);
- break;
- default:
- m_filter_type = software_filter::type(l_sw_hover);
- reset(reset_options::SELECT_FIRST);
- break;
- }
+ });
}
}
@@ -335,36 +317,11 @@ void menu_select_software::populate(float &customtop, float &custombottom)
m_displaylist.clear();
m_tmp.clear();
- switch (m_filter_type)
- {
- case software_filter::PUBLISHERS:
- build_list(m_tmp, m_filter.publisher.ui[m_filter.publisher.actual].c_str());
- break;
-
- case software_filter::LIST:
- build_list(m_tmp, m_filter.swlist.name[m_filter.swlist.actual].c_str());
- break;
-
- case software_filter::YEARS:
- build_list(m_tmp, m_filter.year.ui[m_filter.year.actual].c_str());
- break;
-
- case software_filter::DEVICE_TYPE:
- build_list(m_tmp, m_filter.type.ui[m_filter.type.actual].c_str());
- break;
-
- case software_filter::REGION:
- build_list(m_tmp, m_filter.region.ui[m_filter.region.actual].c_str());
- break;
-
- case software_filter::CUSTOM:
- build_custom();
- break;
-
- default:
- build_list(m_tmp);
- break;
- }
+ filter_map::const_iterator const it(m_filters.find(m_filter_type));
+ if (m_filters.end() == it)
+ m_displaylist = m_sortedlist;
+ else
+ it->second->apply(std::begin(m_sortedlist), std::end(m_sortedlist), std::back_inserter(m_displaylist));
// iterate over entries
for (size_t curitem = 0; curitem < m_displaylist.size(); ++curitem)
@@ -419,8 +376,8 @@ void menu_select_software::build_software_list()
// iterate thru all software lists
for (software_list_device &swlist : software_list_device_iterator(config.root_device()))
{
- m_filter.swlist.name.push_back(swlist.list_name());
- m_filter.swlist.description.push_back(swlist.description());
+ m_filter_data.swlist.name.push_back(swlist.list_name());
+ m_filter_data.swlist.description.push_back(swlist.description());
for (const software_info &swinfo : swlist.get_info())
{
const software_part &part = swinfo.parts().front();
@@ -443,10 +400,10 @@ void menu_select_software::build_software_list()
ui_software_info tmpmatches(swinfo, part, *m_driver, swlist.list_name(), instance_name, type_name);
- m_filter.region.set(tmpmatches.longname);
- m_filter.publisher.set(tmpmatches.publisher);
- m_filter.year.set(tmpmatches.year);
- m_filter.type.set(tmpmatches.devicetype);
+ m_filter_data.region.set(tmpmatches.longname);
+ m_filter_data.publisher.set(tmpmatches.publisher);
+ m_filter_data.year.set(tmpmatches.year);
+ m_filter_data.type.set(tmpmatches.devicetype);
m_swinfo.emplace_back(std::move(tmpmatches));
}
}
@@ -482,7 +439,7 @@ void menu_select_software::build_software_list()
std::string searchstr, curpath;
const osd::directory::entry *dir;
- for (auto & elem : m_filter.swlist.name)
+ for (auto & elem : m_filter_data.swlist.name)
{
path_iterator path(machine().options().media_path());
while (path.next(curpath))
@@ -514,10 +471,10 @@ void menu_select_software::build_software_list()
// sort array
std::stable_sort(m_swinfo.begin() + 1, m_swinfo.end(), compare_software);
- std::stable_sort(m_filter.region.ui.begin(), m_filter.region.ui.end());
- std::stable_sort(m_filter.year.ui.begin(), m_filter.year.ui.end());
- std::stable_sort(m_filter.type.ui.begin(), m_filter.type.ui.end());
- std::stable_sort(m_filter.publisher.ui.begin(), m_filter.publisher.ui.end());
+ std::stable_sort(m_filter_data.region.ui.begin(), m_filter_data.region.ui.end());
+ std::stable_sort(m_filter_data.year.ui.begin(), m_filter_data.year.ui.end());
+ std::stable_sort(m_filter_data.type.ui.begin(), m_filter_data.type.ui.end());
+ std::stable_sort(m_filter_data.publisher.ui.begin(), m_filter_data.publisher.ui.end());
for (size_t x = 1; x < m_swinfo.size(); ++x)
m_sortedlist.push_back(&m_swinfo[x]);
@@ -596,254 +553,14 @@ void menu_select_software::load_sw_custom_filters()
emu_file file(ui().options().ui_path(), OPEN_FLAG_READ);
if (file.open("custom_", m_driver->name, "_filter.ini") == osd_file::error::NONE)
{
- char buffer[MAX_CHAR_INFO];
-
- // get number of filters
- file.gets(buffer, MAX_CHAR_INFO);
- char *pb = strchr(buffer, '=');
- sw_custfltr::numother = atoi(++pb) - 1;
-
- // get main filter
- file.gets(buffer, MAX_CHAR_INFO);
- pb = strchr(buffer, '=') + 2;
-
- for (software_filter::type y = software_filter::FIRST; y < software_filter::COUNT; ++y)
- {
- char const *const name(software_filter::config_name(y));
- if (!strncmp(pb, name, strlen(name)))
- {
- sw_custfltr::main = y;
- break;
- }
- }
-
- for (int x = 1; x <= sw_custfltr::numother; ++x)
- {
- file.gets(buffer, MAX_CHAR_INFO);
- char *cb = strchr(buffer, '=') + 2;
- for (software_filter::type y = software_filter::FIRST; y < software_filter::COUNT; ++y)
- {
- char const *const name(software_filter::config_name(y));
- if (!strncmp(cb, name, strlen(name)))
- {
- sw_custfltr::other[x] = y;
- if (y == software_filter::PUBLISHERS)
- {
- file.gets(buffer, MAX_CHAR_INFO);
- char *ab = strchr(buffer, '=') + 2;
- for (size_t z = 0; z < m_filter.publisher.ui.size(); ++z)
- if (!strncmp(ab, m_filter.publisher.ui[z].c_str(), m_filter.publisher.ui[z].length()))
- sw_custfltr::mnfct[x] = z;
- }
- else if (y == software_filter::YEARS)
- {
- file.gets(buffer, MAX_CHAR_INFO);
- char *db = strchr(buffer, '=') + 2;
- for (size_t z = 0; z < m_filter.year.ui.size(); ++z)
- if (!strncmp(db, m_filter.year.ui[z].c_str(), m_filter.year.ui[z].length()))
- sw_custfltr::year[x] = z;
- }
- else if (y == software_filter::LIST)
- {
- file.gets(buffer, MAX_CHAR_INFO);
- char *gb = strchr(buffer, '=') + 2;
- for (size_t z = 0; z < m_filter.swlist.name.size(); ++z)
- if (!strncmp(gb, m_filter.swlist.name[z].c_str(), m_filter.swlist.name[z].length()))
- sw_custfltr::list[x] = z;
- }
- else if (y == software_filter::DEVICE_TYPE)
- {
- file.gets(buffer, MAX_CHAR_INFO);
- char *fb = strchr(buffer, '=') + 2;
- for (size_t z = 0; z < m_filter.type.ui.size(); ++z)
- if (!strncmp(fb, m_filter.type.ui[z].c_str(), m_filter.type.ui[z].length()))
- sw_custfltr::type[x] = z;
- }
- else if (y == software_filter::REGION)
- {
- file.gets(buffer, MAX_CHAR_INFO);
- char *eb = strchr(buffer, '=') + 2;
- for (size_t z = 0; z < m_filter.region.ui.size(); ++z)
- if (!strncmp(eb, m_filter.region.ui[z].c_str(), m_filter.region.ui[z].length()))
- sw_custfltr::region[x] = z;
- }
- }
- }
- }
+ software_filter::ptr flt(software_filter::create(file, m_filter_data));
+ if (flt)
+ m_filters.emplace(flt->get_type(), std::move(flt));
file.close();
}
}
//-------------------------------------------------
-// set software regions
-//-------------------------------------------------
-
-void c_sw_region::set(std::string &str)
-{
- std::string name = getname(str);
- if (std::find(ui.begin(), ui.end(), name) != ui.end())
- return;
-
- ui.push_back(name);
-}
-
-std::string c_sw_region::getname(std::string &str)
-{
- std::string fullname(str);
- strmakelower(fullname);
- size_t found = fullname.find("(");
-
- if (found != std::string::npos)
- {
- size_t ends = fullname.find_first_not_of("abcdefghijklmnopqrstuvwxyz", found + 1);
- std::string temp(fullname.substr(found + 1, ends - found - 1));
-
- for (auto & elem : region_lists)
- if (temp == elem)
- return (str.substr(found + 1, ends - found - 1));
- }
- return std::string("<none>");
-}
-
-//-------------------------------------------------
-// set software device type
-//-------------------------------------------------
-
-void c_sw_type::set(std::string &str)
-{
- if (std::find(ui.begin(), ui.end(), str) != ui.end())
- return;
-
- ui.push_back(str);
-}
-
-//-------------------------------------------------
-// set software years
-//-------------------------------------------------
-
-void c_sw_year::set(std::string &str)
-{
- if (std::find(ui.begin(), ui.end(), str) != ui.end())
- return;
-
- ui.push_back(str);
-}
-
-//-------------------------------------------------
-// set software publishers
-//-------------------------------------------------
-
-void c_sw_publisher::set(std::string &str)
-{
- std::string name = getname(str);
- if (std::find(ui.begin(), ui.end(), name) != ui.end())
- return;
-
- ui.push_back(name);
-}
-
-std::string c_sw_publisher::getname(std::string &str)
-{
- size_t found = str.find("(");
-
- if (found != std::string::npos)
- return (str.substr(0, found - 1));
- else
- return str;
-}
-
-//-------------------------------------------------
-// build display list
-//-------------------------------------------------
-void menu_select_software::build_list(std::vector<ui_software_info *> &s_drivers, const char *filter_text, int filter)
-{
- if (s_drivers.empty() && filter == -1)
- {
- filter = m_filter_type;
- s_drivers = m_sortedlist;
- }
-
- // iterate over entries
- for (auto & s_driver : s_drivers)
- {
- switch (filter)
- {
- case software_filter::PARENTS:
- if (s_driver->parentname.empty())
- m_displaylist.push_back(s_driver);
- break;
-
- case software_filter::CLONES:
- if (!s_driver->parentname.empty())
- m_displaylist.push_back(s_driver);
- break;
-
- case software_filter::AVAILABLE:
- if (s_driver->available)
- m_displaylist.push_back(s_driver);
- break;
-
- case software_filter::UNAVAILABLE:
- if (!s_driver->available)
- m_displaylist.push_back(s_driver);
- break;
-
- case software_filter::SUPPORTED:
- if (s_driver->supported == SOFTWARE_SUPPORTED_YES)
- m_displaylist.push_back(s_driver);
- break;
-
- case software_filter::PARTIAL_SUPPORTED:
- if (s_driver->supported == SOFTWARE_SUPPORTED_PARTIAL)
- m_displaylist.push_back(s_driver);
- break;
-
- case software_filter::UNSUPPORTED:
- if (s_driver->supported == SOFTWARE_SUPPORTED_NO)
- m_displaylist.push_back(s_driver);
- break;
-
- case software_filter::REGION:
- {
- std::string name = m_filter.region.getname(s_driver->longname);
-
- if(!name.empty() && name == filter_text)
- m_displaylist.push_back(s_driver);
- }
- break;
-
- case software_filter::PUBLISHERS:
- {
- std::string name = m_filter.publisher.getname(s_driver->publisher);
-
- if(!name.empty() && name == filter_text)
- m_displaylist.push_back(s_driver);
- }
- break;
-
- case software_filter::YEARS:
- if(s_driver->year == filter_text)
- m_displaylist.push_back(s_driver);
- break;
-
- case software_filter::LIST:
- if(s_driver->listname == filter_text)
- m_displaylist.push_back(s_driver);
- break;
-
- case software_filter::DEVICE_TYPE:
- if(s_driver->devicetype == filter_text)
- m_displaylist.push_back(s_driver);
- break;
-
- default:
- m_displaylist.push_back(s_driver);
- break;
- }
- }
-}
-
-//-------------------------------------------------
// find approximate matches
//-------------------------------------------------
@@ -882,46 +599,6 @@ void menu_select_software::find_matches(const char *str, int count)
}
//-------------------------------------------------
-// build custom display list
-//-------------------------------------------------
-
-void menu_select_software::build_custom()
-{
- std::vector<ui_software_info *> s_drivers;
-
- build_list(m_sortedlist, nullptr, sw_custfltr::main);
-
- for (int count = 1; count <= sw_custfltr::numother; ++count)
- {
- software_filter::type filter = sw_custfltr::other[count];
- s_drivers = m_displaylist;
- m_displaylist.clear();
-
- switch (filter)
- {
- case software_filter::YEARS:
- build_list(s_drivers, m_filter.year.ui[sw_custfltr::year[count]].c_str(), filter);
- break;
- case software_filter::LIST:
- build_list(s_drivers, m_filter.swlist.name[sw_custfltr::list[count]].c_str(), filter);
- break;
- case software_filter::DEVICE_TYPE:
- build_list(s_drivers, m_filter.type.ui[sw_custfltr::type[count]].c_str(), filter);
- break;
- case software_filter::PUBLISHERS:
- build_list(s_drivers, m_filter.publisher.ui[sw_custfltr::mnfct[count]].c_str(), filter);
- break;
- case software_filter::REGION:
- build_list(s_drivers, m_filter.region.ui[sw_custfltr::region[count]].c_str(), filter);
- break;
- default:
- build_list(s_drivers, nullptr, filter);
- break;
- }
- }
-}
-
-//-------------------------------------------------
// draw left box
//-------------------------------------------------
@@ -929,6 +606,9 @@ float menu_select_software::draw_left_panel(float x1, float y1, float x2, float
{
if (ui_globals::panels_status == SHOW_PANELS || ui_globals::panels_status == HIDE_RIGHT_PANEL)
{
+ filter_map::const_iterator active_filter(m_filters.find(m_filter_type));
+ if (m_filters.end() == active_filter)
+ active_filter = m_filters.emplace(m_filter_type, software_filter::create(m_filter_type, m_filter_data)).first;
float origy1 = y1;
float origy2 = y2;
float text_size = 0.75f;
@@ -946,7 +626,9 @@ float menu_select_software::draw_left_panel(float x1, float y1, float x2, float
line_height = l_height * text_size;
}
- float text_sign = ui().get_string_width("_# ", text_size);
+ std::string tmp("_# ");
+ convert_command_glyph(tmp);
+ float text_sign = ui().get_string_width(tmp.c_str(), text_size);
for (software_filter::type x = software_filter::FIRST; x < software_filter::COUNT; ++x)
{
float total_width;
@@ -971,7 +653,7 @@ float menu_select_software::draw_left_panel(float x1, float y1, float x2, float
for (software_filter::type filter = software_filter::FIRST; filter < software_filter::COUNT; ++filter)
{
- std::string str(software_filter::display_name(filter));
+ std::string const str(active_filter->second->adorned_display_name(filter));
rgb_t bgcolor = UI_TEXT_BG_COLOR;
rgb_t fgcolor = UI_TEXT_COLOR;
@@ -994,35 +676,7 @@ float menu_select_software::draw_left_panel(float x1, float y1, float x2, float
hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1));
}
- float x1t = x1 + text_sign;
- if (m_filter_type == software_filter::CUSTOM)
- {
- if (filter == sw_custfltr::main)
- {
- str = std::string("@custom1 ") + str;
- x1t -= text_sign;
- }
- else
- {
- for (int count = 1; count <= sw_custfltr::numother; ++count)
- {
- int cfilter = sw_custfltr::other[count];
- if (cfilter == filter)
- {
- str = string_format("@custom%d %s", count + 1, str);
- x1t -= text_sign;
- break;
- }
- }
- }
- convert_command_glyph(str);
- }
- else if (filter == m_filter_type)
- {
- str = std::string("_> ") + str;
- x1t -= text_sign;
- convert_command_glyph(str);
- }
+ float const x1t = x1 + ((str == software_filter::display_name(filter)) ? text_sign : 0.0f);
ui().draw_text_full(container(), str.c_str(), x1t, y1, x2 - x1, ui::text_layout::LEFT, ui::text_layout::NEVER,
mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr, text_size);
@@ -1097,19 +751,12 @@ void menu_select_software::make_topbox_text(std::string &line0, std::string &lin
line0 = string_format(_("%1$s %2$s ( %3$d / %4$d software packages )"), emulator_info::get_appname(), bare_build_version, vis_item, m_swinfo.size() - 1);
line1 = string_format(_("Driver: \"%1$s\" software list "), m_driver->type.fullname());
- std::string filtered;
- if (m_filter_type == software_filter::REGION && m_filter.region.ui.size())
- filtered = string_format(_("Region: %1$s -"), m_filter.region.ui[m_filter.region.actual]);
- else if (m_filter_type == software_filter::PUBLISHERS)
- filtered = string_format(_("Publisher: %1$s -"), m_filter.publisher.ui[m_filter.publisher.actual]);
- else if (m_filter_type == software_filter::YEARS)
- filtered = string_format(_("Year: %1$s -"), m_filter.year.ui[m_filter.year.actual]);
- else if (m_filter_type == software_filter::LIST)
- filtered = string_format(_("Software List: %1$s -"), m_filter.swlist.description[m_filter.swlist.actual]);
- else if (m_filter_type == software_filter::DEVICE_TYPE)
- filtered = string_format(_("Device type: %1$s -"), m_filter.type.ui[m_filter.type.actual]);
-
- line2 = string_format(_("%s Search: %s_"), filtered, m_search);
+ filter_map::const_iterator const it(m_filters.find(m_filter_type));
+ char const *const filter((m_filters.end() != it) ? it->second->filter_text() : nullptr);
+ if (filter)
+ line2 = string_format(_("%1$s: %2$s - Search: %3$s_"), it->second->display_name(), filter, m_search);
+ else
+ line2 = string_format(_("Search: %1$s_"), m_search);
}
diff --git a/src/frontend/mame/ui/selsoft.h b/src/frontend/mame/ui/selsoft.h
index 60b6bbeda02..7e92815e08b 100644
--- a/src/frontend/mame/ui/selsoft.h
+++ b/src/frontend/mame/ui/selsoft.h
@@ -14,6 +14,8 @@
#include "ui/custmenu.h"
#include "ui/selmenu.h"
+#include "ui/utils.h"
+
namespace ui {
@@ -30,10 +32,13 @@ protected:
private:
enum { VISIBLE_GAMES_IN_SEARCH = 200 };
+ typedef std::map<software_filter::type, software_filter::ptr> filter_map;
+
std::string m_search;
const game_driver *m_driver;
bool m_has_empty_start;
- s_filter m_filter;
+ s_filter m_filter_data;
+ filter_map m_filters;
software_filter::type m_filter_type;
int highlight;
@@ -56,8 +61,6 @@ private:
std::vector<ui_software_info> m_swinfo;
void build_software_list();
- void build_list(std::vector<ui_software_info *> &vec, const char *filter_text = nullptr, int filter = -1);
- void build_custom();
void find_matches(const char *str, int count);
void load_sw_custom_filters();
diff --git a/src/frontend/mame/ui/utils.cpp b/src/frontend/mame/ui/utils.cpp
index 31122ffe256..9d3274b78f0 100644
--- a/src/frontend/mame/ui/utils.cpp
+++ b/src/frontend/mame/ui/utils.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Maurizio Petrarota
+// copyright-holders:Maurizio Petrarota, Vas Crabb
/***************************************************************************
ui/utils.cpp
@@ -11,10 +11,18 @@
#include "emu.h"
#include "ui/utils.h"
+#include "ui/custmenu.h" // FIXME: get s_filter out of here
+#include "ui/selector.h"
+
#include "language.h"
+#include "drivenum.h"
+#include "rendfont.h"
#include "softlist.h"
+#include <cstdlib>
+#include <iterator>
+
namespace ui {
@@ -33,8 +41,8 @@ constexpr char const *machine_filter_names[machine_filter::COUNT] = {
__("BIOS"),
__("Parents"),
__("Clones"),
- __("Manufacturers"),
- __("Release Years"),
+ __("Manufacturer"),
+ __("Year"),
__("Save Supported"),
__("Save Unsupported"),
__("CHD Required"),
@@ -49,8 +57,8 @@ constexpr char const *software_filter_names[software_filter::COUNT] = {
__("Unavailable"),
__("Parents"),
__("Clones"),
- __("Release Years"),
- __("Publishers"),
+ __("Year"),
+ __("Publisher"),
__("Supported"),
__("Partially Supported"),
__("Unsupported"),
@@ -59,9 +67,1090 @@ constexpr char const *software_filter_names[software_filter::COUNT] = {
__("Software List"),
__("Custom Filter") };
+
+
+//-------------------------------------------------
+// base implementation for simple filters
+//-------------------------------------------------
+
+template <class Base, typename Base::type Type>
+class simple_filter_impl_base : public Base
+{
+public:
+ virtual char const *config_name() const override { return Base::config_name(Type); }
+ virtual char const *display_name() const override { return Base::display_name(Type); }
+ virtual char const *filter_text() const override { return nullptr; }
+
+ virtual void show_ui(mame_ui_manager &mui, render_container &container, std::function<void (Base &)> &&handler) override
+ {
+ handler(*this);
+ }
+
+ virtual bool wants_adjuster() const override { return false; }
+ virtual char const *adjust_text() const override { return filter_text(); }
+ virtual uint32_t arrow_flags() const override { return 0; }
+ virtual bool adjust_left() override { return false; }
+ virtual bool adjust_right() override { return false; }
+
+ virtual void save_ini(emu_file &file, unsigned indent) const override
+ {
+ file.puts(util::string_format("%2$*1$s%3$s = 1\n", 2 * indent, "", config_name()).c_str());
+ }
+
+ virtual typename Base::type get_type() const override { return Type; }
+
+ virtual std::string adorned_display_name(typename Base::type n) const override
+ {
+ std::string result;
+ if (Type == n)
+ {
+ result = "_> ";
+ convert_command_glyph(result);
+ }
+ result.append(Base::display_name(n));
+ return result;
+ }
+
+ using Base::config_name;
+ using Base::display_name;
+
+protected:
+ simple_filter_impl_base() { }
+};
+
+
+
+//-------------------------------------------------
+// base implementation for single-choice filters
+//-------------------------------------------------
+
+template <class Base, typename Base::type Type>
+class choice_filter_impl_base : public simple_filter_impl_base<Base, Type>
+{
+public:
+ virtual char const *filter_text() const override { return selection_valid() ? selection_text().c_str() : nullptr; }
+
+ virtual void show_ui(mame_ui_manager &mui, render_container &container, std::function<void (Base &)> &&handler) override
+ {
+ if (m_choices.empty())
+ {
+ handler(*this);
+ }
+ else
+ {
+ menu::stack_push<menu_selector>(
+ mui, container,
+ std::vector<std::string>(m_choices), // ouch, a vector copy!
+ m_selection,
+ [this, cb = std::move(handler)] (int selection)
+ {
+ m_selection = selection;
+ cb(*this);
+ });
+ }
+ }
+
+ virtual bool wants_adjuster() const override { return have_choices(); }
+
+ virtual uint32_t arrow_flags() const override
+ {
+ return ((have_choices() && m_selection) ? menu::FLAG_LEFT_ARROW : 0) | ((m_choices.size() > (m_selection + 1)) ? menu::FLAG_RIGHT_ARROW : 0);
+ }
+
+ virtual bool adjust_left() override
+ {
+ if (!have_choices() || !m_selection)
+ return false;
+ m_selection = (std::min)(m_selection - 1, unsigned(m_choices.size() - 1));
+ return true;
+ }
+
+ virtual bool adjust_right() override
+ {
+ if (m_choices.size() <= (m_selection + 1))
+ return false;
+ ++m_selection;
+ return true;
+ }
+
+ virtual void save_ini(emu_file &file, unsigned indent) const override
+ {
+ char const *const text(filter_text());
+ file.puts(util::string_format("%2$*1$s%3$s = %4$s\n", 2 * indent, "", this->config_name(), text ? text : "").c_str());
+ }
+
+protected:
+ choice_filter_impl_base(std::vector<std::string> const &choices, char const *value) :
+ m_choices(choices),
+ m_selection(0U)
+ {
+ if (value)
+ {
+ std::vector<std::string>::const_iterator const found(std::find(choices.begin(), choices.end(), value));
+ if (choices.end() != found)
+ m_selection = std::distance(choices.begin(), found);
+ }
+ }
+
+ bool have_choices() const { return !m_choices.empty(); }
+ bool selection_valid() const { return m_choices.size() > m_selection; }
+ std::string const &selection_text() const { return m_choices[m_selection]; }
+
+private:
+ std::vector<std::string> const &m_choices;
+ unsigned m_selection;
+};
+
+
+
+//-------------------------------------------------
+// base implementation for composite filters
+//-------------------------------------------------
+
+template <class Impl, class Base, typename Base::type Type>
+class composite_filter_impl_base : public simple_filter_impl_base<Base, Type>
+{
+public:
+ virtual bool wants_adjuster() const override { return true; }
+ virtual char const *adjust_text() const override { return _("<set up filters>"); }
+
+ virtual void save_ini(emu_file &file, unsigned indent) const override
+ {
+ auto const tail(std::find_if(std::begin(m_filters), std::end(m_filters), [] (typename Base::ptr const &flt) { return !flt; }));
+ file.puts(util::string_format("%2$*1$s%3$s = %4$d\n", 2 * indent, "", this->config_name(), std::distance(std::begin(m_filters), tail)).c_str());
+ for (auto it = std::begin(m_filters); tail != it; ++it)
+ (*it)->save_ini(file, indent + 1);
+ }
+
+ virtual std::string adorned_display_name(typename Base::type n) const override
+ {
+ std::string result;
+ if (Type == n)
+ {
+ result = "_> ";
+ convert_command_glyph(result);
+ }
+ else
+ {
+ for (unsigned i = 0; (MAX > i) && m_filters[i]; ++i)
+ {
+ if (m_filters[i]->get_type() == n)
+ {
+ result = util::string_format("@custom%u ", i + 1);
+ convert_command_glyph(result);
+ break;
+ }
+ }
+ }
+ result.append(Base::display_name(n));
+ return result;
+ }
+
+ virtual bool apply(typename Base::entry_type const &info) const override
+ {
+ std::bitset<Base::COUNT> inclusions, included;
+ for (typename Base::ptr const &flt : m_filters)
+ {
+ if (!flt)
+ break;
+
+ typename Base::type const t(flt->get_type());
+ bool const r(flt->apply(info));
+ if (Impl::is_inclusion(t))
+ {
+ inclusions.set(t);
+ if (r)
+ included.set(t);
+ }
+ else if (!r)
+ {
+ return false;
+ }
+ }
+ return inclusions == included;
+ }
+
+ virtual void show_ui(mame_ui_manager &mui, render_container &container, std::function<void (Base &)> &&handler) override;
+
+protected:
+ composite_filter_impl_base() { }
+
+ void populate(char const *value, emu_file *file, unsigned indent)
+ {
+ // try to load filters from a file
+ if (value && file)
+ {
+ unsigned const cnt(unsigned((std::max)(std::min(int(MAX), std::atoi(value)), 0)));
+ for (unsigned i = 0; cnt > i; ++i)
+ {
+ typename Base::ptr flt(static_cast<Impl &>(*this).create(*file, indent + 1));
+ if (!flt || !check_type(i, flt->get_type()))
+ break;
+ m_filters[i] = std::move(flt);
+ }
+ }
+
+ // instantiate first allowed filter type if we're still empty
+ for (typename Base::type t = Base::FIRST; (Base::COUNT > t) && !m_filters[0]; ++t)
+ {
+ if (Impl::type_allowed(0, t))
+ m_filters[0] = static_cast<Impl &>(*this).create(t);
+ }
+ }
+
+private:
+ static constexpr unsigned MAX = 8;
+
+ class menu_configure : public menu
+ {
+ public:
+ menu_configure(
+ mame_ui_manager &mui,
+ render_container &container,
+ Impl &parent,
+ std::function<void (Base &filter)> &&handler) :
+ menu(mui, container),
+ m_parent(parent),
+ m_handler(std::move(handler)),
+ m_added(false)
+ {
+ }
+
+ virtual ~menu_configure() override { m_handler(m_parent); }
+
+ protected:
+ virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override
+ {
+ char const *const text[] = { _("Select custom filters:") };
+ draw_text_box(
+ std::begin(text), std::end(text),
+ x, x2, y - top, y - UI_BOX_TB_BORDER,
+ ui::text_layout::CENTER, ui::text_layout::NEVER, false,
+ UI_TEXT_COLOR, UI_GREEN_COLOR, 1.0f);
+ }
+
+ private:
+ enum : uintptr_t
+ {
+ FILTER_FIRST = 1,
+ FILTER_LAST = FILTER_FIRST + MAX - 1,
+ ADJUST_FIRST,
+ ADJUST_LAST = ADJUST_FIRST + MAX - 1,
+ REMOVE_FILTER,
+ ADD_FILTER
+ };
+
+ virtual void populate(float &customtop, float &custombottom) override;
+ virtual void handle() override;
+
+ bool set_filter_type(unsigned pos, typename Base::type n)
+ {
+ if (!m_parent.m_filters[pos] || (m_parent.m_filters[pos]->get_type()))
+ {
+ save_filter(pos);
+ retrieve_filter(pos, n);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ bool append_filter()
+ {
+ unsigned pos = 0;
+ while (m_parent.m_filters[pos])
+ {
+ if (MAX <= ++pos)
+ return false;
+ }
+ for (typename Base::type candidate = Base::FIRST; Base::COUNT > candidate; ++candidate)
+ {
+ if (m_parent.check_type(pos, candidate))
+ {
+ set_filter_type(pos, candidate);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool drop_last_filter()
+ {
+ for (unsigned i = 2; MAX >= i; ++i)
+ {
+ if ((MAX <= i) || !m_parent.m_filters[i])
+ {
+ save_filter(i - 1);
+ m_parent.m_filters[i - 1].reset();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void save_filter(unsigned pos)
+ {
+ typename Base::ptr &flt(m_parent.m_filters[pos]);
+ if (flt && flt->wants_adjuster())
+ m_saved_filters[pos][flt->get_type()] = std::move(flt);
+ }
+
+ void retrieve_filter(unsigned pos, typename Base::type n)
+ {
+ typename Base::ptr &flt(m_parent.m_filters[pos]);
+ auto const found(m_saved_filters[pos].find(n));
+ if (m_saved_filters[pos].end() != found)
+ {
+ flt = std::move(found->second);
+ m_saved_filters[pos].erase(found);
+ }
+ else
+ {
+ flt = m_parent.create(n);
+ }
+ }
+
+ uint32_t get_arrow_flags(unsigned pos)
+ {
+ uint32_t result(0);
+ typename Base::type const current(m_parent.m_filters[pos]->get_type());
+
+ // look for a lower type that's allowed and isn't contradictory
+ typename Base::type prev(current);
+ while ((Base::FIRST < prev) && !(FLAG_LEFT_ARROW & result))
+ {
+ if (m_parent.check_type(pos, --prev))
+ result |= FLAG_LEFT_ARROW;
+ }
+
+ // look for a higher type that's allowed and isn't contradictory
+ typename Base::type next(current);
+ while ((Base::LAST > next) && !(FLAG_RIGHT_ARROW & result))
+ {
+ if (m_parent.check_type(pos, ++next))
+ result |= FLAG_RIGHT_ARROW;
+ }
+
+ return result;
+ }
+
+ Impl &m_parent;
+ std::map<typename Base::type, typename Base::ptr> m_saved_filters[MAX];
+ std::function<void (Base &)> m_handler;
+ bool m_added;
+ };
+
+ bool check_type(unsigned pos, typename Base::type candidate)
+ {
+ if (!Impl::type_allowed(pos, candidate))
+ return false;
+ unsigned j = 0;
+ while ((MAX > j) && m_filters[j] && ((pos == j) || !Impl::types_contradictory(m_filters[j]->get_type(), candidate)))
+ ++j;
+ return (MAX <= j) || !m_filters[j];
+ };
+
+ typename Base::ptr m_filters[MAX];
+};
+
+template <class Impl, class Base, typename Base::type Type>
+void composite_filter_impl_base<Impl, Base, Type>::show_ui(
+ mame_ui_manager &mui,
+ render_container &container,
+ std::function<void (Base &filter)> &&handler)
+{
+ menu::stack_push<menu_configure>(mui, container, static_cast<Impl &>(*this), std::move(handler));
+}
+
+
+template <class Impl, class Base, typename Base::type Type>
+void composite_filter_impl_base<Impl, Base, Type>::menu_configure::populate(float &customtop, float &custombottom)
+{
+ // add items for each active filter
+ unsigned i = 0;
+ for (i = 0; (MAX > i) && m_parent.m_filters[i]; ++i)
+ {
+ item_append(util::string_format("Filter %u", i + 1), m_parent.m_filters[i]->display_name(), get_arrow_flags(i), (void *)(FILTER_FIRST + i));
+ if (m_added)
+ selected = item.size() - 2;
+ if (m_parent.m_filters[i]->wants_adjuster())
+ {
+ std::string name("^!");
+ convert_command_glyph(name);
+ item_append(name, m_parent.m_filters[i]->adjust_text(), m_parent.m_filters[i]->arrow_flags(), (void *)(ADJUST_FIRST + i));
+ }
+ item_append(menu_item_type::SEPARATOR);
+ }
+ m_added = false;
+
+ // add remove/add handlers
+ if (1 < i)
+ item_append(_("Remove last filter"), "", 0, (void *)REMOVE_FILTER);
+ if (MAX > i)
+ item_append(_("Add filter"), "", 0, (void *)ADD_FILTER);
+ item_append(menu_item_type::SEPARATOR);
+
+ // leave space for heading
+ customtop = ui().get_line_height() + 3.0f * UI_BOX_TB_BORDER;
+}
+
+template <class Impl, class Base, typename Base::type Type>
+void composite_filter_impl_base<Impl, Base, Type>::menu_configure::handle()
+{
+ const event *menu_event = process(PROCESS_LR_REPEAT);
+ if (menu_event && menu_event->itemref)
+ {
+ m_added = false;
+ bool changed(false);
+ uintptr_t const ref(reinterpret_cast<uintptr_t>(menu_event->itemref));
+ switch (menu_event->iptkey)
+ {
+ case IPT_UI_LEFT:
+ case IPT_UI_RIGHT:
+ if ((FILTER_FIRST <= ref) && (FILTER_LAST >= ref))
+ {
+ // change filter type
+ unsigned const pos(ref - FILTER_FIRST);
+ typename Base::type const current(m_parent.m_filters[pos]->get_type());
+ if (IPT_UI_LEFT == menu_event->iptkey)
+ {
+ typename Base::type n(current);
+ while ((Base::FIRST < n) && !changed)
+ {
+ if (m_parent.check_type(pos, --n))
+ changed = set_filter_type(pos, n);
+ }
+ }
+ else
+ {
+ typename Base::type n(current);
+ while ((Base::LAST > n) && !changed)
+ {
+ if (m_parent.check_type(pos, ++n))
+ changed = set_filter_type(pos, n);
+ }
+ }
+ }
+ else if ((ADJUST_FIRST <= ref) && (ADJUST_LAST >= ref))
+ {
+ // change filter value
+ Base &pos(*m_parent.m_filters[ref - ADJUST_FIRST]);
+ changed = (IPT_UI_LEFT == menu_event->iptkey) ? pos.adjust_left() : pos.adjust_right();
+ }
+ break;
+
+ case IPT_UI_SELECT:
+ if ((FILTER_FIRST <= ref) && (FILTER_LAST >= ref))
+ {
+ // show selector with non-contradictory types
+ std::vector<typename Base::type> types;
+ std::vector<std::string> names;
+ types.reserve(Base::COUNT);
+ names.reserve(Base::COUNT);
+ int sel(-1);
+ unsigned const pos(ref - FILTER_FIRST);
+ typename Base::type const current(m_parent.m_filters[pos]->get_type());
+ for (typename Base::type candidate = Base::FIRST; Base::COUNT > candidate; ++candidate)
+ {
+ if (Impl::type_allowed(pos, candidate))
+ {
+ if (current == candidate)
+ sel = types.size();
+ unsigned i = 0;
+ while ((MAX > i) && m_parent.m_filters[i] && ((pos == i) || !Impl::types_contradictory(m_parent.m_filters[i]->get_type(), candidate)))
+ ++i;
+ if ((MAX <= i) || !m_parent.m_filters[i])
+ {
+ types.emplace_back(candidate);
+ names.emplace_back(Base::display_name(candidate));
+ }
+ }
+ }
+ menu::stack_push<menu_selector>(
+ ui(),
+ container(),
+ std::move(names),
+ sel,
+ [this, pos, t = std::move(types)] (int selection)
+ {
+ if (set_filter_type(pos, t[selection]))
+ reset(reset_options::REMEMBER_REF);
+ });
+ }
+ else if ((ADJUST_FIRST <= ref) && (ADJUST_LAST >= ref))
+ {
+ // show selected filter's UI
+ m_parent.m_filters[ref - ADJUST_FIRST]->show_ui(ui(), container(), [this] (Base &filter) { reset(reset_options::REMEMBER_REF); });
+ }
+ else if (REMOVE_FILTER == ref)
+ {
+ changed = drop_last_filter();
+ }
+ else if (ADD_FILTER == ref)
+ {
+ m_added = append_filter();
+ }
+ break;
+ }
+
+ // rebuild if anything changed
+ if (changed)
+ reset(reset_options::REMEMBER_REF);
+ else if (m_added)
+ reset(reset_options::SELECT_FIRST);
+ }
+}
+
+
+
+//-------------------------------------------------
+// invertable machine filters
+//-------------------------------------------------
+
+template <machine_filter::type Type = machine_filter::WORKING>
+class working_machine_filter_impl : public simple_filter_impl_base<machine_filter, Type>
+{
+public:
+ working_machine_filter_impl(char const *value, emu_file *file, unsigned indent) { }
+
+ virtual bool apply(game_driver const &driver) const override { return !(driver.flags & machine_flags::NOT_WORKING); }
+};
+
+
+template <machine_filter::type Type = machine_filter::MECHANICAL>
+class mechanical_machine_filter_impl : public simple_filter_impl_base<machine_filter, Type>
+{
+public:
+ mechanical_machine_filter_impl(char const *value, emu_file *file, unsigned indent) { }
+
+ virtual bool apply(game_driver const &driver) const override { return driver.flags & machine_flags::MECHANICAL; }
+};
+
+
+template <machine_filter::type Type = machine_filter::PARENTS>
+class parents_machine_filter_impl : public simple_filter_impl_base<machine_filter, Type>
+{
+public:
+ parents_machine_filter_impl(char const *value, emu_file *file, unsigned indent) { }
+
+ virtual bool apply(game_driver const &driver) const override
+ {
+ bool const have_parent(strcmp(driver.parent, "0"));
+ auto const parent_idx(have_parent ? driver_list::find(driver.parent) : -1);
+ return !have_parent || (0 > parent_idx) || (driver_list::driver(parent_idx).flags & machine_flags::IS_BIOS_ROOT);
+ }
+};
+
+
+template <machine_filter::type Type = machine_filter::CHD>
+class chd_machine_filter_impl : public simple_filter_impl_base<machine_filter, Type>
+{
+public:
+ chd_machine_filter_impl(char const *value, emu_file *file, unsigned indent) { }
+
+ virtual bool apply(game_driver const &driver) const override
+ {
+ for (tiny_rom_entry const *rom = driver.rom; rom && rom->name; ++rom)
+ {
+ // FIXME: can't use the convenience macros tiny ROM entries
+ if ((ROMENTRYTYPE_REGION == (rom->flags & ROMENTRY_TYPEMASK)) && (ROMREGION_DATATYPEDISK == (rom->flags & ROMREGION_DATATYPEMASK)))
+ return true;
+ }
+ return false;
+ }
+};
+
+
+template <machine_filter::type Type = machine_filter::SAVE>
+class save_machine_filter_impl : public simple_filter_impl_base<machine_filter, Type>
+{
+public:
+ save_machine_filter_impl(char const *value, emu_file *file, unsigned indent) { }
+
+ virtual bool apply(game_driver const &driver) const override { return driver.flags & machine_flags::SUPPORTS_SAVE; }
+};
+
+
+template <machine_filter::type Type = machine_filter::VERTICAL>
+class vertical_machine_filter_impl : public simple_filter_impl_base<machine_filter, Type>
+{
+public:
+ vertical_machine_filter_impl(char const *value, emu_file *file, unsigned indent) { }
+
+ virtual bool apply(game_driver const &driver) const override { return driver.flags & machine_flags::SWAP_XY; }
+};
+
+
+
+//-------------------------------------------------
+// concrete machine filters
+//-------------------------------------------------
+
+class bios_machine_filter : public simple_filter_impl_base<machine_filter, machine_filter::BIOS>
+{
+public:
+ bios_machine_filter(char const *value, emu_file *file, unsigned indent) { }
+
+ virtual bool apply(game_driver const &driver) const override { return driver.flags & machine_flags::IS_BIOS_ROOT; }
+};
+
+
+class manufacturer_machine_filter : public choice_filter_impl_base<machine_filter, machine_filter::MANUFACTURER>
+{
+public:
+ manufacturer_machine_filter(char const *value, emu_file *file, unsigned indent) :
+ choice_filter_impl_base<machine_filter, machine_filter::MANUFACTURER>(c_mnfct::ui, value)
+ {
+ }
+
+ virtual bool apply(game_driver const &driver) const override
+ {
+ if (!have_choices())
+ return true;
+ else if (!selection_valid())
+ return false;
+
+ std::string const name(c_mnfct::getname(driver.manufacturer));
+ return !name.empty() && (selection_text() == name);
+ }
+};
+
+
+class year_machine_filter : public choice_filter_impl_base<machine_filter, machine_filter::YEAR>
+{
+public:
+ year_machine_filter(char const *value, emu_file *file, unsigned indent) :
+ choice_filter_impl_base<machine_filter, machine_filter::YEAR>(c_year::ui, value)
+ {
+ }
+
+ virtual bool apply(game_driver const &driver) const override { return !have_choices() || (selection_valid() && (selection_text() == driver.year)); }
+};
+
+
+
+//-------------------------------------------------
+// complementary machine filters
+//-------------------------------------------------
+
+template <template <machine_filter::type T> class Base, machine_filter::type Type>
+class inverted_machine_filter : public Base<Type>
+{
+public:
+ using Base<Type>::Base;
+
+ virtual bool apply(game_driver const &driver) const override { return !Base<Type>::apply(driver); }
+};
+
+using working_machine_filter = working_machine_filter_impl<>;
+using mechanical_machine_filter = mechanical_machine_filter_impl<>;
+using parents_machine_filter = parents_machine_filter_impl<>;
+using save_machine_filter = save_machine_filter_impl<>;
+using chd_machine_filter = chd_machine_filter_impl<>;
+using vertical_machine_filter = vertical_machine_filter_impl<>;
+
+using not_working_machine_filter = inverted_machine_filter<working_machine_filter_impl, machine_filter::NOT_WORKING>;
+using not_mechanical_machine_filter = inverted_machine_filter<mechanical_machine_filter_impl, machine_filter::NOT_MECHANICAL>;
+using clones_machine_filter = inverted_machine_filter<parents_machine_filter_impl, machine_filter::CLONES>;
+using nosave_machine_filter = inverted_machine_filter<save_machine_filter_impl, machine_filter::NOSAVE>;
+using nochd_machine_filter = inverted_machine_filter<chd_machine_filter_impl, machine_filter::NOCHD>;
+using horizontal_machine_filter = inverted_machine_filter<vertical_machine_filter_impl, machine_filter::HORIZONTAL>;
+
+
+
+//-------------------------------------------------
+// dummy machine filters (special-cased in menu)
+//-------------------------------------------------
+
+template <machine_filter::type Type>
+class inclusive_machine_filter_impl : public simple_filter_impl_base<machine_filter, Type>
+{
+public:
+ inclusive_machine_filter_impl(char const *value, emu_file *file, unsigned indent) { }
+
+ virtual bool apply(game_driver const &drv) const { return true; }
+};
+
+using all_machine_filter = inclusive_machine_filter_impl<machine_filter::ALL>;
+using available_machine_filter = inclusive_machine_filter_impl<machine_filter::AVAILABLE>;
+using unavailable_machine_filter = inclusive_machine_filter_impl<machine_filter::UNAVAILABLE>;
+using favorite_machine_filter = inclusive_machine_filter_impl<machine_filter::FAVORITE>;
+
+
+
+//-------------------------------------------------
+// composite machine filter
+//-------------------------------------------------
+
+class custom_machine_filter : public composite_filter_impl_base<custom_machine_filter, machine_filter, machine_filter::CUSTOM>
+{
+public:
+ custom_machine_filter(char const *value, emu_file *file, unsigned indent) :
+ composite_filter_impl_base<custom_machine_filter, machine_filter, machine_filter::CUSTOM>()
+ {
+ populate(value, file, indent);
+ }
+
+ ptr create(type n) const { return machine_filter::create(n); }
+ ptr create(emu_file &file, unsigned indent) const { return machine_filter::create(file, indent); }
+
+ static bool type_allowed(unsigned pos, type n)
+ {
+ return (FIRST <= n) && (LAST >= n) && (ALL != n) && (AVAILABLE != n) && (UNAVAILABLE != n) && (CATEGORY != n) && (FAVORITE != n) && (CUSTOM != n);
+ }
+
+ static bool types_contradictory(type n, type m)
+ {
+ switch (n)
+ {
+ case AVAILABLE: return UNAVAILABLE == m;
+ case UNAVAILABLE: return AVAILABLE == m;
+ case WORKING: return NOT_WORKING == m;
+ case NOT_WORKING: return WORKING == m;
+ case MECHANICAL: return NOT_MECHANICAL == m;
+ case NOT_MECHANICAL: return MECHANICAL == m;
+ case PARENTS: return CLONES == m;
+ case CLONES: return PARENTS == m;
+ case SAVE: return NOSAVE == m;
+ case NOSAVE: return SAVE == m;
+ case CHD: return NOCHD == m;
+ case NOCHD: return CHD == m;
+ case VERTICAL: return HORIZONTAL == m;
+ case HORIZONTAL: return VERTICAL == m;
+
+ case ALL:
+ case CATEGORY:
+ case FAVORITE:
+ case BIOS:
+ case MANUFACTURER:
+ case YEAR:
+ case CUSTOM:
+ case COUNT:
+ break;
+ }
+ return false;
+ }
+
+ static bool is_inclusion(type n)
+ {
+ return (MANUFACTURER == n) || (YEAR == n);
+ }
+};
+
+
+
+//-------------------------------------------------
+// concrete software filters
+//-------------------------------------------------
+
+class all_software_filter : public simple_filter_impl_base<software_filter, software_filter::ALL>
+{
+public:
+ all_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) { }
+
+ virtual bool apply(ui_software_info const &info) const override { return true; }
+};
+
+
+class available_software_filter : public simple_filter_impl_base<software_filter, software_filter::AVAILABLE>
+{
+public:
+ available_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) { }
+
+ virtual bool apply(ui_software_info const &info) const override { return info.available; }
+};
+
+
+class unavailable_software_filter : public simple_filter_impl_base<software_filter, software_filter::UNAVAILABLE>
+{
+public:
+ unavailable_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) { }
+
+ virtual bool apply(ui_software_info const &info) const override { return !info.available; }
+};
+
+
+class parents_software_filter : public simple_filter_impl_base<software_filter, software_filter::PARENTS>
+{
+public:
+ parents_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) { }
+
+ virtual bool apply(ui_software_info const &info) const override { return info.parentname.empty(); }
+};
+
+
+class clones_software_filter : public simple_filter_impl_base<software_filter, software_filter::CLONES>
+{
+public:
+ clones_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) { }
+
+ virtual bool apply(ui_software_info const &info) const override { return !info.parentname.empty(); }
+};
+
+
+class years_software_filter : public choice_filter_impl_base<software_filter, software_filter::YEAR>
+{
+public:
+ years_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) :
+ choice_filter_impl_base<software_filter, software_filter::YEAR>(data.year.ui, value)
+ {
+ }
+
+ virtual bool apply(ui_software_info const &info) const override { return !have_choices() || (selection_valid() && (selection_text() == info.year)); }
+};
+
+
+class publishers_software_filter : public choice_filter_impl_base<software_filter, software_filter::PUBLISHERS>
+{
+public:
+ publishers_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) :
+ choice_filter_impl_base<software_filter, software_filter::PUBLISHERS>(data.publisher.ui, value),
+ m_publishers(data.publisher)
+ {
+ }
+
+ virtual bool apply(ui_software_info const &info) const override
+ {
+ if (!have_choices())
+ return true;
+ else if (!selection_valid())
+ return false;
+
+ std::string const name(m_publishers.getname(info.publisher));
+ return !name.empty() && (selection_text() == name);
+ }
+
+private:
+ c_sw_publisher const &m_publishers;
+};
+
+
+class supported_software_filter : public simple_filter_impl_base<software_filter, software_filter::SUPPORTED>
+{
+public:
+ supported_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) { }
+
+ virtual bool apply(ui_software_info const &info) const override { return SOFTWARE_SUPPORTED_YES == info.supported; }
+};
+
+
+
+class partial_supported_software_filter : public simple_filter_impl_base<software_filter, software_filter::PARTIAL_SUPPORTED>
+{
+public:
+ partial_supported_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) { }
+
+ virtual bool apply(ui_software_info const &info) const override { return SOFTWARE_SUPPORTED_PARTIAL == info.supported; }
+};
+
+
+class unsupported_software_filter : public simple_filter_impl_base<software_filter, software_filter::UNSUPPORTED>
+{
+public:
+ unsupported_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) { }
+
+ virtual bool apply(ui_software_info const &info) const override { return SOFTWARE_SUPPORTED_NO == info.supported; }
+};
+
+
+class region_software_filter : public choice_filter_impl_base<software_filter, software_filter::REGION>
+{
+public:
+ region_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) :
+ choice_filter_impl_base<software_filter, software_filter::REGION>(data.region.ui, value),
+ m_regions(data.region)
+ {
+ }
+
+ virtual bool apply(ui_software_info const &info) const override
+ {
+ if (!have_choices())
+ return true;
+ else if (!selection_valid())
+ return false;
+
+ std::string const name(m_regions.getname(info.longname));
+ return !name.empty() && (selection_text() == name);
+ }
+
+private:
+ c_sw_region const &m_regions;
+};
+
+
+class device_type_software_filter : public choice_filter_impl_base<software_filter, software_filter::DEVICE_TYPE>
+{
+public:
+ device_type_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) :
+ choice_filter_impl_base<software_filter, software_filter::DEVICE_TYPE>(data.type.ui, value)
+ {
+ }
+
+ virtual bool apply(ui_software_info const &info) const override { return !have_choices() || (selection_valid() && (selection_text() == info.devicetype)); }
+};
+
+
+class list_software_filter : public choice_filter_impl_base<software_filter, software_filter::LIST>
+{
+public:
+ list_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) :
+ choice_filter_impl_base<software_filter, software_filter::LIST>(data.swlist.name, value)
+ {
+ }
+
+ virtual bool apply(ui_software_info const &info) const override { return !have_choices() || (selection_valid() && (selection_text() == info.listname)); }
+};
+
+
+
+//-------------------------------------------------
+// composite software filter
+//-------------------------------------------------
+
+class custom_software_filter : public composite_filter_impl_base<custom_software_filter, software_filter, software_filter::CUSTOM>
+{
+public:
+ custom_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) :
+ composite_filter_impl_base<custom_software_filter, software_filter, software_filter::CUSTOM>(),
+ m_data(data)
+ {
+ populate(value, file, indent);
+ }
+
+ ptr create(type n) const { return software_filter::create(n, m_data); }
+ ptr create(emu_file &file, unsigned indent) const { return software_filter::create(file, m_data, indent); }
+
+ static bool type_allowed(unsigned pos, type n)
+ {
+ return (FIRST <= n) && (LAST >= n) && (ALL != n) && (CUSTOM != n);
+ }
+
+ static bool types_contradictory(type n, type m)
+ {
+ switch (n)
+ {
+ case AVAILABLE: return UNAVAILABLE == m;
+ case UNAVAILABLE: return AVAILABLE == m;
+ case PARENTS: return CLONES == m;
+ case CLONES: return PARENTS == m;
+ case SUPPORTED: return (PARTIAL_SUPPORTED == m) || (UNSUPPORTED == m);
+ case PARTIAL_SUPPORTED: return (SUPPORTED == m) || (UNSUPPORTED == m);
+ case UNSUPPORTED: return (SUPPORTED == m) || (PARTIAL_SUPPORTED == m);
+
+ case ALL:
+ case YEAR:
+ case PUBLISHERS:
+ case REGION:
+ case DEVICE_TYPE:
+ case LIST:
+ case CUSTOM:
+ case COUNT:
+ break;
+ }
+ return false;
+ }
+
+ static bool is_inclusion(type n)
+ {
+ return (YEAR == n) || (PUBLISHERS == n) || (REGION == n) || (DEVICE_TYPE == n) || (LIST == n);
+ }
+
+private:
+ s_filter const &m_data;
+};
+
} // anonymous namespace
+
+//-------------------------------------------------
+// public machine filter interface
+//-------------------------------------------------
+
+machine_filter::ptr machine_filter::create(type n, char const *value, emu_file *file, unsigned indent)
+{
+ assert(COUNT > n);
+ switch (n)
+ {
+ case ALL:
+ return std::make_unique<all_machine_filter>(value, file, indent);
+ case AVAILABLE:
+ return std::make_unique<available_machine_filter>(value, file, indent);
+ case UNAVAILABLE:
+ return std::make_unique<unavailable_machine_filter>(value, file, indent);
+ case WORKING:
+ return std::make_unique<working_machine_filter>(value, file, indent);
+ case NOT_WORKING:
+ return std::make_unique<not_working_machine_filter>(value, file, indent);
+ case MECHANICAL:
+ return std::make_unique<mechanical_machine_filter>(value, file, indent);
+ case NOT_MECHANICAL:
+ return std::make_unique<not_mechanical_machine_filter>(value, file, indent);
+ case CATEGORY:
+ break;
+ case FAVORITE:
+ return std::make_unique<favorite_machine_filter>(value, file, indent);
+ case BIOS:
+ return std::make_unique<bios_machine_filter>(value, file, indent);
+ case PARENTS:
+ return std::make_unique<parents_machine_filter>(value, file, indent);
+ case CLONES:
+ return std::make_unique<clones_machine_filter>(value, file, indent);
+ case MANUFACTURER:
+ return std::make_unique<manufacturer_machine_filter>(value, file, indent);
+ case YEAR:
+ return std::make_unique<year_machine_filter>(value, file, indent);
+ case SAVE:
+ return std::make_unique<save_machine_filter>(value, file, indent);
+ case NOSAVE:
+ return std::make_unique<nosave_machine_filter>(value, file, indent);
+ case CHD:
+ return std::make_unique<chd_machine_filter>(value, file, indent);
+ case NOCHD:
+ return std::make_unique<nochd_machine_filter>(value, file, indent);
+ case VERTICAL:
+ return std::make_unique<vertical_machine_filter>(value, file, indent);
+ case HORIZONTAL:
+ return std::make_unique<horizontal_machine_filter>(value, file, indent);
+ case CUSTOM:
+ return std::make_unique<custom_machine_filter>(value, file, indent);
+ case COUNT: // not valid, but needed to suppress warnings
+ break;
+ }
+ return nullptr;
+}
+
+machine_filter::ptr machine_filter::create(emu_file &file, unsigned indent)
+{
+ char buffer[MAX_CHAR_INFO];
+ file.gets(buffer, ARRAY_LENGTH(buffer));
+
+ // split it into a key/value or bail
+ std::string key(buffer);
+ for (std::string::size_type i = 0; (2 * indent) > i; ++i)
+ {
+ if ((key.length() <= i) || (' ' != key[i]))
+ return nullptr;
+ }
+ key = key.substr(2 * indent);
+ std::string::size_type const split(key.find(" = "));
+ if (std::string::npos == split)
+ return nullptr;
+ std::string::size_type const nl(key.find_first_of("\r\n", split));
+ std::string const value(key.substr(split + 3, (std::string::npos == nl) ? nl : (nl - split - 3)));
+ key.resize(split);
+
+ // look for a filter type that matches
+ for (type n = FIRST; COUNT > n; ++n)
+ {
+ if (key == config_name(n))
+ return create(n, value.c_str(), &file, indent);
+ }
+ return nullptr;
+}
+
char const *machine_filter::config_name(type n)
{
assert(COUNT > n);
@@ -74,6 +1163,14 @@ char const *machine_filter::display_name(type n)
return _(machine_filter_names[n]);
}
+machine_filter::machine_filter()
+{
+}
+
+
+//-------------------------------------------------
+// public software filter interface
+//-------------------------------------------------
char const *software_filter::config_name(type n)
{
@@ -87,6 +1184,78 @@ char const *software_filter::display_name(type n)
return _(software_filter_names[n]);
}
+software_filter::software_filter()
+{
+}
+
+software_filter::ptr software_filter::create(type n, s_filter const &data, char const *value, emu_file *file, unsigned indent)
+{
+ assert(COUNT > n);
+ switch (n)
+ {
+ case ALL:
+ return std::make_unique<all_software_filter>(data, value, file, indent);
+ case AVAILABLE:
+ return std::make_unique<available_software_filter>(data, value, file, indent);
+ case UNAVAILABLE:
+ return std::make_unique<unavailable_software_filter>(data, value, file, indent);
+ case PARENTS:
+ return std::make_unique<parents_software_filter>(data, value, file, indent);
+ case CLONES:
+ return std::make_unique<clones_software_filter>(data, value, file, indent);
+ case YEAR:
+ return std::make_unique<years_software_filter>(data, value, file, indent);
+ case PUBLISHERS:
+ return std::make_unique<publishers_software_filter>(data, value, file, indent);
+ case SUPPORTED:
+ return std::make_unique<supported_software_filter>(data, value, file, indent);
+ case PARTIAL_SUPPORTED:
+ return std::make_unique<partial_supported_software_filter>(data, value, file, indent);
+ case UNSUPPORTED:
+ return std::make_unique<unsupported_software_filter>(data, value, file, indent);
+ case REGION:
+ return std::make_unique<region_software_filter>(data, value, file, indent);
+ case DEVICE_TYPE:
+ return std::make_unique<device_type_software_filter>(data, value, file, indent);
+ case LIST:
+ return std::make_unique<list_software_filter>(data, value, file, indent);
+ case CUSTOM:
+ return std::make_unique<custom_software_filter>(data, value, file, indent);
+ case COUNT: // not valid, but needed to suppress warnings
+ break;
+ }
+ return nullptr;
+}
+
+software_filter::ptr software_filter::create(emu_file &file, s_filter const &data, unsigned indent)
+{
+ char buffer[MAX_CHAR_INFO];
+ file.gets(buffer, ARRAY_LENGTH(buffer));
+
+ // split it into a key/value or bail
+ std::string key(buffer);
+ for (std::string::size_type i = 0; (2 * indent) > i; ++i)
+ {
+ if ((key.length() <= i) || (' ' != key[i]))
+ return nullptr;
+ }
+ key = key.substr(2 * indent);
+ std::string::size_type const split(key.find(" = "));
+ if (std::string::npos == split)
+ return nullptr;
+ std::string::size_type const nl(key.find_first_of("\r\n", split));
+ std::string const value(key.substr(split + 3, (std::string::npos == nl) ? nl : (nl - split - 3)));
+ key.resize(split);
+
+ // look for a filter type that matches
+ for (type n = FIRST; COUNT > n; ++n)
+ {
+ if (key == config_name(n))
+ return create(n, data, value.c_str(), &file, indent);
+ }
+ return nullptr;
+}
+
} // namesapce ui
@@ -94,16 +1263,14 @@ extern const char UI_VERSION_TAG[];
const char UI_VERSION_TAG[] = "# UI INFO ";
// Years index
-uint16_t c_year::actual = 0;
std::vector<std::string> c_year::ui;
// Manufacturers index
-uint16_t c_mnfct::actual = 0;
std::vector<std::string> c_mnfct::ui;
-std::unordered_map<std::string, int> c_mnfct::uimap;
// Main filters
ui::machine_filter::type main_filters::actual = ui::machine_filter::ALL;
+std::map<ui::machine_filter::type, ui::machine_filter::ptr> main_filters::filters;
// Globals
uint8_t ui_globals::rpanel = 0;
@@ -121,24 +1288,6 @@ int ui_globals::visible_sw_lines = 0;
uint16_t ui_globals::panels_status = 0;
bool ui_globals::has_icons = false;
-// Custom filter
-ui::machine_filter::type custfltr::main = ui::machine_filter::ALL;
-uint16_t custfltr::numother = 0;
-ui::machine_filter::type custfltr::other[MAX_CUST_FILTER];
-uint16_t custfltr::mnfct[MAX_CUST_FILTER];
-uint16_t custfltr::year[MAX_CUST_FILTER];
-uint16_t custfltr::screen[MAX_CUST_FILTER];
-
-// Custom filter
-ui::software_filter::type sw_custfltr::main = ui::software_filter::ALL;
-uint16_t sw_custfltr::numother = 0;
-ui::software_filter::type sw_custfltr::other[MAX_CUST_FILTER];
-uint16_t sw_custfltr::mnfct[MAX_CUST_FILTER];
-uint16_t sw_custfltr::year[MAX_CUST_FILTER];
-uint16_t sw_custfltr::region[MAX_CUST_FILTER];
-uint16_t sw_custfltr::type[MAX_CUST_FILTER];
-uint16_t sw_custfltr::list[MAX_CUST_FILTER];
-
char* chartrimcarriage(char str[])
{
char *pstr = strrchr(str, '\n');
@@ -235,12 +1384,6 @@ int fuzzy_substring(std::string s_needle, std::string s_haystack)
// set manufacturers
//-------------------------------------------------
-void c_mnfct::set(const char *str)
-{
- std::string name = getname(str);
- uimap[name] = 0;
-}
-
std::string c_mnfct::getname(const char *str)
{
std::string name(str);
@@ -252,19 +1395,6 @@ std::string c_mnfct::getname(const char *str)
return name;
}
-//-------------------------------------------------
-// set years
-//-------------------------------------------------
-
-void c_year::set(const char *str)
-{
- std::string name(str);
- if (std::find(ui.begin(), ui.end(), name) != ui.end())
- return;
-
- ui.push_back(name);
-}
-
ui_software_info::ui_software_info(
software_info const &info,
diff --git a/src/frontend/mame/ui/utils.h b/src/frontend/mame/ui/utils.h
index abec24b9d73..0942728152c 100644
--- a/src/frontend/mame/ui/utils.h
+++ b/src/frontend/mame/ui/utils.h
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Maurizio Petrarota
+// copyright-holders:Maurizio Petrarota, Vas Crabb
/***************************************************************************
ui/utils.h
@@ -14,10 +14,111 @@
#include "unicode.h"
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+
+class mame_ui_manager;
+class render_container;
+
+
+// TODO: namespace this thing
+struct ui_software_info
+{
+ ui_software_info() { }
+
+ // info for software list item
+ ui_software_info(
+ software_info const &info,
+ software_part const &p,
+ game_driver const &d,
+ std::string const &li,
+ std::string const &is,
+ std::string const &de);
+
+ // info for starting empty
+ ui_software_info(game_driver const &d);
+
+ // copyable/movable
+ ui_software_info(ui_software_info const &) = default;
+ ui_software_info(ui_software_info &&) = default;
+ ui_software_info &operator=(ui_software_info const &) = default;
+ ui_software_info &operator=(ui_software_info &&) = default;
+
+ bool operator==(ui_software_info const &r)
+ {
+ return shortname == r.shortname && longname == r.longname && parentname == r.parentname
+ && year == r.year && publisher == r.publisher && supported == r.supported
+ && part == r.part && driver == r.driver && listname == r.listname
+ && interface == r.interface && instance == r.instance && startempty == r.startempty
+ && parentlongname == r.parentlongname && usage == r.usage && devicetype == r.devicetype;
+ }
+
+ std::string shortname;
+ std::string longname;
+ std::string parentname;
+ std::string year;
+ std::string publisher;
+ uint8_t supported = 0;
+ std::string part;
+ const game_driver *driver = nullptr;
+ std::string listname;
+ std::string interface;
+ std::string instance;
+ uint8_t startempty = 0;
+ std::string parentlongname;
+ std::string usage;
+ std::string devicetype;
+ bool available = false;
+};
+
namespace ui {
-class machine_filter
+struct s_filter; // FIXME: this is declared in custmenu.h, it shouldn't be
+
+template <class Impl, typename Entry>
+class filter_base
+{
+public:
+ typedef std::unique_ptr<Impl> ptr;
+
+ virtual ~filter_base() { }
+
+ virtual char const *config_name() const = 0;
+ virtual char const *display_name() const = 0;
+ virtual char const *filter_text() const = 0;
+
+ virtual bool apply(Entry const &info) const = 0;
+
+ virtual void show_ui(mame_ui_manager &mui, render_container &container, std::function<void (Impl &)> &&handler) = 0;
+
+ virtual bool wants_adjuster() const = 0;
+ virtual char const *adjust_text() const = 0;
+ virtual uint32_t arrow_flags() const = 0;
+ virtual bool adjust_left() = 0;
+ virtual bool adjust_right() = 0;
+
+ virtual void save_ini(emu_file &file, unsigned indent) const = 0;
+
+ template <typename InputIt, class OutputIt>
+ void apply(InputIt first, InputIt last, OutputIt dest) const
+ {
+ std::copy_if(first, last, dest, [this] (Entry const *info) { return apply(*info); });
+ }
+
+protected:
+ using entry_type = Entry;
+
+ filter_base() { }
+};
+
+
+class machine_filter : public filter_base<machine_filter, game_driver>
{
public:
enum type : uint16_t
@@ -32,7 +133,7 @@ public:
CATEGORY,
FAVORITE,
BIOS,
- PARENT,
+ PARENTS,
CLONES,
MANUFACTURER,
YEAR,
@@ -49,14 +150,28 @@ public:
LAST = COUNT - 1
};
+ virtual type get_type() const = 0;
+ virtual std::string adorned_display_name(type n) const = 0;
+
+ static ptr create(type n) { return create(n, nullptr, nullptr, 0); }
+ static ptr create(emu_file &file) { return create(file, 0); }
static char const *config_name(type n);
static char const *display_name(type n);
+
+ using filter_base<machine_filter, game_driver>::config_name;
+ using filter_base<machine_filter, game_driver>::display_name;
+
+protected:
+ machine_filter();
+
+ static ptr create(type n, char const *value, emu_file *file, unsigned indent);
+ static ptr create(emu_file &file, unsigned indent);
};
DECLARE_ENUM_INCDEC_OPERATORS(machine_filter::type)
-class software_filter
+class software_filter : public filter_base<software_filter, ui_software_info>
{
public:
enum type : uint16_t
@@ -66,7 +181,7 @@ public:
UNAVAILABLE,
PARENTS,
CLONES,
- YEARS,
+ YEAR,
PUBLISHERS,
SUPPORTED,
PARTIAL_SUPPORTED,
@@ -81,8 +196,22 @@ public:
LAST = COUNT - 1
};
+ virtual type get_type() const = 0;
+ virtual std::string adorned_display_name(type n) const = 0;
+
+ static ptr create(type n, s_filter const &data) { return create(n, data, nullptr, nullptr, 0); }
+ static ptr create(emu_file &file, s_filter const &data) { return create(file, data, 0); }
static char const *config_name(type n);
static char const *display_name(type n);
+
+ using filter_base<software_filter, ui_software_info>::config_name;
+ using filter_base<software_filter, ui_software_info>::display_name;
+
+protected:
+ software_filter();
+
+ static ptr create(type n, s_filter const &data, char const *value, emu_file *file, unsigned indent);
+ static ptr create(emu_file &file, s_filter const &data, unsigned indent);
};
DECLARE_ENUM_INCDEC_OPERATORS(software_filter::type)
@@ -151,108 +280,35 @@ enum
HOVER_RP_LAST = (HOVER_RP_FIRST) + 1 + RP_LAST
};
-// GLOBAL STRUCTURES
-struct ui_software_info
-{
- ui_software_info() { }
+// FIXME: this stuff shouldn't all be globals
- // info for software list item
- ui_software_info(
- software_info const &info,
- software_part const &p,
- game_driver const &d,
- std::string const &li,
- std::string const &is,
- std::string const &de);
-
- // info for starting empty
- ui_software_info(game_driver const &d);
-
- // copyable/movable
- ui_software_info(ui_software_info const &) = default;
- ui_software_info(ui_software_info &&) = default;
- ui_software_info &operator=(ui_software_info const &) = default;
- ui_software_info &operator=(ui_software_info &&) = default;
-
- bool operator==(ui_software_info const &r)
- {
- return shortname == r.shortname && longname == r.longname && parentname == r.parentname
- && year == r.year && publisher == r.publisher && supported == r.supported
- && part == r.part && driver == r.driver && listname == r.listname
- && interface == r.interface && instance == r.instance && startempty == r.startempty
- && parentlongname == r.parentlongname && usage == r.usage && devicetype == r.devicetype;
- }
-
- std::string shortname;
- std::string longname;
- std::string parentname;
- std::string year;
- std::string publisher;
- uint8_t supported = 0;
- std::string part;
- const game_driver *driver = nullptr;
- std::string listname;
- std::string interface;
- std::string instance;
- uint8_t startempty = 0;
- std::string parentlongname;
- std::string usage;
- std::string devicetype;
- bool available = false;
+// GLOBAL CLASS
+struct ui_globals
+{
+ static uint8_t curimage_view, curdats_view, curdats_total, cur_sw_dats_view, cur_sw_dats_total, rpanel;
+ static bool switch_image, redraw_icon, default_image, reset;
+ static int visible_main_lines, visible_sw_lines;
+ static uint16_t panels_status;
+ static bool has_icons;
};
// Manufacturers
struct c_mnfct
{
- static void set(const char *str);
static std::string getname(const char *str);
static std::vector<std::string> ui;
- static std::unordered_map<std::string, int> uimap;
- static uint16_t actual;
};
// Years
struct c_year
{
- static void set(const char *str);
static std::vector<std::string> ui;
- static uint16_t actual;
-};
-
-// GLOBAL CLASS
-struct ui_globals
-{
- static uint8_t curimage_view, curdats_view, curdats_total, cur_sw_dats_view, cur_sw_dats_total, rpanel;
- static bool switch_image, redraw_icon, default_image, reset;
- static int visible_main_lines, visible_sw_lines;
- static uint16_t panels_status;
- static bool has_icons;
-};
-
-struct main_filters { static ui::machine_filter::type actual; };
-
-// Custom filter
-struct custfltr
-{
- static ui::machine_filter::type main;
- static uint16_t numother;
- static ui::machine_filter::type other[MAX_CUST_FILTER];
- static uint16_t mnfct[MAX_CUST_FILTER];
- static uint16_t screen[MAX_CUST_FILTER];
- static uint16_t year[MAX_CUST_FILTER];
};
-// Software custom filter
-struct sw_custfltr
+struct main_filters
{
- static ui::software_filter::type main;
- static uint16_t numother;
- static ui::software_filter::type other[MAX_CUST_FILTER];
- static uint16_t mnfct[MAX_CUST_FILTER];
- static uint16_t year[MAX_CUST_FILTER];
- static uint16_t region[MAX_CUST_FILTER];
- static uint16_t type[MAX_CUST_FILTER];
- static uint16_t list[MAX_CUST_FILTER];
+ static ui::machine_filter::type actual;
+ static std::map<ui::machine_filter::type, ui::machine_filter::ptr> filters;
};
// GLOBAL FUNCTIONS