diff --git a/INSTALL.md b/INSTALL.md index 362f8b5cb..d6526dc83 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -836,7 +836,6 @@ You can use `--help` or `-h` to view a list of command line options, as shown he --force-full Force the UI mode to Full --force-kid Force the UI mode to Kid --force-kiosk Force the UI mode to Kiosk ---force-disable-filters Force the UI to ignore applied filters in gamelist --force-input-config Force configuration of input device --home [path] Directory to use as home path --version, -v Displays version information @@ -860,7 +859,6 @@ You can use `--help` or `-h` to view a list of command line options, as shown he --force-full Force the UI mode to Full --force-kid Force the UI mode to Kid --force-kiosk Force the UI mode to Kiosk ---force-disable-filters Force the UI to ignore applied filters in gamelist --force-input-config Force configuration of input device --home [path] Directory to use as home path --version, -v Displays version information @@ -884,7 +882,6 @@ You can use `--help` or `-h` to view a list of command line options, as shown he --force-full Force the UI mode to Full --force-kid Force the UI mode to Kid --force-kiosk Force the UI mode to Kiosk ---force-disable-filters Force the UI to ignore applied filters in gamelist --force-input-config Force configuration of input device --home [path] Directory to use as home path --version, -v Displays version information diff --git a/NEWS.md b/NEWS.md index 1b07233e8..81f394a5f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -61,6 +61,7 @@ Many bugs have been fixed, and numerous features that were only partially implem * Refactoring, cleanup and documentation of the source code, removal of deprecated files etc. * All required fonts bundled with the application, no dependencies on the OS to provide them any longer * Made pugixml an external dependency instead of bundling it +* Overhaul of application settings, now the configuration file is only updated when there have been actual configuration changes * Decreased CPU usage dramatically by only rendering the currently visible view (previously all views were always rendered) * Updated the CMake/CPack install and package build script to work as expected (it can now generate .deb, .rpm, .dmg and NSIS installation packages) * Added support for Clang/LLVM, made the application build with no errors or warnings using this compiler (Unix and macOS only) diff --git a/USERGUIDE.md b/USERGUIDE.md index 2961d3bc4..236ebdee7 100644 --- a/USERGUIDE.md +++ b/USERGUIDE.md @@ -468,7 +468,7 @@ JPG and PNG file formats and file extensions are supported. Remember that on Unix files are case sensitive, and as well the file extensions must be in lower case, i.e. .png intead of .PNG or .Png or the file won't be found. -As an alternative, you can also locate your game media in the ROM directory. This is explained below in this guide under the option **Display game art from ROM directories**. This is however not recommended and the built-in scraper will never save any game media to this folder structure. +As an alternative, you can also locate your game media in the ROM directory. This is explained below in this guide under the option **Display game media from ROM directories**. This is however not recommended and the built-in scraper will never save any game media to this folder structure. Note that it's possible to change the game media directory from within ES, see the option **Game media directory** detailed below. @@ -671,7 +671,7 @@ Options specific to the slideshow screensaver. **Swap images after (secs)** -How long to show images before change to the next game. +How long to play videos before changing to the next game. Allowed range is between 5 and 120 seconds. **Stretch images to screen resolution** @@ -707,7 +707,7 @@ Options specific to the video screensaver. **Swap videos after (secs)** -How long to play videos before change to the next game. +How long to play videos before changing to the next game. Allowed range is between 5 and 120 seconds. **Stretch videos to screen resolution** @@ -791,10 +791,6 @@ The amount of video RAM to use for the application. Defaults to 128 MiB which se This gives you a choice between Normal and Borderless modes. With the borderless being more seamless as the ES window will always stay on top of other windows so the taskbar will not be visible when launching and returning from games. It will however break the alt-tab application switching of your window manager. For normal fullscreen mode, if a lower resolution than the screen resolution has been set via the --resolution command line argument, ES will render in full screen at the lower resolution. If a higher resolution than the screen resolution has been set, ES will run in a window. For the borderless mode, any changes to the resolution will make ES run in a window. -**Power saver modes** - -Can be set to Disabled, Default, Enhanced or Instant. Set to Disabled by default. - **When to save metadata** The metadata for a game is updated both by scraping and modifying data in the metadata editor, but also when launching a game, as the play count and last played date is then updated. This setting enables you to define when to write such metadata changes to the gamelist.xml files. Setting the option to "Never" will disable writing to these files altogether, except for some special conditions such as when a game is manually deleted using the metadata editor, or when scraping using the multi-scraper (the multi-scraper will always save any updates immediately to the gamelist.xml files). In theory "On exit" will give some performance gains, but it's normally recommended to leave the setting at its default value which is "Always". Note that with the settings set to "Never", any updates such as the last played date will still be shown on screen, however during the next application startup, any values previously saved to the gamelist.xml files will be read in again. As well, when changing this setting to "Always" from either of the two other options, any pending changes will be immediately written to the gamelist.xml files. @@ -823,9 +819,9 @@ It's possible to trigger custom scripts for a number of actions in ES. _(Details If enabled, only ROMs that have metadata saved to the gamelist.xml files will be shown in ES. This option is intended primarily for testing and debugging purposes so it should normally not be enabled. -**Display game art from ROM directories** +**Display game media from ROM directories** -Using this option, you can locate game images in the ROM directory tree. The images are searched inside the directory "\/\/images/" and the filenames must be the same as the ROM names, followed by a dash and the image type. For example "~/ROMs/nes/images/Contra-screenshot.jpg" and "~/ROMs/nes/images/Contra-marquee.jpg". This option is mostly intended for legacy purposes, if you have an existing game collection with this media setup that you would like to open in ES. The scraper will never save files to this directory structure and will instead use the standard media directory logic. It's recommended to keep this option disabled unless you really need it since it slows down the application somewhat. +Using this option, you can place game images and videos in the ROM directory tree. The media files are searched inside the directory "\/\/images/" and "\/\/videos/" and the filenames must be the same as the ROM names, followed by a dash and the media type. For example "~/ROMs/nes/images/Contra-screenshot.jpg", "~/ROMs/nes/images/Contra-marquee.jpg" and "~/ROMs/nes/videos/Contra-video.jpg". This option is mostly intended for legacy purposes, if you have an existing game collection with this media setup that you would like to open in ES. The scraper will never save files to this directory structure and will instead use the standard media directory logic. It's recommended to keep this option disabled unless you really need it since it slows down the application somewhat. **Display GPU statistics overlay** diff --git a/es-app/src/FileData.cpp b/es-app/src/FileData.cpp index 2acffb969..c753ca383 100644 --- a/es-app/src/FileData.cpp +++ b/es-app/src/FileData.cpp @@ -213,7 +213,7 @@ const std::string FileData::getMediafilePath(std::string subdirectory, std::stri // No media found in the media directory, so look // for local art as well (if configured to do so). - if (Settings::getInstance()->getBool("LocalArt")) { + if (Settings::getInstance()->getBool("ROMDirGameMedia")) { for (int i = 0; i < 2; i++) { std::string localMediaPath = mEnvData->mStartPath + "/images/" + getDisplayName() + "-" + mediatype + extList[i]; @@ -285,7 +285,7 @@ const std::string FileData::getVideoPath() const // No media found in the media directory, so look // for local art as well (if configured to do so). - if (Settings::getInstance()->getBool("LocalArt")) + if (Settings::getInstance()->getBool("ROMDirGameMedia")) { for (int i = 0; i < 5; i++) { std::string localMediaPath = mEnvData->mStartPath + "/videos/" + diff --git a/es-app/src/FileFilterIndex.cpp b/es-app/src/FileFilterIndex.cpp index 3feb5db74..d8b70ed0a 100644 --- a/es-app/src/FileFilterIndex.cpp +++ b/es-app/src/FileFilterIndex.cpp @@ -288,7 +288,7 @@ void FileFilterIndex::resetFilters() void FileFilterIndex::setUIModeFilters() { - if (!Settings::getInstance()->getBool("ForceDisableFilters")){ + if (Settings::getInstance()->getBool("GamelistFilters")){ if (UIModeController::getInstance()->isUIModeKiosk()) { filterByHidden = true; std::vector val = { "FALSE" }; diff --git a/es-app/src/SystemData.cpp b/es-app/src/SystemData.cpp index 9f9b3965a..bd60f145e 100644 --- a/es-app/src/SystemData.cpp +++ b/es-app/src/SystemData.cpp @@ -619,14 +619,15 @@ FileData* SystemData::getRandomGame(const FileData* currentGame) return gameList.at(target); } -void SystemData::sortSystem(bool reloadGamelist) +void SystemData::sortSystem(bool reloadGamelist, bool jumpToFirstRow) { if (getName() == "recent") return; bool favoritesSorting; - if (this->isCustomCollection()) + if (this->isCustomCollection() || + (this->isCollection() && this->getFullName() == "collections")) favoritesSorting = Settings::getInstance()->getBool("FavFirstCustom"); else favoritesSorting = Settings::getInstance()->getBool("FavoritesFirst"); @@ -646,6 +647,11 @@ void SystemData::sortSystem(bool reloadGamelist) if (reloadGamelist) ViewController::get()->reloadGameListView(this, false); + + if (jumpToFirstRow) { + IGameListView* gameList = ViewController::get()->getGameListView(this).get(); + gameList->setCursor(gameList->getFirstEntry()); + } } std::pair SystemData::getDisplayedGameCount() const diff --git a/es-app/src/SystemData.h b/es-app/src/SystemData.h index a6a5d4c4e..e519ac4c6 100644 --- a/es-app/src/SystemData.h +++ b/es-app/src/SystemData.h @@ -95,7 +95,7 @@ public: static SystemData* getRandomSystem(const SystemData* currentSystem); FileData* getRandomGame(const FileData* currentGame = nullptr); - void sortSystem(bool reloadGamelist = true); + void sortSystem(bool reloadGamelist = true, bool jumpToFirstRow = false); // Load or re-load theme. void loadTheme(); diff --git a/es-app/src/SystemScreenSaver.cpp b/es-app/src/SystemScreenSaver.cpp index 592e2a185..07062dd5b 100644 --- a/es-app/src/SystemScreenSaver.cpp +++ b/es-app/src/SystemScreenSaver.cpp @@ -74,7 +74,7 @@ bool SystemScreenSaver::isScreenSaverActive() void SystemScreenSaver::startScreenSaver() { - std::string screensaver_behavior = Settings::getInstance()->getString("ScreenSaverBehavior"); + std::string screensaver_behavior = Settings::getInstance()->getString("ScreensaverBehavior"); // Set mPreviousGame which will be used to avoid showing the same game again during // the random selection. @@ -86,7 +86,7 @@ void SystemScreenSaver::startScreenSaver() // Configure to fade out the windows, skip fading if mode is set to Instant. mState = PowerSaver::getMode() == PowerSaver::INSTANT ? STATE_SCREENSAVER_ACTIVE : STATE_FADE_OUT_WINDOW; - mVideoChangeTime = Settings::getInstance()->getInt("ScreenSaverSwapVideoTimeout"); + mVideoChangeTime = Settings::getInstance()->getInt("ScreensaverSwapVideoTimeout"); mOpacity = 0.0f; // Load a random video. @@ -103,7 +103,7 @@ void SystemScreenSaver::startScreenSaver() if (!path.empty() && Utils::FileSystem::exists(path)) { #if defined(_RPI_) // Create the correct type of video component - if (Settings::getInstance()->getBool("ScreenSaverOmxPlayer")) + if (Settings::getInstance()->getBool("ScreensaverOmxPlayer")) mVideoScreensaver = new VideoPlayerComponent(mWindow); else mVideoScreensaver = new VideoVlcComponent(mWindow); @@ -116,7 +116,7 @@ void SystemScreenSaver::startScreenSaver() mVideoScreensaver->setPosition(Renderer::getScreenWidth() / 2.0f, Renderer::getScreenHeight() / 2.0f); - if (Settings::getInstance()->getBool("ScreenSaverStretchVideos")) + if (Settings::getInstance()->getBool("ScreensaverStretchVideos")) mVideoScreensaver->setResize(static_cast(Renderer::getScreenWidth()), static_cast(Renderer::getScreenHeight())); else @@ -135,12 +135,12 @@ void SystemScreenSaver::startScreenSaver() // Configure to fade out the windows, skip fading if mode is set to Instant. mState = PowerSaver::getMode() == PowerSaver::INSTANT ? STATE_SCREENSAVER_ACTIVE : STATE_FADE_OUT_WINDOW; - mVideoChangeTime = Settings::getInstance()->getInt("ScreenSaverSwapImageTimeout"); + mVideoChangeTime = Settings::getInstance()->getInt("ScreensaverSwapImageTimeout"); mOpacity = 0.0f; // Load a random image. std::string path = ""; - if (Settings::getInstance()->getBool("SlideshowScreenSaverCustomImageSource")) { + if (Settings::getInstance()->getBool("ScreensaverSlideshowCustomImages")) { pickRandomCustomImage(path); // Custom images are not tied to the game list. mCurrentGame = nullptr; @@ -159,7 +159,7 @@ void SystemScreenSaver::startScreenSaver() mImageScreensaver->setPosition(Renderer::getScreenWidth() / 2.0f, Renderer::getScreenHeight() / 2.0f); - if (Settings::getInstance()->getBool("ScreenSaverStretchImages")) + if (Settings::getInstance()->getBool("ScreensaverStretchImages")) mImageScreensaver->setResize(static_cast(Renderer::getScreenWidth()), static_cast(Renderer::getScreenHeight())); else @@ -167,7 +167,7 @@ void SystemScreenSaver::startScreenSaver() static_cast(Renderer::getScreenHeight())); std::string bg_audio_file = Settings::getInstance()-> - getString("SlideshowScreenSaverBackgroundAudioFile"); + getString("ScreensaverSlideshowAudioFile"); if ((!mBackgroundAudio) && (bg_audio_file != "")) { if (Utils::FileSystem::exists(bg_audio_file)) { // Pause PowerSaver so that the background audio keeps playing. @@ -210,7 +210,7 @@ void SystemScreenSaver::stopScreenSaver() void SystemScreenSaver::renderScreenSaver() { - std::string screensaver_behavior = Settings::getInstance()->getString("ScreenSaverBehavior"); + std::string screensaver_behavior = Settings::getInstance()->getString("ScreensaverBehavior"); if (mVideoScreensaver && screensaver_behavior == "video") { // Render black background. Renderer::setMatrix(Transform4x4f::Identity()); @@ -241,7 +241,7 @@ void SystemScreenSaver::renderScreenSaver() // Check if we need to restart the background audio. if ((mBackgroundAudio) && (Settings::getInstance()-> - getString("SlideshowScreenSaverBackgroundAudioFile") != "")) { + getString("ScreensaverSlideshowAudioFile") != "")) { if (!mBackgroundAudio->isPlaying()) mBackgroundAudio->play(); } @@ -377,14 +377,13 @@ void SystemScreenSaver::pickRandomGameListImage(std::string& path) void SystemScreenSaver::pickRandomCustomImage(std::string& path) { - std::string imageDir = Settings::getInstance()->getString("SlideshowScreenSaverImageDir"); + std::string imageDir = Settings::getInstance()->getString("ScreensaverSlideshowImageDir"); if ((imageDir != "") && (Utils::FileSystem::exists(imageDir))) { - std::string imageFilter = Settings::getInstance()-> - getString("SlideshowScreenSaverImageFilter"); + std::string imageFilter = ".jpg, .JPG, .png, .PNG"; std::vector matchingFiles; Utils::FileSystem::stringList dirContent = Utils::FileSystem::getDirContent( - imageDir, Settings::getInstance()->getBool("SlideshowScreenSaverRecurse")); + imageDir, Settings::getInstance()->getBool("ScreensaverSlideshowRecurse")); for (Utils::FileSystem::stringList::const_iterator it = dirContent.cbegin(); it != dirContent.cend(); ++it) { diff --git a/es-app/src/guis/GuiGamelistOptions.cpp b/es-app/src/guis/GuiGamelistOptions.cpp index a19b9d253..97604ac34 100644 --- a/es-app/src/guis/GuiGamelistOptions.cpp +++ b/es-app/src/guis/GuiGamelistOptions.cpp @@ -133,8 +133,7 @@ GuiGamelistOptions::GuiGamelistOptions( // Add the filters entry, unless this is the grouped custom collections list. if (!isCustomCollectionGroup) { - if (system->getName() != "recent" && - !Settings::getInstance()->getBool("ForceDisableFilters")) { + if (system->getName() != "recent" && Settings::getInstance()->getBool("GamelistFilters")) { row.elements.clear(); row.addElement(std::make_shared (mWindow, "FILTER GAMELIST", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); diff --git a/es-app/src/guis/GuiGeneralScreensaverOptions.cpp b/es-app/src/guis/GuiGeneralScreensaverOptions.cpp index 3dc978fd2..195f4b73c 100644 --- a/es-app/src/guis/GuiGeneralScreensaverOptions.cpp +++ b/es-app/src/guis/GuiGeneralScreensaverOptions.cpp @@ -4,7 +4,6 @@ // GuiGeneralScreensaverOptions.cpp // // User interface for the screensaver options. -// Based on the GuiScreenSaverOptions template. // Submenu to the GuiMenu main menu. // @@ -14,30 +13,38 @@ #include "components/SliderComponent.h" #include "components/SwitchComponent.h" #include "guis/GuiMsgBox.h" -#include "guis/GuiSlideshowScreensaverOptions.h" -#include "guis/GuiVideoScreensaverOptions.h" #include "Settings.h" GuiGeneralScreensaverOptions::GuiGeneralScreensaverOptions(Window* window, const char* title) - : GuiScreensaverOptions(window, title) + : GuiSettings(window, title) { - // Screensaver time. + // Screensaver timer. auto screensaver_time = std::make_shared(mWindow, 0.f, 30.f, 1.f, "m"); - screensaver_time->setValue((float)(Settings::getInstance()-> - getInt("ScreenSaverTime") / (1000 * 60))); + screensaver_time->setValue(static_cast(Settings::getInstance()-> + getInt("ScreensaverTimer") / (1000 * 60))); addWithLabel("SCREENSAVER AFTER", screensaver_time); - addSaveFunc([screensaver_time] { - Settings::getInstance()->setInt("ScreenSaverTime", - (int)Math::round(screensaver_time->getValue()) * (1000 * 60)); - PowerSaver::updateTimeouts(); + addSaveFunc([screensaver_time, this] { + if (static_cast(Math::round(screensaver_time->getValue()) * (1000 * 60)) != + Settings::getInstance()->getInt("ScreensaverTimer")) { + Settings::getInstance()->setInt("ScreensaverTimer", + static_cast(Math::round(screensaver_time->getValue()) * (1000 * 60))); + PowerSaver::updateTimeouts(); + setNeedsSaving(); + } }); - // Allow ScreenSaver Controls - ScreenSaverControls. - auto ss_controls = std::make_shared(mWindow); - ss_controls->setState(Settings::getInstance()->getBool("ScreenSaverControls")); - addWithLabel("SCREENSAVER CONTROLS", ss_controls); - addSaveFunc([ss_controls] { Settings::getInstance()->setBool("ScreenSaverControls", - ss_controls->getState()); }); + // Whether to enable screensaver controls. + auto screensaver_controls = std::make_shared(mWindow); + screensaver_controls->setState(Settings::getInstance()->getBool("ScreensaverControls")); + addWithLabel("SCREENSAVER CONTROLS", screensaver_controls); + addSaveFunc([screensaver_controls, this] { + if (screensaver_controls->getState() != + Settings::getInstance()->getBool("ScreensaverControls")) { + Settings::getInstance()->setBool("ScreensaverControls", + screensaver_controls->getState()); + setNeedsSaving(); + } + }); // Screensaver behavior. auto screensaver_behavior = std::make_shared> @@ -49,20 +56,24 @@ GuiGeneralScreensaverOptions::GuiGeneralScreensaverOptions(Window* window, const screensavers.push_back("video"); for (auto it = screensavers.cbegin(); it != screensavers.cend(); it++) screensaver_behavior->add(*it, *it, Settings::getInstance()-> - getString("ScreenSaverBehavior") == *it); + getString("ScreensaverBehavior") == *it); addWithLabel("SCREENSAVER BEHAVIOR", screensaver_behavior); - addSaveFunc([this, screensaver_behavior] { - if (Settings::getInstance()->getString("ScreenSaverBehavior") != - "video" && screensaver_behavior->getSelected() == "video") { - // If before it wasn't risky but now there's a risk of problems, show warning. - mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), - "THE \"VIDEO\" SCREENSAVER SHOWS\nVIDEOS FROM YOUR GAMELISTS.\n\nIF YOU DO NOT " - "HAVE ANY VIDEOS, THE\nSCREENSAVER WILL DEFAULT TO \"BLACK\"", - "OK", [] { return; }, "", nullptr, "", nullptr)); + addSaveFunc([screensaver_behavior, this] { + if (screensaver_behavior->getSelected() != + Settings::getInstance()->getString("ScreensaverBehavior")) { + if (screensaver_behavior->getSelected() == "video") { + // If before it wasn't risky but now there's a risk of problems, show warning. + mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), + "THE \"VIDEO\" SCREENSAVER SHOWS\nVIDEOS FROM YOUR GAMELISTS.\n\n" + "IF YOU DO NOT HAVE ANY VIDEOS, THE\n" + "SCREENSAVER WILL DEFAULT TO \"BLACK\"", + "OK", [] { return; }, "", nullptr, "", nullptr)); + } + Settings::getInstance()->setString("ScreensaverBehavior", + screensaver_behavior->getSelected()); + setNeedsSaving(); + PowerSaver::updateTimeouts(); } - Settings::getInstance()->setString("ScreenSaverBehavior", - screensaver_behavior->getSelected()); - PowerSaver::updateTimeouts(); }); ComponentListRow row; @@ -85,14 +96,250 @@ GuiGeneralScreensaverOptions::GuiGeneralScreensaverOptions(Window* window, const addRow(row); } -GuiGeneralScreensaverOptions::~GuiGeneralScreensaverOptions() +void GuiGeneralScreensaverOptions::openSlideshowScreensaverOptions() { + auto s = new GuiSettings(mWindow, "SLIDESHOW SCREENSAVER"); + + // Timer for swapping images (in seconds). + auto screensaver_swap_image_timeout = + std::make_shared(mWindow, 5.f, 120.f, 1.f, "s"); + screensaver_swap_image_timeout->setValue(static_cast(Settings::getInstance()-> + getInt("ScreensaverSwapImageTimeout") / (1000))); + s->addWithLabel("SWAP IMAGE AFTER (SECS)", screensaver_swap_image_timeout); + s->addSaveFunc([screensaver_swap_image_timeout, s] { + if (screensaver_swap_image_timeout->getValue() != + static_cast(Settings::getInstance()-> + getInt("ScreensaverSwapImageTimeout") / (1000))) { + Settings::getInstance()->setInt("ScreensaverSwapImageTimeout", + static_cast(Math::round(screensaver_swap_image_timeout->getValue()) * + (1000))); + s->setNeedsSaving(); + PowerSaver::updateTimeouts(); + } + }); + + // Stretch images to screen resolution. + auto screensaver_stretch_images = std::make_shared(mWindow); + screensaver_stretch_images-> + setState(Settings::getInstance()->getBool("ScreensaverStretchImages")); + s->addWithLabel("STRETCH IMAGES TO SCREEN RESOLUTION", screensaver_stretch_images); + s->addSaveFunc([screensaver_stretch_images, s] { + if (screensaver_stretch_images->getState() != + Settings::getInstance()->getBool("ScreensaverStretchImages")) { + Settings::getInstance()->setBool("ScreensaverStretchImages", + screensaver_stretch_images->getState()); + s->setNeedsSaving(); + } + }); + + #if defined(USE_OPENGL_21) + // Render scanlines using a shader. + auto screensaver_image_scanlines = std::make_shared(mWindow); + screensaver_image_scanlines-> + setState(Settings::getInstance()->getBool("ScreensaverImageScanlines")); + s->addWithLabel("RENDER SCANLINES", screensaver_image_scanlines); + s->addSaveFunc([screensaver_image_scanlines, s] { + if (screensaver_image_scanlines->getState() != + Settings::getInstance()->getBool("ScreensaverImageScanlines")) { + Settings::getInstance()-> + setBool("ScreensaverImageScanlines", screensaver_image_scanlines->getState()); + s->setNeedsSaving(); + } + }); + #endif + + // Background audio file. + auto screensaver_slideshow_audio_file = std::make_shared(mWindow, "", + Font::get(FONT_SIZE_SMALL), 0x777777FF, ALIGN_RIGHT); + s->addEditableTextComponent("BACKGROUND AUDIO", screensaver_slideshow_audio_file, + Settings::getInstance()->getString("ScreensaverSlideshowAudioFile"), + "~/.emulationstation/slideshow/audio/slideshow.wav"); + s->addSaveFunc([screensaver_slideshow_audio_file, s] { + if (screensaver_slideshow_audio_file->getValue() != + Settings::getInstance()->getString("ScreensaverSlideshowAudioFile")) { + Settings::getInstance()->setString("ScreensaverSlideshowAudioFile", + screensaver_slideshow_audio_file->getValue()); + s->setNeedsSaving(); + } + }); + + // Whether to use custom images. + auto screensaver_slideshow_custom_images = std::make_shared(mWindow); + screensaver_slideshow_custom_images->setState(Settings::getInstance()-> + getBool("ScreensaverSlideshowCustomImages")); + s->addWithLabel("USE CUSTOM IMAGES", screensaver_slideshow_custom_images); + s->addSaveFunc([screensaver_slideshow_custom_images, s] { + if (screensaver_slideshow_custom_images->getState() != + Settings::getInstance()->getBool("ScreensaverSlideshowCustomImages")) { + Settings::getInstance()->setBool("ScreensaverSlideshowCustomImages", + screensaver_slideshow_custom_images->getState()); + s->setNeedsSaving(); + } + }); + + // Custom image directory. + auto screensaver_slideshow_image_dir = std::make_shared(mWindow, "", + Font::get(FONT_SIZE_SMALL), 0x777777FF, ALIGN_RIGHT); + s->addEditableTextComponent("CUSTOM IMAGE DIR", screensaver_slideshow_image_dir, + Settings::getInstance()->getString("ScreensaverSlideshowImageDir"), + "~/.emulationstation/slideshow/custom_images"); + s->addSaveFunc([screensaver_slideshow_image_dir, s] { + if (screensaver_slideshow_image_dir->getValue() != + Settings::getInstance()->getString("ScreensaverSlideshowImageDir")) { + Settings::getInstance()->setString("ScreensaverSlideshowImageDir", + screensaver_slideshow_image_dir->getValue()); + s->setNeedsSaving(); + } + }); + + // Whether to recurse the custom image directory. + auto screensaver_slideshow_recurse = std::make_shared(mWindow); + screensaver_slideshow_recurse->setState(Settings::getInstance()-> + getBool("ScreensaverSlideshowRecurse")); + s->addWithLabel("CUSTOM IMAGE DIR RECURSIVE", screensaver_slideshow_recurse); + s->addSaveFunc([screensaver_slideshow_recurse, s] { + if (screensaver_slideshow_recurse->getState() != + Settings::getInstance()->getBool("ScreensaverSlideshowRecurse")) { + Settings::getInstance()->setBool("ScreensaverSlideshowRecurse", + screensaver_slideshow_recurse->getState()); + s->setNeedsSaving(); + } + }); + + mWindow->pushGui(s); } -void GuiGeneralScreensaverOptions::openVideoScreensaverOptions() { - mWindow->pushGui(new GuiVideoScreensaverOptions(mWindow, "VIDEO SCREENSAVER")); -} +void GuiGeneralScreensaverOptions::openVideoScreensaverOptions() +{ + auto s = new GuiSettings(mWindow, "VIDEO SCREENSAVER"); -void GuiGeneralScreensaverOptions::openSlideshowScreensaverOptions() { - mWindow->pushGui(new GuiSlideshowScreensaverOptions(mWindow, "SLIDESHOW SCREENSAVER")); + // Timer for swapping videos (in seconds). + auto screensaver_swap_video_timeout = + std::make_shared(mWindow, 5.f, 120.f, 1.f, "s"); + screensaver_swap_video_timeout->setValue(static_cast(Settings::getInstance()-> + getInt("ScreensaverSwapVideoTimeout") / (1000))); + s->addWithLabel("SWAP VIDEO AFTER (SECS)", screensaver_swap_video_timeout); + s->addSaveFunc([screensaver_swap_video_timeout,s ] { + if (screensaver_swap_video_timeout->getValue() != + static_cast(Settings::getInstance()-> + getInt("ScreensaverSwapVideoTimeout") / (1000))) { + Settings::getInstance()->setInt("ScreensaverSwapVideoTimeout", + static_cast(Math::round(screensaver_swap_video_timeout->getValue()) * + (1000))); + s->setNeedsSaving(); + PowerSaver::updateTimeouts(); + } + }); + + // Stretch videos to screen resolution. + auto screensaver_stretch_videos = std::make_shared(mWindow); + screensaver_stretch_videos-> + setState(Settings::getInstance()->getBool("ScreensaverStretchVideos")); + s->addWithLabel("STRETCH VIDEOS TO SCREEN RESOLUTION", screensaver_stretch_videos); + s->addSaveFunc([screensaver_stretch_videos, s] { + if (screensaver_stretch_videos->getState() != + Settings::getInstance()->getBool("ScreensaverStretchVideos")) { + Settings::getInstance()->setBool("ScreensaverStretchVideos", + screensaver_stretch_videos->getState()); + s->setNeedsSaving(); + } + }); + + #if defined(_RPI_) + auto screensaver_omx_player = std::make_shared(mWindow); + screensaver_omx_player->setState(Settings::getInstance()->getBool("ScreensaverOmxPlayer")); + s->addWithLabel("USE OMX PLAYER FOR SCREENSAVER", screensaver_omx_player); + s->addSaveFunc([screensaver_omx_player, s] { + if (screensaver_omx_player->getState() != + Settings::getInstance()->getBool("ScreensaverOmxPlayer")) { + Settings::getInstance()-> + setBool("ScreensaverOmxPlayer", screensaver_omx_player->getState()); + s->setNeedsSaving(); + } + }); + + // TEMPORARY - Disabled for now, need to find a proper way to make an overlay on top of + // the videos. The solution with rendering subtitles is not a good solution. + // And as well the VLC video player subtitles seem to be somehow broken. + // Render video game name as subtitles. +// auto ss_info = std::make_shared> +// (mWindow,getHelpStyle(), "SHOW GAME INFO", false); +// std::vector info_type; +// info_type.push_back("always"); +// info_type.push_back("start & end"); +// info_type.push_back("never"); +// for (auto it = info_type.cbegin(); it != info_type.cend(); it++) +// ss_info->add(*it, *it, Settings::getInstance()->getString("ScreensaverGameInfo") == *it); +// addWithLabel("SHOW GAME INFO ON SCREENSAVER", ss_info); +// addSaveFunc([ss_info, this] { Settings::getInstance()-> +// setString("ScreensaverGameInfo", ss_info->getSelected()); }); + +// ComponentListRow row; + + // Set subtitle position. +// auto ss_omx_subs_align = std::make_shared> +// (mWindow, getHelpStyle(), "GAME INFO ALIGNMENT", false); +// std::vector align_mode; +// align_mode.push_back("left"); +// align_mode.push_back("center"); +// for (auto it = align_mode.cbegin(); it != align_mode.cend(); it++) +// ss_omx_subs_align->add(*it, *it, Settings::getInstance()-> +// getString("SubtitleAlignment") == *it); +// addWithLabel("GAME INFO ALIGNMENT", ss_omx_subs_align); +// addSaveFunc([ss_omx_subs_align, this] { Settings::getInstance()-> +// setString("SubtitleAlignment", ss_omx_subs_align->getSelected()); }); + + // Set font size. +// auto ss_omx_font_size = std::make_shared(mWindow, 1.f, 64.f, 1.f, "h"); +// ss_omx_font_size->setValue((float)(Settings::getInstance()->getInt("SubtitleSize"))); +// addWithLabel("GAME INFO FONT SIZE", ss_omx_font_size); +// addSaveFunc([ss_omx_font_size] { +// int subSize = (int)Math::round(ss_omx_font_size->getValue()); +// Settings::getInstance()->setInt("SubtitleSize", subSize); +// }); + #endif + + auto screensaver_video_audio = std::make_shared(mWindow); + screensaver_video_audio->setState(Settings::getInstance()->getBool("ScreensaverVideoAudio")); + s->addWithLabel("PLAY AUDIO FOR SCREENSAVER VIDEO FILES", screensaver_video_audio); + s->addSaveFunc([screensaver_video_audio, s] { + if (screensaver_video_audio->getState() != + Settings::getInstance()->getBool("ScreensaverVideoAudio")) { + Settings::getInstance()->setBool("ScreensaverVideoAudio", + screensaver_video_audio->getState()); + s->setNeedsSaving(); + } + }); + + + #if defined(USE_OPENGL_21) + // Render scanlines using a shader. + auto screensaver_video_scanlines = std::make_shared(mWindow); + screensaver_video_scanlines-> + setState(Settings::getInstance()->getBool("ScreensaverVideoScanlines")); + s->addWithLabel("RENDER SCANLINES", screensaver_video_scanlines); + s->addSaveFunc([screensaver_video_scanlines, s] { + if (screensaver_video_scanlines->getState() != + Settings::getInstance()->getBool("ScreensaverVideoScanlines")) { + Settings::getInstance()->setBool("ScreensaverVideoScanlines", + screensaver_video_scanlines->getState()); + s->setNeedsSaving(); + } + }); + + // Render blur using a shader. + auto screensaver_video_blur = std::make_shared(mWindow); + screensaver_video_blur->setState(Settings::getInstance()->getBool("ScreensaverVideoBlur")); + s->addWithLabel("RENDER BLUR", screensaver_video_blur); + s->addSaveFunc([screensaver_video_blur, s] { + if (screensaver_video_blur->getState() != + Settings::getInstance()->getBool("ScreensaverVideoBlur")) { + Settings::getInstance()->setBool("ScreensaverVideoBlur", + screensaver_video_blur->getState()); + s->setNeedsSaving(); + } + }); + #endif + + mWindow->pushGui(s); } diff --git a/es-app/src/guis/GuiGeneralScreensaverOptions.h b/es-app/src/guis/GuiGeneralScreensaverOptions.h index 9bf94412d..817550ad0 100644 --- a/es-app/src/guis/GuiGeneralScreensaverOptions.h +++ b/es-app/src/guis/GuiGeneralScreensaverOptions.h @@ -4,24 +4,22 @@ // GuiGeneralScreensaverOptions.h // // User interface for the screensaver options. -// Based on the GuiScreenSaverOptions template. // Submenu to the GuiMenu main menu. // #ifndef ES_APP_GUIS_GUI_GENERAL_SCREENSAVER_OPTIONS_H #define ES_APP_GUIS_GUI_GENERAL_SCREENSAVER_OPTIONS_H -#include "GuiScreensaverOptions.h" +#include "guis/GuiSettings.h" -class GuiGeneralScreensaverOptions : public GuiScreensaverOptions +class GuiGeneralScreensaverOptions : public GuiSettings { public: GuiGeneralScreensaverOptions(Window* window, const char* title); - virtual ~GuiGeneralScreensaverOptions(); private: - void openVideoScreensaverOptions(); void openSlideshowScreensaverOptions(); + void openVideoScreensaverOptions(); }; #endif // ES_APP_GUIS_GUI_GENERAL_SCREENSAVER_OPTIONS_H diff --git a/es-app/src/guis/GuiMenu.cpp b/es-app/src/guis/GuiMenu.cpp index 374f59f61..84c633f6a 100644 --- a/es-app/src/guis/GuiMenu.cpp +++ b/es-app/src/guis/GuiMenu.cpp @@ -79,6 +79,341 @@ void GuiMenu::openScraperSettings() mWindow->pushGui(new GuiScraperMenu(mWindow)); } +void GuiMenu::openUISettings() +{ + auto s = new GuiSettings(mWindow, "UI SETTINGS"); + + // Optionally start in selected system/gamelist. + auto startup_system = std::make_shared> + (mWindow, getHelpStyle(), "GAMELIST ON STARTUP", false); + startup_system->add("NONE", "", Settings::getInstance()->getString("StartupSystem") == ""); + for (auto it = SystemData::sSystemVector.cbegin(); + it != SystemData::sSystemVector.cend(); it++) { + if ("retropie" != (*it)->getName()) { + startup_system->add((*it)->getName(), (*it)->getName(), + Settings::getInstance()->getString("StartupSystem") == (*it)->getName()); + } + } + s->addWithLabel("GAMELIST TO SHOW ON STARTUP", startup_system); + s->addSaveFunc([startup_system, s] { + if (startup_system->getSelected() != Settings::getInstance()->getString("StartupSystem")) { + Settings::getInstance()->setString("StartupSystem", startup_system->getSelected()); + s->setNeedsSaving(); + } + }); + + // GameList view style. + auto gamelist_view_style = std::make_shared> + (mWindow, getHelpStyle(), "GAMELIST VIEW STYLE", false); + std::vector styles; + styles.push_back("automatic"); + styles.push_back("basic"); + styles.push_back("detailed"); + styles.push_back("video"); + styles.push_back("grid"); + for (auto it = styles.cbegin(); it != styles.cend(); it++) + gamelist_view_style->add(*it, *it, Settings::getInstance()-> + getString("GamelistViewStyle") == *it); + s->addWithLabel("GAMELIST VIEW STYLE", gamelist_view_style); + s->addSaveFunc([gamelist_view_style, s] { + if (gamelist_view_style->getSelected() != + Settings::getInstance()->getString("GamelistViewStyle")) { + Settings::getInstance()->setString("GamelistViewStyle", + gamelist_view_style->getSelected()); + s->setNeedsSaving(); + s->setNeedsReloading(); + } + }); + + // Transition style. + auto transition_style = std::make_shared> + (mWindow, getHelpStyle(), "TRANSITION STYLE", false); + std::vector transitions; + transitions.push_back("fade"); + transitions.push_back("slide"); + transitions.push_back("instant"); + for (auto it = transitions.cbegin(); it != transitions.cend(); it++) + transition_style->add(*it, *it, Settings::getInstance()-> + getString("TransitionStyle") == *it); + s->addWithLabel("TRANSITION STYLE", transition_style); + s->addSaveFunc([transition_style, s] { + if (transition_style->getSelected() != + Settings::getInstance()->getString("TransitionStyle")) { + Settings::getInstance()->setString("TransitionStyle", transition_style->getSelected()); + s->setNeedsSaving(); + } + }); + + // Theme selection. + auto themeSets = ThemeData::getThemeSets(); + if (!themeSets.empty()) { + std::map::const_iterator selectedSet = + themeSets.find(Settings::getInstance()->getString("ThemeSet")); + if (selectedSet == themeSets.cend()) + selectedSet = themeSets.cbegin(); + auto theme_set = std::make_shared> + (mWindow, getHelpStyle(), "THEME SET", false); + for (auto it = themeSets.cbegin(); it != themeSets.cend(); it++) + theme_set->add(it->first, it->first, it == selectedSet); + s->addWithLabel("THEME SET", theme_set); + s->addSaveFunc([theme_set, s] { + if (theme_set->getSelected() != Settings::getInstance()->getString("ThemeSet")) { + Scripting::fireEvent("theme-changed", theme_set->getSelected(), + Settings::getInstance()->getString("ThemeSet")); + CollectionSystemManager::get()->updateSystemsList(); + Settings::getInstance()->setString("ThemeSet", theme_set->getSelected()); + s->setNeedsSaving(); + s->setNeedsGoToStart(); + s->setNeedsReloading(); + } + }); + } + + // UI mode. + auto ui_mode = std::make_shared> + (mWindow, getHelpStyle(), "UI MODE", false); + std::vector uiModes; + uiModes.push_back("full"); + uiModes.push_back("kiosk"); + uiModes.push_back("kid"); + for (auto it = uiModes.cbegin(); it != uiModes.cend(); it++) + ui_mode->add(*it, *it, Settings::getInstance()->getString("UIMode") == *it); + s->addWithLabel("UI MODE", ui_mode); + s->addSaveFunc([ui_mode, this, s] { + std::string selectedMode = ui_mode->getSelected(); + if (selectedMode != Settings::getInstance()->getString("UIMode") && + selectedMode != "full") { + std::string msg = "YOU ARE CHANGING THE UI TO A RESTRICTED MODE:\n'" + + Utils::String::toUpper(selectedMode) + "'\n"; + msg += "THIS WILL HIDE MOST MENU OPTIONS TO PREVENT CHANGES TO THE SYSTEM.\n"; + msg += "TO UNLOCK AND RETURN TO THE FULL UI, ENTER THIS CODE: \n"; + msg += "\"" + UIModeController::getInstance()->getFormattedPassKeyStr() + "\"\n\n"; + msg += "DO YOU WANT TO PROCEED?"; + mWindow->pushGui(new GuiMsgBox(mWindow, this->getHelpStyle(), msg, + "YES", [selectedMode, s] { + LOG(LogDebug) << "GuiMenu::openUISettings(): Setting UI mode to '" + << selectedMode << "'."; + Settings::getInstance()->setString("UIMode", selectedMode); + Settings::getInstance()->saveFile(); + }, "NO", nullptr)); + } + else if (ui_mode->getSelected() != Settings::getInstance()->getString("UIMode") && + selectedMode == "full") { + LOG(LogDebug) << "GuiMenu::openUISettings(): Setting UI mode to '" << + selectedMode << "'."; + Settings::getInstance()->setString("UIMode", ui_mode->getSelected()); + s->setNeedsSaving(); + } + }); + + // Default gamelist sort order. + typedef OptionListComponent SortList; + std::string sortOrder; + auto default_sort_order = std::make_shared + (mWindow, getHelpStyle(), "DEFAULT SORT ORDER", false); + for (auto it = FileSorts::SortTypes.cbegin(); it != FileSorts::SortTypes.cend(); it++) { + if (it->description == Settings::getInstance()->getString("DefaultSortOrder")) { + sortOrder = it->description; + break; + } + } + // If an invalid sort order was defined in es_settings.cfg, then apply the default + // sort order 'filename, ascending'. + if (sortOrder == "") + sortOrder = "filename, ascending"; + for (auto it = FileSorts::SortTypes.cbegin(); it != FileSorts::SortTypes.cend(); it++) { + const FileData::SortType& sort = *it; + if (sort.description == sortOrder) + default_sort_order->add(sort.description, &sort, true); + else + default_sort_order->add(sort.description, &sort, false); + } + s->addWithLabel("DEFAULT SORT ORDER", default_sort_order); + s->addSaveFunc([default_sort_order, sortOrder, s] { + std::string selectedSortOrder = default_sort_order.get()->getSelected()->description; + if (selectedSortOrder != sortOrder) { + Settings::getInstance()->setString("DefaultSortOrder", selectedSortOrder); + s->setNeedsSaving(); + s->setNeedsSorting(); + s->setNeedsSortingCollections(); + } + }); + + #if defined(USE_OPENGL_21) + // Open menu effect. + auto menu_opening_effect = std::make_shared> + (mWindow, getHelpStyle(), "MENU OPENING EFFECT", false); + std::vector menu_effects; + menu_effects.push_back("scale-up"); + menu_effects.push_back("fade-in"); + menu_effects.push_back("none"); + for (auto it = menu_effects.cbegin(); it != menu_effects.cend(); it++) + menu_opening_effect->add(*it, *it, Settings::getInstance()-> + getString("MenuOpeningEffect") == *it); + s->addWithLabel("MENU OPENING EFFECT", menu_opening_effect); + s->addSaveFunc([menu_opening_effect, s] { + if (menu_opening_effect->getSelected() != + Settings::getInstance()->getString("MenuOpeningEffect")) { + Settings::getInstance()->setString("MenuOpeningEffect", + menu_opening_effect->getSelected()); + s->setNeedsSaving(); + } + }); + #endif + + // Carousel transitions. + auto carousel_transitions = std::make_shared(mWindow); + carousel_transitions->setState(Settings::getInstance()->getBool("CarouselTransitions")); + s->addWithLabel("DISPLAY CAROUSEL TRANSITIONS", carousel_transitions); + s->addSaveFunc([carousel_transitions, s] { + if (carousel_transitions->getState() != + Settings::getInstance()->getBool("CarouselTransitions")) { + Settings::getInstance()->setBool("CarouselTransitions", + carousel_transitions->getState()); + s->setNeedsSaving(); + } + }); + + #if defined(USE_OPENGL_21) + // Render scanlines for videos in the gamelists. + auto gamelist_video_scanlines = std::make_shared(mWindow); + gamelist_video_scanlines->setState(Settings::getInstance()->getBool("GamelistVideoScanlines")); + s->addWithLabel("RENDER SCANLINES FOR GAMELIST VIDEOS", gamelist_video_scanlines); + s->addSaveFunc([gamelist_video_scanlines, s] { + if (gamelist_video_scanlines->getState() != + Settings::getInstance()->getBool("GamelistVideoScanlines")) { + Settings::getInstance()->setBool("GamelistVideoScanlines", + gamelist_video_scanlines->getState()); + s->setNeedsSaving(); + } + }); + #endif + + // Sort folders on top of the gamelists. + auto folders_on_top = std::make_shared(mWindow); + folders_on_top->setState(Settings::getInstance()->getBool("FoldersOnTop")); + s->addWithLabel("SORT FOLDERS ON TOP OF GAMELISTS", folders_on_top); + s->addSaveFunc([folders_on_top, s] { + if (folders_on_top->getState() != + Settings::getInstance()->getBool("FoldersOnTop")) { + Settings::getInstance()->setBool("FoldersOnTop", folders_on_top->getState()); + s->setNeedsSaving(); + s->setNeedsSorting(); + } + }); + + // Sort favorites on top of non-favorites in the gamelists. + auto favorites_first = std::make_shared(mWindow); + favorites_first->setState(Settings::getInstance()->getBool("FavoritesFirst")); + s->addWithLabel("SORT FAVORITE GAMES ABOVE NON-FAVORITES", favorites_first); + s->addSaveFunc([favorites_first,s ] { + if (favorites_first->getState() != + Settings::getInstance()->getBool("FavoritesFirst")) { + Settings::getInstance()->setBool("FavoritesFirst", favorites_first->getState()); + s->setNeedsSaving(); + s->setNeedsSorting(); + s->setNeedsSortingCollections(); + } + }); + + // Enable gamelist star markings for favorite games. + auto favorites_star = std::make_shared(mWindow); + favorites_star->setState(Settings::getInstance()->getBool("FavoritesStar")); + s->addWithLabel("ADD STAR MARKINGS TO FAVORITE GAMES", favorites_star); + s->addSaveFunc([favorites_star, s] { + if (favorites_star->getState() != Settings::getInstance()->getBool("FavoritesStar")) { + Settings::getInstance()->setBool("FavoritesStar", favorites_star->getState()); + s->setNeedsSaving(); + s->setNeedsReloading(); + } + }); + + // 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->addSaveFunc([favorites_add_button, s] { + if (Settings::getInstance()->getBool("FavoritesAddButton") != + favorites_add_button->getState()) { + Settings::getInstance()->setBool("FavoritesAddButton", + favorites_add_button->getState()); + s->setNeedsSaving(); + } + }); + + // Gamelist filters. + auto gamelist_filters = std::make_shared(mWindow); + gamelist_filters->setState(Settings::getInstance()->getBool("GamelistFilters")); + s->addWithLabel("ENABLE GAMELIST FILTERS", gamelist_filters); + s->addSaveFunc([gamelist_filters, s] { + if (Settings::getInstance()->getBool("GamelistFilters") != + gamelist_filters->getState()) { + Settings::getInstance()->setBool("GamelistFilters", gamelist_filters->getState()); + s->setNeedsSaving(); + s->setNeedsReloading(); + } + }); + + // Quick system select (navigate left/right in gamelist view). + auto quick_system_select = std::make_shared(mWindow); + quick_system_select->setState(Settings::getInstance()->getBool("QuickSystemSelect")); + s->addWithLabel("ENABLE QUICK SYSTEM SELECT", quick_system_select); + s->addSaveFunc([quick_system_select, s] { + if (Settings::getInstance()->getBool("QuickSystemSelect") != + quick_system_select->getState()) { + Settings::getInstance()->setBool("QuickSystemSelect", quick_system_select->getState()); + s->setNeedsSaving(); + } + }); + + // On-screen help prompts. + auto show_help_prompts = std::make_shared(mWindow); + show_help_prompts->setState(Settings::getInstance()->getBool("ShowHelpPrompts")); + s->addWithLabel("DISPLAY ON-SCREEN HELP", show_help_prompts); + s->addSaveFunc([show_help_prompts, s] { + if (Settings::getInstance()->getBool("ShowHelpPrompts") != show_help_prompts->getState()) { + Settings::getInstance()->setBool("ShowHelpPrompts", show_help_prompts->getState()); + s->setNeedsSaving(); + } + }); + + // Play videos immediately (overrides theme setting). + auto play_videos_immediately = std::make_shared(mWindow); + play_videos_immediately->setState(Settings::getInstance()->getBool("PlayVideosImmediately")); + s->addWithLabel("PLAY VIDEOS IMMEDIATELY (OVERRIDE THEME)", play_videos_immediately); + s->addSaveFunc([play_videos_immediately, s] { + if (Settings::getInstance()->getBool("PlayVideosImmediately") != + play_videos_immediately->getState()) { + Settings::getInstance()->setBool("PlayVideosImmediately", + play_videos_immediately->getState()); + s->setNeedsSaving(); + } + }); + + // Whether to show start menu in Kid mode. + auto show_kid_start_menu = std::make_shared(mWindow); + show_kid_start_menu->setState(Settings::getInstance()->getBool("ShowKidStartMenu")); + s->addWithLabel("SHOW START MENU IN KID MODE", show_kid_start_menu); + s->addSaveFunc([show_kid_start_menu, s] { + if (Settings::getInstance()->getBool("ShowKidStartMenu") != + show_kid_start_menu->getState()) { + Settings::getInstance()->setBool("ShowKidStartMenu", show_kid_start_menu->getState()); + s->setNeedsSaving(); + } + }); + + // Screensaver. + ComponentListRow screensaver_row; + screensaver_row.elements.clear(); + screensaver_row.addElement(std::make_shared + (mWindow, "SCREENSAVER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); + screensaver_row.addElement(makeArrow(mWindow), false); + screensaver_row.makeAcceptInputHandler(std::bind(&GuiMenu::openScreensaverOptions, this)); + s->addRow(screensaver_row); + + mWindow->pushGui(s); +} + void GuiMenu::openSoundSettings() { auto s = new GuiSettings(mWindow, "SOUND SETTINGS"); @@ -87,11 +422,13 @@ void GuiMenu::openSoundSettings() // has been implemented for this operating system. #if !defined(__APPLE__) // System volume. - auto volume = std::make_shared(mWindow, 0.f, 100.f, 1.f, "%"); - volume->setValue((float)VolumeControl::getInstance()->getVolume()); - s->addWithLabel("SYSTEM VOLUME", volume); - s->addSaveFunc([volume] { VolumeControl::getInstance()-> - setVolume((int)Math::round(volume->getValue())); }); + auto system_volume = std::make_shared(mWindow, 0.f, 100.f, 1.f, "%"); + system_volume->setValue(static_cast(VolumeControl::getInstance()->getVolume())); + s->addWithLabel("SYSTEM VOLUME", system_volume); + s->addSaveFunc([system_volume] { + VolumeControl::getInstance()-> + setVolume(static_cast(Math::round(system_volume->getValue()))); + }); #endif if (UIModeController::getInstance()->isUIModeFull()) { @@ -104,12 +441,12 @@ void GuiMenu::openSoundSettings() // useful for that device. // #if defined(__linux__) #if defined(_RPI_) - // audio card + // Audio card. auto audio_card = std::make_shared> (mWindow, getHelpStyle(), "AUDIO CARD", false); std::vector audio_cards; #if defined(_RPI_) - // RPi Specific Audio Cards + // RPi Specific Audio Cards. audio_cards.push_back("local"); audio_cards.push_back("hdmi"); audio_cards.push_back("both"); @@ -129,10 +466,13 @@ void GuiMenu::openSoundSettings() for (auto ac = audio_cards.cbegin(); ac != audio_cards.cend(); ac++) audio_card->add(*ac, *ac, Settings::getInstance()->getString("AudioCard") == *ac); s->addWithLabel("AUDIO CARD", audio_card); - s->addSaveFunc([audio_card] { - Settings::getInstance()->setString("AudioCard", audio_card->getSelected()); - VolumeControl::getInstance()->deinit(); - VolumeControl::getInstance()->init(); + s->addSaveFunc([audio_card, s] { + if (audio_card->getSelected() != Settings::getInstance()->getString("AudioCard")) { + Settings::getInstance()->setString("AudioCard", audio_card->getSelected()); + VolumeControl::getInstance()->deinit(); + VolumeControl::getInstance()->init(); + s->setNeedsSaving(); + } }); // Volume control device. @@ -153,10 +493,13 @@ void GuiMenu::openSoundSettings() for (auto it = transitions.cbegin(); it != transitions.cend(); it++) vol_dev->add(*it, *it, Settings::getInstance()->getString("AudioDevice") == *it); s->addWithLabel("AUDIO DEVICE", vol_dev); - s->addSaveFunc([vol_dev] { - Settings::getInstance()->setString("AudioDevice", vol_dev->getSelected()); - VolumeControl::getInstance()->deinit(); - VolumeControl::getInstance()->init(); + s->addSaveFunc([vol_dev, s] { + if (vol_dev->getSelected() != Settings::getInstance()->getString("AudioDevice")) { + Settings::getInstance()->setString("AudioDevice", vol_dev->getSelected()); + VolumeControl::getInstance()->deinit(); + VolumeControl::getInstance()->init(); + s->setNeedsSaving(); + } }); #endif @@ -180,380 +523,43 @@ void GuiMenu::openSoundSettings() for (auto it = omx_cards.cbegin(); it != omx_cards.cend(); it++) omx_audio_dev->add(*it, *it, Settings::getInstance()->getString("OMXAudioDev") == *it); s->addWithLabel("OMX PLAYER AUDIO DEVICE", omx_audio_dev); - s->addSaveFunc([omx_audio_dev] { - if (Settings::getInstance()->getString("OMXAudioDev") != omx_audio_dev->getSelected()) + s->addSaveFunc([omx_audio_dev, s] { + if (omx_audio_dev->getSelected() != + Settings::getInstance()->getString("OMXAudioDev")) { Settings::getInstance()->setString("OMXAudioDev", omx_audio_dev->getSelected()); + s->setNeedsSaving(); + } }); #endif // Video audio. - auto video_audio = std::make_shared(mWindow); - video_audio->setState(Settings::getInstance()->getBool("GamelistVideoAudio")); - s->addWithLabel("PLAY AUDIO FOR VIDEO FILES IN GAMELIST VIEWS", video_audio); - s->addSaveFunc([video_audio] { Settings::getInstance()->setBool("GamelistVideoAudio", - video_audio->getState()); }); + auto gamelist_video_audio = std::make_shared(mWindow); + gamelist_video_audio->setState(Settings::getInstance()->getBool("GamelistVideoAudio")); + s->addWithLabel("PLAY AUDIO FOR VIDEO FILES IN GAMELIST VIEWS", gamelist_video_audio); + s->addSaveFunc([gamelist_video_audio, s] { + if (gamelist_video_audio->getState() != + Settings::getInstance()->getBool("GamelistVideoAudio")) { + Settings::getInstance()->setBool("GamelistVideoAudio", + gamelist_video_audio->getState()); + s->setNeedsSaving(); + } + }); // Navigation sounds. auto navigation_sounds = std::make_shared(mWindow); navigation_sounds->setState(Settings::getInstance()-> getBool("NavigationSounds")); s->addWithLabel("ENABLE NAVIGATION SOUNDS", navigation_sounds); - s->addSaveFunc([navigation_sounds] { - if (navigation_sounds->getState() && - !Settings::getInstance()->getBool("NavigationSounds") && - PowerSaver::getMode() == PowerSaver::INSTANT) { - Settings::getInstance()->setString("PowerSaverMode", "default"); - PowerSaver::init(); - } - Settings::getInstance()->setBool("NavigationSounds", - navigation_sounds->getState()); - }); - } - - mWindow->pushGui(s); -} - -void GuiMenu::openUISettings() -{ - auto s = new GuiSettings(mWindow, "UI SETTINGS"); - - // Optionally start in selected system/gamelist. - auto systemfocus_list = std::make_shared> - (mWindow, getHelpStyle(), "GAMELIST ON STARTUP", false); - systemfocus_list->add("NONE", "", Settings::getInstance()->getString("StartupSystem") == ""); - for (auto it = SystemData::sSystemVector.cbegin(); - it != SystemData::sSystemVector.cend(); it++) { - if ("retropie" != (*it)->getName()) { - systemfocus_list->add((*it)->getName(), (*it)->getName(), - Settings::getInstance()->getString("StartupSystem") == (*it)->getName()); - } - } - s->addWithLabel("GAMELIST TO SHOW ON STARTUP", systemfocus_list); - s->addSaveFunc([systemfocus_list] { - Settings::getInstance()->setString("StartupSystem", systemfocus_list->getSelected()); - }); - - // GameList view style. - auto gamelist_style = std::make_shared> - (mWindow, getHelpStyle(), "GAMELIST VIEW STYLE", false); - std::vector styles; - styles.push_back("automatic"); - styles.push_back("basic"); - styles.push_back("detailed"); - styles.push_back("video"); - styles.push_back("grid"); - - for (auto it = styles.cbegin(); it != styles.cend(); it++) - gamelist_style->add(*it, *it, Settings::getInstance()-> - getString("GamelistViewStyle") == *it); - s->addWithLabel("GAMELIST VIEW STYLE", gamelist_style); - s->addSaveFunc([gamelist_style, this] { - bool needReload = false; - if (Settings::getInstance()->getString("GamelistViewStyle") != - gamelist_style->getSelected()) - needReload = true; - Settings::getInstance()->setString("GamelistViewStyle", gamelist_style->getSelected()); - mWindow->invalidateCachedBackground(); - if (needReload) - ViewController::get()->reloadAll(); - }); - - // Transition style. - auto transition_style = std::make_shared> - (mWindow, getHelpStyle(), "TRANSITION STYLE", false); - std::vector transitions; - transitions.push_back("fade"); - transitions.push_back("slide"); - transitions.push_back("instant"); - for (auto it = transitions.cbegin(); it != transitions.cend(); it++) - transition_style->add(*it, *it, Settings::getInstance()-> - getString("TransitionStyle") == *it); - s->addWithLabel("TRANSITION STYLE", transition_style); - s->addSaveFunc([transition_style] { - if (Settings::getInstance()->getString("TransitionStyle") == "instant" && - transition_style->getSelected() != "instant" && - PowerSaver::getMode() == PowerSaver::INSTANT) { - Settings::getInstance()->setString("PowerSaverMode", "default"); - PowerSaver::init(); - } - Settings::getInstance()->setString("TransitionStyle", transition_style->getSelected()); - }); - - // Theme selection. - auto themeSets = ThemeData::getThemeSets(); - - if (!themeSets.empty()) { - std::map::const_iterator selectedSet = - themeSets.find(Settings::getInstance()->getString("ThemeSet")); - if (selectedSet == themeSets.cend()) - selectedSet = themeSets.cbegin(); - - auto theme_set = std::make_shared> - (mWindow, getHelpStyle(), "THEME SET", false); - for (auto it = themeSets.cbegin(); it != themeSets.cend(); it++) - theme_set->add(it->first, it->first, it == selectedSet); - s->addWithLabel("THEME SET", theme_set); - - Window* window = mWindow; - s->addSaveFunc([window, theme_set] { - bool needReload = false; - std::string oldTheme = Settings::getInstance()->getString("ThemeSet"); - if (oldTheme != theme_set->getSelected()) - needReload = true; - - Settings::getInstance()->setString("ThemeSet", theme_set->getSelected()); - - if (needReload) { - Scripting::fireEvent("theme-changed", theme_set->getSelected(), oldTheme); - CollectionSystemManager::get()->updateSystemsList(); - ViewController::get()->goToStart(); - // TODO - replace this with some sort of signal-based implementation. - ViewController::get()->reloadAll(); + s->addSaveFunc([navigation_sounds, s] { + if (navigation_sounds->getState() != + Settings::getInstance()->getBool("NavigationSounds")) { + Settings::getInstance()->setBool("NavigationSounds", + navigation_sounds->getState()); + s->setNeedsSaving(); } }); } - // UI mode. - auto UImodeSelection = std::make_shared> - (mWindow, getHelpStyle(), "UI MODE", false); - std::vector UImodes = UIModeController::getInstance()->getUIModes(); - for (auto it = UImodes.cbegin(); it != UImodes.cend(); it++) - UImodeSelection->add(*it, *it, Settings::getInstance()->getString("UIMode") == *it); - s->addWithLabel("UI MODE", UImodeSelection); - Window* window = mWindow; - s->addSaveFunc([ UImodeSelection, window, this] { - std::string selectedMode = UImodeSelection->getSelected(); - if (selectedMode != "full") { - std::string msg = "YOU ARE CHANGING THE UI TO A RESTRICTED MODE:\n\"" + - Utils::String::toUpper(selectedMode) + "\"\n"; - msg += "THIS WILL HIDE MOST MENU OPTIONS TO PREVENT CHANGES TO THE SYSTEM.\n"; - msg += "TO UNLOCK AND RETURN TO THE FULL UI, ENTER THIS CODE: \n"; - msg += "\"" + UIModeController::getInstance()->getFormattedPassKeyStr() + "\"\n\n"; - msg += "DO YOU WANT TO PROCEED?"; - window->pushGui(new GuiMsgBox(window, this->getHelpStyle(), msg, - "YES", [selectedMode] { - LOG(LogDebug) << "Setting UI mode to " << selectedMode; - Settings::getInstance()->setString("UIMode", selectedMode); - Settings::getInstance()->saveFile(); - }, "NO",nullptr)); - } - }); - - // Default gamelist sort order. - typedef OptionListComponent SortList; - std::string sortOrder; - auto defaultSortOrder = std::make_shared - (mWindow, getHelpStyle(), "DEFAULT SORT ORDER", false); - for (auto it = FileSorts::SortTypes.cbegin(); it != FileSorts::SortTypes.cend(); it++) { - if (it->description == Settings::getInstance()->getString("DefaultSortOrder")) { - sortOrder = it->description; - break; - } - } - // If an invalid sort order was defined in es_settings.cfg, then apply the default - // sort order 'filename, ascending'. - if (sortOrder == "") - sortOrder = "filename, ascending"; - - for (auto it = FileSorts::SortTypes.cbegin(); it != FileSorts::SortTypes.cend(); it++) { - const FileData::SortType& sort = *it; - if (sort.description == sortOrder) - defaultSortOrder->add(sort.description, &sort, true); - else - defaultSortOrder->add(sort.description, &sort, false); - } - s->addWithLabel("DEFAULT SORT ORDER", defaultSortOrder); - s->addSaveFunc([defaultSortOrder, sortOrder, this] { - std::string selectedSortOrder = defaultSortOrder.get()->getSelected()->description; - if (selectedSortOrder != sortOrder) { - Settings::getInstance()->setString("DefaultSortOrder", selectedSortOrder); - - // Activate the new sort order by setting up the sort type per system - // and then resorting all gamelists. - for (auto it = SystemData::sSystemVector.cbegin(); it != - SystemData::sSystemVector.cend(); it++) { - - (*it)->sortSystem(); - - // Jump to the first row of the gamelist. - IGameListView* gameList = ViewController::get()->getGameListView((*it)).get(); - gameList->setCursor(gameList->getFirstEntry()); - } - mWindow->invalidateCachedBackground(); - } - }); - - #if defined(USE_OPENGL_21) - // Open menu effect. - auto open_menu_effect = std::make_shared> - (mWindow, getHelpStyle(), "MENU OPENING EFFECT", false); - std::vector menu_effects; - menu_effects.push_back("scale-up"); - menu_effects.push_back("fade-in"); - menu_effects.push_back("none"); - - for (auto it = menu_effects.cbegin(); it != menu_effects.cend(); it++) - open_menu_effect->add(*it, *it, Settings::getInstance()-> - getString("MenuOpeningEffect") == *it); - s->addWithLabel("MENU OPENING EFFECT", open_menu_effect); - s->addSaveFunc([open_menu_effect] { - bool needReload = false; - if (Settings::getInstance()->getString("MenuOpeningEffect") != - open_menu_effect->getSelected()) - needReload = true; - Settings::getInstance()->setString("MenuOpeningEffect", open_menu_effect->getSelected()); - if (needReload) - ViewController::get()->reloadAll(); - }); - #endif - - // Carousel transition option. - auto move_carousel = std::make_shared(mWindow); - move_carousel->setState(Settings::getInstance()->getBool("MoveCarousel")); - s->addWithLabel("DISPLAY CAROUSEL TRANSITIONS", move_carousel); - s->addSaveFunc([move_carousel] { - if (move_carousel->getState() && - !Settings::getInstance()->getBool("MoveCarousel") && - PowerSaver::getMode() == PowerSaver::INSTANT) { - Settings::getInstance()->setString("PowerSaverMode", "default"); - PowerSaver::init(); - } - Settings::getInstance()->setBool("MoveCarousel", move_carousel->getState()); - }); - - #if defined(USE_OPENGL_21) - // Render scanlines for videos in the gamelists using a shader. - auto render_video_scanlines = std::make_shared(mWindow); - render_video_scanlines->setState(Settings::getInstance()->getBool("GamelistVideoScanlines")); - s->addWithLabel("RENDER SCANLINES FOR GAMELIST VIDEOS", render_video_scanlines); - s->addSaveFunc([render_video_scanlines] { - Settings::getInstance()->setBool("GamelistVideoScanlines", - render_video_scanlines->getState()); }); - #endif - - // Sort folders on top of the gamelists. - auto folders_on_top = std::make_shared(mWindow); - folders_on_top->setState(Settings::getInstance()->getBool("FoldersOnTop")); - s->addWithLabel("SORT FOLDERS ON TOP OF GAMELISTS", folders_on_top); - s->addSaveFunc([folders_on_top] { - if (Settings::getInstance()->setBool("FoldersOnTop", folders_on_top->getState())) - for (auto it = SystemData::sSystemVector.cbegin(); it != - SystemData::sSystemVector.cend(); it++) { - - if ((*it)->isCollection()) - continue; - - FileData* rootFolder = (*it)->getRootFolder(); - rootFolder->sort(rootFolder->getSortTypeFromString(rootFolder->getSortTypeString()), - Settings::getInstance()->getBool("FavoritesFirst")); - ViewController::get()->reloadGameListView(*it); - - // Jump to the first row of the gamelist. - IGameListView* gameList = ViewController::get()->getGameListView((*it)).get(); - gameList->setCursor(gameList->getFirstEntry()); - } - }); - - // Sort favorites on top of non-favorites in the gamelists. - auto favorites_first = std::make_shared(mWindow); - favorites_first->setState(Settings::getInstance()->getBool("FavoritesFirst")); - s->addWithLabel("SORT FAVORITE GAMES ABOVE NON-FAVORITES", favorites_first); - s->addSaveFunc([favorites_first] { - if (Settings::getInstance()->setBool("FavoritesFirst", favorites_first->getState())) - for (auto it = SystemData::sSystemVector.cbegin(); it != - SystemData::sSystemVector.cend(); it++) { - // The favorites and recent gamelists never sort favorites on top. - if ((*it)->getName() == "favorites" || (*it)->getName() == "recent" || - (*it)->getName() == "collections") - continue; - // Don't re-sort custom collections as they have their own option - // for whether to sort favorites on top or not (FavFirstCustom). - if ((*it)->isCustomCollection()) - continue; - - FileData* rootFolder = (*it)->getRootFolder(); - rootFolder->sort(rootFolder->getSortTypeFromString(rootFolder->getSortTypeString()), - Settings::getInstance()->getBool("FavoritesFirst")); - ViewController::get()->reloadGameListView(*it); - - // Jump to the first row of the gamelist. - IGameListView* gameList = ViewController::get()->getGameListView((*it)).get(); - gameList->setCursor(gameList->getFirstEntry()); - } - }); - - // Enable gamelist star markings for favorite games. - auto favorites_stars = std::make_shared(mWindow); - favorites_stars->setState(Settings::getInstance()->getBool("FavoritesStar")); - s->addWithLabel("ADD STAR MARKINGS TO FAVORITE GAMES", favorites_stars); - s->addSaveFunc([favorites_stars] { - if (Settings::getInstance()->getBool("FavoritesStar") != favorites_stars->getState()) { - Settings::getInstance()->setBool("FavoritesStar", favorites_stars->getState()); - ViewController::get()->reloadAll(); - } - }); - - // 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->addSaveFunc([favorites_add_button] { - if (Settings::getInstance()->getBool("FavoritesAddButton") != - favorites_add_button->getState()) { - Settings::getInstance()->setBool("FavoritesAddButton", - favorites_add_button->getState()); - } - }); - - // Enable filters (ForceDisableFilters). - auto enable_filter = std::make_shared(mWindow); - enable_filter->setState(!Settings::getInstance()->getBool("ForceDisableFilters")); - s->addWithLabel("ENABLE GAMELIST FILTERS", enable_filter); - s->addSaveFunc([enable_filter] { - bool filter_is_enabled = !Settings::getInstance()->getBool("ForceDisableFilters"); - Settings::getInstance()->setBool("ForceDisableFilters", !enable_filter->getState()); - if (enable_filter->getState() != filter_is_enabled) - ViewController::get()->ReloadAndGoToStart(); - }); - - // Quick system select (left/right in game list view). - auto quick_sys_select = std::make_shared(mWindow); - quick_sys_select->setState(Settings::getInstance()->getBool("QuickSystemSelect")); - s->addWithLabel("ENABLE QUICK SYSTEM SELECT", quick_sys_select); - s->addSaveFunc([quick_sys_select] { Settings::getInstance()->setBool("QuickSystemSelect", - quick_sys_select->getState()); }); - - // Show help. - auto show_help = std::make_shared(mWindow); - show_help->setState(Settings::getInstance()->getBool("ShowHelpPrompts")); - s->addWithLabel("DISPLAY ON-SCREEN HELP", show_help); - s->addSaveFunc([show_help] { Settings::getInstance()->setBool("ShowHelpPrompts", - show_help->getState()); }); - - // Play videos immediately (overrides theme setting). - auto play_videos_immediately = std::make_shared(mWindow); - play_videos_immediately->setState(Settings::getInstance()->getBool("PlayVideosImmediately")); - s->addWithLabel("PLAY VIDEOS IMMEDIATELY (OVERRIDE THEME)", play_videos_immediately); - s->addSaveFunc([play_videos_immediately] { - Settings::getInstance()->setBool("PlayVideosImmediately", - play_videos_immediately->getState()); }); - - // Whether to show start menu in Kid Mode. - auto show_kidstartmenu = std::make_shared(mWindow); - show_kidstartmenu->setState(Settings::getInstance()->getBool("ShowKidStartMenu")); - s->addWithLabel("SHOW START MENU IN KID MODE", show_kidstartmenu); - s->addSaveFunc([show_kidstartmenu] { Settings::getInstance()->setBool("ShowKidStartMenu", - show_kidstartmenu->getState()); }); - - // Screensaver. - ComponentListRow screensaver_row; - screensaver_row.elements.clear(); - screensaver_row.addElement(std::make_shared - (mWindow, "SCREENSAVER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); - screensaver_row.addElement(makeArrow(mWindow), false); - screensaver_row.makeAcceptInputHandler(std::bind(&GuiMenu::openScreensaverOptions, this)); - s->addRow(screensaver_row); - mWindow->pushGui(s); } @@ -563,10 +569,15 @@ void GuiMenu::openOtherSettings() // Maximum VRAM. auto max_vram = std::make_shared(mWindow, 80.f, 1024.f, 8.f, "MiB"); - max_vram->setValue((float)(Settings::getInstance()->getInt("MaxVRAM"))); + max_vram->setValue(static_cast(Settings::getInstance()->getInt("MaxVRAM"))); s->addWithLabel("VRAM LIMIT", max_vram); - s->addSaveFunc([max_vram] { Settings::getInstance()->setInt("MaxVRAM", - (int)Math::round(max_vram->getValue())); }); + s->addSaveFunc([max_vram, s] { + if (max_vram->getValue() != Settings::getInstance()->getInt("MaxVRAM")) { + Settings::getInstance()->setInt("MaxVRAM", + static_cast(Math::round(max_vram->getValue()))); + s->setNeedsSaving(); + } + }); #if defined(__unix__) // Fullscreen mode. @@ -578,74 +589,32 @@ void GuiMenu::openOtherSettings() for (auto it = screenmode.cbegin(); it != screenmode.cend(); it++) fullscreen_mode->add(*it, *it, Settings::getInstance()->getString("FullscreenMode") == *it); s->addWithLabel("FULLSCREEN MODE (REQUIRES RESTART)", fullscreen_mode); - s->addSaveFunc([fullscreen_mode] { - if (Settings::getInstance()->getString("FullscreenMode") == "normal" && - fullscreen_mode->getSelected() != "normal") { - Settings::getInstance()->setString("PowerSaverMode", "default"); - PowerSaver::init(); + s->addSaveFunc([fullscreen_mode, s] { + if (fullscreen_mode->getSelected() != + Settings::getInstance()->getString("FullscreenMode")) { + Settings::getInstance()->setString("FullscreenMode", fullscreen_mode->getSelected()); + s->setNeedsSaving(); } - Settings::getInstance()->setString("FullscreenMode", fullscreen_mode->getSelected()); - }); - #endif - - // Power saver. - auto power_saver = std::make_shared> - (mWindow, getHelpStyle(), "POWER SAVER MODES", false); - std::vector modes; - modes.push_back("disabled"); - modes.push_back("default"); - modes.push_back("enhanced"); - modes.push_back("instant"); - for (auto it = modes.cbegin(); it != modes.cend(); it++) - power_saver->add(*it, *it, Settings::getInstance()->getString("PowerSaverMode") == *it); - s->addWithLabel("POWER SAVER MODES", power_saver); - s->addSaveFunc([this, power_saver] { - if (Settings::getInstance()->getString("PowerSaverMode") != - "instant" && power_saver->getSelected() == "instant") { - Settings::getInstance()->setString("TransitionStyle", "instant"); - Settings::getInstance()->setBool("MoveCarousel", false); - Settings::getInstance()->setBool("NavigationSounds", false); - } - Settings::getInstance()->setString("PowerSaverMode", power_saver->getSelected()); - PowerSaver::init(); - }); - - #if defined(_RPI_) - // Video Player - VideoOmxPlayer. - auto omx_player = std::make_shared(mWindow); - omx_player->setState(Settings::getInstance()->getBool("VideoOmxPlayer")); - s->addWithLabel("USE OMX PLAYER (HW ACCELERATED)", omx_player); - s->addSaveFunc([omx_player] { - // Need to reload all views to re-create the right video components. - bool needReload = false; - if (Settings::getInstance()->getBool("VideoOmxPlayer") != omx_player->getState()) - needReload = true; - - Settings::getInstance()->setBool("VideoOmxPlayer", omx_player->getState()); - - if (needReload) - ViewController::get()->reloadAll(); }); #endif // When to save game metadata. - auto gamelistsSaveMode = std::make_shared> - (mWindow, getHelpStyle(), "SAVE METADATA", false); + auto save_gamelist_mode = std::make_shared> + (mWindow, getHelpStyle(), "WHEN TO SAVE METADATA", false); std::vector saveModes; saveModes.push_back("on exit"); saveModes.push_back("always"); saveModes.push_back("never"); - for (auto it = saveModes.cbegin(); it != saveModes.cend(); it++) { - gamelistsSaveMode->add(*it, *it, Settings::getInstance()-> + save_gamelist_mode->add(*it, *it, Settings::getInstance()-> getString("SaveGamelistsMode") == *it); } - s->addWithLabel("WHEN TO SAVE GAME METADATA", gamelistsSaveMode); - s->addSaveFunc([gamelistsSaveMode] { - if (Settings::getInstance()->getString("SaveGamelistsMode") != - gamelistsSaveMode->getSelected()) { + s->addWithLabel("WHEN TO SAVE GAME METADATA", save_gamelist_mode); + s->addSaveFunc([save_gamelist_mode, s] { + if (save_gamelist_mode->getSelected() != + Settings::getInstance()->getString("SaveGamelistsMode")) { Settings::getInstance()->setString("SaveGamelistsMode", - gamelistsSaveMode->getSelected()); + save_gamelist_mode->getSelected()); // Always save the gamelist.xml files if switching to 'always' as there may // be changes that will otherwise be lost. if (Settings::getInstance()->getString("SaveGamelistsMode") == "always") { @@ -653,32 +622,30 @@ void GuiMenu::openOtherSettings() it != SystemData::sSystemVector.cend(); it++) (*it)->writeMetaData(); } + s->setNeedsSaving(); } }); // Game media directory. ComponentListRow row; - auto mediaDirectory = std::make_shared(mWindow, "GAME MEDIA DIRECTORY", + auto media_directory = std::make_shared(mWindow, "GAME MEDIA DIRECTORY", Font::get(FONT_SIZE_MEDIUM), 0x777777FF); auto bracket = std::make_shared(mWindow); bracket->setImage(":/graphics/arrow.svg"); bracket->setResize(Vector2f(0, Font::get(FONT_SIZE_MEDIUM)->getLetterHeight())); - - row.addElement(mediaDirectory, true); + row.addElement(media_directory, true); row.addElement(bracket, false); - std::string title = "ENTER GAME MEDIA DIRECTORY"; std::string mediaDirectoryStaticText = "Default directory:"; std::string defaultDirectoryText = "~/.emulationstation/downloaded_media/"; std::string initValue = Settings::getInstance()->getString("MediaDirectory"); bool multiLine = false; - - auto updateVal = [](const std::string& newVal) { + auto updateVal = [this](const std::string& newVal) { Settings::getInstance()->setString("MediaDirectory", newVal); Settings::getInstance()->saveFile(); ViewController::get()->reloadAll(); + mWindow->invalidateCachedBackground(); }; - row.makeAcceptInputHandler([this, title, mediaDirectoryStaticText, defaultDirectoryText, initValue, updateVal, multiLine] { mWindow->pushGui(new GuiComplexTextEditPopup(mWindow, getHelpStyle(), @@ -688,20 +655,45 @@ void GuiMenu::openOtherSettings() }); s->addRow(row); + #if defined(_RPI_) + // Video Player - VideoOmxPlayer. + auto video_omx_player = std::make_shared(mWindow); + video_omx_player->setState(Settings::getInstance()->getBool("VideoOmxPlayer")); + s->addWithLabel("USE OMX PLAYER (HW ACCELERATED)", video_omx_player); + s->addSaveFunc([video_omx_player, s] { + if (video_omx_player->getState() != + Settings::getInstance()->getBool("VideoOmxPlayer")) { + Settings::getInstance()->setBool("VideoOmxPlayer", video_omx_player->getState()); + s->setNeedsSaving(); + // Need to reload all views to re-create the right video components. + s->setNeedsReloading(); + } + }); + #endif + #if defined(_WIN64) - // Hide taskbar during ES program session. + // Hide taskbar during the ES program session. auto hide_taskbar = std::make_shared(mWindow); hide_taskbar->setState(Settings::getInstance()->getBool("HideTaskbar")); s->addWithLabel("HIDE TASKBAR (REQUIRES RESTART)", hide_taskbar); - s->addSaveFunc([hide_taskbar] { Settings::getInstance()-> - setBool("HideTaskbar", hide_taskbar->getState()); }); + s->addSaveFunc([hide_taskbar, s] { + if (hide_taskbar->getState() != + Settings::getInstance()->getBool("HideTaskbar")) { + Settings::getInstance()-> setBool("HideTaskbar", hide_taskbar->getState()); + s->setNeedsSaving(); + } + }); // Run ES in the background when a game has been launched. auto run_in_background = std::make_shared(mWindow); run_in_background->setState(Settings::getInstance()->getBool("RunInBackground")); s->addWithLabel("RUN IN BACKGROUND (WHILE GAME IS LAUNCHED)", run_in_background); - s->addSaveFunc([run_in_background] { Settings::getInstance()-> - setBool("RunInBackground", run_in_background->getState()); }); + s->addSaveFunc([run_in_background,s] { + if (run_in_background->getState() != Settings::getInstance()->getBool("RunInBackground")) { + Settings::getInstance()->setBool("RunInBackground", run_in_background->getState()); + s->setNeedsSaving(); + } + }); #endif // Allow overriding of the launch command per game (the option to disable this is @@ -709,67 +701,111 @@ void GuiMenu::openOtherSettings() auto launchcommand_override = std::make_shared(mWindow); launchcommand_override->setState(Settings::getInstance()->getBool("LaunchCommandOverride")); s->addWithLabel("PER GAME LAUNCH COMMAND OVERRIDE", launchcommand_override); - s->addSaveFunc([launchcommand_override] { Settings::getInstance()-> - setBool("LaunchCommandOverride", launchcommand_override->getState()); }); + s->addSaveFunc([launchcommand_override, s] { + if (launchcommand_override->getState() != + Settings::getInstance()->getBool("LaunchCommandOverride")) { + Settings::getInstance()-> + setBool("LaunchCommandOverride", launchcommand_override->getState()); + s->setNeedsSaving(); + } + }); - // Hidden files. - auto hidden_files = std::make_shared(mWindow); - hidden_files->setState(Settings::getInstance()->getBool("ShowHiddenFiles")); - s->addWithLabel("SHOW HIDDEN FILES AND FOLDERS (REQUIRES RESTART)", hidden_files); - s->addSaveFunc([hidden_files] { Settings::getInstance()->setBool("ShowHiddenFiles", - hidden_files->getState()); }); + // Show hidden files. + auto show_hidden_files = std::make_shared(mWindow); + show_hidden_files->setState(Settings::getInstance()->getBool("ShowHiddenFiles")); + s->addWithLabel("SHOW HIDDEN FILES AND FOLDERS (REQUIRES RESTART)", show_hidden_files); + s->addSaveFunc([show_hidden_files, s] { + if (show_hidden_files->getState() != Settings::getInstance()->getBool("ShowHiddenFiles")) { + Settings::getInstance()->setBool("ShowHiddenFiles", show_hidden_files->getState()); + s->setNeedsSaving(); + } + }); - // Hidden games. - auto hidden_games = std::make_shared(mWindow); - hidden_games->setState(Settings::getInstance()->getBool("ShowHiddenGames")); - s->addWithLabel("SHOW HIDDEN GAMES (REQUIRES RESTART)", hidden_games); - s->addSaveFunc([hidden_games] { - Settings::getInstance()->setBool("ShowHiddenGames", - hidden_games->getState()); + // Show hidden games. + auto show_hidden_games = std::make_shared(mWindow); + show_hidden_games->setState(Settings::getInstance()->getBool("ShowHiddenGames")); + s->addWithLabel("SHOW HIDDEN GAMES (REQUIRES RESTART)", show_hidden_games); + s->addSaveFunc([show_hidden_games, s] { + if (show_hidden_games->getState() != Settings::getInstance()->getBool("ShowHiddenGames")) { + Settings::getInstance()->setBool("ShowHiddenGames", show_hidden_games->getState()); + s->setNeedsSaving(); + } }); // Custom event scripts, fired using Scripting::fireEvent(). auto custom_eventscripts = std::make_shared(mWindow); custom_eventscripts->setState(Settings::getInstance()->getBool("CustomEventScripts")); s->addWithLabel("ENABLE CUSTOM EVENT SCRIPTS", custom_eventscripts); - s->addSaveFunc([custom_eventscripts] { Settings::getInstance()-> - setBool("CustomEventScripts", custom_eventscripts->getState()); }); + s->addSaveFunc([custom_eventscripts, s] { + if (custom_eventscripts->getState() != + Settings::getInstance()->getBool("CustomEventScripts")) { + Settings::getInstance()->setBool("CustomEventScripts", custom_eventscripts->getState()); + s->setNeedsSaving(); + } + }); - auto parse_gamelists = std::make_shared(mWindow); - parse_gamelists->setState(Settings::getInstance()->getBool("ParseGamelistOnly")); - s->addWithLabel("ONLY SHOW ROMS FROM GAMELIST.XML FILES", parse_gamelists); - s->addSaveFunc([parse_gamelists] { Settings::getInstance()-> - setBool("ParseGamelistOnly", parse_gamelists->getState()); }); + // Only show ROMs included in the gamelist.xml files. + auto parse_gamelist_only = std::make_shared(mWindow); + parse_gamelist_only->setState(Settings::getInstance()->getBool("ParseGamelistOnly")); + s->addWithLabel("ONLY SHOW ROMS FROM GAMELIST.XML FILES", parse_gamelist_only); + s->addSaveFunc([parse_gamelist_only, s] { + if (parse_gamelist_only->getState() != + Settings::getInstance()->getBool("ParseGamelistOnly")) { + Settings::getInstance()->setBool("ParseGamelistOnly", parse_gamelist_only->getState()); + s->setNeedsSaving(); + } + }); - auto local_art = std::make_shared(mWindow); - local_art->setState(Settings::getInstance()->getBool("LocalArt")); - s->addWithLabel("DISPLAY GAME ART FROM ROM DIRECTORIES", local_art); - s->addSaveFunc([local_art] { Settings::getInstance()-> - setBool("LocalArt", local_art->getState()); }); + // Display game media from the ROM directories. + auto rom_dir_game_media = std::make_shared(mWindow); + rom_dir_game_media->setState(Settings::getInstance()->getBool("ROMDirGameMedia")); + s->addWithLabel("DISPLAY GAME MEDIA FROM ROM DIRECTORIES", rom_dir_game_media); + s->addSaveFunc([rom_dir_game_media, s] { + if (rom_dir_game_media->getState() != Settings::getInstance()->getBool("ROMDirGameMedia")) { + Settings::getInstance()->setBool("ROMDirGameMedia", rom_dir_game_media->getState()); + s->setNeedsSaving(); + } + }); - // GPU statistics. - auto gpu_statistics = std::make_shared(mWindow); - gpu_statistics->setState(Settings::getInstance()->getBool("DisplayGPUStatistics")); - s->addWithLabel("DISPLAY GPU STATISTICS OVERLAY", gpu_statistics); - s->addSaveFunc([gpu_statistics] { Settings::getInstance()->setBool("DisplayGPUStatistics", - gpu_statistics->getState()); }); + // GPU statistics overlay. + auto display_gpu_statistics = std::make_shared(mWindow); + display_gpu_statistics->setState(Settings::getInstance()->getBool("DisplayGPUStatistics")); + s->addWithLabel("DISPLAY GPU STATISTICS OVERLAY", display_gpu_statistics); + s->addSaveFunc([display_gpu_statistics, s] { + if (display_gpu_statistics->getState() != + Settings::getInstance()->getBool("DisplayGPUStatistics")) { + Settings::getInstance()->setBool("DisplayGPUStatistics", + display_gpu_statistics->getState()); + s->setNeedsSaving(); + } + }); // macOS requires root privileges to reboot and power off so it doesn't make much // sense to enable these settings and menu entries for this operating system. #if !defined(__APPLE__) // Hide Reboot System option in the quit menu. - auto show_rebootsystem = std::make_shared(mWindow); - show_rebootsystem->setState(Settings::getInstance()->getBool("ShowRebootSystem")); - s->addWithLabel("SHOW 'REBOOT SYSTEM' MENU ENTRY", show_rebootsystem); - s->addSaveFunc([show_rebootsystem] { Settings::getInstance()->setBool("ShowRebootSystem", - show_rebootsystem->getState()); }); + auto show_reboot_system = std::make_shared(mWindow); + show_reboot_system->setState(Settings::getInstance()->getBool("ShowRebootSystem")); + s->addWithLabel("SHOW 'REBOOT SYSTEM' MENU ENTRY", show_reboot_system); + s->addSaveFunc([show_reboot_system, s] { + if (show_reboot_system->getState() != + Settings::getInstance()->getBool("ShowRebootSystem")) { + Settings::getInstance()->setBool("ShowRebootSystem", show_reboot_system->getState()); + s->setNeedsSaving(); + } + }); // Hide Power Off System option in the quit menu. - auto show_poweroffsystem = std::make_shared(mWindow); - show_poweroffsystem->setState(Settings::getInstance()->getBool("ShowPoweroffSystem")); - s->addWithLabel("SHOW 'POWER OFF SYSTEM' MENU ENTRY", show_poweroffsystem); - s->addSaveFunc([show_poweroffsystem] { Settings::getInstance()->setBool("ShowPoweroffSystem", - show_poweroffsystem->getState()); }); + auto show_poweroff_system = std::make_shared(mWindow); + show_poweroff_system->setState(Settings::getInstance()->getBool("ShowPoweroffSystem")); + s->addWithLabel("SHOW 'POWER OFF SYSTEM' MENU ENTRY", show_poweroff_system); + s->addSaveFunc([show_poweroff_system, s] { + if (show_poweroff_system->getState() != + Settings::getInstance()->getBool("ShowPoweroffSystem")) { + Settings::getInstance()->setBool("ShowPoweroffSystem", show_poweroff_system->getState()); + s->setNeedsSaving(); + } + }); #endif mWindow->pushGui(s); @@ -887,7 +923,6 @@ void GuiMenu::addEntry(const char* name, unsigned int color, } row.makeAcceptInputHandler(func); - mMenu.addRow(row); } diff --git a/es-app/src/guis/GuiMenu.h b/es-app/src/guis/GuiMenu.h index 4c193e826..2107680fb 100644 --- a/es-app/src/guis/GuiMenu.h +++ b/es-app/src/guis/GuiMenu.h @@ -29,14 +29,15 @@ private: void addEntry(const char* name, unsigned int color, bool add_arrow, const std::function& func); void addVersionInfo(); - void openCollectionSystemSettings(); - void openConfigInput(); - void openOtherSettings(); - void openQuitMenu(); + void openScraperSettings(); + void openUISettings(); void openScreensaverOptions(); void openSoundSettings(); - void openUISettings(); + void openCollectionSystemSettings(); + void openOtherSettings(); + void openConfigInput(); + void openQuitMenu(); MenuComponent mMenu; TextComponent mVersion; diff --git a/es-app/src/guis/GuiScraperMenu.cpp b/es-app/src/guis/GuiScraperMenu.cpp index d914c5a0a..b16560f19 100644 --- a/es-app/src/guis/GuiScraperMenu.cpp +++ b/es-app/src/guis/GuiScraperMenu.cpp @@ -22,19 +22,21 @@ GuiScraperMenu::GuiScraperMenu(Window* window) : GuiComponent(window), mMenu(window, "SCRAPER") { - // Scrape from. - auto scraper_list = std::make_shared> + // Scraper service. + mScraper = std::make_shared> (mWindow, getHelpStyle(), "SCRAPE FROM", false); std::vector scrapers = getScraperList(); - // Select either the first entry or the one read from the settings, // just in case the scraper from settings has vanished. for (auto it = scrapers.cbegin(); it != scrapers.cend(); it++) - scraper_list->add(*it, *it, *it == Settings::getInstance()->getString("Scraper")); - - mMenu.addWithLabel("SCRAPE FROM", scraper_list); - mMenu.addSaveFunc([scraper_list] { Settings::getInstance()->setString("Scraper", - scraper_list->getSelected()); }); + mScraper->add(*it, *it, *it == Settings::getInstance()->getString("Scraper")); + mMenu.addWithLabel("SCRAPE FROM", mScraper); + mMenu.addSaveFunc([this] { + if (mScraper->getSelected() != Settings::getInstance()->getString("Scraper")) { + Settings::getInstance()->setString("Scraper", mScraper->getSelected()); + mMenu.setNeedsSaving(); + } + }); // Search filters, getSearches() will generate a queue of games to scrape // based on the outcome of the checks below. @@ -71,15 +73,19 @@ GuiScraperMenu::GuiScraperMenu(Window* window) : GuiComponent(window), mMenu.addWithLabel("Systems", mSystems); addEntry("CONTENT SETTINGS", 0x777777FF, true, [this] { - // Always save the settings when entering this menu, so the options that are - // not supported by TheGamesDB can be disabled. - mMenu.save(); + // If the scraper service has been changed before entering this menu, then save the + // settings so that the specific options supported by the respective scrapers + // can be enabled or disabled. + if (mScraper->getSelected() != Settings::getInstance()->getString("Scraper")) + mMenu.save(); openContentSettings(); }); addEntry("OTHER SETTINGS", 0x777777FF, true, [this] { - // Always save the settings when entering this menu, so the options that are - // not supported by TheGamesDB can be disabled. - mMenu.save(); + // If the scraper service has been changed before entering this menu, then save the + // settings so that the specific options supported by the respective scrapers + // can be enabled or disabled. + if (mScraper->getSelected() != Settings::getInstance()->getString("Scraper")) + mMenu.save(); openOtherSettings(); }); @@ -114,18 +120,26 @@ void GuiScraperMenu::openContentSettings() auto s = new GuiSettings(mWindow, "SCRAPER CONTENT SETTINGS"); // Scrape game names. - auto scrape_gamename = std::make_shared(mWindow); - scrape_gamename->setState(Settings::getInstance()->getBool("ScrapeGameNames")); - s->addWithLabel("SCRAPE GAME NAMES", scrape_gamename); - s->addSaveFunc([scrape_gamename] { Settings::getInstance()->setBool("ScrapeGameNames", - scrape_gamename->getState()); }); + auto scrape_game_names = std::make_shared(mWindow); + scrape_game_names->setState(Settings::getInstance()->getBool("ScrapeGameNames")); + s->addWithLabel("SCRAPE GAME NAMES", scrape_game_names); + s->addSaveFunc([scrape_game_names, s] { + if (scrape_game_names->getState() != Settings::getInstance()->getBool("ScrapeGameNames")) { + Settings::getInstance()->setBool("ScrapeGameNames", scrape_game_names->getState()); + s->setNeedsSaving(); + } + }); // Scrape ratings. auto scrape_ratings = std::make_shared(mWindow); scrape_ratings->setState(Settings::getInstance()->getBool("ScrapeRatings")); s->addWithLabel("SCRAPE RATINGS", scrape_ratings); - s->addSaveFunc([scrape_ratings] { Settings::getInstance()->setBool("ScrapeRatings", - scrape_ratings->getState()); }); + s->addSaveFunc([scrape_ratings, s] { + if (scrape_ratings->getState() != Settings::getInstance()->getBool("ScrapeRatings")) { + Settings::getInstance()->setBool("ScrapeRatings", scrape_ratings->getState()); + s->setNeedsSaving(); + } + }); // Ratings are not supported by TheGamesDB, so disable the option if this scraper is selected. if (Settings::getInstance()->getString("Scraper") == "thegamesdb") { @@ -140,15 +154,23 @@ void GuiScraperMenu::openContentSettings() auto scrape_metadata = std::make_shared(mWindow); scrape_metadata->setState(Settings::getInstance()->getBool("ScrapeMetadata")); s->addWithLabel("SCRAPE OTHER METADATA", scrape_metadata); - s->addSaveFunc([scrape_metadata] { Settings::getInstance()->setBool("ScrapeMetadata", - scrape_metadata->getState()); }); + s->addSaveFunc([scrape_metadata, s] { + if (scrape_metadata->getState() != Settings::getInstance()->getBool("ScrapeMetadata")) { + Settings::getInstance()->setBool("ScrapeMetadata", scrape_metadata->getState()); + s->setNeedsSaving(); + } + }); // Scrape videos. auto scrape_videos = std::make_shared(mWindow); scrape_videos->setState(Settings::getInstance()->getBool("ScrapeVideos")); s->addWithLabel("SCRAPE VIDEOS", scrape_videos); - s->addSaveFunc([scrape_videos] { Settings::getInstance()->setBool("ScrapeVideos", - scrape_videos->getState()); }); + s->addSaveFunc([scrape_videos, s] { + if (scrape_videos->getState() != Settings::getInstance()->getBool("ScrapeVideos")) { + Settings::getInstance()->setBool("ScrapeVideos", scrape_videos->getState()); + s->setNeedsSaving(); + } + }); // Videos are not supported by TheGamesDB, so disable the option if this scraper is selected. if (Settings::getInstance()->getString("Scraper") == "thegamesdb") { @@ -163,29 +185,46 @@ void GuiScraperMenu::openContentSettings() auto scrape_screenshots = std::make_shared(mWindow); scrape_screenshots->setState(Settings::getInstance()->getBool("ScrapeScreenshots")); s->addWithLabel("SCRAPE SCREENSHOT IMAGES", scrape_screenshots); - s->addSaveFunc([scrape_screenshots] { Settings::getInstance()->setBool("ScrapeScreenshots", - scrape_screenshots->getState()); }); + s->addSaveFunc([scrape_screenshots, s] { + if (scrape_screenshots->getState() != + Settings::getInstance()->getBool("ScrapeScreenshots")) { + Settings::getInstance()->setBool("ScrapeScreenshots", scrape_screenshots->getState()); + s->setNeedsSaving(); + } + }); // Scrape cover images. auto scrape_covers = std::make_shared(mWindow); scrape_covers->setState(Settings::getInstance()->getBool("ScrapeCovers")); s->addWithLabel("SCRAPE BOX COVER IMAGES", scrape_covers); - s->addSaveFunc([scrape_covers] { Settings::getInstance()->setBool("ScrapeCovers", - scrape_covers->getState()); }); + s->addSaveFunc([scrape_covers, s] { + if (scrape_covers->getState() != Settings::getInstance()->getBool("ScrapeCovers")) { + Settings::getInstance()->setBool("ScrapeCovers", scrape_covers->getState()); + s->setNeedsSaving(); + } + }); // Scrape marquee images. auto scrape_marquees = std::make_shared(mWindow); scrape_marquees->setState(Settings::getInstance()->getBool("ScrapeMarquees")); s->addWithLabel("SCRAPE MARQUEE (WHEEL) IMAGES", scrape_marquees); - s->addSaveFunc([scrape_marquees] { Settings::getInstance()->setBool("ScrapeMarquees", - scrape_marquees->getState()); }); + s->addSaveFunc([scrape_marquees, s] { + if (scrape_marquees->getState() != Settings::getInstance()->getBool("ScrapeMarquees")) { + Settings::getInstance()->setBool("ScrapeMarquees", scrape_marquees->getState()); + s->setNeedsSaving(); + } + }); // Scrape 3D box images. auto scrape_3dboxes = std::make_shared(mWindow); scrape_3dboxes->setState(Settings::getInstance()->getBool("Scrape3DBoxes")); s->addWithLabel("SCRAPE 3D BOX IMAGES", scrape_3dboxes); - s->addSaveFunc([scrape_3dboxes] { Settings::getInstance()->setBool("Scrape3DBoxes", - scrape_3dboxes->getState()); }); + s->addSaveFunc([scrape_3dboxes, s] { + if (scrape_3dboxes->getState() != Settings::getInstance()->getBool("Scrape3DBoxes")) { + Settings::getInstance()->setBool("Scrape3DBoxes", scrape_3dboxes->getState()); + s->setNeedsSaving(); + } + }); // 3D box images are not supported by TheGamesDB, so disable the option if this scraper // is selected. @@ -213,7 +252,6 @@ void GuiScraperMenu::openOtherSettings() transitions_rg.push_back("us"); transitions_rg.push_back("ss"); transitions_rg.push_back("wor"); - if (Settings::getInstance()->getString("ScraperRegion") != "") { if (std::find(transitions_rg.begin(), transitions_rg.end(), Settings::getInstance()->getString("ScraperRegion")) == transitions_rg.end()) { @@ -223,8 +261,11 @@ void GuiScraperMenu::openOtherSettings() for (auto it = transitions_rg.cbegin(); it != transitions_rg.cend(); it++) scraper_region->add(*it, *it, Settings::getInstance()->getString("ScraperRegion") == *it); s->addWithLabel("REGION", scraper_region); - s->addSaveFunc([scraper_region] { - Settings::getInstance()->setString("ScraperRegion", scraper_region->getSelected()); + s->addSaveFunc([scraper_region, s] { + if (scraper_region->getSelected() != Settings::getInstance()->getString("ScraperRegion")) { + Settings::getInstance()->setString("ScraperRegion", scraper_region->getSelected()); + s->setNeedsSaving(); + } }); // Regions are not supported by TheGamesDB, so disable the option if this scraper is selected. @@ -242,7 +283,6 @@ void GuiScraperMenu::openOtherSettings() std::vector transitions_lg; transitions_lg.push_back("en"); transitions_lg.push_back("wor"); - if (Settings::getInstance()->getString("ScraperLanguage") != "") { if (std::find(transitions_lg.begin(), transitions_lg.end(), Settings::getInstance()->getString("ScraperLanguage")) == transitions_lg.end()) { @@ -253,8 +293,12 @@ void GuiScraperMenu::openOtherSettings() scraper_language->add(*it, *it, Settings::getInstance()->getString("ScraperLanguage") == *it); s->addWithLabel("LANGUAGE", scraper_language); - s->addSaveFunc([scraper_language] { - Settings::getInstance()->setString("ScraperLanguage", scraper_language->getSelected()); + s->addSaveFunc([scraper_language, s] { + if (scraper_language->getSelected() != + Settings::getInstance()->getString("ScraperLanguage")) { + Settings::getInstance()->setString("ScraperLanguage", scraper_language->getSelected()); + s->setNeedsSaving(); + } }); // Languages are not supported by TheGamesDB, so disable the option if this scraper is selected. @@ -267,69 +311,108 @@ void GuiScraperMenu::openOtherSettings() } // Overwrite files and data. - auto scrape_overwrite = std::make_shared(mWindow); - scrape_overwrite->setState(Settings::getInstance()->getBool("ScraperOverwriteData")); - s->addWithLabel("OVERWRITE FILES AND DATA", scrape_overwrite); - s->addSaveFunc([scrape_overwrite] { Settings::getInstance()->setBool("ScraperOverwriteData", - scrape_overwrite->getState()); }); + auto scraper_overwrite_data = std::make_shared(mWindow); + scraper_overwrite_data->setState(Settings::getInstance()->getBool("ScraperOverwriteData")); + s->addWithLabel("OVERWRITE FILES AND DATA", scraper_overwrite_data); + s->addSaveFunc([scraper_overwrite_data, s] { + if (scraper_overwrite_data->getState() != + Settings::getInstance()->getBool("ScraperOverwriteData")) { + Settings::getInstance()->setBool("ScraperOverwriteData", + scraper_overwrite_data->getState()); + s->setNeedsSaving(); + } + }); // Search using metadata name. - auto scrape_metadata_name = std::make_shared(mWindow); - scrape_metadata_name->setState(Settings::getInstance()->getBool("ScraperSearchMetadataName")); - s->addWithLabel("SEARCH USING METADATA NAME", scrape_metadata_name); - s->addSaveFunc([scrape_metadata_name] { - Settings::getInstance()->setBool("ScraperSearchMetadataName", - scrape_metadata_name->getState()); }); + auto scraper_search_metadata_name = std::make_shared(mWindow); + scraper_search_metadata_name-> + setState(Settings::getInstance()->getBool("ScraperSearchMetadataName")); + s->addWithLabel("SEARCH USING METADATA NAME", scraper_search_metadata_name); + s->addSaveFunc([scraper_search_metadata_name, s] { + if (scraper_search_metadata_name->getState() != + Settings::getInstance()->getBool("ScraperSearchMetadataName")) { + Settings::getInstance()->setBool("ScraperSearchMetadataName", + scraper_search_metadata_name->getState()); + s->setNeedsSaving(); + } + }); // Interactive scraping. auto scraper_interactive = std::make_shared(mWindow); scraper_interactive->setState(Settings::getInstance()->getBool("ScraperInteractive")); s->addWithLabel("INTERACTIVE MODE", scraper_interactive); - s->addSaveFunc([scraper_interactive] { Settings::getInstance()->setBool("ScraperInteractive", - scraper_interactive->getState()); }); + s->addSaveFunc([scraper_interactive, s] { + if (scraper_interactive->getState() != + Settings::getInstance()->getBool("ScraperInteractive")) { + Settings::getInstance()->setBool("ScraperInteractive", scraper_interactive->getState()); + s->setNeedsSaving(); + } + }); // Semi-automatic scraping. auto scraper_semiautomatic = std::make_shared(mWindow); scraper_semiautomatic->setState(Settings::getInstance()->getBool("ScraperSemiautomatic")); s->addWithLabel("AUTO-ACCEPT SINGLE GAME MATCHES", scraper_semiautomatic); - s->addSaveFunc([scraper_semiautomatic] { + s->addSaveFunc([scraper_semiautomatic ,s] { + if (scraper_semiautomatic->getState() != + Settings::getInstance()->getBool("ScraperSemiautomatic")) { Settings::getInstance()->setBool("ScraperSemiautomatic", - scraper_semiautomatic->getState()); }); + scraper_semiautomatic->getState()); + s->setNeedsSaving(); + } + }); // Respect the per-file multi-scraper exclusion flag. auto scraper_respect_exclusions = std::make_shared(mWindow); scraper_respect_exclusions->setState( Settings::getInstance()->getBool("ScraperRespectExclusions")); s->addWithLabel("RESPECT PER-FILE SCRAPER EXCLUSIONS", scraper_respect_exclusions); - s->addSaveFunc([scraper_respect_exclusions] { + s->addSaveFunc([scraper_respect_exclusions, s] { + if (scraper_respect_exclusions->getState() != + Settings::getInstance()->getBool("ScraperRespectExclusions")) { Settings::getInstance()->setBool("ScraperRespectExclusions", - scraper_respect_exclusions->getState()); }); + scraper_respect_exclusions->getState()); + s->setNeedsSaving(); + } + }); // Exclude files recursively for excluded folders. auto scraper_exclude_recursively = std::make_shared(mWindow); scraper_exclude_recursively->setState( Settings::getInstance()->getBool("ScraperExcludeRecursively")); s->addWithLabel("EXCLUDE FOLDERS RECURSIVELY", scraper_exclude_recursively); - s->addSaveFunc([scraper_exclude_recursively] { + s->addSaveFunc([scraper_exclude_recursively, s] { + if (scraper_exclude_recursively->getState() != + Settings::getInstance()->getBool("ScraperExcludeRecursively")) { Settings::getInstance()->setBool("ScraperExcludeRecursively", - scraper_exclude_recursively->getState()); }); + scraper_exclude_recursively->getState()); + s->setNeedsSaving(); + } + }); // Include actual folders when scraping. auto scraper_include_folders = std::make_shared(mWindow); scraper_include_folders->setState( Settings::getInstance()->getBool("ScraperIncludeFolders")); s->addWithLabel("SCRAPE ACTUAL FOLDERS", scraper_include_folders); - s->addSaveFunc([scraper_include_folders] { + s->addSaveFunc([scraper_include_folders, s] { + if (scraper_include_folders->getState() != + Settings::getInstance()->getBool("ScraperIncludeFolders")) { Settings::getInstance()->setBool("ScraperIncludeFolders", - scraper_include_folders->getState()); }); + scraper_include_folders->getState()); + s->setNeedsSaving(); + } + }); mWindow->pushGui(s); } void GuiScraperMenu::pressedStart() { - // Save any GUI settings that may have been modified. - mMenu.save(); + // If the scraper service has been changed, then save the settings as otherwise the + // wrong scraper would be used. + if (mScraper->getSelected() != Settings::getInstance()->getString("Scraper")) + mMenu.save(); std::vector sys = mSystems->getSelectedObjects(); for (auto it = sys.cbegin(); it != sys.cend(); it++) { diff --git a/es-app/src/guis/GuiScraperMenu.h b/es-app/src/guis/GuiScraperMenu.h index 3d6fa80e0..52715316c 100644 --- a/es-app/src/guis/GuiScraperMenu.h +++ b/es-app/src/guis/GuiScraperMenu.h @@ -45,6 +45,7 @@ private: std::queue getSearches( std::vector systems, GameFilterFunc selector); + std::shared_ptr> mScraper; std::shared_ptr> mFilters; std::shared_ptr> mSystems; diff --git a/es-app/src/guis/GuiSettings.cpp b/es-app/src/guis/GuiSettings.cpp index 3e9887216..163dd4353 100644 --- a/es-app/src/guis/GuiSettings.cpp +++ b/es-app/src/guis/GuiSettings.cpp @@ -4,17 +4,29 @@ // GuiSettings.cpp // // User interface template for a settings GUI. +// The saving of es_settings.cfg and the reload of the gamelists are triggered from here +// based on the flags set by the actual menu entries' lambda functions. // #include "guis/GuiSettings.h" +#include "guis/GuiTextEditPopup.h" +#include "views/gamelist/IGameListView.h" #include "views/ViewController.h" #include "Settings.h" #include "SystemData.h" #include "Window.h" -GuiSettings::GuiSettings(Window* window, const char* title) - : GuiComponent(window), mMenu(window, title) +GuiSettings::GuiSettings( + Window* window, + const char* title) + : GuiComponent(window), + mMenu(window, title), + mNeedsSaving(false), + mNeedsGoToStart(false), + mNeedsReloading(false), + mNeedsSorting(false), + mNeedsSortingCollections(false) { addChild(&mMenu); mMenu.addButton("BACK", "back", [this] { delete this; }); @@ -36,7 +48,68 @@ void GuiSettings::save() for (auto it = mSaveFuncs.cbegin(); it != mSaveFuncs.cend(); it++) (*it)(); - Settings::getInstance()->saveFile(); + if (mNeedsSaving) + Settings::getInstance()->saveFile(); + + if (mNeedsGoToStart) + ViewController::get()->goToStart(); + + if (mNeedsReloading) + ViewController::get()->reloadAll(); + + if (mNeedsSorting) { + for (auto it = SystemData::sSystemVector.cbegin(); it != + SystemData::sSystemVector.cend(); it++) { + if (!(!mNeedsSortingCollections && (*it)->isCollection())) { + (*it)->sortSystem(true); + } + // Jump to the first row of the gamelist. + IGameListView* gameList = ViewController::get()->getGameListView((*it)).get(); + gameList->setCursor(gameList->getFirstEntry()); + } + } + + if (mNeedsSaving || mNeedsGoToStart || mNeedsReloading || mNeedsSorting) + mWindow->invalidateCachedBackground(); +} + +void GuiSettings::addEditableTextComponent(const std::string label, + std::shared_ptr ed, std::string value, std::string defaultValue) +{ + ComponentListRow row; + row.elements.clear(); + + auto lbl = std::make_shared(mWindow, Utils::String::toUpper(label), + Font::get(FONT_SIZE_MEDIUM), 0x777777FF); + + row.addElement(lbl, true); + row.addElement(ed, true); + + auto spacer = std::make_shared(mWindow); + spacer->setSize(Renderer::getScreenWidth() * 0.005f, 0); + row.addElement(spacer, false); + + auto bracket = std::make_shared(mWindow); + bracket->setImage(":/graphics/arrow.svg"); + bracket->setResize(Vector2f(0, lbl->getFont()->getLetterHeight())); + row.addElement(bracket, false); + + // OK callback (apply new value to ed). + auto updateVal = [ed, defaultValue](const std::string& newVal) { + // If the field is blank, apply the default value if it's been passes as an argument. + if (defaultValue != "" && newVal == "") + ed->setValue(defaultValue); + else + ed->setValue(newVal); + }; + row.makeAcceptInputHandler([this, label, ed, updateVal] { + mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), label, + ed->getValue(), updateVal, false)); + }); + assert(ed); + addRow(row); + + ed->setValue(value); } bool GuiSettings::input(InputConfig* config, Input input) @@ -47,9 +120,8 @@ bool GuiSettings::input(InputConfig* config, Input input) } // Keep code for potential future use. -// if (config->isMappedTo("start", input) && input.value != 0) -// { -// // close everything +// if (config->isMappedTo("start", input) && input.value != 0) { +// // Close everything. // Window* window = mWindow; // while (window->peekGui() && window->peekGui() != ViewController::get()) // delete window->peekGui(); diff --git a/es-app/src/guis/GuiSettings.h b/es-app/src/guis/GuiSettings.h index 5739a7702..d1e8b9657 100644 --- a/es-app/src/guis/GuiSettings.h +++ b/es-app/src/guis/GuiSettings.h @@ -4,6 +4,8 @@ // GuiSettings.h // // User interface template for a settings GUI. +// The saving of es_settings.cfg and the reload of the gamelists are triggered from here +// based on the flags set by the actual menu entries' lambda functions. // #ifndef ES_APP_GUIS_GUI_SETTINGS_H @@ -16,21 +18,34 @@ class GuiSettings : public GuiComponent { public: GuiSettings(Window* window, const char* title); - virtual ~GuiSettings(); // Just calls save() + virtual ~GuiSettings(); void save(); inline void addRow(const ComponentListRow& row) { mMenu.addRow(row); }; inline void addWithLabel(const std::string& label, const std::shared_ptr& comp) { mMenu.addWithLabel(label, comp); }; + void addEditableTextComponent(const std::string label, std::shared_ptr ed, + std::string value, std::string defaultValue = ""); inline void addSaveFunc(const std::function& func) { mSaveFuncs.push_back(func); }; + void setNeedsSaving() { mNeedsSaving = true; }; + void setNeedsGoToStart() { mNeedsGoToStart = true; }; + void setNeedsReloading() { mNeedsReloading = true; }; + void setNeedsSorting() { mNeedsSorting = true; }; + void setNeedsSortingCollections() { mNeedsSortingCollections = true; }; + bool input(InputConfig* config, Input input) override; std::vector getHelpPrompts() override; HelpStyle getHelpStyle() override; private: MenuComponent mMenu; - std::vector< std::function > mSaveFuncs; + std::vector> mSaveFuncs; + bool mNeedsSaving; + bool mNeedsGoToStart; + bool mNeedsReloading; + bool mNeedsSorting; + bool mNeedsSortingCollections; }; #endif // ES_APP_GUIS_GUI_SETTINGS_H diff --git a/es-app/src/main.cpp b/es-app/src/main.cpp index 8c0303bbb..4f371f612 100644 --- a/es-app/src/main.cpp +++ b/es-app/src/main.cpp @@ -286,9 +286,6 @@ bool parseArgs(int argc, char* argv[]) else if (strcmp(argv[i], "--force-kid") == 0) { Settings::getInstance()->setBool("ForceKid", true); } - else if (strcmp(argv[i], "--force-disable-filters") == 0) { - Settings::getInstance()->setBool("ForceDisableFilters", true); - } else if (strcmp(argv[i], "--force-input-config") == 0) { forceInputConfig = true; } @@ -321,7 +318,6 @@ bool parseArgs(int argc, char* argv[]) " --force-full Force the UI mode to Full\n" " --force-kid Force the UI mode to Kid\n" " --force-kiosk Force the UI mode to Kiosk\n" -" --force-disable-filters Force the UI to ignore applied filters in gamelist\n" " --force-input-config Force configuration of input device\n" " --home [path] Directory to use as home path\n" " --version, -v Display version information\n" diff --git a/es-app/src/views/SystemView.cpp b/es-app/src/views/SystemView.cpp index d55de7c83..ed6f4648a 100644 --- a/es-app/src/views/SystemView.cpp +++ b/es-app/src/views/SystemView.cpp @@ -218,7 +218,7 @@ bool SystemView::input(InputConfig* config, Input input) if (!UIModeController::getInstance()->isUIModeKid() && config->isMappedTo("select", input) && - Settings::getInstance()->getBool("ScreenSaverControls")) { + Settings::getInstance()->getBool("ScreensaverControls")) { if (!mWindow->isScreenSaverActive()) { mWindow->startScreenSaver(); mWindow->renderScreenSaver(); @@ -315,11 +315,11 @@ void SystemView::onCursorChanged(const CursorState& /*state*/) return; Animation* anim; - bool move_carousel = Settings::getInstance()->getBool("MoveCarousel"); + bool carousel_transitions = Settings::getInstance()->getBool("CarouselTransitions"); if (transition_style == "fade") { float startExtrasFade = mExtrasFadeOpacity; anim = new LambdaAnimation( - [this, startExtrasFade, startPos, endPos, posMax, move_carousel](float t) { + [this, startExtrasFade, startPos, endPos, posMax, carousel_transitions](float t) { t -= 1; float f = Math::lerp(startPos, endPos, t*t*t + 1); if (f < 0) @@ -327,7 +327,7 @@ void SystemView::onCursorChanged(const CursorState& /*state*/) if (f >= posMax) f -= posMax; - this->mCamOffset = move_carousel ? f : endPos; + this->mCamOffset = carousel_transitions ? f : endPos; t += 1; if (t < 0.3f) @@ -345,7 +345,7 @@ void SystemView::onCursorChanged(const CursorState& /*state*/) else if (transition_style == "slide") { // Slide. anim = new LambdaAnimation( - [this, startPos, endPos, posMax, move_carousel](float t) { + [this, startPos, endPos, posMax, carousel_transitions](float t) { t -= 1; float f = Math::lerp(startPos, endPos, t*t*t + 1); if (f < 0) @@ -353,14 +353,14 @@ void SystemView::onCursorChanged(const CursorState& /*state*/) if (f >= posMax) f -= posMax; - this->mCamOffset = move_carousel ? f : endPos; + this->mCamOffset = carousel_transitions ? f : endPos; this->mExtrasCamOffset = f; }, 500); } else { // Instant. anim = new LambdaAnimation( - [this, startPos, endPos, posMax, move_carousel ](float t) { + [this, startPos, endPos, posMax, carousel_transitions ](float t) { t -= 1; float f = Math::lerp(startPos, endPos, t*t*t + 1); if (f < 0) @@ -368,9 +368,9 @@ void SystemView::onCursorChanged(const CursorState& /*state*/) if (f >= posMax) f -= posMax; - this->mCamOffset = move_carousel ? f : endPos; + this->mCamOffset = carousel_transitions ? f : endPos; this->mExtrasCamOffset = endPos; - }, move_carousel ? 500 : 1); + }, carousel_transitions ? 500 : 1); } setAnimation(anim, 0, nullptr, false, 0); @@ -419,7 +419,7 @@ std::vector SystemView::getHelpPrompts() prompts.push_back(HelpPrompt("x", "random")); if (!UIModeController::getInstance()->isUIModeKid() && - Settings::getInstance()->getBool("ScreenSaverControls")) + Settings::getInstance()->getBool("ScreensaverControls")) prompts.push_back(HelpPrompt("select", "toggle screensaver")); return prompts; diff --git a/es-app/src/views/UIModeController.cpp b/es-app/src/views/UIModeController.cpp index 0f6fcb93c..b581b6cf4 100644 --- a/es-app/src/views/UIModeController.cpp +++ b/es-app/src/views/UIModeController.cpp @@ -14,7 +14,7 @@ #include "Log.h" #include "Window.h" -UIModeController* UIModeController::sInstance = nullptr; +UIModeController* UIModeController::sInstance = nullptr; UIModeController* UIModeController::getInstance() { @@ -24,8 +24,7 @@ UIModeController* UIModeController::getInstance() return sInstance; } -UIModeController::UIModeController() - :mPassKeyCounter(0) +UIModeController::UIModeController() : mPassKeyCounter(0) { mPassKeySequence = Settings::getInstance()->getString("UIMode_passkey"); mCurrentUIMode = Settings::getInstance()->getString("UIMode"); diff --git a/es-app/src/views/UIModeController.h b/es-app/src/views/UIModeController.h index e4a97f680..3cf8d285e 100644 --- a/es-app/src/views/UIModeController.h +++ b/es-app/src/views/UIModeController.h @@ -37,7 +37,6 @@ public: bool isUIModeFull(); bool isUIModeKid(); bool isUIModeKiosk(); - inline std::vector getUIModes() { return mUIModes; }; private: UIModeController(); @@ -47,8 +46,7 @@ private: // Return UI mode to 'full'. void unlockUIMode(); - static UIModeController * sInstance; - const std::vector mUIModes = { "full", "kiosk", "kid" }; + static UIModeController* sInstance; // Default passkeyseq = "uuddlrlrba", as defined in the setting 'UIMode_passkey'. std::string mPassKeySequence; diff --git a/es-core/src/PowerSaver.cpp b/es-core/src/PowerSaver.cpp index 14b94955c..7c3de690a 100644 --- a/es-core/src/PowerSaver.cpp +++ b/es-core/src/PowerSaver.cpp @@ -40,18 +40,18 @@ int PowerSaver::getTimeout() void PowerSaver::loadWakeupTime() { // TODO : Move this to Screensaver Class. - std::string behaviour = Settings::getInstance()->getString("ScreenSaverBehavior"); + std::string behaviour = Settings::getInstance()->getString("ScreensaverBehavior"); if (behaviour == "video") - mWakeupTimeout = Settings::getInstance()->getInt("ScreenSaverSwapVideoTimeout") - getMode(); + mWakeupTimeout = Settings::getInstance()->getInt("ScreensaverSwapVideoTimeout") - getMode(); else if (behaviour == "slideshow") - mWakeupTimeout = Settings::getInstance()->getInt("ScreenSaverSwapImageTimeout") - getMode(); + mWakeupTimeout = Settings::getInstance()->getInt("ScreensaverSwapImageTimeout") - getMode(); else // Dim and Blank. mWakeupTimeout = -1; } void PowerSaver::updateTimeouts() { - mScreenSaverTimeout = (unsigned int) Settings::getInstance()->getInt("ScreenSaverTime"); + mScreenSaverTimeout = (unsigned int) Settings::getInstance()->getInt("ScreensaverTimer"); mScreenSaverTimeout = mScreenSaverTimeout > 0 ? mScreenSaverTimeout - getMode() : -1; loadWakeupTime(); } diff --git a/es-core/src/Settings.cpp b/es-core/src/Settings.cpp index 9b4df8298..abe28bf2b 100644 --- a/es-core/src/Settings.cpp +++ b/es-core/src/Settings.cpp @@ -79,6 +79,26 @@ void Settings::setDefaults() // Settings configured via the in-program settings menu. // + // Scraper. + mStringMap["Scraper"] = "screenscraper"; + mBoolMap["ScrapeGameNames"] = true; + mBoolMap["ScrapeRatings"] = true; + mBoolMap["ScrapeMetadata"] = true; + mBoolMap["ScrapeVideos"] = true; + mBoolMap["ScrapeScreenshots"] = true; + mBoolMap["ScrapeCovers"] = true; + mBoolMap["ScrapeMarquees"] = true; + mBoolMap["Scrape3DBoxes"] = true; + mStringMap["ScraperRegion"] = "eu"; + mStringMap["ScraperLanguage"] = "en"; + mBoolMap["ScraperOverwriteData"] = true; + mBoolMap["ScraperSearchMetadataName"] = true; + mBoolMap["ScraperInteractive"] = true; + mBoolMap["ScraperSemiautomatic"] = true; + mBoolMap["ScraperRespectExclusions"] = true; + mBoolMap["ScraperExcludeRecursively"] = true; + mBoolMap["ScraperIncludeFolders"] = false; + // UI settings. mStringMap["StartupSystem"] = ""; mStringMap["GamelistViewStyle"] = "automatic"; @@ -87,44 +107,42 @@ void Settings::setDefaults() mStringMap["UIMode"] = "full"; mStringMap["DefaultSortOrder"] = "filename, ascending"; mStringMap["MenuOpeningEffect"] = "scale-up"; - mBoolMap["MoveCarousel"] = true; + mBoolMap["CarouselTransitions"] = true; mBoolMap["GamelistVideoScanlines"] = true; mBoolMap["FoldersOnTop"] = true; mBoolMap["FavoritesFirst"] = true; mBoolMap["FavoritesStar"] = true; mBoolMap["FavoritesAddButton"] = true; - mBoolMap["ForceDisableFilters"] = false; + mBoolMap["GamelistFilters"] = true; mBoolMap["QuickSystemSelect"] = true; mBoolMap["ShowHelpPrompts"] = true; mBoolMap["PlayVideosImmediately"] = false; mBoolMap["ShowKidStartMenu"] = false; - // UI settings -> scrensaver settings. - mIntMap["ScreenSaverTime"] = 5*60*1000; // 5 minutes - mBoolMap["ScreenSaverControls"] = true; - mStringMap["ScreenSaverBehavior"] = "dim"; + // UI settings -> screensaver settings. + mIntMap["ScreensaverTimer"] = 5*60*1000; // 5 minutes + mBoolMap["ScreensaverControls"] = true; + mStringMap["ScreensaverBehavior"] = "dim"; // UI settings -> screensaver settings -> slideshow screensaver settings. - mIntMap["ScreenSaverSwapImageTimeout"] = 10000; - mBoolMap["ScreenSaverStretchImages"] = false; - mBoolMap["ScreenSaverImageScanlines"] = true; - mStringMap["SlideshowScreenSaverBackgroundAudioFile"] = Utils::FileSystem::getHomePath() + - "/.emulationstation/slideshow/audio/slideshow_bg.wav"; - mBoolMap["SlideshowScreenSaverCustomImageSource"] = false; - mStringMap["SlideshowScreenSaverImageDir"] = Utils::FileSystem::getHomePath() + - "/.emulationstation/slideshow/image"; - mBoolMap["SlideshowScreenSaverRecurse"] = false; - mStringMap["SlideshowScreenSaverImageFilter"] = ".png,.jpg"; + mIntMap["ScreensaverSwapImageTimeout"] = 8000; + mBoolMap["ScreensaverStretchImages"] = false; + mBoolMap["ScreensaverImageScanlines"] = true; + mStringMap["ScreensaverSlideshowAudioFile"] = + "~/.emulationstation/slideshow/audio/slideshow.wav"; + mBoolMap["ScreensaverSlideshowCustomImages"] = false; + mStringMap["ScreensaverSlideshowImageDir"] = "~/.emulationstation/slideshow/custom_images"; + mBoolMap["ScreensaverSlideshowRecurse"] = false; // UI settings -> screensaver settings -> video screensaver settings. - mIntMap["ScreenSaverSwapVideoTimeout"] = 25000; - mBoolMap["ScreenSaverStretchVideos"] = false; + mIntMap["ScreensaverSwapVideoTimeout"] = 25000; + mBoolMap["ScreensaverStretchVideos"] = false; #if defined(_RPI_) - mStringMap["ScreenSaverGameInfo"] = "never"; + mStringMap["ScreensaverGameInfo"] = "never"; #endif - mBoolMap["ScreenSaverVideoAudio"] = false; - mBoolMap["ScreenSaverVideoScanlines"] = true; - mBoolMap["ScreenSaverVideoBlur"] = false; + mBoolMap["ScreensaverVideoAudio"] = false; + mBoolMap["ScreensaverVideoScanlines"] = true; + mBoolMap["ScreensaverVideoBlur"] = false; // Sound settings. // The ALSA Audio Card and Audio Device selection code is disabled at the moment. @@ -151,66 +169,43 @@ void Settings::setDefaults() // Game collection settings. mStringMap["CollectionSystemsAuto"] = ""; mStringMap["CollectionSystemsCustom"] = ""; - mBoolMap["UseCustomCollectionsSystem"] = true; mBoolMap["FavFirstCustom"] = false; mBoolMap["FavStarCustom"] = false; + mBoolMap["UseCustomCollectionsSystem"] = true; mBoolMap["CollectionShowSystemInfo"] = true; - // Scraper. - mStringMap["Scraper"] = "screenscraper"; - mStringMap["ScraperRegion"] = "eu"; - mStringMap["ScraperLanguage"] = "en"; -// mBoolMap["ScraperGenerateMiximages"] = false; -// mBoolMap["ScraperGenerateThumbnails"] = false; - mBoolMap["ScraperInteractive"] = true; - mBoolMap["ScraperSemiautomatic"] = true; - mBoolMap["ScraperSearchMetadataName"] = true; - mBoolMap["ScraperOverwriteData"] = true; - mBoolMap["ScraperRespectExclusions"] = true; - mBoolMap["ScraperExcludeRecursively"] = true; - mBoolMap["ScraperIncludeFolders"] = false; - mBoolMap["ScrapeMetadata"] = true; - mBoolMap["ScrapeGameNames"] = true; - mBoolMap["ScrapeRatings"] = true; - mBoolMap["Scrape3DBoxes"] = true; - mBoolMap["ScrapeCovers"] = true; - mBoolMap["ScrapeMarquees"] = true; - mBoolMap["ScrapeScreenshots"] = true; - mBoolMap["ScrapeVideos"] = true; - // Other settings. #if defined(_RPI_) - mIntMap["MaxVRAM"] = 80; + mIntMap["MaxVRAM"] = 80; #else - mIntMap["MaxVRAM"] = 128; + mIntMap["MaxVRAM"] = 128; #endif #if defined (__unix__) mStringMap["FullscreenMode"] = "normal"; #endif mStringMap["PowerSaverMode"] = "disabled"; - // This setting only applies to raspberry pi but set it for all platforms so + // This setting only applies to Raspberry Pi but we set it for all platforms so // we don't get a warning if we encounter it on a different platform. mBoolMap["VideoOmxPlayer"] = false; #if defined(_RPI_) // We're defaulting to OMX Player for full screen video on the Pi. - mBoolMap["ScreenSaverOmxPlayer"] = true; - #else - mBoolMap["ScreenSaverOmxPlayer"] = false; + mBoolMap["ScreensaverOmxPlayer"] = true; #endif mStringMap["SaveGamelistsMode"] = "always"; #if defined(_WIN64) mBoolMap["HideTaskbar"] = false; - // Set this to true as default as it's unreliable to suspend ES during game launches - // on some Windows versions/installations. - mBoolMap["RunInBackground"] = true; + // This setting may cause problems on some Windows versions, but it seems as if Windows 10 + // handles the suspension of ES correctly. As there are some adverse affects from running ES + // in the background while a game is running, by default this is set to false. + mBoolMap["RunInBackground"] = false; #endif mStringMap["MediaDirectory"] = ""; mBoolMap["LaunchCommandOverride"] = true; - mBoolMap["CustomEventScripts"] = false; - mBoolMap["ParseGamelistOnly"] = false; - mBoolMap["LocalArt"] = false; mBoolMap["ShowHiddenFiles"] = true; mBoolMap["ShowHiddenGames"] = true; + mBoolMap["CustomEventScripts"] = false; + mBoolMap["ParseGamelistOnly"] = false; + mBoolMap["ROMDirGameMedia"] = false; mBoolMap["DisplayGPUStatistics"] = false; // macOS requires root privileges to reboot and power off so it doesn't make much // sense to enable these settings and menu entries for this operating system. @@ -293,7 +288,6 @@ void Settings::saveFile() saveMap(doc, mIntMap, "int"); saveMap(doc, mFloatMap, "float"); - //saveMap(doc, mStringMap, "string"); for (auto iter = mStringMap.cbegin(); iter != mStringMap.cend(); iter++) { pugi::xml_node node = doc.append_child("string"); node.append_attribute("name").set_value(iter->first.c_str()); diff --git a/es-core/src/Window.cpp b/es-core/src/Window.cpp index 56cef4987..f82dfde34 100644 --- a/es-core/src/Window.cpp +++ b/es-core/src/Window.cpp @@ -146,9 +146,9 @@ void Window::input(InputConfig* config, Input input) if (mScreenSaver) { if (mScreenSaver->isScreenSaverActive() && - Settings::getInstance()->getBool("ScreenSaverControls") && - ((Settings::getInstance()->getString("ScreenSaverBehavior") == "video") || - (Settings::getInstance()->getString("ScreenSaverBehavior") == "slideshow"))) { + Settings::getInstance()->getBool("ScreensaverControls") && + ((Settings::getInstance()->getString("ScreensaverBehavior") == "video") || + (Settings::getInstance()->getString("ScreensaverBehavior") == "slideshow"))) { if (mScreenSaver->getCurrentGame() != nullptr && (config->isMappedTo("a", input) || config->isMappedLike("left", input) || config->isMappedLike("right", input))) { @@ -358,11 +358,11 @@ void Window::render() if (!mRenderedHelpPrompts) mHelp->render(transform); - unsigned int screensaverTime = - static_cast(Settings::getInstance()->getInt("ScreenSaverTime")); + unsigned int screensaverTimer = + static_cast(Settings::getInstance()->getInt("ScreensaverTimer")); // If a game has been launched, reset the screensaver timer when it's been reached as we // don't want to start the screensaver in the background when running a game. - if (mTimeSinceLastInput >= screensaverTime && screensaverTime != 0) { + if (mTimeSinceLastInput >= screensaverTimer && screensaverTimer != 0) { if (mGameLaunchedState) mTimeSinceLastInput = 0; else if (!isProcessing() && !mScreenSaver->isScreenSaverActive()) @@ -376,7 +376,7 @@ void Window::render() if (!mRenderScreenSaver && mInfoPopup) mInfoPopup->render(transform); - if (mTimeSinceLastInput >= screensaverTime && screensaverTime != 0) { + if (mTimeSinceLastInput >= screensaverTimer && screensaverTimer != 0) { if (!isProcessing() && mAllowSleep && (!mScreenSaver)) { // Go to sleep. if (mSleeping == false) { @@ -389,11 +389,11 @@ void Window::render() #if defined(USE_OPENGL_21) // Shaders for the screensavers. if (mScreenSaver->isScreenSaverActive()) { - if (Settings::getInstance()->getString("ScreenSaverBehavior") == "video") { + if (Settings::getInstance()->getString("ScreensaverBehavior") == "video") { if (mScreenSaver->getVideoCount() > 0) { - if (Settings::getInstance()->getBool("ScreenSaverVideoBlur")) + if (Settings::getInstance()->getBool("ScreensaverVideoBlur")) Renderer::shaderPostprocessing(Renderer::SHADER_BLUR_HORIZONTAL); - if (Settings::getInstance()->getBool("ScreenSaverVideoScanlines")) + if (Settings::getInstance()->getBool("ScreensaverVideoScanlines")) Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES); } else { @@ -405,11 +405,11 @@ void Window::render() mDimValue = Math::clamp(mDimValue-0.045, 0.0, 1.0); } } - else if (Settings::getInstance()->getString("ScreenSaverBehavior") == "slideshow") { - if (Settings::getInstance()->getBool("ScreenSaverImageScanlines")) + else if (Settings::getInstance()->getString("ScreensaverBehavior") == "slideshow") { + if (Settings::getInstance()->getBool("ScreensaverImageScanlines")) Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES); } - else if (Settings::getInstance()->getString("ScreenSaverBehavior") == "dim") { + else if (Settings::getInstance()->getString("ScreensaverBehavior") == "dim") { Renderer::shaderParameters dimParameters; dimParameters.fragmentDimValue = mDimValue; Renderer::shaderPostprocessing(Renderer::SHADER_DIM, dimParameters); @@ -420,7 +420,7 @@ void Window::render() if (mSaturationAmount > 0.0) mSaturationAmount = Math::clamp(mSaturationAmount-0.035, 0.0, 1.0); } - else if (Settings::getInstance()->getString("ScreenSaverBehavior") == "black") { + else if (Settings::getInstance()->getString("ScreensaverBehavior") == "black") { Renderer::shaderParameters blackParameters; blackParameters.fragmentDimValue = mDimValue; Renderer::shaderPostprocessing(Renderer::SHADER_DIM, blackParameters); diff --git a/es-core/src/components/MenuComponent.cpp b/es-core/src/components/MenuComponent.cpp index 0e9a48b71..957341f51 100644 --- a/es-core/src/components/MenuComponent.cpp +++ b/es-core/src/components/MenuComponent.cpp @@ -22,7 +22,8 @@ MenuComponent::MenuComponent( const std::shared_ptr& titleFont) : GuiComponent(window), mBackground(window), - mGrid(window, Vector2i(1, 3)) + mGrid(window, Vector2i(1, 3)), + mNeedsSaving(false) { addChild(&mBackground); addChild(&mGrid); @@ -59,7 +60,10 @@ void MenuComponent::save() for (auto it = mSaveFuncs.cbegin(); it != mSaveFuncs.cend(); it++) (*it)(); - Settings::getInstance()->saveFile(); + if (mNeedsSaving) { + Settings::getInstance()->saveFile(); + mNeedsSaving = false; + } } void MenuComponent::setTitle(const char* title, const std::shared_ptr& font) diff --git a/es-core/src/components/MenuComponent.h b/es-core/src/components/MenuComponent.h index e5ddb9e27..ae17e3f02 100644 --- a/es-core/src/components/MenuComponent.h +++ b/es-core/src/components/MenuComponent.h @@ -34,6 +34,8 @@ public: void save(); void onSizeChanged() override; + void setNeedsSaving() { mNeedsSaving = true; }; + inline void addRow(const ComponentListRow& row, bool setCursorHere = false) { mList->addRow(row, setCursorHere); updateSize(); } @@ -70,8 +72,10 @@ private: std::shared_ptr mTitle; std::shared_ptr mList; std::shared_ptr mButtonGrid; - std::vector< std::shared_ptr > mButtons; - std::vector< std::function > mSaveFuncs; + std::vector> mButtons; + std::vector> mSaveFuncs; + + bool mNeedsSaving; }; #endif // ES_CORE_COMPONENTS_MENU_COMPONENT_H diff --git a/es-core/src/components/VideoComponent.cpp b/es-core/src/components/VideoComponent.cpp index 4a41e6dc4..5d3c3d1f3 100644 --- a/es-core/src/components/VideoComponent.cpp +++ b/es-core/src/components/VideoComponent.cpp @@ -332,7 +332,7 @@ void VideoComponent::onScreenSaverActivate() { mBlockPlayer = true; mPause = true; - if (Settings::getInstance()->getString("ScreenSaverBehavior") == "dim") + if (Settings::getInstance()->getString("ScreensaverBehavior") == "dim") stopVideo(); manageState(); } diff --git a/es-core/src/components/VideoPlayerComponent.cpp b/es-core/src/components/VideoPlayerComponent.cpp index 9d1d77e30..0e0f18eb7 100644 --- a/es-core/src/components/VideoPlayerComponent.cpp +++ b/es-core/src/components/VideoPlayerComponent.cpp @@ -165,7 +165,7 @@ void VideoPlayerComponent::startVideo() // Check if we want to mute the audio. if ((!Settings::getInstance()->getBool("GamelistVideoAudio") || (float)VolumeControl::getInstance()->getVolume() == 0) || - (!Settings::getInstance()->getBool("ScreenSaverVideoAudio") && + (!Settings::getInstance()->getBool("ScreensaverVideoAudio") && mScreensaverMode)) { argv[8] = "-1000000"; } diff --git a/es-core/src/components/VideoVlcComponent.cpp b/es-core/src/components/VideoVlcComponent.cpp index 6b5e68362..7bc435652 100644 --- a/es-core/src/components/VideoVlcComponent.cpp +++ b/es-core/src/components/VideoVlcComponent.cpp @@ -237,7 +237,7 @@ void VideoVlcComponent::handleLooping() libvlc_media_player_set_media(mMediaPlayer, mMedia); if ((!Settings::getInstance()->getBool("GamelistVideoAudio") && !mScreensaverMode) || - (!Settings::getInstance()->getBool("ScreenSaverVideoAudio") && mScreensaverMode)) + (!Settings::getInstance()->getBool("ScreensaverVideoAudio") && mScreensaverMode)) libvlc_audio_set_mute(mMediaPlayer, 1); libvlc_media_player_play(mMediaPlayer); @@ -316,7 +316,7 @@ void VideoVlcComponent::startVideo() if ((!Settings::getInstance()->getBool("GamelistVideoAudio") && !mScreensaverMode) || - (!Settings::getInstance()->getBool("ScreenSaverVideoAudio") && + (!Settings::getInstance()->getBool("ScreensaverVideoAudio") && mScreensaverMode)) libvlc_audio_set_mute(mMediaPlayer, 1);