From 4a557d7e5c078b1931486d07111ceb01eb08648c Mon Sep 17 00:00:00 2001 From: IlyaShurupov Date: Mon, 24 Jun 2024 22:21:10 +0300 Subject: [PATCH] gui updates --- 3DEditor/applications/Entry.cpp | 4 +- 3DEditor/public/EditorWidget.hpp | 51 +++---- Externals/CMakeLists.txt | 1 + Externals/imgui | 2 +- Graphics/examples/Example.cpp | 7 + Graphics/private/DebugGUI.cpp | 39 +++++ Graphics/private/EventHandler.cpp | 32 +++- Graphics/private/GraphicApplication.cpp | 4 +- Graphics/private/Window.cpp | 18 ++- Graphics/public/EventHandler.hpp | 6 + Graphics/public/Graphics.hpp | 4 +- Graphics/public/InputCodes.hpp | 6 +- Graphics/public/Window.hpp | 2 +- LibraryViewer/applications/Entry.cpp | 2 +- LibraryViewer/public/GUI.hpp | 23 ++- Objects/applications/GUI.cpp | 2 +- Sketch3D/applications/Entry.cpp | 2 +- Sketch3D/public/Sketch3DWidget.hpp | 49 +++--- Widgets/examples/ChatGUI.cpp | 2 +- Widgets/examples/ChatGUI.hpp | 56 +++---- Widgets/examples/SimpleGUI.cpp | 2 +- Widgets/examples/SimpleGUI.hpp | 24 ++- Widgets/private/ButtonWidget.cpp | 40 +++++ Widgets/private/CollapsableMenu.cpp | 84 ++++++++++ Widgets/private/FloatingWidget.cpp | 80 ++++++++++ Widgets/private/LabelWidget.cpp | 17 +++ Widgets/private/ScrollableWidget.cpp | 166 ++++++++++++++++++++ Widgets/private/SliderWidget.cpp | 60 ++++++++ Widgets/private/SplitViewWidget.cpp | 135 +++++++++++++++++ Widgets/private/TextInputWidget.cpp | 57 +++++++ Widgets/private/WidgetBase.cpp | 132 ++++++++++++++++ Widgets/private/WidgetManager.cpp | 74 +++++++++ Widgets/public/ButtonWidget.hpp | 48 ++---- Widgets/public/CollapsableMenu.hpp | 103 ++----------- Widgets/public/FloatingWidget.hpp | 83 +--------- Widgets/public/LabelWidget.hpp | 22 +-- Widgets/public/ScrollableWidget.hpp | 194 +++--------------------- Widgets/public/SliderWidget.hpp | 69 ++------- Widgets/public/SplitViewWidget.hpp | 151 ++---------------- Widgets/public/TextInputWidget.hpp | 57 +------ Widgets/public/WidgetBase.hpp | 156 ++++--------------- Widgets/public/WidgetManager.hpp | 75 ++------- 42 files changed, 1179 insertions(+), 962 deletions(-) create mode 100644 Widgets/private/ButtonWidget.cpp create mode 100644 Widgets/private/CollapsableMenu.cpp create mode 100644 Widgets/private/FloatingWidget.cpp create mode 100644 Widgets/private/LabelWidget.cpp create mode 100644 Widgets/private/ScrollableWidget.cpp create mode 100644 Widgets/private/SliderWidget.cpp create mode 100644 Widgets/private/SplitViewWidget.cpp create mode 100644 Widgets/private/TextInputWidget.cpp create mode 100644 Widgets/private/WidgetBase.cpp create mode 100644 Widgets/private/WidgetManager.cpp diff --git a/3DEditor/applications/Entry.cpp b/3DEditor/applications/Entry.cpp index a7dfd9d..7aa2f1d 100644 --- a/3DEditor/applications/Entry.cpp +++ b/3DEditor/applications/Entry.cpp @@ -10,7 +10,7 @@ class EditorGUI : public Application { public: EditorGUI() { auto canvas = this->mGraphics->getCanvas(); - mGui = new EditorWidget(canvas, &mEditor); + mGui = new EditorWidget(canvas, &mEditor); mEditor.loadDefaults(); @@ -33,7 +33,7 @@ public: private: Editor mEditor; WidgetManager mWidgetManager; - EditorWidget* mGui; + EditorWidget* mGui; }; int main() { diff --git a/3DEditor/public/EditorWidget.hpp b/3DEditor/public/EditorWidget.hpp index 36b32bb..22a93cc 100644 --- a/3DEditor/public/EditorWidget.hpp +++ b/3DEditor/public/EditorWidget.hpp @@ -4,8 +4,7 @@ namespace tp { - template - class ViewportWidget : public Widget { + class ViewportWidget : public Widget { public: explicit ViewportWidget(Canvas* canvas, Editor* editor) { mEditor = editor; @@ -15,9 +14,7 @@ namespace tp { ~ViewportWidget() { mCanvas->deleteImageHandle(mImage); } - void eventProcess(const Events& events) override { - mEditor->setViewportSize(this->mArea.size); - } + void eventProcess(const Events& events) override { mEditor->setViewportSize(this->mArea.size); } void eventDraw(Canvas& canvas) override { mEditor->renderViewport(); @@ -33,12 +30,10 @@ namespace tp { Canvas::ImageHandle mImage; }; - template - class EditorWidget : public Widget { + class EditorWidget : public Widget { public: EditorWidget(Canvas* canvas, Editor* editor) : - mViewport(canvas, editor) - { + mViewport(canvas, editor) { mEditor = editor; this->mChildWidgets.pushBack(&mViewport); @@ -121,11 +116,9 @@ namespace tp { } const auto& activeArea = mViewport.mArea; - if (this->isHolding() && activeArea.isInside(events.getPointer())) { + if (this->isHolding() && activeArea.isInside(events.getPointer())) { switch (mNavigationType) { - case ORBIT: - mEditor->navigationOrbit(events.getPointerDelta() / activeArea.size * 3); - break; + case ORBIT: mEditor->navigationOrbit(events.getPointerDelta() / activeArea.size * 3); break; case PAN: { @@ -135,17 +128,13 @@ namespace tp { } break; - case ZOOM: - mEditor->navigationZoom(1 + (events.getPointerDelta().y / activeArea.size.y)); - break; + case ZOOM: mEditor->navigationZoom(1 + (events.getPointerDelta().y / activeArea.size.y)); break; } } } } - void eventDraw(Canvas& canvas) override { - canvas.rect(this->mArea, mBaseColor); - } + void eventDraw(Canvas& canvas) override { canvas.rect(this->mArea, mBaseColor); } void eventUpdateConfiguration(WidgetManager& wm) override { wm.setActiveId("3DEditor"); @@ -155,25 +144,25 @@ namespace tp { public: Editor* mEditor = nullptr; - SplitView mSplitView; + SplitView mSplitView; - ViewportWidget mViewport; - ScrollableWindow mSettingsWidget; + ViewportWidget mViewport; + ScrollableWindow mSettingsWidget; // Controls - CollapsableMenu mRenderMenu; - ButtonWidget mRenderPathTracer; - ButtonWidget mRenderRaster; - ButtonWidget mRenderDeNoise; + CollapsableMenu mRenderMenu; + ButtonWidget mRenderPathTracer; + ButtonWidget mRenderRaster; + ButtonWidget mRenderDeNoise; // Navigation enum NavigationType { ORBIT, PAN, ZOOM } mNavigationType = ORBIT; - CollapsableMenu mNavigationMenu; - ButtonWidget mNavigationPan; - ButtonWidget mNavigationOrbit; - ButtonWidget mNavigationZoom; - ButtonWidget mNavigationReset; + CollapsableMenu mNavigationMenu; + ButtonWidget mNavigationPan; + ButtonWidget mNavigationOrbit; + ButtonWidget mNavigationZoom; + ButtonWidget mNavigationReset; RGBA mBaseColor; }; diff --git a/Externals/CMakeLists.txt b/Externals/CMakeLists.txt index 70947cd..ce5f9b4 100644 --- a/Externals/CMakeLists.txt +++ b/Externals/CMakeLists.txt @@ -45,6 +45,7 @@ set(${PROJECT_NAME}_SOURCES imgui/imgui_draw.cpp imgui/imgui_tables.cpp imgui/imgui_widgets.cpp + imgui/imgui_demo.cpp imgui/backends/imgui_impl_glfw.cpp imgui/backends/imgui_impl_opengl3.cpp diff --git a/Externals/imgui b/Externals/imgui index 4144d7d..7237d3e 160000 --- a/Externals/imgui +++ b/Externals/imgui @@ -1 +1 @@ -Subproject commit 4144d7d772a800f08693b8b13f7c81f1f22a73c4 +Subproject commit 7237d3e5c3a6b837b7b457460877cf5eea8c3745 diff --git a/Graphics/examples/Example.cpp b/Graphics/examples/Example.cpp index 021a159..90c5477 100644 --- a/Graphics/examples/Example.cpp +++ b/Graphics/examples/Example.cpp @@ -1,5 +1,8 @@ #include "GraphicApplication.hpp" +#include + + #include "imgui.h" using namespace tp; @@ -13,6 +16,10 @@ public: } virtual void drawFrame(Canvas* canvas) override { + glClear(GL_COLOR_BUFFER_BIT); + + ImGui::ShowDemoWindow(); + ImGui::Text("Frames processed per second: %f", this->mFramesProcessedPerSecond); ImGui::Text("Frames drawn per second: %f", this->mFramesDrawnPerSecond); } diff --git a/Graphics/private/DebugGUI.cpp b/Graphics/private/DebugGUI.cpp index 35d5061..eefaa0f 100644 --- a/Graphics/private/DebugGUI.cpp +++ b/Graphics/private/DebugGUI.cpp @@ -37,6 +37,39 @@ DebugGUI::DebugGUI(Window* window) { io.Fonts->AddFontFromFileTTF("Font.ttf", 20.f); io.ConfigInputTrickleEventQueue = false; + + // appearance + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; + + auto& colors = ImGui::GetStyle().Colors; + colors[ImGuiCol_WindowBg] = ImVec4{ 0.1f, 0.105f, 0.11f, 1.0f }; + + // Headers + colors[ImGuiCol_Header] = ImVec4{ 0.2f, 0.205f, 0.21f, 1.0f }; + colors[ImGuiCol_HeaderHovered] = ImVec4{ 0.3f, 0.305f, 0.31f, 1.0f }; + colors[ImGuiCol_HeaderActive] = ImVec4{ 0.15f, 0.1505f, 0.151f, 1.0f }; + + // Buttons + colors[ImGuiCol_Button] = ImVec4{ 0.2f, 0.205f, 0.21f, 1.0f }; + colors[ImGuiCol_ButtonHovered] = ImVec4{ 0.3f, 0.305f, 0.31f, 1.0f }; + colors[ImGuiCol_ButtonActive] = ImVec4{ 0.15f, 0.1505f, 0.151f, 1.0f }; + + // Frame BG + colors[ImGuiCol_FrameBg] = ImVec4{ 0.2f, 0.205f, 0.21f, 1.0f }; + colors[ImGuiCol_FrameBgHovered] = ImVec4{ 0.3f, 0.305f, 0.31f, 1.0f }; + colors[ImGuiCol_FrameBgActive] = ImVec4{ 0.15f, 0.1505f, 0.151f, 1.0f }; + + // Tabs + colors[ImGuiCol_Tab] = ImVec4{ 0.15f, 0.1505f, 0.151f, 1.0f }; + colors[ImGuiCol_TabHovered] = ImVec4{ 0.38f, 0.3805f, 0.381f, 1.0f }; + colors[ImGuiCol_TabActive] = ImVec4{ 0.28f, 0.2805f, 0.281f, 1.0f }; + colors[ImGuiCol_TabUnfocused] = ImVec4{ 0.15f, 0.1505f, 0.151f, 1.0f }; + colors[ImGuiCol_TabUnfocusedActive] = ImVec4{ 0.2f, 0.205f, 0.21f, 1.0f }; + + // Title + colors[ImGuiCol_TitleBg] = ImVec4{ 0.15f, 0.1505f, 0.151f, 1.0f }; + colors[ImGuiCol_TitleBgActive] = ImVec4{ 0.15f, 0.1505f, 0.151f, 1.0f }; + colors[ImGuiCol_TitleBgCollapsed] = ImVec4{ 0.15f, 0.1505f, 0.151f, 1.0f }; } DebugGUI::~DebugGUI() { @@ -47,6 +80,12 @@ DebugGUI::~DebugGUI() { delete mContext; } +void DebugGUI::procBegin() { +} + +void DebugGUI::procEnd() { +} + void DebugGUI::drawBegin() { ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); diff --git a/Graphics/private/EventHandler.cpp b/Graphics/private/EventHandler.cpp index f1f5c10..8c790ea 100644 --- a/Graphics/private/EventHandler.cpp +++ b/Graphics/private/EventHandler.cpp @@ -3,7 +3,10 @@ using namespace tp; -EventHandler::EventHandler() = default; +EventHandler::EventHandler() { + mTimerEvent.reset(); +} + EventHandler::~EventHandler() = default; void EventHandler::postEvent(InputID inputID, InputEvent inputEvent) { @@ -16,6 +19,12 @@ bool EventHandler::isEvents() { mMutex.lock(); auto res = mEventQueue.length(); mMutex.unlock(); + + if (mTimerEvent.isTimeout()) { + mTimerEvent.reset(); + res = true; + } + return res; } @@ -35,6 +44,12 @@ bool transitionsReduce[4][4] = { void EventHandler::processEvent() { mMutex.lock(); + + if (!mEventQueue.size()) { + mMutex.unlock(); + return; + } + auto lastEvent = &mEventQueue.last(); const auto& eventData = lastEvent->second; @@ -56,7 +71,7 @@ void EventHandler::processEvent() { mInputStates[(int) inputId].mCurrentState = transitions[currentState][reportedEvent]; - // printf("%i - %i \n", reportedEvent, mInputStates[(int) InputID::A].mCurrentState); + // printf("%i - %i \n", reportedEvent, mInputStates[(int) InputID::MOUSE1].mCurrentState); if (transitionsReduce[currentState][reportedEvent]) { mEventQueue.popFront(); @@ -65,6 +80,17 @@ void EventHandler::processEvent() { break; } + case InputEvent::Type::SCROLL: + { + if (mScrollDelta == Vec2F { 0, 0 }) { + mScrollDelta = eventData.scrollDelta; + } else { + mEventQueue.popFront(); + mScrollDelta = 0; + } + break; + } + default: { mEventQueue.popFront(); @@ -95,6 +121,6 @@ bool EventHandler::isDown(InputID id) const { mInputStates[(int) id].mCurrentState == InputState::State::HOLD; } -halnf EventHandler::getScrollY() const { return 0; } +halnf EventHandler::getScrollY() const { return mScrollDelta.y; } Vec2F EventHandler::getPointerDelta() const { return mPointer - mPointerPrev; } diff --git a/Graphics/private/GraphicApplication.cpp b/Graphics/private/GraphicApplication.cpp index 270c94d..145394e 100644 --- a/Graphics/private/GraphicApplication.cpp +++ b/Graphics/private/GraphicApplication.cpp @@ -35,9 +35,9 @@ void Application::run() { } while (!mWindow->shouldClose()) { - if (mProcTimer.isTimeout()) { + mWindow->processEvents(); - mWindow->processEvents(); + if (mProcTimer.isTimeout() || eventHandler->isEvents()) { while (eventHandler->isEvents()) { eventHandler->processEvent(); diff --git a/Graphics/private/Window.cpp b/Graphics/private/Window.cpp index f844e21..4798551 100644 --- a/Graphics/private/Window.cpp +++ b/Graphics/private/Window.cpp @@ -89,7 +89,8 @@ void Window::destroyWindow(Window* window) { bool Window::shouldClose() const { return glfwWindowShouldClose(mContext->window); } void Window::processEvents() { - glfwWaitEvents(); + glfwPollEvents(); + // glfwWaitEvents(); checkAxisUpdates(); } @@ -119,13 +120,13 @@ void Window::checkAxisUpdates() { double x, y; glfwGetCursorPos(mContext->window, &x, &y); - int posX, posY; - glfwGetWindowPos(mContext->window, &posX, &posY); + // int posX, posY; + // glfwGetWindowPos(mContext->window, &posX, &posY); if (mPointerPos != Vec2F{ (halnf) x, (halnf) y }) { mPointerPos = { (halnf) x, (halnf) y }; - auto pos = Vec2F{ (halnf) posX, (halnf) posY }; + // auto pos = Vec2F{ (halnf) posX, (halnf) posY }; RectF windowRec = { { 0, 0 }, mSize }; if (windowRec.isInside(mPointerPos)) { @@ -167,9 +168,16 @@ static void mouseButtonCallback(GLFWwindow* window, int button, int action, int ); } else if (action == GLFW_RELEASE) { eventHandler->postEvent(id, { InputEvent::Type::BUTTON_ACTION, InputEvent::ButtonAction::RELEASE, {} }); + // eventHandler->postEvent(id, { InputEvent::Type::BUTTON_ACTION, InputEvent::ButtonAction::NONE, {} }); } } static void scrollCallback(GLFWwindow* window, double xOffset, double yOffset) { - // ignore for now + auto* self = static_cast(glfwGetWindowUserPointer(window)); + if (!self) return; + + EventHandler* eventHandler = self->getEventHandler(); + if (!eventHandler) return; + + eventHandler->postEvent(InputID::SCROLL, { InputEvent::Type::SCROLL, {}, {}, { xOffset, yOffset } }); } \ No newline at end of file diff --git a/Graphics/public/EventHandler.hpp b/Graphics/public/EventHandler.hpp index 802a427..a5dca76 100644 --- a/Graphics/public/EventHandler.hpp +++ b/Graphics/public/EventHandler.hpp @@ -4,6 +4,7 @@ #include "Vec.hpp" #include "List.hpp" #include "Map.hpp" +#include "Timing.hpp" #include @@ -15,6 +16,7 @@ namespace tp { BUTTON_ACTION, MOUSE_DELTA, MOUSE_POS, + SCROLL, } type = Type::NONE; enum class ButtonAction { @@ -26,6 +28,7 @@ namespace tp { } buttonAction = ButtonAction::NONE; Vec2F mouseEvent = { 0, 0 }; + Vec2F scrollDelta = { 0, 0 }; }; class InputState { @@ -89,10 +92,13 @@ namespace tp { // input states Vec2F mPointer; Vec2F mPointerPrev; + Vec2F mScrollDelta; halnf mPointerPressure = 0; InputState mInputStates[(int) InputID::LAST_KEY_CODE]{}; + + Timer mTimerEvent = Timer(1000); }; } \ No newline at end of file diff --git a/Graphics/public/Graphics.hpp b/Graphics/public/Graphics.hpp index e13dc09..49dfee6 100644 --- a/Graphics/public/Graphics.hpp +++ b/Graphics/public/Graphics.hpp @@ -17,8 +17,8 @@ namespace tp { explicit DebugGUI(Window* window); ~DebugGUI(); - void procBegin() {} - void procEnd() {} + void procBegin(); + void procEnd(); void drawBegin(); void drawEnd(); diff --git a/Graphics/public/InputCodes.hpp b/Graphics/public/InputCodes.hpp index cae8e99..1cc8f40 100644 --- a/Graphics/public/InputCodes.hpp +++ b/Graphics/public/InputCodes.hpp @@ -143,8 +143,10 @@ namespace tp { MOUSE4 = 504, MOUSE5 = 505, - LAST_KEY_CODE = 508, + SCROLL, - WINDOW_RESIZE = 1000, + WINDOW_RESIZE, + + LAST_KEY_CODE, }; } \ No newline at end of file diff --git a/Graphics/public/Window.hpp b/Graphics/public/Window.hpp index 15c9680..6236a64 100644 --- a/Graphics/public/Window.hpp +++ b/Graphics/public/Window.hpp @@ -12,7 +12,7 @@ namespace tp { ~Window(); public: - static Window* createWindow(Vec2F size = { 500.f, 500.f }, const char* title = "Window"); + static Window* createWindow(Vec2F size = { 1000.f, 700.f }, const char* title = "Window"); static void destroyWindow(Window* window); public: diff --git a/LibraryViewer/applications/Entry.cpp b/LibraryViewer/applications/Entry.cpp index 38dfca0..197d705 100644 --- a/LibraryViewer/applications/Entry.cpp +++ b/LibraryViewer/applications/Entry.cpp @@ -30,7 +30,7 @@ private: Library library; tp::WidgetManager mWidgetManager; - LibraryWidget gui; + LibraryWidget gui; }; int main() { diff --git a/LibraryViewer/public/GUI.hpp b/LibraryViewer/public/GUI.hpp index 4403553..95bf73a 100644 --- a/LibraryViewer/public/GUI.hpp +++ b/LibraryViewer/public/GUI.hpp @@ -8,8 +8,7 @@ namespace tp { - template - class TrackWidget : public Widget { + class TrackWidget : public Widget { public: explicit TrackWidget(const Track* track = nullptr) : mTrack(track) { @@ -61,8 +60,7 @@ namespace tp { bool mSelected = false; }; - template - class TrackInfoWidget : public Widget { + class TrackInfoWidget : public Widget { struct SortType { std::string text; bool dec = false; @@ -186,8 +184,7 @@ namespace tp { int filterExisting = 0; // all existing no-existing }; - template - class LibraryWidget : public Widget { + class LibraryWidget : public Widget { public: LibraryWidget(Library* lib, Player* player) { mLibrary = (lib); @@ -206,7 +203,7 @@ namespace tp { void updateTracks() { mTracks.clear(); for (auto track : mLibrary->mTraks) { - mTracks.append(TrackWidget(&track.data())); + mTracks.append(TrackWidget(&track.data())); } } @@ -217,7 +214,7 @@ namespace tp { mSongList.setArea(mSplitView.getFirst()); for (auto track : mSongList.getContent()) { - auto trackWidget = (TrackWidget*) track.data(); + auto trackWidget = (TrackWidget*) track.data(); if (trackWidget->mSelected) { mCurrentTrackInfo.mTrack = trackWidget->mTrack; } @@ -265,11 +262,11 @@ namespace tp { Library* mLibrary = nullptr; Player* mPlayer = nullptr; - Buffer> mTracks; + Buffer mTracks; - SplitView mSplitView; - ScrollableWindow mSongList; - TrackInfoWidget mCurrentTrackInfo; - TrackWidget mCurrentTrack; + SplitView mSplitView; + ScrollableWindow mSongList; + TrackInfoWidget mCurrentTrackInfo; + TrackWidget mCurrentTrack; }; } \ No newline at end of file diff --git a/Objects/applications/GUI.cpp b/Objects/applications/GUI.cpp index 97e90c2..d14daf2 100644 --- a/Objects/applications/GUI.cpp +++ b/Objects/applications/GUI.cpp @@ -887,7 +887,7 @@ void obj::ObjectsGUI::explorer() { "child_path", { 0, 45 }, false, - ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_HorizontalScrollbar + ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_HorizontalScrollbar ); tp::List rev_path; for (auto childo = mViewStack.lastNode(); childo; childo = childo->prev) { diff --git a/Sketch3D/applications/Entry.cpp b/Sketch3D/applications/Entry.cpp index 15cb949..5a9092c 100644 --- a/Sketch3D/applications/Entry.cpp +++ b/Sketch3D/applications/Entry.cpp @@ -24,7 +24,7 @@ public: private: WidgetManager mWidgetManager; - Sketch3DGUI mGui; + Sketch3DGUI mGui; }; void runApp() { diff --git a/Sketch3D/public/Sketch3DWidget.hpp b/Sketch3D/public/Sketch3DWidget.hpp index 9c81d01..7229ef8 100644 --- a/Sketch3D/public/Sketch3DWidget.hpp +++ b/Sketch3D/public/Sketch3DWidget.hpp @@ -5,8 +5,7 @@ namespace tp { - template - class Sketch3DWidget : public Widget { + class Sketch3DWidget : public Widget { public: Sketch3DWidget(Canvas& canvas, Vec2F renderResolution) : mRenderer(renderResolution) { @@ -91,15 +90,15 @@ namespace tp { Canvas* mCanvas = nullptr; }; - template - class Sketch3DGUI : public Widget { + + class Sketch3DGUI : public Widget { 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 }); + 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.addWidget(mDrawButton); mOptions.addWidget(mMoveButton); @@ -107,9 +106,9 @@ namespace tp { mOptions.addWidget(mZoomButton); // add color sliders - mRed = new NamedSliderWidget("Red"); - mGreen = new NamedSliderWidget("Green"); - mBlue = new NamedSliderWidget("Blue"); + mRed = new NamedSliderWidget("Red"); + mGreen = new NamedSliderWidget("Green"); + mBlue = new NamedSliderWidget("Blue"); mOptions.addWidget(mRed); mOptions.addWidget(mGreen); @@ -132,13 +131,13 @@ namespace tp { mOptions.setArea(mSplitView.getSecond()); if (mDrawButton->isFired()) { - mViewport.mMode = Sketch3DWidget::Mode::DRAW; + mViewport.mMode = Sketch3DWidget::Mode::DRAW; } else if (mMoveButton->isFired()) { - mViewport.mMode = Sketch3DWidget::Mode::MOVE; + mViewport.mMode = Sketch3DWidget::Mode::MOVE; } else if (mRotateButton->isFired()) { - mViewport.mMode = Sketch3DWidget::Mode::ROTATE; + mViewport.mMode = Sketch3DWidget::Mode::ROTATE; } else if (mZoomButton->isFired()) { - mViewport.mMode = Sketch3DWidget::Mode::ZOOM; + mViewport.mMode = Sketch3DWidget::Mode::ZOOM; } mViewport.setColor(RGBA(mRed->mSlider.mFactor, mGreen->mSlider.mFactor, mBlue->mSlider.mFactor, 1.f)); @@ -154,18 +153,18 @@ namespace tp { } private: - Sketch3DWidget mViewport; - SplitView mSplitView; - ScrollableWindow mOptions; + Sketch3DWidget mViewport; + SplitView mSplitView; + ScrollableWindow mOptions; - ButtonWidget* mDrawButton = nullptr; - ButtonWidget* mMoveButton = nullptr; - ButtonWidget* mRotateButton = nullptr; - ButtonWidget* mZoomButton = nullptr; + ButtonWidget* mDrawButton = nullptr; + ButtonWidget* mMoveButton = nullptr; + ButtonWidget* mRotateButton = nullptr; + ButtonWidget* mZoomButton = nullptr; - NamedSliderWidget* mRed = nullptr; - NamedSliderWidget* mGreen = nullptr; - NamedSliderWidget* mBlue = nullptr; + NamedSliderWidget* mRed = nullptr; + NamedSliderWidget* mGreen = nullptr; + NamedSliderWidget* mBlue = nullptr; RGBA mBackgroundColor; halnf mRounding = 0; diff --git a/Widgets/examples/ChatGUI.cpp b/Widgets/examples/ChatGUI.cpp index 52845e4..204567c 100644 --- a/Widgets/examples/ChatGUI.cpp +++ b/Widgets/examples/ChatGUI.cpp @@ -23,7 +23,7 @@ public: private: WidgetManager mWidgetManager; - ComplexWidget mGui; + ComplexWidget mGui; }; int main() { diff --git a/Widgets/examples/ChatGUI.hpp b/Widgets/examples/ChatGUI.hpp index 4b765cf..11aae17 100644 --- a/Widgets/examples/ChatGUI.hpp +++ b/Widgets/examples/ChatGUI.hpp @@ -4,8 +4,7 @@ namespace tp { - template - class UserWidget : public Widget { + class UserWidget : public Widget { public: UserWidget() = default; @@ -39,8 +38,7 @@ namespace tp { halnf mRounding = 0; }; - template - class MessageWidget : public Widget { + class MessageWidget : public Widget { public: MessageWidget() = default; @@ -84,8 +82,7 @@ namespace tp { halnf mRounding = 0; }; - template - class LoginWidget : public Widget { + class LoginWidget : public Widget { public: explicit LoginWidget() { mPass.mId = "pass"; @@ -120,16 +117,15 @@ namespace tp { } public: - TextInputWidget mUser; - TextInputWidget mPass; - ButtonWidget mButton; + TextInputWidget mUser; + TextInputWidget mPass; + ButtonWidget mButton; bool mLogged = false; RGBA mBGColor; }; - template - class ActiveChatWidget : public Widget { + class ActiveChatWidget : public Widget { public: ActiveChatWidget() { mSend.mLabel.mLabel = "Send"; @@ -172,23 +168,22 @@ namespace tp { } public: - Buffer> mMessages; - ScrollableWindow mHistoryView; - TextInputWidget mMessage; - ButtonWidget mSend; + Buffer mMessages; + ScrollableWindow mHistoryView; + TextInputWidget mMessage; + ButtonWidget mSend; RGBA mBGColor; halnf mPadding = 0; }; - template - class ChattingWidget : public Widget { + class ChattingWidget : public Widget { public: ChattingWidget() { // todo : fetch code - mUsers.append(UserWidget()); - mUsers.append(UserWidget()); - mUsers.append(UserWidget()); + mUsers.append(UserWidget()); + mUsers.append(UserWidget()); + mUsers.append(UserWidget()); mUsers[0].mArea = { 0, 0, 100, 100 }; mUsers[1].mArea = { 0, 0, 100, 100 }; @@ -198,9 +193,9 @@ namespace tp { mSideView.addWidget(&message.data()); } - mActive.mMessages.append(MessageWidget()); - mActive.mMessages.append(MessageWidget()); - mActive.mMessages.append(MessageWidget()); + mActive.mMessages.append(MessageWidget()); + mActive.mMessages.append(MessageWidget()); + mActive.mMessages.append(MessageWidget()); mActive.mMessages[0].mArea = { 0, 0, 100, 50 }; mActive.mMessages[1].mArea = { 0, 0, 100, 50 }; @@ -229,16 +224,15 @@ namespace tp { } public: - Buffer> mUsers; - ScrollableWindow mSideView; - ActiveChatWidget mActive; - SplitView mSplitView; + Buffer mUsers; + ScrollableWindow mSideView; + ActiveChatWidget mActive; + SplitView mSplitView; RGBA mBGColor; }; - template - class ComplexWidget : public Widget { + class ComplexWidget : public Widget { public: ComplexWidget() { this->mChildWidgets.pushBack(&mLogin); @@ -264,8 +258,8 @@ namespace tp { private: bool mLogged = false; - LoginWidget mLogin; - ChattingWidget mChatting; + LoginWidget mLogin; + ChattingWidget mChatting; RGBA mBGColor; }; diff --git a/Widgets/examples/SimpleGUI.cpp b/Widgets/examples/SimpleGUI.cpp index 2e6a49c..5760da3 100644 --- a/Widgets/examples/SimpleGUI.cpp +++ b/Widgets/examples/SimpleGUI.cpp @@ -28,7 +28,7 @@ public: private: WidgetManager mWidgetManager; - SimpleWidget2 mGui; + SimpleWidget2 mGui; }; int main() { diff --git a/Widgets/examples/SimpleGUI.hpp b/Widgets/examples/SimpleGUI.hpp index e1cc85b..50f1b84 100644 --- a/Widgets/examples/SimpleGUI.hpp +++ b/Widgets/examples/SimpleGUI.hpp @@ -2,8 +2,7 @@ namespace tp { - template - class SimpleWidget : public CollapsableMenu { + class SimpleWidget : public CollapsableMenu { public: SimpleWidget() { this->addWidgetToMenu(&mInMenuButton1); @@ -17,30 +16,29 @@ namespace tp { } private: - ButtonWidget mInMenuButton1; - ButtonWidget mInMenuButton2; + ButtonWidget mInMenuButton1; + ButtonWidget mInMenuButton2; - LabelWidget mLabel; - NamedSliderWidget mSlider; + LabelWidget mLabel; + NamedSliderWidget mSlider; }; - template - class SimpleWidget2 : public Widget { + class SimpleWidget2 : public Widget { public: SimpleWidget2() { this->mChildWidgets.pushBack(&mFloating); mFloating.addWidgetToMenu(&mWidget); mFloating.addWidgetToMenu(&mWidget2); - + // this->mChildWidgets.pushBack(&mFloating2); // mFloating2.addWidgetToMenu(&mWidget2); } private: - FloatingWidget mFloating; - SimpleWidget mWidget; + FloatingWidget mFloating; + SimpleWidget mWidget; - FloatingWidget mFloating2; - SimpleWidget mWidget2; + FloatingWidget mFloating2; + SimpleWidget mWidget2; }; } \ No newline at end of file diff --git a/Widgets/private/ButtonWidget.cpp b/Widgets/private/ButtonWidget.cpp new file mode 100644 index 0000000..35ba117 --- /dev/null +++ b/Widgets/private/ButtonWidget.cpp @@ -0,0 +1,40 @@ + +#include "ButtonWidget.hpp" + +using namespace tp; + +ButtonWidget::ButtonWidget() { + this->setArea({ 0, 0, 100, 30 }); + this->mChildWidgets.pushBack(&mLabel); +} + +ButtonWidget::ButtonWidget(const std::string& label, const tp::RectF& aArea) { + this->setArea(aArea); + mLabel.mLabel = label; + this->mChildWidgets.pushBack(&mLabel); +} + +bool ButtonWidget::isFired() { return this->isReleased(); } + +void ButtonWidget::eventProcess(const Events&) { mLabel.setArea(this->mArea); } + +void ButtonWidget::eventDraw(Canvas& canvas) { + if (this->isHolding()) { + canvas.rect(this->mArea, pressedColor, rounding); + } else if (this->isFocus()) { + canvas.rect(this->mArea, hoveredColor, rounding); + } else { + canvas.rect(this->mArea, accentColor, rounding); + } +} + +void ButtonWidget::setLabel(const std::string& string) { mLabel.mLabel = string; } + +void ButtonWidget::eventUpdateConfiguration(WidgetManager& wm) { + wm.setActiveId("Button"); + + pressedColor = wm.getColor("Pressed", "Action"); + hoveredColor = wm.getColor("Hovered", "Interaction"); + accentColor = wm.getColor("Default", "Accent"); + rounding = wm.getNumber("Rounding", "Rounding"); +} diff --git a/Widgets/private/CollapsableMenu.cpp b/Widgets/private/CollapsableMenu.cpp new file mode 100644 index 0000000..d872770 --- /dev/null +++ b/Widgets/private/CollapsableMenu.cpp @@ -0,0 +1,84 @@ + +#include "CollapsableMenu.hpp" + +using namespace tp; + +CollapsableMenu::CollapsableMenu() { + this->mChildWidgets.pushBack(&mHeader); + this->mChildWidgets.pushBack(&mBody); +} + +void CollapsableMenu::eventProcess(const Events&) { + if (mHeader.isReleased()) { + toggleCollapsed(); + } + + updateGeometry(); +} + +void CollapsableMenu::eventDraw(Canvas& canvas) { + canvas.rect(this->mArea, mBorderColor, rounding); + canvas.rect(this->mArea.shrink(mBorderSize), mMenuColor, rounding); +} + +void CollapsableMenu::addWidgetToMenu(Widget* widget) { mBody.addWidget(widget); } + +void CollapsableMenu::setLabel(const std::string& string) { mHeader.mLabel = string; } + +void CollapsableMenu::toggleCollapsed() { setCollapsed(!getCollapsed()); } + +void CollapsableMenu::setCollapsed(bool collapsed) { + if (mLocked) return; + if (collapsed && !mCollapsed) mPrevHeight = this->mArea.size.y; + if (!collapsed && mCollapsed) this->mArea.size.y = mPrevHeight; + mCollapsed = collapsed; +} + +bool CollapsableMenu::getCollapsed() const { return mCollapsed; } + +void CollapsableMenu::updateGeometry() { + mHeader.setArea(getHeaderRect()); + + mBody.mEnable = !mCollapsed; + if (mCollapsed) { + this->mArea.size.y = headerHeight; + } else { + if (mAdjustHeight) { + this->mArea.size.y = headerHeight + getBodyRect().size.y + mPadding * 2; + } + + mBody.setArea(getBodyRect()); + } +} + +RectF CollapsableMenu::getHeaderRect() { + RectF out = { this->mArea.pos, { this->mArea.size.x, headerHeight } }; + return out.shrink(mPadding); +} + +RectF CollapsableMenu::getBodyRect() { + RectF out = { { this->mArea.pos.x, this->mArea.pos.y + headerHeight }, + { this->mArea.size.x, this->mArea.size.y - headerHeight - mPadding } }; + + out.size.y -= mBorderSize * 2; + + if (mAdjustHeight) out.size.y = mBody.getContentSize(); + + if (mBody.getContentSize()) { + out = out.shrink(mPadding); + out.size.y += mPadding * 2 + 1; + } + + return out; +} + +void CollapsableMenu::eventUpdateConfiguration(WidgetManager& wm) { + wm.setActiveId("CollapsableMenu"); + + headerHeight = wm.getNumber("HeaderHeight", 35); + mMenuColor = wm.getColor("MenuColor", RGBA(0, 0, 0, 1.f)); + rounding = wm.getNumber("Rounding", "Rounding"); + mBorderColor = wm.getColor("BorderColor", RGBA(0.16, 0.16, 0.16, 1.f)); + mBorderSize = wm.getNumber("BorderSize", 2.f); + mPadding = wm.getNumber("Padding", "Padding"); +} diff --git a/Widgets/private/FloatingWidget.cpp b/Widgets/private/FloatingWidget.cpp new file mode 100644 index 0000000..9510d2b --- /dev/null +++ b/Widgets/private/FloatingWidget.cpp @@ -0,0 +1,80 @@ + +#include "FloatingWidget.hpp" + +using namespace tp; + +FloatingWidget::FloatingWidget() { + this->mArea = { 0, 0, 300, 300 }; + this->mAdjustHeight = false; +} + +void FloatingWidget::eventProcess(const Events& events) { + checkFloating(events); + checkResizing(events); + + mActionStartRelativePos = events.getPointer() - this->mArea.pos; + + CollapsableMenu::eventProcess(events); +} + +void FloatingWidget::eventDraw(Canvas& canvas) { + CollapsableMenu::eventDraw(canvas); + + if (!this->getCollapsed()) { + auto rect = getResizeHandle(); + canvas.rect(rect, mResizeHandleColor, 0); + canvas.circle(rect.pos - this->mBorderSize, rect.w, this->mMenuColor); + } +} + +void FloatingWidget::eventUpdateConfiguration(WidgetManager& wm) { + CollapsableMenu::eventUpdateConfiguration(wm); + + wm.setActiveId("FloatingWidget"); + + mResizeHandleSize = wm.getNumber("ResizeHandleSize", 15); + mResizeHandleColor = wm.getColor("ResizeHandleColor", RGBA(0.16, 0.16, 0.16, 1.f)); +} + +void FloatingWidget::checkFloating(const Events& events) { + if (this->mHeader.isHolding() && events.getPointerDelta().length2() > 4) { + mFloating = true; + } + + if (mFloating && this->mHeader.isReleased()) { + mFloating = false; + this->mHeader.clearEvents(); + } + + if (mFloating) { + auto relativePos = events.getPointer() - this->mArea.pos; + this->mArea.pos += relativePos - mActionStartRelativePos; + } +} + +void FloatingWidget::checkResizing(const Events& events) { + if (this->getCollapsed()) return; + + if (events.isPressed(InputID::MOUSE1) && getResizeHandle().isInside(events.getPointer())) { + mResizing = true; + } + + if (events.isReleased(InputID::MOUSE1)) { + mResizing = false; + } + + if (mResizing) { + auto relativePos = events.getPointer() - this->mArea.pos; + this->mArea.size += relativePos - mActionStartRelativePos; + } + + if (!this->mCollapsed) { + this->mArea.size.clamp(mMinSize, { FLT_MAX, FLT_MAX }); + } +} + +RectF FloatingWidget::getResizeHandle() { + auto size = Vec2F(mResizeHandleSize); + auto pos = this->mArea.pos + this->mArea.size - size; + return { pos, size }; +} diff --git a/Widgets/private/LabelWidget.cpp b/Widgets/private/LabelWidget.cpp new file mode 100644 index 0000000..dfefe0b --- /dev/null +++ b/Widgets/private/LabelWidget.cpp @@ -0,0 +1,17 @@ +#include "LabelWidget.hpp" + +using namespace tp; + +LabelWidget::LabelWidget() { this->mArea = { 0, 0, 100, 30 }; } + +void LabelWidget::eventDraw(Canvas& canvas) { + canvas.text(mLabel.c_str(), this->mArea, fontSize, Canvas::LC, padding, fontColor); +} + +void LabelWidget::eventUpdateConfiguration(WidgetManager& wm) { + wm.setActiveId("Label"); + + fontSize = wm.getNumber("Size", "FontSize"); + padding = wm.getNumber("Padding", "Padding"); + fontColor = wm.getColor("Default", "Front"); +} diff --git a/Widgets/private/ScrollableWidget.cpp b/Widgets/private/ScrollableWidget.cpp new file mode 100644 index 0000000..7fc945e --- /dev/null +++ b/Widgets/private/ScrollableWidget.cpp @@ -0,0 +1,166 @@ +#include "ScrollableWidget.hpp" + +using namespace tp; + +ScrollBarWidget::ScrollBarWidget() = default; + +void ScrollBarWidget::eventProcess(const Events& events) { + auto area = getHandle(); + mHovered = getHandleHandle().isInside(events.getPointer()); + + if (mSizeFraction > 1.f) { + mPositionFraction = 0; + return; + } + + if (events.getScrollY() != 0) { + auto offset = events.getScrollY() < 0 ? 1.0f : -1.0f; + mPositionFraction += mSizeFraction * offset * 0.3f; + mPositionFraction = tp::clamp(mPositionFraction, 0.f, 1.f - mSizeFraction); + } + + if (events.isPressed(InputID::MOUSE1) && area.isInside(events.getPointer())) { + mIsScrolling = true; + } else if (events.isReleased(InputID::MOUSE1)) { + mIsScrolling = false; + } + + if (mIsScrolling) { + tp::halnf pos = events.getPointer().y; + pos = (pos - area.y - mSizeFraction * area.w / 2.f) / area.w; + mPositionFraction = tp::clamp(pos, 0.f, 1.f - mSizeFraction); + } + + mPositionFraction = tp::clamp(mPositionFraction, 0.f, 1.f - mSizeFraction); +} + +void ScrollBarWidget::eventDraw(Canvas& canvas) { + auto area = getHandle(); + + if (mSizeFraction > 1.f) return; + // if (!areaParent.isOverlap(getHandle())) return; + + tp::RGBA col = mHandleColor; + + if (mIsScrolling) { + col = mScrollingColor; + } else if (mHovered) { + col = mHoveredColor; + } + + canvas.rect(area, mDefaultColor, mRounding); + canvas.rect(getHandleHandle(), col, mRounding); +} + +RectF ScrollBarWidget::getHandleHandle() const { + auto area = getHandle(); + auto sliderSize = tp::clamp(area.w * mSizeFraction, mMinSize * 2, area.w); + auto diffSize = sliderSize - area.w * mSizeFraction; + return { area.x, area.y + (area.w - diffSize) * mPositionFraction, area.z, sliderSize }; +} + +RectF ScrollBarWidget::getViewport() const { + if (mSizeFraction > 1.f) { + return this->mArea; + } + return { this->mArea.x, this->mArea.y, this->mArea.z - mHandleSize, this->mArea.w }; +} + +RectF ScrollBarWidget::getHandle() const { + return { this->mArea.x + this->mArea.z - mHandleSize + mPadding, + this->mArea.y + mPadding, + mHandleSize - mPadding * 2, + this->mArea.w - mPadding * 2 }; +} + +void ScrollBarWidget::eventUpdateConfiguration(WidgetManager& wm) { + wm.setActiveId("Scrollbar"); + + mDefaultColor = wm.getColor("Default", "Base"); + mHandleColor = wm.getColor("Handle", "Accent"); + mHoveredColor = wm.getColor("Hovered", "Interaction"); + mScrollingColor = wm.getColor("Scrolling", "Action"); + mPadding = wm.getNumber("Padding", "Padding"); + mHandleSize = wm.getNumber("HandleSize", 20.f); + mMinSize = wm.getNumber("MinSize", 20.f); + mRounding = wm.getNumber("Rounding", "Rounding"); +} + +ScrollableWindow::ScrollableWindow() { + this->mChildWidgets.pushBack(&mScroller); + this->mChildWidgets.pushBack(&mContentWidget); +} + +ScrollableWindow::~ScrollableWindow() = default; + +void ScrollableWindow::eventProcess(const Events& events) { + List& content = mContentWidget.mChildWidgets; + + updateContents(content); + updateContentSize(content); + + const auto padding = mPadding; + + mScroller.mSizeFraction = mContentWidget.mArea.w / mContentSize; + mScroller.setArea(this->mArea); + mContentWidget.setArea(mScroller.getViewport()); + + if (mScroller.mSizeFraction > 1.f) { + setOffset(content, 0); + } else { + setOffset(content, (-mScroller.mPositionFraction) * mContentSize); + } + + for (auto widget : content) { + widget->setArea({ mContentWidget.mArea.x + padding, + mContentWidget.mArea.y + widget->mArea.y, + mScroller.getViewport().z - padding * 2, + widget->mArea.w }); + } +} + +void ScrollableWindow::addWidget(Widget* widget) { mContentWidget.mChildWidgets.pushBack(widget); } +void ScrollableWindow::clearContent() { mContentWidget.mChildWidgets.removeAll(); } +List& ScrollableWindow::getContent() { return mContentWidget.mChildWidgets; } + +void ScrollableWindow::eventUpdateConfiguration(WidgetManager& wm) { + wm.setActiveId("ScrollableWidget"); + mPadding = wm.getNumber("Padding", "Padding"); +} + +[[nodiscard]] halnf ScrollableWindow::getContentSize() const { return mContentSize; } + +void ScrollableWindow::updateContents(List& contentWidgets) { + if (!contentWidgets.size()) { + return; + } + + const halnf offset = contentWidgets.first()->mArea.y + mPadding; + + halnf start = 0; + for (auto widget : contentWidgets) { + widget->mArea.y = start; + start += widget->mArea.w + mPadding; + } + + for (auto widget : contentWidgets) { + widget->mArea.y += offset; + } +} + +void ScrollableWindow::updateContentSize(List& contentWidgets) { + mContentSize = 0; + if (contentWidgets.size()) { + mContentSize = contentWidgets.last()->mArea.y - contentWidgets.first()->mArea.y; + mContentSize += contentWidgets.last()->mArea.w; + mContentSize += 2 * mPadding; + } +} + +void ScrollableWindow::setOffset(List& contentWidgets, const halnf offset) { + if (!contentWidgets.size()) return; + auto newOffset = offset - contentWidgets.first()->mArea.y + mPadding; + for (auto widget : contentWidgets) { + widget->mArea.y += newOffset; + } +} diff --git a/Widgets/private/SliderWidget.cpp b/Widgets/private/SliderWidget.cpp new file mode 100644 index 0000000..46a1553 --- /dev/null +++ b/Widgets/private/SliderWidget.cpp @@ -0,0 +1,60 @@ +#include "SliderWidget.hpp" + +using namespace tp; + +SliderWidget::SliderWidget() = default; + +void SliderWidget::eventProcess(const Events& events) { + if (this->isPressed()) { + mIsSliding = true; + } else if (events.isReleased(InputID::MOUSE1)) { + mIsSliding = false; + } + + if (mIsSliding) { + mFactor = (events.getPointer().x - this->mArea.x - handleSize / 2.f) / (this->mArea.z - handleSize); + } + + mFactor = tp::clamp(mFactor, 0.f, 1.f); +} + +void SliderWidget::eventDraw(Canvas& canvas) { + canvas.rect(this->mArea, defaultColor, rounding); + canvas.rect(getHandle(), handleColor, rounding); +} + +RectF SliderWidget::getHandle() const { + const auto left = this->mArea.x + (this->mArea.z - handleSize) * mFactor; + return { left, this->mArea.y, handleSize, this->mArea.w }; +} + +void SliderWidget::eventUpdateConfiguration(WidgetManager& wm) { + wm.setActiveId("Slider"); + defaultColor = wm.getColor("Default", "Base"); + handleColor = wm.getColor("Handle", "Accent"); + handleSize = wm.getNumber("HandleSize", 20.f); + rounding = wm.getNumber("Rounding", "Rounding"); +} + +NamedSliderWidget::NamedSliderWidget(const char* name) { + mLabel.mLabel = name; + this->mArea = { 0, 0, 100, 30 }; + + this->mChildWidgets.pushBack(&mSlider); + this->mChildWidgets.pushBack(&mLabel); +} + +void NamedSliderWidget::eventProcess(const Events& events) { + const auto widthFirst = this->mArea.z * mFactor; + const auto widthSecond = this->mArea.z * (1.f - mFactor); + + RectF rec = this->mArea; + rec.size.x = widthFirst; + + mLabel.setArea(rec); + + rec.pos.x += widthFirst; + rec.size.x = widthSecond; + + mSlider.setArea(rec); +} diff --git a/Widgets/private/SplitViewWidget.cpp b/Widgets/private/SplitViewWidget.cpp new file mode 100644 index 0000000..21b3260 --- /dev/null +++ b/Widgets/private/SplitViewWidget.cpp @@ -0,0 +1,135 @@ +#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/TextInputWidget.cpp b/Widgets/private/TextInputWidget.cpp new file mode 100644 index 0000000..54925fa --- /dev/null +++ b/Widgets/private/TextInputWidget.cpp @@ -0,0 +1,57 @@ +#include "TextInputWidget.hpp" + +#include "imgui.h" +#include "imgui_internal.h" + +using namespace tp; + +TextInputWidget::TextInputWidget() = default; + +void TextInputWidget::eventDraw(Canvas&) { + nChanged = false; + + const auto col = mAccentColor; + const auto colSel = mHoveredColor; + + ImGui::GetStyle().Colors[ImGuiCol_FrameBg] = { col.r, col.g, col.b, col.a }; + ImGui::GetStyle().Colors[ImGuiCol_TextSelectedBg] = { colSel.r, colSel.g, colSel.b, colSel.a }; + + ImGui::SetNextWindowPos({ this->mArea.x, this->mArea.y }); + ImGui::SetNextWindowSize({ this->mArea.z, this->mArea.w }); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 0, 0 }); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, mRounding * 1.5f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { mPadding, mPadding }); + + // ImGui::PushID((int) alni(this)); + ImGui::Begin( + mId.c_str(), + 0, + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBackground | + ImGuiWindowFlags_NoResize + ); + + if (mMultiline) { + if (ImGui::InputTextMultiline("input", mBuff, mMaxBufferSize, { this->mArea.z, this->mArea.w })) { + mValue = mBuff; + nChanged = true; + } + } else { + if (ImGui::InputTextEx("input", mId.c_str(), mBuff, mMaxBufferSize, { this->mArea.z, this->mArea.w }, 0)) { + mValue = mBuff; + nChanged = true; + } + } + + ImGui::End(); + ImGui::PopStyleVar(3); +} + +void TextInputWidget::eventUpdateConfiguration(WidgetManager& wm) { + wm.setActiveId("TextInput"); + + mAccentColor = wm.getColor("Accent", "Accent"); + mBaseColor = wm.getColor("Base", "Base"); + mRounding = wm.getNumber("Rounding", "Rounding"); + mHoveredColor = wm.getColor("Hovered", "Accent"); + mPadding = wm.getNumber("Padding", "Padding"); +} diff --git a/Widgets/private/WidgetBase.cpp b/Widgets/private/WidgetBase.cpp new file mode 100644 index 0000000..620ff50 --- /dev/null +++ b/Widgets/private/WidgetBase.cpp @@ -0,0 +1,132 @@ +#include "WidgetBase.hpp" + +using namespace tp; + +Widget::Widget() { mArea = { 0, 0, 100, 100 }; } + +Widget::~Widget() = default; + +void Widget::procWrapper(const Events& events, const RectF& parentArea) { + if (!mEnable) return; + + checkVisibility(events, parentArea); + + if (!mVisible) return; + + checkFocus(events); + + checkClicked(events); + + eventProcess(events); + + for (auto child : mChildWidgets) { + child->procWrapper(events, getArea()); + } +} + +void Widget::drawWrapper(Canvas& canvas) { + if (!mEnable || !mVisible) return; + + eventDraw(canvas); + + // draw child widgets + canvas.pushClamp(this->mArea); + for (auto child : mChildWidgets) { + child->drawWrapper(canvas); + } + canvas.popClamp(); +} + +void Widget::updateConfigWrapper(WidgetManager& wm) { + wm.setActiveId("Global"); + + eventUpdateConfiguration(wm); + + for (auto child : mChildWidgets) { + child->updateConfigWrapper(wm); + } +} + +void Widget::eventProcess(const Events& events) {} +void Widget::eventDraw(Canvas& canvas) {} +void Widget::eventUpdateConfiguration(WidgetManager& wm) {} + +void Widget::eventVisible(const Events& events) {} +void Widget::eventNotVisible(const Events& events) {} + +void Widget::eventFocusEnter(const Events& events) {} +void Widget::eventFocusLeave(const Events& events) {} + +void Widget::eventPressed(const Events& events) {} +void Widget::eventReleased(const Events& events) {} + +void Widget::checkVisibility(const Events& events, const RectF& parentArea) { + const bool currentVisibility = parentArea.isOverlap(getArea()); + + if (currentVisibility != mVisible) { + if (currentVisibility) eventVisible(events); + else eventNotVisible(events); + } + + mVisible = currentVisibility; + + if (!mVisible) { + mHolding = false; + mPressed = false; + mReleased = false; + } +} + +void Widget::checkFocus(const Events& events) { + const bool currentFocus = getArea().isInside(events.getPointer()); + + if (currentFocus != mInFocus) { + if (currentFocus) eventFocusEnter(events); + else eventFocusLeave(events); + } + + mInFocus = currentFocus; + + if (!mInFocus) { + mHolding = false; + mPressed = false; + mReleased = false; + } +} + +void Widget::checkClicked(const Events& events) { + mPressed = false; + mReleased = false; + + if (!mInFocus) return; + + if (mHolding) { + if (events.isReleased(InputID::MOUSE1)) { + eventReleased(events); + mReleased = true; + mHolding = false; + } + } else { + if (events.isPressed(InputID::MOUSE1)) { + eventPressed(events); + mHolding = true; + mPressed = true; + } + } +} + +void Widget::setEnable(bool enable) { mEnable = enable; } +void Widget::setVisible(bool visible) { mVisible = visible; } +void Widget::setArea(const RectF& area) { mArea = area; } + +const RectF& Widget::getArea() const { return mArea; } +bool Widget::isFocus() const { return mInFocus; } +bool Widget::isPressed() const { return mPressed; } +bool Widget::isReleased() const { return mReleased; } +bool Widget::isHolding() const { return mHolding; } + +void Widget::clearEvents() { + mReleased = false; + mPressed = false; + mHolding = false; +} diff --git a/Widgets/private/WidgetManager.cpp b/Widgets/private/WidgetManager.cpp new file mode 100644 index 0000000..268059c --- /dev/null +++ b/Widgets/private/WidgetManager.cpp @@ -0,0 +1,74 @@ +#include "WidgetManager.hpp" + +using namespace tp; + +WidgetManager::WidgetManager() { initGlobalParameters(); } +WidgetManager::~WidgetManager() { mConfigurations.removeAll(); } + +const RGBA& WidgetManager::getColor(const std::string& parameterId, const RGBA& defaultValue) { + WidgetConfig& config = getWidgetConfig(mActiveId); + Parameter& parameter = getParameter(config, parameterId, Parameter(defaultValue)); + return parameter.color; +} + +const RGBA& WidgetManager::getColor(const std::string& parameterId, const char* globalRef) { + WidgetConfig& config = getWidgetConfig(mActiveId); + Parameter& parameter = getParameter(config, parameterId, Parameter(globalRef, Parameter::COL)); + return parameter.color; +} + +halnf WidgetManager::getNumber(const std::string& parameterId, halnf defaultValue) { + WidgetConfig& config = getWidgetConfig(mActiveId); + Parameter& parameter = getParameter(config, parameterId, Parameter(defaultValue)); + return parameter.value; +} + +halnf WidgetManager::getNumber(const std::string& parameterId, const char* globalRef) { + WidgetConfig& config = getWidgetConfig(mActiveId); + Parameter& parameter = getParameter(config, parameterId, Parameter(globalRef, Parameter::VAL)); + return parameter.value; +} + +void WidgetManager::setActiveId(const std::string& id) { mActiveId = id; } + +WidgetConfig& WidgetManager::getWidgetConfig(const std::string& id) { + auto idx = mConfigurations.presents(id); + if (idx) return mConfigurations.getSlotVal(idx); + mConfigurations.put(id, {}); + return mConfigurations.get(id); +} + +WidgetManager::Parameter& WidgetManager::getParameter(WidgetConfig& config, const std::string& id, const Parameter& defaultValue) { + auto idx = config.mParameters.presents(id); + + if (!idx) { + config.mParameters.put(id, defaultValue); + } + + Parameter& parameter = config.mParameters.get(id); + + if (parameter.globalReference) { + return mGlobalConfig.mParameters.get(parameter.globalId); + } else { + return parameter; + } +} + +void WidgetManager::initGlobalParameters() { + auto& params = mGlobalConfig.mParameters; + + params.put("FontSize", Parameter(15.f)); + + params.put("FontSizeDim", Parameter(12.f)); + params.put("Rounding", Parameter(5.f)); + params.put("Padding", Parameter(5.f)); + params.put("HandleSize", Parameter(5.f)); + + params.put("Background", Parameter(RGBA{ 0.03f, 0.03f, 0.03f, 1.f })); + params.put("Base", Parameter(RGBA{ 0.07f, 0.07f, 0.07f, 1.f })); + params.put("Accent", Parameter(RGBA{ 0.13f, 0.13f, 0.13f, 1.f })); + params.put("Interaction", Parameter(RGBA{ 0.33f, 0.33f, 0.3f, 1.f })); + params.put("Action", Parameter(RGBA{ 0.44f, 0.44f, 0.4f, 1.f })); + params.put("Front", Parameter(RGBA{ 1.f, 1.f, 1.f, 1.f })); + params.put("FrontDim", Parameter(RGBA{ 0.7f, 0.7f, 0.7f, 1.f })); +} diff --git a/Widgets/public/ButtonWidget.hpp b/Widgets/public/ButtonWidget.hpp index 9281709..de2a98a 100644 --- a/Widgets/public/ButtonWidget.hpp +++ b/Widgets/public/ButtonWidget.hpp @@ -4,50 +4,20 @@ namespace tp { - template - class ButtonWidget : public Widget { + class ButtonWidget : public Widget { public: - ButtonWidget() { - this->setArea({ 0, 0, 100, 30 }); - this->mChildWidgets.pushBack(&mLabel); - } - - ButtonWidget(const std::string& label, const tp::RectF& aArea) { - this->setArea(aArea); - mLabel.mLabel = label; - this->mChildWidgets.pushBack(&mLabel); - } - - bool isFired() { return this->isReleased(); } - - void eventProcess(const Events&) override { mLabel.setArea(this->mArea); } - - void eventDraw(Canvas& canvas) override { - if (this->isHolding()) { - canvas.rect(this->mArea, pressedColor, rounding); - } else if (this->isFocus()) { - canvas.rect(this->mArea, hoveredColor, rounding); - } else { - canvas.rect(this->mArea, accentColor, rounding); - } - } - - void setLabel(const std::string& string) { - mLabel.mLabel = string; - } + ButtonWidget(); + ButtonWidget(const std::string& label, const tp::RectF& aArea); + bool isFired(); + void eventProcess(const Events&) override; + void eventDraw(Canvas& canvas) override; + void setLabel(const std::string& string); public: - void eventUpdateConfiguration(WidgetManager& wm) override { - wm.setActiveId("Button"); - - pressedColor = wm.getColor("Pressed", "Action"); - hoveredColor = wm.getColor("Hovered", "Interaction"); - accentColor = wm.getColor("Default", "Accent"); - rounding = wm.getNumber("Rounding", "Rounding"); - } + void eventUpdateConfiguration(WidgetManager& wm) override; public: - LabelWidget mLabel; + LabelWidget mLabel; RGBA pressedColor; RGBA hoveredColor; diff --git a/Widgets/public/CollapsableMenu.hpp b/Widgets/public/CollapsableMenu.hpp index cbefa16..e6b2dc9 100644 --- a/Widgets/public/CollapsableMenu.hpp +++ b/Widgets/public/CollapsableMenu.hpp @@ -5,104 +5,31 @@ namespace tp { - template - class CollapsableMenu : public Widget { + class CollapsableMenu : public Widget { public: - CollapsableMenu() { - this->mChildWidgets.pushBack(&mHeader); - this->mChildWidgets.pushBack(&mBody); - } - - void eventProcess(const Events&) override { - if (mHeader.isReleased()) { - toggleCollapsed(); - } - - updateGeometry(); - } - - void eventDraw(Canvas& canvas) override { - canvas.rect(this->mArea, mBorderColor, rounding); - canvas.rect(this->mArea.shrink(mBorderSize), mMenuColor, rounding); - } + CollapsableMenu(); + void eventProcess(const Events&) override; + void eventDraw(Canvas& canvas) override; public: - void addWidgetToMenu(Widget* widget) { - mBody.addWidget(widget); - } + void addWidgetToMenu(Widget* widget); + void setLabel(const std::string& string); - void setLabel(const std::string& string) { - mHeader.mLabel = string; - } - - void toggleCollapsed() { - setCollapsed(!getCollapsed()); - } - - void setCollapsed(bool collapsed) { - if (mLocked) return; - if (collapsed && !mCollapsed) mPrevHeight = this->mArea.size.y; - if (!collapsed && mCollapsed) this->mArea.size.y = mPrevHeight; - mCollapsed = collapsed; - } - - [[nodiscard]] bool getCollapsed() const{ - return mCollapsed; - } - - void updateGeometry() { - mHeader.setArea(getHeaderRect()); - - mBody.mEnable = !mCollapsed; - if (mCollapsed) { - this->mArea.size.y = headerHeight; - } else { - if (mAdjustHeight) { - this->mArea.size.y = headerHeight + getBodyRect().size.y + mPadding * 2; - } - - mBody.setArea(getBodyRect()); - } - } + void toggleCollapsed(); + void setCollapsed(bool collapsed); + [[nodiscard]] bool getCollapsed() const; + void updateGeometry(); private: - RectF getHeaderRect() { - RectF out = { this->mArea.pos, { this->mArea.size.x, headerHeight } }; - return out.shrink(mPadding); - } - - RectF getBodyRect() { - RectF out = { { this->mArea.pos.x, this->mArea.pos.y + headerHeight }, - { this->mArea.size.x, this->mArea.size.y - headerHeight - mPadding } - }; - - out.size.y -= mBorderSize * 2; - - if (mAdjustHeight) out.size.y = mBody.getContentSize(); - - if (mBody.getContentSize()) { - out = out.shrink(mPadding); - out.size.y += mPadding * 2 + 1; - } - - return out; - } + RectF getHeaderRect(); + RectF getBodyRect(); public: - void eventUpdateConfiguration(WidgetManager& wm) override { - wm.setActiveId("CollapsableMenu"); - - headerHeight = wm.getNumber("HeaderHeight", 35); - mMenuColor = wm.getColor("MenuColor", RGBA(0, 0, 0, 1.f)); - rounding = wm.getNumber("Rounding", "Rounding"); - mBorderColor = wm.getColor("BorderColor", RGBA(0.16, 0.16, 0.16, 1.f)); - mBorderSize = wm.getNumber("BorderSize", 2.f); - mPadding = wm.getNumber("Padding", "Padding"); - } + void eventUpdateConfiguration(WidgetManager& wm) override; protected: - ScrollableWindow mBody; - LabelWidget mHeader; + ScrollableWindow mBody; + LabelWidget mHeader; RGBA mMenuColor; RGBA mBorderColor; diff --git a/Widgets/public/FloatingWidget.hpp b/Widgets/public/FloatingWidget.hpp index b81d116..a529db5 100644 --- a/Widgets/public/FloatingWidget.hpp +++ b/Widgets/public/FloatingWidget.hpp @@ -3,85 +3,18 @@ #include "CollapsableMenu.hpp" namespace tp { - template - class FloatingWidget : public CollapsableMenu { + class FloatingWidget : public CollapsableMenu { public: - FloatingWidget() { - this->mArea = { 0, 0, 300, 300 }; - this->mAdjustHeight = false; - } + FloatingWidget(); - void eventProcess(const Events& events) override { - checkFloating(events); - checkResizing(events); - - mActionStartRelativePos = events.getPointer() - this->mArea.pos; - - CollapsableMenu::eventProcess(events); - } - - void eventDraw(Canvas& canvas) override { - CollapsableMenu::eventDraw(canvas); - - if (!this->getCollapsed()) { - auto rect = getResizeHandle(); - canvas.rect(rect, mResizeHandleColor, 0); - canvas.circle(rect.pos - this->mBorderSize, rect.w, this->mMenuColor); - } - } - - void eventUpdateConfiguration(WidgetManager& wm) override { - CollapsableMenu::eventUpdateConfiguration(wm); - - wm.setActiveId("FloatingWidget"); - - mResizeHandleSize = wm.getNumber("ResizeHandleSize", 15); - mResizeHandleColor = wm.getColor("ResizeHandleColor", RGBA(0.16, 0.16, 0.16, 1.f)); - } + void eventProcess(const Events& events) override; + void eventDraw(Canvas& canvas) override; + void eventUpdateConfiguration(WidgetManager& wm) override; private: - void checkFloating(const Events& events) { - if (this->mHeader.isHolding() && events.getPointerDelta().length2() > 4 ) { - mFloating = true; - } - - if (mFloating && this->mHeader.isReleased()) { - mFloating = false; - this->mHeader.clearEvents(); - } - - if (mFloating) { - auto relativePos = events.getPointer() - this->mArea.pos; - this->mArea.pos += relativePos - mActionStartRelativePos; - } - } - - void checkResizing(const Events& events) { - if (this->getCollapsed()) return; - - if (events.isPressed(InputID::MOUSE1) && getResizeHandle().isInside(events.getPointer())) { - mResizing = true; - } - - if (events.isReleased(InputID::MOUSE1)) { - mResizing = false; - } - - if (mResizing) { - auto relativePos = events.getPointer() - this->mArea.pos; - this->mArea.size += relativePos - mActionStartRelativePos; - } - - if (!this->mCollapsed) { - this->mArea.size.clamp(mMinSize, { FLT_MAX, FLT_MAX }); - } - } - - RectF getResizeHandle() { - auto size = Vec2F(mResizeHandleSize); - auto pos = this->mArea.pos + this->mArea.size - size; - return { pos, size }; - } + void checkFloating(const Events& events); + void checkResizing(const Events& events); + RectF getResizeHandle(); private: Vec2F mMinSize = { 70, 70 }; diff --git a/Widgets/public/LabelWidget.hpp b/Widgets/public/LabelWidget.hpp index fd3630d..02ad90a 100644 --- a/Widgets/public/LabelWidget.hpp +++ b/Widgets/public/LabelWidget.hpp @@ -3,25 +3,15 @@ #include "WidgetBase.hpp" namespace tp { - template - class LabelWidget : public Widget { - public: - LabelWidget() { - this->mArea = { 0, 0, 100, 30 }; - } - void eventDraw(Canvas& canvas) override { - canvas.text(mLabel.c_str(), this->mArea, fontSize, Canvas::LC, padding, fontColor); - } + class LabelWidget : public Widget { + public: + LabelWidget(); + + void eventDraw(Canvas& canvas) override; public: - void eventUpdateConfiguration(WidgetManager& wm) override { - wm.setActiveId("Label"); - - fontSize = wm.getNumber("Size", "FontSize"); - padding = wm.getNumber("Padding", "Padding"); - fontColor = wm.getColor("Default", "Front"); - } + void eventUpdateConfiguration(WidgetManager& wm) override; public: std::string mLabel = "Label"; diff --git a/Widgets/public/ScrollableWidget.hpp b/Widgets/public/ScrollableWidget.hpp index 31a7351..71ed13f 100644 --- a/Widgets/public/ScrollableWidget.hpp +++ b/Widgets/public/ScrollableWidget.hpp @@ -5,109 +5,22 @@ namespace tp { - template - class ScrollBarWidget : public Widget { + class ScrollBarWidget : public Widget { public: - ScrollBarWidget() = default; + ScrollBarWidget(); // takes whole area - void eventProcess(const Events& events) override { - auto area = getHandle(); - mHovered = getHandleHandle().isInside(events.getPointer()); + void eventProcess(const Events& events) override; + void eventDraw(Canvas& canvas) override; - if (mSizeFraction > 1.f) { - mPositionFraction = 0; - return; - } - - if (events.getScrollY() != 0) { - auto offset = events.getScrollY() < 0 ? 1.0f : -1.0f; - if (scrollInertia * offset > 0) { - scrollInertia += offset; - } else { - scrollInertia = -scrollInertia + offset; - } - } - - if (tp::abs(scrollInertia) > 0.1f) { - auto offset = scrollInertia * mScrollFactor; - mPositionFraction += offset; - mPositionFraction = tp::clamp(mPositionFraction, 0.f, 1.f - mSizeFraction); - scrollInertia *= 0.f; - return; - } - - if (events.isPressed(InputID::MOUSE1) && area.isInside(events.getPointer())) { - mIsScrolling = true; - } else if (events.isReleased(InputID::MOUSE1)) { - mIsScrolling = false; - } - - if (mIsScrolling) { - tp::halnf pos = events.getPointer().y; - pos = (pos - area.y - mSizeFraction * area.w / 2.f) / area.w; - mPositionFraction = tp::clamp(pos, 0.f, 1.f - mSizeFraction); - } - - mPositionFraction = tp::clamp(mPositionFraction, 0.f, 1.f - mSizeFraction); - } - - void eventDraw(Canvas& canvas) override { - auto area = getHandle(); - - if (mSizeFraction > 1.f) return; - // if (!areaParent.isOverlap(getHandle())) return; - - tp::RGBA col = mHandleColor; - - if (mIsScrolling) { - col = mScrollingColor; - } else if (mHovered) { - col = mHoveredColor; - } - - canvas.rect(area, mDefaultColor, mRounding); - canvas.rect(getHandleHandle(), col, mRounding); - } - - RectF getHandleHandle() const { - auto area = getHandle(); - auto sliderSize = tp::clamp(area.w * mSizeFraction, mMinSize * 2, area.w); - auto diffSize = sliderSize - area.w * mSizeFraction; - return { area.x, area.y + (area.w - diffSize) * mPositionFraction, area.z, sliderSize }; - } - - RectF getViewport() const { - if (mSizeFraction > 1.f) { - return this->mArea; - } - return { this->mArea.x, this->mArea.y, this->mArea.z - mHandleSize, this->mArea.w }; - } - - RectF getHandle() const { - return { this->mArea.x + this->mArea.z - mHandleSize + mPadding, - this->mArea.y + mPadding, - mHandleSize - mPadding * 2, - this->mArea.w - mPadding * 2 }; - } + RectF getHandleHandle() const; + RectF getViewport() const; + RectF getHandle() const; public: - void eventUpdateConfiguration(WidgetManager& wm) override { - wm.setActiveId("Scrollbar"); - - mDefaultColor = wm.getColor("Default", "Base"); - mHandleColor = wm.getColor("Handle", "Accent"); - mHoveredColor = wm.getColor("Hovered", "Interaction"); - mScrollingColor = wm.getColor("Scrolling", "Action"); - mPadding = wm.getNumber("Padding", "Padding"); - mHandleSize = wm.getNumber("HandleSize", 20.f); - mMinSize = wm.getNumber("MinSize", 20.f); - mRounding = wm.getNumber("Rounding", "Rounding"); - } + void eventUpdateConfiguration(WidgetManager& wm) override; public: - halnf mScrollFactor = 0.f; - halnf scrollInertia = 0.f; bool mIsScrolling = false; halnf mSizeFraction = 1.f; halnf mPositionFraction = 0.f; @@ -123,96 +36,33 @@ namespace tp { halnf mRounding = 10; }; - template - class ScrollableWindow : public Widget { + class ScrollableWindow : public Widget { public: - ScrollableWindow() { - this->mChildWidgets.pushBack(&mScroller); - this->mChildWidgets.pushBack(&mContentWidget); - } + ScrollableWindow(); - virtual ~ScrollableWindow() = default; + virtual ~ScrollableWindow(); // takes whole area - void eventProcess(const Events& events) override { - List*>& content = mContentWidget.mChildWidgets; + void eventProcess(const Events& events) override; - updateContents(content); - updateContentSize(content); + void addWidget(Widget* widget); + void clearContent(); + List& getContent(); - const auto padding = mPadding; + void eventUpdateConfiguration(WidgetManager& wm) override; - mScroller.mSizeFraction = mContentWidget.mArea.w / mContentSize; - mScroller.setArea(this->mArea); - mContentWidget.setArea(mScroller.getViewport()); - - if (mScroller.mSizeFraction > 1.f) { - setOffset(content, 0); - } else { - setOffset(content, (-mScroller.mPositionFraction) * mContentSize); - } - - for (auto widget : content) { - widget->setArea({ mContentWidget.mArea.x + padding, - mContentWidget.mArea.y + widget->mArea.y, - mScroller.getViewport().z - padding * 2, - widget->mArea.w }); - } - } - - void addWidget(Widget* widget) { mContentWidget.mChildWidgets.pushBack(widget); } - void clearContent() { mContentWidget.mChildWidgets.removeAll(); } - List*>& getContent() { return mContentWidget.mChildWidgets; } - - void eventUpdateConfiguration(WidgetManager& wm) override { - wm.setActiveId("ScrollableWidget"); - mPadding = wm.getNumber("Padding", "Padding"); - } - - [[nodiscard]] halnf getContentSize() const { - return mContentSize; - } + [[nodiscard]] halnf getContentSize() const; private: - void updateContents(List*>& contentWidgets) { - if (!contentWidgets.size()) { - return; - } - - const halnf offset = contentWidgets.first()->mArea.y + mPadding; - - halnf start = 0; - for (auto widget : contentWidgets) { - widget->mArea.y = start; - start += widget->mArea.w + mPadding; - } - - for (auto widget : contentWidgets) { - widget->mArea.y += offset; - } - } + void updateContents(List& contentWidgets); // ready content size - void updateContentSize(List*>& contentWidgets) { - mContentSize = 0; - if (contentWidgets.size()) { - mContentSize = contentWidgets.last()->mArea.y - contentWidgets.first()->mArea.y; - mContentSize += contentWidgets.last()->mArea.w; - mContentSize += 2 * mPadding; - } - } - - void setOffset(List*>& contentWidgets, const halnf offset) { - if (!contentWidgets.size()) return; - auto newOffset = offset - contentWidgets.first()->mArea.y + mPadding; - for (auto widget : contentWidgets) { - widget->mArea.y += newOffset; - } - } + void updateContentSize(List& contentWidgets); + void setOffset(List& contentWidgets, const halnf offset); private: - Widget mContentWidget; - ScrollBarWidget mScroller; + Widget mContentWidget; + ScrollBarWidget mScroller; halnf mContentSize = 0; diff --git a/Widgets/public/SliderWidget.hpp b/Widgets/public/SliderWidget.hpp index c0bf884..306275b 100644 --- a/Widgets/public/SliderWidget.hpp +++ b/Widgets/public/SliderWidget.hpp @@ -4,43 +4,17 @@ namespace tp { - template - class SliderWidget : public Widget { + class SliderWidget : public Widget { public: - SliderWidget() = default; + SliderWidget(); - void eventProcess(const Events& events) override { - if (this->isPressed()) { - mIsSliding = true; - } else if (events.isReleased(InputID::MOUSE1)) { - mIsSliding = false; - } + void eventProcess(const Events& events) override; + void eventDraw(Canvas& canvas) override; - if (mIsSliding) { - mFactor = (events.getPointer().x - this->mArea.x - handleSize / 2.f) / (this->mArea.z - handleSize); - } - - mFactor = tp::clamp(mFactor, 0.f, 1.f); - } - - void eventDraw(Canvas& canvas) override { - canvas.rect(this->mArea, defaultColor, rounding); - canvas.rect(getHandle(), handleColor, rounding); - } - - RectF getHandle() const { - const auto left = this->mArea.x + (this->mArea.z - handleSize) * mFactor; - return { left, this->mArea.y, handleSize, this->mArea.w }; - } + RectF getHandle() const; public: - void eventUpdateConfiguration(WidgetManager& wm) override { - wm.setActiveId("Slider"); - defaultColor = wm.getColor("Default", "Base"); - handleColor = wm.getColor("Handle", "Accent"); - handleSize = wm.getNumber("HandleSize", 20.f); - rounding = wm.getNumber("Rounding", "Rounding"); - } + void eventUpdateConfiguration(WidgetManager& wm) override; public: halnf mFactor = 0.f; @@ -52,35 +26,14 @@ namespace tp { halnf rounding = 0; }; - template - class NamedSliderWidget : public Widget { + class NamedSliderWidget : public Widget { public: - explicit NamedSliderWidget(const char* name = "Value") { - mLabel.mLabel = name; - this->mArea = { 0, 0, 100, 30 }; - - this->mChildWidgets.pushBack(&mSlider); - this->mChildWidgets.pushBack(&mLabel); - } - - void eventProcess(const Events& events) override { - const auto widthFirst = this->mArea.z * mFactor; - const auto widthSecond = this->mArea.z * (1.f - mFactor); - - RectF rec = this->mArea; - rec.size.x = widthFirst; - - mLabel.setArea(rec); - - rec.pos.x += widthFirst; - rec.size.x = widthSecond; - - mSlider.setArea(rec); - } + explicit NamedSliderWidget(const char* name = "Value"); + void eventProcess(const Events& events) override; public: - SliderWidget mSlider; - LabelWidget mLabel; + SliderWidget mSlider; + LabelWidget mLabel; halnf mFactor = 0.5f; }; diff --git a/Widgets/public/SplitViewWidget.hpp b/Widgets/public/SplitViewWidget.hpp index 7f83bfb..4922f6a 100644 --- a/Widgets/public/SplitViewWidget.hpp +++ b/Widgets/public/SplitViewWidget.hpp @@ -6,145 +6,24 @@ namespace tp { //TODO : clean up this mess // takes the whole parent area - template - class SplitView : public Widget { + class SplitView : public Widget { public: - SplitView() { - mLeftLabel.mLabel = "Left"; - mRightLabel.mLabel = "Right"; + SplitView(); - this->mChildWidgets.pushBack(&mLeftLabel); - this->mChildWidgets.pushBack(&mRightLabel); - } + void eventProcess(const Events& events) override; + void eventDraw(Canvas& canvas) override; - void eventProcess(const Events& events) override { - mIsHover = getHandle().isInside(events.getPointer()); + [[nodiscard]] bool getFirstEnabled() const; + [[nodiscard]] bool getSecondEnabled() const; - 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 eventDraw(Canvas& canvas) override { - if (mResizeInProcess) canvas.rect(getHandle(), mResizingColor); - else if (mIsHover) canvas.rect(getHandle(), mHoveredColor); - else canvas.rect(getHandle(), mHandleColor); - } - - [[nodiscard]] bool getFirstEnabled() const { - return mCollapsedSide != CollapsedSize::LEFT; - } - - [[nodiscard]] bool getSecondEnabled() const { - return mCollapsedSide != CollapsedSize::RIGHT; - } - - RectF 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 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 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 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 getHandle() const { - if (mCollapsedSide != NONE) return {}; - return { this->mArea.x + mFactor * this->mArea.z - mHandleSize / 2.f, this->mArea.y, mHandleSize, this->mArea.w }; - } + RectF getFirst() const; + RectF getFirstHeader() const; + RectF getSecondHeader() const; + RectF getSecond() const ; + RectF getHandle() const; public: - void eventUpdateConfiguration(WidgetManager& wm) override { - 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); - } + void eventUpdateConfiguration(WidgetManager& wm) override; public: halnf mFactor = 0.7f; @@ -159,10 +38,10 @@ namespace tp { // Headers halnf mHeaderSize = 0; - bool mHeaders = true; + bool mHeaders = false; enum CollapsedSize { NONE, LEFT, RIGHT } mCollapsedSide = NONE; - LabelWidget mLeftLabel; - LabelWidget mRightLabel; + LabelWidget mLeftLabel; + LabelWidget mRightLabel; }; } \ No newline at end of file diff --git a/Widgets/public/TextInputWidget.hpp b/Widgets/public/TextInputWidget.hpp index 67e95e7..7b25fdc 100644 --- a/Widgets/public/TextInputWidget.hpp +++ b/Widgets/public/TextInputWidget.hpp @@ -2,64 +2,15 @@ #include "WidgetBase.hpp" -#include "imgui.h" -#include "imgui_internal.h" - namespace tp { - template - class TextInputWidget : public Widget { + class TextInputWidget : public Widget { public: - TextInputWidget() = default; + TextInputWidget(); - void eventDraw(Canvas&) override { - nChanged = false; - - const auto col = mAccentColor; - const auto colSel = mHoveredColor; - - ImGui::GetStyle().Colors[ImGuiCol_FrameBg] = { col.r, col.g, col.b, col.a }; - ImGui::GetStyle().Colors[ImGuiCol_TextSelectedBg] = { colSel.r, colSel.g, colSel.b, colSel.a }; - - ImGui::SetNextWindowPos({ this->mArea.x, this->mArea.y }); - ImGui::SetNextWindowSize({ this->mArea.z, this->mArea.w }); - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 0, 0 }); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, mRounding * 1.5f); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { mPadding, mPadding }); - - // ImGui::PushID((int) alni(this)); - ImGui::Begin( - mId.c_str(), - 0, - ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBackground | - ImGuiWindowFlags_NoResize - ); - - if (mMultiline) { - if (ImGui::InputTextMultiline("input", mBuff, mMaxBufferSize, { this->mArea.z, this->mArea.w })) { - mValue = mBuff; - nChanged = true; - } - } else { - if (ImGui::InputTextEx("input", mId.c_str(), mBuff, mMaxBufferSize, { this->mArea.z, this->mArea.w }, 0)) { - mValue = mBuff; - nChanged = true; - } - } - - ImGui::End(); - ImGui::PopStyleVar(3); - } + void eventDraw(Canvas&) override; public: - void eventUpdateConfiguration(WidgetManager& wm) override { - wm.setActiveId("TextInput"); - - mAccentColor = wm.getColor("Accent", "Accent"); - mBaseColor = wm.getColor("Base", "Base"); - mRounding = wm.getNumber("Rounding", "Rounding"); - mHoveredColor = wm.getColor("Hovered", "Accent"); - mPadding = wm.getNumber("Padding", "Padding"); - } + void eventUpdateConfiguration(WidgetManager& wm) override; public: enum { mMaxBufferSize = 512 }; diff --git a/Widgets/public/WidgetBase.hpp b/Widgets/public/WidgetBase.hpp index 64b2f18..f7bcda9 100644 --- a/Widgets/public/WidgetBase.hpp +++ b/Widgets/public/WidgetBase.hpp @@ -1,149 +1,59 @@ #pragma once +#include "Graphics.hpp" + #include "EventHandler.hpp" #include "WidgetManager.hpp" #include "List.hpp" namespace tp { - template + using Events = EventHandler; + class Widget { public: - Widget() { mArea = { 0, 0, 100, 100 }; } + Widget(); + virtual ~Widget(); - virtual ~Widget() = default; + void procWrapper(const Events& events, const RectF& parentArea); + void drawWrapper(Canvas& canvas); + void updateConfigWrapper(WidgetManager& wm); - virtual void procWrapper(const Events& events, const RectF& parentArea) { - if (!mEnable) return; + virtual void eventProcess(const Events& events); + virtual void eventDraw(Canvas& canvas); + virtual void eventUpdateConfiguration(WidgetManager& wm); - checkVisibility(events, parentArea); + virtual void eventVisible(const Events& events); + virtual void eventNotVisible(const Events& events); - if (!mVisible) return; + virtual void eventFocusEnter(const Events& events); + virtual void eventFocusLeave(const Events& events); - checkFocus(events); - - checkClicked(events); - - eventProcess(events); - - for (auto child : mChildWidgets) { - child->procWrapper(events, getArea()); - } - } - - virtual void drawWrapper(Canvas& canvas) { - if (!mEnable || !mVisible) return; - - eventDraw(canvas); - - // draw child widgets - canvas.pushClamp(this->mArea); - for (auto child : mChildWidgets) { - child->drawWrapper(canvas); - } - canvas.popClamp(); - } - - virtual void updateConfigWrapper(WidgetManager& wm) { - wm.setActiveId("Global"); - - eventUpdateConfiguration(wm); - - for (auto child : mChildWidgets) { - child->updateConfigWrapper(wm); - } - } - - virtual void eventProcess(const Events& events) {} - virtual void eventDraw(Canvas& canvas) {} - virtual void eventUpdateConfiguration(WidgetManager& wm) {} - - virtual void eventVisible(const Events& events) {} - virtual void eventNotVisible(const Events& events) {} - - virtual void eventFocusEnter(const Events& events) {} - virtual void eventFocusLeave(const Events& events) {} - - virtual void eventPressed(const Events& events) {} - virtual void eventReleased(const Events& events) {} + virtual void eventPressed(const Events& events); + virtual void eventReleased(const Events& events); public: - void checkVisibility(const Events& events, const RectF& parentArea) { - const bool currentVisibility = parentArea.isOverlap(getArea()); + void setEnable(bool enable); + void setVisible(bool visible); + void setArea(const RectF& area); - if (currentVisibility != mVisible) { - if (currentVisibility) eventVisible(events); - else eventNotVisible(events); - } + [[nodiscard]] const RectF& getArea() const; + [[nodiscard]] bool isFocus() const; + [[nodiscard]] bool isPressed() const; + [[nodiscard]] bool isReleased() const; + [[nodiscard]] bool isHolding() const; - mVisible = currentVisibility; + void clearEvents(); - if (!mVisible) { - mHolding = false; - mPressed = false; - mReleased = false; - } - } - - void checkFocus(const Events& events) { - const bool currentFocus = getArea().isInside(events.getPointer()); - - if (currentFocus != mInFocus) { - if (currentFocus) eventFocusEnter(events); - else eventFocusLeave(events); - } - - mInFocus = currentFocus; - - if (!mInFocus) { - mHolding = false; - mPressed = false; - mReleased = false; - } - } - - void checkClicked(const Events& events) { - mPressed = false; - mReleased = false; - - if (!mInFocus) return; - - if (mHolding) { - if (events.isReleased(InputID::MOUSE1)) { - eventReleased(events); - mReleased = true; - mHolding = false; - } - } else { - if (events.isPressed(InputID::MOUSE1)) { - eventPressed(events); - mHolding = true; - mPressed = true; - } - } - } - - public: - void setEnable(bool enable) { mEnable = enable; } - void setVisible(bool visible) { mVisible = visible; } - void setArea(const RectF& area) { mArea = area; } - - const RectF& getArea() const { return mArea; } - bool isFocus() const { return mInFocus; } - bool isPressed() const { return mPressed; } - bool isReleased() const { return mReleased; } - bool isHolding() const { return mHolding; } - - void clearEvents() { - mReleased = false; - mPressed = false; - mHolding = false; - } + private: + void checkVisibility(const Events& events, const RectF& parentArea); + void checkFocus(const Events& events); + void checkClicked(const Events& events); public: RectF mArea; - List*> mChildWidgets; + List mChildWidgets; bool mVisible = false; bool mEnable = true; @@ -152,7 +62,5 @@ namespace tp { bool mHolding = false; bool mPressed = false; bool mReleased = false; - - // Vec2F mPressedRelativeLocation; }; } \ No newline at end of file diff --git a/Widgets/public/WidgetManager.hpp b/Widgets/public/WidgetManager.hpp index 8ef875a..fc1932e 100644 --- a/Widgets/public/WidgetManager.hpp +++ b/Widgets/public/WidgetManager.hpp @@ -60,77 +60,22 @@ namespace tp { using Parameter = WidgetConfig::Parameter; public: - WidgetManager() { initGlobalParameters(); } - ~WidgetManager() { mConfigurations.removeAll(); } + WidgetManager(); + ~WidgetManager(); - const RGBA& getColor(const std::string& parameterId, const RGBA& defaultValue) { - WidgetConfig& config = getWidgetConfig(mActiveId); - Parameter& parameter = getParameter(config, parameterId, Parameter(defaultValue)); - return parameter.color; - } + const RGBA& getColor(const std::string& parameterId, const RGBA& defaultValue); + const RGBA& getColor(const std::string& parameterId, const char* globalRef); - const RGBA& getColor(const std::string& parameterId, const char* globalRef) { - WidgetConfig& config = getWidgetConfig(mActiveId); - Parameter& parameter = getParameter(config, parameterId, Parameter(globalRef, Parameter::COL)); - return parameter.color; - } + halnf getNumber(const std::string& parameterId, halnf defaultValue); + halnf getNumber(const std::string& parameterId, const char* globalRef); - halnf getNumber(const std::string& parameterId, halnf defaultValue) { - WidgetConfig& config = getWidgetConfig(mActiveId); - Parameter& parameter = getParameter(config, parameterId, Parameter(defaultValue)); - return parameter.value; - } - - halnf getNumber(const std::string& parameterId, const char* globalRef) { - WidgetConfig& config = getWidgetConfig(mActiveId); - Parameter& parameter = getParameter(config, parameterId, Parameter(globalRef, Parameter::VAL)); - return parameter.value; - } - - void setActiveId(const std::string& id) { mActiveId = id; } + void setActiveId(const std::string& id); private: - WidgetConfig& getWidgetConfig(const std::string& id) { - auto idx = mConfigurations.presents(id); - if (idx) return mConfigurations.getSlotVal(idx); - mConfigurations.put(id, {}); - return mConfigurations.get(id); - } + WidgetConfig& getWidgetConfig(const std::string& id); + Parameter& getParameter(WidgetConfig& config, const std::string& id, const Parameter& defaultValue); - Parameter& getParameter(WidgetConfig& config, const std::string& id, const Parameter& defaultValue) { - auto idx = config.mParameters.presents(id); - - if (!idx) { - config.mParameters.put(id, defaultValue); - } - - Parameter& parameter = config.mParameters.get(id); - - if (parameter.globalReference) { - return mGlobalConfig.mParameters.get(parameter.globalId); - } else { - return parameter; - } - } - - void initGlobalParameters() { - auto& params = mGlobalConfig.mParameters; - - params.put("FontSize", Parameter(15.f)); - - params.put("FontSizeDim", Parameter(12.f)); - params.put("Rounding", Parameter(5.f)); - params.put("Padding", Parameter(5.f)); - params.put("HandleSize", Parameter(5.f)); - - params.put("Background", Parameter(RGBA{ 0.03f, 0.03f, 0.03f, 1.f })); - params.put("Base", Parameter(RGBA{ 0.07f, 0.07f, 0.07f, 1.f })); - params.put("Accent", Parameter(RGBA{ 0.13f, 0.13f, 0.13f, 1.f })); - params.put("Interaction", Parameter(RGBA{ 0.33f, 0.33f, 0.3f, 1.f })); - params.put("Action", Parameter(RGBA{ 0.44f, 0.44f, 0.4f, 1.f })); - params.put("Front", Parameter(RGBA{ 1.f, 1.f, 1.f, 1.f })); - params.put("FrontDim", Parameter(RGBA{ 0.7f, 0.7f, 0.7f, 1.f })); - } + void initGlobalParameters(); private: Map mConfigurations;