Refactor Layout Manager

This commit is contained in:
IlyaShurupov 2024-10-14 21:31:05 +03:00
parent 7cf3328a40
commit 54dcbcb46b
28 changed files with 408 additions and 123 deletions

View file

@ -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;

View file

@ -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);
}

View file

@ -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");
}

View file

@ -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();

View file

@ -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);

View file

@ -1,11 +1,19 @@
#include "DebugManager.hpp"
#include "RootWidget.hpp"
#include "BasicLayout.hpp"
#include "imgui.h"
#include <sstream>
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<BasicLayout*>(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<BasicLayout*>(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();
}
}

View file

@ -1,17 +1,96 @@
#include "LayoutManager.hpp"
#include "DebugManager.hpp"
#include "Widget.hpp"
#include "DockLayout.hpp"
#include <algorithm>
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);
}
);
}
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<DockLayout*>(parent)) return -1;
return sizePolicyDep[int(policyParent)][int(policyChild)];
}

View file

@ -1,4 +1,5 @@
#include "UpdateManager.hpp"
#include "DebugManager.hpp"
using namespace tp;
@ -64,7 +65,7 @@ void UpdateManager::getWidgetPath(Widget* widget, std::vector<Widget*>& 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);
}

View file

@ -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:

View file

@ -37,6 +37,5 @@ namespace tp {
LayoutManager mLayoutManager;
UpdateManager mUpdateManager;
DebugManager mDebugManager;
};
}

View file

@ -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;
};
}

View file

@ -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);

View file

@ -18,7 +18,7 @@ namespace tp {
RectF resizeHandleRect();
public:
void pickRect() override;
void pickRect(bool vertical) override;
private:
bool mIsFloating = false;

View file

@ -2,6 +2,8 @@
#include "Widget.hpp"
#include <set>
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<Widget*> mProcBreakpoints;
std::set<Widget*> mLayBreakpoints;
};
extern DebugManager gDebugWidget;
}

View file

@ -1,11 +1,39 @@
#pragma once
#include "Layout.hpp"
#include "DebugManager.hpp"
#include <map>
#include <vector>
namespace tp {
class LayoutManager {
friend DebugManager;
struct DepNode {
std::vector<Widget*> 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<Widget*, DepNode> mDepGraph;
std::vector<Widget*> mRoots;
std::vector<std::pair<Widget*, int>> mLayOrder;
bool mVertical = false;
};
}

View file

@ -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<Widget*, bool> mTriggeredWidgets;
Widget* mInFocusWidget = nullptr;

View file

@ -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);