mirror of
https://github.com/holub/mame
synced 2025-07-06 02:18:09 +03:00
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
This commit is contained in:
parent
f9f4ae9d36
commit
90f7fa47c2
@ -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/ui.h"
|
||||
#include "ui/menu.h"
|
||||
#include "audit.h"
|
||||
#include "ui/auditmenu.h"
|
||||
|
||||
#include "ui/ui.h"
|
||||
|
||||
#include "audit.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 {
|
||||
|
||||
void *const ITEMREF_START = reinterpret_cast<void *>(std::uintptr_t(1));
|
||||
|
||||
} // anonymous 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');
|
||||
|
||||
if (!clonex && !cloney)
|
||||
return (cs_stricmp(x->type.fullname(), y->type.fullname()) < 0);
|
||||
|
||||
int cx = -1, cy = -1;
|
||||
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;
|
||||
|
||||
if (m_audit_mode == 1)
|
||||
{
|
||||
vptr_game::iterator iter = m_unavailablesorted.begin();
|
||||
while (iter != m_unavailablesorted.end())
|
||||
case phase::AUDIT:
|
||||
{
|
||||
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)
|
||||
{
|
||||
m_availablesorted.push_back((*iter));
|
||||
iter = m_unavailablesorted.erase(iter);
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
// 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;
|
||||
}
|
||||
else
|
||||
{
|
||||
driver_enumerator enumerator(machine().options());
|
||||
media_auditor auditor(enumerator);
|
||||
while (enumerator.next())
|
||||
{
|
||||
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)
|
||||
m_availablesorted.push_back(&enumerator.driver());
|
||||
else
|
||||
m_unavailablesorted.push_back(&enumerator.driver());
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
item_append("Dummy", "", 0, (void *)(uintptr_t)1);
|
||||
item_append(_("Start Audit"), "", 0, ITEMREF_START);
|
||||
customtop = (ui().get_line_height() * 2.0f) + (UI_BOX_TB_BORDER * 3.0f);
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// save drivers infos to file
|
||||
//-------------------------------------------------
|
||||
void menu_audit::handle()
|
||||
{
|
||||
switch (m_phase)
|
||||
{
|
||||
case phase::CONSENT:
|
||||
{
|
||||
event const *const menu_event(process(0));
|
||||
if (menu_event && (ITEMREF_START == menu_event->itemref) && (IPT_UI_SELECT == menu_event->iptkey))
|
||||
{
|
||||
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;
|
||||
});
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void menu_audit::audit_fast()
|
||||
{
|
||||
for (ui_system_info &info : m_availablesorted)
|
||||
{
|
||||
if (!info.available)
|
||||
{
|
||||
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
|
||||
info.available = (summary == media_auditor::CORRECT) || (summary == media_auditor::BEST_AVAILABLE) || (summary == media_auditor::NONE_NEEDED);
|
||||
++m_audited;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void menu_audit::audit_all()
|
||||
{
|
||||
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));
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)
|
||||
noroms = true;
|
||||
|
||||
// check if clone < parent
|
||||
if (!noroms)
|
||||
game_driver const &parent(driver_list::driver(cx));
|
||||
if (driver.rom == parent.rom)
|
||||
{
|
||||
noroms = true;
|
||||
for (; !ROMENTRY_ISEND(rom) && noroms == true; ++rom)
|
||||
}
|
||||
else
|
||||
{
|
||||
// check if clone < parent
|
||||
noroms = true;
|
||||
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;
|
||||
util::hash_collection const hashes(rom->hashdata);
|
||||
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
@ -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];
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user