From 2448869bf922a5773dbfd420a0a0e2cb151b0712 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 7 Aug 2026 00:02:39 +0300 Subject: [PATCH 1/4] fix horizontal panel behaviour --- src/graphics/ui/elements/Panel.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/graphics/ui/elements/Panel.cpp b/src/graphics/ui/elements/Panel.cpp index 885ae3d61..87796a50c 100644 --- a/src/graphics/ui/elements/Panel.cpp +++ b/src/graphics/ui/elements/Panel.cpp @@ -97,16 +97,23 @@ void Panel::refresh() { } else { float maxh = size.y; for (auto& node : nodes) { - glm::vec2 nodesize = node->getSize(); const glm::vec4 margin = node->getMargin(); x += margin.x; - node->setPos(glm::vec2(x, y + margin.y)); - x += nodesize.x + margin.z + interval; - node->refresh(); - maxh = fmax( - maxh, y + margin.y + node->getSize().y + margin.w + padding.w + float ey = y + margin.y; + node->setPos(glm::vec2(x, ey)); + + int height = glm::floor( + size.y - padding.y - padding.w - margin.y - margin.w ); + if (node->isResizing()) { + node->setMaxSize({node->getMaxSize().x, height}); + node->setSize(glm::vec2(node->getSize().x, height)); + } + node->refresh(); + glm::vec2 nodesize = node->getSize(); + x += nodesize.x + margin.z + interval; + maxh = fmax(maxh, ey + nodesize.y + margin.w + padding.w); } actualLength = size.y; } From 863cc923a00ee2a6b5eadf38949b3f6803047a18 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 7 Aug 2026 22:26:58 +0300 Subject: [PATCH 2/4] feat: horizontal scroll --- src/graphics/ui/elements/Container.cpp | 25 ++++++++++++++----------- src/graphics/ui/elements/Container.hpp | 8 +++++--- src/graphics/ui/elements/Panel.cpp | 10 ++++++---- src/graphics/ui/elements/TextBox.cpp | 2 +- 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/graphics/ui/elements/Container.cpp b/src/graphics/ui/elements/Container.cpp index c869e9b3b..954c9879d 100644 --- a/src/graphics/ui/elements/Container.cpp +++ b/src/graphics/ui/elements/Container.cpp @@ -11,7 +11,7 @@ using namespace gui; Container::Container(GUI& gui, glm::vec2 size) : UINode(gui, size) { - actualLength = size.y; + actualLengthY = size.y; setColor(glm::vec4()); } @@ -26,7 +26,7 @@ std::shared_ptr Container::getAt(const glm::vec2& pos) { if (!isInside(pos)) { return nullptr; } - int diff = (actualLength-size.y); + int diff = (actualLengthY-size.y); if (scrollable && diff > 0 && pos.x > calcPos().x + getSize().x - scrollBarWidth) { return UINode::getAt(pos); } @@ -65,11 +65,11 @@ void Container::mouseMove(int x, int y) { auto pos = calcPos(); x -= pos.x; y -= pos.y; - int diff = (actualLength-size.y); + int diff = (actualLengthY-size.y); if (diff > 0) { - scroll -= (y - prevScrollY) / static_cast(size.y) * actualLength; - scroll = -glm::min( - glm::max(static_cast(-scroll), 0.0f), actualLength - size.y + scrollY -= (y - prevScrollY) / static_cast(size.y) * actualLengthY; + scrollY = -glm::min( + glm::max(static_cast(-scrollY), 0.0f), actualLengthY - size.y ); } prevScrollY = y; @@ -110,7 +110,10 @@ void Container::act(float delta) { } void Container::scrolled(int value) { - int diff = (actualLength-getSize().y); + auto size = getSize(); + int diff = (actualLengthY > size.y ? actualLengthY - size.y : actualLengthX - size.x); + int& scroll = (actualLengthY > size.y ? scrollY : scrollX); + if (scroll < 0 && diff <= 0) { scroll = 0; } @@ -146,14 +149,14 @@ void Container::draw(const DrawContext& pctx, const Assets& assets) { node->draw(pctx, assets); } - int diff = (actualLength-size.y); + int diff = (actualLengthY-size.y); if (scrollable && diff > 0) { - int h = glm::max(size.y / actualLength * size.y, scrollBarWidth / 2.0f); + int h = glm::max(size.y / actualLengthY * size.y, scrollBarWidth / 2.0f); batch->untexture(); batch->setColor(glm::vec4(1, 1, 1, 0.3f)); batch->rect( pos.x + size.x - scrollBarWidth, - pos.y - scroll / static_cast(diff) * (size.y - h), + pos.y - scrollY / static_cast(diff) * (size.y - h), scrollBarWidth, h ); } @@ -248,7 +251,7 @@ void Container::refresh() { } void Container::setScroll(int scroll) { - this->scroll = scroll; + this->scrollY = scroll; } const std::vector>& Container::getNodes() const { diff --git a/src/graphics/ui/elements/Container.hpp b/src/graphics/ui/elements/Container.hpp index 3ede2c2a1..36c366010 100644 --- a/src/graphics/ui/elements/Container.hpp +++ b/src/graphics/ui/elements/Container.hpp @@ -13,10 +13,12 @@ namespace gui { protected: std::vector> nodes; std::vector intervalEvents; - int scroll = 0; + int scrollY = 0; + int scrollX = 0; int scrollStep = 40; int scrollBarWidth = 10; - int actualLength = 0; + int actualLengthY = 0; + int actualLengthX = 0; bool scrollable = true; bool isScrolling() const { @@ -40,7 +42,7 @@ namespace gui { virtual void setScrollable(bool flag); void listenInterval(float interval, OnTimeOut callback, int repeat=-1); virtual glm::vec2 getContentOffset() const override { - return glm::vec2(0.0f, scroll); + return glm::vec2(scrollX, scrollY); }; virtual void setSize(const glm::vec2& size) override; virtual int getScrollStep() const; diff --git a/src/graphics/ui/elements/Panel.cpp b/src/graphics/ui/elements/Panel.cpp index 87796a50c..3b452e892 100644 --- a/src/graphics/ui/elements/Panel.cpp +++ b/src/graphics/ui/elements/Panel.cpp @@ -41,10 +41,10 @@ glm::vec2 Panel::getContentSize() const { void Panel::cropToContent() { if (maxLength > 0.0f) { setSize(glm::vec2( - getSize().x, glm::max(minLength, glm::min(maxLength, actualLength)) + glm::max(minLength, glm::min(maxLength, actualLengthX)), glm::max(minLength, glm::min(maxLength, actualLengthY)) )); } else { - setSize(glm::vec2(getSize().x, glm::max(minLength, actualLength))); + setSize(glm::vec2(glm::max(minLength, actualLengthX), glm::max(minLength, actualLengthY))); } } @@ -93,7 +93,8 @@ void Panel::refresh() { y += nodeSize.y + margin.w + interval; maxw = fmax(maxw, ex + nodeSize.x + margin.z + padding.z); } - actualLength = y + padding.w; + actualLengthX = size.x; + actualLengthY = y + padding.w; } else { float maxh = size.y; for (auto& node : nodes) { @@ -115,6 +116,7 @@ void Panel::refresh() { x += nodesize.x + margin.z + interval; maxh = fmax(maxh, ey + nodesize.y + margin.w + padding.w); } - actualLength = size.y; + actualLengthY = size.y; + actualLengthX = x + padding.z; } } diff --git a/src/graphics/ui/elements/TextBox.cpp b/src/graphics/ui/elements/TextBox.cpp index f37673fc1..7bd7cd646 100644 --- a/src/graphics/ui/elements/TextBox.cpp +++ b/src/graphics/ui/elements/TextBox.cpp @@ -452,7 +452,7 @@ void TextBox::refreshLabel() { uint height = label->getLinesNumber() * rawTextCache.metrics.lineHeight * label->getLineInterval(); label->setSize(glm::vec2(label->getSize().x, height)); - actualLength = height; + actualLengthY = height; } else { setScrollable(false); } From 660bd0a5d398bfad225ce5428cc19f2f5d0169b6 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 7 Aug 2026 22:28:48 +0300 Subject: [PATCH 3/4] format Container.cpp and Panel.cpp --- src/graphics/ui/elements/Container.cpp | 89 +++++++++++++++----------- src/graphics/ui/elements/Panel.cpp | 8 ++- 2 files changed, 58 insertions(+), 39 deletions(-) diff --git a/src/graphics/ui/elements/Container.cpp b/src/graphics/ui/elements/Container.cpp index 954c9879d..3d03c2fe3 100644 --- a/src/graphics/ui/elements/Container.cpp +++ b/src/graphics/ui/elements/Container.cpp @@ -1,9 +1,9 @@ #include "Container.hpp" -#include "graphics/core/DrawContext.hpp" -#include "graphics/core/Batch2D.hpp" -#include "window/Window.hpp" #include "../GUI.hpp" +#include "graphics/core/Batch2D.hpp" +#include "graphics/core/DrawContext.hpp" +#include "window/Window.hpp" #include #include @@ -26,15 +26,15 @@ std::shared_ptr Container::getAt(const glm::vec2& pos) { if (!isInside(pos)) { return nullptr; } - int diff = (actualLengthY-size.y); - if (scrollable && diff > 0 && pos.x > calcPos().x + getSize().x - scrollBarWidth) { + int diff = (actualLengthY - size.y); + if (scrollable && diff > 0 && + pos.x > calcPos().x + getSize().x - scrollBarWidth) { return UINode::getAt(pos); } - for (int i = nodes.size()-1; i >= 0; i--) { + for (int i = nodes.size() - 1; i >= 0; i--) { auto& node = nodes[i]; - if (!node->isVisible()) - continue; + if (!node->isVisible()) continue; auto hover = node->getAt(pos); if (hover != nullptr) { return hover; @@ -45,7 +45,7 @@ std::shared_ptr Container::getAt(const glm::vec2& pos) { void Container::click(int x, int y) { UINode::click(x, y); - + if (scrollable) { auto pos = calcPos(); x -= pos.x; @@ -65,9 +65,10 @@ void Container::mouseMove(int x, int y) { auto pos = calcPos(); x -= pos.x; y -= pos.y; - int diff = (actualLengthY-size.y); + int diff = (actualLengthY - size.y); if (diff > 0) { - scrollY -= (y - prevScrollY) / static_cast(size.y) * actualLengthY; + scrollY -= + (y - prevScrollY) / static_cast(size.y) * actualLengthY; scrollY = -glm::min( glm::max(static_cast(-scrollY), 0.0f), actualLengthY - size.y ); @@ -101,26 +102,28 @@ void Container::act(float delta) { } } } - intervalEvents.erase(std::remove_if( - intervalEvents.begin(), intervalEvents.end(), - [](const IntervalEvent& event) { - return event.repeat == 0; - } - ), intervalEvents.end()); + intervalEvents.erase( + std::remove_if( + intervalEvents.begin(), + intervalEvents.end(), + [](const IntervalEvent& event) { return event.repeat == 0; } + ), + intervalEvents.end() + ); } void Container::scrolled(int value) { auto size = getSize(); - int diff = (actualLengthY > size.y ? actualLengthY - size.y : actualLengthX - size.x); - int& scroll = (actualLengthY > size.y ? scrollY : scrollX); + bool isVertical = actualLengthY > size.y; + int diff = (isVertical ? actualLengthY - size.y : actualLengthX - size.x); + int& scroll = (isVertical ? scrollY : scrollX); if (scroll < 0 && diff <= 0) { scroll = 0; } if (diff > 0 && scrollable) { scroll += value * scrollStep; - if (scroll > 0) - scroll = 0; + if (scroll > 0) scroll = 0; if (-scroll > diff) { scroll = -diff; } @@ -143,21 +146,25 @@ void Container::draw(const DrawContext& pctx, const Assets& assets) { if (!nodes.empty()) { batch->flush(); DrawContext ctx = pctx.sub(); - ctx.setScissors(glm::vec4(pos.x, pos.y, glm::ceil(size.x), glm::ceil(size.y))); + ctx.setScissors( + glm::vec4(pos.x, pos.y, glm::ceil(size.x), glm::ceil(size.y)) + ); for (const auto& node : nodes) { - if (node->isVisible()) - node->draw(pctx, assets); + if (node->isVisible()) node->draw(pctx, assets); } - int diff = (actualLengthY-size.y); + int diff = (actualLengthY - size.y); if (scrollable && diff > 0) { - int h = glm::max(size.y / actualLengthY * size.y, scrollBarWidth / 2.0f); + int h = glm::max( + size.y / actualLengthY * size.y, scrollBarWidth / 2.0f + ); batch->untexture(); batch->setColor(glm::vec4(1, 1, 1, 0.3f)); batch->rect( pos.x + size.x - scrollBarWidth, pos.y - scrollY / static_cast(diff) * (size.y - h), - scrollBarWidth, h + scrollBarWidth, + h ); } batch->flush(); @@ -166,8 +173,7 @@ void Container::draw(const DrawContext& pctx, const Assets& assets) { void Container::drawBackground(const DrawContext& pctx, const Assets&) { glm::vec4 color = calcColor(); - if (color.a <= 0.001f) - return; + if (color.a <= 0.001f) return; glm::vec2 pos = calcPos(); auto batch = pctx.getBatch2D(); @@ -197,11 +203,16 @@ void Container::add(const std::shared_ptr& node, glm::vec2 pos) { void Container::remove(UINode* selected) { selected->setParent(nullptr); - nodes.erase(std::remove_if(nodes.begin(), nodes.end(), - [selected](const std::shared_ptr& node) { - return node.get() == selected; - } - ), nodes.end()); + nodes.erase( + std::remove_if( + nodes.begin(), + nodes.end(), + [selected](const std::shared_ptr& node) { + return node.get() == selected; + } + ), + nodes.end() + ); refresh(); } @@ -245,9 +256,13 @@ void Container::setScrollStep(int step) { } void Container::refresh() { - std::stable_sort(nodes.begin(), nodes.end(), [](const auto& a, const auto& b) { - return a->getZIndex() < b->getZIndex(); - }); + std::stable_sort( + nodes.begin(), + nodes.end(), + [](const auto& a, const auto& b) { + return a->getZIndex() < b->getZIndex(); + } + ); } void Container::setScroll(int scroll) { diff --git a/src/graphics/ui/elements/Panel.cpp b/src/graphics/ui/elements/Panel.cpp index 3b452e892..4d133c875 100644 --- a/src/graphics/ui/elements/Panel.cpp +++ b/src/graphics/ui/elements/Panel.cpp @@ -41,10 +41,14 @@ glm::vec2 Panel::getContentSize() const { void Panel::cropToContent() { if (maxLength > 0.0f) { setSize(glm::vec2( - glm::max(minLength, glm::min(maxLength, actualLengthX)), glm::max(minLength, glm::min(maxLength, actualLengthY)) + glm::max(minLength, glm::min(maxLength, actualLengthX)), + glm::max(minLength, glm::min(maxLength, actualLengthY)) )); } else { - setSize(glm::vec2(glm::max(minLength, actualLengthX), glm::max(minLength, actualLengthY))); + setSize(glm::vec2( + glm::max(minLength, actualLengthX), + glm::max(minLength, actualLengthY) + )); } } From 8c5a549773468d3372697d84bc1fee901df395c1 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 7 Aug 2026 22:39:48 +0300 Subject: [PATCH 4/4] cleanup element classes --- src/graphics/ui/elements/CheckBox.hpp | 29 +++-- src/graphics/ui/elements/Frame.hpp | 2 +- src/graphics/ui/elements/InventoryView.hpp | 10 +- src/graphics/ui/elements/Label.hpp | 54 ++++----- src/graphics/ui/elements/Menu.hpp | 2 +- src/graphics/ui/elements/ModelViewer.hpp | 7 +- src/graphics/ui/elements/Plotter.hpp | 2 +- src/graphics/ui/elements/TextBox.cpp | 8 +- src/graphics/ui/elements/TextBox.hpp | 124 ++++++++++----------- src/graphics/ui/elements/TrackBar.cpp | 2 +- src/graphics/ui/elements/TrackBar.hpp | 42 +++---- 11 files changed, 141 insertions(+), 141 deletions(-) diff --git a/src/graphics/ui/elements/CheckBox.hpp b/src/graphics/ui/elements/CheckBox.hpp index 5ca144618..0f520d43f 100644 --- a/src/graphics/ui/elements/CheckBox.hpp +++ b/src/graphics/ui/elements/CheckBox.hpp @@ -6,7 +6,7 @@ #include "Panel.hpp" namespace gui { - class CheckBox : public UINode { + class CheckBox final : public UINode { protected: glm::vec4 checkColor {1.0f, 1.0f, 1.0f, 0.4f}; boolsupplier supplier = nullptr; @@ -15,23 +15,22 @@ namespace gui { public: explicit CheckBox(GUI& gui, bool checked = false); - virtual void draw(const DrawContext& pctx, const Assets& assets) - override; + void draw(const DrawContext& pctx, const Assets& assets) override; - virtual void mouseRelease(int x, int y) override; + void mouseRelease(int x, int y) override; - virtual void setSupplier(boolsupplier supplier); - virtual void setConsumer(boolconsumer consumer); + void setSupplier(boolsupplier supplier); + void setConsumer(boolconsumer consumer); - virtual CheckBox* setChecked(bool flag); + CheckBox* setChecked(bool flag); - virtual bool isChecked() const { + bool isChecked() const { if (supplier) return supplier(); return checked; } }; - class FullCheckBox : public Panel { + class FullCheckBox final : public Panel { protected: std::shared_ptr checkbox; std::shared_ptr