diff --git a/RetroFE/Source/Collection/CollectionInfo.h b/RetroFE/Source/Collection/CollectionInfo.h index f16f84918..ffe1046c8 100644 --- a/RetroFE/Source/Collection/CollectionInfo.h +++ b/RetroFE/Source/Collection/CollectionInfo.h @@ -39,6 +39,7 @@ class CollectionInfo std::string metadataType; std::string launcher; std::vector items; + std::vector playlistItems; typedef std::map *> Playlists_T; Playlists_T playlists; diff --git a/RetroFE/Source/Collection/CollectionInfoBuilder.cpp b/RetroFE/Source/Collection/CollectionInfoBuilder.cpp index b3ec9de1f..c7f93ff96 100644 --- a/RetroFE/Source/Collection/CollectionInfoBuilder.cpp +++ b/RetroFE/Source/Collection/CollectionInfoBuilder.cpp @@ -422,6 +422,7 @@ void CollectionInfoBuilder::addPlaylists(CollectionInfo *info) info->playlists["favorites"] = new std::vector(); return; } + std::map playlistItems; while((dirp = readdir(dp)) != NULL) { @@ -445,6 +446,14 @@ void CollectionInfoBuilder::addPlaylists(CollectionInfo *info) info->playlists[basename] = new std::vector(); + Item* playlistItem = new Item(); + playlistItem->name = basename; + playlistItem->title = basename; + playlistItem->fullTitle = basename; + playlistItem->leaf = false; + playlistItem->collectionInfo = info; + playlistItems[basename] = playlistItem; + // add the playlist list for(std::map::iterator it = playlistFilter.begin(); it != playlistFilter.end(); it++) { @@ -480,6 +489,28 @@ void CollectionInfoBuilder::addPlaylists(CollectionInfo *info) } } } + // if cyclePlaylist then order playlist menu items by that + std::string cycleString; + conf_.getProperty("cyclePlaylist", cycleString); + std::vector cycleVector; + Utils::listToVector(cycleString, cycleVector, ','); + if (cycleVector.size()) + { + // add in order according to cycle list + for (std::vector::iterator itP = cycleVector.begin(); itP != cycleVector.end(); itP++) + { + if (playlistItems[*itP]) { + info->playlistItems.push_back(playlistItems[*itP]); + } + } + } + else { + // convert lookup playlist map to vector + for (std::map::iterator itP = playlistItems.begin(); itP != playlistItems.end(); itP++) + { + info->playlistItems.push_back(itP->second); + } + } if (dp) closedir(dp); diff --git a/RetroFE/Source/Graphics/Component/ScrollingList.cpp b/RetroFE/Source/Graphics/Component/ScrollingList.cpp index 16d78f80f..3a3bba5c1 100644 --- a/RetroFE/Source/Graphics/Component/ScrollingList.cpp +++ b/RetroFE/Source/Graphics/Component/ScrollingList.cpp @@ -44,6 +44,7 @@ ScrollingList::ScrollingList( Configuration &c, Page &p, bool layoutMode, bool commonMode, + bool playlistType, Font *font, std::string layoutKey, std::string imageType, @@ -52,6 +53,7 @@ ScrollingList::ScrollingList( Configuration &c, , horizontalScroll( false ) , layoutMode_( layoutMode ) , commonMode_( commonMode ) + , playlistType_( playlistType ) , spriteList_( NULL ) , scrollPoints_( NULL ) , tweenPoints_( NULL ) @@ -76,6 +78,7 @@ ScrollingList::ScrollingList( const ScrollingList © ) , horizontalScroll( copy.horizontalScroll ) , layoutMode_( copy.layoutMode_ ) , commonMode_( copy.commonMode_ ) + , playlistType_(copy.playlistType_) , spriteList_( NULL ) , itemIndex_( 0 ) , selectedOffsetIndex_( copy.selectedOffsetIndex_ ) @@ -108,13 +111,17 @@ ScrollingList::~ScrollingList( ) } } +std::vector ScrollingList::getItems() +{ + return *items_; +} void ScrollingList::setItems( std::vector *items ) { items_ = items; - if ( items_ ) + if (items_) { - itemIndex_ = loopDecrement( 0, selectedOffsetIndex_, items_->size( ) ); + itemIndex_ = loopDecrement(0, selectedOffsetIndex_, items_->size()); } } @@ -764,6 +771,8 @@ bool ScrollingList::allocateTexture( unsigned int index, Item *item ) names.push_back( item->rating ); if ( typeLC == "score" ) names.push_back( item->score ); + if (typeLC.rfind("playlist", 0) == 0) + names.push_back(item->name); names.push_back("default"); for ( unsigned int n = 0; n < names.size() && !t; ++n ) @@ -1050,6 +1059,9 @@ void ScrollingList::updateScrollPeriod( ) void ScrollingList::scroll( bool forward ) { + // playlist menus don't scroll + if (playlistType_) + return; if ( !items_ || items_->size( ) == 0 ) return; if ( !scrollPoints_ || scrollPoints_->size( ) == 0 ) return; diff --git a/RetroFE/Source/Graphics/Component/ScrollingList.h b/RetroFE/Source/Graphics/Component/ScrollingList.h index e2033fcad..ffa37ad81 100644 --- a/RetroFE/Source/Graphics/Component/ScrollingList.h +++ b/RetroFE/Source/Graphics/Component/ScrollingList.h @@ -37,6 +37,7 @@ class ScrollingList : public Component Page &p, bool layoutMode, bool commonMode, + bool playlistType, Font *font, std::string layoutKey, std::string imageType, @@ -44,6 +45,7 @@ class ScrollingList : public Component ScrollingList( const ScrollingList © ); virtual ~ScrollingList( ); + std::vector getItems(); void triggerEnterEvent( ); void triggerExitEvent( ); void triggerMenuEnterEvent( int menuIndex = -1 ); @@ -101,6 +103,7 @@ class ScrollingList : public Component void resetScrollPeriod( ); void updateScrollPeriod( ); void scroll( bool forward ); + bool playlistType_;//todo make getter private: diff --git a/RetroFE/Source/Graphics/Page.cpp b/RetroFE/Source/Graphics/Page.cpp index 2dc355205..6af07e982 100644 --- a/RetroFE/Source/Graphics/Page.cpp +++ b/RetroFE/Source/Graphics/Page.cpp @@ -40,6 +40,8 @@ Page::Page(Configuration &config, int layoutWidth, int layoutHeight) , selectSoundChunk_(NULL) , minShowTime_(0) , jukebox_(false) + , playlistMenu_(NULL) + , elapsedTime_(0) { for (int i = 0; i < SDL::getNumScreens(); i++) { @@ -150,11 +152,43 @@ void Page::setSelectSound(Sound *chunk) selectSoundChunk_ = chunk; } +void Page::setSelectedItem() +{ + ScrollingList* amenu = getAnActiveMenu(); + if (!amenu) return; + + selectedItem_ = amenu->getSelectedItem(); +} + +ScrollingList* Page::getAnActiveMenu() { + if (activeMenu_.size()) { + for (unsigned int i = 0; i < activeMenu_.size(); i++) + { + if (!activeMenu_[i]->playlistType_) { + return activeMenu_[i]; + } + } + } + + return NULL; +} + +void Page::setActiveMenuItemsFromPlaylist(MenuInfo_S info, ScrollingList* menu) +{ + // keep playlist menu + if (menu->playlistType_ && info.collection->playlistItems.size()) { + menu->setItems(&info.collection->playlistItems); + } + else { + menu->setItems(playlist_->second); + } +} void Page::onNewItemSelected() { - if(!(activeMenu_.size() > 0 && activeMenu_[0])) return; - selectedItem_ = activeMenu_[0]->getSelectedItem(); + if(!getAnActiveMenu()) return; + + setSelectedItem(); for(MenuVector_T::iterator it = menus_.begin(); it != menus_.end(); it++) { @@ -175,8 +209,9 @@ void Page::onNewItemSelected() void Page::onNewScrollItemSelected() { - if(!(activeMenu_.size() > 0 && activeMenu_[0])) return; - selectedItem_ = activeMenu_[0]->getSelectedItem(); + if(!getAnActiveMenu()) return; + + setSelectedItem(); for(std::vector::iterator it = LayerComponents.begin(); it != LayerComponents.end(); ++it) { @@ -188,8 +223,9 @@ void Page::onNewScrollItemSelected() void Page::highlightLoadArt() { - if(!(activeMenu_.size() > 0 && activeMenu_[0])) return; - selectedItem_ = activeMenu_[0]->getSelectedItem(); + if(!getAnActiveMenu()) return; + + setSelectedItem(); for(std::vector::iterator it = LayerComponents.begin(); it != LayerComponents.end(); ++it) { @@ -380,8 +416,10 @@ Item *Page::getSelectedItem() Item *Page::getSelectedItem(int offset) { - if(!(activeMenu_.size() > 0 && activeMenu_[0])) return NULL; - return activeMenu_[0]->getItemByOffset(offset); + ScrollingList* amenu = getAnActiveMenu(); + if (!amenu) return NULL; + + return amenu->getItemByOffset(offset); } @@ -401,7 +439,8 @@ void Page::removeSelectedItem() void Page::setScrollOffsetIndex(unsigned int i) { - if(!(activeMenu_.size() > 0 && activeMenu_[0])) return; + if (!getAnActiveMenu()) return; + for(std::vector::iterator it = activeMenu_.begin(); it != activeMenu_.end(); it++) { ScrollingList *menu = *it; @@ -412,8 +451,10 @@ void Page::setScrollOffsetIndex(unsigned int i) unsigned int Page::getScrollOffsetIndex() { - if(!(activeMenu_.size() > 0 && activeMenu_[0])) return -1; - return activeMenu_[0]->getScrollOffsetIndex(); + ScrollingList* amenu = getAnActiveMenu(); + if (!amenu) return -1; + + return amenu->getScrollOffsetIndex(); } @@ -441,6 +482,8 @@ void Page::playlistChange() { (*it)->setPlaylist(playlist_->first); } + + updatePlaylistMenuPosition(); } @@ -814,46 +857,46 @@ void Page::setScrolling(ScrollDirection direction) bool Page::isHorizontalScroll() { - if(!(activeMenu_.size() > 0 && activeMenu_[0])) return false; - return activeMenu_[0]->horizontalScroll; + ScrollingList* amenu = getAnActiveMenu(); + if(!amenu) return false; + + return amenu->horizontalScroll; } void Page::pageScroll(ScrollDirection direction) { - if(activeMenu_.size() > 0 && activeMenu_[0]) + ScrollingList* amenu = getAnActiveMenu(); + if (!amenu) return; + + if(direction == ScrollDirectionForward) { - if(direction == ScrollDirectionForward) - { - activeMenu_[0]->pageDown(); - } - if(direction == ScrollDirectionBack) - { - activeMenu_[0]->pageUp(); - } + amenu->pageDown(); + } else if(direction == ScrollDirectionBack) + { + amenu->pageUp(); + } - unsigned int index = activeMenu_[0]->getScrollOffsetIndex(); - for(std::vector::iterator it = activeMenu_.begin(); it != activeMenu_.end(); it++) - { - ScrollingList *menu = *it; - if (menu) - menu->setScrollOffsetIndex(index); - } + unsigned int index = amenu->getScrollOffsetIndex(); + for(std::vector::iterator it = activeMenu_.begin(); it != activeMenu_.end(); it++) + { + ScrollingList *menu = *it; + if (menu) + menu->setScrollOffsetIndex(index); } } - void Page::selectRandom() { - if(activeMenu_.size() > 0 && activeMenu_[0]) + ScrollingList* amenu = getAnActiveMenu(); + if (!amenu) return; + + amenu->random(); + unsigned int index = amenu->getScrollOffsetIndex(); + for(std::vector::iterator it = activeMenu_.begin(); it != activeMenu_.end(); it++) { - activeMenu_[0]->random(); - unsigned int index = activeMenu_[0]->getScrollOffsetIndex(); - for(std::vector::iterator it = activeMenu_.begin(); it != activeMenu_.end(); it++) - { - ScrollingList *menu = *it; - menu->setScrollOffsetIndex(index); - } + ScrollingList *menu = *it; + menu->setScrollOffsetIndex(index); } } @@ -920,15 +963,19 @@ void Page::cfwLetterSubScroll(ScrollDirection direction) unsigned int Page::getCollectionSize() { - if(!(activeMenu_.size() > 0 && activeMenu_[0])) return 0; - return activeMenu_[0]->getSize(); + ScrollingList* amenu = getAnActiveMenu(); + if (!amenu) return 0; + + return amenu->getSize(); } unsigned int Page::getSelectedIndex() { - if(!(activeMenu_.size() > 0 && activeMenu_[0])) return 0; - return activeMenu_[0]->getSelectedIndex(); + ScrollingList* amenu = getAnActiveMenu(); + if (!amenu) return 0; + + return amenu->getSelectedIndex(); } @@ -936,22 +983,36 @@ bool Page::pushCollection(CollectionInfo *collection) { // grow the menu as needed - if(menus_.size() <= menuDepth_ && activeMenu_.size() > 0 && activeMenu_[0]) + if(menus_.size() <= menuDepth_ && getAnActiveMenu()) { for(std::vector::iterator it = activeMenu_.begin(); it != activeMenu_.end(); it++) { ScrollingList *menu = *it; ScrollingList *newMenu = new ScrollingList(*menu); + if (&newMenu->playlistType_) { + playlistMenu_ = newMenu; + } pushMenu(newMenu, menuDepth_); } } - - activeMenu_ = menus_[menuDepth_]; - for(std::vector::iterator it = activeMenu_.begin(); it != activeMenu_.end(); it++) - { - ScrollingList *menu = *it; - menu->collectionName = collection->name; - menu->setItems(&collection->items); + if (menus_.size()) { + activeMenu_ = menus_[menuDepth_]; + for (std::vector::iterator it = activeMenu_.begin(); it != activeMenu_.end(); it++) + { + ScrollingList* menu = *it; + menu->collectionName = collection->name; + // add playlist menu items + if (menu->playlistType_ && collection->playlistItems.size()) { + menu->setItems(&collection->playlistItems); + } + else { + // add item collection menu + menu->setItems(&collection->items); + } + } + } + else { + Logger::write(Logger::ZONE_WARNING, "RetroFE", "layout.xml doesn't have any menus"); } // build the collection info instance @@ -980,8 +1041,7 @@ bool Page::pushCollection(CollectionInfo *collection) bool Page::popCollection() { - - if(!(activeMenu_.size() > 0 && activeMenu_[0])) return false; + if (!getAnActiveMenu()) return false; if(menuDepth_ <= 1) return false; if(collections_.size() <= 1) return false; @@ -993,6 +1053,12 @@ bool Page::popCollection() // get the next collection off of the stack collections_.pop_back(); info = &collections_.back(); + + // build playlist menu + if (playlistMenu_ && info->collection->playlistItems.size()) { + playlistMenu_->setItems(&info->collection->playlistItems); + } + playlist_ = info->playlist; playlistChange(); @@ -1161,16 +1227,17 @@ void Page::nextPlaylist() { playlist_++; // wrap - if(playlist_ == info.collection->playlists.end()) playlist_ = info.collection->playlists.begin(); + if(playlist_ == info.collection->playlists.end()) + playlist_ = info.collection->playlists.begin(); // find the first playlist - if(playlist_->second->size() != 0) break; + if(playlist_->second->size() != 0) + break; } for(std::vector::iterator it = activeMenu_.begin(); it != activeMenu_.end(); it++) { - ScrollingList *menu = *it; - menu->setItems(playlist_->second); + setActiveMenuItemsFromPlaylist(info, *it); } playlistChange(); } @@ -1196,8 +1263,7 @@ void Page::prevPlaylist() for(std::vector::iterator it = activeMenu_.begin(); it != activeMenu_.end(); it++) { - ScrollingList *menu = *it; - menu->setItems(playlist_->second); + setActiveMenuItemsFromPlaylist(info, *it); } playlistChange(); } @@ -1228,12 +1294,28 @@ void Page::selectPlaylist(std::string playlist) for(std::vector::iterator it = activeMenu_.begin(); it != activeMenu_.end(); it++) { - ScrollingList *menu = *it; - menu->setItems(playlist_->second); + setActiveMenuItemsFromPlaylist(info, *it); } playlistChange(); } +void Page::updatePlaylistMenuPosition() +{ + if (playlistMenu_) { + unsigned int i = 0; + std::string name = getPlaylistName(); + std::vector items = playlistMenu_->getItems(); + for (std::vector::iterator it = items.begin(); it != items.end(); ++it) { + Item* item = *it; + if (item->name == name) { + playlistMenu_->setScrollOffsetIndex(i); + + return; + } + i++; + } + } +} void Page::nextCyclePlaylist(std::vector list) { diff --git a/RetroFE/Source/Graphics/Page.h b/RetroFE/Source/Graphics/Page.h index 30eedd611..1c4461e85 100644 --- a/RetroFE/Source/Graphics/Page.h +++ b/RetroFE/Source/Graphics/Page.h @@ -60,11 +60,14 @@ class Page void nextCyclePlaylist(std::vector list); void prevCyclePlaylist(std::vector list); void pushMenu(ScrollingList *s, int index = -1); + void updatePlaylistMenuPosition(); bool isMenusFull(); void setLoadSound(Sound *chunk); void setUnloadSound(Sound *chunk); void setHighlightSound(Sound *chunk); void setSelectSound(Sound *chunk); + void setSelectedItem(); + ScrollingList* getAnActiveMenu(); bool addComponent(Component *c); void pageScroll(ScrollDirection direction); void letterScroll(ScrollDirection direction); @@ -141,6 +144,7 @@ class Page unsigned long long getCurrent( ); unsigned long long getDuration( ); bool isPaused( ); + ScrollingList* playlistMenu_;//todo make getter private: void playlistChange(); @@ -156,6 +160,7 @@ class Page typedef std::vector< std::vector > MenuVector_T; typedef std::list CollectionVector_T; + void setActiveMenuItemsFromPlaylist(MenuInfo_S info, ScrollingList* menu); std::vector activeMenu_; unsigned int menuDepth_; diff --git a/RetroFE/Source/Graphics/PageBuilder.cpp b/RetroFE/Source/Graphics/PageBuilder.cpp index 3d4691925..aa9f09ecd 100644 --- a/RetroFE/Source/Graphics/PageBuilder.cpp +++ b/RetroFE/Source/Graphics/PageBuilder.cpp @@ -366,6 +366,9 @@ bool PageBuilder::buildComponents(xml_node<> *layout, Page *page) ScrollingList *scrollingList = buildMenu(componentXml,*page); xml_attribute<> *indexXml = componentXml->first_attribute("menuIndex"); int index = indexXml ? Utils::convertInt(indexXml->value()) : -1; + if (scrollingList->playlistType_) { + page->playlistMenu_ = scrollingList; + } page->pushMenu(scrollingList, index); } @@ -1000,14 +1003,21 @@ ScrollingList * PageBuilder::buildMenu(xml_node<> *menuXml, Page &page) Logger::write(Logger::ZONE_WARNING, "Layout", "Menu tag is missing tag."); } + bool playlistType = false; if(imageTypeXml) { imageType = imageTypeXml->value(); + if (imageType.rfind("playlist", 0) == 0) { + playlistType = true; + } } if(videoTypeXml) { videoType = videoTypeXml->value(); + if (videoType.rfind("playlist", 0) == 0) { + playlistType = true; + } } bool layoutMode = false; @@ -1033,7 +1043,7 @@ ScrollingList * PageBuilder::buildMenu(xml_node<> *menuXml, Page &page) // on default, text will be rendered to the menu. Preload it into cache. Font *font = addFont(itemDefaults, NULL); - menu = new ScrollingList(config_, page, layoutMode, commonMode, font, layoutKey, imageType, videoType); + menu = new ScrollingList(config_, page, layoutMode, commonMode, playlistType, font, layoutKey, imageType, videoType); buildViewInfo(menuXml, menu->baseViewInfo); if(scrollTimeXml) diff --git a/RetroFE/Source/RetroFE.cpp b/RetroFE/Source/RetroFE.cpp index 05ff59e0b..f3b0f88c5 100644 --- a/RetroFE/Source/RetroFE.cpp +++ b/RetroFE/Source/RetroFE.cpp @@ -75,7 +75,7 @@ RetroFE::RetroFE( Configuration &c ) menuMode_ = false; attractMode_ = false; attractModePlaylistCollectionNumber_ = 0; - firstPlaylist_ = "all"; + firstPlaylist_ = "all"; // todo } @@ -1353,7 +1353,7 @@ bool RetroFE::run( ) std::string cycleString; config_.getProperty( "cyclePlaylist", cycleString ); std::vector cycleVector; - Utils::listToVector( cycleString, cycleVector, ',' ); + Utils::listToVector(cycleString, cycleVector, ',' ); if ( cyclePlaylist ) currentPage_->nextCyclePlaylist( cycleVector ); diff --git a/RetroFE/Source/Utility/Utils.cpp b/RetroFE/Source/Utility/Utils.cpp index f6d9cef4c..b27631119 100644 --- a/RetroFE/Source/Utility/Utils.cpp +++ b/RetroFE/Source/Utility/Utils.cpp @@ -256,15 +256,22 @@ std::string Utils::trimEnds(std::string str) void Utils::listToVector( std::string str, std::vector &vec, char delimiter = ',' ) { + std::string value; std::size_t current, previous = 0; current = str.find( delimiter ); while (current != std::string::npos) { - vec.push_back( Utils::trimEnds( str.substr( previous, current - previous ) ) ); + value = Utils::trimEnds(str.substr(previous, current - previous)); + if (value != "") { + vec.push_back(value); + } previous = current + 1; current = str.find( delimiter, previous ); } - vec.push_back( Utils::trimEnds( str.substr( previous, current - previous ) ) ); + value = Utils::trimEnds(str.substr(previous, current - previous)); + if (value != "") { + vec.push_back(value); + } } @@ -274,3 +281,10 @@ int Utils::gcd( int a, int b ) return a; return gcd( b, a % b ); } + +std::string Utils::trim(std::string& str) +{ + str.erase(str.find_last_not_of(' ') + 1); //suffixing spaces + str.erase(0, str.find_first_not_of(' ')); //prefixing spaces + return str; +} \ No newline at end of file diff --git a/RetroFE/Source/Utility/Utils.h b/RetroFE/Source/Utility/Utils.h index 2b1d26f1d..08c636f19 100644 --- a/RetroFE/Source/Utility/Utils.h +++ b/RetroFE/Source/Utility/Utils.h @@ -37,6 +37,7 @@ class Utils static std::string trimEnds(std::string str); static void listToVector( std::string str, std::vector &vec, char delimiter ); static int gcd( int a, int b ); + static std::string trim(std::string& str); //todo: there has to be a better way to do this static std::string combinePath(std::list &paths);