ES-DE/src/components/OptionListComponent.h

268 lines
5.3 KiB
C
Raw Normal View History

2013-10-01 21:52:30 +00:00
#pragma once
#include "../GuiComponent.h"
#include "../resources/Font.h"
2013-10-01 21:52:30 +00:00
#include <vector>
#include <functional>
2013-10-03 20:58:09 +00:00
#include "../Renderer.h"
#include "NinePatchComponent.h"
2013-10-01 21:52:30 +00:00
//Used to display a list of options.
//Can select one or multiple options.
2013-10-03 20:58:09 +00:00
template<typename T>
2013-10-01 21:52:30 +00:00
class OptionListComponent : public GuiComponent
{
public:
OptionListComponent(Window* window, bool multiSelect = false) : GuiComponent(window),
mCursor(0), mScrollOffset(0), mMultiSelect(multiSelect), mEditing(false), mBox(window, ":/textbox.png")
2013-10-03 20:58:09 +00:00
{
2013-10-11 00:55:57 +00:00
setSize(getFont()->sizeText("Not set"));
2013-10-03 20:58:09 +00:00
}
struct ListEntry
{
std::string text;
bool selected;
T object;
};
bool input(InputConfig* config, Input input)
{
if(input.value != 0)
{
if(config->isMappedTo("b", input))
{
close();
return true;
}
if(config->isMappedTo("a", input))
{
if(mEditing)
{
select(mCursor);
if(!mMultiSelect)
close();
}else{
open();
}
2013-10-03 20:58:09 +00:00
return true;
}
if(mEditing && mEntries.size() > 1)
2013-10-03 20:58:09 +00:00
{
if(config->isMappedTo("up", input))
{
if(mCursor > 0)
mCursor--;
return true;
2013-10-03 20:58:09 +00:00
}
if(config->isMappedTo("down", input))
{
if(mCursor < mEntries.size() - 1)
mCursor++;
return true;
2013-10-03 20:58:09 +00:00
}
}
}
return GuiComponent::input(config, input);
}
void render(const Eigen::Affine3f& parentTrans)
{
std::shared_ptr<Font> font = getFont();
//draw the option list
if(mEditing)
2013-10-03 20:58:09 +00:00
{
Eigen::Affine3f trans = parentTrans * getTransform();
unsigned int renderCount = mTextCaches.size() - mScrollOffset;
float height = (float)renderCount * font->getHeight();
trans.translate(Eigen::Vector3f(0, -height / 2 + font->getHeight() * 0.5f, 0));
mBox.fitTo(Eigen::Vector2f(mSize.x(), height));
mBox.render(trans);
2013-10-03 20:58:09 +00:00
Renderer::setMatrix(trans);
Renderer::drawRect(0, 0, (int)getSize().x(), (int)height, 0xFFFFFFFF);
2013-10-03 20:58:09 +00:00
for(unsigned int i = mScrollOffset; i < renderCount; i++)
{
Renderer::setMatrix(trans);
2013-10-03 20:58:09 +00:00
char rectOpacity = 0x00;
if(i == mCursor)
rectOpacity += 0x22;
if(mEntries.at(i).selected)
rectOpacity += 0x44;
Renderer::drawRect(0, 0, (int)mSize.x(), font->getHeight(), 0x00000000 | rectOpacity);
Renderer::setMatrix(trans);
font->renderTextCache(mTextCaches.at(i));
trans = trans.translate(Eigen::Vector3f(0, (float)font->getHeight(), 0));
}
}else{
Renderer::setMatrix(parentTrans * getTransform());
2013-10-01 21:52:30 +00:00
unsigned int color = 0x000000FF;
2013-10-01 21:52:30 +00:00
if(mMultiSelect)
{
//draw "# selected"
unsigned int selectedCount = 0;
for(auto it = mEntries.begin(); it != mEntries.end(); it++)
{
if(it->selected)
selectedCount++;
}
std::stringstream ss;
ss << selectedCount << " selected";
font->drawText(ss.str(), Eigen::Vector2f(0, 0), color);
}else{
//draw selected option
bool found = false;
for(auto it = mEntries.begin(); it != mEntries.end(); it++)
{
if(it->selected)
{
font->drawText(it->text, Eigen::Vector2f(0, 0), color);
found = true;
break;
}
}
if(!found)
font->drawText("Not set", Eigen::Vector2f(0, 0), color);
}
}
renderChildren(parentTrans * getTransform());
2013-10-03 20:58:09 +00:00
}
2013-10-01 21:52:30 +00:00
2013-10-11 00:55:57 +00:00
ListEntry makeEntry(const std::string& name, T obj, bool selected = false) const
2013-10-03 20:58:09 +00:00
{
2013-10-11 00:55:57 +00:00
ListEntry e;
e.text = name;
e.object = obj;
e.selected = selected;
2013-10-03 20:58:09 +00:00
return e;
}
void populate(std::vector<T>& vec, std::function<ListEntry(const T&)> selector)
{
for(auto it = vec.begin(); it != vec.end(); it++)
{
ListEntry e = selector(*it);
if(!e.text.empty())
mEntries.push_back(e);
}
updateTextCaches();
}
void addEntry(ListEntry e)
{
mEntries.push_back(e);
updateTextCaches();
}
std::vector<const ListEntry*> getSelected()
{
std::vector<const ListEntry*> ret;
for(auto it = mEntries.begin(); it != mEntries.end(); it++)
{
if((*it).selected)
ret.push_back(&(*it));
}
return ret;
}
2013-10-11 00:55:57 +00:00
std::vector<T> getSelectedObjects()
{
std::vector<T> ret;
for(auto it = mEntries.begin(); it != mEntries.end(); it++)
{
if((*it).selected)
ret.push_back(it->object);
}
return ret;
}
2013-10-01 21:52:30 +00:00
private:
2013-10-03 20:58:09 +00:00
void select(unsigned int i)
{
if(i >= mEntries.size())
return;
if(!mMultiSelect)
for(auto it = mEntries.begin(); it != mEntries.end(); it++)
it->selected = false;
2013-10-03 20:58:09 +00:00
mEntries.at(i).selected = !mEntries.at(i).selected;
updateTextCaches();
}
void close()
{
mEditing = false;
}
void open()
{
2013-10-11 00:55:57 +00:00
mCursor = 0;
mEditing = true;
2013-10-03 20:58:09 +00:00
}
void updateTextCaches()
{
for(auto it = mTextCaches.begin(); it != mTextCaches.end(); it++)
{
delete *it;
}
mTextCaches.clear();
TextCache* cache;
std::shared_ptr<Font> font = getFont();
Eigen::Vector2f newSize = getSize();
newSize[1] = (float)font->getHeight();
2013-10-03 20:58:09 +00:00
for(unsigned int i = 0; i < mEntries.size(); i++)
{
2013-10-11 00:55:57 +00:00
cache = font->buildTextCache(mEntries.at(i).text, 0, 0, 0x000000FF);
2013-10-03 20:58:09 +00:00
mTextCaches.push_back(cache);
if(cache->metrics.size.x() > newSize.x())
newSize[0] = cache->metrics.size.x();
}
2013-10-03 20:58:09 +00:00
setSize(newSize);
}
std::shared_ptr<Font> getFont()
{
return Font::get(FONT_SIZE_MEDIUM);
2013-10-03 20:58:09 +00:00
}
2013-10-01 21:52:30 +00:00
2013-10-03 20:58:09 +00:00
unsigned int mCursor;
unsigned int mScrollOffset;
bool mMultiSelect;
bool mEditing;
NinePatchComponent mBox;
2013-10-01 21:52:30 +00:00
std::vector<ListEntry> mEntries;
2013-10-03 20:58:09 +00:00
std::vector<TextCache*> mTextCaches;
2013-10-01 21:52:30 +00:00
};