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
This commit is contained in:
Vas Crabb 2017-08-11 10:11:44 +10:00
parent 196a7ea1ce
commit cb7a04174f
17 changed files with 683 additions and 643 deletions

View File

@ -2467,12 +2467,3 @@ msgstr "Gráficos: %s, Sonido: %s"
#~ msgid "Other filter"
#~ msgstr "Otros filtros"
#~ msgid "^!Region"
#~ msgstr "^!Región"
#~ msgid "^!Setup custom filter"
#~ msgstr "^!Aplicar filtro personalizado"
#~ msgid "Region: %1$s -"
#~ msgstr "Región: %1$s -"

View File

@ -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<std::string>::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<std::string>::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));
}

View File

@ -21,7 +21,7 @@ namespace ui {
struct c_sw_region
{
std::vector<std::string> 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<std::string> ui;
void set(std::string &str);
void set(std::string const &str);
std::string getname(std::string const &str) const;
};

View File

@ -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 },

View File

@ -9,135 +9,101 @@
***************************************************************************/
#include "emu.h"
#include "ui/moptions.h"
#include "ui/inifile.h"
#include "softlist_dev.h"
#include "drivenum.h"
//-------------------------------------------------
// GLOBAL VARIABLES
//-------------------------------------------------
uint16_t inifile_manager::c_cat = 0;
uint16_t inifile_manager::c_file = 0;
#include "ui/moptions.h"
#include "drivenum.h"
#include "softlist_dev.h"
//-------------------------------------------------
// 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
//-------------------------------------------------
void inifile_manager::directory_scan()
{
file_enumerator path(m_options.extraini_path());
const osd::directory::entry *dir;
while ((dir = path.next()) != nullptr)
if (core_filename_ends_with(dir->name, ".ini") && parseopen(dir->name))
// 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"))
{
init_category(std::string(dir->name));
parseclose();
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();
}
}
// sort
std::stable_sort(ini_index.begin(), ini_index.end());
}
//-------------------------------------------------
// initialize category
//-------------------------------------------------
void inifile_manager::init_category(std::string filename)
{
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);
}
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()); });
}
//-------------------------------------------------
// load and indexing ini files
//-------------------------------------------------
void inifile_manager::load_ini_category(std::vector<int> &temp_filter)
void inifile_manager::load_ini_category(size_t file, size_t category, std::unordered_set<game_driver const *> &result) const
{
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 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)
{
fseek(fp, offset, SEEK_SET);
char rbuf[MAX_CHAR_INFO];
std::string readbuf;
while (fgets(rbuf, MAX_CHAR_INFO, fp) != nullptr)
{
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);
}
}
parseclose();
osd_printf_error("Failed to open category file %s for reading\n", filename.c_str());
return;
}
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;
}
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();
}
//---------------------------------------------------------
// parseopen - Open up file for reading
//---------------------------------------------------------
//-------------------------------------------------
// initialize category
//-------------------------------------------------
bool inifile_manager::parseopen(const char *filename)
void inifile_manager::init_category(std::string &&filename, emu_file &file)
{
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;
categoryindex index;
char rbuf[MAX_CHAR_INFO];
std::string name;
while (file.gets(rbuf, ARRAY_LENGTH(rbuf)))
{
if ('[' == rbuf[0])
{
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());
}
}
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));
}
/**************************************************************************
FAVORITE MANAGER
**************************************************************************/

View File

@ -13,7 +13,10 @@
#pragma once
#include "../frontend/mame/ui/utils.h"
#include "ui/utils.h"
#include <unordered_set>
//-------------------------------------------------
// 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<game_driver const *> &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<int> &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<std::pair<std::string, long>>;
using categoryindex = std::vector<std::pair<std::string, int64_t>>;
// files indices
static uint16_t c_file, c_cat;
std::vector<std::pair<std::string, categoryindex>> ini_index;
// 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<std::pair<std::string, categoryindex> > m_ini_index;
};
//-------------------------------------------------

View File

@ -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" },

View File

@ -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); }

View File

@ -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<std::string> 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<menu_selector>(
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<std::string> s_sel(total);
for (int index = 0; index < total; ++index)
s_sel[index] = ifile.get_category(index);
menu::stack_push<menu_selector>(
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<uint16_t>(machine_filter::FIRST, machine_filter::LAST, m_main);
if (machine_filter::CATEGORY == m_main)
auto active_filter(main_filters::filters.find(m_main));
if (main_filters::filters.end() == active_filter)
active_filter = main_filters::filters.emplace(m_main, machine_filter::create(m_main)).first;
item_append(_("Filter"), active_filter->second->display_name(), arrow_flags, (void *)(uintptr_t)FILTER_MENU);
// add subitem if the filter wants it
if (active_filter->second->wants_adjuster())
{
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);
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
{
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);

View File

@ -30,9 +30,7 @@ private:
enum
{
FILTER_MENU = 1,
FILE_CATEGORY_FILTER,
FILTER_ADJUST,
CATEGORY_FILTER,
CONF_DIR,
DISPLAY_MENU,
CUSTOM_MENU,

View File

@ -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<menu_game_options>(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<int> 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<machine_filter>(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));

View File

@ -66,7 +66,6 @@ private:
// internal methods
void change_info_pane(int delta);
void build_category();
void build_available_list();
bool isfavorite() const;

View File

@ -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>(machine_filter::type current, std::map<machine_filter::type, machine_filter::ptr> const &filters, int focus, float x1, float y1, float x2, float y2);
template float menu_select_launch::draw_left_panel<software_filter>(software_filter::type current, std::map<software_filter::type, software_filter::ptr> 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 <typename Filter>
float menu_select_launch::draw_left_panel(
typename Filter::type current,
std::map<typename Filter::type, typename Filter::ptr> 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 <typename T> 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
//-------------------------------------------------

View File

@ -114,10 +114,16 @@ protected:
bool draw_error_text();
template <typename Filter>
float draw_left_panel(
typename Filter::type current,
std::map<typename Filter::type, typename Filter::ptr> const &filters,
int focus,
float x1, float y1, float x2, float y2);
template <typename T> 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);

View File

@ -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<software_filter>(m_filter_type, m_filters, highlight, x1, y1, x2, y2);
}
//-------------------------------------------------
// get selected software and/or driver
//-------------------------------------------------

View File

@ -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 <bitset>
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <unordered_set>
namespace ui {
@ -180,9 +185,9 @@ public:
}
protected:
choice_filter_impl_base(std::vector<std::string> const &choices, char const *value) :
m_choices(choices),
m_selection(0U)
choice_filter_impl_base(std::vector<std::string> const &choices, char const *value)
: m_choices(choices)
, m_selection(0U)
{
if (value)
{
@ -211,6 +216,8 @@ template <class Impl, class Base, typename Base::type Type>
class composite_filter_impl_base : public simple_filter_impl_base<Base, Type>
{
public:
virtual void show_ui(mame_ui_manager &mui, render_container &container, std::function<void (Base &)> &&handler) override;
virtual bool wants_adjuster() const override { return true; }
virtual char const *adjust_text() const override { return _("<set up filters>"); }
@ -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<void (Base &)> &&handler) override;
protected:
composite_filter_impl_base() { }
@ -308,11 +314,11 @@ private:
mame_ui_manager &mui,
render_container &container,
Impl &parent,
std::function<void (Base &filter)> &&handler) :
menu(mui, container),
m_parent(parent),
m_handler(std::move(handler)),
m_added(false)
std::function<void (Base &filter)> &&handler)
: menu(mui, container)
, m_parent(parent)
, m_handler(std::move(handler))
, m_added(false)
{
}
@ -472,7 +478,7 @@ void composite_filter_impl_base<Impl, Base, Type>::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<machine_filter, machine_filter::MANUFACTURER>
{
public:
manufacturer_machine_filter(char const *value, emu_file *file, unsigned indent) :
choice_filter_impl_base<machine_filter, machine_filter::MANUFACTURER>(c_mnfct::ui, value)
manufacturer_machine_filter(char const *value, emu_file *file, unsigned indent)
: choice_filter_impl_base<machine_filter, machine_filter::MANUFACTURER>(c_mnfct::ui, value)
{
}
@ -721,8 +727,8 @@ public:
class year_machine_filter : public choice_filter_impl_base<machine_filter, machine_filter::YEAR>
{
public:
year_machine_filter(char const *value, emu_file *file, unsigned indent) :
choice_filter_impl_base<machine_filter, machine_filter::YEAR>(c_year::ui, value)
year_machine_filter(char const *value, emu_file *file, unsigned indent)
: choice_filter_impl_base<machine_filter, machine_filter::YEAR>(c_year::ui, value)
{
}
@ -780,6 +786,339 @@ using favorite_machine_filter = inclusive_machine_filter_impl<machine_filt
//-------------------------------------------------
// category machine filter
//-------------------------------------------------
class category_machine_filter : public simple_filter_impl_base<machine_filter, machine_filter::CATEGORY>
{
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<void (machine_filter &)> &&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<void (machine_filter &filter)> &&handler)
: menu(mui, container)
, m_parent(parent)
, m_handler(std::move(handler))
, m_state(std::make_unique<std::pair<unsigned, bool> []>(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<void (machine_filter &)> m_handler;
std::unique_ptr<std::pair<unsigned, bool> []> 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<game_driver const *> m_cache;
mutable bool m_cache_valid;
};
void category_machine_filter::show_ui(mame_ui_manager &mui, render_container &container, std::function<void (machine_filter &)> &&handler)
{
menu::stack_push<menu_configure>(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<void *>(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<void *>(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<void *>(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<uintptr_t>(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<std::string> 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<menu_selector>(
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<std::string> 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<menu_selector>(
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<machine_filt
class custom_machine_filter : public composite_filter_impl_base<custom_machine_filter, machine_filter, machine_filter::CUSTOM>
{
public:
custom_machine_filter(char const *value, emu_file *file, unsigned indent) :
composite_filter_impl_base<custom_machine_filter, machine_filter, machine_filter::CUSTOM>()
custom_machine_filter(char const *value, emu_file *file, unsigned indent)
: composite_filter_impl_base<custom_machine_filter, machine_filter, machine_filter::CUSTOM>()
{
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<software_filter, software_filter::YEAR>
{
public:
years_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) :
choice_filter_impl_base<software_filter, software_filter::YEAR>(data.year.ui, value)
years_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent)
: choice_filter_impl_base<software_filter, software_filter::YEAR>(data.year.ui, value)
{
}
@ -905,9 +1244,9 @@ public:
class publishers_software_filter : public choice_filter_impl_base<software_filter, software_filter::PUBLISHERS>
{
public:
publishers_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) :
choice_filter_impl_base<software_filter, software_filter::PUBLISHERS>(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<software_filter, software_filter::PUBLISHERS>(data.publisher.ui, value)
, m_publishers(data.publisher)
{
}
@ -958,9 +1297,9 @@ public:
class region_software_filter : public choice_filter_impl_base<software_filter, software_filter::REGION>
{
public:
region_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) :
choice_filter_impl_base<software_filter, software_filter::REGION>(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<software_filter, software_filter::REGION>(data.region.ui, value)
, m_regions(data.region)
{
}
@ -983,8 +1322,8 @@ private:
class device_type_software_filter : public choice_filter_impl_base<software_filter, software_filter::DEVICE_TYPE>
{
public:
device_type_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) :
choice_filter_impl_base<software_filter, software_filter::DEVICE_TYPE>(data.type.ui, value)
device_type_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent)
: choice_filter_impl_base<software_filter, software_filter::DEVICE_TYPE>(data.type.ui, value)
{
}
@ -995,8 +1334,8 @@ public:
class list_software_filter : public choice_filter_impl_base<software_filter, software_filter::LIST>
{
public:
list_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) :
choice_filter_impl_base<software_filter, software_filter::LIST>(data.swlist.name, value)
list_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent)
: choice_filter_impl_base<software_filter, software_filter::LIST>(data.swlist.name, value)
{
}
@ -1012,9 +1351,9 @@ public:
class custom_software_filter : public composite_filter_impl_base<custom_software_filter, software_filter, software_filter::CUSTOM>
{
public:
custom_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent) :
composite_filter_impl_base<custom_software_filter, software_filter, software_filter::CUSTOM>(),
m_data(data)
custom_software_filter(s_filter const &data, char const *value, emu_file *file, unsigned indent)
: composite_filter_impl_base<custom_software_filter, software_filter, software_filter::CUSTOM>()
, 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<not_mechanical_machine_filter>(value, file, indent);
case CATEGORY:
break;
return std::make_unique<category_machine_filter>(value, file, indent);
case FAVORITE:
return std::make_unique<favorite_machine_filter>(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);

View File

@ -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<unsigned>(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
};