summaryrefslogtreecommitdiffstatshomepage
path: root/src/frontend/mame
diff options
context:
space:
mode:
author andreasnaive <andreasnaive@gmail.com>2019-03-25 23:13:40 +0100
committer andreasnaive <andreasnaive@gmail.com>2019-03-25 23:13:40 +0100
commitb380514764cf857469bae61c11143a19f79a74c5 (patch)
tree63c8012e262618f08a332da31dd714281aa2c5ed /src/frontend/mame
parentc24473ddff715ecec2e258a6eb38960cf8c8e98e (diff)
Revert "conflict resolution (nw)"
This reverts commit c24473ddff715ecec2e258a6eb38960cf8c8e98e, reversing changes made to 009cba4fb8102102168ef32870892438327f3705.
Diffstat (limited to 'src/frontend/mame')
-rw-r--r--src/frontend/mame/clifront.cpp451
-rw-r--r--src/frontend/mame/clifront.h2
-rw-r--r--src/frontend/mame/info.cpp19
-rw-r--r--src/frontend/mame/language.cpp2
-rw-r--r--src/frontend/mame/mame.cpp34
-rw-r--r--src/frontend/mame/mame.h20
-rw-r--r--src/frontend/mame/mameopts.cpp4
-rw-r--r--src/frontend/mame/ui/auditmenu.cpp11
-rw-r--r--src/frontend/mame/ui/icorender.cpp781
-rw-r--r--src/frontend/mame/ui/icorender.h227
-rw-r--r--src/frontend/mame/ui/info.cpp35
-rw-r--r--src/frontend/mame/ui/inifile.cpp585
-rw-r--r--src/frontend/mame/ui/inifile.h90
-rw-r--r--src/frontend/mame/ui/mainmenu.cpp6
-rw-r--r--src/frontend/mame/ui/menu.cpp16
-rw-r--r--src/frontend/mame/ui/menu.h25
-rw-r--r--src/frontend/mame/ui/miscmenu.cpp99
-rw-r--r--src/frontend/mame/ui/miscmenu.h22
-rw-r--r--src/frontend/mame/ui/optsmenu.cpp365
-rw-r--r--src/frontend/mame/ui/optsmenu.h53
-rw-r--r--src/frontend/mame/ui/selector.cpp14
-rw-r--r--src/frontend/mame/ui/selector.h16
-rw-r--r--src/frontend/mame/ui/selgame.cpp755
-rw-r--r--src/frontend/mame/ui/selgame.h27
-rw-r--r--src/frontend/mame/ui/selmenu.cpp439
-rw-r--r--src/frontend/mame/ui/selmenu.h40
-rw-r--r--src/frontend/mame/ui/selsoft.cpp383
-rw-r--r--src/frontend/mame/ui/selsoft.h59
-rw-r--r--src/frontend/mame/ui/simpleselgame.cpp10
-rw-r--r--src/frontend/mame/ui/utils.cpp287
-rw-r--r--src/frontend/mame/ui/utils.h166
-rw-r--r--src/frontend/mame/ui/videoopt.cpp2
-rw-r--r--src/frontend/mame/ui/widgets.cpp13
-rw-r--r--src/frontend/mame/ui/widgets.h12
34 files changed, 1820 insertions, 3250 deletions
diff --git a/src/frontend/mame/clifront.cpp b/src/frontend/mame/clifront.cpp
index 28249e7bd3e..f2dbf4e1c55 100644
--- a/src/frontend/mame/clifront.cpp
+++ b/src/frontend/mame/clifront.cpp
@@ -99,11 +99,11 @@ const options_entry cli_option_entries[] =
{ CLICOMMAND_LISTCLONES ";lc", "0", OPTION_COMMAND, "show clones" },
{ CLICOMMAND_LISTBROTHERS ";lb", "0", OPTION_COMMAND, "show \"brothers\", or other drivers from same sourcefile" },
{ CLICOMMAND_LISTCRC, "0", OPTION_COMMAND, "CRC-32s" },
- { CLICOMMAND_LISTROMS ";lr", "0", OPTION_COMMAND, "list required ROMs for a driver" },
+ { CLICOMMAND_LISTROMS ";lr", "0", OPTION_COMMAND, "list required roms for a driver" },
{ CLICOMMAND_LISTSAMPLES, "0", OPTION_COMMAND, "list optional samples for a driver" },
{ CLICOMMAND_VERIFYROMS, "0", OPTION_COMMAND, "report romsets that have problems" },
{ CLICOMMAND_VERIFYSAMPLES, "0", OPTION_COMMAND, "report samplesets that have problems" },
- { CLICOMMAND_ROMIDENT, "0", OPTION_COMMAND, "compare files with known MAME ROMs" },
+ { CLICOMMAND_ROMIDENT, "0", OPTION_COMMAND, "compare files with known MAME roms" },
{ CLICOMMAND_LISTDEVICES ";ld", "0", OPTION_COMMAND, "list available devices" },
{ CLICOMMAND_LISTSLOTS ";lslot", "0", OPTION_COMMAND, "list available slots and slot devices" },
{ CLICOMMAND_LISTMEDIA ";lm", "0", OPTION_COMMAND, "list available media for the system" },
@@ -183,9 +183,9 @@ void print_summary(
//-------------------------------------------------
cli_frontend::cli_frontend(emu_options &options, osd_interface &osd)
- : m_options(options)
- , m_osd(osd)
- , m_result(EMU_ERR_NONE)
+ : m_options(options),
+ m_osd(osd),
+ m_result(EMU_ERR_NONE)
{
m_options.add_entries(cli_option_entries);
}
@@ -211,7 +211,6 @@ void cli_frontend::start_execution(mame_machine_manager *manager, const std::vec
try
{
m_options.parse_command_line(args, OPTION_PRIORITY_CMDLINE);
- m_osd.set_verbose(m_options.verbose());
}
catch (options_exception &ex)
{
@@ -235,10 +234,7 @@ void cli_frontend::start_execution(mame_machine_manager *manager, const std::vec
// read INI's, if appropriate
if (m_options.read_config())
- {
mame_options::parse_standard_inis(m_options, option_errors);
- m_osd.set_verbose(m_options.verbose());
- }
// otherwise, check for a valid system
load_translation(m_options);
@@ -295,25 +291,14 @@ int cli_frontend::execute(std::vector<std::string> &args)
// get the top 16 approximate matches
driver_enumerator drivlist(m_options);
int matches[16];
- drivlist.find_approximate_matches(m_options.attempted_system_name(), ARRAY_LENGTH(matches), matches);
-
- // work out how wide the titles need to be
- int titlelen(0);
- for (int match : matches)
- if (0 <= match)
- titlelen = (std::max)(titlelen, int(strlen(drivlist.driver(match).type.fullname())));
+ drivlist.find_approximate_matches(m_options.attempted_system_name().c_str(), ARRAY_LENGTH(matches), matches);
// print them out
osd_printf_error("\n\"%s\" approximately matches the following\n"
"supported machines (best match first):\n\n", m_options.attempted_system_name().c_str());
- for (int match : matches)
- {
- if (0 <= match)
- {
- game_driver const &drv(drivlist.driver(match));
- osd_printf_error("%s", util::string_format("%-18s%-*s(%s, %s)\n", drv.name, titlelen + 2, drv.type.fullname(), drv.manufacturer, drv.year).c_str());
- }
- }
+ for (auto & matche : matches)
+ if (matche != -1)
+ osd_printf_error("%-18s%s\n", drivlist.driver(matche).name, drivlist.driver(matche).type.fullname());
}
}
catch (emu_exception &)
@@ -364,20 +349,77 @@ void cli_frontend::listxml(const std::vector<std::string> &args)
void cli_frontend::listfull(const std::vector<std::string> &args)
{
- auto const list_system_name = [] (device_type type, bool first)
+ bool const iswild((1U != args.size()) || core_iswildstr(args[0].c_str()));
+ std::vector<bool> matched(args.size(), false);
+ auto const included = [&args, &matched] (char const *name) -> bool
+ {
+ if (args.empty())
+ return true;
+
+ bool result = false;
+ auto it = matched.begin();
+ for (std::string const &pat : args)
+ {
+ if (!core_strwildcmp(pat.c_str(), name))
+ {
+ result = true;
+ *it = true;
+ }
+ ++it;
+ }
+ return result;
+ };
+
+ bool first = true;
+ auto const list_system_name = [&first] (device_type const &type)
{
// print the header
if (first)
osd_printf_info("Name: Description:\n");
+ first = false;
osd_printf_info("%-17s \"%s\"\n", type.shortname(), type.fullname());
};
- apply_action(
- args,
- [&list_system_name] (driver_enumerator &drivlist, bool first)
- { list_system_name(drivlist.driver().type, first); },
- [&list_system_name] (device_type type, bool first)
- { list_system_name(type, first); });
+
+ // determine which drivers to output
+ driver_enumerator drivlist(m_options);
+ while (drivlist.next())
+ {
+ if (included(drivlist.driver().name))
+ {
+ list_system_name(drivlist.driver().type);
+
+ // if it wasn't a wildcard, there can only be one
+ if (!iswild)
+ break;
+ }
+ }
+
+ // try devices as well
+ if (iswild || first)
+ {
+ for (device_type type : registered_device_types)
+ {
+ if (included(type.shortname()))
+ {
+ list_system_name(type);
+
+ // if it wasn't a wildcard, there can only be one
+ if (!iswild)
+ break;
+ }
+ }
+ }
+
+ // return an error if none found
+ auto it = matched.begin();
+ for (std::string const &pat : args)
+ {
+ if (!*it)
+ throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching systems found for '%s'", pat.c_str());
+
+ ++it;
+ }
}
@@ -388,16 +430,16 @@ void cli_frontend::listfull(const std::vector<std::string> &args)
void cli_frontend::listsource(const std::vector<std::string> &args)
{
- auto const list_system_source = [] (device_type type)
- {
- osd_printf_info("%-16s %s\n", type.shortname(), core_filename_extract_base(type.source()).c_str());
- };
- apply_action(
- args,
- [&list_system_source] (driver_enumerator &drivlist, bool first)
- { list_system_source(drivlist.driver().type); },
- [&list_system_source] (device_type type, bool first)
- { list_system_source(type); });
+ const char *gamename = args.empty() ? nullptr : args[0].c_str();
+
+ // determine which drivers to output; return an error if none found
+ driver_enumerator drivlist(m_options, gamename);
+ if (drivlist.count() == 0)
+ throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching systems found for '%s'", gamename);
+
+ // iterate through drivers and output the info
+ while (drivlist.next())
+ osd_printf_info("%-16s %s\n", drivlist.driver().name, core_filename_extract_base(drivlist.driver().type.source()).c_str());
}
@@ -505,92 +547,164 @@ void cli_frontend::listbrothers(const std::vector<std::string> &args)
void cli_frontend::listcrc(const std::vector<std::string> &args)
{
- apply_device_action(
- args,
- [] (device_t &root, char const *type, bool first)
+ const char *gamename = args.empty() ? nullptr : args[0].c_str();
+
+ // determine which drivers to output; return an error if none found
+ driver_enumerator drivlist(m_options, gamename);
+ if (drivlist.count() == 0)
+ throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching systems found for '%s'", gamename);
+
+ // iterate through matches, and then through ROMs
+ while (drivlist.next())
+ {
+ for (device_t const &device : device_iterator(drivlist.config()->root_device()))
+ {
+ for (tiny_rom_entry const *rom = device.rom_region(); rom && !ROMENTRY_ISEND(rom); ++rom)
{
- for (device_t const &device : device_iterator(root))
+ if (ROMENTRY_ISFILE(rom))
{
- for (tiny_rom_entry const *rom = device.rom_region(); rom && !ROMENTRY_ISEND(rom); ++rom)
- {
- if (ROMENTRY_ISFILE(rom))
- {
- // if we have a CRC, display it
- uint32_t crc;
- if (util::hash_collection(rom->hashdata).crc(crc))
- osd_printf_info("%08x %-32s\t%-16s\t%s\n", crc, rom->name, device.shortname(), device.name());
- }
- }
+ // if we have a CRC, display it
+ uint32_t crc;
+ if (util::hash_collection(rom->hashdata).crc(crc))
+ osd_printf_info("%08x %-32s\t%-16s\t%s\n", crc, rom->name, device.shortname(), device.name());
}
- });
+ }
+ }
+ }
}
//-------------------------------------------------
// listroms - output the list of ROMs referenced
-// by matching systems/devices
+// by a given game or set of games
//-------------------------------------------------
void cli_frontend::listroms(const std::vector<std::string> &args)
{
- apply_device_action(
- args,
- [] (device_t &root, char const *type, bool first)
+ bool const iswild((1U != args.size()) || core_iswildstr(args[0].c_str()));
+ std::vector<bool> matched(args.size(), false);
+ auto const included = [&args, &matched] (char const *name) -> bool
+ {
+ if (args.empty())
+ return true;
+
+ bool result = false;
+ auto it = matched.begin();
+ for (std::string const &pat : args)
+ {
+ if (!core_strwildcmp(pat.c_str(), name))
{
- // space between items
- if (!first)
- osd_printf_info("\n");
+ result = true;
+ *it = true;
+ }
+ ++it;
+ }
+ return result;
+ };
- // iterate through ROMs
- bool hasroms = false;
- for (device_t const &device : device_iterator(root))
+ bool first = true;
+ auto const list_system_roms = [&first] (device_t &root, char const *type)
+ {
+ // print a header
+ if (!first)
+ osd_printf_info("\n");
+ first = false;
+
+ // iterate through roms
+ bool hasroms = false;
+ for (device_t const &device : device_iterator(root))
+ {
+ for (const rom_entry *region = rom_first_region(device); region; region = rom_next_region(region))
+ {
+ for (const rom_entry *rom = rom_first_file(region); rom; rom = rom_next_file(rom))
{
- for (const rom_entry *region = rom_first_region(device); region; region = rom_next_region(region))
+ // print a header
+ if (!hasroms)
+ osd_printf_info(
+ "ROMs required for %s \"%s\".\n"
+ "%-32s %10s %s\n",
+ type, root.shortname(), "Name", "Size", "Checksum");
+ hasroms = true;
+
+ // accumulate the total length of all chunks
+ int64_t length = -1;
+ if (ROMREGION_ISROMDATA(region))
+ length = rom_file_size(rom);
+
+ // start with the name
+ const char *name = ROM_GETNAME(rom);
+ osd_printf_info("%-32s ", name);
+
+ // output the length next
+ if (length >= 0)
+ osd_printf_info("%10u", unsigned(uint64_t(length)));
+ else
+ osd_printf_info("%10s", "");
+
+ // output the hash data
+ util::hash_collection hashes(ROM_GETHASHDATA(rom));
+ if (!hashes.flag(util::hash_collection::FLAG_NO_DUMP))
{
- for (const rom_entry *rom = rom_first_file(region); rom; rom = rom_next_file(rom))
- {
- // print a header
- if (!hasroms)
- osd_printf_info(
- "ROMs required for %s \"%s\".\n"
- "%-32s %10s %s\n",
- type, root.shortname(), "Name", "Size", "Checksum");
- hasroms = true;
-
- // accumulate the total length of all chunks
- int64_t length = -1;
- if (ROMREGION_ISROMDATA(region))
- length = rom_file_size(rom);
-
- // start with the name
- const char *name = ROM_GETNAME(rom);
- osd_printf_info("%-32s ", name);
-
- // output the length next
- if (length >= 0)
- osd_printf_info("%10u", unsigned(uint64_t(length)));
- else
- osd_printf_info("%10s", "");
-
- // output the hash data
- util::hash_collection hashes(ROM_GETHASHDATA(rom));
- if (!hashes.flag(util::hash_collection::FLAG_NO_DUMP))
- {
- if (hashes.flag(util::hash_collection::FLAG_BAD_DUMP))
- osd_printf_info(" BAD");
- osd_printf_info(" %s", hashes.macro_string().c_str());
- }
- else
- osd_printf_info(" NO GOOD DUMP KNOWN");
-
- // end with a CR
- osd_printf_info("\n");
- }
+ if (hashes.flag(util::hash_collection::FLAG_BAD_DUMP))
+ osd_printf_info(" BAD");
+ osd_printf_info(" %s", hashes.macro_string().c_str());
}
+ else
+ osd_printf_info(" NO GOOD DUMP KNOWN");
+
+ // end with a CR
+ osd_printf_info("\n");
}
- if (!hasroms)
- osd_printf_info("No ROMs required for %s \"%s\".\n", type, root.shortname());
- });
+ }
+ }
+ if (!hasroms)
+ osd_printf_info("No ROMs required for %s \"%s\".\n", type, root.shortname());
+ };
+
+ // determine which drivers to output
+ driver_enumerator drivlist(m_options);
+
+ // iterate through matches
+ while (drivlist.next())
+ {
+ if (included(drivlist.driver().name))
+ {
+ list_system_roms(drivlist.config()->root_device(), "driver");
+
+ // if it wasn't a wildcard, there can only be one
+ if (!iswild)
+ break;
+ }
+ }
+
+ if (iswild || first)
+ {
+ machine_config config(GAME_NAME(___empty), m_options);
+ machine_config::token const tok(config.begin_configuration(config.root_device()));
+ for (device_type type : registered_device_types)
+ {
+ if (included(type.shortname()))
+ {
+ device_t *const dev = config.device_add("_tmp", type, 0);
+ list_system_roms(*dev, "device");
+ config.device_remove("_tmp");
+
+ // if it wasn't a wildcard, there can only be one
+ if (!iswild)
+ break;
+ }
+ }
+ }
+
+ // return an error if none found
+ auto it = matched.begin();
+ for (std::string const &pat : args)
+ {
+ if (!*it)
+ throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching systems found for '%s'", pat.c_str());
+
+ ++it;
+ }
}
@@ -1109,7 +1223,7 @@ void cli_frontend::output_single_softlist(FILE *out, software_list_device &swlis
for (const feature_list_item &flist : part.featurelist())
fprintf(out, "\t\t\t\t<feature name=\"%s\" value=\"%s\" />\n", flist.name().c_str(), util::xml::normalize_string(flist.value().c_str()));
- // TODO: display ROM region information
+ /* TODO: display rom region information */
for (const rom_entry *region = part.romdata().data(); region; region = rom_next_region(region))
{
int is_disk = ROMREGION_ISDISKDATA(region);
@@ -1240,7 +1354,7 @@ void cli_frontend::listsoftware(const std::vector<std::string> &args)
/*-------------------------------------------------
- verifysoftware - verify ROMs from the software
+ verifysoftware - verify roms from the software
list of the specified driver(s)
-------------------------------------------------*/
void cli_frontend::verifysoftware(const std::vector<std::string> &args)
@@ -1313,7 +1427,6 @@ void cli_frontend::verifysoftware(const std::vector<std::string> &args)
}
-
/*-------------------------------------------------
getsoftlist - retrieve software list by name
-------------------------------------------------*/
@@ -1448,105 +1561,6 @@ void cli_frontend::romident(const std::vector<std::string> &args)
//-------------------------------------------------
-// apply_action - apply action to matching
-// systems/devices
-//-------------------------------------------------
-
-template <typename T, typename U> void cli_frontend::apply_action(const std::vector<std::string> &args, T &&drvact, U &&devact)
-
-{
- bool const iswild((1U != args.size()) || core_iswildstr(args[0].c_str()));
- std::vector<bool> matched(args.size(), false);
- auto const included = [&args, &matched] (char const *name) -> bool
- {
- if (args.empty())
- return true;
-
- bool result = false;
- auto it = matched.begin();
- for (std::string const &pat : args)
- {
- if (!core_strwildcmp(pat.c_str(), name))
- {
- result = true;
- *it = true;
- }
- ++it;
- }
- return result;
- };
-
- // determine which drivers to output
- driver_enumerator drivlist(m_options);
-
- // iterate through matches
- bool first(true);
- while (drivlist.next())
- {
- if (included(drivlist.driver().name))
- {
- drvact(drivlist, first);
- first = false;
-
- // if it wasn't a wildcard, there can only be one
- if (!iswild)
- break;
- }
- }
-
- if (iswild || first)
- {
- for (device_type type : registered_device_types)
- {
- if (included(type.shortname()))
- {
- devact(type, first);
- first = false;
-
- // if it wasn't a wildcard, there can only be one
- if (!iswild)
- break;
- }
- }
- }
-
- // return an error if none found
- auto it = matched.begin();
- for (std::string const &pat : args)
- {
- if (!*it)
- throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching systems found for '%s'", pat.c_str());
-
- ++it;
- }
-}
-
-
-//-------------------------------------------------
-// apply_device_action - apply action to matching
-// systems/devices
-//-------------------------------------------------
-
-template <typename T> void cli_frontend::apply_device_action(const std::vector<std::string> &args, T &&action)
-{
- machine_config config(GAME_NAME(___empty), m_options);
- machine_config::token const tok(config.begin_configuration(config.root_device()));
- apply_action(
- args,
- [&action] (driver_enumerator &drivlist, bool first)
- {
- action(drivlist.config()->root_device(), "driver", first);
- },
- [&action, &config] (device_type type, bool first)
- {
- device_t *const dev = config.device_add("_tmp", type, 0);
- action(*dev, "device", first);
- config.device_remove("_tmp");
- });
-}
-
-
-//-------------------------------------------------
// find_command
//-------------------------------------------------
@@ -1556,10 +1570,10 @@ const cli_frontend::info_command_struct *cli_frontend::find_command(const std::s
{
{ CLICOMMAND_LISTXML, 0, -1, &cli_frontend::listxml, "[pattern] ..." },
{ CLICOMMAND_LISTFULL, 0, -1, &cli_frontend::listfull, "[pattern] ..." },
- { CLICOMMAND_LISTSOURCE, 0, -1, &cli_frontend::listsource, "[system name]" },
+ { CLICOMMAND_LISTSOURCE, 0, 1, &cli_frontend::listsource, "[system name]" },
{ CLICOMMAND_LISTCLONES, 0, 1, &cli_frontend::listclones, "[system name]" },
{ CLICOMMAND_LISTBROTHERS, 0, 1, &cli_frontend::listbrothers, "[system name]" },
- { CLICOMMAND_LISTCRC, 0, -1, &cli_frontend::listcrc, "[system name]" },
+ { CLICOMMAND_LISTCRC, 0, 1, &cli_frontend::listcrc, "[system name]" },
{ CLICOMMAND_LISTDEVICES, 0, 1, &cli_frontend::listdevices, "[system name]" },
{ CLICOMMAND_LISTSLOTS, 0, 1, &cli_frontend::listslots, "[system name]" },
{ CLICOMMAND_LISTROMS, 0, -1, &cli_frontend::listroms, "[pattern] ..." },
@@ -1608,11 +1622,6 @@ void cli_frontend::execute_commands(const char *exename)
// validate?
if (m_options.command() == CLICOMMAND_VALIDATE)
{
- if (m_options.command_arguments().size() > 1)
- {
- osd_printf_error("Auxiliary verb -validate takes at most 1 argument\n");
- return;
- }
validity_checker valid(m_options);
valid.set_validate_all(true);
const char *sysname = m_options.command_arguments().empty() ? nullptr : m_options.command_arguments()[0].c_str();
@@ -1680,9 +1689,9 @@ void cli_frontend::execute_commands(const char *exename)
// validate argument count
const char *error_message = nullptr;
if (m_options.command_arguments().size() < info_command->min_args)
- error_message = "Auxiliary verb -%s requires at least %d argument(s)\n";
+ error_message = "Auxillary verb -%s requires at least %d argument(s)\n";
if ((info_command->max_args >= 0) && (m_options.command_arguments().size() > info_command->max_args))
- error_message = "Auxiliary verb -%s takes at most %d argument(s)\n";
+ error_message = "Auxillary verb -%s takes at most %d argument(s)\n";
if (error_message)
{
osd_printf_info(error_message, info_command->option, info_command->max_args);
@@ -1691,7 +1700,7 @@ void cli_frontend::execute_commands(const char *exename)
return;
}
- // invoke the auxiliary command!
+ // invoke the auxillary command!
(this->*info_command->function)(m_options.command_arguments());
return;
}
diff --git a/src/frontend/mame/clifront.h b/src/frontend/mame/clifront.h
index e05467bc627..15da370ee1f 100644
--- a/src/frontend/mame/clifront.h
+++ b/src/frontend/mame/clifront.h
@@ -67,8 +67,6 @@ private:
void verifysoftlist(const std::vector<std::string> &args);
// internal helpers
- template <typename T, typename U> void apply_action(const std::vector<std::string> &args, T &&drvact, U &&devact);
- template <typename T> void apply_device_action(const std::vector<std::string> &args, T &&action);
void execute_commands(const char *exename);
void display_help(const char *exename);
void output_single_softlist(FILE *out, software_list_device &swlist);
diff --git a/src/frontend/mame/info.cpp b/src/frontend/mame/info.cpp
index 1fe65d7ea3c..6110c5c5fa9 100644
--- a/src/frontend/mame/info.cpp
+++ b/src/frontend/mame/info.cpp
@@ -168,7 +168,7 @@ const char info_xml_creator::s_dtd_string[] =
"\t\t\t<!ATTLIST driver cocktail (good|imperfect|preliminary) #IMPLIED>\n"
"\t\t\t<!ATTLIST driver savestate (supported|unsupported) #REQUIRED>\n"
"\t\t<!ELEMENT feature EMPTY>\n"
-"\t\t\t<!ATTLIST feature type (protection|timing|graphics|palette|sound|capture|camera|microphone|controls|keyboard|mouse|media|disk|printer|tape|punch|drum|rom|comms|lan|wan) #REQUIRED>\n"
+"\t\t\t<!ATTLIST feature type (protection|palette|graphics|sound|controls|keyboard|mouse|microphone|camera|disk|printer|lan|wan|timing) #REQUIRED>\n"
"\t\t\t<!ATTLIST feature status (unemulated|imperfect) #IMPLIED>\n"
"\t\t\t<!ATTLIST feature overall (unemulated|imperfect) #IMPLIED>\n"
"\t\t<!ELEMENT device (instance?, extension*)>\n"
@@ -1639,26 +1639,19 @@ void info_xml_creator::output_features(device_type type, device_t::feature_type
{
static constexpr std::pair<device_t::feature_type, char const *> features[] = {
{ device_t::feature::PROTECTION, "protection" },
- { device_t::feature::TIMING, "timing" },
- { device_t::feature::GRAPHICS, "graphics" },
{ device_t::feature::PALETTE, "palette" },
+ { device_t::feature::GRAPHICS, "graphics" },
{ device_t::feature::SOUND, "sound" },
- { device_t::feature::CAPTURE, "capture" },
- { device_t::feature::CAMERA, "camera" },
- { device_t::feature::MICROPHONE, "microphone" },
{ device_t::feature::CONTROLS, "controls" },
{ device_t::feature::KEYBOARD, "keyboard" },
{ device_t::feature::MOUSE, "mouse" },
- { device_t::feature::MEDIA, "media" },
+ { device_t::feature::MICROPHONE, "microphone" },
+ { device_t::feature::CAMERA, "camera" },
{ device_t::feature::DISK, "disk" },
{ device_t::feature::PRINTER, "printer" },
- { device_t::feature::TAPE, "tape" },
- { device_t::feature::PUNCH, "punch" },
- { device_t::feature::DRUM, "drum" },
- { device_t::feature::ROM, "rom" },
- { device_t::feature::COMMS, "comms" },
{ device_t::feature::LAN, "lan" },
- { device_t::feature::WAN, "wan" } };
+ { device_t::feature::WAN, "wan" },
+ { device_t::feature::TIMING, "timing" } };
device_t::feature_type const flags(type.unemulated_features() | type.imperfect_features() | unemulated | imperfect);
for (auto const &feature : features)
diff --git a/src/frontend/mame/language.cpp b/src/frontend/mame/language.cpp
index 016a32f1811..93d8e410c4a 100644
--- a/src/frontend/mame/language.cpp
+++ b/src/frontend/mame/language.cpp
@@ -72,7 +72,7 @@ void load_translation(emu_options &m_options)
{
std::string original = (const char *)data + buffer[original_table_offset + 2 * i + 1];
std::string translation = (const char *)data + buffer[translation_table_offset + 2 * i + 1];
- g_translation.emplace(std::move(original), std::move(translation));
+ g_translation.insert(std::pair<std::string, std::string>(original, translation));
}
global_free_array(buffer);
}
diff --git a/src/frontend/mame/mame.cpp b/src/frontend/mame/mame.cpp
index f3c08f661e9..528a1717a4a 100644
--- a/src/frontend/mame/mame.cpp
+++ b/src/frontend/mame/mame.cpp
@@ -31,11 +31,12 @@
mame_machine_manager* mame_machine_manager::m_manager = nullptr;
-mame_machine_manager* mame_machine_manager::instance(emu_options &options, osd_interface &osd)
+mame_machine_manager* mame_machine_manager::instance(emu_options &options,osd_interface &osd)
{
- if (!m_manager)
- m_manager = global_alloc(mame_machine_manager(options, osd));
-
+ if(!m_manager)
+ {
+ m_manager = global_alloc(mame_machine_manager(options,osd));
+ }
return m_manager;
}
@@ -48,13 +49,13 @@ mame_machine_manager* mame_machine_manager::instance()
// mame_machine_manager - constructor
//-------------------------------------------------
-mame_machine_manager::mame_machine_manager(emu_options &options,osd_interface &osd) :
- machine_manager(options, osd),
- m_plugins(std::make_unique<plugin_options>()),
- m_lua(global_alloc(lua_engine)),
- m_new_driver_pending(nullptr),
- m_firstrun(true),
- m_autoboot_timer(nullptr)
+mame_machine_manager::mame_machine_manager(emu_options &options,osd_interface &osd)
+ : machine_manager(options, osd),
+ m_plugins(std::make_unique<plugin_options>()),
+ m_lua(global_alloc(lua_engine)),
+ m_new_driver_pending(nullptr),
+ m_firstrun(true),
+ m_autoboot_timer(nullptr)
{
}
@@ -99,8 +100,7 @@ std::vector<std::string> split(const std::string &text, char sep)
{
std::vector<std::string> tokens;
std::size_t start = 0, end = 0;
- while ((end = text.find(sep, start)) != std::string::npos)
- {
+ while ((end = text.find(sep, start)) != std::string::npos) {
std::string temp = text.substr(start, end - start);
if (temp != "") tokens.push_back(temp);
start = end + 1;
@@ -120,8 +120,8 @@ void mame_machine_manager::start_luaengine()
{
m_plugins->parse_json(pluginpath);
}
- std::vector<std::string> include = split(options().plugin(), ',');
- std::vector<std::string> exclude = split(options().no_plugin(), ',');
+ std::vector<std::string> include = split(options().plugin(),',');
+ std::vector<std::string> exclude = split(options().no_plugin(),',');
{
// parse the file
// attempt to open the output file
@@ -304,13 +304,13 @@ void mame_machine_manager::ui_initialize(running_machine& machine)
void mame_machine_manager::create_custom(running_machine& machine)
{
// start the inifile manager
- m_inifile = std::make_unique<inifile_manager>(m_ui->options());
+ m_inifile = std::make_unique<inifile_manager>(machine, m_ui->options());
// allocate autoboot timer
m_autoboot_timer = machine.scheduler().timer_alloc(timer_expired_delegate(FUNC(mame_machine_manager::autoboot_callback), this));
// start favorite manager
- m_favorite = std::make_unique<favorite_manager>(m_ui->options());
+ m_favorite = std::make_unique<favorite_manager>(machine, m_ui->options());
}
void mame_machine_manager::load_cheatfiles(running_machine& machine)
diff --git a/src/frontend/mame/mame.h b/src/frontend/mame/mame.h
index 01a7235972b..3700aaab81b 100644
--- a/src/frontend/mame/mame.h
+++ b/src/frontend/mame/mame.h
@@ -15,20 +15,26 @@
class plugin_options;
class osd_interface;
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
class lua_engine;
class cheat_manager;
class inifile_manager;
class favorite_manager;
class mame_ui_manager;
-//**************************************************************************
-// TYPE DEFINITIONS
-//**************************************************************************
+namespace ui {
+} // namespace ui
// ======================> machine_manager
class mame_machine_manager : public machine_manager
{
+ DISABLE_COPYING(mame_machine_manager);
+private:
+ // construction/destruction
+ mame_machine_manager(emu_options &options, osd_interface &osd);
public:
static mame_machine_manager *instance(emu_options &options, osd_interface &osd);
static mame_machine_manager *instance();
@@ -58,15 +64,7 @@ public:
cheat_manager &cheat() const { assert(m_cheat != nullptr); return *m_cheat; }
inifile_manager &inifile() const { assert(m_inifile != nullptr); return *m_inifile; }
favorite_manager &favorite() const { assert(m_favorite != nullptr); return *m_favorite; }
-
private:
- // construction
- mame_machine_manager(emu_options &options, osd_interface &osd);
- mame_machine_manager(mame_machine_manager const &) = delete;
- mame_machine_manager(mame_machine_manager &&) = delete;
- mame_machine_manager &operator=(mame_machine_manager const &) = delete;
- mame_machine_manager &operator=(mame_machine_manager &&) = delete;
-
std::unique_ptr<plugin_options> m_plugins; // pointer to plugin options
lua_engine * m_lua;
diff --git a/src/frontend/mame/mameopts.cpp b/src/frontend/mame/mameopts.cpp
index 47f1a71c595..d6c1e1044cf 100644
--- a/src/frontend/mame/mameopts.cpp
+++ b/src/frontend/mame/mameopts.cpp
@@ -39,8 +39,8 @@ void mame_options::parse_standard_inis(emu_options &options, std::ostream &error
parse_one_ini(options, "debug", OPTION_PRIORITY_DEBUG_INI, &error_stream);
// if we have a valid system driver, parse system-specific INI files
- game_driver const *const cursystem = !driver ? system(options) : driver;
- if (!cursystem)
+ const game_driver *cursystem = (driver == nullptr) ? system(options) : driver;
+ if (cursystem == nullptr)
return;
// parse "vertical.ini" or "horizont.ini"
diff --git a/src/frontend/mame/ui/auditmenu.cpp b/src/frontend/mame/ui/auditmenu.cpp
index 7d5cbfd7305..0349e1c2949 100644
--- a/src/frontend/mame/ui/auditmenu.cpp
+++ b/src/frontend/mame/ui/auditmenu.cpp
@@ -207,21 +207,24 @@ void menu_audit::audit_fast()
void menu_audit::audit_all()
{
+ m_availablesorted.clear();
driver_enumerator enumerator(machine().options());
media_auditor auditor(enumerator);
- std::vector<bool> available(driver_list::total(), false);
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
- available[enumerator.current()] = (summary == media_auditor::CORRECT) || (summary == media_auditor::BEST_AVAILABLE) || (summary == media_auditor::NONE_NEEDED);
+ m_availablesorted.emplace_back(enumerator.driver(), (summary == media_auditor::CORRECT) || (summary == media_auditor::BEST_AVAILABLE) || (summary == media_auditor::NONE_NEEDED));
++m_audited;
}
- for (ui_system_info &info : m_availablesorted)
- info.available = available[info.index];
+ // 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()
diff --git a/src/frontend/mame/ui/icorender.cpp b/src/frontend/mame/ui/icorender.cpp
deleted file mode 100644
index bea85f9dd60..00000000000
--- a/src/frontend/mame/ui/icorender.cpp
+++ /dev/null
@@ -1,781 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Maurizio Petrarota, Victor Laskin
-/***************************************************************************
-
- ui/icorender.h
-
- Windows icon file parser.
-
- Previously based on code by Victor Laskin (victor.laskin@gmail.com)
- http://vitiy.info/Code/ico.cpp
-
- TODO:
- * Add variant that loads all images from the file
- * Allow size hint for choosing best candidate
- * Allow selecting amongst candidates based on colour depth
-
-***************************************************************************/
-
-#include "emu.h"
-#include "icorender.h"
-
-#include "util/png.h"
-
-#include <algorithm>
-#include <cassert>
-#include <cstdint>
-#include <cstring>
-
-// need to set LOG_OUTPUT_STREAM because there's no logerror outside devices
-#define LOG_OUTPUT_STREAM std::cerr
-
-#define LOG_GENERAL (1U << 0)
-#define LOG_DIB (1U << 1)
-
-//#define VERBOSE (LOG_GENERAL | LOG_DIB)
-
-#include "logmacro.h"
-
-
-namespace ui {
-
-namespace {
-
-// DIB compression schemes
-enum : uint32_t
-{
- DIB_COMP_NONE = 0,
- DIB_COMP_RLE8 = 1,
- DIB_COMP_RLE4 = 2,
- DIB_COMP_BITFIELDS = 3
-};
-
-
-// ICO file header
-struct icon_dir_t
-{
- uint16_t reserved; // must be 0
- uint16_t type; // 1 for icon or 2 for cursor
- uint16_t count; // number of images in the file
-};
-
-// ICO file directory entry
-struct icon_dir_entry_t
-{
- constexpr unsigned get_width() const { return width ? width : 256U; }
- constexpr unsigned get_height() const { return height ? height : 256U; }
-
- void byteswap()
- {
- planes = little_endianize_int16(planes);
- bpp = little_endianize_int16(bpp);
- size = little_endianize_int32(size);
- offset = little_endianize_int32(offset);
- }
-
- uint8_t width; // 0 means 256
- uint8_t height; // 0 means 256
- uint8_t colors; // for indexed colour, or 0 for direct colour
- uint8_t reserved; // documentation says this should be 0 but .NET writes 255
- uint16_t planes; // or hotspot X for cursor
- uint16_t bpp; // 0 to infer from image data, or hotspot Y for cursor
- uint32_t size; // image data size in bytes
- uint32_t offset; // offset to image data from start of file
-};
-
-// old-style DIB header
-struct bitmap_core_header_t
-{
- uint32_t size; // size of the header (12, 16 or 64)
- int16_t width; // width of bitmap in pixels
- int16_t height; // height of the image in pixels
- uint16_t planes; // number of colour planes (must be 1)
- uint16_t bpp; // bits per pixel
-};
-
-// new-style DIB header
-struct bitmap_info_header_t
-{
- uint32_t size; // size of the header
- int32_t width; // width of bitmap in pixels
- int32_t height; // height of bitmap in pixels
- uint16_t planes; // number of colour planes (must be 1)
- uint16_t bpp; // bits per pixel
- uint32_t comp; // compression method
- uint32_t rawsize; // size of bitmap data after decompression or 0 if uncompressed
- int32_t hres; // horizontal resolution in pixels/metre
- int32_t vres; // horizontal resolution in pixels/metre
- uint32_t colors; // number of colours or 0 for 1 << bpp
- uint32_t important; // number of important colours or 0 if all important
- uint32_t red; // red field mask - must be contiguous
- uint32_t green; // green field mask - must be contiguous
- uint32_t blue; // blue field mask - must be contiguous
- uint32_t alpha; // alpha field mask - must be contiguous
-};
-
-
-bool dib_parse_mask(uint32_t mask, unsigned &shift, unsigned &bits)
-{
- shift = count_leading_zeros(mask);
- mask <<= shift;
- bits = count_leading_ones(mask);
- mask <<= shift;
- shift = 32 - shift - bits;
- return !mask;
-}
-
-
-void dib_truncate_channel(unsigned &shift, unsigned &bits)
-{
- if (8U < bits)
- {
- unsigned const excess(bits - 8);
- shift += excess;
- bits -= excess;
- }
-}
-
-
-uint8_t dib_splat_sample(uint8_t val, unsigned bits)
-{
- assert(8U >= bits);
- for (val <<= (8U - bits); bits && (8U > bits); bits <<= 1)
- val |= val >> bits;
- return val;
-}
-
-
-bool load_ico_png(util::core_file &fp, icon_dir_entry_t const &dir, bitmap_argb32 &bitmap)
-{
- // skip out if the data isn't a reasonable size - PNG magic alone is eight bytes
- if (9U >= dir.size)
- return false;
- fp.seek(dir.offset, SEEK_SET);
- png_error const err(png_read_bitmap(fp, bitmap));
- switch (err)
- {
- case PNGERR_NONE:
- // found valid PNG image
- assert(bitmap.valid());
- if ((dir.get_width() == bitmap.width()) && ((dir.get_height() == bitmap.height())))
- {
- LOG("Loaded %d*%d pixel PNG image from ICO file\n", bitmap.width(), bitmap.height());
- }
- else
- {
- LOG(
- "Loaded %d*%d pixel PNG image from ICO file (directory indicated %u*%u)\n",
- bitmap.width(),
- bitmap.height(),
- dir.get_width(),
- dir.get_height());
- }
- return true;
-
- case PNGERR_BAD_SIGNATURE:
- // doesn't look like PNG data - just fall back to DIB without the file header
- return false;
-
- default:
- // invalid PNG data or I/O error
- LOG(
- "Error %u reading PNG image data from ICO file at offset %u (directory size %u)\n",
- unsigned(err),
- dir.offset,
- dir.size);
- return false;
- }
-}
-
-
-bool load_ico_dib(util::core_file &fp, icon_dir_entry_t const &dir, bitmap_argb32 &bitmap)
-{
- // check that these things haven't been padded somehow
- static_assert(sizeof(bitmap_core_header_t) == 12U, "compiler has applied padding to bitmap_core_header_t");
- static_assert(sizeof(bitmap_info_header_t) == 56U, "compiler has applied padding to bitmap_info_header_t");
-
- // ensure the header fits in the space for the image data
- union { bitmap_core_header_t core; bitmap_info_header_t info; } header;
- assert(&header.core.size == &header.info.size);
- if (sizeof(header.core) > dir.size)
- return false;
- std::memset(&header, 0, sizeof(header));
- fp.seek(dir.offset, SEEK_SET);
- if (fp.read(&header.core.size, sizeof(header.core.size)) != sizeof(header.core.size))
- {
- LOG(
- "Error reading DIB header size from ICO file at offset %u (directory size %u)\n",
- dir.offset,
- dir.size);
- return false;
- }
- header.core.size = little_endianize_int32(header.core.size);
- if (dir.size < header.core.size)
- {
- LOG(
- "ICO file image data at %u (%u bytes) is too small for DIB header (%u bytes)\n",
- dir.offset,
- dir.size,
- header.core.size);
- return false;
- }
-
- // identify and read the header - convert OS/2 headers to Windows 3 format
- unsigned palette_bytes(4U);
- switch (header.core.size)
- {
- case 16U:
- case 64U:
- // extended OS/2 bitmap header with support for compression
- LOG(
- "ICO image data at %u (%u bytes) uses unsupported OS/2 DIB header (size %u)\n",
- dir.offset,
- dir.size,
- header.core.size);
- return false;
-
- case 12U:
- // introduced in OS/2 and Windows 2.0
- {
- palette_bytes = 3U;
- uint32_t const header_read(std::min<uint32_t>(header.core.size, sizeof(header.core)) - sizeof(header.core.size));
- if (fp.read(&header.core.width, header_read) != header_read)
- {
- LOG("Error reading DIB core header from ICO file image data at %u (%u bytes)\n", dir.offset, dir.size);
- return false;
- }
- fp.seek(header.core.size - sizeof(header.core.size) - header_read, SEEK_CUR);
- header.core.width = little_endianize_int16(header.core.width);
- header.core.height = little_endianize_int16(header.core.height);
- header.core.planes = little_endianize_int16(header.core.planes);
- header.core.bpp = little_endianize_int16(header.core.bpp);
- LOGMASKED(
- LOG_DIB,
- "Read DIB core header from ICO file image data at %u: %d*%d, %u planes, %u bpp\n",
- dir.offset,
- header.core.width,
- header.core.height,
- header.core.planes,
- header.core.bpp);
-
- // this works because the core header only aliases the width/height of the info header
- header.info.bpp = header.core.bpp;
- header.info.planes = header.core.planes;
- header.info.height = header.core.height;
- header.info.width = header.core.width;
- header.info.size = 40U;
- }
- break;
-
- default:
- // the next version will be longer
- if (124U >= header.core.size)
- {
- LOG(
- "ICO image data at %u (%u bytes) uses unsupported DIB header format (size %u)\n",
- dir.offset,
- dir.size,
- header.core.size);
- return false;
- }
- // fall through
- case 40U:
- case 52U:
- case 56U:
- case 108U:
- case 124U:
- // the Windows 3 bitmap header with optional extensions
- {
- palette_bytes = 4U;
- uint32_t const header_read(std::min<uint32_t>(header.info.size, sizeof(header.info)) - sizeof(header.info.size));
- if (fp.read(&header.info.width, header_read) != header_read)
- {
- LOG("Error reading DIB info header from ICO file image data at %u (%u bytes)\n", dir.offset, dir.size);
- return false;
- }
- fp.seek(header.info.size - sizeof(header.info.size) - header_read, SEEK_CUR);
- header.info.width = little_endianize_int32(header.info.width);
- header.info.height = little_endianize_int32(header.info.height);
- header.info.planes = little_endianize_int16(header.info.planes);
- header.info.bpp = little_endianize_int16(header.info.bpp);
- header.info.comp = little_endianize_int32(header.info.comp);
- header.info.rawsize = little_endianize_int32(header.info.rawsize);
- header.info.hres = little_endianize_int32(header.info.hres);
- header.info.vres = little_endianize_int32(header.info.vres);
- header.info.colors = little_endianize_int32(header.info.colors);
- header.info.important = little_endianize_int32(header.info.important);
- header.info.red = little_endianize_int32(header.info.red);
- header.info.green = little_endianize_int32(header.info.green);
- header.info.blue = little_endianize_int32(header.info.blue);
- header.info.alpha = little_endianize_int32(header.info.alpha);
- LOGMASKED(
- LOG_DIB,
- "Read DIB info header from ICO file image data at %u: %d*%d (%d*%d ppm), %u planes, %u bpp %u/%s%u colors\n",
- dir.offset,
- header.info.width,
- header.info.height,
- header.info.hres,
- header.info.vres,
- header.info.planes,
- header.info.bpp,
- header.info.important,
- header.info.colors ? "" : "2^",
- header.info.colors ? header.info.colors : header.info.bpp);
- }
- break;
- }
-
- // check for unsupported planes/bit depth
- if ((1U != header.info.planes) || !header.info.bpp || (32U < header.info.bpp) || ((8U < header.info.bpp) ? (header.info.bpp % 8) : (8 % header.info.bpp)))
- {
- LOG(
- "ICO file DIB image data at %u uses unsupported planes/bits per pixel %u*%u\n",
- dir.offset,
- header.info.planes,
- header.info.bpp);
- return false;
- }
-
- // check dimensions
- if ((0 >= header.info.width) || (0 == header.info.height))
- {
- LOG(
- "ICO file DIB image data at %u has invalid dimensions %u*%u\n",
- dir.offset,
- header.info.width,
- header.info.height);
- return false;
- }
- bool const top_down(0 > header.info.height);
- if (top_down)
- header.info.height = -header.info.height;
- bool have_and_mask((2 * dir.get_height()) == header.info.height);
- if (!have_and_mask && (dir.get_height() != header.info.height))
- {
- osd_printf_verbose(
- "ICO file DIB image data at %lu height %ld doesn't match directory height %u with or without AND mask\n",
- (unsigned long)dir.offset,
- (long)header.info.height,
- dir.get_height());
- return false;
- }
- if (have_and_mask)
- header.info.height >>= 1;
-
- // ensure compression scheme is supported
- bool indexed(true), no_palette(false);
- switch (header.info.comp)
- {
- case DIB_COMP_NONE:
- // uncompressed - direct colour with implied bitfields if more than eight bits/pixel
- indexed = 8U >= header.info.bpp;
- if (indexed)
- {
- if ((1U << header.info.bpp) < header.info.colors)
- {
- osd_printf_verbose(
- "ICO file DIB image data at %lu has oversized palette with %lu entries for %u bits per pixel\n",
- (unsigned long)dir.offset,
- (unsigned long)header.info.colors,
- (unsigned)header.info.bpp);
- }
- }
- if (!indexed)
- {
- no_palette = true;
- switch(header.info.bpp)
- {
- case 16U:
- header.info.red = 0x00007c00;
- header.info.green = 0x000003e0;
- header.info.blue = 0x0000001f;
- header.info.alpha = 0x00000000;
- break;
- case 24U:
- case 32U:
- header.info.red = 0x00ff0000;
- header.info.green = 0x0000ff00;
- header.info.blue = 0x000000ff;
- header.info.alpha = 0x00000000;
- break;
- }
- }
- break;
-
- case DIB_COMP_BITFIELDS:
- // uncompressed direct colour with explicitly-specified bitfields
- indexed = false;
- if (offsetof(bitmap_info_header_t, alpha) > header.info.size)
- {
- osd_printf_verbose(
- "ICO file DIB image data at %lu specifies bit masks but is too small (size %lu)\n",
- (unsigned long)dir.offset,
- (unsigned long)header.info.size);
- return false;
- }
- break;
-
- default:
- LOG("ICO file DIB image data at %u uses unsupported compression scheme %u\n", header.info.comp);
- return false;
- }
-
- // we can now calculate the size of the palette and row data
- size_t const palette_entries(
- indexed
- ? ((1U == header.info.bpp) ? 2U : header.info.colors ? header.info.colors : (1U << header.info.bpp))
- : (no_palette ? 0U : header.info.colors));
- size_t const palette_size(palette_bytes * palette_entries);
- size_t const row_bytes(((31 + (header.info.width * header.info.bpp)) >> 5) << 2);
- size_t const mask_row_bytes(((31 + header.info.width) >> 5) << 2);
- size_t const required_size(
- header.info.size +
- palette_size +
- ((row_bytes + (have_and_mask ? mask_row_bytes : 0U)) * header.info.height));
- if (required_size > dir.size)
- {
- LOG(
- "ICO file image data at %u (%u bytes) smaller than calculated DIB data size (%u bytes)\n",
- dir.offset,
- dir.size,
- required_size);
- return false;
- }
-
- // load the palette for indexed colour formats or the shifts for direct colour formats
- unsigned red_shift(0), green_shift(0), blue_shift(0), alpha_shift(0);
- unsigned red_bits(0), green_bits(0), blue_bits(0), alpha_bits(0);
- std::unique_ptr<rgb_t []> palette;
- if (indexed)
- {
- // read palette and convert
- std::unique_ptr<uint8_t []> palette_data(new uint8_t [palette_size]);
- if (fp.read(palette_data.get(), palette_size) != palette_size)
- {
- LOG("Error reading palette from ICO file DIB image data at %u (%u bytes)\n", dir.offset, dir.size);
- return false;
- }
- size_t const palette_usable(std::min<size_t>(palette_entries, size_t(1) << header.info.bpp));
- palette.reset(new rgb_t [palette_usable]);
- uint8_t const *ptr(palette_data.get());
- for (size_t i = 0; palette_usable > i; ++i, ptr += palette_bytes)
- palette[i] = rgb_t(ptr[2], ptr[1], ptr[0]);
- }
- else
- {
- // skip over the palette if necessary
- if (palette_entries)
- fp.seek(palette_bytes * palette_entries, SEEK_CUR);
-
- // convert masks to shifts
- bool const masks_contiguous(
- dib_parse_mask(header.info.red, red_shift, red_bits) &&
- dib_parse_mask(header.info.green, green_shift, green_bits) &&
- dib_parse_mask(header.info.blue, blue_shift, blue_bits) &&
- dib_parse_mask(header.info.alpha, alpha_shift, alpha_bits));
- if (!masks_contiguous)
- {
- osd_printf_verbose(
- "ICO file DIB image data at %lu specifies non-contiguous channel masks 0x%lx | 0x%lx | 0x%lx | 0x%lx\n",
- (unsigned long)dir.offset,
- (unsigned long)header.info.red,
- (unsigned long)header.info.green,
- (unsigned long)header.info.blue,
- (unsigned long)header.info.alpha);
- }
- if ((32U != header.info.bpp) && ((header.info.red | header.info.green | header.info.blue | header.info.alpha) >> header.info.bpp))
- {
- LOG(
- "ICO file DIB image data at %lu specifies channel masks 0x%x | 0x%x | 0x%x | 0x%x that exceed %u bits per pixel\n",
- dir.offset,
- header.info.red,
- header.info.green,
- header.info.blue,
- header.info.alpha,
- header.info.bpp);
- return false;
- }
- LOGMASKED(
- LOG_DIB,
- "DIB from ICO file image data at %1$u using channels: R((x >> %3$u) & 0x%4$0*2$x) G((x >> %5$u) & 0x%6$0*2$x) B((x >> %7$u) & 0x%8$0*2$x) A((x >> %9$u) & 0x%10$0*2$x)\n",
- dir.offset,
- (header.info.bpp + 3) >> 2,
- red_shift,
- (uint32_t(1) << red_bits) - 1,
- green_shift,
- (uint32_t(1) << green_bits) - 1,
- blue_shift,
- (uint32_t(1) << blue_bits) - 1,
- alpha_shift,
- (uint32_t(1) << alpha_bits) - 1);
-
- // the MAME bitmap only supports 8 bits/sample maximum
- dib_truncate_channel(red_shift, red_bits);
- dib_truncate_channel(green_shift, green_bits);
- dib_truncate_channel(blue_shift, blue_bits);
- dib_truncate_channel(alpha_shift, alpha_bits);
- }
-
- // allocate the bitmap and process row data
- std::unique_ptr<uint8_t []> row_data(new uint8_t [row_bytes]);
- bitmap.allocate(header.info.width, header.info.height);
- int const y_inc(top_down ? 1 : -1);
- for (int32_t i = 0, y = top_down ? 0 : (header.info.height - 1); header.info.height > i; ++i, y += y_inc)
- {
- if (fp.read(row_data.get(), row_bytes) != row_bytes)
- {
- LOG("Error reading DIB row %d data from ICO image data at %u\n", i, dir.offset);
- return false;
- }
- uint8_t *src(row_data.get());
- uint32_t *dest(&bitmap.pix(y));
- unsigned shift(0U);
- for (int32_t x = 0; header.info.width > x; ++x, ++dest)
- {
- // extract or compose a pixel
- uint32_t pix(0U);
- if (8U >= header.info.bpp)
- {
- assert(8U > shift);
- pix = *src >> (8U - header.info.bpp);
- *src <<= header.info.bpp;
- shift += header.info.bpp;
- if (8U <= shift)
- {
- shift = 0U;
- ++src;
- }
- }
- else for (shift = 0; header.info.bpp > shift; shift += 8U, ++src)
- {
- pix |= uint32_t(*src) << shift;
- }
-
- // convert to RGB
- if (indexed)
- {
- if (palette_entries > pix)
- {
- *dest = palette[pix];
- }
- else
- {
- *dest = rgb_t::transparent();
- osd_printf_verbose(
- "ICO file DIB image data at %lu has out-of-range color %lu at (%ld, %ld) with %lu palette entries\n",
- (unsigned long)dir.offset,
- (unsigned long)pix,
- (long)x,
- (long)y,
- (unsigned long)palette_entries);
- }
- }
- else
- {
- uint8_t r(dib_splat_sample((pix >> red_shift) & ((uint32_t(1) << red_bits) - 1), red_bits));
- uint8_t g(dib_splat_sample((pix >> green_shift) & ((uint32_t(1) << green_bits) - 1), green_bits));
- uint8_t b(dib_splat_sample((pix >> blue_shift) & ((uint32_t(1) << blue_bits) - 1), blue_bits));
- uint8_t a(dib_splat_sample((pix >> alpha_shift) & ((uint32_t(1) << alpha_bits) - 1), alpha_bits));
- *dest = rgb_t(alpha_bits ? a : 255, r, g, b);
- }
- }
- }
-
- // process the AND mask if present
- if (have_and_mask)
- {
- for (int32_t i = 0, y = top_down ? 0 : (header.info.height - 1); header.info.height > i; ++i, y += y_inc)
- {
- if (fp.read(row_data.get(), mask_row_bytes) != mask_row_bytes)
- {
- LOG("Error reading DIB mask row %d data from ICO image data at %u\n", i, dir.offset);
- return false;
- }
- uint8_t *src(row_data.get());
- uint32_t *dest(&bitmap.pix(y));
- unsigned shift(0U);
- for (int32_t x = 0; header.info.width > x; ++x, ++dest)
- {
- assert(8U > shift);
- rgb_t pix(*dest);
- *dest = pix.set_a(BIT(*src, 7U - shift) ? 0U : pix.a());
- if (8U <= ++shift)
- {
- shift = 0U;
- ++src;
- }
- }
- }
- }
-
- // we're done!
- return true;
-}
-
-
-bool load_ico_image(util::core_file &fp, unsigned index, icon_dir_entry_t const &dir, bitmap_argb32 &bitmap)
-{
- // try loading PNG image data (contains PNG file magic if used), and then fall back
- if (load_ico_png(fp, dir, bitmap))
- {
- LOG("Successfully loaded PNG image from ICO file entry %u\n", index);
- return true;
- }
- else if (load_ico_dib(fp, dir, bitmap))
- {
- LOG("Successfully loaded DIB image from ICO file entry %u\n", index);
- return true;
- }
-
- // no luck
- return false;
-}
-
-
-bool load_ico_image(util::core_file &fp, unsigned count, unsigned index, bitmap_argb32 &bitmap)
-{
- // read the directory entry
- icon_dir_entry_t dir;
- fp.seek(sizeof(icon_dir_t) + (sizeof(icon_dir_entry_t) * index), SEEK_SET);
- if (fp.read(&dir, sizeof(dir)) != sizeof(dir))
- {
- LOG("Failed to read ICO file directory entry %u\n", index);
- return false;
- }
- dir.byteswap();
- if ((sizeof(icon_dir_t) + (sizeof(icon_dir_entry_t) * count)) > dir.offset)
- {
- LOG(
- "ICO file image %u data starting at %u overlaps %u bytes of file header and directory\n",
- index,
- dir.offset,
- sizeof(icon_dir_t) + (sizeof(icon_dir_entry_t) * count));
- return false;
- }
- else
- {
- return load_ico_image(fp, index, dir, bitmap);
- }
-}
-
-} // anonymous namespace
-
-
-int images_in_ico(util::core_file &fp)
-{
- // read and check the icon file header
- icon_dir_t header;
- fp.seek(0, SEEK_SET);
- if (fp.read(&header, sizeof(header)) != sizeof(header))
- {
- LOG("Failed to read ICO file header\n");
- return -1;
- }
- header.reserved = little_endianize_int16(header.reserved);
- header.type = little_endianize_int16(header.type);
- header.count = little_endianize_int16(header.count);
- if (0U != header.reserved)
- {
- LOG("Invalid ICO file header reserved field %u (expected 0)\n", header.reserved);
- return -1;
- }
- if ((1U != header.type) && (2U != header.type))
- {
- LOG("Invalid ICO file header type field %u (expected 1 or 2)\n", header.type);
- return -1;
- }
- return int(unsigned(little_endianize_int16(header.count)));
-}
-
-
-void render_load_ico(util::core_file &fp, unsigned index, bitmap_argb32 &bitmap)
-{
- // check that these things haven't been padded somehow
- static_assert(sizeof(icon_dir_t) == 6U, "compiler has applied padding to icon_dir_t");
- static_assert(sizeof(icon_dir_entry_t) == 16U, "compiler has applied padding to icon_dir_entry_t");
-
- // read and check the icon file header, then try to load the specified image
- int const count(images_in_ico(fp));
- if (0 > count)
- {
- // images_in_ico already logged an error
- }
- else if (index >= count)
- {
- osd_printf_verbose("Requested image %u from ICO file containing %d images\n", index, count);
- }
- else if (load_ico_image(fp, count, index, bitmap))
- {
- return;
- }
- bitmap.reset();
-}
-
-
-void render_load_ico_first(util::core_file &fp, bitmap_argb32 &bitmap)
-{
- int const count(images_in_ico(fp));
- for (int i = 0; count > i; ++i)
- {
- if (load_ico_image(fp, count, i, bitmap))
- return;
- }
- bitmap.reset();
-}
-
-
-void render_load_ico_highest_detail(util::core_file &fp, bitmap_argb32 &bitmap)
-{
- // read and check the icon file header - logs a message on error
- int const count(images_in_ico(fp));
- if (0 <= count)
- {
- // now load all the directory entries
- size_t const dir_bytes(sizeof(icon_dir_entry_t) * count);
- std::unique_ptr<icon_dir_entry_t []> dir(new icon_dir_entry_t [count]);
- std::unique_ptr<unsigned []> index(new unsigned [count]);
- if (count && (fp.read(dir.get(), dir_bytes) != dir_bytes))
- {
- LOG("Failed to read ICO file directory entries\n");
- }
- else
- {
- // byteswap and sort by (pixels, depth)
- for (int i = 0; count > i; ++i)
- {
- dir[i].byteswap();
- index[i] = i;
- }
- std::stable_sort(
- index.get(),
- index.get() + count,
- [&dir] (unsigned x, unsigned y)
- {
- unsigned const x_pixels(dir[x].get_width() * dir[x].get_height());
- unsigned const y_pixels(dir[y].get_width() * dir[y].get_height());
- if (x_pixels > y_pixels)
- return true;
- else if (x_pixels < y_pixels)
- return false;
- else
- return dir[x].bpp > dir[y].bpp;
- });
-
- // walk down until something works
- for (int i = 0; count > i; ++i)
- {
- LOG(
- "Try loading ICO file entry %u: %u*%u, %u bits per pixel\n",
- index[i],
- dir[index[i]].get_width(),
- dir[index[i]].get_height(),
- dir[index[i]].bpp);
- if (load_ico_image(fp, index[i], dir[index[i]], bitmap))
- return;
- }
- }
- }
- bitmap.reset();
-}
-
-} // namespace ui
diff --git a/src/frontend/mame/ui/icorender.h b/src/frontend/mame/ui/icorender.h
index bb3f1a083be..17bc5a1d8ea 100644
--- a/src/frontend/mame/ui/icorender.h
+++ b/src/frontend/mame/ui/icorender.h
@@ -1,13 +1,13 @@
// license:BSD-3-Clause
-// copyright-holders:Vas Crabb
+// copyright-holders:Maurizio Petrarota, Victor Laskin
/***************************************************************************
ui/icorender.h
- Windows icon file parser.
+ ICOns file loader.
- File handles passed to these functions must support read and seek
- operations.
+ Original code by Victor Laskin (victor.laskin@gmail.com)
+ http://vitiy.info/Code/ico.cpp
***************************************************************************/
#ifndef MAME_FRONTEND_MAME_UI_ICORENDER_H
@@ -15,20 +15,219 @@
#pragma once
-namespace ui {
+// These next two structs represent how the icon information is stored
+// in an ICO file.
+typedef struct
+{
+ uint8_t bWidth; // Width of the image
+ uint8_t bHeight; // Height of the image (times 2)
+ uint8_t bColorCount; // Number of colors in image (0 if >=8bpp)
+ uint8_t bReserved; // Reserved
+ uint16_t wPlanes; // Color Planes
+ uint16_t wBitCount; // Bits per pixel
+ uint32_t dwBytesInRes; // how many bytes in this resource?
+ uint32_t dwImageOffset; // where in the file is this image
+} ICONDIRENTRY, *LPICONDIRENTRY;
-// get number of images in icon file (-1 on error)
-int images_in_ico(util::core_file &fp);
+typedef struct
+{
+ uint16_t idReserved; // Reserved
+ uint16_t idType; // resource type (1 for icons)
+ uint16_t idCount; // how many images?
+ //ICONDIRENTRY idEntries[1]; // the entries for each image
+} ICONDIR, *LPICONDIR;
-// load specified icon from file (zero-based)
-void render_load_ico(util::core_file &fp, unsigned index, bitmap_argb32 &bitmap);
+// size - 40 bytes
+typedef struct {
+ uint32_t biSize;
+ uint32_t biWidth;
+ uint32_t biHeight; // Icon Height (added height of XOR-Bitmap and AND-Bitmap)
+ uint16_t biPlanes;
+ uint16_t biBitCount;
+ uint32_t biCompression;
+ int32_t biSizeImage;
+ uint32_t biXPelsPerMeter;
+ uint32_t biYPelsPerMeter;
+ uint32_t biClrUsed;
+ uint32_t biClrImportant;
+} s_BITMAPINFOHEADER, *s_PBITMAPINFOHEADER;
-// load first supported icon from file
-void render_load_ico_first(util::core_file &fp, bitmap_argb32 &bitmap);
+// 46 bytes
+typedef struct{
+ s_BITMAPINFOHEADER icHeader; // DIB header
+ uint32_t icColors[1]; // Color table (short 4 bytes) //RGBQUAD
+ uint8_t icXOR[1]; // DIB bits for XOR mask
+ uint8_t icAND[1]; // DIB bits for AND mask
+} ICONIMAGE, *LPICONIMAGE;
-// load highest detail supported icon from file
-void render_load_ico_highest_detail(util::core_file &fp, bitmap_argb32 &bitmap);
+//-------------------------------------------------
+// load an ICO file into a bitmap
+//-------------------------------------------------
-} // namespace ui
+inline void render_load_ico(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, const char *filename)
+{
+ int32_t width = 0;
+ int32_t height = 0;
+
+ // deallocate previous bitmap
+ bitmap.reset();
+
+ // define file's full name
+ std::string fname;
+
+ if (!dirname)
+ fname = filename;
+ else
+ fname.assign(dirname).append(PATH_SEPARATOR).append(filename);
+
+ osd_file::error filerr = file.open(fname.c_str());
+
+ if (filerr != osd_file::error::NONE)
+ return;
+
+ // allocates a buffer for the image
+ uint64_t size = file.size();
+ uint8_t *buffer = global_alloc_array(uint8_t, size + 1);
+
+ // read data from the file and set them in the buffer
+ file.read(buffer, size);
+
+ LPICONDIR icoDir = (LPICONDIR)buffer;
+ int iconsCount = icoDir->idCount;
+
+ if (icoDir->idReserved != 0 || icoDir->idType != 1 || iconsCount == 0 || iconsCount > 20)
+ {
+ file.close();
+ global_free_array(buffer);
+ return;
+ }
+
+ uint8_t* cursor = buffer;
+ cursor += 6;
+ ICONDIRENTRY* dirEntry = (ICONDIRENTRY*)(cursor);
+ int maxSize = 0;
+ int offset = 0;
+ int maxBitCount = 0;
+ for (int i = 0; i < iconsCount; i++, ++dirEntry)
+ {
+ int w = dirEntry->bWidth;
+ int h = dirEntry->bHeight;
+ int bitCount = dirEntry->wBitCount;
+ if (w * h > maxSize || bitCount > maxBitCount) // we choose icon with max resolution
+ {
+ width = w;
+ height = h;
+ offset = dirEntry->dwImageOffset;
+ maxSize = w * h;
+ }
+ }
+
+ if (offset == 0) return;
+
+ cursor = buffer;
+ cursor += offset;
+ ICONIMAGE* icon = (ICONIMAGE*)(cursor);
+ int realBitsCount = (int)icon->icHeader.biBitCount;
+ bool hasAndMask = (realBitsCount < 32) && (height != icon->icHeader.biHeight);
+
+ cursor += 40;
+ bitmap.allocate(width, height);
+
+ // rgba + vertical swap
+ if (realBitsCount >= 32)
+ {
+ for (int x = 0; x < width; ++x)
+ for (int y = 0; y < height; ++y)
+ {
+ int shift2 = 4 * (x + (height - y - 1) * width);
+ bitmap.pix32(y, x) = rgb_t(cursor[shift2 + 3], cursor[shift2 + 2], cursor[shift2 + 1], cursor[shift2]);
+ }
+ }
+ else if (realBitsCount == 24)
+ for (int x = 0; x < width; ++x)
+ for (int y = 0; y < height; ++y)
+ {
+ int shift2 = 3 * (x + (height - y - 1) * width);
+ bitmap.pix32(y, x) = rgb_t(255, cursor[shift2 + 2], cursor[shift2 + 1], cursor[shift2]);
+ }
+ else if (realBitsCount == 8) // 256 colors
+ {
+ // 256 color table
+ uint8_t *colors = cursor;
+ cursor += 256 * 4;
+ for (int x = 0; x < width; ++x)
+ for (int y = 0; y < height; ++y)
+ {
+ int shift2 = (x + (height - y - 1) * width);
+ int index = 4 * cursor[shift2];
+ bitmap.pix32(y, x) = rgb_t(255, colors[index + 2], colors[index + 1], colors[index]);
+ }
+ }
+ else if (realBitsCount == 4) // 16 colors
+ {
+ // 16 color table
+ uint8_t *colors = cursor;
+ cursor += 16 * 4;
+ for (int x = 0; x < width; ++x)
+ for (int y = 0; y < height; ++y)
+ {
+ int shift2 = (x + (height - y - 1) * width);
+ uint8_t index = cursor[shift2 / 2];
+ if (shift2 % 2 == 0)
+ index = (index >> 4) & 0xF;
+ else
+ index = index & 0xF;
+ index *= 4;
+ bitmap.pix32(y, x) = rgb_t(255, colors[index + 2], colors[index + 1], colors[index]);
+ }
+ }
+ else if (realBitsCount == 1) // 2 colors
+ {
+ // 2 color table
+ uint8_t *colors = cursor;
+ cursor += 2 * 4;
+ int boundary = width; // !!! 32 bit boundary (http://www.daubnet.com/en/file-format-ico)
+ while (boundary % 32 != 0) boundary++;
+
+ for (int x = 0; x < width; ++x)
+ for (int y = 0; y < height; ++y)
+ {
+ int shift2 = (x + (height - y - 1) * boundary);
+ uint8_t index = cursor[shift2 / 8];
+
+ // select 1 bit only
+ uint8_t bit = 7 - (x % 8);
+ index = (index >> bit) & 0x01;
+ index *= 4;
+ bitmap.pix32(y, x) = rgb_t(255, colors[index + 2], colors[index + 1], colors[index]);
+ }
+ }
+
+ // Read AND mask after base color data - 1 BIT MASK
+ if (hasAndMask)
+ {
+ int boundary = width * realBitsCount; // !!! 32 bit boundary (http://www.daubnet.com/en/file-format-ico)
+ while (boundary % 32 != 0) boundary++;
+ cursor += boundary * height / 8;
+
+ boundary = width;
+ while (boundary % 32 != 0) boundary++;
+
+ for (int y = 0; y < height; ++y)
+ for (int x = 0; x < width; ++x)
+ {
+ uint8_t bit = 7 - (x % 8);
+ int shift2 = (x + (height - y - 1) * boundary) / 8;
+ int mask = (0x01 & ((uint8_t)cursor[shift2] >> bit));
+ rgb_t colors = bitmap.pix32(y, x);
+ uint8_t alpha = colors.a();
+ alpha *= 1 - mask;
+ colors.set_a(alpha);
+ bitmap.pix32(y, x) = colors;
+ }
+ }
+ file.close();
+ global_free_array(buffer);
+}
#endif // MAME_FRONTEND_MAME_UI_ICORENDER_H
diff --git a/src/frontend/mame/ui/info.cpp b/src/frontend/mame/ui/info.cpp
index e7235b89111..963dfb5597c 100644
--- a/src/frontend/mame/ui/info.cpp
+++ b/src/frontend/mame/ui/info.cpp
@@ -28,27 +28,20 @@ constexpr machine_flags::type MACHINE_WARNINGS = machine_flags::NO_COCKTAIL | m
constexpr machine_flags::type MACHINE_BTANB = machine_flags::NO_SOUND_HW | machine_flags::IS_INCOMPLETE;
constexpr std::pair<device_t::feature_type, char const *> FEATURE_NAMES[] = {
- { device_t::feature::PROTECTION, __("protection") },
- { device_t::feature::TIMING, __("timing") },
- { device_t::feature::GRAPHICS, __("graphics") },
- { device_t::feature::PALETTE, __("color palette") },
- { device_t::feature::SOUND, __("sound") },
- { device_t::feature::CAPTURE, __("capture hardware") },
- { device_t::feature::CAMERA, __("camera") },
- { device_t::feature::MICROPHONE, __("microphone") },
- { device_t::feature::CONTROLS, __("controls") },
- { device_t::feature::KEYBOARD, __("keyboard") },
- { device_t::feature::MOUSE, __("mouse") },
- { device_t::feature::MEDIA, __("media") },
- { device_t::feature::DISK, __("disk") },
- { device_t::feature::PRINTER, __("printer") },
- { device_t::feature::TAPE, __("magnetic tape") },
- { device_t::feature::PUNCH, __("punch tape") },
- { device_t::feature::DRUM, __("magnetic drum") },
- { device_t::feature::ROM, __("solid state storage") },
- { device_t::feature::COMMS, __("communications") },
- { device_t::feature::LAN, __("LAN") },
- { device_t::feature::WAN, __("WAN") } };
+ { device_t::feature::PROTECTION, __("protection") },
+ { device_t::feature::PALETTE, __("color palette") },
+ { device_t::feature::GRAPHICS, __("graphics") },
+ { device_t::feature::SOUND, __("sound") },
+ { device_t::feature::CONTROLS, __("controls") },
+ { device_t::feature::KEYBOARD, __("keyboard") },
+ { device_t::feature::MOUSE, __("mouse") },
+ { device_t::feature::MICROPHONE, __("microphone") },
+ { device_t::feature::CAMERA, __("camera") },
+ { device_t::feature::DISK, __("disk") },
+ { device_t::feature::PRINTER, __("printer") },
+ { device_t::feature::LAN, __("LAN") },
+ { device_t::feature::WAN, __("WAN") },
+ { device_t::feature::TIMING, __("timing") } };
} // anonymous namespace
diff --git a/src/frontend/mame/ui/inifile.cpp b/src/frontend/mame/ui/inifile.cpp
index b68be00122b..852884fea6a 100644
--- a/src/frontend/mame/ui/inifile.cpp
+++ b/src/frontend/mame/ui/inifile.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Maurizio Petrarota, Vas Crabb
+// copyright-holders:Maurizio Petrarota
/***************************************************************************
ui/inifile.cpp
@@ -16,24 +16,13 @@
#include "drivenum.h"
#include "softlist_dev.h"
-#include <algorithm>
-#include <cstring>
-#include <iterator>
-
-
-namespace {
-
-char const FAVORITE_FILENAME[] = "favorites.ini";
-
-} // anonymous namespace
-
//-------------------------------------------------
// ctor
//-------------------------------------------------
-inifile_manager::inifile_manager(ui_options &options)
- : m_options(options)
+inifile_manager::inifile_manager(running_machine &machine, ui_options &moptions)
+ : m_options(moptions)
, m_ini_index()
{
// scan directories and create index
@@ -119,103 +108,204 @@ void inifile_manager::init_category(std::string &&filename, emu_file &file)
FAVORITE MANAGER
**************************************************************************/
-bool favorite_manager::favorite_compare::operator()(ui_software_info const &lhs, ui_software_info const &rhs) const
+//-------------------------------------------------
+// ctor
+//-------------------------------------------------
+
+favorite_manager::favorite_manager(running_machine &machine, ui_options &moptions)
+ : m_machine(machine)
+ , m_options(moptions)
{
- assert(lhs.driver);
- assert(rhs.driver);
+ parse_favorite();
+}
- if (!lhs.startempty)
+//-------------------------------------------------
+// add a game
+//-------------------------------------------------
+
+void favorite_manager::add_favorite_game(const game_driver *driver)
+{
+ m_list.emplace(driver->type.fullname(), *driver);
+ save_favorite_games();
+}
+
+//-------------------------------------------------
+// add a system
+//-------------------------------------------------
+
+void favorite_manager::add_favorite_game(ui_software_info &swinfo)
+{
+ m_list.emplace(swinfo.longname, swinfo);
+ save_favorite_games();
+}
+
+//-------------------------------------------------
+// add a game / system
+//-------------------------------------------------
+
+void favorite_manager::add_favorite_game()
+{
+ if ((machine().system().flags & machine_flags::MASK_TYPE) == machine_flags::TYPE_ARCADE)
{
- if (rhs.startempty)
- return false;
- else if (lhs.listname < rhs.listname)
- return true;
- else if (lhs.listname > rhs.listname)
- return false;
- else if (lhs.shortname < rhs.shortname)
- return true;
- else if (lhs.shortname > rhs.shortname)
- return false;
+ add_favorite_game(&machine().system());
+ return;
}
- else if (!rhs.startempty)
+
+ auto software_avail = false;
+ for (device_image_interface &image : image_interface_iterator(machine().root_device()))
{
- return true;
+ if (image.exists() && image.loaded_through_softlist())
+ {
+ const software_info *swinfo = image.software_entry();
+ const software_part *part = image.part_entry();
+ ui_software_info tmpmatches;
+ tmpmatches.shortname = swinfo->shortname();
+ tmpmatches.longname = image.longname();
+ tmpmatches.parentname = swinfo->parentname();
+ tmpmatches.year = image.year();
+ tmpmatches.publisher = image.manufacturer();
+ tmpmatches.supported = image.supported();
+ tmpmatches.part = part->name();
+ tmpmatches.driver = &machine().system();
+ tmpmatches.listname = strensure(image.software_list_name());
+ tmpmatches.interface = part->interface();
+ tmpmatches.instance = image.instance_name();
+ tmpmatches.startempty = 0;
+ tmpmatches.parentlongname.clear();
+ if (!swinfo->parentname().empty())
+ {
+ auto swlist = software_list_device::find_by_name(machine().config(), image.software_list_name());
+ for (const software_info &c_swinfo : swlist->get_info())
+ {
+ std::string c_parent(c_swinfo.parentname());
+ if (!c_parent.empty() && c_parent == swinfo->shortname())
+ {
+ tmpmatches.parentlongname = c_swinfo.longname();
+ break;
+ }
+ }
+ }
+
+ tmpmatches.usage.clear();
+ for (const feature_list_item &flist : swinfo->other_info())
+ if (!strcmp(flist.name().c_str(), "usage"))
+ tmpmatches.usage = flist.value();
+
+ tmpmatches.devicetype = strensure(image.image_type_name());
+ tmpmatches.available = true;
+ software_avail = true;
+ m_list.emplace(tmpmatches.longname, tmpmatches);
+ save_favorite_games();
+ }
}
- return 0 > std::strncmp(lhs.driver->name, rhs.driver->name, ARRAY_LENGTH(lhs.driver->name));
+ if (!software_avail)
+ add_favorite_game(&machine().system());
}
-bool favorite_manager::favorite_compare::operator()(ui_software_info const &lhs, game_driver const &rhs) const
+//-------------------------------------------------
+// remove a favorite from list
+//-------------------------------------------------
+
+void favorite_manager::remove_favorite_game(ui_software_info const &swinfo)
{
- assert(lhs.driver);
+ for (auto e = m_list.begin(); e != m_list.end(); ++e)
+ if (e->second == swinfo)
+ {
+ m_list.erase(e);
+ break;
+ }
+ m_current = m_list.begin();
+ save_favorite_games();
+}
+
+//-------------------------------------------------
+// remove a favorite from list
+//-------------------------------------------------
- if (!lhs.startempty)
- return false;
- else
- return 0 > std::strncmp(lhs.driver->name, rhs.name, ARRAY_LENGTH(rhs.name));
+void favorite_manager::remove_favorite_game()
+{
+ m_list.erase(m_current);
+ m_current = m_list.begin();
+ save_favorite_games();
}
-bool favorite_manager::favorite_compare::operator()(game_driver const &lhs, ui_software_info const &rhs) const
+//-------------------------------------------------
+// check if game is already in favorite list
+//-------------------------------------------------
+
+bool favorite_manager::isgame_favorite()
{
- assert(rhs.driver);
+ if ((machine().system().flags & machine_flags::MASK_TYPE) == machine_flags::TYPE_ARCADE)
+ return isgame_favorite(&machine().system());
+
+ auto image_loaded = false;
- if (!rhs.startempty)
- return true;
- else
- return 0 > std::strncmp(lhs.name, rhs.driver->name, ARRAY_LENGTH(lhs.name));
+ for (device_image_interface &image : image_interface_iterator(machine().root_device()))
+ {
+ const software_info *swinfo = image.software_entry();
+ if (image.exists() && swinfo != nullptr)
+ {
+ image_loaded = true;
+ for (auto current = m_list.begin(); current != m_list.end(); ++current)
+ if (current->second.shortname == swinfo->shortname() &&
+ current->second.listname == image.software_list_name())
+ {
+ m_current = current;
+ return true;
+ }
+ }
+ }
+
+ if (!image_loaded)
+ return isgame_favorite(&machine().system());
+
+ m_current = m_list.begin();
+ return false;
}
-bool favorite_manager::favorite_compare::operator()(ui_software_info const &lhs, running_software_key const &rhs) const
+//-------------------------------------------------
+// check if game is already in favorite list
+//-------------------------------------------------
+
+bool favorite_manager::isgame_favorite(const game_driver *driver)
{
- assert(lhs.driver);
- assert(std::get<1>(rhs));
-
- if (lhs.startempty)
- return true;
- else if (lhs.listname < std::get<1>(rhs))
- return true;
- else if (lhs.listname > std::get<1>(rhs))
- return false;
- else if (lhs.shortname < std::get<2>(rhs))
- return true;
- else if (lhs.shortname > std::get<2>(rhs))
- return false;
- else
- return 0 > std::strncmp(lhs.driver->name, std::get<0>(rhs).name, ARRAY_LENGTH(lhs.driver->name));
+ for (auto current = m_list.begin(); current != m_list.end(); ++current)
+ if (current->second.driver == driver && current->second.shortname == driver->name)
+ {
+ m_current = current;
+ return true;
+ }
+
+ m_current = m_list.begin();
+ return false;
}
-bool favorite_manager::favorite_compare::operator()(running_software_key const &lhs, ui_software_info const &rhs) const
+//-------------------------------------------------
+// check if game is already in favorite list
+//-------------------------------------------------
+
+bool favorite_manager::isgame_favorite(ui_software_info const &swinfo)
{
- assert(std::get<1>(lhs));
- assert(rhs.driver);
-
- if (rhs.startempty)
- return false;
- else if (std::get<1>(lhs) < rhs.listname)
- return true;
- else if (std::get<1>(lhs) > rhs.listname)
- return false;
- else if (std::get<2>(lhs) < rhs.shortname)
- return true;
- else if (std::get<2>(lhs) > rhs.shortname)
- return false;
- else
- return 0 > std::strncmp(std::get<0>(lhs).name, rhs.driver->name, ARRAY_LENGTH(rhs.driver->name));
-}
+ for (auto current = m_list.begin(); current != m_list.end(); ++current)
+ if (current->second == swinfo)
+ {
+ m_current = current;
+ return true;
+ }
+ m_current = m_list.begin();
+ return false;
+}
//-------------------------------------------------
-// construction/destruction
+// parse favorite file
//-------------------------------------------------
-favorite_manager::favorite_manager(ui_options &options)
- : m_options(options)
- , m_favorites()
- , m_sorted()
- , m_need_sort(true)
+void favorite_manager::parse_favorite()
{
emu_file file(m_options.ui_path(), OPEN_FLAG_READ);
- if (file.open(FAVORITE_FILENAME) == osd_file::error::NONE)
+ if (file.open(favorite_filename) == osd_file::error::NONE)
{
char readbuf[1024];
file.gets(readbuf, 1024);
@@ -242,8 +332,7 @@ favorite_manager::favorite_manager(ui_options &options)
file.gets(readbuf, 1024);
chartrimcarriage(readbuf);
auto dx = driver_list::find(readbuf);
- if (0 > dx)
- continue;
+ if (dx == -1) continue;
tmpmatches.driver = &driver_list::driver(dx);
file.gets(readbuf, 1024);
tmpmatches.listname = chartrimcarriage(readbuf);
@@ -261,319 +350,53 @@ favorite_manager::favorite_manager(ui_options &options)
tmpmatches.devicetype = chartrimcarriage(readbuf);
file.gets(readbuf, 1024);
tmpmatches.available = atoi(readbuf);
- m_favorites.emplace(std::move(tmpmatches));
+ m_list.emplace(tmpmatches.longname, tmpmatches);
}
file.close();
}
}
-
-//-------------------------------------------------
-// add
-//-------------------------------------------------
-
-void favorite_manager::add_favorite_system(game_driver const &driver)
-{
- add_impl(driver);
-}
-
-void favorite_manager::add_favorite_software(ui_software_info const &swinfo)
-{
- add_impl(swinfo);
-}
-
-void favorite_manager::add_favorite(running_machine &machine)
-{
- apply_running_machine(
- machine,
- [this, &machine] (game_driver const &driver, device_image_interface *imagedev, software_info const *software, bool &done)
- {
- if (imagedev)
- {
- // creating this is fairly expensive, but we'll assume this usually succeeds
- ui_software_info info;
- software_part const *const part(imagedev->part_entry());
- assert(software);
- assert(part);
-
- // start with simple stuff that can just be copied
- info.shortname = software->shortname();
- info.longname = imagedev->longname();
- info.parentname = software->parentname();
- info.year = imagedev->year();
- info.publisher = imagedev->manufacturer();
- info.supported = imagedev->supported();
- info.part = part->name();
- info.driver = &driver;
- info.listname = imagedev->software_list_name();
- info.interface = part->interface();
- info.instance = imagedev->instance_name();
- info.startempty = 0;
- info.devicetype = strensure(imagedev->image_type_name());
- info.available = true;
-
- // look up the parent in the list if necessary (eugh, O(n) walk)
- if (!info.parentname.empty())
- {
- auto const listdev = software_list_device::find_by_name(machine.config(), info.listname);
- assert(listdev);
- for (software_info const &other : listdev->get_info())
- {
- if (other.shortname() == info.parentname)
- {
- info.parentlongname = other.longname();
- break;
- }
- }
- }
-
- // fill in with the first usage entry we find
- for (feature_list_item const &feature : software->other_info())
- {
- if (feature.name() == "usage")
- {
- info.usage = feature.value();
- break;
- }
- }
-
- // hooray for move semantics!
- add_impl(std::move(info));
- }
- else
- {
- add_impl(driver);
- }
- });
-}
-
-template <typename T> void favorite_manager::add_impl(T &&key)
-{
- auto const ins(m_favorites.emplace(std::forward<T>(key)));
- if (ins.second)
- {
- if (!m_sorted.empty())
- m_sorted.emplace_back(std::ref(*ins.first));
- m_need_sort = true;
- save_favorites();
- }
-}
-
-
-//-------------------------------------------------
-// check
-//-------------------------------------------------
-
-bool favorite_manager::is_favorite_system(game_driver const &driver) const
-{
- return check_impl(driver);
-}
-
-bool favorite_manager::is_favorite_software(ui_software_info const &swinfo) const
-{
- auto found(m_favorites.lower_bound(swinfo));
- if ((m_favorites.end() != found) && (found->listname == swinfo.listname) && (found->shortname == swinfo.shortname))
- return true;
- else if (m_favorites.begin() == found)
- return false;
-
- // need to back up and check for matching software with lexically earlier driver
- --found;
- return (found->listname == swinfo.listname) && (found->shortname == swinfo.shortname);
-}
-
-bool favorite_manager::is_favorite(running_machine &machine) const
-{
- bool result(false);
- apply_running_machine(
- machine,
- [this, &result] (game_driver const &driver, device_image_interface *imagedev, software_info const *software, bool &done)
- {
- assert(!result);
- result = imagedev
- ? check_impl(running_software_key(driver, imagedev->software_list_name(), software->shortname()))
- : check_impl(driver);
- done = done || result;
- });
- return result;
-}
-
-bool favorite_manager::is_favorite_system_software(ui_software_info const &swinfo) const
-{
- return check_impl(swinfo);
-}
-
-template <typename T> bool favorite_manager::check_impl(T const &key) const
-{
- return m_favorites.find(key) != m_favorites.end();
-}
-
-
-//-------------------------------------------------
-// remove
-//-------------------------------------------------
-
-void favorite_manager::remove_favorite_system(game_driver const &driver)
-{
- remove_impl(driver);
-}
-
-void favorite_manager::remove_favorite_software(ui_software_info const &swinfo)
-{
- remove_impl(swinfo);
-}
-
-void favorite_manager::remove_favorite(running_machine &machine)
-{
- apply_running_machine(
- machine,
- [this] (game_driver const &driver, device_image_interface *imagedev, software_info const *software, bool &done)
- {
- done = imagedev
- ? remove_impl(running_software_key(driver, imagedev->software_list_name(), software->shortname()))
- : remove_impl(driver);
- });
-}
-
-template <typename T> bool favorite_manager::remove_impl(T const &key)
-{
- auto const found(m_favorites.find(key));
- if (m_favorites.end() != found)
- {
- m_favorites.erase(found);
- m_sorted.clear();
- m_need_sort = true;
- save_favorites();
- return true;
- }
- else
- {
- return false;
- }
-}
-
-
//-------------------------------------------------
-// implementation
+// save favorite
//-------------------------------------------------
-template <typename T>
-void favorite_manager::apply_running_machine(running_machine &machine, T &&action)
-{
- bool done(false);
-
- // TODO: this should be changed - it interacts poorly with cartslots on arcade systems
- if ((machine.system().flags & machine_flags::MASK_TYPE) == machine_flags::TYPE_ARCADE)
- {
- action(machine.system(), nullptr, nullptr, done);
- }
- else
- {
- bool have_software(false);
- for (device_image_interface &image_dev : image_interface_iterator(machine.root_device()))
- {
- software_info const *const sw(image_dev.software_entry());
- if (image_dev.exists() && image_dev.loaded_through_softlist() && sw)
- {
- assert(image_dev.software_list_name());
-
- have_software = true;
- action(machine.system(), &image_dev, sw, done);
- if (done)
- return;
- }
- }
-
- if (!have_software)
- action(machine.system(), nullptr, nullptr, done);
- }
-}
-
-void favorite_manager::update_sorted()
-{
- if (m_need_sort)
- {
- if (m_sorted.empty())
- std::copy(m_favorites.begin(), m_favorites.end(), std::back_inserter(m_sorted));
-
- assert(m_favorites.size() == m_sorted.size());
- std::stable_sort(
- m_sorted.begin(),
- m_sorted.end(),
- [] (ui_software_info const &lhs, ui_software_info const &rhs) -> bool
- {
- assert(lhs.driver);
- assert(rhs.driver);
-
- int cmp;
-
- cmp = core_stricmp(lhs.longname.c_str(), rhs.longname.c_str());
- if (0 > cmp)
- return true;
- else if (0 < cmp)
- return false;
-
- cmp = core_stricmp(lhs.driver->type.fullname(), rhs.driver->type.fullname());
- if (0 > cmp)
- return true;
- else if (0 < cmp)
- return false;
-
- cmp = std::strcmp(lhs.listname.c_str(), rhs.listname.c_str());
- if (0 > cmp)
- return true;
- else if (0 < cmp)
- return false;
-
- return false;
- });
-
- m_need_sort = false;
- }
-}
-
-void favorite_manager::save_favorites()
+void favorite_manager::save_favorite_games()
{
// attempt to open the output file
emu_file file(m_options.ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
- if (file.open(FAVORITE_FILENAME) == osd_file::error::NONE)
+ if (file.open(favorite_filename) == osd_file::error::NONE)
{
- if (m_favorites.empty())
+ if (m_list.empty())
{
- // delete it if there are no favorites
file.remove_on_close();
+ file.close();
+ return;
}
- else
+
+ // generate the favorite INI
+ std::ostringstream text;
+ text << "[ROOT_FOLDER]\n[Favorite]\n\n";
+ for (auto & e : m_list)
{
- // generate the favorite INI
- file.puts("[ROOT_FOLDER]\n[Favorite]\n\n");
- util::ovectorstream buf;
- for (ui_software_info const &info : m_favorites)
- {
- buf.clear();
- buf.rdbuf()->clear();
-
- buf << info.shortname << '\n';
- buf << info.longname << '\n';
- buf << info.parentname << '\n';
- buf << info.year << '\n';
- buf << info.publisher << '\n';
- util::stream_format(buf, "%d\n", info.supported);
- buf << info.part << '\n';
- util::stream_format(buf, "%s\n", info.driver->name);
- buf << info.listname << '\n';
- buf << info.interface << '\n';
- buf << info.instance << '\n';
- util::stream_format(buf, "%d\n", info.startempty);
- buf << info.parentlongname << '\n';
- buf << info.usage << '\n';
- buf << info.devicetype << '\n';
- util::stream_format(buf, "%d\n", info.available);
-
- buf.put('\0');
- file.puts(&buf.vec()[0]);
- }
+ auto elem = e.second;
+ text << elem.shortname << '\n';
+ text << elem.longname << '\n';
+ text << elem.parentname << '\n';
+ text << elem.year << '\n';
+ text << elem.publisher << '\n';
+ util::stream_format(text, "%d\n", elem.supported);
+ text << elem.part << '\n';
+ util::stream_format(text, "%s\n", elem.driver->name);
+ text << elem.listname << '\n';
+ text << elem.interface << '\n';
+ text << elem.instance << '\n';
+ util::stream_format(text, "%d\n", elem.startempty);
+ text << elem.parentlongname << '\n';
+ text << elem.usage << '\n';
+ text << elem.devicetype << '\n';
+ util::stream_format(text, "%d\n", elem.available);
}
+ file.puts(text.str().c_str());
file.close();
}
}
diff --git a/src/frontend/mame/ui/inifile.h b/src/frontend/mame/ui/inifile.h
index 68adca3c917..49344fd01eb 100644
--- a/src/frontend/mame/ui/inifile.h
+++ b/src/frontend/mame/ui/inifile.h
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Maurizio Petrarota, Vas Crabb
+// copyright-holders:Maurizio Petrarota
/***************************************************************************
ui/inifile.h
@@ -7,6 +7,7 @@
UI INIs file manager.
***************************************************************************/
+
#ifndef MAME_FRONTEND_UI_INIFILE_H
#define MAME_FRONTEND_UI_INIFILE_H
@@ -14,10 +15,6 @@
#include "ui/utils.h"
-#include <functional>
-#include <set>
-#include <tuple>
-#include <type_traits>
#include <unordered_set>
@@ -31,7 +28,7 @@ class inifile_manager
{
public:
// construction/destruction
- inifile_manager(ui_options &options);
+ inifile_manager(running_machine &machine, ui_options &moptions);
// load systems from category
void load_ini_category(size_t file, size_t category, std::unordered_set<game_driver const *> &result) const;
@@ -62,67 +59,52 @@ class favorite_manager
{
public:
// construction/destruction
- favorite_manager(ui_options &options);
+ favorite_manager(running_machine &machine, ui_options &moptions);
+
+ // favorites comparator
+ struct ci_less
+ {
+ bool operator() (const std::string &s1, const std::string &s2) const
+ {
+ return (core_stricmp(s1.c_str(), s2.c_str()) < 0);
+ }
+ };
+
+ // favorite indices
+ std::multimap<std::string, ui_software_info, ci_less> m_list;
+
+ // getters
+ running_machine &machine() const { return m_machine; }
// add
- void add_favorite_system(game_driver const &driver);
- void add_favorite_software(ui_software_info const &swinfo);
- void add_favorite(running_machine &machine);
+ void add_favorite_game();
+ void add_favorite_game(const game_driver *driver);
+ void add_favorite_game(ui_software_info &swinfo);
// check
- bool is_favorite_system(game_driver const &driver) const;
- bool is_favorite_software(ui_software_info const &swinfo) const;
- bool is_favorite_system_software(ui_software_info const &swinfo) const;
- bool is_favorite(running_machine &machine) const;
+ bool isgame_favorite();
+ bool isgame_favorite(const game_driver *driver);
+ bool isgame_favorite(ui_software_info const &swinfo);
- // remove
- void remove_favorite_system(game_driver const &driver);
- void remove_favorite_software(ui_software_info const &swinfo);
- void remove_favorite(running_machine &machine);
+ // save
+ void save_favorite_games();
- // walk
- template <typename T> void apply(T &&action)
- {
- for (auto const &item : m_favorites)
- action(item);
- }
- template <typename T> void apply_sorted(T &&action)
- {
- update_sorted();
- for (auto const &item : m_sorted)
- action(item.get());
- }
+ // remove
+ void remove_favorite_game();
+ void remove_favorite_game(ui_software_info const &swinfo);
private:
- using running_software_key = std::tuple<game_driver const &, char const *, std::string const &>;
-
- struct favorite_compare
- {
- using is_transparent = std::true_type;
-
- bool operator()(ui_software_info const &lhs, ui_software_info const &rhs) const;
- bool operator()(ui_software_info const &lhs, game_driver const &rhs) const;
- bool operator()(game_driver const &lhs, ui_software_info const &rhs) const;
- bool operator()(ui_software_info const &lhs, running_software_key const &rhs) const;
- bool operator()(running_software_key const &lhs, ui_software_info const &rhs) const;
- };
+ const char *favorite_filename = "favorites.ini";
- using favorites_set = std::set<ui_software_info, favorite_compare>;
- using sorted_favorites = std::vector<std::reference_wrapper<ui_software_info const> >;
+ // current
+ std::multimap<std::string, ui_software_info>::iterator m_current;
- // implementation
- template <typename T> static void apply_running_machine(running_machine &machine, T &&action);
- template <typename T> void add_impl(T &&key);
- template <typename T> bool check_impl(T const &key) const;
- template <typename T> bool remove_impl(T const &key);
- void update_sorted();
- void save_favorites();
+ // parse file ui_favorite
+ void parse_favorite();
// internal state
+ running_machine &m_machine; // reference to our machine
ui_options &m_options;
- favorites_set m_favorites;
- sorted_favorites m_sorted;
- bool m_need_sort;
};
#endif // MAME_FRONTEND_UI_INIFILE_H
diff --git a/src/frontend/mame/ui/mainmenu.cpp b/src/frontend/mame/ui/mainmenu.cpp
index b9befd90991..30b2fbae1e0 100644
--- a/src/frontend/mame/ui/mainmenu.cpp
+++ b/src/frontend/mame/ui/mainmenu.cpp
@@ -123,7 +123,7 @@ void menu_main::populate(float &customtop, float &custombottom)
item_append(menu_item_type::SEPARATOR);
- if (!mame_machine_manager::instance()->favorite().is_favorite(machine()))
+ if (!mame_machine_manager::instance()->favorite().isgame_favorite())
item_append(_("Add To Favorites"), "", 0, (void *)ADD_FAVORITE);
else
item_append(_("Remove From Favorites"), "", 0, (void *)REMOVE_FAVORITE);
@@ -249,12 +249,12 @@ void menu_main::handle()
break;
case ADD_FAVORITE:
- mame_machine_manager::instance()->favorite().add_favorite(machine());
+ mame_machine_manager::instance()->favorite().add_favorite_game();
reset(reset_options::REMEMBER_POSITION);
break;
case REMOVE_FAVORITE:
- mame_machine_manager::instance()->favorite().remove_favorite(machine());
+ mame_machine_manager::instance()->favorite().remove_favorite_game();
reset(reset_options::REMEMBER_POSITION);
break;
diff --git a/src/frontend/mame/ui/menu.cpp b/src/frontend/mame/ui/menu.cpp
index eecaab68978..3a0eff12c5e 100644
--- a/src/frontend/mame/ui/menu.cpp
+++ b/src/frontend/mame/ui/menu.cpp
@@ -31,7 +31,6 @@
namespace ui {
-
/***************************************************************************
CONSTANTS
***************************************************************************/
@@ -86,14 +85,14 @@ menu::global_state::global_state(running_machine &machine, ui_options const &opt
, m_machine(machine)
, m_cleanup_callbacks()
, m_bgrnd_bitmap()
- , m_bgrnd_texture(nullptr, machine.render())
, m_stack()
, m_free()
{
render_manager &render(machine.render());
+ auto const texture_free([&render](render_texture *texture) { render.texture_free(texture); });
// create a texture for main menu background
- m_bgrnd_texture.reset(render.texture_alloc(render_texture::hq_scale));
+ m_bgrnd_texture = texture_ptr(render.texture_alloc(render_texture::hq_scale), texture_free);
if (options.use_background_image() && (&machine.system() == &GAME_NAME(___empty)))
{
m_bgrnd_bitmap = std::make_unique<bitmap_argb32>(0, 0);
@@ -162,17 +161,8 @@ void menu::global_state::stack_reset()
void menu::global_state::clear_free_list()
{
- // free stack is in reverse order - unwind it properly
- std::unique_ptr<menu> reversed;
while (m_free)
- {
- std::unique_ptr<menu> menu(std::move(m_free));
- m_free = std::move(menu->m_parent);
- menu->m_parent = std::move(reversed);
- reversed = std::move(menu);
- }
- while (reversed)
- reversed = std::move(reversed->m_parent);
+ m_free = std::move(m_free->m_parent);
}
diff --git a/src/frontend/mame/ui/menu.h b/src/frontend/mame/ui/menu.h
index ffcb0ed71e8..1a6c2d977f8 100644
--- a/src/frontend/mame/ui/menu.h
+++ b/src/frontend/mame/ui/menu.h
@@ -27,7 +27,6 @@
namespace ui {
-
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
@@ -36,17 +35,18 @@ class menu
{
public:
// flags for menu items
- enum : unsigned
+ enum
{
- FLAG_LEFT_ARROW = 1U << 0,
- FLAG_RIGHT_ARROW = 1U << 1,
- FLAG_INVERT = 1U << 2,
- FLAG_MULTILINE = 1U << 3,
- FLAG_REDTEXT = 1U << 4,
- FLAG_DISABLE = 1U << 5,
- FLAG_UI_DATS = 1U << 6,
- FLAG_UI_HEADING = 1U << 7,
- FLAG_COLOR_BOX = 1U << 8
+ FLAG_LEFT_ARROW = (1 << 0),
+ FLAG_RIGHT_ARROW = (1 << 1),
+ FLAG_INVERT = (1 << 2),
+ FLAG_MULTILINE = (1 << 3),
+ FLAG_REDTEXT = (1 << 4),
+ FLAG_DISABLE = (1 << 5),
+ FLAG_UI_DATS = (1 << 6),
+ FLAG_UI_FAVORITE = (1 << 7),
+ FLAG_UI_HEADING = (1 << 8),
+ FLAG_COLOR_BOX = (1 << 9)
};
virtual ~menu();
@@ -151,6 +151,7 @@ protected:
void reset(reset_options options);
void reset_parent(reset_options options) { m_parent->reset(options); }
+ void reset_topmost(reset_options options) { m_global_state->reset_topmost(options); }
template <typename T> T *topmost_menu() const { return m_global_state->topmost_menu<T>(); }
template <typename T> static T *topmost_menu(running_machine &machine) { return get_global_state(machine)->topmost_menu<T>(); }
@@ -309,6 +310,8 @@ private:
bitmap_argb32 *bgrnd_bitmap() { return m_bgrnd_bitmap.get(); }
render_texture *bgrnd_texture() { return m_bgrnd_texture.get(); }
+ void reset_topmost(reset_options options) { if (m_stack) m_stack->reset(options); }
+
template <typename T>
T *topmost_menu() const { return dynamic_cast<T *>(m_stack.get()); }
diff --git a/src/frontend/mame/ui/miscmenu.cpp b/src/frontend/mame/ui/miscmenu.cpp
index e2f1f0615fc..57b1412dd5d 100644
--- a/src/frontend/mame/ui/miscmenu.cpp
+++ b/src/frontend/mame/ui/miscmenu.cpp
@@ -663,40 +663,25 @@ void menu_export::populate(float &customtop, float &custombottom)
// ctor / dtor
//-------------------------------------------------
-menu_machine_configure::menu_machine_configure(
- mame_ui_manager &mui,
- render_container &container,
- game_driver const &drv,
- std::function<void (bool, bool)> &&handler,
- float x0, float y0)
+menu_machine_configure::menu_machine_configure(mame_ui_manager &mui, render_container &container, const game_driver *prev, float _x0, float _y0)
: menu(mui, container)
- , m_handler(std::move(handler))
- , m_drv(drv)
- , m_x0(x0)
- , m_y0(y0)
+ , m_drv(prev)
+ , x0(_x0)
+ , y0(_y0)
, m_curbios(0)
- , m_was_favorite(mame_machine_manager::instance()->favorite().is_favorite_system(drv))
- , m_want_favorite(m_was_favorite)
+ , m_fav_reset(false)
{
// parse the INI file
std::ostringstream error;
osd_setup_osd_specific_emu_options(m_opts);
- mame_options::parse_standard_inis(m_opts, error, &m_drv);
+ mame_options::parse_standard_inis(m_opts, error, m_drv);
setup_bios();
}
menu_machine_configure::~menu_machine_configure()
{
- if (m_was_favorite != m_want_favorite)
- {
- if (m_want_favorite)
- mame_machine_manager::instance()->favorite().add_favorite_system(m_drv);
- else
- mame_machine_manager::instance()->favorite().remove_favorite_system(m_drv);
- }
-
- if (m_handler)
- m_handler(m_want_favorite, m_was_favorite != m_want_favorite);
+ if (m_fav_reset)
+ reset_topmost(reset_options::SELECT_FIRST);
}
//-------------------------------------------------
@@ -707,16 +692,16 @@ void menu_machine_configure::handle()
{
// process the menu
process_parent();
- const event *menu_event = process(PROCESS_NOIMAGE, m_x0, m_y0);
+ const event *menu_event = process(PROCESS_NOIMAGE, x0, y0);
if (menu_event != nullptr && menu_event->itemref != nullptr)
{
if (menu_event->iptkey == IPT_UI_SELECT)
{
switch ((uintptr_t)menu_event->itemref)
{
- case SAVE:
+ case SAVE:
{
- std::string filename(m_drv.name);
+ std::string filename(m_drv->name);
emu_file file(machine().options().ini_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE);
osd_file::error filerr = file.open(filename.c_str(), ".ini");
if (filerr == osd_file::error::NONE)
@@ -725,30 +710,36 @@ void menu_machine_configure::handle()
file.puts(inistring.c_str());
ui().popup_time(2, "%s", _("\n Configuration saved \n\n"));
}
+ break;
}
- break;
- case ADDFAV:
- m_want_favorite = true;
- reset(reset_options::REMEMBER_POSITION);
- break;
- case DELFAV:
- m_want_favorite = false;
- reset(reset_options::REMEMBER_POSITION);
- break;
- case CONTROLLER:
- if (menu_event->iptkey == IPT_UI_SELECT)
- menu::stack_push<submenu>(ui(), container(), submenu::control_options, &m_drv, &m_opts);
- break;
- case VIDEO:
- if (menu_event->iptkey == IPT_UI_SELECT)
- menu::stack_push<submenu>(ui(), container(), submenu::video_options, &m_drv, &m_opts);
- break;
- case ADVANCED:
- if (menu_event->iptkey == IPT_UI_SELECT)
- menu::stack_push<submenu>(ui(), container(), submenu::advanced_options, &m_drv, &m_opts);
- break;
- default:
- break;
+ case ADDFAV:
+ mame_machine_manager::instance()->favorite().add_favorite_game(m_drv);
+ reset(reset_options::REMEMBER_POSITION);
+ break;
+ case DELFAV:
+ mame_machine_manager::instance()->favorite().remove_favorite_game();
+ if (main_filters::actual == machine_filter::FAVORITE)
+ {
+ m_fav_reset = true;
+ menu::stack_pop();
+ }
+ else
+ reset(reset_options::REMEMBER_POSITION);
+ break;
+ case CONTROLLER:
+ if (menu_event->iptkey == IPT_UI_SELECT)
+ menu::stack_push<submenu>(ui(), container(), submenu::control_options, m_drv, &m_opts);
+ break;
+ case VIDEO:
+ if (menu_event->iptkey == IPT_UI_SELECT)
+ menu::stack_push<submenu>(ui(), container(), submenu::video_options, m_drv, &m_opts);
+ break;
+ case ADVANCED:
+ if (menu_event->iptkey == IPT_UI_SELECT)
+ menu::stack_push<submenu>(ui(), container(), submenu::advanced_options, m_drv, &m_opts);
+ break;
+ default:
+ break;
}
}
else if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
@@ -782,7 +773,7 @@ void menu_machine_configure::populate(float &customtop, float &custombottom)
item_append(_(submenu::control_options[0].description), "", 0, (void *)(uintptr_t)CONTROLLER);
item_append(menu_item_type::SEPARATOR);
- if (!m_want_favorite)
+ if (!mame_machine_manager::instance()->favorite().isgame_favorite(m_drv))
item_append(_("Add To Favorites"), "", 0, (void *)ADDFAV);
else
item_append(_("Remove From Favorites"), "", 0, (void *)DELFAV);
@@ -799,7 +790,7 @@ void menu_machine_configure::populate(float &customtop, float &custombottom)
void menu_machine_configure::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{
- char const *const text[] = { _("Configure machine:"), m_drv.type.fullname() };
+ char const *const text[] = { _("Configure machine:"), m_drv->type.fullname() };
draw_text_box(
std::begin(text), std::end(text),
origx1, origx2, origy1 - top, origy1 - UI_BOX_TB_BORDER,
@@ -809,19 +800,19 @@ void menu_machine_configure::custom_render(void *selectedref, float top, float b
void menu_machine_configure::setup_bios()
{
- if (!m_drv.rom)
+ if (m_drv->rom == nullptr)
return;
std::string specbios(m_opts.bios());
char const *default_name(nullptr);
- for (tiny_rom_entry const *rom = m_drv.rom; !ROMENTRY_ISEND(rom); ++rom)
+ for (tiny_rom_entry const *rom = m_drv->rom; !ROMENTRY_ISEND(rom); ++rom)
{
if (ROMENTRY_ISDEFAULT_BIOS(rom))
default_name = rom->name;
}
std::size_t bios_count = 0;
- for (romload::system_bios const &bios : romload::entries(m_drv.rom).get_system_bioses())
+ for (romload::system_bios const &bios : romload::entries(m_drv->rom).get_system_bioses())
{
std::string name(bios.get_description());
u32 const bios_flags(bios.get_value());
diff --git a/src/frontend/mame/ui/miscmenu.h b/src/frontend/mame/ui/miscmenu.h
index 4df94c60a78..65ef235de57 100644
--- a/src/frontend/mame/ui/miscmenu.h
+++ b/src/frontend/mame/ui/miscmenu.h
@@ -20,7 +20,6 @@
#include <vector>
namespace ui {
-
class menu_keyboard_mode : public menu
{
public:
@@ -135,12 +134,7 @@ private:
class menu_machine_configure : public menu
{
public:
- menu_machine_configure(
- mame_ui_manager &mui,
- render_container &container,
- game_driver const &drv,
- std::function<void (bool, bool)> &&handler = nullptr,
- float x0 = 0.0f, float y0 = 0.0f);
+ menu_machine_configure(mame_ui_manager &mui, render_container &container, const game_driver *prev, float x0 = 0.0f, float y0 = 0.0f);
virtual ~menu_machine_configure();
protected:
@@ -164,17 +158,13 @@ private:
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle() override;
- void setup_bios();
-
- std::function<void (bool, bool)> const m_handler;
- game_driver const &m_drv;
+ const game_driver *m_drv;
emu_options m_opts;
- float const m_x0;
- float const m_y0;
+ float x0, y0;
s_bios m_bios;
std::size_t m_curbios;
- bool const m_was_favorite;
- bool m_want_favorite;
+ void setup_bios();
+ bool m_fav_reset;
};
//-------------------------------------------------
@@ -196,4 +186,4 @@ protected:
} // namespace ui
-#endif // MAME_FRONTEND_UI_MISCMENU_H
+#endif /* MAME_FRONTEND_UI_MISCMENU_H */
diff --git a/src/frontend/mame/ui/optsmenu.cpp b/src/frontend/mame/ui/optsmenu.cpp
index 4452fae9bce..fd29c3329bc 100644
--- a/src/frontend/mame/ui/optsmenu.cpp
+++ b/src/frontend/mame/ui/optsmenu.cpp
@@ -30,44 +30,182 @@ namespace ui {
// ctor
//-------------------------------------------------
-menu_simple_game_options::menu_simple_game_options(
- mame_ui_manager &mui,
- render_container &container,
- std::function<void ()> &&handler)
- : menu(mui, container)
- , m_handler(std::move(handler))
+menu_game_options::menu_game_options(mame_ui_manager &mui, render_container &container) : menu(mui, container)
{
+ m_main = main_filters::actual;
}
//-------------------------------------------------
// dtor
//-------------------------------------------------
-menu_simple_game_options::~menu_simple_game_options()
+menu_game_options::~menu_game_options()
{
+ main_filters::actual = m_main;
+ reset_topmost(reset_options::SELECT_FIRST);
ui().save_ui_options();
- if (m_handler)
- m_handler();
+ ui_globals::switch_image = true;
}
//-------------------------------------------------
// handle
//-------------------------------------------------
-void menu_simple_game_options::handle()
+void menu_game_options::handle()
{
+ bool changed = false;
+
// process the menu
- event const *const menu_event(process(PROCESS_LR_REPEAT));
- if (menu_event && menu_event->itemref)
- handle_item_event(*menu_event);
+ const event *menu_event;
+ if (machine().options().ui() == emu_options::UI_SIMPLE)
+ {
+ menu_event = process(PROCESS_LR_REPEAT);
+ }
+ else
+ {
+ process_parent();
+ menu_event = process(PROCESS_LR_REPEAT | PROCESS_NOIMAGE);
+ }
+
+ if (menu_event != nullptr && menu_event->itemref != nullptr)
+ switch ((uintptr_t)menu_event->itemref)
+ {
+ case FILTER_MENU:
+ 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 = machine_filter::type(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())
+ {
+ 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(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)
+ reset(reset_options::REMEMBER_REF);
}
//-------------------------------------------------
// populate
//-------------------------------------------------
-void menu_simple_game_options::populate(float &customtop, float &custombottom)
+void menu_game_options::populate(float &customtop, float &custombottom)
{
+ if (machine().options().ui() != emu_options::UI_SIMPLE)
+ {
+ // set filter arrow
+ std::string fbuff;
+
+ // add filter item
+ uint32_t arrow_flags = get_arrow_flags<uint16_t>(machine_filter::FIRST, machine_filter::LAST, m_main);
+ 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);
+
+ // add options items
+ item_append(_("Customize UI"), "", 0, (void *)(uintptr_t)CUSTOM_MENU);
+ item_append(_("Configure Directories"), "", 0, (void *)(uintptr_t)CONF_DIR);
+ }
item_append(_(submenu::video_options[0].description), "", 0, (void *)(uintptr_t)DISPLAY_MENU);
item_append(_("Sound Options"), "", 0, (void *)(uintptr_t)SOUND_MENU);
item_append(_(submenu::misc_options[0].description), "", 0, (void *)(uintptr_t)MISC_MENU);
@@ -82,61 +220,10 @@ void menu_simple_game_options::populate(float &customtop, float &custombottom)
}
//-------------------------------------------------
-// handle item
-//-------------------------------------------------
-
-void menu_simple_game_options::handle_item_event(event const &menu_event)
-{
- switch ((uintptr_t)menu_event.itemref)
- {
- 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 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;
- }
-}
-
-//-------------------------------------------------
// perform our special rendering
//-------------------------------------------------
-void menu_simple_game_options::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
+void menu_game_options::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{
char const *const toptext[] = { _("Settings") };
draw_text_box(
@@ -147,150 +234,4 @@ void menu_simple_game_options::custom_render(void *selectedref, float top, float
}
-//-------------------------------------------------
-// ctor
-//-------------------------------------------------
-
-menu_game_options::menu_game_options(
- mame_ui_manager &mui,
- render_container &container,
- machine_filter_data &filter_data,
- std::function<void ()> &&handler)
- : menu_simple_game_options(mui, container, std::move(handler))
- , m_filter_data(filter_data)
- , m_main_filter(filter_data.get_current_filter_type())
-{
-}
-
-//-------------------------------------------------
-// dtor
-//-------------------------------------------------
-
-menu_game_options::~menu_game_options()
-{
- m_filter_data.set_current_filter_type(m_main_filter);
-}
-
-//-------------------------------------------------
-// handle
-//-------------------------------------------------
-
-void menu_game_options::handle()
-{
- // process the menu
- process_parent();
- event const *const menu_event(process(PROCESS_LR_REPEAT | PROCESS_NOIMAGE));
- if (menu_event && menu_event->itemref)
- handle_item_event(*menu_event);
-}
-
-//-------------------------------------------------
-// populate
-//-------------------------------------------------
-
-void menu_game_options::populate(float &customtop, float &custombottom)
-{
- // set filter arrow
- std::string fbuff;
-
- // add filter item
- uint32_t arrow_flags = get_arrow_flags<uint16_t>(machine_filter::FIRST, machine_filter::LAST, m_main_filter);
- machine_filter &active_filter(m_filter_data.get_filter(m_main_filter));
- item_append(_("Filter"), active_filter.display_name(), arrow_flags, (void *)(uintptr_t)FILTER_MENU);
-
- // add subitem if the filter wants it
- if (active_filter.wants_adjuster())
- {
- std::string name("^!");
- convert_command_glyph(name);
- item_append(name, active_filter.adjust_text(), active_filter.arrow_flags(), (void *)(FILTER_ADJUST));
- }
-
- item_append(menu_item_type::SEPARATOR);
-
- // add options items
- item_append(_("Customize UI"), "", 0, (void *)(uintptr_t)CUSTOM_MENU);
- item_append(_("Configure Directories"), "", 0, (void *)(uintptr_t)CONF_DIR);
-
- // add the options that don't relate to the UI
- menu_simple_game_options::populate(customtop, custombottom);
-}
-
-//-------------------------------------------------
-// handle item
-//-------------------------------------------------
-
-void menu_game_options::handle_item_event(event const &menu_event)
-{
- bool changed = false;
-
- switch ((uintptr_t)menu_event.itemref)
- {
- case FILTER_MENU:
- if (menu_event.iptkey == IPT_UI_LEFT || menu_event.iptkey == IPT_UI_RIGHT)
- {
- (menu_event.iptkey == IPT_UI_RIGHT) ? ++m_main_filter : --m_main_filter;
- 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_filter,
- [this] (int selection)
- {
- m_main_filter = machine_filter::type(selection);
- reset(reset_options::REMEMBER_REF);
- });
- }
- break;
- case FILTER_ADJUST:
- if (menu_event.iptkey == IPT_UI_LEFT)
- {
- changed = m_filter_data.get_filter(m_main_filter).adjust_left();
- }
- else if (menu_event.iptkey == IPT_UI_RIGHT)
- {
- changed = m_filter_data.get_filter(m_main_filter).adjust_right();
- }
- else if (menu_event.iptkey == IPT_UI_SELECT)
- {
- m_filter_data.get_filter(m_main_filter).show_ui(
- ui(),
- container(),
- [this] (machine_filter &filter)
- {
- if (machine_filter::CUSTOM == filter.get_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();
- }
- }
- 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 CUSTOM_MENU:
- if (menu_event.iptkey == IPT_UI_SELECT)
- menu::stack_push<menu_custom_ui>(ui(), container());
- break;
- default:
- menu_simple_game_options::handle_item_event(menu_event);
- return;
- }
-
- if (changed)
- reset(reset_options::REMEMBER_REF);
-}
-
} // namespace ui
diff --git a/src/frontend/mame/ui/optsmenu.h b/src/frontend/mame/ui/optsmenu.h
index 2afe9b68a89..e9650e3a95b 100644
--- a/src/frontend/mame/ui/optsmenu.h
+++ b/src/frontend/mame/ui/optsmenu.h
@@ -17,27 +17,23 @@
namespace ui {
-
-class menu_simple_game_options : public menu
+class menu_game_options : public menu
{
public:
- menu_simple_game_options(
- mame_ui_manager &mui,
- render_container &container,
- std::function<void ()> &&handler);
- virtual ~menu_simple_game_options() override;
+ menu_game_options(mame_ui_manager &mui, render_container &container);
+ virtual ~menu_game_options() override;
protected:
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
- virtual void handle() override;
- virtual void populate(float &customtop, float &custombottom) override;
-
- void handle_item_event(event const &menu_event);
private:
enum
{
- DISPLAY_MENU = 1001,
+ FILTER_MENU = 1,
+ FILTER_ADJUST,
+ CONF_DIR,
+ DISPLAY_MENU,
+ CUSTOM_MENU,
SOUND_MENU,
CONTROLLER_MENU,
MISC_MENU,
@@ -47,39 +43,12 @@ private:
SAVE_CONFIG
};
- std::function<void ()> const m_handler;
-};
-
-
-class menu_game_options : public menu_simple_game_options
-{
-public:
- menu_game_options(
- mame_ui_manager &mui,
- render_container &container,
- machine_filter_data &filter_data,
- std::function<void ()> &&handler);
- virtual ~menu_game_options() override;
-
-protected:
- virtual void handle() override;
virtual void populate(float &customtop, float &custombottom) override;
+ virtual void handle() override;
- void handle_item_event(event const &menu_event);
-
-private:
- enum
- {
- FILTER_MENU = 2001,
- FILTER_ADJUST,
- CONF_DIR,
- CUSTOM_MENU
- };
-
- machine_filter_data &m_filter_data;
- machine_filter::type m_main_filter;
+ machine_filter::type m_main;
};
} // namespace ui
-#endif // MAME_FRONTEND_UI_OPTSMENU_H
+#endif /* MAME_FRONTEND_UI_OPTSMENU_H */
diff --git a/src/frontend/mame/ui/selector.cpp b/src/frontend/mame/ui/selector.cpp
index 83738641142..59aa51f9d13 100644
--- a/src/frontend/mame/ui/selector.cpp
+++ b/src/frontend/mame/ui/selector.cpp
@@ -60,6 +60,7 @@ void menu_selector::handle()
m_handler(selection);
+ ui_globals::switch_image = true;
stack_pop();
}
else if (menu_event->iptkey == IPT_SPECIAL)
@@ -135,17 +136,12 @@ void menu_selector::custom_render(void *selectedref, float top, float bottom, fl
void menu_selector::find_matches(const char *str)
{
// allocate memory to track the penalty value
- m_ucs_items.reserve(m_str_items.size());
- std::vector<double> penalty(VISIBLE_GAMES_IN_SEARCH, 1.0);
- std::u32string const search(ustr_from_utf8(normalize_unicode(str, unicode_normalization_form::D, true)));
-
+ std::vector<int> penalty(VISIBLE_GAMES_IN_SEARCH, 9999);
int index = 0;
- for ( ; index < m_str_items.size(); ++index)
+
+ for (; index < m_str_items.size(); ++index)
{
- assert(m_ucs_items.size() >= index);
- if (m_ucs_items.size() == index)
- m_ucs_items.emplace_back(ustr_from_utf8(normalize_unicode(m_str_items[index], unicode_normalization_form::D, true)));
- double const curpenalty(util::edit_distance(search, m_ucs_items[index]));
+ int curpenalty = fuzzy_substring(str, m_str_items[index]);
// insert into the sorted table of matches
for (int matchnum = VISIBLE_GAMES_IN_SEARCH - 1; matchnum >= 0; --matchnum)
diff --git a/src/frontend/mame/ui/selector.h b/src/frontend/mame/ui/selector.h
index f3921536267..bd6a87c4ef9 100644
--- a/src/frontend/mame/ui/selector.h
+++ b/src/frontend/mame/ui/selector.h
@@ -7,15 +7,14 @@
Internal UI user interface.
***************************************************************************/
-#ifndef MAME_FRONTEND_UI_SELECTOR_H
-#define MAME_FRONTEND_UI_SELECTOR_H
#pragma once
+#ifndef MAME_FRONTEND_UI_SELECTOR_H
+#define MAME_FRONTEND_UI_SELECTOR_H
#include "ui/menu.h"
-
namespace ui {
//-------------------------------------------------
@@ -45,12 +44,11 @@ private:
void find_matches(const char *str);
- std::string m_search;
- std::vector<std::string> m_str_items;
- std::function<void (int)> m_handler;
- std::vector<std::u32string> m_ucs_items;
- int m_initial;
- std::string *m_searchlist[VISIBLE_GAMES_IN_SEARCH + 1];
+ std::string m_search;
+ std::vector<std::string> m_str_items;
+ std::function<void (int)> m_handler;
+ int m_initial;
+ std::string *m_searchlist[VISIBLE_GAMES_IN_SEARCH + 1];
};
} // namespace ui
diff --git a/src/frontend/mame/ui/selgame.cpp b/src/frontend/mame/ui/selgame.cpp
index def4ceaa5f9..0b47fa1d7d1 100644
--- a/src/frontend/mame/ui/selgame.cpp
+++ b/src/frontend/mame/ui/selgame.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Maurizio Petrarota, Vas Crabb
+// copyright-holders:Maurizio Petrarota
/*********************************************************************
ui/selgame.cpp
@@ -12,7 +12,6 @@
#include "ui/selgame.h"
#include "ui/auditmenu.h"
-#include "ui/icorender.h"
#include "ui/inifile.h"
#include "ui/miscmenu.h"
#include "ui/optsmenu.h"
@@ -32,190 +31,17 @@
#include "uiinput.h"
#include "luaengine.h"
-#include <atomic>
-#include <condition_variable>
#include <cstring>
#include <iterator>
-#include <memory>
-#include <mutex>
-#include <thread>
extern const char UI_VERSION_TAG[];
namespace ui {
-namespace {
-
-constexpr uint32_t FLAGS_UI = ui::menu::FLAG_LEFT_ARROW | ui::menu::FLAG_RIGHT_ARROW;
-
-} // anonymous namespace
-
-class menu_select_game::persistent_data
-{
-public:
- enum available : unsigned
- {
- AVAIL_NONE = 0U,
- AVAIL_SORTED_LIST = 1U << 0,
- AVAIL_BIOS_COUNT = 1U << 1,
- AVAIL_UCS_SHORTNAME = 1U << 2,
- AVAIL_UCS_DESCRIPTION = 1U << 3,
- AVAIL_UCS_MANUF_DESC = 1U << 4,
- AVAIL_FILTER_DATA = 1U << 5
- };
-
- ~persistent_data()
- {
- if (m_thread)
- m_thread->join();
- }
-
- void cache_data()
- {
- std::unique_lock<std::mutex> lock(m_mutex);
- do_start_caching();
- }
-
- bool is_available(available desired)
- {
- return (m_available.load(std::memory_order_acquire) & desired) == desired;
- }
-
- void wait_available(available desired)
- {
- if (!is_available(desired))
- {
- std::unique_lock<std::mutex> lock(m_mutex);
- do_start_caching();
- m_condition.wait(lock, [this, desired] () { return is_available(desired); });
- }
- }
-
- std::vector<ui_system_info> &sorted_list()
- {
- wait_available(AVAIL_SORTED_LIST);
- return m_sorted_list;
- }
-
- int bios_count()
- {
- wait_available(AVAIL_BIOS_COUNT);
- return m_bios_count;
- }
-
- bool unavailable_systems()
- {
- wait_available(AVAIL_SORTED_LIST);
- return std::find_if(m_sorted_list.begin(), m_sorted_list.end(), [] (ui_system_info const &info) { return !info.available; }) != m_sorted_list.end();
- }
-
- machine_filter_data &filter_data()
- {
- wait_available(AVAIL_FILTER_DATA);
- return m_filter_data;
- }
-
- static persistent_data &instance()
- {
- static persistent_data data;
- return data;
- }
-
-private:
- persistent_data()
- : m_started(false)
- , m_available(AVAIL_NONE)
- , m_bios_count(0)
- {
- }
-
- void notify_available(available value)
- {
- std::unique_lock<std::mutex> lock(m_mutex);
- m_available.fetch_or(value, std::memory_order_release);
- m_condition.notify_all();
- }
-
- void do_start_caching()
- {
- if (!m_started)
- {
- m_started = true;
- m_thread = std::make_unique<std::thread>([this] { do_cache_data(); });
- }
- }
-
- void do_cache_data()
- {
- // generate full list
- m_sorted_list.reserve(driver_list::total());
- std::unordered_set<std::string> manufacturers, years;
- for (int x = 0; x < driver_list::total(); ++x)
- {
- game_driver const &driver(driver_list::driver(x));
- if (&driver != &GAME_NAME(___empty))
- {
- if (driver.flags & machine_flags::IS_BIOS_ROOT)
- ++m_bios_count;
-
- m_sorted_list.emplace_back(driver, x, false);
- m_filter_data.add_manufacturer(driver.manufacturer);
- m_filter_data.add_year(driver.year);
- }
- }
-
- // notify that BIOS count is valie
- notify_available(AVAIL_BIOS_COUNT);
-
- // sort drivers and notify
- std::stable_sort(
- m_sorted_list.begin(),
- m_sorted_list.end(),
- [] (ui_system_info const &lhs, ui_system_info const &rhs) { return sorted_game_list(lhs.driver, rhs.driver); });
- notify_available(AVAIL_SORTED_LIST);
-
- // sort manufacturers and years
- m_filter_data.finalise();
- notify_available(AVAIL_FILTER_DATA);
-
- // convert shortnames to UCS-4
- for (ui_system_info &info : m_sorted_list)
- info.ucs_shortname = ustr_from_utf8(normalize_unicode(info.driver->name, unicode_normalization_form::D, true));
- notify_available(AVAIL_UCS_SHORTNAME);
-
- // convert descriptions to UCS-4
- for (ui_system_info &info : m_sorted_list)
- info.ucs_description = ustr_from_utf8(normalize_unicode(info.driver->type.fullname(), unicode_normalization_form::D, true));
- notify_available(AVAIL_UCS_DESCRIPTION);
-
- // convert "<manufacturer> <description>" to UCS-4
- std::string buf;
- for (ui_system_info &info : m_sorted_list)
- {
- buf.assign(info.driver->manufacturer);
- buf.append(1, ' ');
- buf.append(info.driver->type.fullname());
- info.ucs_manufacturer_description = ustr_from_utf8(normalize_unicode(buf, unicode_normalization_form::D, true));
- }
- notify_available(AVAIL_UCS_MANUF_DESC);
- }
-
- // synchronisation
- std::mutex m_mutex;
- std::condition_variable m_condition;
- std::unique_ptr<std::thread> m_thread;
- std::atomic<bool> m_started;
- std::atomic<unsigned> m_available;
-
- // data
- std::vector<ui_system_info> m_sorted_list;
- machine_filter_data m_filter_data;
- int m_bios_count;
-};
-
-bool menu_select_game::s_first_start = true;
-
+bool menu_select_game::first_start = true;
+std::vector<const game_driver *> menu_select_game::m_sortedlist;
+int menu_select_game::m_isabios = 0;
//-------------------------------------------------
// ctor
@@ -223,30 +49,33 @@ bool menu_select_game::s_first_start = true;
menu_select_game::menu_select_game(mame_ui_manager &mui, render_container &container, const char *gamename)
: menu_select_launch(mui, container, false)
- , m_persistent_data(persistent_data::instance())
- , m_icons(MAX_ICONS_RENDER)
- , m_icon_paths()
- , m_displaylist()
- , m_searchlist()
- , m_searched_fields(persistent_data::AVAIL_NONE)
- , m_populated_favorites(false)
{
std::string error_string, last_filter, sub_filter;
ui_options &moptions = mui.options();
// load drivers cache
- m_persistent_data.cache_data();
+ init_sorted_list();
- // check if there are available system icons
- check_for_icons(nullptr);
+ // check if there are available icons
+ ui_globals::has_icons = false;
+ file_enumerator path(moptions.icons_directory());
+ const osd::directory::entry *dir;
+ while ((dir = path.next()) != nullptr)
+ {
+ std::string src(dir->name);
+ if (src.find(".ico") != std::string::npos || src.find("icons") != std::string::npos)
+ {
+ ui_globals::has_icons = true;
+ break;
+ }
+ }
// build drivers list
if (!load_available_machines())
build_available_list();
- if (s_first_start)
+ if (first_start)
{
- //s_first_start = false; TODO: why wansn't it ever clearing the first start flag?
reselect_last::set_driver(moptions.last_used_machine());
ui_globals::rpanel = std::min<int>(std::max<int>(moptions.last_right_panel(), RP_FIRST), RP_LAST);
@@ -267,23 +96,32 @@ menu_select_game::menu_select_game(mame_ui_manager &mui, render_container &conta
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)
{
- m_persistent_data.filter_data().load_ini(file);
+ machine_filter::ptr flt(machine_filter::create(file));
+ if (flt)
+ {
+ main_filters::actual = flt->get_type();
+ main_filters::filters.emplace(main_filters::actual, std::move(flt));
+ }
file.close();
}
}
// do this after processing the last used filter setting so it overwrites the placeholder
load_custom_filters();
- m_filter_highlight = m_persistent_data.filter_data().get_current_filter_type();
+ m_filter_highlight = main_filters::actual;
if (!moptions.remember_last())
reselect_last::reset();
mui.machine().options().set_value(OPTION_SNAPNAME, "%g/%i", OPTION_PRIORITY_CMDLINE);
+ ui_globals::curimage_view = FIRST_VIEW;
ui_globals::curdats_view = 0;
+ ui_globals::switch_image = false;
+ ui_globals::default_image = true;
ui_globals::panels_status = moptions.hide_panels();
ui_globals::curdats_total = 1;
+ m_searchlist[0] = nullptr;
}
//-------------------------------------------------
@@ -302,7 +140,17 @@ menu_select_game::~menu_select_game()
if (driver)
last_driver = driver->name;
- std::string const filter(m_persistent_data.filter_data().get_config_string());
+ 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_RIGHT_PANEL, ui_globals::rpanel, OPTION_PRIORITY_CMDLINE);
@@ -330,13 +178,13 @@ void menu_select_game::handle()
return;
}
- // if I have to select software, force software list submenu
+ // if i have to reselect a software, force software list submenu
if (reselect_last::get())
{
const game_driver *driver;
const ui_software_info *software;
get_selection(software, driver);
- menu::stack_push<menu_select_software>(ui(), container(), *driver);
+ menu::stack_push<menu_select_software>(ui(), container(), driver);
return;
}
@@ -393,7 +241,7 @@ void menu_select_game::handle()
case IPT_UI_SELECT:
if (get_focus() == focused_menu::MAIN)
{
- if (m_populated_favorites)
+ if (isfavorite())
inkey_select_favorite(menu_event);
else
inkey_select(menu_event);
@@ -402,12 +250,11 @@ void menu_select_game::handle()
case IPT_CUSTOM:
// handle IPT_CUSTOM (mouse right click)
- if (!m_populated_favorites)
+ if (!isfavorite())
{
menu::stack_push<menu_machine_configure>(
ui(), container(),
- *reinterpret_cast<const game_driver *>(m_prev_selected),
- nullptr,
+ reinterpret_cast<const game_driver *>(m_prev_selected),
menu_event->mouse.x0, menu_event->mouse.y0);
}
else
@@ -415,21 +262,18 @@ void menu_select_game::handle()
ui_software_info *sw = reinterpret_cast<ui_software_info *>(m_prev_selected);
menu::stack_push<menu_machine_configure>(
ui(), container(),
- *sw->driver,
- [this, empty = sw->startempty] (bool fav, bool changed)
- {
- if (changed)
- reset(empty ? reset_options::SELECT_FIRST : reset_options::REMEMBER_REF);
- },
+ (const game_driver *)sw->driver,
menu_event->mouse.x0, menu_event->mouse.y0);
}
break;
case IPT_UI_LEFT:
- if (ui_globals::rpanel == RP_IMAGES)
+ if (ui_globals::rpanel == RP_IMAGES && ui_globals::curimage_view > FIRST_VIEW)
{
// Images
- previous_image_view();
+ ui_globals::curimage_view--;
+ ui_globals::switch_image = true;
+ ui_globals::default_image = false;
}
else if (ui_globals::rpanel == RP_INFOS)
{
@@ -439,10 +283,12 @@ void menu_select_game::handle()
break;
case IPT_UI_RIGHT:
- if (ui_globals::rpanel == RP_IMAGES)
+ if (ui_globals::rpanel == RP_IMAGES && ui_globals::curimage_view < LAST_VIEW)
{
// Images
- next_image_view();
+ ui_globals::curimage_view++;
+ ui_globals::switch_image = true;
+ ui_globals::default_image = false;
}
else if (ui_globals::rpanel == RP_INFOS)
{
@@ -455,17 +301,17 @@ void menu_select_game::handle()
if (uintptr_t(menu_event->itemref) > skip_main_items)
{
favorite_manager &mfav(mame_machine_manager::instance()->favorite());
- if (!m_populated_favorites)
+ if (!isfavorite())
{
game_driver const *const driver(reinterpret_cast<game_driver const *>(menu_event->itemref));
- if (!mfav.is_favorite_system(*driver))
+ if (!mfav.isgame_favorite(driver))
{
- mfav.add_favorite_system(*driver);
+ mfav.add_favorite_game(driver);
machine().popmessage(_("%s\n added to favorites list."), driver->type.fullname());
}
else
{
- mfav.remove_favorite_system(*driver);
+ mfav.remove_favorite_game();
machine().popmessage(_("%s\n removed from favorites list."), driver->type.fullname());
}
}
@@ -473,19 +319,19 @@ void menu_select_game::handle()
{
ui_software_info const *const swinfo(reinterpret_cast<ui_software_info const *>(menu_event->itemref));
machine().popmessage(_("%s\n removed from favorites list."), swinfo->longname);
- mfav.remove_favorite_software(*swinfo);
+ mfav.remove_favorite_game(*swinfo);
reset(reset_options::SELECT_FIRST);
}
}
break;
case IPT_UI_AUDIT_FAST:
- if (m_persistent_data.unavailable_systems())
- menu::stack_push<menu_audit>(ui(), container(), m_persistent_data.sorted_list(), menu_audit::mode::FAST);
+ 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_persistent_data.sorted_list(), menu_audit::mode::ALL);
+ menu::stack_push<menu_audit>(ui(), container(), m_availsortedlist, menu_audit::mode::ALL);
break;
}
}
@@ -502,113 +348,98 @@ void menu_select_game::handle()
void menu_select_game::populate(float &customtop, float &custombottom)
{
- for (auto &icon : m_icons) // TODO: why is this here? maybe better on resize or setting change?
- icon.second.texture.reset();
-
- set_switch_image();
+ ui_globals::redraw_icon = true;
+ ui_globals::switch_image = true;
int old_item_selected = -1;
+ uint32_t flags_ui = FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW;
if (!isfavorite())
{
- m_populated_favorites = false;
- m_displaylist.clear();
- machine_filter const *const flt(m_persistent_data.filter_data().get_current_filter());
-
// if search is not empty, find approximate matches
if (!m_search.empty())
{
populate_search();
- if (flt)
- {
- for (auto it = m_searchlist.begin(); (m_searchlist.end() != it) && (MAX_VISIBLE_SEARCH > m_displaylist.size()); ++it)
- {
- if (flt->apply(it->second))
- m_displaylist.emplace_back(it->second);
- }
- }
- else
- {
- std::transform(
- m_searchlist.begin(),
- std::next(m_searchlist.begin(), (std::min)(m_searchlist.size(), MAX_VISIBLE_SEARCH)),
- std::back_inserter(m_displaylist),
- [] (auto const &entry) { return entry.second; });
- }
}
else
{
+ // reset search string
+ m_search.clear();
+ m_displaylist.clear();
+
// if filter is set on category, build category list
- std::vector<ui_system_info> const &sorted(m_persistent_data.sorted_list());
- if (!flt)
- std::copy(sorted.begin(), sorted.end(), std::back_inserter(m_displaylist));
+ auto const it(main_filters::filters.find(main_filters::actual));
+ if (main_filters::filters.end() == it)
+ m_displaylist = m_availsortedlist;
else
- flt->apply(sorted.begin(), sorted.end(), std::back_inserter(m_displaylist));
- }
+ it->second->apply(m_availsortedlist.begin(), m_availsortedlist.end(), std::back_inserter(m_displaylist));
- // iterate over entries
- int curitem = 0;
- for (ui_system_info const &elem : m_displaylist)
- {
- if (old_item_selected == -1 && elem.driver->name == reselect_last::driver())
- old_item_selected = curitem;
-
- bool cloneof = strcmp(elem.driver->parent, "0");
- if (cloneof)
+ // iterate over entries
+ int curitem = 0;
+ for (ui_system_info const &elem : m_displaylist)
{
- int cx = driver_list::find(elem.driver->parent);
- if (cx != -1 && ((driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT) != 0))
- cloneof = false;
- }
+ if (old_item_selected == -1 && elem.driver->name == reselect_last::driver())
+ old_item_selected = curitem;
- item_append(elem.driver->type.fullname(), "", (cloneof) ? (FLAGS_UI | FLAG_INVERT) : FLAGS_UI, (void *)elem.driver);
- curitem++;
+ bool cloneof = strcmp(elem.driver->parent, "0");
+ if (cloneof)
+ {
+ 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.driver->type.fullname(), "", (cloneof) ? (flags_ui | FLAG_INVERT) : flags_ui, (void *)elem.driver);
+ curitem++;
+ }
}
}
else
{
// populate favorites list
- m_populated_favorites = true;
m_search.clear();
- mame_machine_manager::instance()->favorite().apply_sorted(
- [this, &old_item_selected, curitem = 0] (ui_software_info const &info) mutable
- {
- if (info.startempty == 1)
- {
- if (old_item_selected == -1 && info.shortname == reselect_last::driver())
- old_item_selected = curitem;
+ int curitem = 0;
- bool cloneof = strcmp(info.driver->parent, "0");
- if (cloneof)
- {
- int cx = driver_list::find(info.driver->parent);
- if (cx != -1 && ((driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT) != 0))
- cloneof = false;
- }
+ // iterate over entries
+ for (auto & favmap : mame_machine_manager::instance()->favorite().m_list)
+ {
+ auto flags = flags_ui | FLAG_UI_FAVORITE;
+ if (favmap.second.startempty == 1)
+ {
+ if (old_item_selected == -1 && favmap.second.shortname == reselect_last::driver())
+ old_item_selected = curitem;
- item_append(info.longname, "", cloneof ? (FLAGS_UI | FLAG_INVERT) : FLAGS_UI, (void *)&info);
- }
- else
- {
- if (old_item_selected == -1 && info.shortname == reselect_last::driver())
- old_item_selected = curitem;
- item_append(info.longname, info.devicetype,
- info.parentname.empty() ? FLAGS_UI : (FLAG_INVERT | FLAGS_UI), (void *)&info);
- }
- curitem++;
- });
+ bool cloneof = strcmp(favmap.second.driver->parent, "0");
+ if (cloneof)
+ {
+ int cx = driver_list::find(favmap.second.driver->parent);
+ if (cx != -1 && ((driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT) != 0))
+ cloneof = false;
+ }
+
+ item_append(favmap.second.longname, "", (cloneof) ? (flags | FLAG_INVERT) : flags, (void *)&favmap.second);
+ }
+ else
+ {
+ if (old_item_selected == -1 && favmap.second.shortname == reselect_last::driver())
+ old_item_selected = curitem;
+ item_append(favmap.second.longname, favmap.second.devicetype,
+ favmap.second.parentname.empty() ? flags : (FLAG_INVERT | flags), (void *)&favmap.second);
+ }
+ curitem++;
+ }
}
- item_append(menu_item_type::SEPARATOR, FLAGS_UI);
+ item_append(menu_item_type::SEPARATOR, flags_ui);
// add special items
if (stack_has_special_main_menu())
{
- item_append(_("Configure Options"), "", FLAGS_UI, (void *)(uintptr_t)CONF_OPTS);
- item_append(_("Configure Machine"), "", FLAGS_UI, (void *)(uintptr_t)CONF_MACHINE);
+ item_append(_("Configure Options"), "", flags_ui, (void *)(uintptr_t)CONF_OPTS);
+ item_append(_("Configure Machine"), "", flags_ui, (void *)(uintptr_t)CONF_MACHINE);
skip_main_items = 2;
if (machine().options().plugins())
{
- item_append(_("Plugins"), "", FLAGS_UI, (void *)(uintptr_t)CONF_PLUGINS);
+ item_append(_("Plugins"), "", flags_ui, (void *)(uintptr_t)CONF_PLUGINS);
skip_main_items++;
}
}
@@ -656,11 +487,11 @@ void menu_select_game::build_available_list()
// build a name for it
for (src = dir->name; *src != 0 && *src != '.' && dst < &drivername[ARRAY_LENGTH(drivername) - 1]; ++src)
- *dst++ = tolower(uint8_t(*src));
+ *dst++ = tolower((uint8_t) * src);
*dst = 0;
- int const drivnum = driver_list::find(drivername);
- if (0 <= drivnum)
+ int drivnum = driver_list::find(drivername);
+ if (drivnum != -1 && !included[drivnum])
included[drivnum] = true;
}
@@ -731,9 +562,18 @@ void menu_select_game::build_available_list()
}
}
- // copy into the persistent sorted list
- for (ui_system_info &info : m_persistent_data.sorted_list())
- info.available = included[info.index];
+ // sort
+ 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); });
}
@@ -769,17 +609,13 @@ void menu_select_game::inkey_select(const event *menu_event)
if ((uintptr_t)driver == CONF_OPTS)
{
// special case for configure options
- menu::stack_push<menu_game_options>(
- ui(),
- container(),
- m_persistent_data.filter_data(),
- [this] () { reset(reset_options::SELECT_FIRST); });
+ menu::stack_push<menu_game_options>(ui(), container());
}
else if (uintptr_t(driver) == CONF_MACHINE)
{
// special case for configure machine
if (m_prev_selected)
- menu::stack_push<menu_machine_configure>(ui(), container(), *reinterpret_cast<const game_driver *>(m_prev_selected));
+ menu::stack_push<menu_machine_configure>(ui(), container(), reinterpret_cast<const game_driver *>(m_prev_selected));
return;
}
else if ((uintptr_t)driver == CONF_PLUGINS)
@@ -804,7 +640,7 @@ void menu_select_game::inkey_select(const event *menu_event)
{
if (!swlistdev.get_info().empty())
{
- menu::stack_push<menu_select_software>(ui(), container(), *driver);
+ menu::stack_push<menu_select_software>(ui(), container(), driver);
return;
}
}
@@ -831,11 +667,7 @@ void menu_select_game::inkey_select_favorite(const event *menu_event)
if ((uintptr_t)ui_swinfo == CONF_OPTS)
{
// special case for configure options
- menu::stack_push<menu_game_options>(
- ui(),
- container(),
- m_persistent_data.filter_data(),
- [this] () { reset(reset_options::SELECT_FIRST); });
+ menu::stack_push<menu_game_options>(ui(), container());
}
else if ((uintptr_t)ui_swinfo == CONF_MACHINE)
{
@@ -843,15 +675,7 @@ void menu_select_game::inkey_select_favorite(const event *menu_event)
if (m_prev_selected)
{
ui_software_info *swinfo = reinterpret_cast<ui_software_info *>(m_prev_selected);
- menu::stack_push<menu_machine_configure>(
- ui(),
- container(),
- *swinfo->driver,
- [this, empty = swinfo->startempty] (bool fav, bool changed)
- {
- if (changed)
- reset(empty ? reset_options::SELECT_FIRST : reset_options::REMEMBER_REF);
- });
+ menu::stack_push<menu_machine_configure>(ui(), container(), (const game_driver *)swinfo->driver);
}
return;
}
@@ -874,7 +698,7 @@ void menu_select_game::inkey_select_favorite(const event *menu_event)
{
if (!swlistdev.get_info().empty())
{
- menu::stack_push<menu_select_software>(ui(), container(), *ui_swinfo->driver);
+ menu::stack_push<menu_select_software>(ui(), container(), ui_swinfo->driver);
return;
}
}
@@ -922,7 +746,7 @@ void menu_select_game::inkey_select_favorite(const event *menu_event)
bool menu_select_game::isfavorite() const
{
- return machine_filter::FAVORITE == m_persistent_data.filter_data().get_current_filter_type();
+ return machine_filter::FAVORITE == main_filters::actual;
}
@@ -947,7 +771,7 @@ void menu_select_game::change_info_pane(int delta)
game_driver const *drv;
ui_software_info const *soft;
get_selection(soft, drv);
- if (!m_populated_favorites)
+ if (!isfavorite())
{
if (uintptr_t(drv) > skip_main_items)
cap_delta(ui_globals::curdats_view, ui_globals::curdats_total);
@@ -967,59 +791,49 @@ void menu_select_game::change_info_pane(int delta)
void menu_select_game::populate_search()
{
- // ensure search list is populated
- if (m_searchlist.empty())
+ // allocate memory to track the penalty value
+ std::vector<int> penalty(VISIBLE_GAMES_IN_SEARCH, 9999);
+ int index = 0;
+ for (; index < m_displaylist.size(); ++index)
{
- std::vector<ui_system_info> const &sorted(m_persistent_data.sorted_list());
- m_searchlist.reserve(sorted.size());
- for (ui_system_info const &info : sorted)
- m_searchlist.emplace_back(1.0, std::ref(info));
- }
-
- // keep track of what we matched against
- const std::u32string ucs_search(ustr_from_utf8(normalize_unicode(m_search, unicode_normalization_form::D, true)));
-
- // match shortnames
- if (m_persistent_data.is_available(persistent_data::AVAIL_UCS_SHORTNAME))
- {
- m_searched_fields |= persistent_data::AVAIL_UCS_SHORTNAME;
- for (std::pair<double, std::reference_wrapper<ui_system_info const> > &info : m_searchlist)
- info.first = util::edit_distance(ucs_search, info.second.get().ucs_shortname);
- }
+ // pick the best match between driver name and description
+ 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);
- // match descriptions
- if (m_persistent_data.is_available(persistent_data::AVAIL_UCS_DESCRIPTION))
- {
- m_searched_fields |= persistent_data::AVAIL_UCS_DESCRIPTION;
- for (std::pair<double, std::reference_wrapper<ui_system_info const> > &info : m_searchlist)
+ // insert into the sorted table of matches
+ for (int matchnum = VISIBLE_GAMES_IN_SEARCH - 1; matchnum >= 0; --matchnum)
{
- if (info.first)
+ // stop if we're worse than the current entry
+ if (curpenalty >= penalty[matchnum])
+ break;
+
+ // as long as this isn't the last entry, bump this one down
+ if (matchnum < VISIBLE_GAMES_IN_SEARCH - 1)
{
- double const penalty(util::edit_distance(ucs_search, info.second.get().ucs_description));
- info.first = (std::min)(penalty, info.first);
+ penalty[matchnum + 1] = penalty[matchnum];
+ m_searchlist[matchnum + 1] = m_searchlist[matchnum];
}
+
+ m_searchlist[matchnum] = m_displaylist[index].driver;
+ penalty[matchnum] = curpenalty;
}
}
- // match "<manufacturer> <description>"
- if (m_persistent_data.is_available(persistent_data::AVAIL_UCS_MANUF_DESC))
+ (index < VISIBLE_GAMES_IN_SEARCH) ? m_searchlist[index] = nullptr : m_searchlist[VISIBLE_GAMES_IN_SEARCH] = nullptr;
+ uint32_t flags_ui = FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW;
+ for (int curitem = 0; m_searchlist[curitem]; ++curitem)
{
- m_searched_fields |= persistent_data::AVAIL_UCS_MANUF_DESC;
- for (std::pair<double, std::reference_wrapper<ui_system_info const> > &info : m_searchlist)
+ bool cloneof = strcmp(m_searchlist[curitem]->parent, "0");
+ if (cloneof)
{
- if (info.first)
- {
- double const penalty(util::edit_distance(ucs_search, info.second.get().ucs_manufacturer_description));
- info.first = (std::min)(penalty, info.first);
- }
+ int cx = driver_list::find(m_searchlist[curitem]->parent);
+ if (cx != -1 && ((driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT) != 0))
+ cloneof = false;
}
+ item_append(m_searchlist[curitem]->type.fullname(), "", (!cloneof) ? flags_ui : (FLAG_INVERT | flags_ui),
+ (void *)m_searchlist[curitem]);
}
-
- // sort according to edit distance
- std::stable_sort(
- m_searchlist.begin(),
- m_searchlist.end(),
- [] (auto const &lhs, auto const &rhs) { return lhs.first < rhs.first; });
}
//-------------------------------------------------
@@ -1075,21 +889,6 @@ void menu_select_game::general_info(const game_driver *driver, std::string &buff
else
str << _("Sound\tOK\n");
- if (flags.unemulated_features() & device_t::feature::CAPTURE)
- str << _("Capture\tUnimplemented\n");
- else if (flags.imperfect_features() & device_t::feature::CAPTURE)
- str << _("Capture\tImperfect\n");
-
- if (flags.unemulated_features() & device_t::feature::CAMERA)
- str << _("Camera\tUnimplemented\n");
- else if (flags.imperfect_features() & device_t::feature::CAMERA)
- str << _("Camera\tImperfect\n");
-
- if (flags.unemulated_features() & device_t::feature::MICROPHONE)
- str << _("Microphone\tUnimplemented\n");
- else if (flags.imperfect_features() & device_t::feature::MICROPHONE)
- str << _("Microphone\tImperfect\n");
-
if (flags.unemulated_features() & device_t::feature::CONTROLS)
str << _("Controls\tUnimplemented\n");
else if (flags.imperfect_features() & device_t::feature::CONTROLS)
@@ -1105,10 +904,15 @@ void menu_select_game::general_info(const game_driver *driver, std::string &buff
else if (flags.imperfect_features() & device_t::feature::MOUSE)
str << _("Mouse\tImperfect\n");
- if (flags.unemulated_features() & device_t::feature::MEDIA)
- str << _("Media\tUnimplemented\n");
- else if (flags.imperfect_features() & device_t::feature::MEDIA)
- str << _("Media\tImperfect\n");
+ if (flags.unemulated_features() & device_t::feature::MICROPHONE)
+ str << _("Microphone\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::MICROPHONE)
+ str << _("Microphone\tImperfect\n");
+
+ if (flags.unemulated_features() & device_t::feature::CAMERA)
+ str << _("Camera\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::CAMERA)
+ str << _("Camera\tImperfect\n");
if (flags.unemulated_features() & device_t::feature::DISK)
str << _("Disk\tUnimplemented\n");
@@ -1120,31 +924,6 @@ void menu_select_game::general_info(const game_driver *driver, std::string &buff
else if (flags.imperfect_features() & device_t::feature::PRINTER)
str << _("Printer\tImperfect\n");
- if (flags.unemulated_features() & device_t::feature::TAPE)
- str << _("Mag. Tape\tUnimplemented\n");
- else if (flags.imperfect_features() & device_t::feature::TAPE)
- str << _("Mag. Tape\tImperfect\n");
-
- if (flags.unemulated_features() & device_t::feature::PUNCH)
- str << _("Punch Tape\tUnimplemented\n");
- else if (flags.imperfect_features() & device_t::feature::PUNCH)
- str << _("Punch Tape\tImperfect\n");
-
- if (flags.unemulated_features() & device_t::feature::DRUM)
- str << _("Mag. Drum\tUnimplemented\n");
- else if (flags.imperfect_features() & device_t::feature::DRUM)
- str << _("Mag. Drum\tImperfect\n");
-
- if (flags.unemulated_features() & device_t::feature::ROM)
- str << _("(EP)ROM\tUnimplemented\n");
- else if (flags.imperfect_features() & device_t::feature::ROM)
- str << _("(EP)ROM\tImperfect\n");
-
- if (flags.unemulated_features() & device_t::feature::COMMS)
- str << _("Communications\tUnimplemented\n");
- else if (flags.imperfect_features() & device_t::feature::COMMS)
- str << _("Communications\tImperfect\n");
-
if (flags.unemulated_features() & device_t::feature::LAN)
str << _("LAN\tUnimplemented\n");
else if (flags.imperfect_features() & device_t::feature::LAN)
@@ -1208,86 +987,71 @@ void menu_select_game::general_info(const game_driver *driver, std::string &buff
buffer = str.str();
}
-
-//-------------------------------------------------
-// get (possibly cached) icon texture
-//-------------------------------------------------
-
-render_texture *menu_select_game::get_icon_texture(int linenum, void *selectedref)
+void menu_select_game::inkey_export()
{
- game_driver const *const driver(m_populated_favorites
- ? reinterpret_cast<ui_software_info const *>(selectedref)->driver
- : reinterpret_cast<game_driver const *>(selectedref));
- assert(driver);
-
- icon_cache::iterator icon(m_icons.find(driver));
- if ((m_icons.end() == icon) || !icon->second.texture)
+ std::vector<game_driver const *> list;
+ if (!m_search.empty())
{
- if (m_icon_paths.empty())
- m_icon_paths = make_icon_paths(nullptr);
-
- // allocate an entry or allocate a texture on forced redraw
- if (m_icons.end() == icon)
+ for (int curitem = 0; m_searchlist[curitem]; ++curitem)
+ list.push_back(m_searchlist[curitem]);
+ }
+ else
+ {
+ if (isfavorite())
{
- icon = m_icons.emplace(driver, texture_ptr(machine().render().texture_alloc(), machine().render())).first;
+ // iterate over favorites
+ for (auto & favmap : mame_machine_manager::instance()->favorite().m_list)
+ {
+ if (favmap.second.startempty == 1)
+ list.push_back(favmap.second.driver);
+ else
+ return;
+ }
}
else
{
- assert(!icon->second.texture);
- icon->second.texture.reset(machine().render().texture_alloc());
+ list.reserve(m_displaylist.size());
+ for (ui_system_info const &info : m_displaylist)
+ list.emplace_back(info.driver);
}
-
- // set clone status
- bool cloneof = strcmp(driver->parent, "0");
- if (cloneof)
- {
- auto cx = driver_list::find(driver->parent);
- if ((cx >= 0) && (driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT))
- cloneof = false;
- }
-
- bitmap_argb32 tmp;
- emu_file snapfile(std::string(m_icon_paths), OPEN_FLAG_READ);
- if (snapfile.open(std::string(driver->name), ".ico") == osd_file::error::NONE)
- {
- render_load_ico_highest_detail(snapfile, tmp);
- snapfile.close();
- }
- if (!tmp.valid() && cloneof && (snapfile.open(std::string(driver->parent), ".ico") == osd_file::error::NONE))
- {
- render_load_ico_highest_detail(snapfile, tmp);
- snapfile.close();
- }
-
- scale_icon(std::move(tmp), icon->second);
}
- return icon->second.bitmap.valid() ? icon->second.texture.get() : nullptr;
+ menu::stack_push<menu_export>(ui(), container(), std::move(list));
}
+//-------------------------------------------------
+// save drivers infos to file
+//-------------------------------------------------
-void menu_select_game::inkey_export()
+void menu_select_game::init_sorted_list()
{
- std::vector<game_driver const *> list;
- if (m_populated_favorites)
- {
- // iterate over favorites
- mame_machine_manager::instance()->favorite().apply(
- [&list] (ui_software_info const &info)
- {
- assert(info.driver);
- if (info.startempty)
- list.push_back(info.driver);
- });
- }
- else
+ if (!m_sortedlist.empty())
+ return;
+
+ // generate full list
+ std::unordered_set<std::string> manufacturers, years;
+ for (int x = 0; x < driver_list::total(); ++x)
{
- list.reserve(m_displaylist.size());
- for (ui_system_info const &info : m_displaylist)
- list.emplace_back(info.driver);
+ game_driver const &driver(driver_list::driver(x));
+ if (&driver != &GAME_NAME(___empty))
+ {
+ if (driver.flags & machine_flags::IS_BIOS_ROOT)
+ m_isabios++;
+
+ m_sortedlist.push_back(&driver);
+ manufacturers.emplace(c_mnfct::getname(driver.manufacturer));
+ years.emplace(driver.year);
+ }
}
- menu::stack_push<menu_export>(ui(), container(), std::move(list));
+ // sort manufacturers - years and driver
+ 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);
}
//-------------------------------------------------
@@ -1329,18 +1093,27 @@ bool menu_select_game::load_available_machines()
else
available.emplace(std::move(readbuf));
}
- file.close();
// turn it into the sorted system list we all love
- for (ui_system_info &info : m_persistent_data.sorted_list())
+ m_availsortedlist.reserve(driver_list::total());
+ for (std::size_t x = 0; driver_list::total() > x; ++x)
{
- std::unordered_set<std::string>::iterator const it(available.find(&info.driver->name[0]));
- bool const found(available.end() != it);
- info.available = found;
- if (found)
- available.erase(it);
+ 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;
}
@@ -1353,9 +1126,9 @@ void menu_select_game::load_custom_filters()
emu_file file(ui().options().ui_path(), OPEN_FLAG_READ);
if (file.open("custom_", emulator_info::get_configname(), "_filter.ini") == osd_file::error::NONE)
{
- machine_filter::ptr flt(machine_filter::create(file, m_persistent_data.filter_data()));
+ machine_filter::ptr flt(machine_filter::create(file));
if (flt)
- m_persistent_data.filter_data().set_filter(std::move(flt)); // not emplace/insert - could replace bogus filter from ui.ini line
+ main_filters::filters[flt->get_type()] = std::move(flt); // not emplace/insert - could replace bogus filter from ui.ini line
file.close();
}
@@ -1368,8 +1141,7 @@ void menu_select_game::load_custom_filters()
float menu_select_game::draw_left_panel(float x1, float y1, float x2, float y2)
{
- machine_filter_data &filter_data(m_persistent_data.filter_data());
- return menu_select_launch::draw_left_panel<machine_filter>(filter_data.get_current_filter_type(), filter_data.get_filters(), x1, y1, x2, y2);
+ return menu_select_launch::draw_left_panel<machine_filter>(main_filters::actual, main_filters::filters, x1, y1, x2, y2);
}
@@ -1379,7 +1151,7 @@ float menu_select_game::draw_left_panel(float x1, float y1, float x2, float y2)
void menu_select_game::get_selection(ui_software_info const *&software, game_driver const *&driver) const
{
- if (m_populated_favorites)
+ if (item[0].flags & FLAG_UI_FAVORITE) // TODO: work out why this doesn't use isfavorite()
{
software = reinterpret_cast<ui_software_info const *>(get_selection_ptr());
driver = software ? software->driver : nullptr;
@@ -1398,18 +1170,18 @@ void menu_select_game::make_topbox_text(std::string &line0, std::string &line1,
bare_build_version,
visible_items,
(driver_list::total() - 1),
- m_persistent_data.bios_count());
+ m_isabios);
- if (m_populated_favorites)
+ if (isfavorite())
{
line1.clear();
}
else
{
- machine_filter const *const it(m_persistent_data.filter_data().get_current_filter());
- char const *const filter(it ? it->filter_text() : nullptr);
+ 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->display_name(), filter, m_search);
+ 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);
}
@@ -1436,12 +1208,15 @@ void menu_select_game::filter_selected()
{
if ((machine_filter::FIRST <= m_filter_highlight) && (machine_filter::LAST >= m_filter_highlight))
{
- m_persistent_data.filter_data().get_filter(machine_filter::type(m_filter_highlight)).show_ui(
+ m_search.clear();
+ auto it(main_filters::filters.find(machine_filter::type(m_filter_highlight)));
+ if (main_filters::filters.end() == it)
+ it = main_filters::filters.emplace(machine_filter::type(m_filter_highlight), machine_filter::create(machine_filter::type(m_filter_highlight))).first;
+ it->second->show_ui(
ui(),
container(),
[this] (machine_filter &filter)
{
- set_switch_image();
machine_filter::type const new_type(filter.get_type());
if (machine_filter::CUSTOM == new_type)
{
@@ -1452,7 +1227,7 @@ void menu_select_game::filter_selected()
file.close();
}
}
- m_persistent_data.filter_data().set_current_filter_type(new_type);
+ main_filters::actual = new_type;
reset(reset_options::SELECT_FIRST);
});
}
diff --git a/src/frontend/mame/ui/selgame.h b/src/frontend/mame/ui/selgame.h
index da65fee98ce..5778b2c544c 100644
--- a/src/frontend/mame/ui/selgame.h
+++ b/src/frontend/mame/ui/selgame.h
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Maurizio Petrarota, Vas Crabb
+// copyright-holders:Maurizio Petrarota
/***************************************************************************
ui/selgame.h
@@ -15,8 +15,6 @@
#include "ui/selmenu.h"
#include "ui/utils.h"
-#include <functional>
-
class media_auditor;
@@ -39,27 +37,21 @@ private:
CONF_PLUGINS,
};
- using icon_cache = texture_lru<game_driver const *>;
-
- class persistent_data;
-
- persistent_data &m_persistent_data;
- icon_cache m_icons;
- std::string m_icon_paths;
- std::vector<std::reference_wrapper<ui_system_info const> > m_displaylist;
+ enum { VISIBLE_GAMES_IN_SEARCH = 200 };
+ static bool first_start;
+ static int m_isabios;
- std::vector<std::pair<double, std::reference_wrapper<ui_system_info const> > > m_searchlist;
- unsigned m_searched_fields;
- bool m_populated_favorites;
+ static std::vector<const game_driver *> m_sortedlist;
+ std::vector<ui_system_info> m_availsortedlist;
+ std::vector<ui_system_info> m_displaylist;
- static bool s_first_start;
+ const game_driver *m_searchlist[VISIBLE_GAMES_IN_SEARCH + 1];
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle() override;
- // drawing
+ // draw left panel
virtual float draw_left_panel(float x1, float y1, float x2, float y2) override;
- virtual render_texture *get_icon_texture(int linenum, void *selectedref) override;
// get selected software and/or driver
virtual void get_selection(ui_software_info const *&software, game_driver const *&driver) const override;
@@ -83,6 +75,7 @@ private:
bool isfavorite() const;
void populate_search();
+ void init_sorted_list();
bool load_available_machines();
void load_custom_filters();
diff --git a/src/frontend/mame/ui/selmenu.cpp b/src/frontend/mame/ui/selmenu.cpp
index 306c2cad1f0..90dd7af789f 100644
--- a/src/frontend/mame/ui/selmenu.cpp
+++ b/src/frontend/mame/ui/selmenu.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods, Vas Crabb
+// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods
/***************************************************************************
ui/selmenu.cpp
@@ -12,6 +12,7 @@
#include "ui/selmenu.h"
#include "ui/datmenu.h"
+#include "ui/icorender.h"
#include "ui/info.h"
#include "ui/inifile.h"
@@ -44,28 +45,6 @@ namespace ui {
namespace {
-enum
-{
- FIRST_VIEW = 0,
- SNAPSHOT_VIEW = FIRST_VIEW,
- CABINETS_VIEW,
- CPANELS_VIEW,
- PCBS_VIEW,
- FLYERS_VIEW,
- TITLES_VIEW,
- ENDS_VIEW,
- ARTPREV_VIEW,
- BOSSES_VIEW,
- LOGOS_VIEW,
- VERSUS_VIEW,
- GAMEOVER_VIEW,
- HOWTO_VIEW,
- SCORES_VIEW,
- SELECT_VIEW,
- MARQUEES_VIEW,
- LAST_VIEW = MARQUEES_VIEW
-};
-
std::pair<char const *, char const *> const arts_info[] =
{
{ __("Snapshots"), OPTION_SNAPSHOT_DIRECTORY },
@@ -95,8 +74,6 @@ char const *const hover_msg[] = {
} // anonymous namespace
-constexpr std::size_t menu_select_launch::MAX_VISIBLE_SEARCH; // stupid non-inline semantics
-
class menu_select_launch::software_parts : public menu
{
@@ -182,7 +159,7 @@ void menu_select_launch::reselect_last::set_software(game_driver const &driver,
s_driver = driver.name;
if (swinfo.startempty)
{
- // FIXME: magic strings are bad...
+ // magic strings are bad...
s_software = "[Start empty]";
s_swlist.clear();
}
@@ -375,26 +352,27 @@ void menu_select_launch::bios_selection::custom_render(void *selectedref, float
menu_select_launch::cache::cache(running_machine &machine)
: m_snapx_bitmap(std::make_unique<bitmap_argb32>(0, 0))
- , m_snapx_texture(nullptr, machine.render())
+ , m_snapx_texture()
, m_snapx_driver(nullptr)
, m_snapx_software(nullptr)
, m_no_avail_bitmap(256, 256)
, m_star_bitmap(32, 32)
- , m_star_texture(nullptr, machine.render())
+ , m_star_texture()
, m_toolbar_bitmap()
, m_sw_toolbar_bitmap()
, m_toolbar_texture()
, m_sw_toolbar_texture()
{
render_manager &render(machine.render());
+ auto const texture_free([&render](render_texture *texture) { render.texture_free(texture); });
// create a texture for snapshot
- m_snapx_texture.reset(render.texture_alloc(render_texture::hq_scale));
+ m_snapx_texture = texture_ptr(render.texture_alloc(render_texture::hq_scale), texture_free);
std::memcpy(&m_no_avail_bitmap.pix32(0), no_avail_bmp, 256 * 256 * sizeof(uint32_t));
std::memcpy(&m_star_bitmap.pix32(0), favorite_star_bmp, 32 * 32 * sizeof(uint32_t));
- m_star_texture.reset(render.texture_alloc());
+ m_star_texture = texture_ptr(render.texture_alloc(), texture_free);
m_star_texture->set_bitmap(m_star_bitmap, m_star_bitmap.cliprect(), TEXFORMAT_ARGB32);
m_toolbar_bitmap.reserve(UI_TOOLBAR_BUTTONS);
@@ -406,8 +384,8 @@ menu_select_launch::cache::cache(running_machine &machine)
{
m_toolbar_bitmap.emplace_back(32, 32);
m_sw_toolbar_bitmap.emplace_back(32, 32);
- m_toolbar_texture.emplace_back(render.texture_alloc(), render);
- m_sw_toolbar_texture.emplace_back(render.texture_alloc(), render);
+ m_toolbar_texture.emplace_back(texture_ptr(render.texture_alloc(), texture_free));
+ m_sw_toolbar_texture.emplace_back(texture_ptr(render.texture_alloc(), texture_free));
std::memcpy(&m_toolbar_bitmap.back().pix32(0), toolbar_bitmap_bmp[i], 32 * 32 * sizeof(uint32_t));
if (m_toolbar_bitmap.back().valid())
@@ -459,11 +437,8 @@ menu_select_launch::menu_select_launch(mame_ui_manager &mui, render_container &c
, m_pressed(false)
, m_repeat(0)
, m_right_visible_lines(0)
- , m_has_icons(false)
- , m_switch_image(false)
- , m_default_image(true)
- , m_image_view(FIRST_VIEW)
, m_flags(256)
+ , m_icons(MAX_ICONS_RENDER)
{
// set up persistent cache for machine run
{
@@ -484,28 +459,6 @@ menu_select_launch::menu_select_launch(mame_ui_manager &mui, render_container &c
}
-void menu_select_launch::next_image_view()
-{
- if (LAST_VIEW > m_image_view)
- {
- ++m_image_view;
- set_switch_image();
- m_default_image = false;
- }
-}
-
-
-void menu_select_launch::previous_image_view()
-{
- if (FIRST_VIEW < m_image_view)
- {
- --m_image_view;
- set_switch_image();
- m_default_image = false;
- }
-}
-
-
bool menu_select_launch::dismiss_error()
{
bool const result = m_ui_error;
@@ -609,7 +562,7 @@ void menu_select_launch::custom_render(void *selectedref, float top, float botto
rgb_t color = UI_BACKGROUND_COLOR;
if (swinfo && ((swinfo->startempty != 1) || !driver))
{
- isstar = mame_machine_manager::instance()->favorite().is_favorite_system_software(*swinfo);
+ isstar = mame_machine_manager::instance()->favorite().isgame_favorite(*swinfo);
// first line is long name or system
tempbuf[0] = make_software_description(*swinfo);
@@ -645,7 +598,7 @@ void menu_select_launch::custom_render(void *selectedref, float top, float botto
}
else if (driver)
{
- isstar = mame_machine_manager::instance()->favorite().is_favorite_system(*driver);
+ isstar = mame_machine_manager::instance()->favorite().isgame_favorite(driver);
// first line is game description/game name
tempbuf[0] = make_driver_description(*driver);
@@ -991,150 +944,6 @@ float menu_select_launch::draw_left_panel(
}
-//-------------------------------------------------
-// icon helpers
-//-------------------------------------------------
-
-void menu_select_launch::check_for_icons(char const *listname)
-{
- // only ever set the flag, never clear it
- if (m_has_icons)
- return;
-
- // iterate over configured icon paths
- path_iterator paths(ui().options().icons_directory());
- std::string current;
- while (paths.next(current))
- {
- // if we're doing a software list, append it to the configured path
- if (listname)
- {
- if (!current.empty() && !util::is_directory_separator(current.back()))
- current.append(PATH_SEPARATOR);
- current.append(listname);
- }
- osd_printf_verbose("Checking for icons in directory %s\n", current.c_str());
-
- // open and walk the directory
- osd::directory::ptr const dir(osd::directory::open(current));
- if (dir)
- {
- // this could be improved in many ways - it's just a rough go/no-go
- osd::directory::entry const *entry;
- while ((entry = dir->read()) != nullptr)
- {
- current = entry->name;
- std::string::size_type const found(current.rfind(".ico"));
- if ((std::string::npos != found) && ((current.length() - 4) == found))
- {
- osd_printf_verbose("Entry %s is a candidate icon file\n", entry->name);
- m_has_icons = true;
- return;
- }
- else if (("icons" == current) || (current.find("icons.") == 0U))
- {
- osd_printf_verbose("Entry %s is a candidate icon collection\n", entry->name);
- m_has_icons = true;
- return;
- }
- }
- }
- }
-
- // nothing promising
- osd_printf_verbose(
- "No candidate icons found for %s%s\n",
- listname ? "software list " : "",
- listname ? listname : "machines");
-}
-
-std::string menu_select_launch::make_icon_paths(char const *listname) const
-{
- // iterate over configured icon paths
- path_iterator paths(ui().options().icons_directory());
- std::string current, result;
- while (paths.next(current))
- {
- // if we're doing a software list, append it to the configured path
- if (listname)
- {
- if (!current.empty() && !util::is_directory_separator(current.back()))
- current.append(PATH_SEPARATOR);
- current.append(listname);
- }
-
- // append the configured path
- if (!result.empty())
- result.append(1, ';'); // FIXME: should be a macro
- result.append(current);
-
- // append with "icons" appended so it'll search icons.zip or icons.7z in the directory
- if (!current.empty())
- {
- result.append(1, ';'); // FIXME: should be a macro
- result.append(current);
- if (!util::is_directory_separator(result.back()))
- result.append(PATH_SEPARATOR);
- }
- result.append("icons");
- }
-
- // log the result for debugging
- osd_printf_verbose(
- "Icon path for %s%s set to %s\n",
- listname ? "software list " : "",
- listname ? listname : "machines",
- result.c_str());
- return result;
-}
-
-bool menu_select_launch::scale_icon(bitmap_argb32 &&src, texture_and_bitmap &dst) const
-{
- assert(dst.texture);
- if (src.valid())
- {
- // calculate available space for the icon in pixels
- float const height(ui().get_line_height());
- float const width(height * container().manager().ui_aspect());
- render_target const &target(machine().render().ui_target());
- uint32_t const dst_height(target.height());
- uint32_t const dst_width(target.width());
- bool const rotated((target.orientation() & ORIENTATION_SWAP_XY) != 0);
- int const max_height(int((rotated ? dst_width : dst_height) * height));
- int const max_width(int((rotated ? dst_height : dst_width) * width));
-
- // reduce the source bitmap if it's too big
- bitmap_argb32 tmp;
- float const ratio((std::min)({ float(max_height) / src.height(), float(max_width) / src.width(), 1.0F }));
- if (1.0F > ratio)
- {
- float const pix_height(src.height() * ratio);
- float const pix_width(src.width() * ratio);
- tmp.allocate(int32_t(pix_width), int32_t(pix_height));
- render_resample_argb_bitmap_hq(tmp, src, render_color{ 1.0F, 1.0F, 1.0F, 1.0F }, true);
- }
- else
- {
- tmp = std::move(src);
- }
-
- // copy into the destination
- dst.bitmap.allocate(max_width, max_height);
- for (int y = 0; tmp.height() > y; ++y)
- for (int x = 0; tmp.width() > x; ++x)
- dst.bitmap.pix32(y, x) = tmp.pix32(y, x);
- dst.texture->set_bitmap(dst.bitmap, dst.bitmap.cliprect(), TEXFORMAT_ARGB32);
- return true;
- }
- else
- {
- // couldn't load icon
- dst.bitmap.reset();
- return false;
- }
-}
-
-
template <typename T> bool menu_select_launch::select_bios(T const &driver, bool inlist)
{
s_bios biosname;
@@ -1240,16 +1049,124 @@ void menu_select_launch::set_pressed()
// draw icons
//-------------------------------------------------
-void menu_select_launch::draw_icon(int linenum, void *selectedref, float x0, float y0)
+float menu_select_launch::draw_icon(int linenum, void *selectedref, float x0, float y0)
{
- render_texture *const icon(get_icon_texture(linenum, selectedref));
- if (icon)
- {
- float const ud_arrow_width = ui().get_line_height() * container().manager().ui_aspect(&container());
- float const x1 = x0 + ud_arrow_width;
- float const y1 = y0 + ui().get_line_height();
- container().add_quad(x0, y0, x1, y1, rgb_t::white(), icon, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
- };
+ if (!ui_globals::has_icons || m_is_swlist)
+ return 0.0f;
+
+ float ud_arrow_width = ui().get_line_height() * container().manager().ui_aspect(&container());
+ const game_driver *driver = nullptr;
+
+ if (item[0].flags & FLAG_UI_FAVORITE)
+ {
+ ui_software_info *soft = (ui_software_info *)selectedref;
+ if (soft->startempty == 1)
+ driver = soft->driver;
+ }
+ else
+ driver = (const game_driver *)selectedref;
+
+ auto x1 = x0 + ud_arrow_width;
+ auto y1 = y0 + ui().get_line_height();
+
+ icon_cache::iterator icon(m_icons.find(driver));
+ if ((m_icons.end() == icon) || ui_globals::redraw_icon)
+ {
+ if (m_icons.end() == icon)
+ {
+ texture_ptr texture(machine().render().texture_alloc(), [&render = machine().render()] (render_texture *texture) { render.texture_free(texture); });
+ icon = m_icons.emplace(
+ std::piecewise_construct,
+ std::forward_as_tuple(driver),
+ std::forward_as_tuple(std::piecewise_construct, std::forward_as_tuple(std::move(texture)), std::tuple<>())).first;
+ }
+
+ // set clone status
+ bool cloneof = strcmp(driver->parent, "0");
+ if (cloneof)
+ {
+ auto cx = driver_list::find(driver->parent);
+ if ((cx >= 0) && (driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT))
+ cloneof = false;
+ }
+
+ // get search path
+ path_iterator path(ui().options().icons_directory());
+ std::string curpath;
+ std::string searchstr(ui().options().icons_directory());
+
+ // iterate over path and add path for zipped formats
+ while (path.next(curpath))
+ searchstr.append(";").append(curpath.c_str()).append(PATH_SEPARATOR).append("icons");
+
+ bitmap_argb32 tmp;
+ emu_file snapfile(searchstr.c_str(), OPEN_FLAG_READ);
+ std::string fullname = std::string(driver->name).append(".ico");
+ render_load_ico(tmp, snapfile, nullptr, fullname.c_str());
+
+ if (!tmp.valid() && cloneof)
+ {
+ fullname.assign(driver->parent).append(".ico");
+ render_load_ico(tmp, snapfile, nullptr, fullname.c_str());
+ }
+
+ bitmap_argb32 &bitmap(icon->second.second);
+ if (tmp.valid())
+ {
+ float panel_width = x1 - x0;
+ float panel_height = y1 - y0;
+ auto screen_width = machine().render().ui_target().width();
+ auto screen_height = machine().render().ui_target().height();
+
+ if (machine().render().ui_target().orientation() & ORIENTATION_SWAP_XY)
+ std::swap(screen_height, screen_width);
+
+ int panel_width_pixel = panel_width * screen_width;
+ int panel_height_pixel = panel_height * screen_height;
+
+ // Calculate resize ratios for resizing
+ auto ratioW = (float)panel_width_pixel / tmp.width();
+ auto ratioH = (float)panel_height_pixel / tmp.height();
+ auto dest_xPixel = tmp.width();
+ auto dest_yPixel = tmp.height();
+
+ if (ratioW < 1 || ratioH < 1)
+ {
+ // smaller ratio will ensure that the image fits in the view
+ float ratio = std::min(ratioW, ratioH);
+ dest_xPixel = tmp.width() * ratio;
+ dest_yPixel = tmp.height() * ratio;
+ }
+
+ bitmap_argb32 dest_bitmap;
+
+ // resample if necessary
+ if (dest_xPixel != tmp.width() || dest_yPixel != tmp.height())
+ {
+ dest_bitmap.allocate(dest_xPixel, dest_yPixel);
+ render_color color = { 1.0f, 1.0f, 1.0f, 1.0f };
+ render_resample_argb_bitmap_hq(dest_bitmap, tmp, color, true);
+ }
+ else
+ dest_bitmap = std::move(tmp);
+
+ bitmap.allocate(panel_width_pixel, panel_height_pixel);
+ for (int x = 0; x < dest_xPixel; x++)
+ for (int y = 0; y < dest_yPixel; y++)
+ bitmap.pix32(y, x) = dest_bitmap.pix32(y, x);
+
+ icon->second.first->set_bitmap(bitmap, bitmap.cliprect(), TEXFORMAT_ARGB32);
+ }
+ else
+ {
+ bitmap.reset();
+ }
+ }
+
+ if (icon->second.second.valid())
+ container().add_quad(x0, y0, x1, y1, rgb_t::white(), icon->second.first.get(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+
+ return ud_arrow_width * 1.5f;
}
@@ -1260,21 +1177,21 @@ void menu_select_launch::draw_icon(int linenum, void *selectedref, float x0, flo
void menu_select_launch::get_title_search(std::string &snaptext, std::string &searchstr)
{
// get arts title text
- snaptext.assign(_(arts_info[m_image_view].first));
+ snaptext.assign(_(arts_info[ui_globals::curimage_view].first));
// get search path
std::string addpath;
- if (m_image_view == SNAPSHOT_VIEW)
+ if (ui_globals::curimage_view == SNAPSHOT_VIEW)
{
emu_options moptions;
- searchstr = machine().options().value(arts_info[m_image_view].second);
- addpath = moptions.value(arts_info[m_image_view].second);
+ searchstr = machine().options().value(arts_info[ui_globals::curimage_view].second);
+ addpath = moptions.value(arts_info[ui_globals::curimage_view].second);
}
else
{
ui_options moptions;
- searchstr = ui().options().value(arts_info[m_image_view].second);
- addpath = moptions.value(arts_info[m_image_view].second);
+ searchstr = ui().options().value(arts_info[ui_globals::curimage_view].second);
+ addpath = moptions.value(arts_info[ui_globals::curimage_view].second);
}
std::string tmp(searchstr);
@@ -1763,9 +1680,8 @@ void menu_select_launch::draw(uint32_t flags)
{
bool noinput = (flags & PROCESS_NOINPUT);
float line_height = ui().get_line_height();
- float const ud_arrow_width = line_height * machine().render().ui_aspect();
- float const gutter_width = 0.52f * ud_arrow_width;
- float const icon_offset = m_has_icons ? (1.5f * ud_arrow_width) : 0.0f;
+ float ud_arrow_width = line_height * machine().render().ui_aspect();
+ float gutter_width = 0.52f * ud_arrow_width;
float right_panel_size = (ui_globals::panels_status == HIDE_BOTH || ui_globals::panels_status == HIDE_RIGHT_PANEL) ? 2.0f * UI_BOX_LR_BORDER : 0.3f;
float visible_width = 1.0f - 4.0f * UI_BOX_LR_BORDER;
float primary_left = (1.0f - visible_width) * 0.5f;
@@ -1850,21 +1766,18 @@ void menu_select_launch::draw(uint32_t flags)
if (mouse_in_rect(line_x0, line_y0, line_x1, line_y1) && is_selectable(pitem))
hover = itemnum;
+ // if we're selected, draw with a different background
if (is_selected(itemnum) && m_focus == focused_menu::MAIN)
{
- // if we're selected, draw with a different background
fgcolor = rgb_t(0xff, 0xff, 0x00);
bgcolor = rgb_t(0xff, 0xff, 0xff);
fgcolor3 = rgb_t(0xcc, 0xcc, 0x00);
- ui().draw_textured_box(
- container(),
- line_x0 + 0.01f, line_y0, line_x1 - 0.01f, line_y1,
- bgcolor, rgb_t(43, 43, 43),
+ ui().draw_textured_box(container(), line_x0 + 0.01f, line_y0, line_x1 - 0.01f, line_y1, bgcolor, rgb_t(43, 43, 43),
hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1));
}
+ // else if the mouse is over this item, draw with a different background
else if (itemnum == hover)
{
- // else if the mouse is over this item, draw with a different background
fgcolor = fgcolor3 = UI_MOUSEOVER_COLOR;
bgcolor = UI_MOUSEOVER_BG_COLOR;
highlight(line_x0, line_y0, line_x1, line_y1, bgcolor);
@@ -1904,52 +1817,29 @@ void menu_select_launch::draw(uint32_t flags)
else if (pitem.subtext.empty())
{
// draw the item centered
- int const item_invert = pitem.flags & FLAG_INVERT;
- if (m_has_icons)
- draw_icon(linenum, item[itemnum].ref, effective_left, line_y);
- ui().draw_text_full(
- container(),
- itemtext,
- effective_left + icon_offset, line_y, effective_width - icon_offset,
- ui::text_layout::LEFT, ui::text_layout::TRUNCATE,
- mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor,
- nullptr, nullptr);
+ int item_invert = pitem.flags & FLAG_INVERT;
+ auto icon = draw_icon(linenum, item[itemnum].ref, effective_left, line_y);
+ ui().draw_text_full(container(), itemtext, effective_left + icon, line_y, effective_width - icon, ui::text_layout::LEFT, ui::text_layout::TRUNCATE,
+ mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor, nullptr, nullptr);
}
else
{
- int const item_invert = pitem.flags & FLAG_INVERT;
+ auto item_invert = pitem.flags & FLAG_INVERT;
const char *subitem_text = pitem.subtext.c_str();
float item_width, subitem_width;
// compute right space for subitem
- ui().draw_text_full(
- container(),
- subitem_text,
- effective_left + icon_offset, line_y, ui().get_string_width(pitem.subtext.c_str()),
- ui::text_layout::RIGHT, ui::text_layout::NEVER,
- mame_ui_manager::NONE, item_invert ? fgcolor3 : fgcolor, bgcolor,
- &subitem_width, nullptr);
+ ui().draw_text_full(container(), subitem_text, effective_left, line_y, ui().get_string_width(pitem.subtext.c_str()),
+ ui::text_layout::RIGHT, ui::text_layout::NEVER, mame_ui_manager::NONE, item_invert ? fgcolor3 : fgcolor, bgcolor, &subitem_width, nullptr);
subitem_width += gutter_width;
// draw the item left-justified
- if (m_has_icons)
- draw_icon(linenum, item[itemnum].ref, effective_left, line_y);
- ui().draw_text_full(
- container(),
- itemtext,
- effective_left + icon_offset, line_y, effective_width - icon_offset - subitem_width,
- ui::text_layout::LEFT, ui::text_layout::TRUNCATE,
- mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor,
- &item_width, nullptr);
+ ui().draw_text_full(container(), itemtext, effective_left, line_y, effective_width - subitem_width,
+ ui::text_layout::LEFT, ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor, &item_width, nullptr);
// draw the subitem right-justified
- ui().draw_text_full(
- container(),
- subitem_text,
- effective_left + icon_offset + item_width, line_y, effective_width - icon_offset - item_width,
- ui::text_layout::RIGHT, ui::text_layout::NEVER,
- mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor,
- nullptr, nullptr);
+ ui().draw_text_full(container(), subitem_text, effective_left + item_width, line_y, effective_width - item_width,
+ ui::text_layout::RIGHT, ui::text_layout::NEVER, mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor, nullptr, nullptr);
}
}
@@ -2010,6 +1900,9 @@ void menu_select_launch::draw(uint32_t flags)
// return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow
m_visible_items = m_visible_lines - (top_line != 0) - (top_line + m_visible_lines != visible_items);
+ // reset redraw icon stage
+ if (!m_is_swlist) ui_globals::redraw_icon = false;
+
// noinput
if (noinput)
{
@@ -2151,14 +2044,14 @@ void menu_select_launch::arts_render(float origx1, float origy1, float origx2, f
{
m_cache->set_snapx_driver(nullptr);
- if (m_default_image)
- m_image_view = (software->startempty == 0) ? SNAPSHOT_VIEW : CABINETS_VIEW;
+ if (ui_globals::default_image)
+ ui_globals::curimage_view = (software->startempty == 0) ? SNAPSHOT_VIEW : CABINETS_VIEW;
// arts title and searchpath
std::string const searchstr = arts_render_common(origx1, origy1, origx2, origy2);
// loads the image if necessary
- if (!m_cache->snapx_software_is(software) || !snapx_valid() || m_switch_image)
+ if (!m_cache->snapx_software_is(software) || !snapx_valid() || ui_globals::switch_image)
{
emu_file snapfile(searchstr.c_str(), OPEN_FLAG_READ);
bitmap_argb32 tmp_bitmap;
@@ -2204,7 +2097,7 @@ void menu_select_launch::arts_render(float origx1, float origy1, float origx2, f
}
m_cache->set_snapx_software(software);
- m_switch_image = false;
+ ui_globals::switch_image = false;
arts_render_images(std::move(tmp_bitmap), origx1, origy1, origx2, origy2);
}
@@ -2215,13 +2108,13 @@ void menu_select_launch::arts_render(float origx1, float origy1, float origx2, f
{
m_cache->set_snapx_software(nullptr);
- if (m_default_image)
- m_image_view = ((driver->flags & machine_flags::MASK_TYPE) != machine_flags::TYPE_ARCADE) ? CABINETS_VIEW : SNAPSHOT_VIEW;
+ if (ui_globals::default_image)
+ ui_globals::curimage_view = ((driver->flags & machine_flags::MASK_TYPE) != machine_flags::TYPE_ARCADE) ? CABINETS_VIEW : SNAPSHOT_VIEW;
std::string const searchstr = arts_render_common(origx1, origy1, origx2, origy2);
// loads the image if necessary
- if (!m_cache->snapx_driver_is(driver) || !snapx_valid() || m_switch_image)
+ if (!m_cache->snapx_driver_is(driver) || !snapx_valid() || ui_globals::switch_image)
{
emu_file snapfile(searchstr.c_str(), OPEN_FLAG_READ);
snapfile.set_restrict_to_mediapath(true);
@@ -2273,7 +2166,7 @@ void menu_select_launch::arts_render(float origx1, float origy1, float origx2, f
}
m_cache->set_snapx_driver(driver);
- m_switch_image = false;
+ ui_globals::switch_image = false;
arts_render_images(std::move(tmp_bitmap), origx1, origy1, origx2, origy2);
}
@@ -2331,7 +2224,7 @@ std::string menu_select_launch::arts_render_common(float origx1, float origy1, f
ui::text_layout::CENTER, ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, fgcolor, bgcolor,
nullptr, nullptr, tmp_size);
- draw_common_arrow(origx1, origy1 + UI_BOX_TB_BORDER, origx2, origy2, m_image_view, FIRST_VIEW, LAST_VIEW, title_size);
+ draw_common_arrow(origx1, origy1 + UI_BOX_TB_BORDER, origx2, origy2, ui_globals::curimage_view, FIRST_VIEW, LAST_VIEW, title_size);
return searchstr;
}
@@ -2381,7 +2274,7 @@ void menu_select_launch::arts_render_images(bitmap_argb32 &&tmp_bitmap, float or
auto dest_yPixel = tmp_bitmap.height();
// force 4:3 ratio min
- if (ui().options().forced_4x3_snapshot() && ratioI < 0.75f && m_image_view == SNAPSHOT_VIEW)
+ if (ui().options().forced_4x3_snapshot() && ratioI < 0.75f && ui_globals::curimage_view == SNAPSHOT_VIEW)
{
// smaller ratio will ensure that the image fits in the view
dest_yPixel = tmp_bitmap.width() * 0.75f;
@@ -2474,7 +2367,7 @@ bool menu_select_launch::has_multiple_bios(game_driver const &driver, s_bios &bi
for (romload::system_bios const &bios : romload::entries(driver.rom).get_system_bioses())
{
std::string name(bios.get_description());
- uint32_t const bios_flags(bios.get_value());
+ u32 const bios_flags(bios.get_value());
if (default_name && !std::strcmp(bios.get_name(), default_name))
{
diff --git a/src/frontend/mame/ui/selmenu.h b/src/frontend/mame/ui/selmenu.h
index 5e85cb0ce96..1c5b6bdadd9 100644
--- a/src/frontend/mame/ui/selmenu.h
+++ b/src/frontend/mame/ui/selmenu.h
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods, Vas Crabb
+// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods
/***************************************************************************
ui/selmenu.h
@@ -7,6 +7,7 @@
MAME system/software selection menu.
***************************************************************************/
+
#ifndef MAME_FRONTEND_UI_SELMENU_H
#define MAME_FRONTEND_UI_SELMENU_H
@@ -33,8 +34,6 @@ public:
virtual ~menu_select_launch() override;
protected:
- static constexpr std::size_t MAX_ICONS_RENDER = 128;
- static constexpr std::size_t MAX_VISIBLE_SEARCH = 200;
// tab navigation
enum class focused_menu
@@ -45,20 +44,6 @@ protected:
RIGHTBOTTOM
};
- struct texture_and_bitmap
- {
- template <typename T>
- texture_and_bitmap(T &&tex) : texture(std::forward<T>(tex)) { }
- texture_and_bitmap(texture_and_bitmap &&that) = default;
- texture_and_bitmap &operator=(texture_and_bitmap &&that) = default;
-
- texture_ptr texture;
- bitmap_argb32 bitmap;
- };
-
- template <typename Key, typename Compare = std::less<Key> >
- using texture_lru = util::lru_cache_map<Key, texture_and_bitmap, Compare>;
-
class system_flags
{
public:
@@ -108,8 +93,6 @@ protected:
focused_menu get_focus() const { return m_focus; }
void set_focus(focused_menu focus) { m_focus = focus; }
- void next_image_view();
- void previous_image_view();
bool dismiss_error();
void set_error(reset_options ropt, std::string &&message);
@@ -139,14 +122,6 @@ protected:
std::map<typename Filter::type, typename Filter::ptr> const &filters,
float x1, float y1, float x2, float y2);
- // icon helpers
- void check_for_icons(char const *listname);
- std::string make_icon_paths(char const *listname) const;
- bool scale_icon(bitmap_argb32 &&src, texture_and_bitmap &dst) const;
-
- // forcing refresh
- void set_switch_image() { m_switch_image = true; }
-
template <typename T> bool select_bios(T const &driver, bool inlist);
bool select_part(software_info const &info, ui_software_info const &ui_info);
@@ -213,6 +188,9 @@ private:
using cache_ptr_map = std::map<running_machine *, cache_ptr>;
using flags_cache = util::lru_cache_map<game_driver const *, system_flags>;
+ using icon_cache = util::lru_cache_map<game_driver const *, std::pair<texture_ptr, bitmap_argb32> >;
+
+ static constexpr std::size_t MAX_ICONS_RENDER = 128;
void reset_pressed() { m_pressed = false; m_repeat = 0; }
bool mouse_pressed() const { return (osd_ticks() >= m_repeat); }
@@ -252,8 +230,7 @@ private:
void draw_toolbar(float x1, float y1, float x2, float y2);
void draw_star(float x0, float y0);
- void draw_icon(int linenum, void *selectedref, float x1, float y1);
- virtual render_texture *get_icon_texture(int linenum, void *selectedref) = 0;
+ float draw_icon(int linenum, void *selectedref, float x1, float y1);
void get_title_search(std::string &title, std::string &search);
@@ -312,11 +289,8 @@ private:
int m_right_visible_lines; // right box lines
- bool m_has_icons;
- bool m_switch_image;
- bool m_default_image;
- uint8_t m_image_view;
flags_cache m_flags;
+ icon_cache m_icons;
static std::mutex s_cache_guard;
static cache_ptr_map s_caches;
diff --git a/src/frontend/mame/ui/selsoft.cpp b/src/frontend/mame/ui/selsoft.cpp
index 26635c6d31a..e7ebc3effa2 100644
--- a/src/frontend/mame/ui/selsoft.cpp
+++ b/src/frontend/mame/ui/selsoft.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Maurizio Petrarota, Vas Crabb
+// copyright-holders:Maurizio Petrarota
/***************************************************************************
ui/selsoft.cpp
@@ -12,7 +12,6 @@
#include "ui/selsoft.h"
#include "ui/ui.h"
-#include "ui/icorender.h"
#include "ui/inifile.h"
#include "ui/selector.h"
@@ -25,97 +24,75 @@
#include "uiinput.h"
#include "luaengine.h"
-#include <algorithm>
-#include <iterator>
-#include <functional>
-
namespace ui {
-namespace {
-
//-------------------------------------------------
// compares two items in the software list and
// sort them by parent-clone
//-------------------------------------------------
-bool compare_software(ui_software_info const &a, ui_software_info const &b)
+bool compare_software(ui_software_info a, ui_software_info b)
{
- bool const clonex = !a.parentname.empty() && !a.parentlongname.empty();
- bool const cloney = !b.parentname.empty() && !b.parentlongname.empty();
+ ui_software_info *x = &a;
+ ui_software_info *y = &b;
+
+ bool clonex = !x->parentname.empty();
+ bool cloney = !y->parentname.empty();
if (!clonex && !cloney)
+ return (strmakelower(x->longname) < strmakelower(y->longname));
+
+ std::string cx(x->parentlongname), cy(y->parentlongname);
+
+ if (cx.empty())
+ clonex = false;
+
+ if (cy.empty())
+ cloney = false;
+
+ if (!clonex && !cloney)
+ return (strmakelower(x->longname) < strmakelower(y->longname));
+ else if (clonex && cloney)
{
- return 0 > core_stricmp(a.longname.c_str(), b.longname.c_str());
+ if (!core_stricmp(x->parentname.c_str(), y->parentname.c_str()) && !core_stricmp(x->instance.c_str(), y->instance.c_str()))
+ return (strmakelower(x->longname) < strmakelower(y->longname));
+ else
+ return (strmakelower(cx) < strmakelower(cy));
}
else if (!clonex && cloney)
{
- if ((a.shortname == b.parentname) && (a.instance == b.instance))
+ if (!core_stricmp(x->shortname.c_str(), y->parentname.c_str()) && !core_stricmp(x->instance.c_str(), y->instance.c_str()))
return true;
else
- return 0 > core_stricmp(a.longname.c_str(), b.parentlongname.c_str());
+ return (strmakelower(x->longname) < strmakelower(cy));
}
- else if (clonex && !cloney)
+ else
{
- if ((a.parentname == b.shortname) && (a.instance == b.instance))
+ if (!core_stricmp(x->parentname.c_str(), y->shortname.c_str()) && !core_stricmp(x->instance.c_str(), y->instance.c_str()))
return false;
else
- return 0 > core_stricmp(a.parentlongname.c_str(), b.longname.c_str());
- }
- else if ((a.parentname == b.parentname) && (a.instance == b.instance))
- {
- return 0 > core_stricmp(a.longname.c_str(), b.longname.c_str());
- }
- else
- {
- return 0 > core_stricmp(a.parentlongname.c_str(), b.parentlongname.c_str());
+ return (strmakelower(cx) < strmakelower(y->longname));
}
}
-} // anonymous namespace
-
-
-menu_select_software::search_item::search_item(ui_software_info const &s)
- : software(s)
- , ucs_shortname(ustr_from_utf8(normalize_unicode(s.shortname, unicode_normalization_form::D, true)))
- , ucs_longname(ustr_from_utf8(normalize_unicode(s.longname, unicode_normalization_form::D, true)))
- , penalty(1.0)
-{
-}
-
-void menu_select_software::search_item::set_penalty(std::u32string const &search)
-{
- // TODO: search alternate title as well
- penalty = util::edit_distance(search, ucs_shortname);
- if (penalty)
- penalty = (std::min)(penalty, util::edit_distance(search, ucs_longname));
-}
-
-
//-------------------------------------------------
// ctor
//-------------------------------------------------
-menu_select_software::menu_select_software(mame_ui_manager &mui, render_container &container, game_driver const &driver)
+menu_select_software::menu_select_software(mame_ui_manager &mui, render_container &container, const game_driver *driver)
: menu_select_launch(mui, container, true)
- , m_icon_paths()
- , m_icons(MAX_ICONS_RENDER)
- , m_driver(driver)
- , m_has_empty_start(false)
- , m_filter_data()
- , m_filters()
, m_filter_type(software_filter::ALL)
- , m_swinfo()
- , m_searchlist()
- , m_displaylist()
{
reselect_last::reselect(false);
+ m_driver = driver;
build_software_list();
load_sw_custom_filters();
m_filter_highlight = m_filter_type;
- set_switch_image();
+ ui_globals::curimage_view = SNAPSHOT_VIEW;
+ ui_globals::switch_image = true;
ui_globals::cur_sw_dats_view = 0;
ui_globals::cur_sw_dats_total = 1;
}
@@ -126,6 +103,8 @@ menu_select_software::menu_select_software(mame_ui_manager &mui, render_containe
menu_select_software::~menu_select_software()
{
+ ui_globals::curimage_view = CABINETS_VIEW;
+ ui_globals::switch_image = true;
}
//-------------------------------------------------
@@ -156,10 +135,12 @@ void menu_select_software::handle()
break;
case IPT_UI_LEFT:
- if (ui_globals::rpanel == RP_IMAGES)
+ if (ui_globals::rpanel == RP_IMAGES && ui_globals::curimage_view > FIRST_VIEW)
{
// Images
- previous_image_view();
+ ui_globals::curimage_view--;
+ ui_globals::switch_image = true;
+ ui_globals::default_image = false;
}
else if (ui_globals::rpanel == RP_INFOS && ui_globals::cur_sw_dats_view > 0)
{
@@ -170,10 +151,12 @@ void menu_select_software::handle()
break;
case IPT_UI_RIGHT:
- if (ui_globals::rpanel == RP_IMAGES)
+ if (ui_globals::rpanel == RP_IMAGES && ui_globals::curimage_view < LAST_VIEW)
{
// Images
- next_image_view();
+ ui_globals::curimage_view++;
+ ui_globals::switch_image = true;
+ ui_globals::default_image = false;
}
else if (ui_globals::rpanel == RP_INFOS && ui_globals::cur_sw_dats_view < (ui_globals::cur_sw_dats_total - 1))
{
@@ -222,16 +205,16 @@ void menu_select_software::handle()
if ((uintptr_t)swinfo > 2)
{
favorite_manager &mfav = mame_machine_manager::instance()->favorite();
- if (!mfav.is_favorite_system_software(*swinfo))
+ if (!mfav.isgame_favorite(*swinfo))
{
- mfav.add_favorite_software(*swinfo);
+ mfav.add_favorite_game(*swinfo);
machine().popmessage(_("%s\n added to favorites list."), swinfo->longname.c_str());
}
else
{
machine().popmessage(_("%s\n removed from favorites list."), swinfo->longname.c_str());
- mfav.remove_favorite_software(*swinfo);
+ mfav.remove_favorite_game();
}
}
}
@@ -249,27 +232,17 @@ void menu_select_software::handle()
void menu_select_software::populate(float &customtop, float &custombottom)
{
- for (auto &icon : m_icons) // TODO: why is this here? maybe better on resize or setting change?
- icon.second.texture.reset();
-
uint32_t flags_ui = FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW;
m_has_empty_start = true;
int old_software = -1;
- // FIXME: why does it do this relatively expensive operation every time?
- machine_config config(m_driver, machine().options());
+ machine_config config(*m_driver, machine().options());
for (device_image_interface &image : image_interface_iterator(config.root_device()))
- {
- if (!image.filename() && image.must_be_loaded())
+ if (image.filename() == nullptr && image.must_be_loaded())
{
m_has_empty_start = false;
break;
}
- }
-
- // start with an empty list
- m_displaylist.clear();
- filter_map::const_iterator const flt(m_filters.find(m_filter_type));
// no active search
if (m_search.empty())
@@ -278,44 +251,37 @@ void menu_select_software::populate(float &customtop, float &custombottom)
if (m_has_empty_start)
item_append("[Start empty]", "", flags_ui, (void *)&m_swinfo[0]);
- if (m_filters.end() == flt)
- std::copy(std::next(m_swinfo.begin()), m_swinfo.end(), std::back_inserter(m_displaylist));
- else
- flt->second->apply(std::next(m_swinfo.begin()), m_swinfo.end(), std::back_inserter(m_displaylist));
- }
- else
- {
- find_matches();
+ m_displaylist.clear();
+ m_tmp.clear();
- if (m_filters.end() == flt)
- {
- std::transform(
- m_searchlist.begin(),
- std::next(m_searchlist.begin(), (std::min)(m_searchlist.size(), MAX_VISIBLE_SEARCH)),
- std::back_inserter(m_displaylist),
- [] (search_item const &entry) { return entry.software; });
- }
+ 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)
{
- for (auto it = m_searchlist.begin(); (m_searchlist.end() != it) && (MAX_VISIBLE_SEARCH > m_displaylist.size()); ++it)
- {
- if (flt->second->apply(it->software))
- m_displaylist.emplace_back(it->software);
- }
+ if (reselect_last::software() == "[Start empty]" && !reselect_last::driver().empty())
+ old_software = 0;
+
+ else if (m_displaylist[curitem]->shortname == reselect_last::software() && m_displaylist[curitem]->listname == reselect_last::swlist())
+ old_software = m_has_empty_start ? curitem + 1 : curitem;
+
+ item_append(m_displaylist[curitem]->longname, m_displaylist[curitem]->devicetype,
+ m_displaylist[curitem]->parentname.empty() ? flags_ui : (FLAG_INVERT | flags_ui), (void *)m_displaylist[curitem]);
}
}
- // iterate over entries
- for (size_t curitem = 0; curitem < m_displaylist.size(); ++curitem)
+ else
{
- if (reselect_last::software() == "[Start empty]" && !reselect_last::driver().empty())
- old_software = 0;
- else if (m_displaylist[curitem].get().shortname == reselect_last::software() && m_displaylist[curitem].get().listname == reselect_last::swlist())
- old_software = m_has_empty_start ? curitem + 1 : curitem;
-
- item_append(
- m_displaylist[curitem].get().longname, m_displaylist[curitem].get().devicetype,
- m_displaylist[curitem].get().parentname.empty() ? flags_ui : (FLAG_INVERT | flags_ui), (void *)&m_displaylist[curitem].get());
+ find_matches(m_search.c_str(), VISIBLE_GAMES_IN_SEARCH);
+
+ for (int curitem = 0; m_searchlist[curitem] != nullptr; ++curitem)
+ item_append(m_searchlist[curitem]->longname, m_searchlist[curitem]->devicetype,
+ m_searchlist[curitem]->parentname.empty() ? flags_ui : (FLAG_INVERT | flags_ui),
+ (void *)m_searchlist[curitem]);
}
item_append(menu_item_type::SEPARATOR, flags_ui);
@@ -340,51 +306,21 @@ void menu_select_software::populate(float &customtop, float &custombottom)
void menu_select_software::build_software_list()
{
// add start empty item
- m_swinfo.emplace_back(m_driver);
+ m_swinfo.emplace_back(*m_driver);
- machine_config config(m_driver, machine().options());
+ machine_config config(*m_driver, machine().options());
- // iterate through all software lists
- std::vector<std::size_t> orphans;
- struct orphan_less
- {
- std::vector<ui_software_info> &swinfo;
- bool operator()(std::string const &a, std::string const &b) const { return a < b; };
- bool operator()(std::string const &a, std::size_t b) const { return a < swinfo[b].parentname; };
- bool operator()(std::size_t a, std::string const &b) const { return swinfo[a].parentname < b; };
- bool operator()(std::size_t a, std::size_t b) const { return swinfo[a].parentname < swinfo[b].parentname; };
- };
- orphan_less const orphan_cmp{ m_swinfo };
+ // iterate thru all software lists
for (software_list_device &swlist : software_list_device_iterator(config.root_device()))
{
m_filter_data.add_list(swlist.list_name(), swlist.description());
- check_for_icons(swlist.list_name().c_str());
- orphans.clear();
- std::map<std::string, std::string> parentnames;
- std::map<std::string, std::string>::const_iterator prevparent(parentnames.end());
for (const software_info &swinfo : swlist.get_info())
{
- // check for previously-encountered clones
- if (swinfo.parentname().empty())
- {
- if (parentnames.emplace(swinfo.shortname(), swinfo.longname()).second)
- {
- auto const clones(std::equal_range(orphans.begin(), orphans.end(), swinfo.shortname(), orphan_cmp));
- for (auto it = clones.first; clones.second != it; ++it)
- m_swinfo[*it].parentlongname = swinfo.longname();
- orphans.erase(clones.first, clones.second);
- }
- else
- {
- assert([] (auto const x) { return x.first == x.second; } (std::equal_range(orphans.begin(), orphans.end(), swinfo.shortname(), orphan_cmp)));
- }
- }
-
const software_part &part = swinfo.parts().front();
if (swlist.is_compatible(part) == SOFTWARE_IS_COMPATIBLE)
{
- char const *instance_name(nullptr);
- char const *type_name(nullptr);
+ const char *instance_name = nullptr;
+ const char *type_name = nullptr;
for (device_image_interface &image : image_interface_iterator(config.root_device()))
{
char const *const interface = image.image_interface();
@@ -395,35 +331,45 @@ void menu_select_software::build_software_list()
break;
}
}
+ if (!instance_name || !type_name)
+ continue;
- if (instance_name && type_name)
- {
- // add to collection and try to resolve parent if applicable
- auto const ins(m_swinfo.emplace(m_swinfo.end(), swinfo, part, m_driver, swlist.list_name(), instance_name, type_name));
- if (!swinfo.parentname().empty())
- {
- if ((parentnames.end() == prevparent) || (swinfo.parentname() != prevparent->first))
- prevparent = parentnames.find(swinfo.parentname());
+ ui_software_info tmpmatches(swinfo, part, *m_driver, swlist.list_name(), instance_name, type_name);
- if (parentnames.end() != prevparent)
- {
- ins->parentlongname = prevparent->second;
- }
- else
- {
- orphans.emplace(
- std::upper_bound(orphans.begin(), orphans.end(), swinfo.parentname(), orphan_cmp),
- std::distance(m_swinfo.begin(), ins));
- }
- }
+ m_filter_data.add_region(tmpmatches.longname);
+ m_filter_data.add_publisher(tmpmatches.publisher);
+ m_filter_data.add_year(tmpmatches.year);
+ m_filter_data.add_device_type(tmpmatches.devicetype);
+ m_swinfo.emplace_back(std::move(tmpmatches));
+ }
+ }
+ }
+ m_displaylist.resize(m_swinfo.size() + 1);
+
+ // retrieve and set the long name of software for parents
+ for (size_t y = 1; y < m_swinfo.size(); ++y)
+ {
+ if (!m_swinfo[y].parentname.empty())
+ {
+ std::string lparent(m_swinfo[y].parentname);
+ bool found = false;
- // populate filter choices
- m_filter_data.add_region(ins->longname);
- m_filter_data.add_publisher(ins->publisher);
- m_filter_data.add_year(ins->year);
- m_filter_data.add_device_type(ins->devicetype);
+ // first scan backward
+ for (int x = y; x > 0; --x)
+ if (lparent == m_swinfo[x].shortname && m_swinfo[y].listname == m_swinfo[x].listname)
+ {
+ m_swinfo[y].parentlongname = m_swinfo[x].longname;
+ found = true;
+ break;
+ }
+
+ // not found? then scan forward
+ for (size_t x = y; !found && x < m_swinfo.size(); ++x)
+ if (lparent == m_swinfo[x].shortname && m_swinfo[y].listname == m_swinfo[x].listname)
+ {
+ m_swinfo[y].parentlongname = m_swinfo[x].longname;
+ break;
}
- }
}
}
@@ -462,6 +408,9 @@ void menu_select_software::build_software_list()
// sort array
std::stable_sort(m_swinfo.begin() + 1, m_swinfo.end(), compare_software);
m_filter_data.finalise();
+
+ for (size_t x = 1; x < m_swinfo.size(); ++x)
+ m_sortedlist.push_back(&m_swinfo[x]);
}
@@ -525,7 +474,7 @@ void menu_select_software::load_sw_custom_filters()
{
// attempt to open the output file
emu_file file(ui().options().ui_path(), OPEN_FLAG_READ);
- if (file.open("custom_", m_driver.name, "_filter.ini") == osd_file::error::NONE)
+ if (file.open("custom_", m_driver->name, "_filter.ini") == osd_file::error::NONE)
{
software_filter::ptr flt(software_filter::create(file, m_filter_data));
if (flt)
@@ -538,25 +487,38 @@ void menu_select_software::load_sw_custom_filters()
// find approximate matches
//-------------------------------------------------
-void menu_select_software::find_matches()
+void menu_select_software::find_matches(const char *str, int count)
{
- // ensure search list is populated
- if (m_searchlist.empty())
+ // allocate memory to track the penalty value
+ std::vector<int> penalty(count, 9999);
+ int index = 0;
+
+ for (; index < m_displaylist.size(); ++index)
{
- m_searchlist.reserve(m_swinfo.size());
- std::copy(m_swinfo.begin(), m_swinfo.end(), std::back_inserter(m_searchlist));
- }
+ // pick the best match between driver name and description
+ int curpenalty = fuzzy_substring(str, m_displaylist[index]->longname);
+ int tmp = fuzzy_substring(str, m_displaylist[index]->shortname);
+ curpenalty = std::min(curpenalty, tmp);
+
+ // insert into the sorted table of matches
+ for (int matchnum = count - 1; matchnum >= 0; --matchnum)
+ {
+ // stop if we're worse than the current entry
+ if (curpenalty >= penalty[matchnum])
+ break;
- // update search
- const std::u32string ucs_search(ustr_from_utf8(normalize_unicode(m_search, unicode_normalization_form::D, true)));
- for (search_item &entry : m_searchlist)
- entry.set_penalty(ucs_search);
+ // as long as this isn't the last entry, bump this one down
+ if (matchnum < count - 1)
+ {
+ penalty[matchnum + 1] = penalty[matchnum];
+ m_searchlist[matchnum + 1] = m_searchlist[matchnum];
+ }
- // sort according to edit distance
- std::stable_sort(
- m_searchlist.begin(),
- m_searchlist.end(),
- [] (search_item const &lhs, search_item const &rhs) { return lhs.penalty < rhs.penalty; });
+ m_searchlist[matchnum] = m_displaylist[index];
+ penalty[matchnum] = curpenalty;
+ }
+ }
+ (index < count) ? m_searchlist[index] = nullptr : m_searchlist[count] = nullptr;
}
//-------------------------------------------------
@@ -570,56 +532,6 @@ float menu_select_software::draw_left_panel(float x1, float y1, float x2, float
//-------------------------------------------------
-// get (possibly cached) icon texture
-//-------------------------------------------------
-
-render_texture *menu_select_software::get_icon_texture(int linenum, void *selectedref)
-{
- ui_software_info const *const swinfo(reinterpret_cast<ui_software_info const *>(selectedref));
- assert(swinfo);
-
- if (swinfo->startempty)
- return nullptr;
-
- icon_cache::iterator icon(m_icons.find(swinfo));
- if ((m_icons.end() == icon) || !icon->second.texture)
- {
- std::map<std::string, std::string>::iterator paths(m_icon_paths.find(swinfo->listname));
- if (m_icon_paths.end() == paths)
- paths = m_icon_paths.emplace(swinfo->listname, make_icon_paths(swinfo->listname.c_str())).first;
-
- // allocate an entry or allocate a texture on forced redraw
- if (m_icons.end() == icon)
- {
- icon = m_icons.emplace(swinfo, texture_ptr(machine().render().texture_alloc(), machine().render())).first;
- }
- else
- {
- assert(!icon->second.texture);
- icon->second.texture.reset(machine().render().texture_alloc());
- }
-
- bitmap_argb32 tmp;
- emu_file snapfile(std::string(paths->second), OPEN_FLAG_READ);
- if (snapfile.open(std::string(swinfo->shortname), ".ico") == osd_file::error::NONE)
- {
- render_load_ico_highest_detail(snapfile, tmp);
- snapfile.close();
- }
- if (!tmp.valid() && !swinfo->parentname.empty() && (snapfile.open(std::string(swinfo->parentname), ".ico") == osd_file::error::NONE))
- {
- render_load_ico_highest_detail(snapfile, tmp);
- snapfile.close();
- }
-
- scale_icon(std::move(tmp), icon->second);
- }
-
- return icon->second.bitmap.valid() ? icon->second.texture.get() : nullptr;
-}
-
-
-//-------------------------------------------------
// get selected software and/or driver
//-------------------------------------------------
@@ -635,7 +547,7 @@ void menu_select_software::make_topbox_text(std::string &line0, std::string &lin
// determine the text for the header
int vis_item = !m_search.empty() ? visible_items : (m_has_empty_start ? visible_items - 1 : visible_items);
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());
+ line1 = string_format(_("Driver: \"%1$s\" software list "), m_driver->type.fullname());
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);
@@ -664,19 +576,20 @@ void menu_select_software::filter_selected()
{
if ((software_filter::FIRST <= m_filter_highlight) && (software_filter::LAST >= m_filter_highlight))
{
+ m_search.clear();
filter_map::const_iterator it(m_filters.find(software_filter::type(m_filter_highlight)));
if (m_filters.end() == it)
it = m_filters.emplace(software_filter::type(m_filter_highlight), software_filter::create(software_filter::type(m_filter_highlight), m_filter_data)).first;
it->second->show_ui(
ui(),
container(),
- [this] (software_filter &filter)
+ [this, driver = m_driver] (software_filter &filter)
{
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_", m_driver.name, "_filter.ini") == osd_file::error::NONE)
+ if (file.open("custom_", driver->name, "_filter.ini") == osd_file::error::NONE)
{
filter.save_ini(file, 0);
file.close();
diff --git a/src/frontend/mame/ui/selsoft.h b/src/frontend/mame/ui/selsoft.h
index 1bfdd9c1e48..e65a5ddc61f 100644
--- a/src/frontend/mame/ui/selsoft.h
+++ b/src/frontend/mame/ui/selsoft.h
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Maurizio Petrarota, Vas Crabb
+// copyright-holders:Maurizio Petrarota
/***************************************************************************
ui/selsoft.h
@@ -15,10 +15,6 @@
#include "ui/selmenu.h"
#include "ui/utils.h"
-#include <map>
-#include <string>
-#include <vector>
-
namespace ui {
@@ -26,34 +22,25 @@ namespace ui {
class menu_select_software : public menu_select_launch
{
public:
- menu_select_software(mame_ui_manager &mui, render_container &container, game_driver const &driver);
+ menu_select_software(mame_ui_manager &mui, render_container &container, const game_driver *driver);
virtual ~menu_select_software() override;
private:
- using filter_map = std::map<software_filter::type, software_filter::ptr>;
- using icon_cache = texture_lru<ui_software_info const *>;
-
- struct search_item
- {
- search_item(ui_software_info const &s);
- search_item(search_item const &) = default;
- search_item(search_item &&) = default;
- search_item &operator=(search_item const &) = default;
- search_item &operator=(search_item &&) = default;
- void set_penalty(std::u32string const &search);
-
- std::reference_wrapper<ui_software_info const> software;
- std::u32string ucs_shortname;
- std::u32string ucs_longname;
- double penalty;
- };
+ enum { VISIBLE_GAMES_IN_SEARCH = 200 };
+
+ typedef std::map<software_filter::type, software_filter::ptr> filter_map;
+
+ const game_driver *m_driver;
+ bool m_has_empty_start;
+ software_filter_data m_filter_data;
+ filter_map m_filters;
+ software_filter::type m_filter_type;
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle() override;
- // drawing
+ // draw left panel
virtual float draw_left_panel(float x1, float y1, float x2, float y2) override;
- virtual render_texture *get_icon_texture(int linenum, void *selectedref) override;
// get selected software and/or driver
virtual void get_selection(ui_software_info const *&software, game_driver const *&driver) const override;
@@ -69,28 +56,20 @@ private:
// toolbar
virtual void inkey_export() override { throw false; }
+ ui_software_info *m_searchlist[VISIBLE_GAMES_IN_SEARCH + 1];
+ std::vector<ui_software_info *> m_displaylist, m_tmp, m_sortedlist;
+ std::vector<ui_software_info> m_swinfo;
+
void build_software_list();
- void find_matches();
+ void find_matches(const char *str, int count);
void load_sw_custom_filters();
// handlers
void inkey_select(const event *menu_event);
- virtual void general_info(const game_driver *driver, std::string &buffer) override { }
-
- std::map<std::string, std::string> m_icon_paths;
- icon_cache m_icons;
- game_driver const &m_driver;
- bool m_has_empty_start;
- software_filter_data m_filter_data;
- filter_map m_filters;
- software_filter::type m_filter_type;
-
- std::vector<ui_software_info> m_swinfo;
- std::vector<search_item> m_searchlist;
- std::vector<std::reference_wrapper<ui_software_info const> > m_displaylist;
+ virtual void general_info(const game_driver *driver, std::string &buffer) override {}
};
} // namespace ui
-#endif // MAME_FRONTEND_UI_SELSOFT_H
+#endif /* MAME_FRONTEND_UI_SELSOFT_H */
diff --git a/src/frontend/mame/ui/simpleselgame.cpp b/src/frontend/mame/ui/simpleselgame.cpp
index e22e61b6a2b..f81b161dac1 100644
--- a/src/frontend/mame/ui/simpleselgame.cpp
+++ b/src/frontend/mame/ui/simpleselgame.cpp
@@ -163,13 +163,7 @@ void simple_menu_select_game::inkey_select(const event *menu_event)
// special case for configure inputs
if ((uintptr_t)driver == 1)
- {
- menu::stack_push<menu_simple_game_options>(
- ui(),
- container(),
- [this] () { reset(reset_options::SELECT_FIRST); });
- }
-
+ menu::stack_push<menu_game_options>(ui(), container());
// anything else is a driver
else
{
@@ -256,7 +250,7 @@ void simple_menu_select_game::populate(float &customtop, float &custombottom)
// otherwise, rebuild the match list
assert(m_drivlist != nullptr);
if (!m_search.empty() || m_matchlist[0] == -1 || m_rerandomize)
- m_drivlist->find_approximate_matches(m_search, matchcount, m_matchlist);
+ m_drivlist->find_approximate_matches(m_search.c_str(), matchcount, m_matchlist);
m_rerandomize = false;
// iterate over entries
diff --git a/src/frontend/mame/ui/utils.cpp b/src/frontend/mame/ui/utils.cpp
index 52857fc6dbf..1a8ff0ba476 100644
--- a/src/frontend/mame/ui/utils.cpp
+++ b/src/frontend/mame/ui/utils.cpp
@@ -22,9 +22,7 @@
#include "romload.h"
#include "softlist.h"
-#include <atomic>
#include <bitset>
-#include <condition_variable>
#include <cstdlib>
#include <cstring>
#include <iterator>
@@ -84,7 +82,6 @@ constexpr char const *SOFTWARE_FILTER_NAMES[software_filter::COUNT] = {
__("Unfiltered"),
__("Available"),
__("Unavailable"),
- __("Favorites"),
__("Parents"),
__("Clones"),
__("Year"),
@@ -645,7 +642,7 @@ 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(machine_filter_data const &data, char const *value, emu_file *file, unsigned indent) { }
+ 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; }
};
@@ -655,7 +652,7 @@ 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(machine_filter_data const &data, char const *value, emu_file *file, unsigned indent) { }
+ working_machine_filter_impl(char const *value, emu_file *file, unsigned indent) { }
virtual bool apply(ui_system_info const &system) const override { return !(system.driver->flags & machine_flags::NOT_WORKING); }
};
@@ -665,7 +662,7 @@ 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(machine_filter_data const &data, char const *value, emu_file *file, unsigned indent) { }
+ mechanical_machine_filter_impl(char const *value, emu_file *file, unsigned indent) { }
virtual bool apply(ui_system_info const &system) const override { return system.driver->flags & machine_flags::MECHANICAL; }
};
@@ -675,7 +672,7 @@ template <machine_filter::type Type = machine_filter::BIOS>
class bios_machine_filter_impl : public simple_filter_impl_base<machine_filter, Type>
{
public:
- bios_machine_filter_impl(machine_filter_data const &data, char const *value, emu_file *file, unsigned indent) { }
+ bios_machine_filter_impl(char const *value, emu_file *file, unsigned indent) { }
virtual bool apply(ui_system_info const &system) const override { return system.driver->flags & machine_flags::IS_BIOS_ROOT; }
};
@@ -685,7 +682,7 @@ 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(machine_filter_data const &data, char const *value, emu_file *file, unsigned indent) { }
+ parents_machine_filter_impl(char const *value, emu_file *file, unsigned indent) { }
virtual bool apply(ui_system_info const &system) const override
{
@@ -700,7 +697,7 @@ 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(machine_filter_data const &data, char const *value, emu_file *file, unsigned indent) { }
+ chd_machine_filter_impl(char const *value, emu_file *file, unsigned indent) { }
virtual bool apply(ui_system_info const &system) const override
{
@@ -718,7 +715,7 @@ 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(machine_filter_data const &data, char const *value, emu_file *file, unsigned indent) { }
+ save_machine_filter_impl(char const *value, emu_file *file, unsigned indent) { }
virtual bool apply(ui_system_info const &system) const override { return system.driver->flags & machine_flags::SUPPORTS_SAVE; }
};
@@ -728,7 +725,7 @@ 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(machine_filter_data const &data, char const *value, emu_file *file, unsigned indent) { }
+ vertical_machine_filter_impl(char const *value, emu_file *file, unsigned indent) { }
virtual bool apply(ui_system_info const &system) const override { return system.driver->flags & machine_flags::SWAP_XY; }
};
@@ -742,8 +739,8 @@ public:
class manufacturer_machine_filter : public choice_filter_impl_base<machine_filter, machine_filter::MANUFACTURER>
{
public:
- manufacturer_machine_filter(machine_filter_data const &data, char const *value, emu_file *file, unsigned indent)
- : choice_filter_impl_base<machine_filter, machine_filter::MANUFACTURER>(data.manufacturers(), value)
+ manufacturer_machine_filter(char const *value, emu_file *file, unsigned indent)
+ : choice_filter_impl_base<machine_filter, machine_filter::MANUFACTURER>(c_mnfct::ui, value)
{
}
@@ -754,7 +751,7 @@ public:
else if (!selection_valid())
return false;
- std::string const name(machine_filter_data::extract_manufacturer(system.driver->manufacturer));
+ std::string const name(c_mnfct::getname(system.driver->manufacturer));
return !name.empty() && (selection_text() == name);
}
};
@@ -763,8 +760,8 @@ public:
class year_machine_filter : public choice_filter_impl_base<machine_filter, machine_filter::YEAR>
{
public:
- year_machine_filter(machine_filter_data const &data, char const *value, emu_file *file, unsigned indent)
- : choice_filter_impl_base<machine_filter, machine_filter::YEAR>(data.years(), value)
+ year_machine_filter(char const *value, emu_file *file, unsigned indent)
+ : choice_filter_impl_base<machine_filter, machine_filter::YEAR>(c_year::ui, value)
{
}
@@ -781,10 +778,7 @@ template <template <machine_filter::type T> class Base, machine_filter::type Typ
class inverted_machine_filter : public Base<Type>
{
public:
- inverted_machine_filter(machine_filter_data const &data, char const *value, emu_file *file, unsigned indent)
- : Base<Type>(data, value, file, indent)
- {
- }
+ inverted_machine_filter(char const *value, emu_file *file, unsigned indent) : Base<Type>(value, file, indent) { }
virtual bool apply(ui_system_info const &system) const override { return !Base<Type>::apply(system); }
};
@@ -817,7 +811,7 @@ template <machine_filter::type Type>
class inclusive_machine_filter_impl : public simple_filter_impl_base<machine_filter, Type>
{
public:
- inclusive_machine_filter_impl(machine_filter_data const &data, char const *value, emu_file *file, unsigned indent) { }
+ inclusive_machine_filter_impl(char const *value, emu_file *file, unsigned indent) { }
virtual bool apply(ui_system_info const &system) const override { return true; }
};
@@ -834,7 +828,7 @@ using favorite_machine_filter = inclusive_machine_filter_impl<machine_filt
class category_machine_filter : public simple_filter_impl_base<machine_filter, machine_filter::CATEGORY>
{
public:
- category_machine_filter(machine_filter_data const &data, char const *value, emu_file *file, unsigned indent)
+ category_machine_filter(char const *value, emu_file *file, unsigned indent)
: m_ini(0)
, m_group(0)
, m_include_clones(false)
@@ -1167,15 +1161,14 @@ void category_machine_filter::menu_configure::handle()
class custom_machine_filter : public composite_filter_impl_base<custom_machine_filter, machine_filter, machine_filter::CUSTOM>
{
public:
- custom_machine_filter(machine_filter_data const &data, char const *value, emu_file *file, unsigned indent)
+ custom_machine_filter(char const *value, emu_file *file, unsigned indent)
: composite_filter_impl_base<custom_machine_filter, machine_filter, machine_filter::CUSTOM>()
- , m_data(data)
{
populate(value, file, indent);
}
- ptr create(type n) const { return machine_filter::create(n, m_data); }
- ptr create(emu_file &file, unsigned indent) const { return machine_filter::create(file, m_data, 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)
{
@@ -1219,9 +1212,6 @@ public:
{
return (CATEGORY == n) || (MANUFACTURER == n) || (YEAR == n);
}
-
-private:
- machine_filter_data const &m_data;
};
@@ -1257,21 +1247,6 @@ public:
};
-class favorite_software_filter : public simple_filter_impl_base<software_filter, software_filter::FAVORITE>
-{
-public:
- favorite_software_filter(software_filter_data const &data, char const *value, emu_file *file, unsigned indent)
- : m_manager(mame_machine_manager::instance()->favorite())
- {
- }
-
- virtual bool apply(ui_software_info const &info) const override { return m_manager.is_favorite_software(info); }
-
-private:
- favorite_manager const &m_manager;
-};
-
-
class parents_software_filter : public simple_filter_impl_base<software_filter, software_filter::PARENTS>
{
public:
@@ -1439,7 +1414,6 @@ public:
case UNSUPPORTED: return (SUPPORTED == m) || (PARTIAL_SUPPORTED == m);
case ALL:
- case FAVORITE:
case YEAR:
case PUBLISHERS:
case REGION:
@@ -1466,100 +1440,20 @@ private:
//-------------------------------------------------
-// static data for machine filters
-//-------------------------------------------------
-
-void machine_filter_data::add_manufacturer(std::string const &manufacturer)
-{
- std::string name(extract_manufacturer(manufacturer));
- std::vector<std::string>::iterator const pos(std::lower_bound(m_manufacturers.begin(), m_manufacturers.end(), name));
- if ((m_manufacturers.end() == pos) || (*pos != name))
- m_manufacturers.emplace(pos, std::move(name));
-}
-
-void machine_filter_data::add_year(std::string const &year)
-{
- std::vector<std::string>::iterator const pos(std::lower_bound(m_years.begin(), m_years.end(), year));
- if ((m_years.end() == pos) || (*pos != year))
- m_years.emplace(pos, year);
-}
-
-void machine_filter_data::finalise()
-{
- std::stable_sort(m_manufacturers.begin(), m_manufacturers.end());
- std::stable_sort(m_years.begin(), m_years.end());
-}
-
-std::string machine_filter_data::extract_manufacturer(std::string const &manufacturer)
-{
- size_t const found(manufacturer.find('('));
- if ((found != std::string::npos) && (found > 0))
- return manufacturer.substr(0, found - 1);
- else
- return manufacturer;
-}
-
-void machine_filter_data::set_filter(machine_filter::ptr &&filter)
-{
- m_filters[filter->get_type()] = std::move(filter);
-}
-
-machine_filter &machine_filter_data::get_filter(machine_filter::type type)
-{
- auto it(m_filters.find(type));
- if (m_filters.end() == it)
- it = m_filters.emplace(type, machine_filter::create(type, *this)).first;
-
- assert(it->second);
- return *it->second;
-}
-
-std::string machine_filter_data::get_config_string() const
-{
- auto const active_filter(m_filters.find(m_current_filter));
- if (m_filters.end() != active_filter)
- {
- char const *const val(active_filter->second->filter_text());
- return val ? util::string_format("%s,%s", active_filter->second->config_name(), val) : active_filter->second->config_name();
- }
- else
- {
- return machine_filter::config_name(m_current_filter);
- }
-}
-
-bool machine_filter_data::load_ini(emu_file &file)
-{
- machine_filter::ptr flt(machine_filter::create(file, *this));
- if (flt)
- {
- // TODO: it should possibly replace an existing item here, but it may be relying on that not happening because it never clears the first start flag
- m_current_filter = flt->get_type();
- m_filters.emplace(m_current_filter, std::move(flt));
- return true;
- }
- else
- {
- return false;
- }
-}
-
-
-//-------------------------------------------------
// static data for software filters
//-------------------------------------------------
-void software_filter_data::add_region(std::string const &longname)
+void software_filter_data::add_region(std::string const &str)
{
- std::string name(extract_region(longname));
+ std::string name(extract_region(str));
std::vector<std::string>::iterator const pos(std::lower_bound(m_regions.begin(), m_regions.end(), name));
- if ((m_regions.end() == pos) || (*pos != name))
+ if ((m_regions.end() == pos) || (*pos != str))
m_regions.emplace(pos, std::move(name));
}
-void software_filter_data::add_publisher(std::string const &publisher)
+void software_filter_data::add_publisher(std::string const &str)
{
- std::string name(extract_publisher(publisher));
+ std::string name(extract_publisher(str));
std::vector<std::string>::iterator const pos(std::lower_bound(m_publishers.begin(), m_publishers.end(), name));
if ((m_publishers.end() == pos) || (*pos != name))
m_publishers.emplace(pos, std::move(name));
@@ -1624,62 +1518,62 @@ std::string software_filter_data::extract_publisher(std::string const &publisher
// public machine filter interface
//-------------------------------------------------
-machine_filter::ptr machine_filter::create(type n, machine_filter_data const &data, char const *value, emu_file *file, unsigned indent)
+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>(data, value, file, indent);
+ return std::make_unique<all_machine_filter>(value, file, indent);
case AVAILABLE:
- return std::make_unique<available_machine_filter>(data, value, file, indent);
+ return std::make_unique<available_machine_filter>(value, file, indent);
case UNAVAILABLE:
- return std::make_unique<unavailable_machine_filter>(data, value, file, indent);
+ return std::make_unique<unavailable_machine_filter>(value, file, indent);
case WORKING:
- return std::make_unique<working_machine_filter>(data, value, file, indent);
+ return std::make_unique<working_machine_filter>(value, file, indent);
case NOT_WORKING:
- return std::make_unique<not_working_machine_filter>(data, value, file, indent);
+ return std::make_unique<not_working_machine_filter>(value, file, indent);
case MECHANICAL:
- return std::make_unique<mechanical_machine_filter>(data, value, file, indent);
+ return std::make_unique<mechanical_machine_filter>(value, file, indent);
case NOT_MECHANICAL:
- return std::make_unique<not_mechanical_machine_filter>(data, value, file, indent);
+ return std::make_unique<not_mechanical_machine_filter>(value, file, indent);
case CATEGORY:
- return std::make_unique<category_machine_filter>(data, value, file, indent);
+ return std::make_unique<category_machine_filter>(value, file, indent);
case FAVORITE:
- return std::make_unique<favorite_machine_filter>(data, value, file, indent);
+ return std::make_unique<favorite_machine_filter>(value, file, indent);
case BIOS:
- return std::make_unique<bios_machine_filter>(data, value, file, indent);
+ return std::make_unique<bios_machine_filter>(value, file, indent);
case NOT_BIOS:
- return std::make_unique<not_bios_machine_filter>(data, value, file, indent);
+ return std::make_unique<not_bios_machine_filter>(value, file, indent);
case PARENTS:
- return std::make_unique<parents_machine_filter>(data, value, file, indent);
+ return std::make_unique<parents_machine_filter>(value, file, indent);
case CLONES:
- return std::make_unique<clones_machine_filter>(data, value, file, indent);
+ return std::make_unique<clones_machine_filter>(value, file, indent);
case MANUFACTURER:
- return std::make_unique<manufacturer_machine_filter>(data, value, file, indent);
+ return std::make_unique<manufacturer_machine_filter>(value, file, indent);
case YEAR:
- return std::make_unique<year_machine_filter>(data, value, file, indent);
+ return std::make_unique<year_machine_filter>(value, file, indent);
case SAVE:
- return std::make_unique<save_machine_filter>(data, value, file, indent);
+ return std::make_unique<save_machine_filter>(value, file, indent);
case NOSAVE:
- return std::make_unique<nosave_machine_filter>(data, value, file, indent);
+ return std::make_unique<nosave_machine_filter>(value, file, indent);
case CHD:
- return std::make_unique<chd_machine_filter>(data, value, file, indent);
+ return std::make_unique<chd_machine_filter>(value, file, indent);
case NOCHD:
- return std::make_unique<nochd_machine_filter>(data, value, file, indent);
+ return std::make_unique<nochd_machine_filter>(value, file, indent);
case VERTICAL:
- return std::make_unique<vertical_machine_filter>(data, value, file, indent);
+ return std::make_unique<vertical_machine_filter>(value, file, indent);
case HORIZONTAL:
- return std::make_unique<horizontal_machine_filter>(data, value, file, indent);
+ return std::make_unique<horizontal_machine_filter>(value, file, indent);
case CUSTOM:
- return std::make_unique<custom_machine_filter>(data, value, file, indent);
+ 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, machine_filter_data const &data, unsigned indent)
+machine_filter::ptr machine_filter::create(emu_file &file, unsigned indent)
{
char buffer[MAX_CHAR_INFO];
if (!file.gets(buffer, ARRAY_LENGTH(buffer)))
@@ -1704,7 +1598,7 @@ machine_filter::ptr machine_filter::create(emu_file &file, machine_filter_data c
for (type n = FIRST; COUNT > n; ++n)
{
if (key == config_name(n))
- return create(n, data, value.c_str(), &file, indent);
+ return create(n, value.c_str(), &file, indent);
}
return nullptr;
}
@@ -1757,8 +1651,6 @@ software_filter::ptr software_filter::create(type n, software_filter_data const
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 FAVORITE:
- return std::make_unique<favorite_software_filter>(data, value, file, indent);
case PARENTS:
return std::make_unique<parents_software_filter>(data, value, file, indent);
case CLONES:
@@ -1823,16 +1715,31 @@ software_filter::ptr software_filter::create(emu_file &file, software_filter_dat
extern const char UI_VERSION_TAG[];
const char UI_VERSION_TAG[] = "# UI INFO ";
+// Years index
+std::vector<std::string> c_year::ui;
+
+// Manufacturers index
+std::vector<std::string> c_mnfct::ui;
+
+// 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;
+uint8_t ui_globals::curimage_view = 0;
uint8_t ui_globals::curdats_view = 0;
uint8_t ui_globals::cur_sw_dats_total = 0;
uint8_t ui_globals::curdats_total = 0;
uint8_t ui_globals::cur_sw_dats_view = 0;
+bool ui_globals::switch_image = false;
+bool ui_globals::default_image = true;
bool ui_globals::reset = false;
+bool ui_globals::redraw_icon = false;
int ui_globals::visible_main_lines = 0;
int ui_globals::visible_sw_lines = 0;
uint16_t ui_globals::panels_status = 0;
+bool ui_globals::has_icons = false;
char* chartrimcarriage(char str[])
{
@@ -1875,6 +1782,72 @@ std::vector<std::string> tokenize(const std::string &text, char sep)
return tokens;
}
+//-------------------------------------------------
+// search a substring with even partial matching
+//-------------------------------------------------
+
+int fuzzy_substring(std::string s_needle, std::string s_haystack)
+{
+ if (s_needle.empty())
+ return s_haystack.size();
+ if (s_haystack.empty())
+ return s_needle.size();
+
+ strmakelower(s_needle);
+ strmakelower(s_haystack);
+
+ if (s_needle == s_haystack)
+ return 0;
+ if (s_haystack.find(s_needle) != std::string::npos)
+ return 0;
+
+ auto *row1 = global_alloc_array_clear<int>(s_haystack.size() + 2);
+ auto *row2 = global_alloc_array_clear<int>(s_haystack.size() + 2);
+
+ for (int i = 0; i < s_needle.size(); ++i)
+ {
+ row2[0] = i + 1;
+ for (int j = 0; j < s_haystack.size(); ++j)
+ {
+ int cost = (s_needle[i] == s_haystack[j]) ? 0 : 1;
+ row2[j + 1] = std::min(row1[j + 1] + 1, std::min(row2[j] + 1, row1[j] + cost));
+ }
+
+ int *tmp = row1;
+ row1 = row2;
+ row2 = tmp;
+ }
+
+ int *first, *smallest;
+ first = smallest = row1;
+ int *last = row1 + s_haystack.size();
+
+ while (++first != last)
+ if (*first < *smallest)
+ smallest = first;
+
+ int rv = *smallest;
+ global_free_array(row1);
+ global_free_array(row2);
+
+ return rv;
+}
+
+//-------------------------------------------------
+// set manufacturers
+//-------------------------------------------------
+
+std::string c_mnfct::getname(const char *str)
+{
+ std::string name(str);
+ size_t found = name.find("(");
+
+ if (found != std::string::npos)
+ return (name.substr(0, found - 1));
+ else
+ return 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 e6f2acd6bc8..aaedd75854e 100644
--- a/src/frontend/mame/ui/utils.h
+++ b/src/frontend/mame/ui/utils.h
@@ -31,15 +31,10 @@ class render_container;
struct ui_system_info
{
ui_system_info() { }
- ui_system_info(game_driver const &d, int i, bool a) : driver(&d), index(i), available(a) { }
+ ui_system_info(game_driver const &d, bool a) : driver(&d), available(a) { }
game_driver const *driver = nullptr;
- int index;
bool available = false;
-
- std::u32string ucs_shortname;
- std::u32string ucs_description;
- std::u32string ucs_manufacturer_description;
};
struct ui_software_info
@@ -95,8 +90,35 @@ struct ui_software_info
namespace ui {
-class machine_filter_data;
-class software_filter_data;
+class software_filter_data
+{
+public:
+ std::vector<std::string> const &regions() const { return m_regions; }
+ std::vector<std::string> const &publishers() const { return m_publishers; }
+ std::vector<std::string> const &years() const { return m_years; }
+ std::vector<std::string> const &device_types() const { return m_device_types; }
+ std::vector<std::string> const &list_names() const { return m_list_names; }
+ std::vector<std::string> const &list_descriptions() const { return m_list_descriptions; }
+
+ // adding entries
+ void add_region(std::string const &longname);
+ void add_publisher(std::string const &publisher);
+ void add_year(std::string const &year);
+ void add_device_type(std::string const &device_type);
+ void add_list(std::string const &name, std::string const &description);
+ void finalise();
+
+ // use heuristics to extract meaningful parts from software list fields
+ static std::string extract_region(std::string const &longname);
+ static std::string extract_publisher(std::string const &publisher);
+
+private:
+ std::vector<std::string> m_regions;
+ std::vector<std::string> m_publishers;
+ std::vector<std::string> m_years;
+ std::vector<std::string> m_device_types;
+ std::vector<std::string> m_list_names, m_list_descriptions;
+};
template <class Impl, typename Entry>
@@ -174,8 +196,8 @@ public:
virtual type get_type() const = 0;
virtual std::string adorned_display_name(type n) const = 0;
- static ptr create(type n, machine_filter_data const &data) { return create(n, data, nullptr, nullptr, 0); }
- static ptr create(emu_file &file, machine_filter_data const &data) { return create(file, data, 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);
@@ -185,8 +207,8 @@ public:
protected:
machine_filter();
- static ptr create(type n, machine_filter_data const &data, char const *value, emu_file *file, unsigned indent);
- static ptr create(emu_file &file, machine_filter_data const &data, unsigned indent);
+ 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)
@@ -200,7 +222,6 @@ public:
ALL = 0,
AVAILABLE,
UNAVAILABLE,
- FAVORITE,
PARENTS,
CLONES,
YEAR,
@@ -238,82 +259,32 @@ protected:
DECLARE_ENUM_INCDEC_OPERATORS(software_filter::type)
+} // namespace ui
-class machine_filter_data
-{
-public:
- std::vector<std::string> const &manufacturers() const { return m_manufacturers; }
- std::vector<std::string> const &years() const { return m_years; }
-
- // adding entries
- void add_manufacturer(std::string const &manufacturer);
- void add_year(std::string const &year);
- void finalise();
-
- // use heuristics to extract meaningful parts from machine metadata
- static std::string extract_manufacturer(std::string const &manufacturer);
-
- // the selected filter
- machine_filter::type get_current_filter_type() const { return m_current_filter; }
- void set_current_filter_type(machine_filter::type type) { m_current_filter = type; }
-
- // managing current filters
- void set_filter(machine_filter::ptr &&filter);
- auto const &get_filters() { return m_filters; }
- machine_filter &get_filter(machine_filter::type type);
- machine_filter *get_current_filter()
- {
- auto const it(m_filters.find(m_current_filter));
- return (m_filters.end() != it) ? it->second.get() : nullptr;
- }
- std::string get_config_string() const;
- bool load_ini(emu_file &file);
-
-private:
- using filter_map = std::map<machine_filter::type, machine_filter::ptr>;
-
- std::vector<std::string> m_manufacturers;
- std::vector<std::string> m_years;
-
- machine_filter::type m_current_filter = machine_filter::ALL;
- filter_map m_filters;
-};
-
+#define MAX_CHAR_INFO 256
-class software_filter_data
+enum
{
-public:
- std::vector<std::string> const &regions() const { return m_regions; }
- std::vector<std::string> const &publishers() const { return m_publishers; }
- std::vector<std::string> const &years() const { return m_years; }
- std::vector<std::string> const &device_types() const { return m_device_types; }
- std::vector<std::string> const &list_names() const { return m_list_names; }
- std::vector<std::string> const &list_descriptions() const { return m_list_descriptions; }
-
- // adding entries
- void add_region(std::string const &longname);
- void add_publisher(std::string const &publisher);
- void add_year(std::string const &year);
- void add_device_type(std::string const &device_type);
- void add_list(std::string const &name, std::string const &description);
- void finalise();
-
- // use heuristics to extract meaningful parts from software list fields
- static std::string extract_region(std::string const &longname);
- static std::string extract_publisher(std::string const &publisher);
-
-private:
- std::vector<std::string> m_regions;
- std::vector<std::string> m_publishers;
- std::vector<std::string> m_years;
- std::vector<std::string> m_device_types;
- std::vector<std::string> m_list_names, m_list_descriptions;
+ FIRST_VIEW = 0,
+ SNAPSHOT_VIEW = FIRST_VIEW,
+ CABINETS_VIEW,
+ CPANELS_VIEW,
+ PCBS_VIEW,
+ FLYERS_VIEW,
+ TITLES_VIEW,
+ ENDS_VIEW,
+ ARTPREV_VIEW,
+ BOSSES_VIEW,
+ LOGOS_VIEW,
+ VERSUS_VIEW,
+ GAMEOVER_VIEW,
+ HOWTO_VIEW,
+ SCORES_VIEW,
+ SELECT_VIEW,
+ MARQUEES_VIEW,
+ LAST_VIEW = MARQUEES_VIEW
};
-} // namespace ui
-
-#define MAX_CHAR_INFO 256
-
enum
{
RP_FIRST = 0,
@@ -355,13 +326,34 @@ enum
// GLOBAL CLASS
struct ui_globals
{
- static uint8_t curdats_view, curdats_total, cur_sw_dats_view, cur_sw_dats_total, rpanel;
- static bool default_image, reset;
+ 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 uint16_t panels_status;
+ static bool has_icons;
+};
+
+// Manufacturers
+struct c_mnfct
+{
+ static std::string getname(const char *str);
+ static std::vector<std::string> ui;
+};
+
+// Years
+struct c_year
+{
+ static std::vector<std::string> ui;
+};
+
+struct main_filters
+{
+ static ui::machine_filter::type actual;
+ static std::map<ui::machine_filter::type, ui::machine_filter::ptr> filters;
};
// GLOBAL FUNCTIONS
+int fuzzy_substring(std::string needle, std::string haystack);
char* chartrimcarriage(char str[]);
const char* strensure(const char* s);
int getprecisionchr(const char* s);
diff --git a/src/frontend/mame/ui/videoopt.cpp b/src/frontend/mame/ui/videoopt.cpp
index 6cf0076734b..7ee243ec4e2 100644
--- a/src/frontend/mame/ui/videoopt.cpp
+++ b/src/frontend/mame/ui/videoopt.cpp
@@ -75,7 +75,7 @@ void menu_video_options::handle()
const event *menu_event = process(0);
if (menu_event != nullptr && menu_event->itemref != nullptr)
{
- switch ((intptr_t)menu_event->itemref)
+ switch ((uintptr_t)menu_event->itemref)
{
/* rotate adds rotation depending on the direction */
case VIDEO_ITEM_ROTATE:
diff --git a/src/frontend/mame/ui/widgets.cpp b/src/frontend/mame/ui/widgets.cpp
index d8907303b36..cc2c276abfc 100644
--- a/src/frontend/mame/ui/widgets.cpp
+++ b/src/frontend/mame/ui/widgets.cpp
@@ -14,7 +14,6 @@
namespace ui {
-
/***************************************************************************
WIDGETS
***************************************************************************/
@@ -25,12 +24,12 @@ namespace ui {
widgets_manager::widgets_manager(running_machine &machine)
: m_hilight_bitmap(std::make_unique<bitmap_argb32>(256, 1))
- , m_hilight_texture(nullptr, machine.render())
+ , m_hilight_texture()
, m_hilight_main_bitmap(std::make_unique<bitmap_argb32>(1, 128))
- , m_hilight_main_texture(nullptr, machine.render())
- , m_arrow_texture(nullptr, machine.render())
+ , m_hilight_main_texture()
{
render_manager &render(machine.render());
+ auto const texture_free([&render](render_texture *texture) { render.texture_free(texture); });
// create a texture for hilighting items
for (unsigned x = 0; x < 256; ++x)
@@ -38,7 +37,7 @@ widgets_manager::widgets_manager(running_machine &machine)
unsigned const alpha((x < 25) ? (0xff * x / 25) : (x >(256 - 25)) ? (0xff * (255 - x) / 25) : 0xff);
m_hilight_bitmap->pix32(0, x) = rgb_t(alpha, 0xff, 0xff, 0xff);
}
- m_hilight_texture.reset(render.texture_alloc());
+ m_hilight_texture = texture_ptr(render.texture_alloc(), texture_free);
m_hilight_texture->set_bitmap(*m_hilight_bitmap, m_hilight_bitmap->cliprect(), TEXFORMAT_ARGB32);
// create a texture for hilighting items in main menu
@@ -51,11 +50,11 @@ widgets_manager::widgets_manager(running_machine &machine)
unsigned const b = b1 + (y * (b2 - b1) / 128);
m_hilight_main_bitmap->pix32(y, 0) = rgb_t(r, g, b);
}
- m_hilight_main_texture.reset(render.texture_alloc());
+ m_hilight_main_texture = texture_ptr(render.texture_alloc(), texture_free);
m_hilight_main_texture->set_bitmap(*m_hilight_main_bitmap, m_hilight_main_bitmap->cliprect(), TEXFORMAT_ARGB32);
// create a texture for arrow icons
- m_arrow_texture.reset(render.texture_alloc(render_triangle));
+ m_arrow_texture = texture_ptr(render.texture_alloc(render_triangle), texture_free);
}
diff --git a/src/frontend/mame/ui/widgets.h b/src/frontend/mame/ui/widgets.h
index 567b0a4e499..45f1725d7ec 100644
--- a/src/frontend/mame/ui/widgets.h
+++ b/src/frontend/mame/ui/widgets.h
@@ -21,7 +21,6 @@
namespace ui {
-
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
@@ -35,17 +34,8 @@ public:
render_texture *hilight_main_texture() { return m_hilight_main_texture.get(); }
render_texture *arrow_texture() { return m_arrow_texture.get(); }
- class texture_destroyer
- {
- public:
- texture_destroyer(render_manager &manager) : m_manager(manager) { }
- void operator()(render_texture *texture) const { m_manager.get().texture_free(texture); }
- private:
- std::reference_wrapper<render_manager> m_manager;
- };
-
using bitmap_ptr = std::unique_ptr<bitmap_argb32>;
- using texture_ptr = std::unique_ptr<render_texture, texture_destroyer>;
+ using texture_ptr = std::unique_ptr<render_texture, std::function<void(render_texture *)> >;
private:
static void render_triangle(bitmap_argb32 &dest, bitmap_argb32 &source, const rectangle &sbounds, void *param);