First IList implementation

This commit is contained in:
Aloshi 2014-02-07 20:15:48 -06:00
parent 5c12395442
commit 7699a4f9be
7 changed files with 159 additions and 150 deletions

View file

@ -155,7 +155,6 @@ set(ES_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/src/Sound.h ${CMAKE_CURRENT_SOURCE_DIR}/src/Sound.h
${CMAKE_CURRENT_SOURCE_DIR}/src/SystemData.h ${CMAKE_CURRENT_SOURCE_DIR}/src/SystemData.h
${CMAKE_CURRENT_SOURCE_DIR}/src/ThemeData.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/VolumeControl.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Window.h ${CMAKE_CURRENT_SOURCE_DIR}/src/Window.h
${CMAKE_CURRENT_SOURCE_DIR}/src/XMLReader.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/ComponentListComponent.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/DateTimeComponent.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/DateTimeComponent.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/HelpComponent.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/ImageComponent.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageGridComponent.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageGridComponent.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/NinePatchComponent.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/Sound.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/SystemData.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/SystemData.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/ThemeData.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/VolumeControl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Window.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Window.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/XMLReader.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/ComponentListComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/DateTimeComponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/DateTimeComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/HelpComponent.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/ImageComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/NinePatchComponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/NinePatchComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/RatingComponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/RatingComponent.cpp

View file

@ -1,2 +0,0 @@
#include "ThemeDumper.h"

View file

@ -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
{
};

81
src/components/IList.cpp Normal file
View file

@ -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);
}

36
src/components/IList.h Normal file
View file

@ -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;
};

View file

@ -1,11 +1,12 @@
#pragma once #pragma once
#include "../GuiComponent.h" #include "../GuiComponent.h"
#include "IList.h"
#include "../components/ImageComponent.h" #include "../components/ImageComponent.h"
#include "../Log.h" #include "../Log.h"
template<typename T> template<typename T>
class ImageGridComponent : public GuiComponent class ImageGridComponent : public GuiComponent, public IList
{ {
public: public:
ImageGridComponent(Window* window); ImageGridComponent(Window* window);
@ -42,6 +43,11 @@ public:
void update(int deltaTime) override; void update(int deltaTime) override;
void render(const Eigen::Affine3f& parentTrans) 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: private:
Eigen::Vector2f getSquareSize(std::shared_ptr<TextureResource> tex = nullptr) const Eigen::Vector2f getSquareSize(std::shared_ptr<TextureResource> tex = nullptr) const
{ {
@ -89,18 +95,10 @@ private:
void buildImages(); void buildImages();
void updateImages(); 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); void onCursorChanged(CursorState state);
int mCursor; int mCursor;
Eigen::Vector2i mScrollDir;
int mScrollAccumulator;
bool mEntriesDirty; bool mEntriesDirty;
std::vector<Entry> mEntries; std::vector<Entry> mEntries;
@ -112,8 +110,6 @@ ImageGridComponent<T>::ImageGridComponent(Window* window) : GuiComponent(window)
{ {
mEntriesDirty = true; mEntriesDirty = true;
mCursor = 0; mCursor = 0;
mScrollDir << 0, 0;
mScrollAccumulator = 0;
} }
template<typename T> template<typename T>
@ -151,7 +147,6 @@ void ImageGridComponent<T>::clear()
{ {
mEntries.clear(); mEntries.clear();
mCursor = 0; mCursor = 0;
mScrollDir << 0, 0;
onCursorChanged(CURSOR_STOPPED); onCursorChanged(CURSOR_STOPPED);
mEntriesDirty = true; mEntriesDirty = true;
} }
@ -183,35 +178,8 @@ void ImageGridComponent<T>::setCursor(typename std::vector<Entry>::const_iterato
template<typename T> template<typename T>
void ImageGridComponent<T>::stopScrolling() void ImageGridComponent<T>::stopScrolling()
{ {
mScrollDir = Eigen::Vector2i::Zero(); listInput(0);
} onCursorChanged(CURSOR_STOPPED);
template<typename T>
void ImageGridComponent<T>::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<typename T>
void ImageGridComponent<T>::setScrollDir(Eigen::Vector2i dir)
{
mScrollDir = dir;
mScrollAccumulator = -SCROLL_DELAY;
} }
template<typename T> template<typename T>
@ -231,15 +199,13 @@ bool ImageGridComponent<T>::input(InputConfig* config, Input input)
if(dir != Eigen::Vector2i::Zero()) if(dir != Eigen::Vector2i::Zero())
{ {
setScrollDir(dir); listInput(dir.x() + dir.y() * getGridSize().x());
scroll();
return true; return true;
} }
}else{ }else{
if(config->isMappedTo("up", input) || config->isMappedTo("down", input) || config->isMappedTo("left", input) || config->isMappedTo("right", input)) if(config->isMappedTo("up", input) || config->isMappedTo("down", input) || config->isMappedTo("left", input) || config->isMappedTo("right", input))
{ {
mScrollDir << 0, 0; stopScrolling();
onCursorChanged(CURSOR_STOPPED);
} }
} }
@ -249,15 +215,7 @@ bool ImageGridComponent<T>::input(InputConfig* config, Input input)
template<typename T> template<typename T>
void ImageGridComponent<T>::update(int deltaTime) void ImageGridComponent<T>::update(int deltaTime)
{ {
if(mScrollDir != Eigen::Vector2i::Zero()) listUpdate(deltaTime);
{
mScrollAccumulator += deltaTime;
while(mScrollAccumulator >= SCROLL_TIME)
{
scroll();
mScrollAccumulator -= SCROLL_TIME;
}
}
} }
template<typename T> template<typename T>

View file

@ -1,6 +1,6 @@
#ifndef _TEXTLISTCOMPONENT_H_ #pragma once
#define _TEXTLISTCOMPONENT_H_
#include "IList.h"
#include "../Renderer.h" #include "../Renderer.h"
#include "../resources/Font.h" #include "../resources/Font.h"
#include "../GuiComponent.h" #include "../GuiComponent.h"
@ -15,7 +15,7 @@
//A graphical list. Supports multiple colors for rows and scrolling. //A graphical list. Supports multiple colors for rows and scrolling.
template <typename T> template <typename T>
class TextListComponent : public GuiComponent class TextListComponent : public GuiComponent, public IList
{ {
public: public:
TextListComponent(Window* window); TextListComponent(Window* window);
@ -46,8 +46,7 @@ public:
void setCursor(typename std::vector<ListRow>::const_iterator& it); void setCursor(typename std::vector<ListRow>::const_iterator& it);
void stopScrolling(); void stopScrolling();
inline bool isScrolling() const { return mScrollDir != 0 && mScrollAccumulator >= 0; }
enum CursorState enum CursorState
{ {
CURSOR_STOPPED, CURSOR_STOPPED,
@ -78,20 +77,20 @@ public:
inline void setColor(unsigned int id, unsigned int color) { mColors[id] = color; } inline void setColor(unsigned int id, unsigned int color) { mColors[id] = color; }
inline void setSound(const std::shared_ptr<Sound>& sound) { mScrollSound = sound; } inline void setSound(const std::shared_ptr<Sound>& 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: private:
static const int MARQUEE_DELAY = 900; static const int MARQUEE_DELAY = 900;
static const int MARQUEE_SPEED = 16; static const int MARQUEE_SPEED = 16;
static const int MARQUEE_RATE = 3; 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); void onCursorChanged(CursorState state);
int mScrollDir, mScrollAccumulator;
int mMarqueeOffset; int mMarqueeOffset;
int mMarqueeTime; int mMarqueeTime;
@ -116,9 +115,7 @@ TextListComponent<T>::TextListComponent(Window* window) :
GuiComponent(window) GuiComponent(window)
{ {
mCursor = 0; mCursor = 0;
mScrollDir = 0;
mScrollAccumulator = 0;
mMarqueeOffset = 0; mMarqueeOffset = 0;
mMarqueeTime = -MARQUEE_DELAY; mMarqueeTime = -MARQUEE_DELAY;
@ -246,28 +243,24 @@ bool TextListComponent<T>::input(InputConfig* config, Input input)
{ {
if(config->isMappedTo("down", input)) if(config->isMappedTo("down", input))
{ {
setScrollDir(1); listInput(1);
scroll();
return true; return true;
} }
if(config->isMappedTo("up", input)) if(config->isMappedTo("up", input))
{ {
setScrollDir(-1); listInput(-1);
scroll();
return true; return true;
} }
if(config->isMappedTo("pagedown", input)) if(config->isMappedTo("pagedown", input))
{ {
setScrollDir(10); listInput(10);
scroll();
return true; return true;
} }
if(config->isMappedTo("pageup", input)) if(config->isMappedTo("pageup", input))
{ {
setScrollDir(-10); listInput(-10);
scroll();
return true; return true;
} }
}else{ }else{
@ -282,37 +275,12 @@ bool TextListComponent<T>::input(InputConfig* config, Input input)
return GuiComponent::input(config, input); return GuiComponent::input(config, input);
} }
template <typename T>
void TextListComponent<T>::setScrollDir(int val)
{
mScrollDir = val;
mMarqueeOffset = 0;
mMarqueeTime = -MARQUEE_DELAY;
mScrollAccumulator = -SCROLL_DELAY;
}
template <typename T>
void TextListComponent<T>::stopScrolling()
{
mScrollAccumulator = 0;
mScrollDir = 0;
onCursorChanged(CURSOR_STOPPED);
}
template <typename T> template <typename T>
void TextListComponent<T>::update(int deltaTime) void TextListComponent<T>::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! //if we're not scrolling and this object's text goes outside our size, marquee it!
std::string text = getSelectedName(); std::string text = getSelectedName();
@ -333,32 +301,6 @@ void TextListComponent<T>::update(int deltaTime)
GuiComponent::update(deltaTime); GuiComponent::update(deltaTime);
} }
template <typename T>
void TextListComponent<T>::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 //list management stuff
template <typename T> template <typename T>
void TextListComponent<T>::add(const std::string& name, const T& obj, unsigned int color) void TextListComponent<T>::add(const std::string& name, const T& obj, unsigned int color)
@ -395,7 +337,6 @@ void TextListComponent<T>::clear()
{ {
mRowVector.clear(); mRowVector.clear();
mCursor = 0; mCursor = 0;
mScrollDir = 0;
mMarqueeOffset = 0; mMarqueeOffset = 0;
mMarqueeTime = -MARQUEE_DELAY; mMarqueeTime = -MARQUEE_DELAY;
onCursorChanged(CURSOR_STOPPED); onCursorChanged(CURSOR_STOPPED);
@ -429,10 +370,20 @@ void TextListComponent<T>::setCursor(typename std::vector<ListRow>::const_iterat
template <typename T> template <typename T>
void TextListComponent<T>::onCursorChanged(CursorState state) void TextListComponent<T>::onCursorChanged(CursorState state)
{ {
mMarqueeOffset = 0;
mMarqueeTime = -MARQUEE_DELAY;
if(mCursorChangedCallback) if(mCursorChangedCallback)
mCursorChangedCallback(state); mCursorChangedCallback(state);
} }
template <typename T>
void TextListComponent<T>::stopScrolling()
{
listInput(0);
onCursorChanged(CURSOR_STOPPED);
}
template <typename T> template <typename T>
void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties) void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties)
{ {
@ -480,5 +431,3 @@ void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme, c
} }
} }
} }
#endif