mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-28 17:15:38 +00:00
Completely rewrote ComponentGrid to use shared pointers, have support for
borders, work better with nested components, and generally suck less. Split the scraper screen into a "ScraperSearchComponent" so it can be reused in other menus (what could this possibly mean for the future?!). Re-designed the ScraperSearchComponent to fit UI concepts. Added the ability to put a row of buttons at the bottom of a MenuComponent. Redid GuiMetaDataEd to use a MenuComponent instead of ComponentGrid. Redid GuiGameScraper to use a ComponentGrid containing a ScraperSearchComponent. Fixed Renderer::pushClipRect not clipping new rects to be within the bounds of the existing clipRect stack. A ton of little fixes that I forgot to mention. It's a good thing I'm the only developer currently, or I would have to actually break this into multiple commits.
This commit is contained in:
parent
0626f61905
commit
bbb8aeeac3
|
@ -172,6 +172,7 @@ set(ES_HEADERS
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/NinePatchComponent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/NinePatchComponent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/OptionListComponent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/OptionListComponent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/RatingComponent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/RatingComponent.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ScraperSearchComponent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ScrollableContainer.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ScrollableContainer.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SliderComponent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SliderComponent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SwitchComponent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SwitchComponent.h
|
||||||
|
@ -252,6 +253,7 @@ set(ES_SOURCES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/MenuComponent.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/MenuComponent.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
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ScraperSearchComponent.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ScrollableContainer.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ScrollableContainer.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SliderComponent.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SliderComponent.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SwitchComponent.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SwitchComponent.cpp
|
||||||
|
|
|
@ -133,51 +133,33 @@ boost::posix_time::ptime MetaDataList::getTime(const std::string& key) const
|
||||||
return string_to_ptime(get(key), "%Y%m%dT%H%M%S%F%q");
|
return string_to_ptime(get(key), "%Y%m%dT%H%M%S%F%q");
|
||||||
}
|
}
|
||||||
|
|
||||||
GuiComponent* MetaDataList::makeDisplay(Window* window, MetaDataType as)
|
std::shared_ptr<GuiComponent> MetaDataList::makeEditor(Window* window, MetaDataType as)
|
||||||
{
|
{
|
||||||
switch(as)
|
switch(as)
|
||||||
{
|
{
|
||||||
case MD_RATING:
|
case MD_RATING:
|
||||||
{
|
{
|
||||||
RatingComponent* comp = new RatingComponent(window);
|
return std::make_shared<RatingComponent>(window);
|
||||||
return comp;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
TextComponent* comp = new TextComponent(window);
|
|
||||||
return comp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GuiComponent* MetaDataList::makeEditor(Window* window, MetaDataType as)
|
|
||||||
{
|
|
||||||
switch(as)
|
|
||||||
{
|
|
||||||
case MD_RATING:
|
|
||||||
{
|
|
||||||
RatingComponent* comp = new RatingComponent(window);
|
|
||||||
return comp;
|
|
||||||
}
|
}
|
||||||
case MD_MULTILINE_STRING:
|
case MD_MULTILINE_STRING:
|
||||||
{
|
{
|
||||||
TextEditComponent* comp = new TextEditComponent(window);
|
auto comp = std::make_shared<TextEditComponent>(window);
|
||||||
comp->setSize(comp->getSize().x(), comp->getSize().y() * 3);
|
comp->setSize(comp->getSize().x(), comp->getSize().y() * 3);
|
||||||
return comp;
|
return comp;
|
||||||
}
|
}
|
||||||
case MD_DATE:
|
case MD_DATE:
|
||||||
{
|
{
|
||||||
DateTimeComponent* comp = new DateTimeComponent(window);
|
return std::make_shared<DateTimeComponent>(window);
|
||||||
return comp;
|
|
||||||
}
|
}
|
||||||
case MD_TIME:
|
case MD_TIME:
|
||||||
{
|
{
|
||||||
DateTimeComponent* comp = new DateTimeComponent(window);
|
auto comp = std::make_shared<DateTimeComponent>(window);
|
||||||
comp->setDisplayMode(DateTimeComponent::DISP_RELATIVE_TO_NOW);
|
comp->setDisplayMode(DateTimeComponent::DISP_RELATIVE_TO_NOW);
|
||||||
return comp;
|
return comp;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
TextEditComponent* comp = new TextEditComponent(window);
|
return std::make_shared<TextEditComponent>(window);
|
||||||
return comp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,8 +55,7 @@ public:
|
||||||
float getFloat(const std::string& key) const;
|
float getFloat(const std::string& key) const;
|
||||||
boost::posix_time::ptime getTime(const std::string& key) const;
|
boost::posix_time::ptime getTime(const std::string& key) const;
|
||||||
|
|
||||||
static GuiComponent* makeDisplay(Window* window, MetaDataType as);
|
static std::shared_ptr<GuiComponent> makeEditor(Window* window, MetaDataType as);
|
||||||
static GuiComponent* makeEditor(Window* window, MetaDataType as);
|
|
||||||
|
|
||||||
inline MetaDataListType getType() const { return mType; }
|
inline MetaDataListType getType() const { return mType; }
|
||||||
inline const std::vector<MetaDataDecl>& getMDD() const { return getMDDByType(getType()); }
|
inline const std::vector<MetaDataDecl>& getMDD() const { return getMDDByType(getType()); }
|
||||||
|
|
|
@ -39,14 +39,31 @@ namespace Renderer {
|
||||||
if(box[3] == 0)
|
if(box[3] == 0)
|
||||||
box[3] = Renderer::getScreenHeight() - box.y();
|
box[3] = Renderer::getScreenHeight() - box.y();
|
||||||
|
|
||||||
//TODO - make sure the box fits within clipStack.top(), and clip further accordingly!
|
|
||||||
|
|
||||||
//glScissor starts at the bottom left of the window
|
//glScissor starts at the bottom left of the window
|
||||||
//so (0, 0, 1, 1) is the bottom left pixel
|
//so (0, 0, 1, 1) is the bottom left pixel
|
||||||
//everything else uses y+ = down, so flip it to be consistent
|
//everything else uses y+ = down, so flip it to be consistent
|
||||||
//rect.pos.y = Renderer::getScreenHeight() - rect.pos.y - rect.size.y;
|
//rect.pos.y = Renderer::getScreenHeight() - rect.pos.y - rect.size.y;
|
||||||
box[1] = Renderer::getScreenHeight() - box.y() - box[3];
|
box[1] = Renderer::getScreenHeight() - box.y() - box[3];
|
||||||
|
|
||||||
|
//make sure the box fits within clipStack.top(), and clip further accordingly
|
||||||
|
if(clipStack.size())
|
||||||
|
{
|
||||||
|
Eigen::Vector4i& top = clipStack.top();
|
||||||
|
if(top[0] > box[0])
|
||||||
|
box[0] = top[0];
|
||||||
|
if(top[1] > box[1])
|
||||||
|
box[1] = top[1];
|
||||||
|
if(top[0] + top[2] < box[0] + box[2])
|
||||||
|
box[2] = (top[0] + top[2]) - box[0];
|
||||||
|
if(top[1] + top[3] < box[1] + box[3])
|
||||||
|
box[3] = (top[1] + top[3]) - box[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(box[2] < 0)
|
||||||
|
box[2] = 0;
|
||||||
|
if(box[3] < 0)
|
||||||
|
box[3] = 0;
|
||||||
|
|
||||||
clipStack.push(box);
|
clipStack.push(box);
|
||||||
glScissor(box[0], box[1], box[2], box[3]);
|
glScissor(box[0], box[1], box[2], box[3]);
|
||||||
glEnable(GL_SCISSOR_TEST);
|
glEnable(GL_SCISSOR_TEST);
|
||||||
|
|
|
@ -2,12 +2,14 @@
|
||||||
#include "../Renderer.h"
|
#include "../Renderer.h"
|
||||||
#include "../Window.h"
|
#include "../Window.h"
|
||||||
|
|
||||||
ButtonComponent::ButtonComponent(Window* window) : GuiComponent(window),
|
ButtonComponent::ButtonComponent(Window* window, const std::string& text, const std::string& helpText, const std::function<void()>& func) : GuiComponent(window),
|
||||||
mBox(window, ":/button.png"),
|
mBox(window, ":/button.png"),
|
||||||
mFocused(false),
|
mFocused(false),
|
||||||
|
mEnabled(true),
|
||||||
mTextColorFocused(0xFFFFFFFF), mTextColorUnfocused(0x777777FF)
|
mTextColorFocused(0xFFFFFFFF), mTextColorUnfocused(0x777777FF)
|
||||||
{
|
{
|
||||||
setSize(64, 48);
|
setPressedFunc(func);
|
||||||
|
setText(text, helpText);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ButtonComponent::onSizeChanged()
|
void ButtonComponent::onSizeChanged()
|
||||||
|
@ -24,7 +26,7 @@ bool ButtonComponent::input(InputConfig* config, Input input)
|
||||||
{
|
{
|
||||||
if(config->isMappedTo("a", input) && input.value != 0)
|
if(config->isMappedTo("a", input) && input.value != 0)
|
||||||
{
|
{
|
||||||
if(mPressedFunc)
|
if(mPressedFunc && mEnabled)
|
||||||
mPressedFunc();
|
mPressedFunc();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -48,13 +50,34 @@ void ButtonComponent::setText(const std::string& text, const std::string& helpTe
|
||||||
void ButtonComponent::onFocusGained()
|
void ButtonComponent::onFocusGained()
|
||||||
{
|
{
|
||||||
mFocused = true;
|
mFocused = true;
|
||||||
mBox.setImagePath(":/button_filled.png");
|
updateImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ButtonComponent::onFocusLost()
|
void ButtonComponent::onFocusLost()
|
||||||
{
|
{
|
||||||
mFocused = false;
|
mFocused = false;
|
||||||
|
updateImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ButtonComponent::setEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
mEnabled = enabled;
|
||||||
|
updateImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ButtonComponent::updateImage()
|
||||||
|
{
|
||||||
|
if(!mEnabled || !mPressedFunc)
|
||||||
|
{
|
||||||
mBox.setImagePath(":/button.png");
|
mBox.setImagePath(":/button.png");
|
||||||
|
mBox.setCenterColor(0x770000FF);
|
||||||
|
mBox.setEdgeColor(0x770000FF);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mBox.setCenterColor(0xFFFFFFFF);
|
||||||
|
mBox.setEdgeColor(0xFFFFFFFF);
|
||||||
|
mBox.setImagePath(mFocused ? ":/button_filled.png" : ":/button.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ButtonComponent::render(const Eigen::Affine3f& parentTrans)
|
void ButtonComponent::render(const Eigen::Affine3f& parentTrans)
|
||||||
|
|
|
@ -8,10 +8,12 @@
|
||||||
class ButtonComponent : public GuiComponent
|
class ButtonComponent : public GuiComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ButtonComponent(Window* window);
|
ButtonComponent(Window* window, const std::string& text = "", const std::string& helpText = "", const std::function<void()>& func = nullptr);
|
||||||
|
|
||||||
void setPressedFunc(std::function<void()> f);
|
void setPressedFunc(std::function<void()> f);
|
||||||
|
|
||||||
|
void setEnabled(bool enable);
|
||||||
|
|
||||||
bool input(InputConfig* config, Input input) override;
|
bool input(InputConfig* config, Input input) override;
|
||||||
void render(const Eigen::Affine3f& parentTrans) override;
|
void render(const Eigen::Affine3f& parentTrans) override;
|
||||||
|
|
||||||
|
@ -28,10 +30,12 @@ private:
|
||||||
std::function<void()> mPressedFunc;
|
std::function<void()> mPressedFunc;
|
||||||
|
|
||||||
bool mFocused;
|
bool mFocused;
|
||||||
|
bool mEnabled;
|
||||||
unsigned int mTextColorFocused;
|
unsigned int mTextColorFocused;
|
||||||
unsigned int mTextColorUnfocused;
|
unsigned int mTextColorUnfocused;
|
||||||
|
|
||||||
unsigned int getCurTextColor() const;
|
unsigned int getCurTextColor() const;
|
||||||
|
void updateImage();
|
||||||
|
|
||||||
std::string mText;
|
std::string mText;
|
||||||
std::string mHelpText;
|
std::string mHelpText;
|
||||||
|
|
|
@ -2,281 +2,219 @@
|
||||||
#include "../Log.h"
|
#include "../Log.h"
|
||||||
#include "../Renderer.h"
|
#include "../Renderer.h"
|
||||||
|
|
||||||
#define INITIAL_CELL_SIZE 12
|
using namespace GridFlags;
|
||||||
|
|
||||||
ComponentGrid::ComponentGrid(Window* window, Eigen::Vector2i gridDimensions) : GuiComponent(window),
|
ComponentGrid::ComponentGrid(Window* window, const Eigen::Vector2i& gridDimensions) : GuiComponent(window),
|
||||||
mGrid(NULL), mColumnWidths(NULL), mRowHeights(NULL),
|
mGridSize(gridDimensions), mCursor(0, 0)
|
||||||
mColumnWidthForced(NULL), mRowHeightForced(NULL),
|
|
||||||
mCursor(-1, -1)
|
|
||||||
{
|
{
|
||||||
mEntries.reserve(gridDimensions.x() * gridDimensions.y());
|
assert(gridDimensions.x() > 0 && gridDimensions.y() > 0);
|
||||||
makeCells(gridDimensions);
|
|
||||||
|
mCells.reserve(gridDimensions.x() * gridDimensions.y());
|
||||||
|
|
||||||
|
mColWidths = new float[gridDimensions.x()];
|
||||||
|
mRowHeights = new float[gridDimensions.y()];
|
||||||
|
for(int x = 0; x < gridDimensions.x(); x++)
|
||||||
|
mColWidths[x] = 0;
|
||||||
|
for(int y = 0; y < gridDimensions.y(); y++)
|
||||||
|
mRowHeights[y] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ComponentGrid::~ComponentGrid()
|
ComponentGrid::~ComponentGrid()
|
||||||
{
|
{
|
||||||
for(auto iter = mEntries.begin(); iter != mEntries.end(); iter++)
|
|
||||||
{
|
|
||||||
delete *iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ComponentGrid::makeCells(Eigen::Vector2i size)
|
|
||||||
{
|
|
||||||
if(mGrid)
|
|
||||||
delete[] mGrid;
|
|
||||||
if(mColumnWidths)
|
|
||||||
delete[] mColumnWidths;
|
|
||||||
if(mRowHeights)
|
|
||||||
delete[] mRowHeights;
|
delete[] mRowHeights;
|
||||||
|
delete[] mColWidths;
|
||||||
mGridSize = size;
|
|
||||||
mGrid = new ComponentEntry*[size.x() * size.y()];
|
|
||||||
std::fill(mGrid, mGrid + (size.x() * size.y()), (ComponentEntry*)NULL);
|
|
||||||
|
|
||||||
mColumnWidths = new unsigned int[size.x()];
|
|
||||||
std::fill(mColumnWidths, mColumnWidths + size.x(), INITIAL_CELL_SIZE);
|
|
||||||
|
|
||||||
mRowHeights = new unsigned int[size.y()];
|
|
||||||
std::fill(mRowHeights, mRowHeights + size.y(), INITIAL_CELL_SIZE);
|
|
||||||
|
|
||||||
mColumnWidthForced = new bool[size.x()];
|
|
||||||
std::fill(mColumnWidthForced, mColumnWidthForced + size.x(), false);
|
|
||||||
|
|
||||||
mRowHeightForced = new bool[size.y()];
|
|
||||||
std::fill(mRowHeightForced, mRowHeightForced + size.y(), false);
|
|
||||||
|
|
||||||
updateSize();
|
|
||||||
resetCursor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComponentGrid::setEntry(Eigen::Vector2i pos, Eigen::Vector2i size, GuiComponent* component, bool canFocus, AlignmentType align,
|
float ComponentGrid::getColWidth(int col)
|
||||||
Eigen::Matrix<bool, 1, 2> autoFit, UpdateBehavior updateType)
|
|
||||||
{
|
{
|
||||||
if(pos.x() > mGridSize.x() || pos.y() > mGridSize.y() || pos.x() < 0 || pos.y() < 0)
|
if(mColWidths[col] != 0)
|
||||||
|
return mColWidths[col] * mSize.x();
|
||||||
|
|
||||||
|
// calculate automatic width
|
||||||
|
float freeWidthPerc = 1;
|
||||||
|
int between = 0;
|
||||||
|
for(int x = 0; x < mGridSize.x(); x++)
|
||||||
{
|
{
|
||||||
LOG(LogError) << "Tried to set entry beyond grid size!";
|
freeWidthPerc -= mColWidths[x]; // if it's 0 it won't do anything
|
||||||
return;
|
if(mColWidths[x] == 0)
|
||||||
|
between++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(component == NULL)
|
return (freeWidthPerc * mSize.x()) / between;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ComponentGrid::getRowHeight(int row)
|
||||||
|
{
|
||||||
|
if(mRowHeights[row] != 0)
|
||||||
|
return mRowHeights[row] * mSize.y();
|
||||||
|
|
||||||
|
// calculate automatic height
|
||||||
|
float freeHeightPerc = 1;
|
||||||
|
int between = 0;
|
||||||
|
for(int y = 0; y < mGridSize.y(); y++)
|
||||||
{
|
{
|
||||||
LOG(LogError) << "Tried to add NULL component to ComponentList!";
|
freeHeightPerc -= mRowHeights[y]; // if it's 0 it won't do anything
|
||||||
return;
|
if(mRowHeights[y] == 0)
|
||||||
|
between++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ComponentEntry* entry = new ComponentEntry(Eigen::Vector2i(pos.x(), pos.y()), Eigen::Vector2i(size.x(), size.y()), component, updateType, canFocus, align);
|
return (freeHeightPerc * mSize.y()) / between;
|
||||||
|
}
|
||||||
|
|
||||||
mEntries.push_back(entry);
|
void ComponentGrid::setColWidthPerc(int col, float width)
|
||||||
|
{
|
||||||
|
assert(col >= 0 && col < mGridSize.x());
|
||||||
|
mColWidths[col] = width;
|
||||||
|
onSizeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
for(int y = pos.y(); y < pos.y() + size.y(); y++)
|
void ComponentGrid::setRowHeightPerc(int row, float height)
|
||||||
{
|
{
|
||||||
for(int x = pos.x(); x < pos.x() + size.x(); x++)
|
assert(row >= 0 && row < mGridSize.y());
|
||||||
{
|
mRowHeights[row] = height;
|
||||||
setCell(x, y, mEntries.back());
|
onSizeChanged();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(component->getParent() != NULL)
|
void ComponentGrid::setEntry(const std::shared_ptr<GuiComponent>& comp, const Eigen::Vector2i& pos, bool canFocus, bool resize, const Eigen::Vector2i& size,
|
||||||
LOG(LogError) << "ComponentGrid ruining an existing parent-child relationship! Call a social worker!";
|
unsigned int border, GridFlags::UpdateType updateType)
|
||||||
component->setParent(this);
|
{
|
||||||
|
assert(pos.x() >= 0 && pos.x() < mGridSize.x() && pos.y() >= 0 && pos.y() < mGridSize.y());
|
||||||
|
assert(comp != nullptr);
|
||||||
|
assert(comp->getParent() == NULL);
|
||||||
|
|
||||||
|
GridEntry entry(pos, size, comp, canFocus, resize, updateType, border);
|
||||||
|
mCells.push_back(entry);
|
||||||
|
|
||||||
|
addChild(comp.get());
|
||||||
|
|
||||||
if(!cursorValid() && canFocus)
|
if(!cursorValid() && canFocus)
|
||||||
mCursor = pos;
|
mCursor = pos;
|
||||||
|
|
||||||
//update the column width and row height
|
updateCellComponent(mCells.back());
|
||||||
//if(autoFit.x() && (int)getColumnWidth(pos.x()) < component->getSize().x())
|
updateSeparators();
|
||||||
// setColumnWidth(pos.x(), (unsigned int)component->getSize().x());
|
|
||||||
//if(autoFit.y() && (int)getRowHeight(pos.y()) < component->getSize().y())
|
|
||||||
// setRowHeight(pos.y(), (unsigned int)component->getSize().y());
|
|
||||||
updateCellSize(mEntries.back(), autoFit.x(), autoFit.y());
|
|
||||||
|
|
||||||
component->setPosition(getCellOffset(pos));
|
|
||||||
|
|
||||||
updateSize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComponentGrid::removeEntriesIn(Eigen::Vector2i pos, Eigen::Vector2i size)
|
bool ComponentGrid::removeEntry(const std::shared_ptr<GuiComponent>& comp)
|
||||||
{
|
{
|
||||||
auto iter = mEntries.begin();
|
for(auto it = mCells.begin(); it != mCells.end(); it++)
|
||||||
while(iter != mEntries.end())
|
|
||||||
{
|
{
|
||||||
if((*iter)->pos.x() >= pos.x() && (*iter)->pos.x() < pos.x() + size.x()
|
if(it->component == comp)
|
||||||
&& (*iter)->pos.y() >= pos.y() && (*iter)->pos.y() < pos.y() + size.y())
|
|
||||||
{
|
{
|
||||||
if((*iter)->component->getParent() == this)
|
removeChild(comp.get());
|
||||||
(*iter)->component->setParent(NULL);
|
mCells.erase(it);
|
||||||
|
return true;
|
||||||
delete *iter;
|
|
||||||
iter = mEntries.erase(iter);
|
|
||||||
}else{
|
|
||||||
iter++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int y = pos.y(); y < pos.y() + size.y(); y++)
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComponentGrid::updateCellComponent(const GridEntry& cell)
|
||||||
|
{
|
||||||
|
// size
|
||||||
|
Eigen::Vector2f size(0, 0);
|
||||||
|
for(int x = cell.pos.x(); x < cell.pos.x() + cell.dim.x(); x++)
|
||||||
|
size[0] += getColWidth(x);
|
||||||
|
for(int y = cell.pos.y(); y < cell.pos.y() + cell.dim.y(); y++)
|
||||||
|
size[1] += getRowHeight(y);
|
||||||
|
|
||||||
|
if(cell.resize)
|
||||||
|
cell.component->setSize(size);
|
||||||
|
|
||||||
|
// position
|
||||||
|
// find top left corner
|
||||||
|
Eigen::Vector3f pos(0, 0, 0);
|
||||||
|
for(int x = 0; x < cell.pos.x(); x++)
|
||||||
|
pos[0] += getColWidth(x);
|
||||||
|
for(int y = 0; y < cell.pos.y(); y++)
|
||||||
|
pos[1] += getRowHeight(y);
|
||||||
|
|
||||||
|
// center component
|
||||||
|
pos[0] = pos.x() + (size.x() - cell.component->getSize().x()) / 2;
|
||||||
|
pos[1] = pos.y() + (size.y() - cell.component->getSize().y()) / 2;
|
||||||
|
|
||||||
|
cell.component->setPosition(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComponentGrid::updateSeparators()
|
||||||
|
{
|
||||||
|
mLines.clear();
|
||||||
|
|
||||||
|
Eigen::Vector2f pos;
|
||||||
|
Eigen::Vector2f size;
|
||||||
|
for(auto it = mCells.begin(); it != mCells.end(); it++)
|
||||||
{
|
{
|
||||||
for(int x = pos.x(); x < pos.x() + size.x(); x++)
|
if(!it->border)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// find component position + size
|
||||||
|
pos << 0, 0;
|
||||||
|
size << 0, 0;
|
||||||
|
for(int x = 0; x < it->pos.x(); x++)
|
||||||
|
pos[0] += getColWidth(x);
|
||||||
|
for(int y = 0; y < it->pos.y(); y++)
|
||||||
|
pos[1] += getRowHeight(y);
|
||||||
|
for(int x = it->pos.x(); x < it->pos.x() + it->dim.x(); x++)
|
||||||
|
size[0] += getColWidth(x);
|
||||||
|
for(int y = it->pos.y(); y < it->pos.y() + it->dim.y(); y++)
|
||||||
|
size[1] += getRowHeight(y);
|
||||||
|
|
||||||
|
if(it->border & BORDER_TOP)
|
||||||
{
|
{
|
||||||
setCell(x, y, NULL);
|
mLines.push_back(Vert(pos.x(), pos.y()));
|
||||||
|
mLines.push_back(Vert(pos.x() + size.x(), pos.y()));
|
||||||
|
}
|
||||||
|
if(it->border & BORDER_BOTTOM)
|
||||||
|
{
|
||||||
|
mLines.push_back(Vert(pos.x(), pos.y() + size.y()));
|
||||||
|
mLines.push_back(Vert(pos.x() + size.x(), mLines.back().y));
|
||||||
|
}
|
||||||
|
if(it->border & BORDER_LEFT)
|
||||||
|
{
|
||||||
|
mLines.push_back(Vert(pos.x(), pos.y()));
|
||||||
|
mLines.push_back(Vert(pos.x(), pos.y() + size.y()));
|
||||||
|
}
|
||||||
|
if(it->border & BORDER_RIGHT)
|
||||||
|
{
|
||||||
|
mLines.push_back(Vert(pos.x() + size.x(), pos.y()));
|
||||||
|
mLines.push_back(Vert(mLines.back().x, pos.y() + size.y()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!cursorValid())
|
mLineColors.reserve(mLines.size());
|
||||||
resetCursor();
|
Renderer::buildGLColorArray((GLubyte*)mLineColors.data(), 0xC6C7C6FF, mLines.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComponentGrid::forceRowHeight(int row, unsigned int size)
|
void ComponentGrid::onSizeChanged()
|
||||||
{
|
{
|
||||||
mRowHeights[row] = size;
|
for(auto it = mCells.begin(); it != mCells.end(); it++)
|
||||||
mRowHeightForced[row] = true;
|
updateCellComponent(*it);
|
||||||
updateSize();
|
|
||||||
updateComponentOffsets();
|
updateSeparators();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComponentGrid::forceColumnWidth(int col, unsigned int size)
|
ComponentGrid::GridEntry* ComponentGrid::getCellAt(int x, int y)
|
||||||
{
|
{
|
||||||
mColumnWidths[col] = size;
|
assert(x >= 0 && x < mGridSize.x() && y >= 0 && y < mGridSize.y());
|
||||||
mColumnWidthForced[col] = true;
|
|
||||||
updateSize();
|
|
||||||
updateComponentOffsets();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int ComponentGrid::getRowHeight(int row) { return mRowHeights[row]; }
|
for(auto it = mCells.begin(); it != mCells.end(); it++)
|
||||||
unsigned int ComponentGrid::getColumnWidth(int col) { return mColumnWidths[col]; }
|
|
||||||
|
|
||||||
Eigen::Vector3f ComponentGrid::getCellOffset(Eigen::Vector2i pos)
|
|
||||||
{
|
|
||||||
Eigen::Vector3f offset(0, 0, 0);
|
|
||||||
|
|
||||||
for(int y = 0; y < pos.y(); y++)
|
|
||||||
offset[1] += getRowHeight(y);
|
|
||||||
|
|
||||||
for(int x = 0; x < pos.x(); x++)
|
|
||||||
offset[0] += getColumnWidth(x);
|
|
||||||
|
|
||||||
ComponentEntry* entry = getCell(pos.x(), pos.y());
|
|
||||||
|
|
||||||
Eigen::Vector2i gridSize(0, 0);
|
|
||||||
for(int x = pos.x(); x < pos.x() + entry->dim[0]; x++)
|
|
||||||
gridSize[0] += getColumnWidth(x);
|
|
||||||
for(int y = pos.y(); y < pos.y() + entry->dim[1]; y++)
|
|
||||||
gridSize[1] += getRowHeight(y);
|
|
||||||
|
|
||||||
//if AlignCenter, add half of cell width - half of control width
|
|
||||||
if(entry->alignment == AlignCenter)
|
|
||||||
offset[0] += gridSize.x() / 2 - entry->component->getSize().x() / 2;
|
|
||||||
|
|
||||||
//if AlignRight, add cell width - control width
|
|
||||||
if(entry->alignment == AlignRight)
|
|
||||||
offset[0] += gridSize.x() - entry->component->getSize().x();
|
|
||||||
|
|
||||||
//always center on the Y axis
|
|
||||||
offset[1] += gridSize.y() / 2.0f - entry->component->getSize().y() / 2.0f;
|
|
||||||
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ComponentGrid::setCell(unsigned int x, unsigned int y, ComponentEntry* entry)
|
|
||||||
{
|
|
||||||
if(x >= (unsigned int)mGridSize.x() || y >= (unsigned int)mGridSize.y())
|
|
||||||
{
|
{
|
||||||
LOG(LogError) << "Invalid setCell - position " << x << ", " << y << " out of bounds!";
|
int xmin = it->pos.x();
|
||||||
return;
|
int xmax = xmin + it->dim.x();
|
||||||
|
int ymin = it->pos.y();
|
||||||
|
int ymax = ymin + it->dim.y();
|
||||||
|
|
||||||
|
if(x >= xmin && y >= ymin && x < xmax && y < ymax)
|
||||||
|
return &(*it);
|
||||||
}
|
}
|
||||||
|
|
||||||
mGrid[y * mGridSize.x() + x] = entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
ComponentGrid::ComponentEntry* ComponentGrid::getCell(unsigned int x, unsigned int y)
|
|
||||||
{
|
|
||||||
if(x >= (unsigned int)mGridSize.x() || y >= (unsigned int)mGridSize.y())
|
|
||||||
{
|
|
||||||
LOG(LogError) << "Invalid getCell - position " << x << ", " << y << " out of bounds!";
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
|
|
||||||
return mGrid[y * mGridSize.x() + x];
|
|
||||||
}
|
|
||||||
|
|
||||||
void ComponentGrid::updateSize()
|
|
||||||
{
|
|
||||||
mSize = Eigen::Vector2f(0, 0);
|
|
||||||
for(int x = 0; x < mGridSize.x(); x++)
|
|
||||||
mSize.x() += getColumnWidth(x);
|
|
||||||
for(int y = 0; y < mGridSize.y(); y++)
|
|
||||||
mSize.y() += getRowHeight(y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ComponentGrid::updateComponentOffsets()
|
|
||||||
{
|
|
||||||
for(auto iter = mEntries.begin(); iter != mEntries.end(); iter++)
|
|
||||||
{
|
|
||||||
(*iter)->component->setPosition(getCellOffset((*iter)->pos));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ComponentGrid::updateCellSize(ComponentEntry* e, bool updWidth, bool updHeight)
|
|
||||||
{
|
|
||||||
if(!e)
|
|
||||||
{
|
|
||||||
LOG(LogError) << "Tried to updateCellSize NULL ComponentEntry!";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int x = e->pos.x();
|
|
||||||
unsigned int y = e->pos.y();
|
|
||||||
|
|
||||||
if(!mColumnWidthForced[x] && updWidth)
|
|
||||||
{
|
|
||||||
//recalc width to widest in column
|
|
||||||
float widest = 0;
|
|
||||||
for(int row = 0; row < mGridSize.y(); row++)
|
|
||||||
{
|
|
||||||
ComponentEntry* check = getCell(x, row);
|
|
||||||
if(check)
|
|
||||||
{
|
|
||||||
if(check->component->getSize().x() > widest)
|
|
||||||
widest = check->component->getSize().x();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mColumnWidths[x] = (unsigned int)widest;
|
|
||||||
}
|
|
||||||
if(!mRowHeightForced[y] && updHeight)
|
|
||||||
{
|
|
||||||
float tallest = 0;
|
|
||||||
for(int col = 0; col < mGridSize.x(); col++)
|
|
||||||
{
|
|
||||||
ComponentEntry* check = getCell(col, y);
|
|
||||||
if(check)
|
|
||||||
{
|
|
||||||
if(check->component->getSize().y() > tallest)
|
|
||||||
tallest = check->component->getSize().y();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mRowHeights[y] = (unsigned int)tallest;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateComponentOffsets();
|
|
||||||
updateSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ComponentGrid::updateComponent(GuiComponent* cmp)
|
|
||||||
{
|
|
||||||
for(auto iter = mEntries.begin(); iter != mEntries.end(); iter++)
|
|
||||||
{
|
|
||||||
if((*iter)->component == cmp)
|
|
||||||
{
|
|
||||||
updateCellSize(*iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ComponentGrid::input(InputConfig* config, Input input)
|
bool ComponentGrid::input(InputConfig* config, Input input)
|
||||||
{
|
{
|
||||||
if(cursorValid() && getCell(mCursor.x(), mCursor.y())->component->input(config, input))
|
GridEntry* cursorEntry = getCellAt(mCursor);
|
||||||
|
if(cursorEntry && cursorEntry->component->input(config, input))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if(!input.value)
|
if(!input.value)
|
||||||
|
@ -284,23 +222,19 @@ bool ComponentGrid::input(InputConfig* config, Input input)
|
||||||
|
|
||||||
if(config->isMappedTo("down", input))
|
if(config->isMappedTo("down", input))
|
||||||
{
|
{
|
||||||
moveCursor(Eigen::Vector2i(0, 1));
|
return moveCursor(Eigen::Vector2i(0, 1));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
if(config->isMappedTo("up", input))
|
if(config->isMappedTo("up", input))
|
||||||
{
|
{
|
||||||
moveCursor(Eigen::Vector2i(0, -1));
|
return moveCursor(Eigen::Vector2i(0, -1));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
if(config->isMappedTo("left", input))
|
if(config->isMappedTo("left", input))
|
||||||
{
|
{
|
||||||
moveCursor(Eigen::Vector2i(-1, 0));
|
return moveCursor(Eigen::Vector2i(-1, 0));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
if(config->isMappedTo("right", input))
|
if(config->isMappedTo("right", input))
|
||||||
{
|
{
|
||||||
moveCursor(Eigen::Vector2i(1, 0));
|
return moveCursor(Eigen::Vector2i(1, 0));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -308,47 +242,28 @@ bool ComponentGrid::input(InputConfig* config, Input input)
|
||||||
|
|
||||||
void ComponentGrid::resetCursor()
|
void ComponentGrid::resetCursor()
|
||||||
{
|
{
|
||||||
auto iter = mEntries.begin();
|
if(!mCells.size())
|
||||||
while(iter != mEntries.end())
|
|
||||||
{
|
|
||||||
if((*iter)->canFocus)
|
|
||||||
break;
|
|
||||||
iter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(iter == mEntries.end())
|
|
||||||
{
|
|
||||||
mCursor = Eigen::Vector2i(-1, -1);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
const Eigen::Vector2i origCursor = mCursor;
|
for(auto it = mCells.begin(); it != mCells.end(); it++)
|
||||||
mCursor << (*iter)->pos[0], (*iter)->pos[1];
|
{
|
||||||
|
if(it->canFocus)
|
||||||
|
{
|
||||||
|
Eigen::Vector2i origCursor = mCursor;
|
||||||
|
mCursor = it->pos;
|
||||||
onCursorMoved(origCursor, mCursor);
|
onCursorMoved(origCursor, mCursor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComponentGrid::moveCursor(Eigen::Vector2i dir)
|
bool ComponentGrid::moveCursor(Eigen::Vector2i dir)
|
||||||
{
|
{
|
||||||
if(dir.x() != 0 && dir.y() != 0)
|
assert(dir.x() || dir.y());
|
||||||
{
|
|
||||||
LOG(LogError) << "Invalid cursor move dir!";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Eigen::Vector2i origCursor = mCursor;
|
const Eigen::Vector2i origCursor = mCursor;
|
||||||
|
|
||||||
if(!cursorValid())
|
GridEntry* currentCursorEntry = getCellAt(mCursor);
|
||||||
{
|
|
||||||
resetCursor();
|
|
||||||
|
|
||||||
if(!cursorValid())
|
|
||||||
{
|
|
||||||
if(mCursor != origCursor)
|
|
||||||
onCursorMoved(origCursor, mCursor);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Eigen::Vector2i searchAxis(dir.x() == 0, dir.y() == 0);
|
Eigen::Vector2i searchAxis(dir.x() == 0, dir.y() == 0);
|
||||||
|
|
||||||
|
@ -358,13 +273,16 @@ void ComponentGrid::moveCursor(Eigen::Vector2i dir)
|
||||||
|
|
||||||
Eigen::Vector2i curDirPos = mCursor;
|
Eigen::Vector2i curDirPos = mCursor;
|
||||||
|
|
||||||
|
GridEntry* cursorEntry;
|
||||||
//spread out on search axis+
|
//spread out on search axis+
|
||||||
while(mCursor.x() < mGridSize.x() && mCursor.y() < mGridSize.y())
|
while(mCursor.x() < mGridSize.x() && mCursor.y() < mGridSize.y()
|
||||||
|
&& mCursor.x() >= 0 && mCursor.y() >= 0)
|
||||||
{
|
{
|
||||||
if(cursorValid() && getCell(mCursor.x(), mCursor.y())->canFocus)
|
cursorEntry = getCellAt(mCursor);
|
||||||
|
if(cursorEntry && cursorEntry->canFocus && cursorEntry != currentCursorEntry)
|
||||||
{
|
{
|
||||||
onCursorMoved(origCursor, mCursor);
|
onCursorMoved(origCursor, mCursor);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
mCursor += searchAxis;
|
mCursor += searchAxis;
|
||||||
|
@ -372,12 +290,14 @@ void ComponentGrid::moveCursor(Eigen::Vector2i dir)
|
||||||
|
|
||||||
//now again on search axis-
|
//now again on search axis-
|
||||||
mCursor = curDirPos;
|
mCursor = curDirPos;
|
||||||
while(mCursor.x() >= 0 && mCursor.y() >= 0)
|
while(mCursor.x() >= 0 && mCursor.y() >= 0
|
||||||
|
&& mCursor.x() < mGridSize.x() && mCursor.y() < mGridSize.y())
|
||||||
{
|
{
|
||||||
if(cursorValid() && getCell(mCursor.x(), mCursor.y())->canFocus)
|
cursorEntry = getCellAt(mCursor);
|
||||||
|
if(cursorEntry && cursorEntry->canFocus && cursorEntry != currentCursorEntry)
|
||||||
{
|
{
|
||||||
onCursorMoved(origCursor, mCursor);
|
onCursorMoved(origCursor, mCursor);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
mCursor -= searchAxis;
|
mCursor -= searchAxis;
|
||||||
|
@ -388,31 +308,36 @@ void ComponentGrid::moveCursor(Eigen::Vector2i dir)
|
||||||
|
|
||||||
//failed to find another focusable element in this direction
|
//failed to find another focusable element in this direction
|
||||||
mCursor = origCursor;
|
mCursor = origCursor;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComponentGrid::onFocusLost()
|
||||||
|
{
|
||||||
|
GridEntry* cursorEntry = getCellAt(mCursor);
|
||||||
|
if(cursorEntry)
|
||||||
|
cursorEntry->component->onFocusLost();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComponentGrid::onFocusGained()
|
||||||
|
{
|
||||||
|
GridEntry* cursorEntry = getCellAt(mCursor);
|
||||||
|
if(cursorEntry)
|
||||||
|
cursorEntry->component->onFocusGained();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ComponentGrid::cursorValid()
|
bool ComponentGrid::cursorValid()
|
||||||
{
|
{
|
||||||
if(mCursor.x() < 0 || mCursor.y() < 0 || mCursor.x() >= mGridSize.x() || mCursor.y() >= mGridSize.y())
|
return getCellAt(mCursor) != NULL;
|
||||||
return false;
|
|
||||||
|
|
||||||
return getCell(mCursor.x(), mCursor.y()) != NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComponentGrid::update(int deltaTime)
|
void ComponentGrid::update(int deltaTime)
|
||||||
{
|
{
|
||||||
for(auto iter = mEntries.begin(); iter != mEntries.end(); iter++)
|
// update ALL THE THINGS
|
||||||
|
GridEntry* cursorEntry = getCellAt(mCursor);
|
||||||
|
for(auto it = mCells.begin(); it != mCells.end(); it++)
|
||||||
{
|
{
|
||||||
switch((*iter)->updateType)
|
if(it->updateType == UPDATE_ALWAYS || (it->updateType == UPDATE_WHEN_SELECTED && cursorEntry == &(*it)))
|
||||||
{
|
it->component->update(deltaTime);
|
||||||
case UpdateAlways:
|
|
||||||
(*iter)->component->update(deltaTime);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UpdateFocused:
|
|
||||||
if(cursorValid() && getCell(mCursor.x(), mCursor.y())->component == (*iter)->component)
|
|
||||||
(*iter)->component->update(deltaTime);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,79 +345,72 @@ void ComponentGrid::render(const Eigen::Affine3f& parentTrans)
|
||||||
{
|
{
|
||||||
Eigen::Affine3f trans = parentTrans * getTransform();
|
Eigen::Affine3f trans = parentTrans * getTransform();
|
||||||
|
|
||||||
//draw cursor
|
renderChildren(trans);
|
||||||
if(cursorValid())
|
|
||||||
{
|
|
||||||
ComponentEntry* entry = getCell(mCursor.x(), mCursor.y());
|
|
||||||
Eigen::Affine3f entryTrans = trans * entry->component->getTransform();
|
|
||||||
Renderer::setMatrix(entryTrans);
|
|
||||||
|
|
||||||
Renderer::drawRect(0, 0, 4, 4, 0xFF0000FF);
|
// draw cell separators
|
||||||
Renderer::drawRect(0, 0, (int)entry->component->getSize().x(), (int)entry->component->getSize().y(), 0x0000AA22);
|
if(mLines.size())
|
||||||
|
{
|
||||||
|
Renderer::setMatrix(trans);
|
||||||
|
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
|
|
||||||
|
glVertexPointer(2, GL_FLOAT, 0, &mLines[0].x);
|
||||||
|
glColorPointer(4, GL_UNSIGNED_BYTE, 0, mLineColors.data());
|
||||||
|
|
||||||
|
glDrawArrays(GL_LINES, 0, mLines.size());
|
||||||
|
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto iter = mEntries.begin(); iter != mEntries.end(); iter++)
|
|
||||||
{
|
|
||||||
(*iter)->component->render(trans);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//draw cell outlines
|
|
||||||
/*Renderer::setMatrix(trans);
|
|
||||||
Eigen::Vector2i pos(0, 0);
|
|
||||||
for(int x = 0; x < mGridSize.x(); x++)
|
|
||||||
{
|
|
||||||
for(int y = 0; y < mGridSize.y(); y++)
|
|
||||||
{
|
|
||||||
Renderer::drawRect(pos.x(), pos.y(), getColumnWidth(x), 2, 0x000000AA);
|
|
||||||
Renderer::drawRect(pos.x(), pos.y(), 2, getRowHeight(y), 0x000000AA);
|
|
||||||
Renderer::drawRect(pos.x() + getColumnWidth(x), pos.y(), 2, getRowHeight(y), 0x000000AA);
|
|
||||||
Renderer::drawRect(pos.x(), pos.y() + getRowHeight(y) - 2, getColumnWidth(x), 2, 0x000000AA);
|
|
||||||
|
|
||||||
pos[1] += getRowHeight(y);
|
|
||||||
}
|
|
||||||
|
|
||||||
pos[1] = 0;
|
|
||||||
pos[0] += getColumnWidth(x);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComponentGrid::textInput(const char* text)
|
void ComponentGrid::textInput(const char* text)
|
||||||
{
|
{
|
||||||
if(getSelectedComponent() != NULL)
|
GridEntry* selectedEntry = getCellAt(mCursor);
|
||||||
getSelectedComponent()->textInput(text);
|
if(selectedEntry != NULL)
|
||||||
}
|
selectedEntry->component->textInput(text);
|
||||||
|
|
||||||
void ComponentGrid::onPositionChanged()
|
|
||||||
{
|
|
||||||
updateComponentOffsets();
|
|
||||||
}
|
|
||||||
|
|
||||||
GuiComponent* ComponentGrid::getSelectedComponent()
|
|
||||||
{
|
|
||||||
if(!cursorValid())
|
|
||||||
return NULL;
|
|
||||||
return getCell(mCursor.x(), mCursor.y())->component;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComponentGrid::onCursorMoved(Eigen::Vector2i from, Eigen::Vector2i to)
|
void ComponentGrid::onCursorMoved(Eigen::Vector2i from, Eigen::Vector2i to)
|
||||||
{
|
{
|
||||||
if(from != Eigen::Vector2i(-1, -1))
|
GridEntry* cell = getCellAt(from);
|
||||||
getCell(from.x(), from.y())->component->onFocusLost();
|
if(cell)
|
||||||
|
cell->component->onFocusLost();
|
||||||
|
|
||||||
if(to != Eigen::Vector2i(-1, -1))
|
cell = getCellAt(to);
|
||||||
getCell(to.x(), to.y())->component->onFocusGained();
|
if(cell)
|
||||||
|
cell->component->onFocusGained();
|
||||||
|
|
||||||
updateHelpPrompts();
|
updateHelpPrompts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ComponentGrid::setCursorTo(const std::shared_ptr<GuiComponent>& comp)
|
||||||
|
{
|
||||||
|
for(auto it = mCells.begin(); it != mCells.end(); it++)
|
||||||
|
{
|
||||||
|
if(it->component == comp)
|
||||||
|
{
|
||||||
|
Eigen::Vector2i oldCursor = mCursor;
|
||||||
|
mCursor = it->pos;
|
||||||
|
onCursorMoved(oldCursor, mCursor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// component not found!!
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<HelpPrompt> ComponentGrid::getHelpPrompts()
|
std::vector<HelpPrompt> ComponentGrid::getHelpPrompts()
|
||||||
{
|
{
|
||||||
std::vector<HelpPrompt> prompts;
|
std::vector<HelpPrompt> prompts;
|
||||||
if(cursorValid())
|
GridEntry* e = getCellAt(mCursor);
|
||||||
prompts = getSelectedComponent()->getHelpPrompts();
|
if(e)
|
||||||
|
prompts = e->component->getHelpPrompts();
|
||||||
|
|
||||||
bool canScrollVert = true;
|
bool canScrollVert = true;
|
||||||
bool canScrollHoriz = true;
|
bool canScrollHoriz = true;
|
||||||
|
|
|
@ -2,63 +2,87 @@
|
||||||
|
|
||||||
#include "../GuiComponent.h"
|
#include "../GuiComponent.h"
|
||||||
|
|
||||||
|
namespace GridFlags
|
||||||
|
{
|
||||||
|
enum UpdateType
|
||||||
|
{
|
||||||
|
UPDATE_ALWAYS,
|
||||||
|
UPDATE_WHEN_SELECTED,
|
||||||
|
UPDATE_NEVER
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Border : unsigned int
|
||||||
|
{
|
||||||
|
BORDER_NONE = 0,
|
||||||
|
|
||||||
|
BORDER_TOP = 1,
|
||||||
|
BORDER_BOTTOM = 2,
|
||||||
|
BORDER_LEFT = 4,
|
||||||
|
BORDER_RIGHT = 8
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// Used to arrange a bunch of components in a spreadsheet-esque grid.
|
// Used to arrange a bunch of components in a spreadsheet-esque grid.
|
||||||
class ComponentGrid : public GuiComponent
|
class ComponentGrid : public GuiComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ComponentGrid(Window* window, Eigen::Vector2i gridDimensions);
|
ComponentGrid(Window* window, const Eigen::Vector2i& gridDimensions);
|
||||||
virtual ~ComponentGrid();
|
virtual ~ComponentGrid();
|
||||||
|
|
||||||
enum UpdateBehavior
|
bool removeEntry(const std::shared_ptr<GuiComponent>& comp);
|
||||||
{
|
|
||||||
UpdateAlways, UpdateFocused
|
|
||||||
};
|
|
||||||
|
|
||||||
enum AlignmentType
|
void setEntry(const std::shared_ptr<GuiComponent>& comp, const Eigen::Vector2i& pos, bool canFocus, bool resize = true,
|
||||||
{
|
const Eigen::Vector2i& size = Eigen::Vector2i(1, 1), unsigned int border = GridFlags::BORDER_NONE, GridFlags::UpdateType updateType = GridFlags::UPDATE_ALWAYS);
|
||||||
AlignLeft, AlignRight, AlignCenter
|
|
||||||
};
|
|
||||||
|
|
||||||
//DO NOT USE NEGATIVE NUMBERS FOR POSITION OR SIZE.
|
|
||||||
void setEntry(Eigen::Vector2i pos, Eigen::Vector2i size, GuiComponent* component, bool canFocus, AlignmentType align,
|
|
||||||
Eigen::Matrix<bool, 1, 2> autoFit = Eigen::Matrix<bool, 1, 2>(true, true), UpdateBehavior updateType = UpdateAlways);
|
|
||||||
|
|
||||||
void removeEntriesIn(Eigen::Vector2i pos, Eigen::Vector2i size);
|
|
||||||
|
|
||||||
void onPositionChanged() override;
|
|
||||||
|
|
||||||
void textInput(const char* text) override;
|
void textInput(const char* text) override;
|
||||||
bool input(InputConfig* config, Input input) override;
|
bool input(InputConfig* config, Input input) override;
|
||||||
void update(int deltaTime) override;
|
void update(int deltaTime) override;
|
||||||
void render(const Eigen::Affine3f& parentTrans) override;
|
void render(const Eigen::Affine3f& parentTrans) override;
|
||||||
|
void onSizeChanged() override;
|
||||||
void forceColumnWidth(int col, unsigned int size);
|
|
||||||
void forceRowHeight(int row, unsigned int size);
|
|
||||||
|
|
||||||
void updateComponent(GuiComponent* cmp);
|
|
||||||
|
|
||||||
void resetCursor();
|
void resetCursor();
|
||||||
bool cursorValid();
|
bool cursorValid();
|
||||||
|
|
||||||
GuiComponent* getSelectedComponent();
|
float getColWidth(int col);
|
||||||
|
float getRowHeight(int row);
|
||||||
|
|
||||||
void moveCursor(Eigen::Vector2i dir);
|
void setColWidthPerc(int col, float width);
|
||||||
|
void setRowHeightPerc(int row, float height);
|
||||||
|
|
||||||
|
bool moveCursor(Eigen::Vector2i dir);
|
||||||
|
void setCursorTo(const std::shared_ptr<GuiComponent>& comp);
|
||||||
|
|
||||||
|
inline std::shared_ptr<GuiComponent> getSelectedComponent()
|
||||||
|
{
|
||||||
|
GridEntry* e = getCellAt(mCursor);
|
||||||
|
if(e)
|
||||||
|
return e->component;
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onFocusLost() override;
|
||||||
|
void onFocusGained() override;
|
||||||
|
|
||||||
virtual std::vector<HelpPrompt> getHelpPrompts() override;
|
virtual std::vector<HelpPrompt> getHelpPrompts() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class ComponentEntry
|
class GridEntry
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Eigen::Vector2i pos;
|
Eigen::Vector2i pos;
|
||||||
Eigen::Vector2i dim;
|
Eigen::Vector2i dim;
|
||||||
GuiComponent* component;
|
std::shared_ptr<GuiComponent> component;
|
||||||
UpdateBehavior updateType;
|
|
||||||
AlignmentType alignment;
|
|
||||||
bool canFocus;
|
bool canFocus;
|
||||||
|
bool resize;
|
||||||
|
GridFlags::UpdateType updateType;
|
||||||
|
unsigned int border;
|
||||||
|
|
||||||
ComponentEntry() : component(NULL), updateType(UpdateAlways), canFocus(true), alignment(AlignCenter) {};
|
GridEntry(const Eigen::Vector2i& p = Eigen::Vector2i::Zero(), const Eigen::Vector2i& d = Eigen::Vector2i::Zero(),
|
||||||
ComponentEntry(Eigen::Vector2i p, Eigen::Vector2i d, GuiComponent* comp, UpdateBehavior update, bool focus, AlignmentType align) : pos(p), dim(d), component(comp), updateType(update), canFocus(focus), alignment(align) {};
|
const std::shared_ptr<GuiComponent>& cmp = nullptr, bool f = false, bool r = true,
|
||||||
|
GridFlags::UpdateType u = GridFlags::UPDATE_ALWAYS, unsigned int b = GridFlags::BORDER_NONE) :
|
||||||
|
pos(p), dim(d), component(cmp), canFocus(f), resize(r), updateType(u), border(b)
|
||||||
|
{};
|
||||||
|
|
||||||
operator bool() const
|
operator bool() const
|
||||||
{
|
{
|
||||||
|
@ -66,30 +90,30 @@ private:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//Offset we render components by (for scrolling). [unimplemented]
|
float* mRowHeights;
|
||||||
Eigen::Vector2f mComponentOffset;
|
float* mColWidths;
|
||||||
|
|
||||||
|
struct Vert
|
||||||
|
{
|
||||||
|
Vert(float xi = 0, float yi = 0) : x(xi), y(yi) {};
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Vert> mLines;
|
||||||
|
std::vector<unsigned int> mLineColors;
|
||||||
|
|
||||||
|
// Update position & size
|
||||||
|
void updateCellComponent(const GridEntry& cell);
|
||||||
|
void updateSeparators();
|
||||||
|
|
||||||
|
GridEntry* getCellAt(int x, int y);
|
||||||
|
inline GridEntry* getCellAt(const Eigen::Vector2i& pos) { return getCellAt(pos.x(), pos.y()); }
|
||||||
|
|
||||||
Eigen::Vector2i mGridSize;
|
Eigen::Vector2i mGridSize;
|
||||||
ComponentEntry** mGrid;
|
|
||||||
std::vector<ComponentEntry*> mEntries;
|
|
||||||
void makeCells(Eigen::Vector2i size);
|
|
||||||
void setCell(unsigned int x, unsigned int y, ComponentEntry* entry);
|
|
||||||
ComponentEntry* getCell(unsigned int x, unsigned int y);
|
|
||||||
|
|
||||||
unsigned int getColumnWidth(int col);
|
std::vector<GridEntry> mCells;
|
||||||
unsigned int getRowHeight(int row);
|
|
||||||
|
|
||||||
unsigned int* mColumnWidths;
|
|
||||||
unsigned int* mRowHeights;
|
|
||||||
bool* mColumnWidthForced;
|
|
||||||
bool* mRowHeightForced;
|
|
||||||
|
|
||||||
Eigen::Vector3f getCellOffset(Eigen::Vector2i gridPos);
|
|
||||||
void updateSize();
|
|
||||||
|
|
||||||
void onCursorMoved(Eigen::Vector2i from, Eigen::Vector2i to);
|
void onCursorMoved(Eigen::Vector2i from, Eigen::Vector2i to);
|
||||||
Eigen::Vector2i mCursor;
|
Eigen::Vector2i mCursor;
|
||||||
|
|
||||||
void updateComponentOffsets();
|
|
||||||
void updateCellSize(ComponentEntry* e, bool updWidth = true, bool updHeight = true);
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,6 +6,7 @@ ComponentList::ComponentList(Window* window) : IList<ComponentListRow, void*>(wi
|
||||||
{
|
{
|
||||||
mSelectorBarOffset = 0;
|
mSelectorBarOffset = 0;
|
||||||
mCameraOffset = 0;
|
mCameraOffset = 0;
|
||||||
|
mFocused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComponentList::addRow(const ComponentListRow& row, bool setCursorHere)
|
void ComponentList::addRow(const ComponentListRow& row, bool setCursorHere)
|
||||||
|
@ -41,6 +42,16 @@ void ComponentList::onSizeChanged()
|
||||||
onCursorChanged(mScrollVelocity != 0 ? CURSOR_SCROLLING : CURSOR_STOPPED);
|
onCursorChanged(mScrollVelocity != 0 ? CURSOR_SCROLLING : CURSOR_STOPPED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ComponentList::onFocusLost()
|
||||||
|
{
|
||||||
|
mFocused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComponentList::onFocusGained()
|
||||||
|
{
|
||||||
|
mFocused = true;
|
||||||
|
}
|
||||||
|
|
||||||
bool ComponentList::input(InputConfig* config, Input input)
|
bool ComponentList::input(InputConfig* config, Input input)
|
||||||
{
|
{
|
||||||
if(size() == 0)
|
if(size() == 0)
|
||||||
|
@ -127,9 +138,12 @@ void ComponentList::render(const Eigen::Affine3f& parentTrans)
|
||||||
// draw our entries
|
// draw our entries
|
||||||
renderChildren(trans);
|
renderChildren(trans);
|
||||||
|
|
||||||
// draw selector bar
|
// custom rendering
|
||||||
Renderer::setMatrix(trans);
|
Renderer::setMatrix(trans);
|
||||||
|
|
||||||
|
// draw selector bar
|
||||||
|
if(mFocused)
|
||||||
|
{
|
||||||
// inversion: src * (1 - dst) + dst * 0 = where src = 1
|
// inversion: src * (1 - dst) + dst * 0 = where src = 1
|
||||||
// need a function that goes roughly 0x777777 -> 0xFFFFFF
|
// need a function that goes roughly 0x777777 -> 0xFFFFFF
|
||||||
// and 0xFFFFFF -> 0x777777
|
// and 0xFFFFFF -> 0x777777
|
||||||
|
@ -144,6 +158,7 @@ void ComponentList::render(const Eigen::Affine3f& parentTrans)
|
||||||
// hack to draw 2px dark on left/right of the bar
|
// hack to draw 2px dark on left/right of the bar
|
||||||
Renderer::drawRect(0, (int)mSelectorBarOffset, 2, (int)selectedRowHeight, 0x878787FF);
|
Renderer::drawRect(0, (int)mSelectorBarOffset, 2, (int)selectedRowHeight, 0x878787FF);
|
||||||
Renderer::drawRect((int)mSize.x() - 2, (int)mSelectorBarOffset, 2, (int)selectedRowHeight, 0x878787FF);
|
Renderer::drawRect((int)mSize.x() - 2, (int)mSelectorBarOffset, 2, (int)selectedRowHeight, 0x878787FF);
|
||||||
|
}
|
||||||
|
|
||||||
// draw separators
|
// draw separators
|
||||||
float y = 0;
|
float y = 0;
|
||||||
|
|
|
@ -52,11 +52,17 @@ public:
|
||||||
void render(const Eigen::Affine3f& parentTrans) override;
|
void render(const Eigen::Affine3f& parentTrans) override;
|
||||||
|
|
||||||
void onSizeChanged() override;
|
void onSizeChanged() override;
|
||||||
|
void onFocusGained() override;
|
||||||
|
void onFocusLost() override;
|
||||||
|
|
||||||
|
inline int getCursorId() const { return mCursor; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void onCursorChanged(const CursorState& state) override;
|
void onCursorChanged(const CursorState& state) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool mFocused;
|
||||||
|
|
||||||
void updateElementPosition(const ComponentListRow& row);
|
void updateElementPosition(const ComponentListRow& row);
|
||||||
void updateElementSize(const ComponentListRow& row);
|
void updateElementSize(const ComponentListRow& row);
|
||||||
|
|
||||||
|
|
|
@ -1,31 +1,67 @@
|
||||||
#include "MenuComponent.h"
|
#include "MenuComponent.h"
|
||||||
|
#include "ButtonComponent.h"
|
||||||
|
|
||||||
|
using namespace Eigen;
|
||||||
|
|
||||||
MenuComponent::MenuComponent(Window* window, const char* title) : GuiComponent(window),
|
MenuComponent::MenuComponent(Window* window, const char* title) : GuiComponent(window),
|
||||||
mBackground(window), mTitle(window), mList(window)
|
mBackground(window), mGrid(window, Vector2i(1, 3))
|
||||||
{
|
{
|
||||||
|
addChild(&mBackground);
|
||||||
|
addChild(&mGrid);
|
||||||
|
|
||||||
mBackground.setImagePath(":/frame.png");
|
mBackground.setImagePath(":/frame.png");
|
||||||
|
|
||||||
mTitle.setFont(Font::get(FONT_SIZE_LARGE));
|
// set up title which will never change
|
||||||
mTitle.setText(title);
|
mTitle = std::make_shared<TextComponent>(mWindow, title, Font::get(FONT_SIZE_LARGE), 0x555555FF, true);
|
||||||
mTitle.setColor(0x555555FF);
|
mGrid.setEntry(mTitle, Vector2i(0, 0), false);
|
||||||
mTitle.setCentered(true);
|
|
||||||
|
|
||||||
addChild(&mBackground);
|
// set up list which will never change (externally, anyway)
|
||||||
addChild(&mTitle);
|
mList = std::make_shared<ComponentList>(mWindow);
|
||||||
addChild(&mList);
|
mGrid.setEntry(mList, Vector2i(0, 1), true);
|
||||||
|
|
||||||
setSize(Renderer::getScreenWidth() * 0.5f, Renderer::getScreenHeight() * 0.75f);
|
setSize(Renderer::getScreenWidth() * 0.5f, Renderer::getScreenHeight() * 0.75f);
|
||||||
|
updateGrid();
|
||||||
|
mGrid.resetCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuComponent::onSizeChanged()
|
void MenuComponent::onSizeChanged()
|
||||||
{
|
{
|
||||||
mBackground.fitTo(mSize, Eigen::Vector3f::Zero(), Eigen::Vector2f(-32, -32));
|
mBackground.fitTo(mSize, Eigen::Vector3f::Zero(), Eigen::Vector2f(-32, -32));
|
||||||
|
|
||||||
const float titlePadding = mTitle.getFont()->getHeight() * 0.2f;
|
// update grid row/col sizes
|
||||||
|
mGrid.setRowHeightPerc(0, mTitle->getSize().y() / mSize.y());
|
||||||
|
mGrid.setRowHeightPerc(2, mButtonGrid ? (mButtonGrid->getSize().y() + 32) / mSize.y() : 0.07f);
|
||||||
|
|
||||||
mTitle.setSize(mSize.x(), (float)mTitle.getFont()->getHeight());
|
mGrid.setSize(mSize);
|
||||||
mTitle.setPosition(0, titlePadding / 2);
|
}
|
||||||
|
|
||||||
mList.setPosition(0, mTitle.getSize().y() + titlePadding);
|
void MenuComponent::addButton(const std::string& name, const std::string& helpText, const std::function<void()>& callback)
|
||||||
mList.setSize(mSize.x(), mSize.y() - mTitle.getSize().y() - titlePadding);
|
{
|
||||||
|
mButtons.push_back(std::make_shared<ButtonComponent>(mWindow, name, helpText, callback));
|
||||||
|
updateGrid();
|
||||||
|
onSizeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MenuComponent::updateGrid()
|
||||||
|
{
|
||||||
|
if(mButtonGrid)
|
||||||
|
mGrid.removeEntry(mButtonGrid);
|
||||||
|
|
||||||
|
if(mButtons.size())
|
||||||
|
{
|
||||||
|
mButtonGrid = std::make_shared<ComponentGrid>(mWindow, Vector2i(mButtons.size(), 1));
|
||||||
|
|
||||||
|
float buttonGridWidth = 16.0f * mButtons.size(); // initialize to padding
|
||||||
|
for(int i = 0; i < (int)mButtons.size(); i++)
|
||||||
|
{
|
||||||
|
mButtonGrid->setEntry(mButtons.at(i), Vector2i(i, 0), true, false);
|
||||||
|
buttonGridWidth += mButtons.at(i)->getSize().x();
|
||||||
|
}
|
||||||
|
|
||||||
|
mButtonGrid->setSize(buttonGridWidth, mButtons.at(0)->getSize().y());
|
||||||
|
|
||||||
|
mGrid.setEntry(mButtonGrid, Vector2i(0, 2), true, false);
|
||||||
|
}else{
|
||||||
|
mButtonGrid.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
#include "NinePatchComponent.h"
|
#include "NinePatchComponent.h"
|
||||||
#include "ComponentList.h"
|
#include "ComponentList.h"
|
||||||
#include "TextComponent.h"
|
#include "TextComponent.h"
|
||||||
|
#include "ComponentGrid.h"
|
||||||
|
|
||||||
|
class ButtonComponent;
|
||||||
|
|
||||||
class MenuComponent : public GuiComponent
|
class MenuComponent : public GuiComponent
|
||||||
{
|
{
|
||||||
|
@ -11,7 +14,7 @@ public:
|
||||||
|
|
||||||
void onSizeChanged() override;
|
void onSizeChanged() override;
|
||||||
|
|
||||||
inline void addRow(const ComponentListRow& row, bool setCursorHere = false) { mList.addRow(row, setCursorHere); }
|
inline void addRow(const ComponentListRow& row, bool setCursorHere = false) { mList->addRow(row, setCursorHere); }
|
||||||
|
|
||||||
inline void addWithLabel(const std::string& label, const std::shared_ptr<GuiComponent>& comp, bool setCursorHere = false)
|
inline void addWithLabel(const std::string& label, const std::shared_ptr<GuiComponent>& comp, bool setCursorHere = false)
|
||||||
{
|
{
|
||||||
|
@ -21,8 +24,19 @@ public:
|
||||||
addRow(row, setCursorHere);
|
addRow(row, setCursorHere);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addButton(const std::string& label, const std::string& helpText, const std::function<void()>& callback);
|
||||||
|
|
||||||
|
inline void setCursorToList() { mGrid.setCursorTo(mList); }
|
||||||
|
inline void setCursorToButtons() { assert(mButtonGrid); mGrid.setCursorTo(mButtonGrid); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void updateGrid();
|
||||||
|
|
||||||
NinePatchComponent mBackground;
|
NinePatchComponent mBackground;
|
||||||
TextComponent mTitle;
|
ComponentGrid mGrid;
|
||||||
ComponentList mList;
|
|
||||||
|
std::shared_ptr<TextComponent> mTitle;
|
||||||
|
std::shared_ptr<ComponentList> mList;
|
||||||
|
std::shared_ptr<ComponentGrid> mButtonGrid;
|
||||||
|
std::vector< std::shared_ptr<ButtonComponent> > mButtons;
|
||||||
};
|
};
|
||||||
|
|
238
src/components/ScraperSearchComponent.cpp
Normal file
238
src/components/ScraperSearchComponent.cpp
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
#include "ScraperSearchComponent.h"
|
||||||
|
|
||||||
|
#include "../components/TextComponent.h"
|
||||||
|
#include "../components/ScrollableContainer.h"
|
||||||
|
#include "../components/ImageComponent.h"
|
||||||
|
#include "../components/ComponentList.h"
|
||||||
|
#include "../HttpReq.h"
|
||||||
|
#include "../Settings.h"
|
||||||
|
#include "../Log.h"
|
||||||
|
|
||||||
|
ScraperSearchComponent::ScraperSearchComponent(Window* window, SearchType type) : GuiComponent(window),
|
||||||
|
mGrid(window, Eigen::Vector2i(4, 3)),
|
||||||
|
mSearchType(type)
|
||||||
|
{
|
||||||
|
mSearchParams.system = NULL;
|
||||||
|
mSearchParams.game = NULL;
|
||||||
|
|
||||||
|
addChild(&mGrid);
|
||||||
|
|
||||||
|
using namespace Eigen;
|
||||||
|
|
||||||
|
// left spacer (empty component, needed for borders)
|
||||||
|
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 0), false, false, Vector2i(1, 3), GridFlags::BORDER_TOP | GridFlags::BORDER_BOTTOM);
|
||||||
|
|
||||||
|
// selected result name
|
||||||
|
mResultName = std::make_shared<TextComponent>(mWindow, "Result name", Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
||||||
|
mGrid.setEntry(mResultName, Vector2i(1, 0), false, true, Vector2i(2, 1), GridFlags::BORDER_TOP);
|
||||||
|
|
||||||
|
// selected result thumbnail
|
||||||
|
mResultThumbnail = std::make_shared<ImageComponent>(mWindow);
|
||||||
|
mGrid.setEntry(mResultThumbnail, Vector2i(1, 1), false, false, Vector2i(1, 1));
|
||||||
|
|
||||||
|
// selected result desc + container
|
||||||
|
mDescContainer = std::make_shared<ScrollableContainer>(mWindow);
|
||||||
|
mResultDesc = std::make_shared<TextComponent>(mWindow, "Result desc", Font::get(FONT_SIZE_SMALL), 0x777777FF);
|
||||||
|
mDescContainer->addChild(mResultDesc.get());
|
||||||
|
mDescContainer->setAutoScroll(2200, 0.015f);
|
||||||
|
|
||||||
|
// result list
|
||||||
|
mResultList = std::make_shared<ComponentList>(mWindow);
|
||||||
|
|
||||||
|
updateViewStyle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScraperSearchComponent::onSizeChanged()
|
||||||
|
{
|
||||||
|
mGrid.setSize(mSize);
|
||||||
|
|
||||||
|
// column widths
|
||||||
|
mGrid.setColWidthPerc(0, 0.01f);
|
||||||
|
mGrid.setColWidthPerc(1, 0.25f);
|
||||||
|
mGrid.setColWidthPerc(2, 0.25f);
|
||||||
|
mGrid.setColWidthPerc(3, 0.49f);
|
||||||
|
|
||||||
|
// row heights
|
||||||
|
const float fontHeightPerc = (mResultName->getFont()->getHeight()) / mGrid.getSize().y();
|
||||||
|
mGrid.setRowHeightPerc(0, fontHeightPerc); // result name
|
||||||
|
mGrid.setRowHeightPerc(2, 0.375f); // description
|
||||||
|
|
||||||
|
mResultThumbnail->setMaxSize(mGrid.getColWidth(1), mGrid.getRowHeight(1));
|
||||||
|
mResultDesc->setSize(mDescContainer->getSize().x(), 0); // make desc text wrap at edge of container
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScraperSearchComponent::updateViewStyle()
|
||||||
|
{
|
||||||
|
using namespace Eigen;
|
||||||
|
|
||||||
|
// unlink description and result list
|
||||||
|
mGrid.removeEntry(mResultDesc);
|
||||||
|
mGrid.removeEntry(mResultList);
|
||||||
|
|
||||||
|
// add them back depending on search type
|
||||||
|
if(mSearchType == ALWAYS_ACCEPT_FIRST_RESULT)
|
||||||
|
{
|
||||||
|
// show description on the right
|
||||||
|
mGrid.setEntry(mDescContainer, Vector2i(3, 0), false, true, Vector2i(1, 3), GridFlags::BORDER_TOP | GridFlags::BORDER_BOTTOM);
|
||||||
|
mResultDesc->setSize(mDescContainer->getSize().x(), 0); // make desc text wrap at edge of container
|
||||||
|
}else{
|
||||||
|
// show result list on the right
|
||||||
|
mGrid.setEntry(mResultList, Vector2i(3, 0), true, true, Vector2i(1, 3), GridFlags::BORDER_LEFT | GridFlags::BORDER_TOP | GridFlags::BORDER_BOTTOM);
|
||||||
|
|
||||||
|
// show description under image/info
|
||||||
|
mGrid.setEntry(mDescContainer, Vector2i(1, 2), false, true, Vector2i(2, 1), GridFlags::BORDER_BOTTOM);
|
||||||
|
mResultDesc->setSize(mDescContainer->getSize().x(), 0); // make desc text wrap at edge of container
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScraperSearchComponent::setSearchParams(const ScraperSearchParams& params)
|
||||||
|
{
|
||||||
|
mSearchParams = params;
|
||||||
|
search();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScraperSearchComponent::search()
|
||||||
|
{
|
||||||
|
Settings::getInstance()->getScraper()->getResultsAsync(mSearchParams, mWindow, std::bind(&ScraperSearchComponent::onSearchReceived, this, std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScraperSearchComponent::onSearchReceived(std::vector<MetaDataList> results)
|
||||||
|
{
|
||||||
|
mResultList->clear();
|
||||||
|
|
||||||
|
mScraperResults = results;
|
||||||
|
|
||||||
|
const int end = results.size() > 5 ? 5 : results.size(); // at max display 5
|
||||||
|
|
||||||
|
auto font = Font::get(FONT_SIZE_MEDIUM);
|
||||||
|
unsigned int color = 0x777777FF;
|
||||||
|
if(end == 0)
|
||||||
|
{
|
||||||
|
ComponentListRow row;
|
||||||
|
row.addElement(std::make_shared<TextComponent>(mWindow, "No games found!", font, color), true);
|
||||||
|
mResultList->addRow(row);
|
||||||
|
mGrid.resetCursor();
|
||||||
|
}else{
|
||||||
|
ComponentListRow row;
|
||||||
|
for(int i = 0; i < end; i++)
|
||||||
|
{
|
||||||
|
row.elements.clear();
|
||||||
|
row.addElement(std::make_shared<TextComponent>(mWindow, results.at(i).get("name"), font, color), true);
|
||||||
|
mResultList->addRow(row);
|
||||||
|
}
|
||||||
|
mGrid.resetCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateInfoPane();
|
||||||
|
|
||||||
|
if(mSearchType == ALWAYS_ACCEPT_FIRST_RESULT)
|
||||||
|
{
|
||||||
|
if(mScraperResults.size() == 0)
|
||||||
|
returnResult(NULL);
|
||||||
|
else
|
||||||
|
returnResult(&mScraperResults.front());
|
||||||
|
}else if(mSearchType == ALWAYS_ACCEPT_MATCHING_CRC)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ScraperSearchComponent::getSelectedIndex()
|
||||||
|
{
|
||||||
|
if(mScraperResults.size() && mGrid.getSelectedComponent() != mResultList)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return mResultList->getCursorId();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScraperSearchComponent::updateInfoPane()
|
||||||
|
{
|
||||||
|
int i = getSelectedIndex();
|
||||||
|
if(i != -1 && (int)mScraperResults.size() > i)
|
||||||
|
{
|
||||||
|
mResultName->setText(mScraperResults.at(i).get("name"));
|
||||||
|
mResultDesc->setText(mScraperResults.at(i).get("desc"));
|
||||||
|
mDescContainer->setScrollPos(Eigen::Vector2d(0, 0));
|
||||||
|
mDescContainer->resetAutoScrollTimer();
|
||||||
|
|
||||||
|
std::string thumb = mScraperResults.at(i).get("thumbnail");
|
||||||
|
mResultThumbnail->setImage("");
|
||||||
|
if(!thumb.empty())
|
||||||
|
mThumbnailReq = std::unique_ptr<HttpReq>(new HttpReq(thumb));
|
||||||
|
else
|
||||||
|
mThumbnailReq.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScraperSearchComponent::input(InputConfig* config, Input input)
|
||||||
|
{
|
||||||
|
if(config->isMappedTo("a", input) && input.value != 0)
|
||||||
|
{
|
||||||
|
//if you're on a result
|
||||||
|
if(getSelectedIndex() != -1)
|
||||||
|
{
|
||||||
|
returnResult(&mScraperResults.at(getSelectedIndex()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = GuiComponent::input(config, input);
|
||||||
|
|
||||||
|
if(config->isMappedTo("up", input) || config->isMappedTo("down", input) && input.value != 0)
|
||||||
|
{
|
||||||
|
updateInfoPane();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScraperSearchComponent::returnResult(MetaDataList* result)
|
||||||
|
{
|
||||||
|
assert(mAcceptCallback);
|
||||||
|
mAcceptCallback(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScraperSearchComponent::update(int deltaTime)
|
||||||
|
{
|
||||||
|
if(mThumbnailReq && mThumbnailReq->status() != HttpReq::REQ_IN_PROGRESS)
|
||||||
|
{
|
||||||
|
updateThumbnail();
|
||||||
|
}
|
||||||
|
|
||||||
|
GuiComponent::update(deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScraperSearchComponent::updateThumbnail()
|
||||||
|
{
|
||||||
|
if(mThumbnailReq && mThumbnailReq->status() == HttpReq::REQ_SUCCESS)
|
||||||
|
{
|
||||||
|
std::string content = mThumbnailReq->getContent();
|
||||||
|
mResultThumbnail->setImage(content.data(), content.length());
|
||||||
|
}else{
|
||||||
|
LOG(LogWarning) << "thumbnail req failed: " << mThumbnailReq->getErrorMsg();
|
||||||
|
mResultThumbnail->setImage("");
|
||||||
|
}
|
||||||
|
|
||||||
|
mThumbnailReq.reset();
|
||||||
|
mGrid.onSizeChanged(); // a hack to fix the thumbnail position since its size changed
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<HelpPrompt> ScraperSearchComponent::getHelpPrompts()
|
||||||
|
{
|
||||||
|
std::vector<HelpPrompt> prompts = mGrid.getHelpPrompts();
|
||||||
|
if(getSelectedIndex() != -1)
|
||||||
|
prompts.push_back(HelpPrompt("a", "accept result"));
|
||||||
|
|
||||||
|
return prompts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScraperSearchComponent::onFocusGained()
|
||||||
|
{
|
||||||
|
mGrid.onFocusGained();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScraperSearchComponent::onFocusLost()
|
||||||
|
{
|
||||||
|
mGrid.onFocusLost();
|
||||||
|
}
|
64
src/components/ScraperSearchComponent.h
Normal file
64
src/components/ScraperSearchComponent.h
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../GuiComponent.h"
|
||||||
|
#include "../scrapers/Scraper.h"
|
||||||
|
#include "../components/ComponentGrid.h"
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#define MAX_SCRAPER_RESULTS 5
|
||||||
|
|
||||||
|
class ComponentList;
|
||||||
|
class TextEditComponent;
|
||||||
|
class ImageComponent;
|
||||||
|
class ScrollableContainer;
|
||||||
|
class HttpReq;
|
||||||
|
|
||||||
|
class ScraperSearchComponent : public GuiComponent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum SearchType
|
||||||
|
{
|
||||||
|
ALWAYS_ACCEPT_FIRST_RESULT,
|
||||||
|
ALWAYS_ACCEPT_MATCHING_CRC,
|
||||||
|
NEVER_AUTO_ACCEPT
|
||||||
|
};
|
||||||
|
|
||||||
|
ScraperSearchComponent(Window* window, SearchType searchType = NEVER_AUTO_ACCEPT);
|
||||||
|
|
||||||
|
void setSearchParams(const ScraperSearchParams& params);
|
||||||
|
inline void setAcceptCallback(const std::function<void(MetaDataList*)>& acceptCallback) { mAcceptCallback = acceptCallback; }
|
||||||
|
|
||||||
|
bool input(InputConfig* config, Input input) override;
|
||||||
|
void update(int deltaTime) override;
|
||||||
|
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||||
|
void onSizeChanged() override;
|
||||||
|
void onFocusGained() override;
|
||||||
|
void onFocusLost() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateViewStyle();
|
||||||
|
void updateThumbnail();
|
||||||
|
void updateInfoPane();
|
||||||
|
|
||||||
|
void search();
|
||||||
|
void onSearchReceived(std::vector<MetaDataList> results);
|
||||||
|
|
||||||
|
int getSelectedIndex();
|
||||||
|
|
||||||
|
void returnResult(MetaDataList* result);
|
||||||
|
|
||||||
|
ComponentGrid mGrid;
|
||||||
|
|
||||||
|
std::shared_ptr<TextComponent> mResultName;
|
||||||
|
std::shared_ptr<ScrollableContainer> mDescContainer;
|
||||||
|
std::shared_ptr<TextComponent> mResultDesc;
|
||||||
|
std::shared_ptr<ImageComponent> mResultThumbnail;
|
||||||
|
std::shared_ptr<ComponentList> mResultList;
|
||||||
|
|
||||||
|
SearchType mSearchType;
|
||||||
|
ScraperSearchParams mSearchParams;
|
||||||
|
std::function<void(MetaDataList*)> mAcceptCallback;
|
||||||
|
|
||||||
|
std::vector<MetaDataList> mScraperResults;
|
||||||
|
std::unique_ptr<HttpReq> mThumbnailReq;
|
||||||
|
};
|
|
@ -9,8 +9,9 @@ TextComponent::TextComponent(Window* window) : GuiComponent(window),
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
TextComponent::TextComponent(Window* window, const std::string& text, const std::shared_ptr<Font>& font, unsigned int color, Eigen::Vector3f pos, Eigen::Vector2f size) : GuiComponent(window),
|
TextComponent::TextComponent(Window* window, const std::string& text, const std::shared_ptr<Font>& font, unsigned int color, bool center,
|
||||||
mFont(NULL), mColor(0x000000FF), mAutoCalcExtent(true, true), mCentered(false)
|
Eigen::Vector3f pos, Eigen::Vector2f size) : GuiComponent(window),
|
||||||
|
mFont(NULL), mColor(0x000000FF), mAutoCalcExtent(true, true), mCentered(center)
|
||||||
{
|
{
|
||||||
setFont(font);
|
setFont(font);
|
||||||
setColor(color);
|
setColor(color);
|
||||||
|
@ -69,6 +70,10 @@ void TextComponent::render(const Eigen::Affine3f& parentTrans)
|
||||||
{
|
{
|
||||||
Eigen::Affine3f trans = parentTrans * getTransform();
|
Eigen::Affine3f trans = parentTrans * getTransform();
|
||||||
|
|
||||||
|
Eigen::Vector3f dim(mSize.x(), mSize.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()));
|
||||||
|
|
||||||
if(mTextCache)
|
if(mTextCache)
|
||||||
{
|
{
|
||||||
if(mCentered)
|
if(mCentered)
|
||||||
|
@ -86,6 +91,8 @@ void TextComponent::render(const Eigen::Affine3f& parentTrans)
|
||||||
mFont->renderTextCache(mTextCache.get());
|
mFont->renderTextCache(mTextCache.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Renderer::popClipRect();
|
||||||
|
|
||||||
GuiComponent::renderChildren(trans);
|
GuiComponent::renderChildren(trans);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,8 @@ class TextComponent : public GuiComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TextComponent(Window* window);
|
TextComponent(Window* window);
|
||||||
TextComponent(Window* window, const std::string& text, const std::shared_ptr<Font>& font, unsigned int color = 0x000000FF, Eigen::Vector3f pos = Eigen::Vector3f::Zero(), Eigen::Vector2f size = Eigen::Vector2f::Zero());
|
TextComponent(Window* window, const std::string& text, const std::shared_ptr<Font>& font, unsigned int color = 0x000000FF, bool center = false,
|
||||||
|
Eigen::Vector3f pos = Eigen::Vector3f::Zero(), Eigen::Vector2f size = Eigen::Vector2f::Zero());
|
||||||
|
|
||||||
void setFont(const std::shared_ptr<Font>& font);
|
void setFont(const std::shared_ptr<Font>& font);
|
||||||
void onSizeChanged() override;
|
void onSizeChanged() override;
|
||||||
|
|
|
@ -4,152 +4,88 @@
|
||||||
#include "../scrapers/Scraper.h"
|
#include "../scrapers/Scraper.h"
|
||||||
#include "../Settings.h"
|
#include "../Settings.h"
|
||||||
|
|
||||||
|
#include "../components/TextComponent.h"
|
||||||
|
#include "../components/ButtonComponent.h"
|
||||||
|
|
||||||
GuiGameScraper::GuiGameScraper(Window* window, ScraperSearchParams params, std::function<void(MetaDataList)> doneFunc, std::function<void()> skipFunc) : GuiComponent(window),
|
GuiGameScraper::GuiGameScraper(Window* window, ScraperSearchParams params, std::function<void(MetaDataList)> doneFunc, std::function<void()> skipFunc) : GuiComponent(window),
|
||||||
mList(window, Eigen::Vector2i(2, 7 + MAX_SCRAPER_RESULTS)),
|
mGrid(window, Eigen::Vector2i(1, 3)),
|
||||||
mBox(window, ":/frame.png"),
|
mBox(window, ":/frame.png"),
|
||||||
mHeader(window, getCleanFileName(params.game->getPath()), Font::get(FONT_SIZE_MEDIUM)),
|
|
||||||
mResultName(window, "", Font::get(FONT_SIZE_MEDIUM)),
|
|
||||||
mResultInfo(window),
|
|
||||||
mResultDesc(window, "", Font::get(FONT_SIZE_SMALL)),
|
|
||||||
mResultThumbnail(window),
|
|
||||||
|
|
||||||
mSearchLabel(window, "Search for: ", Font::get(FONT_SIZE_SMALL)),
|
|
||||||
mSearchText(window),
|
|
||||||
|
|
||||||
mSearchParams(params),
|
mSearchParams(params),
|
||||||
mDoneFunc(doneFunc),
|
mDoneFunc(doneFunc),
|
||||||
mSkipFunc(skipFunc)
|
mSkipFunc(skipFunc),
|
||||||
|
mSearchCountdown(2)
|
||||||
{
|
{
|
||||||
|
// new screen:
|
||||||
|
|
||||||
// FILE NAME
|
// FILE NAME
|
||||||
//--------------------------------------
|
//--------------------------------------
|
||||||
//Name................. |
|
// Result Title | Result #1
|
||||||
//Desc................. | PREVIEW
|
// |-------| ..... | Result #2
|
||||||
//..................... | IMAGE?
|
// | IMG | info | Result #3
|
||||||
//....(autoscroll)..... |
|
// |-------| ..... | .........
|
||||||
|
// | .........
|
||||||
|
// DESCRIPTION........| .........
|
||||||
|
// ...................| .........
|
||||||
|
// ...................| .........
|
||||||
//--------------------------------------
|
//--------------------------------------
|
||||||
//Search for: [_______________________]
|
// [SEARCH NAME] [CANCEL]
|
||||||
//--------------------------------------
|
|
||||||
//Result #1 Name
|
|
||||||
//Result #2 Name
|
|
||||||
//Result #3 Name
|
|
||||||
//Result #4 Name
|
|
||||||
//Result #5 Name
|
|
||||||
|
|
||||||
addChild(&mBox);
|
addChild(&mBox);
|
||||||
addChild(&mList);
|
addChild(&mGrid);
|
||||||
|
|
||||||
float sw = (float)Renderer::getScreenWidth();
|
setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
|
||||||
float sh = (float)Renderer::getScreenHeight();
|
|
||||||
|
|
||||||
float listWidth = sw * 0.7f;
|
mGrid.setSize(mSize.x() * 0.7f, mSize.y() * 0.65f);
|
||||||
float col1Width = listWidth * 0.7f;
|
|
||||||
float col2Width = listWidth * 0.3f;
|
|
||||||
mList.forceColumnWidth(0, (unsigned int)col1Width);
|
|
||||||
mList.forceColumnWidth(1, (unsigned int)col2Width);
|
|
||||||
|
|
||||||
using namespace Eigen;
|
auto headerFont = Font::get(FONT_SIZE_LARGE);
|
||||||
|
|
||||||
mList.setEntry(Vector2i(0, 0), Vector2i(2, 1), &mHeader, false, ComponentGrid::AlignCenter);
|
mGrid.setRowHeightPerc(0, headerFont->getHeight() / mGrid.getSize().y()); // header
|
||||||
|
mGrid.setRowHeightPerc(2, 0.19f); // buttons
|
||||||
|
|
||||||
//y = 1 is a spacer row
|
// header
|
||||||
|
mGrid.setEntry(std::make_shared<TextComponent>(mWindow, getCleanFileName(mSearchParams.game->getName()),
|
||||||
|
headerFont, 0x777777FF, true), Eigen::Vector2i(0, 0), false, true);
|
||||||
|
|
||||||
mResultName.setText(params.game->getName());
|
// ScraperSearchComponent
|
||||||
mResultName.setColor(0x3B56CCFF);
|
mSearch = std::make_shared<ScraperSearchComponent>(window, ScraperSearchComponent::NEVER_AUTO_ACCEPT);
|
||||||
mList.setEntry(Vector2i(0, 1), Vector2i(1, 1), &mResultName, false, ComponentGrid::AlignLeft);
|
mGrid.setEntry(mSearch, Eigen::Vector2i(0, 1), true);
|
||||||
|
|
||||||
mResultDesc.setText(params.game->metadata.get("desc"));
|
// buttons
|
||||||
mResultDesc.setSize(col1Width, 0);
|
auto buttonGrid = std::make_shared<ComponentGrid>(mWindow, Eigen::Vector2i(3, 1));
|
||||||
mResultInfo.addChild(&mResultDesc);
|
|
||||||
mResultInfo.setSize(mResultDesc.getSize().x(), mResultDesc.getFont()->getHeight() * 3.0f);
|
|
||||||
mList.setEntry(Vector2i(0, 2), Vector2i(1, 1), &mResultInfo, false, ComponentGrid::AlignLeft);
|
|
||||||
|
|
||||||
mResultThumbnail.setMaxSize(col2Width, mResultInfo.getSize().y());
|
auto manualSearchBtn = std::make_shared<ButtonComponent>(mWindow, "MANUAL SEARCH", "enter search terms");
|
||||||
mList.setEntry(Vector2i(1, 2), Vector2i(1, 1), &mResultThumbnail, false, ComponentGrid::AlignCenter);
|
auto cancelBtn = std::make_shared<ButtonComponent>(mWindow, "CANCEL", "cancel");
|
||||||
|
|
||||||
//y = 3 is a spacer row
|
buttonGrid->setSize(manualSearchBtn->getSize().x() + cancelBtn->getSize().x() + 18, manualSearchBtn->getSize().y());
|
||||||
|
buttonGrid->setColWidthPerc(0, 0.5f);
|
||||||
|
buttonGrid->setColWidthPerc(1, 0.5f);
|
||||||
|
|
||||||
mList.setEntry(Vector2i(0, 4), Vector2i(1, 1), &mSearchLabel, false, ComponentGrid::AlignLeft);
|
buttonGrid->setEntry(manualSearchBtn, Eigen::Vector2i(0, 0), true, false);
|
||||||
mSearchText.setValue(!params.nameOverride.empty() ? params.nameOverride : getCleanFileName(params.game->getPath()));
|
buttonGrid->setEntry(cancelBtn, Eigen::Vector2i(1, 0), true, false);
|
||||||
mSearchText.setSize(listWidth - mSearchLabel.getSize().x() - 20, mSearchText.getSize().y());
|
|
||||||
mList.setEntry(Vector2i(1, 4), Vector2i(1, 1), &mSearchText, true, ComponentGrid::AlignRight);
|
|
||||||
|
|
||||||
//y = 5 is a spacer row
|
mGrid.setEntry(buttonGrid, Eigen::Vector2i(0, 2), true, false);
|
||||||
|
|
||||||
std::shared_ptr<Font> font = Font::get(FONT_SIZE_SMALL);
|
// center everything
|
||||||
mResultNames.reserve(MAX_SCRAPER_RESULTS);
|
mGrid.setPosition((mSize.x() - mGrid.getSize().x()) / 2, (mSize.y() - mGrid.getSize().y()) / 2);
|
||||||
for(int i = 0; i < MAX_SCRAPER_RESULTS; i ++)
|
mBox.fitTo(mGrid.getSize(), mGrid.getPosition(), Eigen::Vector2f(-32, -32));
|
||||||
{
|
|
||||||
mResultNames.push_back(TextComponent(mWindow, "RESULT...", font));
|
|
||||||
mResultNames.at(i).setColor(0x111111FF);
|
|
||||||
mList.forceRowHeight(6 + i, (unsigned int)mResultNames.at(i).getSize().y());
|
|
||||||
}
|
|
||||||
|
|
||||||
mList.setPosition((sw - mList.getSize().x()) / 2, (sh - mList.getSize().y()) / 2);
|
mSearch->setAcceptCallback( [this](MetaDataList* result) {
|
||||||
|
if(result != NULL)
|
||||||
|
this->mDoneFunc(*result);
|
||||||
|
else if(this->mSkipFunc)
|
||||||
|
this->mSkipFunc();
|
||||||
|
|
||||||
mBox.fitTo(mList.getSize(), mList.getPosition());
|
delete this;
|
||||||
|
});
|
||||||
|
|
||||||
mResultInfo.setAutoScroll(2200, 0.015f);
|
mGrid.resetCursor();
|
||||||
|
//mSearch->setSearchParams(params); // also starts the search
|
||||||
mList.resetCursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GuiGameScraper::search()
|
|
||||||
{
|
|
||||||
//update mSearchParams
|
|
||||||
mSearchParams.nameOverride = mSearchText.getValue();
|
|
||||||
|
|
||||||
Settings::getInstance()->getScraper()->getResultsAsync(mSearchParams, mWindow, std::bind(&GuiGameScraper::onSearchDone, this, std::placeholders::_1));
|
|
||||||
}
|
|
||||||
|
|
||||||
void GuiGameScraper::onSearchDone(std::vector<MetaDataList> results)
|
|
||||||
{
|
|
||||||
mList.removeEntriesIn(Eigen::Vector2i(0, 6), Eigen::Vector2i(1, 5));
|
|
||||||
|
|
||||||
mScraperResults = results;
|
|
||||||
|
|
||||||
const int end = results.size() > 5 ? 5 : results.size(); //at max display 5
|
|
||||||
|
|
||||||
if(end == 0)
|
|
||||||
{
|
|
||||||
mResultNames.at(0).setText("No games found!");
|
|
||||||
mList.setEntry(Eigen::Vector2i(0, 6), Eigen::Vector2i(1, 1), &mResultNames.at(0), false, ComponentGrid::AlignLeft);
|
|
||||||
}else{
|
|
||||||
for(int i = 0; i < end; i++)
|
|
||||||
{
|
|
||||||
mResultNames.at(i).setText(results.at(i).get("name"));
|
|
||||||
mList.setEntry(Eigen::Vector2i(0, 6 + i), Eigen::Vector2i(1, 1), &mResultNames.at(i), true, ComponentGrid::AlignLeft);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mList.resetCursor();
|
|
||||||
mList.moveCursor(Eigen::Vector2i(0, 1)); //move cursor to first game if there is one
|
|
||||||
updateInfoPane();
|
|
||||||
}
|
|
||||||
|
|
||||||
int GuiGameScraper::getSelectedIndex()
|
|
||||||
{
|
|
||||||
int index = 0;
|
|
||||||
for(auto iter = mResultNames.begin(); iter != mResultNames.end(); iter++, index++)
|
|
||||||
{
|
|
||||||
if(&(*iter) == mList.getSelectedComponent())
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GuiGameScraper::input(InputConfig* config, Input input)
|
bool GuiGameScraper::input(InputConfig* config, Input input)
|
||||||
{
|
{
|
||||||
if(config->isMappedTo("a", input) && input.value != 0)
|
if(config->isMappedTo("b", input) && input.value)
|
||||||
{
|
|
||||||
//if you're on a result
|
|
||||||
if(getSelectedIndex() != -1)
|
|
||||||
{
|
|
||||||
mDoneFunc(mScraperResults.at(getSelectedIndex()));
|
|
||||||
delete this;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}else if(config->isMappedTo("b", input) && input.value != 0)
|
|
||||||
{
|
{
|
||||||
if(mSkipFunc)
|
if(mSkipFunc)
|
||||||
mSkipFunc();
|
mSkipFunc();
|
||||||
|
@ -157,74 +93,23 @@ bool GuiGameScraper::input(InputConfig* config, Input input)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wasEditing = mSearchText.isEditing();
|
return GuiComponent::input(config, input);
|
||||||
bool ret = GuiComponent::input(config, input);
|
|
||||||
|
|
||||||
if(config->isMappedTo("up", input) || config->isMappedTo("down", input) && input.value != 0)
|
|
||||||
{
|
|
||||||
updateInfoPane();
|
|
||||||
}
|
|
||||||
|
|
||||||
//stopped editing
|
|
||||||
if(wasEditing && !mSearchText.isEditing())
|
|
||||||
{
|
|
||||||
//update results
|
|
||||||
search();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GuiGameScraper::updateInfoPane()
|
|
||||||
{
|
|
||||||
int i = getSelectedIndex();
|
|
||||||
if(i != -1)
|
|
||||||
{
|
|
||||||
mResultName.setText(mScraperResults.at(i).get("name"));
|
|
||||||
mResultDesc.setText(mScraperResults.at(i).get("desc"));
|
|
||||||
mResultInfo.setScrollPos(Eigen::Vector2d(0, 0));
|
|
||||||
mResultInfo.resetAutoScrollTimer();
|
|
||||||
|
|
||||||
std::string thumb = mScraperResults.at(i).get("thumbnail");
|
|
||||||
mResultThumbnail.setImage("");
|
|
||||||
if(!thumb.empty())
|
|
||||||
mThumbnailReq = std::unique_ptr<HttpReq>(new HttpReq(thumb));
|
|
||||||
else
|
|
||||||
mThumbnailReq.reset();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiGameScraper::update(int deltaTime)
|
void GuiGameScraper::update(int deltaTime)
|
||||||
{
|
{
|
||||||
if(mThumbnailReq && mThumbnailReq->status() != HttpReq::REQ_IN_PROGRESS)
|
// HAAACK because AsyncReq wont get pushed in the right order if search happens on creation
|
||||||
|
if(mSearchCountdown > 0)
|
||||||
{
|
{
|
||||||
updateThumbnail();
|
mSearchCountdown--;
|
||||||
|
if(mSearchCountdown == 0)
|
||||||
|
mSearch->setSearchParams(mSearchParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
GuiComponent::update(deltaTime);
|
GuiComponent::update(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiGameScraper::updateThumbnail()
|
|
||||||
{
|
|
||||||
if(mThumbnailReq && mThumbnailReq->status() == HttpReq::REQ_SUCCESS)
|
|
||||||
{
|
|
||||||
std::string content = mThumbnailReq->getContent();
|
|
||||||
mResultThumbnail.setImage(content.data(), content.length());
|
|
||||||
}else{
|
|
||||||
LOG(LogWarning) << "thumbnail req failed: " << mThumbnailReq->getErrorMsg();
|
|
||||||
mResultThumbnail.setImage("");
|
|
||||||
}
|
|
||||||
|
|
||||||
mThumbnailReq.reset();
|
|
||||||
mList.onPositionChanged(); // a hack to fix the thumbnail position since its size changed
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<HelpPrompt> GuiGameScraper::getHelpPrompts()
|
std::vector<HelpPrompt> GuiGameScraper::getHelpPrompts()
|
||||||
{
|
{
|
||||||
std::vector<HelpPrompt> prompts = mList.getHelpPrompts();
|
return mGrid.getHelpPrompts();
|
||||||
if(getSelectedIndex() != -1)
|
|
||||||
prompts.push_back(HelpPrompt("a", "accept result"));
|
|
||||||
|
|
||||||
prompts.push_back(HelpPrompt("b", "cancel/skip"));
|
|
||||||
return prompts;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../GuiComponent.h"
|
#include "../GuiComponent.h"
|
||||||
#include "../scrapers/Scraper.h"
|
#include "../components/ScraperSearchComponent.h"
|
||||||
#include "../components/ComponentGrid.h"
|
|
||||||
#include "../components/TextComponent.h"
|
|
||||||
#include "../components/ScrollableContainer.h"
|
|
||||||
#include "../components/TextEditComponent.h"
|
|
||||||
#include "../components/NinePatchComponent.h"
|
#include "../components/NinePatchComponent.h"
|
||||||
#include "../components/ImageComponent.h"
|
|
||||||
#include "../Settings.h"
|
|
||||||
#include "../HttpReq.h"
|
|
||||||
|
|
||||||
#define MAX_SCRAPER_RESULTS 5
|
|
||||||
|
|
||||||
class GuiGameScraper : public GuiComponent
|
class GuiGameScraper : public GuiComponent
|
||||||
{
|
{
|
||||||
|
@ -21,37 +12,18 @@ public:
|
||||||
bool input(InputConfig* config, Input input) override;
|
bool input(InputConfig* config, Input input) override;
|
||||||
void update(int deltaTime) override;
|
void update(int deltaTime) override;
|
||||||
|
|
||||||
void search();
|
|
||||||
|
|
||||||
virtual std::vector<HelpPrompt> getHelpPrompts() override;
|
virtual std::vector<HelpPrompt> getHelpPrompts() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int getSelectedIndex();
|
int mSearchCountdown; // haaack
|
||||||
void onSearchDone(std::vector<MetaDataList> results);
|
|
||||||
void updateInfoPane();
|
|
||||||
void updateThumbnail();
|
|
||||||
|
|
||||||
ComponentGrid mList;
|
ComponentGrid mGrid;
|
||||||
NinePatchComponent mBox;
|
NinePatchComponent mBox;
|
||||||
|
|
||||||
TextComponent mHeader;
|
std::shared_ptr<ScraperSearchComponent> mSearch;
|
||||||
|
|
||||||
TextComponent mResultName;
|
|
||||||
ScrollableContainer mResultInfo;
|
|
||||||
TextComponent mResultDesc;
|
|
||||||
ImageComponent mResultThumbnail;
|
|
||||||
|
|
||||||
TextComponent mSearchLabel;
|
|
||||||
TextEditComponent mSearchText;
|
|
||||||
|
|
||||||
std::vector<TextComponent> mResultNames;
|
|
||||||
|
|
||||||
ScraperSearchParams mSearchParams;
|
ScraperSearchParams mSearchParams;
|
||||||
|
|
||||||
std::vector<MetaDataList> mScraperResults;
|
|
||||||
|
|
||||||
std::function<void(MetaDataList)> mDoneFunc;
|
std::function<void(MetaDataList)> mDoneFunc;
|
||||||
std::function<void()> mSkipFunc;
|
std::function<void()> mSkipFunc;
|
||||||
|
|
||||||
std::unique_ptr<HttpReq> mThumbnailReq;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,115 +7,50 @@
|
||||||
#include "GuiMsgBoxYesNo.h"
|
#include "GuiMsgBoxYesNo.h"
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
#define MDED_RESERVED_ROWS 3
|
|
||||||
|
|
||||||
GuiMetaDataEd::GuiMetaDataEd(Window* window, MetaDataList* md, const std::vector<MetaDataDecl>& mdd, ScraperSearchParams scraperParams,
|
GuiMetaDataEd::GuiMetaDataEd(Window* window, MetaDataList* md, const std::vector<MetaDataDecl>& mdd, ScraperSearchParams scraperParams,
|
||||||
const std::string& header, std::function<void()> saveCallback, std::function<void()> deleteFunc) : GuiComponent(window),
|
const std::string& header, std::function<void()> saveCallback, std::function<void()> deleteFunc) : GuiComponent(window),
|
||||||
mScraperParams(scraperParams),
|
mScraperParams(scraperParams),
|
||||||
mBox(mWindow, ":/frame.png", 0xAAAAAAFF, 0xCCCCCCFF),
|
mMenu(window, header.c_str()),
|
||||||
mList(window, Eigen::Vector2i(2, mdd.size() + MDED_RESERVED_ROWS)),
|
|
||||||
mHeader(window),
|
|
||||||
mMetaDataDecl(mdd),
|
mMetaDataDecl(mdd),
|
||||||
mMetaData(md),
|
mMetaData(md),
|
||||||
mSavedCallback(saveCallback), mDeleteFunc(deleteFunc),
|
mSavedCallback(saveCallback), mDeleteFunc(deleteFunc)
|
||||||
mDeleteButton(window), mFetchButton(window), mSaveButton(window)
|
|
||||||
{
|
{
|
||||||
unsigned int sw = Renderer::getScreenWidth();
|
setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
|
||||||
unsigned int sh = Renderer::getScreenHeight();
|
|
||||||
|
|
||||||
addChild(&mBox);
|
addChild(&mMenu);
|
||||||
|
|
||||||
addChild(&mHeader);
|
|
||||||
mHeader.setText(header);
|
|
||||||
|
|
||||||
//initialize buttons
|
|
||||||
mDeleteButton.setText("DELETE", "delete file");
|
|
||||||
if(mDeleteFunc)
|
|
||||||
{
|
|
||||||
std::function<void()> deleteFileAndSelf = [&] { mDeleteFunc(); delete this; };
|
|
||||||
std::function<void()> pressedFunc = [this, deleteFileAndSelf] { mWindow->pushGui(new GuiMsgBoxYesNo(mWindow, "This will delete a file!\nAre you sure?", deleteFileAndSelf)); };
|
|
||||||
mDeleteButton.setPressedFunc(pressedFunc);
|
|
||||||
}
|
|
||||||
|
|
||||||
mFetchButton.setText("FETCH", "download metadata");
|
|
||||||
mFetchButton.setPressedFunc(std::bind(&GuiMetaDataEd::fetch, this));
|
|
||||||
|
|
||||||
mSaveButton.setText("SAVE", "save");
|
|
||||||
mSaveButton.setPressedFunc([&] { save(); delete this; });
|
|
||||||
|
|
||||||
//initialize metadata list
|
|
||||||
addChild(&mList);
|
|
||||||
populateList(mdd);
|
|
||||||
mList.setPosition((sw - mList.getSize().x()) / 2.0f, (sh - mList.getSize().y()) / 2.0f); //center it
|
|
||||||
mList.resetCursor();
|
|
||||||
|
|
||||||
mBox.fitTo(mList.getSize(), mList.getPosition(), Eigen::Vector2f(12, 12));
|
|
||||||
|
|
||||||
mHeader.setPosition(mList.getPosition());
|
|
||||||
mHeader.setSize(mList.getSize().x(), 0);
|
|
||||||
mHeader.setCentered(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
GuiMetaDataEd::~GuiMetaDataEd()
|
|
||||||
{
|
|
||||||
for(auto iter = mLabels.begin(); iter != mLabels.end(); iter++)
|
|
||||||
{
|
|
||||||
delete *iter;
|
|
||||||
}
|
|
||||||
for(auto iter = mEditors.begin(); iter != mEditors.end(); iter++)
|
|
||||||
{
|
|
||||||
delete *iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GuiMetaDataEd::populateList(const std::vector<MetaDataDecl>& mdd)
|
|
||||||
{
|
|
||||||
// PATH //(centered, not part of componentlist)
|
|
||||||
|
|
||||||
//---GAME NAME--- //(at 1,1; size 3,1) (TextEditComponent)
|
|
||||||
//DEL SCRP --- //(buttons)
|
|
||||||
//Fav: Y/N --- //metadata start
|
|
||||||
//Desc: ... --- //multiline texteditcomponent
|
|
||||||
//Img: ... ---
|
|
||||||
//--- SAVE ---
|
|
||||||
|
|
||||||
using namespace Eigen;
|
|
||||||
|
|
||||||
int y = 0;
|
|
||||||
|
|
||||||
//fetch button
|
|
||||||
mList.setEntry(Vector2i(0, y), Vector2i(1, 1), &mFetchButton, true, ComponentGrid::AlignLeft);
|
|
||||||
|
|
||||||
//delete button
|
|
||||||
mList.setEntry(Vector2i(1, y), Vector2i(1, 1), &mDeleteButton, true, ComponentGrid::AlignRight);
|
|
||||||
|
|
||||||
y++;
|
|
||||||
|
|
||||||
|
// populate list
|
||||||
for(auto iter = mdd.begin(); iter != mdd.end(); iter++)
|
for(auto iter = mdd.begin(); iter != mdd.end(); iter++)
|
||||||
{
|
{
|
||||||
TextComponent* label = new TextComponent(mWindow);
|
auto ed = MetaDataList::makeEditor(mWindow, iter->type);
|
||||||
label->setText(iter->key);
|
|
||||||
mList.setEntry(Vector2i(0, y), Vector2i(1, 1), label, false, ComponentGrid::AlignLeft);
|
|
||||||
mLabels.push_back(label);
|
|
||||||
|
|
||||||
GuiComponent* ed = MetaDataList::makeEditor(mWindow, iter->type);
|
|
||||||
ed->setSize(Renderer::getScreenWidth() * 0.4f, ed->getSize().y());
|
|
||||||
ed->setValue(mMetaData->get(iter->key));
|
ed->setValue(mMetaData->get(iter->key));
|
||||||
mList.setEntry(Vector2i(1, y), Vector2i(1, 1), ed, true, ComponentGrid::AlignRight);
|
|
||||||
mEditors.push_back(ed);
|
mEditors.push_back(ed);
|
||||||
|
mMenu.addWithLabel(iter->key, ed);
|
||||||
y++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//save button
|
//add buttons
|
||||||
mList.setEntry(Vector2i(0, y), Vector2i(2, 1), &mSaveButton, true, ComponentGrid::AlignCenter);
|
mMenu.addButton("SCRAPE", "download metadata from the Internet", std::bind(&GuiMetaDataEd::fetch, this));
|
||||||
|
mMenu.addButton("SAVE", "save changes", [&] { save(); delete this; });
|
||||||
|
|
||||||
|
if(mDeleteFunc)
|
||||||
|
{
|
||||||
|
auto deleteFileAndSelf = [&] { mDeleteFunc(); delete this; };
|
||||||
|
auto deleteBtnFunc = [this, deleteFileAndSelf] { mWindow->pushGui(new GuiMsgBoxYesNo(mWindow, "This will delete a file!\nAre you sure?", deleteFileAndSelf)); };
|
||||||
|
mMenu.addButton("DELETE", "delete this game on disk", deleteBtnFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// initially put cursor on "SCRAPE"
|
||||||
|
mMenu.setCursorToButtons();
|
||||||
|
|
||||||
|
// position menu
|
||||||
|
mMenu.setPosition((mSize.x() - mMenu.getSize().x()) / 2, (mSize.y() - mMenu.getSize().y()) / 2); //center it
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiMetaDataEd::save()
|
void GuiMetaDataEd::save()
|
||||||
{
|
{
|
||||||
for(unsigned int i = 0; i < mLabels.size(); i++)
|
for(unsigned int i = 0; i < mEditors.size(); i++)
|
||||||
{
|
{
|
||||||
mMetaData->set(mLabels.at(i)->getValue(), mEditors.at(i)->getValue());
|
mMetaData->set(mMetaDataDecl.at(i).key, mEditors.at(i)->getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mSavedCallback)
|
if(mSavedCallback)
|
||||||
|
@ -126,7 +61,6 @@ void GuiMetaDataEd::fetch()
|
||||||
{
|
{
|
||||||
GuiGameScraper* scr = new GuiGameScraper(mWindow, mScraperParams, std::bind(&GuiMetaDataEd::fetchDone, this, std::placeholders::_1));
|
GuiGameScraper* scr = new GuiGameScraper(mWindow, mScraperParams, std::bind(&GuiMetaDataEd::fetchDone, this, std::placeholders::_1));
|
||||||
mWindow->pushGui(scr);
|
mWindow->pushGui(scr);
|
||||||
scr->search();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiMetaDataEd::fetchDone(MetaDataList result)
|
void GuiMetaDataEd::fetchDone(MetaDataList result)
|
||||||
|
@ -187,7 +121,7 @@ bool GuiMetaDataEd::input(InputConfig* config, Input input)
|
||||||
|
|
||||||
std::vector<HelpPrompt> GuiMetaDataEd::getHelpPrompts()
|
std::vector<HelpPrompt> GuiMetaDataEd::getHelpPrompts()
|
||||||
{
|
{
|
||||||
std::vector<HelpPrompt> prompts = mList.getHelpPrompts();
|
std::vector<HelpPrompt> prompts = mMenu.getHelpPrompts();
|
||||||
prompts.push_back(HelpPrompt("b", "discard changes"));
|
prompts.push_back(HelpPrompt("b", "discard changes"));
|
||||||
return prompts;
|
return prompts;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../GuiComponent.h"
|
#include "../GuiComponent.h"
|
||||||
#include "../components/ComponentGrid.h"
|
#include "../components/MenuComponent.h"
|
||||||
#include "../MetaData.h"
|
#include "../MetaData.h"
|
||||||
#include "../components/TextComponent.h"
|
|
||||||
#include "../components/NinePatchComponent.h"
|
|
||||||
#include "../components/ButtonComponent.h"
|
|
||||||
#include "../scrapers/Scraper.h"
|
#include "../scrapers/Scraper.h"
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
@ -15,7 +12,6 @@ class GuiMetaDataEd : public GuiComponent
|
||||||
public:
|
public:
|
||||||
GuiMetaDataEd(Window* window, MetaDataList* md, const std::vector<MetaDataDecl>& mdd, ScraperSearchParams params,
|
GuiMetaDataEd(Window* window, MetaDataList* md, const std::vector<MetaDataDecl>& mdd, ScraperSearchParams params,
|
||||||
const std::string& header, std::function<void()> savedCallback, std::function<void()> deleteFunc);
|
const std::string& header, std::function<void()> savedCallback, std::function<void()> deleteFunc);
|
||||||
virtual ~GuiMetaDataEd();
|
|
||||||
|
|
||||||
bool input(InputConfig* config, Input input) override;
|
bool input(InputConfig* config, Input input) override;
|
||||||
|
|
||||||
|
@ -26,25 +22,14 @@ private:
|
||||||
void fetch();
|
void fetch();
|
||||||
void fetchDone(MetaDataList result);
|
void fetchDone(MetaDataList result);
|
||||||
|
|
||||||
void populateList(const std::vector<MetaDataDecl>& mdd);
|
MenuComponent mMenu;
|
||||||
|
|
||||||
ScraperSearchParams mScraperParams;
|
ScraperSearchParams mScraperParams;
|
||||||
|
|
||||||
NinePatchComponent mBox;
|
std::vector< std::shared_ptr<GuiComponent> > mEditors;
|
||||||
|
|
||||||
ComponentGrid mList;
|
|
||||||
|
|
||||||
TextComponent mHeader;
|
|
||||||
|
|
||||||
std::vector<TextComponent*> mLabels;
|
|
||||||
std::vector<GuiComponent*> mEditors;
|
|
||||||
|
|
||||||
std::vector<MetaDataDecl> mMetaDataDecl;
|
std::vector<MetaDataDecl> mMetaDataDecl;
|
||||||
MetaDataList* mMetaData;
|
MetaDataList* mMetaData;
|
||||||
std::function<void()> mSavedCallback;
|
std::function<void()> mSavedCallback;
|
||||||
std::function<void()> mDeleteFunc;
|
std::function<void()> mDeleteFunc;
|
||||||
|
|
||||||
ButtonComponent mDeleteButton;
|
|
||||||
ButtonComponent mFetchButton;
|
|
||||||
ButtonComponent mSaveButton;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -61,7 +61,6 @@ void GuiScraperLog::next()
|
||||||
[this, search] { resultEmpty(search); });
|
[this, search] { resultEmpty(search); });
|
||||||
|
|
||||||
mWindow->pushGui(ggs);
|
mWindow->pushGui(ggs);
|
||||||
ggs->search();
|
|
||||||
}else{
|
}else{
|
||||||
std::shared_ptr<Scraper> scraper = Settings::getInstance()->getScraper();
|
std::shared_ptr<Scraper> scraper = Settings::getInstance()->getScraper();
|
||||||
scraper->getResultsAsync(search, mWindow, [this, search] (std::vector<MetaDataList> mdls) {
|
scraper->getResultsAsync(search, mWindow, [this, search] (std::vector<MetaDataList> mdls) {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
#include "GamesDBScraper.h"
|
#include "GamesDBScraper.h"
|
||||||
#include "../guis/GuiGameScraper.h"
|
#include "../components/ScraperSearchComponent.h"
|
||||||
#include "../components/AsyncReqComponent.h"
|
#include "../components/AsyncReqComponent.h"
|
||||||
#include "../Log.h"
|
#include "../Log.h"
|
||||||
#include "../pugiXML/pugixml.hpp"
|
#include "../pugiXML/pugixml.hpp"
|
||||||
#include "../MetaData.h"
|
#include "../MetaData.h"
|
||||||
|
#include "../Settings.h"
|
||||||
#include <boost/assign.hpp>
|
#include <boost/assign.hpp>
|
||||||
|
|
||||||
const char* GamesDBScraper::getName() { return "TheGamesDB"; }
|
const char* GamesDBScraper::getName() { return "TheGamesDB"; }
|
||||||
|
|
Loading…
Reference in a new issue