summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2017-08-21 21:45:15 +1000
committer Vas Crabb <vas@vastheman.com>2017-08-21 21:45:15 +1000
commit90f7fa47c2c28170ab0dd31e17ebcfbc95fe563f (patch)
tree1d8d5da3d231d35ae949ff5342e46dd4420af857
parentf9f4ae9d3654a8efb40e4beaf3bffee5f573e0a4 (diff)
UI improvements:
* Make (Un)Available a polymorphic filter (works in custom filter again) * Fix bugs and improve performance when detecting systems without ROMs * Show progress while auditing ROMs * Use actual INI file format for mame_avail.ini
-rw-r--r--src/frontend/mame/ui/auditmenu.cpp254
-rw-r--r--src/frontend/mame/ui/auditmenu.h43
-rw-r--r--src/frontend/mame/ui/menu.cpp5
-rw-r--r--src/frontend/mame/ui/selgame.cpp211
-rw-r--r--src/frontend/mame/ui/selgame.h12
-rw-r--r--src/frontend/mame/ui/slotopt.cpp2
-rw-r--r--src/frontend/mame/ui/slotopt.h6
-rw-r--r--src/frontend/mame/ui/utils.cpp52
-rw-r--r--src/frontend/mame/ui/utils.h27
9 files changed, 342 insertions, 270 deletions
diff --git a/src/frontend/mame/ui/auditmenu.cpp b/src/frontend/mame/ui/auditmenu.cpp
index 23c0eee30ba..0349e1c2949 100644
--- a/src/frontend/mame/ui/auditmenu.cpp
+++ b/src/frontend/mame/ui/auditmenu.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Maurizio Petrarota
+// copyright-holders:Maurizio Petrarota, Vas Crabb
/*********************************************************************
ui/auditmenu.cpp
@@ -9,39 +9,31 @@
*********************************************************************/
#include "emu.h"
+#include "ui/auditmenu.h"
+
#include "ui/ui.h"
-#include "ui/menu.h"
+
#include "audit.h"
-#include "ui/auditmenu.h"
#include "drivenum.h"
+#include <numeric>
+
+
extern const char UI_VERSION_TAG[];
namespace ui {
-//-------------------------------------------------
-// sort
-//-------------------------------------------------
-inline int cs_stricmp(const char *s1, const char *s2)
-{
- for (;;)
- {
- int c1 = tolower(*s1++);
- int c2 = tolower(*s2++);
- if (c1 == 0 || c1 != c2)
- return c1 - c2;
- }
-}
+namespace {
-bool sorted_game_list(const game_driver *x, const game_driver *y)
-{
- bool clonex = (x->parent[0] != '0');
- bool cloney = (y->parent[0] != '0');
+void *const ITEMREF_START = reinterpret_cast<void *>(std::uintptr_t(1));
+
+} // anonymous namespace
- if (!clonex && !cloney)
- return (cs_stricmp(x->type.fullname(), y->type.fullname()) < 0);
- int cx = -1, cy = -1;
+bool sorted_game_list(const game_driver *x, const game_driver *y)
+{
+ bool clonex = (x->parent[0] != '0') || x->parent[1];
+ int cx = -1;
if (clonex)
{
cx = driver_list::find(x->parent);
@@ -49,6 +41,8 @@ bool sorted_game_list(const game_driver *x, const game_driver *y)
clonex = false;
}
+ bool cloney = (y->parent[0] != '0') || y->parent[1];
+ int cy = -1;
if (cloney)
{
cy = driver_list::find(y->parent);
@@ -57,123 +51,181 @@ bool sorted_game_list(const game_driver *x, const game_driver *y)
}
if (!clonex && !cloney)
- return (cs_stricmp(x->type.fullname(), y->type.fullname()) < 0);
+ {
+ return (core_stricmp(x->type.fullname(), y->type.fullname()) < 0);
+ }
else if (clonex && cloney)
{
- if (!cs_stricmp(x->parent, y->parent))
- return (cs_stricmp(x->type.fullname(), y->type.fullname()) < 0);
+ if (!core_stricmp(x->parent, y->parent))
+ return (core_stricmp(x->type.fullname(), y->type.fullname()) < 0);
else
- return (cs_stricmp(driver_list::driver(cx).type.fullname(), driver_list::driver(cy).type.fullname()) < 0);
+ return (core_stricmp(driver_list::driver(cx).type.fullname(), driver_list::driver(cy).type.fullname()) < 0);
}
else if (!clonex && cloney)
{
- if (!cs_stricmp(x->name, y->parent))
+ if (!core_stricmp(x->name, y->parent))
return true;
else
- return (cs_stricmp(x->type.fullname(), driver_list::driver(cy).type.fullname()) < 0);
+ return (core_stricmp(x->type.fullname(), driver_list::driver(cy).type.fullname()) < 0);
}
else
{
- if (!cs_stricmp(x->parent, y->name))
+ if (!core_stricmp(x->parent, y->name))
return false;
else
- return (cs_stricmp(driver_list::driver(cx).type.fullname(), y->type.fullname()) < 0);
+ return (core_stricmp(driver_list::driver(cx).type.fullname(), y->type.fullname()) < 0);
}
}
-//-------------------------------------------------
-// ctor / dtor
-//-------------------------------------------------
-menu_audit::menu_audit(mame_ui_manager &mui, render_container &container, vptr_game &availablesorted, vptr_game &unavailablesorted, int _audit_mode)
+menu_audit::menu_audit(mame_ui_manager &mui, render_container &container, std::vector<ui_system_info> &availablesorted, mode audit_mode)
: menu(mui, container)
+ , m_worker_thread()
+ , m_audit_mode(audit_mode)
+ , m_total((mode::FAST == audit_mode)
+ ? std::accumulate(availablesorted.begin(), availablesorted.end(), std::size_t(0), [] (std::size_t n, ui_system_info const &info) { return n + (info.available ? 0 : 1); })
+ : availablesorted.size())
, m_availablesorted(availablesorted)
- , m_unavailablesorted(unavailablesorted)
- , m_audit_mode(_audit_mode)
- , m_first(true)
+ , m_audited(0)
+ , m_current(nullptr)
+ , m_phase(phase::CONSENT)
{
- if (m_audit_mode == 2)
+ switch (m_audit_mode)
{
- m_availablesorted.clear();
- m_unavailablesorted.clear();
+ case mode::FAST:
+ m_prompt[0] = util::string_format(_("Audit ROMs for %1$u machines marked unavailable?"), m_total);
+ break;
+ case mode::ALL:
+ m_prompt[0] = util::string_format(_("Audit ROMs for all %1$u machines?"), m_total);
+ break;
}
+ std::string filename(emulator_info::get_configname());
+ filename += "_avail.ini";
+ m_prompt[1] = util::string_format(_("(results will be saved to %1$s)"), filename);
}
menu_audit::~menu_audit()
{
}
-//-------------------------------------------------
-// handle
-//-------------------------------------------------
-
-void menu_audit::handle()
+void menu_audit::custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2)
{
- process(PROCESS_CUSTOM_ONLY);
-
- if (m_first)
+ switch (m_phase)
{
- ui().draw_text_box(container(), _("Audit in progress..."), ui::text_layout::CENTER, 0.5f, 0.5f, UI_GREEN_COLOR);
- m_first = false;
- return;
+ case phase::CONSENT:
+ draw_text_box(
+ std::begin(m_prompt), std::end(m_prompt),
+ 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);
+ break;
+
+ case phase::AUDIT:
+ {
+ // there's a race here between the total audited being updated and the next driver pointer being loaded
+ // it doesn't matter because we redraw on every frame anyway so it sorts itself out very quickly
+ game_driver const *const driver(m_current.load());
+ std::size_t const audited(m_audited.load());
+ std::string const text(util::string_format(
+ _("Auditing ROMs for machine %2$u of %3$u...\n%1$s"),
+ driver ? driver->type.fullname() : "",
+ audited + 1,
+ m_total));
+ ui().draw_text_box(container(), text.c_str(), ui::text_layout::CENTER, 0.5f, 0.5f, UI_GREEN_COLOR);
+ }
+ break;
}
+}
+
+void menu_audit::populate(float &customtop, float &custombottom)
+{
+ item_append(_("Start Audit"), "", 0, ITEMREF_START);
+ customtop = (ui().get_line_height() * 2.0f) + (UI_BOX_TB_BORDER * 3.0f);
+}
- if (m_audit_mode == 1)
+void menu_audit::handle()
+{
+ switch (m_phase)
{
- vptr_game::iterator iter = m_unavailablesorted.begin();
- while (iter != m_unavailablesorted.end())
+ case phase::CONSENT:
{
- driver_enumerator enumerator(machine().options(), (*iter)->name);
- enumerator.next();
- media_auditor auditor(enumerator);
- media_auditor::summary summary = auditor.audit_media(AUDIT_VALIDATE_FAST);
-
- // if everything looks good, include the driver
- if (summary == media_auditor::CORRECT || summary == media_auditor::BEST_AVAILABLE || summary == media_auditor::NONE_NEEDED)
+ event const *const menu_event(process(0));
+ if (menu_event && (ITEMREF_START == menu_event->itemref) && (IPT_UI_SELECT == menu_event->iptkey))
{
- m_availablesorted.push_back((*iter));
- iter = m_unavailablesorted.erase(iter);
+ m_phase = phase::AUDIT;
+ m_worker_thread = std::thread(
+ [this] ()
+ {
+ switch (m_audit_mode)
+ {
+ case mode::FAST:
+ audit_fast();
+ return;
+ case mode::ALL:
+ audit_all();
+ return;
+ }
+ throw false;
+ });
}
- else
- ++iter;
}
+ break;
+
+ case phase::AUDIT:
+ process(PROCESS_CUSTOM_ONLY | PROCESS_NOINPUT);
+
+ if (m_audited.load() >= m_total)
+ {
+ m_worker_thread.join();
+ save_available_machines();
+ reset_parent(reset_options::SELECT_FIRST);
+ stack_pop();
+ }
+ break;
}
- else
+}
+
+void menu_audit::audit_fast()
+{
+ for (ui_system_info &info : m_availablesorted)
{
- driver_enumerator enumerator(machine().options());
- media_auditor auditor(enumerator);
- while (enumerator.next())
+ if (!info.available)
{
- media_auditor::summary summary = auditor.audit_media(AUDIT_VALIDATE_FAST);
+ m_current.store(info.driver);
+ driver_enumerator enumerator(machine().options(), info.driver->name);
+ enumerator.next();
+ media_auditor auditor(enumerator);
+ media_auditor::summary const summary(auditor.audit_media(AUDIT_VALIDATE_FAST));
+ info.available = (summary == media_auditor::CORRECT) || (summary == media_auditor::BEST_AVAILABLE) || (summary == media_auditor::NONE_NEEDED);
// if everything looks good, include the driver
- if (summary == media_auditor::CORRECT || summary == media_auditor::BEST_AVAILABLE || summary == media_auditor::NONE_NEEDED)
- m_availablesorted.push_back(&enumerator.driver());
- else
- m_unavailablesorted.push_back(&enumerator.driver());
+ info.available = (summary == media_auditor::CORRECT) || (summary == media_auditor::BEST_AVAILABLE) || (summary == media_auditor::NONE_NEEDED);
+ ++m_audited;
}
}
-
- // sort
- std::stable_sort(m_availablesorted.begin(), m_availablesorted.end(), sorted_game_list);
- std::stable_sort(m_unavailablesorted.begin(), m_unavailablesorted.end(), sorted_game_list);
- save_available_machines();
- reset_parent(reset_options::SELECT_FIRST);
- stack_pop();
}
-//-------------------------------------------------
-// populate
-//-------------------------------------------------
-
-void menu_audit::populate(float &customtop, float &custombottom)
+void menu_audit::audit_all()
{
- item_append("Dummy", "", 0, (void *)(uintptr_t)1);
-}
+ m_availablesorted.clear();
+ driver_enumerator enumerator(machine().options());
+ media_auditor auditor(enumerator);
+ while (enumerator.next())
+ {
+ m_current.store(&enumerator.driver());
+ media_auditor::summary const summary(auditor.audit_media(AUDIT_VALIDATE_FAST));
-//-------------------------------------------------
-// save drivers infos to file
-//-------------------------------------------------
+ // if everything looks good, include the driver
+ m_availablesorted.emplace_back(enumerator.driver(), (summary == media_auditor::CORRECT) || (summary == media_auditor::BEST_AVAILABLE) || (summary == media_auditor::NONE_NEEDED));
+ ++m_audited;
+ }
+
+ // sort
+ std::stable_sort(
+ m_availablesorted.begin(),
+ m_availablesorted.end(),
+ [] (ui_system_info const &a, ui_system_info const &b) { return sorted_game_list(a.driver, b.driver); });
+}
void menu_audit::save_available_machines()
{
@@ -182,25 +234,15 @@ void menu_audit::save_available_machines()
if (file.open(emulator_info::get_configname(), "_avail.ini") == osd_file::error::NONE)
{
// generate header
- std::ostringstream buffer;
- buffer << "#\n" << UI_VERSION_TAG << emulator_info::get_bare_build_version() << "\n#\n\n";
- util::stream_format(buffer, "%d\n", m_availablesorted.size());
- util::stream_format(buffer, "%d\n", m_unavailablesorted.size());
+ file.printf("#\n%s%s\n#\n\n", UI_VERSION_TAG, emulator_info::get_bare_build_version());
// generate available list
- for (size_t x = 0; x < m_availablesorted.size(); ++x)
+ for (ui_system_info const &info : m_availablesorted)
{
- int find = driver_list::find(m_availablesorted[x]->name);
- util::stream_format(buffer, "%d\n", find);
+ if (info.available)
+ file.printf("%s\n", info.driver->name);
}
- // generate unavailable list
- for (size_t x = 0; x < m_unavailablesorted.size(); ++x)
- {
- int find = driver_list::find(m_unavailablesorted[x]->name);
- util::stream_format(buffer, "%d\n", find);
- }
- file.puts(buffer.str().c_str());
file.close();
}
}
diff --git a/src/frontend/mame/ui/auditmenu.h b/src/frontend/mame/ui/auditmenu.h
index aadebcbac9f..435bf52cd34 100644
--- a/src/frontend/mame/ui/auditmenu.h
+++ b/src/frontend/mame/ui/auditmenu.h
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Maurizio Petrarota
+// copyright-holders:Maurizio Petrarota, Vas Crabb
/***************************************************************************
ui/auditmenu.h
@@ -7,41 +7,54 @@
Internal UI user interface.
***************************************************************************/
-
-#pragma once
-
#ifndef MAME_FRONTEND_UI_AUDITMENU_H
#define MAME_FRONTEND_UI_AUDITMENU_H
+#pragma once
+
#include "ui/menu.h"
+#include "ui/utils.h"
+
+#include <atomic>
+#include <thread>
+#include <vector>
+
namespace ui {
-//-------------------------------------------------
-// class audit menu
-//-------------------------------------------------
-using vptr_game = std::vector<const game_driver *>;
class menu_audit : public menu
{
public:
- menu_audit(mame_ui_manager &mui, render_container &container, vptr_game &availablesorted, vptr_game &unavailablesorted, int audit_mode);
+ enum class mode { FAST, ALL };
+
+ menu_audit(mame_ui_manager &mui, render_container &container, std::vector<ui_system_info> &availablesorted, mode audit_mode);
virtual ~menu_audit() override;
+protected:
+ virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
+
private:
+ enum class phase { CONSENT, AUDIT };
+
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle() override;
+ void audit_fast();
+ void audit_all();
void save_available_machines();
- vptr_game &m_availablesorted;
- vptr_game &m_unavailablesorted;
-
- int m_audit_mode;
- bool m_first;
+ std::thread m_worker_thread;
+ mode const m_audit_mode;
+ std::size_t const m_total;
+ std::string m_prompt[2];
+ std::vector<ui_system_info> &m_availablesorted;
+ std::atomic<std::size_t> m_audited;
+ std::atomic<game_driver const *> m_current;
+ phase m_phase;
};
bool sorted_game_list(const game_driver *x, const game_driver *y);
} // namespace ui
-#endif /* MAME_FRONTEND_UI_AUDITMENU_H */
+#endif // MAME_FRONTEND_UI_AUDITMENU_H
diff --git a/src/frontend/mame/ui/menu.cpp b/src/frontend/mame/ui/menu.cpp
index 5f1056bc45d..a68b4e016f7 100644
--- a/src/frontend/mame/ui/menu.cpp
+++ b/src/frontend/mame/ui/menu.cpp
@@ -453,7 +453,10 @@ const menu::event *menu::process(uint32_t flags, float x0, float y0)
m_event.type = item[selected].type;
return &m_event;
}
- return nullptr;
+ else
+ {
+ return nullptr;
+ }
}
diff --git a/src/frontend/mame/ui/selgame.cpp b/src/frontend/mame/ui/selgame.cpp
index 9deb0ef6649..c22cb3a54a5 100644
--- a/src/frontend/mame/ui/selgame.cpp
+++ b/src/frontend/mame/ui/selgame.cpp
@@ -30,6 +30,9 @@
#include "uiinput.h"
#include "luaengine.h"
+#include <cstring>
+#include <iterator>
+
extern const char UI_VERSION_TAG[];
@@ -326,12 +329,12 @@ void menu_select_game::handle()
break;
case IPT_UI_AUDIT_FAST:
- if (!m_unavailsortedlist.empty())
- menu::stack_push<menu_audit>(ui(), container(), m_availsortedlist, m_unavailsortedlist, 1);
+ if (std::find_if(m_availsortedlist.begin(), m_availsortedlist.end(), [] (ui_system_info const &info) { return !info.available; }) != m_availsortedlist.end())
+ menu::stack_push<menu_audit>(ui(), container(), m_availsortedlist, menu_audit::mode::FAST);
break;
case IPT_UI_AUDIT_ALL:
- menu::stack_push<menu_audit>(ui(), container(), m_availsortedlist, m_unavailsortedlist, 2);
+ menu::stack_push<menu_audit>(ui(), container(), m_availsortedlist, menu_audit::mode::ALL);
break;
}
}
@@ -367,44 +370,25 @@ void menu_select_game::populate(float &customtop, float &custombottom)
m_displaylist.clear();
// if filter is set on category, build category list
- switch (main_filters::actual)
- {
- case machine_filter::ALL:
- m_displaylist = m_sortedlist;
- break;
- case machine_filter::AVAILABLE:
- m_displaylist = m_availsortedlist;
- break;
- case machine_filter::UNAVAILABLE:
- m_displaylist = m_unavailsortedlist;
- break;
- default:
- {
- 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); });
- }
- }
+ auto const it(main_filters::filters.find(main_filters::actual));
+ it->second->apply(m_availsortedlist.begin(), m_availsortedlist.end(), std::back_inserter(m_displaylist));
// iterate over entries
int curitem = 0;
- for (auto & elem : m_displaylist)
+ for (ui_system_info const &elem : m_displaylist)
{
- if (old_item_selected == -1 && elem->name == reselect_last::driver())
+ if (old_item_selected == -1 && elem.driver->name == reselect_last::driver())
old_item_selected = curitem;
- bool cloneof = strcmp(elem->parent, "0");
+ bool cloneof = strcmp(elem.driver->parent, "0");
if (cloneof)
{
- int cx = driver_list::find(elem->parent);
+ int cx = driver_list::find(elem.driver->parent);
if (cx != -1 && ((driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT) != 0))
cloneof = false;
}
- item_append(elem->type.fullname(), "", (cloneof) ? (flags_ui | FLAG_INVERT) : flags_ui, (void *)elem);
+ item_append(elem.driver->type.fullname(), "", (cloneof) ? (flags_ui | FLAG_INVERT) : flags_ui, (void *)elem.driver);
curitem++;
}
}
@@ -490,19 +474,16 @@ void menu_select_game::populate(float &customtop, float &custombottom)
void menu_select_game::build_available_list()
{
- int m_total = driver_list::total();
- std::vector<bool> m_included(m_total, false);
+ std::size_t const total = driver_list::total();
+ std::vector<bool> included(total, false);
- // open a path to the ROMs and find them in the array
+ // iterate over ROM directories and look for potential ROMs
file_enumerator path(machine().options().media_path());
- const osd::directory::entry *dir;
-
- // iterate while we get new objects
- while ((dir = path.next()) != nullptr)
+ for (osd::directory::entry const *dir = path.next(); dir; dir = path.next())
{
char drivername[50];
char *dst = drivername;
- const char *src;
+ char const *src;
// build a name for it
for (src = dir->name; *src != 0 && *src != '.' && dst < &drivername[ARRAY_LENGTH(drivername) - 1]; ++src)
@@ -510,67 +491,63 @@ void menu_select_game::build_available_list()
*dst = 0;
int drivnum = driver_list::find(drivername);
- if (drivnum != -1 && !m_included[drivnum])
- {
- m_availsortedlist.push_back(&driver_list::driver(drivnum));
- m_included[drivnum] = true;
- }
+ if (drivnum != -1 && !included[drivnum])
+ included[drivnum] = true;
}
// now check and include NONE_NEEDED
if (!ui().options().hide_romless())
{
- for (int x = 0; x < m_total; ++x)
+ // FIXME: can't use the convenience macros tiny ROM entries
+ auto const is_required_rom =
+ [] (tiny_rom_entry const &rom)
+ {
+ return ((rom.flags & ROMENTRY_TYPEMASK) == ROMENTRYTYPE_ROM) && ((rom.flags & ROM_OPTIONALMASK) != ROM_OPTIONAL) && !std::strchr(rom.hashdata, '!');
+ };
+ for (std::size_t x = 0; total > x; ++x)
{
- auto driver = &driver_list::driver(x);
- if (!m_included[x] && driver != &GAME_NAME(___empty))
+ game_driver const &driver(driver_list::driver(x));
+ if (!included[x] && (&GAME_NAME(___empty) != &driver))
{
- auto entries = rom_build_entries(driver->rom);
- const rom_entry *rom = entries.data();
- bool noroms = true;
-
- // check NO-DUMP
- for (; !ROMENTRY_ISEND(rom) && noroms == true; ++rom)
- if (ROMENTRY_ISFILE(rom))
+ bool noroms(true);
+ tiny_rom_entry const *rom;
+ for (rom = driver.rom; (rom->flags & ROMENTRY_TYPEMASK) != ROMENTRYTYPE_END; ++rom)
+ {
+ // check optional and NO_DUMP
+ if (is_required_rom(*rom))
{
- util::hash_collection hashes(ROM_GETHASHDATA(rom));
- if (!hashes.flag(util::hash_collection::FLAG_NO_DUMP) && !ROM_ISOPTIONAL(rom))
- noroms = false;
+ noroms = false;
+ break; // break before incrementing, or it will subtly break the check for all ROMs belonging to parent
}
+ }
if (!noroms)
{
// check if clone == parent
- auto cx = driver_list::clone(*driver);
- if (cx != -1 && m_included[cx])
+ auto const cx(driver_list::clone(driver));
+ if ((0 <= cx) && included[cx])
{
- auto drv = &driver_list::driver(cx);
- if (driver->rom == drv->rom)
+ game_driver const &parent(driver_list::driver(cx));
+ if (driver.rom == parent.rom)
+ {
noroms = true;
-
- // check if clone < parent
- if (!noroms)
+ }
+ else
{
+ // check if clone < parent
noroms = true;
- for (; !ROMENTRY_ISEND(rom) && noroms == true; ++rom)
+ for ( ; noroms && rom && ((rom->flags & ROMENTRY_TYPEMASK) != ROMENTRYTYPE_END); ++rom)
{
- if (ROMENTRY_ISFILE(rom))
+ if (is_required_rom(*rom))
{
- util::hash_collection hashes(ROM_GETHASHDATA(rom));
- if (hashes.flag(util::hash_collection::FLAG_NO_DUMP) || ROM_ISOPTIONAL(rom))
- continue;
-
- uint64_t lenght = ROM_GETLENGTH(rom);
- auto found = false;
- auto parent_entries = rom_build_entries(drv->rom);
- for (auto parentrom = parent_entries.data(); !ROMENTRY_ISEND(parentrom) && found == false; ++parentrom)
+ util::hash_collection const hashes(rom->hashdata);
+
+ bool found(false);
+ for (tiny_rom_entry const *parentrom = parent.rom; !found && ((parentrom->flags & ROMENTRY_TYPEMASK) != ROMENTRYTYPE_END); ++parentrom)
{
- if (ROMENTRY_ISFILE(parentrom) && ROM_GETLENGTH(parentrom) == lenght)
+ if (is_required_rom(*parentrom) && (rom->length == parentrom->length))
{
- util::hash_collection parenthashes(ROM_GETHASHDATA(parentrom));
- if (parenthashes.flag(util::hash_collection::FLAG_NO_DUMP) || ROM_ISOPTIONAL(parentrom))
- continue;
-
+ util::hash_collection const parenthashes(parentrom->hashdata);
if (hashes == parenthashes)
found = true;
}
@@ -583,23 +560,23 @@ void menu_select_game::build_available_list()
}
if (noroms)
- {
- m_availsortedlist.push_back(&driver_list::driver(x));
- m_included[x] = true;
- }
+ included[x] = true;
}
}
}
- // sort
- std::stable_sort(m_availsortedlist.begin(), m_availsortedlist.end(), sorted_game_list);
-
- // now build the unavailable list
- for (int x = 0; x < m_total; ++x)
- if (!m_included[x] && &driver_list::driver(x) != &GAME_NAME(___empty))
- m_unavailsortedlist.push_back(&driver_list::driver(x));
// sort
- std::stable_sort(m_unavailsortedlist.begin(), m_unavailsortedlist.end(), sorted_game_list);
+ m_availsortedlist.reserve(total);
+ for (std::size_t x = 0; total > x; ++x)
+ {
+ game_driver const &driver(driver_list::driver(x));
+ if (&driver != &GAME_NAME(___empty))
+ m_availsortedlist.emplace_back(driver, included[x]);
+ }
+ std::stable_sort(
+ m_availsortedlist.begin(),
+ m_availsortedlist.end(),
+ [] (ui_system_info const &a, ui_system_info const &b) { return sorted_game_list(a.driver, b.driver); });
}
@@ -823,8 +800,8 @@ void menu_select_game::populate_search()
for (; index < m_displaylist.size(); ++index)
{
// pick the best match between driver name and description
- int curpenalty = fuzzy_substring(m_search, m_displaylist[index]->type.fullname());
- int tmp = fuzzy_substring(m_search, m_displaylist[index]->name);
+ int curpenalty = fuzzy_substring(m_search, m_displaylist[index].driver->type.fullname());
+ int tmp = fuzzy_substring(m_search, m_displaylist[index].driver->name);
curpenalty = std::min(curpenalty, tmp);
// insert into the sorted table of matches
@@ -841,7 +818,7 @@ void menu_select_game::populate_search()
m_searchlist[matchnum + 1] = m_searchlist[matchnum];
}
- m_searchlist[matchnum] = m_displaylist[index];
+ m_searchlist[matchnum] = m_displaylist[index].driver;
penalty[matchnum] = curpenalty;
}
}
@@ -1033,7 +1010,9 @@ void menu_select_game::inkey_export()
}
else
{
- list = m_displaylist;
+ list.reserve(m_displaylist.size());
+ for (ui_system_info const &info : m_displaylist)
+ list.emplace_back(info.driver);
}
}
@@ -1086,8 +1065,8 @@ bool menu_select_game::load_available_machines()
if (file.open(emulator_info::get_configname(), "_avail.ini") != osd_file::error::NONE)
return false;
- std::string readbuf;
char rbuf[MAX_CHAR_INFO];
+ std::string readbuf;
file.gets(rbuf, MAX_CHAR_INFO);
file.gets(rbuf, MAX_CHAR_INFO);
readbuf = chartrimcarriage(rbuf);
@@ -1100,28 +1079,40 @@ bool menu_select_game::load_available_machines()
return false;
}
- file.gets(rbuf, MAX_CHAR_INFO);
- file.gets(rbuf, MAX_CHAR_INFO);
- file.gets(rbuf, MAX_CHAR_INFO);
- auto avsize = atoi(rbuf);
- file.gets(rbuf, MAX_CHAR_INFO);
- auto unavsize = atoi(rbuf);
-
// load available list
- for (int x = 0; x < avsize; ++x)
+ std::unordered_set<std::string> available;
+ while (file.gets(rbuf, MAX_CHAR_INFO))
{
- file.gets(rbuf, MAX_CHAR_INFO);
- int find = atoi(rbuf);
- m_availsortedlist.push_back(&driver_list::driver(find));
+ readbuf = rbuf;
+ strtrimspace(readbuf);
+
+ if (readbuf.empty() || ('#' == readbuf[0])) // ignore empty lines and line comments
+ ;
+ else if ('[' == readbuf[0]) // throw out the rest of the file if we find a section heading
+ break;
+ else
+ available.emplace(std::move(readbuf));
}
- // load unavailable list
- for (int x = 0; x < unavsize; ++x)
+ // turn it into the sorted system list we all love
+ m_availsortedlist.reserve(driver_list::total());
+ for (std::size_t x = 0; driver_list::total() > x; ++x)
{
- file.gets(rbuf, MAX_CHAR_INFO);
- int find = atoi(rbuf);
- m_unavailsortedlist.push_back(&driver_list::driver(find));
+ game_driver const &driver(driver_list::driver(x));
+ if (&driver != &GAME_NAME(___empty))
+ {
+ std::unordered_set<std::string>::iterator const it(available.find(&driver.name[0]));
+ bool const found(available.end() != it);
+ m_availsortedlist.emplace_back(driver, found);
+ if (found)
+ available.erase(it);
+ }
}
+ std::stable_sort(
+ m_availsortedlist.begin(),
+ m_availsortedlist.end(),
+ [] (ui_system_info const &a, ui_system_info const &b) { return sorted_game_list(a.driver, b.driver); });
+
file.close();
return true;
}
diff --git a/src/frontend/mame/ui/selgame.h b/src/frontend/mame/ui/selgame.h
index 49d4896f834..5778b2c544c 100644
--- a/src/frontend/mame/ui/selgame.h
+++ b/src/frontend/mame/ui/selgame.h
@@ -7,13 +7,14 @@
Main UI menu.
***************************************************************************/
-
-#pragma once
-
#ifndef MAME_FRONTEND_UI_SELGAME_H
#define MAME_FRONTEND_UI_SELGAME_H
+#pragma once
+
#include "ui/selmenu.h"
+#include "ui/utils.h"
+
class media_auditor;
@@ -41,9 +42,8 @@ private:
static int m_isabios;
static std::vector<const game_driver *> m_sortedlist;
- std::vector<const game_driver *> m_availsortedlist;
- std::vector<const game_driver *> m_unavailsortedlist;
- std::vector<const game_driver *> m_displaylist;
+ std::vector<ui_system_info> m_availsortedlist;
+ std::vector<ui_system_info> m_displaylist;
const game_driver *m_searchlist[VISIBLE_GAMES_IN_SEARCH + 1];
diff --git a/src/frontend/mame/ui/slotopt.cpp b/src/frontend/mame/ui/slotopt.cpp
index 74889c42df9..d61246a7661 100644
--- a/src/frontend/mame/ui/slotopt.cpp
+++ b/src/frontend/mame/ui/slotopt.cpp
@@ -291,7 +291,7 @@ void menu_slot_devices::rotate_slot_device(device_slot_interface &slot, menu_slo
{
return opt_value == target;
});
-
+
// we expect the above search to succeed, because if an internal
// option was selected, the menu item should be disabled
assert(m_current_option_list_iter != m_current_option_list.end());
diff --git a/src/frontend/mame/ui/slotopt.h b/src/frontend/mame/ui/slotopt.h
index 3f0b98850d7..1a4421520d4 100644
--- a/src/frontend/mame/ui/slotopt.h
+++ b/src/frontend/mame/ui/slotopt.h
@@ -43,9 +43,9 @@ private:
// variables
std::unique_ptr<machine_config> m_config;
std::unordered_map<std::string, std::string> m_slot_options;
- std::string m_current_option_list_slot_tag;
- std::vector<std::string> m_current_option_list;
- std::vector<std::string>::const_iterator m_current_option_list_iter;
+ std::string m_current_option_list_slot_tag;
+ std::vector<std::string> m_current_option_list;
+ std::vector<std::string>::const_iterator m_current_option_list_iter;
};
} // namespace ui
diff --git a/src/frontend/mame/ui/utils.cpp b/src/frontend/mame/ui/utils.cpp
index 3de86372fbe..bd5d87f774e 100644
--- a/src/frontend/mame/ui/utils.cpp
+++ b/src/frontend/mame/ui/utils.cpp
@@ -637,13 +637,23 @@ void composite_filter_impl_base<Impl, Base, Type>::menu_configure::handle()
// invertable machine filters
//-------------------------------------------------
+template <machine_filter::type Type = machine_filter::AVAILABLE>
+class available_machine_filter_impl : public simple_filter_impl_base<machine_filter, Type>
+{
+public:
+ available_machine_filter_impl(char const *value, emu_file *file, unsigned indent) { }
+
+ virtual bool apply(ui_system_info const &system) const override { return system.available; }
+};
+
+
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); }
+ virtual bool apply(ui_system_info const &system) const override { return !(system.driver->flags & machine_flags::NOT_WORKING); }
};
@@ -653,7 +663,7 @@ class mechanical_machine_filter_impl : public simple_filter_impl_base<machine_fi
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; }
+ virtual bool apply(ui_system_info const &system) const override { return system.driver->flags & machine_flags::MECHANICAL; }
};
@@ -663,7 +673,7 @@ class bios_machine_filter_impl : public simple_filter_impl_base<machine_filter,
public:
bios_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::IS_BIOS_ROOT; }
+ virtual bool apply(ui_system_info const &system) const override { return system.driver->flags & machine_flags::IS_BIOS_ROOT; }
};
@@ -673,10 +683,10 @@ class parents_machine_filter_impl : public simple_filter_impl_base<machine_filte
public:
parents_machine_filter_impl(char const *value, emu_file *file, unsigned indent) { }
- virtual bool apply(game_driver const &driver) const override
+ virtual bool apply(ui_system_info const &system) const override
{
- bool const have_parent(strcmp(driver.parent, "0"));
- auto const parent_idx(have_parent ? driver_list::find(driver.parent) : -1);
+ bool const have_parent(strcmp(system.driver->parent, "0"));
+ auto const parent_idx(have_parent ? driver_list::find(system.driver->parent) : -1);
return !have_parent || (0 > parent_idx) || (driver_list::driver(parent_idx).flags & machine_flags::IS_BIOS_ROOT);
}
};
@@ -688,9 +698,9 @@ class chd_machine_filter_impl : public simple_filter_impl_base<machine_filter, T
public:
chd_machine_filter_impl(char const *value, emu_file *file, unsigned indent) { }
- virtual bool apply(game_driver const &driver) const override
+ virtual bool apply(ui_system_info const &system) const override
{
- for (tiny_rom_entry const *rom = driver.rom; rom && rom->name; ++rom)
+ for (tiny_rom_entry const *rom = system.driver->rom; ((rom->flags & ROMENTRY_TYPEMASK) != ROMENTRYTYPE_END) && 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)))
@@ -707,7 +717,7 @@ class save_machine_filter_impl : public simple_filter_impl_base<machine_filter,
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; }
+ virtual bool apply(ui_system_info const &system) const override { return system.driver->flags & machine_flags::SUPPORTS_SAVE; }
};
@@ -717,7 +727,7 @@ class vertical_machine_filter_impl : public simple_filter_impl_base<machine_filt
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; }
+ virtual bool apply(ui_system_info const &system) const override { return system.driver->flags & machine_flags::SWAP_XY; }
};
@@ -734,14 +744,14 @@ public:
{
}
- virtual bool apply(game_driver const &driver) const override
+ virtual bool apply(ui_system_info const &system) const override
{
if (!have_choices())
return true;
else if (!selection_valid())
return false;
- std::string const name(c_mnfct::getname(driver.manufacturer));
+ std::string const name(c_mnfct::getname(system.driver->manufacturer));
return !name.empty() && (selection_text() == name);
}
};
@@ -755,7 +765,7 @@ public:
{
}
- virtual bool apply(game_driver const &driver) const override { return !have_choices() || (selection_valid() && (selection_text() == driver.year)); }
+ virtual bool apply(ui_system_info const &system) const override { return !have_choices() || (selection_valid() && (selection_text() == system.driver->year)); }
};
@@ -770,9 +780,10 @@ class inverted_machine_filter : public Base<Type>
public:
inverted_machine_filter(char const *value, emu_file *file, unsigned indent) : Base<Type>(value, file, indent) { }
- virtual bool apply(game_driver const &driver) const override { return !Base<Type>::apply(driver); }
+ virtual bool apply(ui_system_info const &system) const override { return !Base<Type>::apply(system); }
};
+using available_machine_filter = available_machine_filter_impl<>;
using working_machine_filter = working_machine_filter_impl<>;
using mechanical_machine_filter = mechanical_machine_filter_impl<>;
using bios_machine_filter = bios_machine_filter_impl<>;
@@ -781,6 +792,7 @@ 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 unavailable_machine_filter = inverted_machine_filter<available_machine_filter_impl, machine_filter::UNAVAILABLE>;
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 not_bios_machine_filter = inverted_machine_filter<bios_machine_filter_impl, machine_filter::NOT_BIOS>;
@@ -801,12 +813,10 @@ class inclusive_machine_filter_impl : public simple_filter_impl_base<machine_fil
public:
inclusive_machine_filter_impl(char const *value, emu_file *file, unsigned indent) { }
- virtual bool apply(game_driver const &drv) const override { return true; }
+ virtual bool apply(ui_system_info const &system) const override { 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>;
@@ -881,7 +891,7 @@ public:
file.puts(util::string_format("%2$*1$s%3$s = %4$s\n", 2 * indent, "", this->config_name(), text ? text : "").c_str());
}
- virtual bool apply(game_driver const &drv) const override
+ virtual bool apply(ui_system_info const &system) const override
{
inifile_manager const &mgr(mame_machine_manager::instance()->inifile());
if (!mgr.get_file_count())
@@ -893,12 +903,12 @@ public:
mame_machine_manager::instance()->inifile().load_ini_category(m_ini, m_group, m_cache);
m_cache_valid = true;
- if (m_cache.end() != m_cache.find(&drv))
+ if (m_cache.end() != m_cache.find(system.driver))
return true;
if (m_include_clones)
{
- int const found(driver_list::find(drv.parent));
+ int const found(driver_list::find(system.driver->parent));
return m_cache.end() != m_cache.find(&driver_list::driver(found));
}
@@ -1162,7 +1172,7 @@ public:
static bool type_allowed(unsigned pos, type n)
{
- return (FIRST <= n) && (LAST >= n) && (ALL != n) && (AVAILABLE != n) && (UNAVAILABLE != n) && (FAVORITE != n) && (CUSTOM != n);
+ return (FIRST <= n) && (LAST >= n) && (ALL != n) && (FAVORITE != n) && (CUSTOM != n);
}
static bool types_contradictory(type n, type m)
diff --git a/src/frontend/mame/ui/utils.h b/src/frontend/mame/ui/utils.h
index 9d52f8acf8c..60030d07205 100644
--- a/src/frontend/mame/ui/utils.h
+++ b/src/frontend/mame/ui/utils.h
@@ -26,7 +26,17 @@ class mame_ui_manager;
class render_container;
-// TODO: namespace this thing
+// TODO: namespace these things
+
+struct ui_system_info
+{
+ ui_system_info() { }
+ ui_system_info(game_driver const &d, bool a) : driver(&d), available(a) { }
+
+ game_driver const *driver = nullptr;
+ bool available = false;
+};
+
struct ui_software_info
{
ui_software_info() { }
@@ -49,8 +59,9 @@ struct ui_software_info
ui_software_info &operator=(ui_software_info const &) = default;
ui_software_info &operator=(ui_software_info &&) = default;
- bool operator==(ui_software_info const &r)
+ bool operator==(ui_software_info const &r) const
{
+ // compares all fields except available
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
@@ -65,7 +76,7 @@ struct ui_software_info
std::string publisher;
uint8_t supported = 0;
std::string part;
- const game_driver *driver = nullptr;
+ game_driver const *driver = nullptr;
std::string listname;
std::string interface;
std::string instance;
@@ -137,17 +148,19 @@ public:
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); });
+ std::copy_if(first, last, dest, [this] (auto const &info) { return apply(info); });
}
protected:
using entry_type = Entry;
filter_base() { }
+
+ bool apply(Entry const *info) const { return apply(*info); }
};
-class machine_filter : public filter_base<machine_filter, game_driver>
+class machine_filter : public filter_base<machine_filter, ui_system_info>
{
public:
enum type : uint16_t
@@ -188,8 +201,8 @@ public:
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;
+ using filter_base<machine_filter, ui_system_info>::config_name;
+ using filter_base<machine_filter, ui_system_info>::display_name;
protected:
machine_filter();