From 54dcbcb46bee0e501188c07a24fdb16911967bec Mon Sep 17 00:00:00 2001 From: IlyaShurupov Date: Mon, 14 Oct 2024 21:31:05 +0300 Subject: [PATCH] Refactor Layout Manager --- Containers/public/Buffer.hpp | 2 +- Containers/public/Buffer2D.hpp | 4 +- Containers/public/List.hpp | 4 +- Containers/tests/IntervalTreeTests.cpp | 2 +- Graphics/public/GraphicApplication.hpp | 4 +- Math/public/Mat.hpp | 10 +- Modules/public/Assert.hpp | 5 +- Modules/public/Common.hpp | 2 +- Objects/applications/GUI.cpp | 4 +- TODO | 56 +++++--- Widgets/private/GridLayoutWidget.cpp | 2 +- WidgetsNew/examples/Example.cpp | 31 +++++ WidgetsNew/private/RootWidget.cpp | 6 +- WidgetsNew/private/layouts/BasicLayout.cpp | 55 +++++--- WidgetsNew/private/layouts/DockLayout.cpp | 11 +- WidgetsNew/private/layouts/FloatingLayout.cpp | 6 +- WidgetsNew/private/managers/DebugManager.cpp | 128 +++++++++++++----- WidgetsNew/private/managers/LayoutManager.cpp | 99 ++++++++++++-- WidgetsNew/private/managers/UpdateManager.cpp | 17 ++- WidgetsNew/public/Layout.hpp | 7 +- WidgetsNew/public/RootWidget.hpp | 1 - WidgetsNew/public/layouts/BasicLayout.hpp | 11 +- WidgetsNew/public/layouts/DockLayout.hpp | 5 +- WidgetsNew/public/layouts/FloatingLayout.hpp | 2 +- WidgetsNew/public/mangers/DebugManager.hpp | 25 ++++ WidgetsNew/public/mangers/LayoutManager.hpp | 28 ++++ WidgetsNew/public/mangers/UpdateManager.hpp | 3 + WidgetsNew/public/widgets/DockWidget.hpp | 1 + 28 files changed, 408 insertions(+), 123 deletions(-) diff --git a/Containers/public/Buffer.hpp b/Containers/public/Buffer.hpp index ffacad3..8a8821c 100644 --- a/Containers/public/Buffer.hpp +++ b/Containers/public/Buffer.hpp @@ -418,7 +418,7 @@ namespace tp { void reverse() { for (ualni idx = 0; idx < mLoad / 2; idx++) { - swap(mBuff[idx], mBuff[mLoad - idx - 1]); + swapV(mBuff[idx], mBuff[mLoad - idx - 1]); } } diff --git a/Containers/public/Buffer2D.hpp b/Containers/public/Buffer2D.hpp index d0a4431..9fda2a8 100644 --- a/Containers/public/Buffer2D.hpp +++ b/Containers/public/Buffer2D.hpp @@ -63,7 +63,7 @@ namespace tp { for (Index i = 0; i < mSize.x; i++) { const auto lenIdx = mSize.y - 1; for (Index j = 0; j < mSize.y / 2; j++) { - swap(get({i, j}), get({i, lenIdx - j})); + swapV(get({ i, j }), get({ i, lenIdx - j })); } } } @@ -72,7 +72,7 @@ namespace tp { for (Index i = 0; i < mSize.y; i++) { const auto lenIdx = mSize.x - 1; for (Index j = 0; j < mSize.x / 2; j++) { - swap(get({i, j}), get({i, lenIdx - j})); + swapV(get({ i, j }), get({ i, lenIdx - j })); } } } diff --git a/Containers/public/List.hpp b/Containers/public/List.hpp index 0e57e16..4abef32 100644 --- a/Containers/public/List.hpp +++ b/Containers/public/List.hpp @@ -288,9 +288,9 @@ namespace tp { while (iter) { tmp = iter; iter = iter->next; - swap(tmp->next, tmp->prev); + swapV(tmp->next, tmp->prev); } - swap(mFirst, mLast); + swapV(mFirst, mLast); } void detachAll() { diff --git a/Containers/tests/IntervalTreeTests.cpp b/Containers/tests/IntervalTreeTests.cpp index 2acd700..f7fcabb 100644 --- a/Containers/tests/IntervalTreeTests.cpp +++ b/Containers/tests/IntervalTreeTests.cpp @@ -21,7 +21,7 @@ struct Interval { start = ((halnf) randomFloat()) * (span) - offset; end = ((halnf) randomFloat()) * (span) - offset; - if (start > end) swap(start, end); + if (start > end) swapV(start, end); auto len = (end - start) * scale * 0.5f; auto mid = (start + end) / 2.f; diff --git a/Graphics/public/GraphicApplication.hpp b/Graphics/public/GraphicApplication.hpp index 742a18f..253314d 100644 --- a/Graphics/public/GraphicApplication.hpp +++ b/Graphics/public/GraphicApplication.hpp @@ -28,8 +28,8 @@ namespace tp { protected: bool mInitialized = false; - ualni mDrawPerSecond = 60; - ualni mProcPerSecond = 100; + ualni mDrawPerSecond = 1160; + ualni mProcPerSecond = 1300; Timer mDrawTimer; Timer mProcTimer; diff --git a/Math/public/Mat.hpp b/Math/public/Mat.hpp index 967a832..4c51bcd 100644 --- a/Math/public/Mat.hpp +++ b/Math/public/Mat.hpp @@ -221,7 +221,7 @@ namespace tp { static_assert(tNRows == tNColoumns); for (halni i = 0; i < tNColoumns; i++) { for (halni j = i + 1; j < tNColoumns; j++) { - swap((*this)[i][j], (*this)[j][i]); + swapV((*this)[i][j], (*this)[j][i]); } } return *this; @@ -479,7 +479,7 @@ namespace tp { Mat operator*(const Mat& in) { return transform(in); } Mat& transpose() { - swap(j.x, i.y); + swapV(j.x, i.y); return *this; } @@ -635,9 +635,9 @@ namespace tp { } Mat& transpose() { - swap(I.y, J.x); - swap(I.z, K.x); - swap(J.z, K.y); + swapV(I.y, J.x); + swapV(I.z, K.x); + swapV(J.z, K.y); return *this; } diff --git a/Modules/public/Assert.hpp b/Modules/public/Assert.hpp index f1f8a5f..f54ab24 100644 --- a/Modules/public/Assert.hpp +++ b/Modules/public/Assert.hpp @@ -33,9 +33,12 @@ namespace tp { __builtin_debugtrap(); \ } #elif defined(ENV_OS_LINUX) + +#include + #define DEBUG_BREAK(expr) \ if (expr) { \ - __builtin_trap(); \ + raise(SIGTRAP); \ } #else #define DEBUG_BREAK(expr) () diff --git a/Modules/public/Common.hpp b/Modules/public/Common.hpp index 423a6c2..f357e01 100644 --- a/Modules/public/Common.hpp +++ b/Modules/public/Common.hpp @@ -85,7 +85,7 @@ namespace tp { } template - inline void swap(T& t1, T& t2) { + inline void swapV(T& t1, T& t2) { const T tmp = t1; t1 = t2; t2 = tmp; diff --git a/Objects/applications/GUI.cpp b/Objects/applications/GUI.cpp index d14daf2..4eced90 100644 --- a/Objects/applications/GUI.cpp +++ b/Objects/applications/GUI.cpp @@ -697,13 +697,13 @@ obj::ObjectsGUI::ViewStackNode obj::ObjectsGUI::listView(obj::ListObject* obj) { } if (childo.node()->prev && ImGui::Selectable("Move Up")) { - tp::swap(childo.node()->prev->data, childo.data()); + tp::swapV(childo.node()->prev->data, childo.data()); ImGui::EndPopup(); break; } if (childo.node()->next && ImGui::Selectable("Move Down")) { - tp::swap(childo.node()->next->data, childo.data()); + tp::swapV(childo.node()->next->data, childo.data()); ImGui::EndPopup(); break; } diff --git a/TODO b/TODO index d2f0156..c1e841e 100644 --- a/TODO +++ b/TODO @@ -1,14 +1,31 @@ +Widgets-New: + Lock-focus feature + Collapsing menu + Scrolling in basic layout + + Add Widgets: + popups, drop-downs, tool-tips + list menu + + Add UI scaling + Add Theming + + +Sketch3D: + Use new widgets + add gizmos + add save and loads + add better bui + selection ALL: - Gradually introduce STL into the project (replace own classes or add seamless interface and conversions into STL) - Remove BaseModule and Connection modules - remove archiver and add boost serialization - Bring windows old window to graphics - + remove archiver and add boost serialization ?? + Bring ms-windows old window to graphics Check Warnings Make all modules stable with tests + Modules: Remove all static variable into module's data @@ -65,23 +82,23 @@ Language: Make two grammars Regular and Context-free For each grammar make grammar rules parser, example sentence generation and sentence parsing Make automations itself a universal tool - NFA DFA conversions - + Widgets: - Add shortcuts - Config cache may be static - Cleanup - Add animations + Add shortcuts + Config cache may be static + Cleanup + Add animations LibraryViewer: - artworks - how to easily add more songs? - seeker - song idx - non-existing highlight - prev next - remove debug gui - queue & repeat & shuffle... - new database with history + artworks + how to easily add more songs? + seeker + song idx + non-existing highlight + prev next + remove debug gui + queue & repeat & shuffle... + new database with history Math: FFT @@ -92,7 +109,6 @@ Math: RayTracer: Features: - iodn Normals flag Material, Normals, per trig info diff --git a/Widgets/private/GridLayoutWidget.cpp b/Widgets/private/GridLayoutWidget.cpp index fa61231..de92497 100644 --- a/Widgets/private/GridLayoutWidget.cpp +++ b/Widgets/private/GridLayoutWidget.cpp @@ -36,7 +36,7 @@ void DockWidget::removeSideWidget(Side side) { removed = true; } if (removed) { - swap(mSideWidgets[i].order, mSideWidgets[i + 1].order); + swapV(mSideWidgets[i].order, mSideWidgets[i + 1].order); } } mSideWidgets[3].order = -1; diff --git a/WidgetsNew/examples/Example.cpp b/WidgetsNew/examples/Example.cpp index a33296e..a3661f5 100644 --- a/WidgetsNew/examples/Example.cpp +++ b/WidgetsNew/examples/Example.cpp @@ -24,6 +24,34 @@ public: setup1(); } + void setupLay() { + mRootWidget.setRootWidget(&mWidget); + + mWidget.addChild(&mWidgets[1]); + + mWidgets[1].addChild(&mButtons[1]); + mWidgets[1].addChild(&mButtons[2]); + mWidgets[1].addChild(&mWidgets[2]); + + RootWidget::setWidgetArea(mWidgets[1], { 300, 100, 350, 800 }); + RootWidget::setWidgetArea(mButtons[2], { 100, 100, 150, 300 }); + + mWidgets[2].addChild(&mButtons[3]); + mWidgets[2].addChild(&mButtons[4]); + mWidgets[2].addChild(&mButtons[5]); + mWidgets[2].addChild(&mButtons[6]); + + mButtons[1].setSizePolicy(SizePolicy::Expanding, SizePolicy::Expanding); + mButtons[2].setSizePolicy(SizePolicy::Expanding, SizePolicy::Expanding); + mButtons[3].setSizePolicy(SizePolicy::Expanding, SizePolicy::Expanding); + mButtons[4].setSizePolicy(SizePolicy::Expanding, SizePolicy::Expanding); + mButtons[5].setSizePolicy(SizePolicy::Expanding, SizePolicy::Expanding); + mButtons[6].setSizePolicy(SizePolicy::Expanding, SizePolicy::Expanding); + + mWidgets[2].setSizePolicy(SizePolicy::Expanding, SizePolicy::Expanding); + ((BasicLayout*)mWidgets[1].getLayout())->setLayoutPolicy(LayoutPolicy::Horizontal); + } + void setup1() { mRootWidget.setRootWidget(&mDockLayout); @@ -122,6 +150,9 @@ public: } private: + Widget mWidgets[15]; + ButtonWidget mButtons[15]; + Widget mWidget; ButtonWidget mButton; diff --git a/WidgetsNew/private/RootWidget.cpp b/WidgetsNew/private/RootWidget.cpp index bec5a69..9178e95 100644 --- a/WidgetsNew/private/RootWidget.cpp +++ b/WidgetsNew/private/RootWidget.cpp @@ -23,7 +23,7 @@ void RootWidget::setRootWidget(Widget* widget) { void RootWidget::processFrame(EventHandler* events, const RectF& screenArea) { mRoot->setArea(screenArea); - if (!mDebugManager.update(this, *events)) return; + if (!gDebugWidget.update(this, *events)) return; // construct hierarchy tree of widgets to process mUpdateManager.updateTreeToProcess(mRoot); @@ -49,7 +49,7 @@ void RootWidget::processFrame(EventHandler* events, const RectF& screenArea) { } bool RootWidget::needsUpdate() const { - if (mDebugManager.isRedrawAlways()) return true; + if (gDebugWidget.isRedrawAlways()) return true; return mUpdateManager.isPendingUpdates(); } @@ -58,7 +58,7 @@ void RootWidget::drawFrame(Canvas& canvas) { drawRecursion(canvas, mRoot, { 0, 0 }); - mDebugManager.drawDebug(this, canvas); + gDebugWidget.drawDebug(this, canvas); } diff --git a/WidgetsNew/private/layouts/BasicLayout.cpp b/WidgetsNew/private/layouts/BasicLayout.cpp index 5fb1e29..720c959 100644 --- a/WidgetsNew/private/layouts/BasicLayout.cpp +++ b/WidgetsNew/private/layouts/BasicLayout.cpp @@ -7,20 +7,26 @@ using namespace tp; -void BasicLayout::pickRect() { +void BasicLayout::pickRect(bool vertical) { auto current = getArea(); auto children = getChildrenEnclosure(); auto parent = getParentEnclosure(); + RectF newArea = current; - auto rangeX = pickRange(current.getRangeX(), children.getRangeX(), parent.getRangeX(), false); - auto rangeY = pickRange(current.getRangeY(), children.getRangeY(), parent.getRangeY(), true); - - auto newArea = RectF(rangeX, rangeY); + if (vertical) { + auto rangeY = pickRange(current.getRangeY(), children.getRangeY(), parent.getRangeY(), true); + newArea = RectF(current.getRangeX(), rangeY); + } else { + auto rangeX = pickRange(current.getRangeX(), children.getRangeX(), parent.getRangeX(), false); + newArea = RectF(rangeX, current.getRangeY()); + } setArea(newArea); } void BasicLayout::clampRect() { + DEBUG_ASSERT(0) + auto current = getArea(); auto children = getChildrenEnclosure(); auto parent = getParentEnclosure(); @@ -31,13 +37,21 @@ void BasicLayout::clampRect() { setArea(RectF(rangeX, rangeY)); } -void BasicLayout::adjustChildrenRect() { +void BasicLayout::updateLayout(bool vertical) { if (children().empty()) return; - switch (mLayoutPolicy) { - case LayoutPolicy::Passive: break; - case LayoutPolicy::Vertical: adjustLayout(true); break; - case LayoutPolicy::Horizontal: adjustLayout(false); break; + if (vertical) { + switch (mLayoutPolicy) { + case LayoutPolicy::Vertical: adjustLayout(true); break; + case LayoutPolicy::Passive: + case LayoutPolicy::Horizontal: break; + } + } else { + switch (mLayoutPolicy) { + case LayoutPolicy::Horizontal: adjustLayout(false); break; + case LayoutPolicy::Passive: + case LayoutPolicy::Vertical: break; + } } } @@ -61,9 +75,7 @@ void BasicLayout::adjustLayout(bool vertical) { Vec2F availableSize = getArea().size; for (auto child : children()) { - if (child->getLayout()->getSizePolicy()[!vertical] != SizePolicy::Minimal) { - child->getLayout()->pickRect(); - } + child->getLayout()->pickRect(vertical); if (child->getLayout()->getSizePolicy()[vertical] == SizePolicy::Expanding) { contributors.emplace_back( child, true ); @@ -71,7 +83,7 @@ void BasicLayout::adjustLayout(bool vertical) { auto area = child->getLayout()->getArea(); area.size[vertical] = 0; child->setAreaCache(area); - child->getLayout()->clampRect(); + child->getLayout()->clampMinMaxSize(); } contentSize += child->getLayout()->getArea().size; @@ -104,15 +116,26 @@ void BasicLayout::adjustLayout(bool vertical) { ); } - // arrange + // set opposite direction size + for (auto child : children()) { + // if (child->getLayout()->getSizePolicy()[!vertical] != SizePolicy::Minimal) { + auto area = child->getLayout()->getArea(); + area.size[!vertical] = getArea().size[!vertical] - mLayoutMargin * 2; + child->setAreaCache(area); + // } + } + + // set pos halnf iterPos = mLayoutMargin; for (auto child : children()) { auto area = child->getLayout()->getArea(); + area.pos[vertical] = iterPos; + area.pos[!vertical] = mLayoutMargin; + iterPos += area.size[vertical] + mLayoutGap; child->setAreaCache(area); - // child->updateAnimations(); // child->triggerWidgetUpdate("layout changed"); } diff --git a/WidgetsNew/private/layouts/DockLayout.cpp b/WidgetsNew/private/layouts/DockLayout.cpp index c2957b1..adcf48e 100644 --- a/WidgetsNew/private/layouts/DockLayout.cpp +++ b/WidgetsNew/private/layouts/DockLayout.cpp @@ -44,7 +44,7 @@ bool DockLayout::undockWidget(Side side) { removed = true; } if (removed) { - swap(mSideWidgets[i].order, mSideWidgets[i + 1].order); + swapV(mSideWidgets[i].order, mSideWidgets[i + 1].order); } } mSideWidgets[3].order = -1; @@ -184,6 +184,15 @@ auto DockLayout::getSideFromWidget(Widget* widget) -> Side { return DockLayout::NONE; } +void DockLayout::updateLayout(bool vertical) { + for (auto child : children()) { + child->getLayout()->pickRect(vertical); + } + + if (vertical) return; + adjustChildrenRect(); +} + void DockLayout::adjustChildrenRect() { calculateSideAreas(); calculateResizeHandles(); diff --git a/WidgetsNew/private/layouts/FloatingLayout.cpp b/WidgetsNew/private/layouts/FloatingLayout.cpp index a7f6a9d..229de43 100644 --- a/WidgetsNew/private/layouts/FloatingLayout.cpp +++ b/WidgetsNew/private/layouts/FloatingLayout.cpp @@ -3,21 +3,21 @@ using namespace tp; -void FloatingLayout::pickRect() { +void FloatingLayout::pickRect(bool vertical) { if (mIsFloating) { auto area = getArea(); if (mIsResizing) { mPointerCurrent.clamp(mMinSize, mMaxSize); - area.size = mPointerCurrent + mHandleSize / 2.f; + area.size[vertical] = (mPointerCurrent + mHandleSize / 2.f)[vertical]; for (auto child : children()) { child->triggerWidgetUpdate("floating menu resized"); } } else if (mIsFloating) { - area.pos += mPointerCurrent - mPointerStart; + area.pos[vertical] += (mPointerCurrent - mPointerStart)[vertical]; } setArea(area); diff --git a/WidgetsNew/private/managers/DebugManager.cpp b/WidgetsNew/private/managers/DebugManager.cpp index f7416fe..de77067 100644 --- a/WidgetsNew/private/managers/DebugManager.cpp +++ b/WidgetsNew/private/managers/DebugManager.cpp @@ -1,11 +1,19 @@ #include "DebugManager.hpp" #include "RootWidget.hpp" +#include "BasicLayout.hpp" #include "imgui.h" +#include using namespace tp; +DebugManager tp::gDebugWidget; + +#define LIST_SIZE { -FLT_MIN, 150 } + bool DebugManager::update(RootWidget* rootWidget, EventHandler& events) { + mRootWidget = rootWidget; + if (mDebug) { auto area = rootWidget->mRoot->getAreaT(); area.size -= { 400, 0 }; @@ -14,53 +22,86 @@ bool DebugManager::update(RootWidget* rootWidget, EventHandler& events) { events.setEnableKeyEvents(true); if (events.isPressed(InputID::K)) mDebugStopProcessing = !mDebugStopProcessing; if (mDebugStopProcessing) return false; + + if (auto widget = rootWidget->mUpdateManager.mInFocusWidget) { + if (auto lay = dynamic_cast(widget->getLayout())) { + if (events.isPressed(InputID::V)) lay->setLayoutPolicy(LayoutPolicy::Vertical); + if (events.isPressed(InputID::H)) lay->setLayoutPolicy(LayoutPolicy::Horizontal); + + auto sizing = lay->getSizePolicy(); + + if (events.isDown(InputID::X)) { + if (events.isPressed(InputID::S)) lay->setSizePolicy(SizePolicy::Minimal, sizing.y); + if (events.isPressed(InputID::E)) lay->setSizePolicy(SizePolicy::Expanding, sizing.y); + } + if (events.isDown(InputID::Y)) { + if (events.isPressed(InputID::S)) lay->setSizePolicy(sizing.x, SizePolicy::Minimal); + if (events.isPressed(InputID::E)) lay->setSizePolicy(sizing.x, SizePolicy::Expanding); + } + } + } + + if (auto breakWidget = rootWidget->mUpdateManager.mInFocusWidget) { + if (events.isPressed(InputID::P)) mProcBreakpoints.insert(breakWidget); + if (events.isPressed(InputID::L)) mLayBreakpoints.insert(breakWidget); + } } return true; } void DebugManager::drawDebug(RootWidget* rootWidget, Canvas& canvas) { + mRootWidget = rootWidget; + ImGui::Checkbox("Draw debug", &mDebug); + if (!mDebug) { + return; + } + + ImGui::SameLine(); ImGui::Text("To Toggle processing press k"); + auto& upd = rootWidget->mUpdateManager; - if (mDebug) { - recursiveDraw(canvas, rootWidget->mRoot, { 0, 0 }, 0); + recursiveDraw(canvas, rootWidget->mRoot, { 0, 0 }, 0); - ImGui::Text("Triggered Widgets: %i", (int) upd.mTriggeredWidgets.size()); - ImGui::Text("Widgets To Process: %i", upd.mDebugWidgetsToProcess); + ImGui::Text("Triggered: %i", (int) upd.mTriggeredWidgets.size()); + ImGui::SameLine(); ImGui::Text("Processing: %i", upd.mDebugWidgetsToProcess); - ImGui::Text("To Toggle processing press k"); - ImGui::Checkbox("Stop processing", &mDebugStopProcessing); - ImGui::Checkbox("Force new frames", &mDebugRedrawAlways); + ImGui::Checkbox("Stop processing", &mDebugStopProcessing); + ImGui::SameLine(); ImGui::Checkbox("Force new frames", &mDebugRedrawAlways); + ImGui::SameLine(); ImGui::Checkbox("Slow-mo", &mSlowMotion); - if (ImGui::CollapsingHeader("Triggered")) { - if (ImGui::BeginListBox("##triggered", { -FLT_MIN, 300 })) { - for (auto widget : upd.mTriggeredWidgets) { - widgetMenu(widget.first); + if (upd.mInFocusWidget) { + ImGui::Text("Under cursor"); + { + if (ImGui::BeginListBox("##under_cursor", LIST_SIZE)) { + for (auto widget = upd.mInFocusWidget; widget && widget->mParent; widget = widget->mParent) { + widgetMenu(widget); } ImGui::EndListBox(); } } + } - if (upd.mInFocusWidget) { - if (ImGui::CollapsingHeader("Under cursor")) { - if (ImGui::BeginListBox("##under_cursor", { -FLT_MIN, 300 })) { - for (auto widget = upd.mInFocusWidget; widget && widget->mParent; widget = widget->mParent) { - widgetMenu(widget); - } - ImGui::EndListBox(); - } + ImGui::Text("Triggered"); + { + if (ImGui::BeginListBox("##triggered", LIST_SIZE)) { + for (auto widget : upd.mTriggeredWidgets) { + widgetMenu(widget.first); } + ImGui::EndListBox(); } } + + drawLayoutOrder(); } void DebugManager::recursiveDraw(Canvas& canvas, Widget* active, const Vec2F& pos, int depthOrder) { auto area = RectF{ pos, active->getAreaT().size }; if (active->isUpdate()) { - RGBA color = { 1, 0, 0, 1}; + RGBA color = { 1, 0, 0, 1 }; canvas.frame(area, color); canvas.text((active->mDebug.id + ":" + std::to_string(depthOrder)).c_str(), area, 22, Canvas::Align::LC, 2, color); } @@ -71,7 +112,7 @@ void DebugManager::recursiveDraw(Canvas& canvas, Widget* active, const Vec2F& po canvas.circle(active->mDebug.pGlobal, 15, active->mDebug.col); } - RGBA color = { 1, 0, 0, 0.3f}; + RGBA color = { 1, 0, 0, 0.3f }; canvas.debugCross(area, color); } @@ -84,7 +125,8 @@ void DebugManager::recursiveDraw(Canvas& canvas, Widget* active, const Vec2F& po void DebugManager::widgetMenu(Widget* widget) { ImGui::PushID(widget); - if (ImGui::CollapsingHeader(widget->mDebug.id.c_str())) { + + if (ImGui::CollapsingHeader((widget->mDebug.id + std::to_string((long) widget)).c_str())) { ImGui::Text("trigger reason: %s", widget->mDebug.triggerReason.c_str()); @@ -93,24 +135,38 @@ void DebugManager::widgetMenu(Widget* widget) { widget->setArea(area); } - // ImGui::InputFloat2("min size", &widget->mMinSize.x); - // ImGui::InputFloat2("max size", &widget->mMaxSize.x); + auto layout = widget->getLayout(); - // int sizePolicyX = int(widget->mSizePolicy.x); - // int sizePolicyY = int(widget->mSizePolicy.y); - // int layout = int(widget->mLayoutPolicy); + ImGui::InputFloat2("min size", &layout->mMinSize.x); + ImGui::InputFloat2("max size", &layout->mMaxSize.x); - // if (ImGui::Combo("Size Policy X", &sizePolicyX, "Fixed\0Expanding\0Minimal\0")) { - // widget->setSizePolicy(SizePolicy(sizePolicyX), SizePolicy(sizePolicyY)); - // } + if (auto pBasicLayout = dynamic_cast(widget->getLayout())) { + int sizePolicyX = int(pBasicLayout->mSizePolicy.x); + int sizePolicyY = int(pBasicLayout->mSizePolicy.y); + int policy = int(pBasicLayout->mLayoutPolicy); - // if (ImGui::Combo("Size Policy Y", &sizePolicyY, "Fixed\0Expanding\0Minimal\0")) { - // widget->setSizePolicy(SizePolicy(sizePolicyX), SizePolicy(sizePolicyY)); - // } + if (ImGui::Combo("Size Policy X", &sizePolicyX, "Fixed\0Expanding\0Minimal\0")) { + widget->setSizePolicy(SizePolicy(sizePolicyX), SizePolicy(sizePolicyY)); + } - // if (ImGui::Combo("Layout", &layout, "Passive\0Vertical\0Horizontal\0")) { - // widget->setLayoutPolicy(LayoutPolicy(layout)); - // } + if (ImGui::Combo("Size Policy Y", &sizePolicyY, "Fixed\0Expanding\0Minimal\0")) { + widget->setSizePolicy(SizePolicy(sizePolicyX), SizePolicy(sizePolicyY)); + } + + if (ImGui::Combo("Layout", &policy, "Passive\0Vertical\0Horizontal\0")) { + pBasicLayout->mLayoutPolicy = LayoutPolicy(policy); + } + } } ImGui::PopID(); +} + +void DebugManager::drawLayoutOrder() { + ImGui::Text("Layout Processing Order"); + if (ImGui::BeginListBox("##layout_order", LIST_SIZE)) { + for (auto iter : mRootWidget->mLayoutManager.mLayOrder) { + ImGui::Text("%i %s (%s)", iter.second, iter.first->mDebug.id.c_str(), std::to_string((long) iter.first).c_str()); + } + ImGui::EndListBox(); + } } \ No newline at end of file diff --git a/WidgetsNew/private/managers/LayoutManager.cpp b/WidgetsNew/private/managers/LayoutManager.cpp index 92a78a8..3e30e80 100644 --- a/WidgetsNew/private/managers/LayoutManager.cpp +++ b/WidgetsNew/private/managers/LayoutManager.cpp @@ -1,17 +1,96 @@ #include "LayoutManager.hpp" +#include "DebugManager.hpp" -#include "Widget.hpp" +#include "DockLayout.hpp" + +#include using namespace tp; void LayoutManager::adjust(Widget* root) { - Widget::dfs( - root, - [](Widget* widget) { - widget->getLayout()->pickRect(); - }, - [](Widget* widget) { - widget->getLayout()->adjustChildrenRect(); + for (auto i : IterRange(2)) { + mVertical = bool(i); + + mDepGraph.clear(); + mLayOrder.clear(); + mRoots.clear(); + + findDependencies(root); + + // TODO : implement better topological-sort + for (auto iterRoot : mRoots) { + topologicalSort(iterRoot); } - ); -} \ No newline at end of file + + adjustLayouts(); + } +} + +void LayoutManager::findDependencies(Widget* root) { + mDepGraph.insert({ root, {} }); + + Widget::dfs(root, [this](Widget* widget) { mDepGraph.insert({ widget, {} }); }); + + for (auto& [widget, deps] : mDepGraph) { + for (auto child : widget->mChildren) { + mDepGraph.insert({ child, {} }); + + if (auto depOrder = getLayoutOrder(widget->getLayout(), child->getLayout())) { + if (depOrder > 0) { + deps.depends.push_back(child); + mDepGraph[child].references++; + } else { + mDepGraph[child].depends.push_back(widget); + mDepGraph[widget].references++; + } + } + } + } + + // find root + for (auto& node : mDepGraph) { + if (node.second.references == 0) { + mRoots.push_back(node.first); + } + } +} + +void LayoutManager::topologicalSort(Widget* root, int depth) { + mDepGraph.at(root).depth = max(mDepGraph.at(root).depth, depth); + + for (auto& dep : mDepGraph.at(root).depends) { + topologicalSort(dep, depth + 1); + } +} + +void LayoutManager::adjustLayouts() { + for (auto& iter : mDepGraph) { + mLayOrder.emplace_back(iter.first, iter.second.depth); + } + + std::sort(mLayOrder.begin(), mLayOrder.end(), [](auto first, auto second){ + return first.second > second.second; + }); + + for (auto& [iter, _] : mLayOrder) { + iter->getLayout()->updateLayout(mVertical); + } +} + +static int sizePolicyDep[3][3] = { + // f s e child + { 1, 1, 1 }, // parent fixed + { 1, 1, 1 }, // parent shrink + { 1, 1, 1 }, // parent expand +}; + +int LayoutManager::getLayoutOrder(WidgetLayout* parent, WidgetLayout* child) const { + if (!parent || !child) return 0; + + auto policyParent = parent->getSizePolicy()[mVertical]; + auto policyChild = parent->getSizePolicy()[mVertical]; + + if (dynamic_cast(parent)) return -1; + + return sizePolicyDep[int(policyParent)][int(policyChild)]; +} diff --git a/WidgetsNew/private/managers/UpdateManager.cpp b/WidgetsNew/private/managers/UpdateManager.cpp index c17e00a..b03bb76 100644 --- a/WidgetsNew/private/managers/UpdateManager.cpp +++ b/WidgetsNew/private/managers/UpdateManager.cpp @@ -1,4 +1,5 @@ #include "UpdateManager.hpp" +#include "DebugManager.hpp" using namespace tp; @@ -64,7 +65,7 @@ void UpdateManager::getWidgetPath(Widget* widget, std::vector& out) { } for (auto i = 0; i < out.size() / 2; i++) { - swap(out[i], out[out.size() - i - 1]); + swapV(out[i], out[out.size() - i - 1]); } } @@ -136,7 +137,7 @@ void UpdateManager::processActiveTree(Widget* iter, EventHandler& events, Vec2F iter->mDebug.pGlobal = current; events.setCursorOrigin(current); - iter->process(events); + procWidget(iter, events, false); } for (auto child : iter->mDepthOrder) { @@ -178,14 +179,16 @@ void UpdateManager::processFocusItems(EventHandler& events) { widget->mDebug.pGlobal = widgetGlobalPos[iter]; if (!eventsProcessed && widget->processesEvents()) { - events.setEnableKeyEvents(true); - widget->process(events); - - events.setEnableKeyEvents(false); + procWidget(widget, events, true); eventsProcessed = true; } else { - widget->process(events); + procWidget(widget, events, false); } } } +void UpdateManager::procWidget(Widget* widget, EventHandler& events, bool withEvents) { + events.setEnableKeyEvents(withEvents); + gDebugWidget.checkProcBreakPoints(widget); + widget->process(events); +} \ No newline at end of file diff --git a/WidgetsNew/public/Layout.hpp b/WidgetsNew/public/Layout.hpp index 7508523..10c8965 100644 --- a/WidgetsNew/public/Layout.hpp +++ b/WidgetsNew/public/Layout.hpp @@ -19,13 +19,16 @@ namespace tp { }; class WidgetLayout { + friend class DebugManager; + public: explicit WidgetLayout(Widget* widget) { mWidget = widget; } virtual ~WidgetLayout() = default; - virtual void pickRect() = 0; + virtual void updateLayout(bool vertical) {} + + virtual void pickRect(bool vertical) = 0; virtual void clampRect() = 0; - virtual void adjustChildrenRect() = 0; [[nodiscard]] virtual RectF getAvailableChildArea() const; public: diff --git a/WidgetsNew/public/RootWidget.hpp b/WidgetsNew/public/RootWidget.hpp index 94f577e..c2375f4 100644 --- a/WidgetsNew/public/RootWidget.hpp +++ b/WidgetsNew/public/RootWidget.hpp @@ -37,6 +37,5 @@ namespace tp { LayoutManager mLayoutManager; UpdateManager mUpdateManager; - DebugManager mDebugManager; }; } \ No newline at end of file diff --git a/WidgetsNew/public/layouts/BasicLayout.hpp b/WidgetsNew/public/layouts/BasicLayout.hpp index 8f96f61..185e154 100644 --- a/WidgetsNew/public/layouts/BasicLayout.hpp +++ b/WidgetsNew/public/layouts/BasicLayout.hpp @@ -5,14 +5,19 @@ namespace tp { class BasicLayout : public WidgetLayout { + friend class DebugManager; + public: explicit BasicLayout(Widget* widget) : WidgetLayout(widget) {} - void pickRect() override; + void updateLayout(bool vertical) override; + + void pickRect(bool vertical) override; void clampRect() override; - void adjustChildrenRect() override; [[nodiscard]] RectF getAvailableChildArea() const override; + void setLayoutPolicy(LayoutPolicy layout) { mLayoutPolicy = layout; } + private: void adjustLayout(bool vertical); static halnf changeChildSize(Widget*, halnf diff, bool vertical); @@ -20,6 +25,6 @@ namespace tp { private: LayoutPolicy mLayoutPolicy = LayoutPolicy::Vertical; halnf mLayoutGap = 5; - halnf mLayoutMargin = 10; + halnf mLayoutMargin = 9; }; } \ No newline at end of file diff --git a/WidgetsNew/public/layouts/DockLayout.hpp b/WidgetsNew/public/layouts/DockLayout.hpp index 35ee113..5853cbe 100644 --- a/WidgetsNew/public/layouts/DockLayout.hpp +++ b/WidgetsNew/public/layouts/DockLayout.hpp @@ -42,9 +42,10 @@ namespace tp { void updatePreviewSide(const Vec2F& pointer); public: - void pickRect() override {} - void adjustChildrenRect() override; + void pickRect(bool vertical) override {} void clampRect() override {}; + void updateLayout(bool vertical) override; + void adjustChildrenRect(); public: bool setCenterWidget(Widget* widget); diff --git a/WidgetsNew/public/layouts/FloatingLayout.hpp b/WidgetsNew/public/layouts/FloatingLayout.hpp index 5501dcf..c1418fe 100644 --- a/WidgetsNew/public/layouts/FloatingLayout.hpp +++ b/WidgetsNew/public/layouts/FloatingLayout.hpp @@ -18,7 +18,7 @@ namespace tp { RectF resizeHandleRect(); public: - void pickRect() override; + void pickRect(bool vertical) override; private: bool mIsFloating = false; diff --git a/WidgetsNew/public/mangers/DebugManager.hpp b/WidgetsNew/public/mangers/DebugManager.hpp index 7f6219f..e169261 100644 --- a/WidgetsNew/public/mangers/DebugManager.hpp +++ b/WidgetsNew/public/mangers/DebugManager.hpp @@ -2,6 +2,8 @@ #include "Widget.hpp" +#include + namespace tp { class DebugManager { public: @@ -11,15 +13,38 @@ namespace tp { bool update(RootWidget* rootWidget, EventHandler& events); void drawDebug(RootWidget* rootWidget, Canvas& canvas); + void checkProcBreakPoints(Widget* widget) { + if (mProcBreakpoints.find(widget) != mProcBreakpoints.end()) { + mProcBreakpoints.erase(widget); + DEBUG_BREAK(1) + } + } + + void checkLayoutBreakpoints(Widget* widget) { + if (mLayBreakpoints.find(widget) != mLayBreakpoints.end()) { + mLayBreakpoints.erase(widget); + DEBUG_BREAK(1) + } + } + private: void recursiveDraw(Canvas& canvas, Widget* active, const Vec2F& pos, int depthOrder); static void widgetMenu(Widget*); + void drawLayoutOrder(); private: + RootWidget* mRootWidget = nullptr; + // debug bool mDebug = true; bool mDebugStopProcessing = false; bool mDebugRedrawAlways = false; + bool mSlowMotion = false; + + std::set mProcBreakpoints; + std::set mLayBreakpoints; }; + + extern DebugManager gDebugWidget; } \ No newline at end of file diff --git a/WidgetsNew/public/mangers/LayoutManager.hpp b/WidgetsNew/public/mangers/LayoutManager.hpp index c160789..7b2eaef 100644 --- a/WidgetsNew/public/mangers/LayoutManager.hpp +++ b/WidgetsNew/public/mangers/LayoutManager.hpp @@ -1,11 +1,39 @@ #pragma once #include "Layout.hpp" +#include "DebugManager.hpp" + +#include +#include namespace tp { class LayoutManager { + friend DebugManager; + + struct DepNode { + std::vector depends; + int references = 0; + int depth = 0; + }; + public: LayoutManager() = default; + void adjust(Widget* root); + + private: + void findDependencies(Widget* root); + void topologicalSort(Widget* root, int depth = 0); + void adjustLayouts(); + + private: + int getLayoutOrder(WidgetLayout* parent, WidgetLayout* child) const; + + private: + std::map mDepGraph; + std::vector mRoots; + + std::vector> mLayOrder; + bool mVertical = false; }; } \ No newline at end of file diff --git a/WidgetsNew/public/mangers/UpdateManager.hpp b/WidgetsNew/public/mangers/UpdateManager.hpp index f23564f..5a52038 100644 --- a/WidgetsNew/public/mangers/UpdateManager.hpp +++ b/WidgetsNew/public/mangers/UpdateManager.hpp @@ -28,6 +28,9 @@ namespace tp { void processActiveTree(Widget* iter, EventHandler& events, Vec2F pos); void processFocusItems(EventHandler& events); + private: + static void procWidget(Widget* widget, EventHandler& events, bool withEvents = false); + private: std::map mTriggeredWidgets; Widget* mInFocusWidget = nullptr; diff --git a/WidgetsNew/public/widgets/DockWidget.hpp b/WidgetsNew/public/widgets/DockWidget.hpp index baa4fb8..969f0fe 100644 --- a/WidgetsNew/public/widgets/DockWidget.hpp +++ b/WidgetsNew/public/widgets/DockWidget.hpp @@ -12,6 +12,7 @@ namespace tp { [[nodiscard]] bool propagateEventsToChildren() const override; [[nodiscard]] bool needsNextFrame() const override; + [[nodiscard]]bool processesEvents() const override { return true; } void drawSide(DockLayout::Side side, Canvas& canvas);