mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-24 23:25: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/OptionListComponent.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/SliderComponent.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/NinePatchComponent.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/SliderComponent.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");
|
||||
}
|
||||
|
||||
GuiComponent* MetaDataList::makeDisplay(Window* window, MetaDataType as)
|
||||
std::shared_ptr<GuiComponent> MetaDataList::makeEditor(Window* window, MetaDataType as)
|
||||
{
|
||||
switch(as)
|
||||
{
|
||||
case MD_RATING:
|
||||
{
|
||||
RatingComponent* comp = new 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;
|
||||
return std::make_shared<RatingComponent>(window);
|
||||
}
|
||||
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);
|
||||
return comp;
|
||||
}
|
||||
case MD_DATE:
|
||||
{
|
||||
DateTimeComponent* comp = new DateTimeComponent(window);
|
||||
return comp;
|
||||
return std::make_shared<DateTimeComponent>(window);
|
||||
}
|
||||
case MD_TIME:
|
||||
{
|
||||
DateTimeComponent* comp = new DateTimeComponent(window);
|
||||
auto comp = std::make_shared<DateTimeComponent>(window);
|
||||
comp->setDisplayMode(DateTimeComponent::DISP_RELATIVE_TO_NOW);
|
||||
return comp;
|
||||
}
|
||||
default:
|
||||
{
|
||||
TextEditComponent* comp = new TextEditComponent(window);
|
||||
return comp;
|
||||
return std::make_shared<TextEditComponent>(window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,8 +55,7 @@ public:
|
|||
float getFloat(const std::string& key) const;
|
||||
boost::posix_time::ptime getTime(const std::string& key) const;
|
||||
|
||||
static GuiComponent* makeDisplay(Window* window, MetaDataType as);
|
||||
static GuiComponent* makeEditor(Window* window, MetaDataType as);
|
||||
static std::shared_ptr<GuiComponent> makeEditor(Window* window, MetaDataType as);
|
||||
|
||||
inline MetaDataListType getType() const { return mType; }
|
||||
inline const std::vector<MetaDataDecl>& getMDD() const { return getMDDByType(getType()); }
|
||||
|
|
|
@ -39,14 +39,31 @@ namespace Renderer {
|
|||
if(box[3] == 0)
|
||||
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
|
||||
//so (0, 0, 1, 1) is the bottom left pixel
|
||||
//everything else uses y+ = down, so flip it to be consistent
|
||||
//rect.pos.y = Renderer::getScreenHeight() - rect.pos.y - rect.size.y;
|
||||
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);
|
||||
glScissor(box[0], box[1], box[2], box[3]);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
#include "../Renderer.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"),
|
||||
mFocused(false),
|
||||
mEnabled(true),
|
||||
mTextColorFocused(0xFFFFFFFF), mTextColorUnfocused(0x777777FF)
|
||||
{
|
||||
setSize(64, 48);
|
||||
setPressedFunc(func);
|
||||
setText(text, helpText);
|
||||
}
|
||||
|
||||
void ButtonComponent::onSizeChanged()
|
||||
|
@ -24,7 +26,7 @@ bool ButtonComponent::input(InputConfig* config, Input input)
|
|||
{
|
||||
if(config->isMappedTo("a", input) && input.value != 0)
|
||||
{
|
||||
if(mPressedFunc)
|
||||
if(mPressedFunc && mEnabled)
|
||||
mPressedFunc();
|
||||
return true;
|
||||
}
|
||||
|
@ -48,13 +50,34 @@ void ButtonComponent::setText(const std::string& text, const std::string& helpTe
|
|||
void ButtonComponent::onFocusGained()
|
||||
{
|
||||
mFocused = true;
|
||||
mBox.setImagePath(":/button_filled.png");
|
||||
updateImage();
|
||||
}
|
||||
|
||||
void ButtonComponent::onFocusLost()
|
||||
{
|
||||
mFocused = false;
|
||||
mBox.setImagePath(":/button.png");
|
||||
updateImage();
|
||||
}
|
||||
|
||||
void ButtonComponent::setEnabled(bool enabled)
|
||||
{
|
||||
mEnabled = enabled;
|
||||
updateImage();
|
||||
}
|
||||
|
||||
void ButtonComponent::updateImage()
|
||||
{
|
||||
if(!mEnabled || !mPressedFunc)
|
||||
{
|
||||
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)
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
class ButtonComponent : public GuiComponent
|
||||
{
|
||||
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 setEnabled(bool enable);
|
||||
|
||||
bool input(InputConfig* config, Input input) override;
|
||||
void render(const Eigen::Affine3f& parentTrans) override;
|
||||
|
||||
|
@ -28,10 +30,12 @@ private:
|
|||
std::function<void()> mPressedFunc;
|
||||
|
||||
bool mFocused;
|
||||
bool mEnabled;
|
||||
unsigned int mTextColorFocused;
|
||||
unsigned int mTextColorUnfocused;
|
||||
|
||||
unsigned int getCurTextColor() const;
|
||||
void updateImage();
|
||||
|
||||
std::string mText;
|
||||
std::string mHelpText;
|
||||
|
|
|
@ -2,281 +2,219 @@
|
|||
#include "../Log.h"
|
||||
#include "../Renderer.h"
|
||||
|
||||
#define INITIAL_CELL_SIZE 12
|
||||
using namespace GridFlags;
|
||||
|
||||
ComponentGrid::ComponentGrid(Window* window, Eigen::Vector2i gridDimensions) : GuiComponent(window),
|
||||
mGrid(NULL), mColumnWidths(NULL), mRowHeights(NULL),
|
||||
mColumnWidthForced(NULL), mRowHeightForced(NULL),
|
||||
mCursor(-1, -1)
|
||||
ComponentGrid::ComponentGrid(Window* window, const Eigen::Vector2i& gridDimensions) : GuiComponent(window),
|
||||
mGridSize(gridDimensions), mCursor(0, 0)
|
||||
{
|
||||
mEntries.reserve(gridDimensions.x() * gridDimensions.y());
|
||||
makeCells(gridDimensions);
|
||||
assert(gridDimensions.x() > 0 && gridDimensions.y() > 0);
|
||||
|
||||
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()
|
||||
{
|
||||
for(auto iter = mEntries.begin(); iter != mEntries.end(); iter++)
|
||||
{
|
||||
delete *iter;
|
||||
}
|
||||
delete[] mRowHeights;
|
||||
delete[] mColWidths;
|
||||
}
|
||||
|
||||
void ComponentGrid::makeCells(Eigen::Vector2i size)
|
||||
float ComponentGrid::getColWidth(int col)
|
||||
{
|
||||
if(mGrid)
|
||||
delete[] mGrid;
|
||||
if(mColumnWidths)
|
||||
delete[] mColumnWidths;
|
||||
if(mRowHeights)
|
||||
delete[] mRowHeights;
|
||||
if(mColWidths[col] != 0)
|
||||
return mColWidths[col] * mSize.x();
|
||||
|
||||
mGridSize = size;
|
||||
mGrid = new ComponentEntry*[size.x() * size.y()];
|
||||
std::fill(mGrid, mGrid + (size.x() * size.y()), (ComponentEntry*)NULL);
|
||||
// calculate automatic width
|
||||
float freeWidthPerc = 1;
|
||||
int between = 0;
|
||||
for(int x = 0; x < mGridSize.x(); x++)
|
||||
{
|
||||
freeWidthPerc -= mColWidths[x]; // if it's 0 it won't do anything
|
||||
if(mColWidths[x] == 0)
|
||||
between++;
|
||||
}
|
||||
|
||||
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();
|
||||
return (freeWidthPerc * mSize.x()) / between;
|
||||
}
|
||||
|
||||
void ComponentGrid::setEntry(Eigen::Vector2i pos, Eigen::Vector2i size, GuiComponent* component, bool canFocus, AlignmentType align,
|
||||
Eigen::Matrix<bool, 1, 2> autoFit, UpdateBehavior updateType)
|
||||
float ComponentGrid::getRowHeight(int row)
|
||||
{
|
||||
if(pos.x() > mGridSize.x() || pos.y() > mGridSize.y() || pos.x() < 0 || pos.y() < 0)
|
||||
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 set entry beyond grid size!";
|
||||
return;
|
||||
freeHeightPerc -= mRowHeights[y]; // if it's 0 it won't do anything
|
||||
if(mRowHeights[y] == 0)
|
||||
between++;
|
||||
}
|
||||
|
||||
if(component == NULL)
|
||||
{
|
||||
LOG(LogError) << "Tried to add NULL component to ComponentList!";
|
||||
return;
|
||||
}
|
||||
return (freeHeightPerc * mSize.y()) / between;
|
||||
}
|
||||
|
||||
ComponentEntry* entry = new ComponentEntry(Eigen::Vector2i(pos.x(), pos.y()), Eigen::Vector2i(size.x(), size.y()), component, updateType, canFocus, align);
|
||||
void ComponentGrid::setColWidthPerc(int col, float width)
|
||||
{
|
||||
assert(col >= 0 && col < mGridSize.x());
|
||||
mColWidths[col] = width;
|
||||
onSizeChanged();
|
||||
}
|
||||
|
||||
mEntries.push_back(entry);
|
||||
void ComponentGrid::setRowHeightPerc(int row, float height)
|
||||
{
|
||||
assert(row >= 0 && row < mGridSize.y());
|
||||
mRowHeights[row] = height;
|
||||
onSizeChanged();
|
||||
}
|
||||
|
||||
for(int y = pos.y(); y < pos.y() + size.y(); y++)
|
||||
{
|
||||
for(int x = pos.x(); x < pos.x() + size.x(); x++)
|
||||
{
|
||||
setCell(x, y, mEntries.back());
|
||||
}
|
||||
}
|
||||
void ComponentGrid::setEntry(const std::shared_ptr<GuiComponent>& comp, const Eigen::Vector2i& pos, bool canFocus, bool resize, const Eigen::Vector2i& size,
|
||||
unsigned int border, GridFlags::UpdateType updateType)
|
||||
{
|
||||
assert(pos.x() >= 0 && pos.x() < mGridSize.x() && pos.y() >= 0 && pos.y() < mGridSize.y());
|
||||
assert(comp != nullptr);
|
||||
assert(comp->getParent() == NULL);
|
||||
|
||||
if(component->getParent() != NULL)
|
||||
LOG(LogError) << "ComponentGrid ruining an existing parent-child relationship! Call a social worker!";
|
||||
component->setParent(this);
|
||||
GridEntry entry(pos, size, comp, canFocus, resize, updateType, border);
|
||||
mCells.push_back(entry);
|
||||
|
||||
addChild(comp.get());
|
||||
|
||||
if(!cursorValid() && canFocus)
|
||||
mCursor = pos;
|
||||
|
||||
//update the column width and row height
|
||||
//if(autoFit.x() && (int)getColumnWidth(pos.x()) < component->getSize().x())
|
||||
// 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();
|
||||
updateCellComponent(mCells.back());
|
||||
updateSeparators();
|
||||
}
|
||||
|
||||
void ComponentGrid::removeEntriesIn(Eigen::Vector2i pos, Eigen::Vector2i size)
|
||||
bool ComponentGrid::removeEntry(const std::shared_ptr<GuiComponent>& comp)
|
||||
{
|
||||
auto iter = mEntries.begin();
|
||||
while(iter != mEntries.end())
|
||||
for(auto it = mCells.begin(); it != mCells.end(); it++)
|
||||
{
|
||||
if((*iter)->pos.x() >= pos.x() && (*iter)->pos.x() < pos.x() + size.x()
|
||||
&& (*iter)->pos.y() >= pos.y() && (*iter)->pos.y() < pos.y() + size.y())
|
||||
if(it->component == comp)
|
||||
{
|
||||
if((*iter)->component->getParent() == this)
|
||||
(*iter)->component->setParent(NULL);
|
||||
|
||||
delete *iter;
|
||||
iter = mEntries.erase(iter);
|
||||
}else{
|
||||
iter++;
|
||||
removeChild(comp.get());
|
||||
mCells.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
resetCursor();
|
||||
mLineColors.reserve(mLines.size());
|
||||
Renderer::buildGLColorArray((GLubyte*)mLineColors.data(), 0xC6C7C6FF, mLines.size());
|
||||
}
|
||||
|
||||
void ComponentGrid::forceRowHeight(int row, unsigned int size)
|
||||
void ComponentGrid::onSizeChanged()
|
||||
{
|
||||
mRowHeights[row] = size;
|
||||
mRowHeightForced[row] = true;
|
||||
updateSize();
|
||||
updateComponentOffsets();
|
||||
for(auto it = mCells.begin(); it != mCells.end(); it++)
|
||||
updateCellComponent(*it);
|
||||
|
||||
updateSeparators();
|
||||
}
|
||||
|
||||
void ComponentGrid::forceColumnWidth(int col, unsigned int size)
|
||||
ComponentGrid::GridEntry* ComponentGrid::getCellAt(int x, int y)
|
||||
{
|
||||
mColumnWidths[col] = size;
|
||||
mColumnWidthForced[col] = true;
|
||||
updateSize();
|
||||
updateComponentOffsets();
|
||||
}
|
||||
assert(x >= 0 && x < mGridSize.x() && y >= 0 && y < mGridSize.y());
|
||||
|
||||
unsigned int ComponentGrid::getRowHeight(int row) { return mRowHeights[row]; }
|
||||
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())
|
||||
for(auto it = mCells.begin(); it != mCells.end(); it++)
|
||||
{
|
||||
LOG(LogError) << "Invalid setCell - position " << x << ", " << y << " out of bounds!";
|
||||
return;
|
||||
int xmin = it->pos.x();
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if(!input.value)
|
||||
|
@ -284,23 +222,19 @@ bool ComponentGrid::input(InputConfig* config, Input input)
|
|||
|
||||
if(config->isMappedTo("down", input))
|
||||
{
|
||||
moveCursor(Eigen::Vector2i(0, 1));
|
||||
return true;
|
||||
return moveCursor(Eigen::Vector2i(0, 1));
|
||||
}
|
||||
if(config->isMappedTo("up", input))
|
||||
{
|
||||
moveCursor(Eigen::Vector2i(0, -1));
|
||||
return true;
|
||||
return moveCursor(Eigen::Vector2i(0, -1));
|
||||
}
|
||||
if(config->isMappedTo("left", input))
|
||||
{
|
||||
moveCursor(Eigen::Vector2i(-1, 0));
|
||||
return true;
|
||||
return moveCursor(Eigen::Vector2i(-1, 0));
|
||||
}
|
||||
if(config->isMappedTo("right", input))
|
||||
{
|
||||
moveCursor(Eigen::Vector2i(1, 0));
|
||||
return true;
|
||||
return moveCursor(Eigen::Vector2i(1, 0));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -308,47 +242,28 @@ bool ComponentGrid::input(InputConfig* config, Input input)
|
|||
|
||||
void ComponentGrid::resetCursor()
|
||||
{
|
||||
auto iter = mEntries.begin();
|
||||
while(iter != mEntries.end())
|
||||
{
|
||||
if((*iter)->canFocus)
|
||||
break;
|
||||
iter++;
|
||||
}
|
||||
|
||||
if(iter == mEntries.end())
|
||||
{
|
||||
mCursor = Eigen::Vector2i(-1, -1);
|
||||
if(!mCells.size())
|
||||
return;
|
||||
}
|
||||
|
||||
const Eigen::Vector2i origCursor = mCursor;
|
||||
mCursor << (*iter)->pos[0], (*iter)->pos[1];
|
||||
onCursorMoved(origCursor, mCursor);
|
||||
}
|
||||
|
||||
void ComponentGrid::moveCursor(Eigen::Vector2i dir)
|
||||
{
|
||||
if(dir.x() != 0 && dir.y() != 0)
|
||||
for(auto it = mCells.begin(); it != mCells.end(); it++)
|
||||
{
|
||||
LOG(LogError) << "Invalid cursor move dir!";
|
||||
return;
|
||||
}
|
||||
|
||||
Eigen::Vector2i origCursor = mCursor;
|
||||
|
||||
if(!cursorValid())
|
||||
{
|
||||
resetCursor();
|
||||
|
||||
if(!cursorValid())
|
||||
if(it->canFocus)
|
||||
{
|
||||
if(mCursor != origCursor)
|
||||
onCursorMoved(origCursor, mCursor);
|
||||
|
||||
return;
|
||||
Eigen::Vector2i origCursor = mCursor;
|
||||
mCursor = it->pos;
|
||||
onCursorMoved(origCursor, mCursor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ComponentGrid::moveCursor(Eigen::Vector2i dir)
|
||||
{
|
||||
assert(dir.x() || dir.y());
|
||||
|
||||
const Eigen::Vector2i origCursor = mCursor;
|
||||
|
||||
GridEntry* currentCursorEntry = getCellAt(mCursor);
|
||||
|
||||
Eigen::Vector2i searchAxis(dir.x() == 0, dir.y() == 0);
|
||||
|
||||
|
@ -358,13 +273,16 @@ void ComponentGrid::moveCursor(Eigen::Vector2i dir)
|
|||
|
||||
Eigen::Vector2i curDirPos = mCursor;
|
||||
|
||||
GridEntry* cursorEntry;
|
||||
//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);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
mCursor += searchAxis;
|
||||
|
@ -372,12 +290,14 @@ void ComponentGrid::moveCursor(Eigen::Vector2i dir)
|
|||
|
||||
//now again on search axis-
|
||||
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);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
mCursor -= searchAxis;
|
||||
|
@ -388,31 +308,36 @@ void ComponentGrid::moveCursor(Eigen::Vector2i dir)
|
|||
|
||||
//failed to find another focusable element in this direction
|
||||
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()
|
||||
{
|
||||
if(mCursor.x() < 0 || mCursor.y() < 0 || mCursor.x() >= mGridSize.x() || mCursor.y() >= mGridSize.y())
|
||||
return false;
|
||||
|
||||
return getCell(mCursor.x(), mCursor.y()) != NULL;
|
||||
return getCellAt(mCursor) != NULL;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
case UpdateAlways:
|
||||
(*iter)->component->update(deltaTime);
|
||||
break;
|
||||
|
||||
case UpdateFocused:
|
||||
if(cursorValid() && getCell(mCursor.x(), mCursor.y())->component == (*iter)->component)
|
||||
(*iter)->component->update(deltaTime);
|
||||
break;
|
||||
}
|
||||
if(it->updateType == UPDATE_ALWAYS || (it->updateType == UPDATE_WHEN_SELECTED && cursorEntry == &(*it)))
|
||||
it->component->update(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -420,79 +345,72 @@ void ComponentGrid::render(const Eigen::Affine3f& parentTrans)
|
|||
{
|
||||
Eigen::Affine3f trans = parentTrans * getTransform();
|
||||
|
||||
//draw cursor
|
||||
if(cursorValid())
|
||||
{
|
||||
ComponentEntry* entry = getCell(mCursor.x(), mCursor.y());
|
||||
Eigen::Affine3f entryTrans = trans * entry->component->getTransform();
|
||||
Renderer::setMatrix(entryTrans);
|
||||
renderChildren(trans);
|
||||
|
||||
Renderer::drawRect(0, 0, 4, 4, 0xFF0000FF);
|
||||
Renderer::drawRect(0, 0, (int)entry->component->getSize().x(), (int)entry->component->getSize().y(), 0x0000AA22);
|
||||
// draw cell separators
|
||||
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)
|
||||
{
|
||||
if(getSelectedComponent() != NULL)
|
||||
getSelectedComponent()->textInput(text);
|
||||
}
|
||||
|
||||
void ComponentGrid::onPositionChanged()
|
||||
{
|
||||
updateComponentOffsets();
|
||||
}
|
||||
|
||||
GuiComponent* ComponentGrid::getSelectedComponent()
|
||||
{
|
||||
if(!cursorValid())
|
||||
return NULL;
|
||||
return getCell(mCursor.x(), mCursor.y())->component;
|
||||
GridEntry* selectedEntry = getCellAt(mCursor);
|
||||
if(selectedEntry != NULL)
|
||||
selectedEntry->component->textInput(text);
|
||||
}
|
||||
|
||||
void ComponentGrid::onCursorMoved(Eigen::Vector2i from, Eigen::Vector2i to)
|
||||
{
|
||||
if(from != Eigen::Vector2i(-1, -1))
|
||||
getCell(from.x(), from.y())->component->onFocusLost();
|
||||
GridEntry* cell = getCellAt(from);
|
||||
if(cell)
|
||||
cell->component->onFocusLost();
|
||||
|
||||
if(to != Eigen::Vector2i(-1, -1))
|
||||
getCell(to.x(), to.y())->component->onFocusGained();
|
||||
cell = getCellAt(to);
|
||||
if(cell)
|
||||
cell->component->onFocusGained();
|
||||
|
||||
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> prompts;
|
||||
if(cursorValid())
|
||||
prompts = getSelectedComponent()->getHelpPrompts();
|
||||
GridEntry* e = getCellAt(mCursor);
|
||||
if(e)
|
||||
prompts = e->component->getHelpPrompts();
|
||||
|
||||
bool canScrollVert = true;
|
||||
bool canScrollHoriz = true;
|
||||
|
|
|
@ -2,63 +2,87 @@
|
|||
|
||||
#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.
|
||||
class ComponentGrid : public GuiComponent
|
||||
{
|
||||
public:
|
||||
ComponentGrid(Window* window, Eigen::Vector2i gridDimensions);
|
||||
ComponentGrid(Window* window, const Eigen::Vector2i& gridDimensions);
|
||||
virtual ~ComponentGrid();
|
||||
|
||||
enum UpdateBehavior
|
||||
{
|
||||
UpdateAlways, UpdateFocused
|
||||
};
|
||||
bool removeEntry(const std::shared_ptr<GuiComponent>& comp);
|
||||
|
||||
enum AlignmentType
|
||||
{
|
||||
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 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);
|
||||
|
||||
void textInput(const char* text) override;
|
||||
bool input(InputConfig* config, Input input) override;
|
||||
void update(int deltaTime) override;
|
||||
void render(const Eigen::Affine3f& parentTrans) override;
|
||||
|
||||
void forceColumnWidth(int col, unsigned int size);
|
||||
void forceRowHeight(int row, unsigned int size);
|
||||
|
||||
void updateComponent(GuiComponent* cmp);
|
||||
void onSizeChanged() override;
|
||||
|
||||
void resetCursor();
|
||||
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;
|
||||
|
||||
private:
|
||||
class ComponentEntry
|
||||
class GridEntry
|
||||
{
|
||||
public:
|
||||
Eigen::Vector2i pos;
|
||||
Eigen::Vector2i dim;
|
||||
GuiComponent* component;
|
||||
UpdateBehavior updateType;
|
||||
AlignmentType alignment;
|
||||
std::shared_ptr<GuiComponent> component;
|
||||
bool canFocus;
|
||||
bool resize;
|
||||
GridFlags::UpdateType updateType;
|
||||
unsigned int border;
|
||||
|
||||
ComponentEntry() : component(NULL), updateType(UpdateAlways), canFocus(true), alignment(AlignCenter) {};
|
||||
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) {};
|
||||
GridEntry(const Eigen::Vector2i& p = Eigen::Vector2i::Zero(), const Eigen::Vector2i& d = Eigen::Vector2i::Zero(),
|
||||
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
|
||||
{
|
||||
|
@ -66,30 +90,30 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
//Offset we render components by (for scrolling). [unimplemented]
|
||||
Eigen::Vector2f mComponentOffset;
|
||||
float* mRowHeights;
|
||||
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;
|
||||
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);
|
||||
unsigned int getRowHeight(int row);
|
||||
|
||||
unsigned int* mColumnWidths;
|
||||
unsigned int* mRowHeights;
|
||||
bool* mColumnWidthForced;
|
||||
bool* mRowHeightForced;
|
||||
|
||||
Eigen::Vector3f getCellOffset(Eigen::Vector2i gridPos);
|
||||
void updateSize();
|
||||
std::vector<GridEntry> mCells;
|
||||
|
||||
void onCursorMoved(Eigen::Vector2i from, Eigen::Vector2i to);
|
||||
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;
|
||||
mCameraOffset = 0;
|
||||
mFocused = false;
|
||||
}
|
||||
|
||||
void ComponentList::addRow(const ComponentListRow& row, bool setCursorHere)
|
||||
|
@ -41,6 +42,16 @@ void ComponentList::onSizeChanged()
|
|||
onCursorChanged(mScrollVelocity != 0 ? CURSOR_SCROLLING : CURSOR_STOPPED);
|
||||
}
|
||||
|
||||
void ComponentList::onFocusLost()
|
||||
{
|
||||
mFocused = false;
|
||||
}
|
||||
|
||||
void ComponentList::onFocusGained()
|
||||
{
|
||||
mFocused = true;
|
||||
}
|
||||
|
||||
bool ComponentList::input(InputConfig* config, Input input)
|
||||
{
|
||||
if(size() == 0)
|
||||
|
@ -127,23 +138,27 @@ void ComponentList::render(const Eigen::Affine3f& parentTrans)
|
|||
// draw our entries
|
||||
renderChildren(trans);
|
||||
|
||||
// draw selector bar
|
||||
// custom rendering
|
||||
Renderer::setMatrix(trans);
|
||||
|
||||
// inversion: src * (1 - dst) + dst * 0 = where src = 1
|
||||
// need a function that goes roughly 0x777777 -> 0xFFFFFF
|
||||
// and 0xFFFFFF -> 0x777777
|
||||
// (1 - dst) + 0x77
|
||||
// draw selector bar
|
||||
if(mFocused)
|
||||
{
|
||||
// inversion: src * (1 - dst) + dst * 0 = where src = 1
|
||||
// need a function that goes roughly 0x777777 -> 0xFFFFFF
|
||||
// and 0xFFFFFF -> 0x777777
|
||||
// (1 - dst) + 0x77
|
||||
|
||||
const float selectedRowHeight = getRowHeight(mEntries.at(mCursor).data);
|
||||
Renderer::drawRect(0, (int)mSelectorBarOffset, (int)mSize.x(), (int)selectedRowHeight, 0xFFFFFFFF,
|
||||
GL_ONE_MINUS_DST_COLOR, GL_ZERO);
|
||||
Renderer::drawRect(0, (int)mSelectorBarOffset, (int)mSize.x(), (int)selectedRowHeight, 0x777777FF,
|
||||
GL_ONE, GL_ONE);
|
||||
const float selectedRowHeight = getRowHeight(mEntries.at(mCursor).data);
|
||||
Renderer::drawRect(0, (int)mSelectorBarOffset, (int)mSize.x(), (int)selectedRowHeight, 0xFFFFFFFF,
|
||||
GL_ONE_MINUS_DST_COLOR, GL_ZERO);
|
||||
Renderer::drawRect(0, (int)mSelectorBarOffset, (int)mSize.x(), (int)selectedRowHeight, 0x777777FF,
|
||||
GL_ONE, GL_ONE);
|
||||
|
||||
// hack to draw 2px dark on left/right of the bar
|
||||
Renderer::drawRect(0, (int)mSelectorBarOffset, 2, (int)selectedRowHeight, 0x878787FF);
|
||||
Renderer::drawRect((int)mSize.x() - 2, (int)mSelectorBarOffset, 2, (int)selectedRowHeight, 0x878787FF);
|
||||
// hack to draw 2px dark on left/right of the bar
|
||||
Renderer::drawRect(0, (int)mSelectorBarOffset, 2, (int)selectedRowHeight, 0x878787FF);
|
||||
Renderer::drawRect((int)mSize.x() - 2, (int)mSelectorBarOffset, 2, (int)selectedRowHeight, 0x878787FF);
|
||||
}
|
||||
|
||||
// draw separators
|
||||
float y = 0;
|
||||
|
|
|
@ -52,11 +52,17 @@ public:
|
|||
void render(const Eigen::Affine3f& parentTrans) override;
|
||||
|
||||
void onSizeChanged() override;
|
||||
void onFocusGained() override;
|
||||
void onFocusLost() override;
|
||||
|
||||
inline int getCursorId() const { return mCursor; }
|
||||
|
||||
protected:
|
||||
void onCursorChanged(const CursorState& state) override;
|
||||
|
||||
private:
|
||||
bool mFocused;
|
||||
|
||||
void updateElementPosition(const ComponentListRow& row);
|
||||
void updateElementSize(const ComponentListRow& row);
|
||||
|
||||
|
|
|
@ -1,31 +1,67 @@
|
|||
#include "MenuComponent.h"
|
||||
#include "ButtonComponent.h"
|
||||
|
||||
using namespace Eigen;
|
||||
|
||||
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");
|
||||
|
||||
mTitle.setFont(Font::get(FONT_SIZE_LARGE));
|
||||
mTitle.setText(title);
|
||||
mTitle.setColor(0x555555FF);
|
||||
mTitle.setCentered(true);
|
||||
// set up title which will never change
|
||||
mTitle = std::make_shared<TextComponent>(mWindow, title, Font::get(FONT_SIZE_LARGE), 0x555555FF, true);
|
||||
mGrid.setEntry(mTitle, Vector2i(0, 0), false);
|
||||
|
||||
addChild(&mBackground);
|
||||
addChild(&mTitle);
|
||||
addChild(&mList);
|
||||
// set up list which will never change (externally, anyway)
|
||||
mList = std::make_shared<ComponentList>(mWindow);
|
||||
mGrid.setEntry(mList, Vector2i(0, 1), true);
|
||||
|
||||
setSize(Renderer::getScreenWidth() * 0.5f, Renderer::getScreenHeight() * 0.75f);
|
||||
updateGrid();
|
||||
mGrid.resetCursor();
|
||||
}
|
||||
|
||||
void MenuComponent::onSizeChanged()
|
||||
{
|
||||
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());
|
||||
mTitle.setPosition(0, titlePadding / 2);
|
||||
|
||||
mList.setPosition(0, mTitle.getSize().y() + titlePadding);
|
||||
mList.setSize(mSize.x(), mSize.y() - mTitle.getSize().y() - titlePadding);
|
||||
mGrid.setSize(mSize);
|
||||
}
|
||||
|
||||
void MenuComponent::addButton(const std::string& name, const std::string& helpText, const std::function<void()>& callback)
|
||||
{
|
||||
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 "ComponentList.h"
|
||||
#include "TextComponent.h"
|
||||
#include "ComponentGrid.h"
|
||||
|
||||
class ButtonComponent;
|
||||
|
||||
class MenuComponent : public GuiComponent
|
||||
{
|
||||
|
@ -11,7 +14,7 @@ public:
|
|||
|
||||
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)
|
||||
{
|
||||
|
@ -21,8 +24,19 @@ public:
|
|||
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:
|
||||
void updateGrid();
|
||||
|
||||
NinePatchComponent mBackground;
|
||||
TextComponent mTitle;
|
||||
ComponentList mList;
|
||||
ComponentGrid mGrid;
|
||||
|
||||
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),
|
||||
mFont(NULL), mColor(0x000000FF), mAutoCalcExtent(true, true), mCentered(false)
|
||||
TextComponent::TextComponent(Window* window, const std::string& text, const std::shared_ptr<Font>& font, unsigned int color, bool center,
|
||||
Eigen::Vector3f pos, Eigen::Vector2f size) : GuiComponent(window),
|
||||
mFont(NULL), mColor(0x000000FF), mAutoCalcExtent(true, true), mCentered(center)
|
||||
{
|
||||
setFont(font);
|
||||
setColor(color);
|
||||
|
@ -69,6 +70,10 @@ void TextComponent::render(const Eigen::Affine3f& parentTrans)
|
|||
{
|
||||
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(mCentered)
|
||||
|
@ -86,6 +91,8 @@ void TextComponent::render(const Eigen::Affine3f& parentTrans)
|
|||
mFont->renderTextCache(mTextCache.get());
|
||||
}
|
||||
|
||||
Renderer::popClipRect();
|
||||
|
||||
GuiComponent::renderChildren(trans);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,8 @@ class TextComponent : public GuiComponent
|
|||
{
|
||||
public:
|
||||
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 onSizeChanged() override;
|
||||
|
|
|
@ -4,152 +4,88 @@
|
|||
#include "../scrapers/Scraper.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),
|
||||
mList(window, Eigen::Vector2i(2, 7 + MAX_SCRAPER_RESULTS)),
|
||||
mGrid(window, Eigen::Vector2i(1, 3)),
|
||||
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),
|
||||
mDoneFunc(doneFunc),
|
||||
mSkipFunc(skipFunc)
|
||||
mSkipFunc(skipFunc),
|
||||
mSearchCountdown(2)
|
||||
{
|
||||
// new screen:
|
||||
|
||||
// FILE NAME
|
||||
//--------------------------------------
|
||||
//Name................. |
|
||||
//Desc................. | PREVIEW
|
||||
//..................... | IMAGE?
|
||||
//....(autoscroll)..... |
|
||||
// Result Title | Result #1
|
||||
// |-------| ..... | Result #2
|
||||
// | IMG | info | Result #3
|
||||
// |-------| ..... | .........
|
||||
// | .........
|
||||
// DESCRIPTION........| .........
|
||||
// ...................| .........
|
||||
// ...................| .........
|
||||
//--------------------------------------
|
||||
//Search for: [_______________________]
|
||||
//--------------------------------------
|
||||
//Result #1 Name
|
||||
//Result #2 Name
|
||||
//Result #3 Name
|
||||
//Result #4 Name
|
||||
//Result #5 Name
|
||||
// [SEARCH NAME] [CANCEL]
|
||||
|
||||
|
||||
addChild(&mBox);
|
||||
addChild(&mList);
|
||||
addChild(&mGrid);
|
||||
|
||||
float sw = (float)Renderer::getScreenWidth();
|
||||
float sh = (float)Renderer::getScreenHeight();
|
||||
setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
|
||||
|
||||
float listWidth = sw * 0.7f;
|
||||
float col1Width = listWidth * 0.7f;
|
||||
float col2Width = listWidth * 0.3f;
|
||||
mList.forceColumnWidth(0, (unsigned int)col1Width);
|
||||
mList.forceColumnWidth(1, (unsigned int)col2Width);
|
||||
mGrid.setSize(mSize.x() * 0.7f, mSize.y() * 0.65f);
|
||||
|
||||
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());
|
||||
mResultName.setColor(0x3B56CCFF);
|
||||
mList.setEntry(Vector2i(0, 1), Vector2i(1, 1), &mResultName, false, ComponentGrid::AlignLeft);
|
||||
// ScraperSearchComponent
|
||||
mSearch = std::make_shared<ScraperSearchComponent>(window, ScraperSearchComponent::NEVER_AUTO_ACCEPT);
|
||||
mGrid.setEntry(mSearch, Eigen::Vector2i(0, 1), true);
|
||||
|
||||
mResultDesc.setText(params.game->metadata.get("desc"));
|
||||
mResultDesc.setSize(col1Width, 0);
|
||||
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);
|
||||
// buttons
|
||||
auto buttonGrid = std::make_shared<ComponentGrid>(mWindow, Eigen::Vector2i(3, 1));
|
||||
|
||||
mResultThumbnail.setMaxSize(col2Width, mResultInfo.getSize().y());
|
||||
mList.setEntry(Vector2i(1, 2), Vector2i(1, 1), &mResultThumbnail, false, ComponentGrid::AlignCenter);
|
||||
auto manualSearchBtn = std::make_shared<ButtonComponent>(mWindow, "MANUAL SEARCH", "enter search terms");
|
||||
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);
|
||||
mSearchText.setValue(!params.nameOverride.empty() ? params.nameOverride : getCleanFileName(params.game->getPath()));
|
||||
mSearchText.setSize(listWidth - mSearchLabel.getSize().x() - 20, mSearchText.getSize().y());
|
||||
mList.setEntry(Vector2i(1, 4), Vector2i(1, 1), &mSearchText, true, ComponentGrid::AlignRight);
|
||||
buttonGrid->setEntry(manualSearchBtn, Eigen::Vector2i(0, 0), true, false);
|
||||
buttonGrid->setEntry(cancelBtn, Eigen::Vector2i(1, 0), true, false);
|
||||
|
||||
//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);
|
||||
mResultNames.reserve(MAX_SCRAPER_RESULTS);
|
||||
for(int i = 0; i < MAX_SCRAPER_RESULTS; i ++)
|
||||
{
|
||||
mResultNames.push_back(TextComponent(mWindow, "RESULT...", font));
|
||||
mResultNames.at(i).setColor(0x111111FF);
|
||||
mList.forceRowHeight(6 + i, (unsigned int)mResultNames.at(i).getSize().y());
|
||||
}
|
||||
// center everything
|
||||
mGrid.setPosition((mSize.x() - mGrid.getSize().x()) / 2, (mSize.y() - mGrid.getSize().y()) / 2);
|
||||
mBox.fitTo(mGrid.getSize(), mGrid.getPosition(), Eigen::Vector2f(-32, -32));
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
mGrid.resetCursor();
|
||||
//mSearch->setSearchParams(params); // also starts the search
|
||||
}
|
||||
|
||||
bool GuiGameScraper::input(InputConfig* config, Input input)
|
||||
{
|
||||
if(config->isMappedTo("a", input) && input.value != 0)
|
||||
{
|
||||
//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(config->isMappedTo("b", input) && input.value)
|
||||
{
|
||||
if(mSkipFunc)
|
||||
mSkipFunc();
|
||||
|
@ -157,74 +93,23 @@ bool GuiGameScraper::input(InputConfig* config, Input input)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool wasEditing = mSearchText.isEditing();
|
||||
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();
|
||||
}
|
||||
return GuiComponent::input(config, input);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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> prompts = mList.getHelpPrompts();
|
||||
if(getSelectedIndex() != -1)
|
||||
prompts.push_back(HelpPrompt("a", "accept result"));
|
||||
|
||||
prompts.push_back(HelpPrompt("b", "cancel/skip"));
|
||||
return prompts;
|
||||
return mGrid.getHelpPrompts();
|
||||
}
|
||||
|
|
|
@ -1,17 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "../GuiComponent.h"
|
||||
#include "../scrapers/Scraper.h"
|
||||
#include "../components/ComponentGrid.h"
|
||||
#include "../components/TextComponent.h"
|
||||
#include "../components/ScrollableContainer.h"
|
||||
#include "../components/TextEditComponent.h"
|
||||
#include "../components/ScraperSearchComponent.h"
|
||||
#include "../components/NinePatchComponent.h"
|
||||
#include "../components/ImageComponent.h"
|
||||
#include "../Settings.h"
|
||||
#include "../HttpReq.h"
|
||||
|
||||
#define MAX_SCRAPER_RESULTS 5
|
||||
|
||||
class GuiGameScraper : public GuiComponent
|
||||
{
|
||||
|
@ -21,37 +12,18 @@ public:
|
|||
bool input(InputConfig* config, Input input) override;
|
||||
void update(int deltaTime) override;
|
||||
|
||||
void search();
|
||||
|
||||
virtual std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
|
||||
private:
|
||||
int getSelectedIndex();
|
||||
void onSearchDone(std::vector<MetaDataList> results);
|
||||
void updateInfoPane();
|
||||
void updateThumbnail();
|
||||
int mSearchCountdown; // haaack
|
||||
|
||||
ComponentGrid mList;
|
||||
ComponentGrid mGrid;
|
||||
NinePatchComponent mBox;
|
||||
|
||||
TextComponent mHeader;
|
||||
|
||||
TextComponent mResultName;
|
||||
ScrollableContainer mResultInfo;
|
||||
TextComponent mResultDesc;
|
||||
ImageComponent mResultThumbnail;
|
||||
|
||||
TextComponent mSearchLabel;
|
||||
TextEditComponent mSearchText;
|
||||
|
||||
std::vector<TextComponent> mResultNames;
|
||||
std::shared_ptr<ScraperSearchComponent> mSearch;
|
||||
|
||||
ScraperSearchParams mSearchParams;
|
||||
|
||||
std::vector<MetaDataList> mScraperResults;
|
||||
|
||||
std::function<void(MetaDataList)> mDoneFunc;
|
||||
std::function<void()> mSkipFunc;
|
||||
|
||||
std::unique_ptr<HttpReq> mThumbnailReq;
|
||||
};
|
||||
|
|
|
@ -7,115 +7,50 @@
|
|||
#include "GuiMsgBoxYesNo.h"
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#define MDED_RESERVED_ROWS 3
|
||||
|
||||
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),
|
||||
mScraperParams(scraperParams),
|
||||
mBox(mWindow, ":/frame.png", 0xAAAAAAFF, 0xCCCCCCFF),
|
||||
mList(window, Eigen::Vector2i(2, mdd.size() + MDED_RESERVED_ROWS)),
|
||||
mHeader(window),
|
||||
mMenu(window, header.c_str()),
|
||||
mMetaDataDecl(mdd),
|
||||
mMetaData(md),
|
||||
mSavedCallback(saveCallback), mDeleteFunc(deleteFunc),
|
||||
mDeleteButton(window), mFetchButton(window), mSaveButton(window)
|
||||
mSavedCallback(saveCallback), mDeleteFunc(deleteFunc)
|
||||
{
|
||||
unsigned int sw = Renderer::getScreenWidth();
|
||||
unsigned int sh = Renderer::getScreenHeight();
|
||||
setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
|
||||
|
||||
addChild(&mBox);
|
||||
|
||||
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++;
|
||||
addChild(&mMenu);
|
||||
|
||||
// populate list
|
||||
for(auto iter = mdd.begin(); iter != mdd.end(); iter++)
|
||||
{
|
||||
TextComponent* label = new TextComponent(mWindow);
|
||||
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());
|
||||
auto ed = MetaDataList::makeEditor(mWindow, iter->type);
|
||||
ed->setValue(mMetaData->get(iter->key));
|
||||
mList.setEntry(Vector2i(1, y), Vector2i(1, 1), ed, true, ComponentGrid::AlignRight);
|
||||
mEditors.push_back(ed);
|
||||
|
||||
y++;
|
||||
mMenu.addWithLabel(iter->key, ed);
|
||||
}
|
||||
|
||||
//save button
|
||||
mList.setEntry(Vector2i(0, y), Vector2i(2, 1), &mSaveButton, true, ComponentGrid::AlignCenter);
|
||||
//add buttons
|
||||
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()
|
||||
{
|
||||
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)
|
||||
|
@ -126,7 +61,6 @@ void GuiMetaDataEd::fetch()
|
|||
{
|
||||
GuiGameScraper* scr = new GuiGameScraper(mWindow, mScraperParams, std::bind(&GuiMetaDataEd::fetchDone, this, std::placeholders::_1));
|
||||
mWindow->pushGui(scr);
|
||||
scr->search();
|
||||
}
|
||||
|
||||
void GuiMetaDataEd::fetchDone(MetaDataList result)
|
||||
|
@ -187,7 +121,7 @@ bool GuiMetaDataEd::input(InputConfig* config, Input input)
|
|||
|
||||
std::vector<HelpPrompt> GuiMetaDataEd::getHelpPrompts()
|
||||
{
|
||||
std::vector<HelpPrompt> prompts = mList.getHelpPrompts();
|
||||
std::vector<HelpPrompt> prompts = mMenu.getHelpPrompts();
|
||||
prompts.push_back(HelpPrompt("b", "discard changes"));
|
||||
return prompts;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "../GuiComponent.h"
|
||||
#include "../components/ComponentGrid.h"
|
||||
#include "../components/MenuComponent.h"
|
||||
#include "../MetaData.h"
|
||||
#include "../components/TextComponent.h"
|
||||
#include "../components/NinePatchComponent.h"
|
||||
#include "../components/ButtonComponent.h"
|
||||
#include "../scrapers/Scraper.h"
|
||||
|
||||
#include <functional>
|
||||
|
@ -15,7 +12,6 @@ class GuiMetaDataEd : public GuiComponent
|
|||
public:
|
||||
GuiMetaDataEd(Window* window, MetaDataList* md, const std::vector<MetaDataDecl>& mdd, ScraperSearchParams params,
|
||||
const std::string& header, std::function<void()> savedCallback, std::function<void()> deleteFunc);
|
||||
virtual ~GuiMetaDataEd();
|
||||
|
||||
bool input(InputConfig* config, Input input) override;
|
||||
|
||||
|
@ -26,25 +22,14 @@ private:
|
|||
void fetch();
|
||||
void fetchDone(MetaDataList result);
|
||||
|
||||
void populateList(const std::vector<MetaDataDecl>& mdd);
|
||||
MenuComponent mMenu;
|
||||
|
||||
ScraperSearchParams mScraperParams;
|
||||
|
||||
NinePatchComponent mBox;
|
||||
|
||||
ComponentGrid mList;
|
||||
|
||||
TextComponent mHeader;
|
||||
|
||||
std::vector<TextComponent*> mLabels;
|
||||
std::vector<GuiComponent*> mEditors;
|
||||
std::vector< std::shared_ptr<GuiComponent> > mEditors;
|
||||
|
||||
std::vector<MetaDataDecl> mMetaDataDecl;
|
||||
MetaDataList* mMetaData;
|
||||
std::function<void()> mSavedCallback;
|
||||
std::function<void()> mDeleteFunc;
|
||||
|
||||
ButtonComponent mDeleteButton;
|
||||
ButtonComponent mFetchButton;
|
||||
ButtonComponent mSaveButton;
|
||||
};
|
||||
|
|
|
@ -61,7 +61,6 @@ void GuiScraperLog::next()
|
|||
[this, search] { resultEmpty(search); });
|
||||
|
||||
mWindow->pushGui(ggs);
|
||||
ggs->search();
|
||||
}else{
|
||||
std::shared_ptr<Scraper> scraper = Settings::getInstance()->getScraper();
|
||||
scraper->getResultsAsync(search, mWindow, [this, search] (std::vector<MetaDataList> mdls) {
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#include "GamesDBScraper.h"
|
||||
#include "../guis/GuiGameScraper.h"
|
||||
#include "../components/ScraperSearchComponent.h"
|
||||
#include "../components/AsyncReqComponent.h"
|
||||
#include "../Log.h"
|
||||
#include "../pugiXML/pugixml.hpp"
|
||||
#include "../MetaData.h"
|
||||
#include "../Settings.h"
|
||||
#include <boost/assign.hpp>
|
||||
|
||||
const char* GamesDBScraper::getName() { return "TheGamesDB"; }
|
||||
|
|
Loading…
Reference in a new issue