From e51695274cc31d9355f9eaf808f66e5bc0ff6d7c Mon Sep 17 00:00:00 2001 From: SirLynix Date: Wed, 20 Jul 2022 13:37:45 +0200 Subject: [PATCH] Widgets: Fix ScrollAreaWidget --- examples/WidgetDemo/main.cpp | 15 +- include/Nazara/Widgets/BaseWidget.hpp | 2 +- include/Nazara/Widgets/ScrollAreaWidget.hpp | 22 +-- include/Nazara/Widgets/ScrollAreaWidget.inl | 11 -- include/Nazara/Widgets/ScrollbarWidget.hpp | 2 + include/Nazara/Widgets/ScrollbarWidget.inl | 1 + src/Nazara/Widgets/BaseWidget.cpp | 28 ++-- src/Nazara/Widgets/ScrollAreaWidget.cpp | 174 +++++--------------- src/Nazara/Widgets/ScrollbarWidget.cpp | 2 + 9 files changed, 76 insertions(+), 181 deletions(-) diff --git a/examples/WidgetDemo/main.cpp b/examples/WidgetDemo/main.cpp index 37cf0369c..5f501a9ff 100644 --- a/examples/WidgetDemo/main.cpp +++ b/examples/WidgetDemo/main.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -101,12 +101,19 @@ int main() Nz::CheckboxWidget* checkboxWidget = canvas2D.Add(); //checkboxWidget->EnableTristate(true); checkboxWidget->SetPosition(800.f, 800.f); - checkboxWidget->Resize({ 256.f, 256.f }); + checkboxWidget->Resize({ 256.f, 256 }); checkboxWidget->SetState(true); - Nz::ScrollbarWidget* scrollBarWidget = canvas2D.Add(Nz::ScrollbarOrientation::Vertical); + Nz::TextAreaWidget* longTextArea = canvas2D.Add(); + longTextArea->EnableLineWrap(true); + longTextArea->EnableMultiline(true); + longTextArea->SetBackgroundColor(Nz::Color::White); + longTextArea->SetTextColor(Nz::Color::Black); + longTextArea->SetText("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum"); + + Nz::ScrollAreaWidget* scrollBarWidget = canvas2D.Add(longTextArea); scrollBarWidget->SetPosition(1400.f, 800.f); - scrollBarWidget->Resize({ 32.f, 256.f }); + scrollBarWidget->Resize({ 512.f, 256.f }); /*Nz::TextAreaWidget* textAreaWidget2 = canvas2D.Add(); textAreaWidget2->SetPosition(800.f, 700.f); diff --git a/include/Nazara/Widgets/BaseWidget.hpp b/include/Nazara/Widgets/BaseWidget.hpp index 0d1bfd479..320b312ed 100644 --- a/include/Nazara/Widgets/BaseWidget.hpp +++ b/include/Nazara/Widgets/BaseWidget.hpp @@ -82,12 +82,12 @@ namespace Nz inline void Hide(); inline bool IsVisible() const; + std::unique_ptr ReleaseFromParent(); void Resize(const Vector2f& size); void SetBackgroundColor(const Color& color); void SetCursor(SystemCursor systemCursor); void SetFocus(); - void SetParent(BaseWidget* widget); inline void SetFixedHeight(float fixedHeight); inline void SetFixedSize(const Vector2f& fixedSize); diff --git a/include/Nazara/Widgets/ScrollAreaWidget.hpp b/include/Nazara/Widgets/ScrollAreaWidget.hpp index 406512829..5fb81a44f 100644 --- a/include/Nazara/Widgets/ScrollAreaWidget.hpp +++ b/include/Nazara/Widgets/ScrollAreaWidget.hpp @@ -13,6 +13,8 @@ namespace Nz { + class ScrollbarWidget; + class NAZARA_WIDGETS_API ScrollAreaWidget : public BaseWidget { public: @@ -23,8 +25,8 @@ namespace Nz void EnableScrollbar(bool enable); - inline float GetScrollHeight() const; - inline float GetScrollRatio() const; + float GetScrollHeight() const; + float GetScrollRatio() const; inline bool HasScrollbar() const; inline bool IsScrollbarEnabled() const; @@ -37,27 +39,15 @@ namespace Nz ScrollAreaWidget& operator=(ScrollAreaWidget&&) = default; private: - Nz::Rectf GetScrollbarRect() const; - void Layout() override; - void OnMouseButtonPress(int x, int y, Nz::Mouse::Button button) override; - void OnMouseButtonRelease(int x, int y, Nz::Mouse::Button button) override; - void OnMouseExit() override; - void OnMouseMoved(int x, int y, int deltaX, int deltaY) override; - void OnMouseWheelMoved(int x, int y, float delta) override; + bool OnMouseWheelMoved(int x, int y, float delta) override; std::unique_ptr m_style; BaseWidget* m_content; - EntityHandle m_scrollbarBackgroundEntity; - EntityHandle m_scrollbarEntity; - Nz::SpriteRef m_scrollbarBackgroundSprite; - Nz::SpriteRef m_scrollbarSprite; - Nz::Vector2i m_grabbedDelta; - bool m_isGrabbed; + ScrollbarWidget* m_horizontalScrollbar; bool m_isScrollbarEnabled; bool m_hasScrollbar; - float m_scrollRatio; }; } diff --git a/include/Nazara/Widgets/ScrollAreaWidget.inl b/include/Nazara/Widgets/ScrollAreaWidget.inl index 14a1d62ab..517009a7e 100644 --- a/include/Nazara/Widgets/ScrollAreaWidget.inl +++ b/include/Nazara/Widgets/ScrollAreaWidget.inl @@ -3,21 +3,10 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include #include namespace Nz { - inline float ScrollAreaWidget::GetScrollHeight() const - { - return m_scrollRatio * m_content->GetHeight(); - } - - inline float ScrollAreaWidget::GetScrollRatio() const - { - return m_scrollRatio; - } - inline bool ScrollAreaWidget::HasScrollbar() const { return m_hasScrollbar; diff --git a/include/Nazara/Widgets/ScrollbarWidget.hpp b/include/Nazara/Widgets/ScrollbarWidget.hpp index f9c073374..d7b4f39df 100644 --- a/include/Nazara/Widgets/ScrollbarWidget.hpp +++ b/include/Nazara/Widgets/ScrollbarWidget.hpp @@ -32,6 +32,8 @@ namespace Nz ScrollbarWidget& operator=(const ScrollbarWidget&) = delete; ScrollbarWidget& operator=(ScrollbarWidget&&) = default; + NazaraSignal(OnScrollbarValueUpdate, ScrollbarWidget* /*emitter*/, float /*newValue*/); + private: void Layout() override; diff --git a/include/Nazara/Widgets/ScrollbarWidget.inl b/include/Nazara/Widgets/ScrollbarWidget.inl index a85edb811..6ce1fb760 100644 --- a/include/Nazara/Widgets/ScrollbarWidget.inl +++ b/include/Nazara/Widgets/ScrollbarWidget.inl @@ -36,6 +36,7 @@ namespace Nz inline void ScrollbarWidget::SetValue(float newValue) { m_value = Clamp(newValue, m_minimumValue, m_maximumValue); + OnScrollbarValueUpdate(this, m_value); Layout(); } diff --git a/src/Nazara/Widgets/BaseWidget.cpp b/src/Nazara/Widgets/BaseWidget.cpp index 22e7e0326..49c05f159 100644 --- a/src/Nazara/Widgets/BaseWidget.cpp +++ b/src/Nazara/Widgets/BaseWidget.cpp @@ -127,6 +127,20 @@ namespace Nz return m_canvas->IsKeyboardOwner(m_canvasIndex); } + std::unique_ptr BaseWidget::ReleaseFromParent() + { + if (!m_widgetParent) + return {}; + + auto it = std::find_if(m_widgetParent->m_children.begin(), m_widgetParent->m_children.end(), [&](const std::unique_ptr& widgetPtr) { return widgetPtr.get() == this; }); + assert(it != m_widgetParent->m_children.end()); + + std::unique_ptr ownerPtr = std::move(*it); + m_widgetParent->m_children.erase(it); + + return ownerPtr; + } + void BaseWidget::Resize(const Vector2f& size) { // Adjust new size @@ -165,20 +179,6 @@ namespace Nz m_canvas->SetKeyboardOwner(m_canvasIndex); } - void BaseWidget::SetParent(BaseWidget* widget) - { - Canvas* oldCanvas = m_canvas; - Canvas* newCanvas = widget->GetCanvas(); - - // Changing a widget canvas is a problem because of the canvas entities - NazaraAssert(oldCanvas == newCanvas, "Transferring a widget between canvas is not yet supported"); - - Node::SetParent(widget); - m_widgetParent = widget; - - Layout(); - } - void BaseWidget::SetRenderingRect(const Rectf& renderingRect) { m_renderingRect = renderingRect; diff --git a/src/Nazara/Widgets/ScrollAreaWidget.cpp b/src/Nazara/Widgets/ScrollAreaWidget.cpp index 21635efe7..c70c7d970 100644 --- a/src/Nazara/Widgets/ScrollAreaWidget.cpp +++ b/src/Nazara/Widgets/ScrollAreaWidget.cpp @@ -2,47 +2,35 @@ // This file is part of the "Nazara Engine - Widgets module" // For conditions of distribution and use, see copyright notice in Config.hpp -#if 0 - #include +#include #include #include namespace Nz { - namespace - { - constexpr float scrollbarPadding = 5.f; - } - ScrollAreaWidget::ScrollAreaWidget(BaseWidget* parent, BaseWidget* content) : BaseWidget(parent), m_content(content), - m_isGrabbed(false), m_isScrollbarEnabled(true), - m_scrollRatio(0.f) + m_hasScrollbar(false) { - m_content->SetParent(this); + AddChild(m_content->ReleaseFromParent()); m_content->SetPosition(Nz::Vector3f::Zero()); - m_style = GetTheme()->CreateStyle(this); - SetRenderLayerCount(m_style->GetRenderLayerCount()); + //m_style = GetTheme()->CreateStyle(this); + //SetRenderLayerCount(m_style->GetRenderLayerCount()); + + m_horizontalScrollbar = Add(ScrollbarOrientation::Vertical); + m_horizontalScrollbar->OnScrollbarValueUpdate.Connect([this](ScrollbarWidget*, float newValue) + { + float contentPosition = (GetHeight() - m_content->GetHeight()) * (1.f - newValue); + + m_content->SetPosition(0.f, contentPosition); + m_content->SetRenderingRect(Nz::Rectf(-std::numeric_limits::infinity(), -contentPosition, std::numeric_limits::infinity(), GetHeight())); + }); Resize(m_content->GetSize()); //< will automatically layout - - m_scrollbarBackgroundSprite = Nz::Sprite::New(); - m_scrollbarBackgroundSprite->SetColor(Nz::Color(62, 62, 62)); - - m_scrollbarBackgroundEntity = CreateEntity(); - m_scrollbarBackgroundEntity->AddComponent().SetParent(this); - m_scrollbarBackgroundEntity->AddComponent().Attach(m_scrollbarBackgroundSprite, 1); - - m_scrollbarSprite = Nz::Sprite::New(); - m_scrollbarSprite->SetColor(Nz::Color(104, 104, 104)); - - m_scrollbarEntity = CreateEntity(); - m_scrollbarEntity->AddComponent().SetParent(this); - m_scrollbarEntity->AddComponent().Attach(m_scrollbarSprite); } void ScrollAreaWidget::EnableScrollbar(bool enable) @@ -52,64 +40,49 @@ namespace Nz m_isScrollbarEnabled = enable; bool isVisible = IsScrollbarVisible(); - m_scrollbarEntity->Enable(isVisible); - m_scrollbarBackgroundEntity->Enable(isVisible); + m_horizontalScrollbar->Show(isVisible); } } + float ScrollAreaWidget::GetScrollHeight() const + { + return m_horizontalScrollbar->GetValue() * m_content->GetHeight(); + } + + float ScrollAreaWidget::GetScrollRatio() const + { + return m_horizontalScrollbar->GetValue(); + } + void ScrollAreaWidget::ScrollToRatio(float ratio) { - m_scrollRatio = Nz::Clamp(ratio, 0.f, 1.f); - - float widgetHeight = GetHeight(); - float maxHeight = widgetHeight - m_scrollbarSprite->GetSize().y - 2.f * scrollbarPadding; - - auto& scrollbarNode = m_scrollbarEntity->GetComponent(); - scrollbarNode.SetPosition(Nz::Vector2f(scrollbarNode.GetPosition(Nz::CoordSys_Local).x, scrollbarPadding + m_scrollRatio * maxHeight)); - - float contentPosition = m_scrollRatio * (widgetHeight - m_content->GetHeight()); - - m_content->SetPosition(0.f, contentPosition); - m_content->SetRenderingRect(Nz::Rectf(-std::numeric_limits::infinity(), -contentPosition, std::numeric_limits::infinity(), widgetHeight)); - } - - Nz::Rectf ScrollAreaWidget::GetScrollbarRect() const - { - Nz::Vector2f scrollBarPosition = Nz::Vector2f(m_scrollbarEntity->GetComponent().GetPosition(Nz::CoordSys_Local)); - Nz::Vector2f scrollBarSize = m_scrollbarSprite->GetSize(); - return Nz::Rectf(scrollBarPosition.x, scrollBarPosition.y, scrollBarSize.x, scrollBarSize.y); + m_horizontalScrollbar->SetValue(ratio); } void ScrollAreaWidget::Layout() { - constexpr float scrollBarBackgroundWidth = 20.f; - constexpr float scrollBarWidth = scrollBarBackgroundWidth - 2.f * scrollbarPadding; + float scrollBarWidth = m_horizontalScrollbar->GetPreferredWidth(); + float areaWidth = GetWidth(); float areaHeight = GetHeight(); - float contentHeight = m_content->GetHeight(); + + m_content->Resize({ areaWidth, areaHeight }); //< setting width with line wrap adjust preferred height + float contentHeight = m_content->GetPreferredHeight(); if (contentHeight > areaHeight) { m_hasScrollbar = true; - Nz::Vector2f contentSize(GetWidth() - scrollBarBackgroundWidth, contentHeight); + Nz::Vector2f contentSize(areaWidth - scrollBarWidth, contentHeight); m_content->Resize(contentSize); if (m_isScrollbarEnabled) - { - m_scrollbarEntity->Enable(); - m_scrollbarBackgroundEntity->Enable(); - } + m_horizontalScrollbar->Show(); - float scrollBarHeight = std::max(std::floor(areaHeight * (areaHeight / contentHeight)), 20.f); + m_horizontalScrollbar->SetPosition(contentSize.x, 0.f); + m_horizontalScrollbar->Resize({ scrollBarWidth, GetHeight() }); - m_scrollbarBackgroundSprite->SetSize(scrollBarBackgroundWidth, areaHeight); - m_scrollbarSprite->SetSize(scrollBarWidth, scrollBarHeight); - - m_scrollbarBackgroundEntity->GetComponent().SetPosition(contentSize.x, 0.f); - m_scrollbarEntity->GetComponent().SetPosition(contentSize.x + (scrollBarBackgroundWidth - scrollBarWidth) / 2.f, 0.f); - - ScrollToRatio(m_scrollRatio); + ScrollToRatio(m_horizontalScrollbar->GetValue()); } else { @@ -117,8 +90,7 @@ namespace Nz m_content->Resize(GetSize()); - m_scrollbarEntity->Disable(); - m_scrollbarBackgroundEntity->Disable(); + m_horizontalScrollbar->Hide(); ScrollToRatio(0.f); } @@ -126,79 +98,11 @@ namespace Nz BaseWidget::Layout(); } - void ScrollAreaWidget::OnMouseButtonPress(int x, int y, Nz::Mouse::Button button) - { - if (button != Nz::Mouse::Left) - return; - - if (!m_isGrabbed) - { - m_style->OnGrab(); - - auto& scrollbarNode = m_scrollbarEntity->GetComponent(); - - m_grabbedDelta.Set(x, int(y - scrollbarNode.GetPosition(Nz::CoordSys_Local).y)); - } - } - - void ScrollAreaWidget::OnMouseButtonRelease(int x, int y, Nz::Mouse::Button button) - { - if (button != Nz::Mouse::Left) - return; - - if (m_scrollbarStatus == ScrollBarStatus::Grabbed) - { - Nz::Rectf scrollBarRect = GetScrollbarRect(); - UpdateScrollbarStatus((scrollBarRect.Contains(Nz::Vector2f(float(x), float(y)))) ? ScrollBarStatus::Hovered : ScrollBarStatus::None); - } - } - - void ScrollAreaWidget::OnMouseExit() - { - //if (m_scrollbarStatus == ScrollBarStatus::Hovered) - UpdateScrollbarStatus(ScrollBarStatus::None); - } - - void ScrollAreaWidget::OnMouseMoved(int x, int y, int /*deltaX*/, int /*deltaY*/) - { - if (m_scrollbarStatus == ScrollBarStatus::Grabbed) - { - float height = GetHeight(); - float maxHeight = height - m_scrollbarSprite->GetSize().y; - float newHeight = Nz::Clamp(float(y - m_grabbedDelta.y), 0.f, maxHeight); - - ScrollToHeight(newHeight / maxHeight * m_content->GetHeight()); - } - else - { - Nz::Rectf scrollBarRect = GetScrollbarRect(); - UpdateScrollbarStatus((scrollBarRect.Contains(Nz::Vector2f(float(x), float(y)))) ? ScrollBarStatus::Hovered : ScrollBarStatus::None); - } - } - - void ScrollAreaWidget::OnMouseWheelMoved(int /*x*/, int /*y*/, float delta) + bool ScrollAreaWidget::OnMouseWheelMoved(int /*x*/, int /*y*/, float delta) { constexpr float scrollStep = 100.f; ScrollToHeight(GetScrollHeight() - scrollStep * delta); - } - - void ScrollAreaWidget::UpdateScrollbarStatus(ScrollBarStatus status) - { - if (m_scrollbarStatus != status) - { - Nz::Color newColor; - switch (status) - { - case ScrollBarStatus::Grabbed: newColor = Nz::Color(235, 235, 235); break; - case ScrollBarStatus::Hovered: newColor = Nz::Color(152, 152, 152); break; - case ScrollBarStatus::None: newColor = Nz::Color(104, 104, 104); break; - } - - m_scrollbarSprite->SetColor(newColor); - m_scrollbarStatus = status; - } + return true; } } - -#endif diff --git a/src/Nazara/Widgets/ScrollbarWidget.cpp b/src/Nazara/Widgets/ScrollbarWidget.cpp index e75786a14..50d9dd73e 100644 --- a/src/Nazara/Widgets/ScrollbarWidget.cpp +++ b/src/Nazara/Widgets/ScrollbarWidget.cpp @@ -22,6 +22,8 @@ namespace Nz m_style = GetTheme()->CreateStyle(this); SetRenderLayerCount(m_style->GetRenderLayerCount()); + SetPreferredSize({ 32.f, 32.f }); + const WidgetTheme::Config& themeConfig = GetTheme()->GetConfig(); m_scrollCenterButton = Add();