mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-29 09:35:39 +00:00
* Introduce KidMode: Prevent collection editing
* Introduce FileData Filtering for Kiosk and Kid Modes to: 1. In Kiosk mode: Hide items with metadata tag `<hidden>true</hidden>` 2. In Kid mode: only show items with metadata tag `<kidgame>true</kidgame>` * ES will auto-revert UI mode back to Full when there is nothing at all to show. * Changing the setting hideQuitMenuOnKidUI to true will hide this menu.
This commit is contained in:
parent
5b792c4ef2
commit
189eb05fee
|
@ -1,4 +1,6 @@
|
|||
#include "FileFilterIndex.h"
|
||||
#include "Settings.h"
|
||||
#include "views/ViewController.h"
|
||||
|
||||
#include "FileData.h"
|
||||
#include "Log.h"
|
||||
|
@ -9,15 +11,18 @@
|
|||
#define INCLUDE_UNKNOWN false;
|
||||
|
||||
FileFilterIndex::FileFilterIndex()
|
||||
: filterByGenre(false), filterByPlayers(false), filterByPubDev(false), filterByRatings(false), filterByFavorites(false)
|
||||
: filterByFavorites(false), filterByGenre(false), filterByHidden(false), filterByKidGame(false), filterByPlayers(false), filterByPubDev(false), filterByRatings(false)
|
||||
{
|
||||
clearAllFilters();
|
||||
FilterDataDecl filterDecls[] = {
|
||||
//type //allKeys //filteredBy //filteredKeys //primaryKey //hasSecondaryKey //secondaryKey //menuLabel
|
||||
{ FAVORITES_FILTER, &favoritesIndexAllKeys, &filterByFavorites, &favoritesIndexFilteredKeys,"favorite", false, "", "FAVORITES" },
|
||||
{ GENRE_FILTER, &genreIndexAllKeys, &filterByGenre, &genreIndexFilteredKeys, "genre", true, "genre", "GENRE" },
|
||||
{ PLAYER_FILTER, &playersIndexAllKeys, &filterByPlayers, &playersIndexFilteredKeys, "players", false, "", "PLAYERS" },
|
||||
{ PUBDEV_FILTER, &pubDevIndexAllKeys, &filterByPubDev, &pubDevIndexFilteredKeys, "developer", true, "publisher", "PUBLISHER / DEVELOPER" },
|
||||
{ RATINGS_FILTER, &ratingsIndexAllKeys, &filterByRatings, &ratingsIndexFilteredKeys, "rating", false, "", "RATING" }
|
||||
{ RATINGS_FILTER, &ratingsIndexAllKeys, &filterByRatings, &ratingsIndexFilteredKeys, "rating", false, "", "RATING" },
|
||||
{ KIDGAME_FILTER, &kidGameIndexAllKeys, &filterByKidGame, &kidGameIndexFilteredKeys, "kidgame", false, "", "KIDGAME" },
|
||||
{ HIDDEN_FILTER, &hiddenIndexAllKeys, &filterByHidden, &hiddenIndexFilteredKeys, "hidden", false, "", "HIDDEN" }
|
||||
};
|
||||
|
||||
filterDataDecl = std::vector<FilterDataDecl>(filterDecls, filterDecls + sizeof(filterDecls) / sizeof(filterDecls[0]));
|
||||
|
@ -36,17 +41,19 @@ std::vector<FilterDataDecl>& FileFilterIndex::getFilterDataDecls()
|
|||
void FileFilterIndex::importIndex(FileFilterIndex* indexToImport)
|
||||
{
|
||||
struct IndexImportStructure
|
||||
{
|
||||
std::map<std::string, int>* destinationIndex;
|
||||
std::map<std::string, int>* sourceIndex;
|
||||
};
|
||||
{
|
||||
std::map<std::string, int>* destinationIndex;
|
||||
std::map<std::string, int>* sourceIndex;
|
||||
};
|
||||
|
||||
IndexImportStructure indexStructDecls[] = {
|
||||
{ &genreIndexAllKeys, &(indexToImport->genreIndexAllKeys) },
|
||||
{ &playersIndexAllKeys, &(indexToImport->playersIndexAllKeys) },
|
||||
{ &pubDevIndexAllKeys, &(indexToImport->pubDevIndexAllKeys) },
|
||||
{ &ratingsIndexAllKeys, &(indexToImport->ratingsIndexAllKeys) },
|
||||
{ &favoritesIndexAllKeys, &(indexToImport->favoritesIndexAllKeys) }
|
||||
{ &favoritesIndexAllKeys, &(indexToImport->favoritesIndexAllKeys) },
|
||||
{ &hiddenIndexAllKeys, &(indexToImport->hiddenIndexAllKeys) },
|
||||
{ &kidGameIndexAllKeys, &(indexToImport->kidGameIndexAllKeys) },
|
||||
};
|
||||
|
||||
std::vector<IndexImportStructure> indexImportDecl = std::vector<IndexImportStructure>(indexStructDecls, indexStructDecls + sizeof(indexStructDecls) / sizeof(indexStructDecls[0]));
|
||||
|
@ -75,6 +82,8 @@ void FileFilterIndex::resetIndex()
|
|||
clearIndex(pubDevIndexAllKeys);
|
||||
clearIndex(ratingsIndexAllKeys);
|
||||
clearIndex(favoritesIndexAllKeys);
|
||||
clearIndex(hiddenIndexAllKeys);
|
||||
clearIndex(kidGameIndexAllKeys);
|
||||
}
|
||||
|
||||
std::string FileFilterIndex::getIndexableKey(FileData* game, FilterIndexType type, bool getSecondary)
|
||||
|
@ -149,6 +158,20 @@ std::string FileFilterIndex::getIndexableKey(FileData* game, FilterIndexType typ
|
|||
key = strToUpper(game->metadata.get("favorite"));
|
||||
break;
|
||||
}
|
||||
case HIDDEN_FILTER:
|
||||
{
|
||||
if (game->getType() != GAME)
|
||||
return "FALSE";
|
||||
key = strToUpper(game->metadata.get("hidden"));
|
||||
break;
|
||||
}
|
||||
case KIDGAME_FILTER:
|
||||
{
|
||||
if (game->getType() != GAME)
|
||||
return "FALSE";
|
||||
key = strToUpper(game->metadata.get("kidgame"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
boost::trim(key);
|
||||
if (key.empty() || (type == RATINGS_FILTER && key == "0 STARS")) {
|
||||
|
@ -164,6 +187,8 @@ void FileFilterIndex::addToIndex(FileData* game)
|
|||
managePubDevEntryInIndex(game);
|
||||
manageRatingsEntryInIndex(game);
|
||||
manageFavoritesEntryInIndex(game);
|
||||
manageHiddenEntryInIndex(game);
|
||||
manageKidGameEntryInIndex(game);
|
||||
}
|
||||
|
||||
void FileFilterIndex::removeFromIndex(FileData* game)
|
||||
|
@ -173,6 +198,8 @@ void FileFilterIndex::removeFromIndex(FileData* game)
|
|||
managePubDevEntryInIndex(game, true);
|
||||
manageRatingsEntryInIndex(game, true);
|
||||
manageFavoritesEntryInIndex(game, true);
|
||||
manageHiddenEntryInIndex(game, true);
|
||||
manageKidGameEntryInIndex(game, true);
|
||||
}
|
||||
|
||||
void FileFilterIndex::setFilter(FilterIndexType type, std::vector<std::string>* values)
|
||||
|
@ -213,6 +240,28 @@ void FileFilterIndex::clearAllFilters()
|
|||
return;
|
||||
}
|
||||
|
||||
void FileFilterIndex::resetFilters()
|
||||
{
|
||||
clearAllFilters();
|
||||
setUIModeFilters();
|
||||
}
|
||||
|
||||
void FileFilterIndex::setUIModeFilters()
|
||||
{
|
||||
if (!ViewController::get()->isUIModeFull())
|
||||
{
|
||||
filterByHidden = true;
|
||||
std::vector<std::string> val = { "FALSE" };
|
||||
setFilter(HIDDEN_FILTER, &val);
|
||||
}
|
||||
if (ViewController::get()->isUIModeKid())
|
||||
{
|
||||
filterByKidGame = true;
|
||||
std::vector<std::string> val = { "TRUE" };
|
||||
setFilter(KIDGAME_FILTER, &val);
|
||||
}
|
||||
}
|
||||
|
||||
void FileFilterIndex::debugPrintIndexes()
|
||||
{
|
||||
LOG(LogInfo) << "Printing Indexes...";
|
||||
|
@ -231,6 +280,12 @@ void FileFilterIndex::debugPrintIndexes()
|
|||
for (auto x: favoritesIndexAllKeys) {
|
||||
LOG(LogInfo) << "Favorites Index: " << x.first << ": " << x.second;
|
||||
}
|
||||
for (auto x : hiddenIndexAllKeys) {
|
||||
LOG(LogInfo) << "Hidden Index: " << x.first << ": " << x.second;
|
||||
}
|
||||
for (auto x : kidGameIndexAllKeys) {
|
||||
LOG(LogInfo) << "KidGames Index: " << x.first << ": " << x.second;
|
||||
}
|
||||
}
|
||||
|
||||
bool FileFilterIndex::showFile(FileData* game)
|
||||
|
@ -290,10 +345,10 @@ bool FileFilterIndex::showFile(FileData* game)
|
|||
|
||||
bool FileFilterIndex::isKeyBeingFilteredBy(std::string key, FilterIndexType type)
|
||||
{
|
||||
const FilterIndexType filterTypes[5] = { FAVORITES_FILTER, PLAYER_FILTER, RATINGS_FILTER, GENRE_FILTER, PUBDEV_FILTER };
|
||||
std::vector<std::string> filterKeysList[5] = { favoritesIndexFilteredKeys, playersIndexFilteredKeys, ratingsIndexFilteredKeys, genreIndexFilteredKeys, pubDevIndexFilteredKeys };
|
||||
const FilterIndexType filterTypes[7] = { FAVORITES_FILTER, GENRE_FILTER, PLAYER_FILTER, PUBDEV_FILTER, RATINGS_FILTER,HIDDEN_FILTER, KIDGAME_FILTER };
|
||||
std::vector<std::string> filterKeysList[7] = { favoritesIndexFilteredKeys, genreIndexFilteredKeys, playersIndexFilteredKeys, pubDevIndexFilteredKeys, ratingsIndexFilteredKeys, hiddenIndexFilteredKeys, kidGameIndexFilteredKeys };
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
if (filterTypes[i] == type)
|
||||
{
|
||||
|
@ -416,6 +471,32 @@ void FileFilterIndex::manageFavoritesEntryInIndex(FileData* game, bool remove)
|
|||
manageIndexEntry(&favoritesIndexAllKeys, key, remove);
|
||||
}
|
||||
|
||||
void FileFilterIndex::manageHiddenEntryInIndex(FileData* game, bool remove)
|
||||
{
|
||||
// flag for including unknowns
|
||||
bool includeUnknown = INCLUDE_UNKNOWN;
|
||||
std::string key = getIndexableKey(game, HIDDEN_FILTER, false);
|
||||
if (!includeUnknown && key == UNKNOWN_LABEL) {
|
||||
// no valid hidden info found
|
||||
return;
|
||||
}
|
||||
|
||||
manageIndexEntry(&hiddenIndexAllKeys, key, remove);
|
||||
}
|
||||
|
||||
void FileFilterIndex::manageKidGameEntryInIndex(FileData* game, bool remove)
|
||||
{
|
||||
// flag for including unknowns
|
||||
bool includeUnknown = INCLUDE_UNKNOWN;
|
||||
std::string key = getIndexableKey(game, KIDGAME_FILTER, false);
|
||||
if (!includeUnknown && key == UNKNOWN_LABEL) {
|
||||
// no valid kidgame info found
|
||||
return;
|
||||
}
|
||||
|
||||
manageIndexEntry(&kidGameIndexAllKeys, key, remove);
|
||||
}
|
||||
|
||||
void FileFilterIndex::manageIndexEntry(std::map<std::string, int>* index, std::string key, bool remove) {
|
||||
bool includeUnknown = INCLUDE_UNKNOWN;
|
||||
if (!includeUnknown && key == UNKNOWN_LABEL)
|
||||
|
|
|
@ -14,7 +14,9 @@ enum FilterIndexType
|
|||
PLAYER_FILTER,
|
||||
PUBDEV_FILTER,
|
||||
RATINGS_FILTER,
|
||||
FAVORITES_FILTER
|
||||
FAVORITES_FILTER,
|
||||
HIDDEN_FILTER,
|
||||
KIDGAME_FILTER
|
||||
};
|
||||
|
||||
struct FilterDataDecl
|
||||
|
@ -40,12 +42,15 @@ public:
|
|||
void clearAllFilters();
|
||||
void debugPrintIndexes();
|
||||
bool showFile(FileData* game);
|
||||
bool isFiltered() { return (filterByGenre || filterByPlayers || filterByPubDev || filterByRatings || filterByFavorites); };
|
||||
bool isFiltered() { return (filterByGenre || filterByPlayers || filterByPubDev || filterByRatings || filterByFavorites || filterByHidden || filterByKidGame); };
|
||||
bool isKeyBeingFilteredBy(std::string key, FilterIndexType type);
|
||||
std::vector<FilterDataDecl>& getFilterDataDecls();
|
||||
|
||||
void importIndex(FileFilterIndex* indexToImport);
|
||||
void resetIndex();
|
||||
void resetFilters();
|
||||
void setUIModeFilters();
|
||||
|
||||
private:
|
||||
std::vector<FilterDataDecl> filterDataDecl;
|
||||
std::string getIndexableKey(FileData* game, FilterIndexType type, bool getSecondary);
|
||||
|
@ -55,6 +60,8 @@ private:
|
|||
void managePubDevEntryInIndex(FileData* game, bool remove = false);
|
||||
void manageRatingsEntryInIndex(FileData* game, bool remove = false);
|
||||
void manageFavoritesEntryInIndex(FileData* game, bool remove = false);
|
||||
void manageHiddenEntryInIndex(FileData* game, bool remove = false);
|
||||
void manageKidGameEntryInIndex(FileData* game, bool remove = false);
|
||||
|
||||
void manageIndexEntry(std::map<std::string, int>* index, std::string key, bool remove);
|
||||
|
||||
|
@ -65,18 +72,24 @@ private:
|
|||
bool filterByPubDev;
|
||||
bool filterByRatings;
|
||||
bool filterByFavorites;
|
||||
bool filterByHidden;
|
||||
bool filterByKidGame;
|
||||
|
||||
std::map<std::string, int> genreIndexAllKeys;
|
||||
std::map<std::string, int> playersIndexAllKeys;
|
||||
std::map<std::string, int> pubDevIndexAllKeys;
|
||||
std::map<std::string, int> ratingsIndexAllKeys;
|
||||
std::map<std::string, int> favoritesIndexAllKeys;
|
||||
std::map<std::string, int> hiddenIndexAllKeys;
|
||||
std::map<std::string, int> kidGameIndexAllKeys;
|
||||
|
||||
std::vector<std::string> genreIndexFilteredKeys;
|
||||
std::vector<std::string> playersIndexFilteredKeys;
|
||||
std::vector<std::string> pubDevIndexFilteredKeys;
|
||||
std::vector<std::string> ratingsIndexFilteredKeys;
|
||||
std::vector<std::string> favoritesIndexFilteredKeys;
|
||||
std::vector<std::string> hiddenIndexFilteredKeys;
|
||||
std::vector<std::string> kidGameIndexFilteredKeys;
|
||||
|
||||
FileData* mRootFolder;
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ MetaDataDecl gameDecls[] = {
|
|||
{"genre", MD_STRING, "unknown", false, "genre", "enter game genre"},
|
||||
{"players", MD_INT, "1", false, "players", "enter number of players"},
|
||||
{"favorite", MD_BOOL, "false", false, "favorite", "enter favorite off/on"},
|
||||
{"hidden", MD_BOOL, "false", false, "hidden", "enter hidden off/on" },
|
||||
{"kidgame", MD_BOOL, "false", false, "kidgame", "enter kidgame off/on" },
|
||||
{"playcount", MD_INT, "0", true, "play count", "enter number of times played"},
|
||||
{"lastplayed", MD_TIME, "0", true, "last played", "enter last played date"}
|
||||
};
|
||||
|
|
|
@ -340,6 +340,33 @@ std::string SystemData::getConfigPath(bool forWrite)
|
|||
return "/etc/emulationstation/es_systems.cfg";
|
||||
}
|
||||
|
||||
SystemData* SystemData::getNext() const
|
||||
{
|
||||
std::vector<SystemData*>::const_iterator it = getIterator();
|
||||
|
||||
do {
|
||||
it++;
|
||||
if (it == sSystemVector.end())
|
||||
it = sSystemVector.begin();
|
||||
} while ((*it)->getDisplayedGameCount() == 0);
|
||||
// as we are starting in a valid gamelistview, this will always succeed, even if we have to come full circle.
|
||||
|
||||
return *it;
|
||||
}
|
||||
|
||||
SystemData* SystemData::getPrev() const
|
||||
{
|
||||
auto it = getRevIterator();
|
||||
do {
|
||||
it++;
|
||||
if (it == sSystemVector.rend())
|
||||
it = sSystemVector.rbegin();
|
||||
} while ((*it)->getDisplayedGameCount() == 0);
|
||||
// as we are starting in a valid gamelistview, this will always succeed, even if we have to come full circle.
|
||||
|
||||
return *it;
|
||||
}
|
||||
|
||||
std::string SystemData::getGamelistPath(bool forWrite) const
|
||||
{
|
||||
fs::path filePath;
|
||||
|
|
|
@ -56,22 +56,9 @@ public:
|
|||
inline std::vector<SystemData*>::const_reverse_iterator getRevIterator() const { return std::find(sSystemVector.rbegin(), sSystemVector.rend(), this); };
|
||||
inline bool isCollection() { return mIsCollectionSystem; };
|
||||
inline bool isGameSystem() { return mIsGameSystem; }
|
||||
inline SystemData* getNext() const
|
||||
{
|
||||
auto it = getIterator();
|
||||
it++;
|
||||
if(it == sSystemVector.end()) it = sSystemVector.begin();
|
||||
return *it;
|
||||
}
|
||||
|
||||
inline SystemData* getPrev() const
|
||||
{
|
||||
auto it = getRevIterator();
|
||||
it++;
|
||||
if(it == sSystemVector.rend()) it = sSystemVector.rbegin();
|
||||
return *it;
|
||||
}
|
||||
|
||||
SystemData* getNext() const;
|
||||
SystemData* getPrev() const;
|
||||
static SystemData* getRandomSystem();
|
||||
FileData* getRandomGame();
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "guis/GuiGamelistFilter.h"
|
||||
|
||||
#include "components/OptionListComponent.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "SystemData.h"
|
||||
|
||||
GuiGamelistFilter::GuiGamelistFilter(Window* window, SystemData* system) : GuiComponent(window), mMenu(window, "FILTER GAMELIST BY"), mSystem(system)
|
||||
|
@ -34,7 +35,7 @@ void GuiGamelistFilter::initializeMenu()
|
|||
|
||||
void GuiGamelistFilter::resetAllFilters()
|
||||
{
|
||||
mFilterIndex->clearAllFilters();
|
||||
mFilterIndex->resetFilters();
|
||||
for (std::map<FilterIndexType, std::shared_ptr< OptionListComponent<std::string> >>::iterator it = mFilterOptions.begin(); it != mFilterOptions.end(); ++it ) {
|
||||
std::shared_ptr< OptionListComponent<std::string> > optionList = it->second;
|
||||
optionList->selectNone();
|
||||
|
@ -49,7 +50,14 @@ GuiGamelistFilter::~GuiGamelistFilter()
|
|||
void GuiGamelistFilter::addFiltersToMenu()
|
||||
{
|
||||
std::vector<FilterDataDecl> decls = mFilterIndex->getFilterDataDecls();
|
||||
for (std::vector<FilterDataDecl>::iterator it = decls.begin(); it != decls.end(); ++it ) {
|
||||
|
||||
int skip = 0;
|
||||
if (!ViewController::get()->isUIModeFull())
|
||||
skip = 1;
|
||||
if (ViewController::get()->isUIModeKid())
|
||||
skip = 2;
|
||||
|
||||
for (std::vector<FilterDataDecl>::iterator it = decls.begin(); it != decls.end()-skip; ++it ) {
|
||||
|
||||
FilterIndexType type = (*it).type; // type of filter
|
||||
std::map<std::string, int>* allKeys = (*it).allIndexKeys; // all possible filters for this type
|
||||
|
|
|
@ -38,7 +38,8 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
|
|||
if (isFullUI)
|
||||
addEntry("CONFIGURE INPUT", 0x777777FF, true, [this] { openConfigInput(); });
|
||||
|
||||
addEntry("QUIT", 0x777777FF, true, [this] {openQuitMenu(); });
|
||||
if (!(ViewController::get()->isUIModeKid() && Settings::getInstance()->getBool("hideQuitMenuOnKidUI")))
|
||||
addEntry("QUIT", 0x777777FF, true, [this] {openQuitMenu(); });
|
||||
|
||||
addChild(&mMenu);
|
||||
addVersionInfo();
|
||||
|
@ -422,12 +423,11 @@ void GuiMenu::openQuitMenu()
|
|||
s->addRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
row.elements.clear();
|
||||
row.makeAcceptInputHandler([window] {
|
||||
window->pushGui(new GuiMsgBox(window, "REALLY RESTART?", "YES",
|
||||
[] {
|
||||
if(quitES("/tmp/es-sysrestart") != 0)
|
||||
if (quitES("/tmp/es-sysrestart") != 0)
|
||||
LOG(LogWarning) << "Restart terminated with non-zero result!";
|
||||
}, "NO", nullptr));
|
||||
});
|
||||
|
@ -455,7 +455,6 @@ void GuiMenu::addVersionInfo()
|
|||
mVersion.setText("EMULATIONSTATION V" + strToUpper(PROGRAM_VERSION_STRING));
|
||||
mVersion.setHorizontalAlignment(ALIGN_CENTER);
|
||||
addChild(&mVersion);
|
||||
|
||||
}
|
||||
|
||||
void GuiMenu::openScreensaverOptions() {
|
||||
|
|
|
@ -86,7 +86,12 @@ bool parseArgs(int argc, char* argv[], unsigned int* width, unsigned int* height
|
|||
else if (strcmp(argv[i], "--force-kiosk") == 0)
|
||||
{
|
||||
Settings::getInstance()->setBool("ForceKiosk", true);
|
||||
}else if(strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0)
|
||||
}
|
||||
else if (strcmp(argv[i], "--force-kid") == 0)
|
||||
{
|
||||
Settings::getInstance()->setBool("ForceKid", true);
|
||||
}
|
||||
else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0)
|
||||
{
|
||||
#ifdef WIN32
|
||||
// This is a bit of a hack, but otherwise output will go to nowhere
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "views/SystemView.h"
|
||||
|
||||
#include "animations/LambdaAnimation.h"
|
||||
#include "guis/GuiMsgBox.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "Log.h"
|
||||
#include "Renderer.h"
|
||||
|
@ -35,78 +36,88 @@ void SystemView::populate()
|
|||
if(mViewNeedsReload)
|
||||
getViewElements(theme);
|
||||
|
||||
Entry e;
|
||||
e.name = (*it)->getName();
|
||||
e.object = *it;
|
||||
|
||||
// make logo
|
||||
const ThemeData::ThemeElement* logoElem = theme->getElement("system", "logo", "image");
|
||||
if(logoElem)
|
||||
if((*it)->getDisplayedGameCount() > 0)
|
||||
{
|
||||
std::string path = logoElem->get<std::string>("path");
|
||||
std::string defaultPath = logoElem->has("default") ? logoElem->get<std::string>("default") : "";
|
||||
if((!path.empty() && ResourceManager::getInstance()->fileExists(path))
|
||||
|| (!defaultPath.empty() && ResourceManager::getInstance()->fileExists(defaultPath)))
|
||||
Entry e;
|
||||
e.name = (*it)->getName();
|
||||
e.object = *it;
|
||||
|
||||
// make logo
|
||||
const ThemeData::ThemeElement* logoElem = theme->getElement("system", "logo", "image");
|
||||
if(logoElem)
|
||||
{
|
||||
ImageComponent* logo = new ImageComponent(mWindow, false, false);
|
||||
logo->setMaxSize(mCarousel.logoSize * mCarousel.logoScale);
|
||||
logo->applyTheme(theme, "system", "logo", ThemeFlags::PATH | ThemeFlags::COLOR);
|
||||
|
||||
e.data.logo = std::shared_ptr<GuiComponent>(logo);
|
||||
std::string path = logoElem->get<std::string>("path");
|
||||
std::string defaultPath = logoElem->has("default") ? logoElem->get<std::string>("default") : "";
|
||||
if((!path.empty() && ResourceManager::getInstance()->fileExists(path))
|
||||
|| (!defaultPath.empty() && ResourceManager::getInstance()->fileExists(defaultPath)))
|
||||
{
|
||||
ImageComponent* logo = new ImageComponent(mWindow, false, false);
|
||||
logo->setMaxSize(mCarousel.logoSize * mCarousel.logoScale);
|
||||
logo->applyTheme(theme, "system", "logo", ThemeFlags::PATH | ThemeFlags::COLOR);
|
||||
e.data.logo = std::shared_ptr<GuiComponent>(logo);
|
||||
}
|
||||
}
|
||||
if (!e.data.logo)
|
||||
{
|
||||
// no logo in theme; use text
|
||||
TextComponent* text = new TextComponent(mWindow,
|
||||
(*it)->getName(),
|
||||
Font::get(FONT_SIZE_LARGE),
|
||||
0x000000FF,
|
||||
ALIGN_CENTER);
|
||||
text->setSize(mCarousel.logoSize * mCarousel.logoScale);
|
||||
text->applyTheme((*it)->getTheme(), "system", "logoText", ThemeFlags::FONT_PATH | ThemeFlags::FONT_SIZE | ThemeFlags::COLOR | ThemeFlags::FORCE_UPPERCASE);
|
||||
e.data.logo = std::shared_ptr<GuiComponent>(text);
|
||||
|
||||
if (mCarousel.type == VERTICAL || mCarousel.type == VERTICAL_WHEEL)
|
||||
text->setHorizontalAlignment(mCarousel.logoAlignment);
|
||||
else
|
||||
text->setVerticalAlignment(mCarousel.logoAlignment);
|
||||
}
|
||||
}
|
||||
if (!e.data.logo)
|
||||
{
|
||||
// no logo in theme; use text
|
||||
TextComponent* text = new TextComponent(mWindow,
|
||||
(*it)->getName(),
|
||||
Font::get(FONT_SIZE_LARGE),
|
||||
0x000000FF,
|
||||
ALIGN_CENTER);
|
||||
text->setSize(mCarousel.logoSize * mCarousel.logoScale);
|
||||
text->applyTheme((*it)->getTheme(), "system", "logoText", ThemeFlags::FONT_PATH | ThemeFlags::FONT_SIZE | ThemeFlags::COLOR | ThemeFlags::FORCE_UPPERCASE);
|
||||
e.data.logo = std::shared_ptr<GuiComponent>(text);
|
||||
|
||||
if (mCarousel.type == VERTICAL || mCarousel.type == VERTICAL_WHEEL)
|
||||
text->setHorizontalAlignment(mCarousel.logoAlignment);
|
||||
else
|
||||
text->setVerticalAlignment(mCarousel.logoAlignment);
|
||||
}
|
||||
{
|
||||
if (mCarousel.logoAlignment == ALIGN_LEFT)
|
||||
e.data.logo->setOrigin(0, 0.5);
|
||||
else if (mCarousel.logoAlignment == ALIGN_RIGHT)
|
||||
e.data.logo->setOrigin(1.0, 0.5);
|
||||
else
|
||||
e.data.logo->setOrigin(0.5, 0.5);
|
||||
} else {
|
||||
if (mCarousel.logoAlignment == ALIGN_TOP)
|
||||
e.data.logo->setOrigin(0.5, 0);
|
||||
else if (mCarousel.logoAlignment == ALIGN_BOTTOM)
|
||||
e.data.logo->setOrigin(0.5, 1);
|
||||
else
|
||||
e.data.logo->setOrigin(0.5, 0.5);
|
||||
}
|
||||
|
||||
if (mCarousel.type == VERTICAL || mCarousel.type == VERTICAL_WHEEL)
|
||||
Vector2f denormalized = mCarousel.logoSize * e.data.logo->getOrigin();
|
||||
e.data.logo->setPosition(denormalized.x(), denormalized.y(), 0.0);
|
||||
// delete any existing extras
|
||||
for (auto extra : e.data.backgroundExtras)
|
||||
delete extra;
|
||||
e.data.backgroundExtras.clear();
|
||||
|
||||
// make background extras
|
||||
e.data.backgroundExtras = ThemeData::makeExtras((*it)->getTheme(), "system", mWindow);
|
||||
|
||||
// sort the extras by z-index
|
||||
std::stable_sort(e.data.backgroundExtras.begin(), e.data.backgroundExtras.end(), [](GuiComponent* a, GuiComponent* b) {
|
||||
return b->getZIndex() > a->getZIndex();
|
||||
});
|
||||
|
||||
this->add(e);
|
||||
}
|
||||
}
|
||||
if (mEntries.size() == 0)
|
||||
{
|
||||
// Something is wrong, there is not a single system to show, check if UI mode is not full
|
||||
if (!ViewController::get()->isUIModeFull())
|
||||
{
|
||||
if (mCarousel.logoAlignment == ALIGN_LEFT)
|
||||
e.data.logo->setOrigin(0, 0.5);
|
||||
else if (mCarousel.logoAlignment == ALIGN_RIGHT)
|
||||
e.data.logo->setOrigin(1.0, 0.5);
|
||||
else
|
||||
e.data.logo->setOrigin(0.5, 0.5);
|
||||
} else {
|
||||
if (mCarousel.logoAlignment == ALIGN_TOP)
|
||||
e.data.logo->setOrigin(0.5, 0);
|
||||
else if (mCarousel.logoAlignment == ALIGN_BOTTOM)
|
||||
e.data.logo->setOrigin(0.5, 1);
|
||||
else
|
||||
e.data.logo->setOrigin(0.5, 0.5);
|
||||
Settings::getInstance()->setString("UIMode", "Full");
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, "The selected UI mode has nothing to show,\n returning to UI mode: FULL", "OK", nullptr));
|
||||
}
|
||||
|
||||
Vector2f denormalized = mCarousel.logoSize * e.data.logo->getOrigin();
|
||||
e.data.logo->setPosition(denormalized.x(), denormalized.y(), 0.0);
|
||||
|
||||
// delete any existing extras
|
||||
for (auto extra : e.data.backgroundExtras)
|
||||
delete extra;
|
||||
e.data.backgroundExtras.clear();
|
||||
|
||||
// make background extras
|
||||
e.data.backgroundExtras = ThemeData::makeExtras((*it)->getTheme(), "system", mWindow);
|
||||
|
||||
// sort the extras by z-index
|
||||
std::stable_sort(e.data.backgroundExtras.begin(), e.data.backgroundExtras.end(), [](GuiComponent* a, GuiComponent* b) {
|
||||
return b->getZIndex() > a->getZIndex();
|
||||
});
|
||||
|
||||
this->add(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "views/gamelist/IGameListView.h"
|
||||
#include "views/gamelist/VideoGameListView.h"
|
||||
#include "views/SystemView.h"
|
||||
#include "FileFilterIndex.h"
|
||||
#include "Log.h"
|
||||
#include "Settings.h"
|
||||
#include "SystemData.h"
|
||||
|
@ -393,7 +394,7 @@ void ViewController::render(const Transform4x4f& parentTrans)
|
|||
|
||||
if(guiEnd.x() >= viewStart.x() && guiEnd.y() >= viewStart.y() &&
|
||||
guiStart.x() <= viewEnd.x() && guiStart.y() <= viewEnd.y())
|
||||
it->second->render(trans);
|
||||
it->second->render(trans);
|
||||
}
|
||||
|
||||
if(mWindow->peekGui() == this)
|
||||
|
@ -411,6 +412,7 @@ void ViewController::preload()
|
|||
{
|
||||
for(auto it = SystemData::sSystemVector.begin(); it != SystemData::sSystemVector.end(); it++)
|
||||
{
|
||||
(*it)->getIndex()->resetFilters();
|
||||
getGameListView(*it);
|
||||
}
|
||||
}
|
||||
|
@ -448,6 +450,7 @@ void ViewController::reloadGameListView(IGameListView* view, bool reloadTheme)
|
|||
|
||||
void ViewController::reloadAll()
|
||||
{
|
||||
// clear all gamelistviews
|
||||
std::map<SystemData*, FileData*> cursorMap;
|
||||
for(auto it = mGameListViews.begin(); it != mGameListViews.end(); it++)
|
||||
{
|
||||
|
@ -455,12 +458,16 @@ void ViewController::reloadAll()
|
|||
}
|
||||
mGameListViews.clear();
|
||||
|
||||
|
||||
// load themes, create gamelistviews and reset filters
|
||||
for(auto it = cursorMap.begin(); it != cursorMap.end(); it++)
|
||||
{
|
||||
it->first->loadTheme();
|
||||
it->first->getIndex()->resetFilters();
|
||||
getGameListView(it->first)->setCursor(it->second);
|
||||
}
|
||||
|
||||
// Rebuild SystemListView
|
||||
mSystemListView.reset();
|
||||
getSystemListView();
|
||||
|
||||
|
@ -486,6 +493,7 @@ void ViewController::monitorUIMode()
|
|||
std::string uimode = Settings::getInstance()->getString("UIMode");
|
||||
if (uimode != mCurUIMode) // UIMODE HAS CHANGED
|
||||
{
|
||||
mWindow->renderLoadingScreen();
|
||||
mCurUIMode = uimode;
|
||||
reloadAll();
|
||||
goToStart();
|
||||
|
@ -497,6 +505,12 @@ bool ViewController::isUIModeFull()
|
|||
return ((mCurUIMode == "Full") && ! Settings::getInstance()->getBool("ForceKiosk"));
|
||||
}
|
||||
|
||||
bool ViewController::isUIModeKid()
|
||||
{
|
||||
return (Settings::getInstance()->getBool("ForceKid") ||
|
||||
((mCurUIMode == "Kid") && !Settings::getInstance()->getBool("ForceKiosk")));
|
||||
}
|
||||
|
||||
std::vector<HelpPrompt> ViewController::getHelpPrompts()
|
||||
{
|
||||
std::vector<HelpPrompt> prompts;
|
||||
|
|
|
@ -11,7 +11,7 @@ class IGameListView;
|
|||
class SystemData;
|
||||
class SystemView;
|
||||
|
||||
const std::vector<std::string> UIModes = { "Full", "Kiosk" };
|
||||
const std::vector<std::string> UIModes = { "Full", "Kiosk", "Kid" };
|
||||
|
||||
// Used to smoothly transition the camera between multiple views (e.g. from system to system, from gamelist to gamelist).
|
||||
class ViewController : public GuiComponent
|
||||
|
@ -33,8 +33,9 @@ public:
|
|||
void reloadAll(); // Reload everything with a theme. Used when the "ThemeSet" setting changes.
|
||||
|
||||
void monitorUIMode();
|
||||
bool isUIModeFull();
|
||||
inline std::vector<std::string> getUIModes() { return UIModes; };
|
||||
bool isUIModeFull();
|
||||
bool isUIModeKid();
|
||||
|
||||
// Navigation.
|
||||
void goToNextGameList();
|
||||
|
|
|
@ -141,7 +141,7 @@ std::vector<HelpPrompt> BasicGameListView::getHelpPrompts()
|
|||
prompts.push_back(HelpPrompt("b", "back"));
|
||||
prompts.push_back(HelpPrompt("select", "options"));
|
||||
prompts.push_back(HelpPrompt("x", "random"));
|
||||
if(mRoot->getSystem()->isGameSystem())
|
||||
if(mRoot->getSystem()->isGameSystem() && !ViewController::get()->isUIModeKid())
|
||||
{
|
||||
std::string prompt = CollectionSystemManager::get()->getEditingCollection();
|
||||
prompts.push_back(HelpPrompt("y", prompt));
|
||||
|
|
|
@ -142,7 +142,7 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
|||
setCursor(randomGame);
|
||||
}
|
||||
return true;
|
||||
}else if (config->isMappedTo("y", input))
|
||||
}else if (config->isMappedTo("y", input) && !(ViewController::get()->isUIModeKid()))
|
||||
{
|
||||
if(mRoot->getSystem()->isGameSystem())
|
||||
{
|
||||
|
|
|
@ -14,6 +14,7 @@ std::vector<const char*> settings_dont_save = boost::assign::list_of
|
|||
("Debug")
|
||||
("DebugGrid")
|
||||
("DebugText")
|
||||
("ForceKid")
|
||||
("ForceKiosk")
|
||||
("IgnoreGamelist")
|
||||
("HideConsole")
|
||||
|
@ -124,6 +125,8 @@ void Settings::setDefaults()
|
|||
mStringMap["UIMode"] = "Full";
|
||||
mStringMap["UIMode_passkey"] = "uuddlrlrba";
|
||||
mBoolMap["ForceKiosk"] = false;
|
||||
mBoolMap["ForceKid"] = false;
|
||||
mBoolMap["hideQuitMenuOnKidUI"] = false;
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
|
|
Loading…
Reference in a new issue