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

@ -418,7 +418,7 @@ namespace tp {
void reverse() { void reverse() {
for (ualni idx = 0; idx < mLoad / 2; idx++) { for (ualni idx = 0; idx < mLoad / 2; idx++) {
swap(mBuff[idx], mBuff[mLoad - idx - 1]); swapV(mBuff[idx], mBuff[mLoad - idx - 1]);
} }
} }

View file

@ -63,7 +63,7 @@ namespace tp {
for (Index i = 0; i < mSize.x; i++) { for (Index i = 0; i < mSize.x; i++) {
const auto lenIdx = mSize.y - 1; const auto lenIdx = mSize.y - 1;
for (Index j = 0; j < mSize.y / 2; j++) { 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++) { for (Index i = 0; i < mSize.y; i++) {
const auto lenIdx = mSize.x - 1; const auto lenIdx = mSize.x - 1;
for (Index j = 0; j < mSize.x / 2; j++) { 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 }));
} }
} }
} }

View file

@ -288,9 +288,9 @@ namespace tp {
while (iter) { while (iter) {
tmp = iter; tmp = iter;
iter = iter->next; iter = iter->next;
swap(tmp->next, tmp->prev); swapV(tmp->next, tmp->prev);
} }
swap(mFirst, mLast); swapV(mFirst, mLast);
} }
void detachAll() { void detachAll() {

View file

@ -21,7 +21,7 @@ struct Interval {
start = ((halnf) randomFloat()) * (span) - offset; start = ((halnf) randomFloat()) * (span) - offset;
end = ((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 len = (end - start) * scale * 0.5f;
auto mid = (start + end) / 2.f; auto mid = (start + end) / 2.f;

View file

@ -28,8 +28,8 @@ namespace tp {
protected: protected:
bool mInitialized = false; bool mInitialized = false;
ualni mDrawPerSecond = 60; ualni mDrawPerSecond = 1160;
ualni mProcPerSecond = 100; ualni mProcPerSecond = 1300;
Timer mDrawTimer; Timer mDrawTimer;
Timer mProcTimer; Timer mProcTimer;

View file

@ -221,7 +221,7 @@ namespace tp {
static_assert(tNRows == tNColoumns); static_assert(tNRows == tNColoumns);
for (halni i = 0; i < tNColoumns; i++) { for (halni i = 0; i < tNColoumns; i++) {
for (halni j = i + 1; j < tNColoumns; j++) { for (halni j = i + 1; j < tNColoumns; j++) {
swap((*this)[i][j], (*this)[j][i]); swapV((*this)[i][j], (*this)[j][i]);
} }
} }
return *this; return *this;
@ -479,7 +479,7 @@ namespace tp {
Mat operator*(const Mat& in) { return transform(in); } Mat operator*(const Mat& in) { return transform(in); }
Mat& transpose() { Mat& transpose() {
swap(j.x, i.y); swapV(j.x, i.y);
return *this; return *this;
} }
@ -635,9 +635,9 @@ namespace tp {
} }
Mat& transpose() { Mat& transpose() {
swap(I.y, J.x); swapV(I.y, J.x);
swap(I.z, K.x); swapV(I.z, K.x);
swap(J.z, K.y); swapV(J.z, K.y);
return *this; return *this;
} }

View file

@ -33,9 +33,12 @@ namespace tp {
__builtin_debugtrap(); \ __builtin_debugtrap(); \
} }
#elif defined(ENV_OS_LINUX) #elif defined(ENV_OS_LINUX)
#include <csignal>
#define DEBUG_BREAK(expr) \ #define DEBUG_BREAK(expr) \
if (expr) { \ if (expr) { \
__builtin_trap(); \ raise(SIGTRAP); \
} }
#else #else
#define DEBUG_BREAK(expr) () #define DEBUG_BREAK(expr) ()

View file

@ -85,7 +85,7 @@ namespace tp {
} }
template <typename T> template <typename T>
inline void swap(T& t1, T& t2) { inline void swapV(T& t1, T& t2) {
const T tmp = t1; const T tmp = t1;
t1 = t2; t1 = t2;
t2 = tmp; t2 = tmp;

View file

@ -697,13 +697,13 @@ obj::ObjectsGUI::ViewStackNode obj::ObjectsGUI::listView(obj::ListObject* obj) {
} }
if (childo.node()->prev && ImGui::Selectable("Move Up")) { 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(); ImGui::EndPopup();
break; break;
} }
if (childo.node()->next && ImGui::Selectable("Move Down")) { 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(); ImGui::EndPopup();
break; break;
} }

28
TODO
View file

@ -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: ALL:
Gradually introduce STL into the project (replace own classes or add seamless interface and conversions into STL)
Remove BaseModule and Connection modules Remove BaseModule and Connection modules
remove archiver and add boost serialization remove archiver and add boost serialization ??
Bring windows old window to graphics Bring ms-windows old window to graphics
Check Warnings Check Warnings
Make all modules stable with tests Make all modules stable with tests
Modules: Modules:
Remove all static variable into module's data Remove all static variable into module's data
@ -92,7 +109,6 @@ Math:
RayTracer: RayTracer:
Features: Features:
iodn
Normals flag Normals flag
Material, Normals, per trig info Material, Normals, per trig info

View file

@ -36,7 +36,7 @@ void DockWidget::removeSideWidget(Side side) {
removed = true; removed = true;
} }
if (removed) { if (removed) {
swap(mSideWidgets[i].order, mSideWidgets[i + 1].order); swapV(mSideWidgets[i].order, mSideWidgets[i + 1].order);
} }
} }
mSideWidgets[3].order = -1; mSideWidgets[3].order = -1;

View file

@ -24,6 +24,34 @@ public:
setup1(); 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() { void setup1() {
mRootWidget.setRootWidget(&mDockLayout); mRootWidget.setRootWidget(&mDockLayout);
@ -122,6 +150,9 @@ public:
} }
private: private:
Widget mWidgets[15];
ButtonWidget mButtons[15];
Widget mWidget; Widget mWidget;
ButtonWidget mButton; ButtonWidget mButton;

View file

@ -23,7 +23,7 @@ void RootWidget::setRootWidget(Widget* widget) {
void RootWidget::processFrame(EventHandler* events, const RectF& screenArea) { void RootWidget::processFrame(EventHandler* events, const RectF& screenArea) {
mRoot->setArea(screenArea); mRoot->setArea(screenArea);
if (!mDebugManager.update(this, *events)) return; if (!gDebugWidget.update(this, *events)) return;
// construct hierarchy tree of widgets to process // construct hierarchy tree of widgets to process
mUpdateManager.updateTreeToProcess(mRoot); mUpdateManager.updateTreeToProcess(mRoot);
@ -49,7 +49,7 @@ void RootWidget::processFrame(EventHandler* events, const RectF& screenArea) {
} }
bool RootWidget::needsUpdate() const { bool RootWidget::needsUpdate() const {
if (mDebugManager.isRedrawAlways()) return true; if (gDebugWidget.isRedrawAlways()) return true;
return mUpdateManager.isPendingUpdates(); return mUpdateManager.isPendingUpdates();
} }
@ -58,7 +58,7 @@ void RootWidget::drawFrame(Canvas& canvas) {
drawRecursion(canvas, mRoot, { 0, 0 }); drawRecursion(canvas, mRoot, { 0, 0 });
mDebugManager.drawDebug(this, canvas); gDebugWidget.drawDebug(this, canvas);
} }

View file

@ -7,20 +7,26 @@
using namespace tp; using namespace tp;
void BasicLayout::pickRect() { void BasicLayout::pickRect(bool vertical) {
auto current = getArea(); auto current = getArea();
auto children = getChildrenEnclosure(); auto children = getChildrenEnclosure();
auto parent = getParentEnclosure(); auto parent = getParentEnclosure();
RectF newArea = current;
auto rangeX = pickRange(current.getRangeX(), children.getRangeX(), parent.getRangeX(), false); if (vertical) {
auto rangeY = pickRange(current.getRangeY(), children.getRangeY(), parent.getRangeY(), true); auto rangeY = pickRange(current.getRangeY(), children.getRangeY(), parent.getRangeY(), true);
newArea = RectF(current.getRangeX(), rangeY);
auto newArea = RectF(rangeX, rangeY); } else {
auto rangeX = pickRange(current.getRangeX(), children.getRangeX(), parent.getRangeX(), false);
newArea = RectF(rangeX, current.getRangeY());
}
setArea(newArea); setArea(newArea);
} }
void BasicLayout::clampRect() { void BasicLayout::clampRect() {
DEBUG_ASSERT(0)
auto current = getArea(); auto current = getArea();
auto children = getChildrenEnclosure(); auto children = getChildrenEnclosure();
auto parent = getParentEnclosure(); auto parent = getParentEnclosure();
@ -31,13 +37,21 @@ void BasicLayout::clampRect() {
setArea(RectF(rangeX, rangeY)); setArea(RectF(rangeX, rangeY));
} }
void BasicLayout::adjustChildrenRect() { void BasicLayout::updateLayout(bool vertical) {
if (children().empty()) return; if (children().empty()) return;
if (vertical) {
switch (mLayoutPolicy) { switch (mLayoutPolicy) {
case LayoutPolicy::Passive: break;
case LayoutPolicy::Vertical: adjustLayout(true); break; case LayoutPolicy::Vertical: adjustLayout(true); break;
case LayoutPolicy::Passive:
case LayoutPolicy::Horizontal: break;
}
} else {
switch (mLayoutPolicy) {
case LayoutPolicy::Horizontal: adjustLayout(false); break; 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; Vec2F availableSize = getArea().size;
for (auto child : children()) { for (auto child : children()) {
if (child->getLayout()->getSizePolicy()[!vertical] != SizePolicy::Minimal) { child->getLayout()->pickRect(vertical);
child->getLayout()->pickRect();
}
if (child->getLayout()->getSizePolicy()[vertical] == SizePolicy::Expanding) { if (child->getLayout()->getSizePolicy()[vertical] == SizePolicy::Expanding) {
contributors.emplace_back( child, true ); contributors.emplace_back( child, true );
@ -71,7 +83,7 @@ void BasicLayout::adjustLayout(bool vertical) {
auto area = child->getLayout()->getArea(); auto area = child->getLayout()->getArea();
area.size[vertical] = 0; area.size[vertical] = 0;
child->setAreaCache(area); child->setAreaCache(area);
child->getLayout()->clampRect(); child->getLayout()->clampMinMaxSize();
} }
contentSize += child->getLayout()->getArea().size; 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; halnf iterPos = mLayoutMargin;
for (auto child : children()) { for (auto child : children()) {
auto area = child->getLayout()->getArea(); auto area = child->getLayout()->getArea();
area.pos[vertical] = iterPos; area.pos[vertical] = iterPos;
area.pos[!vertical] = mLayoutMargin;
iterPos += area.size[vertical] + mLayoutGap; iterPos += area.size[vertical] + mLayoutGap;
child->setAreaCache(area); child->setAreaCache(area);
// child->updateAnimations(); // child->updateAnimations();
// child->triggerWidgetUpdate("layout changed"); // child->triggerWidgetUpdate("layout changed");
} }

View file

@ -44,7 +44,7 @@ bool DockLayout::undockWidget(Side side) {
removed = true; removed = true;
} }
if (removed) { if (removed) {
swap(mSideWidgets[i].order, mSideWidgets[i + 1].order); swapV(mSideWidgets[i].order, mSideWidgets[i + 1].order);
} }
} }
mSideWidgets[3].order = -1; mSideWidgets[3].order = -1;
@ -184,6 +184,15 @@ auto DockLayout::getSideFromWidget(Widget* widget) -> Side {
return DockLayout::NONE; return DockLayout::NONE;
} }
void DockLayout::updateLayout(bool vertical) {
for (auto child : children()) {
child->getLayout()->pickRect(vertical);
}
if (vertical) return;
adjustChildrenRect();
}
void DockLayout::adjustChildrenRect() { void DockLayout::adjustChildrenRect() {
calculateSideAreas(); calculateSideAreas();
calculateResizeHandles(); calculateResizeHandles();

View file

@ -3,21 +3,21 @@
using namespace tp; using namespace tp;
void FloatingLayout::pickRect() { void FloatingLayout::pickRect(bool vertical) {
if (mIsFloating) { if (mIsFloating) {
auto area = getArea(); auto area = getArea();
if (mIsResizing) { if (mIsResizing) {
mPointerCurrent.clamp(mMinSize, mMaxSize); mPointerCurrent.clamp(mMinSize, mMaxSize);
area.size = mPointerCurrent + mHandleSize / 2.f; area.size[vertical] = (mPointerCurrent + mHandleSize / 2.f)[vertical];
for (auto child : children()) { for (auto child : children()) {
child->triggerWidgetUpdate("floating menu resized"); child->triggerWidgetUpdate("floating menu resized");
} }
} else if (mIsFloating) { } else if (mIsFloating) {
area.pos += mPointerCurrent - mPointerStart; area.pos[vertical] += (mPointerCurrent - mPointerStart)[vertical];
} }
setArea(area); setArea(area);

View file

@ -1,11 +1,19 @@
#include "DebugManager.hpp" #include "DebugManager.hpp"
#include "RootWidget.hpp" #include "RootWidget.hpp"
#include "BasicLayout.hpp"
#include "imgui.h" #include "imgui.h"
#include <sstream>
using namespace tp; using namespace tp;
DebugManager tp::gDebugWidget;
#define LIST_SIZE { -FLT_MIN, 150 }
bool DebugManager::update(RootWidget* rootWidget, EventHandler& events) { bool DebugManager::update(RootWidget* rootWidget, EventHandler& events) {
mRootWidget = rootWidget;
if (mDebug) { if (mDebug) {
auto area = rootWidget->mRoot->getAreaT(); auto area = rootWidget->mRoot->getAreaT();
area.size -= { 400, 0 }; area.size -= { 400, 0 };
@ -14,38 +22,60 @@ bool DebugManager::update(RootWidget* rootWidget, EventHandler& events) {
events.setEnableKeyEvents(true); events.setEnableKeyEvents(true);
if (events.isPressed(InputID::K)) mDebugStopProcessing = !mDebugStopProcessing; if (events.isPressed(InputID::K)) mDebugStopProcessing = !mDebugStopProcessing;
if (mDebugStopProcessing) return false; 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; return true;
} }
void DebugManager::drawDebug(RootWidget* rootWidget, Canvas& canvas) { void DebugManager::drawDebug(RootWidget* rootWidget, Canvas& canvas) {
mRootWidget = rootWidget;
ImGui::Checkbox("Draw debug", &mDebug); ImGui::Checkbox("Draw debug", &mDebug);
if (!mDebug) {
return;
}
ImGui::SameLine(); ImGui::Text("To Toggle processing press k");
auto& upd = rootWidget->mUpdateManager; 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("Triggered: %i", (int) upd.mTriggeredWidgets.size());
ImGui::Text("Widgets To Process: %i", upd.mDebugWidgetsToProcess); ImGui::SameLine(); ImGui::Text("Processing: %i", upd.mDebugWidgetsToProcess);
ImGui::Text("To Toggle processing press k");
ImGui::Checkbox("Stop processing", &mDebugStopProcessing); ImGui::Checkbox("Stop processing", &mDebugStopProcessing);
ImGui::Checkbox("Force new frames", &mDebugRedrawAlways); 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);
}
ImGui::EndListBox();
}
}
if (upd.mInFocusWidget) { if (upd.mInFocusWidget) {
if (ImGui::CollapsingHeader("Under cursor")) { ImGui::Text("Under cursor");
if (ImGui::BeginListBox("##under_cursor", { -FLT_MIN, 300 })) { {
if (ImGui::BeginListBox("##under_cursor", LIST_SIZE)) {
for (auto widget = upd.mInFocusWidget; widget && widget->mParent; widget = widget->mParent) { for (auto widget = upd.mInFocusWidget; widget && widget->mParent; widget = widget->mParent) {
widgetMenu(widget); widgetMenu(widget);
} }
@ -53,7 +83,18 @@ void DebugManager::drawDebug(RootWidget* rootWidget, Canvas& canvas) {
} }
} }
} }
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) { void DebugManager::recursiveDraw(Canvas& canvas, Widget* active, const Vec2F& pos, int depthOrder) {
@ -84,7 +125,8 @@ void DebugManager::recursiveDraw(Canvas& canvas, Widget* active, const Vec2F& po
void DebugManager::widgetMenu(Widget* widget) { void DebugManager::widgetMenu(Widget* widget) {
ImGui::PushID(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()); ImGui::Text("trigger reason: %s", widget->mDebug.triggerReason.c_str());
@ -93,24 +135,38 @@ void DebugManager::widgetMenu(Widget* widget) {
widget->setArea(area); widget->setArea(area);
} }
// ImGui::InputFloat2("min size", &widget->mMinSize.x); auto layout = widget->getLayout();
// ImGui::InputFloat2("max size", &widget->mMaxSize.x);
// int sizePolicyX = int(widget->mSizePolicy.x); ImGui::InputFloat2("min size", &layout->mMinSize.x);
// int sizePolicyY = int(widget->mSizePolicy.y); ImGui::InputFloat2("max size", &layout->mMaxSize.x);
// int layout = int(widget->mLayoutPolicy);
// if (ImGui::Combo("Size Policy X", &sizePolicyX, "Fixed\0Expanding\0Minimal\0")) { if (auto pBasicLayout = dynamic_cast<BasicLayout*>(widget->getLayout())) {
// widget->setSizePolicy(SizePolicy(sizePolicyX), SizePolicy(sizePolicyY)); 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")) { if (ImGui::Combo("Size Policy X", &sizePolicyX, "Fixed\0Expanding\0Minimal\0")) {
// widget->setSizePolicy(SizePolicy(sizePolicyX), SizePolicy(sizePolicyY)); widget->setSizePolicy(SizePolicy(sizePolicyX), SizePolicy(sizePolicyY));
// } }
// if (ImGui::Combo("Layout", &layout, "Passive\0Vertical\0Horizontal\0")) { if (ImGui::Combo("Size Policy Y", &sizePolicyY, "Fixed\0Expanding\0Minimal\0")) {
// widget->setLayoutPolicy(LayoutPolicy(layout)); widget->setSizePolicy(SizePolicy(sizePolicyX), SizePolicy(sizePolicyY));
// } }
if (ImGui::Combo("Layout", &policy, "Passive\0Vertical\0Horizontal\0")) {
pBasicLayout->mLayoutPolicy = LayoutPolicy(policy);
}
}
} }
ImGui::PopID(); 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 "LayoutManager.hpp"
#include "DebugManager.hpp"
#include "Widget.hpp" #include "DockLayout.hpp"
#include <algorithm>
using namespace tp; using namespace tp;
void LayoutManager::adjust(Widget* root) { void LayoutManager::adjust(Widget* root) {
Widget::dfs( for (auto i : IterRange(2)) {
root, mVertical = bool(i);
[](Widget* widget) {
widget->getLayout()->pickRect(); mDepGraph.clear();
}, mLayOrder.clear();
[](Widget* widget) { mRoots.clear();
widget->getLayout()->adjustChildrenRect();
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 "UpdateManager.hpp"
#include "DebugManager.hpp"
using namespace tp; 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++) { 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; iter->mDebug.pGlobal = current;
events.setCursorOrigin(current); events.setCursorOrigin(current);
iter->process(events); procWidget(iter, events, false);
} }
for (auto child : iter->mDepthOrder) { for (auto child : iter->mDepthOrder) {
@ -178,14 +179,16 @@ void UpdateManager::processFocusItems(EventHandler& events) {
widget->mDebug.pGlobal = widgetGlobalPos[iter]; widget->mDebug.pGlobal = widgetGlobalPos[iter];
if (!eventsProcessed && widget->processesEvents()) { if (!eventsProcessed && widget->processesEvents()) {
events.setEnableKeyEvents(true); procWidget(widget, events, true);
widget->process(events);
events.setEnableKeyEvents(false);
eventsProcessed = true; eventsProcessed = true;
} else { } 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 { class WidgetLayout {
friend class DebugManager;
public: public:
explicit WidgetLayout(Widget* widget) { mWidget = widget; } explicit WidgetLayout(Widget* widget) { mWidget = widget; }
virtual ~WidgetLayout() = default; virtual ~WidgetLayout() = default;
virtual void pickRect() = 0; virtual void updateLayout(bool vertical) {}
virtual void pickRect(bool vertical) = 0;
virtual void clampRect() = 0; virtual void clampRect() = 0;
virtual void adjustChildrenRect() = 0;
[[nodiscard]] virtual RectF getAvailableChildArea() const; [[nodiscard]] virtual RectF getAvailableChildArea() const;
public: public:

View file

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

View file

@ -5,14 +5,19 @@
namespace tp { namespace tp {
class BasicLayout : public WidgetLayout { class BasicLayout : public WidgetLayout {
friend class DebugManager;
public: public:
explicit BasicLayout(Widget* widget) : WidgetLayout(widget) {} explicit BasicLayout(Widget* widget) : WidgetLayout(widget) {}
void pickRect() override; void updateLayout(bool vertical) override;
void pickRect(bool vertical) override;
void clampRect() override; void clampRect() override;
void adjustChildrenRect() override;
[[nodiscard]] RectF getAvailableChildArea() const override; [[nodiscard]] RectF getAvailableChildArea() const override;
void setLayoutPolicy(LayoutPolicy layout) { mLayoutPolicy = layout; }
private: private:
void adjustLayout(bool vertical); void adjustLayout(bool vertical);
static halnf changeChildSize(Widget*, halnf diff, bool vertical); static halnf changeChildSize(Widget*, halnf diff, bool vertical);
@ -20,6 +25,6 @@ namespace tp {
private: private:
LayoutPolicy mLayoutPolicy = LayoutPolicy::Vertical; LayoutPolicy mLayoutPolicy = LayoutPolicy::Vertical;
halnf mLayoutGap = 5; halnf mLayoutGap = 5;
halnf mLayoutMargin = 10; halnf mLayoutMargin = 9;
}; };
} }

View file

@ -42,9 +42,10 @@ namespace tp {
void updatePreviewSide(const Vec2F& pointer); void updatePreviewSide(const Vec2F& pointer);
public: public:
void pickRect() override {} void pickRect(bool vertical) override {}
void adjustChildrenRect() override;
void clampRect() override {}; void clampRect() override {};
void updateLayout(bool vertical) override;
void adjustChildrenRect();
public: public:
bool setCenterWidget(Widget* widget); bool setCenterWidget(Widget* widget);

View file

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

View file

@ -2,6 +2,8 @@
#include "Widget.hpp" #include "Widget.hpp"
#include <set>
namespace tp { namespace tp {
class DebugManager { class DebugManager {
public: public:
@ -11,15 +13,38 @@ namespace tp {
bool update(RootWidget* rootWidget, EventHandler& events); bool update(RootWidget* rootWidget, EventHandler& events);
void drawDebug(RootWidget* rootWidget, Canvas& canvas); 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: private:
void recursiveDraw(Canvas& canvas, Widget* active, const Vec2F& pos, int depthOrder); void recursiveDraw(Canvas& canvas, Widget* active, const Vec2F& pos, int depthOrder);
static void widgetMenu(Widget*); static void widgetMenu(Widget*);
void drawLayoutOrder();
private: private:
RootWidget* mRootWidget = nullptr;
// debug // debug
bool mDebug = true; bool mDebug = true;
bool mDebugStopProcessing = false; bool mDebugStopProcessing = false;
bool mDebugRedrawAlways = 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 #pragma once
#include "Layout.hpp" #include "Layout.hpp"
#include "DebugManager.hpp"
#include <map>
#include <vector>
namespace tp { namespace tp {
class LayoutManager { class LayoutManager {
friend DebugManager;
struct DepNode {
std::vector<Widget*> depends;
int references = 0;
int depth = 0;
};
public: public:
LayoutManager() = default; LayoutManager() = default;
void adjust(Widget* root); 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 processActiveTree(Widget* iter, EventHandler& events, Vec2F pos);
void processFocusItems(EventHandler& events); void processFocusItems(EventHandler& events);
private:
static void procWidget(Widget* widget, EventHandler& events, bool withEvents = false);
private: private:
std::map<Widget*, bool> mTriggeredWidgets; std::map<Widget*, bool> mTriggeredWidgets;
Widget* mInFocusWidget = nullptr; Widget* mInFocusWidget = nullptr;

View file

@ -12,6 +12,7 @@ namespace tp {
[[nodiscard]] bool propagateEventsToChildren() const override; [[nodiscard]] bool propagateEventsToChildren() const override;
[[nodiscard]] bool needsNextFrame() const override; [[nodiscard]] bool needsNextFrame() const override;
[[nodiscard]]bool processesEvents() const override { return true; }
void drawSide(DockLayout::Side side, Canvas& canvas); void drawSide(DockLayout::Side side, Canvas& canvas);