From 7cf3328a405284047d2701d68990a431fa808b1c Mon Sep 17 00:00:00 2001 From: IlyaShurupov Date: Mon, 14 Oct 2024 16:41:13 +0300 Subject: [PATCH] Reorganize code in widgets --- .../public/SpringAnimations.hpp | 0 Modules/public/Utils.hpp | 6 +- Modules/tests/Test.cpp | 19 ++ WidgetsNew/CMakeLists.txt | 2 +- WidgetsNew/examples/Example.cpp | 4 + WidgetsNew/private/Layout.cpp | 96 ++++++ WidgetsNew/private/RootWidget.cpp | 319 ++---------------- WidgetsNew/private/Widget.cpp | 20 +- .../BasicLayout.cpp} | 106 +----- .../private/{ => layouts}/DockLayout.cpp | 0 .../private/{ => layouts}/FloatingLayout.cpp | 0 WidgetsNew/private/managers/DebugManager.cpp | 116 +++++++ WidgetsNew/private/managers/LayoutManager.cpp | 17 + WidgetsNew/private/managers/UpdateManager.cpp | 191 +++++++++++ .../{ => widgets}/AnimationTestWidget.cpp | 0 .../private/{ => widgets}/DockWidget.cpp | 11 +- .../private/{ => widgets}/FloatingWidget.cpp | 0 .../private/{ => widgets}/SimpleWidgets.cpp | 0 .../public/{LayoutManager.hpp => Layout.hpp} | 32 +- WidgetsNew/public/RootWidget.hpp | 43 +-- WidgetsNew/public/Widget.hpp | 42 ++- WidgetsNew/public/layouts/BasicLayout.hpp | 25 ++ .../public/{ => layouts}/DockLayout.hpp | 0 .../public/{ => layouts}/FloatingLayout.hpp | 4 +- WidgetsNew/public/mangers/DebugManager.hpp | 25 ++ WidgetsNew/public/mangers/LayoutManager.hpp | 11 + WidgetsNew/public/mangers/UpdateManager.hpp | 38 +++ .../{ => widgets}/AnimationTestWidget.hpp | 0 .../public/{ => widgets}/DockWidget.hpp | 0 .../public/{ => widgets}/FloatingWidget.hpp | 4 +- .../public/{ => widgets}/SimpleWidgets.hpp | 2 +- 31 files changed, 652 insertions(+), 481 deletions(-) rename {WidgetsNew => Math}/public/SpringAnimations.hpp (100%) create mode 100644 WidgetsNew/private/Layout.cpp rename WidgetsNew/private/{LayoutManager.cpp => layouts/BasicLayout.cpp} (56%) rename WidgetsNew/private/{ => layouts}/DockLayout.cpp (100%) rename WidgetsNew/private/{ => layouts}/FloatingLayout.cpp (100%) create mode 100644 WidgetsNew/private/managers/DebugManager.cpp create mode 100644 WidgetsNew/private/managers/LayoutManager.cpp create mode 100644 WidgetsNew/private/managers/UpdateManager.cpp rename WidgetsNew/private/{ => widgets}/AnimationTestWidget.cpp (100%) rename WidgetsNew/private/{ => widgets}/DockWidget.cpp (92%) rename WidgetsNew/private/{ => widgets}/FloatingWidget.cpp (100%) rename WidgetsNew/private/{ => widgets}/SimpleWidgets.cpp (100%) rename WidgetsNew/public/{LayoutManager.hpp => Layout.hpp} (65%) create mode 100644 WidgetsNew/public/layouts/BasicLayout.hpp rename WidgetsNew/public/{ => layouts}/DockLayout.hpp (100%) rename WidgetsNew/public/{ => layouts}/FloatingLayout.hpp (88%) create mode 100644 WidgetsNew/public/mangers/DebugManager.hpp create mode 100644 WidgetsNew/public/mangers/LayoutManager.hpp create mode 100644 WidgetsNew/public/mangers/UpdateManager.hpp rename WidgetsNew/public/{ => widgets}/AnimationTestWidget.hpp (100%) rename WidgetsNew/public/{ => widgets}/DockWidget.hpp (100%) rename WidgetsNew/public/{ => widgets}/FloatingWidget.hpp (95%) rename WidgetsNew/public/{ => widgets}/SimpleWidgets.hpp (97%) diff --git a/WidgetsNew/public/SpringAnimations.hpp b/Math/public/SpringAnimations.hpp similarity index 100% rename from WidgetsNew/public/SpringAnimations.hpp rename to Math/public/SpringAnimations.hpp diff --git a/Modules/public/Utils.hpp b/Modules/public/Utils.hpp index 1035d50..0466b61 100644 --- a/Modules/public/Utils.hpp +++ b/Modules/public/Utils.hpp @@ -34,13 +34,13 @@ namespace tp { } } - bool get(int1 idx) { return mFlags & (1l << idx); } + [[nodiscard]] bool get(int1 idx) const { return mFlags & (1l << idx); } void set(int1 idx, bool val) { if (val) { - mFlags |= (1l << idx); + mFlags |= (1 << idx); } else { - mFlags &= ~(1l << idx); + mFlags &= ~(1 << idx); } } }; diff --git a/Modules/tests/Test.cpp b/Modules/tests/Test.cpp index 0dee468..6786409 100644 --- a/Modules/tests/Test.cpp +++ b/Modules/tests/Test.cpp @@ -241,4 +241,23 @@ SUITE(BaseModule) { } } +SUITE(BitFields) { + TEST(Basic) { + Bits bits; + + for (auto i = 0; i < 8; i ++) { + bits.set((int1) i, true); + CHECK(bits.get(i)); + } + + bits.set(1, false); + CHECK(!bits.get(1)); + + bits.set(3, false); + CHECK(!bits.get(3)); + + bits.set(4, false); + CHECK(!bits.get(4)); + } +} int main() { return UnitTest::RunAllTests(); } \ No newline at end of file diff --git a/WidgetsNew/CMakeLists.txt b/WidgetsNew/CMakeLists.txt index 43e03af..ffeec33 100644 --- a/WidgetsNew/CMakeLists.txt +++ b/WidgetsNew/CMakeLists.txt @@ -5,7 +5,7 @@ file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp") file(GLOB HEADERS "./public/*.hpp") add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS}) -target_include_directories(${PROJECT_NAME} PUBLIC ./public/) +target_include_directories(${PROJECT_NAME} PUBLIC ./public/ ./public/layouts ./public/mangers ./public/widgets) target_link_libraries(${PROJECT_NAME} PUBLIC Math Graphics Imgui) ### -------------------------- Applications -------------------------- ### diff --git a/WidgetsNew/examples/Example.cpp b/WidgetsNew/examples/Example.cpp index 08c4ab2..a33296e 100644 --- a/WidgetsNew/examples/Example.cpp +++ b/WidgetsNew/examples/Example.cpp @@ -45,6 +45,10 @@ public: mButton5.setAction([this]() { mDockLayout.dockWidget(&mFloatingMenu, DockLayout::LEFT); }); mButton6.setAction([this]() { mDockLayout.undockWidget(DockLayout::LEFT); }); + mButton3.setAction([this]() { mDockLayout.toggleWidgetVisibility(DockLayout::LEFT); }); + // mButton4.setAction([this]() { mDockLayout.undockWidget(DockLayout::LEFT); }); + + mButton3.setText("toggle"); mButton5.setText("dock"); mButton6.setText("undock"); diff --git a/WidgetsNew/private/Layout.cpp b/WidgetsNew/private/Layout.cpp new file mode 100644 index 0000000..bd56f95 --- /dev/null +++ b/WidgetsNew/private/Layout.cpp @@ -0,0 +1,96 @@ +#include +#include "Layout.hpp" + +#include "Widget.hpp" + +using namespace tp; + +const RectF& WidgetLayout::getArea() const { + return mWidget->mAreaCache; +} + +RectF WidgetLayout::getAnimatedArea() const { + return mWidget->getArea(); +} + +void WidgetLayout::setArea(const RectF& area) { + mWidget->setAreaCache(area); +} + +Widget* WidgetLayout::parent() const { return mWidget->mParent; } + +const std::vector& WidgetLayout::children() const { return mWidget->mChildren; } + +const Vec2F& WidgetLayout::getMinSize() { return mMinSize; } + +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; +} \ No newline at end of file diff --git a/WidgetsNew/private/RootWidget.cpp b/WidgetsNew/private/RootWidget.cpp index 966db9e..bec5a69 100644 --- a/WidgetsNew/private/RootWidget.cpp +++ b/WidgetsNew/private/RootWidget.cpp @@ -1,169 +1,70 @@ +#include "RootWidget.hpp" +#include "BasicLayout.hpp" + + #include -#include "RootWidget.hpp" - -#include "imgui.h" using namespace tp; +WidgetLayout* WidgetManagerInterface::defaultLayout(Widget* widget) { + return new BasicLayout(widget); +} + +RootWidget::RootWidget() { + setDebug("root", RGBA(1)); +} + void RootWidget::setRootWidget(Widget* widget) { mRoot = widget; widget->mParent = this; } void RootWidget::processFrame(EventHandler* events, const RectF& screenArea) { - mScreenArea = screenArea; + mRoot->setArea(screenArea); - if (mDebug) { - mScreenArea.size -= { 400, 0 }; - events->setEnableKeyEvents(true); - if (events->isPressed(InputID::K)) mDebugStopProcessing = !mDebugStopProcessing; - if (mDebugStopProcessing) return; - } - - mRoot->setArea(mScreenArea); + if (!mDebugManager.update(this, *events)) return; // construct hierarchy tree of widgets to process - updateTreeToProcess(); + mUpdateManager.updateTreeToProcess(mRoot); updateAnimations(); updateAreaCache(mRoot, true); // update all events and call all event processing callbacks - events->setEnableKeyEvents(true); - events->setCursorOrigin({ 0, 0 }); - processFocusItems(*events); - - events->setEnableKeyEvents(false); - events->setCursorOrigin({ 0, 0 }); - processActiveTree(mRoot, *events, { 0, 0 }); + mUpdateManager.processWidgets(mRoot, *events); updateAreaCache(mRoot, true); // update widget sizes base on individual size policies - processLayout(); + mLayoutManager.adjust(mRoot); updateAreaCache(mRoot, false); // trigger some widgets by moise pointer - handleFocusChanges(*events); + mUpdateManager.handleFocusChanges(mRoot, *events); // check triggered widgets for removal - erase_if(mTriggeredWidgets, [](auto iter) { - auto widget = iter.first; - auto flag = iter.second; - - if (!flag) return false; - - // if (mWidgetsToProcess.find(widget) == mWidgetsToProcess.end()) return false; - widget->updateAnimations(); - auto end = !widget->needsNextFrame(); - if (end) { - widget->endAnimations(); - widget->mDebug.triggerReason = "del"; - } - return end; - }); + mUpdateManager.clean(); } -bool RootWidget::needsUpdate() const { return !mTriggeredWidgets.empty() || mDebugRedrawAlways; } - -void RootWidget::debugDrawWidget(Widget* widget) { - - ImGui::PushID(widget); - if (ImGui::CollapsingHeader(widget->mDebug.id.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); - - // 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 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)); - // } - } - ImGui::PopID(); +bool RootWidget::needsUpdate() const { + if (mDebugManager.isRedrawAlways()) return true; + return mUpdateManager.isPendingUpdates(); } void RootWidget::drawFrame(Canvas& canvas) { - // draw from top to bottom - canvas.rect(mScreenArea, RGBA(0, 0, 0, 1)); + canvas.rect(mRoot->getAreaT(), RGBA(0, 0, 0, 1)); - // draw all tree from top to bottom drawRecursion(canvas, mRoot, { 0, 0 }); - ImGui::Checkbox("Draw debug", &mDebug); - - if (mDebug) { - drawDebug(canvas, mRoot, { 0, 0 }, 0); - - ImGui::Text("Triggered Widgets: %i", (int) mTriggeredWidgets.size()); - ImGui::Text("Widgets To Process: %i", mDebugWidgetsToProcess); - - ImGui::Text("To Toggle processing press k"); - ImGui::Checkbox("Stop processing", &mDebugStopProcessing); - ImGui::Checkbox("Force new frames", &mDebugRedrawAlways); - - if (ImGui::CollapsingHeader("Triggered")) { - if (ImGui::BeginListBox("##triggered", { -FLT_MIN, 300 })) { - for (auto widget : mTriggeredWidgets) { - debugDrawWidget(widget.first); - } - ImGui::EndListBox(); - } - } - - if (mInFocusWidget) { - if (ImGui::CollapsingHeader("Under cursor")) { - if (ImGui::BeginListBox("##under_cursor", { -FLT_MIN, 300 })) { - for (auto widget = mInFocusWidget; widget && widget != this; widget = widget->mParent) { - debugDrawWidget(widget); - } - ImGui::EndListBox(); - } - } - } - } + mDebugManager.drawDebug(this, canvas); } -void RootWidget::updateTreeToProcess() { - dfs(mRoot, [](Widget* widget) { - widget->mNeedsProcessing = false; - }); - - for (auto& [widget, flag] : mTriggeredWidgets) { - flag = true; - - 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) { + if (!active->mFlags.get(ENABLED)) return; + canvas.setOrigin(pos); canvas.pushClamp({ pos, active->getArea().size }); @@ -179,31 +80,6 @@ void RootWidget::drawRecursion(Canvas& canvas, Widget* active, const Vec2F& pos) active->drawOverlay(canvas); } -void RootWidget::drawDebug(Canvas& canvas, Widget* active, const Vec2F& pos, int depthOrder) { - auto area = RectF{ pos, active->getAreaT().size }; - - if (active->mNeedsProcessing) { - 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); - } - - 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) { - RGBA color = { 1, 0, 0, 0.3f}; - canvas.debugCross(area, color); - } - - int orderIdx = 0; - for (auto child = active->mDepthOrder.lastNode(); child; child = child->prev) { - drawDebug(canvas, child->data, pos + child->data->getAreaT().pos, orderIdx++); - } -} - void RootWidget::setWidgetArea(Widget& widget, const RectF& rect) { widget.mArea.setTargetRect(rect); widget.mArea.endAnimation(); @@ -215,85 +91,14 @@ void RootWidget::updateAnimations() { }); } -void RootWidget::getWidgetPath(Widget* widget, std::vector& out) { - if (!widget) return; - - for (auto iter = widget; iter && iter != this; iter = iter->mParent) { - out.push_back(iter); - } - - for (auto i = 0; i < out.size() / 2; i++) { - swap(out[i], out[out.size() - i - 1]); - } -} - -void RootWidget::handleFocusChanges(EventHandler& events) { - auto prevFocus = mInFocusWidget; - - events.setCursorOrigin({ 0, 0 }); - - findFocusWidget(mRoot, &mInFocusWidget, events.getPointer()); - - // if (mInFocusWidget == prevFocus) return; - if (mInFocusWidget) updateWidget(mInFocusWidget, "focus entered"); - - std::vector path2; - getWidgetPath(mInFocusWidget, path2); - size_t propLen2 = path2.size(); - for (auto i = 0; i < path2.size(); i++) { - if (!path2[i]->propagateEventsToChildren()) { - propLen2 = i + 1; - break; - } - } - - std::vector path1; - getWidgetPath(prevFocus, path1); - size_t propLen1 = path1.size(); - for (auto i = 0; i < path1.size(); i++) { - if (!path1[i]->propagateEventsToChildren()) { - propLen1 = i + 1; - break; - } - } - - size_t mostCommonIdx = 0; - if (!(path1.empty() || path2.empty())) { - while (path1[mostCommonIdx] == path2[mostCommonIdx] && mostCommonIdx < min(path1.size(), path2.size())) { - mostCommonIdx++; - } - } - mostCommonIdx--; - - for (auto i = 0; i < path1.size(); i++) { - path1[i]->mInFocus = false; - if (i > mostCommonIdx && i < propLen1) path1[i]->mouseLeave(); - } - - for (auto i = 0; i < path2.size(); i++) { - path2[i]->mInFocus = true; - if (i > mostCommonIdx && i < propLen2) path2[i]->mouseEnter(); - } -} - -void RootWidget::findFocusWidget(Widget* iter, Widget** focus, const Vec2F& pointer) { - if (!iter->mArea.getTargetRect().isInside(pointer)) return; - - *focus = iter; - - for (auto child = iter->mDepthOrder.lastNode(); child; child = child->prev) { - findFocusWidget(child->data, focus, pointer - iter->mArea.getTargetRect().pos); - } -} void RootWidget::updateWidget(Widget* widget, const char* reason) { DEBUG_ASSERT(reason) - widget->mDebug.triggerReason = reason; - mTriggeredWidgets.insert({ widget, false }); + mUpdateManager.scheduleUpdate(widget, reason); } void RootWidget::updateAreaCache(Widget* iter, bool read) { - if (!iter || !iter->mNeedsProcessing) return; + if (!iter || !iter->isUpdate()) return; if (read) { iter->mAreaCache = iter->getAreaT(); @@ -314,70 +119,4 @@ void RootWidget::updateAreaCache(Widget* iter, bool read) { for (auto child : iter->mDepthOrder) { updateAreaCache(child.data(), read); } -} - -void RootWidget::processLayout() { - mLayoutManager.adjust(mRoot); -} - -void RootWidget::processActiveTree(Widget* iter, EventHandler& events, Vec2F parent) { - if (!iter || !iter->mNeedsProcessing) return; - - auto current = parent + iter->getAreaT().pos; - - if (!iter->mInFocus) { - iter->mDebug.pGlobal = current; - - events.setCursorOrigin(current); - iter->process(events); - } - - for (auto child : iter->mDepthOrder) { - processActiveTree(child.data(), events, current); - } -} - -void RootWidget::processFocusItems(EventHandler& events) { - if (!mInFocusWidget) return; - - // FIXME : cringe - - std::vector path; - getWidgetPath(mInFocusWidget, path); - - size_t len = path.size(); - for (auto i = 0; i < len; i++) { - if (!path[i]->propagateEventsToChildren()) { - len = i + 1; - break; - } - } - - std::vector widgetGlobalPos(path.size()); - - widgetGlobalPos[0] = 0; - for (auto widget = 0; widget < path.size() - 1; widget++) { - widgetGlobalPos[widget + 1] = widgetGlobalPos[widget] + path[widget + 1]->getAreaT().pos; - // path[widget]->mGlobalPoint = widgetGlobalPos[widget]; - } - - bool eventsProcessed = false; - - for (int iter = (int) len - 1; iter >= 0; iter--) { - auto widget = path[iter]; - - events.setCursorOrigin(widgetGlobalPos[iter]); - - widget->mDebug.pGlobal = widgetGlobalPos[iter]; - - if (!eventsProcessed && widget->processesEvents()) { - events.setEnableKeyEvents(true); - widget->process(events); - - events.setEnableKeyEvents(false); - eventsProcessed = true; - } else { - widget->process(events); - } - } -} +} \ No newline at end of file diff --git a/WidgetsNew/private/Widget.cpp b/WidgetsNew/private/Widget.cpp index 95a4427..7a15368 100644 --- a/WidgetsNew/private/Widget.cpp +++ b/WidgetsNew/private/Widget.cpp @@ -6,8 +6,10 @@ using namespace tp; Widget::Widget() { mArea.setTargetRect({ 100, 100, 10, 10 }); - setLayout(new BasicLayout(this)); + setLayout(WidgetManagerInterface::defaultLayout(this)); mArea.endAnimation(); + + mFlags.set(ENABLED, true); } Widget::~Widget() { @@ -72,11 +74,13 @@ void Widget::bringToBack() { order.pushBack(node); } -void Widget::mouseEnter() { mInFocus = true; } -void Widget::mouseLeave() { mInFocus = false; } +void Widget::mouseEnter() { mFlags.set(IN_FOCUS, true); } +void Widget::mouseLeave() { mFlags.set(IN_FOCUS, false); } + bool Widget::propagateEventsToChildren() const { return true; } void Widget::setLayout(tp::WidgetLayout* layout) { + delete mLayout; mLayout = layout; triggerWidgetUpdate("chane layout"); } @@ -112,15 +116,15 @@ RectF Widget::getArea() const { return mArea.getCurrentRect(); } RectF Widget::getAreaT() const { return mArea.getTargetRect(); } -// 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 }; } - void Widget::setDebug(const char* name, RGBA col) { mDebug.id = name; mDebug.col = col; -} \ No newline at end of file +} + +void Widget::setSizePolicy(SizePolicy x, SizePolicy y) { + getLayout()->setSizePolicy(x, y); +} diff --git a/WidgetsNew/private/LayoutManager.cpp b/WidgetsNew/private/layouts/BasicLayout.cpp similarity index 56% rename from WidgetsNew/private/LayoutManager.cpp rename to WidgetsNew/private/layouts/BasicLayout.cpp index 4627cfb..5fb1e29 100644 --- a/WidgetsNew/private/LayoutManager.cpp +++ b/WidgetsNew/private/layouts/BasicLayout.cpp @@ -1,99 +1,11 @@ -#include -#include "LayoutManager.hpp" +#include "BasicLayout.hpp" #include "Widget.hpp" +#include + using namespace tp; -const RectF& WidgetLayout::getArea() const { - return mWidget->mAreaCache; -} - -RectF WidgetLayout::getAnimatedArea() const { - return mWidget->getArea(); -} - -void WidgetLayout::setArea(const RectF& area) { - mWidget->setAreaCache(area); -} - -Widget* WidgetLayout::parent() const { return mWidget->mParent; } - -const std::vector& WidgetLayout::children() const { return mWidget->mChildren; } - -const Vec2F& WidgetLayout::getMinSize() { return mMinSize; } - -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(); @@ -209,16 +121,4 @@ void BasicLayout::adjustLayout(bool vertical) { RectF BasicLayout::getAvailableChildArea() const { auto out = WidgetLayout::getAvailableChildArea(); return out.scaleFromCenter(mLayoutMargin, true); -} - -void LayoutManager::adjust(Widget* root) { - Widget::dfs( - root, - [](Widget* widget) { - widget->getLayout()->pickRect(); - }, - [](Widget* widget) { - widget->getLayout()->adjustChildrenRect(); - } - ); } \ No newline at end of file diff --git a/WidgetsNew/private/DockLayout.cpp b/WidgetsNew/private/layouts/DockLayout.cpp similarity index 100% rename from WidgetsNew/private/DockLayout.cpp rename to WidgetsNew/private/layouts/DockLayout.cpp diff --git a/WidgetsNew/private/FloatingLayout.cpp b/WidgetsNew/private/layouts/FloatingLayout.cpp similarity index 100% rename from WidgetsNew/private/FloatingLayout.cpp rename to WidgetsNew/private/layouts/FloatingLayout.cpp diff --git a/WidgetsNew/private/managers/DebugManager.cpp b/WidgetsNew/private/managers/DebugManager.cpp new file mode 100644 index 0000000..f7416fe --- /dev/null +++ b/WidgetsNew/private/managers/DebugManager.cpp @@ -0,0 +1,116 @@ +#include "DebugManager.hpp" +#include "RootWidget.hpp" + +#include "imgui.h" + +using namespace tp; + +bool DebugManager::update(RootWidget* rootWidget, EventHandler& events) { + if (mDebug) { + auto area = rootWidget->mRoot->getAreaT(); + area.size -= { 400, 0 }; + rootWidget->mRoot->setArea(area); + + events.setEnableKeyEvents(true); + if (events.isPressed(InputID::K)) mDebugStopProcessing = !mDebugStopProcessing; + if (mDebugStopProcessing) return false; + } + + return true; +} + +void DebugManager::drawDebug(RootWidget* rootWidget, Canvas& canvas) { + ImGui::Checkbox("Draw debug", &mDebug); + + auto& upd = rootWidget->mUpdateManager; + + if (mDebug) { + 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("To Toggle processing press k"); + ImGui::Checkbox("Stop processing", &mDebugStopProcessing); + ImGui::Checkbox("Force new frames", &mDebugRedrawAlways); + + 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 (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(); + } + } + } + } +} + +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}; + canvas.frame(area, color); + canvas.text((active->mDebug.id + ":" + std::to_string(depthOrder)).c_str(), area, 22, Canvas::Align::LC, 2, color); + } + + if (active->mFlags.get(Widget::IN_FOCUS)) { + if (active->isUpdate()) { + canvas.circle(pos + active->mDebug.pLocal, 5, active->mDebug.col); + canvas.circle(active->mDebug.pGlobal, 15, active->mDebug.col); + } + + RGBA color = { 1, 0, 0, 0.3f}; + canvas.debugCross(area, color); + } + + int orderIdx = 0; + for (auto child = active->mDepthOrder.lastNode(); child; child = child->prev) { + recursiveDraw(canvas, child->data, pos + child->data->getAreaT().pos, orderIdx++); + } +} + +void DebugManager::widgetMenu(Widget* widget) { + + ImGui::PushID(widget); + if (ImGui::CollapsingHeader(widget->mDebug.id.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); + + // 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 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)); + // } + } + ImGui::PopID(); +} \ No newline at end of file diff --git a/WidgetsNew/private/managers/LayoutManager.cpp b/WidgetsNew/private/managers/LayoutManager.cpp new file mode 100644 index 0000000..92a78a8 --- /dev/null +++ b/WidgetsNew/private/managers/LayoutManager.cpp @@ -0,0 +1,17 @@ +#include "LayoutManager.hpp" + +#include "Widget.hpp" + +using namespace tp; + +void LayoutManager::adjust(Widget* root) { + Widget::dfs( + root, + [](Widget* widget) { + widget->getLayout()->pickRect(); + }, + [](Widget* widget) { + widget->getLayout()->adjustChildrenRect(); + } + ); +} \ No newline at end of file diff --git a/WidgetsNew/private/managers/UpdateManager.cpp b/WidgetsNew/private/managers/UpdateManager.cpp new file mode 100644 index 0000000..c17e00a --- /dev/null +++ b/WidgetsNew/private/managers/UpdateManager.cpp @@ -0,0 +1,191 @@ +#include "UpdateManager.hpp" + +using namespace tp; + +void UpdateManager::processWidgets(Widget* root, EventHandler& events) { + events.setEnableKeyEvents(true); + events.setCursorOrigin({ 0, 0 }); + + processFocusItems(events); + + events.setEnableKeyEvents(false); + events.setCursorOrigin({ 0, 0 }); + + processActiveTree(root, events, { 0, 0 }); +} + +void UpdateManager::clean() { + erase_if(mTriggeredWidgets, [](auto iter) { + auto widget = iter.first; + auto flag = iter.second; + + if (!flag) return false; + + // if (mWidgetsToProcess.find(widget) == mWidgetsToProcess.end()) return false; + widget->updateAnimations(); + auto end = !widget->needsNextFrame(); + if (end) { + widget->endAnimations(); + widget->mDebug.triggerReason = "del"; + } + return end; + }); +} + +void UpdateManager::scheduleUpdate(Widget* widget, const char* reason) { + widget->mDebug.triggerReason = reason; + mTriggeredWidgets.insert({ widget, false }); +} + +void UpdateManager::updateTreeToProcess(Widget* root) { + Widget::dfs(root, [](Widget* widget) { + widget->mFlags.set(Widget::NEEDS_UPDATE, false); + }); + + for (auto& [widget, flag] : mTriggeredWidgets) { + flag = true; + + for (auto iter = widget; iter && iter->mParent; iter = iter->mParent) { + iter->mFlags.set(Widget::NEEDS_UPDATE, true); + } + } + + mDebugWidgetsToProcess = 0; + Widget::dfs(root, [this](Widget*) { + mDebugWidgetsToProcess++; + }); +} + +void UpdateManager::getWidgetPath(Widget* widget, std::vector& out) { + if (!widget) return; + + for (auto iter = widget; iter && iter->mParent; iter = iter->mParent) { + out.push_back(iter); + } + + for (auto i = 0; i < out.size() / 2; i++) { + swap(out[i], out[out.size() - i - 1]); + } +} + +void UpdateManager::handleFocusChanges(Widget* root, EventHandler& events) { + auto prevFocus = mInFocusWidget; + + events.setCursorOrigin({ 0, 0 }); + + findFocusWidget(root, &mInFocusWidget, events.getPointer()); + + // if (mInFocusWidget == prevFocus) return; + if (mInFocusWidget) scheduleUpdate(mInFocusWidget, "focus entered"); + + std::vector path2; + getWidgetPath(mInFocusWidget, path2); + size_t propLen2 = path2.size(); + for (auto i = 0; i < path2.size(); i++) { + if (!path2[i]->propagateEventsToChildren()) { + propLen2 = i + 1; + break; + } + } + + std::vector path1; + getWidgetPath(prevFocus, path1); + size_t propLen1 = path1.size(); + for (auto i = 0; i < path1.size(); i++) { + if (!path1[i]->propagateEventsToChildren()) { + propLen1 = i + 1; + break; + } + } + + size_t mostCommonIdx = 0; + if (!(path1.empty() || path2.empty())) { + while (path1[mostCommonIdx] == path2[mostCommonIdx] && mostCommonIdx < min(path1.size(), path2.size())) { + mostCommonIdx++; + } + } + mostCommonIdx--; + + for (auto i = 0; i < path1.size(); i++) { + path1[i]->mFlags.set(Widget::IN_FOCUS, false); + if (i > mostCommonIdx && i < propLen1) path1[i]->mouseLeave(); + } + + for (auto i = 0; i < path2.size(); i++) { + path2[i]->mFlags.set(Widget::IN_FOCUS, true); + if (i > mostCommonIdx && i < propLen2) path2[i]->mouseEnter(); + } +} + +void UpdateManager::findFocusWidget(Widget* iter, Widget** focus, const Vec2F& pointer) { + if (!iter->mArea.getTargetRect().isInside(pointer) || !iter->mFlags.get(Widget::ENABLED)) return; + + *focus = iter; + + for (auto child = iter->mDepthOrder.lastNode(); child; child = child->prev) { + findFocusWidget(child->data, focus, pointer - iter->mArea.getTargetRect().pos); + } +} + +void UpdateManager::processActiveTree(Widget* iter, EventHandler& events, Vec2F parent) { + if (!iter || !iter->isUpdate()) return; + + auto current = parent + iter->getAreaT().pos; + + if (!iter->mFlags.get(Widget::IN_FOCUS)) { + iter->mDebug.pGlobal = current; + + events.setCursorOrigin(current); + iter->process(events); + } + + for (auto child : iter->mDepthOrder) { + processActiveTree(child.data(), events, current); + } +} + +void UpdateManager::processFocusItems(EventHandler& events) { + if (!mInFocusWidget) return; + + // FIXME : cringe + + std::vector path; + getWidgetPath(mInFocusWidget, path); + + size_t len = path.size(); + for (auto i = 0; i < len; i++) { + if (!path[i]->propagateEventsToChildren()) { + len = i + 1; + break; + } + } + + std::vector widgetGlobalPos(path.size()); + + widgetGlobalPos[0] = 0; + for (auto widget = 0; widget < path.size() - 1; widget++) { + widgetGlobalPos[widget + 1] = widgetGlobalPos[widget] + path[widget + 1]->getAreaT().pos; + // path[widget]->mGlobalPoint = widgetGlobalPos[widget]; + } + + bool eventsProcessed = false; + + for (int iter = (int) len - 1; iter >= 0; iter--) { + auto widget = path[iter]; + + events.setCursorOrigin(widgetGlobalPos[iter]); + + widget->mDebug.pGlobal = widgetGlobalPos[iter]; + + if (!eventsProcessed && widget->processesEvents()) { + events.setEnableKeyEvents(true); + widget->process(events); + + events.setEnableKeyEvents(false); + eventsProcessed = true; + } else { + widget->process(events); + } + } +} + diff --git a/WidgetsNew/private/AnimationTestWidget.cpp b/WidgetsNew/private/widgets/AnimationTestWidget.cpp similarity index 100% rename from WidgetsNew/private/AnimationTestWidget.cpp rename to WidgetsNew/private/widgets/AnimationTestWidget.cpp diff --git a/WidgetsNew/private/DockWidget.cpp b/WidgetsNew/private/widgets/DockWidget.cpp similarity index 92% rename from WidgetsNew/private/DockWidget.cpp rename to WidgetsNew/private/widgets/DockWidget.cpp index e655231..1d9c0a6 100644 --- a/WidgetsNew/private/DockWidget.cpp +++ b/WidgetsNew/private/widgets/DockWidget.cpp @@ -3,7 +3,8 @@ using namespace tp; -DockWidget::DockWidget() { +DockWidget::DockWidget() : Widget() { + setDebug("dock", {}); setLayout(new DockLayout(this)); } @@ -39,7 +40,13 @@ void DockWidget::setCenterWidget(Widget* widget) { } void DockWidget::toggleWidgetVisibility(DockLayout::Side side) { - layout()->toggleWidgetVisibility(side); + if (layout()->sideExists(side)) { + auto widget = layout()->getSideWidget(side); + widget->setEnabled(!layout()->isSideVisible(side)); + widget->bringToBack(); + + layout()->toggleWidgetVisibility(side); + } } void DockWidget::process(const EventHandler& events) { diff --git a/WidgetsNew/private/FloatingWidget.cpp b/WidgetsNew/private/widgets/FloatingWidget.cpp similarity index 100% rename from WidgetsNew/private/FloatingWidget.cpp rename to WidgetsNew/private/widgets/FloatingWidget.cpp diff --git a/WidgetsNew/private/SimpleWidgets.cpp b/WidgetsNew/private/widgets/SimpleWidgets.cpp similarity index 100% rename from WidgetsNew/private/SimpleWidgets.cpp rename to WidgetsNew/private/widgets/SimpleWidgets.cpp diff --git a/WidgetsNew/public/LayoutManager.hpp b/WidgetsNew/public/Layout.hpp similarity index 65% rename from WidgetsNew/public/LayoutManager.hpp rename to WidgetsNew/public/Layout.hpp index 5eecbff..7508523 100644 --- a/WidgetsNew/public/LayoutManager.hpp +++ b/WidgetsNew/public/Layout.hpp @@ -26,18 +26,18 @@ namespace tp { virtual void pickRect() = 0; virtual void clampRect() = 0; virtual void adjustChildrenRect() = 0; - virtual RectF getAvailableChildArea() const; + [[nodiscard]] virtual RectF getAvailableChildArea() const; public: const Vec2F& getMinSize(); void setMinSize(const Vec2F& size); - const Vec2& getSizePolicy() const; + [[nodiscard]] const Vec2& getSizePolicy() const; void setSizePolicy(SizePolicy x, SizePolicy y); public: [[nodiscard]] const RectF& getArea() const; - RectF getAnimatedArea() const; + [[nodiscard]] RectF getAnimatedArea() const; void setArea(const RectF& area); [[nodiscard]] Widget* parent() const; @@ -60,30 +60,4 @@ namespace tp { Vec2F mMinSize = { 50, 50 }; Vec2F mMaxSize = { FLT_MAX / 2, FLT_MAX / 2 }; }; - - class BasicLayout : public WidgetLayout { - public: - explicit BasicLayout(Widget* widget) : WidgetLayout(widget) {} - - void pickRect() override; - void clampRect() override; - void adjustChildrenRect() override; - RectF getAvailableChildArea() const override; - - private: - void adjustLayout(bool vertical); - static halnf changeChildSize(Widget*, halnf diff, bool vertical); - - private: - LayoutPolicy mLayoutPolicy = LayoutPolicy::Vertical; - 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 9eb16d5..94f577e 100644 --- a/WidgetsNew/public/RootWidget.hpp +++ b/WidgetsNew/public/RootWidget.hpp @@ -2,54 +2,41 @@ #include "Widget.hpp" -#include -#include -#include +#include "UpdateManager.hpp" +#include "LayoutManager.hpp" +#include "DebugManager.hpp" namespace tp { class RootWidget : public WidgetManagerInterface { + friend DebugManager; + public: - RootWidget() { setDebug("root", RGBA(1)); } + RootWidget(); + // User Interface + public: void setRootWidget(Widget* widget); - void updateWidget(Widget*, const char* reason = nullptr) override; - static void setWidgetArea(Widget& widget, const RectF& rect); + // Graphic Application Interface public: void processFrame(EventHandler* events, const RectF& screenArea); void drawFrame(Canvas& canvas); - [[nodiscard]] bool needsUpdate() const; + // Internals private: - void updateTreeToProcess(); - 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(Widget* iter, EventHandler& events, Vec2F pos); - void processFocusItems(EventHandler& events); + void updateWidget(Widget*, const char* reason = nullptr) override; + void updateAnimations(); 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; - Widget* mInFocusWidget = nullptr; - - bool mDebug = true; - bool mDebugStopProcessing = false; - bool mDebugRedrawAlways = false; - int mDebugWidgetsToProcess = 0; + LayoutManager mLayoutManager; + UpdateManager mUpdateManager; + DebugManager mDebugManager; }; } \ No newline at end of file diff --git a/WidgetsNew/public/Widget.hpp b/WidgetsNew/public/Widget.hpp index b84ca5d..a0b2cc1 100644 --- a/WidgetsNew/public/Widget.hpp +++ b/WidgetsNew/public/Widget.hpp @@ -1,7 +1,8 @@ #pragma once #include "SpringAnimations.hpp" -#include "LayoutManager.hpp" + +#include "Layout.hpp" #include "EventHandler.hpp" #include "Graphics.hpp" @@ -10,14 +11,32 @@ #include namespace tp { - class WidgetManagerInterface; class WidgetLayout; + class LayoutManager; + class UpdateManager; + class DebugManager; + + class WidgetManagerInterface; class RootWidget; class Widget { friend RootWidget; + friend LayoutManager; + friend UpdateManager; + friend DebugManager; + + using BitField = Bits; + + using DFSAction = std::function; + + enum Flags : int1 { + ENABLED = 0, + NEEDS_UPDATE, + IN_FOCUS, + TRIGGERED, + }; public: Widget(); @@ -30,10 +49,12 @@ namespace tp { void bringToBack(); void setLayout(WidgetLayout* layout); - void setSizePolicy(SizePolicy x, SizePolicy y) { getLayout()->setSizePolicy(x, y); } + void setSizePolicy(SizePolicy x, SizePolicy y); + + void setEnabled(bool val) { mFlags.set(ENABLED, val); } WidgetLayout* getLayout(); - const WidgetLayout* getLayout() const; + [[nodiscard]] const WidgetLayout* getLayout() const; void triggerWidgetUpdate(const char* reason = nullptr); @@ -58,20 +79,19 @@ namespace tp { public: [[nodiscard]] RectF getArea() const; [[nodiscard]] RectF getAreaT() const; - // [[nodiscard]] const RectF& getAreaCache() const; [[nodiscard]] RectF getRelativeArea() const; [[nodiscard]] RectF getRelativeAreaT() const; - // [[nodiscard]] RectF getRelativeAreaCache() const; void setArea(const RectF& area); void setAreaCache(const RectF& area); private: - using DFSAction = std::function; + [[nodiscard]] bool isUpdate() const { return mFlags.get(ENABLED) && mFlags.get(NEEDS_UPDATE); } + [[nodiscard]] bool isDraw() const { return mFlags.get(ENABLED); } static void dfs(Widget* iter, const DFSAction& before, const DFSAction& after = [](auto){}) { - if (!iter->mNeedsProcessing) return; + if (!iter->isUpdate()) return; before(iter); @@ -96,10 +116,7 @@ namespace tp { WidgetLayout* mLayout = nullptr; - // TODO : make bitfield processing flags - bool mInFocus = false; - bool mNeedsProcessing = false; - bool mTriggered = false; + BitField mFlags; // debug struct { @@ -113,5 +130,6 @@ namespace tp { struct WidgetManagerInterface : public Widget { virtual void updateWidget(Widget*, const char* reason) = 0; + static WidgetLayout* defaultLayout(Widget* widget); }; } \ No newline at end of file diff --git a/WidgetsNew/public/layouts/BasicLayout.hpp b/WidgetsNew/public/layouts/BasicLayout.hpp new file mode 100644 index 0000000..8f96f61 --- /dev/null +++ b/WidgetsNew/public/layouts/BasicLayout.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "Layout.hpp" + +namespace tp { + + class BasicLayout : public WidgetLayout { + public: + explicit BasicLayout(Widget* widget) : WidgetLayout(widget) {} + + void pickRect() override; + void clampRect() override; + void adjustChildrenRect() override; + [[nodiscard]] RectF getAvailableChildArea() const override; + + private: + void adjustLayout(bool vertical); + static halnf changeChildSize(Widget*, halnf diff, bool vertical); + + private: + LayoutPolicy mLayoutPolicy = LayoutPolicy::Vertical; + halnf mLayoutGap = 5; + halnf mLayoutMargin = 10; + }; +} \ No newline at end of file diff --git a/WidgetsNew/public/DockLayout.hpp b/WidgetsNew/public/layouts/DockLayout.hpp similarity index 100% rename from WidgetsNew/public/DockLayout.hpp rename to WidgetsNew/public/layouts/DockLayout.hpp diff --git a/WidgetsNew/public/FloatingLayout.hpp b/WidgetsNew/public/layouts/FloatingLayout.hpp similarity index 88% rename from WidgetsNew/public/FloatingLayout.hpp rename to WidgetsNew/public/layouts/FloatingLayout.hpp index 4db0808..5501dcf 100644 --- a/WidgetsNew/public/FloatingLayout.hpp +++ b/WidgetsNew/public/layouts/FloatingLayout.hpp @@ -1,11 +1,11 @@ #pragma once -#include "LayoutManager.hpp" +#include "BasicLayout.hpp" namespace tp { class FloatingLayout : public BasicLayout { public: - FloatingLayout(Widget* widget) : + explicit FloatingLayout(Widget* widget) : BasicLayout(widget) {} public: diff --git a/WidgetsNew/public/mangers/DebugManager.hpp b/WidgetsNew/public/mangers/DebugManager.hpp new file mode 100644 index 0000000..7f6219f --- /dev/null +++ b/WidgetsNew/public/mangers/DebugManager.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "Widget.hpp" + +namespace tp { + class DebugManager { + public: + DebugManager() = default; + + bool isRedrawAlways() const { return mDebugRedrawAlways; } + bool update(RootWidget* rootWidget, EventHandler& events); + void drawDebug(RootWidget* rootWidget, Canvas& canvas); + + private: + void recursiveDraw(Canvas& canvas, Widget* active, const Vec2F& pos, int depthOrder); + + static void widgetMenu(Widget*); + + private: + // debug + bool mDebug = true; + bool mDebugStopProcessing = false; + bool mDebugRedrawAlways = false; + }; +} \ No newline at end of file diff --git a/WidgetsNew/public/mangers/LayoutManager.hpp b/WidgetsNew/public/mangers/LayoutManager.hpp new file mode 100644 index 0000000..c160789 --- /dev/null +++ b/WidgetsNew/public/mangers/LayoutManager.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include "Layout.hpp" + +namespace tp { + class LayoutManager { + public: + LayoutManager() = default; + void adjust(Widget* root); + }; +} \ No newline at end of file diff --git a/WidgetsNew/public/mangers/UpdateManager.hpp b/WidgetsNew/public/mangers/UpdateManager.hpp new file mode 100644 index 0000000..f23564f --- /dev/null +++ b/WidgetsNew/public/mangers/UpdateManager.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "Widget.hpp" + +#include + +namespace tp { + class UpdateManager { + friend DebugManager; + + public: + UpdateManager() = default; + + void scheduleUpdate(Widget* widget, const char* reason); + + [[nodiscard]] bool isPendingUpdates() const { + return !mTriggeredWidgets.empty(); + } + + void processWidgets(Widget* root, EventHandler& eventHandler); + void clean(); + + void updateTreeToProcess(Widget* root); + void handleFocusChanges(Widget* root, EventHandler& events); + + void findFocusWidget(Widget* iter, Widget** focus, const Vec2F& pointer); + static void getWidgetPath(Widget* widget, std::vector& out); + void processActiveTree(Widget* iter, EventHandler& events, Vec2F pos); + void processFocusItems(EventHandler& events); + + private: + std::map mTriggeredWidgets; + Widget* mInFocusWidget = nullptr; + + private: + int mDebugWidgetsToProcess = 0; + }; +} \ No newline at end of file diff --git a/WidgetsNew/public/AnimationTestWidget.hpp b/WidgetsNew/public/widgets/AnimationTestWidget.hpp similarity index 100% rename from WidgetsNew/public/AnimationTestWidget.hpp rename to WidgetsNew/public/widgets/AnimationTestWidget.hpp diff --git a/WidgetsNew/public/DockWidget.hpp b/WidgetsNew/public/widgets/DockWidget.hpp similarity index 100% rename from WidgetsNew/public/DockWidget.hpp rename to WidgetsNew/public/widgets/DockWidget.hpp diff --git a/WidgetsNew/public/FloatingWidget.hpp b/WidgetsNew/public/widgets/FloatingWidget.hpp similarity index 95% rename from WidgetsNew/public/FloatingWidget.hpp rename to WidgetsNew/public/widgets/FloatingWidget.hpp index f5e14fd..decba02 100644 --- a/WidgetsNew/public/FloatingWidget.hpp +++ b/WidgetsNew/public/widgets/FloatingWidget.hpp @@ -6,7 +6,7 @@ namespace tp { class FloatingWidget : public Widget { public: - FloatingWidget() { + FloatingWidget() : Widget() { setDebug("float", { 0.0, 0.9, 0.1, 1 }); setLayout(new FloatingLayout(this)); } @@ -30,7 +30,7 @@ namespace tp { class FloatingMenu : public FloatingWidget { public: - FloatingMenu() { + FloatingMenu() : FloatingWidget() { setDebug("float menu", { 0.0, 0.9, 0.1, 0.7 }); // addChild(&mMenuLayout); diff --git a/WidgetsNew/public/SimpleWidgets.hpp b/WidgetsNew/public/widgets/SimpleWidgets.hpp similarity index 97% rename from WidgetsNew/public/SimpleWidgets.hpp rename to WidgetsNew/public/widgets/SimpleWidgets.hpp index 214ea8c..91554ea 100644 --- a/WidgetsNew/public/SimpleWidgets.hpp +++ b/WidgetsNew/public/widgets/SimpleWidgets.hpp @@ -7,7 +7,7 @@ namespace tp { class LabelWidget : public Widget { public: - LabelWidget() { + LabelWidget() : Widget() { setDebug("label", { 0.1, 0.1, 0.1, 0.1 }); }