Refactoring ScrollingList to address memory leak issues (required for playlists)

This commit is contained in:
Don Honerbrink 2015-07-31 17:33:54 -05:00
parent 8bd246818c
commit f912afcdf0
3 changed files with 298 additions and 701 deletions

View File

@ -19,7 +19,6 @@
#include "../Animate/Animation.h" #include "../Animate/Animation.h"
#include "../Animate/AnimationEvents.h" #include "../Animate/AnimationEvents.h"
#include "../Animate/TweenTypes.h" #include "../Animate/TweenTypes.h"
#include "../ComponentItemBinding.h"
#include "../Font.h" #include "../Font.h"
#include "ScrollingList.h" #include "ScrollingList.h"
#include "ImageBuilder.h" #include "ImageBuilder.h"
@ -50,10 +49,9 @@ ScrollingList::ScrollingList(Configuration &c,
, spriteList_(NULL) , spriteList_(NULL)
, scrollPoints_(NULL) , scrollPoints_(NULL)
, tweenPoints_(NULL) , tweenPoints_(NULL)
, tweenEnterTime_(0)
, focus_(false) , focus_(false)
, firstSpriteIndex_(0) , itemIndex_(0)
, selectedSpriteListIndex_(0) , componentIndex_(0)
, scrollStopRequested_(true) , scrollStopRequested_(true)
, notifyAllRequested_(false) , notifyAllRequested_(false)
, currentScrollDirection_(ScrollDirectionIdle) , currentScrollDirection_(ScrollDirectionIdle)
@ -68,6 +66,7 @@ ScrollingList::ScrollingList(Configuration &c,
, fontInst_(font) , fontInst_(font)
, layoutKey_(layoutKey) , layoutKey_(layoutKey)
, imageType_(imageType) , imageType_(imageType)
, items_(NULL)
{ {
} }
@ -75,10 +74,7 @@ ScrollingList::ScrollingList(const ScrollingList &copy)
: Component(copy) : Component(copy)
, horizontalScroll(copy.horizontalScroll) , horizontalScroll(copy.horizontalScroll)
, spriteList_(NULL) , spriteList_(NULL)
, tweenEnterTime_(0)
, focus_(false) , focus_(false)
, firstSpriteIndex_(0)
, selectedSpriteListIndex_(copy.selectedSpriteListIndex_)
, scrollStopRequested_(true) , scrollStopRequested_(true)
, notifyAllRequested_(false) , notifyAllRequested_(false)
, currentScrollDirection_(ScrollDirectionIdle) , currentScrollDirection_(ScrollDirectionIdle)
@ -93,6 +89,7 @@ ScrollingList::ScrollingList(const ScrollingList &copy)
, fontInst_(copy.fontInst_) , fontInst_(copy.fontInst_)
, layoutKey_(copy.layoutKey_) , layoutKey_(copy.layoutKey_)
, imageType_(copy.imageType_) , imageType_(copy.imageType_)
, items_(NULL)
{ {
scrollPoints_ = NULL; scrollPoints_ = NULL;
@ -126,38 +123,34 @@ ScrollingList::~ScrollingList()
} }
void ScrollingList::setItems(std::vector<ComponentItemBinding *> *spriteList) void ScrollingList::setItems(CollectionInfo *info)
{ {
notifyAllRequested_ = true; std::cout << "setItems" << std::endl;
spriteList_ = spriteList; deallocateSpritePoints();
firstSpriteIndex_ = 0;
if(!spriteList_) collection_ = info;
{ items_ = &collection_->items;
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_);
}
itemIndex_ = 0;
componentIndex_ = 0;
allocateSpritePoints(); 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;
// (A - B) % C = ((A % C) - (B % C)) % C
return ((offset % size) - (i % size) ) % size;
} }
@ -173,214 +166,125 @@ void ScrollingList::setStartScrollTime(float value)
void ScrollingList::deallocateSpritePoints() 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_);
} }
} }
void ScrollingList::allocateSpritePoints() void ScrollingList::allocateSpritePoints()
{ {
if(!scrollPoints_) for(unsigned int i = 0; items_ && i < scrollPoints_->size(); ++i)
{ {
return; unsigned int index = loopIncrement(itemIndex_, i, items_->size());
} Item *item = items_->at(index);
if(!spriteList_)
{
return;
}
if(spriteList_->size() == 0)
{
return;
}
if(!tweenPoints_)
{
return;
}
unsigned int spriteIndex = firstSpriteIndex_; allocateTexture(i, item);
Component *c = components_.at(i);
for(unsigned int i = 0; i < scrollPoints_->size(); ++i) ViewInfo *current = scrollPoints_->at(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);
resetTweens(c, tweenPoints_->at(i), currentViewInfo, nextViewInfo, 0); unsigned int nextI = loopIncrement(i, 1, scrollPoints_->size());
ViewInfo *next = scrollPoints_->at(nextI);
circularIncrement(spriteIndex, spriteList_); resetTweens(c, tweenPoints_->at(i), current, next, 0);
} }
} }
void ScrollingList::destroyItems() void ScrollingList::destroyItems()
{ {
if(!spriteList_) deallocateSpritePoints();
{ //todo: who deletes the CollectionInfo?
return;
}
std::vector<ComponentItemBinding *>::iterator it = spriteList_->begin();
while(it != spriteList_->end())
{
if(*it != NULL)
{
deallocateTexture(*it);
// items are destroyed when collections are destroyed
delete *it;
}
spriteList_->erase(it);
it = spriteList_->begin();
}
delete spriteList_;
spriteList_ = NULL;
} }
void ScrollingList::setPoints(std::vector<ViewInfo *> *scrollPoints, std::vector<AnimationEvents *> *tweenPoints) void ScrollingList::setPoints(std::vector<ViewInfo *> *scrollPoints, std::vector<AnimationEvents *> *tweenPoints)
{ {
deallocateSpritePoints();
scrollPoints_ = scrollPoints; scrollPoints_ = scrollPoints;
tweenPoints_ = tweenPoints; tweenPoints_ = tweenPoints;
// empty out the list as we will resize it
components_.clear();
if(scrollPoints && scrollPoints_->size() > components_.size())
{
components_.resize(scrollPoints_->size(), NULL);
}
allocateSpritePoints();
} }
unsigned int ScrollingList::getScrollOffsetIndex() unsigned int ScrollingList::getScrollOffsetIndex()
{ {
return firstSpriteIndex_; return itemIndex_;
} }
void ScrollingList::setScrollOffsetIndex(unsigned int index) void ScrollingList::setScrollOffsetIndex(unsigned int index)
{ {
if(spriteList_ && index < spriteList_->size()) itemIndex_ = index;
{
deallocateSpritePoints();
firstSpriteIndex_ = index;
allocateSpritePoints();
}
} }
void ScrollingList::setSelectedIndex(int selectedIndex) void ScrollingList::setSelectedIndex(int selectedIndex)
{ {
selectedSpriteListIndex_ = selectedIndex; selectedOffsetIndex_ = selectedIndex;
for(unsigned int i = 0; spriteList_ && scrollPoints_ && i < selectedSpriteListIndex_; ++i)
{
circularDecrement(firstSpriteIndex_, spriteList_);
}
} }
void ScrollingList::click(double nextScrollTime) void ScrollingList::click(double nextScrollTime)
{ {
if(!spriteList_) ViewInfo *cur;
{ ViewInfo *next;
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) if(currentScrollDirection_ == ScrollDirectionBack)
{ {
deallocSpriteIndex = end; next = scrollPoints_->at(componentIndex_);
circularDecrement(firstSpriteIndex_, spriteList_); itemIndex_ = loopIncrement(itemIndex_, 1, items_->size());
allocSpriteIndex = firstSpriteIndex_; componentIndex_ = loopIncrement(componentIndex_, 1, components_.size());
allocPoint = 0; cur = scrollPoints_->at(componentIndex_);
} }
else if(currentScrollDirection_ == ScrollDirectionForward) else if(currentScrollDirection_ == ScrollDirectionForward)
{ {
deallocSpriteIndex = firstSpriteIndex_; next = scrollPoints_->at(componentIndex_);
circularIncrement(firstSpriteIndex_, spriteList_); itemIndex_ = loopDecrement(itemIndex_, 1, items_->size());
allocSpriteIndex = circularIncrement(firstSpriteIndex_, listSize - 1, spriteList_); componentIndex_ = loopDecrement(componentIndex_, 1, components_.size());
allocPoint = listSize - 1; cur = scrollPoints_->at(componentIndex_);
} }
else else
{ {
return; return;
} }
deallocateTexture(spriteList_->at(deallocSpriteIndex)); Item *i = items_->at(itemIndex_);
allocateTexture(spriteList_->at(allocSpriteIndex));
Component *c = spriteList_->at(allocSpriteIndex)->component; deallocateTexture(componentIndex_);
ViewInfo *currentViewInfo = scrollPoints_->at(allocPoint); allocateTexture(componentIndex_, i);
unsigned int nextI = getNextTween(allocPoint, scrollPoints_); Component *c = components_.at(componentIndex_);
ViewInfo *nextViewInfo = scrollPoints_->at(nextI);
resetTweens(c, tweenPoints_->at(allocPoint), currentViewInfo, nextViewInfo, nextScrollTime); resetTweens(c, tweenPoints_->at(componentIndex_), cur, next, 0);
}
unsigned int ScrollingList::getNextTween(unsigned int currentIndex, std::vector<ViewInfo *> *list)
{
if(currentScrollDirection_ == ScrollDirectionForward)
{
circularDecrement(currentIndex, list);
}
else if(currentScrollDirection_ == ScrollDirectionBack)
{
circularIncrement(currentIndex, list);
}
return currentIndex;
} }
void ScrollingList::pageUp() void ScrollingList::pageUp()
{ {
notifyAllRequested_ = true; notifyAllRequested_ = true;
if(components_.size() == 0) return;
deallocateSpritePoints(); deallocateSpritePoints();
if(spriteList_ && scrollPoints_ && scrollPoints_->size() > 2) itemIndex_ = loopDecrement(itemIndex_, components_.size(), items_->size());
{
scrollPeriod_ = 0;
unsigned int counts = scrollPoints_->size() - 2;
for(unsigned int i = 0; i < counts; i++)
{
circularDecrement(firstSpriteIndex_, spriteList_);
}
}
allocateSpritePoints(); allocateSpritePoints();
// CurrentScrollState = ScrollStatePageChange;
} }
void ScrollingList::pageDown() void ScrollingList::pageDown()
{ {
notifyAllRequested_ = true; notifyAllRequested_ = true;
if(components_.size() == 0) return;
deallocateSpritePoints(); deallocateSpritePoints();
if(spriteList_ && scrollPoints_ && scrollPoints_->size() > 2) itemIndex_ = loopIncrement(itemIndex_, components_.size(), items_->size());
{
unsigned int counts = scrollPoints_->size() - 2;
scrollPeriod_ = 0;
for(unsigned int i = 0; i < counts; i++)
{
circularIncrement(firstSpriteIndex_, spriteList_);
}
}
allocateSpritePoints(); allocateSpritePoints();
} }
@ -388,77 +292,39 @@ void ScrollingList::pageDown()
void ScrollingList::letterUp() void ScrollingList::letterUp()
{ {
notifyAllRequested_ = true; letterChange(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();
} }
void ScrollingList::letterDown() void ScrollingList::letterDown()
{
letterChange(false);
}
void ScrollingList::letterChange(bool increment)
{ {
notifyAllRequested_ = true; notifyAllRequested_ = true;
deallocateSpritePoints(); 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 = items_->at(index)->lowercaseFullTitle();
std::string endname = startname;
unsigned int i = 0; // check if we are changing characters from a-z, or changing from alpha character to non-alpha character
bool done = false; if(isalpha(startname[0]) ^ isalpha(endname[0]))
while(!done && i < spriteList_->size())
{ {
circularIncrement(firstSpriteIndex_, spriteList_); break;
endname = getSelectedCollectionItemSprite()->item->lowercaseFullTitle(); itemIndex_ = index;
++i; }
else if(isalpha(startname[0]) && isalpha(endname[0]) && startname[0] != endname[0])
// 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])) itemIndex_ = index;
{ break;
done = true;
}
else if(isalpha(startname[0]) && isalpha(endname[0]) && startname[0] != endname[0])
{
done = true;
}
} }
} }
@ -469,18 +335,12 @@ void ScrollingList::letterDown()
void ScrollingList::freeGraphicsMemory() void ScrollingList::freeGraphicsMemory()
{ {
Component::freeGraphicsMemory(); Component::freeGraphicsMemory();
tweenEnterTime_ = 0;
currentScrollDirection_ = ScrollDirectionIdle; currentScrollDirection_ = ScrollDirectionIdle;
requestedScrollDirection_ = ScrollDirectionIdle; requestedScrollDirection_ = ScrollDirectionIdle;
currentScrollState_ = ScrollStateIdle; currentScrollState_ = ScrollStateIdle;
scrollPeriod_ = 0; scrollPeriod_ = 0;
for(unsigned int i = 0; spriteList_ && i < spriteList_->size(); i++) deallocateSpritePoints();
{
ComponentItemBinding *s = spriteList_->at(i);
deallocateTexture(s);
}
} }
void ScrollingList::triggerMenuEnterEvent() void ScrollingList::triggerMenuEnterEvent()
@ -488,36 +348,10 @@ void ScrollingList::triggerMenuEnterEvent()
focus_ = true; focus_ = true;
notifyAllRequested_ = true; notifyAllRequested_ = true;
if(!scrollPoints_) for(unsigned int i = 0; i < components_.size(); ++i)
{ {
return; Component *c = components_.at(i);
} if(c) c->triggerMenuEnterEvent();
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_);
} }
} }
@ -526,36 +360,10 @@ void ScrollingList::triggerMenuExitEvent()
focus_ = false; focus_ = false;
notifyAllRequested_ = true; notifyAllRequested_ = true;
if(!scrollPoints_) for(unsigned int i = 0; i < components_.size(); ++i)
{ {
return; Component *c = components_.at(i);
} if(c) c->triggerMenuExitEvent();
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_);
} }
} }
@ -563,29 +371,15 @@ void ScrollingList::update(float dt)
{ {
Component::update(dt); Component::update(dt);
if(!scrollPoints_)
{
return;
}
if(!spriteList_)
{
return;
}
if(spriteList_->size() == 0)
{
return;
}
bool readyToScroll = true; bool readyToScroll = true;
bool scrollChanged = false; bool scrollChanged = false;
bool scrollRequested = false; bool scrollRequested = false;
bool scrollStopped = false; bool scrollStopped = false;
// validate all scroll points are done tweening to the next position // validate all scroll points are done tweening to the next position
for(unsigned int i = 0; i < spriteList_->size(); i++) for(unsigned int i = 0; i < components_.size(); i++)
{ {
ComponentItemBinding *s = spriteList_->at(i); Component *c = components_.at(i);
Component *c = s->component;
if(c && c->isMenuScrolling()) if(c && c->isMenuScrolling())
{ {
@ -620,20 +414,11 @@ void ScrollingList::update(float dt)
currentScrollState_ = ScrollStateIdle; currentScrollState_ = ScrollStateIdle;
scrollStopped = true; scrollStopped = true;
// update the tweens now that we are done
unsigned int spriteIndex = firstSpriteIndex_;
for(unsigned int i = 0; i < tweenPoints_->size(); ++i) for(unsigned int i = 0; i < tweenPoints_->size(); ++i)
{ {
ComponentItemBinding *s = spriteList_->at(spriteIndex); Component *c = components_.at(i);
Component *c = s->component; if(c) c->setTweens(tweenPoints_->at(i));
if(c)
{
c->setTweens(tweenPoints_->at(i));
}
circularIncrement(spriteIndex, spriteList_);
} }
} }
@ -652,28 +437,44 @@ void ScrollingList::update(float dt)
} }
unsigned int spriteIndex = firstSpriteIndex_;
for(unsigned int i = 0; i < scrollPoints_->size(); i++) for(unsigned int i = 0; i < scrollPoints_->size(); i++)
{ {
updateSprite(spriteIndex, i, (scrollRequested || scrollChanged), dt, scrollPeriod_); unsigned int cindex = loopIncrement(componentIndex_, i, components_.size());
circularIncrement(spriteIndex, spriteList_); Component *c = components_.at(cindex);
if(c && (scrollRequested || scrollChanged))
{
ViewInfo *currentvi = scrollPoints_->at(i);
unsigned int nextI = 0;
if(currentScrollDirection_ == ScrollDirectionBack)
{
nextI = loopIncrement(i, 1, scrollPoints_->size());
}
if(currentScrollDirection_ == ScrollDirectionForward)
{
nextI = loopDecrement(i, 1, scrollPoints_->size());
}
ViewInfo *nextvi = scrollPoints_->at(nextI);
resetTweens(c, tweenPoints_->at(i), currentvi, nextvi, scrollPeriod_);
c->triggerMenuScrollEvent();
}
if(c) c->update(dt);
} }
if(scrollStopped || (notifyAllRequested_ && focus_)) if(scrollStopped || (notifyAllRequested_ && focus_))
{ {
ComponentItemBinding *sprite = getPendingCollectionItemSprite(); Item *item = getPendingItem();
Item *item = NULL;
if(sprite)
{
item = sprite->item;
}
for(std::vector<MenuNotifierInterface *>::iterator it = notificationComponents_.begin(); for(std::vector<MenuNotifierInterface *>::iterator it = notificationComponents_.begin();
it != notificationComponents_.end(); it != notificationComponents_.end();
it++) it++)
{ {
MenuNotifierInterface *c = *it; MenuNotifierInterface *c = *it;
if(c && item) if(c && item)
{ {
c->onNewItemSelected(item); c->onNewItemSelected(item);
@ -689,47 +490,12 @@ void ScrollingList::update(float dt)
notifyAllRequested_ = false; 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) void ScrollingList::resetTweens(Component *c, AnimationEvents *sets, ViewInfo *currentViewInfo, ViewInfo *nextViewInfo, double scrollTime)
{ {
if(!c) if(!c) return;
{ if(!sets) return;
return; if(!currentViewInfo) return;
} if(!nextViewInfo) return;
if(!sets)
{
return;
}
if(!currentViewInfo)
{
return;
}
if(!nextViewInfo)
{
return;
}
currentViewInfo->ImageHeight = c->baseViewInfo.ImageHeight; currentViewInfo->ImageHeight = c->baseViewInfo.ImageHeight;
currentViewInfo->ImageWidth = c->baseViewInfo.ImageWidth; currentViewInfo->ImageWidth = c->baseViewInfo.ImageWidth;
@ -761,15 +527,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) if(index >= components_.size()) return false;
{
return false;
}
const Item *item = s->item;
//todo: will create a runtime fault if not of the right type //todo: will create a runtime fault if not of the right type
//todo: remove coupling from knowing the collection name //todo: remove coupling from knowing the collection name
@ -834,20 +596,23 @@ bool ScrollingList::allocateTexture(ComponentItemBinding *s)
if(t) if(t)
{ {
s->component = t; components_.at(index) = t;
} }
return true; 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; delete s;
//todo: memory leak here, need to destroy allocated tween points here and in page (cannot be destroyed by component) components_.at(index) = NULL;
} }
s->component = NULL;
} }
void ScrollingList::draw() void ScrollingList::draw()
@ -858,32 +623,11 @@ void ScrollingList::draw()
void ScrollingList::draw(unsigned int layer) void ScrollingList::draw(unsigned int layer)
{ {
if(!scrollPoints_)
for(unsigned int i = 0; i < components_.size(); ++i)
{ {
return; Component *c = components_.at(i);
} if(c) c->draw();
if(!spriteList_)
{
return;
}
if(spriteList_->size() == 0)
{
return;
}
unsigned int spriteIndex = firstSpriteIndex_;
for(unsigned int i = 0; i < scrollPoints_->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_);
} }
} }
@ -895,69 +639,6 @@ void ScrollingList::setScrollDirection(ScrollDirection direction)
scrollStopRequested_ = (direction == ScrollDirectionIdle); 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<ComponentItemBinding *>::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<ComponentItemBinding *> *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) void ScrollingList::addComponentForNotifications(MenuNotifierInterface *c)
{ {
@ -978,29 +659,24 @@ void ScrollingList::removeComponentForNotifications(MenuNotifierInterface *c)
} }
ComponentItemBinding* ScrollingList::getPendingSelectedCollectionItemSprite() Item* ScrollingList::getPendingItem()
{ {
ComponentItemBinding *item = NULL; Item *item = NULL;
if(spriteList_) if(items_ && items_->size() > 0)
{ {
unsigned int index = selectedSpriteListIndex_; unsigned int index = itemIndex_;
if(currentScrollDirection_ == ScrollDirectionBack) if(currentScrollDirection_ == ScrollDirectionBack)
{ {
circularDecrement(index, spriteList_); index = loopDecrement(index, 1, items_->size());
} }
if(currentScrollDirection_ == ScrollDirectionForward) if(currentScrollDirection_ == ScrollDirectionForward)
{ {
circularIncrement(index, spriteList_); index = loopIncrement(index, 1, items_->size());
} }
if(spriteList_ && spriteList_->size() > 0) item = items_->at(index);
{
index = (index + selectedSpriteListIndex_) % spriteList_->size();
item = spriteList_->at(index);
}
} }
return item; return item;
@ -1011,74 +687,4 @@ bool ScrollingList::isIdle()
return (Component::isIdle() && currentScrollState_ == ScrollStateIdle); return (Component::isIdle() && currentScrollState_ == ScrollStateIdle);
} }
void ScrollingList::circularIncrement(unsigned int &index, std::vector<ViewInfo*>* list)
{
index++;
if(index >= list->size())
{
index = 0;
}
}
void ScrollingList::circularDecrement(unsigned int &index, std::vector<ViewInfo*>* 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<ComponentItemBinding *> *list)
{
unsigned int end = index + offset;
while(end >= list->size() && list->size() > 0)
{
end -= list->size();
}
return end;
}
void ScrollingList::circularIncrement(unsigned int &index, std::vector<ComponentItemBinding*> *list)
{
index++;
if(index >= list->size())
{
index = 0;
}
}
void ScrollingList::circularDecrement(unsigned int &index, std::vector<ComponentItemBinding*> *list)
{
if(index > 0)
{
index--;
}
else
{
if(list && list->size() > 0)
{
index = list->size() - 1;
}
else
{
index = 0;
}
}
}

View File

@ -1,136 +1,134 @@
/* This file is part of RetroFE. /* This file is part of RetroFE.
* *
* RetroFE is free software: you can redistribute it and/or modify * RetroFE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* RetroFE is distributed in the hope that it will be useful, * RetroFE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with RetroFE. If not, see <http://www.gnu.org/licenses/>. * along with RetroFE. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <vector> #include <vector>
#include "Component.h" #include "Component.h"
#include "../Animate/Tween.h" #include "../Animate/Tween.h"
#include "../ComponentItemBinding.h" #include "../MenuNotifierInterface.h"
#include "../MenuNotifierInterface.h" #include "../ViewInfo.h"
#include "../ViewInfo.h" #include "../../Database/Configuration.h"
#include "../../Database/Configuration.h" #include <SDL2/SDL.h>
#include <SDL2/SDL.h>
//todo: This scrolling implementation needs to be overhauled
//todo: This scrolling implementation needs to be overhauled // It needs to have a common interface to support different menu types
// It needs to have a common interface to support different menu types // (It was originally sandbox code that creeped into here)
// (It was originally sandbox code that creeped into here)
class Configuration;
class Configuration; class Font;
class Font;
class ScrollingList : public Component
class ScrollingList : public Component {
{ public:
public: enum ScrollDirection
enum ScrollDirection {
{ ScrollDirectionBack,
ScrollDirectionBack, ScrollDirectionForward,
ScrollDirectionForward, ScrollDirectionIdle,
ScrollDirectionIdle,
};
};
ScrollingList(Configuration &c,
ScrollingList(Configuration &c, float scaleX,
float scaleX, float scaleY,
float scaleY, Font *font,
Font *font, std::string layoutKey,
std::string layoutKey, std::string imageType);
std::string imageType);
ScrollingList(const ScrollingList &copy);
ScrollingList(const ScrollingList &copy); virtual ~ScrollingList();
virtual ~ScrollingList(); void triggerMenuEnterEvent();
void triggerMenuEnterEvent(); void triggerMenuExitEvent();
void triggerMenuExitEvent();
bool allocateTexture(unsigned int index, Item *i);
bool allocateTexture(ComponentItemBinding *s); void deallocateTexture(unsigned int index);
void deallocateTexture(ComponentItemBinding *s); void setItems(CollectionInfo *info);
void setItems(std::vector<ComponentItemBinding *> *spriteList); void destroyItems();
void destroyItems(); void setPoints(std::vector<ViewInfo *> *scrollPoints, std::vector<AnimationEvents *> *tweenPoints);
void setPoints(std::vector<ViewInfo *> *scrollPoints, std::vector<AnimationEvents *> *tweenPoints); void setScrollDirection(ScrollDirection direction);
void setScrollDirection(ScrollDirection direction); void pageUp();
void pageUp(); void pageDown();
void pageDown(); void letterUp();
void letterUp(); void letterDown();
void letterDown(); void letterChange(bool increment);
bool isIdle(); bool isIdle();
unsigned int getScrollOffsetIndex(); unsigned int getScrollOffsetIndex();
void setScrollOffsetIndex(unsigned int index); void setScrollOffsetIndex(unsigned int index);
void setSelectedIndex(int selectedIndex); void setSelectedIndex(int selectedIndex);
ComponentItemBinding *getSelectedCollectionItemSprite(); Item *getPendingItem();
ComponentItemBinding *getPendingCollectionItemSprite(); void addComponentForNotifications(MenuNotifierInterface *c);
ComponentItemBinding *getPendingSelectedCollectionItemSprite(); void removeComponentForNotifications(MenuNotifierInterface *c);
void addComponentForNotifications(MenuNotifierInterface *c); void freeGraphicsMemory();
void removeComponentForNotifications(MenuNotifierInterface *c); void update(float dt);
std::vector<ComponentItemBinding *> *getCollectionItemSprites(); void draw();
void removeSelectedItem(); void draw(unsigned int layer);
void freeGraphicsMemory(); void setScrollAcceleration(float value);
void update(float dt); void setStartScrollTime(float value);
void draw(); bool horizontalScroll;
void draw(unsigned int layer);
void setScrollAcceleration(float value);
void setStartScrollTime(float value); private:
bool horizontalScroll; void click(double nextScrollTime);
void deallocateSpritePoints();
private: void allocateSpritePoints();
void click(double nextScrollTime); void resetTweens(Component *c, AnimationEvents *sets, ViewInfo *currentViewInfo, ViewInfo *nextViewInfo, double scrollTime);
void deallocateSpritePoints(); unsigned int loopIncrement(unsigned int offset, unsigned int i, unsigned int size);
void allocateSpritePoints(); unsigned int loopDecrement(unsigned int offset, unsigned int i, unsigned int size);
void updateSprite(unsigned int spriteIndex, unsigned int pointIndex, bool newScroll, float dt, double nextScrollTime);
unsigned int getNextTween(unsigned int currentIndex, std::vector<ViewInfo *> *list); enum ScrollState
void resetTweens(Component *c, AnimationEvents *sets, ViewInfo *currentViewInfo, ViewInfo *nextViewInfo, double scrollTime); {
ScrollStateActive,
enum ScrollState ScrollStatePageChange,
{ ScrollStateStopping,
ScrollStateActive, ScrollStateIdle
ScrollStatePageChange, };
ScrollStateStopping,
ScrollStateIdle std::vector<Component *> *spriteList_;
}; std::vector<ViewInfo *> *scrollPoints_;
std::vector<AnimationEvents *> *tweenPoints_;
std::vector<ComponentItemBinding *> *spriteList_; std::vector<MenuNotifierInterface *> notificationComponents_;
std::vector<ViewInfo *> *scrollPoints_; bool focus_;
std::vector<AnimationEvents *> *tweenPoints_;
std::vector<MenuNotifierInterface *> notificationComponents_; unsigned int itemIndex_;
float tweenEnterTime_; unsigned int componentIndex_;
bool focus_; unsigned int selectedOffsetIndex_;
unsigned int firstSpriteIndex_; bool scrollStopRequested_;
unsigned int selectedSpriteListIndex_; bool notifyAllRequested_;
bool scrollStopRequested_;
bool notifyAllRequested_; ScrollDirection currentScrollDirection_;
ScrollDirection currentScrollDirection_; ScrollDirection requestedScrollDirection_;
ScrollDirection requestedScrollDirection_; ScrollState currentScrollState_;
ScrollState currentScrollState_;
float scrollAcceleration_; float scrollAcceleration_;
float startScrollTime_; float startScrollTime_;
float scrollPeriod_; float scrollPeriod_;
int circularIncrement(unsigned int index, unsigned int offset, std::vector<ComponentItemBinding *> *list); Configuration &config_;
void circularIncrement(unsigned &index, std::vector<ComponentItemBinding *> *list); float scaleX_;
void circularDecrement(unsigned &index, std::vector<ComponentItemBinding *> *list); float scaleY_;
void circularIncrement(unsigned &index, std::vector<ViewInfo *> *list); Font *fontInst_;
void circularDecrement(unsigned &index, std::vector<ViewInfo *> *list); std::string layoutKey_;
void updateOffset(float dt); std::string imageType_;
CollectionInfo *collection_;
std::string collection_;
Configuration &config_;
float scaleX_; std::vector<Item *> *items_;
float scaleY_; std::vector<Component *> components_;
Font *fontInst_;
std::string layoutKey_; };
std::string imageType_;
};

View File

@ -411,7 +411,6 @@ void Page::letterScroll(ScrollDirection direction)
bool Page::pushCollection(CollectionInfo *collection) bool Page::pushCollection(CollectionInfo *collection)
{ {
collections_.push_back(collection); collections_.push_back(collection);
std::vector<ComponentItemBinding *> *sprites = ComponentItemBindingBuilder::buildCollectionItems(&collection->items);
int menuExitIndex = -1; int menuExitIndex = -1;
int menuEnterIndex = -1; int menuEnterIndex = -1;
@ -436,7 +435,7 @@ bool Page::pushCollection(CollectionInfo *collection)
activeMenu_ = menus_[menuDepth_]; activeMenu_ = menus_[menuDepth_];
activeMenu_->collectionName = collection->name; activeMenu_->collectionName = collection->name;
activeMenu_->destroyItems(); activeMenu_->destroyItems();
activeMenu_->setItems(sprites); activeMenu_->setItems(collection);
activeMenu_->triggerMenuEnterEvent(); activeMenu_->triggerMenuEnterEvent();
playlist_ = collection->playlists.begin(); playlist_ = collection->playlists.begin();
@ -515,10 +514,6 @@ bool Page::popCollection()
} }
} }
if(collection)
{
delete collection;
}
return true; return true;
} }
@ -529,10 +524,8 @@ void Page::nextPlaylist()
playlist_++; playlist_++;
if(playlist_ == collection->playlists.end()) playlist_ = collection->playlists.begin(); if(playlist_ == collection->playlists.end()) playlist_ = collection->playlists.begin();
std::vector<ComponentItemBinding *> *sprites = ComponentItemBindingBuilder::buildCollectionItems(&playlist_->second);
activeMenu_->destroyItems(); activeMenu_->destroyItems();
activeMenu_->setItems(sprites); activeMenu_->setItems(collection);
activeMenu_->triggerMenuEnterEvent(); activeMenu_->triggerMenuEnterEvent();
} }