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

View File

@ -82,12 +82,12 @@ namespace Nz
inline void Hide();
inline bool IsVisible() const;
std::unique_ptr<BaseWidget> 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);

View File

@ -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<ScrollAreaWidgetStyle> 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;
};
}

View File

@ -3,21 +3,10 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Widgets/ScrollAreaWidget.hpp>
#include <NDK/Widgets/ScrollAreaWidget.hpp>
#include <Nazara/Widgets/Debug.hpp>
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;

View File

@ -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;

View File

@ -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();
}

View File

@ -127,6 +127,20 @@ namespace Nz
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)
{
// 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;

View File

@ -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 <Nazara/Widgets/ScrollAreaWidget.hpp>
#include <Nazara/Widgets/ScrollbarWidget.hpp>
#include <Nazara/Math/Algorithm.hpp>
#include <Nazara/Widgets/Debug.hpp>
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<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
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)
@ -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<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);
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<NodeComponent>().SetPosition(contentSize.x, 0.f);
m_scrollbarEntity->GetComponent<NodeComponent>().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<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)
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

View File

@ -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<ScrollbarButtonWidget>();