diff options
Diffstat (limited to 'src/frontend/mame/ui/selgame.cpp')
-rw-r--r-- | src/frontend/mame/ui/selgame.cpp | 755 |
1 files changed, 265 insertions, 490 deletions
diff --git a/src/frontend/mame/ui/selgame.cpp b/src/frontend/mame/ui/selgame.cpp index def4ceaa5f9..0b47fa1d7d1 100644 --- a/src/frontend/mame/ui/selgame.cpp +++ b/src/frontend/mame/ui/selgame.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Maurizio Petrarota, Vas Crabb +// copyright-holders:Maurizio Petrarota /********************************************************************* ui/selgame.cpp @@ -12,7 +12,6 @@ #include "ui/selgame.h" #include "ui/auditmenu.h" -#include "ui/icorender.h" #include "ui/inifile.h" #include "ui/miscmenu.h" #include "ui/optsmenu.h" @@ -32,190 +31,17 @@ #include "uiinput.h" #include "luaengine.h" -#include <atomic> -#include <condition_variable> #include <cstring> #include <iterator> -#include <memory> -#include <mutex> -#include <thread> extern const char UI_VERSION_TAG[]; namespace ui { -namespace { - -constexpr uint32_t FLAGS_UI = ui::menu::FLAG_LEFT_ARROW | ui::menu::FLAG_RIGHT_ARROW; - -} // anonymous namespace - -class menu_select_game::persistent_data -{ -public: - enum available : unsigned - { - AVAIL_NONE = 0U, - AVAIL_SORTED_LIST = 1U << 0, - AVAIL_BIOS_COUNT = 1U << 1, - AVAIL_UCS_SHORTNAME = 1U << 2, - AVAIL_UCS_DESCRIPTION = 1U << 3, - AVAIL_UCS_MANUF_DESC = 1U << 4, - AVAIL_FILTER_DATA = 1U << 5 - }; - - ~persistent_data() - { - if (m_thread) - m_thread->join(); - } - - void cache_data() - { - std::unique_lock<std::mutex> lock(m_mutex); - do_start_caching(); - } - - bool is_available(available desired) - { - return (m_available.load(std::memory_order_acquire) & desired) == desired; - } - - void wait_available(available desired) - { - if (!is_available(desired)) - { - std::unique_lock<std::mutex> lock(m_mutex); - do_start_caching(); - m_condition.wait(lock, [this, desired] () { return is_available(desired); }); - } - } - - std::vector<ui_system_info> &sorted_list() - { - wait_available(AVAIL_SORTED_LIST); - return m_sorted_list; - } - - int bios_count() - { - wait_available(AVAIL_BIOS_COUNT); - return m_bios_count; - } - - bool unavailable_systems() - { - wait_available(AVAIL_SORTED_LIST); - return std::find_if(m_sorted_list.begin(), m_sorted_list.end(), [] (ui_system_info const &info) { return !info.available; }) != m_sorted_list.end(); - } - - machine_filter_data &filter_data() - { - wait_available(AVAIL_FILTER_DATA); - return m_filter_data; - } - - static persistent_data &instance() - { - static persistent_data data; - return data; - } - -private: - persistent_data() - : m_started(false) - , m_available(AVAIL_NONE) - , m_bios_count(0) - { - } - - void notify_available(available value) - { - std::unique_lock<std::mutex> lock(m_mutex); - m_available.fetch_or(value, std::memory_order_release); - m_condition.notify_all(); - } - - void do_start_caching() - { - if (!m_started) - { - m_started = true; - m_thread = std::make_unique<std::thread>([this] { do_cache_data(); }); - } - } - - void do_cache_data() - { - // generate full list - m_sorted_list.reserve(driver_list::total()); - std::unordered_set<std::string> manufacturers, years; - for (int x = 0; x < driver_list::total(); ++x) - { - game_driver const &driver(driver_list::driver(x)); - if (&driver != &GAME_NAME(___empty)) - { - if (driver.flags & machine_flags::IS_BIOS_ROOT) - ++m_bios_count; - - m_sorted_list.emplace_back(driver, x, false); - m_filter_data.add_manufacturer(driver.manufacturer); - m_filter_data.add_year(driver.year); - } - } - - // notify that BIOS count is valie - notify_available(AVAIL_BIOS_COUNT); - - // sort drivers and notify - std::stable_sort( - m_sorted_list.begin(), - m_sorted_list.end(), - [] (ui_system_info const &lhs, ui_system_info const &rhs) { return sorted_game_list(lhs.driver, rhs.driver); }); - notify_available(AVAIL_SORTED_LIST); - - // sort manufacturers and years - m_filter_data.finalise(); - notify_available(AVAIL_FILTER_DATA); - - // convert shortnames to UCS-4 - for (ui_system_info &info : m_sorted_list) - info.ucs_shortname = ustr_from_utf8(normalize_unicode(info.driver->name, unicode_normalization_form::D, true)); - notify_available(AVAIL_UCS_SHORTNAME); - - // convert descriptions to UCS-4 - for (ui_system_info &info : m_sorted_list) - info.ucs_description = ustr_from_utf8(normalize_unicode(info.driver->type.fullname(), unicode_normalization_form::D, true)); - notify_available(AVAIL_UCS_DESCRIPTION); - - // convert "<manufacturer> <description>" to UCS-4 - std::string buf; - for (ui_system_info &info : m_sorted_list) - { - buf.assign(info.driver->manufacturer); - buf.append(1, ' '); - buf.append(info.driver->type.fullname()); - info.ucs_manufacturer_description = ustr_from_utf8(normalize_unicode(buf, unicode_normalization_form::D, true)); - } - notify_available(AVAIL_UCS_MANUF_DESC); - } - - // synchronisation - std::mutex m_mutex; - std::condition_variable m_condition; - std::unique_ptr<std::thread> m_thread; - std::atomic<bool> m_started; - std::atomic<unsigned> m_available; - - // data - std::vector<ui_system_info> m_sorted_list; - machine_filter_data m_filter_data; - int m_bios_count; -}; - -bool menu_select_game::s_first_start = true; - +bool menu_select_game::first_start = true; +std::vector<const game_driver *> menu_select_game::m_sortedlist; +int menu_select_game::m_isabios = 0; //------------------------------------------------- // ctor @@ -223,30 +49,33 @@ bool menu_select_game::s_first_start = true; menu_select_game::menu_select_game(mame_ui_manager &mui, render_container &container, const char *gamename) : menu_select_launch(mui, container, false) - , m_persistent_data(persistent_data::instance()) - , m_icons(MAX_ICONS_RENDER) - , m_icon_paths() - , m_displaylist() - , m_searchlist() - , m_searched_fields(persistent_data::AVAIL_NONE) - , m_populated_favorites(false) { std::string error_string, last_filter, sub_filter; ui_options &moptions = mui.options(); // load drivers cache - m_persistent_data.cache_data(); + init_sorted_list(); - // check if there are available system icons - check_for_icons(nullptr); + // check if there are available icons + ui_globals::has_icons = false; + file_enumerator path(moptions.icons_directory()); + const osd::directory::entry *dir; + while ((dir = path.next()) != nullptr) + { + std::string src(dir->name); + if (src.find(".ico") != std::string::npos || src.find("icons") != std::string::npos) + { + ui_globals::has_icons = true; + break; + } + } // build drivers list if (!load_available_machines()) build_available_list(); - if (s_first_start) + if (first_start) { - //s_first_start = false; TODO: why wansn't it ever clearing the first start flag? reselect_last::set_driver(moptions.last_used_machine()); ui_globals::rpanel = std::min<int>(std::max<int>(moptions.last_right_panel(), RP_FIRST), RP_LAST); @@ -267,23 +96,32 @@ menu_select_game::menu_select_game(mame_ui_manager &mui, render_container &conta emu_file file(ui().options().ui_path(), OPEN_FLAG_READ); if (file.open_ram(fake_ini.c_str(), fake_ini.size()) == osd_file::error::NONE) { - m_persistent_data.filter_data().load_ini(file); + machine_filter::ptr flt(machine_filter::create(file)); + if (flt) + { + main_filters::actual = flt->get_type(); + main_filters::filters.emplace(main_filters::actual, std::move(flt)); + } file.close(); } } // do this after processing the last used filter setting so it overwrites the placeholder load_custom_filters(); - m_filter_highlight = m_persistent_data.filter_data().get_current_filter_type(); + m_filter_highlight = main_filters::actual; if (!moptions.remember_last()) reselect_last::reset(); mui.machine().options().set_value(OPTION_SNAPNAME, "%g/%i", OPTION_PRIORITY_CMDLINE); + ui_globals::curimage_view = FIRST_VIEW; ui_globals::curdats_view = 0; + ui_globals::switch_image = false; + ui_globals::default_image = true; ui_globals::panels_status = moptions.hide_panels(); ui_globals::curdats_total = 1; + m_searchlist[0] = nullptr; } //------------------------------------------------- @@ -302,7 +140,17 @@ menu_select_game::~menu_select_game() if (driver) last_driver = driver->name; - std::string const filter(m_persistent_data.filter_data().get_config_string()); + std::string filter; + auto const active_filter(main_filters::filters.find(main_filters::actual)); + if (main_filters::filters.end() != active_filter) + { + char const *val(active_filter->second->filter_text()); + filter = val ? util::string_format("%s,%s", active_filter->second->config_name(), val) : active_filter->second->config_name(); + } + else + { + filter = machine_filter::config_name(main_filters::actual); + } ui_options &mopt = ui().options(); mopt.set_value(OPTION_LAST_RIGHT_PANEL, ui_globals::rpanel, OPTION_PRIORITY_CMDLINE); @@ -330,13 +178,13 @@ void menu_select_game::handle() return; } - // if I have to select software, force software list submenu + // if i have to reselect a software, force software list submenu if (reselect_last::get()) { const game_driver *driver; const ui_software_info *software; get_selection(software, driver); - menu::stack_push<menu_select_software>(ui(), container(), *driver); + menu::stack_push<menu_select_software>(ui(), container(), driver); return; } @@ -393,7 +241,7 @@ void menu_select_game::handle() case IPT_UI_SELECT: if (get_focus() == focused_menu::MAIN) { - if (m_populated_favorites) + if (isfavorite()) inkey_select_favorite(menu_event); else inkey_select(menu_event); @@ -402,12 +250,11 @@ void menu_select_game::handle() case IPT_CUSTOM: // handle IPT_CUSTOM (mouse right click) - if (!m_populated_favorites) + if (!isfavorite()) { menu::stack_push<menu_machine_configure>( ui(), container(), - *reinterpret_cast<const game_driver *>(m_prev_selected), - nullptr, + reinterpret_cast<const game_driver *>(m_prev_selected), menu_event->mouse.x0, menu_event->mouse.y0); } else @@ -415,21 +262,18 @@ void menu_select_game::handle() ui_software_info *sw = reinterpret_cast<ui_software_info *>(m_prev_selected); menu::stack_push<menu_machine_configure>( ui(), container(), - *sw->driver, - [this, empty = sw->startempty] (bool fav, bool changed) - { - if (changed) - reset(empty ? reset_options::SELECT_FIRST : reset_options::REMEMBER_REF); - }, + (const game_driver *)sw->driver, menu_event->mouse.x0, menu_event->mouse.y0); } break; case IPT_UI_LEFT: - if (ui_globals::rpanel == RP_IMAGES) + if (ui_globals::rpanel == RP_IMAGES && ui_globals::curimage_view > FIRST_VIEW) { // Images - previous_image_view(); + ui_globals::curimage_view--; + ui_globals::switch_image = true; + ui_globals::default_image = false; } else if (ui_globals::rpanel == RP_INFOS) { @@ -439,10 +283,12 @@ void menu_select_game::handle() break; case IPT_UI_RIGHT: - if (ui_globals::rpanel == RP_IMAGES) + if (ui_globals::rpanel == RP_IMAGES && ui_globals::curimage_view < LAST_VIEW) { // Images - next_image_view(); + ui_globals::curimage_view++; + ui_globals::switch_image = true; + ui_globals::default_image = false; } else if (ui_globals::rpanel == RP_INFOS) { @@ -455,17 +301,17 @@ void menu_select_game::handle() if (uintptr_t(menu_event->itemref) > skip_main_items) { favorite_manager &mfav(mame_machine_manager::instance()->favorite()); - if (!m_populated_favorites) + if (!isfavorite()) { game_driver const *const driver(reinterpret_cast<game_driver const *>(menu_event->itemref)); - if (!mfav.is_favorite_system(*driver)) + if (!mfav.isgame_favorite(driver)) { - mfav.add_favorite_system(*driver); + mfav.add_favorite_game(driver); machine().popmessage(_("%s\n added to favorites list."), driver->type.fullname()); } else { - mfav.remove_favorite_system(*driver); + mfav.remove_favorite_game(); machine().popmessage(_("%s\n removed from favorites list."), driver->type.fullname()); } } @@ -473,19 +319,19 @@ void menu_select_game::handle() { ui_software_info const *const swinfo(reinterpret_cast<ui_software_info const *>(menu_event->itemref)); machine().popmessage(_("%s\n removed from favorites list."), swinfo->longname); - mfav.remove_favorite_software(*swinfo); + mfav.remove_favorite_game(*swinfo); reset(reset_options::SELECT_FIRST); } } break; case IPT_UI_AUDIT_FAST: - if (m_persistent_data.unavailable_systems()) - menu::stack_push<menu_audit>(ui(), container(), m_persistent_data.sorted_list(), menu_audit::mode::FAST); + if (std::find_if(m_availsortedlist.begin(), m_availsortedlist.end(), [] (ui_system_info const &info) { return !info.available; }) != m_availsortedlist.end()) + menu::stack_push<menu_audit>(ui(), container(), m_availsortedlist, menu_audit::mode::FAST); break; case IPT_UI_AUDIT_ALL: - menu::stack_push<menu_audit>(ui(), container(), m_persistent_data.sorted_list(), menu_audit::mode::ALL); + menu::stack_push<menu_audit>(ui(), container(), m_availsortedlist, menu_audit::mode::ALL); break; } } @@ -502,113 +348,98 @@ void menu_select_game::handle() void menu_select_game::populate(float &customtop, float &custombottom) { - for (auto &icon : m_icons) // TODO: why is this here? maybe better on resize or setting change? - icon.second.texture.reset(); - - set_switch_image(); + ui_globals::redraw_icon = true; + ui_globals::switch_image = true; int old_item_selected = -1; + uint32_t flags_ui = FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW; if (!isfavorite()) { - m_populated_favorites = false; - m_displaylist.clear(); - machine_filter const *const flt(m_persistent_data.filter_data().get_current_filter()); - // if search is not empty, find approximate matches if (!m_search.empty()) { populate_search(); - if (flt) - { - for (auto it = m_searchlist.begin(); (m_searchlist.end() != it) && (MAX_VISIBLE_SEARCH > m_displaylist.size()); ++it) - { - if (flt->apply(it->second)) - m_displaylist.emplace_back(it->second); - } - } - else - { - std::transform( - m_searchlist.begin(), - std::next(m_searchlist.begin(), (std::min)(m_searchlist.size(), MAX_VISIBLE_SEARCH)), - std::back_inserter(m_displaylist), - [] (auto const &entry) { return entry.second; }); - } } else { + // reset search string + m_search.clear(); + m_displaylist.clear(); + // if filter is set on category, build category list - std::vector<ui_system_info> const &sorted(m_persistent_data.sorted_list()); - if (!flt) - std::copy(sorted.begin(), sorted.end(), std::back_inserter(m_displaylist)); + auto const it(main_filters::filters.find(main_filters::actual)); + if (main_filters::filters.end() == it) + m_displaylist = m_availsortedlist; else - flt->apply(sorted.begin(), sorted.end(), std::back_inserter(m_displaylist)); - } + it->second->apply(m_availsortedlist.begin(), m_availsortedlist.end(), std::back_inserter(m_displaylist)); - // iterate over entries - int curitem = 0; - for (ui_system_info const &elem : m_displaylist) - { - if (old_item_selected == -1 && elem.driver->name == reselect_last::driver()) - old_item_selected = curitem; - - bool cloneof = strcmp(elem.driver->parent, "0"); - if (cloneof) + // iterate over entries + int curitem = 0; + for (ui_system_info const &elem : m_displaylist) { - int cx = driver_list::find(elem.driver->parent); - if (cx != -1 && ((driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT) != 0)) - cloneof = false; - } + if (old_item_selected == -1 && elem.driver->name == reselect_last::driver()) + old_item_selected = curitem; - item_append(elem.driver->type.fullname(), "", (cloneof) ? (FLAGS_UI | FLAG_INVERT) : FLAGS_UI, (void *)elem.driver); - curitem++; + bool cloneof = strcmp(elem.driver->parent, "0"); + if (cloneof) + { + int cx = driver_list::find(elem.driver->parent); + if (cx != -1 && ((driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT) != 0)) + cloneof = false; + } + + item_append(elem.driver->type.fullname(), "", (cloneof) ? (flags_ui | FLAG_INVERT) : flags_ui, (void *)elem.driver); + curitem++; + } } } else { // populate favorites list - m_populated_favorites = true; m_search.clear(); - mame_machine_manager::instance()->favorite().apply_sorted( - [this, &old_item_selected, curitem = 0] (ui_software_info const &info) mutable - { - if (info.startempty == 1) - { - if (old_item_selected == -1 && info.shortname == reselect_last::driver()) - old_item_selected = curitem; + int curitem = 0; - bool cloneof = strcmp(info.driver->parent, "0"); - if (cloneof) - { - int cx = driver_list::find(info.driver->parent); - if (cx != -1 && ((driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT) != 0)) - cloneof = false; - } + // iterate over entries + for (auto & favmap : mame_machine_manager::instance()->favorite().m_list) + { + auto flags = flags_ui | FLAG_UI_FAVORITE; + if (favmap.second.startempty == 1) + { + if (old_item_selected == -1 && favmap.second.shortname == reselect_last::driver()) + old_item_selected = curitem; - item_append(info.longname, "", cloneof ? (FLAGS_UI | FLAG_INVERT) : FLAGS_UI, (void *)&info); - } - else - { - if (old_item_selected == -1 && info.shortname == reselect_last::driver()) - old_item_selected = curitem; - item_append(info.longname, info.devicetype, - info.parentname.empty() ? FLAGS_UI : (FLAG_INVERT | FLAGS_UI), (void *)&info); - } - curitem++; - }); + bool cloneof = strcmp(favmap.second.driver->parent, "0"); + if (cloneof) + { + int cx = driver_list::find(favmap.second.driver->parent); + if (cx != -1 && ((driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT) != 0)) + cloneof = false; + } + + item_append(favmap.second.longname, "", (cloneof) ? (flags | FLAG_INVERT) : flags, (void *)&favmap.second); + } + else + { + if (old_item_selected == -1 && favmap.second.shortname == reselect_last::driver()) + old_item_selected = curitem; + item_append(favmap.second.longname, favmap.second.devicetype, + favmap.second.parentname.empty() ? flags : (FLAG_INVERT | flags), (void *)&favmap.second); + } + curitem++; + } } - item_append(menu_item_type::SEPARATOR, FLAGS_UI); + item_append(menu_item_type::SEPARATOR, flags_ui); // add special items if (stack_has_special_main_menu()) { - item_append(_("Configure Options"), "", FLAGS_UI, (void *)(uintptr_t)CONF_OPTS); - item_append(_("Configure Machine"), "", FLAGS_UI, (void *)(uintptr_t)CONF_MACHINE); + item_append(_("Configure Options"), "", flags_ui, (void *)(uintptr_t)CONF_OPTS); + item_append(_("Configure Machine"), "", flags_ui, (void *)(uintptr_t)CONF_MACHINE); skip_main_items = 2; if (machine().options().plugins()) { - item_append(_("Plugins"), "", FLAGS_UI, (void *)(uintptr_t)CONF_PLUGINS); + item_append(_("Plugins"), "", flags_ui, (void *)(uintptr_t)CONF_PLUGINS); skip_main_items++; } } @@ -656,11 +487,11 @@ void menu_select_game::build_available_list() // build a name for it for (src = dir->name; *src != 0 && *src != '.' && dst < &drivername[ARRAY_LENGTH(drivername) - 1]; ++src) - *dst++ = tolower(uint8_t(*src)); + *dst++ = tolower((uint8_t) * src); *dst = 0; - int const drivnum = driver_list::find(drivername); - if (0 <= drivnum) + int drivnum = driver_list::find(drivername); + if (drivnum != -1 && !included[drivnum]) included[drivnum] = true; } @@ -731,9 +562,18 @@ void menu_select_game::build_available_list() } } - // copy into the persistent sorted list - for (ui_system_info &info : m_persistent_data.sorted_list()) - info.available = included[info.index]; + // sort + m_availsortedlist.reserve(total); + for (std::size_t x = 0; total > x; ++x) + { + game_driver const &driver(driver_list::driver(x)); + if (&driver != &GAME_NAME(___empty)) + m_availsortedlist.emplace_back(driver, included[x]); + } + std::stable_sort( + m_availsortedlist.begin(), + m_availsortedlist.end(), + [] (ui_system_info const &a, ui_system_info const &b) { return sorted_game_list(a.driver, b.driver); }); } @@ -769,17 +609,13 @@ void menu_select_game::inkey_select(const event *menu_event) if ((uintptr_t)driver == CONF_OPTS) { // special case for configure options - menu::stack_push<menu_game_options>( - ui(), - container(), - m_persistent_data.filter_data(), - [this] () { reset(reset_options::SELECT_FIRST); }); + menu::stack_push<menu_game_options>(ui(), container()); } else if (uintptr_t(driver) == CONF_MACHINE) { // special case for configure machine if (m_prev_selected) - menu::stack_push<menu_machine_configure>(ui(), container(), *reinterpret_cast<const game_driver *>(m_prev_selected)); + menu::stack_push<menu_machine_configure>(ui(), container(), reinterpret_cast<const game_driver *>(m_prev_selected)); return; } else if ((uintptr_t)driver == CONF_PLUGINS) @@ -804,7 +640,7 @@ void menu_select_game::inkey_select(const event *menu_event) { if (!swlistdev.get_info().empty()) { - menu::stack_push<menu_select_software>(ui(), container(), *driver); + menu::stack_push<menu_select_software>(ui(), container(), driver); return; } } @@ -831,11 +667,7 @@ void menu_select_game::inkey_select_favorite(const event *menu_event) if ((uintptr_t)ui_swinfo == CONF_OPTS) { // special case for configure options - menu::stack_push<menu_game_options>( - ui(), - container(), - m_persistent_data.filter_data(), - [this] () { reset(reset_options::SELECT_FIRST); }); + menu::stack_push<menu_game_options>(ui(), container()); } else if ((uintptr_t)ui_swinfo == CONF_MACHINE) { @@ -843,15 +675,7 @@ void menu_select_game::inkey_select_favorite(const event *menu_event) if (m_prev_selected) { ui_software_info *swinfo = reinterpret_cast<ui_software_info *>(m_prev_selected); - menu::stack_push<menu_machine_configure>( - ui(), - container(), - *swinfo->driver, - [this, empty = swinfo->startempty] (bool fav, bool changed) - { - if (changed) - reset(empty ? reset_options::SELECT_FIRST : reset_options::REMEMBER_REF); - }); + menu::stack_push<menu_machine_configure>(ui(), container(), (const game_driver *)swinfo->driver); } return; } @@ -874,7 +698,7 @@ void menu_select_game::inkey_select_favorite(const event *menu_event) { if (!swlistdev.get_info().empty()) { - menu::stack_push<menu_select_software>(ui(), container(), *ui_swinfo->driver); + menu::stack_push<menu_select_software>(ui(), container(), ui_swinfo->driver); return; } } @@ -922,7 +746,7 @@ void menu_select_game::inkey_select_favorite(const event *menu_event) bool menu_select_game::isfavorite() const { - return machine_filter::FAVORITE == m_persistent_data.filter_data().get_current_filter_type(); + return machine_filter::FAVORITE == main_filters::actual; } @@ -947,7 +771,7 @@ void menu_select_game::change_info_pane(int delta) game_driver const *drv; ui_software_info const *soft; get_selection(soft, drv); - if (!m_populated_favorites) + if (!isfavorite()) { if (uintptr_t(drv) > skip_main_items) cap_delta(ui_globals::curdats_view, ui_globals::curdats_total); @@ -967,59 +791,49 @@ void menu_select_game::change_info_pane(int delta) void menu_select_game::populate_search() { - // ensure search list is populated - if (m_searchlist.empty()) + // allocate memory to track the penalty value + std::vector<int> penalty(VISIBLE_GAMES_IN_SEARCH, 9999); + int index = 0; + for (; index < m_displaylist.size(); ++index) { - std::vector<ui_system_info> const &sorted(m_persistent_data.sorted_list()); - m_searchlist.reserve(sorted.size()); - for (ui_system_info const &info : sorted) - m_searchlist.emplace_back(1.0, std::ref(info)); - } - - // keep track of what we matched against - const std::u32string ucs_search(ustr_from_utf8(normalize_unicode(m_search, unicode_normalization_form::D, true))); - - // match shortnames - if (m_persistent_data.is_available(persistent_data::AVAIL_UCS_SHORTNAME)) - { - m_searched_fields |= persistent_data::AVAIL_UCS_SHORTNAME; - for (std::pair<double, std::reference_wrapper<ui_system_info const> > &info : m_searchlist) - info.first = util::edit_distance(ucs_search, info.second.get().ucs_shortname); - } + // pick the best match between driver name and description + int curpenalty = fuzzy_substring(m_search, m_displaylist[index].driver->type.fullname()); + int tmp = fuzzy_substring(m_search, m_displaylist[index].driver->name); + curpenalty = std::min(curpenalty, tmp); - // match descriptions - if (m_persistent_data.is_available(persistent_data::AVAIL_UCS_DESCRIPTION)) - { - m_searched_fields |= persistent_data::AVAIL_UCS_DESCRIPTION; - for (std::pair<double, std::reference_wrapper<ui_system_info const> > &info : m_searchlist) + // insert into the sorted table of matches + for (int matchnum = VISIBLE_GAMES_IN_SEARCH - 1; matchnum >= 0; --matchnum) { - if (info.first) + // stop if we're worse than the current entry + if (curpenalty >= penalty[matchnum]) + break; + + // as long as this isn't the last entry, bump this one down + if (matchnum < VISIBLE_GAMES_IN_SEARCH - 1) { - double const penalty(util::edit_distance(ucs_search, info.second.get().ucs_description)); - info.first = (std::min)(penalty, info.first); + penalty[matchnum + 1] = penalty[matchnum]; + m_searchlist[matchnum + 1] = m_searchlist[matchnum]; } + + m_searchlist[matchnum] = m_displaylist[index].driver; + penalty[matchnum] = curpenalty; } } - // match "<manufacturer> <description>" - if (m_persistent_data.is_available(persistent_data::AVAIL_UCS_MANUF_DESC)) + (index < VISIBLE_GAMES_IN_SEARCH) ? m_searchlist[index] = nullptr : m_searchlist[VISIBLE_GAMES_IN_SEARCH] = nullptr; + uint32_t flags_ui = FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW; + for (int curitem = 0; m_searchlist[curitem]; ++curitem) { - m_searched_fields |= persistent_data::AVAIL_UCS_MANUF_DESC; - for (std::pair<double, std::reference_wrapper<ui_system_info const> > &info : m_searchlist) + bool cloneof = strcmp(m_searchlist[curitem]->parent, "0"); + if (cloneof) { - if (info.first) - { - double const penalty(util::edit_distance(ucs_search, info.second.get().ucs_manufacturer_description)); - info.first = (std::min)(penalty, info.first); - } + int cx = driver_list::find(m_searchlist[curitem]->parent); + if (cx != -1 && ((driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT) != 0)) + cloneof = false; } + item_append(m_searchlist[curitem]->type.fullname(), "", (!cloneof) ? flags_ui : (FLAG_INVERT | flags_ui), + (void *)m_searchlist[curitem]); } - - // sort according to edit distance - std::stable_sort( - m_searchlist.begin(), - m_searchlist.end(), - [] (auto const &lhs, auto const &rhs) { return lhs.first < rhs.first; }); } //------------------------------------------------- @@ -1075,21 +889,6 @@ void menu_select_game::general_info(const game_driver *driver, std::string &buff else str << _("Sound\tOK\n"); - if (flags.unemulated_features() & device_t::feature::CAPTURE) - str << _("Capture\tUnimplemented\n"); - else if (flags.imperfect_features() & device_t::feature::CAPTURE) - str << _("Capture\tImperfect\n"); - - if (flags.unemulated_features() & device_t::feature::CAMERA) - str << _("Camera\tUnimplemented\n"); - else if (flags.imperfect_features() & device_t::feature::CAMERA) - str << _("Camera\tImperfect\n"); - - if (flags.unemulated_features() & device_t::feature::MICROPHONE) - str << _("Microphone\tUnimplemented\n"); - else if (flags.imperfect_features() & device_t::feature::MICROPHONE) - str << _("Microphone\tImperfect\n"); - if (flags.unemulated_features() & device_t::feature::CONTROLS) str << _("Controls\tUnimplemented\n"); else if (flags.imperfect_features() & device_t::feature::CONTROLS) @@ -1105,10 +904,15 @@ void menu_select_game::general_info(const game_driver *driver, std::string &buff else if (flags.imperfect_features() & device_t::feature::MOUSE) str << _("Mouse\tImperfect\n"); - if (flags.unemulated_features() & device_t::feature::MEDIA) - str << _("Media\tUnimplemented\n"); - else if (flags.imperfect_features() & device_t::feature::MEDIA) - str << _("Media\tImperfect\n"); + if (flags.unemulated_features() & device_t::feature::MICROPHONE) + str << _("Microphone\tUnimplemented\n"); + else if (flags.imperfect_features() & device_t::feature::MICROPHONE) + str << _("Microphone\tImperfect\n"); + + if (flags.unemulated_features() & device_t::feature::CAMERA) + str << _("Camera\tUnimplemented\n"); + else if (flags.imperfect_features() & device_t::feature::CAMERA) + str << _("Camera\tImperfect\n"); if (flags.unemulated_features() & device_t::feature::DISK) str << _("Disk\tUnimplemented\n"); @@ -1120,31 +924,6 @@ void menu_select_game::general_info(const game_driver *driver, std::string &buff else if (flags.imperfect_features() & device_t::feature::PRINTER) str << _("Printer\tImperfect\n"); - if (flags.unemulated_features() & device_t::feature::TAPE) - str << _("Mag. Tape\tUnimplemented\n"); - else if (flags.imperfect_features() & device_t::feature::TAPE) - str << _("Mag. Tape\tImperfect\n"); - - if (flags.unemulated_features() & device_t::feature::PUNCH) - str << _("Punch Tape\tUnimplemented\n"); - else if (flags.imperfect_features() & device_t::feature::PUNCH) - str << _("Punch Tape\tImperfect\n"); - - if (flags.unemulated_features() & device_t::feature::DRUM) - str << _("Mag. Drum\tUnimplemented\n"); - else if (flags.imperfect_features() & device_t::feature::DRUM) - str << _("Mag. Drum\tImperfect\n"); - - if (flags.unemulated_features() & device_t::feature::ROM) - str << _("(EP)ROM\tUnimplemented\n"); - else if (flags.imperfect_features() & device_t::feature::ROM) - str << _("(EP)ROM\tImperfect\n"); - - if (flags.unemulated_features() & device_t::feature::COMMS) - str << _("Communications\tUnimplemented\n"); - else if (flags.imperfect_features() & device_t::feature::COMMS) - str << _("Communications\tImperfect\n"); - if (flags.unemulated_features() & device_t::feature::LAN) str << _("LAN\tUnimplemented\n"); else if (flags.imperfect_features() & device_t::feature::LAN) @@ -1208,86 +987,71 @@ void menu_select_game::general_info(const game_driver *driver, std::string &buff buffer = str.str(); } - -//------------------------------------------------- -// get (possibly cached) icon texture -//------------------------------------------------- - -render_texture *menu_select_game::get_icon_texture(int linenum, void *selectedref) +void menu_select_game::inkey_export() { - game_driver const *const driver(m_populated_favorites - ? reinterpret_cast<ui_software_info const *>(selectedref)->driver - : reinterpret_cast<game_driver const *>(selectedref)); - assert(driver); - - icon_cache::iterator icon(m_icons.find(driver)); - if ((m_icons.end() == icon) || !icon->second.texture) + std::vector<game_driver const *> list; + if (!m_search.empty()) { - if (m_icon_paths.empty()) - m_icon_paths = make_icon_paths(nullptr); - - // allocate an entry or allocate a texture on forced redraw - if (m_icons.end() == icon) + for (int curitem = 0; m_searchlist[curitem]; ++curitem) + list.push_back(m_searchlist[curitem]); + } + else + { + if (isfavorite()) { - icon = m_icons.emplace(driver, texture_ptr(machine().render().texture_alloc(), machine().render())).first; + // iterate over favorites + for (auto & favmap : mame_machine_manager::instance()->favorite().m_list) + { + if (favmap.second.startempty == 1) + list.push_back(favmap.second.driver); + else + return; + } } else { - assert(!icon->second.texture); - icon->second.texture.reset(machine().render().texture_alloc()); + list.reserve(m_displaylist.size()); + for (ui_system_info const &info : m_displaylist) + list.emplace_back(info.driver); } - - // set clone status - bool cloneof = strcmp(driver->parent, "0"); - if (cloneof) - { - auto cx = driver_list::find(driver->parent); - if ((cx >= 0) && (driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT)) - cloneof = false; - } - - bitmap_argb32 tmp; - emu_file snapfile(std::string(m_icon_paths), OPEN_FLAG_READ); - if (snapfile.open(std::string(driver->name), ".ico") == osd_file::error::NONE) - { - render_load_ico_highest_detail(snapfile, tmp); - snapfile.close(); - } - if (!tmp.valid() && cloneof && (snapfile.open(std::string(driver->parent), ".ico") == osd_file::error::NONE)) - { - render_load_ico_highest_detail(snapfile, tmp); - snapfile.close(); - } - - scale_icon(std::move(tmp), icon->second); } - return icon->second.bitmap.valid() ? icon->second.texture.get() : nullptr; + menu::stack_push<menu_export>(ui(), container(), std::move(list)); } +//------------------------------------------------- +// save drivers infos to file +//------------------------------------------------- -void menu_select_game::inkey_export() +void menu_select_game::init_sorted_list() { - std::vector<game_driver const *> list; - if (m_populated_favorites) - { - // iterate over favorites - mame_machine_manager::instance()->favorite().apply( - [&list] (ui_software_info const &info) - { - assert(info.driver); - if (info.startempty) - list.push_back(info.driver); - }); - } - else + if (!m_sortedlist.empty()) + return; + + // generate full list + std::unordered_set<std::string> manufacturers, years; + for (int x = 0; x < driver_list::total(); ++x) { - list.reserve(m_displaylist.size()); - for (ui_system_info const &info : m_displaylist) - list.emplace_back(info.driver); + game_driver const &driver(driver_list::driver(x)); + if (&driver != &GAME_NAME(___empty)) + { + if (driver.flags & machine_flags::IS_BIOS_ROOT) + m_isabios++; + + m_sortedlist.push_back(&driver); + manufacturers.emplace(c_mnfct::getname(driver.manufacturer)); + years.emplace(driver.year); + } } - menu::stack_push<menu_export>(ui(), container(), std::move(list)); + // sort manufacturers - years and driver + for (auto it = manufacturers.begin(); manufacturers.end() != it; it = manufacturers.erase(it)) + c_mnfct::ui.emplace_back(*it); + std::sort(c_mnfct::ui.begin(), c_mnfct::ui.end(), [] (std::string const &x, std::string const &y) { return 0 > core_stricmp(x.c_str(), y.c_str()); }); + for (auto it = years.begin(); years.end() != it; it = years.erase(it)) + c_year::ui.emplace_back(*it); + std::stable_sort(c_year::ui.begin(), c_year::ui.end()); + std::stable_sort(m_sortedlist.begin(), m_sortedlist.end(), sorted_game_list); } //------------------------------------------------- @@ -1329,18 +1093,27 @@ bool menu_select_game::load_available_machines() else available.emplace(std::move(readbuf)); } - file.close(); // turn it into the sorted system list we all love - for (ui_system_info &info : m_persistent_data.sorted_list()) + m_availsortedlist.reserve(driver_list::total()); + for (std::size_t x = 0; driver_list::total() > x; ++x) { - std::unordered_set<std::string>::iterator const it(available.find(&info.driver->name[0])); - bool const found(available.end() != it); - info.available = found; - if (found) - available.erase(it); + game_driver const &driver(driver_list::driver(x)); + if (&driver != &GAME_NAME(___empty)) + { + std::unordered_set<std::string>::iterator const it(available.find(&driver.name[0])); + bool const found(available.end() != it); + m_availsortedlist.emplace_back(driver, found); + if (found) + available.erase(it); + } } + std::stable_sort( + m_availsortedlist.begin(), + m_availsortedlist.end(), + [] (ui_system_info const &a, ui_system_info const &b) { return sorted_game_list(a.driver, b.driver); }); + file.close(); return true; } @@ -1353,9 +1126,9 @@ void menu_select_game::load_custom_filters() emu_file file(ui().options().ui_path(), OPEN_FLAG_READ); if (file.open("custom_", emulator_info::get_configname(), "_filter.ini") == osd_file::error::NONE) { - machine_filter::ptr flt(machine_filter::create(file, m_persistent_data.filter_data())); + machine_filter::ptr flt(machine_filter::create(file)); if (flt) - m_persistent_data.filter_data().set_filter(std::move(flt)); // not emplace/insert - could replace bogus filter from ui.ini line + main_filters::filters[flt->get_type()] = std::move(flt); // not emplace/insert - could replace bogus filter from ui.ini line file.close(); } @@ -1368,8 +1141,7 @@ void menu_select_game::load_custom_filters() float menu_select_game::draw_left_panel(float x1, float y1, float x2, float y2) { - machine_filter_data &filter_data(m_persistent_data.filter_data()); - return menu_select_launch::draw_left_panel<machine_filter>(filter_data.get_current_filter_type(), filter_data.get_filters(), x1, y1, x2, y2); + return menu_select_launch::draw_left_panel<machine_filter>(main_filters::actual, main_filters::filters, x1, y1, x2, y2); } @@ -1379,7 +1151,7 @@ float menu_select_game::draw_left_panel(float x1, float y1, float x2, float y2) void menu_select_game::get_selection(ui_software_info const *&software, game_driver const *&driver) const { - if (m_populated_favorites) + if (item[0].flags & FLAG_UI_FAVORITE) // TODO: work out why this doesn't use isfavorite() { software = reinterpret_cast<ui_software_info const *>(get_selection_ptr()); driver = software ? software->driver : nullptr; @@ -1398,18 +1170,18 @@ void menu_select_game::make_topbox_text(std::string &line0, std::string &line1, bare_build_version, visible_items, (driver_list::total() - 1), - m_persistent_data.bios_count()); + m_isabios); - if (m_populated_favorites) + if (isfavorite()) { line1.clear(); } else { - machine_filter const *const it(m_persistent_data.filter_data().get_current_filter()); - char const *const filter(it ? it->filter_text() : nullptr); + auto const it(main_filters::filters.find(main_filters::actual)); + char const *const filter((main_filters::filters.end() != it) ? it->second->filter_text() : nullptr); if (filter) - line1 = string_format(_("%1$s: %2$s - Search: %3$s_"), it->display_name(), filter, m_search); + line1 = string_format(_("%1$s: %2$s - Search: %3$s_"), it->second->display_name(), filter, m_search); else line1 = string_format(_("Search: %1$s_"), m_search); } @@ -1436,12 +1208,15 @@ void menu_select_game::filter_selected() { if ((machine_filter::FIRST <= m_filter_highlight) && (machine_filter::LAST >= m_filter_highlight)) { - m_persistent_data.filter_data().get_filter(machine_filter::type(m_filter_highlight)).show_ui( + m_search.clear(); + auto it(main_filters::filters.find(machine_filter::type(m_filter_highlight))); + if (main_filters::filters.end() == it) + it = main_filters::filters.emplace(machine_filter::type(m_filter_highlight), machine_filter::create(machine_filter::type(m_filter_highlight))).first; + it->second->show_ui( ui(), container(), [this] (machine_filter &filter) { - set_switch_image(); machine_filter::type const new_type(filter.get_type()); if (machine_filter::CUSTOM == new_type) { @@ -1452,7 +1227,7 @@ void menu_select_game::filter_selected() file.close(); } } - m_persistent_data.filter_data().set_current_filter_type(new_type); + main_filters::actual = new_type; reset(reset_options::SELECT_FIRST); }); } |