From 8740756c970fe503183dcb7d37d99c51691bcd80 Mon Sep 17 00:00:00 2001 From: ravi688 Date: Wed, 11 Sep 2024 02:49:54 +0530 Subject: [PATCH] [SUTK] Implemented and tested SUTK::HPaneContainer it is now working as expected - with minor improvements still need to be made --- sutk/include/sutk/AnchorRect.hpp | 9 ++- sutk/include/sutk/Container.hpp | 5 +- sutk/include/sutk/HPaneContainer.hpp | 23 ++++--- sutk/include/sutk/tests/HPaneTest.hpp | 3 +- sutk/source/AnchorRect.cpp | 23 +++++-- sutk/source/Container.cpp | 47 +++++++++----- sutk/source/HPaneContainer.cpp | 91 ++++++++++++++++++++++----- sutk/source/tests/HPaneTest.cpp | 22 ++++++- 8 files changed, 174 insertions(+), 49 deletions(-) diff --git a/sutk/include/sutk/AnchorRect.hpp b/sutk/include/sutk/AnchorRect.hpp index e4f6839d..cbc32c05 100644 --- a/sutk/include/sutk/AnchorRect.hpp +++ b/sutk/include/sutk/AnchorRect.hpp @@ -12,9 +12,9 @@ namespace SUTK private: Rect2Df m_rect; Rect2Df m_constraintRect; - Container& m_childRect; - Container& m_parentRect; - AnchorRect(Container& childRect, Container& parentRect) noexcept; + Container* m_childRect; + Container* m_parentRect; + AnchorRect(Container* childRect, Container* parentRect) noexcept; friend class Container; // should be called by the parent container whenever its rect is resized or changes its position @@ -24,6 +24,9 @@ namespace SUTK Rect2Df getUnnormalizedAnchorRect() noexcept; void recalculateConstraints() noexcept; + + void setParent(Container* parent) noexcept; + void setChild(Container* child) noexcept; public: // getters diff --git a/sutk/include/sutk/Container.hpp b/sutk/include/sutk/Container.hpp index 949e817d..5826c4fa 100644 --- a/sutk/include/sutk/Container.hpp +++ b/sutk/include/sutk/Container.hpp @@ -85,6 +85,7 @@ namespace SUTK void setLayoutAttributes(const LayoutAttributes& attrs) noexcept; bool isLayoutIgnore() const noexcept { return m_isLayoutIgnore || (!isActive()); } void setLayoutIgnore(bool isIgnore) noexcept; + void setLayoutExpand() noexcept; // childs getters std::vector& getChilds() noexcept { return getContainerList(); } @@ -94,7 +95,7 @@ namespace SUTK Container* getParent() { return m_parent; } const Container* getParent() const { return m_parent; } // parent setters - void setParent(Container* parent) noexcept; + void setParent(Container* parent, bool isInvariantPos = true) noexcept; // rect getters Rect2Df getRect() const { return m_rect; } @@ -136,7 +137,7 @@ namespace SUTK // addition and removal of child containers // adds a new container as a child to this container - virtual void add(Container* container); + virtual void add(Container* container, bool isInvariantPos = true); // removes an existing container from this container virtual void remove(Container* container); }; diff --git a/sutk/include/sutk/HPaneContainer.hpp b/sutk/include/sutk/HPaneContainer.hpp index 57a94729..55fae6d2 100644 --- a/sutk/include/sutk/HPaneContainer.hpp +++ b/sutk/include/sutk/HPaneContainer.hpp @@ -1,26 +1,35 @@ #pragma once -#include +#include #include +#include // for std::array + namespace SUTK { - class RenderRectFill; + class RenderableContainer; - class HPaneContainer : public Container, + class HPaneContainer : public HBoxContainer, public MouseClickHandlerObject, public MouseMoveHandlerObject { private: - bool m_isGrabbed; - std::vector m_handleRects; + bool m_isHandleRect; + std::array m_grabbedHandle; + struct HandleAdjacencyData + { + Container* left; + Container* right; + }; + std::vector> m_handleRects; std::vector m_externalChilds; + Vec2Df m_prevPos; protected: virtual void onMouseClick(MouseButton button, KeyEvent action) override; virtual void onMouseMove(Vec2Df position) override; - virtual void onAddChild(Container* child) override; - virtual void onRemoveChild(Container* child) override; + virtual void add(Container* child, bool isInvariantPos = true) override; + virtual void remove(Container* child) override; public: HPaneContainer(UIDriver& driver, Container* parent = NULL) noexcept; virtual ~HPaneContainer() noexcept = default; diff --git a/sutk/include/sutk/tests/HPaneTest.hpp b/sutk/include/sutk/tests/HPaneTest.hpp index 89eeef4c..52c15b96 100644 --- a/sutk/include/sutk/tests/HPaneTest.hpp +++ b/sutk/include/sutk/tests/HPaneTest.hpp @@ -16,11 +16,12 @@ namespace SUTK { private: UIDriver* m_uiDriver; + IInputDriver* m_inputDriver; IGfxDriver* m_gfxDriver; HPaneContainer* m_hPaneContainer; public: - HPaneTest() : m_uiDriver(NULL), m_gfxDriver(NULL) { } + HPaneTest() : m_uiDriver(NULL), m_inputDriver(NULL), m_gfxDriver(NULL) { } DriverInitializationData getInitializationData() override; diff --git a/sutk/source/AnchorRect.cpp b/sutk/source/AnchorRect.cpp index 346f124f..dfb89508 100644 --- a/sutk/source/AnchorRect.cpp +++ b/sutk/source/AnchorRect.cpp @@ -3,7 +3,7 @@ namespace SUTK { - AnchorRect::AnchorRect(Container& childRect, Container& parentRect) noexcept : m_childRect(childRect), m_parentRect(parentRect) + AnchorRect::AnchorRect(Container* childRect, Container* parentRect) noexcept : m_childRect(childRect), m_parentRect(parentRect) { // NOTE: initially the anchor rect is degenerate (width and height both is zero) and has position as { 0, 0 } @@ -12,7 +12,8 @@ namespace SUTK Rect2Df AnchorRect::getUnnormalizedAnchorRect() noexcept { - Vec2Df parentSize = m_parentRect.getSize(); + _com_assert(m_parentRect != NULL); + Vec2Df parentSize = m_parentRect->getSize(); // calculate unnormalized anchor rect in the parent rect's local coordinates Rect2Df anchorRect { m_rect.getPosition() * parentSize, m_rect.getSize() * parentSize }; return anchorRect; @@ -20,16 +21,30 @@ namespace SUTK void AnchorRect::recalculateConstraints() noexcept { + if((m_childRect == NULL) || ((m_parentRect == NULL))) + return; Rect2Df anchorRect = getUnnormalizedAnchorRect(); // signed difference is the constraint - m_constraintRect = anchorRect - m_childRect.getRect(); + m_constraintRect = anchorRect - m_childRect->getRect(); + } + + void AnchorRect::setParent(Container* parent) noexcept + { + m_parentRect = parent; + recalculateConstraints(); + } + void AnchorRect::setChild(Container* child) noexcept + { + m_childRect = child; + recalculateConstraints(); } void AnchorRect::onParentResize(const Rect2Df& newRect, bool isPositionChanged, bool isSizeChanged) noexcept { + _com_assert(m_childRect != NULL); Rect2Df anchorRect = getUnnormalizedAnchorRect(); Rect2Df newChildRect = anchorRect - m_constraintRect; - m_childRect.setRect(newChildRect); + m_childRect->setRect(newChildRect); } void AnchorRect::onChildResize(const Rect2Df& newRect, bool isPositionChanged, bool isSizeChanged) noexcept diff --git a/sutk/source/Container.cpp b/sutk/source/Container.cpp index af78cb49..bdc5fca7 100644 --- a/sutk/source/Container.cpp +++ b/sutk/source/Container.cpp @@ -19,10 +19,7 @@ namespace SUTK m_isDebug(false) { if(parent != NULL) - { - setParentChildRelation(parent); - m_anchorRect = new AnchorRect(*this, *parent); - } + setParent(parent, false); } Container::~Container() @@ -39,6 +36,9 @@ namespace SUTK // remove this container from the list of "childs" of the (old) parent container bool result = com::erase_first_if(m_parent->m_containers.begin(), m_parent->m_containers.end(), [this](Container*& _container) { return _container == this; }); _assert(result == true); + _com_assert(m_anchorRect != NULL); + if(parent == NULL) + m_anchorRect->setParent(NULL); // invoke onRemoveChild callback for the parent container as a child 'this' has been removed from that m_parent->onRemoveChild(this); m_parent = NULL; @@ -52,6 +52,10 @@ namespace SUTK // add this container into the list of "childs" of the (new) parent container parent->m_containers.push_back(this); m_parent = parent; + if(m_anchorRect == NULL) + m_anchorRect = new AnchorRect(this, parent); + else + m_anchorRect->setParent(parent); // invoke onAdd callback function for this container as it has now been added into another (parent) container onAdd(this); // invoke onAddChild callback function for the parent container as a new child 'this' has been added into that @@ -59,14 +63,12 @@ namespace SUTK } } - void Container::setParent(Container* parent) noexcept + void Container::setParent(Container* parent, bool isInvariantPos) noexcept { - // recalculate this container's rect into the local space of new parent container - Vec2Df screenCoords = getLocalCoordsToScreenCoords({ 0u, 0u }); - Vec2Df localCoords = (parent != NULL) ? parent->getScreenCoordsToLocalCoords(screenCoords) : screenCoords; - setPosition(localCoords); - - setParentChildRelation(parent); + if(parent != NULL) + parent->add(this, isInvariantPos); + else if(m_parent != NULL) + m_parent->remove(this); } bool Container::containsGlobalCoords(Vec2Df globalCoords) const noexcept @@ -114,16 +116,26 @@ namespace SUTK _assert(parent != NULL); } - void Container::add(Container* container) + void Container::add(Container* container, bool isInvariantPos) { _assert(container != NULL); - container->setParent(this); + if(isInvariantPos) + { + // recalculate this container's rect into the local space of new parent container + Vec2Df screenCoords = container->getLocalCoordsToScreenCoords({ 0u, 0u }); + Vec2Df localCoords = getScreenCoordsToLocalCoords(screenCoords); + container->setPosition(localCoords); + } + else + container->setPosition({ 0.0f, 0.0f }); + + container->setParentChildRelation(this); } void Container::remove(Container* container) { _assert(container != NULL); - container->setParent(NULL); + container->setParentChildRelation(NULL); } void Container::onParentResize(const Rect2Df& newRect, bool isPositionChanged, bool isSizeChanged) @@ -209,4 +221,11 @@ namespace SUTK recalculateLayoutParent(); m_isLayoutIgnore = isIgnore; } + + void Container::setLayoutExpand() noexcept + { + auto& attr = getLayoutAttributes(); + attr.prefSize = attr.maxSize; + setLayoutAttributes(attr); + } } \ No newline at end of file diff --git a/sutk/source/HPaneContainer.cpp b/sutk/source/HPaneContainer.cpp index 9a5a5498..ac52818c 100644 --- a/sutk/source/HPaneContainer.cpp +++ b/sutk/source/HPaneContainer.cpp @@ -1,42 +1,101 @@ #include #include +#include -#define HANDLE_HIGHLIGHT_COLOR Color4::grey(0.5f) +#define HANDLE_HOVER_COLOR Color4::grey(0.5f) +#define HANDLE_IDLE_COLOR Color4::grey(0.2f) +#define HANDLE_WIDTH 0.1f namespace SUTK { - HPaneContainer::HPaneContainer(UIDriver& driver, Container* parent) noexcept : Container(driver, parent), + HPaneContainer::HPaneContainer(UIDriver& driver, Container* parent) noexcept : HBoxContainer(driver, parent), MouseClickHandlerObject(driver, this), - MouseMoveHandlerObject(driver, this) + MouseMoveHandlerObject(driver, this), + m_isHandleRect(false), + m_grabbedHandle({ NULL, NULL, NULL }) { } void HPaneContainer::onMouseClick(MouseButton button, KeyEvent action) { - // if((m_handleRect == NULL) || (button != MouseButton::Left)) - // return; - - // if(action == KeyEvent::Press) - // { - // Vec2Df pos = getInputDriver().getMousePosition(); - // if(m_handleRect->containsGlobalCoords(pos)) - // m_isGrabbed = true; - // } - // else - // m_isGrabbed = false; + if(button != MouseButton::Left) + return; + + if(action == KeyEvent::Press) + { + Vec2Df pos = getInputDriver().getMousePosition(); + for(const auto &handle : m_handleRects) + { + if(handle.first->containsGlobalCoords(pos)) + { + m_grabbedHandle[0] = handle.first; + m_grabbedHandle[1] = handle.second.left; + m_grabbedHandle[2] = handle.second.right; + m_prevPos = pos; + break; + } + } + } + else + m_grabbedHandle = { NULL, NULL, NULL }; } void HPaneContainer::onMouseMove(Vec2Df position) { + if(m_grabbedHandle[0]) + { + Vec2Df pos = getInputDriver().getMousePosition(); + auto disp = pos - m_prevPos; + m_prevPos = pos; + + auto left = m_grabbedHandle[1]; + auto middle = m_grabbedHandle[0]; + auto right = m_grabbedHandle[2]; + + auto rect = left->getRect(); + rect.extendRight(disp.x); + left->setRect(rect); + + rect = middle->getRect(); + rect.extendLeft(-disp.x); + rect.extendRight(disp.x); + middle->setRect(rect); + + rect = right->getRect(); + rect.extendLeft(-disp.x); + right->setRect(rect); + } } - void HPaneContainer::onAddChild(Container* child) + void HPaneContainer::add(Container* child, bool isInvariantPos) { + if(m_isHandleRect) + { + HBoxContainer::add(child, isInvariantPos); + m_isHandleRect = false; + return; + } + std::size_t externChildCount = m_externalChilds.size(); + if(externChildCount > 0) + { + m_isHandleRect = true; + RenderableContainer* handleRectCont = getUIDriver().createContainer(this); + LayoutAttributes attr = handleRectCont->getLayoutAttributes(); + attr.minSize.width = HANDLE_WIDTH; + attr.prefSize.width = HANDLE_WIDTH; + handleRectCont->setLayoutAttributes(attr); + RenderRect* handleRect = getUIDriver().createRenderable(handleRectCont); + handleRect->setColor(HANDLE_IDLE_COLOR); + _com_assert(getChilds().size() > 1); + m_handleRects.push_back({ handleRectCont, { getChilds()[getChilds().size() - 2], child } }); + } + HBoxContainer::add(child, isInvariantPos); m_externalChilds.push_back(child); } - void HPaneContainer::onRemoveChild(Container* child) + void HPaneContainer::remove(Container* child) { + HBoxContainer::remove(child); bool result = com::find_erase(m_externalChilds, child); _com_assert(result); } diff --git a/sutk/source/tests/HPaneTest.cpp b/sutk/source/tests/HPaneTest.cpp index 5fa72215..10166ea2 100644 --- a/sutk/source/tests/HPaneTest.cpp +++ b/sutk/source/tests/HPaneTest.cpp @@ -1,8 +1,11 @@ #include #include +#include #include #include +#include +#include namespace SUTK { @@ -16,16 +19,31 @@ namespace SUTK void HPaneTest::initialize(SGE::Driver& driver) { m_gfxDriver = new SGEGfxDriver(driver); - m_uiDriver = new UIDriver(*m_gfxDriver); + m_inputDriver = new SGEInputDriver(driver); + m_uiDriver = new UIDriver(*m_gfxDriver, *m_inputDriver); FullWindowContainer* rootContainer = m_uiDriver->createContainer(NULL); m_hPaneContainer = m_uiDriver->createContainer(rootContainer); m_hPaneContainer->alwaysFitInParent(); - m_hPaneContainer->enableDebug(); + // m_hPaneContainer->enableDebug(); + + RenderableContainer* c1 = m_uiDriver->createContainer(m_hPaneContainer); + RenderRectFill* r1 = m_uiDriver->createRenderable(c1); + r1->setColor(Color4::red()); + RenderableContainer* c2 = m_uiDriver->createContainer(m_hPaneContainer); + RenderRectFill* r2 = m_uiDriver->createRenderable(c2); + r2->setColor(Color4::green()); + RenderableContainer* c3 = m_uiDriver->createContainer(m_hPaneContainer); + RenderRectFill* r3 = m_uiDriver->createRenderable(c3); + r3->setColor(Color4::blue()); + c1->setLayoutExpand(); + c2->setLayoutExpand(); + c3->setLayoutExpand(); } void HPaneTest::terminate(SGE::Driver& driver) { delete m_uiDriver; + delete m_inputDriver; delete m_gfxDriver; }