Added support for correctly navigating arbitrarily sized ComponentGrid entries.

Also added a callback for handling navigation attempts beyond the grid boundary as well as a function to move to an absolute cursor position.
This commit is contained in:
Leon Styhre 2021-09-17 21:35:37 +02:00
parent db4fb1ab92
commit 08790ed1f3
2 changed files with 72 additions and 5 deletions

View file

@ -252,19 +252,24 @@ bool ComponentGrid::input(InputConfig* config, Input input)
if (!input.value)
return false;
bool withinBoundary = false;
if (config->isMappedLike("down", input))
return moveCursor(glm::ivec2{0, 1});
withinBoundary = moveCursor(glm::ivec2{0, 1});
if (config->isMappedLike("up", input))
return moveCursor(glm::ivec2{0, -1});
withinBoundary = moveCursor(glm::ivec2{0, -1});
if (config->isMappedLike("left", input))
return moveCursor(glm::ivec2{-1, 0});
withinBoundary = moveCursor(glm::ivec2{-1, 0});
if (config->isMappedLike("right", input))
return moveCursor(glm::ivec2{1, 0});
withinBoundary = moveCursor(glm::ivec2{1, 0});
return false;
if (!withinBoundary && mPastBoundaryCallback)
return mPastBoundaryCallback(config, input);
return withinBoundary;
}
void ComponentGrid::resetCursor()
@ -290,6 +295,34 @@ bool ComponentGrid::moveCursor(glm::ivec2 dir)
const GridEntry* currentCursorEntry = getCellAt(mCursor);
glm::ivec2 searchAxis(dir.x == 0, dir.y == 0);
// Logic to handle entries that span several cells.
if (currentCursorEntry->dim.x > 1) {
if (dir.x < 0 && currentCursorEntry->pos.x == 0 && mCursor.x > currentCursorEntry->pos.x) {
onCursorMoved(mCursor, glm::ivec2{0, mCursor.y});
mCursor.x = 0;
return false;
}
if (dir.x > 0 && currentCursorEntry->pos.x + currentCursorEntry->dim.x == mGridSize.x &&
mCursor.x < currentCursorEntry->pos.x + currentCursorEntry->dim.x - 1) {
onCursorMoved(mCursor, glm::ivec2{mGridSize.x - 1, mCursor.y});
mCursor.x = mGridSize.x - 1;
return false;
}
if (dir.x > 0 && mCursor.x != currentCursorEntry->pos.x + currentCursorEntry->dim.x - 1)
dir.x = currentCursorEntry->dim.x - (mCursor.x - currentCursorEntry->pos.x);
else if (dir.x < 0 && mCursor.x != currentCursorEntry->pos.x)
dir.x = -(mCursor.x - currentCursorEntry->pos.x + 1);
}
if (currentCursorEntry->dim.y > 1) {
if (dir.y > 0 && mCursor.y != currentCursorEntry->pos.y + currentCursorEntry->dim.y - 1)
dir.y = currentCursorEntry->dim.y - (mCursor.y - currentCursorEntry->pos.y);
else if (dir.y < 0 && mCursor.y != currentCursorEntry->pos.y)
dir.y = -(mCursor.y - currentCursorEntry->pos.y + 1);
}
while (mCursor.x >= 0 && mCursor.y >= 0 && mCursor.x < mGridSize.x && mCursor.y < mGridSize.y) {
mCursor = mCursor + dir;
glm::ivec2 curDirPos{mCursor};
@ -299,6 +332,13 @@ bool ComponentGrid::moveCursor(glm::ivec2 dir)
while (mCursor.x < mGridSize.x && mCursor.y < mGridSize.y && mCursor.x >= 0 &&
mCursor.y >= 0) {
cursorEntry = getCellAt(mCursor);
// Multi-cell entries.
if (dir.x < 0 && cursorEntry->dim.x > 1)
mCursor.x = getCellAt(origCursor)->pos.x - cursorEntry->dim.x;
if (dir.y < 0 && cursorEntry->dim.y > 1)
mCursor.y = getCellAt(origCursor)->pos.y - cursorEntry->dim.y;
if (cursorEntry && cursorEntry->canFocus && cursorEntry != currentCursorEntry) {
onCursorMoved(origCursor, mCursor);
return true;
@ -326,6 +366,24 @@ bool ComponentGrid::moveCursor(glm::ivec2 dir)
return false;
}
void ComponentGrid::moveCursorTo(int xPos, int yPos, bool selectLeftCell)
{
const glm::ivec2 origCursor{mCursor};
if (xPos != -1)
mCursor.x = xPos;
if (yPos != -1)
mCursor.y = yPos;
const GridEntry* currentCursorEntry = getCellAt(mCursor);
// If requested, select the leftmost cell of entries wider than 1 cell.
if (selectLeftCell && mCursor.x > currentCursorEntry->pos.x)
mCursor.x = currentCursorEntry->pos.x;
onCursorMoved(origCursor, mCursor);
}
void ComponentGrid::onFocusLost()
{
const GridEntry* cursorEntry = getCellAt(mCursor);

View file

@ -46,6 +46,11 @@ public:
unsigned int border = GridFlags::BORDER_NONE,
GridFlags::UpdateType updateType = GridFlags::UPDATE_ALWAYS);
void setPastBoundaryCallback(const std::function<bool(InputConfig* config, Input input)>& func)
{
mPastBoundaryCallback = func;
}
void textInput(const std::string& text) override;
bool input(InputConfig* config, Input input) override;
void update(int deltaTime) override;
@ -65,6 +70,8 @@ public:
void setRowHeightPerc(int row, float height, bool update = true);
bool moveCursor(glm::ivec2 dir);
// Pass -1 for xPos or yPos to keep its axis cursor position.
void moveCursorTo(int xPos, int yPos, bool selectLeftCell = false);
void setCursorTo(const std::shared_ptr<GuiComponent>& comp);
std::shared_ptr<GuiComponent> getSelectedComponent()
@ -126,6 +133,8 @@ private:
std::vector<GridEntry> mCells;
glm::ivec2 mCursor;
std::function<bool(InputConfig* config, Input input)> mPastBoundaryCallback;
float* mRowHeights;
float* mColWidths;
};