2013-06-02 15:08:32 +00:00
|
|
|
#ifndef _TEXTLISTCOMPONENT_H_
|
|
|
|
#define _TEXTLISTCOMPONENT_H_
|
|
|
|
|
|
|
|
#include "../Renderer.h"
|
|
|
|
#include "../Font.h"
|
|
|
|
#include "../GuiComponent.h"
|
|
|
|
#include "../InputManager.h"
|
|
|
|
#include <vector>
|
|
|
|
#include <string>
|
|
|
|
#include <memory>
|
|
|
|
#include "../Sound.h"
|
2013-07-10 11:29:43 +00:00
|
|
|
#include "../Log.h"
|
2013-06-02 15:08:32 +00:00
|
|
|
|
2013-06-15 18:06:52 +00:00
|
|
|
#define MARQUEE_DELAY 900
|
2013-06-02 22:33:49 +00:00
|
|
|
#define MARQUEE_SPEED 16
|
|
|
|
#define MARQUEE_RATE 3
|
|
|
|
|
2013-06-02 15:08:32 +00:00
|
|
|
//A graphical list. Supports multiple colors for rows and scrolling.
|
|
|
|
template <typename T>
|
|
|
|
class TextListComponent : public GuiComponent
|
|
|
|
{
|
|
|
|
public:
|
2013-07-10 11:29:43 +00:00
|
|
|
TextListComponent(Window* window, float offsetX, float offsetY, std::shared_ptr<Font> font);
|
2013-06-02 15:08:32 +00:00
|
|
|
virtual ~TextListComponent();
|
|
|
|
|
2013-07-10 11:29:43 +00:00
|
|
|
bool input(InputConfig* config, Input input) override;
|
|
|
|
void update(int deltaTime) override;
|
|
|
|
void render(const Eigen::Affine3f& parentTrans) override;
|
|
|
|
|
|
|
|
void onPositionChanged() override;
|
2013-06-02 15:08:32 +00:00
|
|
|
|
|
|
|
void addObject(std::string name, T obj, unsigned int color = 0xFF0000);
|
|
|
|
void clear();
|
|
|
|
|
|
|
|
std::string getSelectedName();
|
|
|
|
T getSelectedObject();
|
|
|
|
int getSelection();
|
|
|
|
void stopScrolling();
|
|
|
|
bool isScrolling();
|
|
|
|
|
|
|
|
void setSelectorColor(unsigned int selectorColor);
|
|
|
|
void setSelectedTextColor(unsigned int selectedColor);
|
|
|
|
void setCentered(bool centered);
|
|
|
|
void setScrollSound(std::shared_ptr<Sound> & sound);
|
|
|
|
void setTextOffsetX(int textoffsetx);
|
|
|
|
|
|
|
|
int getObjectCount();
|
|
|
|
T getObject(int i);
|
|
|
|
void setSelection(int i);
|
|
|
|
|
2013-07-03 07:54:55 +00:00
|
|
|
void setFont(std::shared_ptr<Font> f);
|
2013-06-02 15:08:32 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
static const int SCROLLDELAY = 507;
|
|
|
|
static const int SCROLLTIME = 200;
|
|
|
|
|
|
|
|
void scroll(); //helper method, scrolls in whatever direction scrollDir is
|
2013-06-02 22:33:49 +00:00
|
|
|
void setScrollDir(int val); //helper method, set mScrollDir as well as reset marquee stuff
|
2013-06-02 15:08:32 +00:00
|
|
|
|
|
|
|
int mScrollDir, mScrollAccumulator;
|
|
|
|
bool mScrolling;
|
|
|
|
|
2013-06-02 22:33:49 +00:00
|
|
|
int mMarqueeOffset;
|
|
|
|
int mMarqueeTime;
|
|
|
|
|
2013-07-03 07:54:55 +00:00
|
|
|
std::shared_ptr<Font> mFont;
|
2013-06-02 15:08:32 +00:00
|
|
|
unsigned int mSelectorColor, mSelectedTextColorOverride;
|
|
|
|
bool mDrawCentered;
|
|
|
|
|
|
|
|
int mTextOffsetX;
|
|
|
|
|
|
|
|
struct ListRow
|
|
|
|
{
|
|
|
|
std::string name;
|
|
|
|
T object;
|
|
|
|
unsigned int color;
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<ListRow> mRowVector;
|
|
|
|
int mSelection;
|
|
|
|
std::shared_ptr<Sound> mScrollSound;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
2013-07-10 11:29:43 +00:00
|
|
|
TextListComponent<T>::TextListComponent(Window* window, float offsetX, float offsetY, std::shared_ptr<Font> font) : GuiComponent(window)
|
2013-06-02 15:08:32 +00:00
|
|
|
{
|
|
|
|
mSelection = 0;
|
|
|
|
mScrollDir = 0;
|
|
|
|
mScrolling = 0;
|
|
|
|
mScrollAccumulator = 0;
|
|
|
|
|
2013-07-10 11:29:43 +00:00
|
|
|
setPosition(offsetX, offsetY);
|
|
|
|
|
2013-06-02 22:33:49 +00:00
|
|
|
mMarqueeOffset = 0;
|
|
|
|
mMarqueeTime = -MARQUEE_DELAY;
|
2013-06-02 15:08:32 +00:00
|
|
|
mTextOffsetX = 0;
|
|
|
|
|
|
|
|
mFont = font;
|
|
|
|
mSelectorColor = 0x000000FF;
|
|
|
|
mSelectedTextColorOverride = 0;
|
|
|
|
mScrollSound = NULL;
|
|
|
|
mDrawCentered = true;
|
|
|
|
}
|
|
|
|
|
2013-07-10 11:29:43 +00:00
|
|
|
template <typename T>
|
|
|
|
void TextListComponent<T>::onPositionChanged()
|
|
|
|
{
|
|
|
|
setSize(Renderer::getScreenWidth() - getPosition().x(), Renderer::getScreenHeight() - getPosition().y());
|
|
|
|
}
|
|
|
|
|
2013-06-02 15:08:32 +00:00
|
|
|
template <typename T>
|
|
|
|
TextListComponent<T>::~TextListComponent()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2013-07-10 11:29:43 +00:00
|
|
|
void TextListComponent<T>::render(const Eigen::Affine3f& parentTrans)
|
2013-06-02 15:08:32 +00:00
|
|
|
{
|
2013-07-10 11:29:43 +00:00
|
|
|
Eigen::Affine3f trans = parentTrans * getTransform();
|
|
|
|
Renderer::setMatrix(trans);
|
|
|
|
|
2013-06-02 19:34:50 +00:00
|
|
|
const int cutoff = 0;
|
2013-06-02 15:08:32 +00:00
|
|
|
const int entrySize = mFont->getHeight() + 5;
|
|
|
|
|
|
|
|
int startEntry = 0;
|
|
|
|
|
|
|
|
//number of entries that can fit on the screen simultaniously
|
2013-08-23 16:21:00 +00:00
|
|
|
int screenCount = (int)mSize.y() / entrySize;
|
|
|
|
|
2013-06-02 15:08:32 +00:00
|
|
|
if((int)mRowVector.size() >= screenCount)
|
|
|
|
{
|
|
|
|
startEntry = mSelection - (int)(screenCount * 0.5);
|
|
|
|
if(startEntry < 0)
|
|
|
|
startEntry = 0;
|
|
|
|
if(startEntry >= (int)mRowVector.size() - screenCount)
|
|
|
|
startEntry = mRowVector.size() - screenCount;
|
|
|
|
}
|
|
|
|
|
2013-07-10 11:29:43 +00:00
|
|
|
float y = (float)cutoff;
|
2013-06-02 15:08:32 +00:00
|
|
|
|
|
|
|
if(mRowVector.size() == 0)
|
|
|
|
{
|
2013-07-03 07:54:55 +00:00
|
|
|
mFont->drawCenteredText("The list is empty.", 0, y, 0xFF0000FF);
|
2013-06-02 15:08:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int listCutoff = startEntry + screenCount;
|
|
|
|
if(listCutoff > (int)mRowVector.size())
|
|
|
|
listCutoff = mRowVector.size();
|
|
|
|
|
2013-08-06 13:15:20 +00:00
|
|
|
Eigen::Vector3f dim(getSize().x(), getSize().y(), 0);
|
|
|
|
dim = trans * dim - trans.translation();
|
|
|
|
Renderer::pushClipRect(Eigen::Vector2i((int)trans.translation().x(), (int)trans.translation().y()), Eigen::Vector2i((int)dim.x(), (int)dim.y()));
|
|
|
|
|
|
|
|
//Renderer::pushClipRect(pos, dim);
|
|
|
|
//Renderer::pushClipRect(Eigen::Vector2i((int)trans.translation().x(), (int)trans.translation().y()), Eigen::Vector2i((int)getSize().x() * trans., (int)getSize().y() * trans.scale().y()));
|
2013-07-10 11:29:43 +00:00
|
|
|
//Renderer::pushClipRect(getGlobalOffset(), getSize());
|
2013-06-14 15:48:13 +00:00
|
|
|
|
2013-06-02 15:08:32 +00:00
|
|
|
for(int i = startEntry; i < listCutoff; i++)
|
|
|
|
{
|
|
|
|
//draw selector bar
|
|
|
|
if(mSelection == i)
|
|
|
|
{
|
2013-07-10 11:29:43 +00:00
|
|
|
Renderer::drawRect(0, (int)y, (int)getSize().x(), mFont->getHeight(), mSelectorColor);
|
2013-06-02 15:08:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ListRow row = mRowVector.at((unsigned int)i);
|
|
|
|
|
2013-07-10 11:29:43 +00:00
|
|
|
float x = (float)mTextOffsetX - (mSelection == i ? mMarqueeOffset : 0);
|
2013-06-02 22:33:49 +00:00
|
|
|
unsigned int color = (mSelection == i && mSelectedTextColorOverride != 0) ? mSelectedTextColorOverride : row.color;
|
|
|
|
|
2013-06-02 15:08:32 +00:00
|
|
|
if(mDrawCentered)
|
2013-07-03 07:54:55 +00:00
|
|
|
mFont->drawCenteredText(row.name, x, y, color);
|
2013-06-02 15:08:32 +00:00
|
|
|
else
|
2013-07-10 11:29:43 +00:00
|
|
|
mFont->drawText(row.name, Eigen::Vector2f(x, y), color);
|
2013-06-02 22:33:49 +00:00
|
|
|
|
2013-06-02 15:08:32 +00:00
|
|
|
y += entrySize;
|
|
|
|
}
|
2013-06-02 19:34:50 +00:00
|
|
|
|
2013-06-14 15:48:13 +00:00
|
|
|
Renderer::popClipRect();
|
|
|
|
|
2013-07-10 11:29:43 +00:00
|
|
|
GuiComponent::renderChildren(trans);
|
2013-06-02 15:08:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
bool TextListComponent<T>::input(InputConfig* config, Input input)
|
|
|
|
{
|
|
|
|
if(mRowVector.size() > 0)
|
|
|
|
{
|
|
|
|
if(input.value != 0)
|
|
|
|
{
|
|
|
|
if(config->isMappedTo("down", input))
|
|
|
|
{
|
2013-06-02 22:33:49 +00:00
|
|
|
setScrollDir(1);
|
2013-06-02 15:08:32 +00:00
|
|
|
scroll();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(config->isMappedTo("up", input))
|
|
|
|
{
|
2013-06-02 22:33:49 +00:00
|
|
|
setScrollDir(-1);
|
2013-06-02 15:08:32 +00:00
|
|
|
scroll();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if(config->isMappedTo("pagedown", input))
|
|
|
|
{
|
2013-06-02 22:33:49 +00:00
|
|
|
setScrollDir(10);
|
2013-06-02 15:08:32 +00:00
|
|
|
scroll();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(config->isMappedTo("pageup", input))
|
|
|
|
{
|
2013-06-02 22:33:49 +00:00
|
|
|
setScrollDir(-10);
|
2013-06-02 15:08:32 +00:00
|
|
|
scroll();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
if(config->isMappedTo("down", input) || config->isMappedTo("up", input) || config->isMappedTo("pagedown", input) || config->isMappedTo("pageup", input))
|
|
|
|
{
|
|
|
|
stopScrolling();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-02 19:34:50 +00:00
|
|
|
return GuiComponent::input(config, input);
|
2013-06-02 15:08:32 +00:00
|
|
|
}
|
|
|
|
|
2013-06-02 22:33:49 +00:00
|
|
|
template <typename T>
|
|
|
|
void TextListComponent<T>::setScrollDir(int val)
|
|
|
|
{
|
|
|
|
mScrollDir = val;
|
|
|
|
mMarqueeOffset = 0;
|
|
|
|
mMarqueeTime = -MARQUEE_DELAY;
|
|
|
|
}
|
|
|
|
|
2013-06-02 15:08:32 +00:00
|
|
|
template <typename T>
|
|
|
|
void TextListComponent<T>::stopScrolling()
|
|
|
|
{
|
|
|
|
mScrollAccumulator = 0;
|
|
|
|
mScrolling = false;
|
|
|
|
mScrollDir = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void TextListComponent<T>::update(int deltaTime)
|
|
|
|
{
|
|
|
|
if(mScrollDir != 0)
|
|
|
|
{
|
|
|
|
mScrollAccumulator += deltaTime;
|
|
|
|
|
|
|
|
if(!mScrolling)
|
|
|
|
{
|
|
|
|
if(mScrollAccumulator >= SCROLLDELAY)
|
|
|
|
{
|
|
|
|
mScrollAccumulator = SCROLLTIME;
|
|
|
|
mScrolling = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(mScrolling)
|
|
|
|
{
|
|
|
|
mScrollAccumulator += deltaTime;
|
|
|
|
|
|
|
|
while(mScrollAccumulator >= SCROLLTIME)
|
|
|
|
{
|
|
|
|
mScrollAccumulator -= SCROLLTIME;
|
|
|
|
|
|
|
|
scroll();
|
|
|
|
}
|
|
|
|
}
|
2013-06-02 22:33:49 +00:00
|
|
|
}else{
|
|
|
|
//if we're not scrolling and this object's text goes outside our size, marquee it!
|
|
|
|
std::string text = getSelectedName();
|
2013-07-10 11:29:43 +00:00
|
|
|
|
|
|
|
Eigen::Vector2f textSize = mFont->sizeText(text);
|
2013-06-02 22:33:49 +00:00
|
|
|
|
|
|
|
//it's long enough to marquee
|
2013-07-10 11:29:43 +00:00
|
|
|
if(textSize.x() - mMarqueeOffset > getSize().x() - 12)
|
2013-06-02 22:33:49 +00:00
|
|
|
{
|
|
|
|
mMarqueeTime += deltaTime;
|
|
|
|
while(mMarqueeTime > MARQUEE_SPEED)
|
|
|
|
{
|
|
|
|
mMarqueeOffset += MARQUEE_RATE;
|
|
|
|
mMarqueeTime -= MARQUEE_SPEED;
|
|
|
|
}
|
|
|
|
}
|
2013-06-02 15:08:32 +00:00
|
|
|
}
|
2013-06-02 19:34:50 +00:00
|
|
|
|
|
|
|
GuiComponent::update(deltaTime);
|
2013-06-02 15:08:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void TextListComponent<T>::scroll()
|
|
|
|
{
|
|
|
|
mSelection += mScrollDir;
|
|
|
|
|
|
|
|
if(mSelection < 0)
|
|
|
|
{
|
|
|
|
if(mScrollDir < -1)
|
|
|
|
mSelection = 0;
|
|
|
|
else
|
|
|
|
mSelection += mRowVector.size();
|
|
|
|
}
|
|
|
|
if(mSelection >= (int)mRowVector.size())
|
|
|
|
{
|
|
|
|
if(mScrollDir > 1)
|
|
|
|
mSelection = (int)mRowVector.size() - 1;
|
|
|
|
else
|
|
|
|
mSelection -= mRowVector.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(mScrollSound)
|
|
|
|
mScrollSound->play();
|
|
|
|
}
|
|
|
|
|
|
|
|
//list management stuff
|
|
|
|
template <typename T>
|
|
|
|
void TextListComponent<T>::addObject(std::string name, T obj, unsigned int color)
|
|
|
|
{
|
|
|
|
ListRow row = {name, obj, color};
|
|
|
|
mRowVector.push_back(row);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void TextListComponent<T>::clear()
|
|
|
|
{
|
|
|
|
mRowVector.clear();
|
|
|
|
mSelection = 0;
|
2013-06-15 18:06:52 +00:00
|
|
|
mMarqueeOffset = 0;
|
|
|
|
mMarqueeTime = -MARQUEE_DELAY;
|
2013-06-02 15:08:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
std::string TextListComponent<T>::getSelectedName()
|
|
|
|
{
|
|
|
|
if((int)mRowVector.size() > mSelection)
|
|
|
|
return mRowVector.at(mSelection).name;
|
|
|
|
else
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
T TextListComponent<T>::getSelectedObject()
|
|
|
|
{
|
|
|
|
if((int)mRowVector.size() > mSelection)
|
|
|
|
return mRowVector.at(mSelection).object;
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
int TextListComponent<T>::getSelection()
|
|
|
|
{
|
|
|
|
return mSelection;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
bool TextListComponent<T>::isScrolling()
|
|
|
|
{
|
|
|
|
return mScrollDir != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void TextListComponent<T>::setSelectorColor(unsigned int selectorColor)
|
|
|
|
{
|
|
|
|
mSelectorColor = selectorColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void TextListComponent<T>::setSelectedTextColor(unsigned int selectedColor)
|
|
|
|
{
|
|
|
|
mSelectedTextColorOverride = selectedColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
void TextListComponent<T>::setCentered(bool centered)
|
|
|
|
{
|
|
|
|
mDrawCentered = centered;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
void TextListComponent<T>::setTextOffsetX(int textoffsetx)
|
|
|
|
{
|
|
|
|
mTextOffsetX = textoffsetx;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
int TextListComponent<T>::getObjectCount()
|
|
|
|
{
|
|
|
|
return mRowVector.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
T TextListComponent<T>::getObject(int i)
|
|
|
|
{
|
|
|
|
return mRowVector.at(i).object;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void TextListComponent<T>::setSelection(int i)
|
|
|
|
{
|
|
|
|
mSelection = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void TextListComponent<T>::setScrollSound(std::shared_ptr<Sound> & sound)
|
|
|
|
{
|
|
|
|
mScrollSound = sound;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2013-07-03 07:54:55 +00:00
|
|
|
void TextListComponent<T>::setFont(std::shared_ptr<Font> font)
|
2013-06-02 15:08:32 +00:00
|
|
|
{
|
|
|
|
mFont = font;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|