diff --git a/es-app/src/FileFilterIndex.cpp b/es-app/src/FileFilterIndex.cpp index 1013bb77c..c2c1bc33e 100644 --- a/es-app/src/FileFilterIndex.cpp +++ b/es-app/src/FileFilterIndex.cpp @@ -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(filterDecls, filterDecls + sizeof(filterDecls) / sizeof(filterDecls[0])); @@ -36,17 +41,19 @@ std::vector& FileFilterIndex::getFilterDataDecls() void FileFilterIndex::importIndex(FileFilterIndex* indexToImport) { struct IndexImportStructure - { - std::map* destinationIndex; - std::map* sourceIndex; - }; + { + std::map* destinationIndex; + std::map* 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 indexImportDecl = std::vector(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* 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 val = { "FALSE" }; + setFilter(HIDDEN_FILTER, &val); + } + if (ViewController::get()->isUIModeKid()) + { + filterByKidGame = true; + std::vector val = { "TRUE" }; + setFilter(KIDGAME_FILTER, &val); + } +} + void FileFilterIndex::debugPrintIndexes() { LOG(LogInfo) << "Printing Indexes..."; @@ -230,6 +279,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; } } @@ -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 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 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* index, std::string key, bool remove) { bool includeUnknown = INCLUDE_UNKNOWN; if (!includeUnknown && key == UNKNOWN_LABEL) diff --git a/es-app/src/FileFilterIndex.h b/es-app/src/FileFilterIndex.h index 57575a172..93b9c8d9f 100644 --- a/es-app/src/FileFilterIndex.h +++ b/es-app/src/FileFilterIndex.h @@ -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& getFilterDataDecls(); void importIndex(FileFilterIndex* indexToImport); void resetIndex(); + void resetFilters(); + void setUIModeFilters(); + private: std::vector 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* index, std::string key, bool remove); @@ -65,18 +72,24 @@ private: bool filterByPubDev; bool filterByRatings; bool filterByFavorites; + bool filterByHidden; + bool filterByKidGame; std::map genreIndexAllKeys; std::map playersIndexAllKeys; std::map pubDevIndexAllKeys; std::map ratingsIndexAllKeys; std::map favoritesIndexAllKeys; + std::map hiddenIndexAllKeys; + std::map kidGameIndexAllKeys; std::vector genreIndexFilteredKeys; std::vector playersIndexFilteredKeys; std::vector pubDevIndexFilteredKeys; std::vector ratingsIndexFilteredKeys; std::vector favoritesIndexFilteredKeys; + std::vector hiddenIndexFilteredKeys; + std::vector kidGameIndexFilteredKeys; FileData* mRootFolder; diff --git a/es-app/src/MetaData.cpp b/es-app/src/MetaData.cpp index 161f6da84..5c6fb7f25 100644 --- a/es-app/src/MetaData.cpp +++ b/es-app/src/MetaData.cpp @@ -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"} }; diff --git a/es-app/src/SystemData.cpp b/es-app/src/SystemData.cpp index ee659dd0b..148b91c13 100644 --- a/es-app/src/SystemData.cpp +++ b/es-app/src/SystemData.cpp @@ -340,6 +340,33 @@ std::string SystemData::getConfigPath(bool forWrite) return "/etc/emulationstation/es_systems.cfg"; } +SystemData* SystemData::getNext() const +{ + std::vector::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; diff --git a/es-app/src/SystemData.h b/es-app/src/SystemData.h index 09690f273..ede8edcd7 100644 --- a/es-app/src/SystemData.h +++ b/es-app/src/SystemData.h @@ -56,22 +56,9 @@ public: inline std::vector::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(); diff --git a/es-app/src/guis/GuiGamelistFilter.cpp b/es-app/src/guis/GuiGamelistFilter.cpp index a2c7f24b7..15be39d2e 100644 --- a/es-app/src/guis/GuiGamelistFilter.cpp +++ b/es-app/src/guis/GuiGamelistFilter.cpp @@ -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 >>::iterator it = mFilterOptions.begin(); it != mFilterOptions.end(); ++it ) { std::shared_ptr< OptionListComponent > optionList = it->second; optionList->selectNone(); @@ -49,7 +50,14 @@ GuiGamelistFilter::~GuiGamelistFilter() void GuiGamelistFilter::addFiltersToMenu() { std::vector decls = mFilterIndex->getFilterDataDecls(); - for (std::vector::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::iterator it = decls.begin(); it != decls.end()-skip; ++it ) { FilterIndexType type = (*it).type; // type of filter std::map* allKeys = (*it).allIndexKeys; // all possible filters for this type diff --git a/es-app/src/guis/GuiMenu.cpp b/es-app/src/guis/GuiMenu.cpp index 85014f2a2..b99ea8eea 100644 --- a/es-app/src/guis/GuiMenu.cpp +++ b/es-app/src/guis/GuiMenu.cpp @@ -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() { diff --git a/es-app/src/main.cpp b/es-app/src/main.cpp index 2e9344a18..68bb91b3b 100644 --- a/es-app/src/main.cpp +++ b/es-app/src/main.cpp @@ -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 diff --git a/es-app/src/views/SystemView.cpp b/es-app/src/views/SystemView.cpp index b05566925..99814b41e 100644 --- a/es-app/src/views/SystemView.cpp +++ b/es-app/src/views/SystemView.cpp @@ -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("path"); - std::string defaultPath = logoElem->has("default") ? logoElem->get("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(logo); + std::string path = logoElem->get("path"); + std::string defaultPath = logoElem->has("default") ? logoElem->get("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(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(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(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); } } diff --git a/es-app/src/views/ViewController.cpp b/es-app/src/views/ViewController.cpp index 3ae32b1a4..f81cba7e7 100644 --- a/es-app/src/views/ViewController.cpp +++ b/es-app/src/views/ViewController.cpp @@ -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 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 ViewController::getHelpPrompts() { std::vector prompts; diff --git a/es-app/src/views/ViewController.h b/es-app/src/views/ViewController.h index 985df16a8..a999edf9d 100644 --- a/es-app/src/views/ViewController.h +++ b/es-app/src/views/ViewController.h @@ -11,7 +11,7 @@ class IGameListView; class SystemData; class SystemView; -const std::vector UIModes = { "Full", "Kiosk" }; +const std::vector 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 getUIModes() { return UIModes; }; + bool isUIModeFull(); + bool isUIModeKid(); // Navigation. void goToNextGameList(); diff --git a/es-app/src/views/gamelist/BasicGameListView.cpp b/es-app/src/views/gamelist/BasicGameListView.cpp index b81e6462d..a8326f0c4 100644 --- a/es-app/src/views/gamelist/BasicGameListView.cpp +++ b/es-app/src/views/gamelist/BasicGameListView.cpp @@ -141,7 +141,7 @@ std::vector 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)); diff --git a/es-app/src/views/gamelist/ISimpleGameListView.cpp b/es-app/src/views/gamelist/ISimpleGameListView.cpp index de7e83cf5..0ae982bcd 100644 --- a/es-app/src/views/gamelist/ISimpleGameListView.cpp +++ b/es-app/src/views/gamelist/ISimpleGameListView.cpp @@ -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()) { diff --git a/es-core/src/Settings.cpp b/es-core/src/Settings.cpp index cb1ff06d8..c52525e6b 100644 --- a/es-core/src/Settings.cpp +++ b/es-core/src/Settings.cpp @@ -14,6 +14,7 @@ std::vector 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