diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a5088342..1ba440e90 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -155,7 +155,6 @@ set(ES_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/Sound.h ${CMAKE_CURRENT_SOURCE_DIR}/src/SystemData.h ${CMAKE_CURRENT_SOURCE_DIR}/src/ThemeData.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/ThemeDumper.h ${CMAKE_CURRENT_SOURCE_DIR}/src/VolumeControl.h ${CMAKE_CURRENT_SOURCE_DIR}/src/Window.h ${CMAKE_CURRENT_SOURCE_DIR}/src/XMLReader.h @@ -165,6 +164,7 @@ set(ES_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ComponentListComponent.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/DateTimeComponent.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/HelpComponent.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/components/IList.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageComponent.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageGridComponent.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/NinePatchComponent.h @@ -235,7 +235,6 @@ set(ES_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/Sound.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/SystemData.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/ThemeData.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/ThemeDumper.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/VolumeControl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Window.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/XMLReader.cpp @@ -245,6 +244,7 @@ set(ES_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ComponentListComponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/DateTimeComponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/HelpComponent.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/components/IList.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageComponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/NinePatchComponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/RatingComponent.cpp diff --git a/src/ThemeDumper.cpp b/src/ThemeDumper.cpp deleted file mode 100644 index e7ec37ad4..000000000 --- a/src/ThemeDumper.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "ThemeDumper.h" - diff --git a/src/ThemeDumper.h b/src/ThemeDumper.h deleted file mode 100644 index efd7a374b..000000000 --- a/src/ThemeDumper.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "ThemeData.h" - -// Should be able to: -// 1. Take a list of "tests" to run. -// a. Each test works by calling setTheme on a theme with a "fake" theme that records all getElement() access. -// 2. Results can be output to a text file, OR compared with a loaded theme to create warnings about potentially unused elements. - -class ThemeDumper -{ - -}; diff --git a/src/components/IList.cpp b/src/components/IList.cpp new file mode 100644 index 000000000..148cd429e --- /dev/null +++ b/src/components/IList.cpp @@ -0,0 +1,81 @@ +#include "IList.h" + +const IList::ScrollTier IList::SCROLL_SPEED[IList::SCROLL_SPEED_COUNT] = { + {500, 500}, + {2600, 150}, + {0, 100} +}; + +IList::IList() +{ + mScrollTier = 0; + mScrollVelocity = 0; + mScrollTierAccumulator = 0; + mScrollCursorAccumulator = 0; +} + +void IList::listInput(int velocity) +{ + mScrollVelocity = velocity; + mScrollTier = 0; + mScrollTierAccumulator = 0; + mScrollCursorAccumulator = 0; + scroll(mScrollVelocity); +} + +void IList::listUpdate(int deltaTime) +{ + if(mScrollVelocity == 0 || getLength() < 2) + return; + + mScrollCursorAccumulator += deltaTime; + mScrollTierAccumulator += deltaTime; + + while(mScrollCursorAccumulator >= SCROLL_SPEED[mScrollTier].scrollDelay) + { + mScrollCursorAccumulator -= SCROLL_SPEED[mScrollTier].scrollDelay; + scroll(mScrollVelocity); + } + + // are we ready to go even FASTER? + while(mScrollTier < SCROLL_SPEED_COUNT - 1 && mScrollTierAccumulator >= SCROLL_SPEED[mScrollTier].length) + { + mScrollTierAccumulator -= SCROLL_SPEED[mScrollTier].length; + mScrollTier++; + } +} + +void IList::scroll(int amt) +{ + if(mScrollVelocity == 0 || getLength() < 2) + return; + + int cursor = getCursorIndex() + amt; + int absAmt = amt < 0 ? -amt : amt; + + // stop at the end if we've been holding down the button for a long time or + // we're scrolling faster than one item at a time (e.g. page up/down) + // otherwise, loop around + if(mScrollTier > 0 || absAmt > 1) + { + if(cursor < 0) + cursor = 0; + else if(cursor >= getLength()) + cursor = getLength() - 1; + }else{ + if(cursor < 0) + cursor += getLength(); + else if(cursor >= getLength()) + cursor -= getLength(); + } + + if(cursor != getCursorIndex()) + onScroll(absAmt); + + setCursorIndex(cursor); +} + +bool IList::isScrolling() const +{ + return (mScrollVelocity != 0 && mScrollTier > 0); +} diff --git a/src/components/IList.h b/src/components/IList.h new file mode 100644 index 000000000..04417584c --- /dev/null +++ b/src/components/IList.h @@ -0,0 +1,36 @@ +#pragma once + +class IList +{ +public: + IList(); + + bool isScrolling() const; + +protected: + void listInput(int velocity); // a velocity of 0 = stop scrolling + void listUpdate(int deltaTime); + + virtual int getCursorIndex() = 0; + virtual void setCursorIndex(int index) = 0; // (index >= 0 && index < getLength()) is guaranteed to be true + virtual int getLength() = 0; + + void scroll(int amt); + virtual void onScroll(int amt) {}; + +private: + struct ScrollTier + { + int length; // how long we stay on this level before going to the next + int scrollDelay; // how long between scrolls + }; + + static const int SCROLL_SPEED_COUNT = 3; + static const ScrollTier SCROLL_SPEED[SCROLL_SPEED_COUNT]; + + int mScrollTier; + int mScrollVelocity; + + int mScrollTierAccumulator; + int mScrollCursorAccumulator; +}; diff --git a/src/components/ImageGridComponent.h b/src/components/ImageGridComponent.h index 0b99ae43a..d2f8529cf 100644 --- a/src/components/ImageGridComponent.h +++ b/src/components/ImageGridComponent.h @@ -1,11 +1,12 @@ #pragma once #include "../GuiComponent.h" +#include "IList.h" #include "../components/ImageComponent.h" #include "../Log.h" template -class ImageGridComponent : public GuiComponent +class ImageGridComponent : public GuiComponent, public IList { public: ImageGridComponent(Window* window); @@ -42,6 +43,11 @@ public: void update(int deltaTime) override; void render(const Eigen::Affine3f& parentTrans) override; +protected: + virtual int getCursorIndex() { return mCursor; } + virtual void setCursorIndex(int index) { mCursor = index; onCursorChanged(CURSOR_STOPPED); } + virtual int getLength() { return mEntries.size(); } + private: Eigen::Vector2f getSquareSize(std::shared_ptr tex = nullptr) const { @@ -89,18 +95,10 @@ private: void buildImages(); void updateImages(); - static const int SCROLL_DELAY = 507; - static const int SCROLL_TIME = 150; - - void setScrollDir(Eigen::Vector2i dir); - void scroll(); void onCursorChanged(CursorState state); int mCursor; - Eigen::Vector2i mScrollDir; - int mScrollAccumulator; - bool mEntriesDirty; std::vector mEntries; @@ -112,8 +110,6 @@ ImageGridComponent::ImageGridComponent(Window* window) : GuiComponent(window) { mEntriesDirty = true; mCursor = 0; - mScrollDir << 0, 0; - mScrollAccumulator = 0; } template @@ -151,7 +147,6 @@ void ImageGridComponent::clear() { mEntries.clear(); mCursor = 0; - mScrollDir << 0, 0; onCursorChanged(CURSOR_STOPPED); mEntriesDirty = true; } @@ -183,35 +178,8 @@ void ImageGridComponent::setCursor(typename std::vector::const_iterato template void ImageGridComponent::stopScrolling() { - mScrollDir = Eigen::Vector2i::Zero(); -} - -template -void ImageGridComponent::scroll() -{ - if(mEntries.size() == 0) - return; - - int offset = 0; - Eigen::Vector2i size = getGridSize(); - - offset += mScrollDir.x(); - offset += mScrollDir.y() * size.x(); - - mCursor += offset; - if(mCursor < 0) - mCursor += mEntries.size(); - if(mCursor >= (int)mEntries.size()) - mCursor -= mEntries.size(); - - onCursorChanged(CURSOR_SCROLLING); -} - -template -void ImageGridComponent::setScrollDir(Eigen::Vector2i dir) -{ - mScrollDir = dir; - mScrollAccumulator = -SCROLL_DELAY; + listInput(0); + onCursorChanged(CURSOR_STOPPED); } template @@ -231,15 +199,13 @@ bool ImageGridComponent::input(InputConfig* config, Input input) if(dir != Eigen::Vector2i::Zero()) { - setScrollDir(dir); - scroll(); + listInput(dir.x() + dir.y() * getGridSize().x()); return true; } }else{ if(config->isMappedTo("up", input) || config->isMappedTo("down", input) || config->isMappedTo("left", input) || config->isMappedTo("right", input)) { - mScrollDir << 0, 0; - onCursorChanged(CURSOR_STOPPED); + stopScrolling(); } } @@ -249,15 +215,7 @@ bool ImageGridComponent::input(InputConfig* config, Input input) template void ImageGridComponent::update(int deltaTime) { - if(mScrollDir != Eigen::Vector2i::Zero()) - { - mScrollAccumulator += deltaTime; - while(mScrollAccumulator >= SCROLL_TIME) - { - scroll(); - mScrollAccumulator -= SCROLL_TIME; - } - } + listUpdate(deltaTime); } template diff --git a/src/components/TextListComponent.h b/src/components/TextListComponent.h index b3f23f1b9..74246c15f 100644 --- a/src/components/TextListComponent.h +++ b/src/components/TextListComponent.h @@ -1,6 +1,6 @@ -#ifndef _TEXTLISTCOMPONENT_H_ -#define _TEXTLISTCOMPONENT_H_ +#pragma once +#include "IList.h" #include "../Renderer.h" #include "../resources/Font.h" #include "../GuiComponent.h" @@ -15,7 +15,7 @@ //A graphical list. Supports multiple colors for rows and scrolling. template -class TextListComponent : public GuiComponent +class TextListComponent : public GuiComponent, public IList { public: TextListComponent(Window* window); @@ -46,8 +46,7 @@ public: void setCursor(typename std::vector::const_iterator& it); void stopScrolling(); - inline bool isScrolling() const { return mScrollDir != 0 && mScrollAccumulator >= 0; } - + enum CursorState { CURSOR_STOPPED, @@ -78,20 +77,20 @@ public: inline void setColor(unsigned int id, unsigned int color) { mColors[id] = color; } inline void setSound(const std::shared_ptr& sound) { mScrollSound = sound; } +protected: + // IList implementations + virtual int getCursorIndex() { return mCursor; } + virtual void setCursorIndex(int index) { mCursor = index; onCursorChanged(isScrolling() ? CURSOR_SCROLLING : CURSOR_STOPPED); } + virtual int getLength() { return mRowVector.size(); } + virtual void onScroll(int amt) { if(mScrollSound) mScrollSound->play(); } + private: static const int MARQUEE_DELAY = 900; static const int MARQUEE_SPEED = 16; static const int MARQUEE_RATE = 3; - static const int SCROLL_DELAY = 507; - static const int SCROLL_TIME = 150; - - void scroll(); //helper method, scrolls in whatever direction scrollDir is - void setScrollDir(int val); //helper method, set mScrollDir as well as reset marquee stuff void onCursorChanged(CursorState state); - int mScrollDir, mScrollAccumulator; - int mMarqueeOffset; int mMarqueeTime; @@ -116,9 +115,7 @@ TextListComponent::TextListComponent(Window* window) : GuiComponent(window) { mCursor = 0; - mScrollDir = 0; - mScrollAccumulator = 0; - + mMarqueeOffset = 0; mMarqueeTime = -MARQUEE_DELAY; @@ -246,28 +243,24 @@ bool TextListComponent::input(InputConfig* config, Input input) { if(config->isMappedTo("down", input)) { - setScrollDir(1); - scroll(); + listInput(1); return true; } if(config->isMappedTo("up", input)) { - setScrollDir(-1); - scroll(); + listInput(-1); return true; } if(config->isMappedTo("pagedown", input)) { - setScrollDir(10); - scroll(); + listInput(10); return true; } if(config->isMappedTo("pageup", input)) { - setScrollDir(-10); - scroll(); + listInput(-10); return true; } }else{ @@ -282,37 +275,12 @@ bool TextListComponent::input(InputConfig* config, Input input) return GuiComponent::input(config, input); } -template -void TextListComponent::setScrollDir(int val) -{ - mScrollDir = val; - mMarqueeOffset = 0; - mMarqueeTime = -MARQUEE_DELAY; - mScrollAccumulator = -SCROLL_DELAY; -} - -template -void TextListComponent::stopScrolling() -{ - mScrollAccumulator = 0; - mScrollDir = 0; - onCursorChanged(CURSOR_STOPPED); -} - template void TextListComponent::update(int deltaTime) { - if(mScrollDir != 0) + listUpdate(deltaTime); + if(!isScrolling()) { - mScrollAccumulator += deltaTime; - - while(mScrollAccumulator >= SCROLL_TIME) - { - mScrollAccumulator -= SCROLL_TIME; - scroll(); - } - - }else{ //if we're not scrolling and this object's text goes outside our size, marquee it! std::string text = getSelectedName(); @@ -333,32 +301,6 @@ void TextListComponent::update(int deltaTime) GuiComponent::update(deltaTime); } -template -void TextListComponent::scroll() -{ - mCursor += mScrollDir; - - if(mCursor < 0) - { - if(mScrollDir < -1) - mCursor = 0; - else - mCursor += mRowVector.size(); - } - if(mCursor >= (int)mRowVector.size()) - { - if(mScrollDir > 1) - mCursor = (int)mRowVector.size() - 1; - else - mCursor -= mRowVector.size(); - } - - onCursorChanged(CURSOR_SCROLLING); - - if(mScrollSound) - mScrollSound->play(); -} - //list management stuff template void TextListComponent::add(const std::string& name, const T& obj, unsigned int color) @@ -395,7 +337,6 @@ void TextListComponent::clear() { mRowVector.clear(); mCursor = 0; - mScrollDir = 0; mMarqueeOffset = 0; mMarqueeTime = -MARQUEE_DELAY; onCursorChanged(CURSOR_STOPPED); @@ -429,10 +370,20 @@ void TextListComponent::setCursor(typename std::vector::const_iterat template void TextListComponent::onCursorChanged(CursorState state) { + mMarqueeOffset = 0; + mMarqueeTime = -MARQUEE_DELAY; + if(mCursorChangedCallback) mCursorChangedCallback(state); } +template +void TextListComponent::stopScrolling() +{ + listInput(0); + onCursorChanged(CURSOR_STOPPED); +} + template void TextListComponent::applyTheme(const std::shared_ptr& theme, const std::string& view, const std::string& element, unsigned int properties) { @@ -480,5 +431,3 @@ void TextListComponent::applyTheme(const std::shared_ptr& theme, c } } } - -#endif