From cb7a04174fa62761853a825c12fb261ea8854d32 Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Fri, 11 Aug 2017 10:11:44 +1000 Subject: ui: make category filter work like all the other filters * category filter is now saved/restored if it's last used * category filter can be used in composite custom filters * category filter now provides UI rather than relying on options menu * less confusing when no categories found * also de-duplicated code for drawing category list (nw) please test this everyone and let me know if there are reproducible crashes or things that don't work right - I'm trying to make the internal UI more consistent and stable --- src/frontend/mame/ui/custmenu.cpp | 6 +- src/frontend/mame/ui/custmenu.h | 4 +- src/frontend/mame/ui/dirmenu.cpp | 2 +- src/frontend/mame/ui/inifile.cpp | 156 ++++++-------- src/frontend/mame/ui/inifile.h | 54 ++--- src/frontend/mame/ui/moptions.cpp | 2 +- src/frontend/mame/ui/moptions.h | 4 +- src/frontend/mame/ui/optsmenu.cpp | 101 +-------- src/frontend/mame/ui/optsmenu.h | 2 - src/frontend/mame/ui/selgame.cpp | 223 +++----------------- src/frontend/mame/ui/selgame.h | 1 - src/frontend/mame/ui/selmenu.cpp | 163 ++++++++++++++- src/frontend/mame/ui/selmenu.h | 9 +- src/frontend/mame/ui/selsoft.cpp | 141 +------------ src/frontend/mame/ui/utils.cpp | 425 ++++++++++++++++++++++++++++++++++---- src/frontend/mame/ui/utils.h | 6 +- 16 files changed, 674 insertions(+), 625 deletions(-) (limited to 'src/frontend/mame') diff --git a/src/frontend/mame/ui/custmenu.cpp b/src/frontend/mame/ui/custmenu.cpp index ea5562a0d9e..6f604ece04a 100644 --- a/src/frontend/mame/ui/custmenu.cpp +++ b/src/frontend/mame/ui/custmenu.cpp @@ -45,7 +45,7 @@ constexpr char const *region_lists[] = { // set software regions //------------------------------------------------- -void c_sw_region::set(std::string &str) +void c_sw_region::set(std::string const &str) { std::string name(getname(str)); std::vector::iterator const pos(std::lower_bound(ui.begin(), ui.end(), name)); @@ -97,11 +97,11 @@ void c_sw_year::set(std::string &str) // set software publishers //------------------------------------------------- -void c_sw_publisher::set(std::string &str) +void c_sw_publisher::set(std::string const &str) { std::string name(getname(str)); std::vector::iterator const pos(std::lower_bound(ui.begin(), ui.end(), name)); - if ((ui.end() == pos) || (*pos != str)) + if ((ui.end() == pos) || (*pos != name)) ui.emplace(pos, std::move(name)); } diff --git a/src/frontend/mame/ui/custmenu.h b/src/frontend/mame/ui/custmenu.h index 09911a50787..dc3c7535b2e 100644 --- a/src/frontend/mame/ui/custmenu.h +++ b/src/frontend/mame/ui/custmenu.h @@ -21,7 +21,7 @@ namespace ui { struct c_sw_region { std::vector ui; - void set(std::string &str); + void set(std::string const &str); std::string getname(std::string const &str) const; }; @@ -29,7 +29,7 @@ struct c_sw_region struct c_sw_publisher { std::vector ui; - void set(std::string &str); + void set(std::string const &str); std::string getname(std::string const &str) const; }; diff --git a/src/frontend/mame/ui/dirmenu.cpp b/src/frontend/mame/ui/dirmenu.cpp index c3c5d85f8d1..f3939089f25 100644 --- a/src/frontend/mame/ui/dirmenu.cpp +++ b/src/frontend/mame/ui/dirmenu.cpp @@ -39,7 +39,7 @@ static const folders_entry s_folders[] = { __("Samples"), OPTION_SAMPLEPATH, ADDING }, { __("DATs"), OPTION_HISTORY_PATH, ADDING }, { __("INIs"), OPTION_INIPATH, ADDING }, - { __("Extra INIs"), OPTION_EXTRAINI_PATH, CHANGE }, + { __("Category INIs"), OPTION_CATEGORYINI_PATH, CHANGE }, { __("Icons"), OPTION_ICONS_PATH, ADDING }, { __("Cheats"), OPTION_CHEATPATH, ADDING }, { __("Snapshots"), OPTION_SNAPSHOT_DIRECTORY, ADDING }, diff --git a/src/frontend/mame/ui/inifile.cpp b/src/frontend/mame/ui/inifile.cpp index d9673f13a67..852884fea6a 100644 --- a/src/frontend/mame/ui/inifile.cpp +++ b/src/frontend/mame/ui/inifile.cpp @@ -9,134 +9,100 @@ ***************************************************************************/ #include "emu.h" -#include "ui/moptions.h" #include "ui/inifile.h" -#include "softlist_dev.h" + +#include "ui/moptions.h" + #include "drivenum.h" +#include "softlist_dev.h" -//------------------------------------------------- -// GLOBAL VARIABLES -//------------------------------------------------- -uint16_t inifile_manager::c_cat = 0; -uint16_t inifile_manager::c_file = 0; //------------------------------------------------- // ctor //------------------------------------------------- inifile_manager::inifile_manager(running_machine &machine, ui_options &moptions) - : m_machine(machine) - , m_options(moptions) + : m_options(moptions) + , m_ini_index() { - ini_index.clear(); - directory_scan(); + // scan directories and create index + file_enumerator path(m_options.categoryini_path()); + for (osd::directory::entry const *dir = path.next(); dir; dir = path.next()) + { + std::string name(dir->name); + if (core_filename_ends_with(name, ".ini")) + { + emu_file file(m_options.categoryini_path(), OPEN_FLAG_READ); + if (file.open(name) == osd_file::error::NONE) + { + init_category(std::move(name), file); + file.close(); + } + } + } + std::stable_sort(m_ini_index.begin(), m_ini_index.end(), [] (auto const &x, auto const &y) { return 0 > core_stricmp(x.first.c_str(), y.first.c_str()); }); } //------------------------------------------------- -// scan directories and create index +// load and indexing ini files //------------------------------------------------- -void inifile_manager::directory_scan() +void inifile_manager::load_ini_category(size_t file, size_t category, std::unordered_set &result) const { - file_enumerator path(m_options.extraini_path()); - const osd::directory::entry *dir; + std::string const &filename(m_ini_index[file].first); + emu_file fp(m_options.categoryini_path(), OPEN_FLAG_READ); + if (fp.open(filename) != osd_file::error::NONE) + { + osd_printf_error("Failed to open category file %s for reading\n", filename.c_str()); + return; + } - while ((dir = path.next()) != nullptr) - if (core_filename_ends_with(dir->name, ".ini") && parseopen(dir->name)) - { - init_category(std::string(dir->name)); - parseclose(); - } + int64_t const offset(m_ini_index[file].second[category].second); + if (fp.seek(offset, SEEK_SET) || (fp.tell() != offset)) + { + fp.close(); + osd_printf_error("Failed to seek to category offset in file %s\n", filename.c_str()); + return; + } - // sort - std::stable_sort(ini_index.begin(), ini_index.end()); + char rbuf[MAX_CHAR_INFO]; + while (fp.gets(rbuf, MAX_CHAR_INFO) && rbuf[0] && ('[' != rbuf[0])) + { + auto const tail(std::find_if(std::begin(rbuf), std::prev(std::end(rbuf)), [] (char ch) { return !ch || ('\r' == ch) || ('\n' == ch); })); + *tail = '\0'; + int const dfind(driver_list::find(rbuf)); + if (0 <= dfind) + result.emplace(&driver_list::driver(dfind)); + } + + fp.close(); } //------------------------------------------------- // initialize category //------------------------------------------------- -void inifile_manager::init_category(std::string filename) +void inifile_manager::init_category(std::string &&filename, emu_file &file) { categoryindex index; char rbuf[MAX_CHAR_INFO]; - std::string readbuf; - while (fgets(rbuf, MAX_CHAR_INFO, fp) != nullptr) - if (rbuf[0] == '[') - { - readbuf = rbuf; - auto name = readbuf.substr(1, readbuf.find("]") - 1); - if (name == "FOLDER_SETTINGS") continue; - index.emplace_back(name, ftell(fp)); - } - - // sort - std::stable_sort(index.begin(), index.end()); - - if (!index.empty()) - ini_index.emplace_back(strmakelower(filename), index); -} - -//------------------------------------------------- -// load and indexing ini files -//------------------------------------------------- - -void inifile_manager::load_ini_category(std::vector &temp_filter) -{ - if (ini_index.empty()) - return; - - auto search_clones = false; - std::string filename(ini_index[c_file].first); - auto offset = ini_index[c_file].second[c_cat].second; - - if (filename == "category.ini" || filename == "alltime.ini") - search_clones = true; - - if (parseopen(filename.c_str())) + std::string name; + while (file.gets(rbuf, ARRAY_LENGTH(rbuf))) { - fseek(fp, offset, SEEK_SET); - char rbuf[MAX_CHAR_INFO]; - std::string readbuf; - while (fgets(rbuf, MAX_CHAR_INFO, fp) != nullptr) + if ('[' == rbuf[0]) { - readbuf = chartrimcarriage(rbuf); - - if (readbuf.empty() || readbuf[0] == '[') - break; - - auto dfind = driver_list::find(readbuf.c_str()); - if (dfind != -1) - { - temp_filter.push_back(dfind); - if (search_clones && driver_list::non_bios_clone(dfind) == -1) - for (int x = 0; x < driver_list::total(); x++) - if (readbuf == driver_list::driver(x).parent && readbuf != driver_list::driver(x).name) - temp_filter.push_back(x); - } + auto const head(std::next(std::begin(rbuf))); + auto const tail(std::find_if(head, std::end(rbuf), [] (char ch) { return !ch || (']' == ch); })); + name.assign(head, tail); + if ("FOLDER_SETTINGS" != name) + index.emplace_back(std::move(name), file.tell()); } - parseclose(); } + std::stable_sort(index.begin(), index.end(), [] (auto const &x, auto const &y) { return 0 > core_stricmp(x.first.c_str(), y.first.c_str()); }); + if (!index.empty()) + m_ini_index.emplace_back(std::move(filename), std::move(index)); } -//--------------------------------------------------------- -// parseopen - Open up file for reading -//--------------------------------------------------------- - -bool inifile_manager::parseopen(const char *filename) -{ - emu_file file(m_options.extraini_path(), OPEN_FLAG_READ); - if (file.open(filename) != osd_file::error::NONE) - return false; - - m_fullpath = file.fullpath(); - file.close(); - fp = fopen(m_fullpath.c_str(), "r"); - - fgetc(fp); - fseek(fp, 0, SEEK_SET); - return true; -} /************************************************************************** FAVORITE MANAGER diff --git a/src/frontend/mame/ui/inifile.h b/src/frontend/mame/ui/inifile.h index 88466a5c977..49344fd01eb 100644 --- a/src/frontend/mame/ui/inifile.h +++ b/src/frontend/mame/ui/inifile.h @@ -13,7 +13,10 @@ #pragma once -#include "../frontend/mame/ui/utils.h" +#include "ui/utils.h" + +#include + //------------------------------------------------- // INIFILE MANAGER @@ -27,50 +30,25 @@ public: // construction/destruction inifile_manager(running_machine &machine, ui_options &moptions); + // load systems from category + void load_ini_category(size_t file, size_t category, std::unordered_set &result) const; + // getters - running_machine &machine() const { return m_machine; } - std::string get_file() { return ini_index[c_file].first; } - std::string get_file(int file) { return ini_index[file].first; } - std::string get_category(int cat) { return ini_index[c_file].second[cat].first; } - std::string get_category() { return ini_index[c_file].second[c_cat].first; } - size_t total() { return ini_index.size(); } - size_t cat_total() { return ini_index[c_file].second.size(); } - uint16_t &cur_file() { return c_file; } - uint16_t &cur_cat() { return c_cat; } - - // load games from category - void load_ini_category(std::vector &temp_filter); - - // setters - void move_file(int d) { c_file += d; c_cat = 0; } - void move_cat(int d) { c_cat += d; } - void set_cat(uint16_t i) { c_cat = i; } - void set_file(uint16_t i) { c_file = i; } + size_t get_file_count() const { return m_ini_index.size(); } + std::string const &get_file_name(size_t file) const { return m_ini_index[file].first; } + size_t get_category_count(size_t file) const { return m_ini_index[file].second.size(); } + std::string const &get_category_name(size_t file, size_t category) const { return m_ini_index[file].second[category].first; } private: - // ini file structure - using categoryindex = std::vector>; - - // files indices - static uint16_t c_file, c_cat; - std::vector> ini_index; + using categoryindex = std::vector>; - // init category index - void init_category(std::string filename); - - // init file index - void directory_scan(); - - // file open/close/seek - bool parseopen(const char *filename); - void parseclose() { if (fp != nullptr) fclose(fp); } + void init_category(std::string &&filename, emu_file &file); // internal state - running_machine &m_machine; // reference to our machine - ui_options &m_options; - std::string m_fullpath; - FILE *fp = nullptr; + ui_options &m_options; + std::vector > m_ini_index; + }; //------------------------------------------------- diff --git a/src/frontend/mame/ui/moptions.cpp b/src/frontend/mame/ui/moptions.cpp index a59090a8f57..a030fa219ef 100644 --- a/src/frontend/mame/ui/moptions.cpp +++ b/src/frontend/mame/ui/moptions.cpp @@ -22,7 +22,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_EXTRAINI_PATH, "folders", OPTION_STRING, "path to extra ini files" }, + { OPTION_CATEGORYINI_PATH, "folders", OPTION_STRING, "path to catagory 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" }, { OPTION_PCBS_PATH, "pcb", OPTION_STRING, "path to pcbs image" }, diff --git a/src/frontend/mame/ui/moptions.h b/src/frontend/mame/ui/moptions.h index 71f42211755..9b750583307 100644 --- a/src/frontend/mame/ui/moptions.h +++ b/src/frontend/mame/ui/moptions.h @@ -17,7 +17,7 @@ // core directory options #define OPTION_HISTORY_PATH "historypath" -#define OPTION_EXTRAINI_PATH "extrainipath" +#define OPTION_CATEGORYINI_PATH "categorypath" #define OPTION_CABINETS_PATH "cabinets_directory" #define OPTION_CPANELS_PATH "cpanels_directory" #define OPTION_PCBS_PATH "pcbs_directory" @@ -80,7 +80,7 @@ public: // Search path options const char *history_path() const { return value(OPTION_HISTORY_PATH); } - const char *extraini_path() const { return value(OPTION_EXTRAINI_PATH); } + const char *categoryini_path() const { return value(OPTION_CATEGORYINI_PATH); } const char *cabinets_directory() const { return value(OPTION_CABINETS_PATH); } const char *cpanels_directory() const { return value(OPTION_CPANELS_PATH); } const char *pcbs_directory() const { return value(OPTION_PCBS_PATH); } diff --git a/src/frontend/mame/ui/optsmenu.cpp b/src/frontend/mame/ui/optsmenu.cpp index 901671081fc..fd29c3329bc 100644 --- a/src/frontend/mame/ui/optsmenu.cpp +++ b/src/frontend/mame/ui/optsmenu.cpp @@ -13,11 +13,9 @@ #include "ui/ui.h" #include "ui/submenu.h" -#include "ui/inifile.h" #include "ui/selector.h" #include "ui/custui.h" #include "ui/sndmenu.h" -#include "ui/custmenu.h" #include "ui/inputmap.h" #include "ui/dirmenu.h" @@ -25,6 +23,7 @@ #include "mameopts.h" #include "rendfont.h" + namespace ui { //------------------------------------------------- @@ -92,65 +91,6 @@ void menu_game_options::handle() }); } break; - case FILE_CATEGORY_FILTER: - if (menu_event->iptkey == IPT_UI_LEFT) - { - mame_machine_manager::instance()->inifile().move_file(-1); - changed = true; - } - else if (menu_event->iptkey == IPT_UI_RIGHT) - { - mame_machine_manager::instance()->inifile().move_file(1); - changed = true; - } - else if (menu_event->iptkey == IPT_UI_SELECT) - { - inifile_manager &ifile = mame_machine_manager::instance()->inifile(); - int total = ifile.total(); - std::vector s_sel(total); - mame_machine_manager::instance()->inifile().set_cat(0); - for (size_t index = 0; index < total; ++index) - s_sel[index] = ifile.get_file(index); - - menu::stack_push( - ui(), container(), std::move(s_sel), ifile.cur_file(), - [this] (int selection) - { - mame_machine_manager::instance()->inifile().set_file(selection); - mame_machine_manager::instance()->inifile().set_cat(0); - reset(reset_options::REMEMBER_REF); - }); - } - break; - case CATEGORY_FILTER: - if (menu_event->iptkey == IPT_UI_LEFT) - { - mame_machine_manager::instance()->inifile().move_cat(-1); - changed = true; - } - else if (menu_event->iptkey == IPT_UI_RIGHT) - { - mame_machine_manager::instance()->inifile().move_cat(1); - changed = true; - } - else if (menu_event->iptkey == IPT_UI_SELECT) - { - inifile_manager &ifile = mame_machine_manager::instance()->inifile(); - int total = ifile.cat_total(); - std::vector s_sel(total); - for (int index = 0; index < total; ++index) - s_sel[index] = ifile.get_category(index); - - menu::stack_push( - ui(), container(), std::move(s_sel), ifile.cur_cat(), - [this] (int selection) - { - mame_machine_manager::instance()->inifile().cur_cat() = selection; - mame_machine_manager::instance()->inifile().set_cat(selection); - reset(reset_options::REMEMBER_REF); - }); - } - break; case FILTER_ADJUST: if (menu_event->iptkey == IPT_UI_LEFT) { @@ -247,38 +187,17 @@ void menu_game_options::populate(float &customtop, float &custombottom) // add filter item uint32_t arrow_flags = get_arrow_flags(machine_filter::FIRST, machine_filter::LAST, m_main); - if (machine_filter::CATEGORY == m_main) - { - item_append(_("Filter"), machine_filter::display_name(m_main), arrow_flags, (void *)(uintptr_t)FILTER_MENU); - if (mame_machine_manager::instance()->inifile().total() > 0) - { - inifile_manager &inif = mame_machine_manager::instance()->inifile(); - - arrow_flags = get_arrow_flags(uint16_t(0), uint16_t(inif.total() - 1), inif.cur_file()); - fbuff = _(" ^!File"); - convert_command_glyph(fbuff); - item_append(fbuff, inif.get_file(), arrow_flags, (void *)(uintptr_t)FILE_CATEGORY_FILTER); + auto active_filter(main_filters::filters.find(m_main)); + if (main_filters::filters.end() == active_filter) + active_filter = main_filters::filters.emplace(m_main, machine_filter::create(m_main)).first; + item_append(_("Filter"), active_filter->second->display_name(), arrow_flags, (void *)(uintptr_t)FILTER_MENU); - arrow_flags = get_arrow_flags(uint16_t(0), uint16_t(inif.cat_total() - 1), inif.cur_cat()); - fbuff = _(" ^!Category"); - convert_command_glyph(fbuff); - item_append(fbuff, inif.get_category(), arrow_flags, (void *)(uintptr_t)CATEGORY_FILTER); - } - } - else + // add subitem if the filter wants it + if (active_filter->second->wants_adjuster()) { - auto active_filter(main_filters::filters.find(m_main)); - if (main_filters::filters.end() == active_filter) - active_filter = main_filters::filters.emplace(m_main, machine_filter::create(m_main)).first; - item_append(_("Filter"), active_filter->second->display_name(), arrow_flags, (void *)(uintptr_t)FILTER_MENU); - - // add subitem if the filter wants it - if (active_filter->second->wants_adjuster()) - { - std::string name("^!"); - convert_command_glyph(name); - item_append(name, active_filter->second->adjust_text(), active_filter->second->arrow_flags(), (void *)(FILTER_ADJUST)); - } + std::string name("^!"); + convert_command_glyph(name); + item_append(name, active_filter->second->adjust_text(), active_filter->second->arrow_flags(), (void *)(FILTER_ADJUST)); } item_append(menu_item_type::SEPARATOR); diff --git a/src/frontend/mame/ui/optsmenu.h b/src/frontend/mame/ui/optsmenu.h index 2ef9d2969c8..e9650e3a95b 100644 --- a/src/frontend/mame/ui/optsmenu.h +++ b/src/frontend/mame/ui/optsmenu.h @@ -30,9 +30,7 @@ private: enum { FILTER_MENU = 1, - FILE_CATEGORY_FILTER, FILTER_ADJUST, - CATEGORY_FILTER, CONF_DIR, DISPLAY_MENU, CUSTOM_MENU, diff --git a/src/frontend/mame/ui/selgame.cpp b/src/frontend/mame/ui/selgame.cpp index cb66194acb5..e2e1ee0bfb4 100644 --- a/src/frontend/mame/ui/selgame.cpp +++ b/src/frontend/mame/ui/selgame.cpp @@ -27,7 +27,6 @@ #include "drivenum.h" #include "emuopts.h" #include "mame.h" -#include "rendfont.h" #include "rendutil.h" #include "softlist_dev.h" #include "uiinput.h" @@ -170,8 +169,6 @@ void menu_select_game::handle() if (!m_prev_selected) m_prev_selected = item[0].ref; - bool check_filter = false; - // if I have to load datfile, perform a hard reset if (ui_globals::reset) { @@ -195,6 +192,7 @@ void menu_select_game::handle() machine().ui_input().pressed(IPT_UI_PAUSE); // process the menu + bool check_filter(false); const event *menu_event = process(PROCESS_LR_REPEAT); if (menu_event) { @@ -228,7 +226,8 @@ void menu_select_game::handle() // this is generated when something in the left box is clicked m_prev_selected = nullptr; check_filter = true; - highlight = l_hover; + highlight = hover - HOVER_FILTER_FIRST; + assert((machine_filter::FIRST <= highlight) && (machine_filter::LAST >= highlight)); break; case IPT_UI_CONFIGURE: @@ -250,7 +249,6 @@ void menu_select_game::handle() } else if (get_focus() == focused_menu::LEFT) { - l_hover = highlight; check_filter = true; m_prev_selected = nullptr; } @@ -377,38 +375,29 @@ void menu_select_game::handle() if (check_filter) { m_search.clear(); - switch (l_hover) + if ((machine_filter::FIRST <= highlight) && (machine_filter::LAST >= highlight)) { - case machine_filter::CATEGORY: - // FIXME: this should be unified with the other filters - main_filters::actual = machine_filter::type(l_hover); - menu::stack_push(ui(), container()); - break; - default: - if (l_hover >= machine_filter::ALL) - { - auto it(main_filters::filters.find(machine_filter::type(l_hover))); - if (main_filters::filters.end() == it) - it = main_filters::filters.emplace(machine_filter::type(l_hover), machine_filter::create(machine_filter::type(l_hover))).first; - it->second->show_ui( - ui(), - container(), - [this] (machine_filter &filter) + auto it(main_filters::filters.find(machine_filter::type(highlight))); + if (main_filters::filters.end() == it) + it = main_filters::filters.emplace(machine_filter::type(highlight), machine_filter::create(machine_filter::type(highlight))).first; + it->second->show_ui( + ui(), + container(), + [this] (machine_filter &filter) + { + machine_filter::type const new_type(filter.get_type()); + if (machine_filter::CUSTOM == new_type) { - machine_filter::type const new_type(filter.get_type()); - if (machine_filter::CUSTOM == new_type) + emu_file file(ui().options().ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + if (file.open("custom_", emulator_info::get_configname(), "_filter.ini") == osd_file::error::NONE) { - emu_file file(ui().options().ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - if (file.open("custom_", emulator_info::get_configname(), "_filter.ini") == osd_file::error::NONE) - { - filter.save_ini(file, 0); - file.close(); - } + filter.save_ini(file, 0); + file.close(); } - main_filters::actual = new_type; - reset(reset_options::SELECT_FIRST); - }); - } + } + main_filters::actual = new_type; + reset(reset_options::SELECT_FIRST); + }); } } } @@ -449,9 +438,6 @@ void menu_select_game::populate(float &customtop, float &custombottom) case machine_filter::UNAVAILABLE: m_displaylist = m_unavailsortedlist; break; - case machine_filter::CATEGORY: - build_category(); - break; default: { auto const it(main_filters::filters.find(main_filters::actual)); @@ -885,22 +871,6 @@ void menu_select_game::change_info_pane(int delta) } } -//------------------------------------------------- -// build category list -//------------------------------------------------- - -void menu_select_game::build_category() -{ - m_displaylist.clear(); - std::vector temp_filter; - mame_machine_manager::instance()->inifile().load_ini_category(temp_filter); - - for (auto actual : temp_filter) - m_displaylist.push_back(&driver_list::driver(actual)); - - std::stable_sort(m_displaylist.begin(), m_displaylist.end(), sorted_game_list); -} - //------------------------------------------------- // populate search list //------------------------------------------------- @@ -1240,147 +1210,10 @@ void menu_select_game::load_custom_filters() float menu_select_game::draw_left_panel(float x1, float y1, float x2, float y2) { - float line_height = ui().get_line_height(); - - if (ui_globals::panels_status == SHOW_PANELS || ui_globals::panels_status == HIDE_RIGHT_PANEL) - { - auto const active_filter(main_filters::filters.find(main_filters::actual)); - float origy1 = y1; - float origy2 = y2; - float text_size = ui().options().infos_size(); - float line_height_max = line_height * text_size; - float left_width = 0.0f; - int line_count = machine_filter::COUNT; - int phover = HOVER_FILTER_FIRST; - float sc = y2 - y1 - (2.0f * UI_BOX_TB_BORDER); - - if ((line_count * line_height_max) > sc) - { - float lm = sc / (line_count); - text_size = lm / line_height; - line_height_max = line_height * text_size; - } - - std::string tmp("_# "); - convert_command_glyph(tmp); - float text_sign = ui().get_string_width(tmp.c_str(), text_size); - for (machine_filter::type x = machine_filter::FIRST; x < machine_filter::COUNT; ++x) - { - float total_width; - - // compute width of left hand side - total_width = ui().get_string_width(machine_filter::display_name(x), text_size); - total_width += text_sign; - - // track the maximum - if (total_width > left_width) - left_width = total_width; - } - - x2 = x1 + left_width + 2.0f * UI_BOX_LR_BORDER; - ui().draw_outlined_box(container(), x1, y1, x2, y2, UI_BACKGROUND_COLOR); - - // take off the borders - x1 += UI_BOX_LR_BORDER; - x2 -= UI_BOX_LR_BORDER; - y1 += UI_BOX_TB_BORDER; - y2 -= UI_BOX_TB_BORDER; - - for (machine_filter::type filter = machine_filter::FIRST; filter < machine_filter::COUNT; ++filter) - { - std::string str; - if (main_filters::filters.end() != active_filter) - { - str = active_filter->second->adorned_display_name(filter); - } - else - { - if (main_filters::actual == filter) - { - str = std::string("_> ") + str; - convert_command_glyph(str); - } - str.append(machine_filter::display_name(filter)); - } - - rgb_t bgcolor = UI_TEXT_BG_COLOR; - rgb_t fgcolor = UI_TEXT_COLOR; - - if (mouse_in_rect(x1, y1, x2, y1 + line_height_max)) - { - bgcolor = UI_MOUSEOVER_BG_COLOR; - fgcolor = UI_MOUSEOVER_COLOR; - hover = phover + filter; - menu::highlight(x1, y1, x2, y1 + line_height_max, bgcolor); - } - - if (highlight == filter && get_focus() == focused_menu::LEFT) - { - fgcolor = rgb_t(0xff, 0xff, 0xff, 0x00); - bgcolor = rgb_t(0xff, 0xff, 0xff, 0xff); - ui().draw_textured_box(container(), x1, y1, x2, y1 + line_height_max, bgcolor, rgb_t(255, 43, 43, 43), - hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1)); - } - - float const x1t = x1 + ((str == machine_filter::display_name(filter)) ? text_sign : 0.0f); - - ui().draw_text_full(container(), str.c_str(), x1t, y1, x2 - x1, ui::text_layout::LEFT, ui::text_layout::NEVER, - mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr, text_size); - y1 += line_height_max; - } - - x1 = x2 + UI_BOX_LR_BORDER; - x2 = x1 + 2.0f * UI_BOX_LR_BORDER; - y1 = origy1; - y2 = origy2; - float space = x2 - x1; - float lr_arrow_width = 0.4f * space * machine().render().ui_aspect(); - rgb_t fgcolor = UI_TEXT_COLOR; - - // set left-right arrows dimension - float ar_x0 = 0.5f * (x2 + x1) - 0.5f * lr_arrow_width; - float ar_y0 = 0.5f * (y2 + y1) + 0.1f * space; - float ar_x1 = ar_x0 + lr_arrow_width; - float ar_y1 = 0.5f * (y2 + y1) + 0.9f * space; - - ui().draw_outlined_box(container(), x1, y1, x2, y2, rgb_t(0xEF, 0x12, 0x47, 0x7B)); - - if (mouse_in_rect(x1, y1, x2, y2)) - { - fgcolor = UI_MOUSEOVER_COLOR; - hover = HOVER_LPANEL_ARROW; - } - - draw_arrow(ar_x0, ar_y0, ar_x1, ar_y1, fgcolor, ROT90 ^ ORIENTATION_FLIP_X); - return x2 + UI_BOX_LR_BORDER; - } - else - { - float space = x2 - x1; - float lr_arrow_width = 0.4f * space * machine().render().ui_aspect(); - rgb_t fgcolor = UI_TEXT_COLOR; - - // set left-right arrows dimension - float ar_x0 = 0.5f * (x2 + x1) - 0.5f * lr_arrow_width; - float ar_y0 = 0.5f * (y2 + y1) + 0.1f * space; - float ar_x1 = ar_x0 + lr_arrow_width; - float ar_y1 = 0.5f * (y2 + y1) + 0.9f * space; - - ui().draw_outlined_box(container(), x1, y1, x2, y2, rgb_t(0xEF, 0x12, 0x47, 0x7B)); - - if (mouse_in_rect(x1, y1, x2, y2)) - { - fgcolor = UI_MOUSEOVER_COLOR; - hover = HOVER_LPANEL_ARROW; - } - - draw_arrow(ar_x0, ar_y0, ar_x1, ar_y1, fgcolor, ROT90); - return x2 + UI_BOX_LR_BORDER; - } + return menu_select_launch::draw_left_panel(main_filters::actual, main_filters::filters, highlight, x1, y1, x2, y2); } - //------------------------------------------------- // get selected software and/or driver //------------------------------------------------- @@ -1401,8 +1234,6 @@ void menu_select_game::get_selection(ui_software_info const *&software, game_dri void menu_select_game::make_topbox_text(std::string &line0, std::string &line1, std::string &line2) const { - inifile_manager &inifile = mame_machine_manager::instance()->inifile(); - line0 = string_format(_("%1$s %2$s ( %3$d / %4$d machines (%5$d BIOS) )"), emulator_info::get_appname(), bare_build_version, @@ -1414,14 +1245,6 @@ void menu_select_game::make_topbox_text(std::string &line0, std::string &line1, { line1.clear(); } - else if (main_filters::actual == machine_filter::CATEGORY && inifile.total() > 0) - { - line1 = string_format(_("%1$s (%2$s - %3$s) - Search: %4$s_"), - machine_filter::display_name(main_filters::actual), - inifile.get_file(), - inifile.get_category(), - m_search); - } else { auto const it(main_filters::filters.find(main_filters::actual)); diff --git a/src/frontend/mame/ui/selgame.h b/src/frontend/mame/ui/selgame.h index 0a2b49e08bd..7cccab7a2fb 100644 --- a/src/frontend/mame/ui/selgame.h +++ b/src/frontend/mame/ui/selgame.h @@ -66,7 +66,6 @@ private: // internal methods void change_info_pane(int delta); - void build_category(); void build_available_list(); bool isfavorite() const; diff --git a/src/frontend/mame/ui/selmenu.cpp b/src/frontend/mame/ui/selmenu.cpp index 7ae24e1cdae..9a41f285a57 100644 --- a/src/frontend/mame/ui/selmenu.cpp +++ b/src/frontend/mame/ui/selmenu.cpp @@ -26,6 +26,7 @@ #include "drivenum.h" #include "emuopts.h" +#include "rendfont.h" #include "rendutil.h" #include "softlist.h" #include "softlist_dev.h" @@ -133,9 +134,11 @@ char const *const menu_select_launch::s_info_titles[] = { __("Sysinfo") }; -// instantiate possible variants of select_bios so derived classes don't get link errors +// 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); +template float menu_select_launch::draw_left_panel(machine_filter::type current, std::map const &filters, int focus, float x1, float y1, float x2, float y2); +template float menu_select_launch::draw_left_panel(software_filter::type current, std::map const &filters, int focus, float x1, float y1, float x2, float y2); menu_select_launch::system_flags::system_flags(machine_static_info const &info) @@ -813,6 +816,127 @@ bool menu_select_launch::draw_error_text() } +template +float menu_select_launch::draw_left_panel( + typename Filter::type current, + std::map const &filters, + int focus, + float x1, float y1, float x2, float y2) +{ + if ((ui_globals::panels_status != SHOW_PANELS) && (ui_globals::panels_status != HIDE_RIGHT_PANEL)) + return draw_collapsed_left_panel(x1, y1, x2, y2); + + // calculate line height + float const line_height(ui().get_line_height()); + float const text_size(ui().options().infos_size()); + float const sc(y2 - y1 - (2.0f * UI_BOX_TB_BORDER)); + float line_height_max(line_height * text_size); + if ((Filter::COUNT * line_height_max) > sc) + { + float const lm(sc / Filter::COUNT); + line_height_max = line_height * (lm / line_height); + } + + // calculate horizontal offset for unadorned names + std::string tmp("_# "); + convert_command_glyph(tmp); + float const text_sign = ui().get_string_width(tmp.c_str(), text_size); + + // get the maximum width of a filter name + float left_width(0.0f); + for (typename Filter::type x = Filter::FIRST; Filter::COUNT > x; ++x) + left_width = std::max(ui().get_string_width(Filter::display_name(x), text_size) + text_sign, left_width); + + // outline the box and inset by the border width + float const origy1(y1); + float const origy2(y2); + x2 = x1 + left_width + 2.0f * UI_BOX_LR_BORDER; + ui().draw_outlined_box(container(), x1, y1, x2, y2, UI_BACKGROUND_COLOR); + x1 += UI_BOX_LR_BORDER; + x2 -= UI_BOX_LR_BORDER; + y1 += UI_BOX_TB_BORDER; + y2 -= UI_BOX_TB_BORDER; + + // now draw the rows + auto const active_filter(filters.find(current)); + for (typename Filter::type filter = Filter::FIRST; Filter::COUNT > filter; ++filter) + { + std::string str; + if (filters.end() != active_filter) + { + str = active_filter->second->adorned_display_name(filter); + } + else + { + if (current == filter) + { + str = std::string("_> "); + convert_command_glyph(str); + } + str.append(Filter::display_name(filter)); + } + + // handle mouse hover in passing + rgb_t bgcolor = UI_TEXT_BG_COLOR; + rgb_t fgcolor = UI_TEXT_COLOR; + if (mouse_in_rect(x1, y1, x2, y1 + line_height_max)) + { + bgcolor = UI_MOUSEOVER_BG_COLOR; + fgcolor = UI_MOUSEOVER_COLOR; + hover = HOVER_FILTER_FIRST + filter; + highlight(x1, y1, x2, y1 + line_height_max, bgcolor); + } + + // draw primary highlight if keyboard focus is here + if ((focus == filter) && (get_focus() == focused_menu::LEFT)) + { + fgcolor = rgb_t(0xff, 0xff, 0xff, 0x00); + bgcolor = rgb_t(0xff, 0xff, 0xff, 0xff); + ui().draw_textured_box( + container(), + x1, y1, x2, y1 + line_height_max, + bgcolor, rgb_t(255, 43, 43, 43), + hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1)); + } + + // finally draw the text itself and move to the next line + float const x1t = x1 + ((str == Filter::display_name(filter)) ? text_sign : 0.0f); + ui().draw_text_full( + container(), str.c_str(), + x1t, y1, x2 - x1, + ui::text_layout::LEFT, ui::text_layout::NEVER, + mame_ui_manager::NORMAL, fgcolor, bgcolor, + nullptr, nullptr, text_size); + y1 += line_height_max; + } + + x1 = x2 + UI_BOX_LR_BORDER; + x2 = x1 + 2.0f * UI_BOX_LR_BORDER; + y1 = origy1; + y2 = origy2; + float const space = x2 - x1; + float const lr_arrow_width = 0.4f * space * machine().render().ui_aspect(); + + // set left-right arrows dimension + float const ar_x0 = 0.5f * (x2 + x1) - 0.5f * lr_arrow_width; + float const ar_y0 = 0.5f * (y2 + y1) + 0.1f * space; + float const ar_x1 = ar_x0 + lr_arrow_width; + float const ar_y1 = 0.5f * (y2 + y1) + 0.9f * space; + + ui().draw_outlined_box(container(), x1, y1, x2, y2, rgb_t(0xef, 0x12, 0x47, 0x7b)); + + rgb_t fgcolor = UI_TEXT_COLOR; + if (mouse_in_rect(x1, y1, x2, y2)) + { + fgcolor = UI_MOUSEOVER_COLOR; + hover = HOVER_LPANEL_ARROW; + } + + draw_arrow(ar_x0, ar_y0, ar_x1, ar_y1, fgcolor, ROT90 ^ ORIENTATION_FLIP_X); + return x2 + UI_BOX_LR_BORDER; +} + + template bool menu_select_launch::select_bios(T const &driver, bool inlist) { s_bios biosname; @@ -1416,15 +1540,8 @@ void menu_select_launch::handle_events(uint32_t flags, event &ev) ui_globals::rpanel = (HOVER_RP_FIRST - hover) * (-1); stop = true; } - else if (hover >= HOVER_SW_FILTER_FIRST && hover <= HOVER_SW_FILTER_LAST) - { - l_sw_hover = (HOVER_SW_FILTER_FIRST - hover) * (-1); - ev.iptkey = IPT_OTHER; - stop = true; - } else if (hover >= HOVER_FILTER_FIRST && hover <= HOVER_FILTER_LAST) { - l_hover = (HOVER_FILTER_FIRST - hover) * (-1); ev.iptkey = IPT_OTHER; stop = true; } @@ -2282,6 +2399,36 @@ void menu_select_launch::exit(running_machine &machine) } +//------------------------------------------------- +// draw collapsed left panel +//------------------------------------------------- + +float menu_select_launch::draw_collapsed_left_panel(float x1, float y1, float x2, float y2) +{ + float const space = x2 - x1; + float const lr_arrow_width = 0.4f * space * machine().render().ui_aspect(); + + // set left-right arrows dimension + float const ar_x0 = 0.5f * (x2 + x1) - (0.5f * lr_arrow_width); + float const ar_y0 = 0.5f * (y2 + y1) + (0.1f * space); + float const ar_x1 = ar_x0 + lr_arrow_width; + float const ar_y1 = 0.5f * (y2 + y1) + (0.9f * space); + + ui().draw_outlined_box(container(), x1, y1, x2, y2, rgb_t(0xef, 0x12, 0x47, 0x7b)); // FIXME: magic numbers in colour? + + rgb_t fgcolor = UI_TEXT_COLOR; + if (mouse_in_rect(x1, y1, x2, y2)) + { + fgcolor = UI_MOUSEOVER_COLOR; + hover = HOVER_LPANEL_ARROW; + } + + draw_arrow(ar_x0, ar_y0, ar_x1, ar_y1, fgcolor, ROT90); + + return x2 + UI_BOX_LR_BORDER; +} + + //------------------------------------------------- // draw infos //------------------------------------------------- diff --git a/src/frontend/mame/ui/selmenu.h b/src/frontend/mame/ui/selmenu.h index 8b8d0157448..5bad2445b97 100644 --- a/src/frontend/mame/ui/selmenu.h +++ b/src/frontend/mame/ui/selmenu.h @@ -114,10 +114,16 @@ protected: bool draw_error_text(); + template + float draw_left_panel( + typename Filter::type current, + std::map const &filters, + int focus, + float x1, float y1, float x2, float y2); + template bool select_bios(T const &driver, bool inlist); bool select_part(software_info const &info, ui_software_info const &ui_info); - int l_hover, l_sw_hover; int visible_items; void *m_prev_selected; int m_total_lines; @@ -188,6 +194,7 @@ private: // draw left panel virtual float draw_left_panel(float x1, float y1, float x2, float y2) = 0; + float draw_collapsed_left_panel(float x1, float y1, float x2, float y2); // draw infos void infos_render(float x1, float y1, float x2, float y2); diff --git a/src/frontend/mame/ui/selsoft.cpp b/src/frontend/mame/ui/selsoft.cpp index e64a6136cf7..ec8262c4a93 100644 --- a/src/frontend/mame/ui/selsoft.cpp +++ b/src/frontend/mame/ui/selsoft.cpp @@ -20,7 +20,6 @@ #include "drivenum.h" #include "emuopts.h" #include "mame.h" -#include "rendfont.h" #include "rendutil.h" #include "softlist_dev.h" #include "uiinput.h" @@ -119,12 +118,11 @@ void menu_select_software::handle() if (m_prev_selected == nullptr) m_prev_selected = item[0].ref; - bool check_filter = false; - // ignore pause keys by swallowing them before we process the menu machine().ui_input().pressed(IPT_UI_PAUSE); // process the menu + bool check_filter(false); const event *menu_event = process(PROCESS_LR_REPEAT); if (menu_event) { @@ -137,7 +135,6 @@ void menu_select_software::handle() case IPT_UI_SELECT: if (get_focus() == focused_menu::LEFT) { - l_sw_hover = highlight; check_filter = true; m_prev_selected = nullptr; } @@ -201,8 +198,9 @@ void menu_select_software::handle() case IPT_OTHER: // this is generated when something in the left box is clicked - highlight = l_sw_hover; check_filter = true; + highlight = hover - HOVER_FILTER_FIRST; + assert((software_filter::FIRST <= highlight) && (software_filter::LAST >= highlight)); m_prev_selected = nullptr; break; @@ -256,9 +254,9 @@ void menu_select_software::handle() { m_search.clear(); - filter_map::const_iterator it(m_filters.find(software_filter::type(l_sw_hover))); + filter_map::const_iterator it(m_filters.find(software_filter::type(highlight))); if (m_filters.end() == it) - it = m_filters.emplace(software_filter::type(l_sw_hover), software_filter::create(software_filter::type(l_sw_hover), m_filter_data)).first; + it = m_filters.emplace(software_filter::type(highlight), software_filter::create(software_filter::type(highlight), m_filter_data)).first; it->second->show_ui( ui(), container(), @@ -585,135 +583,10 @@ void menu_select_software::find_matches(const char *str, int count) float menu_select_software::draw_left_panel(float x1, float y1, float x2, float y2) { - if (ui_globals::panels_status == SHOW_PANELS || ui_globals::panels_status == HIDE_RIGHT_PANEL) - { - filter_map::const_iterator active_filter(m_filters.find(m_filter_type)); - if (m_filters.end() == active_filter) - active_filter = m_filters.emplace(m_filter_type, software_filter::create(m_filter_type, m_filter_data)).first; - float origy1 = y1; - float origy2 = y2; - float text_size = 0.75f; - float l_height = ui().get_line_height(); - float line_height = l_height * text_size; - float left_width = 0.0f; - int line_count = software_filter::COUNT; - int phover = HOVER_SW_FILTER_FIRST; - float sc = y2 - y1 - (2.0f * UI_BOX_TB_BORDER); - - if ((line_count * line_height) > sc) - { - float lm = sc / (line_count); - text_size = lm / l_height; - line_height = l_height * text_size; - } - - std::string tmp("_# "); - convert_command_glyph(tmp); - float text_sign = ui().get_string_width(tmp.c_str(), text_size); - for (software_filter::type x = software_filter::FIRST; x < software_filter::COUNT; ++x) - { - float total_width; - - // compute width of left hand side - total_width = ui().get_string_width(software_filter::display_name(x), text_size); - total_width += text_sign; - - // track the maximum - if (total_width > left_width) - left_width = total_width; - } - - x2 = x1 + left_width + 2.0f * UI_BOX_LR_BORDER; - ui().draw_outlined_box(container(), x1, y1, x2, y2, UI_BACKGROUND_COLOR); - - // take off the borders - x1 += UI_BOX_LR_BORDER; - x2 -= UI_BOX_LR_BORDER; - y1 += UI_BOX_TB_BORDER; - y2 -= UI_BOX_TB_BORDER; - - for (software_filter::type filter = software_filter::FIRST; filter < software_filter::COUNT; ++filter) - { - std::string const str(active_filter->second->adorned_display_name(filter)); - rgb_t bgcolor = UI_TEXT_BG_COLOR; - rgb_t fgcolor = UI_TEXT_COLOR; - - if (mouse_in_rect(x1, y1, x2, y1 + line_height)) - { - bgcolor = UI_MOUSEOVER_BG_COLOR; - fgcolor = UI_MOUSEOVER_COLOR; - hover = phover + filter; - } - - if (highlight == filter && get_focus() == focused_menu::LEFT) - { - fgcolor = rgb_t(0xff, 0xff, 0xff, 0x00); - bgcolor = rgb_t(0xff, 0xff, 0xff, 0xff); - } - - if (bgcolor != UI_TEXT_BG_COLOR) - { - ui().draw_textured_box(container(), x1, y1, x2, y1 + line_height, bgcolor, rgb_t(255, 43, 43, 43), - hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1)); - } - - float const x1t = x1 + ((str == software_filter::display_name(filter)) ? text_sign : 0.0f); - - ui().draw_text_full(container(), str.c_str(), x1t, y1, x2 - x1, ui::text_layout::LEFT, ui::text_layout::NEVER, - mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr, text_size); - y1 += line_height; - } - - x1 = x2 + UI_BOX_LR_BORDER; - x2 = x1 + 2.0f * UI_BOX_LR_BORDER; - y1 = origy1; - y2 = origy2; - float space = x2 - x1; - float lr_arrow_width = 0.4f * space * machine().render().ui_aspect(); - rgb_t fgcolor = UI_TEXT_COLOR; - - // set left-right arrows dimension - float ar_x0 = 0.5f * (x2 + x1) - 0.5f * lr_arrow_width; - float ar_y0 = 0.5f * (y2 + y1) + 0.1f * space; - float ar_x1 = ar_x0 + lr_arrow_width; - float ar_y1 = 0.5f * (y2 + y1) + 0.9f * space; - - ui().draw_outlined_box(container(), x1, y1, x2, y2, rgb_t(0xEF, 0x12, 0x47, 0x7B)); - - if (mouse_in_rect(x1, y1, x2, y2)) - { - fgcolor = UI_MOUSEOVER_COLOR; - hover = HOVER_LPANEL_ARROW; - } - - draw_arrow(ar_x0, ar_y0, ar_x1, ar_y1, fgcolor, ROT90 ^ ORIENTATION_FLIP_X); - return x2 + UI_BOX_LR_BORDER; - } - else - { - float space = x2 - x1; - float lr_arrow_width = 0.4f * space * machine().render().ui_aspect(); - rgb_t fgcolor = UI_TEXT_COLOR; - - // set left-right arrows dimension - float ar_x0 = 0.5f * (x2 + x1) - 0.5f * lr_arrow_width; - float ar_y0 = 0.5f * (y2 + y1) + 0.1f * space; - float ar_x1 = ar_x0 + lr_arrow_width; - float ar_y1 = 0.5f * (y2 + y1) + 0.9f * space; - - ui().draw_outlined_box(container(), x1, y1, x2, y2, rgb_t(0xEF, 0x12, 0x47, 0x7B)); - - if (mouse_in_rect(x1, y1, x2, y2)) - { - fgcolor = UI_MOUSEOVER_COLOR; - hover = HOVER_LPANEL_ARROW; - } - - draw_arrow(ar_x0, ar_y0, ar_x1, ar_y1, fgcolor, ROT90); - return x2 + UI_BOX_LR_BORDER; - } + return menu_select_launch::draw_left_panel(m_filter_type, m_filters, highlight, x1, y1, x2, y2); } + //------------------------------------------------- // get selected software and/or driver //------------------------------------------------- diff --git a/src/frontend/mame/ui/utils.cpp b/src/frontend/mame/ui/utils.cpp index df60068d949..5bd6c6cfe1f 100644 --- a/src/frontend/mame/ui/utils.cpp +++ b/src/frontend/mame/ui/utils.cpp @@ -12,16 +12,21 @@ #include "ui/utils.h" #include "ui/custmenu.h" // FIXME: get s_filter out of here +#include "ui/inifile.h" #include "ui/selector.h" #include "language.h" +#include "mame.h" #include "drivenum.h" #include "rendfont.h" #include "softlist.h" +#include #include +#include #include +#include namespace ui { @@ -180,9 +185,9 @@ public: } protected: - choice_filter_impl_base(std::vector const &choices, char const *value) : - m_choices(choices), - m_selection(0U) + choice_filter_impl_base(std::vector const &choices, char const *value) + : m_choices(choices) + , m_selection(0U) { if (value) { @@ -211,6 +216,8 @@ template class composite_filter_impl_base : public simple_filter_impl_base { public: + virtual void show_ui(mame_ui_manager &mui, render_container &container, std::function &&handler) override; + virtual bool wants_adjuster() const override { return true; } virtual char const *adjust_text() const override { return _(""); } @@ -255,14 +262,15 @@ public: break; typename Base::type const t(flt->get_type()); - bool const r(flt->apply(info)); if (Impl::is_inclusion(t)) { - inclusions.set(t); - if (r) - included.set(t); + if (!included.test(t)) + { + inclusions.set(t); + included.set(t, flt->apply(info)); + } } - else if (!r) + else if (!flt->apply(info)) { return false; } @@ -270,8 +278,6 @@ public: return inclusions == included; } - virtual void show_ui(mame_ui_manager &mui, render_container &container, std::function &&handler) override; - protected: composite_filter_impl_base() { } @@ -308,11 +314,11 @@ private: mame_ui_manager &mui, render_container &container, Impl &parent, - std::function &&handler) : - menu(mui, container), - m_parent(parent), - m_handler(std::move(handler)), - m_added(false) + std::function &&handler) + : menu(mui, container) + , m_parent(parent) + , m_handler(std::move(handler)) + , m_added(false) { } @@ -472,7 +478,7 @@ void composite_filter_impl_base::menu_configure::populate(floa unsigned i = 0; for (i = 0; (MAX > i) && m_parent.m_filters[i]; ++i) { - item_append(util::string_format("Filter %u", i + 1), m_parent.m_filters[i]->display_name(), get_arrow_flags(i), (void *)(FILTER_FIRST + i)); + item_append(util::string_format(_("Filter %1$u"), i + 1), m_parent.m_filters[i]->display_name(), get_arrow_flags(i), (void *)(FILTER_FIRST + i)); if (m_added) selected = item.size() - 2; if (m_parent.m_filters[i]->wants_adjuster()) @@ -700,8 +706,8 @@ public: class manufacturer_machine_filter : public choice_filter_impl_base { public: - manufacturer_machine_filter(char const *value, emu_file *file, unsigned indent) : - choice_filter_impl_base(c_mnfct::ui, value) + manufacturer_machine_filter(char const *value, emu_file *file, unsigned indent) + : choice_filter_impl_base(c_mnfct::ui, value) { } @@ -721,8 +727,8 @@ public: class year_machine_filter : public choice_filter_impl_base { public: - year_machine_filter(char const *value, emu_file *file, unsigned indent) : - choice_filter_impl_base(c_year::ui, value) + year_machine_filter(char const *value, emu_file *file, unsigned indent) + : choice_filter_impl_base(c_year::ui, value) { } @@ -780,6 +786,339 @@ using favorite_machine_filter = inclusive_machine_filter_impl +{ +public: + category_machine_filter(char const *value, emu_file *file, unsigned indent) + : m_ini(0) + , m_group(0) + , m_include_clones(false) + , m_adjust_text() + , m_cache() + , m_cache_valid(false) + { + inifile_manager const &mgr(mame_machine_manager::instance()->inifile()); + if (value) + { + char const *const split(std::strchr(value, '/')); + std::string ini; + if (split) + ini.assign(value, split); + else + ini.assign(value); + + for (unsigned i = 0; mgr.get_file_count() > i; ++i) + { + if (mgr.get_file_name(i) == ini) + { + m_ini = i; + if (split) + { + std::string const group(split + 1); + for (unsigned j = 0; mgr.get_category_count(i) > j; ++j) + { + if (mgr.get_category_name(i, j) == group) + { + m_group = j; + break; + } + } + } + break; + } + } + } + + if (mgr.get_file_count() > m_ini) + m_include_clones = include_clones_default(mgr.get_file_name(m_ini)); + + set_adjust_text(); + } + + virtual char const *filter_text() const override + { + inifile_manager const &mgr(mame_machine_manager::instance()->inifile()); + return ((mgr.get_file_count() > m_ini) && (mgr.get_category_count(m_ini) > m_group)) ? m_adjust_text.c_str() : nullptr; + } + + virtual void show_ui(mame_ui_manager &mui, render_container &container, std::function &&handler) override; + + virtual bool wants_adjuster() const override { return mame_machine_manager::instance()->inifile().get_file_count(); } + virtual char const *adjust_text() const override { return m_adjust_text.c_str(); } + + virtual void save_ini(emu_file &file, unsigned indent) const override + { + char const *const text(filter_text()); + file.puts(util::string_format("%2$*1$s%3$s = %4$s\n", 2 * indent, "", this->config_name(), text ? text : "").c_str()); + } + + virtual bool apply(game_driver const &drv) const override + { + inifile_manager const &mgr(mame_machine_manager::instance()->inifile()); + if (!mgr.get_file_count()) + return true; + else if ((mgr.get_file_count() <= m_ini) || (mgr.get_category_count(m_ini) <= m_group)) + return false; + + if (!m_cache_valid) + mame_machine_manager::instance()->inifile().load_ini_category(m_ini, m_group, m_cache); + m_cache_valid = true; + + if (m_cache.end() != m_cache.find(&drv)) + return true; + + if (m_include_clones) + { + int const found(driver_list::find(drv.parent)); + return m_cache.end() != m_cache.find(&driver_list::driver(found)); + } + + return false; + } + +private: + class menu_configure : public menu + { + public: + menu_configure( + mame_ui_manager &mui, + render_container &container, + category_machine_filter &parent, + std::function &&handler) + : menu(mui, container) + , m_parent(parent) + , m_handler(std::move(handler)) + , m_state(std::make_unique []>(mame_machine_manager::instance()->inifile().get_file_count())) + , m_ini(parent.m_ini) + { + inifile_manager const &mgr(mame_machine_manager::instance()->inifile()); + for (size_t i = 0; mgr.get_file_count() > i; ++i) + { + m_state[i].first = (m_ini == i) ? m_parent.m_group : 0U; + m_state[i].second = (m_ini == i) ? m_parent.m_include_clones : include_clones_default(mgr.get_file_name(i)); + } + } + + virtual ~menu_configure() override + { + bool const valid(mame_machine_manager::instance()->inifile().get_file_count() > m_ini); + unsigned const group(valid ? m_state[m_ini].first : 0); + if ((m_ini != m_parent.m_ini) || (group != m_parent.m_group)) + { + m_parent.m_cache.clear(); + m_parent.m_cache_valid = false; + } + m_parent.m_ini = m_ini; + m_parent.m_group = group; + m_parent.m_include_clones = valid ? m_state[m_ini].second : false; + m_parent.set_adjust_text(); + m_handler(m_parent); + } + + protected: + virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override + { + char const *const text[] = { _("Select category:") }; + draw_text_box( + std::begin(text), std::end(text), + x, x2, y - top, y - UI_BOX_TB_BORDER, + ui::text_layout::CENTER, ui::text_layout::NEVER, false, + UI_TEXT_COLOR, UI_GREEN_COLOR, 1.0f); + } + + private: + enum : uintptr_t + { + INI_FILE = 1, + SYSTEM_GROUP, + INCLUDE_CLONES + }; + + virtual void populate(float &customtop, float &custombottom) override; + virtual void handle() override; + + category_machine_filter &m_parent; + std::function m_handler; + std::unique_ptr []> const m_state; + unsigned m_ini; + }; + + void set_adjust_text() + { + inifile_manager const &mgr(mame_machine_manager::instance()->inifile()); + unsigned const filecnt(mgr.get_file_count()); + if (!filecnt) + { + m_adjust_text = _("[no category INI files]"); + } + else + { + m_ini = std::min(m_ini, filecnt - 1); + unsigned const groupcnt(mgr.get_category_count(m_ini)); + if (!groupcnt) + { + m_adjust_text = _("[no groups in INI file]"); + } + else + { + m_group = std::min(m_group, groupcnt - 1); + m_adjust_text = util::string_format("%s/%s", mgr.get_file_name(m_ini), mgr.get_category_name(m_ini, m_group)); + } + } + } + + static bool include_clones_default(std::string const &name) + { + return !core_stricmp(name.c_str(), "category.ini") || !core_stricmp(name.c_str(), "alltime.ini"); + } + + unsigned m_ini, m_group; + bool m_include_clones; + std::string m_adjust_text; + mutable std::unordered_set m_cache; + mutable bool m_cache_valid; +}; + +void category_machine_filter::show_ui(mame_ui_manager &mui, render_container &container, std::function &&handler) +{ + menu::stack_push(mui, container, *this, std::move(handler)); +} + + +void category_machine_filter::menu_configure::populate(float &customtop, float &custombottom) +{ + inifile_manager const &mgr(mame_machine_manager::instance()->inifile()); + unsigned const filecnt(mgr.get_file_count()); + if (!filecnt) + { + item_append(_("No category INI files found"), "", FLAG_DISABLE, nullptr); + } + else + { + m_ini = std::min(m_ini, filecnt - 1); + item_append(_("File"), mgr.get_file_name(m_ini), get_arrow_flags(0U, filecnt - 1, m_ini), reinterpret_cast(INI_FILE)); + unsigned const groupcnt(mgr.get_category_count(m_ini)); + if (!groupcnt) + { + item_append(_("No groups found in category file"), "", FLAG_DISABLE, nullptr); + } + else + { + m_state[m_ini].first = std::min(m_state[m_ini].first, groupcnt - 1); + item_append(_("Group"), mgr.get_category_name(m_ini, m_state[m_ini].first), get_arrow_flags(0U, groupcnt - 1, m_state[m_ini].first), reinterpret_cast(SYSTEM_GROUP)); + item_append(_("Include clones"), m_state[m_ini].second ? _("Yes") : _("No"), m_state[m_ini].second ? FLAG_LEFT_ARROW : FLAG_RIGHT_ARROW, reinterpret_cast(INCLUDE_CLONES)); + } + } + item_append(menu_item_type::SEPARATOR); + customtop = ui().get_line_height() + 3.0f * UI_BOX_TB_BORDER; +} + +void category_machine_filter::menu_configure::handle() +{ + const event *menu_event = process(PROCESS_LR_REPEAT); + if (menu_event && menu_event->itemref) + { + bool changed(false); + uintptr_t const ref(reinterpret_cast(menu_event->itemref)); + inifile_manager const &mgr(mame_machine_manager::instance()->inifile()); + switch (menu_event->iptkey) + { + case IPT_UI_LEFT: + if ((INI_FILE == ref) && m_ini) + { + --m_ini; + changed = true; + } + else if ((SYSTEM_GROUP == ref) && m_state[m_ini].first) + { + --m_state[m_ini].first; + changed = true; + } + else if ((INCLUDE_CLONES == ref) && m_state[m_ini].second) + { + m_state[m_ini].second = false; + changed = true; + } + break; + case IPT_UI_RIGHT: + if ((INI_FILE == ref) && (mgr.get_file_count() > (m_ini + 1))) + { + ++m_ini; + changed = true; + } + else if ((SYSTEM_GROUP == ref) && (mgr.get_category_count(m_ini) > (m_state[m_ini].first + 1))) + { + ++m_state[m_ini].first; + changed = true; + } + else if ((INCLUDE_CLONES == ref) && !m_state[m_ini].second) + { + m_state[m_ini].second = true; + changed = true; + } + break; + + case IPT_UI_SELECT: + if (INI_FILE == ref) + { + std::vector choices; + choices.reserve(mgr.get_file_count()); + for (size_t i = 0; mgr.get_file_count() > i; ++i) + choices.emplace_back(mgr.get_file_name(i)); + menu::stack_push( + ui(), + container(), + std::move(choices), + m_ini, + [this] (int selection) + { + if (selection != m_ini) + { + m_ini = selection; + reset(reset_options::REMEMBER_REF); + } + }); + } + else if (SYSTEM_GROUP == ref) + { + std::vector choices; + choices.reserve(mgr.get_category_count(m_ini)); + for (size_t i = 0; mgr.get_category_count(m_ini) > i; ++i) + choices.emplace_back(mgr.get_category_name(m_ini, i)); + menu::stack_push( + ui(), + container(), + std::move(choices), + m_state[m_ini].first, + [this] (int selection) + { + if (selection != m_state[m_ini].first) + { + m_state[m_ini].first = selection; + reset(reset_options::REMEMBER_REF); + } + }); + } + else if (INCLUDE_CLONES == ref) + { + m_state[m_ini].second = !m_state[m_ini].second; + reset(reset_options::REMEMBER_REF); + } + break; + } + + // rebuild if anything changed + if (changed) + reset(reset_options::REMEMBER_REF); + } +} + + + //------------------------------------------------- // composite machine filter //------------------------------------------------- @@ -787,8 +1126,8 @@ using favorite_machine_filter = inclusive_machine_filter_impl { public: - custom_machine_filter(char const *value, emu_file *file, unsigned indent) : - composite_filter_impl_base() + custom_machine_filter(char const *value, emu_file *file, unsigned indent) + : composite_filter_impl_base() { populate(value, file, indent); } @@ -798,7 +1137,7 @@ public: static bool type_allowed(unsigned pos, type n) { - return (FIRST <= n) && (LAST >= n) && (ALL != n) && (AVAILABLE != n) && (UNAVAILABLE != n) && (CATEGORY != n) && (FAVORITE != n) && (CUSTOM != n); + return (FIRST <= n) && (LAST >= n) && (ALL != n) && (AVAILABLE != n) && (UNAVAILABLE != n) && (FAVORITE != n) && (CUSTOM != n); } static bool types_contradictory(type n, type m) @@ -835,7 +1174,7 @@ public: static bool is_inclusion(type n) { - return (MANUFACTURER == n) || (YEAR == n); + return (CATEGORY == n) || (MANUFACTURER == n) || (YEAR == n); } }; @@ -893,8 +1232,8 @@ public: class years_software_filter : public choice_filter_impl_base { public: - years_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) : - choice_filter_impl_base(data.year.ui, value) + years_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) + : choice_filter_impl_base(data.year.ui, value) { } @@ -905,9 +1244,9 @@ public: class publishers_software_filter : public choice_filter_impl_base { public: - publishers_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) : - choice_filter_impl_base(data.publisher.ui, value), - m_publishers(data.publisher) + publishers_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) + : choice_filter_impl_base(data.publisher.ui, value) + , m_publishers(data.publisher) { } @@ -958,9 +1297,9 @@ public: class region_software_filter : public choice_filter_impl_base { public: - region_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) : - choice_filter_impl_base(data.region.ui, value), - m_regions(data.region) + region_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) + : choice_filter_impl_base(data.region.ui, value) + , m_regions(data.region) { } @@ -983,8 +1322,8 @@ private: class device_type_software_filter : public choice_filter_impl_base { public: - device_type_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) : - choice_filter_impl_base(data.type.ui, value) + device_type_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) + : choice_filter_impl_base(data.type.ui, value) { } @@ -995,8 +1334,8 @@ public: class list_software_filter : public choice_filter_impl_base { public: - list_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) : - choice_filter_impl_base(data.swlist.name, value) + list_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) + : choice_filter_impl_base(data.swlist.name, value) { } @@ -1012,9 +1351,9 @@ public: class custom_software_filter : public composite_filter_impl_base { public: - custom_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) : - composite_filter_impl_base(), - m_data(data) + custom_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) + : composite_filter_impl_base() + , m_data(data) { populate(value, file, indent); } @@ -1089,7 +1428,7 @@ machine_filter::ptr machine_filter::create(type n, char const *value, emu_file * case NOT_MECHANICAL: return std::make_unique(value, file, indent); case CATEGORY: - break; + return std::make_unique(value, file, indent); case FAVORITE: return std::make_unique(value, file, indent); case BIOS: @@ -1125,7 +1464,8 @@ machine_filter::ptr machine_filter::create(type n, char const *value, emu_file * machine_filter::ptr machine_filter::create(emu_file &file, unsigned indent) { char buffer[MAX_CHAR_INFO]; - file.gets(buffer, ARRAY_LENGTH(buffer)); + if (!file.gets(buffer, ARRAY_LENGTH(buffer))) + return nullptr; // split it into a key/value or bail std::string key(buffer); @@ -1230,7 +1570,8 @@ software_filter::ptr software_filter::create(type n, s_filter const &data, char software_filter::ptr software_filter::create(emu_file &file, s_filter const &data, unsigned indent) { char buffer[MAX_CHAR_INFO]; - file.gets(buffer, ARRAY_LENGTH(buffer)); + if (!file.gets(buffer, ARRAY_LENGTH(buffer))) + return nullptr; // split it into a key/value or bail std::string key(buffer); diff --git a/src/frontend/mame/ui/utils.h b/src/frontend/mame/ui/utils.h index 67685bcfdba..7018007eaee 100644 --- a/src/frontend/mame/ui/utils.h +++ b/src/frontend/mame/ui/utils.h @@ -272,11 +272,9 @@ enum HOVER_RPANEL_ARROW, HOVER_LPANEL_ARROW, HOVER_FILTER_FIRST, - HOVER_FILTER_LAST = (HOVER_FILTER_FIRST) + ui::machine_filter::COUNT, - HOVER_SW_FILTER_FIRST, - HOVER_SW_FILTER_LAST = (HOVER_SW_FILTER_FIRST) + ui::software_filter::COUNT, + HOVER_FILTER_LAST = HOVER_FILTER_FIRST + std::max(ui::machine_filter::COUNT, ui::software_filter::COUNT), HOVER_RP_FIRST, - HOVER_RP_LAST = (HOVER_RP_FIRST) + 1 + RP_LAST, + HOVER_RP_LAST = HOVER_RP_FIRST + 1 + RP_LAST, HOVER_INFO_TEXT }; -- cgit v1.2.3