From da6990ddc8b41b14ad740b2206ca7765a26d279c Mon Sep 17 00:00:00 2001 From: IlyaShurupov Date: Wed, 26 Jun 2024 11:30:02 +0300 Subject: [PATCH] Cleanup widgets --- 3DEditor/public/EditorWidget.hpp | 73 ++-- Containers/public/List.hpp | 11 +- Graphics/private/Window.cpp | 10 +- LibraryViewer/public/GUI.hpp | 23 +- Math/public/Rect.hpp | 6 + Sketch3D/public/Sketch3DWidget.hpp | 75 ++-- TODO | 3 +- Widgets/examples/ChatGUI.hpp | 16 +- Widgets/examples/SimpleGUI.cpp | 28 +- Widgets/examples/SimpleGUI.hpp | 48 ++- Widgets/private/CollapsableMenu.cpp | 13 +- Widgets/private/DockspaceWidget.cpp | 249 ------------- Widgets/private/FloatSpaceWidget.cpp | 47 +++ Widgets/private/FloatingWidget.cpp | 10 +- Widgets/private/GridLayoutWidget.cpp | 328 ++++++++++++++++++ Widgets/private/ScrollableWidget.cpp | 4 +- Widgets/private/SliderWidget.cpp | 8 +- Widgets/private/SplitViewWidget.cpp | 135 ------- Widgets/private/WidgetBase.cpp | 11 +- Widgets/private/WorkspaceWidget.cpp | 72 ++++ Widgets/public/ButtonWidget.hpp | 4 + Widgets/public/CollapsableMenu.hpp | 3 + Widgets/public/FloatingLayoutWidget.hpp | 18 + Widgets/public/FloatingWidget.hpp | 6 + ...ckspaceWidget.hpp => GridLayoutWidget.hpp} | 77 ++-- Widgets/public/SliderWidget.hpp | 1 + Widgets/public/SplitViewWidget.hpp | 47 --- Widgets/public/WidgetBase.hpp | 7 + Widgets/public/Widgets.hpp | 7 +- Widgets/public/WorkspaceWidget.hpp | 19 + 30 files changed, 705 insertions(+), 654 deletions(-) delete mode 100644 Widgets/private/DockspaceWidget.cpp create mode 100644 Widgets/private/FloatSpaceWidget.cpp create mode 100644 Widgets/private/GridLayoutWidget.cpp delete mode 100644 Widgets/private/SplitViewWidget.cpp create mode 100644 Widgets/private/WorkspaceWidget.cpp create mode 100644 Widgets/public/FloatingLayoutWidget.hpp rename Widgets/public/{DockspaceWidget.hpp => GridLayoutWidget.hpp} (51%) delete mode 100644 Widgets/public/SplitViewWidget.hpp create mode 100644 Widgets/public/WorkspaceWidget.hpp diff --git a/3DEditor/public/EditorWidget.hpp b/3DEditor/public/EditorWidget.hpp index 22a93cc..ebaf9f6 100644 --- a/3DEditor/public/EditorWidget.hpp +++ b/3DEditor/public/EditorWidget.hpp @@ -30,15 +30,15 @@ namespace tp { Canvas::ImageHandle mImage; }; - class EditorWidget : public Widget { + class EditorWidget : public WorkspaceWidget { public: EditorWidget(Canvas* canvas, Editor* editor) : mViewport(canvas, editor) { mEditor = editor; - this->mChildWidgets.pushBack(&mViewport); - this->mChildWidgets.pushBack(&mSplitView); - this->mChildWidgets.pushBack(&mSettingsWidget); + mDockSpace.addSideWidget(&mNavigationMenu, GridLayoutWidget::RIGHT); + mDockSpace.addSideWidget(&mRenderMenu, GridLayoutWidget::LEFT); + mDockSpace.setCenterWidget(&mViewport); // Render { @@ -68,55 +68,24 @@ namespace tp { mNavigationMenu.setLabel("Navigation"); } - mSettingsWidget.addWidget(&mRenderMenu); - mSettingsWidget.addWidget(&mNavigationMenu); + mRenderPathTracer.mCallback = [this]() { + mEditor->renderPathFrame(); + mEditor->setRenderType(Editor::RenderType::PATH_TRACER); + }; + + mRenderRaster.mCallback = [this]() { mEditor->setRenderType(Editor::RenderType::RASTER); }; + mRenderDeNoise.mCallback = [this]() { mEditor->denoisePathRenderBuffers(); }; + mNavigationOrbit.mCallback = [this]() { mNavigationType = ORBIT; }; + mNavigationPan.mCallback = [this]() { mNavigationType = PAN; }; + mNavigationZoom.mCallback = [this](){ mNavigationType = ZOOM; }; + mNavigationReset.mCallback = [this]() { mEditor->navigationReset(); }; } void eventProcess(const Events& events) override { - mSplitView.setArea(this->mArea); - - mViewport.setArea(mSplitView.getFirst()); - mViewport.mEnable = mSplitView.getFirstEnabled(); - - mSettingsWidget.setArea(mSplitView.getSecond()); - mSettingsWidget.mEnable = mSplitView.getSecondEnabled(); - - // render settings - { - if (mRenderPathTracer.isFired()) { - mEditor->renderPathFrame(); - mEditor->setRenderType(Editor::RenderType::PATH_TRACER); - } - - if (mRenderRaster.isFired()) { - mEditor->setRenderType(Editor::RenderType::RASTER); - } - - if (mRenderDeNoise.isFired()) { - mEditor->denoisePathRenderBuffers(); - } - } - // navigation { - if (mNavigationOrbit.isFired()) { - mNavigationType = ORBIT; - } - - if (mNavigationPan.isFired()) { - mNavigationType = PAN; - } - - if (mNavigationZoom.isFired()) { - mNavigationType = ZOOM; - } - - if (mNavigationReset.isFired()) { - mEditor->navigationReset(); - } - const auto& activeArea = mViewport.mArea; - if (this->isHolding() && activeArea.isInside(events.getPointer())) { + if (mViewport.isHolding()) { switch (mNavigationType) { case ORBIT: mEditor->navigationOrbit(events.getPointerDelta() / activeArea.size * 3); break; @@ -132,6 +101,8 @@ namespace tp { } } } + + WorkspaceWidget::eventProcess(events); } void eventDraw(Canvas& canvas) override { canvas.rect(this->mArea, mBaseColor); } @@ -144,13 +115,13 @@ namespace tp { public: Editor* mEditor = nullptr; - SplitView mSplitView; + // SplitView mSplitView; ViewportWidget mViewport; - ScrollableWindow mSettingsWidget; + // ScrollableWindow mSettingsWidget; // Controls - CollapsableMenu mRenderMenu; + FloatingWidget mRenderMenu; ButtonWidget mRenderPathTracer; ButtonWidget mRenderRaster; ButtonWidget mRenderDeNoise; @@ -158,7 +129,7 @@ namespace tp { // Navigation enum NavigationType { ORBIT, PAN, ZOOM } mNavigationType = ORBIT; - CollapsableMenu mNavigationMenu; + FloatingWidget mNavigationMenu; ButtonWidget mNavigationPan; ButtonWidget mNavigationOrbit; ButtonWidget mNavigationZoom; diff --git a/Containers/public/List.hpp b/Containers/public/List.hpp index 4d2e70e..0e57e16 100644 --- a/Containers/public/List.hpp +++ b/Containers/public/List.hpp @@ -159,15 +159,10 @@ namespace tp { } [[nodiscard]] Node* find(const TypeArg data) const { - Node* found = mFirst; - for (alni i = 0; data != found->data; i++) { - if (i == length()) return nullptr; - if (!found->next) { - return nullptr; - } - found = found->next; + for (Node* found = mFirst; found; found = found->next) { + if (data == found->data) return found; } - return found; + return nullptr; } [[nodiscard]] inline const Type& operator[](Index idx) const { diff --git a/Graphics/private/Window.cpp b/Graphics/private/Window.cpp index 4798551..bcd01e5 100644 --- a/Graphics/private/Window.cpp +++ b/Graphics/private/Window.cpp @@ -26,7 +26,8 @@ static void scrollCallback(GLFWwindow* window, double xOffset, double yOffset); Window::Window(Vec2F size, const char* title) { mContext = new Context(); - glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, 1); + // glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, 1); + // glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); // Create a window and OpenGL context mContext->window = glfwCreateWindow((int) size.x, (int) size.y, title, nullptr, nullptr); @@ -63,7 +64,8 @@ Window* Window::createWindow(Vec2F size, const char* title) { } count--; - glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_X11); + // glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_X11); + // glfwInitHint(GLFW_WAYLAND_LIBDECOR, GLFW_WAYLAND_DISABLE_LIBDECOR); // Initialize GLFW if (!glfwInit()) { @@ -89,8 +91,8 @@ void Window::destroyWindow(Window* window) { bool Window::shouldClose() const { return glfwWindowShouldClose(mContext->window); } void Window::processEvents() { - glfwPollEvents(); - // glfwWaitEvents(); + // glfwPollEvents(); + glfwWaitEvents(); checkAxisUpdates(); } diff --git a/LibraryViewer/public/GUI.hpp b/LibraryViewer/public/GUI.hpp index 95bf73a..50730f6 100644 --- a/LibraryViewer/public/GUI.hpp +++ b/LibraryViewer/public/GUI.hpp @@ -184,7 +184,7 @@ namespace tp { int filterExisting = 0; // all existing no-existing }; - class LibraryWidget : public Widget { + class LibraryWidget : public WorkspaceWidget { public: LibraryWidget(Library* lib, Player* player) { mLibrary = (lib); @@ -194,10 +194,11 @@ namespace tp { mCurrentTrackInfo.mPlayer = mPlayer; - this->mChildWidgets.pushBack(&mSplitView); - this->mChildWidgets.pushBack(&mSongList); - this->mChildWidgets.pushBack(&mCurrentTrackInfo); - this->mChildWidgets.pushBack(&mCurrentTrack); + mDockSpace.setCenterWidget(&mSongList); + mDockSpace.addSideWidget(&mCurrentTrackInfo, GridLayoutWidget::RIGHT); + + // this->mChildWidgets.pushBack(&mCurrentTrackInfo); + // this->mChildWidgets.pushBack(&mCurrentTrack); } void updateTracks() { @@ -210,9 +211,6 @@ namespace tp { void eventProcess(const Events& events) override { filter(); - mSplitView.setArea(this->mArea); - mSongList.setArea(mSplitView.getFirst()); - for (auto track : mSongList.getContent()) { auto trackWidget = (TrackWidget*) track.data(); if (trackWidget->mSelected) { @@ -220,12 +218,14 @@ namespace tp { } } - mCurrentTrackInfo.setArea(mSplitView.getSecond()); - // mCurrentTrack.proc(events, this->mArea, mSplitView.getFirst()); + + WorkspaceWidget::eventProcess(events); } - void eventDraw(Canvas& canvas) override { canvas.rect(this->mArea, { 0.1f, 0.1f, 0.1f, 1.f }); } + // void eventDraw(Canvas& canvas) override { + // canvas.rect(this->mArea, { 0.1f, 0.1f, 0.1f, 1.f }); + // } void filter() { if (!mCurrentTrackInfo.isSongFilterChanged) return; @@ -264,7 +264,6 @@ namespace tp { Buffer mTracks; - SplitView mSplitView; ScrollableWindow mSongList; TrackInfoWidget mCurrentTrackInfo; TrackWidget mCurrentTrack; diff --git a/Math/public/Rect.hpp b/Math/public/Rect.hpp index 4705736..ac4496b 100644 --- a/Math/public/Rect.hpp +++ b/Math/public/Rect.hpp @@ -245,6 +245,12 @@ namespace tp { return { x, y + abs, size.x, size.y - abs }; } + Rect getSizedFromCenter(Vec2 size) { + const auto pivot = center(); + const auto sizeHalf = size / 2; + return { pivot - sizeHalf, size }; + } + public: union { Vec2 v1; diff --git a/Sketch3D/public/Sketch3DWidget.hpp b/Sketch3D/public/Sketch3DWidget.hpp index 7229ef8..3ff027a 100644 --- a/Sketch3D/public/Sketch3DWidget.hpp +++ b/Sketch3D/public/Sketch3DWidget.hpp @@ -91,56 +91,36 @@ namespace tp { }; - class Sketch3DGUI : public Widget { + class Sketch3DGUI : public WorkspaceWidget { public: Sketch3DGUI(Canvas& canvas, Vec2F renderResolution) : - mViewport(canvas, renderResolution) { - mDrawButton = new ButtonWidget("Draw", { 0, 0, 100, 30 }); - mMoveButton = new ButtonWidget("Pan View", { 0, 0, 100, 30 }); - mRotateButton = new ButtonWidget("Rotate view", { 0, 0, 100, 30 }); - mZoomButton = new ButtonWidget("Zoom view", { 0, 0, 100, 30 }); + mViewport(canvas, renderResolution) + { - mOptions.addWidget(mDrawButton); - mOptions.addWidget(mMoveButton); - mOptions.addWidget(mRotateButton); - mOptions.addWidget(mZoomButton); + mControls.addWidgetToMenu(&mDrawButton); + mControls.addWidgetToMenu(&mMoveButton); + mControls.addWidgetToMenu(&mRotateButton); + mControls.addWidgetToMenu(&mZoomButton); - // add color sliders - mRed = new NamedSliderWidget("Red"); - mGreen = new NamedSliderWidget("Green"); - mBlue = new NamedSliderWidget("Blue"); + mColorPicker.addWidgetToMenu(&mRed); + mColorPicker.addWidgetToMenu(&mGreen); + mColorPicker.addWidgetToMenu(&mBlue); - mOptions.addWidget(mRed); - mOptions.addWidget(mGreen); - mOptions.addWidget(mBlue); + mDockSpace.setCenterWidget(&mViewport); - this->mChildWidgets.pushBack(&mViewport); - this->mChildWidgets.pushBack(&mSplitView); - this->mChildWidgets.pushBack(&mOptions); - } + mFloatingLayer.mChildWidgets.pushBack(&mControls); + mFloatingLayer.mChildWidgets.pushBack(&mColorPicker); - ~Sketch3DGUI() { - for (auto item : mOptions.getContent()) { - delete item.data(); - } + mDrawButton.mCallback = [this]() { mViewport.mMode = Sketch3DWidget::Mode::DRAW; }; + mMoveButton.mCallback = [this]() { mViewport.mMode = Sketch3DWidget::Mode::MOVE; }; + mRotateButton.mCallback = [this]() { mViewport.mMode = Sketch3DWidget::Mode::ROTATE; }; + mZoomButton.mCallback = [this]() { mViewport.mMode = Sketch3DWidget::Mode::ZOOM; }; } void eventProcess(const Events& events) override { - mSplitView.setArea(this->mArea); - mViewport.setArea(mSplitView.getFirst()); - mOptions.setArea(mSplitView.getSecond()); + WorkspaceWidget::eventProcess(events); - if (mDrawButton->isFired()) { - mViewport.mMode = Sketch3DWidget::Mode::DRAW; - } else if (mMoveButton->isFired()) { - mViewport.mMode = Sketch3DWidget::Mode::MOVE; - } else if (mRotateButton->isFired()) { - mViewport.mMode = Sketch3DWidget::Mode::ROTATE; - } else if (mZoomButton->isFired()) { - mViewport.mMode = Sketch3DWidget::Mode::ZOOM; - } - - mViewport.setColor(RGBA(mRed->mSlider.mFactor, mGreen->mSlider.mFactor, mBlue->mSlider.mFactor, 1.f)); + mViewport.setColor(RGBA(mRed.mSlider.mFactor, mGreen.mSlider.mFactor, mBlue.mSlider.mFactor, 1.f)); } void eventDraw(Canvas& canvas) override { canvas.rect(this->mArea, mBackgroundColor, mRounding); } @@ -154,17 +134,18 @@ namespace tp { private: Sketch3DWidget mViewport; - SplitView mSplitView; ScrollableWindow mOptions; - ButtonWidget* mDrawButton = nullptr; - ButtonWidget* mMoveButton = nullptr; - ButtonWidget* mRotateButton = nullptr; - ButtonWidget* mZoomButton = nullptr; + FloatingWidget mControls; + ButtonWidget mDrawButton = ButtonWidget("Draw", { 0, 0, 100, 30 }); + ButtonWidget mMoveButton = ButtonWidget("Pan", { 0, 0, 100, 30 }); + ButtonWidget mRotateButton = ButtonWidget("Orbit", { 0, 0, 100, 30 }); + ButtonWidget mZoomButton = ButtonWidget("Zoom", { 0, 0, 100, 30 }); - NamedSliderWidget* mRed = nullptr; - NamedSliderWidget* mGreen = nullptr; - NamedSliderWidget* mBlue = nullptr; + FloatingWidget mColorPicker; + NamedSliderWidget mRed = NamedSliderWidget("Red"); + NamedSliderWidget mGreen = NamedSliderWidget("Green"); + NamedSliderWidget mBlue = NamedSliderWidget("Blue"); RGBA mBackgroundColor; halnf mRounding = 0; diff --git a/TODO b/TODO index 07a8f33..d2f0156 100644 --- a/TODO +++ b/TODO @@ -67,9 +67,10 @@ Language: Make automations itself a universal tool - NFA DFA conversions Widgets: - Add tree structure interface to simplify code Add shortcuts Config cache may be static + Cleanup + Add animations LibraryViewer: artworks diff --git a/Widgets/examples/ChatGUI.hpp b/Widgets/examples/ChatGUI.hpp index 11aae17..cba4243 100644 --- a/Widgets/examples/ChatGUI.hpp +++ b/Widgets/examples/ChatGUI.hpp @@ -177,7 +177,7 @@ namespace tp { halnf mPadding = 0; }; - class ChattingWidget : public Widget { + class ChattingWidget : public GridLayoutWidget { public: ChattingWidget() { // todo : fetch code @@ -205,19 +205,10 @@ namespace tp { mActive.mHistoryView.addWidget(&message.data()); } - this->mChildWidgets.pushBack(&mSideView); - this->mChildWidgets.pushBack(&mActive); - this->mChildWidgets.pushBack(&mSplitView); + addSideWidget(&mSideView, GridLayoutWidget::RIGHT); + setCenterWidget(&mActive); } - void eventProcess(const Events& events) override { - mSplitView.setArea(this->mArea); - mSideView.setArea(mSplitView.getSecond()); - mActive.setArea(mSplitView.getFirst()); - } - - void eventDraw(Canvas& canvas) override { canvas.rect(this->mArea, mBGColor); } - void eventUpdateConfiguration(WidgetManager& wm) override { wm.setActiveId("ChattingWidget"); mBGColor = wm.getColor("Back", "Background"); @@ -227,7 +218,6 @@ namespace tp { Buffer mUsers; ScrollableWindow mSideView; ActiveChatWidget mActive; - SplitView mSplitView; RGBA mBGColor; }; diff --git a/Widgets/examples/SimpleGUI.cpp b/Widgets/examples/SimpleGUI.cpp index 1eb39de..900ec77 100644 --- a/Widgets/examples/SimpleGUI.cpp +++ b/Widgets/examples/SimpleGUI.cpp @@ -9,28 +9,7 @@ using namespace tp; class SimpleGUI : public Application { public: SimpleGUI() { - - // debug - - mGui.addSideWidget(&mButtons[0], DockSpaceWidget::BOTTOM); - mGui.addSideWidget(&mButtons[1], DockSpaceWidget::RIGHT); - - mGui.removeSideWidget(DockSpaceWidget::BOTTOM); - - mGui.addSideWidget(&mButtons[0], DockSpaceWidget::TOP); - mGui.addSideWidget(&mButtons[2], DockSpaceWidget::LEFT); - - mGui.removeSideWidget(DockSpaceWidget::TOP); - - mGui.addSideWidget(&mButtons[0], DockSpaceWidget::BOTTOM); - - mGui.addSideWidget(&mButtons[3], DockSpaceWidget::TOP); - mGui.setCenterWidget(&mButtons[4]); - - mButtons[4].mCallback = [&]() { mGui.toggleHiddenState(DockSpaceWidget::BOTTOM); }; - mButtons[0].mCallback = [&]() { mGui.toggleHiddenState(DockSpaceWidget::TOP); }; - mButtons[2].mCallback = [&]() { mGui.toggleHiddenState(DockSpaceWidget::RIGHT); }; - mButtons[3].mCallback = [&]() { mGui.toggleHiddenState(DockSpaceWidget::LEFT); }; + // mGui.mPreview = true; } void processFrame(EventHandler* eventHandler) override { @@ -49,9 +28,8 @@ public: private: WidgetManager mWidgetManager; - DockSpaceWidget mGui; - - ButtonWidget mButtons[5]; + // DockSpaceWidget mGui; + SimpleWidget3 mGui; }; int main() { diff --git a/Widgets/examples/SimpleGUI.hpp b/Widgets/examples/SimpleGUI.hpp index 636a53a..dc9ebc8 100644 --- a/Widgets/examples/SimpleGUI.hpp +++ b/Widgets/examples/SimpleGUI.hpp @@ -5,13 +5,19 @@ namespace tp { class SimpleWidget : public CollapsableMenu { public: SimpleWidget() { + this->addWidgetToMenu(&mSlider); + this->addWidgetToMenu(&mInMenuButton1); this->addWidgetToMenu(&mInMenuButton2); this->addWidgetToMenu(&mLabel); - this->addWidgetToMenu(&mSlider); mInMenuButton1.mLabel.mLabel = "Button1"; + + mInMenuButton1.mCallback = []() { + printf("asd\n"); + }; + mInMenuButton2.mLabel.mLabel = "Button2"; } @@ -23,31 +29,41 @@ namespace tp { NamedSliderWidget mSlider; }; - class SimpleWidget2 : public DockSpaceWidget { + class SimpleWidget3 : public WorkspaceWidget { public: - SimpleWidget2() { - this->mChildWidgets.pushBack(&mFloating); - mFloating.addWidgetToMenu(&mWidget); + SimpleWidget3() { - this->mChildWidgets.pushBack(&mFloating2); - mFloating2.addWidgetToMenu(&mWidget2); + mDockSpace.addSideWidget(&mButtons[0], GridLayoutWidget::BOTTOM); + mDockSpace.addSideWidget(&mButtons[1], GridLayoutWidget::RIGHT); - mFloating2.mArea = { 200, 100, 100, 100 }; + mDockSpace.removeSideWidget(GridLayoutWidget::BOTTOM); - this->mChildWidgets.pushBack(&mFloating3); - mFloating3.addWidgetToMenu(&mWidget3); + mDockSpace.addSideWidget(&mButtons[0], GridLayoutWidget::TOP); + mDockSpace.addSideWidget(&mButtons[2], GridLayoutWidget::LEFT); - mFloating3.mArea = { 400, 100, 100, 100 }; + mDockSpace.removeSideWidget(GridLayoutWidget::TOP); + + mDockSpace.addSideWidget(&mButtons[0], GridLayoutWidget::BOTTOM); + + mDockSpace.addSideWidget(&mButtons[3], GridLayoutWidget::TOP); + mDockSpace.setCenterWidget(&mButtons[4]); + + /* + mButtons[4].mCallback = [&]() { mDockSpace.toggleHiddenState(DockSpaceWidget::BOTTOM); }; + mButtons[0].mCallback = [&]() { mDockSpace.toggleHiddenState(DockSpaceWidget::TOP); }; + mButtons[2].mCallback = [&]() { mDockSpace.toggleHiddenState(DockSpaceWidget::RIGHT); }; + mButtons[3].mCallback = [&]() { mDockSpace.toggleHiddenState(DockSpaceWidget::LEFT); }; + */ + + mButtons[0].addWidgetToMenu(&mWidget); + mButtons[1].addWidgetToMenu(&mWidget2); } private: - FloatingWidget mFloating; + FloatingWidget mButtons[5]; + SimpleWidget mWidget; - - FloatingWidget mFloating2; SimpleWidget mWidget2; - - FloatingWidget mFloating3; SimpleWidget mWidget3; }; } \ No newline at end of file diff --git a/Widgets/private/CollapsableMenu.cpp b/Widgets/private/CollapsableMenu.cpp index f2a8947..75e2aa2 100644 --- a/Widgets/private/CollapsableMenu.cpp +++ b/Widgets/private/CollapsableMenu.cpp @@ -17,8 +17,12 @@ void CollapsableMenu::eventProcess(const Events&) { } void CollapsableMenu::eventDraw(Canvas& canvas) { - canvas.rect(this->mArea, mBorderColor, rounding); - canvas.rect(this->mArea.shrink(mBorderSize), mMenuColor, rounding); + if (mBorders) { + canvas.rect(this->mArea, mBorderColor, rounding); + canvas.rect(this->mArea.shrink(mBorderSize), mMenuColor, rounding); + } else { + canvas.rect(this->mArea, mMenuColor, rounding); + } } void CollapsableMenu::addWidgetToMenu(Widget* widget) { @@ -60,7 +64,8 @@ void CollapsableMenu::updateGeometry() { RectF CollapsableMenu::getHeaderRect() { RectF out = { this->mArea.pos, { this->mArea.size.x, headerHeight } }; - return out.shrink(mPadding); + if (mBorders) out = out.shrink(mPadding); + return out; } RectF CollapsableMenu::getBodyRect() { @@ -71,7 +76,7 @@ RectF CollapsableMenu::getBodyRect() { if (mAdjustHeight) out.size.y = mBody.getContentSize(); - if (mBody.getContentSize()) { + if (mBody.getContentSize() && mBorders) { out = out.shrink(mPadding); out.size.y += mPadding * 2 + 1; } diff --git a/Widgets/private/DockspaceWidget.cpp b/Widgets/private/DockspaceWidget.cpp deleted file mode 100644 index 4518606..0000000 --- a/Widgets/private/DockspaceWidget.cpp +++ /dev/null @@ -1,249 +0,0 @@ -#include "DockspaceWidget.hpp" - -using namespace tp; - -DockSpaceWidget::DockSpaceWidget() = default; - -void DockSpaceWidget::addSideWidget(Widget* widget, Side side) { - if (mSideWidgets[side]) return; - mSideWidgets[side] = widget; - for (auto& order : mSideSplitOrder) { - if (order == -1) { - order = side; - break; - } - } - mChildWidgets.pushBack(widget); - widget->mIsDocked = true; - mSideHidden[side] = false; -} - -void DockSpaceWidget::removeSideWidget(Side side) { - if (!mSideWidgets[side]) return; - - bool removed = false; - for (ualni i = 0; i < 3; i++) { - if (mSideSplitOrder[i] == side) { - removed = true; - } - if (removed) { - mSideSplitOrder[i] = mSideSplitOrder[i + 1]; - } - } - mSideSplitOrder[3] = -1; - - auto widget = mSideWidgets[side]; - mSideWidgets[side] = nullptr; - widget->mIsDocked = false; - - mChildWidgets.removeNode(mChildWidgets.find(widget)); -} - -void DockSpaceWidget::setCenterWidget(Widget* widget) { - mChildWidgets.removeNode(mChildWidgets.find(mCenterWidget)); - mCenterWidget = widget; - mChildWidgets.pushBack(mCenterWidget); -} - -void DockSpaceWidget::toggleHiddenState(DockSpaceWidget::Side side) { - if (!isSideExists(side)) return; - mSideHidden[side] = !mSideHidden[side]; -} - -void DockSpaceWidget::eventProcess(const tp::Events& events) { - updateActiveWindow(events); - - calculateSideAreas(); - calculateResizeHandles(); - // calculateHeaderAreas(); - handleResizeEvents(events); - - updateChildSideWidgets(); -} - -void DockSpaceWidget::eventDraw(Canvas& canvas) { - canvas.rect(this->mArea, mBackgroundColor, 0); - - for (auto sizeHandle : mResizeHandles) { - if (sizeHandle->active) { - canvas.rect(sizeHandle->area.shrink(mPadding / 1.5f), mResizeHandleColorActive, 0); - } else if (sizeHandle->hover) { - canvas.rect(sizeHandle->area.shrink(mPadding / 1.5f), mResizeHandleColorHovered, 0); - } - } - - for (auto& header : mSideHeaderAreas) { - canvas.rect(header, mResizeHandleColorActive, 0); - } -} - -void DockSpaceWidget::updateActiveWindow(const tp::Events& events) { - if (this->mChildWidgets.size() > 1 && events.isPressed(InputID::MOUSE1)) { - - Widget* activeChild = nullptr; - - for (auto childNode = this->mChildWidgets.firstNode(); childNode; childNode = childNode->next) { - auto child = childNode->data; - - if (child->mIsDocked) continue; - if (child->mArea.isInside(events.getPointer())) { - - mChildWidgets.detach(childNode); - mChildWidgets.pushFront(childNode); - - child->mHandlesEvents = true; - activeChild = child; - break; - } - } - - if (activeChild) { - for (auto child : this->mChildWidgets) { - if (activeChild != child.data() && !child->mIsDocked) child->mHandlesEvents = false; - } - } - } -} - -void DockSpaceWidget::calculateSideAreas() { - auto startArea = this->mArea; - for (ualni i = 0; i < 4; i++) { - const auto side = mSideSplitOrder[i]; - - if (side == -1) break; - if (mSideHidden[side]) continue; - - bool vertical = side == TOP || side == BOTTOM; - bool opposite = side == BOTTOM || side == RIGHT; - - const auto maxAbsoluteSize = startArea.size[vertical]; - const auto paddingFactor = mSideSizePadding / maxAbsoluteSize; - - mSideAbsoluteSize[side] = - clamp(mSideAbsoluteSize[side], maxAbsoluteSize * paddingFactor, maxAbsoluteSize * (1.f - paddingFactor)); - - auto factor = mSideAbsoluteSize[side] / startArea.size[vertical]; - if (opposite) factor = factor * -1 + 1; - - if (!vertical) { - const auto first = startArea.splitByFactorHL(factor); - const auto second = startArea.splitByFactorHR(factor); - mSideAreas[side] = side == LEFT ? first : second; - startArea = side == LEFT ? second : first; - } else { - const auto first = startArea.splitByFactorVT(factor); - const auto second = startArea.splitByFactorVB(factor); - mSideAreas[side] = side == TOP ? first : second; - startArea = side == TOP ? second : first; - } - - mSideAreas[side] = mSideAreas[side].shrink(mPadding); - } - - mCenterArea = startArea.shrink(mPadding); -} - -void DockSpaceWidget::calculateResizeHandles() { - mResizeHandles.clear(); - RectF rec; - - if (isSideVisible(LEFT)) { - rec = { mSideAreas[LEFT].p4(), { mPadding * 2, mSideAreas[LEFT].size.y } }; - mResizeHandles.append({ rec, LEFT, 0, mCenterArea.p3().x }); - } - if (isSideVisible(RIGHT)) { - rec = { mSideAreas[RIGHT].p1(), { mPadding * 2, mSideAreas[RIGHT].size.y } }; - rec.x -= mPadding * 2; - mResizeHandles.append({ rec, RIGHT, mCenterArea.p1().x, rec.p3().x }); - } - if (isSideVisible(TOP)) { - rec = { mSideAreas[TOP].p2(), { mSideAreas[TOP].size.x, mPadding * 2 } }; - mResizeHandles.append({ rec, TOP, 0, mCenterArea.p2().y }); - } - if (isSideVisible(BOTTOM)) { - rec = { mSideAreas[BOTTOM].p1(), { mSideAreas[BOTTOM].size.x, mPadding * 2 } }; - rec.y -= mPadding * 2; - mResizeHandles.append({ rec, BOTTOM, mCenterArea.p1().y, rec.p2().y }); - } -} - -void DockSpaceWidget::handleResizeEvents(const Events& events) { - for (auto resizeHandle : mResizeHandles) { - resizeHandle->hover = false; - if (resizeHandle->area.isInside(events.getPointerPrev())) { - resizeHandle->hover = true; - } - } - - if (events.isDown(InputID::MOUSE1)) { - for (auto resizeHandle : mResizeHandles) { - resizeHandle->active = false; - if (resizeHandle->area.isInside(events.getPointerPrev())) { - auto factorDeltaVec = events.getPointerDelta(); - halnf factorDelta = factorDeltaVec[(resizeHandle->side == TOP || resizeHandle->side == BOTTOM)]; - if (resizeHandle->side == BOTTOM || resizeHandle->side == RIGHT) factorDelta *= -1; - mSideAbsoluteSize[resizeHandle->side] += factorDelta; - resizeHandle->active = true; - } - } - } -} - -void DockSpaceWidget::updateChildSideWidgets() { - // Update Child Widgets - { - for (ualni i = 0; i < 4; i++) { - if (!isSideExists(Side(i))) continue; - - if (!isSideVisible(Side(i))) { - mSideWidgets[i]->mEnable = false; - } else { - mSideWidgets[i]->setArea(mSideAreas[i]); - mSideWidgets[i]->mEnable = true; - } - } - - if (mCenterWidget) mCenterWidget->setArea(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 DockSpaceWidget::calculateHeaderAreas() { - for (ualni i = 0; i < 4; i++) { - if (!isSideVisible(Side(i))) continue; - const auto factor = mHeaderSize / mSideAreas[i].size.y; - mSideHeaderAreas[i] = mSideAreas[i].splitByFactorVT(factor); - mSideAreas[i] = mSideAreas[i].splitByFactorVB(factor); - - mSideHeaderAreas[i].size.y -= mPadding; - } -} - -bool DockSpaceWidget::isSideVisible(DockSpaceWidget::Side side) { return mSideWidgets[side] && !mSideHidden[side]; } - -bool DockSpaceWidget::isSideExists(DockSpaceWidget::Side side) { return mSideWidgets[side]; } - - -ualni DockSpaceWidget::getVisibleSidesSize() { - ualni out = 0; - for (ualni i = 0; i < 4; i++) { - if (isSideVisible(Side(i))) out++; - } - return out; -} diff --git a/Widgets/private/FloatSpaceWidget.cpp b/Widgets/private/FloatSpaceWidget.cpp new file mode 100644 index 0000000..c3c857e --- /dev/null +++ b/Widgets/private/FloatSpaceWidget.cpp @@ -0,0 +1,47 @@ +#include "FloatingLayoutWidget.hpp" + +using namespace tp; + +FloatingLayoutWidget::FloatingLayoutWidget() = default; + +void FloatingLayoutWidget::eventProcess(const tp::Events& events) { + updateActiveWindow(events); +} + +void FloatingLayoutWidget::updateActiveWindow(const tp::Events& events) { + mIsPassThrough = true; + for (auto childNode = this->mChildWidgets.firstNode(); childNode; childNode = childNode->next) { + auto child = childNode->data; + if (child->mArea.isInside(events.getPointer())) { + mIsPassThrough = false; + } + } + + if (events.isPressed(InputID::MOUSE1)) { + + Widget* activeChild = nullptr; + + for (auto childNode = this->mChildWidgets.firstNode(); childNode; childNode = childNode->next) { + auto child = childNode->data; + + if (child->mArea.isInside(events.getPointer())) { + + mChildWidgets.detach(childNode); + mChildWidgets.pushFront(childNode); + + child->mHandlesEvents = true; + activeChild = child; + break; + } + } + + if (activeChild) { + for (auto child : this->mChildWidgets) { + if (activeChild != child.data() && !child->mIsDocked) child->mHandlesEvents = false; + } + } + + } +} + +bool FloatingLayoutWidget::handlesEvent() const { return !mIsPassThrough; } diff --git a/Widgets/private/FloatingWidget.cpp b/Widgets/private/FloatingWidget.cpp index 8adc986..e0f1cc6 100644 --- a/Widgets/private/FloatingWidget.cpp +++ b/Widgets/private/FloatingWidget.cpp @@ -12,7 +12,7 @@ void FloatingWidget::eventProcess(const Events& events) { mActionStartRelativePos = events.getPointerPrev() - this->mArea.pos; checkFloating(events); - checkResizing(events); + if (mResizable) checkResizing(events); CollapsableMenu::eventProcess(events); } @@ -20,7 +20,7 @@ void FloatingWidget::eventProcess(const Events& events) { void FloatingWidget::eventDraw(Canvas& canvas) { CollapsableMenu::eventDraw(canvas); - if (!this->getCollapsed()) { + if (!this->getCollapsed() && mResizable) { auto rect = getResizeHandle(); canvas.rect(rect, mResizeHandleColor, 0); canvas.circle(rect.pos - this->mBorderSize, rect.w, this->mMenuColor); @@ -78,3 +78,9 @@ RectF FloatingWidget::getResizeHandle() { auto pos = this->mArea.pos + this->mArea.size - size; return { pos, size }; } + +bool FloatingWidget::isFloating() const { return mFloating; } + +void FloatingWidget::stopFloating() { + mFloating = false; +} diff --git a/Widgets/private/GridLayoutWidget.cpp b/Widgets/private/GridLayoutWidget.cpp new file mode 100644 index 0000000..35df2a1 --- /dev/null +++ b/Widgets/private/GridLayoutWidget.cpp @@ -0,0 +1,328 @@ +#include "GridLayoutWidget.hpp" + +using namespace tp; + +GridLayoutWidget::GridLayoutWidget() { + mSideWidgets[0].side = LEFT; + mSideWidgets[1].side = TOP; + mSideWidgets[2].side = RIGHT; + mSideWidgets[3].side = BOTTOM; +} + +void GridLayoutWidget::addSideWidget(Widget* widget, Side side) { + if (isSideExists(side)) return; + + auto& sideWidget = mSideWidgets[side]; + sideWidget.widget = widget; + for (auto& order : mSideWidgets) { + if (order.order == -1) { + order.order = side; + break; + } + } + + sideWidget.hidden = false; + + mChildWidgets.pushBack(widget); + widget->mIsDocked = true; +} + +void GridLayoutWidget::removeSideWidget(Side side) { + if (!isSideExists(side)) return; + + bool removed = false; + for (ualni i = 0; i < 3; i++) { + if (mSideWidgets[i].order == side) { + removed = true; + } + if (removed) { + swap(mSideWidgets[i].order, mSideWidgets[i + 1].order); + } + } + mSideWidgets[3].order = -1; + + auto widget = mSideWidgets[side].widget; + widget->mIsDocked = false; + mChildWidgets.removeNode(mChildWidgets.find(widget)); + + mSideWidgets[side].widget = nullptr; +} + +void GridLayoutWidget::setCenterWidget(Widget* widget) { + mChildWidgets.removeNode(mChildWidgets.find(mCenterWidget)); + mCenterWidget = widget; + mChildWidgets.pushBack(mCenterWidget); +} + +void GridLayoutWidget::toggleHiddenState(GridLayoutWidget::Side side) { + if (!isSideExists(side)) return; + mSideWidgets[side].hidden = !mSideWidgets[side].hidden; +} + +void GridLayoutWidget::eventProcess(const tp::Events& events) { + calculateSideAreas(); + calculateResizeHandles(); + // calculateHeaderAreas(); + + handlePreview(events); + handleResizeEvents(events); + + updateChildSideWidgets(); +} + +void GridLayoutWidget::eventDraw(Canvas& canvas) { + canvas.rect(this->mArea, mBackgroundColor, 0); + + 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); + } +} + +void GridLayoutWidget::eventDrawOver(Canvas& canvas) { + if (!mPreview) return; + + 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); + } +} + +void GridLayoutWidget::calculateSideAreas() { + auto startArea = this->mArea; + for (auto& sideWidget : mSideWidgets) { + const auto side = sideWidget.order; + + if (side == -1) break; + if (!isSideVisible(Side(side))) continue; + + bool vertical = side == TOP || side == BOTTOM; + bool opposite = side == BOTTOM || side == RIGHT; + + auto& sideSize = mSideWidgets[side].absoluteSize; + + auto factor = sideSize / startArea.size[vertical]; + if (opposite) factor = factor * -1 + 1; + auto& area = mSideWidgets[side].area; + + if (!vertical) { + const auto first = startArea.splitByFactorHL(factor); + const auto second = startArea.splitByFactorHR(factor); + area = side == LEFT ? first : second; + startArea = side == LEFT ? second : first; + } else { + const auto first = startArea.splitByFactorVT(factor); + const auto second = startArea.splitByFactorVB(factor); + area = side == TOP ? first : second; + startArea = side == TOP ? second : first; + } + + area = area.shrink(mPadding); + } + + mCenterArea = startArea.shrink(mPadding); +} + +void GridLayoutWidget::calculateResizeHandles() { + RectF rec; + + if (isSideVisible(LEFT)) { + auto& side = mSideWidgets[LEFT]; + rec = { side.area.p4(), { mPadding * 2, side.area.size.y } }; + side.resizeHandle = { rec, 0, mCenterArea.p3().x }; + } + if (isSideVisible(RIGHT)) { + auto& side = mSideWidgets[RIGHT]; + rec = { side.area.p1(), { mPadding * 2, side.area.size.y } }; + rec.x -= mPadding * 2; + side.resizeHandle = { rec, 0, (this->mArea.p3() - mCenterArea.p1()).x }; + } + if (isSideVisible(TOP)) { + auto& side = mSideWidgets[TOP]; + rec = { side.area.p2(), { side.area.size.x, mPadding * 2 } }; + side.resizeHandle = { rec, 0, mCenterArea.p2().y }; + } + if (isSideVisible(BOTTOM)) { + auto& side = mSideWidgets[BOTTOM]; + rec = { side.area.p1(), { side.area.size.x, mPadding * 2 } }; + rec.y -= mPadding * 2; + side.resizeHandle = { rec, 0, (this->mArea.p3() - mCenterArea.p1()).y }; + } +} + +void GridLayoutWidget::handleResizeEvents(const Events& events) { + for (auto& sideWidget : mSideWidgets) { + auto& sideSize = sideWidget.absoluteSize; + auto& resizeHandle = sideWidget.resizeHandle; + if (resizeHandle.end < mSideSizePadding * 2) { + sideSize = resizeHandle.end / 2.f; + } else { + sideSize = clamp(sideSize, resizeHandle.start + mSideSizePadding, resizeHandle.end - mSideSizePadding); + } + } + + for (auto& sideWidget : mSideWidgets) { + sideWidget.resizeHandle.hover = false; + if (sideWidget.resizeHandle.area.isInside(events.getPointerPrev())) { + sideWidget.resizeHandle.hover = true; + } + } + + for (auto& sideWidget : mSideWidgets) { + sideWidget.resizeHandle.active = false; + } + + if (mPreview) return; + + auto resizeSideWidget = [&events](SideWidgetData& sideWidget, Vec2F deltaVec) { + halnf delta = deltaVec[(sideWidget.side == TOP || sideWidget.side == BOTTOM)]; + if (sideWidget.side == BOTTOM || sideWidget.side == RIGHT) delta *= -1; + sideWidget.absoluteSize += delta; + sideWidget.resizeHandle.active = true; + }; + + if (events.isDown(InputID::MOUSE1)) { + for (auto& sideWidget : mSideWidgets) { + if (sideWidget.resizeHandle.area.isInside(events.getPointerPrev())) { + resizeSideWidget(sideWidget, events.getPointerDelta()); + } + } + } + + if (events.isDown(InputID::LEFT_ALT)) { + const auto pointer = events.getPointerPrev(); + if (!mCenterArea.isInside(pointer)) return; + + if (events.isPressed(InputID::MOUSE1)) { + for (auto i : { 0, 1 }) { + const auto step = mCenterArea.size[i] / 3.f; + const auto rec1 = mCenterArea.pos[i]; + const auto pos = pointer[i]; + if (pos > rec1 && pos < rec1 + step) resizeType[i] = 0; + if (pos > rec1 + step && pos < rec1 + step * 2) resizeType[i] = 1; + if (pos > rec1 + step * 2) resizeType[i] = 2; + } + } else if (events.isDown(InputID::MOUSE1)) { + const auto deltaVec = events.getPointerDelta(); + + if (resizeType[0] == 0) resizeSideWidget(mSideWidgets[LEFT], deltaVec); + if (resizeType[1] == 0) resizeSideWidget(mSideWidgets[TOP], deltaVec); + if (resizeType[0] == 2) resizeSideWidget(mSideWidgets[RIGHT], deltaVec); + if (resizeType[1] == 2) resizeSideWidget(mSideWidgets[BOTTOM], deltaVec); + } + } +} + +void GridLayoutWidget::updateChildSideWidgets() { + // Update Child Widgets + { + for (ualni i = 0; i < 4; i++) { + if (!isSideExists(Side(i))) continue; + auto widget = mSideWidgets[i].widget; + + if (!isSideVisible(Side(i))) { + widget->mEnable = false; + } else { + widget->setArea(mSideWidgets[i].area); + widget->mEnable = true; + } + } + + if (mCenterWidget) mCenterWidget->setArea(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 GridLayoutWidget::calculateHeaderAreas() { + for (ualni i = 0; i < 4; i++) { + if (!isSideVisible(Side(i))) continue; + auto& area = mSideWidgets[i].area; + const auto factor = mHeaderSize / area.size.y; + mSideWidgets[i].headerArea = area.splitByFactorVT(factor); + area = area.splitByFactorVB(factor); + + mSideWidgets[i].headerArea.size.y -= mPadding; + } +} + +bool GridLayoutWidget::isSideVisible(GridLayoutWidget::Side side) { + return isSideExists(side) && !mSideWidgets[side].hidden; +} + +bool GridLayoutWidget::isSideExists(GridLayoutWidget::Side side) { return mSideWidgets[side].widget; } + +ualni GridLayoutWidget::getVisibleSidesSize() { + ualni out = 0; + for (ualni i = 0; i < 4; i++) { + if (isSideVisible(Side(i))) out++; + } + return out; +} + +GridLayoutWidget::Side GridLayoutWidget::getPreviewSide() { return mPreviewSide; } + +void GridLayoutWidget::handlePreview(const Events& events) { + if (!mPreview) { + mPreviewSide = NONE; + return; + } + + const halnf factor = 0.3; + const halnf handleFactor = 0.1; + + const auto handleSize = min(mCenterArea.size.x, mCenterArea.size.y) * handleFactor; + + 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; + default: break; + } + + sideWidget.area = sideWidget.area.shrink(mPadding * 2); + sideWidget.previewHandleArea = sideWidget.area.getSizedFromCenter({ handleSize, handleSize }); + } + + mPreviewArea = {}; + mPreviewSide = NONE; + for (auto& sideWidget : mSideWidgets) { + if (sideWidget.widget) continue; + + if (sideWidget.previewHandleArea.isInside(events.getPointer())) { + mPreviewArea = sideWidget.area; + mPreviewSide = sideWidget.side; + } + } +} \ No newline at end of file diff --git a/Widgets/private/ScrollableWidget.cpp b/Widgets/private/ScrollableWidget.cpp index 8578473..91fe2c8 100644 --- a/Widgets/private/ScrollableWidget.cpp +++ b/Widgets/private/ScrollableWidget.cpp @@ -13,7 +13,7 @@ void ScrollBarWidget::eventProcess(const Events& events) { return; } - if (events.getScrollY() != 0) { + if (events.getScrollY() != 0 && mArea.isInside(events.getPointer())) { auto offset = events.getScrollY() < 0 ? 1.0f : -1.0f; mPositionFraction += mSizeFraction * offset * 0.3f; mPositionFraction = tp::clamp(mPositionFraction, 0.f, 1.f - mSizeFraction); @@ -98,7 +98,7 @@ void ScrollableWindow::eventProcess(const Events& events) { // to account all changed geometry of child widgets for (auto widget : content) { - widget->procWrapper(events, this->mArea); + widget->procWrapper(events, mContentWidget.mVisibleArea); } updateContents(content); diff --git a/Widgets/private/SliderWidget.cpp b/Widgets/private/SliderWidget.cpp index 46a1553..4b2b68e 100644 --- a/Widgets/private/SliderWidget.cpp +++ b/Widgets/private/SliderWidget.cpp @@ -19,7 +19,8 @@ void SliderWidget::eventProcess(const Events& events) { } void SliderWidget::eventDraw(Canvas& canvas) { - canvas.rect(this->mArea, defaultColor, rounding); + canvas.rect(this->mArea, handleColor, rounding); + canvas.rect(this->mArea.shrink(borderSize), defaultColor, rounding); canvas.rect(getHandle(), handleColor, rounding); } @@ -31,8 +32,9 @@ RectF SliderWidget::getHandle() const { void SliderWidget::eventUpdateConfiguration(WidgetManager& wm) { wm.setActiveId("Slider"); defaultColor = wm.getColor("Default", "Base"); - handleColor = wm.getColor("Handle", "Accent"); - handleSize = wm.getNumber("HandleSize", 20.f); + handleColor = wm.getColor("Handle", RGBA(0.3f, 0.3f, 0.3f, 1.f)); + borderSize = wm.getNumber("BorderSize", 2); + handleSize = wm.getNumber("HandleSize", 15.f); rounding = wm.getNumber("Rounding", "Rounding"); } diff --git a/Widgets/private/SplitViewWidget.cpp b/Widgets/private/SplitViewWidget.cpp deleted file mode 100644 index 21b3260..0000000 --- a/Widgets/private/SplitViewWidget.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "SplitViewWidget.hpp" - -using namespace tp; - -SplitView::SplitView() { - mLeftLabel.mLabel = "Left"; - mRightLabel.mLabel = "Right"; - - this->mChildWidgets.pushBack(&mLeftLabel); - this->mChildWidgets.pushBack(&mRightLabel); -} - -void SplitView::eventProcess(const Events& events) { - mIsHover = getHandle().isInside(events.getPointer()); - - if (events.isPressed(InputID::MOUSE1) && mIsHover) { - mResizeInProcess = true; - } else if (events.isReleased(InputID::MOUSE1)) { - mResizeInProcess = false; - } - - if (mResizeInProcess) { - halnf pos = events.getPointer().x; - auto diff = pos - (this->mArea.x + mFactor * this->mArea.z); - mFactor += diff / this->mArea.z; - } - - mFactor = tp::clamp(mFactor, mMinSize / this->mArea.z, 1 - mMinSize / this->mArea.z); - - if (mMinSize * 2.f > this->mArea.z) { - mFactor = 0.5f; - } - - mLeftLabel.mEnable = mHeaders && mCollapsedSide != LEFT; - mRightLabel.mEnable = mHeaders && mCollapsedSide != RIGHT; - - if (mHeaders) { - mLeftLabel.setArea(getFirstHeader()); - mRightLabel.setArea(getSecondHeader()); - } - - if (mLeftLabel.isReleased()) { - mCollapsedSide = (mCollapsedSide == NONE) ? RIGHT : NONE; - } - - if (mRightLabel.isReleased()) { - mCollapsedSide = (mCollapsedSide == NONE) ? LEFT : NONE; - } -} - -void SplitView::eventDraw(Canvas& canvas) { - if (mResizeInProcess) canvas.rect(getHandle(), mResizingColor); - else if (mIsHover) canvas.rect(getHandle(), mHoveredColor); - else canvas.rect(getHandle(), mHandleColor); -} - -bool SplitView::getFirstEnabled() const { return mCollapsedSide != CollapsedSize::LEFT; } - -bool SplitView::getSecondEnabled() const { return mCollapsedSide != CollapsedSize::RIGHT; } - -RectF SplitView::getFirst() const { - Rect out = { this->mArea.x, this->mArea.y, mFactor * this->mArea.z - mHandleSize / 2.f, this->mArea.w }; - - if (mCollapsedSide == RIGHT) { - out.pos.x = this->mArea.pos.x; - out.size.x = this->mArea.size.x; - } - - if (mHeaders) { - out.pos.y += mHeaderSize; - out.size.y -= mHeaderSize; - } - - return out; -} - -RectF SplitView::getFirstHeader() const { - Rect out = { this->mArea.x, this->mArea.y, mFactor * this->mArea.z - mHandleSize / 2.f, mHeaderSize }; - - if (mCollapsedSide == RIGHT) { - out.pos.x = this->mArea.pos.x; - out.size.x = this->mArea.size.x; - } - - return out; -} - -RectF SplitView::getSecondHeader() const { - RectF out = { this->mArea.x + mFactor * this->mArea.z + mHandleSize / 2.f, - this->mArea.y, - (1.f - mFactor) * this->mArea.z - mHandleSize / 2.f, - mHeaderSize }; - - if (mCollapsedSide == LEFT) { - out.pos.x = this->mArea.pos.x; - out.size.x = this->mArea.size.x; - } - - return out; -} - -RectF SplitView::getSecond() const { - RectF out = { this->mArea.x + mFactor * this->mArea.z + mHandleSize / 2.f, - this->mArea.y, - (1.f - mFactor) * this->mArea.z - mHandleSize / 2.f, - this->mArea.w }; - - if (mCollapsedSide == LEFT) { - out.pos.x = this->mArea.pos.x; - out.size.x = this->mArea.size.x; - } - - if (mHeaders) { - out.pos.y += mHeaderSize; - out.size.y -= mHeaderSize; - } - - return out; -} - -RectF SplitView::getHandle() const { - if (mCollapsedSide != NONE) return {}; - return { this->mArea.x + mFactor * this->mArea.z - mHandleSize / 2.f, this->mArea.y, mHandleSize, this->mArea.w }; -} - -void SplitView::eventUpdateConfiguration(WidgetManager& wm) { - wm.setActiveId("SplitView"); - - mHandleColor = wm.getColor("Handle", "Accent"); - mHoveredColor = wm.getColor("Hovered", "Interaction"); - mResizingColor = wm.getColor("Resizing", "Action"); - mMinSize = wm.getNumber("Min", 200.f); - mHandleSize = wm.getNumber("HandleSize", 7.f); - mHeaderSize = wm.getNumber("HeaderSize", 30.f); -} diff --git a/Widgets/private/WidgetBase.cpp b/Widgets/private/WidgetBase.cpp index 59db281..0d7d4d2 100644 --- a/Widgets/private/WidgetBase.cpp +++ b/Widgets/private/WidgetBase.cpp @@ -22,7 +22,7 @@ void Widget::procWrapper(const Events& events, const RectF& parentArea) { eventProcess(events); for (auto child : mChildWidgets) { - child->procWrapper(events, getArea()); + child->procWrapper(events, mVisibleArea); } } } @@ -38,6 +38,8 @@ void Widget::drawWrapper(Canvas& canvas) { child->data->drawWrapper(canvas); } canvas.popClamp(); + + eventDrawOver(canvas); } void Widget::updateConfigWrapper(WidgetManager& wm) { @@ -52,6 +54,7 @@ void Widget::updateConfigWrapper(WidgetManager& wm) { void Widget::eventProcess(const Events& events) {} void Widget::eventDraw(Canvas& canvas) {} +void Widget::eventDrawOver(Canvas& canvas) {} void Widget::eventUpdateConfiguration(WidgetManager& wm) {} void Widget::eventVisible(const Events& events) {} @@ -66,6 +69,8 @@ void Widget::eventReleased(const Events& events) {} void Widget::checkVisibility(const Events& events, const RectF& parentArea) { const bool currentVisibility = parentArea.isOverlap(getArea()); + parentArea.calcIntersection(mArea, mVisibleArea); + if (currentVisibility != mVisible) { if (currentVisibility) eventVisible(events); else eventNotVisible(events); @@ -81,7 +86,7 @@ void Widget::checkVisibility(const Events& events, const RectF& parentArea) { } void Widget::checkFocus(const Events& events) { - const bool currentFocus = getArea().isInside(events.getPointer()); + const bool currentFocus = mVisibleArea.isInside(events.getPointer()); if (currentFocus != mInFocus) { if (currentFocus) eventFocusEnter(events); @@ -110,7 +115,7 @@ void Widget::checkClicked(const Events& events) { mHolding = false; } } else { - if (events.isPressed(InputID::MOUSE1)) { + if (events.isPressed(InputID::MOUSE1) && mVisibleArea.isInside(events.getPointer())) { eventPressed(events); mHolding = true; mPressed = true; diff --git a/Widgets/private/WorkspaceWidget.cpp b/Widgets/private/WorkspaceWidget.cpp new file mode 100644 index 0000000..b8b6993 --- /dev/null +++ b/Widgets/private/WorkspaceWidget.cpp @@ -0,0 +1,72 @@ +#include "WorkspaceWidget.hpp" + +using namespace tp; + +WorkspaceWidget::WorkspaceWidget() { + this->mChildWidgets.pushBack(&mFloatingLayer); + this->mChildWidgets.pushBack(&mDockSpace); +} + +void WorkspaceWidget::eventProcess(const Events& events) { + mDockSpace.setArea(this->mArea); + mFloatingLayer.setArea(this->mArea); + + mDockSpace.mPreview = false; + mDockSpace.mHandlesEvents = !mFloatingLayer.handlesEvent(); + + for (auto floatingChild : mFloatingLayer.mChildWidgets) { + auto widget = dynamic_cast(floatingChild.data()); + if (!widget) continue; + if (widget->isFloating()) { + if (widget->isReleased()) { + auto side = mDockSpace.getPreviewSide(); + if (side != GridLayoutWidget::NONE) { + mFloatingLayer.mChildWidgets.removeNode(mFloatingLayer.mChildWidgets.find(widget)); + widget->setCollapsed(true); + widget->stopFloating(); + mDockSpace.addSideWidget(widget, side); + } + } else { + mDockSpace.mHandlesEvents = true; + mDockSpace.mPreview = true; + } + } + } + + for (auto& dockedChild : mDockSpace.mSideWidgets) { + auto widget = dynamic_cast(dockedChild.widget); + if (!widget) continue; + + if (widget->isFloating()) { + mDockSpace.removeSideWidget(dockedChild.side); + mFloatingLayer.mChildWidgets.pushBack(widget); + widget->mArea.pos = events.getPointer() - 20; + widget->mArea.size = mDefaultFloatSize; + + widget->mResizable = true; + // widget->mBorders = true; + } + } + + // toggle hide state + if (events.isDown(InputID::LEFT_ALT)) { + if (events.isPressed(InputID::N1)) { + mDockSpace.toggleHiddenState(GridLayoutWidget::LEFT); + } else if (events.isPressed(InputID::N2)) { + mDockSpace.toggleHiddenState(GridLayoutWidget::TOP); + } else if (events.isPressed(InputID::N3)) { + mDockSpace.toggleHiddenState(GridLayoutWidget::RIGHT); + } else if (events.isPressed(InputID::N4)) { + mDockSpace.toggleHiddenState(GridLayoutWidget::BOTTOM); + } + } + + for (auto& dockedChild : mDockSpace.mSideWidgets) { + auto widget = dynamic_cast(dockedChild.widget); + if (!widget) continue; + + widget->setCollapsed(false); + widget->mResizable = false; + // widget->mBorders = false; + } +} \ No newline at end of file diff --git a/Widgets/public/ButtonWidget.hpp b/Widgets/public/ButtonWidget.hpp index deeee4e..160e880 100644 --- a/Widgets/public/ButtonWidget.hpp +++ b/Widgets/public/ButtonWidget.hpp @@ -7,6 +7,9 @@ namespace tp { class ButtonWidget : public Widget { + public: + // enum State { NONE, ANTICIPATION, ACTIVATED, CONFIRMED }; + public: ButtonWidget(); ButtonWidget(const std::string& label, const tp::RectF& aArea); @@ -20,6 +23,7 @@ namespace tp { public: LabelWidget mLabel; + // State mStat = NONE; RGBA pressedColor; RGBA hoveredColor; diff --git a/Widgets/public/CollapsableMenu.hpp b/Widgets/public/CollapsableMenu.hpp index e6b2dc9..4c31490 100644 --- a/Widgets/public/CollapsableMenu.hpp +++ b/Widgets/public/CollapsableMenu.hpp @@ -44,5 +44,8 @@ namespace tp { bool mCollapsed = true; bool mLocked = false; bool mAdjustHeight = true; + + public: + bool mBorders = true; }; } \ No newline at end of file diff --git a/Widgets/public/FloatingLayoutWidget.hpp b/Widgets/public/FloatingLayoutWidget.hpp new file mode 100644 index 0000000..b8c7267 --- /dev/null +++ b/Widgets/public/FloatingLayoutWidget.hpp @@ -0,0 +1,18 @@ +#include "FloatingWidget.hpp" + +namespace tp { + class FloatingLayoutWidget : public Widget { + public: + FloatingLayoutWidget(); + + void eventProcess(const Events& events) override; + + [[nodiscard]] bool handlesEvent() const; + + private: + void updateActiveWindow(const tp::Events& events); + + private: + bool mIsPassThrough = false; + }; +} \ No newline at end of file diff --git a/Widgets/public/FloatingWidget.hpp b/Widgets/public/FloatingWidget.hpp index a529db5..ca18214 100644 --- a/Widgets/public/FloatingWidget.hpp +++ b/Widgets/public/FloatingWidget.hpp @@ -11,6 +11,9 @@ namespace tp { void eventDraw(Canvas& canvas) override; void eventUpdateConfiguration(WidgetManager& wm) override; + [[nodiscard]] bool isFloating() const; + void stopFloating(); + private: void checkFloating(const Events& events); void checkResizing(const Events& events); @@ -26,5 +29,8 @@ namespace tp { bool mResizing = false; Vec2F mActionStartRelativePos = {}; + + public: + bool mResizable = true; }; } \ No newline at end of file diff --git a/Widgets/public/DockspaceWidget.hpp b/Widgets/public/GridLayoutWidget.hpp similarity index 51% rename from Widgets/public/DockspaceWidget.hpp rename to Widgets/public/GridLayoutWidget.hpp index 5eba3d0..69b867a 100644 --- a/Widgets/public/DockspaceWidget.hpp +++ b/Widgets/public/GridLayoutWidget.hpp @@ -1,25 +1,51 @@ -#include "FloatingWidget.hpp" +#include "WidgetBase.hpp" namespace tp { - class DockSpaceWidget : public Widget { + class GridLayoutWidget : public Widget { public: - enum Side { LEFT, TOP, RIGHT, BOTTOM }; + 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; + }; public: - DockSpaceWidget(); + GridLayoutWidget(); void eventProcess(const Events& events) override; void eventDraw(Canvas& canvas) override; + void eventDrawOver(Canvas& canvas) override; void addSideWidget(Widget* widget, Side side); void removeSideWidget(Side side); - void toggleHiddenState(DockSpaceWidget::Side side); + void toggleHiddenState(Side side); void setCenterWidget(Widget* widget); + Side getPreviewSide(); + private: - void updateActiveWindow(const tp::Events& events); void calculateSideAreas(); void calculateResizeHandles(); void handleResizeEvents(const Events& events); @@ -27,43 +53,36 @@ namespace tp { void calculateHeaderAreas(); - bool isSideVisible(Side side); bool isSideExists(Side side); ualni getVisibleSidesSize(); + void handlePreview(const Events& events); private: - // todo : make better grouping into structs + RectF mPreviewArea = {}; + Side mPreviewSide = NONE; + int resizeType[2] = { 0, 0 }; - Widget* mSideWidgets[4] { nullptr, nullptr, nullptr, nullptr }; + public: + SideWidgetData mSideWidgets[4]; + + private: Widget* mCenterWidget = nullptr; - - alni mSideSplitOrder[4] = { -1, -1, -1, -1 }; - halnf mSideAbsoluteSize[4] { 200, 100, 200, 100 }; - bool mSideHidden[4] { true, false, false, false }; - halnf mSideSizePadding = 50.f; - - // Geometry cache - struct ResizeHandle { - RectF area{ 0, 0, 0, 0 }; - Side side{ TOP }; - halnf start{ 0 }; - halnf end{ 0 }; - bool active = false; - bool hover = false; - }; - - Buffer mResizeHandles; - RectF mSideAreas[4]; - RectF mSideHeaderAreas[4]; RectF mCenterArea {}; - // View Parameters + // 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, 1); + + public: + bool mPreview = false; }; } \ No newline at end of file diff --git a/Widgets/public/SliderWidget.hpp b/Widgets/public/SliderWidget.hpp index 306275b..1a33970 100644 --- a/Widgets/public/SliderWidget.hpp +++ b/Widgets/public/SliderWidget.hpp @@ -24,6 +24,7 @@ namespace tp { RGBA handleColor; halnf handleSize = 0; halnf rounding = 0; + halnf borderSize = 2; }; class NamedSliderWidget : public Widget { diff --git a/Widgets/public/SplitViewWidget.hpp b/Widgets/public/SplitViewWidget.hpp deleted file mode 100644 index 4922f6a..0000000 --- a/Widgets/public/SplitViewWidget.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include "LabelWidget.hpp" - -namespace tp { - - //TODO : clean up this mess - // takes the whole parent area - class SplitView : public Widget { - public: - SplitView(); - - void eventProcess(const Events& events) override; - void eventDraw(Canvas& canvas) override; - - [[nodiscard]] bool getFirstEnabled() const; - [[nodiscard]] bool getSecondEnabled() const; - - RectF getFirst() const; - RectF getFirstHeader() const; - RectF getSecondHeader() const; - RectF getSecond() const ; - RectF getHandle() const; - - public: - void eventUpdateConfiguration(WidgetManager& wm) override; - - public: - halnf mFactor = 0.7f; - bool mResizeInProcess = false; - bool mIsHover = false; - - RGBA mHandleColor; - RGBA mHoveredColor; - RGBA mResizingColor; - halnf mMinSize = 0; - halnf mHandleSize = 0; - - // Headers - halnf mHeaderSize = 0; - bool mHeaders = false; - enum CollapsedSize { NONE, LEFT, RIGHT } mCollapsedSide = NONE; - - LabelWidget mLeftLabel; - LabelWidget mRightLabel; - }; -} \ No newline at end of file diff --git a/Widgets/public/WidgetBase.hpp b/Widgets/public/WidgetBase.hpp index 950bd10..44b3d20 100644 --- a/Widgets/public/WidgetBase.hpp +++ b/Widgets/public/WidgetBase.hpp @@ -20,7 +20,13 @@ namespace tp { void updateConfigWrapper(WidgetManager& wm); virtual void eventProcess(const Events& events); + + // draws before child widgets virtual void eventDraw(Canvas& canvas); + + // draws overlay after child widgets + virtual void eventDrawOver(Canvas& canvas); + virtual void eventUpdateConfiguration(WidgetManager& wm); virtual void eventVisible(const Events& events); @@ -52,6 +58,7 @@ namespace tp { public: RectF mArea; + RectF mVisibleArea; List mChildWidgets; diff --git a/Widgets/public/Widgets.hpp b/Widgets/public/Widgets.hpp index 4de32ca..3cd7d13 100644 --- a/Widgets/public/Widgets.hpp +++ b/Widgets/public/Widgets.hpp @@ -1,12 +1,13 @@ #pragma once +#include "Animations.hpp" #include "ButtonWidget.hpp" #include "LabelWidget.hpp" #include "ScrollableWidget.hpp" -#include "SplitViewWidget.hpp" #include "TextInputWidget.hpp" #include "SliderWidget.hpp" #include "CollapsableMenu.hpp" #include "FloatingWidget.hpp" -#include "Animations.hpp" -#include "DockspaceWidget.hpp" +#include "FloatingLayoutWidget.hpp" +#include "GridLayoutWidget.hpp" +#include "WorkspaceWidget.hpp" diff --git a/Widgets/public/WorkspaceWidget.hpp b/Widgets/public/WorkspaceWidget.hpp new file mode 100644 index 0000000..b4aa8d7 --- /dev/null +++ b/Widgets/public/WorkspaceWidget.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "Widgets.hpp" + +namespace tp { + class WorkspaceWidget : public Widget { + public: + WorkspaceWidget(); + + void eventProcess(const Events& events) override; + + protected: + GridLayoutWidget mDockSpace; + FloatingLayoutWidget mFloatingLayer; + + // Parameters + Vec2F mDefaultFloatSize = { 200, 200 }; + }; +}