From bbb2aa5217b5251063048fc83783e4ffdb215957 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Tue, 10 Nov 2020 22:18:20 +0100 Subject: [PATCH] Overhaul of the screensaver. --- NEWS.md | 3 + USERGUIDE.md | 40 +- es-app/src/SystemScreenSaver.cpp | 562 +++++++++--------- es-app/src/SystemScreenSaver.h | 51 +- es-app/src/guis/GuiScreensaverOptions.cpp | 167 +++--- es-app/src/main.cpp | 2 +- es-app/src/views/SystemView.cpp | 6 +- .../src/views/gamelist/VideoGameListView.cpp | 2 +- es-core/src/PowerSaver.cpp | 6 +- es-core/src/PowerSaver.h | 4 +- es-core/src/Settings.cpp | 11 +- es-core/src/Window.cpp | 77 ++- es-core/src/Window.h | 25 +- .../src/components/ScrollableContainer.cpp | 2 +- es-core/src/components/TextListComponent.h | 2 +- es-core/src/components/VideoComponent.cpp | 2 +- 16 files changed, 463 insertions(+), 499 deletions(-) diff --git a/NEWS.md b/NEWS.md index c8a7215a8..9a370a4d5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -27,6 +27,7 @@ Many bugs have been fixed, and numerous features that were only partially implem * Files or folders can now be flagged for exclusion when scraping with the multi-scraper, and for folders it can be set to apply recursively * Gamelist sorting is now working as expected and is persistent throughout the application session * Overhaul of the game collection functionality including many bug fixes and optimizations +* Added ability to delete custom collections from the GUI menu * Game counting is now done during sorting instead of every time a system is selected. This should make the UI more responsive in case of large game libraries * Added a system view counter for favorite games in addition to the total number of games * Added support for jumping to the start and end of gamelists and menus using the controller trigger buttons (or equivalent keyboard mappings) @@ -90,8 +91,10 @@ Many bugs have been fixed, and numerous features that were only partially implem * The random game selection traversed folders, i.e. a game could be selected inside a subdirectory and vice versa * Deleting a game from the metadata editor did not delete the game media files or the entry in the gamelist.xml file * SystemView didn't properly loop the systems if only two systems were available +* Switching to the Grid view style with a placeholder shown in the gamelist crashed the application * When changing to the video view style from inside a gamelist, the view was not completely initialized * Hidden files still showed up if they had a gamelist.xml entry +* FileSystemUtil::getDirContent() crashed when searching through directories recursively * Fixed an annoying gamelist issue that caused the game images and data to be updated and rendered up to six times every time the list was scrolled * VRAM statistics overlay was somewhat broken and incorrectly displayed numbers in megabytes instead of mebibytes * Not all input events were logged when running with debug logging activated diff --git a/USERGUIDE.md b/USERGUIDE.md index ec0df38a5..3761a1c7d 100644 --- a/USERGUIDE.md +++ b/USERGUIDE.md @@ -669,25 +669,25 @@ Hiding or showing the menu when the UI mode is set to Kid. Settings for the built-in screensaver. -**Screensaver after** +**Start screensaver after (minutes)** -After how many minutes to start the screensaver. If set to 0 minutes, the automatic screensaver will be deactivated. It can however still be started manually, if the Screensaver controls settings is activated. +After how many minutes to start the screensaver. If set to 0 minutes, the timer will be deactivated and the screensaver will never start automatically. It's however still possible to start the screensaver manually in this case, assuming the _Enable screensaver controls_ setting is enabled. Note that while any menu is open, the screensaver will not start. -**Screensaver controls** +**Screensaver type** + +The screensaven type to use; _Dim_, _Black_, _Slideshow_ or _Video_. + +**Enable screensaver controls** This includes the ability to start the screensaver manually, but also to browse Left and Right between images or videos, and to launch the game shown by the screensaver using the A button. -**Screensaver behavior** - -The screensaven style to use, which includes _Dim_, _Black_, _Slideshow_ and _Video_. - #### Slideshow screensaver settings Options specific to the slideshow screensaver. -**Swap images after (secs)** +**Swap images after (seconds)** -How long to play videos before changing to the next game. Allowed range is between 5 and 120 seconds. +For how long to display images before changing to the next game. Allowed range is between 5 and 120 seconds. **Stretch images to screen resolution** @@ -697,33 +697,29 @@ This will fill the entire screen surface but will possibly break the aspect rati Whether to use a shader to render scanlines on top of the images. -**Background audio** - -Background audio to play when the screensaver is active. - **Use custom images** Using this option, it's possible to use custom images instead of random images from the game library. -**Custom image dir** - -The directory for the custom images. - -**Custom image dir recursive** +**Custom image directory recursive search** Whether to search the custom image directory recursively. -**Custom image filter** +**Custom image directory** -The file extensions to consider for the custom images. +The directory for the custom images. #### Video screensaver settings Options specific to the video screensaver. -**Swap videos after (secs)** +**Swap videos after (seconds)** -How long to play videos before changing to the next game. Allowed range is between 5 and 120 seconds. +For how long to play videos before changing to the next game. Allowed range is between 5 and 120 seconds. + +**Show game info overlay** + +This will display an overlay on top of the videos, showing the game name and game system name. **Stretch videos to screen resolution** diff --git a/es-app/src/SystemScreenSaver.cpp b/es-app/src/SystemScreenSaver.cpp index 07062dd5b..29c96b262 100644 --- a/es-app/src/SystemScreenSaver.cpp +++ b/es-app/src/SystemScreenSaver.cpp @@ -3,7 +3,7 @@ // EmulationStation Desktop Edition // SystemScreenSaver.cpp // -// Screensaver, supporting the following modes: +// Screensaver, supporting the following types: // Dim, black, slideshow, video. // @@ -17,12 +17,11 @@ #include "views/gamelist/IGameListView.h" #include "views/ViewController.h" #include "FileData.h" -#include "FileFilterIndex.h" #include "Log.h" #include "PowerSaver.h" -#include "Sound.h" #include "SystemData.h" +#include #include #include @@ -32,73 +31,126 @@ #define FADE_TIME 300 -SystemScreenSaver::SystemScreenSaver( - Window* window) - : mVideoScreensaver(nullptr), - mImageScreensaver(nullptr), - mWindow(window), - mVideosCounted(false), - mVideoCount(0), - mImagesCounted(false), - mImageCount(0), - mState(STATE_INACTIVE), - mOpacity(0.0f), - mTimer(0), - mSystemName(""), - mGameName(""), - mCurrentGame(nullptr), - mStopBackgroundAudio(true) +SystemScreensaver::SystemScreensaver( + Window* window) + : mImageScreensaver(nullptr), + mVideoScreensaver(nullptr), + mWindow(window), + mState(STATE_INACTIVE), + mOpacity(0.0f), + mTimer(0), + mSystemName(""), + mGameName(""), + mCurrentGame(nullptr), + mHasMediaFiles(false) { - mWindow->setScreenSaver(this); - - srand((unsigned int)time(nullptr)); + mWindow->setScreensaver(this); mVideoChangeTime = 30000; } -SystemScreenSaver::~SystemScreenSaver() +SystemScreensaver::~SystemScreensaver() { mCurrentGame = nullptr; delete mVideoScreensaver; delete mImageScreensaver; } -bool SystemScreenSaver::allowSleep() +bool SystemScreensaver::allowSleep() { return ((mVideoScreensaver == nullptr) && (mImageScreensaver == nullptr)); } -bool SystemScreenSaver::isScreenSaverActive() +bool SystemScreensaver::isScreensaverActive() { return (mState != STATE_INACTIVE); } -void SystemScreenSaver::startScreenSaver() +void SystemScreensaver::startScreensaver(bool generateMediaList) { - std::string screensaver_behavior = Settings::getInstance()->getString("ScreensaverBehavior"); + std::string path = ""; + std::string screensaverType = Settings::getInstance()->getString("ScreensaverType"); + mHasMediaFiles = false; // Set mPreviousGame which will be used to avoid showing the same game again during // the random selection. - if ((screensaver_behavior == "video" || screensaver_behavior == "slideshow") && + if ((screensaverType == "video" || screensaverType == "slideshow") && mCurrentGame != nullptr) mPreviousGame = mCurrentGame; - if (!mVideoScreensaver && (screensaver_behavior == "video")) { - // 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; + if (screensaverType == "slideshow") { + if (generateMediaList) { + mImageFiles.clear(); + mImageCustomFiles.clear(); + } + + // This creates a fade transition between the images. + mState = STATE_FADE_OUT_WINDOW; + + mVideoChangeTime = Settings::getInstance()->getInt("ScreensaverSwapImageTimeout"); + mOpacity = 0.0f; + + // Load a random image. + if (Settings::getInstance()->getBool("ScreensaverSlideshowCustomImages")) { + if (generateMediaList) + generateCustomImageList(); + pickRandomCustomImage(path); + + if (mImageCustomFiles.size() > 0) + mHasMediaFiles = true; + // Custom images are not tied to the game list. + mCurrentGame = nullptr; + } + else { + if (generateMediaList) + generateImageList(); + pickRandomImage(path); + } + + if (mImageFiles.size() > 0) + mHasMediaFiles = true; + + // Don't attempt to render the screensaver if there are no images available, but + // do flag it as running. This way Window::render() will fade to a black screen, i.e. + // it will activate the 'Black' screensaver type. + if (mImageFiles.size() > 0 || mImageCustomFiles.size() > 0) { + if (!mImageScreensaver) + mImageScreensaver = new ImageComponent(mWindow, false, false); + + mTimer = 0; + + mImageScreensaver->setImage(path); + mImageScreensaver->setOrigin(0.5f, 0.5f); + mImageScreensaver->setPosition(Renderer::getScreenWidth() / 2.0f, + Renderer::getScreenHeight() / 2.0f); + + if (Settings::getInstance()->getBool("ScreensaverStretchImages")) + mImageScreensaver->setResize(static_cast(Renderer::getScreenWidth()), + static_cast(Renderer::getScreenHeight())); + else + mImageScreensaver->setMaxSize(static_cast(Renderer::getScreenWidth()), + static_cast(Renderer::getScreenHeight())); + } + PowerSaver::runningScreensaver(true); + mTimer = 0; + return; + } + else if (!mVideoScreensaver && (screensaverType == "video")) { + if (generateMediaList) + mVideoFiles.clear(); + + // This creates a fade transition between the videos. + mState = STATE_FADE_OUT_WINDOW; + mVideoChangeTime = Settings::getInstance()->getInt("ScreensaverSwapVideoTimeout"); mOpacity = 0.0f; // Load a random video. - std::string path = ""; + if (generateMediaList) + generateVideoList(); pickRandomVideo(path); - int retry = 200; - while (retry > 0 && ((path.empty() || !Utils::FileSystem::exists(path)) || - mCurrentGame == nullptr)) { - retry--; - pickRandomVideo(path); - } + if (mVideoFiles.size() > 0) + mHasMediaFiles = true; if (!path.empty() && Utils::FileSystem::exists(path)) { #if defined(_RPI_) @@ -126,92 +178,49 @@ void SystemScreenSaver::startScreenSaver() mVideoScreensaver->setVideo(path); mVideoScreensaver->setScreensaverMode(true); mVideoScreensaver->onShow(); - PowerSaver::runningScreenSaver(true); + PowerSaver::runningScreensaver(true); mTimer = 0; return; } } - else if (screensaver_behavior == "slideshow") { - // 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"); - mOpacity = 0.0f; - - // Load a random image. - std::string path = ""; - if (Settings::getInstance()->getBool("ScreensaverSlideshowCustomImages")) { - pickRandomCustomImage(path); - // Custom images are not tied to the game list. - mCurrentGame = nullptr; - } - else { - pickRandomGameListImage(path); - } - - if (!mImageScreensaver) - mImageScreensaver = new ImageComponent(mWindow, false, false); - - mTimer = 0; - - mImageScreensaver->setImage(path); - mImageScreensaver->setOrigin(0.5f, 0.5f); - mImageScreensaver->setPosition(Renderer::getScreenWidth() / 2.0f, - Renderer::getScreenHeight() / 2.0f); - - if (Settings::getInstance()->getBool("ScreensaverStretchImages")) - mImageScreensaver->setResize(static_cast(Renderer::getScreenWidth()), - static_cast(Renderer::getScreenHeight())); - else - mImageScreensaver->setMaxSize(static_cast(Renderer::getScreenWidth()), - static_cast(Renderer::getScreenHeight())); - - std::string bg_audio_file = Settings::getInstance()-> - getString("ScreensaverSlideshowAudioFile"); - if ((!mBackgroundAudio) && (bg_audio_file != "")) { - if (Utils::FileSystem::exists(bg_audio_file)) { - // Pause PowerSaver so that the background audio keeps playing. - PowerSaver::pause(); - mBackgroundAudio = Sound::get(bg_audio_file); - mBackgroundAudio->play(); - } - } - - PowerSaver::runningScreenSaver(true); - mTimer = 0; - return; - } - // No videos. Just use a standard screensaver. + // No videos or images, just use a standard screensaver. mState = STATE_SCREENSAVER_ACTIVE; mCurrentGame = nullptr; } -void SystemScreenSaver::stopScreenSaver() +void SystemScreensaver::stopScreensaver() { - if ((mBackgroundAudio) && (mStopBackgroundAudio)) { - mBackgroundAudio->stop(); - mBackgroundAudio.reset(); - // If we were playing audio, we paused PowerSaver. - PowerSaver::resume(); - } - - // So that we stop the background audio next time, unless we're restarting the screensaver. - mStopBackgroundAudio = true; - delete mVideoScreensaver; mVideoScreensaver = nullptr; delete mImageScreensaver; mImageScreensaver = nullptr; - // We need this to loop through different videos. mState = STATE_INACTIVE; - PowerSaver::runningScreenSaver(false); + PowerSaver::runningScreensaver(false); } -void SystemScreenSaver::renderScreenSaver() +void SystemScreensaver::nextGame() { + stopScreensaver(); + startScreensaver(false); +} + +void SystemScreensaver::launchGame() { - std::string screensaver_behavior = Settings::getInstance()->getString("ScreensaverBehavior"); - if (mVideoScreensaver && screensaver_behavior == "video") { + if (mCurrentGame != nullptr) { + // Launching game + ViewController::get()->goToGameList(mCurrentGame->getSystem()); + IGameListView* view = ViewController::get()-> + getGameListView(mCurrentGame->getSystem()).get(); + view->setCursor(mCurrentGame); + ViewController::get()->resetMovingCamera(); + ViewController::get()->launch(mCurrentGame); + } +} + +void SystemScreensaver::renderScreensaver() +{ + std::string screensaverType = Settings::getInstance()->getString("ScreensaverType"); + if (mVideoScreensaver && screensaverType == "video") { // Render black background. Renderer::setMatrix(Transform4x4f::Identity()); Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), @@ -223,14 +232,14 @@ void SystemScreenSaver::renderScreenSaver() mVideoScreensaver->render(transform); } } - else if (mImageScreensaver && screensaver_behavior == "slideshow") { - // Render black background. + else if (mImageScreensaver && screensaverType == "slideshow") { + // Render a black background. Renderer::setMatrix(Transform4x4f::Identity()); Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(), 0x000000FF, 0x000000FF); // Only render the video if the state requires it. - if ((int)mState >= STATE_FADE_IN_VIDEO) { + if (static_cast(mState) >= STATE_FADE_IN_VIDEO) { if (mImageScreensaver->hasImage()) { mImageScreensaver->setOpacity(255 - static_cast(mOpacity * 255)); @@ -238,181 +247,18 @@ void SystemScreenSaver::renderScreenSaver() mImageScreensaver->render(transform); } } - - // Check if we need to restart the background audio. - if ((mBackgroundAudio) && (Settings::getInstance()-> - getString("ScreensaverSlideshowAudioFile") != "")) { - if (!mBackgroundAudio->isPlaying()) - mBackgroundAudio->play(); - } } + #if !defined(USE_OPENGL_21) else if (mState != STATE_INACTIVE) { - #if !defined(USE_OPENGL_21) Renderer::setMatrix(Transform4x4f::Identity()); - unsigned char color = screensaver_behavior == "dim" ? 0x000000A0 : 0x000000FF; + unsigned char color = screensaverType == "dim" ? 0x000000A0 : 0x000000FF; Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(), color, color); - #endif } + #endif } -unsigned long SystemScreenSaver::countGameListNodes(const char *nodeName) -{ - unsigned long nodeCount = 0; - std::vector::const_iterator it; - for (it = SystemData::sSystemVector.cbegin(); - it != SystemData::sSystemVector.cend(); ++it) { - // We only want nodes from game systems that are not collections. - if (!(*it)->isGameSystem() || (*it)->isCollection()) - continue; - - FileData* rootFileData = (*it)->getRootFolder(); - - FileType type = GAME; - std::vector allFiles = rootFileData->getFilesRecursive(type, true); - std::vector::const_iterator itf; // Declare an iterator to a vector of strings. - - for (itf=allFiles.cbegin() ; itf < allFiles.cend(); itf++) { - if ((strcmp(nodeName, "video") == 0 && (*itf)->getVideoPath() != "") || - (strcmp(nodeName, "image") == 0 && (*itf)->getImagePath() != "")) - nodeCount++; - } - } - return nodeCount; -} - -void SystemScreenSaver::countVideos() -{ - if (!mVideosCounted) { - mVideoCount = countGameListNodes("video"); - mVideosCounted = true; - } -} - -void SystemScreenSaver::countImages() -{ - if (!mImagesCounted) { - mImageCount = countGameListNodes("image"); - mImagesCounted = true; - } -} - -void SystemScreenSaver::pickGameListNode(unsigned long index, - const char *nodeName, std::string& path) -{ - std::vector::const_iterator it; - for (it = SystemData::sSystemVector.cbegin(); - it != SystemData::sSystemVector.cend(); ++it) { - // We only want nodes from game systems that are not collections. - if (!(*it)->isGameSystem() || (*it)->isCollection()) - continue; - - FileData* rootFileData = (*it)->getRootFolder(); - - FileType type = GAME; - std::vector allFiles = rootFileData->getFilesRecursive(type, true); - std::vector::const_iterator itf; // Declare an iterator to a vector of strings. - - for (itf=allFiles.cbegin() ; itf < allFiles.cend(); itf++) { - if ((strcmp(nodeName, "video") == 0 && (*itf)->getVideoPath() != "") || - (strcmp(nodeName, "image") == 0 && (*itf)->getImagePath() != "")) { - if (index-- == 0) { - // We have it. - path = ""; - if (strcmp(nodeName, "video") == 0) - path = (*itf)->getVideoPath(); - else if (strcmp(nodeName, "image") == 0) - path = (*itf)->getImagePath(); - mSystemName = (*it)->getFullName(); - mGameName = (*itf)->getName(); - mCurrentGame = (*itf); - - // End of getting FileData. - return; - } - } - } - } -} - -void SystemScreenSaver::pickRandomVideo(std::string& path) -{ - countVideos(); - mCurrentGame = nullptr; - - if (mVideoCount < 2) - mPreviousGame = nullptr; - - // If there are more than 1 videos available, keep trying until the same game is - // not shown again. - if (mVideoCount > 0) { - do { - int video = static_cast((static_cast(rand()) / - static_cast(RAND_MAX)) * static_cast(mVideoCount)); - pickGameListNode(video, "video", path); - } - while (mPreviousGame && mCurrentGame == mPreviousGame); - } -} - -void SystemScreenSaver::pickRandomGameListImage(std::string& path) -{ - countImages(); - mCurrentGame = nullptr; - - if (mImageCount < 2) - mPreviousGame = nullptr; - - // If there are more than 1 images available, keep trying until the same game is - // not shown again. - if (mImageCount > 0) { - do { - int image = static_cast((static_cast(rand()) / - static_cast(RAND_MAX)) * static_cast(mImageCount)); - pickGameListNode(image, "image", path); - } - while (mPreviousGame && mCurrentGame == mPreviousGame); - } -} - -void SystemScreenSaver::pickRandomCustomImage(std::string& path) -{ - std::string imageDir = Settings::getInstance()->getString("ScreensaverSlideshowImageDir"); - - if ((imageDir != "") && (Utils::FileSystem::exists(imageDir))) { - std::string imageFilter = ".jpg, .JPG, .png, .PNG"; - std::vector matchingFiles; - Utils::FileSystem::stringList dirContent = Utils::FileSystem::getDirContent( - imageDir, Settings::getInstance()->getBool("ScreensaverSlideshowRecurse")); - - for (Utils::FileSystem::stringList::const_iterator it = dirContent.cbegin(); - it != dirContent.cend(); ++it) { - if (Utils::FileSystem::isRegularFile(*it)) { - // If the image filter is empty, or the file extension is in the filter - // string, add it to the matching files list. - if ((imageFilter.length() <= 0) || (imageFilter.find( - Utils::FileSystem::getExtension(*it)) != std::string::npos)) - matchingFiles.push_back(*it); - } - } - - int fileCount = static_cast(matchingFiles.size()); - if (fileCount > 0) { - // Get a random index in the range 0 to fileCount (exclusive). - int randomIndex = rand() % fileCount; - path = matchingFiles[randomIndex]; - } - else { - LOG(LogError) << "Slideshow Screensaver - No image files found\n"; - } - } - else { - LOG(LogError) << "Slideshow Screensaver - Image directory does not exist: " << - imageDir << "\n"; - } -} - -void SystemScreenSaver::update(int deltaTime) +void SystemScreensaver::update(int deltaTime) { // Use this to update the fade value for the current fade stage. if (mState == STATE_FADE_OUT_WINDOW) { @@ -446,27 +292,149 @@ void SystemScreenSaver::update(int deltaTime) mImageScreensaver->update(deltaTime); } -void SystemScreenSaver::nextGame() { - mStopBackgroundAudio = false; - stopScreenSaver(); - startScreenSaver(); - mState = STATE_SCREENSAVER_ACTIVE; -} - -FileData* SystemScreenSaver::getCurrentGame() +void SystemScreensaver::generateImageList() { - return mCurrentGame; -} + for (auto it = SystemData::sSystemVector.cbegin(); + it != SystemData::sSystemVector.cend(); ++it) { + // We only want nodes from game systems that are not collections. + if (!(*it)->isGameSystem() || (*it)->isCollection()) + continue; -void SystemScreenSaver::launchGame() -{ - if (mCurrentGame != nullptr) { - // Launching game - ViewController::get()->goToGameList(mCurrentGame->getSystem()); - IGameListView* view = ViewController::get()-> - getGameListView(mCurrentGame->getSystem()).get(); - view->setCursor(mCurrentGame); - ViewController::get()->resetMovingCamera(); - ViewController::get()->launch(mCurrentGame); + std::vector allFiles = (*it)->getRootFolder()->getFilesRecursive(GAME, true); + for (auto it = allFiles.begin(); it != allFiles.end(); it++) { + std::string imagePath = (*it)->getImagePath(); + if (imagePath != "") + mImageFiles.push_back((*it)); + } } } + +void SystemScreensaver::generateVideoList() +{ + for (auto it = SystemData::sSystemVector.cbegin(); + it != SystemData::sSystemVector.cend(); ++it) { + // We only want nodes from game systems that are not collections. + if (!(*it)->isGameSystem() || (*it)->isCollection()) + continue; + + std::vector allFiles = (*it)->getRootFolder()->getFilesRecursive(GAME, true); + for (auto it = allFiles.begin(); it != allFiles.end(); it++) { + std::string videoPath = (*it)->getVideoPath(); + if (videoPath != "") + mVideoFiles.push_back((*it)); + } + } +} + +void SystemScreensaver::generateCustomImageList() +{ + std::string imageDir = Utils::FileSystem::expandHomePath( + Settings::getInstance()->getString("ScreensaverSlideshowImageDir")); + + if (imageDir != "" && Utils::FileSystem::isDirectory(imageDir)) { + std::string imageFilter = ".jpg, .JPG, .png, .PNG"; + Utils::FileSystem::stringList dirContent = Utils::FileSystem::getDirContent( + imageDir, Settings::getInstance()->getBool("ScreensaverSlideshowRecurse")); + + for (auto it = dirContent.begin(); it != dirContent.end(); it++) { + if (Utils::FileSystem::isRegularFile(*it)) { + if (imageFilter.find(Utils::FileSystem::getExtension(*it)) != std::string::npos) + mImageCustomFiles.push_back(*it); + } + } + } + else { + LOG(LogWarning) << "Custom screensaver image directory '" << + imageDir << "' does not exist."; + } +} + +void SystemScreensaver::pickRandomImage(std::string& path) +{ + mCurrentGame = nullptr; + + if (mImageFiles.size() == 0) + return; + + if (mImageFiles.size() == 1) { + mPreviousGame = nullptr; + mCurrentGame = mImageFiles.front(); + path = mImageFiles.front()->getImagePath(); + return; + } + + unsigned int index; + do { + // Get a random number in range. + std::random_device randDev; + // Mersenne Twister pseudorandom number generator. + std::mt19937 engine{randDev()}; + std::uniform_int_distribution uniform_dist(0, mImageFiles.size() - 1); + index = uniform_dist(engine); + } + while (mPreviousGame && mImageFiles.at(index) == mPreviousGame); + + path = mImageFiles.at(index)->getImagePath(); + mGameName = mImageFiles.at(index)->getName(); + mSystemName = mImageFiles.at(index)->getSystem()->getFullName(); + mCurrentGame = mImageFiles.at(index); +} + +void SystemScreensaver::pickRandomVideo(std::string& path) +{ + mCurrentGame = nullptr; + + if (mVideoFiles.size() == 0) + return; + + if (mVideoFiles.size() == 1) { + mPreviousGame = nullptr; + mCurrentGame = mVideoFiles.front(); + path = mVideoFiles.front()->getVideoPath(); + return; + } + + unsigned int index; + do { + // Get a random number in range. + std::random_device randDev; + // Mersenne Twister pseudorandom number generator. + std::mt19937 engine{randDev()}; + std::uniform_int_distribution uniform_dist(0, mVideoFiles.size() - 1); + index = uniform_dist(engine); + } + while (mPreviousGame && mVideoFiles.at(index) == mPreviousGame); + + path = mVideoFiles.at(index)->getVideoPath(); + mGameName = mVideoFiles.at(index)->getName(); + mSystemName = mVideoFiles.at(index)->getSystem()->getFullName(); + mCurrentGame = mVideoFiles.at(index); +} + +void SystemScreensaver::pickRandomCustomImage(std::string& path) +{ + if (mImageCustomFiles.size() == 0) + return; + + if (mVideoFiles.size() == 1) { + mPreviousCustomImage = mImageCustomFiles.front(); + path = mImageCustomFiles.front(); + return; + } + + unsigned int index; + do { + // Get a random number in range. + std::random_device randDev; + // Mersenne Twister pseudorandom number generator. + std::mt19937 engine{randDev()}; + std::uniform_int_distribution uniform_dist(0, mImageCustomFiles.size() - 1); + index = uniform_dist(engine); + } + while (mPreviousCustomImage != "" && mImageCustomFiles.at(index) == mPreviousCustomImage); + + path = mImageCustomFiles.at(index); + mPreviousCustomImage = path; + mGameName = ""; + mSystemName = ""; +} diff --git a/es-app/src/SystemScreenSaver.h b/es-app/src/SystemScreenSaver.h index f765bf242..b745d5a22 100644 --- a/es-app/src/SystemScreenSaver.h +++ b/es-app/src/SystemScreenSaver.h @@ -3,7 +3,7 @@ // EmulationStation Desktop Edition // SystemScreenSaver.h // -// Screensaver, supporting the following modes: +// Screensaver, supporting the following types: // Dim, black, slideshow, video. // @@ -16,37 +16,35 @@ class ImageComponent; class Sound; class VideoComponent; -// Screensaver implementation for main window. -class SystemScreenSaver : public Window::ScreenSaver +// Screensaver implementation. +class SystemScreensaver : public Window::Screensaver { public: - SystemScreenSaver(Window* window); - virtual ~SystemScreenSaver(); + SystemScreensaver(Window* window); + virtual ~SystemScreensaver(); - virtual void startScreenSaver(); - virtual void stopScreenSaver(); - virtual void nextGame(); - virtual void renderScreenSaver(); virtual bool allowSleep(); - virtual void update(int deltaTime); - virtual bool isScreenSaverActive(); + virtual bool isScreensaverActive(); - virtual FileData* getCurrentGame(); + virtual void startScreensaver(bool generateMediaList); + virtual void stopScreensaver(); + virtual void nextGame(); virtual void launchGame(); - virtual void resetCounts() { mVideosCounted = false; mImagesCounted = false; }; - virtual unsigned int getVideoCount() { return mVideoCount; }; + + virtual void renderScreensaver(); + virtual void update(int deltaTime); + + virtual bool getHasMediaFiles() { return mHasMediaFiles; }; + virtual FileData* getCurrentGame() { return mCurrentGame; }; private: - unsigned long countGameListNodes(const char *nodeName); - void countVideos(); - void countImages(); - void pickGameListNode(unsigned long index, const char *nodeName, std::string& path); + void generateImageList(); + void generateVideoList(); + void generateCustomImageList(); + void pickRandomImage(std::string& path); void pickRandomVideo(std::string& path); - void pickRandomGameListImage(std::string& path); void pickRandomCustomImage(std::string& path); - void input(InputConfig* config, Input input); - enum STATE { STATE_INACTIVE, STATE_FADE_OUT_WINDOW, @@ -54,11 +52,11 @@ private: STATE_SCREENSAVER_ACTIVE }; - bool mVideosCounted; - unsigned long mVideoCount; + std::vector mImageFiles; + std::vector mVideoFiles; + std::vector mImageCustomFiles; + bool mHasMediaFiles; VideoComponent* mVideoScreensaver; - bool mImagesCounted; - unsigned long mImageCount; ImageComponent* mImageScreensaver; Window* mWindow; STATE mState; @@ -66,11 +64,10 @@ private: int mTimer; FileData* mCurrentGame; FileData* mPreviousGame; + std::string mPreviousCustomImage; std::string mGameName; std::string mSystemName; int mVideoChangeTime; - std::shared_ptr mBackgroundAudio; - bool mStopBackgroundAudio; }; #endif // ES_APP_SYSTEM_SCREEN_SAVER_H diff --git a/es-app/src/guis/GuiScreensaverOptions.cpp b/es-app/src/guis/GuiScreensaverOptions.cpp index 92e8bf18b..32edec379 100644 --- a/es-app/src/guis/GuiScreensaverOptions.cpp +++ b/es-app/src/guis/GuiScreensaverOptions.cpp @@ -19,24 +19,54 @@ GuiScreensaverOptions::GuiScreensaverOptions(Window* window, const char* title) : GuiSettings(window, title) { // Screensaver timer. - auto screensaver_time = std::make_shared(mWindow, 0.f, 30.f, 1.f, "m"); - screensaver_time->setValue(static_cast(Settings::getInstance()-> + auto screensaver_timer = std::make_shared(mWindow, 0.f, 30.f, 1.f, "m"); + screensaver_timer->setValue(static_cast(Settings::getInstance()-> getInt("ScreensaverTimer") / (1000 * 60))); - addWithLabel("SCREENSAVER AFTER", screensaver_time); - addSaveFunc([screensaver_time, this] { - if (static_cast(Math::round(screensaver_time->getValue()) * (1000 * 60)) != + addWithLabel("START SCREENSAVER AFTER (MINUTES)", screensaver_timer); + addSaveFunc([screensaver_timer, this] { + if (static_cast(Math::round(screensaver_timer->getValue()) * (1000 * 60)) != Settings::getInstance()->getInt("ScreensaverTimer")) { Settings::getInstance()->setInt("ScreensaverTimer", - static_cast(Math::round(screensaver_time->getValue()) * (1000 * 60))); + static_cast(Math::round(screensaver_timer->getValue()) * (1000 * 60))); PowerSaver::updateTimeouts(); setNeedsSaving(); } }); + // Screensaver type. + auto screensaver_type = std::make_shared> + (mWindow, getHelpStyle(), "SCREENSAVER TYPE", false); + std::vector screensavers; + screensavers.push_back("dim"); + screensavers.push_back("black"); + screensavers.push_back("slideshow"); + screensavers.push_back("video"); + for (auto it = screensavers.cbegin(); it != screensavers.cend(); it++) + screensaver_type->add(*it, *it, Settings::getInstance()-> + getString("ScreensaverType") == *it); + addWithLabel("SCREENSAVER TYPE", screensaver_type); + addSaveFunc([screensaver_type, this] { + if (screensaver_type->getSelected() != + Settings::getInstance()->getString("ScreensaverType")) { + if (screensaver_type->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("ScreensaverType", + screensaver_type->getSelected()); + setNeedsSaving(); + PowerSaver::updateTimeouts(); + } + }); + // Whether to enable screensaver controls. auto screensaver_controls = std::make_shared(mWindow); screensaver_controls->setState(Settings::getInstance()->getBool("ScreensaverControls")); - addWithLabel("SCREENSAVER CONTROLS", screensaver_controls); + addWithLabel("ENABLE SCREENSAVER CONTROLS", screensaver_controls); addSaveFunc([screensaver_controls, this] { if (screensaver_controls->getState() != Settings::getInstance()->getBool("ScreensaverControls")) { @@ -46,39 +76,8 @@ GuiScreensaverOptions::GuiScreensaverOptions(Window* window, const char* title) } }); - // Screensaver behavior. - auto screensaver_behavior = std::make_shared> - (mWindow, getHelpStyle(), "SCREENSAVER BEHAVIOR", false); - std::vector screensavers; - screensavers.push_back("dim"); - screensavers.push_back("black"); - screensavers.push_back("slideshow"); - screensavers.push_back("video"); - for (auto it = screensavers.cbegin(); it != screensavers.cend(); it++) - screensaver_behavior->add(*it, *it, Settings::getInstance()-> - getString("ScreensaverBehavior") == *it); - addWithLabel("SCREENSAVER BEHAVIOR", screensaver_behavior); - 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(); - } - }); - - ComponentListRow row; - // Show filtered menu. + ComponentListRow row; row.elements.clear(); row.addElement(std::make_shared(mWindow, "SLIDESHOW SCREENSAVER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); @@ -105,7 +104,7 @@ void GuiScreensaverOptions::openSlideshowScreensaverOptions() 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->addWithLabel("SWAP IMAGES AFTER (SECONDS)", screensaver_swap_image_timeout); s->addSaveFunc([screensaver_swap_image_timeout, s] { if (screensaver_swap_image_timeout->getValue() != static_cast(Settings::getInstance()-> @@ -148,21 +147,6 @@ void GuiScreensaverOptions::openSlideshowScreensaverOptions() }); #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()-> @@ -177,10 +161,24 @@ void GuiScreensaverOptions::openSlideshowScreensaverOptions() } }); + // 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 DIRECTORY RECURSIVE SEARCH", 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(); + } + }); + // 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, + s->addEditableTextComponent("CUSTOM IMAGE DIRECTORY", screensaver_slideshow_image_dir, Settings::getInstance()->getString("ScreensaverSlideshowImageDir"), "~/.emulationstation/slideshow/custom_images"); s->addSaveFunc([screensaver_slideshow_image_dir, s] { @@ -192,20 +190,6 @@ void GuiScreensaverOptions::openSlideshowScreensaverOptions() } }); - // 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); } @@ -218,7 +202,7 @@ void GuiScreensaverOptions::openVideoScreensaverOptions() 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->addWithLabel("SWAP VIDEOS AFTER (SECONDS)", screensaver_swap_video_timeout); s->addSaveFunc([screensaver_swap_video_timeout,s ] { if (screensaver_swap_video_timeout->getValue() != static_cast(Settings::getInstance()-> @@ -231,6 +215,26 @@ void GuiScreensaverOptions::openVideoScreensaverOptions() } }); + // Show game info overlay. + auto screensaver_video_game_info = std::make_shared> + (mWindow,getHelpStyle(), "SHOW GAME INFO OVERLAY", 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++) + screensaver_video_game_info->add(*it, *it, + Settings::getInstance()->getString("ScreensaverVideoGameInfo") == *it); + s->addWithLabel("SHOW GAME INFO OVERLAY", screensaver_video_game_info); + s->addSaveFunc([screensaver_video_game_info, s] { + if (screensaver_video_game_info->getSelected() != + Settings::getInstance()->getString("ScreensaverVideoGameInfo")) { + Settings::getInstance()->setString("ScreensaverVideoGameInfo", + screensaver_video_game_info->getSelected()); + s->setNeedsSaving(); + } + }); + // Stretch videos to screen resolution. auto screensaver_stretch_videos = std::make_shared(mWindow); screensaver_stretch_videos-> @@ -257,22 +261,7 @@ void GuiScreensaverOptions::openVideoScreensaverOptions() 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()); }); + #endif // ComponentListRow row; @@ -297,11 +286,10 @@ void GuiScreensaverOptions::openVideoScreensaverOptions() // 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->addWithLabel("PLAY AUDIO FOR SCREENSAVER VIDEOS", screensaver_video_audio); s->addSaveFunc([screensaver_video_audio, s] { if (screensaver_video_audio->getState() != Settings::getInstance()->getBool("ScreensaverVideoAudio")) { @@ -311,7 +299,6 @@ void GuiScreensaverOptions::openVideoScreensaverOptions() } }); - #if defined(USE_OPENGL_21) // Render scanlines using a shader. auto screensaver_video_scanlines = std::make_shared(mWindow); diff --git a/es-app/src/main.cpp b/es-app/src/main.cpp index 4f371f612..940ec67f4 100644 --- a/es-app/src/main.cpp +++ b/es-app/src/main.cpp @@ -454,7 +454,7 @@ int main(int argc, char* argv[]) } Window window; - SystemScreenSaver screensaver(&window); + SystemScreensaver screensaver(&window); PowerSaver::init(); ViewController::init(&window); CollectionSystemManager::init(&window); diff --git a/es-app/src/views/SystemView.cpp b/es-app/src/views/SystemView.cpp index 763ba2826..bc26373d6 100644 --- a/es-app/src/views/SystemView.cpp +++ b/es-app/src/views/SystemView.cpp @@ -219,9 +219,9 @@ bool SystemView::input(InputConfig* config, Input input) if (!UIModeController::getInstance()->isUIModeKid() && config->isMappedTo("select", input) && Settings::getInstance()->getBool("ScreensaverControls")) { - if (!mWindow->isScreenSaverActive()) { - mWindow->startScreenSaver(); - mWindow->renderScreenSaver(); + if (!mWindow->isScreensaverActive()) { + mWindow->startScreensaver(); + mWindow->renderScreensaver(); } return true; } diff --git a/es-app/src/views/gamelist/VideoGameListView.cpp b/es-app/src/views/gamelist/VideoGameListView.cpp index 8e8cb8f9f..36d49f2bc 100644 --- a/es-app/src/views/gamelist/VideoGameListView.cpp +++ b/es-app/src/views/gamelist/VideoGameListView.cpp @@ -544,7 +544,7 @@ void VideoGameListView::update(int deltaTime) { if (!mVideoPlaying) mVideo->onHide(); - else if (mVideoPlaying && !mVideo->isVideoPaused()) + else if (mVideoPlaying && !mVideo->isVideoPaused() && !mWindow->isScreensaverActive()) mVideo->onShow(); BasicGameListView::update(deltaTime); diff --git a/es-core/src/PowerSaver.cpp b/es-core/src/PowerSaver.cpp index 7c3de690a..199968911 100644 --- a/es-core/src/PowerSaver.cpp +++ b/es-core/src/PowerSaver.cpp @@ -40,7 +40,7 @@ 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("ScreensaverType"); if (behaviour == "video") mWakeupTimeout = Settings::getInstance()->getInt("ScreensaverSwapVideoTimeout") - getMode(); else if (behaviour == "slideshow") @@ -91,7 +91,7 @@ void PowerSaver::setState(bool state) mState = ps_enabled && state; } -void PowerSaver::runningScreenSaver(bool state) +void PowerSaver::runningScreensaver(bool state) { mRunningScreenSaver = state; if (mWakeupTimeout < mMode) { @@ -100,7 +100,7 @@ void PowerSaver::runningScreenSaver(bool state) } } -bool PowerSaver::isScreenSaverActive() +bool PowerSaver::isScreensaverActive() { return mRunningScreenSaver; } diff --git a/es-core/src/PowerSaver.h b/es-core/src/PowerSaver.h index 67c1c0459..556182bc8 100644 --- a/es-core/src/PowerSaver.h +++ b/es-core/src/PowerSaver.h @@ -43,8 +43,8 @@ public: static void resume() { setState(true); } // This is used by ScreenSaver to let PS know when to switch to SS timeouts. - static void runningScreenSaver(bool state); - static bool isScreenSaverActive(); + static void runningScreensaver(bool state); + static bool isScreensaverActive(); private: static bool mState; diff --git a/es-core/src/Settings.cpp b/es-core/src/Settings.cpp index 8541059aa..8aa1adff2 100644 --- a/es-core/src/Settings.cpp +++ b/es-core/src/Settings.cpp @@ -124,25 +124,22 @@ void Settings::setDefaults() // UI settings -> screensaver settings. mIntMap["ScreensaverTimer"] = 5*60*1000; // 5 minutes + mStringMap["ScreensaverType"] = "dim"; mBoolMap["ScreensaverControls"] = true; - mStringMap["ScreensaverBehavior"] = "dim"; // UI settings -> screensaver settings -> slideshow screensaver settings. 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; + mStringMap["ScreensaverSlideshowImageDir"] = + "~/.emulationstation/slideshow/custom_images"; // UI settings -> screensaver settings -> video screensaver settings. mIntMap["ScreensaverSwapVideoTimeout"] = 25000; mBoolMap["ScreensaverStretchVideos"] = false; - #if defined(_RPI_) - mStringMap["ScreensaverGameInfo"] = "never"; - #endif + mStringMap["ScreensaverVideoGameInfo"] = "always"; mBoolMap["ScreensaverVideoAudio"] = false; mBoolMap["ScreensaverVideoScanlines"] = true; mBoolMap["ScreensaverVideoBlur"] = false; diff --git a/es-core/src/Window.cpp b/es-core/src/Window.cpp index f82dfde34..48c8d193c 100644 --- a/es-core/src/Window.cpp +++ b/es-core/src/Window.cpp @@ -145,11 +145,16 @@ void Window::input(InputConfig* config, Input input) logInput(config, input); if (mScreenSaver) { - if (mScreenSaver->isScreenSaverActive() && + if (mScreenSaver->isScreensaverActive() && Settings::getInstance()->getBool("ScreensaverControls") && - ((Settings::getInstance()->getString("ScreensaverBehavior") == "video") || - (Settings::getInstance()->getString("ScreensaverBehavior") == "slideshow"))) { - if (mScreenSaver->getCurrentGame() != nullptr && + ((Settings::getInstance()->getString("ScreensaverType") == "video") || + (Settings::getInstance()->getString("ScreensaverType") == "slideshow"))) { + bool customImageSlideshow = false; + if (Settings::getInstance()->getString("ScreensaverType") == "slideshow" && + Settings::getInstance()->getBool("ScreensaverSlideshowCustomImages")) + customImageSlideshow = true; + + if (customImageSlideshow || mScreenSaver->getCurrentGame() != nullptr && (config->isMappedTo("a", input) || config->isMappedLike("left", input) || config->isMappedLike("right", input))) { // Left or right browses to the next video or image. @@ -162,7 +167,7 @@ void Window::input(InputConfig* config, Input input) } else if (config->isMappedTo("a", input) && input.value != 0) { // Launch game. - cancelScreenSaver(); + cancelScreensaver(); mScreenSaver->launchGame(); // To force handling the wake up process. mSleeping = true; @@ -173,15 +178,15 @@ void Window::input(InputConfig* config, Input input) if (mSleeping) { // Wake up. - cancelScreenSaver(); + cancelScreensaver(); mSleeping = false; onWake(); return; } // Any keypress cancels the screensaver. - if (input.value != 0 && isScreenSaverActive()) { - cancelScreenSaver(); + if (input.value != 0 && isScreensaverActive()) { + cancelScreensaver(); return; } @@ -360,18 +365,21 @@ void Window::render() 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 >= screensaverTimer && screensaverTimer != 0) { - if (mGameLaunchedState) + // If a menu is open, reset the screensaver timer so that the screensaver won't start. + if (mGuiStack.front() != mGuiStack.back()) mTimeSinceLastInput = 0; - else if (!isProcessing() && !mScreenSaver->isScreenSaverActive()) - startScreenSaver(); + // If a game has been launched, reset the screensaver timer as we don't want to start + // the screensaver in the background when running a game. + else if (mGameLaunchedState) + mTimeSinceLastInput = 0; + else if (!isProcessing() && !mScreenSaver->isScreensaverActive()) + startScreensaver(); } // Always call the screensaver render function regardless of whether the screensaver is active // or not because it may perform a fade on transition. - renderScreenSaver(); + renderScreensaver(); if (!mRenderScreenSaver && mInfoPopup) mInfoPopup->render(transform); @@ -388,16 +396,16 @@ void Window::render() #if defined(USE_OPENGL_21) // Shaders for the screensavers. - if (mScreenSaver->isScreenSaverActive()) { - if (Settings::getInstance()->getString("ScreensaverBehavior") == "video") { - if (mScreenSaver->getVideoCount() > 0) { + if (mScreenSaver->isScreensaverActive()) { + if (Settings::getInstance()->getString("ScreensaverType") == "video") { + if (mScreenSaver->getHasMediaFiles()) { if (Settings::getInstance()->getBool("ScreensaverVideoBlur")) Renderer::shaderPostprocessing(Renderer::SHADER_BLUR_HORIZONTAL); if (Settings::getInstance()->getBool("ScreensaverVideoScanlines")) Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES); } else { - // If there are no videos, render a black screen. + // If there are no videos, fade in a black screen. Renderer::shaderParameters blackParameters; blackParameters.fragmentDimValue = mDimValue; Renderer::shaderPostprocessing(Renderer::SHADER_DIM, blackParameters); @@ -405,11 +413,21 @@ 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")) - Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES); + else if (Settings::getInstance()->getString("ScreensaverType") == "slideshow") { + if (mScreenSaver->getHasMediaFiles()) { + if (Settings::getInstance()->getBool("ScreensaverImageScanlines")) + Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES); + } + else { + // If there are no images, fade in a black screen. + Renderer::shaderParameters blackParameters; + blackParameters.fragmentDimValue = mDimValue; + Renderer::shaderPostprocessing(Renderer::SHADER_DIM, blackParameters); + if (mDimValue > 0.0) + mDimValue = Math::clamp(mDimValue-0.045, 0.0, 1.0); + } } - else if (Settings::getInstance()->getString("ScreensaverBehavior") == "dim") { + else if (Settings::getInstance()->getString("ScreensaverType") == "dim") { Renderer::shaderParameters dimParameters; dimParameters.fragmentDimValue = mDimValue; Renderer::shaderPostprocessing(Renderer::SHADER_DIM, dimParameters); @@ -420,7 +438,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("ScreensaverType") == "black") { Renderer::shaderParameters blackParameters; blackParameters.fragmentDimValue = mDimValue; Renderer::shaderPostprocessing(Renderer::SHADER_DIM, blackParameters); @@ -587,7 +605,7 @@ void Window::unsetLaunchedGame() mGameLaunchedState = false; } -void Window::startScreenSaver() +void Window::startScreensaver() { if (mScreenSaver && !mRenderScreenSaver) { // Tell the GUI components the screensaver is starting. @@ -595,17 +613,16 @@ void Window::startScreenSaver() (*it)->onScreenSaverActivate(); stopInfoPopup(); - mScreenSaver->startScreenSaver(); + mScreenSaver->startScreensaver(true); mRenderScreenSaver = true; } } -bool Window::cancelScreenSaver() +bool Window::cancelScreensaver() { if (mScreenSaver && mRenderScreenSaver) { - mScreenSaver->stopScreenSaver(); + mScreenSaver->stopScreensaver(); mRenderScreenSaver = false; - mScreenSaver->resetCounts(); // Tell the GUI components the screensaver has stopped. for (auto it = mGuiStack.cbegin(); it != mGuiStack.cend(); it++) { @@ -624,8 +641,8 @@ bool Window::cancelScreenSaver() return false; } -void Window::renderScreenSaver() +void Window::renderScreensaver() { if (mScreenSaver) - mScreenSaver->renderScreenSaver(); + mScreenSaver->renderScreensaver(); } diff --git a/es-core/src/Window.h b/es-core/src/Window.h index 035d185f6..7fbc6635f 100644 --- a/es-core/src/Window.h +++ b/es-core/src/Window.h @@ -30,20 +30,19 @@ struct HelpStyle; class Window { public: - class ScreenSaver + class Screensaver { public: - virtual void startScreenSaver() = 0; - virtual void stopScreenSaver() = 0; + virtual void startScreensaver(bool generateMediaList) = 0; + virtual void stopScreensaver() = 0; virtual void nextGame() = 0; - virtual void renderScreenSaver() = 0; + virtual void renderScreensaver() = 0; virtual bool allowSleep() = 0; virtual void update(int deltaTime) = 0; - virtual bool isScreenSaverActive() = 0; + virtual bool isScreensaverActive() = 0; virtual FileData* getCurrentGame() = 0; virtual void launchGame() = 0; - virtual void resetCounts() = 0; - virtual unsigned int getVideoCount() = 0; + virtual bool getHasMediaFiles() = 0; }; class InfoPopup @@ -82,14 +81,14 @@ public: void renderHelpPromptsEarly(); // Used to render HelpPrompts before a fade. void setHelpPrompts(const std::vector& prompts, const HelpStyle& style); - void setScreenSaver(ScreenSaver* screenSaver) { mScreenSaver = screenSaver; } + void setScreensaver(Screensaver* screenSaver) { mScreenSaver = screenSaver; } void setInfoPopup(InfoPopup* infoPopup) { delete mInfoPopup; mInfoPopup = infoPopup; } inline void stopInfoPopup() { if (mInfoPopup) mInfoPopup->stop(); }; - void startScreenSaver(); - bool cancelScreenSaver(); - void renderScreenSaver(); - bool isScreenSaverActive() { return mRenderScreenSaver; }; + void startScreensaver(); + bool cancelScreensaver(); + void renderScreensaver(); + bool isScreensaverActive() { return mRenderScreenSaver; }; void setLaunchedGame(); void unsetLaunchedGame(); @@ -108,7 +107,7 @@ private: HelpComponent* mHelp; ImageComponent* mBackgroundOverlay; - ScreenSaver* mScreenSaver; + Screensaver* mScreenSaver; InfoPopup* mInfoPopup; std::vector mGuiStack; std::vector> mDefaultFonts; diff --git a/es-core/src/components/ScrollableContainer.cpp b/es-core/src/components/ScrollableContainer.cpp index 74014cc97..8955c7111 100644 --- a/es-core/src/components/ScrollableContainer.cpp +++ b/es-core/src/components/ScrollableContainer.cpp @@ -82,7 +82,7 @@ void ScrollableContainer::setScrollPos(const Vector2f& pos) void ScrollableContainer::update(int deltaTime) { // Don't scroll if the screensaver is active or text scrolling is disabled; - if (mWindow->isScreenSaverActive() || !mWindow->getAllowTextScrolling()) { + if (mWindow->isScreensaverActive() || !mWindow->getAllowTextScrolling()) { if (mScrollPos != 0) reset(); return; diff --git a/es-core/src/components/TextListComponent.h b/es-core/src/components/TextListComponent.h index 2bdda7090..3b16f8a60 100644 --- a/es-core/src/components/TextListComponent.h +++ b/es-core/src/components/TextListComponent.h @@ -327,7 +327,7 @@ void TextListComponent::update(int deltaTime) { listUpdate(deltaTime); - if (mWindow->isScreenSaverActive() || !mWindow->getAllowTextScrolling()) + if (mWindow->isScreensaverActive() || !mWindow->getAllowTextScrolling()) stopScrolling(); if (!isScrolling() && size() > 0) { diff --git a/es-core/src/components/VideoComponent.cpp b/es-core/src/components/VideoComponent.cpp index 5d3c3d1f3..401dfcaff 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("ScreensaverType") == "dim") stopVideo(); manageState(); }