diff --git a/RetroFE/Source/CMakeLists.txt b/RetroFE/Source/CMakeLists.txt index d7084a4..c1be59a 100644 --- a/RetroFE/Source/CMakeLists.txt +++ b/RetroFE/Source/CMakeLists.txt @@ -86,6 +86,7 @@ set(RETROFE_HEADERS "${RETROFE_DIR}/Source/Execute/Launcher.h" "${RETROFE_DIR}/Source/Graphics/Animate/Tween.h" "${RETROFE_DIR}/Source/Graphics/Animate/TweenTypes.h" + "${RETROFE_DIR}/Source/Graphics/Animate/TweenSet.h" "${RETROFE_DIR}/Source/Graphics/ComponentItemBinding.h" "${RETROFE_DIR}/Source/Graphics/Component/Container.h" "${RETROFE_DIR}/Source/Graphics/Component/Component.h" @@ -126,12 +127,13 @@ set(RETROFE_SOURCES "${RETROFE_DIR}/Source/Database/MetadataDatabase.cpp" "${RETROFE_DIR}/Source/Execute/AttractMode.cpp" "${RETROFE_DIR}/Source/Execute/Launcher.cpp" - "${RETROFE_DIR}/Source/Graphics/Animate/Tween.cpp" "${RETROFE_DIR}/Source/Graphics/Font.cpp" "${RETROFE_DIR}/Source/Graphics/FontCache.cpp" "${RETROFE_DIR}/Source/Graphics/PageBuilder.cpp" "${RETROFE_DIR}/Source/Graphics/Page.cpp" "${RETROFE_DIR}/Source/Graphics/ViewInfo.cpp" + "${RETROFE_DIR}/Source/Graphics/Animate/Tween.cpp" + "${RETROFE_DIR}/Source/Graphics/Animate/TweenSet.cpp" "${RETROFE_DIR}/Source/Graphics/ComponentItemBindingBuilder.cpp" "${RETROFE_DIR}/Source/Graphics/ComponentItemBinding.cpp" "${RETROFE_DIR}/Source/Graphics/Component/Container.cpp" diff --git a/RetroFE/Source/Collection/MenuParser.cpp b/RetroFE/Source/Collection/MenuParser.cpp index eb76da8..7eda450 100644 --- a/RetroFE/Source/Collection/MenuParser.cpp +++ b/RetroFE/Source/Collection/MenuParser.cpp @@ -56,7 +56,6 @@ bool MenuParser::GetMenuItems(CollectionInfo *collection) // gracefully exit if there is no menu file for the pa if(file.good()) { - Logger::Write(Logger::ZONE_INFO, "Menu", "Found menu"); std::vector buffer((std::istreambuf_iterator(file)), std::istreambuf_iterator()); buffer.push_back('\0'); diff --git a/RetroFE/Source/Database/Configuration.cpp b/RetroFE/Source/Database/Configuration.cpp index 3d3a4be..cb2e187 100644 --- a/RetroFE/Source/Database/Configuration.cpp +++ b/RetroFE/Source/Database/Configuration.cpp @@ -41,6 +41,8 @@ Configuration::~Configuration() void Configuration::Initialize() { + Configuration::SetAbsolutePath("D:/RetroFE"); +#if 0 const char *environment = std::getenv("RETROFE_PATH"); std::string environmentStr; if (environment != NULL) @@ -68,6 +70,7 @@ void Configuration::Initialize() Configuration::SetAbsolutePath(sPath); } +#endif } void Configuration::SetCurrentCollection(std::string collection) diff --git a/RetroFE/Source/Graphics/Animate/Tween.h b/RetroFE/Source/Graphics/Animate/Tween.h index 9afecec..72c0267 100644 --- a/RetroFE/Source/Graphics/Animate/Tween.h +++ b/RetroFE/Source/Graphics/Animate/Tween.h @@ -1,5 +1,17 @@ -/* This file is subject to the terms and conditions defined in - * file 'LICENSE.txt', which is part of this source code package. +/* 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 diff --git a/RetroFE/Source/Graphics/Animate/TweenSet.cpp b/RetroFE/Source/Graphics/Animate/TweenSet.cpp new file mode 100644 index 0000000..e69de29 diff --git a/RetroFE/Source/Graphics/Animate/TweenSet.h b/RetroFE/Source/Graphics/Animate/TweenSet.h new file mode 100644 index 0000000..35a5dfd --- /dev/null +++ b/RetroFE/Source/Graphics/Animate/TweenSet.h @@ -0,0 +1,74 @@ +/* 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 "Tween.h" +#include +#include + + + +class TweenSet +{ +public: + typedef std::vector *> TweenSets; + //todo: delete the tweens in a destructor + + + TweenSets *GetOnEnterTweens() + { + return &OnEnterTweens; + } + TweenSets *GetOnExitTweens() + { + return &OnExitTweens; + } + TweenSets *GetOnIdleTweens() + { + return &OnIdleTweens; + } + TweenSets *GetOnHighlightEnterTweens() + { + return &OnHighlightEnterTweens; + } + TweenSets *GetOnHighlightExitTweens() + { + return &OnHighlightExitTweens; + } + TweenSets *GetOnMenuEnterTweens() + { + return &OnMenuEnterTweens; + } + TweenSets *GetOnMenuScrollTweens() + { + return &OnMenuScrollTweens; + } + TweenSets *GetOnMenuExitTweens() + { + return &OnMenuExitTweens; + } + +private: + TweenSets OnEnterTweens; + TweenSets OnExitTweens; + TweenSets OnIdleTweens; + TweenSets OnHighlightEnterTweens; + TweenSets OnHighlightExitTweens; + TweenSets OnMenuEnterTweens; + TweenSets OnMenuScrollTweens; + TweenSets OnMenuExitTweens; + +}; \ No newline at end of file diff --git a/RetroFE/Source/Graphics/Component/Component.cpp b/RetroFE/Source/Graphics/Component/Component.cpp index 879cdbe..bc3d538 100644 --- a/RetroFE/Source/Graphics/Component/Component.cpp +++ b/RetroFE/Source/Graphics/Component/Component.cpp @@ -21,15 +21,12 @@ Component::Component() { - OnEnterTweens = NULL; - OnExitTweens = NULL; - OnIdleTweens = NULL; - OnHighlightEnterTweens = NULL; - OnHighlightExitTweens = NULL; + Tweens = NULL; SelectedItem = NULL; NewItemSelectedSinceEnter = false; BackgroundTexture = NULL; FreeGraphicsMemory(); + } Component::~Component() @@ -42,6 +39,10 @@ void Component::FreeGraphicsMemory() CurrentAnimationState = HIDDEN; EnterRequested = false; ExitRequested = false; + MenuEnterRequested = false; + MenuScrollRequested = false; + MenuExitRequested = false; + NewItemSelected = false; HighlightExitComplete = false; CurrentTweens = NULL; @@ -87,6 +88,23 @@ void Component::TriggerExitEvent() ExitRequested = true; } + + +void Component::TriggerMenuEnterEvent() +{ + MenuEnterRequested = true; +} + +void Component::TriggerMenuScrollEvent() +{ + MenuScrollRequested = true; +} + + +void Component::TriggerMenuExitEvent() +{ + MenuExitRequested = true; +} void Component::TriggerHighlightEvent(Item *selectedItem) { NewItemSelected = true; @@ -108,6 +126,22 @@ bool Component::IsWaiting() return (CurrentAnimationState == HIGHLIGHT_WAIT); } +bool Component::IsMenuScrolling() +{ + return (CurrentAnimationState == MENU_ENTER || CurrentAnimationState == MENU_SCROLL || CurrentAnimationState == MENU_EXIT || MenuScrollRequested); +} + + +std::string Component::GetCollectionName() +{ + return CollectionName; +} + +void Component::SetCollectionName(std::string collectionName) +{ + CollectionName = collectionName; +} + void Component::Update(float dt) { ElapsedTweenTime += dt; @@ -122,21 +156,38 @@ void Component::Update(float dt) CurrentTweens = NULL; // There was no request to override our state path. Continue on as normal. + std::stringstream ss; switch(CurrentAnimationState) { + case MENU_ENTER: + CurrentTweens = NULL; + CurrentAnimationState = IDLE; + break; + + case MENU_SCROLL: + CurrentTweens = NULL; + CurrentAnimationState = IDLE; + break; + + case MENU_EXIT: + CurrentTweens = NULL; + CurrentAnimationState = IDLE; + Logger::Write(Logger::ZONE_ERROR, "Component", "completed menu exit tween (hidden)"); + break; + + case ENTER: - CurrentTweens = OnHighlightEnterTweens; + CurrentTweens = Tweens->GetOnHighlightEnterTweens(); CurrentAnimationState = HIGHLIGHT_ENTER; break; case EXIT: CurrentTweens = NULL; CurrentAnimationState = HIDDEN; - break; case HIGHLIGHT_ENTER: - CurrentTweens = OnIdleTweens; + CurrentTweens = Tweens->GetOnIdleTweens(); CurrentAnimationState = IDLE; break; @@ -144,17 +195,35 @@ void Component::Update(float dt) // prevent us from automatically jumping to the exit tween upon enter if(EnterRequested) { - EnterRequested = false; - NewItemSelected = false; + EnterRequested = false; + NewItemSelected = false; + } + else if(MenuEnterRequested) + { + MenuEnterRequested = false; + CurrentTweens = Tweens->GetOnMenuEnterTweens(); + CurrentAnimationState = MENU_ENTER; + } + else if(MenuScrollRequested) + { + MenuScrollRequested = false; + CurrentTweens = Tweens->GetOnMenuScrollTweens(); + CurrentAnimationState = MENU_SCROLL; + } + else if(MenuExitRequested) + { + MenuExitRequested = false; + CurrentTweens = Tweens->GetOnMenuExitTweens(); + CurrentAnimationState = MENU_EXIT; } else if(IsScrollActive() || NewItemSelected || ExitRequested) { - CurrentTweens = OnHighlightExitTweens; + CurrentTweens = Tweens->GetOnHighlightExitTweens(); CurrentAnimationState = HIGHLIGHT_EXIT; } else { - CurrentTweens = OnIdleTweens; + CurrentTweens = Tweens->GetOnIdleTweens(); CurrentAnimationState = IDLE; } break; @@ -166,14 +235,14 @@ void Component::Update(float dt) if(ExitRequested && (CurrentAnimationState == HIGHLIGHT_WAIT)) { - CurrentTweens = OnHighlightExitTweens; + CurrentTweens = Tweens->GetOnHighlightExitTweens(); CurrentAnimationState = HIGHLIGHT_EXIT; } else if(ExitRequested && (CurrentAnimationState == HIGHLIGHT_EXIT)) { - CurrentTweens = OnExitTweens; + CurrentTweens = Tweens->GetOnExitTweens(); CurrentAnimationState = EXIT; ExitRequested = false; } @@ -184,7 +253,7 @@ void Component::Update(float dt) } else if(NewItemSelected) { - CurrentTweens = OnHighlightEnterTweens; + CurrentTweens = Tweens->GetOnHighlightEnterTweens(); CurrentAnimationState = HIGHLIGHT_ENTER; HighlightExitComplete = true; NewItemSelected = false; @@ -199,9 +268,28 @@ void Component::Update(float dt) case HIDDEN: if(EnterRequested || ExitRequested) { - CurrentTweens = OnEnterTweens; + CurrentTweens = Tweens->GetOnEnterTweens(); CurrentAnimationState = ENTER; } + else if(MenuExitRequested) + { + CurrentTweens = Tweens->GetOnMenuExitTweens(); + CurrentAnimationState = MENU_EXIT; + MenuExitRequested = false; + } + else if(MenuEnterRequested) + { + CurrentTweens = Tweens->GetOnMenuEnterTweens(); + CurrentAnimationState = MENU_ENTER; + MenuEnterRequested = false; + + } + else if(MenuScrollRequested) + { + MenuScrollRequested = false; + CurrentTweens = Tweens->GetOnMenuScrollTweens(); + CurrentAnimationState = MENU_SCROLL; + } else { CurrentTweens = NULL; diff --git a/RetroFE/Source/Graphics/Component/Component.h b/RetroFE/Source/Graphics/Component/Component.h index 24da67e..25555b0 100644 --- a/RetroFE/Source/Graphics/Component/Component.h +++ b/RetroFE/Source/Graphics/Component/Component.h @@ -1,5 +1,17 @@ -/* This file is subject to the terms and conditions defined in - * file 'LICENSE.txt', which is part of this source code package. +/* 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 @@ -9,6 +21,7 @@ #include "../MenuNotifierInterface.h" #include "../ViewInfo.h" #include "../Animate/Tween.h" +#include "../Animate/TweenSet.h" #include "../../Collection/Item.h" class Component @@ -22,36 +35,29 @@ public: virtual void LaunchExit() {} void TriggerEnterEvent(); void TriggerExitEvent(); + void TriggerMenuEnterEvent(); + void TriggerMenuExitEvent(); + void TriggerMenuScrollEvent(); void TriggerHighlightEvent(Item *selectedItem); bool IsIdle(); bool IsHidden(); bool IsWaiting(); + bool IsMenuScrolling(); + std::string GetCollectionName(); + void SetCollectionName(std::string collectionName); typedef std::vector *> TweenSets; - void SetOnEnterTweens(TweenSets *tweens) + TweenSet *GetTweens() { return Tweens; } + + void SetTweens(TweenSet *set) { - this->OnEnterTweens = tweens; + Tweens = set; + CurrentAnimationState = IDLE; + CurrentTweenIndex = 0; + CurrentTweenComplete = false; + ElapsedTweenTime = 0; } - void SetOnExitTweens(TweenSets *tweens) - { - this->OnExitTweens = tweens; - } - - void SetOnIdleTweens(TweenSets *tweens) - { - this->OnIdleTweens = tweens; - } - - void SetOnHighlightEnterTweens(TweenSets *tweens) - { - this->OnHighlightEnterTweens = tweens; - } - - void SetOnHighlightExitTweens(TweenSets *tweens) - { - this->OnHighlightExitTweens = tweens; - } virtual void Update(float dt); virtual void Draw(); @@ -78,6 +84,7 @@ public: protected: + std::string CollectionName; Item *GetSelectedItem() { return SelectedItem; @@ -90,12 +97,18 @@ protected: HIGHLIGHT_WAIT, HIGHLIGHT_ENTER, EXIT, + MENU_ENTER, + MENU_SCROLL, + MENU_EXIT, HIDDEN }; AnimationState CurrentAnimationState; bool EnterRequested; bool ExitRequested; + bool MenuEnterRequested; + bool MenuScrollRequested; + bool MenuExitRequested; bool NewItemSelected; bool HighlightExitComplete; bool NewItemSelectedSinceEnter; @@ -103,13 +116,7 @@ private: bool Animate(bool loop); bool IsTweenSequencingComplete(); void ResetTweenSequence(std::vector *tweens); - - TweenSets *OnEnterTweens; - TweenSets *OnExitTweens; - TweenSets *OnIdleTweens; - TweenSets *OnHighlightEnterTweens; - TweenSets *OnHighlightExitTweens; - + TweenSet *Tweens; TweenSets *CurrentTweens; unsigned int CurrentTweenIndex; diff --git a/RetroFE/Source/Graphics/Component/ReloadableMedia.cpp b/RetroFE/Source/Graphics/Component/ReloadableMedia.cpp index f2f63d8..b1bc67d 100644 --- a/RetroFE/Source/Graphics/Component/ReloadableMedia.cpp +++ b/RetroFE/Source/Graphics/Component/ReloadableMedia.cpp @@ -27,12 +27,12 @@ #include #include -ReloadableMedia::ReloadableMedia(std::string imagePath, std::string videoPath, bool isVideo, float scaleX, float scaleY) - : LoadedComponent(NULL) - , ImagePath(imagePath) - , VideoPath(videoPath) +ReloadableMedia::ReloadableMedia(Configuration &config, std::string type, bool isVideo, float scaleX, float scaleY) + : Config(config) + , LoadedComponent(NULL) , ReloadRequested(false) , FirstLoad(true) + , Type(type) , IsVideo(isVideo) , ScaleX(scaleX) , ScaleY(scaleY) @@ -134,19 +134,14 @@ void ReloadableMedia::ReloadTexture() { names.push_back(selectedItem->GetCloneOf()); } + std::string videoPath; + Config.GetMediaPropertyAbsolutePath(GetCollectionName(), "video", videoPath); for(unsigned int n = 0; n < names.size() && !found; ++n) { - std::string filePrefix; - filePrefix.append(VideoPath); - filePrefix.append("/"); - filePrefix.append(names[n]); - - std::string file; - VideoBuilder videoBuild; - LoadedComponent = videoBuild.CreateVideo(VideoPath, names[n], ScaleX, ScaleY); + LoadedComponent = videoBuild.CreateVideo(videoPath, names[n], ScaleX, ScaleY); if(LoadedComponent) { @@ -158,8 +153,10 @@ void ReloadableMedia::ReloadTexture() if(!LoadedComponent) { + std::string imagePath; + Config.GetMediaPropertyAbsolutePath(GetCollectionName(), Type, imagePath); ImageBuilder imageBuild; - LoadedComponent = imageBuild.CreateImage(ImagePath, selectedItem->GetFullTitle(), ScaleX, ScaleY); + LoadedComponent = imageBuild.CreateImage(imagePath, selectedItem->GetFullTitle(), ScaleX, ScaleY); if (LoadedComponent != NULL) { diff --git a/RetroFE/Source/Graphics/Component/ReloadableMedia.h b/RetroFE/Source/Graphics/Component/ReloadableMedia.h index 43d0d37..dca738d 100644 --- a/RetroFE/Source/Graphics/Component/ReloadableMedia.h +++ b/RetroFE/Source/Graphics/Component/ReloadableMedia.h @@ -14,7 +14,7 @@ class Image; class ReloadableMedia : public Component { public: - ReloadableMedia(std::string imagePath, std::string videoPath, bool isVideo, float scaleX, float scaleY); + ReloadableMedia(Configuration &config, std::string type, bool isVideo, float scaleX, float scaleY); virtual ~ReloadableMedia(); void Update(float dt); void Draw(); @@ -25,14 +25,14 @@ public: private: void ReloadTexture(); + Configuration &Config; Component *LoadedComponent; - std::string ImagePath; - std::string VideoPath; bool ReloadRequested; bool FirstLoad; IVideo *VideoInst; bool IsVideo; + std::string Type; float ScaleX; float ScaleY; }; diff --git a/RetroFE/Source/Graphics/Component/ReloadableText.cpp b/RetroFE/Source/Graphics/Component/ReloadableText.cpp index 8a2f5ad..91c368e 100644 --- a/RetroFE/Source/Graphics/Component/ReloadableText.cpp +++ b/RetroFE/Source/Graphics/Component/ReloadableText.cpp @@ -23,10 +23,9 @@ #include #include -ReloadableText::ReloadableText(std::string type, Font *font, SDL_Color color, std::string layoutKey, std::string collection, float scaleX, float scaleY) +ReloadableText::ReloadableText(std::string type, Font *font, SDL_Color color, std::string layoutKey, float scaleX, float scaleY) : ImageInst(NULL) , LayoutKey(layoutKey) - , Collection(collection) , ReloadRequested(false) , FirstLoad(true) , FontInst(font) diff --git a/RetroFE/Source/Graphics/Component/ReloadableText.h b/RetroFE/Source/Graphics/Component/ReloadableText.h index 71e26c4..91f3d61 100644 --- a/RetroFE/Source/Graphics/Component/ReloadableText.h +++ b/RetroFE/Source/Graphics/Component/ReloadableText.h @@ -12,7 +12,7 @@ class ReloadableText : public Component { public: - ReloadableText(std::string type, Font *font, SDL_Color color, std::string layoutKey, std::string collectionName, float scaleX, float scaleY); + ReloadableText(std::string type, Font *font, SDL_Color color, std::string layoutKey, float scaleX, float scaleY); virtual ~ReloadableText(); void Update(float dt); void Draw(); @@ -37,7 +37,6 @@ private: Text *ImageInst; TextType Type; std::string LayoutKey; - std::string Collection; bool ReloadRequested; bool FirstLoad; Font *FontInst; diff --git a/RetroFE/Source/Graphics/Component/ScrollingList.cpp b/RetroFE/Source/Graphics/Component/ScrollingList.cpp index 10fc525..154e888 100644 --- a/RetroFE/Source/Graphics/Component/ScrollingList.cpp +++ b/RetroFE/Source/Graphics/Component/ScrollingList.cpp @@ -41,37 +41,98 @@ ScrollingList::ScrollingList(Configuration &c, Font *font, SDL_Color fontColor, std::string layoutKey, - std::string collectionName, std::string imageType) - : IsScrollChangedStarted(true) - , IsScrollChangedSignalled(false) - , IsScrollChangedComplete(false) - , SpriteList(NULL) + : SpriteList(NULL) , ScrollPoints(NULL) , TweenEnterTime(0) , FirstSpriteIndex(0) , SelectedSpriteListIndex(0) - , CurrentAnimateTime(0) // in seconds - , ScrollTime(0) // in seconds + , ScrollStopRequested(true) , CurrentScrollDirection(ScrollDirectionIdle) , RequestedScrollDirection(ScrollDirectionIdle) , CurrentScrollState(ScrollStateIdle) , ScrollAcceleration(6) // todo: make configurable - , ScrollVelocity(0) + , ScrollPeriod(0) , Config(c) , ScaleX(scaleX) , ScaleY(scaleY) , FontInst(font) , FontColor(fontColor) , LayoutKey(layoutKey) - , CollectionName(collectionName) , ImageType(imageType) , MaxLayer(0) + , Focus(false) { } ScrollingList::~ScrollingList() { + DestroyItems(); +} + +void ScrollingList::SetItems(std::vector *spriteList) +{ + 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)->GetCollectionItem(); + + *newItem = *originalItem; + ComponentItemBinding *newSprite = new ComponentItemBinding(newItem); + SpriteList->push_back(newSprite); + } + } + + for(unsigned int i = 0; ScrollPoints && i < SelectedSpriteListIndex; ++i) + { + CircularDecrement(FirstSpriteIndex, SpriteList); + } + + AllocateSpritePoints(); +} + +void ScrollingList::DeallocateSpritePoints() +{ + unsigned int spriteIndex = FirstSpriteIndex; + + for(unsigned int i = 0; i < ScrollPoints->size(); ++i) + { + DeallocateTexture(SpriteList->at(spriteIndex)); + CircularIncrement(spriteIndex, SpriteList); + } +} + +void ScrollingList::AllocateSpritePoints() +{ + unsigned int spriteIndex = FirstSpriteIndex; + + for(unsigned int i = 0; i < ScrollPoints->size(); ++i) + { + + AllocateTexture(SpriteList->at(spriteIndex)); + Component *c = SpriteList->at(spriteIndex)->GetComponent(); + ViewInfo *currentViewInfo = ScrollPoints->at(i); + unsigned int nextI = GetNextTween(i, ScrollPoints); + ViewInfo *nextViewInfo = ScrollPoints->at(nextI); + + ResetTweens(c, TweenPoints->at(i), currentViewInfo, nextViewInfo, 0); + + CircularIncrement(spriteIndex, SpriteList); + } +} + +void ScrollingList::DestroyItems() +{ if(SpriteList) { std::vector::iterator it = SpriteList->begin(); @@ -81,6 +142,7 @@ ScrollingList::~ScrollingList() if(*it != NULL) { DeallocateTexture(*it); + if((*it)->GetCollectionItem()) { delete (*it)->GetCollectionItem(); @@ -89,6 +151,7 @@ ScrollingList::~ScrollingList() delete *it; } + SpriteList->erase(it); it = SpriteList->begin(); @@ -97,43 +160,14 @@ ScrollingList::~ScrollingList() delete SpriteList; SpriteList = NULL; } -} +} -void ScrollingList::SetItems(std::vector *spriteList) -{ - SpriteList = spriteList; - FirstSpriteIndex = 0; - // loop the scroll points if there are not enough - - if(SpriteList) - { - unsigned int originalSize = SpriteList->size(); - - while(ScrollPoints && ScrollPoints->size()+4 > SpriteList->size() && SpriteList->size() > 0) - { - for(unsigned int i = 0; i < originalSize; ++i) - { - Item *newItem = new Item(); - Item *originalItem = SpriteList->at(i)->GetCollectionItem(); - - *newItem = *originalItem; - ComponentItemBinding *newSprite = new ComponentItemBinding(newItem); - SpriteList->push_back(newSprite); - } - } - for(unsigned int i = 0; ScrollPoints && i < SelectedSpriteListIndex; ++i) - { - CircularDecrement(FirstSpriteIndex, SpriteList); - } - - IsScrollChangedComplete = true; - } -} - -void ScrollingList::SetPoints(std::vector *scrollPoints) +void ScrollingList::SetPoints(std::vector *scrollPoints, std::vector *tweenPoints) { ScrollPoints = scrollPoints; + TweenPoints = tweenPoints; + for(unsigned int i = 0; i != scrollPoints->size(); ++i) { ViewInfo *info = scrollPoints->at(i); @@ -150,21 +184,47 @@ void ScrollingList::SetSelectedIndex(int selectedIndex) { CircularDecrement(FirstSpriteIndex, SpriteList); } - } -void ScrollingList::Click() +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); - IsScrollChangedComplete = true; + allocSpriteIndex = FirstSpriteIndex; + allocPoint = 0; } - if(CurrentScrollDirection == ScrollDirectionForward) + else if(CurrentScrollDirection == ScrollDirectionForward) { + deallocSpriteIndex = FirstSpriteIndex; CircularIncrement(FirstSpriteIndex, SpriteList); - IsScrollChangedComplete = true; + allocSpriteIndex = CircularIncrement(FirstSpriteIndex, listSize - 1, SpriteList); + allocPoint = listSize - 1; } + else + { + return; + } + + DeallocateTexture(SpriteList->at(deallocSpriteIndex)); + AllocateTexture(SpriteList->at(allocSpriteIndex)); + + Component *c = SpriteList->at(allocSpriteIndex)->GetComponent(); + 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) @@ -183,10 +243,12 @@ unsigned int ScrollingList::GetNextTween(unsigned int currentIndex, std::vector< void ScrollingList::PageUp() { - if(ScrollPoints && ScrollPoints->size() > 4) + DeallocateSpritePoints(); + + if(SpriteList && ScrollPoints && ScrollPoints->size() > 2) { - ScrollVelocity = 0; - unsigned int counts = ScrollPoints->size() - 4; + ScrollPeriod = 0; + unsigned int counts = ScrollPoints->size() - 2; for(unsigned int i = 0; i < counts; i++) { @@ -194,44 +256,42 @@ void ScrollingList::PageUp() } } - CurrentScrollState = ScrollStatePageChange; - IsScrollChangedStarted = true; - IsScrollChangedSignalled = false; - IsScrollChangedComplete = false; + AllocateSpritePoints(); + +// CurrentScrollState = ScrollStatePageChange; } void ScrollingList::PageDown() { - if(ScrollPoints && ScrollPoints->size() > 4) - { - unsigned int counts = ScrollPoints->size() - 4; + DeallocateSpritePoints(); - ScrollVelocity = 0; + 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); } } - CurrentScrollState = ScrollStatePageChange; - IsScrollChangedStarted = true; - IsScrollChangedSignalled = false; - IsScrollChangedComplete = false; + AllocateSpritePoints(); +//todo: may want to handle this properly +// CurrentScrollState = ScrollStatePageChange; } void ScrollingList::FreeGraphicsMemory() { Component::FreeGraphicsMemory(); TweenEnterTime = 0; - CurrentAnimateTime = 0; - ScrollTime = 0; CurrentScrollDirection = ScrollDirectionIdle; RequestedScrollDirection = ScrollDirectionIdle; CurrentScrollState = ScrollStateIdle; ScrollAcceleration = 6; // todo: make configurable - ScrollVelocity = 0; + ScrollPeriod = 0; - for(unsigned int i = 0; i < SpriteList->size(); i++) + for(unsigned int i = 0; SpriteList && i < SpriteList->size(); i++) { ComponentItemBinding *s = SpriteList->at(i); @@ -239,156 +299,151 @@ void ScrollingList::FreeGraphicsMemory() } } +void ScrollingList::TriggerMenuEnterEvent() +{ + Focus = true; + + if(!ScrollPoints) { 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->GetComponent(); + if(c) + { + c->TriggerMenuEnterEvent(); + } + + CircularIncrement(spriteIndex, SpriteList); + } +} + +void ScrollingList::TriggerMenuExitEvent() +{ + Focus = false; + if(!ScrollPoints) { 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->GetComponent(); + if(c) + { + c->TriggerMenuExitEvent(); + } + + CircularIncrement(spriteIndex, SpriteList); + } +} void ScrollingList::Update(float dt) { float scrollPeriod = 0; + bool initializePoints = false; Component::Update(dt); - if(!ScrollPoints) + 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++) { - return; + ComponentItemBinding *s = SpriteList->at(i); + Component *c = s->GetComponent(); + + if(c && c->IsMenuScrolling()) + { + readyToScroll = false; + break; + } } - switch(CurrentScrollState) + // check if it was requested to change directions + if(CurrentScrollState == ScrollStateActive && RequestedScrollDirection != CurrentScrollDirection) { - case ScrollStateActive: - if(RequestedScrollDirection != CurrentScrollDirection) - { - CurrentScrollState = ScrollStateStopping; - - } - - break; - - case ScrollStateIdle: - ScrollTime = 0; - CurrentAnimateTime = 0; - ScrollVelocity = 0; - + CurrentScrollState = ScrollStateStopping; + } + else if(CurrentScrollState == ScrollStateIdle && readyToScroll) + { + ScrollPeriod = 0.500; + // check to see if requested to scroll if(RequestedScrollDirection != ScrollDirectionIdle) { + initializePoints = true; CurrentScrollState = ScrollStateActive; CurrentScrollDirection = RequestedScrollDirection; + scrollRequested = true; } - break; - default: - break; + } - }; - - if(CurrentScrollState != ScrollStatePageChange && CurrentScrollState != ScrollStateIdle) + // if currently scrolling, process it + if(!scrollRequested && readyToScroll) { - IsScrollChangedStarted = true; - ScrollTime += dt; - CurrentAnimateTime += dt; - ScrollVelocity = ScrollTime * ScrollAcceleration; - - // clip at 5 items scrolled per second - if(ScrollVelocity > 30) + if(CurrentScrollState == ScrollStateStopping) { - ScrollVelocity = 30; - } - if(ScrollVelocity > 0) - { - scrollPeriod = 1 / ScrollVelocity; - } - - // have we exceeded the time of when to stop on the next item in the list? - if(CurrentScrollState == ScrollStateStopping && CurrentAnimateTime >= scrollPeriod) - { - Click(); - CurrentAnimateTime = 0; - ScrollVelocity = 0; + Click(0); CurrentScrollState = ScrollStateIdle; - } - } + scrollStopped = true; + + // update the tweens now that we are done + unsigned int spriteIndex = FirstSpriteIndex; - while(CurrentScrollState != ScrollStatePageChange && ScrollVelocity > 0 && CurrentAnimateTime >= scrollPeriod) - { - Click(); - CurrentAnimateTime -= scrollPeriod; - } - - - if(ScrollPoints && SpriteList->size() > 0 && FirstSpriteIndex < SpriteList->size()) - { - unsigned int spriteIndex = FirstSpriteIndex; - unsigned int numIterations = (ScrollPoints->size() > SpriteList->size()) ? SpriteList->size() : ScrollPoints->size(); - unsigned int start = (ScrollPoints->size() > SpriteList->size()) ? SelectedSpriteListIndex : 0; - - for(unsigned int i = start; i < start+numIterations && spriteIndex < SpriteList->size(); i++) - { - ComponentItemBinding *s = SpriteList->at(spriteIndex); - unsigned int nextI = GetNextTween(i, ScrollPoints); - - ViewInfo *currentViewInfo = ScrollPoints->at(i); - ViewInfo *nextViewInfo = ScrollPoints->at(nextI); - - AllocateTexture(s); - - Component *c = s->GetComponent(); - if(c) + for(unsigned int i = 0; i < TweenPoints->size(); ++i) { - currentViewInfo->SetImageHeight(c->GetBaseViewInfo()->GetImageHeight()); - currentViewInfo->SetImageWidth(c->GetBaseViewInfo()->GetImageWidth()); - nextViewInfo->SetImageHeight(c->GetBaseViewInfo()->GetImageHeight()); - nextViewInfo->SetImageWidth(c->GetBaseViewInfo()->GetImageWidth()); - nextViewInfo->SetBackgroundAlpha(c->GetBaseViewInfo()->GetBackgroundAlpha()); + ComponentItemBinding *s = SpriteList->at(spriteIndex); - //todo: 30 is a magic number - ViewInfo *spriteViewInfo = c->GetBaseViewInfo(); + Component *c = s->GetComponent(); + if(c) + { + c->SetTweens(TweenPoints->at(i)); + } - spriteViewInfo->SetX(Tween::AnimateSingle(LINEAR, currentViewInfo->GetX(), nextViewInfo->GetX(), scrollPeriod, CurrentAnimateTime)); - spriteViewInfo->SetY(Tween::AnimateSingle(LINEAR, currentViewInfo->GetY(), nextViewInfo->GetY(), scrollPeriod, CurrentAnimateTime)); - spriteViewInfo->SetXOrigin(Tween::AnimateSingle(LINEAR, currentViewInfo->GetXOrigin(), nextViewInfo->GetXOrigin(), scrollPeriod, CurrentAnimateTime)); - spriteViewInfo->SetYOrigin(Tween::AnimateSingle(LINEAR, currentViewInfo->GetYOrigin(), nextViewInfo->GetYOrigin(), scrollPeriod, CurrentAnimateTime)); - spriteViewInfo->SetXOffset(Tween::AnimateSingle(LINEAR, currentViewInfo->GetXOffset(), nextViewInfo->GetXOffset(), scrollPeriod, CurrentAnimateTime)); - spriteViewInfo->SetYOffset(Tween::AnimateSingle(LINEAR, currentViewInfo->GetYOffset(), nextViewInfo->GetYOffset(), scrollPeriod, CurrentAnimateTime)); - spriteViewInfo->SetHeight(Tween::AnimateSingle(LINEAR, currentViewInfo->GetHeight(), nextViewInfo->GetHeight(), scrollPeriod, CurrentAnimateTime)); - spriteViewInfo->SetWidth(Tween::AnimateSingle(LINEAR, currentViewInfo->GetWidth(), nextViewInfo->GetWidth(), scrollPeriod, CurrentAnimateTime)); - spriteViewInfo->SetAlpha(Tween::AnimateSingle(LINEAR, currentViewInfo->GetAlpha(), nextViewInfo->GetAlpha(), scrollPeriod, CurrentAnimateTime)); - spriteViewInfo->SetAngle(Tween::AnimateSingle(LINEAR, currentViewInfo->GetAngle(), nextViewInfo->GetAngle(), scrollPeriod, CurrentAnimateTime)); - spriteViewInfo->SetFontSize(Tween::AnimateSingle(LINEAR, currentViewInfo->GetFontSize(), nextViewInfo->GetFontSize(), scrollPeriod, CurrentAnimateTime)); - spriteViewInfo->SetBackgroundAlpha(Tween::AnimateSingle(LINEAR, currentViewInfo->GetBackgroundAlpha(), nextViewInfo->GetBackgroundAlpha(), scrollPeriod, CurrentAnimateTime)); - c->Update(dt); - - } - - CircularIncrement(spriteIndex, SpriteList); - } - - // start freeing up memory if the list is too large - if(SpriteList->size() + 4 > ScrollPoints->size()) - { - spriteIndex = FirstSpriteIndex; - - CircularDecrement(spriteIndex, SpriteList); - DeallocateTexture(SpriteList->at(spriteIndex)); - - CircularDecrement(spriteIndex, SpriteList); - DeallocateTexture(SpriteList->at(spriteIndex)); - - - // point to the end of the list to start deallocating.. - // It's not fast, but it's easy to read - spriteIndex = FirstSpriteIndex; - for(unsigned int i = 0; i < ScrollPoints->size(); i++) - { CircularIncrement(spriteIndex, SpriteList); } - CircularIncrement(spriteIndex, SpriteList); - DeallocateTexture(SpriteList->at(spriteIndex)); + } - CircularIncrement(spriteIndex, SpriteList); - DeallocateTexture(SpriteList->at(spriteIndex)); + else if(CurrentScrollState == ScrollStateActive) + { + ScrollPeriod -= 0.050f; + if(ScrollPeriod < 0.050) + { + ScrollPeriod = 0.050f; + } + + Click(ScrollPeriod); + scrollChanged = true; } } - if(IsScrollChangedStarted && !IsScrollChangedSignalled) + + unsigned int spriteIndex = FirstSpriteIndex; + for(unsigned int i = 0; i < ScrollPoints->size(); i++) + { + UpdateSprite(spriteIndex, i, (scrollRequested || scrollChanged), dt, ScrollPeriod); + CircularIncrement(spriteIndex, SpriteList); + } + + if(scrollStopped || scrollChanged) { - IsScrollChangedSignalled = true; ComponentItemBinding *sprite = GetPendingCollectionItemSprite(); Item *item = NULL; @@ -410,65 +465,122 @@ void ScrollingList::Update(float dt) if(CurrentScrollState == ScrollStatePageChange) { - IsScrollChangedComplete = true; CurrentScrollState = ScrollStateIdle; } } - - if(IsScrollChangedStarted && IsScrollChangedSignalled && IsScrollChangedComplete) - { - IsScrollChangedStarted = false; - IsScrollChangedComplete = false; - IsScrollChangedSignalled = false; - } - } -void ScrollingList::AllocateTexture(ComponentItemBinding *s) +void ScrollingList::UpdateSprite(unsigned int spriteIndex, unsigned int pointIndex, bool newScroll, float dt, double nextScrollTime) { - //todo: move this outside of the Draw routine - if(s && s->GetComponent() == NULL) + ComponentItemBinding *s = SpriteList->at(spriteIndex); + + Component *c = s->GetComponent(); + //todo: remove me + if(c && newScroll) { - const Item *item = s->GetCollectionItem(); - //todo: will create a runtime fault if not of the right type - //todo: remove coupling from knowing the collection name + ViewInfo *currentViewInfo = ScrollPoints->at(pointIndex); + unsigned int nextI = GetNextTween(pointIndex, ScrollPoints); + ViewInfo *nextViewInfo = ScrollPoints->at(nextI); - std::string videoKey ="collections." + CollectionName + ".media.video"; - std::string imagePath; - std::string videoPath; - - Component *t = NULL; - - /* - // todo: to be supported at a later date - if(c->GetProperty(videoKey, videoPath)) - { - t = new VideoComponent(videoPath, item->GetFullTitle(), ScaleX, ScaleY); - } - */ - if(!t) - { - - ImageBuilder imageBuild; - Config.GetMediaPropertyAbsolutePath(CollectionName, ImageType, imagePath); - t = imageBuild.CreateImage(imagePath, item->GetName(), ScaleX, ScaleY); - - if(!t && item->GetTitle() != item->GetFullTitle()) - { - t = imageBuild.CreateImage(imagePath, item->GetFullTitle(), ScaleX, ScaleY); - } - } - if (!t) - { - t = new Text(item->GetTitle(), FontInst, FontColor, ScaleX, ScaleY); - } - - if(t) - { - s->SetComponent(t); - } + ResetTweens(c, TweenPoints->at(pointIndex), currentViewInfo, nextViewInfo, nextScrollTime); + c->TriggerMenuScrollEvent(); + } + if(c) + { + c->Update(dt); } + CircularIncrement(spriteIndex, SpriteList); +} + +void ScrollingList::ResetTweens(Component *c, TweenSet *sets, ViewInfo *currentViewInfo, ViewInfo *nextViewInfo, double scrollTime) +{ + if(!c) { return; } + if(!sets) { return; } + if(!currentViewInfo) { return; } + if(!nextViewInfo) { return; } + + currentViewInfo->SetImageHeight(c->GetBaseViewInfo()->GetImageHeight()); + currentViewInfo->SetImageWidth(c->GetBaseViewInfo()->GetImageWidth()); + nextViewInfo->SetImageHeight(c->GetBaseViewInfo()->GetImageHeight()); + nextViewInfo->SetImageWidth(c->GetBaseViewInfo()->GetImageWidth()); + nextViewInfo->SetBackgroundAlpha(c->GetBaseViewInfo()->GetBackgroundAlpha()); + + //todo: delete properly, memory leak (big), proof of concept + c->SetTweens(sets); + + TweenSets *scrollTween = sets->GetOnMenuScrollTweens(); + TweenSets::iterator it = scrollTween->begin(); + + while(it != scrollTween->end()) + { + std::vector::iterator it2 = (*it)->begin(); + while(it2 != (*it)->end()) + { + delete *it2; + (*it)->erase(it2); + it2 = (*it)->begin(); + } + delete *it; + scrollTween->erase(it); + it = scrollTween->begin(); + + } + + scrollTween->clear(); + c->UpdateBaseViewInfo(*currentViewInfo); + + std::vector *set = new std::vector(); + set->push_back(new Tween(TWEEN_PROPERTY_HEIGHT, LINEAR, currentViewInfo->GetHeight(), nextViewInfo->GetHeight(), scrollTime)); + set->push_back(new Tween(TWEEN_PROPERTY_WIDTH, LINEAR, currentViewInfo->GetWidth(), nextViewInfo->GetWidth(), scrollTime)); + set->push_back(new Tween(TWEEN_PROPERTY_ANGLE, LINEAR, currentViewInfo->GetAngle(), nextViewInfo->GetAngle(), scrollTime)); + set->push_back(new Tween(TWEEN_PROPERTY_ALPHA, LINEAR, currentViewInfo->GetAlpha(), nextViewInfo->GetAlpha(), scrollTime)); + set->push_back(new Tween(TWEEN_PROPERTY_X, LINEAR, currentViewInfo->GetX(), nextViewInfo->GetX(), scrollTime)); + set->push_back(new Tween(TWEEN_PROPERTY_Y, LINEAR, currentViewInfo->GetY(), nextViewInfo->GetY(), scrollTime)); + set->push_back(new Tween(TWEEN_PROPERTY_X_ORIGIN, LINEAR, currentViewInfo->GetXOrigin(), nextViewInfo->GetXOrigin(), scrollTime)); + set->push_back(new Tween(TWEEN_PROPERTY_Y_ORIGIN, LINEAR, currentViewInfo->GetYOrigin(), nextViewInfo->GetYOrigin(), scrollTime)); + set->push_back(new Tween(TWEEN_PROPERTY_X_OFFSET, LINEAR, currentViewInfo->GetXOffset(), nextViewInfo->GetXOffset(), scrollTime)); + set->push_back(new Tween(TWEEN_PROPERTY_Y_OFFSET, LINEAR, currentViewInfo->GetYOffset(), nextViewInfo->GetYOffset(), scrollTime)); + set->push_back(new Tween(TWEEN_PROPERTY_FONT_SIZE, LINEAR, currentViewInfo->GetFontSize(), nextViewInfo->GetFontSize(), scrollTime)); + set->push_back(new Tween(TWEEN_PROPERTY_BACKGROUND_ALPHA, LINEAR, currentViewInfo->GetBackgroundAlpha(), nextViewInfo->GetBackgroundAlpha(), scrollTime)); + scrollTween->push_back(set); +} + + +bool ScrollingList::AllocateTexture(ComponentItemBinding *s) +{ + + if(!s || s->GetComponent() != NULL) { return false; } + + const Item *item = s->GetCollectionItem(); + //todo: will create a runtime fault if not of the right type + //todo: remove coupling from knowing the collection name + + std::string videoKey ="collections." + GetCollectionName() + ".media.video"; + std::string imagePath; + std::string videoPath; + + Component *t = NULL; + + ImageBuilder imageBuild; + Config.GetMediaPropertyAbsolutePath(GetCollectionName(), ImageType, imagePath); + t = imageBuild.CreateImage(imagePath, item->GetName(), ScaleX, ScaleY); + + if(!t && item->GetTitle() != item->GetFullTitle()) + { + t = imageBuild.CreateImage(imagePath, item->GetFullTitle(), ScaleX, ScaleY); + } + if (!t) + { + t = new Text(item->GetTitle(), FontInst, FontColor, ScaleX, ScaleY); + } + + if(t) + { + s->SetComponent(t); + } + + return true; } void ScrollingList::DeallocateTexture(ComponentItemBinding *s) @@ -476,6 +588,7 @@ void ScrollingList::DeallocateTexture(ComponentItemBinding *s) if(s && s->GetComponent() != NULL) { delete s->GetComponent(); + //todo: memory leak here, need to destroy allocated tween points here and in page (cannot be destroyed by component) } s->SetComponent(NULL); } @@ -486,25 +599,25 @@ void ScrollingList::Draw() // caller should instead call ScrollingList::Draw(unsigned int layer) } -//todo: this is kind of a hack. Aggregation needs to happen differently void ScrollingList::Draw(unsigned int layer) { - if(ScrollPoints && SpriteList && SpriteList->size() > 0 && FirstSpriteIndex < SpriteList->size()) + if(!ScrollPoints) { return; } + if(!SpriteList) { return; } + if(SpriteList->size() == 0) { return; } + + unsigned int spriteIndex = FirstSpriteIndex; + + for(unsigned int i = 0; i < ScrollPoints->size(); i++) { - unsigned int spriteIndex = FirstSpriteIndex; + ComponentItemBinding *s = SpriteList->at(spriteIndex); + Component *c = s->GetComponent(); + ViewInfo *currentViewInfo = ScrollPoints->at(i); - for(unsigned int i = 0; i < ScrollPoints->size(); i++) + if(c && currentViewInfo && currentViewInfo->GetLayer() == layer) { - std::vector::iterator it = SpriteList->begin() + spriteIndex; - Component *c = (*it)->GetComponent(); - ViewInfo *currentViewInfo = ScrollPoints->at(i); - - if(currentViewInfo && currentViewInfo->GetLayer() == layer) - { - c->Draw(); - } - CircularIncrement(spriteIndex, SpriteList); + c->Draw(); } + CircularIncrement(spriteIndex, SpriteList); } } @@ -512,12 +625,14 @@ void ScrollingList::Draw(unsigned int layer) void ScrollingList::SetScrollDirection(ScrollDirection direction) { RequestedScrollDirection = direction; + + ScrollStopRequested = (direction == ScrollDirection::ScrollDirectionIdle); } void ScrollingList::RemoveSelectedItem() { ComponentItemBinding *sprite = GetSelectedCollectionItemSprite(); - if(sprite) + if(sprite && SpriteList) { Item *item = sprite->GetCollectionItem(); DeallocateTexture(sprite); @@ -542,7 +657,6 @@ void ScrollingList::RemoveSelectedItem() FirstSpriteIndex = 0; } } - IsScrollChangedComplete = true; } @@ -569,17 +683,6 @@ ComponentItemBinding* ScrollingList::GetPendingCollectionItemSprite() { ComponentItemBinding *item = NULL; unsigned int index = FirstSpriteIndex; - if(CurrentScrollState != ScrollStatePageChange) - { - if(CurrentScrollDirection == ScrollDirectionBack) - { - CircularDecrement(index, SpriteList); - } - if(CurrentScrollDirection == ScrollDirectionForward) - { - CircularIncrement(index, SpriteList); - } - } if(SpriteList && SpriteList->size() > 0) { index = (index + SelectedSpriteListIndex) % SpriteList->size(); @@ -613,22 +716,25 @@ ComponentItemBinding* ScrollingList::GetPendingSelectedCollectionItemSprite() { ComponentItemBinding *item = NULL; - unsigned int index = SelectedSpriteListIndex; - - if(CurrentScrollDirection == ScrollDirectionBack) + if(SpriteList) { - CircularDecrement(index, SpriteList); - } - if(CurrentScrollDirection == ScrollDirectionForward) - { - CircularIncrement(index, SpriteList); - } + unsigned int index = SelectedSpriteListIndex; - if(SpriteList && SpriteList->size() > 0) - { - index = (index + SelectedSpriteListIndex) % SpriteList->size(); + if(CurrentScrollDirection == ScrollDirectionBack) + { + CircularDecrement(index, SpriteList); + } + if(CurrentScrollDirection == ScrollDirectionForward) + { + CircularIncrement(index, SpriteList); + } - item = SpriteList->at(index); + if(SpriteList && SpriteList->size() > 0) + { + index = (index + SelectedSpriteListIndex) % SpriteList->size(); + + item = SpriteList->at(index); + } } return item; @@ -668,6 +774,18 @@ void ScrollingList::CircularDecrement(unsigned int &index, std::vector *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 *list) { @@ -678,6 +796,7 @@ void ScrollingList::CircularIncrement(unsigned int &index, std::vector *list) { if(index > 0) diff --git a/RetroFE/Source/Graphics/Component/ScrollingList.h b/RetroFE/Source/Graphics/Component/ScrollingList.h index c293b75..5ee1969 100644 --- a/RetroFE/Source/Graphics/Component/ScrollingList.h +++ b/RetroFE/Source/Graphics/Component/ScrollingList.h @@ -31,12 +31,22 @@ public: }; - ScrollingList(Configuration &c, float scaleX, float scaleY, Font *font, SDL_Color fontColor, std::string layoutKey, std::string CollectionName, std::string imageType); + ScrollingList(Configuration &c, + float scaleX, + float scaleY, + Font *font, + SDL_Color fontColor, + std::string layoutKey, + std::string imageType); virtual ~ScrollingList(); - void AllocateTexture(ComponentItemBinding *s); + void TriggerMenuEnterEvent(); + void TriggerMenuExitEvent(); + + bool AllocateTexture(ComponentItemBinding *s); void DeallocateTexture(ComponentItemBinding *s); void SetItems(std::vector *spriteList); - void SetPoints(std::vector *scrollPoints); + void DestroyItems(); + void SetPoints(std::vector *scrollPoints, std::vector *tweenPoints); void SetScrollDirection(ScrollDirection direction); void PageUp(); void PageDown(); @@ -55,11 +65,12 @@ public: void Draw(unsigned int layer); private: - void Click(); + 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); - bool IsScrollChangedStarted; - bool IsScrollChangedSignalled; - bool IsScrollChangedComplete; + void ResetTweens(Component *c, TweenSet *sets, ViewInfo *currentViewInfo, ViewInfo *nextViewInfo, double scrollTime); enum ScrollState { @@ -71,20 +82,22 @@ private: std::vector *SpriteList; std::vector *ScrollPoints; + std::vector *TweenPoints; std::vector NotificationComponents; float TweenEnterTime; + bool Focus; unsigned int FirstSpriteIndex; unsigned int SelectedSpriteListIndex; - float CurrentAnimateTime; - float ScrollTime; + bool ScrollStopRequested; ScrollDirection CurrentScrollDirection; ScrollDirection RequestedScrollDirection; ScrollState CurrentScrollState; float ScrollAcceleration; - float ScrollVelocity; + 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); @@ -98,7 +111,6 @@ private: Font *FontInst; SDL_Color FontColor; std::string LayoutKey; - std::string CollectionName; std::string ImageType; unsigned int MaxLayer; }; diff --git a/RetroFE/Source/Graphics/ComponentItemBinding.h b/RetroFE/Source/Graphics/ComponentItemBinding.h index 50b3221..40f42eb 100644 --- a/RetroFE/Source/Graphics/ComponentItemBinding.h +++ b/RetroFE/Source/Graphics/ComponentItemBinding.h @@ -1,5 +1,17 @@ -/* This file is subject to the terms and conditions defined in - * file 'LICENSE.txt', which is part of this source code package. +/* 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 @@ -17,6 +29,7 @@ public: void SetComponent(Component *c); Component* GetComponent() const; + private: Component *CollectionComponent; Item *CollectionItem; diff --git a/RetroFE/Source/Graphics/Page.cpp b/RetroFE/Source/Graphics/Page.cpp index 10b2724..7a9aa23 100644 --- a/RetroFE/Source/Graphics/Page.cpp +++ b/RetroFE/Source/Graphics/Page.cpp @@ -25,10 +25,10 @@ #include "ComponentItemBindingBuilder.h" #include -Page::Page(std::string collectionName, Configuration &config) - : CollectionName(collectionName) - , Config(config) - , Menu(NULL) +Page::Page(Configuration &config) + : Config(config) + , ActiveMenu(NULL) + , MenuDepth(0) , Items(NULL) , ScrollActive(false) , SelectedItem(NULL) @@ -45,9 +45,14 @@ Page::Page(std::string collectionName, Configuration &config) Page::~Page() { - if(Menu) + MenuVector_T::iterator it = Menus.begin(); + while(it != Menus.end()) { - Menu->RemoveComponentForNotifications(this); + ScrollingList *menu = *it; + menu->RemoveComponentForNotifications(this); + Menus.erase(it); + delete menu; + it = Menus.begin(); } for(unsigned int i = 0; i < sizeof(LayerComponents)/sizeof(LayerComponents[0]); ++i) @@ -60,10 +65,6 @@ Page::~Page() LayerComponents[i].clear(); } - if(Menu) - { - delete Menu; - } if(LoadSoundChunk) { @@ -97,14 +98,13 @@ void Page::OnNewItemSelected(Item *item) SelectedItemChanged = true; } -void Page::SetMenu(ScrollingList *s) +void Page::PushMenu(ScrollingList *s) { - // todo: delete the old menu - Menu = s; - - if(Menu) + Menus.push_back(s); + + if(s) { - Menu->AddComponentForNotifications(this); + s->AddComponentForNotifications(this); } } @@ -141,9 +141,15 @@ bool Page::IsIdle() { bool idle = true; - if(Menu && !Menu->IsIdle()) + for(MenuVector_T::iterator it = Menus.begin(); it != Menus.end(); it++) { - idle = false; + ScrollingList *menu = *it; + + if(!menu->IsIdle()) + { + idle = false; + break; + } } for(unsigned int i = 0; i < NUM_LAYERS && idle; ++i) @@ -160,7 +166,19 @@ bool Page::IsIdle() bool Page::IsHidden() { - bool hidden = (!Menu || Menu->IsHidden()); + bool hidden = true; + + for(MenuVector_T::iterator it = Menus.begin(); it != Menus.end(); it++) + { + ScrollingList *menu = *it; + + if(!menu->IsHidden()) + { + hidden = false; + break; + } + } + for(unsigned int i = 0; hidden && i < NUM_LAYERS; ++i) { @@ -175,9 +193,10 @@ bool Page::IsHidden() void Page::Start() { - if(Menu) + for(MenuVector_T::iterator it = Menus.begin(); it != Menus.end(); it++) { - Menu->TriggerEnterEvent(); + ScrollingList *menu = *it; + menu->TriggerEnterEvent(); } if(LoadSoundChunk) @@ -185,6 +204,12 @@ void Page::Start() LoadSoundChunk->Play(); } + StartComponents(); +} + + +void Page::StartComponents() +{ for(unsigned int i = 0; i < NUM_LAYERS; ++i) { for(std::vector::iterator it = LayerComponents[i].begin(); it != LayerComponents[i].end(); ++it) @@ -196,10 +221,12 @@ void Page::Start() void Page::Stop() { - if(Menu) + for(MenuVector_T::iterator it = Menus.begin(); it != Menus.end(); it++) { - Menu->TriggerExitEvent(); + ScrollingList *menu = *it; + menu->TriggerExitEvent(); } + if(UnloadSoundChunk) { UnloadSoundChunk->Play(); @@ -222,11 +249,13 @@ Item *Page::GetSelectedItem() void Page::RemoveSelectedItem() { + /* //todo: change method to RemoveItem() and pass in SelectedItem if(Menu) { Menu->RemoveSelectedItem(); } + */ SelectedItem = NULL; } @@ -238,10 +267,10 @@ void Page::Highlight() if(item) { - if(Menu) + if(ActiveMenu) { - Menu->TriggerHighlightEvent(item); - Menu->SetScrollActive(ScrollActive); + ActiveMenu->TriggerHighlightEvent(item); + ActiveMenu->SetScrollActive(ScrollActive); } for(unsigned int i = 0; i < NUM_LAYERS; ++i) @@ -277,45 +306,94 @@ void Page::SetScrolling(ScrollDirection direction) break; } - if(Menu) - { - Menu->SetScrollDirection(menuDirection); - } + ActiveMenu->SetScrollDirection(menuDirection); } void Page::PageScroll(ScrollDirection direction) { - if(Menu) + if(ActiveMenu) { if(direction == ScrollDirectionForward) { - Menu->PageDown(); + ActiveMenu->PageDown(); } if(direction == ScrollDirectionBack) { - Menu->PageUp(); + ActiveMenu->PageUp(); } } } - -void Page::SetCollection(CollectionInfo *collection) +bool Page::PushCollection(CollectionInfo *collection) { + Collections.push_back(collection); std::vector *sprites = ComponentItemBindingBuilder::BuildCollectionItems(collection->GetItems()); - if(Menu) + + if(ActiveMenu) { - Menu->SetItems(sprites); + ActiveMenu->TriggerMenuExitEvent(); } + + ActiveMenu = Menus[MenuDepth]; + + ActiveMenu->SetCollectionName(collection->GetName()); + ActiveMenu->DestroyItems(); + ActiveMenu->SetItems(sprites); + ActiveMenu->TriggerMenuEnterEvent(); + + if(MenuDepth < Menus.size()) + { + MenuDepth++; + } + + for(unsigned int i = 0; i < NUM_LAYERS; ++i) + { + for(std::vector::iterator it = LayerComponents[i].begin(); it != LayerComponents[i].end(); ++it) + { + (*it)->SetCollectionName(collection->GetName()); + } + } + + return true; } +bool Page::PopCollection() +{ + if(MenuDepth > 1) + { + if(Collections.size() > 1) + { + Collections.pop_back(); + } + + if(ActiveMenu) + { + ActiveMenu->TriggerMenuExitEvent(); + } + + MenuDepth--; + + ActiveMenu = Menus[MenuDepth - 1]; + if(ActiveMenu) + { + ActiveMenu->TriggerMenuEnterEvent(); + } + + return true; + } + return false; +} void Page::Update(float dt) { - if(Menu) + for(MenuVector_T::iterator it = Menus.begin(); it != Menus.end(); it++) { - Menu->Update(dt); + ScrollingList *menu = *it; + + menu->Update(dt); } + if(SelectedItemChanged && !HasSoundedWhenActive && HighlightSoundChunk) { // skip the first sound being played (as it is part of the on-enter) @@ -357,24 +435,35 @@ void Page::Draw() (*it)->Draw(); } - if(Menu) + for(MenuVector_T::iterator it = Menus.begin(); it != Menus.end(); it++) { - Menu->Draw(i); + ScrollingList *menu = *it; + menu->Draw(i); } } + } -const std::string& Page::GetCollectionName() const +std::string Page::GetCollectionName() { - return CollectionName; + CollectionInfo *info = Collections.back(); + + if(info) + { + return info->GetName(); + } + + return ""; } void Page::FreeGraphicsMemory() { Logger::Write(Logger::ZONE_DEBUG, "Page", "Free"); - if(Menu) + + for(MenuVector_T::iterator it = Menus.begin(); it != Menus.end(); it++) { - Menu->FreeGraphicsMemory(); + ScrollingList *menu = *it; + menu->FreeGraphicsMemory(); } if(LoadSoundChunk) LoadSoundChunk->Free(); @@ -395,9 +484,12 @@ void Page::AllocateGraphicsMemory() { FirstSoundPlayed = false; Logger::Write(Logger::ZONE_DEBUG, "Page", "Allocating graphics memory"); - if(Menu) + + for(MenuVector_T::iterator it = Menus.begin(); it != Menus.end(); it++) { - Menu->AllocateGraphicsMemory(); + ScrollingList *menu = *it; + + menu->AllocateGraphicsMemory(); } if(LoadSoundChunk) LoadSoundChunk->Allocate(); @@ -417,9 +509,9 @@ void Page::AllocateGraphicsMemory() void Page::LaunchEnter() { - if(Menu) + if(ActiveMenu) { - Menu->LaunchEnter(); + ActiveMenu->LaunchEnter(); } for(unsigned int i = 0; i < NUM_LAYERS; ++i) @@ -433,9 +525,9 @@ void Page::LaunchEnter() void Page::LaunchExit() { - if(Menu) + if(ActiveMenu) { - Menu->LaunchExit(); + ActiveMenu->LaunchExit(); } for(unsigned int i = 0; i < NUM_LAYERS; ++i) diff --git a/RetroFE/Source/Graphics/Page.h b/RetroFE/Source/Graphics/Page.h index 3be321b..e5185ee 100644 --- a/RetroFE/Source/Graphics/Page.h +++ b/RetroFE/Source/Graphics/Page.h @@ -1,12 +1,26 @@ -/* This file is subject to the terms and conditions defined in - * file 'LICENSE.txt', which is part of this source code package. +/* 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 "MenuNotifierInterface.h" -#include +#include #include +#include +#include class CollectionInfo; class Component; @@ -27,11 +41,14 @@ public: }; - Page(std::string collectionName, Configuration &c); + Page(Configuration &c); virtual ~Page(); virtual void OnNewItemSelected(Item *); - void SetCollection(CollectionInfo *collection); - void SetMenu(ScrollingList *s); + bool PushCollection(CollectionInfo *collection); + bool IsMenusFull() { return (MenuDepth > Menus.size()); } + bool PopCollection(); + void PushMenu(ScrollingList *s); + void SetLoadSound(Sound *chunk) { LoadSoundChunk = chunk; @@ -48,11 +65,14 @@ public: { SelectSoundChunk = chunk; } + bool AddComponent(Component *c); void PageScroll(ScrollDirection direction); void Start(); + void StartComponents(); void Stop(); void SetScrolling(ScrollDirection direction); + unsigned int GetMenuDepth() { return MenuDepth; } Item *GetSelectedItem(); Item *GetPendingSelectedItem(); void RemoveSelectedItem(); @@ -65,17 +85,25 @@ public: void AllocateGraphicsMemory(); void LaunchEnter(); void LaunchExit(); - const std::string& GetCollectionName() const; + std::string GetCollectionName(); private: void Highlight(); std::string CollectionName; Configuration &Config; - ScrollingList *Menu; + typedef std::vector MenuVector_T; + typedef std::vector CollectionInfo_T; + + ScrollingList *ActiveMenu; + unsigned int MenuDepth; + MenuVector_T Menus; + CollectionInfo_T Collections; + static const unsigned int NUM_LAYERS = 8; std::vector LayerComponents[NUM_LAYERS]; std::vector *Items; bool ScrollActive; + Item *SelectedItem; Text *TextStatusComponent; bool SelectedItemChanged; @@ -86,4 +114,5 @@ private: bool HasSoundedWhenActive; bool FirstSoundPlayed; + }; diff --git a/RetroFE/Source/Graphics/PageBuilder.cpp b/RetroFE/Source/Graphics/PageBuilder.cpp index 18c6cd1..01adf7b 100644 --- a/RetroFE/Source/Graphics/PageBuilder.cpp +++ b/RetroFE/Source/Graphics/PageBuilder.cpp @@ -23,6 +23,7 @@ #include "Component/ReloadableText.h" #include "Component/ReloadableMedia.h" #include "Component/ScrollingList.h" +#include "Animate/TweenSet.h" #include "Animate/TweenTypes.h" #include "../Sound/Sound.h" #include "../Collection/Item.h" @@ -46,9 +47,8 @@ static const int MENU_END = -2; // last item transitions here after it scroll static const int MENU_CENTER = -4; //todo: this file is starting to become a god class of building. Consider splitting into sub-builders -PageBuilder::PageBuilder(std::string layoutKey, std::string collection, Configuration &c, FontCache *fc) +PageBuilder::PageBuilder(std::string layoutKey, Configuration &c, FontCache *fc) : LayoutKey(layoutKey) - , Collection(collection) , Config(c) , ScaleX(1) , ScaleY(1) @@ -168,7 +168,7 @@ Page *PageBuilder::BuildPage() ss << layoutWidth << "x" << layoutHeight << " (scale " << ScaleX << "x" << ScaleY << ")"; Logger::Write(Logger::ZONE_DEBUG, "Layout", "Layout resolution " + ss.str()); - page = new Page(Collection, Config); + page = new Page(Config); // load sounds for(xml_node<> *sound = root->first_node("sound"); sound; sound = sound->next_sibling("sound")) @@ -207,6 +207,7 @@ Page *PageBuilder::BuildPage() } } } + if(!BuildComponents(root, page)) { delete page; @@ -314,15 +315,12 @@ float PageBuilder::GetVerticalAlignment(xml_attribute<> *attribute, float valueI bool PageBuilder::BuildComponents(xml_node<> *layout, Page *page) { - xml_node<> *menuXml = layout->first_node("menu"); - - if(menuXml) + for(xml_node<> *componentXml = layout->first_node("menu"); componentXml; componentXml = componentXml->next_sibling("menu")) { - ScrollingList *scrollingList = BuildMenu(menuXml); - page->SetMenu(scrollingList); + ScrollingList *scrollingList = BuildMenu(componentXml); + page->PushMenu(scrollingList); } - for(xml_node<> *componentXml = layout->first_node("container"); componentXml; componentXml = componentXml->next_sibling("container")) { Container *c = new Container(); @@ -424,14 +422,6 @@ void PageBuilder::LoadReloadableImages(xml_node<> *layout, std::string tagName, Logger::Write(Logger::ZONE_ERROR, "Layout", "Image component in layout does not specify a source image file"); } - if(type && (tagName == "reloadableVideo" || tagName == "reloadableImage")) - { - std::string configImagePath = "collections." + Collection + ".media." + type->value(); - - Config.GetMediaPropertyAbsolutePath(Collection, type->value(), reloadableImagePath); - - Config.GetMediaPropertyAbsolutePath(Collection, "video", reloadableVideoPath); - } Component *c = NULL; @@ -441,12 +431,12 @@ void PageBuilder::LoadReloadableImages(xml_node<> *layout, std::string tagName, if(type) { FC->LoadFont(Font, FontSize, FontColor); - c = new ReloadableText(type->value(), FC->GetFont(Font), FontColor, LayoutKey, Collection, ScaleX, ScaleY); + c = new ReloadableText(type->value(), FC->GetFont(Font), FontColor, LayoutKey, ScaleX, ScaleY); } } else { - c = new ReloadableMedia(reloadableImagePath, reloadableVideoPath, (tagName == "reloadableVideo"), ScaleX, ScaleY); + c = new ReloadableMedia(Config, type->value(), (tagName == "reloadableVideo"), ScaleX, ScaleY); } if(c) @@ -463,26 +453,22 @@ void PageBuilder::LoadTweens(Component *c, xml_node<> *componentXml) BuildViewInfo(componentXml, v); - Component::TweenSets *tweenSets; - tweenSets = new std::vector *>(); - GetTweenSets(componentXml->first_node("onEnter"), tweenSets); - c->SetOnEnterTweens(tweenSets); + c->SetTweens(CreateTweenInstance(componentXml)); +} - tweenSets = new std::vector *>(); - GetTweenSets(componentXml->first_node("onExit"), tweenSets); - c->SetOnExitTweens(tweenSets); +TweenSet *PageBuilder::CreateTweenInstance(xml_node<> *componentXml) +{ + TweenSet *tweens = new TweenSet(); - tweenSets = new std::vector *>(); - GetTweenSets(componentXml->first_node("onIdle"), tweenSets); - c->SetOnIdleTweens(tweenSets); + GetTweenSets(componentXml->first_node("onEnter"), tweens->GetOnEnterTweens()); + GetTweenSets(componentXml->first_node("onExit"), tweens->GetOnExitTweens()); + GetTweenSets(componentXml->first_node("onIdle"), tweens->GetOnIdleTweens()); + GetTweenSets(componentXml->first_node("onHighlightEnter"), tweens->GetOnHighlightEnterTweens()); + GetTweenSets(componentXml->first_node("onHighlightExit"), tweens->GetOnHighlightExitTweens()); + GetTweenSets(componentXml->first_node("onMenuEnter"), tweens->GetOnMenuEnterTweens()); + GetTweenSets(componentXml->first_node("onMenuExit"), tweens->GetOnMenuExitTweens()); - tweenSets = new std::vector *>(); - GetTweenSets(componentXml->first_node("onHighlightEnter"), tweenSets); - c->SetOnHighlightEnterTweens(tweenSets); - - tweenSets = new std::vector *>(); - GetTweenSets(componentXml->first_node("onHighlightExit"), tweenSets); - c->SetOnHighlightExitTweens(tweenSets); + return tweens; } @@ -515,7 +501,7 @@ ScrollingList * PageBuilder::BuildMenu(xml_node<> *menuXml) // on default, text will be rendered to the menu. Preload it into cache. FC->LoadFont(Font, FontSize, FontColor); - menu = new ScrollingList(Config, ScaleX, ScaleY, FC->GetFont(Font), FontColor, LayoutKey, Collection, imageType); + menu = new ScrollingList(Config, ScaleX, ScaleY, FC->GetFont(Font), FontColor, LayoutKey, imageType); ViewInfo *v = menu->GetBaseViewInfo(); BuildViewInfo(menuXml, v); @@ -529,6 +515,8 @@ ScrollingList * PageBuilder::BuildMenu(xml_node<> *menuXml) BuildVerticalMenu(menu, menuXml, itemDefaults); } + LoadTweens(menu, menuXml); + return menu; } @@ -536,6 +524,7 @@ ScrollingList * PageBuilder::BuildMenu(xml_node<> *menuXml) void PageBuilder::BuildCustomMenu(ScrollingList *menu, xml_node<> *menuXml, xml_node<> *itemDefaults) { std::vector *points = new std::vector(); + std::vector *tweenPoints = new std::vector(); int i = 0; @@ -543,9 +532,9 @@ void PageBuilder::BuildCustomMenu(ScrollingList *menu, xml_node<> *menuXml, xml_ { ViewInfo *viewInfo = new ViewInfo(); BuildViewInfo(componentXml, viewInfo, itemDefaults); - + points->push_back(viewInfo); - + tweenPoints->push_back(CreateTweenInstance(componentXml)); xml_attribute<> *selected = componentXml->first_attribute("selected"); if(selected) @@ -556,12 +545,13 @@ void PageBuilder::BuildCustomMenu(ScrollingList *menu, xml_node<> *menuXml, xml_ i++; } - menu->SetPoints(points); + menu->SetPoints(points, tweenPoints); } void PageBuilder::BuildVerticalMenu(ScrollingList *menu, xml_node<> *menuXml, xml_node<> *itemDefaults) { std::vector *points = new std::vector(); + std::vector *tweenPoints = new std::vector(); int selectedIndex = MENU_FIRST; std::map *> overrideItems; @@ -600,6 +590,7 @@ void PageBuilder::BuildVerticalMenu(ScrollingList *menu, xml_node<> *menuXml, xm xml_node<> *component = overrideItems[MENU_START]; ViewInfo *viewInfo = CreateMenuItemInfo(component, itemDefaults, menu->GetBaseViewInfo()->GetY() + height); points->push_back(viewInfo); + tweenPoints->push_back(CreateTweenInstance(component)); } while(!end) { @@ -637,6 +628,7 @@ void PageBuilder::BuildVerticalMenu(ScrollingList *menu, xml_node<> *menuXml, xm height = nextHeight; viewInfo->SetY(menu->GetBaseViewInfo()->GetY() + (float)height); points->push_back(viewInfo); + tweenPoints->push_back(CreateTweenInstance(component)); index++; } @@ -646,6 +638,7 @@ void PageBuilder::BuildVerticalMenu(ScrollingList *menu, xml_node<> *menuXml, xm xml_node<> *component = overrideItems[MENU_END]; ViewInfo *viewInfo = CreateMenuItemInfo(component, itemDefaults, menu->GetBaseViewInfo()->GetY() + height); points->push_back(viewInfo); + tweenPoints->push_back(CreateTweenInstance(component)); } if(selectedIndex >= ((int)points->size()-2)) @@ -658,7 +651,7 @@ void PageBuilder::BuildVerticalMenu(ScrollingList *menu, xml_node<> *menuXml, xm menu->SetSelectedIndex(selectedIndex+1); } - menu->SetPoints(points); + menu->SetPoints(points, tweenPoints); } ViewInfo *PageBuilder::CreateMenuItemInfo(xml_node<> *component, xml_node<> *defaults, float y) @@ -780,10 +773,8 @@ void PageBuilder::BuildViewInfo(xml_node<> *componentXml, ViewInfo *info, xml_no { info->SetBackgroundAlpha( backgroundAlpha ? Utils::ConvertFloat(backgroundAlpha->value()) : 1); } - } - void PageBuilder::GetTweenSets(xml_node<> *node, std::vector *> *tweenSets) { if(node) diff --git a/RetroFE/Source/Graphics/PageBuilder.h b/RetroFE/Source/Graphics/PageBuilder.h index 26ff93a..8eee594 100644 --- a/RetroFE/Source/Graphics/PageBuilder.h +++ b/RetroFE/Source/Graphics/PageBuilder.h @@ -18,14 +18,13 @@ class Configuration; class PageBuilder { public: - PageBuilder(std::string layoutKey, std::string collection, Configuration &c, FontCache *fc); + PageBuilder(std::string layoutKey, Configuration &c, FontCache *fc); virtual ~PageBuilder(); Page *BuildPage(); private: std::string LayoutKey; std::string LayoutPath; - std::string Collection; Configuration &Config; float ScaleX; float ScaleY; @@ -42,6 +41,7 @@ private: void BuildViewInfo(rapidxml::xml_node<> *componentXml, ViewInfo *info, rapidxml::xml_node<> *defaultXml = NULL); bool BuildComponents(rapidxml::xml_node<> *layout, Page *page); void LoadTweens(Component *c, rapidxml::xml_node<> *componentXml); + TweenSet *CreateTweenInstance(rapidxml::xml_node<> *componentXml); ScrollingList * BuildMenu(rapidxml::xml_node<> *menuXml); void BuildCustomMenu(ScrollingList *menu, rapidxml::xml_node<> *menuXml, rapidxml::xml_node<> *itemDefaults); void BuildVerticalMenu(ScrollingList *menu, rapidxml::xml_node<> *menuXml, rapidxml::xml_node<> *itemDefaults); diff --git a/RetroFE/Source/RetroFE.cpp b/RetroFE/Source/RetroFE.cpp index 803be1d..558d10a 100644 --- a/RetroFE/Source/RetroFE.cpp +++ b/RetroFE/Source/RetroFE.cpp @@ -43,6 +43,7 @@ RetroFE::RetroFE(Configuration &c) , Config(c) , Db(NULL) , Input(Config) + , CurrentPage(NULL) , KeyInputDisable(0) , CurrentTime(0) { @@ -59,15 +60,11 @@ void RetroFE::Render() SDL_SetRenderDrawColor(SDL::GetRenderer(), 0x0, 0x0, 0x00, 0xFF); SDL_RenderClear(SDL::GetRenderer()); - if(PageChain.size() > 0) + if(CurrentPage) { - Page *page = PageChain.back(); - - if(page) - { - page->Draw(); - } + CurrentPage->Draw(); } + SDL_RenderPresent(SDL::GetRenderer()); SDL_UnlockMutex(SDL::GetMutex()); } @@ -111,11 +108,11 @@ int RetroFE::Initialize(void *context) void RetroFE::LaunchEnter() { - if(PageChain.size() > 0) + if(CurrentPage) { - Page *p = PageChain.back(); - p->LaunchEnter(); + CurrentPage->LaunchEnter(); } + SDL_SetWindowGrab(SDL::GetWindow(), SDL_FALSE); } @@ -125,20 +122,18 @@ void RetroFE::LaunchExit() SDL_RestoreWindow(SDL::GetWindow()); SDL_SetWindowGrab(SDL::GetWindow(), SDL_TRUE); - if(PageChain.size() > 0) + if(CurrentPage) { - Page *p = PageChain.back(); - p->LaunchExit(); + CurrentPage->LaunchExit(); } } void RetroFE::FreeGraphicsMemory() { - if(PageChain.size() > 0) + if(CurrentPage) { - Page *p = PageChain.back(); - p->FreeGraphicsMemory(); + CurrentPage->FreeGraphicsMemory(); } FC.DeInitialize(); @@ -151,11 +146,10 @@ void RetroFE::AllocateGraphicsMemory() FC.Initialize(); - if(PageChain.size() > 0) + if(CurrentPage) { - Page *p = PageChain.back(); - p->AllocateGraphicsMemory(); - p->Start(); + CurrentPage->AllocateGraphicsMemory(); + CurrentPage->Start(); } } @@ -166,11 +160,10 @@ bool RetroFE::DeInitialize() bool videoEnable = true; - while(PageChain.size() > 0) + if(CurrentPage) { - Page *page = PageChain.back(); - delete page; - PageChain.pop_back(); + delete CurrentPage; + CurrentPage = NULL; } if(MetaDb) { @@ -218,7 +211,7 @@ void RetroFE::Run() int initializeStatus = 0; // load the initial splash screen, unload it once it is complete - Page * page = LoadSplashPage(); + CurrentPage = LoadSplashPage(); bool splashMode = true; Launcher l(*this, Config); @@ -227,9 +220,8 @@ void RetroFE::Run() { float lastTime = 0; float deltaTime = 0; - page = PageChain.back(); - if(!page) + if(!CurrentPage) { Logger::Write(Logger::ZONE_WARNING, "RetroFE", "Could not load page"); running = false; @@ -239,9 +231,9 @@ void RetroFE::Run() switch(state) { case RETROFE_IDLE: - if(page && !splashMode) + if(CurrentPage && !splashMode) { - state = ProcessUserInput(page); + state = ProcessUserInput(CurrentPage); } else { @@ -253,65 +245,65 @@ void RetroFE::Run() if(Initialized && splashMode) { SDL_WaitThread(InitializeThread, &initializeStatus); - state = RETROFE_BACK_WAIT; - page->Stop(); + + // delete the splash screen and use the standard menu + delete CurrentPage; + CurrentPage = LoadPage(); + splashMode = false; + if(CurrentPage) + { + std::string firstCollection; + Config.GetProperty("firstCollection", firstCollection); + + CurrentPage->Start(); + Config.SetCurrentCollection(firstCollection); + CollectionInfo *info = GetCollection(firstCollection); + CurrentPage->PushCollection(info); + } + else + { + state = RETROFE_QUIT_REQUEST; + } + } break; case RETROFE_NEXT_PAGE_REQUEST: - page->Stop(); - state = RETROFE_NEXT_PAGE_WAIT; - break; - - case RETROFE_NEXT_PAGE_WAIT: - if(page->IsHidden()) + if(CurrentPage->IsIdle()) { - page = LoadPage(NextPageItem->GetName()); state = RETROFE_NEW; } break; case RETROFE_LAUNCH_REQUEST: - l.Run(page->GetCollectionName(), NextPageItem); + NextPageItem = CurrentPage->GetSelectedItem(); + l.Run(CurrentPage->GetCollectionName(), NextPageItem); state = RETROFE_IDLE; break; case RETROFE_BACK_REQUEST: - page->Stop(); - state = RETROFE_BACK_WAIT; - break; + CurrentPage->PopCollection(); + Config.SetCurrentCollection(CurrentPage->GetCollectionName()); - case RETROFE_BACK_WAIT: - if(page->IsHidden()) - { - PageChain.pop_back(); - delete page; + state = RETROFE_NEW; - page = (splashMode) ? LoadPage(firstCollection) : PageChain.back(); - splashMode = false; - CurrentTime = (float)SDL_GetTicks() / 1000; - - page->AllocateGraphicsMemory(); - page->Start(); - state = RETROFE_NEW; - } break; case RETROFE_NEW: - if(page->IsIdle()) + if(CurrentPage->IsIdle()) { state = RETROFE_IDLE; } break; case RETROFE_QUIT_REQUEST: - page->Stop(); + CurrentPage->Stop(); state = RETROFE_QUIT; break; case RETROFE_QUIT: - if(page->IsHidden()) + if(CurrentPage->IsHidden()) { running = false; } @@ -337,10 +329,10 @@ void RetroFE::Run() SDL_Delay(static_cast(sleepTime)); } - if(page) + if(CurrentPage) { - Attract.Update(deltaTime, *page); - page->Update(deltaTime); + Attract.Update(deltaTime, *CurrentPage); + CurrentPage->Update(deltaTime); } Render(); @@ -353,22 +345,16 @@ void RetroFE::Run() bool RetroFE::Back(bool &exit) { bool canGoBack = false; - bool exitOnBack = false; Config.GetProperty("exitOnFirstPageBack", exitOnBack); exit = false; - if(PageChain.size() > 1) + if(CurrentPage->GetMenuDepth() == 0) { - Page *page = PageChain.back(); - page->Stop(); - canGoBack = true; + exit = exitOnBack; } - else if(PageChain.size() == 1 && exitOnBack) + else { - Page *page = PageChain.back(); - page->Stop(); - exit = true; canGoBack = true; } @@ -413,10 +399,22 @@ RetroFE::RETROFE_STATE RetroFE::ProcessUserInput(Page *page) if (keys[Input.GetScancode(UserInput::KeyCodeSelect)]) { NextPageItem = page->GetSelectedItem(); + Logger::Write(Logger::ZONE_INFO, "RetroFE", "SELECT KEYCODE START"); if(NextPageItem) { - state = (NextPageItem->IsLeaf()) ? RETROFE_LAUNCH_REQUEST : RETROFE_NEXT_PAGE_REQUEST; + if(NextPageItem->IsLeaf()) + { + state = RETROFE_LAUNCH_REQUEST; + } + else + { + Config.SetCurrentCollection(NextPageItem->GetName()); + CollectionInfo *info = GetCollection(NextPageItem->GetName()); + + page->PushCollection(info); + state = RETROFE_NEXT_PAGE_REQUEST; + } } } @@ -449,7 +447,7 @@ void RetroFE::WaitToInitialize() { Logger::Write(Logger::ZONE_INFO, "RetroFE", "Loading splash screen"); - PageBuilder pb("splash", "", Config, &FC); + PageBuilder pb("splash", Config, &FC); Page * page = pb.BuildPage(); while(!Initialized) @@ -467,47 +465,32 @@ void RetroFE::WaitToInitialize() } -Page *RetroFE::LoadPage(std::string collectionName) +Page *RetroFE::LoadPage() { - Logger::Write(Logger::ZONE_INFO, "RetroFE", "Creating page for collection " + collectionName); + std::string layoutName; - Page *page = NULL; + Config.GetProperty("layout", layoutName); - Config.SetCurrentCollection(collectionName); - CollectionInfo *collection = GetCollection(collectionName); - std::string layoutName = GetLayout(collectionName); - - if(PageChain.size() > 0) - { - Page *oldPage = PageChain.back(); - oldPage->FreeGraphicsMemory(); - } - - PageBuilder pb(layoutName, collectionName, Config, &FC); - page = pb.BuildPage(); + PageBuilder pb(layoutName, Config, &FC); + Page *page = pb.BuildPage(); if(!page) { - Logger::Write(Logger::ZONE_ERROR, "RetroFE", "Could not create page for " + collectionName); + Logger::Write(Logger::ZONE_ERROR, "RetroFE", "Could not create page"); } else { - page->SetCollection(collection); page->Start(); - - PageChain.push_back(page); } return page; } + Page *RetroFE::LoadSplashPage() { - PageBuilder pb("Splash", "", Config, &FC); + PageBuilder pb("Splash", Config, &FC); Page * page = pb.BuildPage(); - Config.SetCurrentCollection(""); - page->SetCollection(new CollectionInfo("", "", "", "", "")); page->Start(); - PageChain.push_back(page); return page; } diff --git a/RetroFE/Source/RetroFE.h b/RetroFE/Source/RetroFE.h index be8cda0..df9c1eb 100644 --- a/RetroFE/Source/RetroFE.h +++ b/RetroFE/Source/RetroFE.h @@ -38,10 +38,8 @@ private: { RETROFE_IDLE, RETROFE_NEXT_PAGE_REQUEST, - RETROFE_NEXT_PAGE_WAIT, RETROFE_LAUNCH_REQUEST, RETROFE_BACK_REQUEST, - RETROFE_BACK_WAIT, RETROFE_NEW, RETROFE_QUIT_REQUEST, RETROFE_QUIT, @@ -51,7 +49,7 @@ private: bool Back(bool &exit); void Quit(); void WaitToInitialize(); - Page *LoadPage(std::string collectionName); + Page *LoadPage(); Page *LoadSplashPage(); RETROFE_STATE ProcessUserInput(Page *page); void Update(float dt, bool scrollActive); @@ -61,7 +59,7 @@ private: DB *Db; MetadataDatabase *MetaDb; UserInput Input; - std::list PageChain; + Page *CurrentPage; float KeyInputDisable; float CurrentTime; Item *NextPageItem;