summaryrefslogtreecommitdiffstatshomepage
path: root/src/frontend
diff options
context:
space:
mode:
author Vas Crabb <cuavas@users.noreply.github.com>2021-10-09 12:16:17 +1100
committer GitHub <noreply@github.com>2021-10-09 12:16:17 +1100
commit38082ccbee749d650ccea886ae376a5d1dec337c (patch)
tree9ba9a900ba826bda58832834278025ced17f42f5 /src/frontend
parent34b3bf701098082feb9077db49987507962c1578 (diff)
Overdue internal UI enhancements (#8674)
* frontend: Added support for message context to localisations. * frontend: Added string_view versions of the message lookup functions. * frontend: Added a few more folder options to the internal UI. * emu/softlist.cpp: Use more appropriate containers. * Switched to Python 3 by default - this will become a requirement. * Updated msgfmt.py for message context support. * frontend: Show all software item info in the internal UI. * frontend: Search alternate titles in software selection menu. * 3rdparty/utf8proc: Updated to v2.6.1 (has several fixes). * frontend: Added software filters for common info fields. * frontend: Allow UI manager to hold onto persistent session data. * frontend: Cache software lists for eight machines. * frontend: Added support for loading localised system names. * frontend: Add UI for selecting localised system names.
Diffstat (limited to 'src/frontend')
-rw-r--r--src/frontend/mame/clifront.cpp7
-rw-r--r--src/frontend/mame/language.cpp115
-rw-r--r--src/frontend/mame/language.h19
-rw-r--r--src/frontend/mame/luaengine.cpp4
-rw-r--r--src/frontend/mame/ui/auditmenu.cpp48
-rw-r--r--src/frontend/mame/ui/auditmenu.h2
-rw-r--r--src/frontend/mame/ui/custui.cpp213
-rw-r--r--src/frontend/mame/ui/custui.h10
-rw-r--r--src/frontend/mame/ui/datmenu.cpp8
-rw-r--r--src/frontend/mame/ui/dirmenu.cpp68
-rw-r--r--src/frontend/mame/ui/info.cpp46
-rw-r--r--src/frontend/mame/ui/inifile.cpp75
-rw-r--r--src/frontend/mame/ui/menu.cpp10
-rw-r--r--src/frontend/mame/ui/menu.h8
-rw-r--r--src/frontend/mame/ui/miscmenu.cpp25
-rw-r--r--src/frontend/mame/ui/miscmenu.h18
-rw-r--r--src/frontend/mame/ui/moptions.cpp3
-rw-r--r--src/frontend/mame/ui/moptions.h2
-rw-r--r--src/frontend/mame/ui/selgame.cpp404
-rw-r--r--src/frontend/mame/ui/selgame.h5
-rw-r--r--src/frontend/mame/ui/selmenu.cpp183
-rw-r--r--src/frontend/mame/ui/selmenu.h30
-rw-r--r--src/frontend/mame/ui/selsoft.cpp654
-rw-r--r--src/frontend/mame/ui/selsoft.h40
-rw-r--r--src/frontend/mame/ui/submenu.cpp166
-rw-r--r--src/frontend/mame/ui/ui.cpp3
-rw-r--r--src/frontend/mame/ui/ui.h24
-rw-r--r--src/frontend/mame/ui/utils.cpp379
-rw-r--r--src/frontend/mame/ui/utils.h43
29 files changed, 1642 insertions, 970 deletions
diff --git a/src/frontend/mame/clifront.cpp b/src/frontend/mame/clifront.cpp
index bc78cb1112c..191ae747a4c 100644
--- a/src/frontend/mame/clifront.cpp
+++ b/src/frontend/mame/clifront.cpp
@@ -1136,9 +1136,12 @@ void cli_frontend::output_single_softlist(std::ostream &out, software_list_devic
if (!swinfo.notes().empty())
util::stream_format(out, "\t\t\t<notes>%s</notes>\n", util::xml::normalize_string(swinfo.notes().c_str()));
- for (const feature_list_item &flist : swinfo.other_info())
+ for (const auto &flist : swinfo.info())
util::stream_format(out, "\t\t\t<info name=\"%s\" value=\"%s\"/>\n", flist.name(), util::xml::normalize_string(flist.value().c_str()));
+ for (const auto &flist : swinfo.shared_features())
+ util::stream_format(out, "\t\t\t<sharedfeat name=\"%s\" value=\"%s\"/>\n", flist.name(), util::xml::normalize_string(flist.value().c_str()));
+
for (const software_part &part : swinfo.parts())
{
util::stream_format(out, "\t\t\t<part name=\"%s\"", util::xml::normalize_string(part.name().c_str()));
@@ -1147,7 +1150,7 @@ void cli_frontend::output_single_softlist(std::ostream &out, software_list_devic
out << ">\n";
- for (const feature_list_item &flist : part.featurelist())
+ for (const auto &flist : part.features())
util::stream_format(out, "\t\t\t\t<feature name=\"%s\" value=\"%s\" />\n", flist.name(), util::xml::normalize_string(flist.value().c_str()));
// TODO: display ROM region information
diff --git a/src/frontend/mame/language.cpp b/src/frontend/mame/language.cpp
index eae75b3fd6f..4ecdc2aba0c 100644
--- a/src/frontend/mame/language.cpp
+++ b/src/frontend/mame/language.cpp
@@ -9,6 +9,8 @@
***************************************************************************/
#include "emu.h"
+#include "language.h"
+
#include "emuopts.h"
#include "corestr.h"
@@ -17,46 +19,20 @@
#include <memory>
#include <new>
#include <unordered_map>
+#include <utility>
namespace {
-constexpr uint32_t MO_MAGIC = 0x950412de;
-constexpr uint32_t MO_MAGIC_REVERSED = 0xde120495;
-
-struct cstr_hash
-{
- size_t operator()(char const *s) const noexcept
- {
- // Bernstein string hash
- size_t result(5381);
- while (*s)
- result = ((result << 5) + result) + u8(*s++);
- return result;
- }
-};
-
-struct cstr_compare
-{
- size_t operator()(char const *x, char const *y) const noexcept
- {
- return !std::strcmp(x, y);
- }
-};
+constexpr u32 MO_MAGIC = 0x950412de;
+constexpr u32 MO_MAGIC_REVERSED = 0xde120495;
std::unique_ptr<u32 []> f_translation_data;
-std::unordered_map<char const *, char const *, cstr_hash, cstr_compare> f_translation_map;
+std::unordered_map<std::string_view, std::pair<char const *, u32> > f_translation_map;
} // anonymous namespace
-char const *lang_translate(char const *word)
-{
- auto const found = f_translation_map.find(word);
- return (f_translation_map.end() != found) ? found->second : word;
-}
-
-
void load_translation(emu_options &m_options)
{
f_translation_data.reset();
@@ -84,7 +60,7 @@ void load_translation(emu_options &m_options)
return;
}
- f_translation_data.reset(new (std::nothrow) uint32_t [(size + 3) / 4]);
+ f_translation_data.reset(new (std::nothrow) u32 [(size + 3) / 4]);
if (!f_translation_data)
{
file.close();
@@ -169,12 +145,81 @@ void load_translation(emu_options &m_options)
continue;
}
- char const *const original = &data[original_offset];
- char const *const translation = &data[translation_offset];
- auto const ins = f_translation_map.emplace(original, translation);
+ std::string_view const original(&data[original_offset], original_length);
+ char const *const translation(&data[translation_offset]);
+ auto const ins = f_translation_map.emplace(original, std::make_pair(translation, translation_length));
if (!ins.second)
- osd_printf_warning("Loading translation file %s: translation %u '%s'='%s' conflicts with previous translation '%s'='%s'\n", name, i, original, translation, ins.first->first, ins.first->second);
+ {
+ osd_printf_warning(
+ "Loading translation file %s: translation %u '%s'='%s' conflicts with previous translation '%s'='%s'\n",
+ name,
+ i,
+ original,
+ translation,
+ ins.first->first,
+ ins.first->second.first);
+ }
}
osd_printf_verbose("Loaded %u translations from file %s\n", f_translation_map.size(), name);
}
+
+
+char const *lang_translate(char const *message)
+{
+ auto const found = f_translation_map.find(message);
+ if (f_translation_map.end() != found)
+ return found->second.first;
+ return message;
+}
+
+
+std::string_view lang_translate(std::string_view message)
+{
+ auto const found = f_translation_map.find(message);
+ if (f_translation_map.end() != found)
+ return std::string_view(found->second.first, found->second.second);
+ return message;
+}
+
+
+char const *lang_translate(char const *context, char const *message)
+{
+ if (!f_translation_map.empty())
+ {
+ auto const ctxlen(std::strlen(context));
+ auto const msglen(std::strlen(message));
+ std::string key;
+ key.reserve(ctxlen + 1 + msglen);
+ key.append(context, ctxlen);
+ key.append(1, '\004');
+ key.append(message, msglen);
+ auto const found = f_translation_map.find(key);
+ if (f_translation_map.end() != found)
+ return found->second.first;
+ }
+ return message;
+}
+
+
+std::string_view lang_translate(char const *context, std::string_view message)
+{
+ return lang_translate(std::string_view(context), message);
+}
+
+
+std::string_view lang_translate(std::string_view context, std::string_view message)
+{
+ if (!f_translation_map.empty())
+ {
+ std::string key;
+ key.reserve(context.length() + 1 + message.length());
+ key.append(context);
+ key.append(1, '\004');
+ key.append(message);
+ auto const found = f_translation_map.find(key);
+ if (f_translation_map.end() != found)
+ return std::string_view(found->second.first, found->second.second);
+ }
+ return message;
+}
diff --git a/src/frontend/mame/language.h b/src/frontend/mame/language.h
index d688b2ba93a..93e3c491382 100644
--- a/src/frontend/mame/language.h
+++ b/src/frontend/mame/language.h
@@ -12,16 +12,25 @@
#pragma once
+#include <string_view>
+
+
//**************************************************************************
// LOCALIZATION SUPPORT
//**************************************************************************
-#define _(param) lang_translate(param)
-// Fake one to make possible using it in static text definitions, on those
-// lang_translate must be called afterwards
-#define __(param) param
+#define _(...) lang_translate(__VA_ARGS__)
+
+#define N_(msg) (msg)
+#define N_p(ctx, msg) (msg)
void load_translation(emu_options &option);
-const char *lang_translate(const char *word);
+
+char const *lang_translate(char const *message);
+std::string_view lang_translate(std::string_view message);
+
+char const *lang_translate(char const *context, char const *message);
+std::string_view lang_translate(char const *context, std::string_view message);
+std::string_view lang_translate(std::string_view context, std::string_view message);
#endif // MAME_FRONTEND_MAME_LANGUAGE_H
diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp
index 54fdd78b01c..78521783541 100644
--- a/src/frontend/mame/luaengine.cpp
+++ b/src/frontend/mame/luaengine.cpp
@@ -761,7 +761,9 @@ void lua_engine::initialize()
engine->machine().scheduler().timer_set(attotime::from_double(lua_tonumber(L, 1)), timer_expired_delegate(FUNC(lua_engine::resume), engine), ref, nullptr);
return lua_yield(L, 0);
});
- emu["lang_translate"] = &lang_translate;
+ emu["lang_translate"] = sol::overload(
+ static_cast<char const *(*)(char const *)>(&lang_translate),
+ static_cast<char const *(*)(char const *, char const *)>(&lang_translate));
emu["pid"] = &osd_getpid;
emu["subst_env"] =
[] (const std::string &str)
diff --git a/src/frontend/mame/ui/auditmenu.cpp b/src/frontend/mame/ui/auditmenu.cpp
index 66c1aab0597..6da405b3698 100644
--- a/src/frontend/mame/ui/auditmenu.cpp
+++ b/src/frontend/mame/ui/auditmenu.cpp
@@ -31,54 +31,6 @@ void *const ITEMREF_START = reinterpret_cast<void *>(std::uintptr_t(1));
} // anonymous namespace
-bool sorted_game_list(const game_driver *x, const game_driver *y)
-{
- bool clonex = (x->parent[0] != '0') || x->parent[1];
- int cx = -1;
- if (clonex)
- {
- cx = driver_list::find(x->parent);
- if ((0 > cx) || (driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT))
- clonex = false;
- }
-
- bool cloney = (y->parent[0] != '0') || y->parent[1];
- int cy = -1;
- if (cloney)
- {
- cy = driver_list::find(y->parent);
- if ((0 > cy) || (driver_list::driver(cy).flags & machine_flags::IS_BIOS_ROOT))
- cloney = false;
- }
-
- if (!clonex && !cloney)
- {
- return (core_stricmp(x->type.fullname(), y->type.fullname()) < 0);
- }
- else if (clonex && cloney)
- {
- if (!core_stricmp(x->parent, y->parent))
- return (core_stricmp(x->type.fullname(), y->type.fullname()) < 0);
- else
- return (core_stricmp(driver_list::driver(cx).type.fullname(), driver_list::driver(cy).type.fullname()) < 0);
- }
- else if (!clonex && cloney)
- {
- if (!core_stricmp(x->name, y->parent))
- return true;
- else
- return (core_stricmp(x->type.fullname(), driver_list::driver(cy).type.fullname()) < 0);
- }
- else
- {
- if (!core_stricmp(x->parent, y->name))
- return false;
- else
- return (core_stricmp(driver_list::driver(cx).type.fullname(), y->type.fullname()) < 0);
- }
-}
-
-
menu_audit::menu_audit(mame_ui_manager &mui, render_container &container, std::vector<ui_system_info> &availablesorted, mode audit_mode)
: menu(mui, container)
, m_worker_thread()
diff --git a/src/frontend/mame/ui/auditmenu.h b/src/frontend/mame/ui/auditmenu.h
index 435bf52cd34..33b0c54863a 100644
--- a/src/frontend/mame/ui/auditmenu.h
+++ b/src/frontend/mame/ui/auditmenu.h
@@ -53,8 +53,6 @@ private:
phase m_phase;
};
-bool sorted_game_list(const game_driver *x, const game_driver *y);
-
} // namespace ui
#endif // MAME_FRONTEND_UI_AUDITMENU_H
diff --git a/src/frontend/mame/ui/custui.cpp b/src/frontend/mame/ui/custui.cpp
index c748bee1e7c..9b06465f9f8 100644
--- a/src/frontend/mame/ui/custui.cpp
+++ b/src/frontend/mame/ui/custui.cpp
@@ -30,10 +30,10 @@
namespace ui {
const char *const menu_custom_ui::HIDE_STATUS[] = {
- __("Show All"),
- __("Hide Filters"),
- __("Hide Info/Image"),
- __("Hide Both") };
+ N_("Show All"),
+ N_("Hide Filters"),
+ N_("Hide Info/Image"),
+ N_("Hide Both") };
//-------------------------------------------------
// ctor
@@ -43,30 +43,10 @@ menu_custom_ui::menu_custom_ui(mame_ui_manager &mui, render_container &container
: menu(mui, container)
, m_handler(std::move(handler))
, m_currlang(0)
+ , m_currsysnames(0)
{
- // load languages
- file_enumerator path(mui.machine().options().language_path());
- const char *const lang = mui.machine().options().language();
- const osd::directory::entry *dirent;
- std::string name;
- while ((dirent = path.next()))
- {
- if (dirent->type == osd::directory::entry::entry_type::DIR && strcmp(dirent->name, ".") != 0 && strcmp(dirent->name, "..") != 0)
- {
- name = dirent->name;
- auto i = strreplace(name, "_", " (");
- if (i > 0)
- name.append(")");
- m_lang.emplace_back(std::move(name));
- }
- }
- std::sort(
- m_lang.begin(),
- m_lang.end(),
- [] (const std::string &x, const std::string &y) { return 0 > core_stricmp(x.c_str(), y.c_str()); });
- const auto found = std::lower_bound(m_lang.begin(), m_lang.end(), lang, [] (std::string const &x, const char *y) { return 0 > core_stricmp(x.c_str(), y); });
- if ((m_lang.end() != found) && !core_stricmp(found->c_str(), lang))
- m_currlang = std::distance(m_lang.begin(), found);
+ find_languages();
+ find_sysnames();
}
//-------------------------------------------------
@@ -76,11 +56,12 @@ menu_custom_ui::menu_custom_ui(mame_ui_manager &mui, render_container &container
menu_custom_ui::~menu_custom_ui()
{
ui().options().set_value(OPTION_HIDE_PANELS, ui_globals::panels_status, OPTION_PRIORITY_CMDLINE);
- if (!m_lang.empty())
- {
- machine().options().set_value(OPTION_LANGUAGE, m_lang[m_currlang], OPTION_PRIORITY_CMDLINE);
- load_translation(machine().options());
- }
+
+ machine().options().set_value(OPTION_LANGUAGE, m_currlang ? m_languages[m_currlang] : "", OPTION_PRIORITY_CMDLINE);
+ load_translation(machine().options());
+
+ ui().options().set_value(OPTION_SYSTEM_NAMES, m_currsysnames ? m_sysnames[m_currsysnames] : "", OPTION_PRIORITY_CMDLINE);
+
ui_globals::reset = true;
if (m_handler)
@@ -96,7 +77,7 @@ void menu_custom_ui::handle()
bool changed = false;
// process the menu
- const event *menu_event = process(0);
+ const event *menu_event = process(PROCESS_LR_REPEAT);
if (menu_event != nullptr && menu_event->itemref != nullptr)
{
@@ -140,13 +121,16 @@ void menu_custom_ui::handle()
if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
{
changed = true;
- (menu_event->iptkey == IPT_UI_RIGHT) ? m_currlang++ : m_currlang--;
+ if (menu_event->iptkey == IPT_UI_LEFT)
+ m_currlang = (m_currlang ? m_currlang : m_languages.size())- 1;
+ else if (++m_currlang >= m_languages.size())
+ m_currlang = 0;
}
else if (menu_event->iptkey == IPT_UI_SELECT)
{
// copying list of language names - expensive
menu::stack_push<menu_selector>(
- ui(), container(), std::vector<std::string>(m_lang), m_currlang,
+ ui(), container(), std::vector<std::string>(m_languages), m_currlang,
[this] (int selection)
{
m_currlang = selection;
@@ -154,6 +138,27 @@ void menu_custom_ui::handle()
});
}
break;
+ case SYSNAMES_MENU:
+ if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
+ {
+ changed = true;
+ if (menu_event->iptkey == IPT_UI_LEFT)
+ m_currsysnames = (m_currsysnames ? m_currsysnames : m_sysnames.size())- 1;
+ else if (++m_currsysnames >= m_sysnames.size())
+ m_currsysnames = 0;
+ }
+ else if (menu_event->iptkey == IPT_UI_SELECT)
+ {
+ // copying list of file names - expensive
+ menu::stack_push<menu_selector>(
+ ui(), container(), std::vector<std::string>(m_sysnames), m_currsysnames,
+ [this] (int selection)
+ {
+ m_currsysnames = selection;
+ reset(reset_options::REMEMBER_REF);
+ });
+ }
+ break;
}
}
@@ -171,11 +176,11 @@ void menu_custom_ui::populate(float &customtop, float &custombottom)
item_append(_("Fonts"), 0, (void *)(uintptr_t)FONT_MENU);
item_append(_("Colors"), 0, (void *)(uintptr_t)COLORS_MENU);
- if (!m_lang.empty())
- {
- arrow_flags = get_arrow_flags<std::uint16_t>(0, m_lang.size() - 1, m_currlang);
- item_append(_("Language"), m_lang[m_currlang], arrow_flags, (void *)(uintptr_t)LANGUAGE_MENU);
- }
+ arrow_flags = get_arrow_flags<std::size_t>(0, m_languages.size() - 1, m_currlang);
+ item_append(_("Language"), m_languages[m_currlang], arrow_flags, (void *)(uintptr_t)LANGUAGE_MENU);
+
+ arrow_flags = get_arrow_flags<std::size_t>(0, m_sysnames.size() - 1, m_currsysnames);
+ item_append(_("System Names"), m_sysnames[m_currsysnames], arrow_flags, (void *)(uintptr_t)SYSNAMES_MENU);
arrow_flags = get_arrow_flags<uint16_t>(0, HIDE_BOTH, ui_globals::panels_status);
item_append(_("Show side panels"), _(HIDE_STATUS[ui_globals::panels_status]), arrow_flags, (void *)(uintptr_t)HIDE_MENU);
@@ -190,7 +195,7 @@ void menu_custom_ui::populate(float &customtop, float &custombottom)
void menu_custom_ui::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{
- char const *const text[] = { _("Custom UI Settings") };
+ char const *const text[] = { _("UI Customization Settings") };
draw_text_box(
std::begin(text), std::end(text),
origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(),
@@ -199,6 +204,94 @@ void menu_custom_ui::custom_render(void *selectedref, float top, float bottom, f
}
//-------------------------------------------------
+// find UI translation files
+//-------------------------------------------------
+
+void menu_custom_ui::find_languages()
+{
+ m_languages.emplace_back(_("[built-in]"));
+
+ file_enumerator path(machine().options().language_path());
+ osd::directory::entry const *dirent;
+ std::string name;
+ while ((dirent = path.next()))
+ {
+ if (dirent->type == osd::directory::entry::entry_type::DIR && strcmp(dirent->name, ".") != 0 && strcmp(dirent->name, "..") != 0)
+ {
+ name = dirent->name;
+ auto i = strreplace(name, "_", " (");
+ if (i > 0)
+ name.append(")");
+ m_languages.emplace_back(std::move(name));
+ }
+ }
+ std::sort(
+ std::next(m_languages.begin()),
+ m_languages.end(),
+ [] (std::string const &x, std::string const &y) { return 0 > core_stricmp(x.c_str(), y.c_str()); });
+
+ char const *const lang = machine().options().language();
+ if (*lang)
+ {
+ auto const found = std::lower_bound(
+ std::next(m_languages.begin()),
+ m_languages.end(),
+ lang,
+ [] (std::string const &x, char const *y) { return 0 > core_stricmp(x.c_str(), y); });
+ if ((m_languages.end() != found) && !core_stricmp(found->c_str(), lang))
+ m_currlang = std::distance(m_languages.begin(), found);
+ }
+ else
+ {
+ m_currlang = 0;
+ }
+}
+
+//-------------------------------------------------
+// find translated system names
+//-------------------------------------------------
+
+void menu_custom_ui::find_sysnames()
+{
+ m_sysnames.emplace_back(_("[built-in]"));
+
+ path_iterator search(ui().options().history_path());
+ std::string path;
+ while (search.next(path))
+ {
+ file_enumerator dir(path);
+ osd::directory::entry const *dirent;
+ while ((dirent = dir.next()))
+ {
+ if (dirent->type == osd::directory::entry::entry_type::FILE && core_filename_ends_with(dirent->name, ".lst"))
+ m_sysnames.emplace_back(dirent->name);
+ }
+ }
+ std::sort(
+ m_sysnames.begin(),
+ m_sysnames.end(),
+ [] (std::string const &x, std::string const &y) { return 0 > core_stricmp(x.c_str(), y.c_str()); });
+
+ char const *const names = ui().options().system_names();
+ if (*names)
+ {
+ auto const found = std::lower_bound(
+ std::next(m_sysnames.begin()),
+ m_sysnames.end(),
+ names,
+ [] (std::string const &x, char const *y) { return 0 > core_stricmp(x.c_str(), y); });
+ m_currsysnames = std::distance(m_sysnames.begin(), found);
+ if ((m_sysnames.end() == found) || core_stricmp(found->c_str(), names))
+ m_sysnames.emplace(found, names);
+ }
+ else
+ {
+ m_currsysnames = 0;
+ }
+}
+
+
+//-------------------------------------------------
// ctor
//-------------------------------------------------
@@ -781,34 +874,34 @@ void menu_rgb_ui::populate(float &customtop, float &custombottom)
if (m_lock_ref != RGB_ALPHA)
{
arrow_flags = get_arrow_flags<uint8_t>(0, 255, m_color->a());
- item_append(_("Alpha"), string_format("%3u", m_color->a()), arrow_flags, (void *)(uintptr_t)RGB_ALPHA);
+ item_append(_("color-channel", "Alpha"), string_format("%3u", m_color->a()), arrow_flags, (void *)(uintptr_t)RGB_ALPHA);
}
else
- item_append(_("Alpha"), s_text, 0, (void *)(uintptr_t)RGB_ALPHA);
+ item_append(_("color-channel", "Alpha"), s_text, 0, (void *)(uintptr_t)RGB_ALPHA);
if (m_lock_ref != RGB_RED)
{
arrow_flags = get_arrow_flags<uint8_t>(0, 255, m_color->r());
- item_append(_("Red"), string_format("%3u", m_color->r()), arrow_flags, (void *)(uintptr_t)RGB_RED);
+ item_append(_("color-channel", "Red"), string_format("%3u", m_color->r()), arrow_flags, (void *)(uintptr_t)RGB_RED);
}
else
- item_append(_("Red"), s_text, 0, (void *)(uintptr_t)RGB_RED);
+ item_append(_("color-channel", "Red"), s_text, 0, (void *)(uintptr_t)RGB_RED);
if (m_lock_ref != RGB_GREEN)
{
arrow_flags = get_arrow_flags<uint8_t>(0, 255, m_color->g());
- item_append(_("Green"), string_format("%3u", m_color->g()), arrow_flags, (void *)(uintptr_t)RGB_GREEN);
+ item_append(_("color-channel", "Green"), string_format("%3u", m_color->g()), arrow_flags, (void *)(uintptr_t)RGB_GREEN);
}
else
- item_append(_("Green"), s_text, 0, (void *)(uintptr_t)RGB_GREEN);
+ item_append(_("color-channel", "Green"), s_text, 0, (void *)(uintptr_t)RGB_GREEN);
if (m_lock_ref != RGB_BLUE)
{
arrow_flags = get_arrow_flags<uint8_t>(0, 255, m_color->b());
- item_append(_("Blue"), string_format("%3u", m_color->b()), arrow_flags, (void *)(uintptr_t)RGB_BLUE);
+ item_append(_("color-channel", "Blue"), string_format("%3u", m_color->b()), arrow_flags, (void *)(uintptr_t)RGB_BLUE);
}
else
- item_append(_("Blue"), s_text, 0, (void *)(uintptr_t)RGB_BLUE);
+ item_append(_("color-channel", "Blue"), s_text, 0, (void *)(uintptr_t)RGB_BLUE);
item_append(menu_item_type::SEPARATOR);
item_append(_("Choose from palette"), 0, (void *)(uintptr_t)PALETTE_CHOOSE);
@@ -931,16 +1024,16 @@ void menu_rgb_ui::inkey_special(const event *menu_event)
}
std::pair<const char *, const char *> const menu_palette_sel::s_palette[] = {
- { __("White"), "FFFFFFFF" },
- { __("Silver"), "FFC0C0C0" },
- { __("Gray"), "FF808080" },
- { __("Black"), "FF000000" },
- { __("Red"), "FFFF0000" },
- { __("Orange"), "FFFFA500" },
- { __("Yellow"), "FFFFFF00" },
- { __("Green"), "FF00FF00" },
- { __("Blue"), "FF0000FF" },
- { __("Violet"), "FF8F00FF" }
+ { N_p("color-preset", "White"), "FFFFFFFF" },
+ { N_p("color-preset", "Silver"), "FFC0C0C0" },
+ { N_p("color-preset", "Gray"), "FF808080" },
+ { N_p("color-preset", "Black"), "FF000000" },
+ { N_p("color-preset", "Red"), "FFFF0000" },
+ { N_p("color-preset", "Orange"), "FFFFA500" },
+ { N_p("color-preset", "Yellow"), "FFFFFF00" },
+ { N_p("color-preset", "Green"), "FF00FF00" },
+ { N_p("color-preset", "Blue"), "FF0000FF" },
+ { N_p("color-preset", "Violet"), "FF8F00FF" }
};
//-------------------------------------------------
@@ -986,7 +1079,7 @@ void menu_palette_sel::handle()
void menu_palette_sel::populate(float &customtop, float &custombottom)
{
for (unsigned x = 0; x < std::size(s_palette); ++x)
- item_append(_(s_palette[x].first), s_palette[x].second, FLAG_COLOR_BOX, (void *)(uintptr_t)(x + 1));
+ item_append(_("color-preset", s_palette[x].first), s_palette[x].second, FLAG_COLOR_BOX, (void *)(uintptr_t)(x + 1));
item_append(menu_item_type::SEPARATOR);
}
diff --git a/src/frontend/mame/ui/custui.h b/src/frontend/mame/ui/custui.h
index 2da5cfd132b..33e8149ffdc 100644
--- a/src/frontend/mame/ui/custui.h
+++ b/src/frontend/mame/ui/custui.h
@@ -37,6 +37,7 @@ private:
enum
{
LANGUAGE_MENU = 1,
+ SYSNAMES_MENU,
FONT_MENU,
COLORS_MENU,
HIDE_MENU
@@ -45,11 +46,16 @@ private:
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle() override;
+ void find_languages();
+ void find_sysnames();
+
static const char *const HIDE_STATUS[];
std::function<void ()> m_handler;
- std::vector<std::string> m_lang;
- std::uint16_t m_currlang;
+ std::vector<std::string> m_languages;
+ std::vector<std::string> m_sysnames;
+ std::size_t m_currlang;
+ std::size_t m_currsysnames;
};
//-------------------------------------------------
diff --git a/src/frontend/mame/ui/datmenu.cpp b/src/frontend/mame/ui/datmenu.cpp
index b772273d61a..6dabbc09223 100644
--- a/src/frontend/mame/ui/datmenu.cpp
+++ b/src/frontend/mame/ui/datmenu.cpp
@@ -77,10 +77,10 @@ menu_dats_view::menu_dats_view(mame_ui_manager &mui, render_container &container
, m_issoft(true)
{
- if (swinfo != nullptr && !swinfo->usage.empty())
- m_items_list.emplace_back(_("Software Usage"), 0, "");
+ if (swinfo != nullptr && !swinfo->infotext.empty())
+ m_items_list.emplace_back(_("Software List Info"), 0, "");
std::vector<std::string> lua_list;
- if(mame_machine_manager::instance()->lua()->call_plugin("data_list", std::string(m_short).append(1, ',').append(m_list).c_str(), lua_list))
+ if (mame_machine_manager::instance()->lua()->call_plugin("data_list", std::string(m_short).append(1, ',').append(m_list).c_str(), lua_list))
{
int count = 1;
for(std::string &item : lua_list)
@@ -417,7 +417,7 @@ void menu_dats_view::get_data_sw()
std::vector<int> xend;
std::string buffer;
if (m_items_list[m_actual].option == 0)
- buffer = m_swinfo->usage;
+ buffer = m_swinfo->infotext;
else
mame_machine_manager::instance()->lua()->call_plugin("data", m_items_list[m_actual].option - 1, buffer);
diff --git a/src/frontend/mame/ui/dirmenu.cpp b/src/frontend/mame/ui/dirmenu.cpp
index 9d6fd462e74..85ca2fc085b 100644
--- a/src/frontend/mame/ui/dirmenu.cpp
+++ b/src/frontend/mame/ui/dirmenu.cpp
@@ -34,35 +34,37 @@ struct folders_entry
static const folders_entry s_folders[] =
{
- { __("ROMs"), OPTION_MEDIAPATH, ADDING },
- { __("Software Media"), OPTION_SWPATH, CHANGE },
- { __("UI"), OPTION_UI_PATH, CHANGE },
- { __("Language"), OPTION_LANGUAGEPATH, CHANGE },
- { __("Samples"), OPTION_SAMPLEPATH, ADDING },
- { __("DATs"), OPTION_HISTORY_PATH, ADDING },
- { __("INIs"), OPTION_INIPATH, ADDING },
- { __("Category INIs"), OPTION_CATEGORYINI_PATH, CHANGE },
- { __("Icons"), OPTION_ICONS_PATH, ADDING },
- { __("Cheats"), OPTION_CHEATPATH, ADDING },
- { __("Snapshots"), OPTION_SNAPSHOT_DIRECTORY, ADDING },
- { __("Cabinets"), OPTION_CABINETS_PATH, ADDING },
- { __("Flyers"), OPTION_FLYERS_PATH, ADDING },
- { __("Titles"), OPTION_TITLES_PATH, ADDING },
- { __("Ends"), OPTION_ENDS_PATH, ADDING },
- { __("PCBs"), OPTION_PCBS_PATH, ADDING },
- { __("Marquees"), OPTION_MARQUEES_PATH, ADDING },
- { __("Controls Panels"), OPTION_CPANELS_PATH, ADDING },
- { __("Crosshairs"), OPTION_CROSSHAIRPATH, ADDING },
- { __("Artworks"), OPTION_ARTPATH, ADDING },
- { __("Bosses"), OPTION_BOSSES_PATH, ADDING },
- { __("Artworks Preview"), OPTION_ARTPREV_PATH, ADDING },
- { __("Select"), OPTION_SELECT_PATH, ADDING },
- { __("GameOver"), OPTION_GAMEOVER_PATH, ADDING },
- { __("HowTo"), OPTION_HOWTO_PATH, ADDING },
- { __("Logos"), OPTION_LOGOS_PATH, ADDING },
- { __("Scores"), OPTION_SCORES_PATH, ADDING },
- { __("Versus"), OPTION_VERSUS_PATH, ADDING },
- { __("Covers"), OPTION_COVER_PATH, ADDING }
+ { N_p("path-option", "ROMs"), OPTION_MEDIAPATH, ADDING },
+ { N_p("path-option", "Software Media"), OPTION_SWPATH, CHANGE },
+ { N_p("path-option", "Sound Samples"), OPTION_SAMPLEPATH, ADDING },
+ { N_p("path-option", "Artwork"), OPTION_ARTPATH, ADDING },
+ { N_p("path-option", "Crosshairs"), OPTION_CROSSHAIRPATH, ADDING },
+ { N_p("path-option", "Cheat Files"), OPTION_CHEATPATH, ADDING },
+ { N_p("path-option", "Plugins"), OPTION_PLUGINSPATH, ADDING },
+ { N_p("path-option", "UI Translations"), OPTION_LANGUAGEPATH, CHANGE },
+ { N_p("path-option", "INIs"), OPTION_INIPATH, ADDING },
+ { N_p("path-option", "UI Settings"), OPTION_UI_PATH, CHANGE },
+ { N_p("path-option", "Plugin Data"), OPTION_PLUGINDATAPATH, CHANGE },
+ { N_p("path-option", "DATs"), OPTION_HISTORY_PATH, ADDING },
+ { N_p("path-option", "Category INIs"), OPTION_CATEGORYINI_PATH, CHANGE },
+ { N_p("path-option", "Snapshots"), OPTION_SNAPSHOT_DIRECTORY, ADDING },
+ { N_p("path-option", "Icons"), OPTION_ICONS_PATH, ADDING },
+ { N_p("path-option", "Control Panels"), OPTION_CPANELS_PATH, ADDING },
+ { N_p("path-option", "Cabinets"), OPTION_CABINETS_PATH, ADDING },
+ { N_p("path-option", "Marquees"), OPTION_MARQUEES_PATH, ADDING },
+ { N_p("path-option", "PCBs"), OPTION_PCBS_PATH, ADDING },
+ { N_p("path-option", "Flyers"), OPTION_FLYERS_PATH, ADDING },
+ { N_p("path-option", "Title Screens"), OPTION_TITLES_PATH, ADDING },
+ { N_p("path-option", "Game Endings"), OPTION_ENDS_PATH, ADDING },
+ { N_p("path-option", "Bosses"), OPTION_BOSSES_PATH, ADDING },
+ { N_p("path-option", "Artwork Previews"), OPTION_ARTPREV_PATH, ADDING },
+ { N_p("path-option", "Select"), OPTION_SELECT_PATH, ADDING },
+ { N_p("path-option", "Game Over Screens"), OPTION_GAMEOVER_PATH, ADDING },
+ { N_p("path-option", "HowTo"), OPTION_HOWTO_PATH, ADDING },
+ { N_p("path-option", "Logos"), OPTION_LOGOS_PATH, ADDING },
+ { N_p("path-option", "Scores"), OPTION_SCORES_PATH, ADDING },
+ { N_p("path-option", "Versus"), OPTION_VERSUS_PATH, ADDING },
+ { N_p("path-option", "Covers"), OPTION_COVER_PATH, ADDING }
};
@@ -103,7 +105,7 @@ void menu_directory::handle()
void menu_directory::populate(float &customtop, float &custombottom)
{
for (auto & elem : s_folders)
- item_append(_(elem.name), 0, (void *)(uintptr_t)elem.action);
+ item_append(_("path-option", elem.name), 0, (void *)(uintptr_t)elem.action);
item_append(menu_item_type::SEPARATOR);
customtop = ui().get_line_height() + 3.0f * ui().box_tb_border();
@@ -166,7 +168,7 @@ void menu_display_actual::handle()
void menu_display_actual::populate(float &customtop, float &custombottom)
{
- m_heading[0] = string_format(_("Current %1$s Folders"), _(s_folders[m_ref].name));
+ m_heading[0] = string_format(_("Current %1$s Folders"), _("path-option", s_folders[m_ref].name));
if (ui().options().exists(s_folders[m_ref].option))
m_searchpath.assign(ui().options().value(s_folders[m_ref].option));
else
@@ -417,7 +419,7 @@ void menu_add_change_folder::custom_render(void *selectedref, float top, float b
std::string const toptext[] = {
util::string_format(
m_change ? _("Change %1$s Folder - Search: %2$s_") : _("Add %1$s Folder - Search: %2$s_"),
- _(s_folders[m_ref].name),
+ _("path-option", s_folders[m_ref].name),
m_search),
m_current_path };
draw_text_box(
@@ -511,7 +513,7 @@ void menu_remove_folder::populate(float &customtop, float &custombottom)
void menu_remove_folder::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{
- std::string const toptext[] = {string_format(_("Remove %1$s Folder"), _(s_folders[m_ref].name)) };
+ std::string const toptext[] = {string_format(_("Remove %1$s Folder"), _("path-option", s_folders[m_ref].name)) };
draw_text_box(
std::begin(toptext), std::end(toptext),
origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(),
diff --git a/src/frontend/mame/ui/info.cpp b/src/frontend/mame/ui/info.cpp
index 1c9e649dce7..e3f557ed54e 100644
--- a/src/frontend/mame/ui/info.cpp
+++ b/src/frontend/mame/ui/info.cpp
@@ -28,27 +28,27 @@ 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, N_p("emulation-feature", "protection") },
+ { device_t::feature::TIMING, N_p("emulation-feature", "timing") },
+ { device_t::feature::GRAPHICS, N_p("emulation-feature", "graphics") },
+ { device_t::feature::PALETTE, N_p("emulation-feature", "color palette") },
+ { device_t::feature::SOUND, N_p("emulation-feature", "sound") },
+ { device_t::feature::CAPTURE, N_p("emulation-feature", "capture hardware") },
+ { device_t::feature::CAMERA, N_p("emulation-feature", "camera") },
+ { device_t::feature::MICROPHONE, N_p("emulation-feature", "microphone") },
+ { device_t::feature::CONTROLS, N_p("emulation-feature", "controls") },
+ { device_t::feature::KEYBOARD, N_p("emulation-feature", "keyboard") },
+ { device_t::feature::MOUSE, N_p("emulation-feature", "mouse") },
+ { device_t::feature::MEDIA, N_p("emulation-feature", "media") },
+ { device_t::feature::DISK, N_p("emulation-feature", "disk") },
+ { device_t::feature::PRINTER, N_p("emulation-feature", "printer") },
+ { device_t::feature::TAPE, N_p("emulation-feature", "magnetic tape") },
+ { device_t::feature::PUNCH, N_p("emulation-feature", "punch tape") },
+ { device_t::feature::DRUM, N_p("emulation-feature", "magnetic drum") },
+ { device_t::feature::ROM, N_p("emulation-feature", "solid state storage") },
+ { device_t::feature::COMMS, N_p("emulation-feature", "communications") },
+ { device_t::feature::LAN, N_p("emulation-feature", "LAN") },
+ { device_t::feature::WAN, N_p("emulation-feature", "WAN") } };
} // anonymous namespace
@@ -253,7 +253,7 @@ std::string machine_info::warnings_string() const
{
if (unemulated_features() & feature.first)
{
- util::stream_format(buf, first ? _("%s") : _(", %s"), _(feature.second));
+ util::stream_format(buf, first ? _("%s") : _(", %s"), _("emulation-feature", feature.second));
first = false;
}
}
@@ -269,7 +269,7 @@ std::string machine_info::warnings_string() const
{
if (imperfect_features() & feature.first)
{
- util::stream_format(buf, first ? _("%s") : _(", %s"), _(feature.second));
+ util::stream_format(buf, first ? _("%s") : _(", %s"), _("emulation-feature", feature.second));
first = false;
}
}
diff --git a/src/frontend/mame/ui/inifile.cpp b/src/frontend/mame/ui/inifile.cpp
index 000ea922a4a..317df1c637a 100644
--- a/src/frontend/mame/ui/inifile.cpp
+++ b/src/frontend/mame/ui/inifile.cpp
@@ -219,48 +219,48 @@ favorite_manager::favorite_manager(ui_options &options)
if (!file.open(FAVORITE_FILENAME))
{
char readbuf[1024];
- file.gets(readbuf, 1024);
+ file.gets(readbuf, std::size(readbuf));
while (readbuf[0] == '[')
- file.gets(readbuf, 1024);
+ file.gets(readbuf, std::size(readbuf));
- while (file.gets(readbuf, 1024))
+ while (file.gets(readbuf, std::size(readbuf)))
{
ui_software_info tmpmatches;
tmpmatches.shortname = chartrimcarriage(readbuf);
- file.gets(readbuf, 1024);
+ file.gets(readbuf, std::size(readbuf));
tmpmatches.longname = chartrimcarriage(readbuf);
- file.gets(readbuf, 1024);
+ file.gets(readbuf, std::size(readbuf));
tmpmatches.parentname = chartrimcarriage(readbuf);
- file.gets(readbuf, 1024);
+ file.gets(readbuf, std::size(readbuf));
tmpmatches.year = chartrimcarriage(readbuf);
- file.gets(readbuf, 1024);
+ file.gets(readbuf, std::size(readbuf));
tmpmatches.publisher = chartrimcarriage(readbuf);
- file.gets(readbuf, 1024);
+ file.gets(readbuf, std::size(readbuf));
tmpmatches.supported = software_support(atoi(readbuf));
- file.gets(readbuf, 1024);
+ file.gets(readbuf, std::size(readbuf));
tmpmatches.part = chartrimcarriage(readbuf);
- file.gets(readbuf, 1024);
+ file.gets(readbuf, std::size(readbuf));
chartrimcarriage(readbuf);
auto dx = driver_list::find(readbuf);
if (0 > dx)
continue;
tmpmatches.driver = &driver_list::driver(dx);
- file.gets(readbuf, 1024);
+ file.gets(readbuf, std::size(readbuf));
tmpmatches.listname = chartrimcarriage(readbuf);
- file.gets(readbuf, 1024);
+ file.gets(readbuf, std::size(readbuf));
tmpmatches.interface = chartrimcarriage(readbuf);
- file.gets(readbuf, 1024);
+ file.gets(readbuf, std::size(readbuf));
tmpmatches.instance = chartrimcarriage(readbuf);
- file.gets(readbuf, 1024);
+ file.gets(readbuf, std::size(readbuf));
tmpmatches.startempty = atoi(readbuf);
- file.gets(readbuf, 1024);
+ file.gets(readbuf, std::size(readbuf));
tmpmatches.parentlongname = chartrimcarriage(readbuf);
- file.gets(readbuf, 1024);
- tmpmatches.usage = chartrimcarriage(readbuf);
- file.gets(readbuf, 1024);
+ file.gets(readbuf, std::size(readbuf));
+ //tmpmatches.usage = chartrimcarriage(readbuf); TODO: recover multi-line info
+ file.gets(readbuf, std::size(readbuf));
tmpmatches.devicetype = chartrimcarriage(readbuf);
- file.gets(readbuf, 1024);
+ file.gets(readbuf, std::size(readbuf));
tmpmatches.available = atoi(readbuf);
m_favorites.emplace(std::move(tmpmatches));
}
@@ -292,25 +292,18 @@ void favorite_manager::add_favorite(running_machine &machine)
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 = software->longname();
- info.parentname = software->parentname();
- info.year = software->year();
- info.publisher = software->publisher();
- info.supported = software->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());
+ ui_software_info info(
+ *software,
+ *part,
+ driver,
+ imagedev->software_list_name(),
+ imagedev->instance_name(),
+ strensure(imagedev->image_type_name()));
+
+ // assume it's available if it's mounted
info.available = true;
// look up the parent in the list if necessary (eugh, O(n) walk)
@@ -328,16 +321,6 @@ void favorite_manager::add_favorite(running_machine &machine)
}
}
- // 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));
}
@@ -567,7 +550,7 @@ void favorite_manager::save_favorites()
buf << info.instance << '\n';
util::stream_format(buf, "%d\n", info.startempty);
buf << info.parentlongname << '\n';
- buf << info.usage << '\n';
+ buf << '\n'; //buf << info.usage << '\n'; TODO: store multi-line info in a recoverable format
buf << info.devicetype << '\n';
util::stream_format(buf, "%d\n", info.available);
diff --git a/src/frontend/mame/ui/menu.cpp b/src/frontend/mame/ui/menu.cpp
index 923a0fae6df..b785deea72b 100644
--- a/src/frontend/mame/ui/menu.cpp
+++ b/src/frontend/mame/ui/menu.cpp
@@ -78,7 +78,6 @@ bool menu::exclusive_input_pressed(int &iptkey, int key, int repeat)
menu::global_state::global_state(running_machine &machine, ui_options const &options)
: widgets_manager(machine)
, m_machine(machine)
- , m_cleanup_callbacks()
, m_bgrnd_bitmap()
, m_bgrnd_texture(nullptr, machine.render())
, m_stack()
@@ -120,15 +119,6 @@ menu::global_state::~global_state()
stack_reset();
clear_free_list();
-
- for (auto const &callback : m_cleanup_callbacks)
- callback(m_machine);
-}
-
-
-void menu::global_state::add_cleanup_callback(cleanup_callback &&callback)
-{
- m_cleanup_callbacks.emplace_back(std::move(callback));
}
diff --git a/src/frontend/mame/ui/menu.h b/src/frontend/mame/ui/menu.h
index bb99e84f0ad..2d8d5e9173c 100644
--- a/src/frontend/mame/ui/menu.h
+++ b/src/frontend/mame/ui/menu.h
@@ -132,7 +132,6 @@ private:
void draw_text_box();
protected:
- using cleanup_callback = std::function<void(running_machine &)>;
using bitmap_ptr = widgets_manager::bitmap_ptr;
using texture_ptr = widgets_manager::texture_ptr;
@@ -181,8 +180,6 @@ protected:
void stack_reset() { m_global_state->stack_reset(); }
bool stack_has_special_main_menu() const { return m_global_state->stack_has_special_main_menu(); }
- void add_cleanup_callback(cleanup_callback &&callback) { m_global_state->add_cleanup_callback(std::move(callback)); }
-
// process a menu, drawing it and returning any interesting events
const event *process(uint32_t flags, float x0 = 0.0f, float y0 = 0.0f);
void process_parent() { m_parent->process(PROCESS_NOINPUT); }
@@ -336,8 +333,6 @@ private:
global_state(global_state &&) = delete;
~global_state();
- void add_cleanup_callback(cleanup_callback &&callback);
-
bitmap_argb32 *bgrnd_bitmap() { return m_bgrnd_bitmap.get(); }
render_texture *bgrnd_texture() { return m_bgrnd_texture.get(); }
@@ -351,10 +346,7 @@ private:
bool stack_has_special_main_menu() const;
private:
- using cleanup_callback_vector = std::vector<cleanup_callback>;
-
running_machine &m_machine;
- cleanup_callback_vector m_cleanup_callbacks;
bitmap_ptr m_bgrnd_bitmap;
texture_ptr m_bgrnd_texture;
diff --git a/src/frontend/mame/ui/miscmenu.cpp b/src/frontend/mame/ui/miscmenu.cpp
index da7989e6e3b..f053d2572f4 100644
--- a/src/frontend/mame/ui/miscmenu.cpp
+++ b/src/frontend/mame/ui/miscmenu.cpp
@@ -15,6 +15,7 @@
#include "ui/selector.h"
#include "ui/submenu.h"
#include "ui/ui.h"
+#include "ui/utils.h"
#include "infoxml.h"
#include "mame.h"
@@ -702,11 +703,33 @@ void menu_export::populate(float &customtop, float &custombottom)
menu_machine_configure::menu_machine_configure(
mame_ui_manager &mui,
render_container &container,
+ ui_system_info const &info,
+ std::function<void (bool, bool)> &&handler,
+ float x0, float y0)
+ : menu_machine_configure(mui, container, info.description.c_str(), *info.driver, std::move(handler), x0, y0)
+{
+}
+
+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(mui, container, drv.type.fullname(), drv, std::move(handler), x0, y0)
+{
+}
+
+menu_machine_configure::menu_machine_configure(
+ mame_ui_manager &mui,
+ render_container &container,
+ char const *description,
game_driver const &drv,
std::function<void (bool, bool)> &&handler,
float x0, float y0)
: menu(mui, container)
, m_handler(std::move(handler))
+ , m_description(description)
, m_drv(drv)
, m_x0(x0)
, m_y0(y0)
@@ -835,7 +858,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_description };
draw_text_box(
std::begin(text), std::end(text),
origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(),
diff --git a/src/frontend/mame/ui/miscmenu.h b/src/frontend/mame/ui/miscmenu.h
index c8d833ae4e2..5fdf7fb8a8e 100644
--- a/src/frontend/mame/ui/miscmenu.h
+++ b/src/frontend/mame/ui/miscmenu.h
@@ -21,6 +21,9 @@
#include <vector>
+struct ui_system_info;
+
+
namespace ui {
class menu_network_devices : public menu
@@ -130,6 +133,12 @@ public:
menu_machine_configure(
mame_ui_manager &mui,
render_container &container,
+ ui_system_info const &info,
+ 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,
game_driver const &drv,
std::function<void (bool, bool)> &&handler = nullptr,
float x0 = 0.0f, float y0 = 0.0f);
@@ -153,12 +162,21 @@ private:
LAST = ADVANCED
};
+ menu_machine_configure(
+ mame_ui_manager &mui,
+ render_container &container,
+ char const *description,
+ game_driver const &drv,
+ std::function<void (bool, bool)> &&handler,
+ float x0, float y0);
+
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle() override;
void setup_bios();
std::function<void (bool, bool)> const m_handler;
+ char const *const m_description;
game_driver const &m_drv;
emu_options m_opts;
float const m_x0;
diff --git a/src/frontend/mame/ui/moptions.cpp b/src/frontend/mame/ui/moptions.cpp
index cf1d521ef3b..375bbddf16a 100644
--- a/src/frontend/mame/ui/moptions.cpp
+++ b/src/frontend/mame/ui/moptions.cpp
@@ -21,7 +21,7 @@ const options_entry ui_options::s_option_entries[] =
{
// search path options
{ nullptr, nullptr, OPTION_HEADER, "UI SEARCH PATH OPTIONS" },
- { OPTION_HISTORY_PATH, "history;dats;.", OPTION_STRING, "path to history files" },
+ { OPTION_HISTORY_PATH, "history;dats;.", OPTION_STRING, "path to system/software info files" },
{ OPTION_CATEGORYINI_PATH, "folders", OPTION_STRING, "path to category ini files" },
{ OPTION_CABINETS_PATH, "cabinets;cabdevs", OPTION_STRING, "path to cabinets / devices image" },
{ OPTION_CPANELS_PATH, "cpanel", OPTION_STRING, "path to control panel image" },
@@ -44,6 +44,7 @@ const options_entry ui_options::s_option_entries[] =
// misc options
{ nullptr, nullptr, OPTION_HEADER, "UI MISC OPTIONS" },
+ { OPTION_SYSTEM_NAMES, "", OPTION_STRING, "translated system names file" },
{ OPTION_SKIP_WARNINGS, "0", OPTION_BOOLEAN, "display fewer repeated warnings about imperfect emulation" },
{ OPTION_REMEMBER_LAST, "1", OPTION_BOOLEAN, "initially select last used system in main menu" },
{ OPTION_ENLARGE_SNAPS, "1", OPTION_BOOLEAN, "enlarge artwork (snapshot, title, etc.) in right panel (keeping aspect ratio)" },
diff --git a/src/frontend/mame/ui/moptions.h b/src/frontend/mame/ui/moptions.h
index a345972bdc0..4b228aad974 100644
--- a/src/frontend/mame/ui/moptions.h
+++ b/src/frontend/mame/ui/moptions.h
@@ -38,6 +38,7 @@
#define OPTION_UI_PATH "ui_path"
// core misc options
+#define OPTION_SYSTEM_NAMES "system_names"
#define OPTION_SKIP_WARNINGS "skip_warnings"
#define OPTION_REMEMBER_LAST "remember_last"
#define OPTION_ENLARGE_SNAPS "enlarge_snaps"
@@ -104,6 +105,7 @@ public:
const char *ui_path() const { return value(OPTION_UI_PATH); }
// Misc options
+ const char *system_names() const { return value(OPTION_SYSTEM_NAMES); }
bool skip_warnings() const { return bool_value(OPTION_SKIP_WARNINGS); }
bool remember_last() const { return bool_value(OPTION_REMEMBER_LAST); }
bool enlarge_snaps() const { return bool_value(OPTION_ENLARGE_SNAPS); }
diff --git a/src/frontend/mame/ui/selgame.cpp b/src/frontend/mame/ui/selgame.cpp
index 7582c90e0d8..89892664fc0 100644
--- a/src/frontend/mame/ui/selgame.cpp
+++ b/src/frontend/mame/ui/selgame.cpp
@@ -37,8 +37,10 @@
#include <condition_variable>
#include <cstring>
#include <iterator>
+#include <locale>
#include <memory>
#include <mutex>
+#include <string_view>
#include <thread>
@@ -57,13 +59,15 @@ 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
+ 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_UCS_DFLT_DESC = 1U << 5,
+ AVAIL_UCS_MANUF_DFLT_DESC = 1U << 6,
+ AVAIL_FILTER_DATA = 1U << 7
};
~persistent_data()
@@ -72,10 +76,31 @@ public:
m_thread->join();
}
- void cache_data()
+ void cache_data(ui_options const &options)
{
std::unique_lock<std::mutex> lock(m_mutex);
- do_start_caching();
+ if (!m_started)
+ {
+ m_started = true;
+ m_thread = std::make_unique<std::thread>(
+ [this, datpath = std::string(options.history_path()), titles = std::string(options.system_names())]
+ {
+ do_cache_data(datpath, titles);
+ });
+ }
+ }
+
+ void reset_cache()
+ {
+ if (m_thread)
+ m_thread->join();
+ std::unique_lock<std::mutex> lock(m_mutex);
+ m_thread.reset();
+ m_started = false;
+ m_available = AVAIL_NONE;
+ m_sorted_list.clear();
+ m_filter_data = machine_filter_data();
+ m_bios_count = 0U;
}
bool is_available(available desired)
@@ -87,8 +112,8 @@ public:
{
if (!is_available(desired))
{
+ assert(m_started);
std::unique_lock<std::mutex> lock(m_mutex);
- do_start_caching();
m_condition.wait(lock, [this, desired] () { return is_available(desired); });
}
}
@@ -138,42 +163,86 @@ private:
m_condition.notify_all();
}
- void do_start_caching()
+ void do_cache_data(std::string const &datpath, std::string const &titles)
{
- if (!m_started)
- {
- m_started = true;
- m_thread = std::make_unique<std::thread>([this] { do_cache_data(); });
- }
- }
+ // try to open the titles file for optimisation reasons
+ emu_file titles_file(datpath, OPEN_FLAG_READ);
+ bool const try_titles(!titles.empty() && !titles_file.open(titles));
- 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);
- }
- }
+ // generate full list - initially ordered by shortname
+ populate_list(!try_titles);
// notify that BIOS count is valie
notify_available(AVAIL_BIOS_COUNT);
+ // try to load localised descriptions
+ if (try_titles)
+ load_titles(titles_file);
+
+ // populate parent descriptions while still ordered by shortname
+ populate_parents();
+
// sort drivers and notify
+ std::collate<wchar_t> const &coll = std::use_facet<std::collate<wchar_t>>(std::locale());
+ auto const compare_names =
+ [&coll] (std::string const &x, std::string const &y) -> bool
+ {
+ std::wstring const wx = wstring_from_utf8(x);
+ std::wstring const wy = wstring_from_utf8(y);
+ return 0 > coll.compare(wx.data(), wx.data() + wx.size(), wy.data(), wy.data() + wy.size());
+ };
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); });
+ [&compare_names] (ui_system_info const &lhs, ui_system_info const &rhs)
+ {
+ game_driver const &x(*lhs.driver);
+ game_driver const &y(*rhs.driver);
+
+ bool clonex = (x.parent[0] != '0') || x.parent[1];
+ int cx = -1;
+ if (clonex)
+ {
+ cx = driver_list::find(x.parent);
+ if ((0 > cx) || (driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT))
+ clonex = false;
+ }
+
+ bool cloney = (y.parent[0] != '0') || y.parent[1];
+ int cy = -1;
+ if (cloney)
+ {
+ cy = driver_list::find(y.parent);
+ if ((0 > cy) || (driver_list::driver(cy).flags & machine_flags::IS_BIOS_ROOT))
+ cloney = false;
+ }
+
+ if (!clonex && !cloney)
+ {
+ return compare_names(lhs.description, rhs.description);
+ }
+ else if (clonex && cloney)
+ {
+ if (!std::strcmp(x.parent, y.parent))
+ return compare_names(lhs.description, rhs.description);
+ else
+ return compare_names(lhs.parent, rhs.parent);
+ }
+ else if (!clonex && cloney)
+ {
+ if (!std::strcmp(x.name, y.parent))
+ return true;
+ else
+ return compare_names(lhs.description, rhs.parent);
+ }
+ else
+ {
+ if (!std::strcmp(x.parent, y.name))
+ return false;
+ else
+ return compare_names(lhs.parent, rhs.description);
+ }
+ });
notify_available(AVAIL_SORTED_LIST);
// sort manufacturers and years
@@ -187,7 +256,7 @@ private:
// 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));
+ info.ucs_description = ustr_from_utf8(normalize_unicode(info.description, unicode_normalization_form::D, true));
notify_available(AVAIL_UCS_DESCRIPTION);
// convert "<manufacturer> <description>" to UCS-4
@@ -196,10 +265,141 @@ private:
{
buf.assign(info.driver->manufacturer);
buf.append(1, ' ');
- buf.append(info.driver->type.fullname());
+ buf.append(info.description);
info.ucs_manufacturer_description = ustr_from_utf8(normalize_unicode(buf, unicode_normalization_form::D, true));
}
notify_available(AVAIL_UCS_MANUF_DESC);
+
+ // convert default descriptions to UCS-4
+ if (try_titles)
+ {
+ for (ui_system_info &info : m_sorted_list)
+ {
+ std::string_view const fullname(info.driver->type.fullname());
+ if (info.description != fullname)
+ info.ucs_default_description = ustr_from_utf8(normalize_unicode(fullname, unicode_normalization_form::D, true));
+ }
+ }
+ notify_available(AVAIL_UCS_DFLT_DESC);
+
+ // convert "<manufacturer> <default description>" to UCS-4
+ if (try_titles)
+ {
+ for (ui_system_info &info : m_sorted_list)
+ {
+ std::string_view const fullname(info.driver->type.fullname());
+ if (info.description != fullname)
+ {
+ buf.assign(info.driver->manufacturer);
+ buf.append(1, ' ');
+ buf.append(fullname);
+ info.ucs_manufacturer_default_description = ustr_from_utf8(normalize_unicode(buf, unicode_normalization_form::D, true));
+ }
+ }
+ }
+ notify_available(AVAIL_UCS_MANUF_DFLT_DESC);
+ }
+
+ void populate_list(bool copydesc)
+ {
+ 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;
+
+ ui_system_info &ins(m_sorted_list.emplace_back(driver, x, false));
+ if (copydesc)
+ ins.description = driver.type.fullname();
+
+ m_filter_data.add_manufacturer(driver.manufacturer);
+ m_filter_data.add_year(driver.year);
+ }
+ }
+ }
+
+ void load_titles(util::core_file &file)
+ {
+ char readbuf[1024];
+ while (file.gets(readbuf, std::size(readbuf)))
+ {
+ // shortname and description separated by tab
+ auto const split(std::find(std::begin(readbuf), std::end(readbuf), '\t'));
+ if (std::end(readbuf) == split)
+ continue;
+ std::string_view const shortname(readbuf, split - readbuf);
+
+ // find matching system - still sorted by shortname at this point
+ auto const found(
+ std::lower_bound(
+ m_sorted_list.begin(),
+ m_sorted_list.end(),
+ shortname,
+ [] (ui_system_info const &a, std::string_view const &b)
+ {
+ return a.driver->name < b;
+ }));
+ if ((m_sorted_list.end() == found) || (shortname != found->driver->name))
+ {
+ //osd_printf_verbose("System '%s' not found\n", shortname); very spammy for single-driver builds
+ continue;
+ }
+
+ // strip additional columns
+ auto const start(std::next(split));
+ auto const end(std::find(start, std::end(readbuf), '\t'));
+ auto const description(strtrimspace(std::string_view(start, end - start)));
+ if (description.empty())
+ {
+ osd_printf_warning("Empty translated description for system '%s'\n", shortname);
+ }
+ else if (!found->description.empty())
+ {
+ osd_printf_warning(
+ "Multiple translated descriptions for system '%s' ('%s' and '%s')\n",
+ shortname,
+ found->description,
+ description);
+ }
+ else
+ {
+ found->description = description;
+ }
+ }
+
+ // fill in untranslated descriptions
+ for (ui_system_info &info : m_sorted_list)
+ {
+ if (info.description.empty())
+ info.description = info.driver->type.fullname();
+ }
+ }
+
+ void populate_parents()
+ {
+ for (ui_system_info &info : m_sorted_list)
+ {
+ if (info.driver->parent[0] != '0')
+ {
+ auto const found(
+ std::lower_bound(
+ m_sorted_list.begin(),
+ m_sorted_list.end(),
+ std::string_view(info.driver->parent),
+ [] (ui_system_info const &a, std::string_view const &b)
+ {
+ return a.driver->name < b;
+ }));
+ if (m_sorted_list.end() != found)
+ info.parent = found->description;
+ else
+ info.parent = info.driver->parent;
+ }
+ }
}
// synchronisation
@@ -236,7 +436,7 @@ menu_select_game::menu_select_game(mame_ui_manager &mui, render_container &conta
ui_options &moptions = mui.options();
// load drivers cache
- m_persistent_data.cache_data();
+ m_persistent_data.cache_data(mui.options());
// check if there are available system icons
check_for_icons(nullptr);
@@ -294,14 +494,13 @@ menu_select_game::menu_select_game(mame_ui_manager &mui, render_container &conta
menu_select_game::~menu_select_game()
{
std::string error_string, last_driver;
- game_driver const *driver;
+ ui_system_info const *system;
ui_software_info const *swinfo;
- get_selection(swinfo, driver);
+ get_selection(swinfo, system);
if (swinfo)
last_driver = swinfo->shortname;
- else
- if (driver)
- last_driver = driver->name;
+ else if (system)
+ last_driver = system->driver->name;
std::string const filter(m_persistent_data.filter_data().get_config_string());
@@ -325,6 +524,10 @@ void menu_select_game::handle()
// if I have to load datfile, perform a hard reset
if (ui_globals::reset)
{
+ // dumb workaround for not being able to add an exit notifier
+ struct cache_reset { ~cache_reset() { persistent_data::instance().reset_cache(); } };
+ ui().get_session_data<cache_reset, cache_reset>();
+
ui_globals::reset = false;
machine().schedule_hard_reset();
stack_reset();
@@ -334,10 +537,10 @@ void menu_select_game::handle()
// if I have to select software, force software list submenu
if (reselect_last::get())
{
- const game_driver *driver;
+ const ui_system_info *system;
const ui_software_info *software;
- get_selection(software, driver);
- menu::stack_push<menu_select_software>(ui(), container(), *driver);
+ get_selection(software, system);
+ menu::stack_push<menu_select_software>(ui(), container(), *system);
return;
}
@@ -403,7 +606,7 @@ void menu_select_game::handle()
{
menu::stack_push<menu_machine_configure>(
ui(), container(),
- *reinterpret_cast<const game_driver *>(m_prev_selected),
+ *reinterpret_cast<ui_system_info const *>(m_prev_selected),
nullptr,
menu_event->mouse.x0, menu_event->mouse.y0);
}
@@ -454,16 +657,17 @@ void menu_select_game::handle()
favorite_manager &mfav(mame_machine_manager::instance()->favorite());
if (!m_populated_favorites)
{
- game_driver const *const driver(reinterpret_cast<game_driver const *>(menu_event->itemref));
- if (!mfav.is_favorite_system(*driver))
+ auto const &info(*reinterpret_cast<ui_system_info const *>(menu_event->itemref));
+ auto const &driver(*info.driver);
+ if (!mfav.is_favorite_system(driver))
{
- mfav.add_favorite_system(*driver);
- machine().popmessage(_("%s\n added to favorites list."), driver->type.fullname());
+ mfav.add_favorite_system(driver);
+ machine().popmessage(_("%s\n added to favorites list."), info.description);
}
else
{
- mfav.remove_favorite_system(*driver);
- machine().popmessage(_("%s\n removed from favorites list."), driver->type.fullname());
+ mfav.remove_favorite_system(driver);
+ machine().popmessage(_("%s\n removed from favorites list."), info.description);
}
}
else
@@ -557,7 +761,7 @@ void menu_select_game::populate(float &customtop, float &custombottom)
cloneof = false;
}
- item_append(elem.driver->type.fullname(), (cloneof) ? (FLAGS_UI | FLAG_INVERT) : FLAGS_UI, (void *)elem.driver);
+ item_append(elem.description, (cloneof) ? (FLAGS_UI | FLAG_INVERT) : FLAGS_UI, (void *)&elem);
curitem++;
}
}
@@ -761,9 +965,9 @@ void menu_select_game::force_game_select(mame_ui_manager &mui, render_container
void menu_select_game::inkey_select(const event *menu_event)
{
- const game_driver *driver = (const game_driver *)menu_event->itemref;
+ auto const system = reinterpret_cast<ui_system_info const *>(menu_event->itemref);
- if ((uintptr_t)driver == CONF_OPTS)
+ if (uintptr_t(system) == CONF_OPTS)
{
// special case for configure options
menu::stack_push<menu_game_options>(
@@ -772,14 +976,14 @@ void menu_select_game::inkey_select(const event *menu_event)
m_persistent_data.filter_data(),
[this] () { reset(reset_options::SELECT_FIRST); });
}
- else if (uintptr_t(driver) == CONF_MACHINE)
+ else if (uintptr_t(system) == 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 ui_system_info *>(m_prev_selected));
return;
}
- else if ((uintptr_t)driver == CONF_PLUGINS)
+ else if (uintptr_t(system) == CONF_PLUGINS)
{
// special case for configure plugins
menu::stack_push<menu_plugins_configure>(ui(), container());
@@ -787,7 +991,7 @@ void menu_select_game::inkey_select(const event *menu_event)
else
{
// anything else is a driver
- driver_enumerator enumerator(machine().options(), *driver);
+ driver_enumerator enumerator(machine().options(), *system->driver);
enumerator.next();
// if there are software entries, show a software selection menu
@@ -795,7 +999,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(), *system);
return;
}
}
@@ -807,8 +1011,8 @@ void menu_select_game::inkey_select(const event *menu_event)
// if everything looks good, schedule the new driver
if (audit_passed(summary))
{
- if (!select_bios(*driver, false))
- launch_system(*driver);
+ if (!select_bios(*system->driver, false))
+ launch_system(*system->driver);
}
else
{
@@ -853,7 +1057,7 @@ void menu_select_game::inkey_select_favorite(const event *menu_event)
}
return;
}
- else if ((uintptr_t)ui_swinfo == CONF_PLUGINS)
+ else if (uintptr_t(ui_swinfo) == CONF_PLUGINS)
{
// special case for configure plugins
menu::stack_push<menu_plugins_configure>(ui(), container());
@@ -954,12 +1158,12 @@ void menu_select_game::change_info_pane(int delta)
m_topline_datsview = 0;
}
};
- game_driver const *drv;
+ ui_system_info const *sys;
ui_software_info const *soft;
- get_selection(soft, drv);
+ get_selection(soft, sys);
if (!m_populated_favorites)
{
- if (uintptr_t(drv) > skip_main_items)
+ if (uintptr_t(sys) > skip_main_items)
cap_delta(ui_globals::curdats_view, ui_globals::curdats_total);
}
else if (uintptr_t(soft) > skip_main_items)
@@ -1025,6 +1229,34 @@ void menu_select_game::populate_search()
}
}
+ // match default description
+ if (m_persistent_data.is_available(persistent_data::AVAIL_UCS_DFLT_DESC))
+ {
+ m_searched_fields |= persistent_data::AVAIL_UCS_DFLT_DESC;
+ for (std::pair<double, std::reference_wrapper<ui_system_info const> > &info : m_searchlist)
+ {
+ if (info.first && !info.second.get().ucs_default_description.empty())
+ {
+ double const penalty(util::edit_distance(ucs_search, info.second.get().ucs_default_description));
+ info.first = (std::min)(penalty, info.first);
+ }
+ }
+ }
+
+ // match default description
+ if (m_persistent_data.is_available(persistent_data::AVAIL_UCS_MANUF_DFLT_DESC))
+ {
+ m_searched_fields |= persistent_data::AVAIL_UCS_DFLT_DESC;
+ for (std::pair<double, std::reference_wrapper<ui_system_info const> > &info : m_searchlist)
+ {
+ if (info.first && !info.second.get().ucs_manufacturer_default_description.empty())
+ {
+ double const penalty(util::edit_distance(ucs_search, info.second.get().ucs_manufacturer_default_description));
+ info.first = (std::min)(penalty, info.first);
+ }
+ }
+ }
+
// sort according to edit distance
std::stable_sort(
m_searchlist.begin(),
@@ -1036,20 +1268,21 @@ void menu_select_game::populate_search()
// generate general info
//-------------------------------------------------
-void menu_select_game::general_info(const game_driver *driver, std::string &buffer)
+void menu_select_game::general_info(ui_system_info const &system, std::string &buffer)
{
- system_flags const &flags(get_system_flags(*driver));
+ game_driver const &driver(*system.driver);
+ system_flags const &flags(get_system_flags(driver));
std::ostringstream str;
str << "#j2\n";
- util::stream_format(str, _("Romset\t%1$-.100s\n"), driver->name);
- util::stream_format(str, _("Year\t%1$s\n"), driver->year);
- util::stream_format(str, _("Manufacturer\t%1$-.100s\n"), driver->manufacturer);
+ util::stream_format(str, _("Romset\t%1$-.100s\n"), driver.name);
+ util::stream_format(str, _("Year\t%1$s\n"), driver.year);
+ util::stream_format(str, _("Manufacturer\t%1$-.100s\n"), driver.manufacturer);
- int cloneof = driver_list::non_bios_clone(*driver);
+ int cloneof = driver_list::non_bios_clone(driver);
if (cloneof != -1)
- util::stream_format(str, _("Driver is Clone of\t%1$-.100s\n"), driver_list::driver(cloneof).type.fullname());
+ util::stream_format(str, _("Driver is Clone of\t%1$-.100s\n"), system.parent);
else
str << _("Driver is Parent\t\n");
@@ -1179,7 +1412,7 @@ void menu_select_game::general_info(const game_driver *driver, std::string &buff
str << ((flags.machine_flags() & machine_flags::SUPPORTS_SAVE) ? _("Support Save\tYes\n") : _("Support Save\tNo\n"));
str << ((flags.machine_flags() & ORIENTATION_SWAP_XY) ? _("Screen Orientation\tVertical\n") : _("Screen Orientation\tHorizontal\n"));
bool found = false;
- for (romload::region const &region : romload::entries(driver->rom).get_regions())
+ for (romload::region const &region : romload::entries(driver.rom).get_regions())
{
if (region.is_diskdata())
{
@@ -1192,7 +1425,7 @@ void menu_select_game::general_info(const game_driver *driver, std::string &buff
// audit the game first to see if we're going to work
if (ui().options().info_audit())
{
- driver_enumerator enumerator(machine().options(), *driver);
+ driver_enumerator enumerator(machine().options(), driver);
enumerator.next();
media_auditor auditor(enumerator);
media_auditor::summary summary = auditor.audit_media(AUDIT_VALIDATE_FAST);
@@ -1228,7 +1461,7 @@ render_texture *menu_select_game::get_icon_texture(int linenum, void *selectedre
{
game_driver const *const driver(m_populated_favorites
? reinterpret_cast<ui_software_info const *>(selectedref)->driver
- : reinterpret_cast<game_driver const *>(selectedref));
+ : reinterpret_cast<ui_system_info const *>(selectedref)->driver);
assert(driver);
icon_cache::iterator icon(m_icons.find(driver));
@@ -1387,17 +1620,17 @@ float menu_select_game::draw_left_panel(float x1, float y1, float x2, float y2)
// get selected software and/or driver
//-------------------------------------------------
-void menu_select_game::get_selection(ui_software_info const *&software, game_driver const *&driver) const
+void menu_select_game::get_selection(ui_software_info const *&software, ui_system_info const *&system) const
{
if (m_populated_favorites)
{
software = reinterpret_cast<ui_software_info const *>(get_selection_ptr());
- driver = software ? software->driver : nullptr;
+ system = nullptr;
}
else
{
software = nullptr;
- driver = reinterpret_cast<game_driver const *>(get_selection_ptr());
+ system = reinterpret_cast<ui_system_info const *>(get_selection_ptr());
}
}
@@ -1428,17 +1661,10 @@ void menu_select_game::make_topbox_text(std::string &line0, std::string &line1,
}
-std::string menu_select_game::make_driver_description(game_driver const &driver) const
-{
- // first line is game name
- return string_format(_("Romset: %1$-.100s"), driver.name);
-}
-
-
std::string menu_select_game::make_software_description(ui_software_info const &software) const
{
// first line is system
- return string_format(_("System: %1$-.100s"), software.driver->type.fullname());
+ return string_format(_("System: %1$-.100s"), software.driver->type.fullname()); // TODO: localise description
}
diff --git a/src/frontend/mame/ui/selgame.h b/src/frontend/mame/ui/selgame.h
index 13bfd1170ac..7eac71d534d 100644
--- a/src/frontend/mame/ui/selgame.h
+++ b/src/frontend/mame/ui/selgame.h
@@ -60,12 +60,11 @@ private:
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;
+ virtual void get_selection(ui_software_info const *&software, ui_system_info const *&system) const override;
virtual bool accept_search() const override { return !isfavorite(); }
// text for main top/bottom panels
virtual void make_topbox_text(std::string &line0, std::string &line1, std::string &line2) const override;
- virtual std::string make_driver_description(game_driver const &driver) const override;
virtual std::string make_software_description(ui_software_info const &software) const override;
// filter navigation
@@ -85,7 +84,7 @@ private:
void load_custom_filters();
// General info
- virtual void general_info(const game_driver *driver, std::string &buffer) override;
+ virtual void general_info(ui_system_info const &system, std::string &buffer) override;
// handlers
void inkey_select(const event *menu_event);
diff --git a/src/frontend/mame/ui/selmenu.cpp b/src/frontend/mame/ui/selmenu.cpp
index 15c7e1c3364..a8ee5faa263 100644
--- a/src/frontend/mame/ui/selmenu.cpp
+++ b/src/frontend/mame/ui/selmenu.cpp
@@ -73,29 +73,29 @@ enum
std::pair<char const *, char const *> const arts_info[] =
{
- { __("Snapshots"), OPTION_SNAPSHOT_DIRECTORY },
- { __("Cabinets"), OPTION_CABINETS_PATH },
- { __("Control Panels"), OPTION_CPANELS_PATH },
- { __("PCBs"), OPTION_PCBS_PATH },
- { __("Flyers"), OPTION_FLYERS_PATH },
- { __("Titles"), OPTION_TITLES_PATH },
- { __("Ends"), OPTION_ENDS_PATH },
- { __("Artwork Preview"), OPTION_ARTPREV_PATH },
- { __("Bosses"), OPTION_BOSSES_PATH },
- { __("Logos"), OPTION_LOGOS_PATH },
- { __("Versus"), OPTION_VERSUS_PATH },
- { __("Game Over"), OPTION_GAMEOVER_PATH },
- { __("HowTo"), OPTION_HOWTO_PATH },
- { __("Scores"), OPTION_SCORES_PATH },
- { __("Select"), OPTION_SELECT_PATH },
- { __("Marquees"), OPTION_MARQUEES_PATH },
- { __("Covers"), OPTION_COVER_PATH },
+ { N_p("selmenu-artwork", "Snapshots"), OPTION_SNAPSHOT_DIRECTORY },
+ { N_p("selmenu-artwork", "Cabinet"), OPTION_CABINETS_PATH },
+ { N_p("selmenu-artwork", "Control Panel"), OPTION_CPANELS_PATH },
+ { N_p("selmenu-artwork", "PCB"), OPTION_PCBS_PATH },
+ { N_p("selmenu-artwork", "Flyer"), OPTION_FLYERS_PATH },
+ { N_p("selmenu-artwork", "Title Screen"), OPTION_TITLES_PATH },
+ { N_p("selmenu-artwork", "Ending"), OPTION_ENDS_PATH },
+ { N_p("selmenu-artwork", "Artwork Preview"), OPTION_ARTPREV_PATH },
+ { N_p("selmenu-artwork", "Bosses"), OPTION_BOSSES_PATH },
+ { N_p("selmenu-artwork", "Logo"), OPTION_LOGOS_PATH },
+ { N_p("selmenu-artwork", "Versus"), OPTION_VERSUS_PATH },
+ { N_p("selmenu-artwork", "Game Over"), OPTION_GAMEOVER_PATH },
+ { N_p("selmenu-artwork", "HowTo"), OPTION_HOWTO_PATH },
+ { N_p("selmenu-artwork", "Scores"), OPTION_SCORES_PATH },
+ { N_p("selmenu-artwork", "Select"), OPTION_SELECT_PATH },
+ { N_p("selmenu-artwork", "Marquee"), OPTION_MARQUEES_PATH },
+ { N_p("selmenu-artwork", "Covers"), OPTION_COVER_PATH },
};
char const *const hover_msg[] = {
- __("Add or remove favorites"),
- __("Export displayed list to file"),
- __("Show DATs view"),
+ N_("Add or remove favorites"),
+ N_("Export displayed list to file"),
+ N_("Show DATs view"),
};
@@ -202,9 +202,6 @@ std::string menu_select_launch::reselect_last::s_software;
std::string menu_select_launch::reselect_last::s_swlist;
bool menu_select_launch::reselect_last::s_reselect = false;
-std::mutex menu_select_launch::s_cache_guard;
-menu_select_launch::cache_ptr_map menu_select_launch::s_caches;
-
// instantiate possible variants of these so derived classes don't get link errors
template bool menu_select_launch::select_bios(game_driver const &, bool);
template bool menu_select_launch::select_bios(ui_software_info const &, bool);
@@ -514,7 +511,7 @@ menu_select_launch::menu_select_launch(mame_ui_manager &mui, render_container &c
, m_info_view(-1)
, m_items_list()
, m_info_buffer()
- , m_cache()
+ , m_cache(mui.get_session_data<menu_select_launch, cache_wrapper>(machine()))
, m_is_swlist(is_swlist)
, m_focus(focused_menu::MAIN)
, m_pressed(false)
@@ -526,22 +523,6 @@ menu_select_launch::menu_select_launch(mame_ui_manager &mui, render_container &c
, m_image_view(FIRST_VIEW)
, m_flags(256)
{
- // set up persistent cache for machine run
- {
- std::lock_guard<std::mutex> guard(s_cache_guard);
- auto const found(s_caches.find(&machine()));
- if (found != s_caches.end())
- {
- assert(found->second);
- m_cache = found->second;
- }
- else
- {
- m_cache = std::make_shared<cache>(machine());
- s_caches.emplace(&machine(), m_cache);
- add_cleanup_callback(&menu_select_launch::exit);
- }
- }
}
@@ -663,12 +644,12 @@ void menu_select_launch::custom_render(void *selectedref, float top, float botto
// determine the text to render below
ui_software_info const *swinfo;
- game_driver const *driver;
- get_selection(swinfo, driver);
+ ui_system_info const *system;
+ get_selection(swinfo, system);
bool isstar = false;
rgb_t color = ui().colors().background_color();
- if (swinfo && ((swinfo->startempty != 1) || !driver))
+ if (swinfo && !swinfo->startempty)
{
isstar = mame_machine_manager::instance()->favorite().is_favorite_system_software(*swinfo);
@@ -704,26 +685,29 @@ void menu_select_launch::custom_render(void *selectedref, float top, float botto
// last line is romset name
tempbuf[4] = string_format(_("Software list/item: %1$s:%2$s"), swinfo->listname, swinfo->shortname);
}
- else if (driver)
+ else if (system || (swinfo && swinfo->driver))
{
- isstar = mame_machine_manager::instance()->favorite().is_favorite_system(*driver);
+ game_driver const &driver(system ? *system->driver : *swinfo->driver);
+ isstar = mame_machine_manager::instance()->favorite().is_favorite_system(driver);
- // first line is game description/game name
- tempbuf[0] = make_driver_description(*driver);
+ // first line is the ROM set
+ tempbuf[0] = string_format(_("Romset: %1$-.100s"), driver.name);
// next line is year, manufacturer
- tempbuf[1] = string_format(_("%1$s, %2$-.100s"), driver->year, driver->manufacturer);
+ tempbuf[1] = string_format(_("%1$s, %2$-.100s"), driver.year, driver.manufacturer);
// next line is clone/parent status
- int cloneof = driver_list::non_bios_clone(*driver);
+ int cloneof = driver_list::non_bios_clone(driver);
- if (cloneof != -1)
- tempbuf[2] = string_format(_("Driver is clone of: %1$-.100s"), driver_list::driver(cloneof).type.fullname());
- else
+ if (0 > cloneof)
tempbuf[2] = _("Driver is parent");
+ else if (system)
+ tempbuf[2] = string_format(_("Driver is clone of: %1$-.100s"), system->parent);
+ else
+ tempbuf[2] = string_format(_("Driver is clone of: %1$-.100s"), driver_list::driver(cloneof).type.fullname());
// next line is overall driver status
- system_flags const &flags(get_system_flags(*driver));
+ system_flags const &flags(get_system_flags(driver));
if (flags.machine_flags() & machine_flags::NOT_WORKING)
tempbuf[3] = _("Overall: NOT WORKING");
else if ((flags.unemulated_features() | flags.imperfect_features()) & device_t::feature::PROTECTION)
@@ -739,7 +723,7 @@ void menu_select_launch::custom_render(void *selectedref, float top, float botto
else
tempbuf[4] = _("Graphics: OK, ");
- if (driver->flags & machine_flags::NO_SOUND_HW)
+ if (driver.flags & machine_flags::NO_SOUND_HW)
tempbuf[4].append(_("Sound: None"));
else if (flags.unemulated_features() & device_t::feature::SOUND)
tempbuf[4].append(_("Sound: Unimplemented"));
@@ -852,19 +836,19 @@ void menu_select_launch::rotate_focus(int dir)
void menu_select_launch::inkey_dats()
{
ui_software_info const *software;
- game_driver const *driver;
- get_selection(software, driver);
+ ui_system_info const *system;
+ get_selection(software, system);
if (software)
{
if (software->startempty && mame_machine_manager::instance()->lua()->call_plugin_check<const char *>("data_list", software->driver->name, true))
menu::stack_push<menu_dats_view>(ui(), container(), software->driver);
- else if (mame_machine_manager::instance()->lua()->call_plugin_check<const char *>("data_list", std::string(software->shortname).append(1, ',').append(software->listname).c_str()) || !software->usage.empty())
+ else if (mame_machine_manager::instance()->lua()->call_plugin_check<const char *>("data_list", std::string(software->shortname).append(1, ',').append(software->listname).c_str()) || !software->infotext.empty())
menu::stack_push<menu_dats_view>(ui(), container(), software);
}
- else if (driver)
+ else if (system)
{
- if (mame_machine_manager::instance()->lua()->call_plugin_check<const char *>("data_list", driver->name, true))
- menu::stack_push<menu_dats_view>(ui(), container(), driver);
+ if (mame_machine_manager::instance()->lua()->call_plugin_check<const char *>("data_list", system->driver->name, true))
+ menu::stack_push<menu_dats_view>(ui(), container(), system->driver);
}
}
@@ -1261,8 +1245,8 @@ void menu_select_launch::draw_toolbar(float x1, float y1, float x2, float y2)
y1 += ui().box_tb_border();
y2 -= ui().box_tb_border();
- texture_ptr_vector const &t_texture(m_is_swlist ? m_cache->sw_toolbar_texture() : m_cache->toolbar_texture());
- bitmap_vector const &t_bitmap(m_is_swlist ? m_cache->sw_toolbar_bitmap() : m_cache->toolbar_bitmap());
+ texture_ptr_vector const &t_texture(m_is_swlist ? m_cache.sw_toolbar_texture() : m_cache.toolbar_texture());
+ bitmap_vector const &t_bitmap(m_is_swlist ? m_cache.sw_toolbar_bitmap() : m_cache.toolbar_bitmap());
auto const num_valid(std::count_if(std::begin(t_bitmap), std::end(t_bitmap), [](bitmap_argb32 const &e) { return e.valid(); }));
@@ -1300,7 +1284,7 @@ void menu_select_launch::draw_star(float x0, float y0)
{
float y1 = y0 + ui().get_line_height();
float x1 = x0 + ui().get_line_height() * container().manager().ui_aspect(&container());
- container().add_quad(x0, y0, x1, y1, rgb_t::white(), m_cache->star_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_PACKABLE);
+ container().add_quad(x0, y0, x1, y1, rgb_t::white(), m_cache.star_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_PACKABLE);
}
@@ -1335,7 +1319,7 @@ 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(_("selmenu-artwork", arts_info[m_image_view].first));
// get search path
std::string addpath;
@@ -2253,12 +2237,12 @@ float menu_select_launch::draw_right_box_title(float x1, float y1, float x2, flo
void menu_select_launch::arts_render(float origx1, float origy1, float origx2, float origy2)
{
ui_software_info const *software;
- game_driver const *driver;
- get_selection(software, driver);
+ ui_system_info const *system;
+ get_selection(software, system);
- if (software && (!software->startempty || !driver))
+ if (software && (!software->startempty || !system))
{
- m_cache->set_snapx_driver(nullptr);
+ m_cache.set_snapx_driver(nullptr);
if (m_default_image)
m_image_view = (software->startempty == 0) ? SNAPSHOT_VIEW : CABINETS_VIEW;
@@ -2267,7 +2251,7 @@ void menu_select_launch::arts_render(float origx1, float origy1, float origx2, f
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() || m_switch_image)
{
emu_file snapfile(searchstr.c_str(), OPEN_FLAG_READ);
bitmap_argb32 tmp_bitmap;
@@ -2287,7 +2271,7 @@ void menu_select_launch::arts_render(float origx1, float origy1, float origx2, f
load_image(tmp_bitmap, snapfile, util::path_concat(software->driver->name + software->part, software->shortname));
}
- m_cache->set_snapx_software(software);
+ m_cache.set_snapx_software(software);
m_switch_image = false;
arts_render_images(std::move(tmp_bitmap), origx1, origy1, origx2, origy2);
}
@@ -2295,23 +2279,23 @@ void menu_select_launch::arts_render(float origx1, float origy1, float origx2, f
// if the image is available, loaded and valid, display it
draw_snapx(origx1, origy1, origx2, origy2);
}
- else if (driver)
+ else if (system)
{
- m_cache->set_snapx_software(nullptr);
+ 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;
+ m_image_view = ((system->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(system->driver) || !snapx_valid() || m_switch_image)
{
emu_file snapfile(searchstr, OPEN_FLAG_READ);
bitmap_argb32 tmp_bitmap;
- load_driver_image(tmp_bitmap, snapfile, *driver);
+ load_driver_image(tmp_bitmap, snapfile, *system->driver);
- m_cache->set_snapx_driver(driver);
+ m_cache.set_snapx_driver(system->driver);
m_switch_image = false;
arts_render_images(std::move(tmp_bitmap), origx1, origy1, origx2, origy2);
}
@@ -2340,7 +2324,7 @@ std::string menu_select_launch::arts_render_common(float origx1, float origy1, f
{
float text_length;
ui().draw_text_full(container(),
- _(arts_info[x].first), origx1, origy1, origx2 - origx1,
+ _("selmenu-artwork", arts_info[x].first), origx1, origy1, origx2 - origx1,
ui::text_layout::CENTER, ui::text_layout::TRUNCATE, mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(),
&text_length, nullptr);
title_size = (std::max)(text_length + 0.01f, title_size);
@@ -2389,7 +2373,7 @@ void menu_select_launch::arts_render_images(bitmap_argb32 &&tmp_bitmap, float or
if (!tmp_bitmap.valid())
{
tmp_bitmap.allocate(256, 256);
- const bitmap_argb32 &src(m_cache->no_avail_bitmap());
+ const bitmap_argb32 &src(m_cache.no_avail_bitmap());
for (int x = 0; x < 256; x++)
{
for (int y = 0; y < 256; y++)
@@ -2398,7 +2382,7 @@ void menu_select_launch::arts_render_images(bitmap_argb32 &&tmp_bitmap, float or
no_available = true;
}
- bitmap_argb32 &snapx_bitmap(m_cache->snapx_bitmap());
+ bitmap_argb32 &snapx_bitmap(m_cache.snapx_bitmap());
if (tmp_bitmap.valid())
{
float panel_width = origx2 - origx1 - 0.02f;
@@ -2459,7 +2443,7 @@ void menu_select_launch::arts_render_images(bitmap_argb32 &&tmp_bitmap, float or
snapx_bitmap.pix(y + y1, x + x1) = dest_bitmap.pix(y, x);
// apply bitmap
- m_cache->snapx_texture()->set_bitmap(snapx_bitmap, snapx_bitmap.cliprect(), TEXFORMAT_ARGB32);
+ m_cache.snapx_texture()->set_bitmap(snapx_bitmap, snapx_bitmap.cliprect(), TEXFORMAT_ARGB32);
}
else
{
@@ -2484,7 +2468,7 @@ void menu_select_launch::draw_snapx(float origx1, float origy1, float origx2, fl
float const y2 = origy2 - ui().box_tb_border() - line_height;
// apply texture
- container().add_quad(x1, y1, x2, y2, rgb_t::white(), m_cache->snapx_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ container().add_quad(x1, y1, x2, y2, rgb_t::white(), m_cache.snapx_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
}
}
@@ -2598,13 +2582,6 @@ bool menu_select_launch::has_multiple_bios(game_driver const &driver, s_bios &bi
}
-void menu_select_launch::exit(running_machine &machine)
-{
- std::lock_guard<std::mutex> guard(s_cache_guard);
- s_caches.erase(&machine);
-}
-
-
//-------------------------------------------------
// draw collapsed left panel
//-------------------------------------------------
@@ -2648,14 +2625,14 @@ void menu_select_launch::infos_render(float origx1, float origy1, float origx2,
std::vector<int> xend;
const char *first = "";
ui_software_info const *software;
- game_driver const *driver;
+ ui_system_info const *system;
int total;
- get_selection(software, driver);
+ get_selection(software, system);
- if (software && (!software->startempty || !driver))
+ if (software && (!software->startempty || !system))
{
m_info_driver = nullptr;
- first = __("Usage");
+ first = N_("Software List Info");
if ((m_info_software != software) || (m_info_view != ui_globals::cur_sw_dats_view))
{
@@ -2677,7 +2654,7 @@ void menu_select_launch::infos_render(float origx1, float origy1, float origx2,
if (m_info_view == 0)
{
- m_info_buffer = software->usage;
+ m_info_buffer = software->infotext;
}
else
{
@@ -2687,31 +2664,33 @@ void menu_select_launch::infos_render(float origx1, float origy1, float origx2,
}
total = ui_globals::cur_sw_dats_total;
}
- else if (driver)
+ else if (system)
{
m_info_software = nullptr;
- first = __("General Info");
+ first = N_("General Info");
- if (driver != m_info_driver || ui_globals::curdats_view != m_info_view)
+ if (system->driver != m_info_driver || ui_globals::curdats_view != m_info_view)
{
m_info_buffer.clear();
- if (driver == m_info_driver)
+ if (system->driver == m_info_driver)
{
m_info_view = ui_globals::curdats_view;
}
else
{
- m_info_driver = driver;
+ m_info_driver = system->driver;
m_info_view = 0;
ui_globals::curdats_view = 0;
m_items_list.clear();
- mame_machine_manager::instance()->lua()->call_plugin("data_list", driver->name, m_items_list);
+ mame_machine_manager::instance()->lua()->call_plugin("data_list", system->driver->name, m_items_list);
ui_globals::curdats_total = m_items_list.size() + 1;
}
if (m_info_view == 0)
- general_info(driver, m_info_buffer);
+ {
+ general_info(*system, m_info_buffer);
+ }
else
{
m_info_buffer = "";
@@ -2731,13 +2710,13 @@ void menu_select_launch::infos_render(float origx1, float origy1, float origx2,
float const ud_arrow_width = line_height * aspect;
float oy1 = origy1 + line_height;
- std::string_view const snaptext(m_info_view ? std::string_view(m_items_list[m_info_view - 1]) : std::string_view(_(first)));
+ std::string_view const snaptext(m_info_view ? std::string_view(m_items_list[m_info_view - 1]) : std::string_view(_("selmenu-artwork", first)));
// get width of widest title
float title_size(0.0f);
for (std::size_t x = 0; total > x; ++x)
{
- std::string_view const name(x ? std::string_view(m_items_list[x - 1]) : std::string_view(_(first)));
+ std::string_view const name(x ? std::string_view(m_items_list[x - 1]) : std::string_view(_("selmenu-artwork", first)));
float txt_length(0.0f);
ui().draw_text_full(
container(), name,
diff --git a/src/frontend/mame/ui/selmenu.h b/src/frontend/mame/ui/selmenu.h
index 251df450e72..040c4e991fb 100644
--- a/src/frontend/mame/ui/selmenu.h
+++ b/src/frontend/mame/ui/selmenu.h
@@ -20,12 +20,13 @@
#include <map>
#include <memory>
-#include <mutex>
#include <vector>
+struct ui_system_info;
struct ui_software_info;
+
namespace ui {
class machine_static_info;
@@ -220,8 +221,16 @@ private:
texture_ptr_vector m_toolbar_texture;
texture_ptr_vector m_sw_toolbar_texture;
};
- using cache_ptr = std::shared_ptr<cache>;
- using cache_ptr_map = std::map<running_machine *, cache_ptr>;
+
+ // this is to satisfy the std::any requirement that objects be copyable
+ class cache_wrapper : public cache
+ {
+ public:
+ cache_wrapper(running_machine &machine) : cache(machine), m_machine(machine) { }
+ cache_wrapper(cache_wrapper const &that) : cache(that.m_machine), m_machine(that.m_machine) { }
+ private:
+ running_machine &m_machine;
+ };
using flags_cache = util::lru_cache_map<game_driver const *, system_flags>;
@@ -229,7 +238,7 @@ private:
bool mouse_pressed() const { return (osd_ticks() >= m_repeat); }
void set_pressed();
- bool snapx_valid() const { return m_cache->snapx_bitmap().valid(); }
+ bool snapx_valid() const { return m_cache.snapx_bitmap().valid(); }
// draw left panel
virtual float draw_left_panel(float x1, float y1, float x2, float y2) = 0;
@@ -237,10 +246,10 @@ private:
// draw infos
void infos_render(float x1, float y1, float x2, float y2);
- virtual void general_info(const game_driver *driver, std::string &buffer) = 0;
+ virtual void general_info(ui_system_info const &system, std::string &buffer) = 0;
// get selected software and/or driver
- virtual void get_selection(ui_software_info const *&software, game_driver const *&driver) const = 0;
+ virtual void get_selection(ui_software_info const *&software, ui_system_info const *&system) const = 0;
virtual bool accept_search() const { return true; }
void select_prev()
{
@@ -293,7 +302,6 @@ private:
// text for main top/bottom panels
virtual void make_topbox_text(std::string &line0, std::string &line1, std::string &line2) const = 0;
- virtual std::string make_driver_description(game_driver const &driver) const = 0;
virtual std::string make_software_description(ui_software_info const &software) const = 0;
// filter navigation
@@ -305,9 +313,6 @@ private:
static bool has_multiple_bios(ui_software_info const &swinfo, s_bios &biosname);
static bool has_multiple_bios(game_driver const &driver, s_bios &biosname);
- // cleanup function
- static void exit(running_machine &machine);
-
bool m_ui_error;
std::string m_error_text;
@@ -317,7 +322,7 @@ private:
std::vector<std::string> m_items_list;
std::string m_info_buffer;
- cache_ptr m_cache;
+ cache &m_cache;
bool m_is_swlist;
focused_menu m_focus;
bool m_pressed; // mouse button held down
@@ -330,9 +335,6 @@ private:
bool m_default_image;
uint8_t m_image_view;
flags_cache m_flags;
-
- static std::mutex s_cache_guard;
- static cache_ptr_map s_caches;
};
} // namespace ui
diff --git a/src/frontend/mame/ui/selsoft.cpp b/src/frontend/mame/ui/selsoft.cpp
index e00a1618016..8e48cbd51cb 100644
--- a/src/frontend/mame/ui/selsoft.cpp
+++ b/src/frontend/mame/ui/selsoft.cpp
@@ -29,26 +29,329 @@
#include <algorithm>
#include <iterator>
#include <functional>
+#include <thread>
#include <locale>
namespace ui {
-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)
+struct menu_select_software::search_item
{
-}
+ search_item(search_item const &) = default;
+ search_item(search_item &&) = default;
+ search_item &operator=(search_item const &) = default;
+ search_item &operator=(search_item &&) = default;
+
+ 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)))
+ , ucs_alttitles()
+ , penalty(1.0)
+ {
+ ucs_alttitles.reserve(s.alttitles.size());
+ for (std::string const &alttitle : s.alttitles)
+ ucs_alttitles.emplace_back(ustr_from_utf8(normalize_unicode(alttitle, unicode_normalization_form::D, true)));
+ }
+
+ void set_penalty(std::u32string const &search)
+ {
+ penalty = util::edit_distance(search, ucs_shortname);
+ if (penalty)
+ penalty = (std::min)(penalty, util::edit_distance(search, ucs_longname));
+ auto it(ucs_alttitles.begin());
+ while (penalty && (ucs_alttitles.end() != it))
+ penalty = (std::min)(penalty, util::edit_distance(search, *it++));
+ }
+
+ std::reference_wrapper<ui_software_info const> software;
+ std::u32string ucs_shortname;
+ std::u32string ucs_longname;
+ std::vector<std::u32string> ucs_alttitles;
+ double penalty;
+};
-void menu_select_software::search_item::set_penalty(std::u32string const &search)
+
+
+class menu_select_software::machine_data
{
- // 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));
-}
+public:
+ machine_data(menu_select_software &menu)
+ : m_icons(MAX_ICONS_RENDER)
+ , m_has_empty_start(false)
+ , m_filter_data()
+ , m_filters()
+ , m_filter_type(software_filter::ALL)
+ , m_swinfo()
+ , m_searchlist()
+ {
+ // add start empty item
+ m_swinfo.emplace_back(menu.m_driver);
+
+ machine_config config(menu.m_driver, menu.machine().options());
+
+ // see if any media devices require an image to be loaded
+ m_has_empty_start = true;
+ for (device_image_interface &image : image_interface_enumerator(config.root_device()))
+ {
+ if (!image.filename() && image.must_be_loaded())
+ {
+ m_has_empty_start = false;
+ break;
+ }
+ }
+
+ // 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 };
+ for (software_list_device &swlist : software_list_device_enumerator(config.root_device()))
+ {
+ m_filter_data.add_list(swlist.list_name(), swlist.description());
+ menu.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);
+ for (device_image_interface &image : image_interface_enumerator(config.root_device()))
+ {
+ char const *const interface = image.image_interface();
+ if (interface && part.matches_interface(interface))
+ {
+ instance_name = image.instance_name().c_str();
+ type_name = image.image_type_name();
+ break;
+ }
+ }
+
+ 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, menu.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());
+
+ 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));
+ }
+ }
+
+ // populate filter choices
+ m_filter_data.add_region(ins->longname);
+ m_filter_data.add_publisher(ins->publisher);
+ m_filter_data.add_year(ins->year);
+ for (software_info_item const &i : ins->info)
+ m_filter_data.add_info(i);
+ m_filter_data.add_device_type(ins->devicetype);
+ }
+ }
+ }
+ }
+
+ std::string searchstr, curpath;
+ for (auto &elem : m_filter_data.list_names())
+ {
+ path_iterator path(menu.machine().options().media_path());
+ while (path.next(curpath))
+ {
+ searchstr.assign(curpath).append(PATH_SEPARATOR).append(elem).append(";");
+ file_enumerator fpath(searchstr.c_str());
+
+ // iterate while we get new objects
+ osd::directory::entry const *dir;
+ while ((dir = fpath.next()) != nullptr)
+ {
+ std::string name;
+ if (dir->type == osd::directory::entry::entry_type::FILE)
+ name = strmakelower(core_filename_extract_base(dir->name, true));
+ else if (dir->type == osd::directory::entry::entry_type::DIR && strcmp(dir->name, ".") != 0)
+ name = strmakelower(dir->name);
+ else
+ continue;
+
+ for (auto & yelem : m_swinfo)
+ if (yelem.shortname == name && yelem.listname == elem)
+ {
+ yelem.available = true;
+ break;
+ }
+ }
+ }
+ }
+
+ // sort array
+ std::collate<wchar_t> const &coll = std::use_facet<std::collate<wchar_t>>(std::locale());
+ auto const compare_names =
+ [&coll] (std::string const &x, std::string const &y) -> bool
+ {
+ std::wstring const wx = wstring_from_utf8(x);
+ std::wstring const wy = wstring_from_utf8(y);
+ return 0 > coll.compare(wx.data(), wx.data() + wx.size(), wy.data(), wy.data() + wy.size());
+ };
+ std::stable_sort(
+ m_swinfo.begin() + 1,
+ m_swinfo.end(),
+ [&compare_names] (ui_software_info const &a, ui_software_info const &b) -> bool
+ {
+ bool const clonex = !a.parentname.empty() && !a.parentlongname.empty();
+ bool const cloney = !b.parentname.empty() && !b.parentlongname.empty();
+
+ if (!clonex && !cloney)
+ {
+ return compare_names(a.longname, b.longname);
+ }
+ else if (!clonex && cloney)
+ {
+ if ((a.shortname == b.parentname) && (a.instance == b.instance))
+ return true;
+ else
+ return compare_names(a.longname, b.longname);
+ }
+ else if (clonex && !cloney)
+ {
+ if ((a.parentname == b.shortname) && (a.instance == b.instance))
+ return false;
+ else
+ return compare_names(a.longname, b.longname);
+ }
+ else if ((a.parentname == b.parentname) && (a.instance == b.instance))
+ {
+ return compare_names(a.longname, b.longname);
+ }
+ else
+ {
+ return compare_names(a.parentlongname, b.parentlongname);
+ }
+ });
+
+ // start populating search info in background
+ m_search_thread = std::make_unique<std::thread>(
+ [this] ()
+ {
+ m_searchlist.reserve(m_swinfo.size());
+ for (ui_software_info const &sw : m_swinfo)
+ m_searchlist.emplace_back(sw);
+ });
+
+ // build derivative filter data
+ m_filter_data.finalise();
+
+ // load custom filters info from file
+ emu_file file(menu.ui().options().ui_path(), OPEN_FLAG_READ);
+ if (!file.open(util::string_format("custom_%s_filter.ini", menu.m_driver.name)))
+ {
+ software_filter::ptr flt(software_filter::create(file, m_filter_data));
+ if (flt)
+ m_filters.emplace(flt->get_type(), std::move(flt));
+ file.close();
+ }
+ }
+
+ ~machine_data()
+ {
+ if (m_search_thread)
+ m_search_thread->join();
+ }
+
+ icon_cache &icons() { return m_icons; }
+
+ bool has_empty_start() const noexcept { return m_has_empty_start; }
+
+ filter_map const &filters() const noexcept { return m_filters; }
+
+ software_filter::type filter_type() const noexcept { return m_filter_type; }
+ void set_filter_type(software_filter::type type) noexcept { m_filter_type = type; }
+
+ software_filter const *current_filter() const noexcept
+ {
+ auto const found(m_filters.find(m_filter_type));
+ return (m_filters.end() != found) ? found->second.get() : nullptr;
+ }
+
+ software_filter &get_filter(software_filter::type type)
+ {
+ filter_map::const_iterator it(m_filters.find(type));
+ if (m_filters.end() != it)
+ return *it->second;
+ else
+ return *m_filters.emplace(type, software_filter::create(type, m_filter_data)).first->second;
+ }
+
+ std::vector<ui_software_info> const &swinfo() const noexcept { return m_swinfo; }
+
+ std::vector<search_item> const &find_matches(std::string const &search)
+ {
+ // ensure search list is populated
+ if (m_search_thread)
+ {
+ m_search_thread->join();
+ m_search_thread.reset();
+ }
+
+ // update search
+ const std::u32string ucs_search(ustr_from_utf8(normalize_unicode(search, unicode_normalization_form::D, true)));
+ for (search_item &entry : m_searchlist)
+ entry.set_penalty(ucs_search);
+
+ // 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; });
+
+ // return reference to search results
+ return m_searchlist;
+ }
+
+private:
+ icon_cache m_icons;
+ 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::unique_ptr<std::thread> m_search_thread;
+};
//-------------------------------------------------
@@ -56,23 +359,35 @@ void menu_select_software::search_item::set_penalty(std::u32string const &search
//-------------------------------------------------
menu_select_software::menu_select_software(mame_ui_manager &mui, render_container &container, game_driver const &driver)
+ : menu_select_software(mui, container, driver.type.fullname(), driver)
+{
+}
+
+menu_select_software::menu_select_software(mame_ui_manager &mui, render_container &container, ui_system_info const &system)
+ : menu_select_software(mui, container, system.description.c_str(), *system.driver)
+{
+}
+
+menu_select_software::menu_select_software(
+ mame_ui_manager &mui,
+ render_container &container,
+ char const *description,
+ game_driver const &driver)
: menu_select_launch(mui, container, true)
, m_icon_paths()
- , m_icons(MAX_ICONS_RENDER)
+ , m_description(description)
, 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);
- build_software_list();
- load_sw_custom_filters();
- m_filter_highlight = m_filter_type;
+ using machine_data_cache = util::lru_cache_map<game_driver const *, std::shared_ptr<machine_data> >;
+ auto &cached(mui.get_session_data<menu_select_software, machine_data_cache>(8)[&driver]);
+ if (!cached)
+ cached = std::make_shared<machine_data>(*this);
+ m_data = cached;
+
+ m_filter_highlight = m_data->filter_type();
set_switch_image();
ui_globals::cur_sw_dats_view = 0;
@@ -204,7 +519,7 @@ 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?
+ for (auto &icon : m_data->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;
@@ -212,37 +527,37 @@ void menu_select_software::populate(float &customtop, float &custombottom)
// start with an empty list
m_displaylist.clear();
- filter_map::const_iterator const flt(m_filters.find(m_filter_type));
+ software_filter const *const flt(m_data->current_filter());
// no active search
if (m_search.empty())
{
// if the device can be loaded empty, add an item
- if (m_has_empty_start)
- item_append("[Start empty]", flags_ui, (void *)&m_swinfo[0]);
+ if (m_data->has_empty_start())
+ item_append("[Start empty]", flags_ui, (void *)&m_data->swinfo()[0]);
- if (m_filters.end() == flt)
- std::copy(std::next(m_swinfo.begin()), m_swinfo.end(), std::back_inserter(m_displaylist));
+ if (!flt)
+ std::copy(std::next(m_data->swinfo().begin()), m_data->swinfo().end(), std::back_inserter(m_displaylist));
else
- flt->second->apply(std::next(m_swinfo.begin()), m_swinfo.end(), std::back_inserter(m_displaylist));
+ flt->apply(std::next(m_data->swinfo().begin()), m_data->swinfo().end(), std::back_inserter(m_displaylist));
}
else
{
- find_matches();
+ std::vector<search_item> const &searchlist = m_data->find_matches(m_search);
- if (m_filters.end() == flt)
+ if (!flt)
{
std::transform(
- m_searchlist.begin(),
- std::next(m_searchlist.begin(), (std::min)(m_searchlist.size(), MAX_VISIBLE_SEARCH)),
+ searchlist.begin(),
+ std::next(searchlist.begin(), (std::min)(searchlist.size(), MAX_VISIBLE_SEARCH)),
std::back_inserter(m_displaylist),
[] (search_item const &entry) { return entry.software; });
}
else
{
- for (auto it = m_searchlist.begin(); (m_searchlist.end() != it) && (MAX_VISIBLE_SEARCH > m_displaylist.size()); ++it)
+ for (auto it = searchlist.begin(); (searchlist.end() != it) && (MAX_VISIBLE_SEARCH > m_displaylist.size()); ++it)
{
- if (flt->second->apply(it->software))
+ if (flt->apply(it->software))
m_displaylist.emplace_back(it->software);
}
}
@@ -254,7 +569,7 @@ void menu_select_software::populate(float &customtop, float &custombottom)
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;
+ old_software = m_data->has_empty_start() ? curitem + 1 : curitem;
item_append(
m_displaylist[curitem].get().longname, m_displaylist[curitem].get().devicetype,
@@ -276,191 +591,6 @@ void menu_select_software::populate(float &customtop, float &custombottom)
reselect_last::reset();
}
-//-------------------------------------------------
-// build a list of software
-//-------------------------------------------------
-
-void menu_select_software::build_software_list()
-{
- // add start empty item
- m_swinfo.emplace_back(m_driver);
-
- machine_config config(m_driver, machine().options());
-
- // see if any media devices require an image to be loaded
- m_has_empty_start = true;
- for (device_image_interface &image : image_interface_enumerator(config.root_device()))
- {
- if (!image.filename() && image.must_be_loaded())
- {
- m_has_empty_start = false;
- break;
- }
- }
-
- // 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 };
- for (software_list_device &swlist : software_list_device_enumerator(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);
- for (device_image_interface &image : image_interface_enumerator(config.root_device()))
- {
- char const *const interface = image.image_interface();
- if (interface && part.matches_interface(interface))
- {
- instance_name = image.instance_name().c_str();
- type_name = image.image_type_name();
- break;
- }
- }
-
- 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());
-
- 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));
- }
- }
-
- // 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);
- }
- }
- }
- }
-
- std::string searchstr, curpath;
- for (auto &elem : m_filter_data.list_names())
- {
- path_iterator path(machine().options().media_path());
- while (path.next(curpath))
- {
- searchstr.assign(curpath).append(PATH_SEPARATOR).append(elem).append(";");
- file_enumerator fpath(searchstr.c_str());
-
- // iterate while we get new objects
- osd::directory::entry const *dir;
- while ((dir = fpath.next()) != nullptr)
- {
- std::string name;
- if (dir->type == osd::directory::entry::entry_type::FILE)
- name = strmakelower(core_filename_extract_base(dir->name, true));
- else if (dir->type == osd::directory::entry::entry_type::DIR && strcmp(dir->name, ".") != 0)
- name = strmakelower(dir->name);
- else
- continue;
-
- for (auto & yelem : m_swinfo)
- if (yelem.shortname == name && yelem.listname == elem)
- {
- yelem.available = true;
- break;
- }
- }
- }
- }
-
- // sort array
- std::collate<wchar_t> const &coll = std::use_facet<std::collate<wchar_t>>(std::locale());
- auto const compare_names =
- [&coll] (std::string const &x, std::string const &y) -> bool
- {
- std::wstring const wx = wstring_from_utf8(x);
- std::wstring const wy = wstring_from_utf8(y);
- return 0 > coll.compare(wx.data(), wx.data() + wx.size(), wy.data(), wy.data() + wy.size());
- };
- std::stable_sort(
- m_swinfo.begin() + 1,
- m_swinfo.end(),
- [&compare_names] (ui_software_info const &a, ui_software_info const &b) -> bool
- {
- bool const clonex = !a.parentname.empty() && !a.parentlongname.empty();
- bool const cloney = !b.parentname.empty() && !b.parentlongname.empty();
-
- if (!clonex && !cloney)
- {
- return compare_names(a.longname, b.longname);
- }
- else if (!clonex && cloney)
- {
- if ((a.shortname == b.parentname) && (a.instance == b.instance))
- return true;
- else
- return compare_names(a.longname, b.longname);
- }
- else if (clonex && !cloney)
- {
- if ((a.parentname == b.shortname) && (a.instance == b.instance))
- return false;
- else
- return compare_names(a.longname, b.longname);
- }
- else if ((a.parentname == b.parentname) && (a.instance == b.instance))
- {
- return compare_names(a.longname, b.longname);
- }
- else
- {
- return compare_names(a.parentlongname, b.parentlongname);
- }
- });
-
-
- m_filter_data.finalise();
-}
-
//-------------------------------------------------
// handle select key event
@@ -512,54 +642,12 @@ void menu_select_software::inkey_select(const event *menu_event)
//-------------------------------------------------
-// load custom filters info from file
-//-------------------------------------------------
-
-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(util::string_format("custom_%s_filter.ini", m_driver.name)))
- {
- software_filter::ptr flt(software_filter::create(file, m_filter_data));
- if (flt)
- m_filters.emplace(flt->get_type(), std::move(flt));
- file.close();
- }
-}
-
-//-------------------------------------------------
-// find approximate matches
-//-------------------------------------------------
-
-void menu_select_software::find_matches()
-{
- // ensure search list is populated
- if (m_searchlist.empty())
- {
- m_searchlist.reserve(m_swinfo.size());
- std::copy(m_swinfo.begin(), m_swinfo.end(), std::back_inserter(m_searchlist));
- }
-
- // 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);
-
- // 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; });
-}
-
-//-------------------------------------------------
// draw left box
//-------------------------------------------------
float menu_select_software::draw_left_panel(float x1, float y1, float x2, float y2)
{
- return menu_select_launch::draw_left_panel<software_filter>(m_filter_type, m_filters, x1, y1, x2, y2);
+ return menu_select_launch::draw_left_panel<software_filter>(m_data->filter_type(), m_data->filters(), x1, y1, x2, y2);
}
@@ -575,17 +663,17 @@ render_texture *menu_select_software::get_icon_texture(int linenum, void *select
if (swinfo->startempty)
return nullptr;
- icon_cache::iterator icon(m_icons.find(swinfo));
- if ((m_icons.end() == icon) || !icon->second.texture)
+ icon_cache::iterator icon(m_data->icons().find(swinfo));
+ if ((m_data->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)
+ if (m_data->icons().end() == icon)
{
- icon = m_icons.emplace(swinfo, texture_ptr(machine().render().texture_alloc(), machine().render())).first;
+ icon = m_data->icons().emplace(swinfo, texture_ptr(machine().render().texture_alloc(), machine().render())).first;
}
else
{
@@ -617,36 +705,29 @@ render_texture *menu_select_software::get_icon_texture(int linenum, void *select
// get selected software and/or driver
//-------------------------------------------------
-void menu_select_software::get_selection(ui_software_info const *&software, game_driver const *&driver) const
+void menu_select_software::get_selection(ui_software_info const *&software, ui_system_info const *&system) const
{
software = reinterpret_cast<ui_software_info const *>(get_selection_ptr());
- driver = software ? software->driver : nullptr;
+ system = nullptr;
}
void menu_select_software::make_topbox_text(std::string &line0, std::string &line1, std::string &line2) const
{
// determine the text for the header
- int vis_item = !m_search.empty() ? m_available_items : (m_has_empty_start ? m_available_items - 1 : m_available_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());
+ int vis_item = !m_search.empty() ? m_available_items : (m_data->has_empty_start() ? m_available_items - 1 : m_available_items);
+ line0 = string_format(_("%1$s %2$s ( %3$d / %4$d software packages )"), emulator_info::get_appname(), bare_build_version, vis_item, m_data->swinfo().size() - 1);
+ line1 = string_format(_("Driver: \"%1$s\" software list "), m_description);
- 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);
+ software_filter const *const it(m_data->current_filter());
+ char const *const filter(it ? it->filter_text() : nullptr);
if (filter)
- line2 = string_format(_("%1$s: %2$s - Search: %3$s_"), it->second->display_name(), filter, m_search);
+ line2 = string_format(_("%1$s: %2$s - Search: %3$s_"), it->display_name(), filter, m_search);
else
line2 = string_format(_("Search: %1$s_"), m_search);
}
-std::string menu_select_software::make_driver_description(game_driver const &driver) const
-{
- // first line is game description
- return string_format(_("%1$-.100s"), driver.type.fullname());
-}
-
-
std::string menu_select_software::make_software_description(ui_software_info const &software) const
{
// first line is long name
@@ -658,10 +739,7 @@ void menu_select_software::filter_selected()
{
if ((software_filter::FIRST <= m_filter_highlight) && (software_filter::LAST >= m_filter_highlight))
{
- 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(
+ m_data->get_filter(software_filter::type(m_filter_highlight)).show_ui(
ui(),
container(),
[this] (software_filter &filter)
@@ -676,7 +754,7 @@ void menu_select_software::filter_selected()
file.close();
}
}
- m_filter_type = new_type;
+ m_data->set_filter_type(new_type);
reset(reset_options::SELECT_FIRST);
});
}
diff --git a/src/frontend/mame/ui/selsoft.h b/src/frontend/mame/ui/selsoft.h
index 1bfdd9c1e48..ebf3e77df89 100644
--- a/src/frontend/mame/ui/selsoft.h
+++ b/src/frontend/mame/ui/selsoft.h
@@ -15,7 +15,10 @@
#include "ui/selmenu.h"
#include "ui/utils.h"
+#include "lrucache.h"
+
#include <map>
+#include <memory>
#include <string>
#include <vector>
@@ -27,26 +30,17 @@ 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, ui_system_info const &system);
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;
- };
+ struct search_item;
+ class machine_data;
+
+ menu_select_software(mame_ui_manager &mui, render_container &container, char const *description, game_driver const &driver);
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle() override;
@@ -56,11 +50,10 @@ private:
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;
+ virtual void get_selection(ui_software_info const *&software, ui_system_info const *&system) const override;
// text for main top/bottom panels
virtual void make_topbox_text(std::string &line0, std::string &line1, std::string &line2) const override;
- virtual std::string make_driver_description(game_driver const &driver) const override;
virtual std::string make_software_description(ui_software_info const &software) const override;
// filter navigation
@@ -69,25 +62,16 @@ private:
// toolbar
virtual void inkey_export() override { throw false; }
- void build_software_list();
- void find_matches();
- 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 { }
+ virtual void general_info(ui_system_info const &system, std::string &buffer) override { }
std::map<std::string, std::string> m_icon_paths;
- icon_cache m_icons;
+ char const *const m_description;
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::shared_ptr<machine_data> m_data;
- std::vector<ui_software_info> m_swinfo;
- std::vector<search_item> m_searchlist;
std::vector<std::reference_wrapper<ui_software_info const> > m_displaylist;
};
diff --git a/src/frontend/mame/ui/submenu.cpp b/src/frontend/mame/ui/submenu.cpp
index d93b7a8af6a..5e6e0cc4152 100644
--- a/src/frontend/mame/ui/submenu.cpp
+++ b/src/frontend/mame/ui/submenu.cpp
@@ -28,111 +28,111 @@ namespace ui {
std::vector<submenu::option> submenu::misc_options()
{
return std::vector<option>{
- { option_type::HEAD, __("Miscellaneous Options") },
- { option_type::UI, __("Skip imperfect emulation warnings"), OPTION_SKIP_WARNINGS },
- { option_type::UI, __("Re-select last machine launched"), OPTION_REMEMBER_LAST },
- { option_type::UI, __("Enlarge images in the right panel"), OPTION_ENLARGE_SNAPS },
- { option_type::EMU, __("Cheats"), OPTION_CHEAT },
- { option_type::EMU, __("Show mouse pointer"), OPTION_UI_MOUSE },
- { option_type::EMU, __("Confirm quit from machines"), OPTION_CONFIRM_QUIT },
- { option_type::EMU, __("Skip information screen at startup"), OPTION_SKIP_GAMEINFO },
- { option_type::UI, __("Force 4:3 aspect for snapshot display"), OPTION_FORCED4X3 },
- { option_type::UI, __("Use image as background"), OPTION_USE_BACKGROUND },
- { option_type::UI, __("Skip BIOS selection menu"), OPTION_SKIP_BIOS_MENU },
- { option_type::UI, __("Skip software parts selection menu"), OPTION_SKIP_PARTS_MENU },
- { option_type::UI, __("Info auto audit"), OPTION_INFO_AUTO_AUDIT },
- { option_type::UI, __("Hide romless machine from available list"),OPTION_HIDE_ROMLESS } };
+ { option_type::HEAD, N_("Miscellaneous Options") },
+ { option_type::UI, N_("Skip imperfect emulation warnings"), OPTION_SKIP_WARNINGS },
+ { option_type::UI, N_("Re-select last machine launched"), OPTION_REMEMBER_LAST },
+ { option_type::UI, N_("Enlarge images in the right panel"), OPTION_ENLARGE_SNAPS },
+ { option_type::EMU, N_("Cheats"), OPTION_CHEAT },
+ { option_type::EMU, N_("Show mouse pointer"), OPTION_UI_MOUSE },
+ { option_type::EMU, N_("Confirm quit from machines"), OPTION_CONFIRM_QUIT },
+ { option_type::EMU, N_("Skip information screen at startup"), OPTION_SKIP_GAMEINFO },
+ { option_type::UI, N_("Force 4:3 aspect for snapshot display"), OPTION_FORCED4X3 },
+ { option_type::UI, N_("Use image as background"), OPTION_USE_BACKGROUND },
+ { option_type::UI, N_("Skip BIOS selection menu"), OPTION_SKIP_BIOS_MENU },
+ { option_type::UI, N_("Skip software parts selection menu"), OPTION_SKIP_PARTS_MENU },
+ { option_type::UI, N_("Info auto audit"), OPTION_INFO_AUTO_AUDIT },
+ { option_type::UI, N_("Hide romless machine from available list"),OPTION_HIDE_ROMLESS } };
}
std::vector<submenu::option> submenu::advanced_options()
{
return std::vector<option>{
- { option_type::HEAD, __("Advanced Options") },
- { option_type::HEAD, __("Performance Options") },
- { option_type::EMU, __("Auto frame skip"), OPTION_AUTOFRAMESKIP },
- { option_type::EMU, __("Frame skip"), OPTION_FRAMESKIP },
- { option_type::EMU, __("Throttle"), OPTION_THROTTLE },
- { option_type::UI, __("Mute when unthrottled"), OPTION_UNTHROTTLE_MUTE },
- { option_type::EMU, __("Sleep"), OPTION_SLEEP },
- { option_type::EMU, __("Speed"), OPTION_SPEED },
- { option_type::EMU, __("Adjust speed to match refresh rate"), OPTION_REFRESHSPEED },
- { option_type::EMU, __("Low latency"), OPTION_LOWLATENCY },
-
- { option_type::HEAD, __("Rotation Options") },
- { option_type::EMU, __("Rotate"), OPTION_ROTATE },
- { option_type::EMU, __("Rotate right"), OPTION_ROR },
- { option_type::EMU, __("Rotate left"), OPTION_ROL },
- { option_type::EMU, __("Auto rotate right"), OPTION_AUTOROR },
- { option_type::EMU, __("Auto rotate left"), OPTION_AUTOROL },
- { option_type::EMU, __("Flip X"), OPTION_FLIPX },
- { option_type::EMU, __("Flip Y"), OPTION_FLIPY },
-
- { option_type::HEAD, __("Artwork Options") },
- { option_type::EMU, __("Zoom to screen area"), OPTION_ARTWORK_CROP },
-
- { option_type::HEAD, __("State/Playback Options") },
- { option_type::EMU, __("Automatic save/restore"), OPTION_AUTOSAVE },
- { option_type::EMU, __("Allow rewind"), OPTION_REWIND },
- { option_type::EMU, __("Rewind capacity"), OPTION_REWIND_CAPACITY },
- { option_type::EMU, __("Bilinear filtering for snapshots"), OPTION_SNAPBILINEAR },
- { option_type::EMU, __("Burn-in"), OPTION_BURNIN },
-
- { option_type::HEAD, __("Input Options") },
- { option_type::EMU, __("Coin lockout"), OPTION_COIN_LOCKOUT },
- { option_type::EMU, __("Mouse"), OPTION_MOUSE },
- { option_type::EMU, __("Joystick"), OPTION_JOYSTICK },
- { option_type::EMU, __("Lightgun"), OPTION_LIGHTGUN },
- { option_type::EMU, __("Multi-keyboard"), OPTION_MULTIKEYBOARD },
- { option_type::EMU, __("Multi-mouse"), OPTION_MULTIMOUSE },
- { option_type::EMU, __("Steadykey"), OPTION_STEADYKEY },
- { option_type::EMU, __("UI active"), OPTION_UI_ACTIVE },
- { option_type::EMU, __("Offscreen reload"), OPTION_OFFSCREEN_RELOAD },
- { option_type::EMU, __("Joystick deadzone"), OPTION_JOYSTICK_DEADZONE },
- { option_type::EMU, __("Joystick saturation"), OPTION_JOYSTICK_SATURATION },
- { option_type::EMU, __("Natural keyboard"), OPTION_NATURAL_KEYBOARD },
- { option_type::EMU, __("Simultaneous contradictory"), OPTION_JOYSTICK_CONTRADICTORY },
- { option_type::EMU, __("Coin impulse"), OPTION_COIN_IMPULSE } };
+ { option_type::HEAD, N_("Advanced Options") },
+ { option_type::HEAD, N_("Performance Options") },
+ { option_type::EMU, N_("Auto frame skip"), OPTION_AUTOFRAMESKIP },
+ { option_type::EMU, N_("Frame skip"), OPTION_FRAMESKIP },
+ { option_type::EMU, N_("Throttle"), OPTION_THROTTLE },
+ { option_type::UI, N_("Mute when unthrottled"), OPTION_UNTHROTTLE_MUTE },
+ { option_type::EMU, N_("Sleep"), OPTION_SLEEP },
+ { option_type::EMU, N_("Speed"), OPTION_SPEED },
+ { option_type::EMU, N_("Adjust speed to match refresh rate"), OPTION_REFRESHSPEED },
+ { option_type::EMU, N_("Low latency"), OPTION_LOWLATENCY },
+
+ { option_type::HEAD, N_("Rotation Options") },
+ { option_type::EMU, N_("Rotate"), OPTION_ROTATE },
+ { option_type::EMU, N_("Rotate right"), OPTION_ROR },
+ { option_type::EMU, N_("Rotate left"), OPTION_ROL },
+ { option_type::EMU, N_("Auto rotate right"), OPTION_AUTOROR },
+ { option_type::EMU, N_("Auto rotate left"), OPTION_AUTOROL },
+ { option_type::EMU, N_("Flip X"), OPTION_FLIPX },
+ { option_type::EMU, N_("Flip Y"), OPTION_FLIPY },
+
+ { option_type::HEAD, N_("Artwork Options") },
+ { option_type::EMU, N_("Zoom to screen area"), OPTION_ARTWORK_CROP },
+
+ { option_type::HEAD, N_("State/Playback Options") },
+ { option_type::EMU, N_("Automatic save/restore"), OPTION_AUTOSAVE },
+ { option_type::EMU, N_("Allow rewind"), OPTION_REWIND },
+ { option_type::EMU, N_("Rewind capacity"), OPTION_REWIND_CAPACITY },
+ { option_type::EMU, N_("Bilinear filtering for snapshots"), OPTION_SNAPBILINEAR },
+ { option_type::EMU, N_("Burn-in"), OPTION_BURNIN },
+
+ { option_type::HEAD, N_("Input Options") },
+ { option_type::EMU, N_("Coin lockout"), OPTION_COIN_LOCKOUT },
+ { option_type::EMU, N_("Mouse"), OPTION_MOUSE },
+ { option_type::EMU, N_("Joystick"), OPTION_JOYSTICK },
+ { option_type::EMU, N_("Lightgun"), OPTION_LIGHTGUN },
+ { option_type::EMU, N_("Multi-keyboard"), OPTION_MULTIKEYBOARD },
+ { option_type::EMU, N_("Multi-mouse"), OPTION_MULTIMOUSE },
+ { option_type::EMU, N_("Steadykey"), OPTION_STEADYKEY },
+ { option_type::EMU, N_("UI active"), OPTION_UI_ACTIVE },
+ { option_type::EMU, N_("Offscreen reload"), OPTION_OFFSCREEN_RELOAD },
+ { option_type::EMU, N_("Joystick deadzone"), OPTION_JOYSTICK_DEADZONE },
+ { option_type::EMU, N_("Joystick saturation"), OPTION_JOYSTICK_SATURATION },
+ { option_type::EMU, N_("Natural keyboard"), OPTION_NATURAL_KEYBOARD },
+ { option_type::EMU, N_("Simultaneous contradictory"), OPTION_JOYSTICK_CONTRADICTORY },
+ { option_type::EMU, N_("Coin impulse"), OPTION_COIN_IMPULSE } };
}
std::vector<submenu::option> submenu::control_options()
{
return std::vector<option>{
- { option_type::HEAD, __("Device Mapping") },
- { option_type::EMU, __("Lightgun Device Assignment"), OPTION_LIGHTGUN_DEVICE },
- { option_type::EMU, __("Trackball Device Assignment"), OPTION_TRACKBALL_DEVICE },
- { option_type::EMU, __("Pedal Device Assignment"), OPTION_PEDAL_DEVICE },
- { option_type::EMU, __("Adstick Device Assignment"), OPTION_ADSTICK_DEVICE },
- { option_type::EMU, __("Paddle Device Assignment"), OPTION_PADDLE_DEVICE },
- { option_type::EMU, __("Dial Device Assignment"), OPTION_DIAL_DEVICE },
- { option_type::EMU, __("Positional Device Assignment"), OPTION_POSITIONAL_DEVICE },
- { option_type::EMU, __("Mouse Device Assignment"), OPTION_MOUSE_DEVICE } };
+ { option_type::HEAD, N_("Device Mapping") },
+ { option_type::EMU, N_("Lightgun Device Assignment"), OPTION_LIGHTGUN_DEVICE },
+ { option_type::EMU, N_("Trackball Device Assignment"), OPTION_TRACKBALL_DEVICE },
+ { option_type::EMU, N_("Pedal Device Assignment"), OPTION_PEDAL_DEVICE },
+ { option_type::EMU, N_("Adstick Device Assignment"), OPTION_ADSTICK_DEVICE },
+ { option_type::EMU, N_("Paddle Device Assignment"), OPTION_PADDLE_DEVICE },
+ { option_type::EMU, N_("Dial Device Assignment"), OPTION_DIAL_DEVICE },
+ { option_type::EMU, N_("Positional Device Assignment"), OPTION_POSITIONAL_DEVICE },
+ { option_type::EMU, N_("Mouse Device Assignment"), OPTION_MOUSE_DEVICE } };
}
std::vector<submenu::option> submenu::video_options()
{
return std::vector<option>{
- { option_type::HEAD, __("Video Options") },
- { option_type::OSD, __("Video Mode"), OSDOPTION_VIDEO },
- { option_type::OSD, __("Number Of Screens"), OSDOPTION_NUMSCREENS },
+ { option_type::HEAD, N_("Video Options") },
+ { option_type::OSD, N_("Video Mode"), OSDOPTION_VIDEO },
+ { option_type::OSD, N_("Number Of Screens"), OSDOPTION_NUMSCREENS },
#if defined(UI_WINDOWS) && !defined(UI_SDL)
- { option_type::OSD, __("Triple Buffering"), WINOPTION_TRIPLEBUFFER },
- { option_type::OSD, __("HLSL"), WINOPTION_HLSL_ENABLE },
+ { option_type::OSD, N_("Triple Buffering"), WINOPTION_TRIPLEBUFFER },
+ { option_type::OSD, N_("HLSL"), WINOPTION_HLSL_ENABLE },
#endif
- { option_type::OSD, __("GLSL"), OSDOPTION_GL_GLSL },
- { option_type::OSD, __("Bilinear Filtering"), OSDOPTION_FILTER },
- { option_type::OSD, __("Bitmap Prescaling"), OSDOPTION_PRESCALE },
- { option_type::OSD, __("Window Mode"), OSDOPTION_WINDOW },
- { option_type::EMU, __("Enforce Aspect Ratio"), OPTION_KEEPASPECT },
- { option_type::OSD, __("Start Out Maximized"), OSDOPTION_MAXIMIZE },
- { option_type::OSD, __("Synchronized Refresh"), OSDOPTION_SYNCREFRESH },
- { option_type::OSD, __("Wait Vertical Sync"), OSDOPTION_WAITVSYNC } };
+ { option_type::OSD, N_("GLSL"), OSDOPTION_GL_GLSL },
+ { option_type::OSD, N_("Bilinear Filtering"), OSDOPTION_FILTER },
+ { option_type::OSD, N_("Bitmap Prescaling"), OSDOPTION_PRESCALE },
+ { option_type::OSD, N_("Window Mode"), OSDOPTION_WINDOW },
+ { option_type::EMU, N_("Enforce Aspect Ratio"), OPTION_KEEPASPECT },
+ { option_type::OSD, N_("Start Out Maximized"), OSDOPTION_MAXIMIZE },
+ { option_type::OSD, N_("Synchronized Refresh"), OSDOPTION_SYNCREFRESH },
+ { option_type::OSD, N_("Wait Vertical Sync"), OSDOPTION_WAITVSYNC } };
}
//std::vector<submenu::option> submenu::export_options()
//{
// return std::vector<option>{
-// { option_type::COMMAND, __("Export XML format (like -listxml)"), "exportxml" },
-// { option_type::COMMAND, __("Export TXT format (like -listfull)"), "exporttxt" } };
+// { option_type::COMMAND, N_("Export XML format (like -listxml)"), "exportxml" },
+// { option_type::COMMAND, N_("Export TXT format (like -listfull)"), "exporttxt" } };
//}
diff --git a/src/frontend/mame/ui/ui.cpp b/src/frontend/mame/ui/ui.cpp
index 1f8e5b7bda8..2e5f999da08 100644
--- a/src/frontend/mame/ui/ui.cpp
+++ b/src/frontend/mame/ui/ui.cpp
@@ -251,6 +251,9 @@ void mame_ui_manager::exit()
// free the font
m_font.reset();
+
+ // free persistent data for other classes
+ m_session_data.clear();
}
diff --git a/src/frontend/mame/ui/ui.h b/src/frontend/mame/ui/ui.h
index e9df57b3b2d..633d3c476f4 100644
--- a/src/frontend/mame/ui/ui.h
+++ b/src/frontend/mame/ui/ui.h
@@ -21,10 +21,15 @@
#include "ui/slider.h"
#include "ui/text.h"
+#include <any>
+#include <cassert>
#include <ctime>
#include <functional>
+#include <map>
#include <set>
#include <string_view>
+#include <typeindex>
+#include <typeinfo>
#include <utility>
#include <vector>
@@ -213,9 +218,22 @@ public:
virtual void menu_reset() override;
+ template <typename Owner, typename Data, typename... Param>
+ Data &get_session_data(Param &&... args)
+ {
+ auto const ins(m_session_data.try_emplace(typeid(Owner)));
+ assert(!ins.first->second.has_value() == ins.second);
+ if (ins.second)
+ return ins.first->second.emplace<Data>(std::forward<Param>(args)...);
+ Data *const result(std::any_cast<Data>(&ins.first->second));
+ assert(result);
+ return *result;
+ }
+
private:
using handler_callback_func = std::function<uint32_t (render_container &)>;
using device_feature_set = std::set<std::pair<std::string, std::string> >;
+ using session_data_map = std::map<std::type_index, std::any>;
// instance variables
std::unique_ptr<render_font> m_font;
@@ -243,6 +261,8 @@ private:
std::time_t m_last_launch_time;
std::time_t m_last_warning_time;
+ session_data_map m_session_data;
+
// static variables
static std::string messagebox_text;
static std::string messagebox_poptext;
@@ -284,10 +304,10 @@ private:
int32_t slider_beam_dot_size(screen_device &screen, std::string *str, int32_t newval);
int32_t slider_beam_intensity_weight(screen_device &screen, std::string *str, int32_t newval);
std::string slider_get_screen_desc(screen_device &screen);
- #ifdef MAME_DEBUG
+#ifdef MAME_DEBUG
int32_t slider_crossscale(ioport_field &field, std::string *str, int32_t newval);
int32_t slider_crossoffset(ioport_field &field, std::string *str, int32_t newval);
- #endif
+#endif
std::vector<std::unique_ptr<slider_state>> m_sliders;
};
diff --git a/src/frontend/mame/ui/utils.cpp b/src/frontend/mame/ui/utils.cpp
index b18b3aa22af..7da3abb7111 100644
--- a/src/frontend/mame/ui/utils.cpp
+++ b/src/frontend/mame/ui/utils.cpp
@@ -30,6 +30,7 @@
#include <cstring>
#include <iterator>
#include <unordered_set>
+#include <utility>
namespace ui {
@@ -57,46 +58,87 @@ constexpr char const *SOFTWARE_REGIONS[] = {
"tha", "tpe", "tw",
"uk", "ukr", "usa" };
+// must be sorted in std::string comparison order
+constexpr std::pair<char const *, char const *> SOFTWARE_INFO_NAMES[] = {
+ { "alt_title", N_p("swlist-info", "Alternate Title") },
+ { "author", N_p("swlist-info", "Author") },
+ { "barcode", N_p("swlist-info", "Barcode Number") },
+ { "developer", N_p("swlist-info", "Developer") },
+ { "distributor", N_p("swlist-info", "Distributor") },
+ { "install", N_p("swlist-info", "Installation Instructions") },
+ { "isbn", N_p("swlist-info", "ISBN") },
+ { "oem", N_p("swlist-info", "OEM") },
+ { "original_publisher", N_p("swlist-info", "Original Publisher") },
+ { "partno", N_p("swlist-info", "Part Number") },
+ { "pcb", N_p("swlist-info", "PCB") },
+ { "programmer", N_p("swlist-info", "Programmer") },
+ { "release", N_p("swlist-info", "Release Date") },
+ { "serial", N_p("swlist-info", "Serial Number") },
+ { "usage", N_p("swlist-info", "Usage Instructions") },
+ { "version", N_p("swlist-info", "Version") } };
+
+
+
+// must be in sync with the machine_filter::type enum
constexpr char const *MACHINE_FILTER_NAMES[machine_filter::COUNT] = {
- __("Unfiltered"),
- __("Available"),
- __("Unavailable"),
- __("Working"),
- __("Not Working"),
- __("Mechanical"),
- __("Not Mechanical"),
- __("Category"),
- __("Favorites"),
- __("BIOS"),
- __("Not BIOS"),
- __("Parents"),
- __("Clones"),
- __("Manufacturer"),
- __("Year"),
- __("Save Supported"),
- __("Save Unsupported"),
- __("CHD Required"),
- __("No CHD Required"),
- __("Vertical Screen"),
- __("Horizontal Screen"),
- __("Custom Filter") };
-
+ N_p("machine-filter", "Unfiltered"),
+ N_p("machine-filter", "Available"),
+ N_p("machine-filter", "Unavailable"),
+ N_p("machine-filter", "Working"),
+ N_p("machine-filter", "Not Working"),
+ N_p("machine-filter", "Mechanical"),
+ N_p("machine-filter", "Not Mechanical"),
+ N_p("machine-filter", "Category"),
+ N_p("machine-filter", "Favorites"),
+ N_p("machine-filter", "BIOS"),
+ N_p("machine-filter", "Not BIOS"),
+ N_p("machine-filter", "Parents"),
+ N_p("machine-filter", "Clones"),
+ N_p("machine-filter", "Manufacturer"),
+ N_p("machine-filter", "Year"),
+ N_p("machine-filter", "Save Supported"),
+ N_p("machine-filter", "Save Unsupported"),
+ N_p("machine-filter", "CHD Required"),
+ N_p("machine-filter", "No CHD Required"),
+ N_p("machine-filter", "Vertical Screen"),
+ N_p("machine-filter", "Horizontal Screen"),
+ N_p("machine-filter", "Custom Filter") };
+
+// must be in sync with the software_filter::type enum
constexpr char const *SOFTWARE_FILTER_NAMES[software_filter::COUNT] = {
- __("Unfiltered"),
- __("Available"),
- __("Unavailable"),
- __("Favorites"),
- __("Parents"),
- __("Clones"),
- __("Year"),
- __("Publisher"),
- __("Supported"),
- __("Partially Supported"),
- __("Unsupported"),
- __("Release Region"),
- __("Device Type"),
- __("Software List"),
- __("Custom Filter") };
+ N_p("software-filter", "Unfiltered"),
+ N_p("software-filter", "Available"),
+ N_p("software-filter", "Unavailable"),
+ N_p("software-filter", "Favorites"),
+ N_p("software-filter", "Parents"),
+ N_p("software-filter", "Clones"),
+ N_p("software-filter", "Year"),
+ N_p("software-filter", "Publisher"),
+ N_p("software-filter", "Developer"),
+ N_p("software-filter", "Distributor"),
+ N_p("software-filter", "Author"),
+ N_p("software-filter", "Programmer"),
+ N_p("software-filter", "Supported"),
+ N_p("software-filter", "Partially Supported"),
+ N_p("software-filter", "Unsupported"),
+ N_p("software-filter", "Release Region"),
+ N_p("software-filter", "Device Type"),
+ N_p("software-filter", "Software List"),
+ N_p("software-filter", "Custom Filter") };
+
+
+
+//-------------------------------------------------
+// helper for building a sorted vector
+//-------------------------------------------------
+
+template <typename T>
+void add_info_value(std::vector<std::string> &items, T &&value)
+{
+ std::vector<std::string>::iterator const pos(std::lower_bound(items.begin(), items.end(), value));
+ if ((items.end() == pos) || (*pos != value))
+ items.emplace(pos, std::forward<T>(value));
+}
@@ -213,11 +255,14 @@ protected:
, m_selection(0U)
{
if (value)
- {
- std::vector<std::string>::const_iterator const found(std::find(choices.begin(), choices.end(), value));
- if (choices.end() != found)
- m_selection = std::distance(choices.begin(), found);
- }
+ set_value(value);
+ }
+
+ void set_value(char const *value)
+ {
+ auto const found(std::find(m_choices.begin(), m_choices.end(), value));
+ if (m_choices.end() != found)
+ m_selection = std::distance(m_choices.begin(), found);
}
bool have_choices() const { return !m_choices.empty(); }
@@ -1395,6 +1440,93 @@ private:
//-------------------------------------------------
+// software info filters
+//-------------------------------------------------
+
+template <software_filter::type Type>
+class software_info_filter_base : public choice_filter_impl_base<software_filter, Type>
+{
+public:
+ virtual bool apply(ui_software_info const &info) const override
+ {
+ if (!this->have_choices())
+ {
+ return true;
+ }
+ else if (!this->selection_valid())
+ {
+ return false;
+ }
+ else
+ {
+ auto const found(
+ std::find_if(
+ info.info.begin(),
+ info.info.end(),
+ [this] (software_info_item const &i) { return this->apply(i); }));
+ return info.info.end() != found;
+ }
+ }
+
+protected:
+ software_info_filter_base(char const *type, std::vector<std::string> const &choices, char const *value)
+ : choice_filter_impl_base<software_filter, Type>(choices, value)
+ , m_info_type(type)
+ {
+ }
+
+private:
+ bool apply(software_info_item const &info) const
+ {
+ return (info.name() == m_info_type) && (info.value() == this->selection_text());
+ }
+
+ char const *const m_info_type;
+};
+
+
+class developer_software_filter : public software_info_filter_base<software_filter::DEVELOPERS>
+{
+public:
+ developer_software_filter(software_filter_data const &data, char const *value, emu_file *file, unsigned indent)
+ : software_info_filter_base<software_filter::DEVELOPERS>("developer", data.developers(), value)
+ {
+ }
+};
+
+
+class distributor_software_filter : public software_info_filter_base<software_filter::DISTRIBUTORS>
+{
+public:
+ distributor_software_filter(software_filter_data const &data, char const *value, emu_file *file, unsigned indent)
+ : software_info_filter_base<software_filter::DISTRIBUTORS>("distributor", data.distributors(), value)
+ {
+ }
+};
+
+
+class author_software_filter : public software_info_filter_base<software_filter::AUTHORS>
+{
+public:
+ author_software_filter(software_filter_data const &data, char const *value, emu_file *file, unsigned indent)
+ : software_info_filter_base<software_filter::AUTHORS>("author", data.authors(), value)
+ {
+ }
+};
+
+
+class programmer_software_filter : public software_info_filter_base<software_filter::PROGRAMMERS>
+{
+public:
+ programmer_software_filter(software_filter_data const &data, char const *value, emu_file *file, unsigned indent)
+ : software_info_filter_base<software_filter::PROGRAMMERS>("programmer", data.programmers(), value)
+ {
+ }
+};
+
+
+
+//-------------------------------------------------
// composite software filter
//-------------------------------------------------
@@ -1432,6 +1564,10 @@ public:
case FAVORITE:
case YEAR:
case PUBLISHERS:
+ case DEVELOPERS:
+ case DISTRIBUTORS:
+ case AUTHORS:
+ case PROGRAMMERS:
case REGION:
case DEVICE_TYPE:
case LIST:
@@ -1444,7 +1580,15 @@ public:
static bool is_inclusion(type n)
{
- return (YEAR == n) || (PUBLISHERS == n) || (REGION == n) || (DEVICE_TYPE == n) || (LIST == n);
+ return (YEAR == n)
+ || (PUBLISHERS == n)
+ || (DEVELOPERS == n)
+ || (DISTRIBUTORS == n)
+ || (AUTHORS == n)
+ || (PROGRAMMERS == n)
+ || (REGION == n)
+ || (DEVICE_TYPE == n)
+ || (LIST == n);
}
private:
@@ -1542,31 +1686,35 @@ bool machine_filter_data::load_ini(emu_file &file)
void software_filter_data::add_region(std::string const &longname)
{
std::string name(extract_region(longname));
- std::vector<std::string>::iterator const pos(std::lower_bound(m_regions.begin(), m_regions.end(), name));
- if ((m_regions.end() == pos) || (*pos != name))
- m_regions.emplace(pos, std::move(name));
+ add_info_value(m_regions, std::move(name));
}
void software_filter_data::add_publisher(std::string const &publisher)
{
std::string name(extract_publisher(publisher));
- 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));
+ add_info_value(m_publishers, std::move(name));
}
void software_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);
+ add_info_value(m_years, year);
+}
+
+void software_filter_data::add_info(software_info_item const &info)
+{
+ if (info.name() == "developer")
+ add_info_value(m_developers, info.value());
+ else if (info.name() == "distributor")
+ add_info_value(m_distributors, info.value());
+ else if (info.name() == "author")
+ add_info_value(m_authors, info.value());
+ else if (info.name() == "programmer")
+ add_info_value(m_programmers, info.value());
}
void software_filter_data::add_device_type(std::string const &device_type)
{
- std::vector<std::string>::iterator const pos(std::lower_bound(m_device_types.begin(), m_device_types.end(), device_type));
- if ((m_device_types.end() == pos) || (*pos != device_type))
- m_device_types.emplace(pos, device_type);
+ add_info_value(m_device_types, device_type);
}
void software_filter_data::add_list(std::string const &name, std::string const &description)
@@ -1707,7 +1855,7 @@ char const *machine_filter::config_name(type n)
char const *machine_filter::display_name(type n)
{
assert(COUNT > n);
- return _(MACHINE_FILTER_NAMES[n]);
+ return _("machine-filter", MACHINE_FILTER_NAMES[n]);
}
machine_filter::machine_filter()
@@ -1728,7 +1876,7 @@ char const *software_filter::config_name(type n)
char const *software_filter::display_name(type n)
{
assert(COUNT > n);
- return _(SOFTWARE_FILTER_NAMES[n]);
+ return _("software-filter", SOFTWARE_FILTER_NAMES[n]);
}
software_filter::software_filter()
@@ -1756,6 +1904,14 @@ software_filter::ptr software_filter::create(type n, software_filter_data const
return std::make_unique<years_software_filter>(data, value, file, indent);
case PUBLISHERS:
return std::make_unique<publishers_software_filter>(data, value, file, indent);
+ case DEVELOPERS:
+ return std::make_unique<developer_software_filter>(data, value, file, indent);
+ case DISTRIBUTORS:
+ return std::make_unique<distributor_software_filter>(data, value, file, indent);
+ case AUTHORS:
+ return std::make_unique<author_software_filter>(data, value, file, indent);
+ case PROGRAMMERS:
+ return std::make_unique<programmer_software_filter>(data, value, file, indent);
case SUPPORTED:
return std::make_unique<supported_software_filter>(data, value, file, indent);
case PARTIAL_SUPPORTED:
@@ -1866,31 +2022,52 @@ std::vector<std::string> tokenize(const std::string &text, char sep)
ui_software_info::ui_software_info(
- software_info const &info,
+ software_info const &sw,
software_part const &p,
game_driver const &d,
std::string const &li,
std::string const &is,
std::string const &de)
- : shortname(info.shortname()), longname(info.longname()), parentname(info.parentname())
- , year(info.year()), publisher(info.publisher())
- , supported(info.supported())
+ : shortname(sw.shortname()), longname(sw.longname()), parentname(sw.parentname())
+ , year(sw.year()), publisher(sw.publisher())
+ , supported(sw.supported())
, part(p.name())
, driver(&d)
, listname(li), interface(p.interface()), instance(is)
, startempty(0)
, parentlongname()
- , usage()
+ , infotext()
, devicetype(de)
+ , info()
+ , alttitles()
, available(false)
{
- for (feature_list_item const &feature : info.other_info())
+ info.reserve(sw.info().size());
+ bool firstinfo(true);
+ for (software_info_item const &feature : sw.info())
{
- if (feature.name() == "usage")
- {
- usage = feature.value();
- break;
- }
+ // add info for the internal UI, localising recognised
+ if (!firstinfo)
+ infotext.append(2, '\n');
+ firstinfo = false;
+ auto const found = std::lower_bound(
+ std::begin(ui::SOFTWARE_INFO_NAMES),
+ std::end(ui::SOFTWARE_INFO_NAMES),
+ feature.name().c_str(),
+ [] (std::pair<char const *, char const *> const &a, char const *b)
+ {
+ return 0 > std::strcmp(a.first, b);
+ });
+ if ((std::end(ui::SOFTWARE_INFO_NAMES) != found) && (feature.name() == found->first))
+ infotext.append(_("swlist-info", found->second));
+ else
+ infotext.append(feature.name());
+ infotext.append(1, '\n').append(feature.value());
+
+ // keep references to stuff for filtering and searching
+ auto const &ins = info.emplace_back(feature.name(), feature.value());
+ if (feature.name() == "alt_title")
+ alttitles.emplace_back(ins.value());
}
}
@@ -1899,3 +2076,67 @@ ui_software_info::ui_software_info(game_driver const &d)
: shortname(d.name), longname(d.type.fullname()), driver(&d), startempty(1), available(true)
{
}
+
+ui_software_info::ui_software_info(ui_software_info const &that)
+ : shortname(that.shortname)
+ , longname(that.longname)
+ , parentname(that.parentname)
+ , year(that.year)
+ , publisher(that.publisher)
+ , supported(that.supported)
+ , part(that.part)
+ , driver(that.driver)
+ , listname(that.listname)
+ , interface(that.interface)
+ , instance(that.instance)
+ , startempty(that.startempty)
+ , parentlongname(that.parentlongname)
+ , infotext(that.infotext)
+ , devicetype(that.devicetype)
+ , info(that.info)
+ , alttitles()
+ , available(that.available)
+{
+ // build self-referencing member
+ alttitles.reserve(that.alttitles.size());
+ for (software_info_item const &feature : info)
+ {
+ if (feature.name() == "alt_title")
+ alttitles.emplace_back(feature.value());
+ }
+}
+
+ui_software_info &ui_software_info::operator=(ui_software_info const &that)
+{
+ if (&that != this)
+ {
+ // copy simple stuff
+ shortname = that.shortname;
+ longname = that.longname;
+ parentname = that.parentname;
+ year = that.year;
+ publisher = that.publisher;
+ supported = that.supported;
+ part = that.part;
+ driver = that.driver;
+ listname = that.listname;
+ interface = that.interface;
+ instance = that.instance;
+ startempty = that.startempty;
+ parentlongname = that.parentlongname;
+ infotext = that.infotext;
+ devicetype = that.devicetype;
+ info = that.info;
+ alttitles.clear();
+ available = that.available;
+
+ // build self-referencing member
+ alttitles.reserve(that.alttitles.size());
+ for (software_info_item const &feature : info)
+ {
+ if (feature.name() == "alt_title")
+ alttitles.emplace_back(feature.value());
+ }
+ }
+ return *this;
+}
diff --git a/src/frontend/mame/ui/utils.h b/src/frontend/mame/ui/utils.h
index 67320c19b6f..184f922d7d2 100644
--- a/src/frontend/mame/ui/utils.h
+++ b/src/frontend/mame/ui/utils.h
@@ -16,6 +16,7 @@
#include "unicode.h"
#include <algorithm>
+#include <functional>
#include <limits>
#include <memory>
#include <string>
@@ -38,9 +39,14 @@ struct ui_system_info
int index;
bool available = false;
+ std::string description;
+ std::string parent;
+
std::u32string ucs_shortname;
std::u32string ucs_description;
std::u32string ucs_manufacturer_description;
+ std::u32string ucs_default_description;
+ std::u32string ucs_manufacturer_default_description;
};
struct ui_software_info
@@ -49,7 +55,7 @@ struct ui_software_info
// info for software list item
ui_software_info(
- software_info const &info,
+ software_info const &sw,
software_part const &p,
game_driver const &d,
std::string const &li,
@@ -60,19 +66,19 @@ struct ui_software_info
ui_software_info(game_driver const &d);
// copyable/movable
- ui_software_info(ui_software_info const &) = default;
- ui_software_info(ui_software_info &&) = default;
- ui_software_info &operator=(ui_software_info const &) = default;
+ ui_software_info(ui_software_info const &that);
+ ui_software_info(ui_software_info &&that) = default;
+ ui_software_info &operator=(ui_software_info const &that);
ui_software_info &operator=(ui_software_info &&) = default;
bool operator==(ui_software_info const &r) const
{
- // compares all fields except available
- return shortname == r.shortname && longname == r.longname && parentname == r.parentname
- && year == r.year && publisher == r.publisher && supported == r.supported
- && part == r.part && driver == r.driver && listname == r.listname
- && interface == r.interface && instance == r.instance && startempty == r.startempty
- && parentlongname == r.parentlongname && usage == r.usage && devicetype == r.devicetype;
+ // compares all fields except info (fragile), alttitles (included in info) and available (environmental)
+ return (shortname == r.shortname) && (longname == r.longname) && (parentname == r.parentname)
+ && (year == r.year) && (publisher == r.publisher) && (supported == r.supported)
+ && (part == r.part) && (driver == r.driver) && (listname == r.listname)
+ && (interface == r.interface) && (instance == r.instance) && (startempty == r.startempty)
+ && (parentlongname == r.parentlongname) && (devicetype == r.devicetype);
}
std::string shortname;
@@ -88,8 +94,10 @@ struct ui_software_info
std::string instance;
uint8_t startempty = 0;
std::string parentlongname;
- std::string usage;
+ std::string infotext;
std::string devicetype;
+ std::vector<software_info_item> info;
+ std::vector<std::reference_wrapper<std::string const> > alttitles;
bool available = false;
};
@@ -206,6 +214,10 @@ public:
CLONES,
YEAR,
PUBLISHERS,
+ DEVELOPERS,
+ DISTRIBUTORS,
+ AUTHORS,
+ PROGRAMMERS,
SUPPORTED,
PARTIAL_SUPPORTED,
UNSUPPORTED,
@@ -287,6 +299,10 @@ 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 &developers() const { return m_developers; }
+ std::vector<std::string> const &distributors() const { return m_distributors; }
+ std::vector<std::string> const &authors() const { return m_authors; }
+ std::vector<std::string> const &programmers() const { return m_programmers; }
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; }
@@ -295,6 +311,7 @@ public:
void add_region(std::string const &longname);
void add_publisher(std::string const &publisher);
void add_year(std::string const &year);
+ void add_info(software_info_item const &info);
void add_device_type(std::string const &device_type);
void add_list(std::string const &name, std::string const &description);
void finalise();
@@ -307,6 +324,10 @@ private:
std::vector<std::string> m_regions;
std::vector<std::string> m_publishers;
std::vector<std::string> m_years;
+ std::vector<std::string> m_developers;
+ std::vector<std::string> m_distributors;
+ std::vector<std::string> m_authors;
+ std::vector<std::string> m_programmers;
std::vector<std::string> m_device_types;
std::vector<std::string> m_list_names, m_list_descriptions;
};