diff --git a/Package/Environment/Common/controls.conf b/Package/Environment/Common/controls.conf index a86cc1ce4..3056c5f41 100644 --- a/Package/Environment/Common/controls.conf +++ b/Package/Environment/Common/controls.conf @@ -17,7 +17,6 @@ random = R select = 1,Return,joyButton0 back = Escape,joyButton1 quit = Q -menu = Tab deadZone = 20 diff --git a/Package/Environment/Common/layouts/Aeon Nox/layout 4x3.xml b/Package/Environment/Common/layouts/Aeon Nox/layout 4x3.xml index 32636046b..75e37b712 100644 --- a/Package/Environment/Common/layouts/Aeon Nox/layout 4x3.xml +++ b/Package/Environment/Common/layouts/Aeon Nox/layout 4x3.xml @@ -197,7 +197,7 @@ - + @@ -229,7 +229,7 @@ - + @@ -498,18 +498,18 @@ - + - + - + - + - + - + diff --git a/Package/Environment/Common/layouts/Aeon Nox/layout.xml b/Package/Environment/Common/layouts/Aeon Nox/layout.xml index b60483d83..4e3012763 100644 --- a/Package/Environment/Common/layouts/Aeon Nox/layout.xml +++ b/Package/Environment/Common/layouts/Aeon Nox/layout.xml @@ -197,7 +197,7 @@ - + @@ -229,7 +229,7 @@ - + @@ -498,18 +498,18 @@ - + - + - + - + - + - + diff --git a/README.md b/README.md index 6b3384dc0..9a01f22ca 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,16 @@ Depending on your version of OS X the GUI will read user defined Environment var ## Mac download and compile RetroFE from source code ## + +## Install the Packages + +Best option is to use homebrew: + + brew install + brew install sdl2 sdl2_mixer sdl2_image sdl2_ttf gstreamer \ + gst-plugins-base gst-plugins-good gst-plugins-bad \ + gst-plugins-ugly gst-libav + If you don't use Homebrew you will need to download and install the same dependencies as given in the linux instuctions. You may need to export the libs with $LIBRARY_PATH and or supply the include folders with $CPATH before building. @@ -94,8 +104,6 @@ Compile RetroFE and create a full environment: Copy your live RetroFE system to any folder of your choosing: cp -r Artifacts\linux\RetroFE /your/ideal/retrofe/path - - # Compiling and installing on Windows # ** Visit the [RetroFE downloads](http://http://retrofe.nl/download/) page to download a precompiled version if you do not want to compile your own. ** diff --git a/RetroFE/Source/CMakeLists.txt b/RetroFE/Source/CMakeLists.txt index ec130a37d..5ce534ace 100644 --- a/RetroFE/Source/CMakeLists.txt +++ b/RetroFE/Source/CMakeLists.txt @@ -197,10 +197,18 @@ set(RETROFE_SOURCES "${SQLITE3_ROOT}/sqlite3.c" ) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) set(EXECUTABLE_OUTPUT_PATH "${RETROFE_DIR}/Build" CACHE PATH "Build directory" FORCE) set(LIBRARY_OUTPUT_PATH "${RETROFE_DIR}/Build" CACHE PATH "Build directory" FORCE) +IF(APPLE) + # Fix linking on 10.14+. See https://stackoverflow.com/questions/54068035 + LINK_DIRECTORIES(/usr/local/lib) + # can't brew link gettext, so we need to pass the path to the library + LINK_DIRECTORIES(/usr/local/opt/gettext/lib) +ENDIF() include_directories(${RETROFE_INCLUDE_DIRS}) add_executable(retrofe ${RETROFE_SOURCES} ${RETROFE_HEADERS}) diff --git a/RetroFE/Source/Collection/CollectionInfoBuilder.cpp b/RetroFE/Source/Collection/CollectionInfoBuilder.cpp index 151b5a5c3..b3ec9de1f 100644 --- a/RetroFE/Source/Collection/CollectionInfoBuilder.cpp +++ b/RetroFE/Source/Collection/CollectionInfoBuilder.cpp @@ -256,7 +256,7 @@ bool CollectionInfoBuilder::ImportBasicList(CollectionInfo *info, std::string fi if (!found) { - Item *i = new Item(); + Item *i = new Item(); line.erase( std::remove(line.begin(), line.end(), '\r'), line.end() ); @@ -309,16 +309,18 @@ bool CollectionInfoBuilder::ImportDirectory(CollectionInfo *info, std::string me ImportBasicList(info, includeFile, includeFilter); ImportBasicList(info, excludeFile, excludeFilter); - if (showMissing) + for(std::vector::iterator it = includeFilterUnsorted.begin(); it != includeFilterUnsorted.end(); ++it) { - for(std::vector::iterator it = includeFilterUnsorted.begin(); it != includeFilterUnsorted.end(); ++it) + if (showMissing && excludeFilter.find((*it)->name) == excludeFilter.end()) { - if (excludeFilter.find((*it)->name) == excludeFilter.end()) - { - info->items.push_back(*it); - } + info->items.push_back(*it); + } + else + { + delete *it; } } + includeFilterUnsorted.clear( ); // Read ROM directory if showMissing is false if (!showMissing || includeFilter.size() == 0) @@ -469,7 +471,12 @@ void CollectionInfoBuilder::addPlaylists(CollectionInfo *info) } } } - + while ( playlistFilter.size( ) > 0 ) + { + std::map::iterator it = playlistFilter.begin(); + delete it->second; + playlistFilter.erase( it->first ); + } } } } diff --git a/RetroFE/Source/Control/UserInput.cpp b/RetroFE/Source/Control/UserInput.cpp index 76d7348c2..39a90d270 100644 --- a/RetroFE/Source/Control/UserInput.cpp +++ b/RetroFE/Source/Control/UserInput.cpp @@ -76,8 +76,14 @@ bool UserInput::initialize() MapKey("togglePlaylist", KeyCodeTogglePlaylist, false); MapKey("random", KeyCodeRandom, false); MapKey("menu", KeyCodeMenu, false); - MapKey("reboot", KeyCodeReboot, false); - MapKey("saveFirstPlaylist", KeyCodeSaveFirstPlaylist, false); + MapKey("reboot", KeyCodeReboot, false); + MapKey("saveFirstPlaylist", KeyCodeSaveFirstPlaylist, false); + MapKey("jbFastForward1m", KeyCodeSkipForward, false); + MapKey("jbFastRewind1m", KeyCodeSkipBackward, false); + MapKey("jbFastForward5p", KeyCodeSkipForwardp, false); + MapKey("jbFastRewind5p", KeyCodeSkipBackwardp, false); + MapKey("jbPause", KeyCodePause, false); + MapKey("jbRestart", KeyCodeRestart, false); bool retVal = true; diff --git a/RetroFE/Source/Control/UserInput.h b/RetroFE/Source/Control/UserInput.h index a5f22e9a3..9b147ff7e 100644 --- a/RetroFE/Source/Control/UserInput.h +++ b/RetroFE/Source/Control/UserInput.h @@ -59,12 +59,18 @@ class UserInput KeyCodeMenu, KeyCodeAddPlaylist, KeyCodeRemovePlaylist, - KeyCodeTogglePlaylist, + KeyCodeTogglePlaylist, KeyCodeAdminMode, KeyCodeHideItem, KeyCodeQuit, - KeyCodeReboot, - KeyCodeSaveFirstPlaylist, + KeyCodeReboot, + KeyCodeSaveFirstPlaylist, + KeyCodeSkipForward, + KeyCodeSkipBackward, + KeyCodeSkipForwardp, + KeyCodeSkipBackwardp, + KeyCodePause, + KeyCodeRestart, KeyCodeMax }; diff --git a/RetroFE/Source/Execute/Launcher.cpp b/RetroFE/Source/Execute/Launcher.cpp index 968be7ab8..116fef79a 100644 --- a/RetroFE/Source/Execute/Launcher.cpp +++ b/RetroFE/Source/Execute/Launcher.cpp @@ -129,6 +129,62 @@ bool Launcher::run(std::string collection, Item *collectionItem) return reboot; } + +void Launcher::LEDBlinky( int command, std::string collection, Item *collectionItem ) +{ + std::string LEDBlinkyDirectory = ""; + config_.getProperty( "LEDBlinkyDirectory", LEDBlinkyDirectory ); + std::string exe = LEDBlinkyDirectory + "\\LEDBlinky.exe"; + std::string args = std::to_string( command ); + bool wait = false; + if ( command == 2 ) + wait = true; + if ( command == 8 ) + { + std::string launcherName = collectionItem->collectionInfo->launcher; + std::string launcherFile = Utils::combinePath( Configuration::absolutePath, "collections", collectionItem->collectionInfo->name, "launchers", collectionItem->name + ".conf" ); + std::ifstream launcherStream( launcherFile.c_str( ) ); + if (launcherStream.good( )) // Launcher file found + { + std::string line; + if (std::getline( launcherStream, line)) // Launcher found + { + launcherName = line; + } + } + launcherName = Utils::toLower( launcherName ); + std::string emulator = collection; + config_.getProperty("launchers." + launcherName + ".LEDBlinkyEmulator", emulator ); + args = args + " \"" + emulator + "\""; + } + if ( command == 3 || command == 9 ) + { + std::string launcherName = collectionItem->collectionInfo->launcher; + std::string launcherFile = Utils::combinePath( Configuration::absolutePath, "collections", collectionItem->collectionInfo->name, "launchers", collectionItem->name + ".conf" ); + std::ifstream launcherStream( launcherFile.c_str( ) ); + if (launcherStream.good( )) // Launcher file found + { + std::string line; + if (std::getline( launcherStream, line)) // Launcher found + { + launcherName = line; + } + } + launcherName = Utils::toLower( launcherName ); + std::string emulator = launcherName; + config_.getProperty("launchers." + launcherName + ".LEDBlinkyEmulator", emulator ); + args = args + " \"" + collectionItem->name + "\" \"" + emulator + "\""; + if ( emulator == "" ) + return; + } + if ( LEDBlinkyDirectory != "" && !execute( exe, args, LEDBlinkyDirectory, wait ) ) + { + Logger::write( Logger::ZONE_ERROR, "LEDBlinky", "Failed to launch." ); + } + return; +} + + std::string Launcher::replaceVariables(std::string str, std::string itemFilePath, std::string itemName, @@ -151,7 +207,7 @@ std::string Launcher::replaceVariables(std::string str, return str; } -bool Launcher::execute(std::string executable, std::string args, std::string currentDirectory) +bool Launcher::execute(std::string executable, std::string args, std::string currentDirectory, bool wait) { bool retVal = false; std::string executionString = "\"" + executable + "\" " + args; @@ -192,13 +248,16 @@ bool Launcher::execute(std::string executable, std::string args, std::string cur else { #ifdef WIN32 - while(WAIT_OBJECT_0 != MsgWaitForMultipleObjects(1, &processInfo.hProcess, FALSE, INFINITE, QS_ALLINPUT)) - { - MSG msg; - while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - DispatchMessage(&msg); - } + if ( wait ) + { + while(WAIT_OBJECT_0 != MsgWaitForMultipleObjects(1, &processInfo.hProcess, FALSE, INFINITE, QS_ALLINPUT)) + { + MSG msg; + while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + DispatchMessage(&msg); + } + } } // result = GetExitCodeProcess(processInfo.hProcess, &exitCode); diff --git a/RetroFE/Source/Execute/Launcher.h b/RetroFE/Source/Execute/Launcher.h index 8ae3b378f..f5fcba8e1 100644 --- a/RetroFE/Source/Execute/Launcher.h +++ b/RetroFE/Source/Execute/Launcher.h @@ -26,6 +26,7 @@ class Launcher public: Launcher(Configuration &c); bool run(std::string collection, Item *collectionItem); + void LEDBlinky( int command, std::string collection = "", Item *collectionItem = NULL); private: std::string replaceString( @@ -38,7 +39,7 @@ class Launcher bool launcherArgs(std::string &args, std::string launcherName); bool extensions(std::string &extensions, std::string launcherName); bool collectionDirectory(std::string &directory, std::string collection); - bool execute(std::string executable, std::string arguments, std::string currentDirectory); + bool execute(std::string executable, std::string arguments, std::string currentDirectory, bool wait = true); bool findFile(std::string &foundFilePath, std::string &foundFilename, std::string directory, std::string filenameWithoutExtension, std::string extensions); std::string replaceVariables(std::string str, std::string itemFilePath, diff --git a/RetroFE/Source/Graphics/Animate/AnimationEvents.cpp b/RetroFE/Source/Graphics/Animate/AnimationEvents.cpp index f7c87329d..44de49169 100644 --- a/RetroFE/Source/Graphics/Animate/AnimationEvents.cpp +++ b/RetroFE/Source/Graphics/Animate/AnimationEvents.cpp @@ -48,20 +48,16 @@ Animation *AnimationEvents::getAnimation(std::string tween) Animation *AnimationEvents::getAnimation(std::string tween, int index) { if(animationMap_.find(tween) == animationMap_.end()) - { animationMap_[tween][-1] = new Animation(); - } if(animationMap_[tween].find(index) == animationMap_[tween].end()) { index = -1; - if(animationMap_[tween].find(index) == animationMap_[tween].end()) { animationMap_[tween][index] = new Animation(); } } - return animationMap_[tween][index]; } diff --git a/RetroFE/Source/Graphics/Animate/Tween.cpp b/RetroFE/Source/Graphics/Animate/Tween.cpp index 13b32ba74..a0af8d83f 100644 --- a/RetroFE/Source/Graphics/Animate/Tween.cpp +++ b/RetroFE/Source/Graphics/Animate/Tween.cpp @@ -78,27 +78,27 @@ TweenAlgorithm Tween::getTweenType(std::string name) { if(tweenTypeMap_.size() == 0) { - tweenTypeMap_["easeInquadratic"] = EASE_IN_QUADRATIC; - tweenTypeMap_["easeOutquadratic"] = EASE_OUT_QUADRATIC; - tweenTypeMap_["easeInoutquadratic"] = EASE_INOUT_QUADRATIC; - tweenTypeMap_["easeIncubic"] = EASE_IN_CUBIC; - tweenTypeMap_["easeOutcubic"] = EASE_OUT_CUBIC; - tweenTypeMap_["easeInoutcubic"] = EASE_INOUT_CUBIC; - tweenTypeMap_["easeInquartic"] = EASE_IN_QUARTIC; - tweenTypeMap_["easeOutquartic"] = EASE_OUT_QUARTIC; - tweenTypeMap_["easeInoutquartic"] = EASE_INOUT_QUARTIC; - tweenTypeMap_["easeInquintic"] = EASE_IN_QUINTIC; - tweenTypeMap_["easeOutquintic"] = EASE_OUT_QUINTIC; - tweenTypeMap_["easeInoutquintic"] = EASE_INOUT_QUINTIC; - tweenTypeMap_["easeInsine"] = EASE_IN_SINE; - tweenTypeMap_["easeOutsine"] = EASE_OUT_SINE; - tweenTypeMap_["easeInoutsine"] = EASE_INOUT_SINE; - tweenTypeMap_["easeInexponential"] = EASE_IN_EXPONENTIAL; - tweenTypeMap_["easeOutexponential"] = EASE_OUT_EXPONENTIAL; - tweenTypeMap_["easeInoutexponential"] = EASE_INOUT_EXPONENTIAL; - tweenTypeMap_["easeIncircular"] = EASE_IN_CIRCULAR; - tweenTypeMap_["easeOutcircular"] = EASE_OUT_CIRCULAR; - tweenTypeMap_["easeInoutcircular"] = EASE_INOUT_CIRCULAR; + tweenTypeMap_["easeinquadratic"] = EASE_IN_QUADRATIC; + tweenTypeMap_["easeoutquadratic"] = EASE_OUT_QUADRATIC; + tweenTypeMap_["easeinoutquadratic"] = EASE_INOUT_QUADRATIC; + tweenTypeMap_["easeincubic"] = EASE_IN_CUBIC; + tweenTypeMap_["easeoutcubic"] = EASE_OUT_CUBIC; + tweenTypeMap_["easeinoutcubic"] = EASE_INOUT_CUBIC; + tweenTypeMap_["easeinquartic"] = EASE_IN_QUARTIC; + tweenTypeMap_["easeoutquartic"] = EASE_OUT_QUARTIC; + tweenTypeMap_["easeinoutquartic"] = EASE_INOUT_QUARTIC; + tweenTypeMap_["easeinquintic"] = EASE_IN_QUINTIC; + tweenTypeMap_["easeoutquintic"] = EASE_OUT_QUINTIC; + tweenTypeMap_["easeonoutquintic"] = EASE_INOUT_QUINTIC; + tweenTypeMap_["easeinsine"] = EASE_IN_SINE; + tweenTypeMap_["easeoutsine"] = EASE_OUT_SINE; + tweenTypeMap_["easeinoutsine"] = EASE_INOUT_SINE; + tweenTypeMap_["easeinexponential"] = EASE_IN_EXPONENTIAL; + tweenTypeMap_["easeoutexponential"] = EASE_OUT_EXPONENTIAL; + tweenTypeMap_["easeinoutexponential"] = EASE_INOUT_EXPONENTIAL; + tweenTypeMap_["easeincircular"] = EASE_IN_CIRCULAR; + tweenTypeMap_["easeoutcircular"] = EASE_OUT_CIRCULAR; + tweenTypeMap_["easeinoutcircular"] = EASE_INOUT_CIRCULAR; tweenTypeMap_["linear"] = LINEAR; } diff --git a/RetroFE/Source/Graphics/Component/Component.h b/RetroFE/Source/Graphics/Component/Component.h index 384b94bc0..83ac986a4 100644 --- a/RetroFE/Source/Graphics/Component/Component.h +++ b/RetroFE/Source/Graphics/Component/Component.h @@ -49,6 +49,15 @@ class Component void setTweens(AnimationEvents *set); virtual bool isPlaying(); virtual bool isJukeboxPlaying(); + virtual void skipForward( ) {}; + virtual void skipBackward( ) {}; + virtual void skipForwardp( ) {}; + virtual void skipBackwardp( ) {}; + virtual void pause( ) {}; + virtual void restart( ) {}; + virtual unsigned long long getCurrent( ) {return 0;}; + virtual unsigned long long getDuration( ) {return 0;}; + virtual bool isPaused( ) {return false;}; ViewInfo baseViewInfo; std::string collectionName; void setMenuScrollReload(bool menuScrollReload); diff --git a/RetroFE/Source/Graphics/Component/ReloadableMedia.cpp b/RetroFE/Source/Graphics/Component/ReloadableMedia.cpp index a58a71e78..658470d6f 100644 --- a/RetroFE/Source/Graphics/Component/ReloadableMedia.cpp +++ b/RetroFE/Source/Graphics/Component/ReloadableMedia.cpp @@ -65,7 +65,8 @@ void ReloadableMedia::enableTextFallback_(bool value) void ReloadableMedia::update(float dt) { if (newItemSelected || - (newScrollItemSelected && getMenuScrollReload())) + (newScrollItemSelected && getMenuScrollReload()) || + type_ == "isPaused") { reloadTexture(); @@ -137,7 +138,7 @@ void ReloadableMedia::reloadTexture() names.push_back(selectedItem->cloneof); } - std::string typeLC = Utils::toLower(type_); + std::string typeLC = Utils::toLower(type_); if (typeLC == "isfavorite") { if (selectedItem->isFavorite) @@ -149,6 +150,17 @@ void ReloadableMedia::reloadTexture() names.push_back("no"); } } + if (typeLC == "ispaused") + { + if (page.isPaused( )) + { + names.push_back("yes"); + } + else + { + names.push_back("no"); + } + } names.push_back("default"); @@ -229,8 +241,13 @@ void ReloadableMedia::reloadTexture() { std::string basename = names[n]; bool defined = false; + std::string type = type_; + if ( isVideo_ ) + { typeLC = Utils::toLower(imageType_); + type = imageType_; + } if(basename == "default") { @@ -310,7 +327,7 @@ void ReloadableMedia::reloadTexture() if (!selectedItem->leaf) // item is not a leaf { - (void)config_.getProperty("collections." + selectedItem->name + "." + type_, basename ); + (void)config_.getProperty("collections." + selectedItem->name + "." + type, basename ); } bool overwriteXML = false; @@ -318,7 +335,7 @@ void ReloadableMedia::reloadTexture() if ( !defined || overwriteXML ) // No basename was found yet; check the info in stead { std::string basename_tmp; - selectedItem->getInfo( type_, basename_tmp ); + selectedItem->getInfo( type, basename_tmp ); if ( basename_tmp != "" ) { basename = basename_tmp; @@ -331,12 +348,12 @@ void ReloadableMedia::reloadTexture() { // check the master collection for the system artifact - loadedComponent_ = findComponent(collectionName, type_, type_, "", true, false); + loadedComponent_ = findComponent(collectionName, type, type, "", true, false); // check collection for the system artifact if(!loadedComponent_) { - loadedComponent_ = findComponent(selectedItem->collectionInfo->name, type_, type_, "", true, false); + loadedComponent_ = findComponent(selectedItem->collectionInfo->name, type, type, "", true, false); } } @@ -348,18 +365,18 @@ void ReloadableMedia::reloadTexture() { // check the master collection for the artifact - loadedComponent_ = findComponent(collectionName, type_, basename, "", false, false); + loadedComponent_ = findComponent(collectionName, type, basename, "", false, false); // check the collection for the artifact if(!loadedComponent_) { - loadedComponent_ = findComponent(selectedItem->collectionInfo->name, type_, basename, "", false, false); + loadedComponent_ = findComponent(selectedItem->collectionInfo->name, type, basename, "", false, false); } // check the rom directory for the artifact if(!loadedComponent_) { - loadedComponent_ = findComponent(selectedItem->collectionInfo->name, type_, type_, selectedItem->filepath, false, false); + loadedComponent_ = findComponent(selectedItem->collectionInfo->name, type, type, selectedItem->filepath, false, false); } } @@ -367,18 +384,18 @@ void ReloadableMedia::reloadTexture() { // check the master collection for the artifact - loadedComponent_ = findComponent(collectionName, type_, basename, "", false, false); + loadedComponent_ = findComponent(collectionName, type, basename, "", false, false); // check the collection for the artifact if(!loadedComponent_) { - loadedComponent_ = findComponent(selectedItem->collectionInfo->name, type_, basename, "", false, false); + loadedComponent_ = findComponent(selectedItem->collectionInfo->name, type, basename, "", false, false); } // check the submenu collection for the system artifact if (!loadedComponent_) { - loadedComponent_ = findComponent(selectedItem->name, type_, type_, "", true, false); + loadedComponent_ = findComponent(selectedItem->name, type, type, "", true, false); } } @@ -483,3 +500,74 @@ bool ReloadableMedia::isJukeboxPlaying() else return false; } + + +void ReloadableMedia::skipForward( ) +{ + if ( jukebox_ && loadedComponent_ ) + loadedComponent_->skipForward( ); +} + + +void ReloadableMedia::skipBackward( ) +{ + if ( jukebox_ && loadedComponent_ ) + loadedComponent_->skipBackward( ); +} + + +void ReloadableMedia::skipForwardp( ) +{ + if ( jukebox_ && loadedComponent_ ) + loadedComponent_->skipForwardp( ); +} + + +void ReloadableMedia::skipBackwardp( ) +{ + if ( jukebox_ && loadedComponent_ ) + loadedComponent_->skipBackwardp( ); +} + + +void ReloadableMedia::pause( ) +{ + if ( jukebox_ && loadedComponent_ ) + loadedComponent_->pause( ); +} + + +void ReloadableMedia::restart( ) +{ + if ( jukebox_ && loadedComponent_ ) + loadedComponent_->restart( ); +} + + +unsigned long long ReloadableMedia::getCurrent( ) +{ + if ( jukebox_ && loadedComponent_ ) + return loadedComponent_->getCurrent( ); + else + return 0; +} + + +unsigned long long ReloadableMedia::getDuration( ) +{ + if ( jukebox_ && loadedComponent_ ) + return loadedComponent_->getDuration( ); + else + return 0; +} + + +bool ReloadableMedia::isPaused( ) +{ + if ( jukebox_ && loadedComponent_ ) + return loadedComponent_->isPaused( ); + else + return false; +} + + diff --git a/RetroFE/Source/Graphics/Component/ReloadableMedia.h b/RetroFE/Source/Graphics/Component/ReloadableMedia.h index 7d8b583e0..87c31a551 100644 --- a/RetroFE/Source/Graphics/Component/ReloadableMedia.h +++ b/RetroFE/Source/Graphics/Component/ReloadableMedia.h @@ -37,6 +37,15 @@ class ReloadableMedia : public Component void enableTextFallback_(bool value); virtual bool isJukeboxPlaying(); + virtual void skipForward( ); + virtual void skipBackward( ); + virtual void skipForwardp( ); + virtual void skipBackwardp( ); + virtual void pause( ); + virtual void restart( ); + virtual unsigned long long getCurrent( ); + virtual unsigned long long getDuration( ); + virtual bool isPaused( ); private: diff --git a/RetroFE/Source/Graphics/Component/ReloadableText.cpp b/RetroFE/Source/Graphics/Component/ReloadableText.cpp index e2ad9b886..8b5722e70 100644 --- a/RetroFE/Source/Graphics/Component/ReloadableText.cpp +++ b/RetroFE/Source/Graphics/Component/ReloadableText.cpp @@ -57,7 +57,7 @@ void ReloadableText::update(float dt) { if (newItemSelected || (newScrollItemSelected && getMenuScrollReload()) || - type_ == "time") + type_ == "time" || type_ == "current" || type_ == "duration" || type_ == "isPaused") { ReloadTexture(); newItemSelected = false; @@ -237,6 +237,53 @@ void ReloadableText::ReloadTexture() else text = "no"; } + else if (type_ == "isPaused") + { + if (page.isPaused( )) + text = "Paused"; + else + text = ""; + } + else if (type_ == "current") + { + unsigned long long current = 0; + current = page.getCurrent( ); + current /= 1000000000; + int seconds = current%60; + int minutes = (current/60)%60; + int hours = int( current/3600 ); + text = std::to_string( hours ) + ":"; + if ( minutes < 10 ) + text += "0" + std::to_string( minutes ) + ":"; + else + text += std::to_string( minutes ) + ":"; + if ( seconds < 10 ) + text += "0" + std::to_string( seconds ); + else + text += std::to_string( seconds ); + if ( page.getDuration( ) == 0 ) + text = "--:--:--"; + } + else if (type_ == "duration") + { + unsigned long long duration = 0; + duration = page.getDuration( ); + duration /= 1000000000; + int seconds = duration%60; + int minutes = (duration/60)%60; + int hours = int( duration/3600 ); + text = std::to_string( hours ) + ":"; + if ( minutes < 10 ) + text += "0" + std::to_string( minutes ) + ":"; + else + text += std::to_string( minutes ) + ":"; + if ( seconds < 10 ) + text += "0" + std::to_string( seconds ); + else + text += std::to_string( seconds ); + if ( page.getDuration( ) == 0 ) + text = "--:--:--"; + } if (!selectedItem->leaf || systemMode_) // item is not a leaf { diff --git a/RetroFE/Source/Graphics/Component/ScrollingList.cpp b/RetroFE/Source/Graphics/Component/ScrollingList.cpp index cf1dea4d0..16d78f80f 100644 --- a/RetroFE/Source/Graphics/Component/ScrollingList.cpp +++ b/RetroFE/Source/Graphics/Component/ScrollingList.cpp @@ -100,6 +100,12 @@ ScrollingList::ScrollingList( const ScrollingList © ) ScrollingList::~ScrollingList( ) { destroyItems( ); + while( scrollPoints_->size( ) > 0 ) + { + ViewInfo *scrollPoint = scrollPoints_->back( ); + delete scrollPoint; + scrollPoints_->pop_back( ); + } } @@ -191,7 +197,10 @@ void ScrollingList::destroyItems( ) for ( unsigned int i = 0; i < components_.size( ); ++i ) { if ( components_.at( i ) ) + { + components_.at( i )->freeGraphicsMemory( ); delete components_.at( i ); + } components_.at( i ) = NULL; } } @@ -614,15 +623,17 @@ void ScrollingList::triggerAttractExitEvent( int menuIndex ) } } -void ScrollingList::update( float dt ) +void ScrollingList::triggerJukeboxJumpEvent( int menuIndex ) { - - // Check if scrollPeriod_ has been properly initialised already or if something went wrong - // while updating the scrollPeriod_ - if ( scrollPeriod_ < minScrollTime_ ) + for ( unsigned int i = 0; i < components_.size( ); ++i ) { - scrollPeriod_ = startScrollTime_; + Component *c = components_.at( i ); + if ( c ) c->triggerEvent( "jukeboxJump", menuIndex ); } +} + +void ScrollingList::update( float dt ) +{ Component::update( dt ); @@ -969,9 +980,7 @@ void ScrollingList::deallocateTexture( unsigned int index ) Component *s = components_.at( index ); if ( s ) - { s->freeGraphicsMemory( ); - } } void ScrollingList::draw( ) @@ -1045,6 +1054,11 @@ void ScrollingList::scroll( bool forward ) if ( !items_ || items_->size( ) == 0 ) return; if ( !scrollPoints_ || scrollPoints_->size( ) == 0 ) return; + if ( scrollPeriod_ < minScrollTime_ ) + { + scrollPeriod_ = minScrollTime_; + } + // Replace the item that's scrolled out if ( forward ) { diff --git a/RetroFE/Source/Graphics/Component/ScrollingList.h b/RetroFE/Source/Graphics/Component/ScrollingList.h index b62967b13..e2033fcad 100644 --- a/RetroFE/Source/Graphics/Component/ScrollingList.h +++ b/RetroFE/Source/Graphics/Component/ScrollingList.h @@ -59,6 +59,7 @@ class ScrollingList : public Component void triggerAttractEnterEvent( int menuIndex = -1 ); void triggerAttractEvent( int menuIndex = -1 ); void triggerAttractExitEvent( int menuIndex = -1 ); + void triggerJukeboxJumpEvent( int menuIndex = -1 ); bool allocateTexture( unsigned int index, Item *i ); void deallocateTexture( unsigned int index ); diff --git a/RetroFE/Source/Graphics/Component/Video.cpp b/RetroFE/Source/Graphics/Component/Video.cpp index 31ef96f39..f688a0d08 100644 --- a/RetroFE/Source/Graphics/Component/Video.cpp +++ b/RetroFE/Source/Graphics/Component/Video.cpp @@ -26,7 +26,7 @@ bool Video::enabled_ = true; -Video::Video(std::string file, std::string altFile, int numLoops, Page &p) +Video::Video(std::string file, std::string altFile, int numLoops, Page &p, int monitor) : Component(p) , video_(NULL) , file_(file) @@ -34,6 +34,7 @@ Video::Video(std::string file, std::string altFile, int numLoops, Page &p) , numLoops_(numLoops) { + baseViewInfo.Monitor = monitor; allocateGraphicsMemory( ); } @@ -101,7 +102,7 @@ void Video::allocateGraphicsMemory( ) IVideo *video = new GStreamerVideo( baseViewInfo.Monitor ); video->initialize(); ((GStreamerVideo *)(video))->setNumLoops( numLoops_ ); - video_ = new VideoComponent( video, page, file ); + video_ = new VideoComponent( video, page, file ); } } diff --git a/RetroFE/Source/Graphics/Component/Video.h b/RetroFE/Source/Graphics/Component/Video.h index ecc2a1a9f..3c1e76ffb 100644 --- a/RetroFE/Source/Graphics/Component/Video.h +++ b/RetroFE/Source/Graphics/Component/Video.h @@ -22,7 +22,7 @@ class Video : public Component { public: - Video( std::string file, std::string altFile, int numLoops, Page &page ); + Video( std::string file, std::string altFile, int numLoops, Page &page, int monitor ); virtual ~Video( ); static void setEnabled(bool enabled); void update(float dt); diff --git a/RetroFE/Source/Graphics/Component/VideoBuilder.cpp b/RetroFE/Source/Graphics/Component/VideoBuilder.cpp index d75a884cc..e76bb5595 100644 --- a/RetroFE/Source/Graphics/Component/VideoBuilder.cpp +++ b/RetroFE/Source/Graphics/Component/VideoBuilder.cpp @@ -30,10 +30,14 @@ VideoComponent * VideoBuilder::createVideo(std::string path, Page &page, std::st extensions.push_back("MP4"); extensions.push_back("avi"); extensions.push_back("AVI"); + extensions.push_back("mkv"); + extensions.push_back("MKV"); extensions.push_back("mp3"); extensions.push_back("MP3"); extensions.push_back("wav"); extensions.push_back("WAV"); + extensions.push_back("flac"); + extensions.push_back("FLAC"); std::string prefix = Utils::combinePath(path, name); std::string file; diff --git a/RetroFE/Source/Graphics/Component/VideoComponent.cpp b/RetroFE/Source/Graphics/Component/VideoComponent.cpp index 72b919955..ed9c1699c 100644 --- a/RetroFE/Source/Graphics/Component/VideoComponent.cpp +++ b/RetroFE/Source/Graphics/Component/VideoComponent.cpp @@ -19,6 +19,7 @@ #include "../../Database/Configuration.h" #include "../../Utility/Log.h" #include "../../Video/GStreamerVideo.h" +#include "../../Video/VideoFactory.h" #include "../../SDL.h" VideoComponent::VideoComponent(IVideo *videoInst, Page &p, std::string videoFile) @@ -37,7 +38,8 @@ VideoComponent::~VideoComponent() if(videoInst_) { videoInst_->stop(); -// delete videoInst_; + if ( VideoFactory::canDelete( videoInst_ ) ) + delete videoInst_; videoInst_ = NULL; } } @@ -106,3 +108,72 @@ bool VideoComponent::isPlaying() { return isPlaying_; } + + +void VideoComponent::skipForward( ) +{ + if ( videoInst_ ) + videoInst_->skipForward( ); +} + + +void VideoComponent::skipBackward( ) +{ + if ( videoInst_ ) + videoInst_->skipBackward( ); +} + + +void VideoComponent::skipForwardp( ) +{ + if ( videoInst_ ) + videoInst_->skipForwardp( ); +} + + +void VideoComponent::skipBackwardp( ) +{ + if ( videoInst_ ) + videoInst_->skipBackwardp( ); +} + + +void VideoComponent::pause( ) +{ + if ( videoInst_ ) + videoInst_->pause( ); +} + + +void VideoComponent::restart( ) +{ + if ( videoInst_ ) + videoInst_->restart( ); +} + + +unsigned long long VideoComponent::getCurrent( ) +{ + if ( videoInst_ ) + return videoInst_->getCurrent( ); + else + return 0; +} + + +unsigned long long VideoComponent::getDuration( ) +{ + if ( videoInst_ ) + return videoInst_->getDuration( ); + else + return 0; +} + + +bool VideoComponent::isPaused( ) +{ + if ( videoInst_ ) + return videoInst_->isPaused( ); + else + return false; +} diff --git a/RetroFE/Source/Graphics/Component/VideoComponent.h b/RetroFE/Source/Graphics/Component/VideoComponent.h index 3b7ca23d5..27c948ab3 100644 --- a/RetroFE/Source/Graphics/Component/VideoComponent.h +++ b/RetroFE/Source/Graphics/Component/VideoComponent.h @@ -32,6 +32,15 @@ class VideoComponent : public Component void freeGraphicsMemory(); void allocateGraphicsMemory(); virtual bool isPlaying(); + virtual void skipForward( ); + virtual void skipBackward( ); + virtual void skipForwardp( ); + virtual void skipBackwardp( ); + virtual void pause( ); + virtual void restart( ); + virtual unsigned long long getCurrent( ); + virtual unsigned long long getDuration( ); + virtual bool isPaused( ); private: std::string videoFile_; diff --git a/RetroFE/Source/Graphics/Page.cpp b/RetroFE/Source/Graphics/Page.cpp index 0a88e8dba..2dc355205 100644 --- a/RetroFE/Source/Graphics/Page.cpp +++ b/RetroFE/Source/Graphics/Page.cpp @@ -56,6 +56,9 @@ Page::~Page() void Page::deInitialize() { + + cleanup( ); + MenuVector_T::iterator it = menus_.begin(); while(it != menus_.end()) { @@ -733,6 +736,37 @@ void Page::attractExit() } +void Page::jukeboxJump() +{ + Item *item = selectedItem_; + + if(!item) return; + for(MenuVector_T::iterator it = menus_.begin(); it != menus_.end(); it++) + { + for(std::vector::iterator it2 = menus_[std::distance(menus_.begin(), it)].begin(); it2 != menus_[std::distance(menus_.begin(), it)].end(); it2++) + { + ScrollingList *menu = *it2; + if(menuDepth_-1 == static_cast(distance(menus_.begin(), it))) + { + // Also trigger animations for index i for active menu + menu->triggerEvent( "jukeboxJump", MENU_INDEX_HIGH + menuDepth_ - 1 ); + menu->triggerJukeboxJumpEvent( MENU_INDEX_HIGH + menuDepth_ - 1 ); + } + else + { + menu->triggerEvent( "jukeboxJump", menuDepth_ - 1 ); + menu->triggerJukeboxJumpEvent( menuDepth_ - 1 ); + } + } + } + + for(std::vector::iterator it = LayerComponents.begin(); it != LayerComponents.end(); ++it) + { + (*it)->triggerEvent( "jukeboxJump", menuDepth_ - 1 ); + } +} + + void Page::triggerEvent( std::string action ) { for(std::vector::iterator it = LayerComponents.begin(); it != LayerComponents.end(); ++it) @@ -1667,3 +1701,90 @@ bool Page::isJukeboxPlaying() return retVal; } + + +void Page::skipForward( ) +{ + for(std::vector::iterator it = LayerComponents.begin(); it != LayerComponents.end(); ++it) + { + (*it)->skipForward( ); + } +} + + +void Page::skipBackward( ) +{ + for(std::vector::iterator it = LayerComponents.begin(); it != LayerComponents.end(); ++it) + { + (*it)->skipBackward( ); + } +} + + +void Page::skipForwardp( ) +{ + for(std::vector::iterator it = LayerComponents.begin(); it != LayerComponents.end(); ++it) + { + (*it)->skipForwardp( ); + } +} + + +void Page::skipBackwardp( ) +{ + for(std::vector::iterator it = LayerComponents.begin(); it != LayerComponents.end(); ++it) + { + (*it)->skipBackwardp( ); + } +} + + +void Page::pause( ) +{ + for(std::vector::iterator it = LayerComponents.begin(); it != LayerComponents.end(); ++it) + { + (*it)->pause( ); + } +} + + +void Page::restart( ) +{ + for(std::vector::iterator it = LayerComponents.begin(); it != LayerComponents.end(); ++it) + { + (*it)->restart( ); + } +} + + +unsigned long long Page::getCurrent( ) +{ + unsigned long long ret = 0; + for(std::vector::iterator it = LayerComponents.begin(); it != LayerComponents.end(); ++it) + { + ret += (*it)->getCurrent( ); + } + return ret; +} + + +unsigned long long Page::getDuration( ) +{ + unsigned long long ret = 0; + for(std::vector::iterator it = LayerComponents.begin(); it != LayerComponents.end(); ++it) + { + ret += (*it)->getDuration( ); + } + return ret; +} + + +bool Page::isPaused( ) +{ + bool ret = false; + for(std::vector::iterator it = LayerComponents.begin(); it != LayerComponents.end(); ++it) + { + ret |= (*it)->isPaused( ); + } + return ret; +} diff --git a/RetroFE/Source/Graphics/Page.h b/RetroFE/Source/Graphics/Page.h index ad68a813c..30eedd611 100644 --- a/RetroFE/Source/Graphics/Page.h +++ b/RetroFE/Source/Graphics/Page.h @@ -111,6 +111,7 @@ class Page void attractEnter( ); void attract( ); void attractExit( ); + void jukeboxJump( ); void triggerEvent( std::string action ); void setText( std::string text, int id ); void addPlaylist(); @@ -131,6 +132,15 @@ class Page void setJukebox(); bool isJukebox(); bool isJukeboxPlaying(); + void skipForward( ); + void skipBackward( ); + void skipForwardp( ); + void skipBackwardp( ); + void pause( ); + void restart( ); + unsigned long long getCurrent( ); + unsigned long long getDuration( ); + bool isPaused( ); private: void playlistChange(); diff --git a/RetroFE/Source/Graphics/PageBuilder.cpp b/RetroFE/Source/Graphics/PageBuilder.cpp index b6beeb8e9..3d4691925 100644 --- a/RetroFE/Source/Graphics/PageBuilder.cpp +++ b/RetroFE/Source/Graphics/PageBuilder.cpp @@ -432,6 +432,7 @@ bool PageBuilder::buildComponents(xml_node<> *layout, Page *page) xml_attribute<> *srcXml = componentXml->first_attribute("src"); xml_attribute<> *numLoopsXml = componentXml->first_attribute("numLoops"); xml_attribute<> *idXml = componentXml->first_attribute("id"); + xml_attribute<> *monitorXml = componentXml->first_attribute("monitor"); int id = -1; if (idXml) @@ -453,7 +454,8 @@ bool PageBuilder::buildComponents(xml_node<> *layout, Page *page) altVideoPath = Utils::combinePath(Configuration::absolutePath, "layouts", layoutName, std::string(srcXml->value())); int numLoops = numLoopsXml ? Utils::convertInt(numLoopsXml->value()) : 1; - Video *c = new Video(videoPath, altVideoPath, numLoops, *page); + int monitor = monitorXml ? Utils::convertInt(monitorXml->value()) : monitor_; + Video *c = new Video(videoPath, altVideoPath, numLoops, *page, monitor); c->setId( id ); xml_attribute<> *menuScrollReload = componentXml->first_attribute("menuScrollReload"); if (menuScrollReload && @@ -885,6 +887,7 @@ AnimationEvents *PageBuilder::createTweenInstance(xml_node<> *componentXml) buildTweenSet(tweens, componentXml, "onAttractEnter", "attractEnter"); buildTweenSet(tweens, componentXml, "onAttract", "attract"); buildTweenSet(tweens, componentXml, "onAttractExit", "attractExit"); + buildTweenSet(tweens, componentXml, "onJukeboxJump", "jukeboxJump"); buildTweenSet(tweens, componentXml, "onMenuActionInputEnter", "menuActionInputEnter"); buildTweenSet(tweens, componentXml, "onMenuActionInputExit", "menuActionInputExit"); diff --git a/RetroFE/Source/RetroFE.cpp b/RetroFE/Source/RetroFE.cpp index 9a30c8226..30468906c 100644 --- a/RetroFE/Source/RetroFE.cpp +++ b/RetroFE/Source/RetroFE.cpp @@ -31,6 +31,7 @@ #include "Graphics/Page.h" #include "Graphics/Component/ScrollingList.h" #include "Graphics/Component/Video.h" +#include #include "Video/VideoFactory.h" #include #include @@ -158,6 +159,14 @@ void RetroFE::launchEnter( ) // Free the textures, and optionally take down SDL freeGraphicsMemory( ); + bool hideMouse = false; + int mouseX = 5000; + int mouseY = 5000; + config_.getProperty( "hideMouse", hideMouse ); + config_.getProperty( "mouseX", mouseX ); + config_.getProperty( "mouseY", mouseY ); + if ( hideMouse ) + SDL_WarpMouseGlobal( mouseX, mouseY ); } @@ -187,8 +196,18 @@ void RetroFE::launchExit( ) // Restore time settings currentTime_ = static_cast( SDL_GetTicks( ) ) / 1000; + keyLastTime_ = currentTime_; lastLaunchReturnTime_ = currentTime_; + bool hideMouse = false; + int mouseX = 5000; + int mouseY = 5000; + config_.getProperty( "hideMouse", hideMouse ); + config_.getProperty( "mouseX", mouseX ); + config_.getProperty( "mouseY", mouseY ); + if ( hideMouse ) + SDL_WarpMouseGlobal( mouseX, mouseY ); + } @@ -277,6 +296,7 @@ bool RetroFE::deInitialize( ) { Logger::write( Logger::ZONE_INFO, "RetroFE", "Exiting" ); SDL::deInitialize( ); + gst_deinit( ); } return retVal; @@ -308,7 +328,6 @@ bool RetroFE::run( ) config_.getProperty( "videoLoop", videoLoop ); VideoFactory::setEnabled( videoEnable ); VideoFactory::setNumLoops( videoLoop ); - VideoFactory::createVideo( 0, false ); // pre-initialize the gstreamer engine Video::setEnabled( videoEnable ); initializeThread = SDL_CreateThread( initialize, "RetroFEInit", (void *)this ); @@ -363,6 +382,7 @@ bool RetroFE::run( ) Launcher l( config_ ); Menu m( config_, input_ ); preloadTime = static_cast( SDL_GetTicks( ) ) / 1000; + l.LEDBlinky( 1 ); while ( running ) { @@ -402,6 +422,8 @@ bool RetroFE::run( ) // Idle state; waiting for input case RETROFE_IDLE: + currentPage_->cleanup( ); + // Not in splash mode if ( currentPage_ && !splashMode ) { @@ -602,6 +624,8 @@ bool RetroFE::run( ) // Start onHighlightEnter animation case RETROFE_HIGHLIGHT_LOAD_ART: currentPage_->highlightEnter( ); + if ( currentPage_->getSelectedItem( ) ) + l.LEDBlinky( 9, currentPage_->getSelectedItem( )->collectionInfo->name, currentPage_->getSelectedItem( ) ); state = RETROFE_HIGHLIGHT_ENTER; break; @@ -631,6 +655,8 @@ bool RetroFE::run( ) case RETROFE_NEXT_PAGE_MENU_EXIT: if ( currentPage_->isIdle( ) ) { + if ( currentPage_->getSelectedItem( ) ) + l.LEDBlinky( 8, currentPage_->getSelectedItem( )->name, currentPage_->getSelectedItem( ) ); lastMenuOffsets_[currentPage_->getCollectionName( )] = currentPage_->getScrollOffsetIndex( ); lastMenuPlaylists_[currentPage_->getCollectionName( )] = currentPage_->getPlaylistName( ); std::string nextPageName = nextPageItem_->name; @@ -709,6 +735,8 @@ bool RetroFE::run( ) { currentPage_->start( ); } + if ( currentPage_->getSelectedItem( ) ) + l.LEDBlinky( 9, currentPage_->getSelectedItem( )->collectionInfo->name, currentPage_->getSelectedItem( ) ); state = RETROFE_NEXT_PAGE_MENU_ENTER; break; @@ -920,6 +948,8 @@ bool RetroFE::run( ) // Start onHighlightEnter animation case RETROFE_COLLECTION_HIGHLIGHT_LOAD_ART: currentPage_->highlightEnter( ); + if ( currentPage_->getSelectedItem( ) ) + l.LEDBlinky( 9, currentPage_->getSelectedItem( )->collectionInfo->name, currentPage_->getSelectedItem( ) ); state = RETROFE_COLLECTION_HIGHLIGHT_ENTER; break; @@ -1102,9 +1132,12 @@ bool RetroFE::run( ) config_.getProperty( "attractModeSkipPlaylist", attractModeSkipPlaylist ); config_.getProperty( "lastPlayedSkipCollection", lastPlayedSkipCollection ); config_.getProperty( "lastplayedSize", size ); + if (currentPage_->getPlaylistName( ) != attractModeSkipPlaylist && nextPageItem_->collectionInfo->name != lastPlayedSkipCollection) cib.updateLastPlayedPlaylist( currentPage_->getCollection(), nextPageItem_, size ); // Update last played playlist if not currently in the skip playlist (e.g. settings) + + l.LEDBlinky( 3, nextPageItem_->collectionInfo->name, nextPageItem_ ); if (l.run(nextPageItem_->collectionInfo->name, nextPageItem_)) // Run and check if we need to reboot { attract_.reset( ); @@ -1114,6 +1147,7 @@ bool RetroFE::run( ) else { launchExit( ); + l.LEDBlinky( 4 ); currentPage_->exitGame( ); state = RETROFE_LAUNCH_EXIT; } @@ -1201,7 +1235,6 @@ bool RetroFE::run( ) case RETROFE_BACK_MENU_ENTER: if ( currentPage_->isIdle( ) ) { - currentPage_->cleanup( ); bool collectionInputClear = false; config_.getProperty( "collectionInputClear", collectionInputClear ); if ( collectionInputClear ) @@ -1276,7 +1309,10 @@ bool RetroFE::run( ) // Wait for onExit animation to finish before quitting RetroFE case RETROFE_QUIT: if ( currentPage_->isGraphicsIdle( ) ) + { + l.LEDBlinky( 2 ); running = false; + } break; } @@ -1297,7 +1333,7 @@ bool RetroFE::run( ) sleepTime = fpsIdleTime - deltaTime*1000; else sleepTime = fpsTime - deltaTime*1000; - if ( sleepTime > 0 ) + if ( sleepTime > 0 && sleepTime < 1000 ) { SDL_Delay( static_cast( sleepTime ) ); } @@ -1355,10 +1391,12 @@ bool RetroFE::run( ) if ( !attractMode_ && attract_.isSet( ) ) { currentPage_->attractEnter( ); + l.LEDBlinky( 5 ); } else if ( attractMode_ && !attract_.isSet( ) ) { currentPage_->attractExit( ); + l.LEDBlinky( 6 ); } else if ( attract_.isSet( ) ) { @@ -1594,6 +1632,53 @@ RetroFE::RETROFE_STATE RetroFE::processUserInput( Page *page ) state = RETROFE_PLAYLIST_REQUEST; } + else if ( input_.keystate(UserInput::KeyCodeSkipForward) ) + { + attract_.reset( ); + page->skipForward( ); + page->jukeboxJump( ); + keyLastTime_ = currentTime_; + } + + else if ( input_.keystate(UserInput::KeyCodeSkipBackward) ) + { + attract_.reset( ); + page->skipBackward( ); + page->jukeboxJump( ); + keyLastTime_ = currentTime_; + } + + else if ( input_.keystate(UserInput::KeyCodeSkipForwardp) ) + { + attract_.reset( ); + page->skipForwardp( ); + page->jukeboxJump( ); + keyLastTime_ = currentTime_; + } + + else if ( input_.keystate(UserInput::KeyCodeSkipBackwardp) ) + { + attract_.reset( ); + page->skipBackwardp( ); + page->jukeboxJump( ); + keyLastTime_ = currentTime_; + } + + else if ( input_.keystate(UserInput::KeyCodePause) ) + { + attract_.reset( ); + page->pause( ); + page->jukeboxJump( ); + keyLastTime_ = currentTime_; + } + + else if ( input_.keystate(UserInput::KeyCodeRestart) ) + { + attract_.reset( ); + page->restart( ); + keyLastTime_ = currentTime_; + } + else if ( input_.keystate(UserInput::KeyCodeRandom) ) { attract_.reset( ); diff --git a/RetroFE/Source/SDL.cpp b/RetroFE/Source/SDL.cpp index 6439531a1..cc2f8dea1 100644 --- a/RetroFE/Source/SDL.cpp +++ b/RetroFE/Source/SDL.cpp @@ -45,7 +45,7 @@ bool SDL::initialize( Configuration &config ) bool hideMouse; Logger::write( Logger::ZONE_INFO, "SDL", "Initializing" ); - if ( SDL_Init( SDL_INIT_EVERYTHING ) != 0 ) + if ( SDL_Init( SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS ) != 0 ) { std::string error = SDL_GetError( ); Logger::write( Logger::ZONE_ERROR, "SDL", "Initialize failed: " + error ); @@ -82,7 +82,16 @@ bool SDL::initialize( Configuration &config ) { SDL_DisplayMode mode; - Uint32 windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS; + bool windowBorder = false; + bool windowResize = false; + Uint32 windowFlags = SDL_WINDOW_OPENGL; + + config.getProperty( "windowBorder", windowBorder ); + if ( !windowBorder ) + windowFlags |= SDL_WINDOW_BORDERLESS; + config.getProperty( "windowResize", windowResize ); + if ( windowResize ) + windowFlags |= SDL_WINDOW_RESIZABLE; int screenNum = 0; if ( !config.getProperty( "screenNum" + std::to_string( i ), screenNum ) && i != 0 ) @@ -122,7 +131,7 @@ bool SDL::initialize( Configuration &config ) Logger::write( Logger::ZONE_ERROR, "Configuration", "Missing property \"horizontal\"" + std::to_string(i) ); return false; } - else if ( hString != "stretch" && (i == 0 && !config.getProperty( "horizontal", windowWidth_[i] )) && !config.getProperty( "horizontal" + std::to_string(i), windowWidth_[i] )) + else if ( hString != "stretch" && (i != 0 || !config.getProperty( "horizontal", windowWidth_[i] )) && !config.getProperty( "horizontal" + std::to_string(i), windowWidth_[i] )) { Logger::write( Logger::ZONE_ERROR, "Configuration", "Invalid property value for \"horizontal\"" + std::to_string(i) ); return false; @@ -139,7 +148,7 @@ bool SDL::initialize( Configuration &config ) Logger::write( Logger::ZONE_ERROR, "Configuration", "Missing property \"vertical\"" + std::to_string(i) ); return false; } - else if ( vString != "stretch" && (i == 0 && !config.getProperty( "vertical", windowHeight_[i] )) && !config.getProperty( "vertical" + std::to_string(i), windowHeight_[i] ) ) + else if ( vString != "stretch" && (i != 0 || !config.getProperty( "vertical", windowHeight_[i] )) && !config.getProperty( "vertical" + std::to_string(i), windowHeight_[i] ) ) { Logger::write( Logger::ZONE_ERROR, "Configuration", "Invalid property value for \"vertical\"" + std::to_string(i) ); return false; @@ -264,17 +273,23 @@ bool SDL::deInitialize( ) for ( int i = 0; i < numScreens_; ++i ) { - if ( renderer_[0] ) + if ( renderer_.size( ) > 0 ) { - SDL_DestroyRenderer( renderer_[0] ); + if ( renderer_[0] ) + { + SDL_DestroyRenderer( renderer_[0] ); + } + renderer_.erase( renderer_.begin( ) ); } - renderer_.erase( renderer_.begin( ) ); - if ( window_[0] ) + if ( window_.size( ) > 0 ) { - SDL_DestroyWindow( window_[0] ); + if ( window_[0] ) + { + SDL_DestroyWindow( window_[0] ); + } + window_.erase( window_.begin( ) ); } - window_.erase( window_.begin( ) ); } displayWidth_.clear( ); displayHeight_.clear( ); @@ -319,6 +334,8 @@ bool SDL::renderCopy( SDL_Texture *texture, float alpha, SDL_Rect *src, SDL_Rect if ( alpha == 0 || viewInfo.Monitor >= numScreens_ || !renderer_[viewInfo.Monitor] ) return true; + SDL_GetWindowSize( getWindow( viewInfo.Monitor ), &windowWidth_[viewInfo.Monitor], &windowHeight_[viewInfo.Monitor] ); + float scaleX = (float)windowWidth_[viewInfo.Monitor] / (float)layoutWidth; float scaleY = (float)windowHeight_[viewInfo.Monitor] / (float)layoutHeight; diff --git a/RetroFE/Source/Version.cpp b/RetroFE/Source/Version.cpp index be8d2480d..1e1c7b28f 100644 --- a/RetroFE/Source/Version.cpp +++ b/RetroFE/Source/Version.cpp @@ -21,7 +21,7 @@ std::string retrofe_version_major = "0"; std::string retrofe_version_minor = "10"; -std::string retrofe_version_build = "21"; +std::string retrofe_version_build = "33"; std::string Version::getString( ) diff --git a/RetroFE/Source/Video/GStreamerVideo.cpp b/RetroFE/Source/Video/GStreamerVideo.cpp index 07e33d106..d3b0100a0 100644 --- a/RetroFE/Source/Video/GStreamerVideo.cpp +++ b/RetroFE/Source/Video/GStreamerVideo.cpp @@ -34,14 +34,6 @@ bool GStreamerVideo::initialized_ = false; -//todo: this started out as sandbox code. This class needs to be refactored - -// MUST match video size -//gboolean GStreamerVideo::busCallback(GstBus * /* bus */, GstMessage * /* msg */, gpointer /* data */) -//{ -// // this callback only needs to be defined so we can loop the video once it completes -// return TRUE; -//} GStreamerVideo::GStreamerVideo( int monitor ) : playbin_(NULL) , videoBin_(NULL) @@ -57,10 +49,11 @@ GStreamerVideo::GStreamerVideo( int monitor ) , isPlaying_(false) , playCount_(0) , numLoops_(0) - , volume_(0.0) + , volume_(0.0) , currentVolume_(0.0) , monitor_(monitor) { + paused_ = false; } GStreamerVideo::~GStreamerVideo() { @@ -120,6 +113,7 @@ bool GStreamerVideo::initialize() #endif initialized_ = true; + paused_ = false; return true; } @@ -128,12 +122,16 @@ bool GStreamerVideo::deInitialize() { gst_deinit(); initialized_ = false; + paused_ = false; return true; } bool GStreamerVideo::stop() { + + paused_ = false; + if(!initialized_) { return false; @@ -173,6 +171,7 @@ bool GStreamerVideo::stop() bool GStreamerVideo::play(std::string file) { + playCount_ = 0; if(!initialized_) @@ -180,21 +179,17 @@ bool GStreamerVideo::play(std::string file) return false; } - stop(); - currentFile_ = file; - const gchar *uriFile = gst_filename_to_uri (file.c_str(), NULL); + stop(); + + gchar *uriFile = gst_filename_to_uri (file.c_str(), NULL); if(!uriFile) { return false; } else { -// Configuration::convertToAbsolutePath(Configuration::absolutePath, file); - file = uriFile; - delete uriFile; - if(!playbin_) { playbin_ = gst_element_factory_make("playbin", "player"); @@ -256,7 +251,8 @@ bool GStreamerVideo::play(std::string file) gst_object_unref(videoConvertSinkPad); videoConvertSinkPad = NULL; } - g_object_set(G_OBJECT(playbin_), "uri", file.c_str(), "video-sink", videoBin_, NULL); + g_object_set(G_OBJECT(playbin_), "uri", uriFile, "video-sink", videoBin_, NULL); + g_free( uriFile ); isPlaying_ = true; @@ -265,7 +261,6 @@ bool GStreamerVideo::play(std::string file) g_signal_connect(videoSink_, "handoff", G_CALLBACK(processNewBuffer), this); videoBus_ = gst_pipeline_get_bus(GST_PIPELINE(playbin_)); -// gst_bus_add_watch(videoBus_, &busCallback, this); /* Start playing */ GstStateChangeReturn playState = gst_element_set_state(GST_ELEMENT(playbin_), GST_STATE_PLAYING); @@ -299,26 +294,14 @@ void GStreamerVideo::freeElements() gst_object_unref(playbin_); playbin_ = NULL; } -// if(videoSink_) -// { -// gst_object_unref(videoSink_); - videoSink_ = NULL; -// } -// if(videoConvert_) -// { - // gst_object_unref(videoConvert_); - videoConvert_ = NULL; -// } if(videoConvertCaps_) { gst_caps_unref(videoConvertCaps_); videoConvertCaps_ = NULL; } -// if(videoBin_) -// { -// gst_object_unref(videoBin_); - videoBin_ = NULL; -// } + videoSink_ = NULL; + videoConvert_ = NULL; + videoBin_ = NULL; } @@ -388,7 +371,6 @@ void GStreamerVideo::update(float /* dt */) GstMapInfo bufInfo; unsigned int y_stride, u_stride, v_stride; const Uint8 *y_plane, *u_plane, *v_plane; - std::stringstream ss; y_stride = GST_ROUND_UP_4(width_); u_stride = v_stride = GST_ROUND_UP_4(y_stride / 2); @@ -471,3 +453,136 @@ void GStreamerVideo::setVolume(float volume) { volume_ = volume; } + + +void GStreamerVideo::skipForward( ) +{ + + if ( !isPlaying_ ) + return; + + gint64 current; + gint64 duration; + + if ( !gst_element_query_position( playbin_, GST_FORMAT_TIME, ¤t ) ) + return; + + if ( !gst_element_query_duration( playbin_, GST_FORMAT_TIME, &duration ) ) + return; + + current += 60 * GST_SECOND; + if ( current > duration ) + current = duration-1; + gst_element_seek_simple( playbin_, GST_FORMAT_TIME, GstSeekFlags( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT ), current ); + +} + +void GStreamerVideo::skipBackward( ) +{ + + if ( !isPlaying_ ) + return; + + gint64 current; + + if ( !gst_element_query_position( playbin_, GST_FORMAT_TIME, ¤t ) ) + return; + + if ( current > 60 * GST_SECOND ) + current -= 60 * GST_SECOND; + else + current = 0; + gst_element_seek_simple( playbin_, GST_FORMAT_TIME, GstSeekFlags( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT ), current ); + +} + + +void GStreamerVideo::skipForwardp( ) +{ + + if ( !isPlaying_ ) + return; + + gint64 current; + gint64 duration; + + if ( !gst_element_query_position( playbin_, GST_FORMAT_TIME, ¤t ) ) + return; + + if ( !gst_element_query_duration( playbin_, GST_FORMAT_TIME, &duration ) ) + return; + + current += duration/20; + if ( current > duration ) + current = duration-1; + gst_element_seek_simple( playbin_, GST_FORMAT_TIME, GstSeekFlags( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT ), current ); + +} + +void GStreamerVideo::skipBackwardp( ) +{ + + if ( !isPlaying_ ) + return; + + gint64 current; + gint64 duration; + + if ( !gst_element_query_position( playbin_, GST_FORMAT_TIME, ¤t ) ) + return; + + if ( !gst_element_query_duration( playbin_, GST_FORMAT_TIME, &duration ) ) + return; + + if ( current > duration/20 ) + current -= duration/20; + else + current = 0; + gst_element_seek_simple( playbin_, GST_FORMAT_TIME, GstSeekFlags( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT ), current ); + +} + + +void GStreamerVideo::pause( ) +{ + paused_ = !paused_; + if (paused_) + gst_element_set_state(GST_ELEMENT(playbin_), GST_STATE_PAUSED); + else + gst_element_set_state(GST_ELEMENT(playbin_), GST_STATE_PLAYING); +} + + +void GStreamerVideo::restart( ) +{ + + if ( !isPlaying_ ) + return; + + gst_element_seek_simple( playbin_, GST_FORMAT_TIME, GstSeekFlags( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT ), 0 ); + +} + + +unsigned long long GStreamerVideo::getCurrent( ) +{ + gint64 ret = 0; + if ( !gst_element_query_position( playbin_, GST_FORMAT_TIME, &ret ) || !isPlaying_ ) + ret = 0; + return (unsigned long long)ret; +} + + +unsigned long long GStreamerVideo::getDuration( ) +{ + gint64 ret = 0; + if ( !gst_element_query_duration( playbin_, GST_FORMAT_TIME, &ret ) || !isPlaying_ ) + ret = 0; + return (unsigned long long)ret; +} + + +bool GStreamerVideo::isPaused( ) +{ + return paused_; +} diff --git a/RetroFE/Source/Video/GStreamerVideo.h b/RetroFE/Source/Video/GStreamerVideo.h index 0cd32d81e..6305d7ecc 100644 --- a/RetroFE/Source/Video/GStreamerVideo.h +++ b/RetroFE/Source/Video/GStreamerVideo.h @@ -41,7 +41,16 @@ class GStreamerVideo : public IVideo int getHeight(); int getWidth(); bool isPlaying(); - void setVolume(float volume); + void setVolume(float volume); + void skipForward( ); + void skipBackward( ); + void skipForwardp( ); + void skipBackwardp( ); + void pause( ); + void restart( ); + unsigned long long getCurrent( ); + unsigned long long getDuration( ); + bool isPaused( ); private: static void processNewBuffer (GstElement *fakesink, GstBuffer *buf, GstPad *pad, gpointer data); @@ -63,7 +72,8 @@ class GStreamerVideo : public IVideo int playCount_; std::string currentFile_; int numLoops_; - float volume_; + float volume_; double currentVolume_; int monitor_; + bool paused_; }; diff --git a/RetroFE/Source/Video/IVideo.h b/RetroFE/Source/Video/IVideo.h index 6769b3762..4833eadce 100644 --- a/RetroFE/Source/Video/IVideo.h +++ b/RetroFE/Source/Video/IVideo.h @@ -32,4 +32,13 @@ class IVideo virtual int getHeight() = 0; virtual int getWidth() = 0; virtual void setVolume(float volume) = 0; + virtual void skipForward( ) = 0; + virtual void skipBackward( ) = 0; + virtual void skipForwardp( ) = 0; + virtual void skipBackwardp( ) = 0; + virtual void pause( ) = 0; + virtual void restart( ) = 0; + virtual unsigned long long getCurrent( ) = 0; + virtual unsigned long long getDuration( ) = 0; + virtual bool isPaused( ) = 0; }; diff --git a/RetroFE/Source/Video/VideoFactory.cpp b/RetroFE/Source/Video/VideoFactory.cpp index c913496d5..f336915a5 100644 --- a/RetroFE/Source/Video/VideoFactory.cpp +++ b/RetroFE/Source/Video/VideoFactory.cpp @@ -56,3 +56,9 @@ void VideoFactory::setNumLoops(int numLoops) { numLoops_ = numLoops; } + + +bool VideoFactory::canDelete( IVideo *instance ) +{ + return ( instance != instance_ ); +} diff --git a/RetroFE/Source/Video/VideoFactory.h b/RetroFE/Source/Video/VideoFactory.h index 3fe481228..d8cb93d7e 100644 --- a/RetroFE/Source/Video/VideoFactory.h +++ b/RetroFE/Source/Video/VideoFactory.h @@ -23,6 +23,7 @@ class VideoFactory static IVideo *createVideo( int monitor, bool isTypeVideo, int numLoops = -1 ); static void setEnabled(bool enabled); static void setNumLoops(int numLoops); + static bool canDelete( IVideo *instance ); private: static bool enabled_;