From 774ab04ade2df9aa59ae3ccf997beaab7438b994 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Tue, 24 Jan 2023 21:06:51 -0800 Subject: [PATCH] Added UI Grid --- src/dawn/ui/CMakeLists.txt | 2 +- src/dawn/ui/UIComponent.cpp | 129 ++++++++++++----------- src/dawn/ui/UIComponent.hpp | 27 ++++- src/dawn/ui/UIGrid.cpp | 109 +++++++++++++++---- src/dawn/ui/UIGrid.hpp | 73 +++++++++---- src/dawnpokergame/scenes/TestUIScene.cpp | 26 +++-- src/dawnpokergame/scenes/TestUIScene.hpp | 2 + 7 files changed, 254 insertions(+), 114 deletions(-) diff --git a/src/dawn/ui/CMakeLists.txt b/src/dawn/ui/CMakeLists.txt index 017d8056..3ae4ab2d 100644 --- a/src/dawn/ui/CMakeLists.txt +++ b/src/dawn/ui/CMakeLists.txt @@ -11,5 +11,5 @@ target_sources(${DAWN_TARGET_NAME} UILabel.cpp UISprite.cpp UIEmpty.cpp - # UIGrid.cpp + UIGrid.cpp ) \ No newline at end of file diff --git a/src/dawn/ui/UIComponent.cpp b/src/dawn/ui/UIComponent.cpp index 5a07dea4..018d3607 100644 --- a/src/dawn/ui/UIComponent.cpp +++ b/src/dawn/ui/UIComponent.cpp @@ -7,78 +7,81 @@ using namespace Dawn; +void UIComponent::calculateDimensions( + enum UIComponentAlign align, + float_t *position, + float_t *size, + float_t outerSize, + float_t innerSize, + glm::vec2 alignment +) { + assertNotNull(position); + assertNotNull(size); + + switch(align) { + case UI_COMPONENT_ALIGN_STRETCH: + *position = alignment[0]; + *size = outerSize + (alignment[0] + alignment[1]); + break; + + case UI_COMPONENT_ALIGN_START: + *position = alignment[0]; + *size = alignment[1]; + break; + + case UI_COMPONENT_ALIGN_MIDDLE: + *size = innerSize; + *position = (outerSize / 2.0f) - (innerSize / 2.0f) + alignment[0]; + break; + + case UI_COMPONENT_ALIGN_END: + *size = alignment[0]; + *position = outerSize - innerSize - alignment[1]; + break; + + default: + assertUnreachable(); + break; + } +} + UIComponent::UIComponent(UICanvas *canvas) { assertNotNull(canvas); this->canvas = canvas; } void UIComponent::updatePositions() { - // X Alignment - if(this->alignX == UI_COMPONENT_ALIGN_STRETCH) { - if(this->parent == nullptr) { - this->width = this->canvas->getWidth(); - } else { - this->width = this->parent->getWidth(); - } - this->relativeX = this->alignment[0]; - this->width -= (this->alignment[0] + this->alignment[2]); - } else if(this->alignX == UI_COMPONENT_ALIGN_START) { - this->relativeX = this->alignment[0]; - this->width = this->alignment[2]; - } else if(this->alignX == UI_COMPONENT_ALIGN_END) { - this->width = this->alignment[0]; - if(this->parent == nullptr) { - this->relativeX = this->canvas->getWidth(); - } else { - this->relativeX = this->parent->getWidth(); - } - this->relativeX -= this->width; - this->relativeX -= this->alignment[2]; - } else if(this->alignX == UI_COMPONENT_ALIGN_MIDDLE) { - this->width = this->alignment[2]; - if(this->parent == nullptr) { - this->relativeX = this->canvas->getWidth(); - } else { - this->relativeX = this->parent->getWidth(); - } - this->relativeX = (this->relativeX / 2.0f) - (this->width / 2.0f) + this->alignment[0]; + float_t outerWidth, outerHeight; + + if(this->parent == nullptr) { + outerWidth = this->canvas->getWidth(); + outerHeight = this->canvas->getHeight(); + } else { + outerWidth = this->parent->getWidth(); + outerHeight = this->parent->getHeight(); } - // Y Alignment - if(this->alignY == UI_COMPONENT_ALIGN_STRETCH) { - if(this->parent == nullptr) { - this->height = this->canvas->getHeight(); - } else { - this->height = this->parent->getHeight(); - } - this->relativeY = this->alignment[1]; - this->height -= (this->alignment[1] + this->alignment[3]); - } else if(this->alignY == UI_COMPONENT_ALIGN_START) { - this->relativeY = this->alignment[1]; - this->height = this->alignment[3]; - } else if(this->alignY == UI_COMPONENT_ALIGN_END) { - this->height = this->alignment[1]; - if(this->parent == nullptr) { - this->relativeY = this->canvas->getHeight(); - } else { - this->relativeY = this->parent->getHeight(); - } - this->relativeY -= this->height; - this->relativeY -= this->alignment[3]; - } else if(this->alignY == UI_COMPONENT_ALIGN_MIDDLE) { - this->height = this->alignment[3]; - if(this->parent == nullptr) { - this->relativeY = this->canvas->getHeight(); - } else { - this->relativeY = this->parent->getHeight(); - } - this->relativeY = (this->relativeY / 2.0f) - (this->height / 2.0f) + this->alignment[1]; - } + UIComponent::calculateDimensions( + this->alignX, + &this->relativeX, + &this->width, + outerWidth, + this->getContentWidth(), + glm::vec2(this->alignment[0], this->alignment[2]) + ); + UIComponent::calculateDimensions( + this->alignY, + &this->relativeY, + &this->height, + outerHeight, + this->getContentHeight(), + glm::vec2(this->alignment[1], this->alignment[3]) + ); - this->relativeX = mathRound(this->relativeX); - this->relativeY = mathRound(this->relativeY); - this->width = mathRound(this->width); - this->height = mathRound(this->height); +// this->relativeX = mathRound(this->relativeX); +// this->relativeY = mathRound(this->relativeY); +// this->width = mathRound(this->width); +// this->height = mathRound(this->height); // Update children auto it = this->children.begin(); diff --git a/src/dawn/ui/UIComponent.hpp b/src/dawn/ui/UIComponent.hpp index ae25dc35..ff070dd2 100644 --- a/src/dawn/ui/UIComponent.hpp +++ b/src/dawn/ui/UIComponent.hpp @@ -18,6 +18,8 @@ namespace Dawn { UI_COMPONENT_ALIGN_END, UI_COMPONENT_ALIGN_STRETCH }; + + class UIGrid; class UIComponent { protected: @@ -67,6 +69,25 @@ namespace Dawn { ) = 0; public: + /** + * Method used to calculate alignment dimensions. + * + * @param align Alignment value enumator. + * @param position Output position floating point. + * @param size Output size floating point. + * @param outerSize Outer size (of the parent). + * @param innerSize Inner size (of this element's content). + * @param alignment Alignment settings. + */ + static void calculateDimensions( + enum UIComponentAlign align, + float_t *position, + float_t *size, + float_t outerSize, + float_t innerSize, + glm::vec2 alignment + ); + UICanvas *canvas; UIComponent(UICanvas *canvas); @@ -165,16 +186,18 @@ namespace Dawn { * * @param child Child UI Component to add. */ - void addChild(UIComponent *child); + virtual void addChild(UIComponent *child); /** * Removes a child from this UI Component. * * @param child Child to remove. */ - void removeChild(UIComponent *child); + virtual void removeChild(UIComponent *child); virtual ~UIComponent(); + friend class UICanvas; + friend class UIGrid; }; } \ No newline at end of file diff --git a/src/dawn/ui/UIGrid.cpp b/src/dawn/ui/UIGrid.cpp index 0451eae7..164a75b4 100644 --- a/src/dawn/ui/UIGrid.cpp +++ b/src/dawn/ui/UIGrid.cpp @@ -8,28 +8,101 @@ using namespace Dawn; UIGrid::UIGrid(UICanvas *canvas) : UIComponent(canvas) { + } -void UIGrid::setSize(int32_t rows, int32_t columns) { - this->gridArea.clear(); - - this->rows = rows; - this->columns = columns; +void UIGrid::updatePositions() { + UIComponent::updatePositions(); - int32_t i, l; - l = rows * columns; - for(i = 0; i < l; i++) { - struct GridArea area; - area.uiComponent = nullptr; - this->gridArea.push_back(area); + this->sizeCol = ( + this->width - (this->gutterX * (this->columns - 1)) + ) / this->columns; + this->sizeRow = ( + this->height - (this->gutterY * (this->rows - 1)) + ) / this->rows; + + auto it = this->gridChildren.begin(); + while(it != this->gridChildren.end()) { + this->alignChild(it->first, it->second); + ++it; } } -void UIGrid::setItem(int32_t x, int32_t y, UIComponent *comp) { - auto item = &this->gridArea[(y * this->rows) + x]; - - //Too lazy to support re setting. Need to mod setSize too - assertNull(item->uiComponent); - - item->uiComponent = comp; +std::vector UIGrid::getSelfPassItems( + glm::mat4 projection, + glm::mat4 view, + glm::mat4 transform +) { + return std::vector(); } + +void UIGrid::alignChild(UIComponent *child, struct UIGridPosition pos) { + float_t gridX = (this->sizeCol * pos.x) + (this->gutterX * pos.x); + float_t gridY = (this->sizeRow * pos.y) + (this->gutterY * pos.y); + + // Hack for when content width is undefined. + child->width = this->sizeCol; + child->height = this->sizeRow; + + // Alignment + float_t x, y, sizeX, sizeY; + UIComponent::calculateDimensions( + UI_COMPONENT_ALIGN_MIDDLE, + &x, + &sizeX, + this->sizeCol, + child->getContentWidth(), + glm::vec2(0, 0) + ); + UIComponent::calculateDimensions( + UI_COMPONENT_ALIGN_MIDDLE, + &y, + &sizeY, + this->sizeRow, + child->getContentHeight(), + glm::vec2(0, 0) + ); + + child->setTransform( + UI_COMPONENT_ALIGN_START, UI_COMPONENT_ALIGN_START, + glm::vec4(gridX + x, gridY + y, sizeX, sizeY), + 0.0f + ); +} + +void UIGrid::setGridSize( + int32_t columns, int32_t rows, + float_t gutterX, float_t gutterY +) { + this->rows = rows; + this->columns = columns; + this->gutterX = gutterX; + this->gutterY = gutterY; + + this->gridChildren.clear(); + this->updatePositions(); +} + +void UIGrid::addToGrid(UIComponent *ui, int32_t x, int32_t y) { + assertTrue(x >= 0 && x < this->columns); + assertTrue(y >= 0 && y < this->rows); + this->addChild(ui); + struct UIGridPosition pos; + pos.x = x; + pos.y = y; + this->gridChildren[ui] = pos; + this->alignChild(ui, pos); +} + +int32_t UIGrid::getRows() { + return this->rows; +} + +int32_t UIGrid::getColumns() { + return this->columns; +} + +void UIGrid::removeChild(UIComponent *component) { + UIComponent::removeChild(component); + assertUnreachable(); +} \ No newline at end of file diff --git a/src/dawn/ui/UIGrid.hpp b/src/dawn/ui/UIGrid.hpp index d596f585..b02deaf4 100644 --- a/src/dawn/ui/UIGrid.hpp +++ b/src/dawn/ui/UIGrid.hpp @@ -5,37 +5,70 @@ #pragma once #include "UIComponent.hpp" +#include "util/mathutils.hpp" namespace Dawn { - enum GridAlign { - ALIGN_GROW, - ALIGN_CONTENT, - ALIGN_FIXED + struct UIGridPosition { + int32_t x; + int32_t y; + UIComponentAlign alignX; + UIComponentAlign alignY; }; - struct GridArea { - enum GridAlignment xAlign; - enum GridAlignment yAlign; - float_t width, height; - float_t x, y; - UIComponent *uiComponent; - }; class UIGrid : public UIComponent { - protected: - void alignChildren(); - - public: - glm::vec2 cellPadding; - glm::vec2 cellMargin; + private: int32_t rows = 1; int32_t columns = 1; - std::vector gridArea; + float_t gutterX = 0; + float_t gutterY = 0; + float_t sizeRow, sizeCol; + std::map gridChildren; + /** + * Internal method to update the alignment of a child. + * + * @param child Child UI component. + * @param pos Positional information of the child UI item.. + */ + void alignChild(UIComponent *child, struct UIGridPosition pos); + + protected: + void updatePositions() override; + std::vector getSelfPassItems( + glm::mat4 projection, + glm::mat4 view, + glm::mat4 transform + ) override; + + public: UIGrid(UICanvas *canvas); - void setSize(int32_t rows, int32_t columns); + /** + * Sets the dimensions of the grid. + * + * @param columns Count of columns in the grid. + * @param rows Count of rows in the grid. + * @param gutterX Gutter spacing between the cells of the grid. + * @param gutterY Gutter spacing between the cells of the grid. + */ + void setGridSize( + int32_t columns, int32_t rows, + float_t gutterX, float_t gutterY + ); - void setItem(int32_t row, int32_t col, UIComponent *comp); + /** + * Adds a UI component to the grid. + * + * @param component Component to add to the grid. + * @param column Column Position. + * @param row Row Position. + */ + void addToGrid(UIComponent *component, int32_t column, int32_t row); + + int32_t getRows(); + int32_t getColumns(); + + void removeChild(UIComponent *component) override; }; } \ No newline at end of file diff --git a/src/dawnpokergame/scenes/TestUIScene.cpp b/src/dawnpokergame/scenes/TestUIScene.cpp index 7c7060e3..1a5bf486 100644 --- a/src/dawnpokergame/scenes/TestUIScene.cpp +++ b/src/dawnpokergame/scenes/TestUIScene.cpp @@ -32,7 +32,7 @@ void TestUIScene::stage() { this->canvas = UICanvas::create(this); // auto text = man->get("texture_test"); - // auto border = this->canvas->addElement(); + // auto border = this->canvas->addElement(); // border->texture = &text->texture; // border->setBorderSize(glm::vec2(4, 4)); // border->setTransform( @@ -42,13 +42,19 @@ void TestUIScene::stage() { // ); auto assetFont = man->get("truetype_alice"); - auto label = this->canvas->addElement(); - label->setFont(&assetFont->font); - label->setText("test.1"); - label->setFontSize(24); - label->setTransform( - UI_COMPONENT_ALIGN_STRETCH, UI_COMPONENT_ALIGN_STRETCH, - glm::vec4(0, 0, 0, 0), - 0.0f - ); + + auto grid = this->canvas->addElement(); + grid->setTransform(UI_COMPONENT_ALIGN_STRETCH, UI_COMPONENT_ALIGN_STRETCH, glm::vec4(0, 0, 0, 0), 0); + grid->setGridSize(4, 4, 8, 8); + + for(int32_t x = 0; x < grid->getColumns(); x++) { + for(int32_t y = 0; y < grid->getRows(); y++) { + auto label = this->canvas->addElement(); + label->setFont(&assetFont->font); + label->setText("test.1"); + label->setFontSize(24); + + grid->addToGrid(label, x, y); + } + } } \ No newline at end of file diff --git a/src/dawnpokergame/scenes/TestUIScene.hpp b/src/dawnpokergame/scenes/TestUIScene.hpp index 8440f4ce..ad76acc6 100644 --- a/src/dawnpokergame/scenes/TestUIScene.hpp +++ b/src/dawnpokergame/scenes/TestUIScene.hpp @@ -9,6 +9,8 @@ #include "scene/components/ui/UICanvas.hpp" #include "ui/UILabel.hpp" #include "ui/UIBorder.hpp" +#include "ui/UIGrid.hpp" +#include "ui/UISprite.hpp" #include "prefabs/SimpleSpinningCubePrefab.hpp" namespace Dawn {