Refactor Layout Manager

This commit is contained in:
IlyaShurupov 2024-10-14 21:31:05 +03:00 committed by Ilya Shurupov
parent e00dec67ba
commit 96b293d1b5
28 changed files with 408 additions and 123 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

54
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:
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
@ -67,21 +84,21 @@ Language:
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

View file

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

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