// SPDX-License-Identifier: MIT // // ES-DE Frontend // ComponentGrid.h // // Provides basic layout of components in an X*Y grid. // #ifndef ES_CORE_COMPONENTS_COMPONENT_GRID_H #define ES_CORE_COMPONENTS_COMPONENT_GRID_H #include "GuiComponent.h" #include "renderers/Renderer.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 }; } // namespace GridFlags // Provides basic layout of components in an X*Y grid. class ComponentGrid : public GuiComponent { public: ComponentGrid(const glm::ivec2& gridDimensions); virtual ~ComponentGrid(); bool removeEntry(const std::shared_ptr& comp); void setEntry(const std::shared_ptr& comp, const glm::ivec2& pos, bool canFocus, bool resize = true, const glm::ivec2& size = glm::ivec2 {1, 1}, unsigned int border = GridFlags::BORDER_NONE, GridFlags::UpdateType updateType = GridFlags::UPDATE_ALWAYS, glm::ivec2 autoCalcExtent = {0, 0}); void setPastBoundaryCallback(const std::function& func) { mPastBoundaryCallback = func; } void textInput(const std::string& text, const bool pasting = false) override; bool input(InputConfig* config, Input input) override; void update(int deltaTime) override; void render(const glm::mat4& parentTrans) override; void onSizeChanged() override; void resetCursor(); bool cursorValid(); float getColWidth(int col); float getRowHeight(int row); // If update is false, will not call an onSizeChanged() which triggers // a (potentially costly) repositioning + resizing of every element. void setColWidthPerc(int col, float width, bool update = true); // Dito. 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& comp); std::shared_ptr getSelectedComponent() { const GridEntry* e = getCellAt(mCursor); if (e) return e->component; else return nullptr; } void onFocusLost() override; void onFocusGained() override; std::vector getHelpPrompts() override; private: class GridEntry { public: glm::ivec2 pos; glm::ivec2 dim; std::shared_ptr component; bool canFocus; bool resize; GridFlags::UpdateType updateType; unsigned int border; GridEntry(const glm::ivec2& p = glm::ivec2 {}, const glm::ivec2& d = glm::ivec2 {}, const std::shared_ptr& 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 { return component != nullptr; } }; // Update position and size. void updateCellComponent(const GridEntry& cell); void updateSeparators(); void onCursorMoved(glm::ivec2 from, glm::ivec2 to); const GridEntry* getCellAt(int x, int y) const; const GridEntry* getCellAt(const glm::ivec2& pos) const { return getCellAt(pos.x, pos.y); } Renderer* mRenderer; std::vector> mSeparators; glm::ivec2 mGridSize; std::vector mCells; glm::ivec2 mCursor; std::function mPastBoundaryCallback; float* mRowHeights; float* mColWidths; }; #endif // ES_CORE_COMPONENTS_COMPONENT_GRID_H