From 87d8ce84dcf28fe05a97245a15da4a58af0dbb74 Mon Sep 17 00:00:00 2001 From: IlyaShurupov Date: Mon, 18 Mar 2024 14:37:39 +0300 Subject: [PATCH] Adding new gui to Sketch3d --- Math/public/Vec.hpp | 1 + Sketch3D/applications/Entry.cpp | 4 +- Sketch3D/public/Sketch3D.hpp | 14 ++-- Sketch3D/public/Sketch3DWidget.hpp | 107 +++++++++++++++++++++++++++- Widgets/public/ButtonWidget.hpp | 12 ++++ Widgets/public/ScrollableWidget.hpp | 6 ++ 6 files changed, 134 insertions(+), 10 deletions(-) diff --git a/Math/public/Vec.hpp b/Math/public/Vec.hpp index 3e682e2..27d502d 100644 --- a/Math/public/Vec.hpp +++ b/Math/public/Vec.hpp @@ -292,6 +292,7 @@ namespace tp { Vec2 operator-(Type val) const { return Vec2(x - val, y - val); } Vec2 operator*(Type val) const { return Vec2(x * val, y * val); } Vec2 operator/(Type val) const { return Vec2(x / val, y / val); } + Vec2 operator/(Vec2 val) const { return Vec2(x / val.x, y / val.y); } // write void operator-=(Type val) { diff --git a/Sketch3D/applications/Entry.cpp b/Sketch3D/applications/Entry.cpp index 5e22f67..39d8ac5 100644 --- a/Sketch3D/applications/Entry.cpp +++ b/Sketch3D/applications/Entry.cpp @@ -13,7 +13,7 @@ void runApp() { auto window = tp::Window::createWindow(800, 600, "Window 1"); { - tp::Sketch3DWidget gui(window->getCanvas(), {1800, 1000}); + tp::Sketch3DGUI gui(window->getCanvas(), {1920, 1080}); if (window) { while (!window->shouldClose()) { @@ -47,5 +47,7 @@ int main() { runApp(); + // FIXME : leaks in stacktrace itself + binModule.deinitialize(); } \ No newline at end of file diff --git a/Sketch3D/public/Sketch3D.hpp b/Sketch3D/public/Sketch3D.hpp index 3805572..f1d5cbd 100644 --- a/Sketch3D/public/Sketch3D.hpp +++ b/Sketch3D/public/Sketch3D.hpp @@ -115,16 +115,16 @@ namespace tp { class Brush { public: String mType = "equal"; - Brush() {} + Brush() = default; virtual void sample(Project* proj, Vec2F crs, halnf pressure) {} virtual void draw(Renderer* render, const Camera* camera) {} - virtual ~Brush() {} + virtual ~Brush() = default; }; class PencilBrush : public Brush { public: PencilBrush(); - virtual ~PencilBrush(); + ~PencilBrush() override; virtual void sample(Project* proj, Vec2F crs, halnf pressure) override; virtual void draw(Renderer* render, const Camera* camera) override; @@ -147,14 +147,14 @@ namespace tp { halni mMaxPoints = 100; - Stroke* mStroke = NULL; + Stroke* mStroke = nullptr; Stroke mTempDisplayStroke; }; struct EraserBrush : public Brush { EraserBrush() { mType = "eraser"; } - virtual void sample(Project* proj, Vec2F crs, halnf pressure) override {} - virtual void draw(Renderer* render, const Camera* camera) override {} - virtual ~EraserBrush() {} + void sample(Project* proj, Vec2F crs, halnf pressure) override {} + void draw(Renderer* render, const Camera* camera) override {} + ~EraserBrush() override = default; }; } \ No newline at end of file diff --git a/Sketch3D/public/Sketch3DWidget.hpp b/Sketch3D/public/Sketch3DWidget.hpp index 36e1054..b1dec9a 100644 --- a/Sketch3D/public/Sketch3DWidget.hpp +++ b/Sketch3D/public/Sketch3DWidget.hpp @@ -12,6 +12,8 @@ namespace tp { mRenderer(renderResolution) { mImage = canvas.createImageFromTextId(mRenderer.getBuff()->texId(), mRenderer.getBuff()->getSize()); mCanvas = &canvas; + + mProject.mBackgroundColor = { 0.13f, 0.13f, 0.13f, 1.f }; } ~Sketch3DWidget() { @@ -33,9 +35,41 @@ namespace tp { crs.y /= this->mArea.w; crs = (crs - 0.5) * 2; - mProject.sample(events.pressure, this->mArea.w / this->mArea.z, crs); + // TODO : make better api for events + Vec2F absolutePos = events.getPos() - this->mArea.pos; - // mProject.setBackGroundColor(); + if (events.isPressed()) { + mAction = true; + } else if (events.isReleased()) { + mAction = false; + } + + Vec2F relativePos = ((absolutePos / this->mArea.size) - 0.5f) * 2.f; + Vec2F relativePosPrev = ((mActionPosAbsolutePrev / this->mArea.size) - 0.5f) * 2.f; + Vec2F relativeDelta = relativePos - relativePosPrev; + + switch (mMode) { + case Mode::MOVE: { + if (mAction) mProject.mCamera.move(relativePos, relativePosPrev); + break; + } + case Mode::ZOOM: { + halnf factor = absolutePos.y / mActionPosAbsolutePrev.y; + if (mAction) mProject.mCamera.zoom(factor); + break; + } + case Mode::ROTATE: { + if (mAction) mProject.mCamera.rotate(-relativeDelta.x * halnf(PI), -relativeDelta.y * halnf(PI)); + break; + } + case Mode::DRAW: { + mProject.sample(events.pressure, this->mArea.w / this->mArea.z, crs); + break; + } + default: break; + } + + mActionPosAbsolutePrev = absolutePos; } void draw(Canvas& canvas) override { @@ -44,10 +78,79 @@ namespace tp { canvas.drawImage(this->mArea, &mImage, 0, 1, 12); } + public: + enum class Mode { + MOVE, ROTATE, ZOOM, DRAW, NONE + } mMode = Mode::NONE; + + Vec2F mActionPosAbsolutePrev = { 0, 0 }; + bool mAction = false; + private: Renderer mRenderer; Project mProject; Canvas::ImageHandle mImage; Canvas* mCanvas = nullptr; }; + + template + class Sketch3DGUI : public Widget { + public: + Sketch3DGUI(Canvas& canvas, Vec2F renderResolution) : mViewport(canvas, renderResolution) { + this->createConfig("Sketch3D"); + + this->addColor("Background", "Background"); + this->addValue("Rounding", "Rounding"); + + 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 }); + + mOptions.mContents.append(mDrawButton); + mOptions.mContents.append(mMoveButton); + mOptions.mContents.append(mRotateButton); + mOptions.mContents.append(mZoomButton); + } + + void proc(const Events& events, const RectF& areaParent, const RectF& area) override { + this->mArea = area; + this->mVisible = area.isOverlap(areaParent); + if (!this->mVisible) return; + + mSplitView.proc(events, this->mArea, this->mArea); + mViewport.proc(events, this->mArea, mSplitView.getFirst()); + mOptions.proc(events, this->mArea, mSplitView.getSecond()); + + if (mDrawButton->mIsPressed) { + mViewport.mMode = Sketch3DWidget::Mode::DRAW; + } else if (mMoveButton->mIsPressed) { + mViewport.mMode = Sketch3DWidget::Mode::MOVE; + } else if (mRotateButton->mIsPressed) { + mViewport.mMode = Sketch3DWidget::Mode::ROTATE; + } else if (mZoomButton->mIsPressed) { + mViewport.mMode = Sketch3DWidget::Mode::ZOOM; + } + } + + void draw(Canvas& canvas) override { + if (!this->mVisible) return; + + canvas.rect(this->mArea, this->getColor("Background"), this->getValue("Rounding")); + + mSplitView.draw(canvas); + mViewport.draw(canvas); + mOptions.draw(canvas); + } + + private: + Sketch3DWidget mViewport; + SplitView mSplitView; + ScrollableWindow mOptions; + + ButtonWidget* mDrawButton = nullptr; + ButtonWidget* mMoveButton = nullptr; + ButtonWidget* mRotateButton = nullptr; + ButtonWidget* mZoomButton = nullptr; + }; } \ No newline at end of file diff --git a/Widgets/public/ButtonWidget.hpp b/Widgets/public/ButtonWidget.hpp index 1063b9e..7811572 100644 --- a/Widgets/public/ButtonWidget.hpp +++ b/Widgets/public/ButtonWidget.hpp @@ -8,6 +8,18 @@ namespace tp { class ButtonWidget : public Widget { public: ButtonWidget() { + this->mArea = { 0, 0, 100, 100 }; + this->createConfig("Button"); + this->addColor("Pressed", "Action"); + this->addColor("Hovered", "Interaction"); + this->addColor("Default", "Accent"); + this->addValue("Rounding", "Rounding"); + } + + ButtonWidget(const String& label, const tp::RectF& aArea) { + this->mArea = aArea; + this->mLabel.mLabel = label; + this->createConfig("Button"); this->addColor("Pressed", "Action"); this->addColor("Hovered", "Interaction"); diff --git a/Widgets/public/ScrollableWidget.hpp b/Widgets/public/ScrollableWidget.hpp index 5a9296d..3f38fdd 100644 --- a/Widgets/public/ScrollableWidget.hpp +++ b/Widgets/public/ScrollableWidget.hpp @@ -132,6 +132,12 @@ namespace tp { this->addValue("Padding", "Padding"); } + ~ScrollableWindow() { + for (auto content : mContents) { + delete content.data(); + } + } + // takes whole area void proc(const Events& events, const tp::RectF& areaParent, const tp::RectF& aArea) override { this->mArea = aArea;