diff --git a/Package/Environment/Common/controls.conf b/Package/Environment/Common/controls.conf index 299347c..e2946ee 100644 --- a/Package/Environment/Common/controls.conf +++ b/Package/Environment/Common/controls.conf @@ -6,6 +6,7 @@ pageUp = A pageDown = B letterUp = N letterDown = M +nextPlaylist = P select = Space back = Escape quit = Q diff --git a/RetroFE/Source/Collection/CollectionInfo.cpp b/RetroFE/Source/Collection/CollectionInfo.cpp index 45ff5e7..88304fe 100644 --- a/RetroFE/Source/Collection/CollectionInfo.cpp +++ b/RetroFE/Source/Collection/CollectionInfo.cpp @@ -46,6 +46,18 @@ CollectionInfo::~CollectionInfo() } + Playlists_T::iterator pit = playlists.begin(); + + while(pit != playlists.end()) + { + if(pit->second != &items) + { + delete pit->second; + } + playlists.erase(pit); + pit = playlists.begin(); + } + std::vector::iterator it = items.begin(); while(it != items.end()) { diff --git a/RetroFE/Source/Collection/CollectionInfo.h b/RetroFE/Source/Collection/CollectionInfo.h index 04bc908..b017fcf 100644 --- a/RetroFE/Source/Collection/CollectionInfo.h +++ b/RetroFE/Source/Collection/CollectionInfo.h @@ -17,6 +17,7 @@ #include #include +#include class Item; @@ -35,6 +36,10 @@ public: std::string metadataType; std::string launcher; std::vector items; + + typedef std::map *> Playlists_T; + Playlists_T playlists; + bool menusort; private: std::vector subcollections_; diff --git a/RetroFE/Source/Collection/CollectionInfoBuilder.cpp b/RetroFE/Source/Collection/CollectionInfoBuilder.cpp index e7925ec..79a150c 100644 --- a/RetroFE/Source/Collection/CollectionInfoBuilder.cpp +++ b/RetroFE/Source/Collection/CollectionInfoBuilder.cpp @@ -231,8 +231,10 @@ bool CollectionInfoBuilder::ImportDirectory(CollectionInfo *info, std::string me struct dirent *dirp; std::string path = info->listpath; std::map includeFilter; + std::map favoritesFilter; std::map excludeFilter; std::string includeFile = Utils::combinePath(Configuration::absolutePath, "collections", info->name, "include.txt"); + std::string favoritesFile = Utils::combinePath(Configuration::absolutePath, "collections", info->name, "favorites.txt"); std::string excludeFile = Utils::combinePath(Configuration::absolutePath, "collections", info->name, "exclude.txt"); std::string launcher; @@ -258,6 +260,7 @@ bool CollectionInfoBuilder::ImportDirectory(CollectionInfo *info, std::string me { Logger::write(Logger::ZONE_INFO, "CollectionInfoBuilder", "Checking for \"" + includeFile + "\""); ImportBasicList(info, includeFile, includeFilter); + ImportBasicList(info, favoritesFile, favoritesFilter); ImportBasicList(info, excludeFile, excludeFilter); } @@ -265,6 +268,8 @@ bool CollectionInfoBuilder::ImportDirectory(CollectionInfo *info, std::string me std::vector::iterator extensionsIt; info->extensionList(extensions); + info->playlists["all"] = &info->items; + info->playlists["favorites"] = new std::vector(); dp = opendir(path.c_str()); @@ -286,6 +291,11 @@ bool CollectionInfoBuilder::ImportDirectory(CollectionInfo *info, std::string me } } } + // add the favorites list + for(std::map::iterator it = favoritesFilter.begin(); it != favoritesFilter.end(); it++) + { + info->playlists["favorites"]->push_back(it->second); + } while((dirp = readdir(dp)) != NULL) { diff --git a/RetroFE/Source/Control/UserInput.cpp b/RetroFE/Source/Control/UserInput.cpp index 8e5559c..d57bd3b 100644 --- a/RetroFE/Source/Control/UserInput.cpp +++ b/RetroFE/Source/Control/UserInput.cpp @@ -73,6 +73,7 @@ bool UserInput::initialize() retVal = MapKey("select", KeyCodeSelect) && retVal; retVal = MapKey("back", KeyCodeBack) && retVal; retVal = MapKey("quit", KeyCodeQuit) && retVal; + MapKey("nextPlaylist", KeyCodeNextPlaylist); // these features will need to be implemented at a later time // retVal = MapKey("admin", KeyCodeAdminMode) && retVal; // retVal = MapKey("remove", KeyCodeHideItem) && retVal; diff --git a/RetroFE/Source/Control/UserInput.h b/RetroFE/Source/Control/UserInput.h index 610c995..d63337e 100644 --- a/RetroFE/Source/Control/UserInput.h +++ b/RetroFE/Source/Control/UserInput.h @@ -39,6 +39,7 @@ public: KeyCodePageUp, KeyCodeLetterDown, KeyCodeLetterUp, + KeyCodeNextPlaylist, KeyCodeAdminMode, KeyCodeHideItem, KeyCodeQuit, diff --git a/RetroFE/Source/Graphics/Component/ScrollingList.cpp b/RetroFE/Source/Graphics/Component/ScrollingList.cpp index c42c291..d140618 100644 --- a/RetroFE/Source/Graphics/Component/ScrollingList.cpp +++ b/RetroFE/Source/Graphics/Component/ScrollingList.cpp @@ -19,7 +19,6 @@ #include "../Animate/Animation.h" #include "../Animate/AnimationEvents.h" #include "../Animate/TweenTypes.h" -#include "../ComponentItemBinding.h" #include "../Font.h" #include "ScrollingList.h" #include "ImageBuilder.h" @@ -37,7 +36,7 @@ #include #include #include - +#include //todo: remove coupling from configuration data (if possible) ScrollingList::ScrollingList(Configuration &c, @@ -50,10 +49,9 @@ ScrollingList::ScrollingList(Configuration &c, , spriteList_(NULL) , scrollPoints_(NULL) , tweenPoints_(NULL) - , tweenEnterTime_(0) , focus_(false) - , firstSpriteIndex_(0) - , selectedSpriteListIndex_(0) + , itemIndex_(0) + , componentIndex_(0) , scrollStopRequested_(true) , notifyAllRequested_(false) , currentScrollDirection_(ScrollDirectionIdle) @@ -68,6 +66,7 @@ ScrollingList::ScrollingList(Configuration &c, , fontInst_(font) , layoutKey_(layoutKey) , imageType_(imageType) + , items_(NULL) { } @@ -75,10 +74,9 @@ ScrollingList::ScrollingList(const ScrollingList ©) : Component(copy) , horizontalScroll(copy.horizontalScroll) , spriteList_(NULL) - , tweenEnterTime_(0) , focus_(false) - , firstSpriteIndex_(0) - , selectedSpriteListIndex_(copy.selectedSpriteListIndex_) + , itemIndex_(0) + , componentIndex_(0) , scrollStopRequested_(true) , notifyAllRequested_(false) , currentScrollDirection_(ScrollDirectionIdle) @@ -93,8 +91,8 @@ ScrollingList::ScrollingList(const ScrollingList ©) , fontInst_(copy.fontInst_) , layoutKey_(copy.layoutKey_) , imageType_(copy.imageType_) + , items_(NULL) { - scrollPoints_ = NULL; tweenPoints_ = NULL; @@ -125,38 +123,30 @@ ScrollingList::~ScrollingList() destroyItems(); } -void ScrollingList::setItems(std::vector *spriteList) + +void ScrollingList::setItems(std::vector *items) { - notifyAllRequested_ = true; - spriteList_ = spriteList; - firstSpriteIndex_ = 0; - - if(!spriteList_) - { - return; - } - unsigned int originalSize = spriteList_->size(); - - // loop the scroll points if there are not enough, the +2 represents the head and tail nodes (for when the item is allocated) - while(scrollPoints_ && scrollPoints_->size()+2 > spriteList_->size() && spriteList_->size() > 0) - { - for(unsigned int i = 0; i < originalSize; ++i) - { - Item *newItem = new Item(); - Item *originalItem = spriteList_->at(i)->item; - - *newItem = *originalItem; - ComponentItemBinding *newSprite = new ComponentItemBinding(newItem); - spriteList_->push_back(newSprite); - } - } - - for(unsigned int i = 0; scrollPoints_ && i < selectedSpriteListIndex_; ++i) - { - circularDecrement(firstSpriteIndex_, spriteList_); - } + deallocateSpritePoints(); + items_ = items; + itemIndex_ = 0; + allocateSpritePoints(); + + notifyAllRequested_ = true; + +} + +unsigned int ScrollingList::loopIncrement(unsigned int offset, unsigned int i, unsigned int size) +{ + if(size == 0) return 0; + return (offset + i) % size; +} + +unsigned int ScrollingList::loopDecrement(unsigned int offset, unsigned int i, unsigned int size) +{ + if(size == 0) return 0; + return ((offset % size) - (i % size) + size) % size; } @@ -172,217 +162,132 @@ void ScrollingList::setStartScrollTime(float value) void ScrollingList::deallocateSpritePoints() { - if(!spriteList_) + for(unsigned int i = 0; i < components_.size(); ++i) { - return; + deallocateTexture(i); } - unsigned int spriteIndex = firstSpriteIndex_; - - for(unsigned int i = 0; i < scrollPoints_->size() && spriteList_->size() > spriteIndex; ++i) - { - deallocateTexture(spriteList_->at(spriteIndex)); - circularIncrement(spriteIndex, spriteList_); - } + componentIndex_ = 0; } void ScrollingList::allocateSpritePoints() { - if(!scrollPoints_) - { - return; - } - if(!spriteList_) - { - return; - } - if(spriteList_->size() == 0) - { - return; - } - if(!tweenPoints_) - { - return; - } - - unsigned int spriteIndex = firstSpriteIndex_; + if(!items_ || items_->size() == 0) return; + if(!scrollPoints_) return; for(unsigned int i = 0; i < scrollPoints_->size(); ++i) { - allocateTexture(spriteList_->at(spriteIndex)); - Component *c = spriteList_->at(spriteIndex)->component; - ViewInfo *currentViewInfo = scrollPoints_->at(i); - unsigned int nextI = getNextTween(i, scrollPoints_); - ViewInfo *nextViewInfo = scrollPoints_->at(nextI); + componentIndex_ = 0; + unsigned int index = loopIncrement(itemIndex_, i, items_->size()); + Item *item = items_->at(index); - resetTweens(c, tweenPoints_->at(i), currentViewInfo, nextViewInfo, 0); + allocateTexture(i, item); + Component *c = components_.at(i); - circularIncrement(spriteIndex, spriteList_); + ViewInfo *current = scrollPoints_->at(i); + + unsigned int nextI = loopIncrement(i, 1, scrollPoints_->size()); + ViewInfo *next = scrollPoints_->at(nextI); + + resetTweens(c, tweenPoints_->at(i), current, next, 0); } } void ScrollingList::destroyItems() { - if(!spriteList_) - { - return; - } - std::vector::iterator it = spriteList_->begin(); - - while(it != spriteList_->end()) - { - if(*it != NULL) - { - deallocateTexture(*it); - - if((*it)->item) - { - delete (*it)->item; - } - - delete *it; - } - - - spriteList_->erase(it); - - it = spriteList_->begin(); - } - - delete spriteList_; - spriteList_ = NULL; + deallocateSpritePoints(); +//todo: who deletes the CollectionInfo? } void ScrollingList::setPoints(std::vector *scrollPoints, std::vector *tweenPoints) { + deallocateSpritePoints(); + scrollPoints_ = scrollPoints; tweenPoints_ = tweenPoints; + + // empty out the list as we will resize it + components_.clear(); + + int size = 0; + + if(scrollPoints) size = scrollPoints_->size(); + components_.resize(size); + + allocateSpritePoints(); } unsigned int ScrollingList::getScrollOffsetIndex() { - return firstSpriteIndex_; + return itemIndex_; } void ScrollingList::setScrollOffsetIndex(unsigned int index) { - if(spriteList_ && index < spriteList_->size()) - { - deallocateSpritePoints(); - firstSpriteIndex_ = index; - allocateSpritePoints(); - } + itemIndex_ = index; } void ScrollingList::setSelectedIndex(int selectedIndex) { - selectedSpriteListIndex_ = selectedIndex; - - for(unsigned int i = 0; spriteList_ && scrollPoints_ && i < selectedSpriteListIndex_; ++i) - { - circularDecrement(firstSpriteIndex_, spriteList_); - } + selectedOffsetIndex_ = selectedIndex; } void ScrollingList::click(double nextScrollTime) { - if(!spriteList_) - { - return; - } - if(spriteList_->size() == 0) - { - return; - } - - unsigned int listSize = scrollPoints_->size(); - unsigned int end = circularIncrement(firstSpriteIndex_, listSize - 1, spriteList_); - unsigned int allocSpriteIndex = 0; - unsigned int deallocSpriteIndex = 0; - unsigned int allocPoint = 0; - if(currentScrollDirection_ == ScrollDirectionBack) { - deallocSpriteIndex = end; - circularDecrement(firstSpriteIndex_, spriteList_); - allocSpriteIndex = firstSpriteIndex_; - allocPoint = 0; + // get the previous item + itemIndex_ = loopDecrement(itemIndex_, 1, items_->size()); + Item *i = items_->at(itemIndex_); + componentIndex_ = loopDecrement(componentIndex_, 1, components_.size()); + + deallocateTexture(componentIndex_); + allocateTexture(componentIndex_, i); + + Component *c = components_.at(componentIndex_); + ViewInfo *v = scrollPoints_->at(0); + resetTweens(c, tweenPoints_->at(componentIndex_), v, v, 0); } else if(currentScrollDirection_ == ScrollDirectionForward) { - deallocSpriteIndex = firstSpriteIndex_; - circularIncrement(firstSpriteIndex_, spriteList_); - allocSpriteIndex = circularIncrement(firstSpriteIndex_, listSize - 1, spriteList_); - allocPoint = listSize - 1; + unsigned int itemIncrement = loopIncrement(itemIndex_, scrollPoints_->size(), items_->size()); + itemIndex_ = loopIncrement(itemIndex_, 1, items_->size()); + Item *i = items_->at(itemIncrement); + + deallocateTexture(componentIndex_); + allocateTexture(componentIndex_, i); + + Component *c = components_.at(componentIndex_); + ViewInfo *v = scrollPoints_->back(); + resetTweens(c, tweenPoints_->at(componentIndex_), v, v, 0); + + componentIndex_ = loopIncrement(componentIndex_, 1, components_.size()); } - else - { - return; - } - - deallocateTexture(spriteList_->at(deallocSpriteIndex)); - allocateTexture(spriteList_->at(allocSpriteIndex)); - - Component *c = spriteList_->at(allocSpriteIndex)->component; - ViewInfo *currentViewInfo = scrollPoints_->at(allocPoint); - unsigned int nextI = getNextTween(allocPoint, scrollPoints_); - ViewInfo *nextViewInfo = scrollPoints_->at(nextI); - - resetTweens(c, tweenPoints_->at(allocPoint), currentViewInfo, nextViewInfo, nextScrollTime); -} - -unsigned int ScrollingList::getNextTween(unsigned int currentIndex, std::vector *list) -{ - if(currentScrollDirection_ == ScrollDirectionForward) - { - circularDecrement(currentIndex, list); - } - else if(currentScrollDirection_ == ScrollDirectionBack) - { - circularIncrement(currentIndex, list); - } - - return currentIndex; } void ScrollingList::pageUp() { notifyAllRequested_ = true; + + if(components_.size() == 0) return; + deallocateSpritePoints(); - if(spriteList_ && scrollPoints_ && scrollPoints_->size() > 2) - { - scrollPeriod_ = 0; - unsigned int counts = scrollPoints_->size() - 2; - - for(unsigned int i = 0; i < counts; i++) - { - circularDecrement(firstSpriteIndex_, spriteList_); - } - } - + itemIndex_ = loopDecrement(itemIndex_, components_.size(), items_->size()); + allocateSpritePoints(); - -// CurrentScrollState = ScrollStatePageChange; } void ScrollingList::pageDown() { notifyAllRequested_ = true; + if(components_.size() == 0) return; + deallocateSpritePoints(); - if(spriteList_ && scrollPoints_ && scrollPoints_->size() > 2) - { - unsigned int counts = scrollPoints_->size() - 2; - - scrollPeriod_ = 0; - for(unsigned int i = 0; i < counts; i++) - { - circularIncrement(firstSpriteIndex_, spriteList_); - } - } + itemIndex_ = loopIncrement(itemIndex_, components_.size(), items_->size()); allocateSpritePoints(); } @@ -390,77 +295,39 @@ void ScrollingList::pageDown() void ScrollingList::letterUp() { - notifyAllRequested_ = true; - deallocateSpritePoints(); - - if(spriteList_ && scrollPoints_ && getSelectedCollectionItemSprite()) - { - unsigned int i = 0; - - // Select the previous item in the list in case we are at the top of all the items - // for the currently selected letter. - circularDecrement(firstSpriteIndex_, spriteList_); - std::string startname = getSelectedCollectionItemSprite()->item->lowercaseFullTitle(); - ++i; - - bool done = false; - - // traverse up through the list until we find the first item that starts with a different letter - while(!done && i < spriteList_->size()) - { - circularDecrement(firstSpriteIndex_, spriteList_); - std::string endname = getSelectedCollectionItemSprite()->item->lowercaseFullTitle(); - ++i; - - // check if we are changing characters from a-z, or changing from alpha character to non-alpha character - if(isalpha(startname[0]) ^ isalpha(endname[0])) - { - done = true; - } - else if(isalpha(startname[0]) && isalpha(endname[0]) && startname[0] != endname[0]) - { - done = true; - } - - if(done) - { - // our searching went too far, rewind to the first item in the list that matches the starting letter - circularIncrement(firstSpriteIndex_, spriteList_); - } - } - } - - allocateSpritePoints(); + letterChange(true); } void ScrollingList::letterDown() +{ + letterChange(false); +} + +void ScrollingList::letterChange(bool increment) { notifyAllRequested_ = true; deallocateSpritePoints(); - if(spriteList_ && scrollPoints_ && getSelectedCollectionItemSprite()) + std::string startname = items_->at(itemIndex_)->lowercaseFullTitle(); + + for(unsigned int i = 0; i < items_->size(); ++i) { + unsigned int index = 0; + if(increment) index = loopIncrement(itemIndex_, i, items_->size()); + else index = loopDecrement(itemIndex_, i, items_->size()); - std::string startname = getSelectedCollectionItemSprite()->item->lowercaseFullTitle(); - std::string endname = startname; + std::string endname = items_->at(index)->lowercaseFullTitle(); - unsigned int i = 0; - bool done = false; - while(!done && i < spriteList_->size()) + // check if we are changing characters from a-z, or changing from alpha character to non-alpha character + if(isalpha(startname[0]) ^ isalpha(endname[0])) { - circularIncrement(firstSpriteIndex_, spriteList_); - endname = getSelectedCollectionItemSprite()->item->lowercaseFullTitle(); - ++i; - - // check if we are changing characters from a-z, or changing from alpha character to non-alpha character - if(isalpha(startname[0]) ^ isalpha(endname[0])) - { - done = true; - } - else if(isalpha(startname[0]) && isalpha(endname[0]) && startname[0] != endname[0]) - { - done = true; - } + break; + itemIndex_ = index; + } + else if(isalpha(startname[0]) && isalpha(endname[0]) && startname[0] != endname[0]) + { + itemIndex_ = index; + break; } } @@ -471,18 +338,12 @@ void ScrollingList::letterDown() void ScrollingList::freeGraphicsMemory() { Component::freeGraphicsMemory(); - tweenEnterTime_ = 0; currentScrollDirection_ = ScrollDirectionIdle; requestedScrollDirection_ = ScrollDirectionIdle; currentScrollState_ = ScrollStateIdle; scrollPeriod_ = 0; - - for(unsigned int i = 0; spriteList_ && i < spriteList_->size(); i++) - { - ComponentItemBinding *s = spriteList_->at(i); - - deallocateTexture(s); - } + + deallocateSpritePoints(); } void ScrollingList::triggerMenuEnterEvent() @@ -490,36 +351,10 @@ void ScrollingList::triggerMenuEnterEvent() focus_ = true; notifyAllRequested_ = true; - if(!scrollPoints_) + for(unsigned int i = 0; i < components_.size(); ++i) { - return; - } - if(!spriteList_) - { - return; - } - if(spriteList_->size() == 0 ) - { - return; - } - if(firstSpriteIndex_ >= spriteList_->size()) - { - return; - } - - unsigned int spriteIndex = firstSpriteIndex_; - - for(unsigned int i = 0; i < scrollPoints_->size(); ++i) - { - ComponentItemBinding *s = spriteList_->at(spriteIndex); - - Component *c = s->component; - if(c) - { - c->triggerMenuEnterEvent(); - } - - circularIncrement(spriteIndex, spriteList_); + Component *c = components_.at(i); + if(c) c->triggerMenuEnterEvent(); } } @@ -528,36 +363,10 @@ void ScrollingList::triggerMenuExitEvent() focus_ = false; notifyAllRequested_ = true; - if(!scrollPoints_) + for(unsigned int i = 0; i < components_.size(); ++i) { - return; - } - if(!spriteList_) - { - return; - } - if(spriteList_->size() == 0 ) - { - return; - } - if(firstSpriteIndex_ >= spriteList_->size()) - { - return; - } - - unsigned int spriteIndex = firstSpriteIndex_; - - for(unsigned int i = 0; i < scrollPoints_->size(); ++i) - { - ComponentItemBinding *s = spriteList_->at(spriteIndex); - - Component *c = s->component; - if(c) - { - c->triggerMenuExitEvent(); - } - - circularIncrement(spriteIndex, spriteList_); + Component *c = components_.at(i); + if(c) c->triggerMenuExitEvent(); } } @@ -565,31 +374,18 @@ void ScrollingList::update(float dt) { Component::update(dt); - if(!scrollPoints_) - { - return; - } - if(!spriteList_) - { - return; - } - if(spriteList_->size() == 0) - { - return; - } - bool readyToScroll = true; bool scrollChanged = false; bool scrollRequested = false; bool scrollStopped = false; - // validate all scroll points are done tweening to the next position - for(unsigned int i = 0; i < spriteList_->size(); i++) - { - ComponentItemBinding *s = spriteList_->at(i); - Component *c = s->component; + if(components_.size() == 0) return; + if(!items_ || items_->size() == 0) return; - if(c && c->isMenuScrolling()) + // validate all scroll points are done tweening to the next position + for(std::vector::iterator c = components_.begin(); c != components_.end(); c++) + { + if(*c && (*c)->isMenuScrolling()) { readyToScroll = false; break; @@ -618,24 +414,16 @@ void ScrollingList::update(float dt) { if(currentScrollState_ == ScrollStateStopping) { - click(0); currentScrollState_ = ScrollStateIdle; scrollStopped = true; - - // update the tweens now that we are done - unsigned int spriteIndex = firstSpriteIndex_; + click(0); for(unsigned int i = 0; i < tweenPoints_->size(); ++i) { - ComponentItemBinding *s = spriteList_->at(spriteIndex); + unsigned int cindex = loopIncrement(componentIndex_, i, components_.size()); + Component *c = components_.at(cindex); - Component *c = s->component; - if(c) - { - c->setTweens(tweenPoints_->at(i)); - } - - circularIncrement(spriteIndex, spriteList_); + if(c) c->setTweens(tweenPoints_->at(i)); } } @@ -654,28 +442,47 @@ void ScrollingList::update(float dt) } - unsigned int spriteIndex = firstSpriteIndex_; for(unsigned int i = 0; i < scrollPoints_->size(); i++) { - updateSprite(spriteIndex, i, (scrollRequested || scrollChanged), dt, scrollPeriod_); - circularIncrement(spriteIndex, spriteList_); + unsigned int cindex = loopIncrement(componentIndex_, i, components_.size()); + + Component *c = components_.at(cindex); + + if(c && (scrollRequested || scrollChanged)) + { + unsigned int nextI = 0; + if(currentScrollDirection_ == ScrollDirectionBack) + { + nextI = loopIncrement(i, 1, scrollPoints_->size()); + } + if(currentScrollDirection_ == ScrollDirectionForward) + { + nextI = loopDecrement(i, 1, scrollPoints_->size()); + } + + ViewInfo *currentvi = scrollPoints_->at(i); + ViewInfo *nextvi = scrollPoints_->at(nextI); + + resetTweens(c, tweenPoints_->at(i), currentvi, nextvi, scrollPeriod_); + c->triggerMenuScrollEvent(); + } + + if(c) c->update(dt); + } if(scrollStopped || (notifyAllRequested_ && focus_)) { - ComponentItemBinding *sprite = getPendingCollectionItemSprite(); Item *item = NULL; - - if(sprite) - { - item = sprite->item; - } + unsigned index = loopIncrement(itemIndex_, selectedOffsetIndex_, items_->size()); + item = items_->at(index); for(std::vector::iterator it = notificationComponents_.begin(); it != notificationComponents_.end(); it++) { MenuNotifierInterface *c = *it; + if(c && item) { c->onNewItemSelected(item); @@ -691,47 +498,12 @@ void ScrollingList::update(float dt) notifyAllRequested_ = false; } -void ScrollingList::updateSprite(unsigned int spriteIndex, unsigned int pointIndex, bool newScroll, float dt, double nextScrollTime) -{ - ComponentItemBinding *s = spriteList_->at(spriteIndex); - - Component *c = s->component; - //todo: remove me - if(c && newScroll) - { - ViewInfo *currentViewInfo = scrollPoints_->at(pointIndex); - unsigned int nextI = getNextTween(pointIndex, scrollPoints_); - ViewInfo *nextViewInfo = scrollPoints_->at(nextI); - - resetTweens(c, tweenPoints_->at(pointIndex), currentViewInfo, nextViewInfo, nextScrollTime); - c->triggerMenuScrollEvent(); - } - if(c) - { - c->update(dt); - } - - circularIncrement(spriteIndex, spriteList_); -} - void ScrollingList::resetTweens(Component *c, AnimationEvents *sets, ViewInfo *currentViewInfo, ViewInfo *nextViewInfo, double scrollTime) { - if(!c) - { - return; - } - if(!sets) - { - return; - } - if(!currentViewInfo) - { - return; - } - if(!nextViewInfo) - { - return; - } + if(!c) return; + if(!sets) return; + if(!currentViewInfo) return; + if(!nextViewInfo) return; currentViewInfo->ImageHeight = c->baseViewInfo.ImageHeight; currentViewInfo->ImageWidth = c->baseViewInfo.ImageWidth; @@ -763,15 +535,11 @@ void ScrollingList::resetTweens(Component *c, AnimationEvents *sets, ViewInfo *c } -bool ScrollingList::allocateTexture(ComponentItemBinding *s) +bool ScrollingList::allocateTexture(unsigned int index, Item *item) { - if(!s || s->component != NULL) - { - return false; - } + if(index >= components_.size()) return false; - const Item *item = s->item; //todo: will create a runtime fault if not of the right type //todo: remove coupling from knowing the collection name @@ -836,20 +604,23 @@ bool ScrollingList::allocateTexture(ComponentItemBinding *s) if(t) { - s->component = t; + components_.at(index) = t; } return true; } -void ScrollingList::deallocateTexture(ComponentItemBinding *s) +void ScrollingList::deallocateTexture(unsigned int index) { - if(s && s->component != NULL) + if(components_.size() <= index) return; + + Component *s = components_.at(index); + + if(s) { - delete s->component; - //todo: memory leak here, need to destroy allocated tween points here and in page (cannot be destroyed by component) + delete s; + components_.at(index) = NULL; } - s->component = NULL; } void ScrollingList::draw() @@ -860,32 +631,13 @@ void ScrollingList::draw() void ScrollingList::draw(unsigned int layer) { - if(!scrollPoints_) - { - return; - } - if(!spriteList_) - { - return; - } - if(spriteList_->size() == 0) - { - return; - } + + if(components_.size() == 0) return; - unsigned int spriteIndex = firstSpriteIndex_; - - for(unsigned int i = 0; i < scrollPoints_->size(); i++) + for(unsigned int i = 0; i < components_.size(); ++i) { - ComponentItemBinding *s = spriteList_->at(spriteIndex); - Component *c = s->component; - ViewInfo *currentViewInfo = scrollPoints_->at(i); - - if(c && currentViewInfo && currentViewInfo->Layer == layer) - { - c->draw(); - } - circularIncrement(spriteIndex, spriteList_); + Component *c = components_.at(i); + if(c) c->draw(); } } @@ -897,69 +649,6 @@ void ScrollingList::setScrollDirection(ScrollDirection direction) scrollStopRequested_ = (direction == ScrollDirectionIdle); } -void ScrollingList::removeSelectedItem() -{ - ComponentItemBinding *sprite = getSelectedCollectionItemSprite(); - if(sprite && spriteList_) - { - Item *item = sprite->item; - deallocateTexture(sprite); - int index = (firstSpriteIndex_ + selectedSpriteListIndex_) % spriteList_->size(); - - std::vector::iterator it = spriteList_->begin() + index; - - spriteList_->erase(it); - delete sprite; - - if(item) - { - delete item; - } - - if(selectedSpriteListIndex_ >= spriteList_->size()) - { - selectedSpriteListIndex_ = 0; - } - if(firstSpriteIndex_ >= spriteList_->size()) - { - firstSpriteIndex_ = 0; - } - } -} - - -std::vector *ScrollingList::getCollectionItemSprites() -{ - return spriteList_; -} - -ComponentItemBinding* ScrollingList::getSelectedCollectionItemSprite() -{ - ComponentItemBinding *item = NULL; - - if(spriteList_ && spriteList_->size() > 0) - { - int index = (firstSpriteIndex_ + selectedSpriteListIndex_) % spriteList_->size(); - - item = spriteList_->at(index); - } - - return item; -} - -ComponentItemBinding* ScrollingList::getPendingCollectionItemSprite() -{ - ComponentItemBinding *item = NULL; - unsigned int index = firstSpriteIndex_; - if(spriteList_ && spriteList_->size() > 0) - { - index = (index + selectedSpriteListIndex_) % spriteList_->size(); - - item = spriteList_->at(index); - } - - return item; -} void ScrollingList::addComponentForNotifications(MenuNotifierInterface *c) { @@ -979,108 +668,17 @@ void ScrollingList::removeComponentForNotifications(MenuNotifierInterface *c) } } - -ComponentItemBinding* ScrollingList::getPendingSelectedCollectionItemSprite() -{ - ComponentItemBinding *item = NULL; - - if(spriteList_) - { - unsigned int index = selectedSpriteListIndex_; - - if(currentScrollDirection_ == ScrollDirectionBack) - { - circularDecrement(index, spriteList_); - } - if(currentScrollDirection_ == ScrollDirectionForward) - { - circularIncrement(index, spriteList_); - } - - if(spriteList_ && spriteList_->size() > 0) - { - index = (index + selectedSpriteListIndex_) % spriteList_->size(); - - item = spriteList_->at(index); - } - } - - return item; -} - bool ScrollingList::isIdle() { - return (Component::isIdle() && currentScrollState_ == ScrollStateIdle); -} + if(!Component::isIdle() || currentScrollState_ != ScrollStateIdle) return false; -void ScrollingList::circularIncrement(unsigned int &index, std::vector* list) -{ - index++; - - if(index >= list->size()) + for(unsigned int i = 0; i < components_.size(); ++i) { - index = 0; - } -} - -void ScrollingList::circularDecrement(unsigned int &index, std::vector* list) -{ - if(index > 0) - { - index--; - } - else - { - if(list->size() > 0) - { - index = list->size() - 1; - } - else - { - index = 0; - } - } -} - -int ScrollingList::circularIncrement(unsigned int index, unsigned int offset, std::vector *list) -{ - unsigned int end = index + offset; - - while(end >= list->size() && list->size() > 0) - { - end -= list->size(); + Component *c = components_.at(i); + if(c && !c->isIdle()) return false; } - return end; + return true; } -void ScrollingList::circularIncrement(unsigned int &index, std::vector *list) -{ - index++; - - if(index >= list->size()) - { - index = 0; - } -} - -void ScrollingList::circularDecrement(unsigned int &index, std::vector *list) -{ - if(index > 0) - { - index--; - } - else - { - if(list && list->size() > 0) - { - index = list->size() - 1; - } - else - { - index = 0; - } - } -} - diff --git a/RetroFE/Source/Graphics/Component/ScrollingList.h b/RetroFE/Source/Graphics/Component/ScrollingList.h index 2a87fb9..9680317 100644 --- a/RetroFE/Source/Graphics/Component/ScrollingList.h +++ b/RetroFE/Source/Graphics/Component/ScrollingList.h @@ -1,136 +1,133 @@ -/* This file is part of RetroFE. - * - * RetroFE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RetroFE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RetroFE. If not, see . - */ -#pragma once - -#include -#include "Component.h" -#include "../Animate/Tween.h" -#include "../ComponentItemBinding.h" -#include "../MenuNotifierInterface.h" -#include "../ViewInfo.h" -#include "../../Database/Configuration.h" -#include - - -//todo: This scrolling implementation needs to be overhauled -// It needs to have a common interface to support different menu types -// (It was originally sandbox code that creeped into here) - -class Configuration; -class Font; - -class ScrollingList : public Component -{ -public: - enum ScrollDirection - { - ScrollDirectionBack, - ScrollDirectionForward, - ScrollDirectionIdle, - - }; - - ScrollingList(Configuration &c, - float scaleX, - float scaleY, - Font *font, - std::string layoutKey, - std::string imageType); - - ScrollingList(const ScrollingList ©); - virtual ~ScrollingList(); - void triggerMenuEnterEvent(); - void triggerMenuExitEvent(); - - bool allocateTexture(ComponentItemBinding *s); - void deallocateTexture(ComponentItemBinding *s); - void setItems(std::vector *spriteList); - void destroyItems(); - void setPoints(std::vector *scrollPoints, std::vector *tweenPoints); - void setScrollDirection(ScrollDirection direction); - void pageUp(); - void pageDown(); - void letterUp(); - void letterDown(); - bool isIdle(); +/* This file is part of RetroFE. + * + * RetroFE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RetroFE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RetroFE. If not, see . + */ +#pragma once + +#include +#include "Component.h" +#include "../Animate/Tween.h" +#include "../MenuNotifierInterface.h" +#include "../ViewInfo.h" +#include "../../Database/Configuration.h" +#include + + +//todo: This scrolling implementation needs to be overhauled +// It needs to have a common interface to support different menu types +// (It was originally sandbox code that creeped into here) + +class Configuration; +class Font; + +class ScrollingList : public Component +{ +public: + enum ScrollDirection + { + ScrollDirectionBack, + ScrollDirectionForward, + ScrollDirectionIdle, + + }; + + ScrollingList(Configuration &c, + float scaleX, + float scaleY, + Font *font, + std::string layoutKey, + std::string imageType); + + ScrollingList(const ScrollingList ©); + virtual ~ScrollingList(); + void triggerMenuEnterEvent(); + void triggerMenuExitEvent(); + + bool allocateTexture(unsigned int index, Item *i); + void deallocateTexture(unsigned int index); + void setItems(std::vector *items); + void destroyItems(); + void setPoints(std::vector *scrollPoints, std::vector *tweenPoints); + void setScrollDirection(ScrollDirection direction); + void pageUp(); + void pageDown(); + void letterUp(); + void letterDown(); + void letterChange(bool increment); + bool isIdle(); unsigned int getScrollOffsetIndex(); void setScrollOffsetIndex(unsigned int index); - void setSelectedIndex(int selectedIndex); - ComponentItemBinding *getSelectedCollectionItemSprite(); - ComponentItemBinding *getPendingCollectionItemSprite(); - ComponentItemBinding *getPendingSelectedCollectionItemSprite(); - void addComponentForNotifications(MenuNotifierInterface *c); - void removeComponentForNotifications(MenuNotifierInterface *c); - std::vector *getCollectionItemSprites(); - void removeSelectedItem(); - void freeGraphicsMemory(); - void update(float dt); - void draw(); - void draw(unsigned int layer); - void setScrollAcceleration(float value); - void setStartScrollTime(float value); - bool horizontalScroll; - -private: - void click(double nextScrollTime); - void deallocateSpritePoints(); - void allocateSpritePoints(); - void updateSprite(unsigned int spriteIndex, unsigned int pointIndex, bool newScroll, float dt, double nextScrollTime); - unsigned int getNextTween(unsigned int currentIndex, std::vector *list); - void resetTweens(Component *c, AnimationEvents *sets, ViewInfo *currentViewInfo, ViewInfo *nextViewInfo, double scrollTime); - - enum ScrollState - { - ScrollStateActive, - ScrollStatePageChange, - ScrollStateStopping, - ScrollStateIdle - }; - - std::vector *spriteList_; - std::vector *scrollPoints_; - std::vector *tweenPoints_; - std::vector notificationComponents_; - float tweenEnterTime_; - bool focus_; - - unsigned int firstSpriteIndex_; - unsigned int selectedSpriteListIndex_; - bool scrollStopRequested_; - bool notifyAllRequested_; - ScrollDirection currentScrollDirection_; - ScrollDirection requestedScrollDirection_; - ScrollState currentScrollState_; - float scrollAcceleration_; - float startScrollTime_; - float scrollPeriod_; - - int circularIncrement(unsigned int index, unsigned int offset, std::vector *list); - void circularIncrement(unsigned &index, std::vector *list); - void circularDecrement(unsigned &index, std::vector *list); - void circularIncrement(unsigned &index, std::vector *list); - void circularDecrement(unsigned &index, std::vector *list); - void updateOffset(float dt); - - std::string collection_; - Configuration &config_; - float scaleX_; - float scaleY_; - Font *fontInst_; - std::string layoutKey_; - std::string imageType_; -}; - + void setSelectedIndex(int selectedIndex); + void addComponentForNotifications(MenuNotifierInterface *c); + void removeComponentForNotifications(MenuNotifierInterface *c); + void freeGraphicsMemory(); + void update(float dt); + void draw(); + void draw(unsigned int layer); + void setScrollAcceleration(float value); + void setStartScrollTime(float value); + bool horizontalScroll; + + +private: + void click(double nextScrollTime); + void deallocateSpritePoints(); + void allocateSpritePoints(); + void resetTweens(Component *c, AnimationEvents *sets, ViewInfo *currentViewInfo, ViewInfo *nextViewInfo, double scrollTime); + unsigned int loopIncrement(unsigned int offset, unsigned int i, unsigned int size); + unsigned int loopDecrement(unsigned int offset, unsigned int i, unsigned int size); + + enum ScrollState + { + ScrollStateActive, + ScrollStatePageChange, + ScrollStateStopping, + ScrollStateIdle + }; + + std::vector *spriteList_; + std::vector *scrollPoints_; + std::vector *tweenPoints_; + std::vector notificationComponents_; + bool focus_; + + unsigned int itemIndex_; + unsigned int componentIndex_; + unsigned int selectedOffsetIndex_; + + bool scrollStopRequested_; + bool notifyAllRequested_; + + ScrollDirection currentScrollDirection_; + ScrollDirection requestedScrollDirection_; + ScrollState currentScrollState_; + + float scrollAcceleration_; + float startScrollTime_; + float scrollPeriod_; + + Configuration &config_; + float scaleX_; + float scaleY_; + Font *fontInst_; + std::string layoutKey_; + std::string imageType_; + + + std::vector *items_; + std::vector components_; + + +}; + diff --git a/RetroFE/Source/Graphics/Page.cpp b/RetroFE/Source/Graphics/Page.cpp index eb7392e..9054507 100644 --- a/RetroFE/Source/Graphics/Page.cpp +++ b/RetroFE/Source/Graphics/Page.cpp @@ -23,13 +23,13 @@ #include "Component/ScrollingList.h" #include "../Sound/Sound.h" #include "ComponentItemBindingBuilder.h" +#include #include Page::Page(Configuration &config) : config_(config) , activeMenu_(NULL) , menuDepth_(0) - , items_(NULL) , scrollActive_(false) , selectedItem_(NULL) , textStatusComponent_(NULL) @@ -410,8 +410,6 @@ void Page::letterScroll(ScrollDirection direction) bool Page::pushCollection(CollectionInfo *collection) { - collections_.push_back(collection); - std::vector *sprites = ComponentItemBindingBuilder::buildCollectionItems(&collection->items); int menuExitIndex = -1; int menuEnterIndex = -1; @@ -426,6 +424,7 @@ bool Page::pushCollection(CollectionInfo *collection) menuExitIndex = menuDepth_ - 1; } + // grow the menu as needed if(menus_.size() >= menuDepth_ && activeMenu_) { ScrollingList *newList = new ScrollingList(*activeMenu_); @@ -433,12 +432,22 @@ bool Page::pushCollection(CollectionInfo *collection) pushMenu(newList); } + activeMenu_ = menus_[menuDepth_]; activeMenu_->collectionName = collection->name; - activeMenu_->destroyItems(); - activeMenu_->setItems(sprites); + activeMenu_->setItems(&collection->items); activeMenu_->triggerMenuEnterEvent(); + // build the collection info instance + MenuInfo_S info; + info.collection = collection; + info.menu = activeMenu_; + info.playlist = collection->playlists.begin(); + info.queueDelete = false; + collections_.push_back(info); + + playlist_ = info.playlist; + if(menuDepth_ < menus_.size()) { menuEnterIndex = menuDepth_; @@ -469,18 +478,19 @@ bool Page::popCollection() { int menuExitIndex = -1; int menuEnterIndex = -1; - CollectionInfo *collection = NULL; - if(menuDepth_ <= 1) - { - return false; - } - if(collections_.size() <= 1) - { - return false; - } + if(!activeMenu_) return false; + if(menuDepth_ <= 1) return false; + if(collections_.size() <= 1) return false; + + // queue the collection for deletion + MenuInfo_S &info = collections_.back(); + info.queueDelete = true; + + // get the next collection off of the stack collections_.pop_back(); - collection = collections_.back(); + info = collections_.back(); + playlist_ = info.playlist; if(activeMenu_) { @@ -500,7 +510,7 @@ bool Page::popCollection() { for(std::vector::iterator it = LayerComponents[i].begin(); it != LayerComponents[i].end(); ++it) { - (*it)->collectionName = collection->name; + (*it)->collectionName = info.collection->name; if(menuEnterIndex >= 0) { @@ -517,6 +527,24 @@ bool Page::popCollection() return true; } +void Page::nextPlaylist() +{ + MenuInfo_S &info = collections_.back(); + unsigned int numlists = info.collection->playlists.size(); + + for(unsigned int i = 0; i <= numlists; ++i) + { + playlist_++; + // wrap + if(playlist_ == info.collection->playlists.end()) playlist_ = info.collection->playlists.begin(); + + // find the first playlist + if(playlist_->second->size() != 0) break; + } + + activeMenu_->setItems(playlist_->second); + activeMenu_->triggerMenuEnterEvent(); +} void Page::update(float dt) { @@ -544,7 +572,28 @@ void Page::update(float dt) { for(std::vector::iterator it = LayerComponents[i].begin(); it != LayerComponents[i].end(); ++it) { - (*it)->update(dt); + if(*it) (*it)->update(dt); + } + } + + // many nodes still have handles on the collection info. We need to delete + // them once everything is done using them + std::list::iterator del = collections_.begin(); + + while(del != collections_.end()) + { + MenuInfo_S &info = *del; + if(info.queueDelete && info.menu && info.menu->isIdle()) + { + std::list::iterator next = del; + ++next; + + if(info.collection) delete info.collection; + collections_.erase(del); + } + else + { + ++del; } } } @@ -555,7 +604,7 @@ void Page::draw() { for(std::vector::iterator it = LayerComponents[i].begin(); it != LayerComponents[i].end(); ++it) { - (*it)->draw(); + if(*it) (*it)->draw(); } for(MenuVector_T::iterator it = menus_.begin(); it != menus_.end(); it++) @@ -569,14 +618,11 @@ void Page::draw() std::string Page::getCollectionName() { - CollectionInfo *info = collections_.back(); + if(collections_.size() == 0) return ""; - if(info) - { - return info->name; - } + MenuInfo_S &info = collections_.back(); + return info.collection->name; - return ""; } void Page::freeGraphicsMemory() diff --git a/RetroFE/Source/Graphics/Page.h b/RetroFE/Source/Graphics/Page.h index 617fa76..cbf6406 100644 --- a/RetroFE/Source/Graphics/Page.h +++ b/RetroFE/Source/Graphics/Page.h @@ -16,13 +16,13 @@ #pragma once #include "MenuNotifierInterface.h" +#include "../Collection/CollectionInfo.h" #include #include #include #include -class CollectionInfo; class Component; class Configuration; class ScrollingList; @@ -46,6 +46,7 @@ public: virtual void onNewItemSelected(Item *); bool pushCollection(CollectionInfo *collection); bool popCollection(); + void nextPlaylist(); void pushMenu(ScrollingList *s); bool isMenusFull(); void setLoadSound(Sound *chunk); @@ -83,17 +84,28 @@ private: void highlight(); std::string collectionName_; Configuration &config_; + + struct MenuInfo_S + { + CollectionInfo *collection; + ScrollingList *menu; + CollectionInfo::Playlists_T::iterator playlist; + bool queueDelete; + }; + typedef std::vector MenuVector_T; - typedef std::vector CollectionInfo_T; + typedef std::list CollectionVector_T; ScrollingList *activeMenu_; unsigned int menuDepth_; MenuVector_T menus_; - CollectionInfo_T collections_; + CollectionVector_T collections_; static const unsigned int NUM_LAYERS = 8; std::vector LayerComponents[NUM_LAYERS]; - std::vector *items_; + std::list deleteMenuList_; + std::list deleteCollectionList_; + bool scrollActive_; Item *selectedItem_; @@ -105,6 +117,7 @@ private: Sound *selectSoundChunk_; float minShowTime_; float elapsedTime_; + CollectionInfo::Playlists_T::iterator playlist_; }; diff --git a/RetroFE/Source/RetroFE.cpp b/RetroFE/Source/RetroFE.cpp index e7a3111..8cc0a88 100644 --- a/RetroFE/Source/RetroFE.cpp +++ b/RetroFE/Source/RetroFE.cpp @@ -512,6 +512,10 @@ RetroFE::RETROFE_STATE RetroFE::processUserInput(Page *page) } } } + if(input_.keystate(UserInput::KeyCodeNextPlaylist) && page->isMenuIdle()) + { + page->nextPlaylist(); + } if (input_.keystate(UserInput::KeyCodeBack) && page->isMenuIdle()) {