mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-28 17:15:38 +00:00
First IList implementation
This commit is contained in:
parent
5c12395442
commit
7699a4f9be
|
@ -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
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
#include "ThemeDumper.h"
|
||||
|
|
@ -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
81
src/components/IList.cpp
Normal 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
36
src/components/IList.h
Normal 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;
|
||||
};
|
|
@ -1,11 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "../GuiComponent.h"
|
||||
#include "IList.h"
|
||||
#include "../components/ImageComponent.h"
|
||||
#include "../Log.h"
|
||||
|
||||
template<typename T>
|
||||
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<TextureResource> 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<Entry> mEntries;
|
||||
|
@ -112,8 +110,6 @@ ImageGridComponent<T>::ImageGridComponent(Window* window) : GuiComponent(window)
|
|||
{
|
||||
mEntriesDirty = true;
|
||||
mCursor = 0;
|
||||
mScrollDir << 0, 0;
|
||||
mScrollAccumulator = 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -151,7 +147,6 @@ void ImageGridComponent<T>::clear()
|
|||
{
|
||||
mEntries.clear();
|
||||
mCursor = 0;
|
||||
mScrollDir << 0, 0;
|
||||
onCursorChanged(CURSOR_STOPPED);
|
||||
mEntriesDirty = true;
|
||||
}
|
||||
|
@ -183,35 +178,8 @@ void ImageGridComponent<T>::setCursor(typename std::vector<Entry>::const_iterato
|
|||
template<typename T>
|
||||
void ImageGridComponent<T>::stopScrolling()
|
||||
{
|
||||
mScrollDir = Eigen::Vector2i::Zero();
|
||||
}
|
||||
|
||||
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;
|
||||
listInput(0);
|
||||
onCursorChanged(CURSOR_STOPPED);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -231,15 +199,13 @@ bool ImageGridComponent<T>::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<T>::input(InputConfig* config, Input input)
|
|||
template<typename T>
|
||||
void ImageGridComponent<T>::update(int deltaTime)
|
||||
{
|
||||
if(mScrollDir != Eigen::Vector2i::Zero())
|
||||
{
|
||||
mScrollAccumulator += deltaTime;
|
||||
while(mScrollAccumulator >= SCROLL_TIME)
|
||||
{
|
||||
scroll();
|
||||
mScrollAccumulator -= SCROLL_TIME;
|
||||
}
|
||||
}
|
||||
listUpdate(deltaTime);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
|
|
@ -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 <typename T>
|
||||
class TextListComponent : public GuiComponent
|
||||
class TextListComponent : public GuiComponent, public IList
|
||||
{
|
||||
public:
|
||||
TextListComponent(Window* window);
|
||||
|
@ -46,8 +46,7 @@ public:
|
|||
void setCursor(typename std::vector<ListRow>::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>& 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<T>::TextListComponent(Window* window) :
|
|||
GuiComponent(window)
|
||||
{
|
||||
mCursor = 0;
|
||||
mScrollDir = 0;
|
||||
mScrollAccumulator = 0;
|
||||
|
||||
|
||||
mMarqueeOffset = 0;
|
||||
mMarqueeTime = -MARQUEE_DELAY;
|
||||
|
||||
|
@ -246,28 +243,24 @@ bool TextListComponent<T>::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<T>::input(InputConfig* config, Input 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>
|
||||
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!
|
||||
std::string text = getSelectedName();
|
||||
|
||||
|
@ -333,32 +301,6 @@ void TextListComponent<T>::update(int 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
|
||||
template <typename T>
|
||||
void TextListComponent<T>::add(const std::string& name, const T& obj, unsigned int color)
|
||||
|
@ -395,7 +337,6 @@ void TextListComponent<T>::clear()
|
|||
{
|
||||
mRowVector.clear();
|
||||
mCursor = 0;
|
||||
mScrollDir = 0;
|
||||
mMarqueeOffset = 0;
|
||||
mMarqueeTime = -MARQUEE_DELAY;
|
||||
onCursorChanged(CURSOR_STOPPED);
|
||||
|
@ -429,10 +370,20 @@ void TextListComponent<T>::setCursor(typename std::vector<ListRow>::const_iterat
|
|||
template <typename T>
|
||||
void TextListComponent<T>::onCursorChanged(CursorState state)
|
||||
{
|
||||
mMarqueeOffset = 0;
|
||||
mMarqueeTime = -MARQUEE_DELAY;
|
||||
|
||||
if(mCursorChangedCallback)
|
||||
mCursorChangedCallback(state);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void TextListComponent<T>::stopScrolling()
|
||||
{
|
||||
listInput(0);
|
||||
onCursorChanged(CURSOR_STOPPED);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue