diff --git a/3DEditor/public/EditorWidget.hpp b/3DEditor/public/EditorWidget.hpp index 2c22d51..95e3ad8 100644 --- a/3DEditor/public/EditorWidget.hpp +++ b/3DEditor/public/EditorWidget.hpp @@ -36,8 +36,8 @@ namespace tp { mViewport(canvas, editor) { mEditor = editor; - mDockSpace.addSideWidget(&mNavigationMenu, DockLayoutWidget::RIGHT); - mDockSpace.addSideWidget(&mRenderMenu, DockLayoutWidget::LEFT); + mDockSpace.addSideWidget(&mNavigationMenu, DockWidget::RIGHT); + mDockSpace.addSideWidget(&mRenderMenu, DockWidget::LEFT); mDockSpace.setCenterWidget(&mViewport); // Render diff --git a/LibraryViewer/public/GUI.hpp b/LibraryViewer/public/GUI.hpp index a6362aa..e99079e 100644 --- a/LibraryViewer/public/GUI.hpp +++ b/LibraryViewer/public/GUI.hpp @@ -195,7 +195,7 @@ namespace tp { mCurrentTrackInfo.mPlayer = mPlayer; mDockSpace.setCenterWidget(&mSongList); - mDockSpace.addSideWidget(&mCurrentTrackInfo, DockLayoutWidget::RIGHT); + mDockSpace.addSideWidget(&mCurrentTrackInfo, DockWidget::RIGHT); // this->mChildWidgets.pushBack(&mCurrentTrackInfo); // this->mChildWidgets.pushBack(&mCurrentTrack); diff --git a/Math/public/Rect.hpp b/Math/public/Rect.hpp index f200dda..3331b61 100644 --- a/Math/public/Rect.hpp +++ b/Math/public/Rect.hpp @@ -97,6 +97,10 @@ namespace tp { } } + Rect relative() const { + return { { 0, 0 }, size }; + } + // argument isInside bool isInside(const Vec2& p) const { return isInside(p.x, p.y); } diff --git a/Widgets/examples/ChatGUI.hpp b/Widgets/examples/ChatGUI.hpp index 7fcad0d..9043e6c 100644 --- a/Widgets/examples/ChatGUI.hpp +++ b/Widgets/examples/ChatGUI.hpp @@ -177,7 +177,7 @@ namespace tp { halnf mPadding = 0; }; - class ChattingWidget : public DockLayoutWidget { + class ChattingWidget : public DockWidget { public: ChattingWidget() { // todo : fetch code @@ -205,7 +205,7 @@ namespace tp { mActive.mHistoryView.addWidget(&message.data()); } - addSideWidget(&mSideView, DockLayoutWidget::RIGHT); + addSideWidget(&mSideView, DockWidget::RIGHT); setCenterWidget(&mActive); } diff --git a/Widgets/examples/SimpleGUI.hpp b/Widgets/examples/SimpleGUI.hpp index b924838..259f66a 100644 --- a/Widgets/examples/SimpleGUI.hpp +++ b/Widgets/examples/SimpleGUI.hpp @@ -33,19 +33,19 @@ namespace tp { public: SimpleWidget3() { - mDockSpace.addSideWidget(&mButtons[0], DockLayoutWidget::BOTTOM); - mDockSpace.addSideWidget(&mButtons[1], DockLayoutWidget::RIGHT); + mDockSpace.addSideWidget(&mButtons[0], DockWidget::BOTTOM); + mDockSpace.addSideWidget(&mButtons[1], DockWidget::RIGHT); - mDockSpace.removeSideWidget(DockLayoutWidget::BOTTOM); + mDockSpace.removeSideWidget(DockWidget::BOTTOM); - mDockSpace.addSideWidget(&mButtons[0], DockLayoutWidget::TOP); - mDockSpace.addSideWidget(&mButtons[2], DockLayoutWidget::LEFT); + mDockSpace.addSideWidget(&mButtons[0], DockWidget::TOP); + mDockSpace.addSideWidget(&mButtons[2], DockWidget::LEFT); - mDockSpace.removeSideWidget(DockLayoutWidget::TOP); + mDockSpace.removeSideWidget(DockWidget::TOP); - mDockSpace.addSideWidget(&mButtons[0], DockLayoutWidget::BOTTOM); + mDockSpace.addSideWidget(&mButtons[0], DockWidget::BOTTOM); - mDockSpace.addSideWidget(&mButtons[3], DockLayoutWidget::TOP); + mDockSpace.addSideWidget(&mButtons[3], DockWidget::TOP); mDockSpace.setCenterWidget(&mButtons[4]); /* diff --git a/Widgets/private/GridLayoutWidget.cpp b/Widgets/private/GridLayoutWidget.cpp index c1a4857..fa61231 100644 --- a/Widgets/private/GridLayoutWidget.cpp +++ b/Widgets/private/GridLayoutWidget.cpp @@ -2,14 +2,14 @@ using namespace tp; -DockLayoutWidget::DockLayoutWidget() { +DockWidget::DockWidget() { mSideWidgets[0].side = LEFT; mSideWidgets[1].side = TOP; mSideWidgets[2].side = RIGHT; mSideWidgets[3].side = BOTTOM; } -void DockLayoutWidget::addSideWidget(Widget* widget, Side side) { +void DockWidget::addSideWidget(Widget* widget, Side side) { if (sideExists(side)) return; auto& sideWidget = mSideWidgets[side]; @@ -27,7 +27,7 @@ void DockLayoutWidget::addSideWidget(Widget* widget, Side side) { widget->mIsDocked = true; } -void DockLayoutWidget::removeSideWidget(Side side) { +void DockWidget::removeSideWidget(Side side) { if (!sideExists(side)) return; bool removed = false; @@ -48,18 +48,18 @@ void DockLayoutWidget::removeSideWidget(Side side) { mSideWidgets[side].widget = nullptr; } -void DockLayoutWidget::setCenterWidget(Widget* widget) { +void DockWidget::setCenterWidget(Widget* widget) { mChildWidgets.removeNode(mChildWidgets.find(mCenterWidget)); mCenterWidget = widget; mChildWidgets.pushBack(mCenterWidget); } -void DockLayoutWidget::toggleHiddenState(DockLayoutWidget::Side side) { +void DockWidget::toggleHiddenState(DockWidget::Side side) { if (!sideExists(side)) return; mSideWidgets[side].hidden = !mSideWidgets[side].hidden; } -void DockLayoutWidget::eventProcess(const tp::Events& events) { +void DockWidget::eventProcess(const tp::Events& events) { calculateSideAreas(); calculateResizeHandles(); // calculateHeaderAreas(); @@ -70,7 +70,7 @@ void DockLayoutWidget::eventProcess(const tp::Events& events) { updateChildSideWidgets(); } -void DockLayoutWidget::eventDraw(Canvas& canvas) { +void DockWidget::eventDraw(Canvas& canvas) { canvas.rect(this->mArea, mBackgroundColor, 0); for (auto& sideWidget : mSideWidgets) { @@ -89,7 +89,7 @@ void DockLayoutWidget::eventDraw(Canvas& canvas) { } } -void DockLayoutWidget::eventDrawOver(Canvas& canvas) { +void DockWidget::eventDrawOver(Canvas& canvas) { if (!mPreview) return; if (mPreviewSide != NONE) canvas.rect(mPreviewArea.shrink(mPadding * 2), mPreviewColor, mRounding); @@ -100,7 +100,7 @@ void DockLayoutWidget::eventDrawOver(Canvas& canvas) { } } -void DockLayoutWidget::calculateSideAreas() { +void DockWidget::calculateSideAreas() { auto startArea = this->mArea; for (auto& sideWidget : mSideWidgets) { const auto side = sideWidget.order; @@ -135,7 +135,7 @@ void DockLayoutWidget::calculateSideAreas() { mCenterArea = startArea.shrink(mPadding); } -void DockLayoutWidget::calculateResizeHandles() { +void DockWidget::calculateResizeHandles() { RectF rec; if (isSideVisible(LEFT)) { @@ -162,7 +162,7 @@ void DockLayoutWidget::calculateResizeHandles() { } } -void DockLayoutWidget::handleResizeEvents(const Events& events) { +void DockWidget::handleResizeEvents(const Events& events) { for (auto& sideWidget : mSideWidgets) { auto& sideSize = sideWidget.absoluteSize; auto& resizeHandle = sideWidget.resizeHandle; @@ -225,7 +225,7 @@ void DockLayoutWidget::handleResizeEvents(const Events& events) { } } -void DockLayoutWidget::updateChildSideWidgets() { +void DockWidget::updateChildSideWidgets() { // Update Child Widgets { for (ualni i = 0; i < 4; i++) { @@ -261,7 +261,7 @@ void DockLayoutWidget::updateChildSideWidgets() { */ } -void DockLayoutWidget::calculateHeaderAreas() { +void DockWidget::calculateHeaderAreas() { for (ualni i = 0; i < 4; i++) { if (!isSideVisible(Side(i))) continue; auto& area = mSideWidgets[i].area; @@ -273,13 +273,13 @@ void DockLayoutWidget::calculateHeaderAreas() { } } -bool DockLayoutWidget::isSideVisible(DockLayoutWidget::Side side) { +bool DockWidget::isSideVisible(DockWidget::Side side) { return sideExists(side) && !mSideWidgets[side].hidden; } -bool DockLayoutWidget::sideExists(DockLayoutWidget::Side side) { return mSideWidgets[side].widget; } +bool DockWidget::sideExists(DockWidget::Side side) { return mSideWidgets[side].widget; } -ualni DockLayoutWidget::getVisibleSidesSize() { +ualni DockWidget::getVisibleSidesSize() { ualni out = 0; for (ualni i = 0; i < 4; i++) { if (isSideVisible(Side(i))) out++; @@ -287,9 +287,9 @@ ualni DockLayoutWidget::getVisibleSidesSize() { return out; } -DockLayoutWidget::Side DockLayoutWidget::getPreviewSide() { return mPreviewSide; } +DockWidget::Side DockWidget::getPreviewSide() { return mPreviewSide; } -void DockLayoutWidget::handlePreview(const Events& events) { +void DockWidget::handlePreview(const Events& events) { if (!mPreview) { mPreviewSide = NONE; return; diff --git a/Widgets/private/WorkspaceWidget.cpp b/Widgets/private/WorkspaceWidget.cpp index 3d38668..0e5ac2a 100644 --- a/Widgets/private/WorkspaceWidget.cpp +++ b/Widgets/private/WorkspaceWidget.cpp @@ -20,7 +20,7 @@ void WorkspaceWidget::eventProcess(const Events& events) { if (widget->mDropped) { auto side = mDockSpace.getPreviewSide(); - if (side != DockLayoutWidget::NONE) { + if (side != DockWidget::NONE) { mFloatingLayer.mChildWidgets.removeNode(mFloatingLayer.mChildWidgets.find(widget)); widget->setCollapsed(false); widget->stopFloating(); @@ -52,13 +52,13 @@ void WorkspaceWidget::eventProcess(const Events& events) { // toggle hide state if (events.isDown(InputID::LEFT_ALT)) { if (events.isPressed(InputID::N1)) { - mDockSpace.toggleHiddenState(DockLayoutWidget::LEFT); + mDockSpace.toggleHiddenState(DockWidget::LEFT); } else if (events.isPressed(InputID::N2)) { - mDockSpace.toggleHiddenState(DockLayoutWidget::TOP); + mDockSpace.toggleHiddenState(DockWidget::TOP); } else if (events.isPressed(InputID::N3)) { - mDockSpace.toggleHiddenState(DockLayoutWidget::RIGHT); + mDockSpace.toggleHiddenState(DockWidget::RIGHT); } else if (events.isPressed(InputID::N4)) { - mDockSpace.toggleHiddenState(DockLayoutWidget::BOTTOM); + mDockSpace.toggleHiddenState(DockWidget::BOTTOM); } } diff --git a/Widgets/public/GridLayoutWidget.hpp b/Widgets/public/GridLayoutWidget.hpp index 65179b0..7b4a058 100644 --- a/Widgets/public/GridLayoutWidget.hpp +++ b/Widgets/public/GridLayoutWidget.hpp @@ -1,7 +1,7 @@ #include "WidgetBase.hpp" namespace tp { - class DockLayoutWidget : public Widget { + class DockWidget : public Widget { public: enum Side { LEFT, TOP, RIGHT, BOTTOM, NONE }; @@ -30,7 +30,7 @@ namespace tp { }; public: - DockLayoutWidget(); + DockWidget(); void eventProcess(const Events& events) override; void eventDraw(Canvas& canvas) override; @@ -54,7 +54,7 @@ namespace tp { void calculateHeaderAreas(); bool isSideVisible(Side side); - bool sideExists(DockLayoutWidget::Side side); + bool sideExists(DockWidget::Side side); ualni getVisibleSidesSize(); void handlePreview(const Events& events); diff --git a/Widgets/public/WorkspaceWidget.hpp b/Widgets/public/WorkspaceWidget.hpp index f8363cc..617a0e4 100644 --- a/Widgets/public/WorkspaceWidget.hpp +++ b/Widgets/public/WorkspaceWidget.hpp @@ -10,7 +10,7 @@ namespace tp { void eventProcess(const Events& events) override; protected: - DockLayoutWidget mDockSpace; + DockWidget mDockSpace; FloatingLayoutWidget mFloatingLayer; // Parameters diff --git a/WidgetsNew/examples/Example.cpp b/WidgetsNew/examples/Example.cpp index 7d3a430..08c4ab2 100644 --- a/WidgetsNew/examples/Example.cpp +++ b/WidgetsNew/examples/Example.cpp @@ -4,7 +4,7 @@ #include "RootWidget.hpp" #include "AnimationTestWidget.hpp" #include "FloatingWidget.hpp" -#include "DockLayoutWidget.hpp" +#include "DockWidget.hpp" using namespace tp; @@ -31,7 +31,7 @@ public: mDockLayout.addChild(&mFloatingMenu); mDockLayout.setCenterWidget(&mButton5); - mDockLayout.dockWidget(&mButton6, DockLayoutWidget::RIGHT); + mDockLayout.dockWidget(&mButton6, DockLayout::RIGHT); mFloatingMenu.addToMenu(&mButton); mFloatingMenu2.addToMenu(&mButton2); @@ -42,8 +42,8 @@ public: mButton.setAction([this]() { mButton2.setColor(RGBA::random()); }); mButton2.setAction([this]() { mButton.setColor(RGBA::random()); }); - mButton5.setAction([this]() { mDockLayout.dockWidget(&mFloatingMenu, DockLayoutWidget::Side::LEFT); }); - mButton6.setAction([this]() { mDockLayout.undockWidget(DockLayoutWidget::Side::LEFT); }); + mButton5.setAction([this]() { mDockLayout.dockWidget(&mFloatingMenu, DockLayout::LEFT); }); + mButton6.setAction([this]() { mDockLayout.undockWidget(DockLayout::LEFT); }); mButton5.setText("dock"); mButton6.setText("undock"); @@ -94,10 +94,10 @@ public: mButton3.setSizePolicy(SizePolicy::Expanding, SizePolicy::Minimal); mWidget.setSizePolicy(SizePolicy::Minimal, SizePolicy::Minimal); - mWidget.setLayoutPolicy(LayoutPolicy::Horizontal); + // mWidget.setLayoutPolicy(LayoutPolicy::Horizontal); - mButton.setAction([this]() { mButton2.setMinSize(mButton2.getMinSize() + 10); }); - mButton2.setAction([this]() { mButton.setMinSize(mButton.getMinSize() + 10); } ); + // mButton.setAction([this]() { mButton2.setMinSize(mButton2.getMinSize() + 10); }); + // mButton2.setAction([this]() { mButton.setMinSize(mButton.getMinSize() + 10); } ); RootWidget::setWidgetArea(mWidget, { 400, 100, 150, 200 }); } @@ -135,7 +135,7 @@ private: FloatingWidget mWidgetFloating; AnimationTestWidget mAnimationTestWidget; - DockLayoutWidget mDockLayout; + DockWidget mDockLayout; RootWidget mRootWidget; }; diff --git a/WidgetsNew/private/DockLayoutWidget.cpp b/WidgetsNew/private/DockLayout.cpp similarity index 50% rename from WidgetsNew/private/DockLayoutWidget.cpp rename to WidgetsNew/private/DockLayout.cpp index 33e766f..c2957b1 100644 --- a/WidgetsNew/private/DockLayoutWidget.cpp +++ b/WidgetsNew/private/DockLayout.cpp @@ -1,99 +1,23 @@ -#include "DockLayoutWidget.hpp" -#include "FloatingWidget.hpp" +#include "DockLayout.hpp" using namespace tp; -DockLayoutWidget::DockLayoutWidget() { +DockLayout::DockLayout(Widget* widget) : + WidgetLayout(widget) { mSideWidgets[0].side = LEFT; mSideWidgets[1].side = TOP; mSideWidgets[2].side = RIGHT; mSideWidgets[3].side = BOTTOM; } -void DockLayoutWidget::process(const EventHandler& events) { - // calculateHeaderAreas(); - - Widget* floater = nullptr; - for (auto child : mChildren) { - if (auto iter = dynamic_cast(child)) { - if (iter->isFloating()) { - floater = iter; - break; - } - } - } - - if (floater) undockWidget(getSideFromWidget(floater), false); - - if (floater) { - handlePreview(events); - } - - if (mPreviewWidget && !floater) { - dockWidget(mPreviewWidget, mPreviewSide); - } - - mPreviewWidget = floater; - - if (!mPreviewWidget) { - handleResizeEvents(events); - } -} - -void DockLayoutWidget::draw(Canvas& canvas) { - canvas.rect(getRelativeArea(), mBackgroundColor, 0); -} - -void DockLayoutWidget::drawOverlay(Canvas& canvas) { - for (auto& sideWidget : mSideWidgets) { - if (!isSideVisible(sideWidget.side)) continue; - auto& handle = sideWidget.resizeHandle; - - if (handle.active) { - canvas.rect(handle.area.shrink(mPadding / 1.5f), mResizeHandleColorActive, 0); - } else if (handle.hover) { - canvas.rect(handle.area.shrink(mPadding / 1.5f), mResizeHandleColorHovered, 0); - } - } - - for (auto& sideWidget : mSideWidgets) { - if (!isSideVisible(sideWidget.side)) continue; - canvas.rect(sideWidget.headerArea, mResizeHandleColorActive, 0); - } - - if (mPreviewWidget) { - if (mPreviewSide != NONE) canvas.rect(mPreviewArea.shrink(mPadding * 2), mPreviewColor, mRounding); - - for (auto& sideWidget : mSideWidgets) { - if (sideWidget.widget) continue; - canvas.rect(sideWidget.previewHandleArea, mPreviewColor, mRounding); - } - } -} - -bool DockLayoutWidget::propagateEventsToChildren() const { - return !mResizing; -} - -bool DockLayoutWidget::needsNextFrame() const { - return Widget::needsNextFrame() || mResizing; -} - -void DockLayoutWidget::setCenterWidget(Widget* widget) { +bool DockLayout::setCenterWidget(Widget* widget) { + if (mCenterWidget) return false; mCenterWidget = widget; - addChild(widget); + return true; } -void DockLayoutWidget::dockWidget(Widget* widget, Side side) { - if (sideExists(side) || side == Side::NONE) return; - - addChild(widget); - - widget->bringToBack(); - if (mCenterWidget) mCenterWidget->bringToBack(); - for (auto& order : mSideWidgets) { - if (order.widget) order.widget->bringToBack(); - } +bool DockLayout::dockWidget(Widget* widget, Side side) { + if (sideExists(side) || side == Side::NONE) return false; auto& sideWidget = mSideWidgets[side]; sideWidget.widget = widget; @@ -107,20 +31,12 @@ void DockLayoutWidget::dockWidget(Widget* widget, Side side) { sideWidget.hidden = false; sideWidget.areaBeforeDocking = widget->getArea(); + + return true; } -void DockLayoutWidget::undockWidget(Side side, bool restoreArea) { - if (!sideExists(side) || (side == Side::NONE)) return; - - auto& sideWidget = mSideWidgets[side]; - - sideWidget.widget->bringToFront(); - - if (restoreArea) { - sideWidget.widget->setArea(sideWidget.areaBeforeDocking); - } else { - sideWidget.widget->endAnimations(); - } +bool DockLayout::undockWidget(Side side) { + if (!sideExists(side) || (side == Side::NONE)) return false; bool removed = false; for (ualni i = 0; i < 3; i++) { @@ -132,17 +48,18 @@ void DockLayoutWidget::undockWidget(Side side, bool restoreArea) { } } mSideWidgets[3].order = -1; - mSideWidgets[side].widget = nullptr; + + return true; } -void DockLayoutWidget::toggleWidgetVisibility(Side side) { +void DockLayout::toggleWidgetVisibility(Side side) { DEBUG_ASSERT(sideExists(side)) mSideWidgets[side].hidden = !mSideWidgets[side].hidden; } -void DockLayoutWidget::calculateSideAreas() { - auto startArea = getRelativeAreaCache(); +void DockLayout::calculateSideAreas() { + auto startArea = getArea().relative(); for (auto& sideWidget : mSideWidgets) { const auto side = sideWidget.order; @@ -177,9 +94,9 @@ void DockLayoutWidget::calculateSideAreas() { mCenterArea = startArea.shrink(mPadding); } -void DockLayoutWidget::calculateResizeHandles() { +void DockLayout::calculateResizeHandles() { RectF rec; - RectF area = getRelativeArea(); + RectF area = getArea().relative(); for (auto& sideWidget : mSideWidgets) { auto& sideSize = sideWidget.absoluteSize; @@ -224,80 +141,23 @@ void DockLayoutWidget::calculateResizeHandles() { } } -void DockLayoutWidget::handleResizeEvents(const EventHandler& events) { - auto pointer = events.getPointer(); - auto pointerDelta = events.getPointerDelta(); +void DockLayout::updateChildSideWidgets() { + for (ualni i = 0; i < 4; i++) { + if (!sideExists(Side(i))) continue; + auto widget = mSideWidgets[i].widget; - // check triggers - if (events.isReleased(InputID::MOUSE1)) { - for (auto& sideWidget : mSideWidgets) { - sideWidget.resizeHandle.active = false; - } - - mResizing = false; - } else { - for (auto& sideWidget : mSideWidgets) { - sideWidget.resizeHandle.hover = sideWidget.resizeHandle.area.isInside(pointer); - if (sideWidget.resizeHandle.hover && events.isPressed(InputID::MOUSE1)) { - sideWidget.resizeHandle.active = true; - - mResizing = true; - triggerWidgetUpdate("new docked child"); - } + if (!isSideVisible(Side(i))) { + // FIXME : widget->mEnable = false; + } else { + widget->setAreaCache(mSideWidgets[i].area); + // FIXME : widget->mEnable = true; } } - // do the resizing - for (auto& sideWidget : mSideWidgets) { - if (!sideWidget.resizeHandle.active) continue; - - halnf delta = pointerDelta[(sideWidget.side == TOP || sideWidget.side == BOTTOM)]; - - if (sideWidget.side == BOTTOM || sideWidget.side == RIGHT) { - delta *= -1; - } - - sideWidget.absoluteSize += delta; - } + if (mCenterWidget) mCenterWidget->setAreaCache(mCenterArea); } -void DockLayoutWidget::updateChildSideWidgets() { - // Update Child Widgets - { - for (ualni i = 0; i < 4; i++) { - if (!sideExists(Side(i))) continue; - auto widget = mSideWidgets[i].widget; - - if (!isSideVisible(Side(i))) { - // widget->mEnable = false; - } else { - widget->setAreaCache(mSideWidgets[i].area); - // widget->mEnable = true; - } - } - - if (mCenterWidget) mCenterWidget->setAreaCache(mCenterArea); - } - - // update depth order - /* - if (mChildWidgets.size() > 1) { - for (auto sideChild : mSideWidgets) { - if (!sideChild) continue; - - for (auto childNode = mChildWidgets.firstNode(); childNode; childNode = childNode->next) { - if (childNode->data == sideChild) { - mChildWidgets.detach(childNode); - mChildWidgets.pushBack(childNode); - break; - } - } - } - } - */ -} - -void DockLayoutWidget::calculateHeaderAreas() { +void DockLayout::calculateHeaderAreas() { for (ualni i = 0; i < 4; i++) { if (!isSideVisible(Side(i))) continue; auto& area = mSideWidgets[i].area; @@ -309,15 +169,7 @@ void DockLayoutWidget::calculateHeaderAreas() { } } -bool DockLayoutWidget::isSideVisible(DockLayoutWidget::Side side) { - return sideExists(side) && !mSideWidgets[side].hidden; -} - -bool DockLayoutWidget::sideExists(DockLayoutWidget::Side side) { - return mSideWidgets[side].widget; -} - -ualni DockLayoutWidget::getVisibleSidesSize() { +ualni DockLayout::getVisibleSidesSize() { ualni out = 0; for (ualni i = 0; i < 4; i++) { if (isSideVisible(Side(i))) out++; @@ -325,20 +177,30 @@ ualni DockLayoutWidget::getVisibleSidesSize() { return out; } -void DockLayoutWidget::handlePreview(const EventHandler& events) { - const halnf factor = 0.3; - const halnf handleFactor = 0.1; +auto DockLayout::getSideFromWidget(Widget* widget) -> Side { + for (auto& sideWidget : mSideWidgets) { + if (sideWidget.widget == widget) return sideWidget.side; + } + return DockLayout::NONE; +} - const auto handleSize = min(mCenterArea.size.x, mCenterArea.size.y) * handleFactor; +void DockLayout::adjustChildrenRect() { + calculateSideAreas(); + calculateResizeHandles(); + updateChildSideWidgets(); +} + +void DockLayout::updatePreviewSide(const Vec2F& pointer) { + const auto handleSize = min(mCenterArea.size.x, mCenterArea.size.y) * mHandleFactor; for (auto& sideWidget : mSideWidgets) { if (sideWidget.widget) continue; switch (sideWidget.side) { - case TOP: sideWidget.area = mCenterArea.splitByFactorVT(factor); break; - case BOTTOM: sideWidget.area = mCenterArea.splitByFactorVB(1 - factor); break; - case LEFT: sideWidget.area = mCenterArea.splitByFactorHL(factor); break; - case RIGHT: sideWidget.area = mCenterArea.splitByFactorHR(1 - factor); break; + case TOP: sideWidget.area = mCenterArea.splitByFactorVT(mHandleSplitFactor); break; + case BOTTOM: sideWidget.area = mCenterArea.splitByFactorVB(1 - mHandleSplitFactor); break; + case LEFT: sideWidget.area = mCenterArea.splitByFactorHL(mHandleSplitFactor); break; + case RIGHT: sideWidget.area = mCenterArea.splitByFactorHR(1 - mHandleSplitFactor); break; default: break; } @@ -351,23 +213,69 @@ void DockLayoutWidget::handlePreview(const EventHandler& events) { for (auto& sideWidget : mSideWidgets) { if (sideWidget.widget) continue; - - if (sideWidget.previewHandleArea.isInside(events.getPointer())) { + + if (sideWidget.previewHandleArea.isInside(pointer)) { mPreviewArea = sideWidget.area; mPreviewSide = sideWidget.side; } } } -auto DockLayoutWidget::getSideFromWidget(Widget* widget) -> Side { - for (auto& sideWidget : mSideWidgets) { - if (sideWidget.widget == widget) return sideWidget.side; - } - return DockLayoutWidget::NONE; +DockLayout::Side DockLayout::getPreviewSide() { + return mPreviewSide; } -void DockLayoutWidget::adjustChildrenRect() { - calculateSideAreas(); - calculateResizeHandles(); - updateChildSideWidgets(); +void DockLayout::updateResizeHover(const Vec2F& pointer) { + for (auto& sideWidget : mSideWidgets) { + sideWidget.resizeHandle.hover = sideWidget.resizeHandle.area.isInside(pointer); + } } + +void DockLayout::updateResize(const Vec2F& pointerDelta) { + if (!mResizing) return; + + // do the resizing + for (auto& sideWidget : mSideWidgets) { + if (!sideWidget.resizeHandle.active) continue; + halnf delta = pointerDelta[(sideWidget.side == TOP || sideWidget.side == BOTTOM)]; + if (sideWidget.side == BOTTOM || sideWidget.side == RIGHT) { + delta *= -1; + } + sideWidget.absoluteSize += delta; + } +} + +bool DockLayout::startResize(const Vec2F& pointer) { + for (auto& sideWidget : mSideWidgets) { + if (sideWidget.resizeHandle.hover) { + sideWidget.resizeHandle.active = true; + mResizing = true; + return true; + } + } + return false; +} + +void DockLayout::endResize() { + for (auto& sideWidget : mSideWidgets) { + sideWidget.resizeHandle.active = false; + } + mResizing = false; +} + +bool DockLayout::isSideVisible(DockLayout::Side side) const { + return sideExists(side) && !mSideWidgets[side].hidden; +} + +bool DockLayout::sideExists(DockLayout::Side side) const { + return mSideWidgets[side].widget; +} + +const std::vector& DockLayout::getDockedWidgets() { + mDockedWidgets.resize(5); + for (auto i = 0; i < 4; i++) { + mDockedWidgets[i] = mSideWidgets[i].widget; + } + mDockedWidgets[4] = mCenterWidget; + return mDockedWidgets; +} \ No newline at end of file diff --git a/WidgetsNew/private/DockWidget.cpp b/WidgetsNew/private/DockWidget.cpp new file mode 100644 index 0000000..e655231 --- /dev/null +++ b/WidgetsNew/private/DockWidget.cpp @@ -0,0 +1,131 @@ +#include "DockWidget.hpp" +#include "FloatingWidget.hpp" + +using namespace tp; + +DockWidget::DockWidget() { + setLayout(new DockLayout(this)); +} + +void DockWidget::dockWidget(Widget* widget, DockLayout::Side side) { + if (layout()->dockWidget(widget, side)) { + addChild(widget); + + for (auto child : layout()->getDockedWidgets()) { + if (child) child->bringToBack(); + } + } +} + +void DockWidget::undockWidget(DockLayout::Side side, bool restoreArea) { + if (layout()->sideExists(side) && side != DockLayout::NONE) { + auto widget = layout()->getSideWidget(side); + + widget->bringToFront(); + if (restoreArea) { + widget->setArea(layout()->getRectBeforeDocked(side)); + } else { + // FIXME : widget->endAnimations(); + } + + layout()->undockWidget(side); + } +} + +void DockWidget::setCenterWidget(Widget* widget) { + if (layout()->setCenterWidget(widget)) { + addChild(widget); + } +} + +void DockWidget::toggleWidgetVisibility(DockLayout::Side side) { + layout()->toggleWidgetVisibility(side); +} + +void DockWidget::process(const EventHandler& events) { + // calculateHeaderAreas(); + + Widget* floater = nullptr; + for (auto child : mChildren) { + if (auto iter = dynamic_cast(child)) { + if (iter->isFloating()) { + floater = iter; + break; + } + } + } + + if (floater) undockWidget(layout()->getSideFromWidget(floater), false); + + if (floater) { + layout()->updatePreviewSide(events.getPointer()); + } + + if (mPreviewWidget && !floater) { + dockWidget(mPreviewWidget, layout()->getPreviewSide()); + } + + mPreviewWidget = floater; + + if (!mPreviewWidget) { + layout()->updateResizeHover(events.getPointer()); + + if (events.isPressed(InputID::MOUSE1)) { + if (layout()->startResize(events.getPointer())) { + triggerWidgetUpdate("dock layout resizing"); + } + } else if (events.isReleased(InputID::MOUSE1)) { + layout()->endResize(); + } + + if (layout()->isResizing()) { + layout()->updateResize(events.getPointerDelta()); + } + } +} + +bool DockWidget::propagateEventsToChildren() const { + return !layout()->isResizing(); +} + +bool DockWidget::needsNextFrame() const { + return Widget::needsNextFrame() || layout()->isResizing(); +} + +void DockWidget::draw(Canvas& canvas) { + canvas.rect(getRelativeArea(), mBackgroundColor, 0); +} + +void DockWidget::drawSide(DockLayout::Side side, tp::Canvas& canvas) { + auto lay = layout(); + + if (lay->isSideVisible(side)) { + // header + canvas.rect(lay->getHeaderArea(side), mResizeHandleColorActive, 0); + + // resize + if (lay->isResizing(side)) { + canvas.rect(lay->getResizeHandleArea(side).shrink(mPadding / 1.5f), mResizeHandleColorActive, 0); + } else if (lay->isResizeHandleHover(side)) { + canvas.rect(lay->getResizeHandleArea(side).shrink(mPadding / 1.5f), mResizeHandleColorHovered, 0); + } + + } else { + // preview handles + if (mPreviewWidget) { + // preview active + if (lay->getPreviewSide() == side) { + canvas.rect(lay->getPreviewArea().shrink(mPadding * 2), mPreviewColor, mRounding); + } else { + canvas.rect(lay->getPreviewHandleArea(side), mPreviewColor, mRounding); + } + } + } +} + +void DockWidget::drawOverlay(Canvas& canvas) { + drawSide(DockLayout::Side::LEFT, canvas); + drawSide(DockLayout::Side::RIGHT, canvas); + drawSide(DockLayout::Side::TOP, canvas); + drawSide(DockLayout::Side::BOTTOM, canvas); +} \ No newline at end of file diff --git a/WidgetsNew/private/FloatingLayout.cpp b/WidgetsNew/private/FloatingLayout.cpp new file mode 100644 index 0000000..a7f6a9d --- /dev/null +++ b/WidgetsNew/private/FloatingLayout.cpp @@ -0,0 +1,52 @@ +#include "FloatingLayout.hpp" +#include "Widget.hpp" + +using namespace tp; + +void FloatingLayout::pickRect() { + if (mIsFloating) { + auto area = getArea(); + + if (mIsResizing) { + mPointerCurrent.clamp(mMinSize, mMaxSize); + + area.size = mPointerCurrent + mHandleSize / 2.f; + + for (auto child : children()) { + child->triggerWidgetUpdate("floating menu resized"); + } + + } else if (mIsFloating) { + area.pos += mPointerCurrent - mPointerStart; + } + + setArea(area); + } + + clampMinMaxSize(); +} + +RectF FloatingLayout::resizeHandleRect() { + auto area = getAnimatedArea().relative(); + area.pos = area.p3() - mHandleSize; + area.size = mHandleSize; + area.shrink(mHandlePadding); + return area; +} + +void FloatingLayout::startAction(const Vec2F& pointer) { + mPointerStart = pointer; + + mIsFloating = true; + if (resizeHandleRect().isInside(mPointerStart)) { + mIsResizing = true; + } +} + +void FloatingLayout::updateAction(const Vec2F& pointer) { + mPointerCurrent = pointer; +} + +void FloatingLayout::endAction() { + mIsResizing = mIsFloating = false; +} \ No newline at end of file diff --git a/WidgetsNew/private/FloatingWidget.cpp b/WidgetsNew/private/FloatingWidget.cpp index 78bfdd8..cb88bac 100644 --- a/WidgetsNew/private/FloatingWidget.cpp +++ b/WidgetsNew/private/FloatingWidget.cpp @@ -3,76 +3,39 @@ using namespace tp; void FloatingWidget::process(const EventHandler& events) { - const auto relativePointer = events.getPointer(); - - bool inside = getRelativeAreaT().isInside(relativePointer); - - if (inside && events.isPressed(InputID::MOUSE1)) { - mPointerStart = relativePointer; - mIsFloating = true; - - if (resizeHandleRect().isInside(relativePointer)) { - mIsResizing = true; - } + const auto pointer = events.getPointer(); + if (getRelativeAreaT().isInside(pointer) && events.isPressed(InputID::MOUSE1)) { + layout()->startAction(pointer); bringToFront(); } - - if (mIsFloating && events.isReleased(InputID::MOUSE1)) { - mIsFloating = false; - mIsResizing = false; + if (layout()->isFloating() && events.isReleased(InputID::MOUSE1)) { + layout()->endAction(); } - mPointerCurrent = relativePointer; - - // triggerWidgetUpdate(); -} - -void FloatingWidget::pickRect() { - if (mIsFloating) { - auto area = getAreaCache(); - - if (mIsResizing) { - mPointerCurrent.clamp(mMinSize, mMaxSize); - - area.size = mPointerCurrent + mHandleSize / 2.f; - - for (auto child : mChildren) { - child->triggerWidgetUpdate("floating menu resized"); - } - - } else if (mIsFloating) { - area.pos += mPointerCurrent - mPointerStart; - } - - setAreaCache(area); - } - - clampMinMaxSize(); + layout()->updateAction(pointer); } void FloatingWidget::draw(Canvas& canvas) { - canvas.rect(resizeHandleRect(), RGBA(0.7f), 2); + canvas.rect(layout()->resizeHandleRect(), RGBA(0.7f), 2); canvas.rect(getRelativeArea(), RGBA(0.5f), 10); } -RectF FloatingWidget::resizeHandleRect() { - auto area = getRelativeArea(); - area.pos = area.p3() - mHandleSize; - area.size = mHandleSize; - area.shrink(mHandlePadding); - return area; -} - bool FloatingWidget::propagateEventsToChildren() const { - return !mIsFloating; + return !layout()->isFloating(); } bool FloatingWidget::isFloating() const { - return mIsFloating; + return layout()->isFloating(); } bool FloatingWidget::needsNextFrame() const { return Widget::needsNextFrame() || isFloating(); } + +FloatingLayout* FloatingWidget::layout() { return dynamic_cast(Widget::getLayout()); } + +const FloatingLayout* FloatingWidget::layout() const { + return dynamic_cast(Widget::getLayout()); +} diff --git a/WidgetsNew/private/LayoutPolicies.cpp b/WidgetsNew/private/LayoutManager.cpp similarity index 65% rename from WidgetsNew/private/LayoutPolicies.cpp rename to WidgetsNew/private/LayoutManager.cpp index 521ec6e..4627cfb 100644 --- a/WidgetsNew/private/LayoutPolicies.cpp +++ b/WidgetsNew/private/LayoutManager.cpp @@ -1,12 +1,16 @@ #include -#include "LayoutPolicies.hpp" +#include "LayoutManager.hpp" #include "Widget.hpp" using namespace tp; const RectF& WidgetLayout::getArea() const { - return mWidget->getAreaCache(); + return mWidget->mAreaCache; +} + +RectF WidgetLayout::getAnimatedArea() const { + return mWidget->getArea(); } void WidgetLayout::setArea(const RectF& area) { @@ -17,9 +21,79 @@ Widget* WidgetLayout::parent() const { return mWidget->mParent; } const std::vector& WidgetLayout::children() const { return mWidget->mChildren; } -const Vec2F& BasicLayout::getMinSize() { return mMinSize; } +const Vec2F& WidgetLayout::getMinSize() { return mMinSize; } -void BasicLayout::setMinSize(const Vec2F& size) { mMinSize = size; } +void WidgetLayout::setMinSize(const Vec2F& size) { mMinSize = size; } + +const Vec2& WidgetLayout::getSizePolicy() const { return mSizePolicy; } + +void WidgetLayout::setSizePolicy(SizePolicy x, SizePolicy y) { mSizePolicy = { x, y }; } + +RangeF WidgetLayout::pickRange(const RangeF& current, const RangeF& children, const RangeF& parent, bool vertical) const { + RangeF out; + + switch (mSizePolicy[vertical]) { + case SizePolicy::Fixed: out = current; break; + case SizePolicy::Expanding: out = parent; break; + case SizePolicy::Minimal: out = children; break; + } + + out = clampRange(out, children, parent, vertical); + return out; +} + +void WidgetLayout::clampMinMaxSize() { + auto current = getArea(); + current.size.clamp(mMinSize, mMaxSize); + setArea(current); +} + +RangeF WidgetLayout::clampRange(const RangeF& current, const RangeF& child, const RangeF& parent, bool vertical) const { + auto out = current; + + if (!children().empty()) { + auto clampedChild = child; + clampedChild.clamp(parent); + out.clamp(clampedChild, parent); + } else { + out.clamp(parent); + } + + // clamp min max sizes + auto len = clamp(current.size(), mMinSize[vertical], mMaxSize[vertical]); + if (len != current.size()) { + out.resizeFromCenter(len); + } + + return out; +} + +RectF WidgetLayout::getChildrenEnclosure() const { + RectF out; + + if (children().empty()) { + out = { getArea().center(), { 0, 0 } }; + } else { + out = children().front()->getLayout()->getArea(); + for (auto child : children()) { + out.expand(child->getLayout()->getArea()); + } + out.pos += getArea().pos; + } + + return out; +} + +RectF WidgetLayout::getAvailableChildArea() const { + return getArea().relative(); +} + +RectF WidgetLayout::getParentEnclosure() const { + DEBUG_ASSERT(parent()) + if (!parent()) return { { 0, 0 }, mMaxSize }; + auto out = parent()->getLayout()->getAvailableChildArea(); + return out; +} void BasicLayout::pickRect() { auto current = getArea(); @@ -57,16 +131,15 @@ void BasicLayout::adjustChildrenRect() { halnf BasicLayout::changeChildSize(tp::Widget* widget, halnf diff, bool vertical) { - auto prevSize = widget->getAreaCache().size[vertical]; + auto prevSize = widget->getLayout()->getArea().size[vertical]; { - auto area = widget->getAreaCache(); + auto area = widget->getLayout()->getArea(); area.size[vertical] += diff; widget->setAreaCache(area); - // FIXME : widget->clampMinMaxSize(); + widget->getLayout()->clampMinMaxSize(); } - auto newSize = widget->getAreaCache().size[vertical]; - + auto newSize = widget->getLayout()->getArea().size[vertical]; return newSize - prevSize; } @@ -76,22 +149,20 @@ void BasicLayout::adjustLayout(bool vertical) { Vec2F availableSize = getArea().size; for (auto child : children()) { - // FIXME : + if (child->getLayout()->getSizePolicy()[!vertical] != SizePolicy::Minimal) { + child->getLayout()->pickRect(); + } - // if (child->mSizePolicy[!vertical] != SizePolicy::Minimal) { - // child->pickRect(); - // } - - // if (child->mSizePolicy[vertical] == SizePolicy::Expanding) { + if (child->getLayout()->getSizePolicy()[vertical] == SizePolicy::Expanding) { contributors.emplace_back( child, true ); - auto area = child->getAreaCache(); + auto area = child->getLayout()->getArea(); area.size[vertical] = 0; child->setAreaCache(area); - // child->clampRect(); + child->getLayout()->clampRect(); + } - //} - contentSize += child->getAreaCache().size; + contentSize += child->getLayout()->getArea().size; } availableSize -= mLayoutGap * ((halnf) children().size() - 1) + mLayoutMargin * 2; @@ -124,7 +195,7 @@ void BasicLayout::adjustLayout(bool vertical) { // arrange halnf iterPos = mLayoutMargin; for (auto child : children()) { - auto area = child->getAreaCache(); + auto area = child->getLayout()->getArea(); area.pos[vertical] = iterPos; iterPos += area.size[vertical] + mLayoutGap; child->setAreaCache(area); @@ -135,72 +206,19 @@ void BasicLayout::adjustLayout(bool vertical) { } } -RangeF BasicLayout::pickRange(const RangeF& current, const RangeF& children, const RangeF& parent, bool vertical) const { - RangeF out; - - switch (mSizePolicy[vertical]) { - case SizePolicy::Fixed: out = current; break; - case SizePolicy::Expanding: out = parent; break; - case SizePolicy::Minimal: out = children; break; - } - - out = clampRange(out, children, parent, vertical); - return out; +RectF BasicLayout::getAvailableChildArea() const { + auto out = WidgetLayout::getAvailableChildArea(); + return out.scaleFromCenter(mLayoutMargin, true); } -void BasicLayout::clampMinMaxSize() { - auto current = getArea(); - current.size.clamp(mMinSize, mMaxSize); - setArea(current); -} - -RangeF BasicLayout::clampRange(const RangeF& current, const RangeF& child, const RangeF& parent, bool vertical) const { - auto out = current; - - if (!children().empty()) { - auto clampedChild = child; - clampedChild.clamp(parent); - out.clamp(clampedChild, parent); - } else { - out.clamp(parent); - } - - // clamp min max sizes - auto len = clamp(current.size(), mMinSize[vertical], mMaxSize[vertical]); - if (len != current.size()) { - out.resizeFromCenter(len); - } - - return out; -} - -RectF BasicLayout::getChildrenEnclosure() const { - RectF out; - - if (children().empty()) { - out = { getArea().center(), { 0, 0 } }; - } else { - out = children().front()->getAreaCache(); - for (auto child : children()) { - out.expand(child->getAreaCache()); +void LayoutManager::adjust(Widget* root) { + Widget::dfs( + root, + [](Widget* widget) { + widget->getLayout()->pickRect(); + }, + [](Widget* widget) { + widget->getLayout()->adjustChildrenRect(); } - out.pos += getArea().pos; - } - - return out; -} - -RectF BasicLayout::getParentEnclosure() const { - DEBUG_ASSERT(parent()) - if (!parent()) return { { 0, 0 }, mMaxSize }; - - // FIXME : - // auto out = parent()->getRelativeAreaT(); - - // if (parent()->mLayoutPolicy != LayoutPolicy::Passive) { - // return out.scaleFromCenter(parent()->mLayoutMargin, true); - // } - - // return out; - return {}; + ); } \ No newline at end of file diff --git a/WidgetsNew/private/RootWidget.cpp b/WidgetsNew/private/RootWidget.cpp index c948b86..966db9e 100644 --- a/WidgetsNew/private/RootWidget.cpp +++ b/WidgetsNew/private/RootWidget.cpp @@ -26,10 +26,8 @@ void RootWidget::processFrame(EventHandler* events, const RectF& screenArea) { // construct hierarchy tree of widgets to process updateTreeToProcess(); - auto root = mWidgetsToProcess.find(mRoot) == mWidgetsToProcess.end() ? nullptr : &mWidgetsToProcess[mRoot]; - - // update active tree animations - updateAnimations(root); + updateAnimations(); + updateAreaCache(mRoot, true); // update all events and call all event processing callbacks events->setEnableKeyEvents(true); @@ -38,14 +36,14 @@ void RootWidget::processFrame(EventHandler* events, const RectF& screenArea) { events->setEnableKeyEvents(false); events->setCursorOrigin({ 0, 0 }); - processActiveTree(root, *events, { 0, 0 }); + processActiveTree(mRoot, *events, { 0, 0 }); - updateAreaCache(root, true); + updateAreaCache(mRoot, true); // update widget sizes base on individual size policies - adjustSizes(root); + processLayout(); - updateAreaCache(root, false); + updateAreaCache(mRoot, false); // trigger some widgets by moise pointer handleFocusChanges(*events); @@ -62,7 +60,7 @@ void RootWidget::processFrame(EventHandler* events, const RectF& screenArea) { auto end = !widget->needsNextFrame(); if (end) { widget->endAnimations(); - widget->mTriggerReason = "del"; + widget->mDebug.triggerReason = "del"; } return end; }); @@ -73,33 +71,33 @@ bool RootWidget::needsUpdate() const { return !mTriggeredWidgets.empty() || mDeb void RootWidget::debugDrawWidget(Widget* widget) { ImGui::PushID(widget); - if (ImGui::CollapsingHeader(widget->mName.c_str())) { + if (ImGui::CollapsingHeader(widget->mDebug.id.c_str())) { - ImGui::Text("trigger reason: %s", widget->mTriggerReason.c_str()); + ImGui::Text("trigger reason: %s", widget->mDebug.triggerReason.c_str()); auto area = widget->getAreaT(); if (ImGui::InputFloat4("rect", &area.x)) { widget->setArea(area); } - ImGui::InputFloat2("min size", &widget->mMinSize.x); - ImGui::InputFloat2("max size", &widget->mMaxSize.x); + // ImGui::InputFloat2("min size", &widget->mMinSize.x); + // ImGui::InputFloat2("max size", &widget->mMaxSize.x); - int sizePolicyX = int(widget->mSizePolicy.x); - int sizePolicyY = int(widget->mSizePolicy.y); - int layout = int(widget->mLayoutPolicy); + // int sizePolicyX = int(widget->mSizePolicy.x); + // int sizePolicyY = int(widget->mSizePolicy.y); + // int layout = int(widget->mLayoutPolicy); - if (ImGui::Combo("Size Policy X", &sizePolicyX, "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("Size Policy Y", &sizePolicyY, "Fixed\0Expanding\0Minimal\0")) { - widget->setSizePolicy(SizePolicy(sizePolicyX), SizePolicy(sizePolicyY)); - } + // if (ImGui::Combo("Size Policy Y", &sizePolicyY, "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("Layout", &layout, "Passive\0Vertical\0Horizontal\0")) { + // widget->setLayoutPolicy(LayoutPolicy(layout)); + // } } ImGui::PopID(); } @@ -117,7 +115,7 @@ void RootWidget::drawFrame(Canvas& canvas) { drawDebug(canvas, mRoot, { 0, 0 }, 0); ImGui::Text("Triggered Widgets: %i", (int) mTriggeredWidgets.size()); - ImGui::Text("Widgets To Process: %i", (int) mWidgetsToProcess.size()); + ImGui::Text("Widgets To Process: %i", mDebugWidgetsToProcess); ImGui::Text("To Toggle processing press k"); ImGui::Checkbox("Stop processing", &mDebugStopProcessing); @@ -147,17 +145,22 @@ void RootWidget::drawFrame(Canvas& canvas) { void RootWidget::updateTreeToProcess() { - mWidgetsToProcess.clear(); + dfs(mRoot, [](Widget* widget) { + widget->mNeedsProcessing = false; + }); + for (auto& [widget, flag] : mTriggeredWidgets) { flag = true; - for (auto iter = widget; iter; iter = iter->mParent) { - if (iter->mParent) { - mWidgetsToProcess[iter->mParent].children.insert(&mWidgetsToProcess[iter]); - mWidgetsToProcess[iter->mParent].widget= iter->mParent; - mWidgetsToProcess[iter].widget= iter; - } + + for (auto iter = widget; iter && iter != this; iter = iter->mParent) { + iter->mNeedsProcessing = true; } } + + mDebugWidgetsToProcess = 0; + dfs(mRoot, [this](Widget*) { + mDebugWidgetsToProcess++; + }); } void RootWidget::drawRecursion(Canvas& canvas, Widget* active, const Vec2F& pos) { @@ -179,17 +182,15 @@ void RootWidget::drawRecursion(Canvas& canvas, Widget* active, const Vec2F& pos) void RootWidget::drawDebug(Canvas& canvas, Widget* active, const Vec2F& pos, int depthOrder) { auto area = RectF{ pos, active->getAreaT().size }; - auto processed = mWidgetsToProcess.find(active) != mWidgetsToProcess.end(); - - if (processed) { + if (active->mNeedsProcessing) { RGBA color = { 1, 0, 0, 1}; canvas.frame(area, color); - canvas.text((active->mName + ":" + std::to_string(depthOrder)).c_str(), area, 22, Canvas::Align::LC, 2, color); + canvas.text((active->mDebug.id + ":" + std::to_string(depthOrder)).c_str(), area, 22, Canvas::Align::LC, 2, color); } - if (processed || active->mInFocus) { - canvas.circle(pos + active->mLocalPoint, 5, active->mDebugColor); - canvas.circle(active->mGlobalPoint, 15, active->mDebugColor); + if (active->mNeedsProcessing || active->mInFocus) { + canvas.circle(pos + active->mDebug.pLocal, 5, active->mDebug.col); + canvas.circle(active->mDebug.pGlobal, 15, active->mDebug.col); } if (active->mInFocus) { @@ -208,12 +209,10 @@ void RootWidget::setWidgetArea(Widget& widget, const RectF& rect) { widget.mArea.endAnimation(); } -void RootWidget::updateAnimations(ActiveTreeNode* iter) { - if (!iter) return; - iter->widget->updateAnimations(); - for (auto child : iter->children) { - updateAnimations(child); - } +void RootWidget::updateAnimations() { + dfs(mRoot, [](Widget* widget) { + widget->updateAnimations(); + }); } void RootWidget::getWidgetPath(Widget* widget, std::vector& out) { @@ -289,21 +288,21 @@ void RootWidget::findFocusWidget(Widget* iter, Widget** focus, const Vec2F& poin void RootWidget::updateWidget(Widget* widget, const char* reason) { DEBUG_ASSERT(reason) - widget->mTriggerReason = reason; + widget->mDebug.triggerReason = reason; mTriggeredWidgets.insert({ widget, false }); } -void RootWidget::updateAreaCache(ActiveTreeNode* iter, bool read) { - if (!iter) return; +void RootWidget::updateAreaCache(Widget* iter, bool read) { + if (!iter || !iter->mNeedsProcessing) return; if (read) { - iter->widget->mAreaCache = iter->widget->getAreaT(); + iter->mAreaCache = iter->getAreaT(); } else { - iter->widget->setArea(iter->widget->mAreaCache); - iter->widget->mArea.updateCurrentRect(); + iter->setArea(iter->mAreaCache); + iter->mArea.updateCurrentRect(); } - for (auto child : iter->widget->mChildren) { + for (auto child : iter->mChildren) { if (read) { child->mAreaCache = child->getAreaT(); } else { @@ -312,37 +311,29 @@ void RootWidget::updateAreaCache(ActiveTreeNode* iter, bool read) { } } - for (auto child : iter->children) { - updateAreaCache(child, read); + for (auto child : iter->mDepthOrder) { + updateAreaCache(child.data(), read); } } -void RootWidget::adjustSizes(ActiveTreeNode* iter) { - if (!iter) return; - - iter->widget->pickRect(); - - for (auto child : iter->children) { - adjustSizes(child); - } - - iter->widget->adjustChildrenRect(); +void RootWidget::processLayout() { + mLayoutManager.adjust(mRoot); } -void RootWidget::processActiveTree(ActiveTreeNode* iter, EventHandler& events, Vec2F parent) { - if (!iter) return; +void RootWidget::processActiveTree(Widget* iter, EventHandler& events, Vec2F parent) { + if (!iter || !iter->mNeedsProcessing) return; - auto current = parent + iter->widget->getAreaT().pos; + auto current = parent + iter->getAreaT().pos; - if (!iter->widget->mInFocus) { - iter->widget->mGlobalPoint = current; + if (!iter->mInFocus) { + iter->mDebug.pGlobal = current; events.setCursorOrigin(current); - iter->widget->process(events); + iter->process(events); } - for (auto child : iter->children) { - processActiveTree(child, events, current); + for (auto child : iter->mDepthOrder) { + processActiveTree(child.data(), events, current); } } @@ -377,7 +368,7 @@ void RootWidget::processFocusItems(EventHandler& events) { events.setCursorOrigin(widgetGlobalPos[iter]); - widget->mGlobalPoint = widgetGlobalPos[iter]; + widget->mDebug.pGlobal = widgetGlobalPos[iter]; if (!eventsProcessed && widget->processesEvents()) { events.setEnableKeyEvents(true); diff --git a/WidgetsNew/private/Widget.cpp b/WidgetsNew/private/Widget.cpp index 8407e92..95a4427 100644 --- a/WidgetsNew/private/Widget.cpp +++ b/WidgetsNew/private/Widget.cpp @@ -14,7 +14,7 @@ Widget::~Widget() { delete mLayout; } -void Widget::addChild(Widget* child) { +void Widget::addChild(Widget* child, bool front) { if (auto node = mDepthOrder.find(child)) { node->data->bringToFront(); return; @@ -25,7 +25,12 @@ void Widget::addChild(Widget* child) { } mChildren.push_back(child); - mDepthOrder.pushBack(child); + + if (front) { + mDepthOrder.pushFront(child); + } else { + mDepthOrder.pushBack(child); + } child->mParent = this; @@ -78,6 +83,8 @@ void Widget::setLayout(tp::WidgetLayout* layout) { WidgetLayout* Widget::getLayout() { return mLayout; } +const WidgetLayout* Widget::getLayout() const { return mLayout; } + WidgetManagerInterface* Widget::getRoot() { Widget* iter = mParent; while (iter && iter->mParent) { @@ -105,13 +112,13 @@ RectF Widget::getArea() const { return mArea.getCurrentRect(); } RectF Widget::getAreaT() const { return mArea.getTargetRect(); } -const RectF& Widget::getAreaCache() const { return mAreaCache; } +// const RectF& Widget::getAreaCache() const { return mAreaCache; } RectF Widget::getRelativeArea() const { return { {}, mArea.getCurrentRect().size }; } RectF Widget::getRelativeAreaT() const { return { {}, mArea.getTargetRect().size }; } -RectF Widget::getRelativeAreaCache() const { return { {}, mAreaCache.size }; } +// RectF Widget::getRelativeAreaCache() const { return { {}, mAreaCache.size }; } void Widget::setDebug(const char* name, RGBA col) { mDebug.id = name; diff --git a/WidgetsNew/public/DockLayout.hpp b/WidgetsNew/public/DockLayout.hpp new file mode 100644 index 0000000..35ee113 --- /dev/null +++ b/WidgetsNew/public/DockLayout.hpp @@ -0,0 +1,108 @@ +#include "Widget.hpp" + +namespace tp { + class DockLayout : public WidgetLayout { + public: + enum Side { LEFT, TOP, RIGHT, BOTTOM, NONE }; + + private: + struct ResizeHandle { + RectF area{ 0, 0, 0, 0 }; + halnf start{ 0 }; + halnf end{ 0 }; + bool active = false; + bool hover = false; + }; + + struct SideWidgetData { + Widget* widget = nullptr; + bool hidden = false; + halnf absoluteSize = 200; + alni order = -1; + + Side side = { TOP }; + + RectF area = {}; + RectF headerArea = {}; + RectF previewHandleArea = {}; + + ResizeHandle resizeHandle; + + RectF areaBeforeDocking = {}; + }; + + public: + explicit DockLayout(Widget* widget); + + void updateResizeHover(const Vec2F& pointer); + bool startResize(const Vec2F& pointer); + void updateResize(const Vec2F& pointerDelta); + void endResize(); + + void updatePreviewSide(const Vec2F& pointer); + + public: + void pickRect() override {} + void adjustChildrenRect() override; + void clampRect() override {}; + + public: + bool setCenterWidget(Widget* widget); + + bool dockWidget(Widget* widget, Side side); + bool undockWidget(Side side); + void toggleWidgetVisibility(Side side); + + public: + [[nodiscard]] bool isSideVisible(Side side) const; + [[nodiscard]] bool sideExists(Side side) const; + + [[nodiscard]] bool isResizing() const { return mResizing; } + [[nodiscard]] bool isResizing(Side side) const { return mSideWidgets[side].resizeHandle.active; } + [[nodiscard]] bool isResizeHandleHover(Side side) const { return mSideWidgets[side].resizeHandle.hover; } + + Side getSideFromWidget(Widget*); + Side getPreviewSide(); + + [[nodiscard]] RectF getRectBeforeDocked(Side side) const { return mSideWidgets[side].areaBeforeDocking; } + [[nodiscard]] RectF getResizeHandleArea(Side side) const { return mSideWidgets[side].resizeHandle.area; } + [[nodiscard]] RectF getHeaderArea(Side side) const { return mSideWidgets[side].headerArea; } + [[nodiscard]] RectF getPreviewHandleArea(Side side) const { return mSideWidgets[side].previewHandleArea; } + [[nodiscard]] RectF getPreviewArea() const { return mPreviewArea; } + + Widget* getSideWidget(Side side) { return mSideWidgets[side].widget; } + + const std::vector& getDockedWidgets(); + + private: + ualni getVisibleSidesSize(); + + void calculateSideAreas(); + void calculateResizeHandles(); + void updateChildSideWidgets(); + void calculateHeaderAreas(); + + private: + RectF mPreviewArea = {}; + Side mPreviewSide = NONE; + int resizeType[2] = { 0, 0 }; + + SideWidgetData mSideWidgets[4]; + + std::vector mDockedWidgets; + + private: + bool mResizing = false; + + Widget* mCenterWidget = nullptr; + RectF mCenterArea {}; + + // Parameters + const halnf mHandleSplitFactor = 0.3; + const halnf mHandleFactor = 0.1; + + halnf mSideSizePadding = 150.f; + halnf mPadding = 4; + halnf mHeaderSize = 27; + }; +} \ No newline at end of file diff --git a/WidgetsNew/public/DockLayoutWidget.hpp b/WidgetsNew/public/DockLayoutWidget.hpp deleted file mode 100644 index d88a63c..0000000 --- a/WidgetsNew/public/DockLayoutWidget.hpp +++ /dev/null @@ -1,97 +0,0 @@ -#include "Widget.hpp" - -namespace tp { - class DockLayoutWidget : public Widget { - public: - enum Side { LEFT, TOP, RIGHT, BOTTOM, NONE }; - - private: - struct ResizeHandle { - RectF area{ 0, 0, 0, 0 }; - halnf start{ 0 }; - halnf end{ 0 }; - bool active = false; - bool hover = false; - }; - - struct SideWidgetData { - Widget* widget = nullptr; - bool hidden = false; - halnf absoluteSize = 200; - alni order = -1; - - Side side = { TOP }; - - RectF area = {}; - RectF headerArea = {}; - RectF previewHandleArea = {}; - - ResizeHandle resizeHandle; - - RectF areaBeforeDocking = {}; - }; - - public: - DockLayoutWidget(); - - public: - void pickRect() override {} - void adjustChildrenRect() override; - - void process(const EventHandler& events) override; - void draw(Canvas& canvas) override; - void drawOverlay(Canvas& canvas) override; - - [[nodiscard]] bool propagateEventsToChildren() const override; - [[nodiscard]] bool needsNextFrame() const override; - - public: - void setCenterWidget(Widget* widget); - - void dockWidget(Widget* widget, Side side); - void undockWidget(Side side, bool restoreArea = true); - void toggleWidgetVisibility(Side side); - - private: - Side getSideFromWidget(Widget*); - void calculateSideAreas(); - void calculateResizeHandles(); - void handleResizeEvents(const EventHandler& events); - void updateChildSideWidgets(); - - void calculateHeaderAreas(); - - bool isSideVisible(Side side); - bool sideExists(DockLayoutWidget::Side side); - ualni getVisibleSidesSize(); - void handlePreview(const EventHandler& events); - - private: - RectF mPreviewArea = {}; - Side mPreviewSide = NONE; - int resizeType[2] = { 0, 0 }; - - SideWidgetData mSideWidgets[4]; - - private: - bool mResizing = false; - - Widget* mCenterWidget = nullptr; - RectF mCenterArea {}; - - // Parameters - halnf mSideSizePadding = 150.f; - halnf mPadding = 4; - halnf mHeaderSize = 27; - halnf mRounding = 10; - Vec2F mPreviewHandleSize = { 50, 50 }; - - RGBA mResizeHandleColorHovered = RGBA(0.3, 0.3, 0.3, 1); - RGBA mResizeHandleColorActive = RGBA(0.6, 0.6, 0.6, 1); - RGBA mBackgroundColor = RGBA(0, 0, 0, 1); - RGBA mPreviewColor = RGBA(0.6, 0.6, 0.6, 0.2); - - public: - Widget* mPreviewWidget = nullptr; - }; -} \ No newline at end of file diff --git a/WidgetsNew/public/DockWidget.hpp b/WidgetsNew/public/DockWidget.hpp new file mode 100644 index 0000000..baa4fb8 --- /dev/null +++ b/WidgetsNew/public/DockWidget.hpp @@ -0,0 +1,41 @@ +#include "DockLayout.hpp" + +namespace tp { + class DockWidget : public Widget { + public: + DockWidget(); + + public: + void process(const EventHandler& events) override; + void draw(Canvas& canvas) override; + void drawOverlay(Canvas& canvas) override; + + [[nodiscard]] bool propagateEventsToChildren() const override; + [[nodiscard]] bool needsNextFrame() const override; + + void drawSide(DockLayout::Side side, Canvas& canvas); + + public: + void setCenterWidget(Widget* widget); + + void dockWidget(Widget* widget, DockLayout::Side side); + void undockWidget(DockLayout::Side side, bool restoreArea = true); + void toggleWidgetVisibility(DockLayout::Side side); + + private: + DockLayout* layout() { return dynamic_cast(mLayout); } + const DockLayout* layout() const { return dynamic_cast(mLayout); } + + private: + Widget* mPreviewWidget = nullptr; + + private: + halnf mRounding = 10; + halnf mPadding = 4; + + RGBA mResizeHandleColorHovered = RGBA(0.3, 0.3, 0.3, 1); + RGBA mResizeHandleColorActive = RGBA(0.6, 0.6, 0.6, 1); + RGBA mBackgroundColor = RGBA(0, 0, 0, 1); + RGBA mPreviewColor = RGBA(0.6, 0.6, 0.6, 0.2); + }; +} \ No newline at end of file diff --git a/WidgetsNew/public/FloatingLayout.hpp b/WidgetsNew/public/FloatingLayout.hpp new file mode 100644 index 0000000..4db0808 --- /dev/null +++ b/WidgetsNew/public/FloatingLayout.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include "LayoutManager.hpp" + +namespace tp { + class FloatingLayout : public BasicLayout { + public: + FloatingLayout(Widget* widget) : + BasicLayout(widget) {} + + public: + void startAction(const Vec2F& pointer); + void updateAction(const Vec2F& pointer); + void endAction(); + + bool isFloating() const { return mIsFloating; } + + RectF resizeHandleRect(); + + public: + void pickRect() override; + + private: + bool mIsFloating = false; + bool mIsResizing = false; + + Vec2F mPointerStart; + Vec2F mPointerCurrent; + + // TODO : remove? + halnf mHandleSize = 10; + halnf mHandlePadding = 2; + }; +} \ No newline at end of file diff --git a/WidgetsNew/public/FloatingWidget.hpp b/WidgetsNew/public/FloatingWidget.hpp index 91de51e..f5e14fd 100644 --- a/WidgetsNew/public/FloatingWidget.hpp +++ b/WidgetsNew/public/FloatingWidget.hpp @@ -1,24 +1,20 @@ #pragma once #include "SimpleWidgets.hpp" +#include "FloatingLayout.hpp" namespace tp { class FloatingWidget : public Widget { public: FloatingWidget() { setDebug("float", { 0.0, 0.9, 0.1, 1 }); - - mSizePolicy = { SizePolicy::Fixed, SizePolicy::Fixed }; - mLayoutPolicy = LayoutPolicy::Horizontal; + setLayout(new FloatingLayout(this)); } void process(const EventHandler& events) override; - void pickRect() override; - void draw(Canvas& canvas) override; - RectF resizeHandleRect(); [[nodiscard]] bool needsNextFrame() const override; @@ -28,14 +24,8 @@ namespace tp { [[nodiscard]] bool isFloating() const; private: - bool mIsFloating = false; - bool mIsResizing = false; - - halnf mHandleSize = 10; - halnf mHandlePadding = 2; - - Vec2F mPointerStart; - Vec2F mPointerCurrent; + FloatingLayout* layout(); + [[nodiscard]] const FloatingLayout* layout() const; }; class FloatingMenu : public FloatingWidget { @@ -53,8 +43,8 @@ namespace tp { mHeader.setSizePolicy(SizePolicy::Expanding, SizePolicy::Minimal); mBodyLayout.setSizePolicy(SizePolicy::Expanding, SizePolicy::Expanding); - setLayoutPolicy(LayoutPolicy::Vertical); - mBodyLayout.setLayoutPolicy(LayoutPolicy::Vertical); + // getLayout()->setLayoutPolicy(LayoutPolicy::Vertical); + // mBodyLayout.getLayout()->setLayoutPolicy(LayoutPolicy::Vertical); } public: diff --git a/WidgetsNew/public/LayoutPolicies.hpp b/WidgetsNew/public/LayoutManager.hpp similarity index 83% rename from WidgetsNew/public/LayoutPolicies.hpp rename to WidgetsNew/public/LayoutManager.hpp index 14d9939..5eecbff 100644 --- a/WidgetsNew/public/LayoutPolicies.hpp +++ b/WidgetsNew/public/LayoutManager.hpp @@ -26,15 +26,39 @@ namespace tp { virtual void pickRect() = 0; virtual void clampRect() = 0; virtual void adjustChildrenRect() = 0; + virtual RectF getAvailableChildArea() const; - protected: + public: + const Vec2F& getMinSize(); + void setMinSize(const Vec2F& size); + + const Vec2& getSizePolicy() const; + void setSizePolicy(SizePolicy x, SizePolicy y); + + public: [[nodiscard]] const RectF& getArea() const; + RectF getAnimatedArea() const; + void setArea(const RectF& area); [[nodiscard]] Widget* parent() const; [[nodiscard]] const std::vector& children() const; + public: + void clampMinMaxSize(); + + [[nodiscard]] RangeF pickRange(const RangeF& current, const RangeF& child, const RangeF& parent, bool v) const; + [[nodiscard]] RangeF clampRange(const RangeF& current, const RangeF& child, const RangeF& parent, bool v) const; + + [[nodiscard]] RectF getChildrenEnclosure() const; + [[nodiscard]] RectF getParentEnclosure() const; + private: Widget* mWidget = nullptr; + + protected: + Vec2 mSizePolicy = { SizePolicy::Fixed, SizePolicy::Fixed }; + Vec2F mMinSize = { 50, 50 }; + Vec2F mMaxSize = { FLT_MAX / 2, FLT_MAX / 2 }; }; class BasicLayout : public WidgetLayout { @@ -44,31 +68,22 @@ namespace tp { void pickRect() override; void clampRect() override; void adjustChildrenRect() override; - - public: - const Vec2F& getMinSize(); - void setMinSize(const Vec2F& size); + RectF getAvailableChildArea() const override; private: void adjustLayout(bool vertical); static halnf changeChildSize(Widget*, halnf diff, bool vertical); - [[nodiscard]] RangeF pickRange(const RangeF& current, const RangeF& child, const RangeF& parent, bool v) const; - [[nodiscard]] RangeF clampRange(const RangeF& current, const RangeF& child, const RangeF& parent, bool v) const; - - void clampMinMaxSize(); - - [[nodiscard]] RectF getChildrenEnclosure() const; - [[nodiscard]] RectF getParentEnclosure() const; - private: LayoutPolicy mLayoutPolicy = LayoutPolicy::Vertical; - Vec2 mSizePolicy = { SizePolicy::Fixed, SizePolicy::Fixed }; - - Vec2F mMinSize = { 50, 50 }; - Vec2F mMaxSize = { FLT_MAX / 2, FLT_MAX / 2 }; - halnf mLayoutGap = 5; halnf mLayoutMargin = 10; }; + + class LayoutManager { + public: + LayoutManager() = default; + + void adjust(Widget* root); + }; } \ No newline at end of file diff --git a/WidgetsNew/public/RootWidget.hpp b/WidgetsNew/public/RootWidget.hpp index d9f7d8a..9eb16d5 100644 --- a/WidgetsNew/public/RootWidget.hpp +++ b/WidgetsNew/public/RootWidget.hpp @@ -8,13 +8,6 @@ namespace tp { class RootWidget : public WidgetManagerInterface { - - struct ActiveTreeNode { - ActiveTreeNode* parent = nullptr; - std::set children; - Widget* widget = nullptr; - }; - public: RootWidget() { setDebug("root", RGBA(1)); } @@ -31,29 +24,32 @@ namespace tp { private: void updateTreeToProcess(); - void updateAnimations(ActiveTreeNode* iter); + void updateAnimations(); + void processLayout(); void drawRecursion(Canvas& canvas, Widget* active, const Vec2F& pos); void drawDebug(Canvas& canvas, Widget* active, const Vec2F& pos, int depthOrder); void findFocusWidget(Widget* iter, Widget** focus, const Vec2F& pointer); void handleFocusChanges(EventHandler& events); void getWidgetPath(Widget* widget, std::vector& out); - void processActiveTree(ActiveTreeNode* iter, EventHandler& events, Vec2F pos); + void processActiveTree(Widget* iter, EventHandler& events, Vec2F pos); void processFocusItems(EventHandler& events); - void adjustSizes(ActiveTreeNode* iter); - void updateAreaCache(ActiveTreeNode* iter, bool read); + + void updateAreaCache(Widget* iter, bool read); static void debugDrawWidget(Widget* widget); private: + LayoutManager mLayoutManager; + RectF mScreenArea; Widget* mRoot = nullptr; // frame to frame changes std::map mTriggeredWidgets; - std::map mWidgetsToProcess; Widget* mInFocusWidget = nullptr; bool mDebug = true; bool mDebugStopProcessing = false; bool mDebugRedrawAlways = false; + int mDebugWidgetsToProcess = 0; }; } \ No newline at end of file diff --git a/WidgetsNew/public/Widget.hpp b/WidgetsNew/public/Widget.hpp index db6c85a..b84ca5d 100644 --- a/WidgetsNew/public/Widget.hpp +++ b/WidgetsNew/public/Widget.hpp @@ -1,32 +1,41 @@ #pragma once #include "SpringAnimations.hpp" -#include "LayoutPolicies.hpp" +#include "LayoutManager.hpp" #include "EventHandler.hpp" #include "Graphics.hpp" #include +#include namespace tp { class WidgetManagerInterface; class WidgetLayout; + class LayoutManager; + class RootWidget; class Widget { - friend class RootWidget; + friend RootWidget; + friend LayoutManager; public: Widget(); virtual ~Widget(); - void addChild(Widget* child); + void addChild(Widget* child, bool front = false); void removeChild(Widget* child); void bringToFront(); void bringToBack(); void setLayout(WidgetLayout* layout); + void setSizePolicy(SizePolicy x, SizePolicy y) { getLayout()->setSizePolicy(x, y); } + WidgetLayout* getLayout(); + const WidgetLayout* getLayout() const; + + void triggerWidgetUpdate(const char* reason = nullptr); protected: virtual void process(const EventHandler& events) {} @@ -45,20 +54,34 @@ namespace tp { protected: void setDebug(const char* name, RGBA col); WidgetManagerInterface* getRoot(); - void triggerWidgetUpdate(const char* reason = nullptr); public: [[nodiscard]] RectF getArea() const; [[nodiscard]] RectF getAreaT() const; - [[nodiscard]] const RectF& getAreaCache() const; + // [[nodiscard]] const RectF& getAreaCache() const; [[nodiscard]] RectF getRelativeArea() const; [[nodiscard]] RectF getRelativeAreaT() const; - [[nodiscard]] RectF getRelativeAreaCache() const; + // [[nodiscard]] RectF getRelativeAreaCache() const; void setArea(const RectF& area); void setAreaCache(const RectF& area); + private: + using DFSAction = std::function; + + static void dfs(Widget* iter, const DFSAction& before, const DFSAction& after = [](auto){}) { + if (!iter->mNeedsProcessing) return; + + before(iter); + + for (auto child : iter->mDepthOrder) { + dfs(child.data(), before, after); + } + + after(iter); + } + protected: friend WidgetLayout; @@ -73,7 +96,10 @@ namespace tp { WidgetLayout* mLayout = nullptr; + // TODO : make bitfield processing flags bool mInFocus = false; + bool mNeedsProcessing = false; + bool mTriggered = false; // debug struct {