diff --git a/USERGUIDE.md b/USERGUIDE.md index 849ac1335..ec0df38a5 100644 --- a/USERGUIDE.md +++ b/USERGUIDE.md @@ -641,7 +641,7 @@ Whether to sort your favorite games above your other games in the gamelists. With this setting enabled, there is a star symbol added at the beginning of the game name in the gamelist views. It's strongly recommended to keep this setting enabled if the option to sort favorite games above non-favorites has been enabled. If not, favorite games would be sorted on top of the gamelist with no visual indication that they are favorites, which would be very confusing. -**Enable button shortcut to toggle favorites** +**Enable shortcut to toggle favorites** This setting enables the 'Y' button for quickly toggling a game as favorite. Although this may be convenient at times, it's also quite easy to accidentally remove a favorite tagging of a game when using the application more casually. As such it could sometimes make sense to disable this functionality. It's of course still possible to mark a game as favorite using the metadata editor when this setting is disabled. For additional restrictions, the application can be set to Kid or Kiosk mode as is explained elsewhere in this document. Note that this setting does not affect the functionality to use the 'Y' button to add games to custom collections. @@ -763,6 +763,10 @@ Enable or disable navigation sounds throughout the application. Sounds are playe Handles collections, which are built using the games already present for your game systems. _(Details on how this works are discussed later in this guide.)_ +**Finish editing _'COLLECTION NAME'_ collection** + +Self explanatory. This menu entry is only visible when editing a collection. + **Automatic game collections** This opens a screen that lets you enable or disable the automatic game collections _All games_, _Favorites_ and _Last played_. @@ -773,12 +777,16 @@ This lets you create your own custom game collections. **Create new custom collection from theme** -If the theme set in use provides themes for custom collections, then this can be selected here. For example, there could be themes for _"Fighting games"_ or _"Driving games"_ etc. As of version 1.0.0, the default rbsimple-DE theme set does not provides such themes for custom collections. +If the theme set in use provides themes for custom collections, then this entry can be selected here. For example, there could be themes for _"Fighting games"_ or _"Driving games"_ etc. The default rbsimple-DE theme set does not provide such themes for custom collections and in general it's not recommended to use this approach, as is explained [later](USERGUIDE.md#custom-collections) in this guide. This menu entry is not visible if the theme does not have any available themes to use for custom collections. **Create new custom collection** This lets you create a completely custom collection with a name that you choose. +**Delete custom collection** + +This permanently deletes a custom collection, including its configuration file on the file system. A list of available collections is shown, and a confirmation dialog is displayed before committing the actual deletion. Only one collection at a time can be deleted. + **Sort favorites on top for custom collections** Whether to sort your favorite games above your other games. This is disabled by default, as for collections you probably want to be able to mix all games regardless of whether they are favorites or not. @@ -930,6 +938,10 @@ This opens the metadata editor, which will be described in detail below. This is only shown if the system is a collection. This will also be described in more detail below. +### Finish editing _'COLLECTION NAME'_ collection + +This menu entry is only visible when editing the collection. + ## Metadata editor diff --git a/es-app/src/CollectionSystemManager.cpp b/es-app/src/CollectionSystemManager.cpp index d2d814eb6..ae59af65c 100644 --- a/es-app/src/CollectionSystemManager.cpp +++ b/es-app/src/CollectionSystemManager.cpp @@ -857,6 +857,42 @@ SystemData* CollectionSystemManager::addNewCustomCollection(std::string name) return createNewCollectionEntry(name, decl, true, true); } +void CollectionSystemManager::deleteCustomCollection(std::string collectionName) +{ + auto collectionEntry = mCustomCollectionSystemsData.find(collectionName); + + // The window deletion needs to be located here instead of in GuiCollectionSystemsOptions + // (where the custom collection deletions are initiated), as there seems to be some random + // issue with accessing mWindow via the lambda expression. + while (mWindow->peekGui() && mWindow->peekGui() != ViewController::get()) + delete mWindow->peekGui(); + + if (collectionEntry != mCustomCollectionSystemsData.end()) { + CollectionSystemManager::get()->loadEnabledListFromSettings(); + CollectionSystemManager::get()->updateSystemsList(); + + ViewController::get()->removeGameListView(collectionEntry->second.system); + ViewController::get()->reloadAll(); + + delete collectionEntry->second.system; + mCustomCollectionSystemsData.erase(collectionName); + + // Remove the collection configuration file. + std::string configFile = getCustomCollectionConfigPath(collectionName); + Utils::FileSystem::removeFile(configFile); + LOG(LogDebug) << "CollectionSystemManager::deleteCustomCollection(): Deleted the " + "configuration file '" << configFile << "'."; + + GuiInfoPopup* s = new GuiInfoPopup(mWindow, "DELETED THE COLLECTION '" + + Utils::String::toUpper(collectionName) + "'", 5000); + mWindow->setInfoPopup(s); + } + else { + LOG(LogError) << "Attempted to delete custom collection '" + collectionName + "' " + + "which doesn't exist."; + } +} + // Functions below to Handle loading of collection systems, creating empty ones, // and populating on demand. diff --git a/es-app/src/CollectionSystemManager.h b/es-app/src/CollectionSystemManager.h index eb82c6704..76c3c5384 100644 --- a/es-app/src/CollectionSystemManager.h +++ b/es-app/src/CollectionSystemManager.h @@ -103,6 +103,7 @@ public: std::vector getUnusedSystemsFromTheme(); SystemData* addNewCustomCollection(std::string name); + void deleteCustomCollection(std::string collectionName); private: static CollectionSystemManager* sInstance; diff --git a/es-app/src/guis/GuiCollectionSystemsOptions.cpp b/es-app/src/guis/GuiCollectionSystemsOptions.cpp index abd2db712..ac8a623e5 100644 --- a/es-app/src/guis/GuiCollectionSystemsOptions.cpp +++ b/es-app/src/guis/GuiCollectionSystemsOptions.cpp @@ -11,15 +11,19 @@ #include "components/OptionListComponent.h" #include "components/SwitchComponent.h" +#include "guis/GuiMsgBox.h" #include "guis/GuiSettings.h" #include "guis/GuiTextEditPopup.h" #include "views/ViewController.h" #include "CollectionSystemManager.h" -GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(Window* window, std::string title) - : GuiSettings(window, title), mAddedCustomCollection(false) +GuiCollectionSystemsOptions::GuiCollectionSystemsOptions( + Window* window, + std::string title) + : GuiSettings(window, title), + mAddedCustomCollection(false), + mDeletedCustomCollection(false) { - // Finish editing custom collection. if (CollectionSystemManager::get()->isEditing()) { ComponentListRow row; @@ -72,19 +76,22 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(Window* window, std::st it->second.isEnabled); addWithLabel("CUSTOM GAME COLLECTIONS", collection_systems_custom); addSaveFunc([this] { - std::string customSystemsSelected = Utils::String::vectorToCommaString( - collection_systems_custom->getSelectedObjects(), true); - std::string customSystemsConfig = Settings::getInstance()-> - getString("CollectionSystemsCustom"); - if (customSystemsSelected != customSystemsConfig) { - if (CollectionSystemManager::get()->isEditing()) - CollectionSystemManager::get()->exitEditMode(); - Settings::getInstance()->setString("CollectionSystemsCustom", customSystemsSelected); - setNeedsSaving(); - setNeedsReloading(); - setNeedsCollectionsUpdate(); - if (!mAddedCustomCollection) - setNeedsGoToSystemView(SystemData::sSystemVector.front()); + if (!mDeletedCustomCollection) { + std::string customSystemsSelected = Utils::String::vectorToCommaString( + collection_systems_custom->getSelectedObjects(), true); + std::string customSystemsConfig = Settings::getInstance()-> + getString("CollectionSystemsCustom"); + if (customSystemsSelected != customSystemsConfig) { + if (CollectionSystemManager::get()->isEditing()) + CollectionSystemManager::get()->exitEditMode(); + Settings::getInstance()->setString("CollectionSystemsCustom", + customSystemsSelected); + setNeedsSaving(); + setNeedsReloading(); + setNeedsCollectionsUpdate(); + if (!mAddedCustomCollection) + setNeedsGoToSystemView(SystemData::sSystemVector.front()); + } } }); @@ -117,6 +124,11 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(Window* window, std::st auto themeFolder = std::make_shared(mWindow, Utils::String::toUpper(name), Font::get(FONT_SIZE_SMALL), 0x777777FF); row.addElement(themeFolder, true); + // This transparent bracket is only added to generate the correct help prompts. + auto bracket = std::make_shared(mWindow); + bracket->setImage(":/graphics/arrow.svg"); + bracket->setOpacity(0); + row.addElement(bracket, false); ss->addRow(row); } mWindow->pushGui(ss); @@ -149,6 +161,79 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(Window* window, std::st }); addRow(row); + // Delete custom collection. + row.elements.clear(); + auto deleteCollection = std::make_shared(mWindow, + "DELETE CUSTOM COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF); + auto bracketDeleteCollection = std::make_shared(mWindow); + bracketDeleteCollection->setImage(":/graphics/arrow.svg"); + bracketDeleteCollection->setResize(Vector2f(0, + Font::get(FONT_SIZE_MEDIUM)->getLetterHeight())); + row.addElement(deleteCollection, true); + row.addElement(bracketDeleteCollection, false); + row.makeAcceptInputHandler([this, customSystems] { + auto ss = new GuiSettings(mWindow, "SELECT COLLECTION TO DELETE"); + std::shared_ptr> customCollections = + std::make_shared>(mWindow, + getHelpStyle(), "", true); + for (std::map::const_iterator + it = customSystems.cbegin(); it != customSystems.cend() ; it++) { + ComponentListRow row; + std::string name = (*it).first; + std::function deleteCollectionCall = [this, name] { + mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), + "THIS WILL PERMANENTLY\nDELETE THE COLLECTION\n'" + + Utils::String::toUpper(name) + "'.\n" + "ARE YOU SURE?", + "YES", [this, name] { + if (CollectionSystemManager::get()->isEditing()) + CollectionSystemManager::get()->exitEditMode(); + mDeletedCustomCollection = true; + std::vector selectedCustomCollections = + collection_systems_custom->getSelectedObjects(); + std::string collectionsConfigEntry; + // Create the configuration file entry. If the collection to be + // deleted was activated, then exclude it. + for (auto it = selectedCustomCollections.begin(); + it != selectedCustomCollections.end(); it++) { + if ((*it) != name) { + if ((*it) != selectedCustomCollections.front() && + collectionsConfigEntry != "") + collectionsConfigEntry += ","; + collectionsConfigEntry += (*it); + } + } + // If the system to be deleted was present in es_settings.cfg, we + // need to re-write it. + if (collectionsConfigEntry != + Settings::getInstance()->getString("CollectionSystemsCustom")) { + Settings::getInstance()->setString("CollectionSystemsCustom", + collectionsConfigEntry); + setNeedsSaving(); + setNeedsGoToSystemView(SystemData::sSystemVector.front()); + } + CollectionSystemManager::get()->deleteCustomCollection(name); + return true; + }, + "NO", [this] { + return false; + })); + }; + row.makeAcceptInputHandler(deleteCollectionCall); + auto customCollection = std::make_shared(mWindow, + Utils::String::toUpper(name), Font::get(FONT_SIZE_SMALL), 0x777777FF); + row.addElement(customCollection, true); + // This transparent bracket is only added generate the correct help prompts. + auto bracket = std::make_shared(mWindow); + bracket->setImage(":/graphics/arrow.svg"); + bracket->setOpacity(0); + row.addElement(bracket, false); + ss->addRow(row); + } + mWindow->pushGui(ss); + }); + addRow(row); + // Sort favorites on top for custom collections. auto fav_first_custom = std::make_shared(mWindow); fav_first_custom->setState(Settings::getInstance()->getBool("FavFirstCustom")); diff --git a/es-app/src/guis/GuiCollectionSystemsOptions.h b/es-app/src/guis/GuiCollectionSystemsOptions.h index 337bb7473..1499a6b8c 100644 --- a/es-app/src/guis/GuiCollectionSystemsOptions.h +++ b/es-app/src/guis/GuiCollectionSystemsOptions.h @@ -27,6 +27,7 @@ private: std::shared_ptr> collection_systems_custom; bool mAddedCustomCollection; + bool mDeletedCustomCollection; }; #endif // ES_APP_GUIS_GUI_COLLECTION_SYSTEM_OPTIONS_H diff --git a/es-app/src/guis/GuiMenu.cpp b/es-app/src/guis/GuiMenu.cpp index 11e4b79cb..eb4969215 100644 --- a/es-app/src/guis/GuiMenu.cpp +++ b/es-app/src/guis/GuiMenu.cpp @@ -330,7 +330,7 @@ void GuiMenu::openUISettings() // Enable the 'Y' button for tagging games as favorites. auto favorites_add_button = std::make_shared(mWindow); favorites_add_button->setState(Settings::getInstance()->getBool("FavoritesAddButton")); - s->addWithLabel("ENABLE BUTTON SHORTCUT TO TOGGLE FAVORITES", favorites_add_button); + s->addWithLabel("ENABLE SHORTCUT TO TOGGLE FAVORITES", favorites_add_button); s->addSaveFunc([favorites_add_button, s] { if (Settings::getInstance()->getBool("FavoritesAddButton") != favorites_add_button->getState()) { diff --git a/es-app/src/guis/GuiSettings.cpp b/es-app/src/guis/GuiSettings.cpp index 5d56491bd..291d9bb5a 100644 --- a/es-app/src/guis/GuiSettings.cpp +++ b/es-app/src/guis/GuiSettings.cpp @@ -30,8 +30,7 @@ GuiSettings::GuiSettings( mNeedsSortingCollections(false), mGoToSystem(nullptr), mNeedsGoToStart(false), - mNeedsGoToSystemView(false), - mNeedsDestroyAllWindows(false) + mNeedsGoToSystemView(false) { addChild(&mMenu); mMenu.addButton("BACK", "back", [this] { delete this; }); @@ -82,13 +81,8 @@ void GuiSettings::save() if (mNeedsGoToSystemView) ViewController::get()->goToSystemView(mGoToSystem); - if (mNeedsDestroyAllWindows) { - while (mWindow->peekGui() && mWindow->peekGui() != ViewController::get()) - delete mWindow->peekGui(); - } - if (mNeedsSaving || mNeedsCollectionsUpdate || mNeedsReloading || mNeedsSorting || - mNeedsGoToStart || mNeedsGoToSystemView || mNeedsDestroyAllWindows) + mNeedsGoToStart || mNeedsGoToSystemView) mWindow->invalidateCachedBackground(); } diff --git a/es-app/src/guis/GuiSettings.h b/es-app/src/guis/GuiSettings.h index bf943b6ee..7028ad112 100644 --- a/es-app/src/guis/GuiSettings.h +++ b/es-app/src/guis/GuiSettings.h @@ -41,7 +41,6 @@ public: void setNeedsGoToStart() { mNeedsGoToStart = true; }; void setNeedsGoToSystemView(SystemData* goToSystem) { mNeedsGoToSystemView = true; mGoToSystem = goToSystem; }; - void setNeedsDestroyAllWindows() { mNeedsDestroyAllWindows = true; }; bool input(InputConfig* config, Input input) override; std::vector getHelpPrompts() override; @@ -57,7 +56,6 @@ private: bool mNeedsSortingCollections; bool mNeedsGoToStart; bool mNeedsGoToSystemView; - bool mNeedsDestroyAllWindows; SystemData* mGoToSystem; };