Widgets: Fix ScrollAreaWidget

This commit is contained in:
SirLynix 2022-07-20 13:37:45 +02:00 committed by Jérôme Leclercq
parent 0fcf24f336
commit e51695274c
9 changed files with 76 additions and 181 deletions

View File

@ -14,7 +14,7 @@
#include <Nazara/Utility/Components.hpp> #include <Nazara/Utility/Components.hpp>
#include <Nazara/Widgets.hpp> #include <Nazara/Widgets.hpp>
#include <Nazara/Widgets/ImageButtonWidget.hpp> #include <Nazara/Widgets/ImageButtonWidget.hpp>
#include <Nazara/Widgets/ScrollbarWidget.hpp> #include <Nazara/Widgets/ScrollAreaWidget.hpp>
#include <entt/entt.hpp> #include <entt/entt.hpp>
#include <array> #include <array>
#include <iostream> #include <iostream>
@ -101,12 +101,19 @@ int main()
Nz::CheckboxWidget* checkboxWidget = canvas2D.Add<Nz::CheckboxWidget>(); Nz::CheckboxWidget* checkboxWidget = canvas2D.Add<Nz::CheckboxWidget>();
//checkboxWidget->EnableTristate(true); //checkboxWidget->EnableTristate(true);
checkboxWidget->SetPosition(800.f, 800.f); checkboxWidget->SetPosition(800.f, 800.f);
checkboxWidget->Resize({ 256.f, 256.f }); checkboxWidget->Resize({ 256.f, 256 });
checkboxWidget->SetState(true); checkboxWidget->SetState(true);
Nz::ScrollbarWidget* scrollBarWidget = canvas2D.Add<Nz::ScrollbarWidget>(Nz::ScrollbarOrientation::Vertical); Nz::TextAreaWidget* longTextArea = canvas2D.Add<Nz::TextAreaWidget>();
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<Nz::ScrollAreaWidget>(longTextArea);
scrollBarWidget->SetPosition(1400.f, 800.f); scrollBarWidget->SetPosition(1400.f, 800.f);
scrollBarWidget->Resize({ 32.f, 256.f }); scrollBarWidget->Resize({ 512.f, 256.f });
/*Nz::TextAreaWidget* textAreaWidget2 = canvas2D.Add<Nz::TextAreaWidget>(); /*Nz::TextAreaWidget* textAreaWidget2 = canvas2D.Add<Nz::TextAreaWidget>();
textAreaWidget2->SetPosition(800.f, 700.f); textAreaWidget2->SetPosition(800.f, 700.f);

View File

@ -82,12 +82,12 @@ namespace Nz
inline void Hide(); inline void Hide();
inline bool IsVisible() const; inline bool IsVisible() const;
std::unique_ptr<BaseWidget> ReleaseFromParent();
void Resize(const Vector2f& size); void Resize(const Vector2f& size);
void SetBackgroundColor(const Color& color); void SetBackgroundColor(const Color& color);
void SetCursor(SystemCursor systemCursor); void SetCursor(SystemCursor systemCursor);
void SetFocus(); void SetFocus();
void SetParent(BaseWidget* widget);
inline void SetFixedHeight(float fixedHeight); inline void SetFixedHeight(float fixedHeight);
inline void SetFixedSize(const Vector2f& fixedSize); inline void SetFixedSize(const Vector2f& fixedSize);

View File

@ -13,6 +13,8 @@
namespace Nz namespace Nz
{ {
class ScrollbarWidget;
class NAZARA_WIDGETS_API ScrollAreaWidget : public BaseWidget class NAZARA_WIDGETS_API ScrollAreaWidget : public BaseWidget
{ {
public: public:
@ -23,8 +25,8 @@ namespace Nz
void EnableScrollbar(bool enable); void EnableScrollbar(bool enable);
inline float GetScrollHeight() const; float GetScrollHeight() const;
inline float GetScrollRatio() const; float GetScrollRatio() const;
inline bool HasScrollbar() const; inline bool HasScrollbar() const;
inline bool IsScrollbarEnabled() const; inline bool IsScrollbarEnabled() const;
@ -37,27 +39,15 @@ namespace Nz
ScrollAreaWidget& operator=(ScrollAreaWidget&&) = default; ScrollAreaWidget& operator=(ScrollAreaWidget&&) = default;
private: private:
Nz::Rectf GetScrollbarRect() const;
void Layout() override; void Layout() override;
void OnMouseButtonPress(int x, int y, Nz::Mouse::Button button) override; bool OnMouseWheelMoved(int x, int y, float delta) 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;
std::unique_ptr<ScrollAreaWidgetStyle> m_style; std::unique_ptr<ScrollAreaWidgetStyle> m_style;
BaseWidget* m_content; BaseWidget* m_content;
EntityHandle m_scrollbarBackgroundEntity; ScrollbarWidget* m_horizontalScrollbar;
EntityHandle m_scrollbarEntity;
Nz::SpriteRef m_scrollbarBackgroundSprite;
Nz::SpriteRef m_scrollbarSprite;
Nz::Vector2i m_grabbedDelta;
bool m_isGrabbed;
bool m_isScrollbarEnabled; bool m_isScrollbarEnabled;
bool m_hasScrollbar; bool m_hasScrollbar;
float m_scrollRatio;
}; };
} }

View File

@ -3,21 +3,10 @@
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Widgets/ScrollAreaWidget.hpp> #include <Nazara/Widgets/ScrollAreaWidget.hpp>
#include <NDK/Widgets/ScrollAreaWidget.hpp>
#include <Nazara/Widgets/Debug.hpp> #include <Nazara/Widgets/Debug.hpp>
namespace Nz 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 inline bool ScrollAreaWidget::HasScrollbar() const
{ {
return m_hasScrollbar; return m_hasScrollbar;

View File

@ -32,6 +32,8 @@ namespace Nz
ScrollbarWidget& operator=(const ScrollbarWidget&) = delete; ScrollbarWidget& operator=(const ScrollbarWidget&) = delete;
ScrollbarWidget& operator=(ScrollbarWidget&&) = default; ScrollbarWidget& operator=(ScrollbarWidget&&) = default;
NazaraSignal(OnScrollbarValueUpdate, ScrollbarWidget* /*emitter*/, float /*newValue*/);
private: private:
void Layout() override; void Layout() override;

View File

@ -36,6 +36,7 @@ namespace Nz
inline void ScrollbarWidget::SetValue(float newValue) inline void ScrollbarWidget::SetValue(float newValue)
{ {
m_value = Clamp(newValue, m_minimumValue, m_maximumValue); m_value = Clamp(newValue, m_minimumValue, m_maximumValue);
OnScrollbarValueUpdate(this, m_value);
Layout(); Layout();
} }

View File

@ -127,6 +127,20 @@ namespace Nz
return m_canvas->IsKeyboardOwner(m_canvasIndex); return m_canvas->IsKeyboardOwner(m_canvasIndex);
} }
std::unique_ptr<BaseWidget> 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<BaseWidget>& widgetPtr) { return widgetPtr.get() == this; });
assert(it != m_widgetParent->m_children.end());
std::unique_ptr<BaseWidget> ownerPtr = std::move(*it);
m_widgetParent->m_children.erase(it);
return ownerPtr;
}
void BaseWidget::Resize(const Vector2f& size) void BaseWidget::Resize(const Vector2f& size)
{ {
// Adjust new size // Adjust new size
@ -165,20 +179,6 @@ namespace Nz
m_canvas->SetKeyboardOwner(m_canvasIndex); 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) void BaseWidget::SetRenderingRect(const Rectf& renderingRect)
{ {
m_renderingRect = renderingRect; m_renderingRect = renderingRect;

View File

@ -2,47 +2,35 @@
// This file is part of the "Nazara Engine - Widgets module" // This file is part of the "Nazara Engine - Widgets module"
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
#if 0
#include <Nazara/Widgets/ScrollAreaWidget.hpp> #include <Nazara/Widgets/ScrollAreaWidget.hpp>
#include <Nazara/Widgets/ScrollbarWidget.hpp>
#include <Nazara/Math/Algorithm.hpp> #include <Nazara/Math/Algorithm.hpp>
#include <Nazara/Widgets/Debug.hpp> #include <Nazara/Widgets/Debug.hpp>
namespace Nz namespace Nz
{ {
namespace
{
constexpr float scrollbarPadding = 5.f;
}
ScrollAreaWidget::ScrollAreaWidget(BaseWidget* parent, BaseWidget* content) : ScrollAreaWidget::ScrollAreaWidget(BaseWidget* parent, BaseWidget* content) :
BaseWidget(parent), BaseWidget(parent),
m_content(content), m_content(content),
m_isGrabbed(false),
m_isScrollbarEnabled(true), 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_content->SetPosition(Nz::Vector3f::Zero());
m_style = GetTheme()->CreateStyle(this); //m_style = GetTheme()->CreateStyle(this);
SetRenderLayerCount(m_style->GetRenderLayerCount()); //SetRenderLayerCount(m_style->GetRenderLayerCount());
m_horizontalScrollbar = Add<ScrollbarWidget>(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<float>::infinity(), -contentPosition, std::numeric_limits<float>::infinity(), GetHeight()));
});
Resize(m_content->GetSize()); //< will automatically layout 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<NodeComponent>().SetParent(this);
m_scrollbarBackgroundEntity->AddComponent<GraphicsComponent>().Attach(m_scrollbarBackgroundSprite, 1);
m_scrollbarSprite = Nz::Sprite::New();
m_scrollbarSprite->SetColor(Nz::Color(104, 104, 104));
m_scrollbarEntity = CreateEntity();
m_scrollbarEntity->AddComponent<NodeComponent>().SetParent(this);
m_scrollbarEntity->AddComponent<GraphicsComponent>().Attach(m_scrollbarSprite);
} }
void ScrollAreaWidget::EnableScrollbar(bool enable) void ScrollAreaWidget::EnableScrollbar(bool enable)
@ -52,64 +40,49 @@ namespace Nz
m_isScrollbarEnabled = enable; m_isScrollbarEnabled = enable;
bool isVisible = IsScrollbarVisible(); bool isVisible = IsScrollbarVisible();
m_scrollbarEntity->Enable(isVisible); m_horizontalScrollbar->Show(isVisible);
m_scrollbarBackgroundEntity->Enable(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) void ScrollAreaWidget::ScrollToRatio(float ratio)
{ {
m_scrollRatio = Nz::Clamp(ratio, 0.f, 1.f); m_horizontalScrollbar->SetValue(ratio);
float widgetHeight = GetHeight();
float maxHeight = widgetHeight - m_scrollbarSprite->GetSize().y - 2.f * scrollbarPadding;
auto& scrollbarNode = m_scrollbarEntity->GetComponent<NodeComponent>();
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<float>::infinity(), -contentPosition, std::numeric_limits<float>::infinity(), widgetHeight));
}
Nz::Rectf ScrollAreaWidget::GetScrollbarRect() const
{
Nz::Vector2f scrollBarPosition = Nz::Vector2f(m_scrollbarEntity->GetComponent<NodeComponent>().GetPosition(Nz::CoordSys_Local));
Nz::Vector2f scrollBarSize = m_scrollbarSprite->GetSize();
return Nz::Rectf(scrollBarPosition.x, scrollBarPosition.y, scrollBarSize.x, scrollBarSize.y);
} }
void ScrollAreaWidget::Layout() void ScrollAreaWidget::Layout()
{ {
constexpr float scrollBarBackgroundWidth = 20.f; float scrollBarWidth = m_horizontalScrollbar->GetPreferredWidth();
constexpr float scrollBarWidth = scrollBarBackgroundWidth - 2.f * scrollbarPadding;
float areaWidth = GetWidth();
float areaHeight = GetHeight(); 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) if (contentHeight > areaHeight)
{ {
m_hasScrollbar = true; m_hasScrollbar = true;
Nz::Vector2f contentSize(GetWidth() - scrollBarBackgroundWidth, contentHeight); Nz::Vector2f contentSize(areaWidth - scrollBarWidth, contentHeight);
m_content->Resize(contentSize); m_content->Resize(contentSize);
if (m_isScrollbarEnabled) if (m_isScrollbarEnabled)
{ m_horizontalScrollbar->Show();
m_scrollbarEntity->Enable();
m_scrollbarBackgroundEntity->Enable();
}
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); ScrollToRatio(m_horizontalScrollbar->GetValue());
m_scrollbarSprite->SetSize(scrollBarWidth, scrollBarHeight);
m_scrollbarBackgroundEntity->GetComponent<NodeComponent>().SetPosition(contentSize.x, 0.f);
m_scrollbarEntity->GetComponent<NodeComponent>().SetPosition(contentSize.x + (scrollBarBackgroundWidth - scrollBarWidth) / 2.f, 0.f);
ScrollToRatio(m_scrollRatio);
} }
else else
{ {
@ -117,8 +90,7 @@ namespace Nz
m_content->Resize(GetSize()); m_content->Resize(GetSize());
m_scrollbarEntity->Disable(); m_horizontalScrollbar->Hide();
m_scrollbarBackgroundEntity->Disable();
ScrollToRatio(0.f); ScrollToRatio(0.f);
} }
@ -126,79 +98,11 @@ namespace Nz
BaseWidget::Layout(); BaseWidget::Layout();
} }
void ScrollAreaWidget::OnMouseButtonPress(int x, int y, Nz::Mouse::Button button) bool ScrollAreaWidget::OnMouseWheelMoved(int /*x*/, int /*y*/, float delta)
{
if (button != Nz::Mouse::Left)
return;
if (!m_isGrabbed)
{
m_style->OnGrab();
auto& scrollbarNode = m_scrollbarEntity->GetComponent<NodeComponent>();
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)
{ {
constexpr float scrollStep = 100.f; constexpr float scrollStep = 100.f;
ScrollToHeight(GetScrollHeight() - scrollStep * delta); ScrollToHeight(GetScrollHeight() - scrollStep * delta);
} return true;
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;
} }
} }
}
#endif

View File

@ -22,6 +22,8 @@ namespace Nz
m_style = GetTheme()->CreateStyle(this); m_style = GetTheme()->CreateStyle(this);
SetRenderLayerCount(m_style->GetRenderLayerCount()); SetRenderLayerCount(m_style->GetRenderLayerCount());
SetPreferredSize({ 32.f, 32.f });
const WidgetTheme::Config& themeConfig = GetTheme()->GetConfig(); const WidgetTheme::Config& themeConfig = GetTheme()->GetConfig();
m_scrollCenterButton = Add<ScrollbarButtonWidget>(); m_scrollCenterButton = Add<ScrollbarButtonWidget>();