diff --git a/examples/WidgetDemo/main.cpp b/examples/WidgetDemo/main.cpp index 86e04f4eb..37cf0369c 100644 --- a/examples/WidgetDemo/main.cpp +++ b/examples/WidgetDemo/main.cpp @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include #include @@ -80,11 +82,14 @@ int main() basicMat.SetBaseColorMap(Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/diffuse.png", texParams)); basicMat.SetBaseColorSampler(samplerInfo); - Nz::ImageWidget* imageWidget = canvas2D.Add(); + Nz::ImageWidget* imageWidget = canvas2D.Add(material); imageWidget->SetPosition(1200.f, 200.f); - imageWidget->SetMaterial(material); imageWidget->Resize(imageWidget->GetPreferredSize() / 4.f); + Nz::ImageButtonWidget* imageButtonWidget = canvas2D.Add(material); + imageButtonWidget->SetPosition(1400, 500.f); + imageButtonWidget->Resize(imageButtonWidget->GetPreferredSize() / 4.f); + Nz::TextAreaWidget* textAreaWidget = canvas2D.Add(); textAreaWidget->SetPosition(800.f, 500.f); textAreaWidget->SetText("Je suis un TextAreaWidget !"); @@ -99,6 +104,10 @@ int main() checkboxWidget->Resize({ 256.f, 256.f }); checkboxWidget->SetState(true); + Nz::ScrollbarWidget* scrollBarWidget = canvas2D.Add(Nz::ScrollbarOrientation::Vertical); + scrollBarWidget->SetPosition(1400.f, 800.f); + scrollBarWidget->Resize({ 32.f, 256.f }); + /*Nz::TextAreaWidget* textAreaWidget2 = canvas2D.Add(); textAreaWidget2->SetPosition(800.f, 700.f); textAreaWidget2->SetText("Je suis un autre TextAreaWidget !"); diff --git a/include/Nazara/Widgets/BoxLayout.hpp b/include/Nazara/Widgets/BoxLayout.hpp new file mode 100644 index 000000000..adbd7deda --- /dev/null +++ b/include/Nazara/Widgets/BoxLayout.hpp @@ -0,0 +1,41 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Widgets module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_WIDGETS_BOXLAYOUT_HPP +#define NAZARA_WIDGETS_BOXLAYOUT_HPP + +#include +#include +#include +#include + +namespace Nz +{ + class NDK_CLIENT_API BoxLayout : public BaseWidget + { + public: + BoxLayout(BaseWidget* parent, BoxLayoutOrientation orientation); + BoxLayout(const BoxLayout&) = delete; + BoxLayout(BoxLayout&&) = delete; + ~BoxLayout(); + + void Layout() override; + + BoxLayout& operator=(const BoxLayout&) = delete; + BoxLayout& operator=(BoxLayout&&) = delete; + + private: + struct State; + + std::unique_ptr m_state; + BoxLayoutOrientation m_orientation; + float m_spacing; + }; +} + +#include + +#endif // NAZARA_WIDGETS_BOXLAYOUT_HPP diff --git a/include/Nazara/Widgets/BoxLayout.inl b/include/Nazara/Widgets/BoxLayout.inl new file mode 100644 index 000000000..2264db0bc --- /dev/null +++ b/include/Nazara/Widgets/BoxLayout.inl @@ -0,0 +1,13 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Widgets module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ +} + +#include diff --git a/include/Nazara/Widgets/DefaultWidgetTheme.hpp b/include/Nazara/Widgets/DefaultWidgetTheme.hpp index 3bba7ad98..29d1ffb83 100644 --- a/include/Nazara/Widgets/DefaultWidgetTheme.hpp +++ b/include/Nazara/Widgets/DefaultWidgetTheme.hpp @@ -23,8 +23,12 @@ namespace Nz ~DefaultWidgetTheme() = default; std::unique_ptr CreateStyle(ButtonWidget* buttonWidget) const override; - std::unique_ptr CreateStyle(CheckboxWidget* buttonWidget) const override; - std::unique_ptr CreateStyle(LabelWidget* buttonWidget) const override; + std::unique_ptr CreateStyle(CheckboxWidget* checkboxWidget) const override; + std::unique_ptr CreateStyle(ImageButtonWidget* imageButtonWidget) const override; + std::unique_ptr CreateStyle(LabelWidget* labelWidget) const override; + std::unique_ptr CreateStyle(ScrollAreaWidget* scrollAreaWidget) const override; + std::unique_ptr CreateStyle(ScrollbarWidget* scrollbarWidget) const override; + std::unique_ptr CreateStyle(ScrollbarButtonWidget* scrollbarButtonWidget) const override; DefaultWidgetTheme& operator=(const DefaultWidgetTheme&) = delete; DefaultWidgetTheme& operator=(DefaultWidgetTheme&&) = default; @@ -38,6 +42,12 @@ namespace Nz std::shared_ptr m_checkboxBackgroundHoveredMaterial; std::shared_ptr m_checkboxCheckMaterial; std::shared_ptr m_checkboxTristateMaterial; + std::shared_ptr m_hoveredMaterial; + std::shared_ptr m_scrollbarBackgroundHorizontalMaterial; + std::shared_ptr m_scrollbarBackgroundVerticalMaterial; + std::shared_ptr m_scrollbarButtonMaterial; + std::shared_ptr m_scrollbarButtonHoveredMaterial; + std::shared_ptr m_scrollbarButtonGrabbedMaterial; }; } diff --git a/include/Nazara/Widgets/Enums.hpp b/include/Nazara/Widgets/Enums.hpp index 450b1ef7c..4795b6b03 100644 --- a/include/Nazara/Widgets/Enums.hpp +++ b/include/Nazara/Widgets/Enums.hpp @@ -32,6 +32,12 @@ namespace Nz Max = Normal }; + + enum class ScrollbarOrientation + { + Horizontal, + Vertical + }; } #endif // NAZARA_WIDGETS_ENUMS_HPP diff --git a/include/Nazara/Widgets/ImageButtonWidget.hpp b/include/Nazara/Widgets/ImageButtonWidget.hpp new file mode 100644 index 000000000..cab8b3a41 --- /dev/null +++ b/include/Nazara/Widgets/ImageButtonWidget.hpp @@ -0,0 +1,76 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Widgets module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_WIDGETS_IMAGEBUTTONWIDGET_HPP +#define NAZARA_WIDGETS_IMAGEBUTTONWIDGET_HPP + +#include +#include +#include +#include +#include + +namespace Nz +{ + class AbstractTextDrawer; + class MaterialPass; + + class NAZARA_WIDGETS_API ImageButtonWidget : public BaseWidget + { + public: + inline ImageButtonWidget(BaseWidget* parent, std::shared_ptr material); + inline ImageButtonWidget(BaseWidget* parent, std::shared_ptr material, float cornerSize, float cornerTexCoords); + ImageButtonWidget(BaseWidget* parent, std::shared_ptr material, std::shared_ptr hoveredMaterial, std::shared_ptr pressedMaterial, float cornerSize, float cornerTexCoords); + ImageButtonWidget(const ImageButtonWidget&) = delete; + ImageButtonWidget(ImageButtonWidget&&) = default; + ~ImageButtonWidget() = default; + + inline const Color& GetColor() const; + inline float GetCornerSize() const; + inline float GetCornerTexCoords() const; + inline const std::shared_ptr& GetHoveredMaterial() const; + inline const std::shared_ptr& GetMaterial() const; + inline const std::shared_ptr& GetPressedMaterial() const; + inline const Rectf& GetTextureCoords() const; + + inline void SetColor(const Color& color); + inline void SetCorner(float size, float texcoords); + inline void SetHoveredMaterial(std::shared_ptr material); + inline void SetMaterial(std::shared_ptr material); + inline void SetPressedMaterial(std::shared_ptr material); + inline void SetTextureCoords(const Rectf& coords); + + ImageButtonWidget& operator=(const ImageButtonWidget&) = delete; + ImageButtonWidget& operator=(ImageButtonWidget&&) = default; + + NazaraSignal(OnButtonTrigger, const ImageButtonWidget* /*button*/); + + private: + void Layout() override; + + void OnMouseEnter() override; + void OnMouseButtonPress(int x, int y, Mouse::Button button) override; + void OnMouseButtonRelease(int x, int y, Mouse::Button button) override; + void OnMouseExit() override; + + void OnRenderLayerUpdated(int baseRenderLayer) override; + + void UpdatePreferredSize(); + + std::unique_ptr m_style; + std::shared_ptr m_hoveredMaterial; + std::shared_ptr m_material; + std::shared_ptr m_pressedMaterial; + Color m_color; + Rectf m_textureCoords; + float m_cornerSize; + float m_cornerTexCoords; + }; +} + +#include + +#endif // NAZARA_WIDGETS_IMAGEBUTTONWIDGET_HPP diff --git a/include/Nazara/Widgets/ImageButtonWidget.inl b/include/Nazara/Widgets/ImageButtonWidget.inl new file mode 100644 index 000000000..b571e3171 --- /dev/null +++ b/include/Nazara/Widgets/ImageButtonWidget.inl @@ -0,0 +1,101 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Widgets module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + inline ImageButtonWidget::ImageButtonWidget(BaseWidget* parent, std::shared_ptr material) : + ImageButtonWidget(parent, std::move(material), {}, {}, 0.f, 0.f) + { + } + + inline ImageButtonWidget::ImageButtonWidget(BaseWidget* parent, std::shared_ptr material, float cornerSize, float cornerTexCoords) : + ImageButtonWidget(parent, std::move(material), {}, {}, cornerSize, cornerTexCoords) + { + } + + inline const Color& ImageButtonWidget::GetColor() const + { + return m_color; + } + + inline float ImageButtonWidget::GetCornerSize() const + { + return m_cornerSize; + } + + inline float ImageButtonWidget::GetCornerTexCoords() const + { + return m_cornerTexCoords; + } + + inline const std::shared_ptr& ImageButtonWidget::GetHoveredMaterial() const + { + return m_hoveredMaterial; + } + + inline const std::shared_ptr& ImageButtonWidget::GetMaterial() const + { + return m_material; + } + + inline const std::shared_ptr& ImageButtonWidget::GetPressedMaterial() const + { + return m_pressedMaterial; + } + + inline const Rectf& ImageButtonWidget::GetTextureCoords() const + { + return m_textureCoords; + } + + inline void ImageButtonWidget::SetColor(const Color& color) + { + m_color = color; + + m_style->OnUpdate(); + } + + inline void ImageButtonWidget::SetCorner(float size, float texcoords) + { + m_cornerSize = size; + m_cornerTexCoords = texcoords; + + m_style->OnUpdate(); + } + + inline void ImageButtonWidget::SetHoveredMaterial(std::shared_ptr material) + { + m_hoveredMaterial = std::move(material); + + m_style->OnUpdate(); + } + + inline void ImageButtonWidget::SetMaterial(std::shared_ptr material) + { + m_material = std::move(material); + UpdatePreferredSize(); + + m_style->OnUpdate(); + } + + inline void ImageButtonWidget::SetPressedMaterial(std::shared_ptr material) + { + m_pressedMaterial = std::move(material); + + m_style->OnUpdate(); + } + + inline void ImageButtonWidget::SetTextureCoords(const Rectf& coords) + { + m_textureCoords = coords; + UpdatePreferredSize(); + + m_style->OnUpdate(); + } +} + +#include diff --git a/include/Nazara/Widgets/ImageWidget.hpp b/include/Nazara/Widgets/ImageWidget.hpp index 03d2588cf..55475d96d 100644 --- a/include/Nazara/Widgets/ImageWidget.hpp +++ b/include/Nazara/Widgets/ImageWidget.hpp @@ -17,7 +17,7 @@ namespace Nz class NAZARA_WIDGETS_API ImageWidget : public BaseWidget { public: - ImageWidget(BaseWidget* parent); + ImageWidget(BaseWidget* parent, std::shared_ptr material); ImageWidget(const ImageWidget&) = delete; ImageWidget(ImageWidget&&) = default; ~ImageWidget() = default; @@ -36,6 +36,7 @@ namespace Nz private: void Layout() override; + inline void UpdatePreferredSize(); entt::entity m_entity; std::shared_ptr m_sprite; diff --git a/include/Nazara/Widgets/ImageWidget.inl b/include/Nazara/Widgets/ImageWidget.inl index 3b689b1df..0b0df34ba 100644 --- a/include/Nazara/Widgets/ImageWidget.inl +++ b/include/Nazara/Widgets/ImageWidget.inl @@ -30,7 +30,23 @@ namespace Nz inline void ImageWidget::SetMaterial(const std::shared_ptr& texture) { m_sprite->SetMaterial(texture); + UpdatePreferredSize(); + } + inline void ImageWidget::SetTextureCoords(const Rectf& coords) + { + m_sprite->SetTextureCoords(coords); + UpdatePreferredSize(); + } + + inline void ImageWidget::SetTextureRect(const Rectf& rect) + { + m_sprite->SetTextureRect(rect); + UpdatePreferredSize(); + } + + inline void ImageWidget::UpdatePreferredSize() + { const Rectf& textureCoords = GetTextureCoords(); Vector2f textureSize = Vector2f(Vector2ui(m_sprite->GetTextureSize())); @@ -39,16 +55,6 @@ namespace Nz SetPreferredSize(textureSize); } - - inline void ImageWidget::SetTextureCoords(const Rectf& coords) - { - m_sprite->SetTextureCoords(coords); - } - - inline void ImageWidget::SetTextureRect(const Rectf& rect) - { - m_sprite->SetTextureRect(rect); - } } #include diff --git a/include/Nazara/Widgets/ProgressBarWidget.hpp b/include/Nazara/Widgets/ProgressBarWidget.hpp new file mode 100644 index 000000000..896d05d6d --- /dev/null +++ b/include/Nazara/Widgets/ProgressBarWidget.hpp @@ -0,0 +1,101 @@ +// Copyright (C) 2022 Samy Bensaid +// This file is part of the "Nazara Engine - Widgets module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_WIDGETS_PROGRESSBARWIDGET_HPP +#define NAZARA_WIDGETS_PROGRESSBARWIDGET_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class NDK_CLIENT_API ProgressBarWidget : public BaseWidget + { + friend class Sdk; + + public: + ProgressBarWidget(BaseWidget* parent); + ProgressBarWidget(const ProgressBarWidget&) = delete; + ProgressBarWidget(ProgressBarWidget&&) = default; + ~ProgressBarWidget() = default; + + //virtual ProgressBarWidget* Clone() const = 0; + + inline void EnableText(bool enable = true); + inline void EnableBorder(bool enable = true); + + inline bool IsTextEnabled() const; + inline bool IsBorderEnabled() const; + + + inline unsigned GetPercentageValue() const; + inline Nz::Vector2f GetProgressBarSize() const; + inline Nz::Vector2f GetProgressBarBorderSize() const; + inline float GetTextMargin() const; + + + inline const Nz::Color& GetBarBackgroundColor() const; + inline const Nz::Color& GetBarBackgroundCornerColor() const; + inline const Nz::Color& GetBarColor() const; + inline const Nz::Color& GetBarCornerColor() const; + + inline const Nz::TextureRef& GetBarBackgroundTexture() const; + inline const Nz::TextureRef& GetBarTexture() const; + + static const Nz::Color& GetDefaultBarColor(); + static const Nz::Color& GetDefaultBarCornerColor(); + static const Nz::Color& GetDefaultBarBackgroundColor(); + static const Nz::Color& GetDefaultBarBackgroundCornerColor(); + + + inline void SetBarBackgroundColor(const Nz::Color& globalColor, const Nz::Color& cornerColor); + inline void SetBarBackgroundTexture(Nz::TextureRef texture, bool resetColors = true); + inline void SetBarColor(const Nz::Color& globalColor, const Nz::Color& cornerColor); + inline void SetBarTexture(Nz::TextureRef texture, bool resetColors = true); + + + inline void SetPercentageValue(unsigned percentage); + inline void SetTextMargin(float margin); + inline void SetTextColor(const Nz::Color& color); + + NazaraSignal(OnValueChanged, const ProgressBarWidget* /*progressBar*/); + + private: + void Layout() override; + inline void UpdateText(); + + + EntityHandle m_borderEntity; + EntityHandle m_barEntity; + EntityHandle m_textEntity; + + static Nz::Color s_borderColor; + static Nz::Color s_barBackgroundColor; + static Nz::Color s_barBackgroundCornerColor; + static Nz::Color s_barColor; + static Nz::Color s_barCornerColor; + Nz::Color m_textColor; + + Nz::SpriteRef m_borderSprite; + Nz::SpriteRef m_barBackgroundSprite; + Nz::SpriteRef m_barSprite; + Nz::TextSpriteRef m_textSprite; + + static float s_borderScale; + float m_textMargin; + unsigned m_value; + }; +} + +#include + +#endif // NAZARA_WIDGETS_PROGRESSBARWIDGET_HPP diff --git a/include/Nazara/Widgets/ProgressBarWidget.inl b/include/Nazara/Widgets/ProgressBarWidget.inl new file mode 100644 index 000000000..e88e69390 --- /dev/null +++ b/include/Nazara/Widgets/ProgressBarWidget.inl @@ -0,0 +1,155 @@ +// Copyright (C) 2022 Samy Bensaid +// This file is part of the "Nazara Engine - Widgets module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +namespace Nz +{ + inline void ProgressBarWidget::EnableText(bool enable) + { + m_textEntity->Enable(enable); + Layout(); + } + + inline void ProgressBarWidget::EnableBorder(bool enable) + { + m_borderEntity->Enable(enable); + } + + inline bool ProgressBarWidget::IsTextEnabled() const + { + return m_textEntity->IsEnabled(); + } + + inline bool ProgressBarWidget::IsBorderEnabled() const + { + return m_borderEntity->IsEnabled(); + } + + + inline unsigned ProgressBarWidget::GetPercentageValue() const + { + return m_value; + } + + inline Nz::Vector2f ProgressBarWidget::GetProgressBarSize() const + { + Nz::Vector3f progressBarSize = m_borderSprite->GetBoundingVolume().obb.localBox.GetLengths(); + + if (IsTextEnabled()) + { + Nz::Vector3f textSize = m_textSprite->GetBoundingVolume().obb.localBox.GetLengths(); + progressBarSize -= { textSize.x + m_textMargin, 0.f, 0.f }; + } + + return { progressBarSize.x, progressBarSize.y }; + } + + inline Nz::Vector2f ProgressBarWidget::GetProgressBarBorderSize() const + { + Nz::Vector2f barSize = GetProgressBarSize(); + return { barSize.y / s_borderScale, barSize.y / s_borderScale }; + } + + inline float ProgressBarWidget::GetTextMargin() const + { + return m_textMargin; + } + + + inline const Nz::Color& ProgressBarWidget::GetBarBackgroundColor() const + { + return m_barBackgroundSprite->GetColor(); + } + + inline const Nz::Color& ProgressBarWidget::GetBarBackgroundCornerColor() const + { + return m_barBackgroundSprite->GetCornerColor(Nz::RectCorner_LeftTop); + } + + inline const Nz::Color& ProgressBarWidget::GetBarColor() const + { + return m_barSprite->GetColor(); + } + + inline const Nz::Color& ProgressBarWidget::GetBarCornerColor() const + { + return m_barSprite->GetCornerColor(Nz::RectCorner_LeftTop); + } + + + inline const Nz::TextureRef& ProgressBarWidget::GetBarBackgroundTexture() const + { + return m_barBackgroundSprite->GetMaterial()->GetDiffuseMap(); + } + + inline const Nz::TextureRef& ProgressBarWidget::GetBarTexture() const + { + return m_barSprite->GetMaterial()->GetDiffuseMap(); + } + + + inline void ProgressBarWidget::SetBarBackgroundColor(const Nz::Color& globalColor, const Nz::Color& cornerColor) + { + m_barBackgroundSprite->SetColor(globalColor); + m_barBackgroundSprite->SetCornerColor(Nz::RectCorner_LeftTop, cornerColor); + m_barBackgroundSprite->SetCornerColor(Nz::RectCorner_RightTop, cornerColor); + m_barBackgroundSprite->SetCornerColor(Nz::RectCorner_LeftBottom, globalColor); + m_barBackgroundSprite->SetCornerColor(Nz::RectCorner_RightBottom, globalColor); + } + + inline void ProgressBarWidget::SetBarBackgroundTexture(Nz::TextureRef texture, bool resetColors) + { + m_barBackgroundSprite->SetTexture(texture, false); + + if (resetColors) + SetBarBackgroundColor(Nz::Color::White, Nz::Color::White); + } + + inline void ProgressBarWidget::SetBarColor(const Nz::Color& globalColor, const Nz::Color& cornerColor) + { + m_barSprite->SetColor(globalColor); + m_barSprite->SetCornerColor(Nz::RectCorner_LeftTop, cornerColor); + m_barSprite->SetCornerColor(Nz::RectCorner_RightTop, cornerColor); + m_barSprite->SetCornerColor(Nz::RectCorner_LeftBottom, globalColor); + m_barSprite->SetCornerColor(Nz::RectCorner_RightBottom, globalColor); + } + + inline void ProgressBarWidget::SetBarTexture(Nz::TextureRef texture, bool resetColors) + { + m_barSprite->SetTexture(texture, false); + + if (resetColors) + SetBarColor(Nz::Color::White, Nz::Color::White); + } + + + inline void ProgressBarWidget::SetPercentageValue(unsigned percentage) + { + m_value = percentage; + OnValueChanged(this); + Layout(); + } + + inline void ProgressBarWidget::SetTextMargin(float margin) + { + m_textMargin = margin; + + if (IsTextEnabled()) + Layout(); + } + + inline void ProgressBarWidget::SetTextColor(const Nz::Color& color) + { + m_textColor = color; + UpdateText(); + } + + inline void ProgressBarWidget::UpdateText() + { + if (IsTextEnabled()) + { + Nz::Vector2f size = GetSize(); + m_textSprite->Update(Nz::SimpleTextDrawer::Draw(Nz::String::Number(m_value).Append('%'), static_cast(std::min(size.x, size.y) / 2.f), 0u, m_textColor)); + } + } +} diff --git a/include/Nazara/Widgets/ScrollAreaWidget.hpp b/include/Nazara/Widgets/ScrollAreaWidget.hpp new file mode 100644 index 000000000..406512829 --- /dev/null +++ b/include/Nazara/Widgets/ScrollAreaWidget.hpp @@ -0,0 +1,66 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Widgets module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_WIDGETS_SCROLLAREAWIDGET_HPP +#define NAZARA_WIDGETS_SCROLLAREAWIDGET_HPP + +#include +#include +#include + +namespace Nz +{ + class NAZARA_WIDGETS_API ScrollAreaWidget : public BaseWidget + { + public: + ScrollAreaWidget(BaseWidget* parent, BaseWidget* content); + ScrollAreaWidget(const ScrollAreaWidget&) = delete; + ScrollAreaWidget(ScrollAreaWidget&&) = default; + ~ScrollAreaWidget() = default; + + void EnableScrollbar(bool enable); + + inline float GetScrollHeight() const; + inline float GetScrollRatio() const; + + inline bool HasScrollbar() const; + inline bool IsScrollbarEnabled() const; + inline bool IsScrollbarVisible() const; + + inline void ScrollToHeight(float height); + void ScrollToRatio(float ratio); + + ScrollAreaWidget& operator=(const ScrollAreaWidget&) = delete; + 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; + + 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; + bool m_isScrollbarEnabled; + bool m_hasScrollbar; + float m_scrollRatio; + }; +} + +#include + +#endif // NAZARA_WIDGETS_SCROLLAREAWIDGET_HPP diff --git a/include/Nazara/Widgets/ScrollAreaWidget.inl b/include/Nazara/Widgets/ScrollAreaWidget.inl new file mode 100644 index 000000000..14a1d62ab --- /dev/null +++ b/include/Nazara/Widgets/ScrollAreaWidget.inl @@ -0,0 +1,43 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Widgets module" +// 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; + } + + inline bool ScrollAreaWidget::IsScrollbarEnabled() const + { + return m_isScrollbarEnabled; + } + + inline bool ScrollAreaWidget::IsScrollbarVisible() const + { + return HasScrollbar() && IsScrollbarEnabled(); + } + + inline void ScrollAreaWidget::ScrollToHeight(float height) + { + float contentHeight = m_content->GetHeight(); + ScrollToRatio(height / contentHeight); + } +} + +#include diff --git a/include/Nazara/Widgets/ScrollbarButtonWidget.hpp b/include/Nazara/Widgets/ScrollbarButtonWidget.hpp new file mode 100644 index 000000000..ec45e2d7a --- /dev/null +++ b/include/Nazara/Widgets/ScrollbarButtonWidget.hpp @@ -0,0 +1,54 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Widgets module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_WIDGETS_SCROLLBARBUTTONWIDGET_HPP +#define NAZARA_WIDGETS_SCROLLBARBUTTONWIDGET_HPP + +#include +#include +#include +#include +#include + +namespace Nz +{ + class AbstractTextDrawer; + class MaterialPass; + + class NAZARA_WIDGETS_API ScrollbarButtonWidget : public BaseWidget + { + public: + inline ScrollbarButtonWidget(BaseWidget* parent); + ScrollbarButtonWidget(const ScrollbarButtonWidget&) = delete; + ScrollbarButtonWidget(ScrollbarButtonWidget&&) = default; + ~ScrollbarButtonWidget() = default; + + ScrollbarButtonWidget& operator=(const ScrollbarButtonWidget&) = delete; + ScrollbarButtonWidget& operator=(ScrollbarButtonWidget&&) = default; + + NazaraSignal(OnButtonGrabbed, ScrollbarButtonWidget* /*emitter*/, int /*x*/, int /*y*/); + NazaraSignal(OnButtonMoved, ScrollbarButtonWidget* /*emitter*/, int /*x*/, int /*y*/); + NazaraSignal(OnButtonReleased, ScrollbarButtonWidget* /*emitter*/); + + private: + void Layout() override; + + void OnMouseEnter() override; + void OnMouseButtonPress(int x, int y, Mouse::Button button) override; + void OnMouseButtonRelease(int x, int y, Mouse::Button button) override; + void OnMouseExit() override; + void OnMouseMoved(int x, int y, int deltaX, int deltaY) override; + + void OnRenderLayerUpdated(int baseRenderLayer) override; + + std::unique_ptr m_style; + bool m_isGrabbed; + }; +} + +#include + +#endif // NAZARA_WIDGETS_SCROLLBARBUTTONWIDGET_HPP diff --git a/include/Nazara/Widgets/ScrollbarButtonWidget.inl b/include/Nazara/Widgets/ScrollbarButtonWidget.inl new file mode 100644 index 000000000..c8cacd466 --- /dev/null +++ b/include/Nazara/Widgets/ScrollbarButtonWidget.inl @@ -0,0 +1,12 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Widgets module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ +} + +#include diff --git a/include/Nazara/Widgets/ScrollbarWidget.hpp b/include/Nazara/Widgets/ScrollbarWidget.hpp new file mode 100644 index 000000000..f9c073374 --- /dev/null +++ b/include/Nazara/Widgets/ScrollbarWidget.hpp @@ -0,0 +1,60 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Widgets module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_WIDGETS_SCROLLBARWIDGET_HPP +#define NAZARA_WIDGETS_SCROLLBARWIDGET_HPP + +#include +#include +#include + +namespace Nz +{ + class NAZARA_WIDGETS_API ScrollbarWidget : public BaseWidget + { + public: + ScrollbarWidget(BaseWidget* parent, ScrollbarOrientation orientation); + ScrollbarWidget(const ScrollbarWidget&) = delete; + ScrollbarWidget(ScrollbarWidget&&) = default; + ~ScrollbarWidget() = default; + + inline ScrollbarOrientation GetOrientation() const; + inline float GetMaximumValue() const; + inline float GetMinimumValue() const; + inline float GetStep() const; + inline float GetValue() const; + + inline void SetValue(float newValue); + + ScrollbarWidget& operator=(const ScrollbarWidget&) = delete; + ScrollbarWidget& operator=(ScrollbarWidget&&) = default; + + private: + void Layout() override; + + void OnMouseEnter() override; + void OnMouseExit() override; + + void OnRenderLayerUpdated(int baseRenderLayer); + + std::unique_ptr m_style; + ImageButtonWidget* m_scrollBackButton; + ImageButtonWidget* m_scrollNextButton; + ScrollbarButtonWidget* m_scrollCenterButton; + ScrollbarOrientation m_orientation; + bool m_isGrabbed; + float m_maximumValue; + float m_minimumValue; + float m_step; + float m_value; + float m_grabbedValue; + int m_grabbedPosition; + }; +} + +#include + +#endif // NAZARA_WIDGETS_SCROLLBARWIDGET_HPP diff --git a/include/Nazara/Widgets/ScrollbarWidget.inl b/include/Nazara/Widgets/ScrollbarWidget.inl new file mode 100644 index 000000000..a85edb811 --- /dev/null +++ b/include/Nazara/Widgets/ScrollbarWidget.inl @@ -0,0 +1,44 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Widgets module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + inline ScrollbarOrientation ScrollbarWidget::GetOrientation() const + { + return m_orientation; + } + + inline float ScrollbarWidget::GetMaximumValue() const + { + return m_maximumValue; + } + + inline float ScrollbarWidget::GetMinimumValue() const + { + return m_minimumValue; + } + + inline float ScrollbarWidget::GetStep() const + { + return m_step; + } + + inline float ScrollbarWidget::GetValue() const + { + return m_value; + } + + inline void ScrollbarWidget::SetValue(float newValue) + { + m_value = Clamp(newValue, m_minimumValue, m_maximumValue); + + Layout(); + } +} + +#include diff --git a/include/Nazara/Widgets/SimpleWidgetStyles.hpp b/include/Nazara/Widgets/SimpleWidgetStyles.hpp index 3970dc85d..d108c512e 100644 --- a/include/Nazara/Widgets/SimpleWidgetStyles.hpp +++ b/include/Nazara/Widgets/SimpleWidgetStyles.hpp @@ -7,6 +7,7 @@ #ifndef NAZARA_WIDGETS_SIMPLEWIDGETSTYLES_HPP #define NAZARA_WIDGETS_SIMPLEWIDGETSTYLES_HPP +#include #include #include #include @@ -108,7 +109,48 @@ namespace Nz entt::entity m_checkEntity; bool m_isHovered; }; + + class NAZARA_WIDGETS_API SimpleImageButtonWidgetStyle : public ImageButtonWidgetStyle + { + public: + struct StyleConfig; + SimpleImageButtonWidgetStyle(ImageButtonWidget* imageButtonWidget, StyleConfig config); + SimpleImageButtonWidgetStyle(const SimpleImageButtonWidgetStyle&) = delete; + SimpleImageButtonWidgetStyle(SimpleImageButtonWidgetStyle&&) = default; + ~SimpleImageButtonWidgetStyle() = default; + + void Layout(const Vector2f& size) override; + + void OnHoverBegin() override; + void OnHoverEnd() override; + void OnPress() override; + void OnRelease() override; + void OnUpdate() override; + + void UpdateRenderLayer(int baseRenderLayer) override; + + SimpleImageButtonWidgetStyle& operator=(const SimpleImageButtonWidgetStyle&) = delete; + SimpleImageButtonWidgetStyle& operator=(SimpleImageButtonWidgetStyle&&) = default; + + struct StyleConfig + { + std::shared_ptr hoveredMaterial; + float hoveredCornerSize; + float hoveredCornerTexCoords; + }; + + protected: + virtual void Update(bool hovered, bool pressed); + + private: + std::shared_ptr m_hoveredSprite; + std::shared_ptr m_sprite; + entt::entity m_entity; + bool m_isHovered; + bool m_isPressed; + }; + class NAZARA_WIDGETS_API SimpleLabelWidgetStyle : public LabelWidgetStyle { public: @@ -137,6 +179,106 @@ namespace Nz std::shared_ptr m_textSprite; entt::entity m_entity; }; + + class NAZARA_WIDGETS_API SimpleScrollAreaWidgetStyle : public ScrollAreaWidgetStyle + { + public: + SimpleScrollAreaWidgetStyle(ScrollAreaWidget* scrollAreaWidget); + SimpleScrollAreaWidgetStyle(const SimpleScrollAreaWidgetStyle&) = delete; + SimpleScrollAreaWidgetStyle(SimpleScrollAreaWidgetStyle&&) = default; + ~SimpleScrollAreaWidgetStyle() = default; + + void Layout(const Vector2f& size) override; + + void UpdateRenderLayer(int baseRenderLayer) override; + + SimpleScrollAreaWidgetStyle& operator=(const SimpleScrollAreaWidgetStyle&) = delete; + SimpleScrollAreaWidgetStyle& operator=(SimpleScrollAreaWidgetStyle&&) = default; + + private: + std::shared_ptr m_hoveredMaterial; + std::shared_ptr m_material; + std::shared_ptr m_textSprite; + entt::entity m_entity; + }; + + class NAZARA_WIDGETS_API SimpleScrollbarWidgetStyle : public ScrollbarWidgetStyle + { + public: + struct StyleConfig; + + SimpleScrollbarWidgetStyle(ScrollbarWidget* scrollBarWidget, StyleConfig config); + SimpleScrollbarWidgetStyle(const SimpleScrollbarWidgetStyle&) = delete; + SimpleScrollbarWidgetStyle(SimpleScrollbarWidgetStyle&&) = default; + ~SimpleScrollbarWidgetStyle() = default; + + void Layout(const Vector2f& size) override; + + void UpdateRenderLayer(int baseRenderLayer) override; + + SimpleScrollbarWidgetStyle& operator=(const SimpleScrollbarWidgetStyle&) = delete; + SimpleScrollbarWidgetStyle& operator=(SimpleScrollbarWidgetStyle&&) = default; + + struct StyleConfig + { + std::shared_ptr backgroundHorizontalMaterial; + std::shared_ptr backgroundVerticalMaterial; + }; + + private: + StyleConfig m_config; + std::shared_ptr m_backgroundScrollbarSprite; + std::shared_ptr m_scrollbarSprite; + entt::entity m_backgroundScrollbarSpriteEntity; + entt::entity m_scrollbarSpriteEntity; + }; + + class NAZARA_WIDGETS_API SimpleScrollbarButtonWidgetStyle : public ScrollbarButtonWidgetStyle + { + public: + struct StyleConfig; + + SimpleScrollbarButtonWidgetStyle(ScrollbarButtonWidget* scrollbarButtonWidget, StyleConfig config); + SimpleScrollbarButtonWidgetStyle(const SimpleScrollbarWidgetStyle&) = delete; + SimpleScrollbarButtonWidgetStyle(SimpleScrollbarButtonWidgetStyle&&) = default; + ~SimpleScrollbarButtonWidgetStyle() = default; + + void Layout(const Vector2f& size) override; + + void OnHoverBegin() override; + void OnHoverEnd() override; + void OnGrab() override; + void OnRelease() override; + + void UpdateRenderLayer(int baseRenderLayer) override; + + SimpleScrollbarButtonWidgetStyle& operator=(const SimpleScrollbarButtonWidgetStyle&) = delete; + SimpleScrollbarButtonWidgetStyle& operator=(SimpleScrollbarButtonWidgetStyle&&) = default; + + struct StyleConfig + { + std::shared_ptr material; + std::shared_ptr grabbedMaterial; + std::shared_ptr grabbedHoveredMaterial; + std::shared_ptr hoveredMaterial; + float cornerSize; + float cornerTexCoords; + }; + + protected: + virtual void Update(bool hovered, bool pressed); + + private: + StyleConfig m_config; + std::shared_ptr m_hoveredMaterial; + std::shared_ptr m_material; + std::shared_ptr m_pressedMaterial; + std::shared_ptr m_pressedHoveredMaterial; + std::shared_ptr m_sprite; + entt::entity m_entity; + bool m_isHovered; + bool m_isPressed; + }; } #include diff --git a/include/Nazara/Widgets/WidgetTheme.hpp b/include/Nazara/Widgets/WidgetTheme.hpp index 394c1e9d7..9c22c3b30 100644 --- a/include/Nazara/Widgets/WidgetTheme.hpp +++ b/include/Nazara/Widgets/WidgetTheme.hpp @@ -20,25 +20,60 @@ namespace Nz class ButtonWidgetStyle; class CheckboxWidget; class CheckboxWidgetStyle; + class ImageButtonWidget; + class ImageButtonWidgetStyle; class LabelWidget; class LabelWidgetStyle; + class ScrollAreaWidget; + class ScrollAreaWidgetStyle; + class ScrollbarWidget; + class ScrollbarWidgetStyle; + class ScrollbarButtonWidget; + class ScrollbarButtonWidgetStyle; class NAZARA_WIDGETS_API WidgetTheme { public: + struct Config; + WidgetTheme() = default; WidgetTheme(const WidgetTheme&) = delete; WidgetTheme(WidgetTheme&&) = default; virtual ~WidgetTheme(); virtual std::unique_ptr CreateStyle(ButtonWidget* buttonWidget) const = 0; - virtual std::unique_ptr CreateStyle(CheckboxWidget* buttonWidget) const = 0; - virtual std::unique_ptr CreateStyle(LabelWidget* buttonWidget) const = 0; + virtual std::unique_ptr CreateStyle(CheckboxWidget* checkboxWidget) const = 0; + virtual std::unique_ptr CreateStyle(ImageButtonWidget* imageButtonWidget) const = 0; + virtual std::unique_ptr CreateStyle(LabelWidget* labelWidget) const = 0; + virtual std::unique_ptr CreateStyle(ScrollAreaWidget* scrollareaWidget) const = 0; + virtual std::unique_ptr CreateStyle(ScrollbarWidget* scrollbarWidget) const = 0; + virtual std::unique_ptr CreateStyle(ScrollbarButtonWidget* scrollbarButtonWidget) const = 0; + + inline const Config& GetConfig() const; WidgetTheme& operator=(const WidgetTheme&) = delete; WidgetTheme& operator=(WidgetTheme&&) = default; - private: + struct Config + { + std::shared_ptr scrollbarButtonDownMaterial; + std::shared_ptr scrollbarButtonDownHoveredMaterial; + std::shared_ptr scrollbarButtonDownPressedMaterial; + std::shared_ptr scrollbarButtonLeftMaterial; + std::shared_ptr scrollbarButtonLeftHoveredMaterial; + std::shared_ptr scrollbarButtonLeftPressedMaterial; + std::shared_ptr scrollbarButtonRightMaterial; + std::shared_ptr scrollbarButtonRightHoveredMaterial; + std::shared_ptr scrollbarButtonRightPressedMaterial; + std::shared_ptr scrollbarButtonUpMaterial; + std::shared_ptr scrollbarButtonUpHoveredMaterial; + std::shared_ptr scrollbarButtonUpPressedMaterial; + float scrollbarButtonCornerSize; + float scrollbarButtonCornerTexcoords; + }; + + protected: + Config m_config; }; class NAZARA_WIDGETS_API BaseWidgetStyle @@ -53,6 +88,7 @@ namespace Nz entt::entity CreateGraphicsEntity(); inline void DestroyEntity(entt::entity entity); + template T* GetOwnerWidget() const; inline entt::registry& GetRegistry(); inline const entt::registry& GetRegistry() const; UInt32 GetRenderMask() const; @@ -88,7 +124,7 @@ namespace Nz ButtonWidgetStyle& operator=(const ButtonWidgetStyle&) = delete; ButtonWidgetStyle& operator=(ButtonWidgetStyle&&) = default; }; - + class NAZARA_WIDGETS_API CheckboxWidgetStyle : public BaseWidgetStyle { public: @@ -108,6 +144,26 @@ namespace Nz CheckboxWidgetStyle& operator=(const CheckboxWidgetStyle&) = delete; CheckboxWidgetStyle& operator=(CheckboxWidgetStyle&&) = default; }; + + class NAZARA_WIDGETS_API ImageButtonWidgetStyle : public BaseWidgetStyle + { + public: + using BaseWidgetStyle::BaseWidgetStyle; + ImageButtonWidgetStyle(const ImageButtonWidgetStyle&) = delete; + ImageButtonWidgetStyle(ImageButtonWidgetStyle&&) = default; + ~ImageButtonWidgetStyle() = default; + + virtual void Layout(const Vector2f& size) = 0; + + virtual void OnHoverBegin(); + virtual void OnHoverEnd(); + virtual void OnPress(); + virtual void OnRelease(); + virtual void OnUpdate() = 0; + + ImageButtonWidgetStyle& operator=(const ImageButtonWidgetStyle&) = delete; + ImageButtonWidgetStyle& operator=(ImageButtonWidgetStyle&&) = default; + }; class NAZARA_WIDGETS_API LabelWidgetStyle : public BaseWidgetStyle { @@ -127,6 +183,58 @@ namespace Nz LabelWidgetStyle& operator=(const LabelWidgetStyle&) = delete; LabelWidgetStyle& operator=(LabelWidgetStyle&&) = default; }; + + class NAZARA_WIDGETS_API ScrollAreaWidgetStyle : public BaseWidgetStyle + { + public: + using BaseWidgetStyle::BaseWidgetStyle; + ScrollAreaWidgetStyle(const ScrollAreaWidgetStyle&) = delete; + ScrollAreaWidgetStyle(ScrollAreaWidgetStyle&&) = default; + ~ScrollAreaWidgetStyle() = default; + + virtual void Layout(const Vector2f& size) = 0; + + ScrollAreaWidgetStyle& operator=(const ScrollAreaWidgetStyle&) = delete; + ScrollAreaWidgetStyle& operator=(ScrollAreaWidgetStyle&&) = default; + }; + + class NAZARA_WIDGETS_API ScrollbarWidgetStyle : public BaseWidgetStyle + { + public: + using BaseWidgetStyle::BaseWidgetStyle; + ScrollbarWidgetStyle(const ScrollbarWidgetStyle&) = delete; + ScrollbarWidgetStyle(ScrollbarWidgetStyle&&) = default; + ~ScrollbarWidgetStyle() = default; + + virtual void Layout(const Vector2f& size) = 0; + + virtual void OnButtonGrab(); + virtual void OnButtonRelease(); + virtual void OnHoverBegin(); + virtual void OnHoverEnd(); + + ScrollbarWidgetStyle& operator=(const ScrollbarWidgetStyle&) = delete; + ScrollbarWidgetStyle& operator=(ScrollbarWidgetStyle&&) = default; + }; + + class NAZARA_WIDGETS_API ScrollbarButtonWidgetStyle : public BaseWidgetStyle + { + public: + using BaseWidgetStyle::BaseWidgetStyle; + ScrollbarButtonWidgetStyle(const ScrollbarButtonWidgetStyle&) = delete; + ScrollbarButtonWidgetStyle(ScrollbarButtonWidgetStyle&&) = default; + ~ScrollbarButtonWidgetStyle() = default; + + virtual void Layout(const Vector2f& size) = 0; + + virtual void OnHoverBegin(); + virtual void OnHoverEnd(); + virtual void OnGrab(); + virtual void OnRelease(); + + ScrollbarButtonWidgetStyle& operator=(const ScrollbarButtonWidgetStyle&) = delete; + ScrollbarButtonWidgetStyle& operator=(ScrollbarButtonWidgetStyle&&) = default; + }; } #include diff --git a/include/Nazara/Widgets/WidgetTheme.inl b/include/Nazara/Widgets/WidgetTheme.inl index 4f171d6be..9f5258e49 100644 --- a/include/Nazara/Widgets/WidgetTheme.inl +++ b/include/Nazara/Widgets/WidgetTheme.inl @@ -3,11 +3,18 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include namespace Nz { + inline auto WidgetTheme::GetConfig() const -> const Config& + { + return m_config; + } + + inline BaseWidgetStyle::BaseWidgetStyle(BaseWidget* widget, int renderLayerCount) : m_widgetOwner(widget), m_renderLayerCount(renderLayerCount) @@ -25,6 +32,12 @@ namespace Nz m_widgetOwner->DestroyEntity(entity); } + template + T* BaseWidgetStyle::GetOwnerWidget() const + { + return SafeCast(m_widgetOwner); + } + inline entt::registry& BaseWidgetStyle::GetRegistry() { return m_widgetOwner->GetRegistry(); diff --git a/src/Nazara/Widgets/BaseWidget.cpp b/src/Nazara/Widgets/BaseWidget.cpp index f7f869f11..3ec725e5e 100644 --- a/src/Nazara/Widgets/BaseWidget.cpp +++ b/src/Nazara/Widgets/BaseWidget.cpp @@ -15,8 +15,8 @@ namespace Nz { /*! - * \ingroup NDK - * \class Ndk::BaseWidget + * \ingroup Widgets + * \class BaseWidget * \brief Abstract class serving as a base class for all widgets */ @@ -288,8 +288,9 @@ namespace Nz { } - void BaseWidget::OnMouseButtonDoublePress(int /*x*/, int /*y*/, Mouse::Button /*button*/) + void BaseWidget::OnMouseButtonDoublePress(int x, int y, Mouse::Button button) { + return OnMouseButtonPress(x, y, button); } void BaseWidget::OnMouseButtonPress(int /*x*/, int /*y*/, Mouse::Button /*button*/) @@ -300,8 +301,9 @@ namespace Nz { } - void BaseWidget::OnMouseButtonTriplePress(int /*x*/, int /*y*/, Mouse::Button /*button*/) + void BaseWidget::OnMouseButtonTriplePress(int x, int y, Mouse::Button button) { + return OnMouseButtonPress(x, y, button); } void BaseWidget::OnMouseWheelMoved(int /*x*/, int /*y*/, float /*delta*/) diff --git a/src/Nazara/Widgets/BoxLayout.cpp b/src/Nazara/Widgets/BoxLayout.cpp new file mode 100644 index 000000000..2a72ba1a6 --- /dev/null +++ b/src/Nazara/Widgets/BoxLayout.cpp @@ -0,0 +1,142 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// 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 +#include +#include +#include +#include + +namespace Nz +{ + struct BoxLayout::State + { + std::vector sizeVar; + kiwi::Solver solver; + }; + + BoxLayout::BoxLayout(BaseWidget* parent, BoxLayoutOrientation orientation) : + BaseWidget(parent), + m_orientation(orientation), + m_spacing(5.f) + { + m_state = std::make_unique(); + } + + BoxLayout::~BoxLayout() = default; + + void BoxLayout::Layout() + { + BaseWidget::Layout(); + + std::size_t axis; + + switch (m_orientation) + { + case BoxLayoutOrientation_Horizontal: + axis = 0; //< x + break; + + case BoxLayoutOrientation_Vertical: + axis = 1; //< y + break; + + default: + assert(false); + break; + } + + //TODO: Keep solver state when widgets don't change + std::size_t widgetChildCount = GetWidgetChildCount(); + if (widgetChildCount == 0) + return; + + m_state->solver.reset(); + + m_state->sizeVar.clear(); + m_state->sizeVar.reserve(widgetChildCount); + + kiwi::Expression sizeSum; + + Nz::Vector2f layoutSize = GetSize(); + float availableSpace = layoutSize[axis] - m_spacing * (widgetChildCount - 1); + float perfectSpacePerWidget = availableSpace / widgetChildCount; + + // Handle size + ForEachWidgetChild([&](BaseWidget* child) + { + if (!child->IsVisible()) + return; + + float maximumSize = child->GetMaximumSize()[axis]; + float minimumSize = child->GetMinimumSize()[axis]; + + m_state->sizeVar.emplace_back(); + auto& sizeVar = m_state->sizeVar.back(); + + m_state->solver.addConstraint({ sizeVar >= minimumSize | kiwi::strength::required }); + + if (maximumSize < std::numeric_limits::infinity()) + m_state->solver.addConstraint({ sizeVar <= maximumSize | kiwi::strength::required }); + + m_state->solver.addConstraint({ sizeVar >= perfectSpacePerWidget | kiwi::strength::medium }); + + sizeSum = sizeSum + sizeVar; + }); + + kiwi::Variable targetSize("LayoutSize"); + + m_state->solver.addConstraint(sizeSum <= targetSize | kiwi::strength::strong); + + m_state->solver.addEditVariable(targetSize, kiwi::strength::strong); + m_state->solver.suggestValue(targetSize, availableSpace); + + m_state->solver.updateVariables(); + + std::size_t varIndex = 0; + + float remainingSize = availableSpace; + + ForEachWidgetChild([&](BaseWidget* child) + { + if (!child->IsVisible()) + return; + + Nz::Vector2f newSize = layoutSize; + newSize[axis] = m_state->sizeVar[varIndex].value(); + + child->Resize(newSize); + remainingSize -= newSize[axis]; + + varIndex++; + }); + + float spacing = m_spacing + remainingSize / (widgetChildCount - 1); + + // Handle position + float cursor = 0.f; + bool first = true; + ForEachWidgetChild([&](BaseWidget* child) + { + if (first) + first = false; + else + cursor += spacing; + + Nz::Vector2f position = Nz::Vector2f(0.f, 0.f); + position[axis] = cursor; + + child->SetPosition(position); + + cursor += child->GetSize()[axis]; + }); + } +} + +#endif diff --git a/src/Nazara/Widgets/ButtonWidget.cpp b/src/Nazara/Widgets/ButtonWidget.cpp index 8e88271e2..ab5e2674b 100644 --- a/src/Nazara/Widgets/ButtonWidget.cpp +++ b/src/Nazara/Widgets/ButtonWidget.cpp @@ -3,15 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include -#include -#include -#include -#include #include -#include -#include -#include #include namespace Nz @@ -56,7 +48,7 @@ namespace Nz // If user clicks inside button and holds it outside, a release mouse button event will be triggered outside of the widget // we don't want this to trigger the button, so double-check - if (IsInside(x, y)) + if (IsInside(float(x), float(y))) OnButtonTrigger(this); } } diff --git a/src/Nazara/Widgets/DefaultWidgetTheme.cpp b/src/Nazara/Widgets/DefaultWidgetTheme.cpp index b6668933c..a13a74d9a 100644 --- a/src/Nazara/Widgets/DefaultWidgetTheme.cpp +++ b/src/Nazara/Widgets/DefaultWidgetTheme.cpp @@ -45,13 +45,85 @@ namespace Nz const UInt8 s_defaultThemeCheckboxTristateImage[] = { #include }; + + const UInt8 s_defaultThemeHoveredImage[] = { + #include + }; + + const UInt8 s_defaultThemeScrollbarHorizontalBackgroundImage[] = { + #include + }; + + const UInt8 s_defaultThemeScrollbarVerticalBackgroundImage[] = { + #include + }; + + const UInt8 s_defaultThemeScrollbarArrowDownImage[] = { + #include + }; + + const UInt8 s_defaultThemeScrollbarArrowDownHoveredImage[] = { + #include + }; + + const UInt8 s_defaultThemeScrollbarArrowDownPressedImage[] = { + #include + }; + + const UInt8 s_defaultThemeScrollbarArrowLeftImage[] = { + #include + }; + + const UInt8 s_defaultThemeScrollbarArrowLeftHoveredImage[] = { + #include + }; + + const UInt8 s_defaultThemeScrollbarArrowLeftPressedImage[] = { + #include + }; + + const UInt8 s_defaultThemeScrollbarArrowRightImage[] = { + #include + }; + + const UInt8 s_defaultThemeScrollbarArrowRightHoveredImage[] = { + #include + }; + + const UInt8 s_defaultThemeScrollbarArrowRightPressedImage[] = { + #include + }; + + const UInt8 s_defaultThemeScrollbarArrowUpImage[] = { + #include + }; + + const UInt8 s_defaultThemeScrollbarArrowUpHoveredImage[] = { + #include + }; + + const UInt8 s_defaultThemeScrollbarArrowUpPressedImage[] = { + #include + }; + + const UInt8 s_defaultThemeScrollbarCenterImage[] = { + #include + }; + + const UInt8 s_defaultThemeScrollbarGrabbedImage[] = { + #include + }; + + const UInt8 s_defaultThemeScrollbarHoveredImage[] = { + #include + }; } DefaultWidgetTheme::DefaultWidgetTheme() { TextureParams texParams; texParams.renderDevice = Graphics::Instance()->GetRenderDevice(); - texParams.loadFormat = PixelFormat::RGBA8_SRGB; + texParams.loadFormat = PixelFormat::RGBA8; //< TODO: Re-enable gamma correction auto CreateMaterialFromTexture = [](std::shared_ptr texture) { @@ -70,18 +142,48 @@ namespace Nz return material; }; - - // Button material + + m_hoveredMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeHoveredImage, sizeof(s_defaultThemeHoveredImage), texParams)); + + // Button materials m_buttonMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeButtonImage, sizeof(s_defaultThemeButtonImage), texParams)); m_buttonHoveredMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeButtonHoveredImage, sizeof(s_defaultThemeButtonHoveredImage), texParams)); m_buttonPressedMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeButtonPressedImage, sizeof(s_defaultThemeButtonPressedImage), texParams)); m_buttonPressedHoveredMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeButtonPressedHoveredImage, sizeof(s_defaultThemeButtonPressedHoveredImage), texParams)); - // Checkbox material + // Checkbox materials m_checkboxBackgroundMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeCheckboxBackgroundImage, sizeof(s_defaultThemeCheckboxBackgroundImage), texParams)); m_checkboxBackgroundHoveredMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeCheckboxBackgroundHoveredImage, sizeof(s_defaultThemeCheckboxBackgroundHoveredImage), texParams)); m_checkboxCheckMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeCheckboxCheckImage, sizeof(s_defaultThemeCheckboxCheckImage), texParams)); m_checkboxTristateMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeCheckboxTristateImage, sizeof(s_defaultThemeCheckboxTristateImage), texParams)); + + // Scrollbar materials + m_scrollbarBackgroundHorizontalMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeScrollbarHorizontalBackgroundImage, sizeof(s_defaultThemeScrollbarHorizontalBackgroundImage), texParams)); + m_scrollbarBackgroundVerticalMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeScrollbarVerticalBackgroundImage, sizeof(s_defaultThemeScrollbarVerticalBackgroundImage), texParams)); + + // Config + m_config.scrollbarButtonCornerSize = 0.f; + m_config.scrollbarButtonCornerTexcoords = 0.f; + + m_scrollbarButtonMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeScrollbarCenterImage, sizeof(s_defaultThemeScrollbarCenterImage), texParams)); + m_scrollbarButtonGrabbedMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeScrollbarGrabbedImage, sizeof(s_defaultThemeScrollbarGrabbedImage), texParams)); + m_scrollbarButtonHoveredMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeScrollbarHoveredImage, sizeof(s_defaultThemeScrollbarHoveredImage), texParams)); + + m_config.scrollbarButtonDownMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeScrollbarArrowDownImage, sizeof(s_defaultThemeScrollbarArrowDownImage), texParams)); + m_config.scrollbarButtonDownHoveredMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeScrollbarArrowDownHoveredImage, sizeof(s_defaultThemeScrollbarArrowDownHoveredImage), texParams)); + m_config.scrollbarButtonDownPressedMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeScrollbarArrowDownPressedImage, sizeof(s_defaultThemeScrollbarArrowDownPressedImage), texParams)); + + m_config.scrollbarButtonLeftMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeScrollbarArrowLeftImage, sizeof(s_defaultThemeScrollbarArrowLeftImage), texParams)); + m_config.scrollbarButtonLeftHoveredMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeScrollbarArrowLeftHoveredImage, sizeof(s_defaultThemeScrollbarArrowLeftHoveredImage), texParams)); + m_config.scrollbarButtonLeftPressedMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeScrollbarArrowLeftPressedImage, sizeof(s_defaultThemeScrollbarArrowLeftPressedImage), texParams)); + + m_config.scrollbarButtonRightMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeScrollbarArrowRightImage, sizeof(s_defaultThemeScrollbarArrowRightImage), texParams)); + m_config.scrollbarButtonRightHoveredMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeScrollbarArrowRightHoveredImage, sizeof(s_defaultThemeScrollbarArrowRightHoveredImage), texParams)); + m_config.scrollbarButtonRightPressedMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeScrollbarArrowRightPressedImage, sizeof(s_defaultThemeScrollbarArrowRightPressedImage), texParams)); + + m_config.scrollbarButtonUpMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeScrollbarArrowUpImage, sizeof(s_defaultThemeScrollbarArrowUpImage), texParams)); + m_config.scrollbarButtonUpHoveredMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeScrollbarArrowUpHoveredImage, sizeof(s_defaultThemeScrollbarArrowUpHoveredImage), texParams)); + m_config.scrollbarButtonUpPressedMaterial = CreateMaterialFromTexture(Texture::LoadFromMemory(s_defaultThemeScrollbarArrowUpPressedImage, sizeof(s_defaultThemeScrollbarArrowUpPressedImage), texParams)); } std::unique_ptr DefaultWidgetTheme::CreateStyle(ButtonWidget* buttonWidget) const @@ -110,8 +212,45 @@ namespace Nz return std::make_unique(checkboxWidget, styleConfig); } + std::unique_ptr DefaultWidgetTheme::CreateStyle(ImageButtonWidget* imageButtonWidget) const + { + SimpleImageButtonWidgetStyle::StyleConfig styleConfig; + styleConfig.hoveredCornerSize = 8.f; + styleConfig.hoveredCornerTexCoords = 8.f / 64.f; + styleConfig.hoveredMaterial = m_hoveredMaterial; + + return std::make_unique(imageButtonWidget, styleConfig); + } + std::unique_ptr DefaultWidgetTheme::CreateStyle(LabelWidget* labelWidget) const { return std::make_unique(labelWidget, Widgets::Instance()->GetTransparentMaterial()); } + + std::unique_ptr DefaultWidgetTheme::CreateStyle(ScrollAreaWidget* scrollAreaWidget) const + { + return nullptr; + } + + std::unique_ptr DefaultWidgetTheme::CreateStyle(ScrollbarWidget* scrollBarWidget) const + { + SimpleScrollbarWidgetStyle::StyleConfig styleConfig; + styleConfig.backgroundHorizontalMaterial = m_scrollbarBackgroundHorizontalMaterial; + styleConfig.backgroundVerticalMaterial = m_scrollbarBackgroundVerticalMaterial; + + return std::make_unique(scrollBarWidget, styleConfig); + } + + std::unique_ptr DefaultWidgetTheme::CreateStyle(ScrollbarButtonWidget* scrollbarButtonWidget) const + { + SimpleScrollbarButtonWidgetStyle::StyleConfig styleConfig; + styleConfig.cornerSize = 16.f; + styleConfig.cornerTexCoords = 16.f / 64.f; + styleConfig.grabbedMaterial = m_scrollbarButtonGrabbedMaterial; + styleConfig.hoveredMaterial = m_scrollbarButtonHoveredMaterial; + styleConfig.material = m_scrollbarButtonMaterial; + + return std::make_unique(scrollbarButtonWidget, styleConfig); + } + } diff --git a/src/Nazara/Widgets/ImageButtonWidget.cpp b/src/Nazara/Widgets/ImageButtonWidget.cpp new file mode 100644 index 000000000..7e3228462 --- /dev/null +++ b/src/Nazara/Widgets/ImageButtonWidget.cpp @@ -0,0 +1,91 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Widgets module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace Nz +{ + ImageButtonWidget::ImageButtonWidget(BaseWidget* parent, std::shared_ptr material, std::shared_ptr hoveredMaterial, std::shared_ptr pressedMaterial, float cornerSize, float cornerTexCoords) : + BaseWidget(parent), + m_hoveredMaterial(std::move(hoveredMaterial)), + m_material(std::move(material)), + m_pressedMaterial(std::move(pressedMaterial)), + m_color(Color::White), + m_textureCoords(0.f, 0.f, 1.f, 1.f), + m_cornerSize(cornerSize), + m_cornerTexCoords(cornerTexCoords) + { + m_style = GetTheme()->CreateStyle(this); + SetRenderLayerCount(m_style->GetRenderLayerCount()); + + UpdatePreferredSize(); + Layout(); + } + + void ImageButtonWidget::Layout() + { + BaseWidget::Layout(); + m_style->Layout(GetSize()); + } + + void ImageButtonWidget::OnMouseButtonPress(int /*x*/, int /*y*/, Mouse::Button button) + { + if (button == Mouse::Left) + m_style->OnPress(); + } + + void ImageButtonWidget::OnMouseButtonRelease(int x, int y, Mouse::Button button) + { + if (button == Mouse::Left) + { + m_style->OnRelease(); + + // If user clicks inside button and holds it outside, a release mouse button event will be triggered outside of the widget + // we don't want this to trigger the button, so double-check + if (IsInside(float(x), float(y))) + OnButtonTrigger(this); + } + } + + void ImageButtonWidget::OnMouseEnter() + { + m_style->OnHoverBegin(); + } + + void ImageButtonWidget::OnMouseExit() + { + m_style->OnHoverEnd(); + } + + void ImageButtonWidget::OnRenderLayerUpdated(int baseRenderLayer) + { + m_style->UpdateRenderLayer(baseRenderLayer); + } + + void ImageButtonWidget::UpdatePreferredSize() + { + const Rectf& textureCoords = GetTextureCoords(); + + // TODO: Move this in a separate function + if (const auto& material = m_material->FindPass("ForwardPass")) + { + BasicMaterial mat(*material); + if (mat.HasDiffuseMap()) + { + // Material should always have textures but we're better safe than sorry + if (const auto& texture = mat.GetDiffuseMap()) + { + Vector2f textureSize = Vector2f(Vector2ui(texture->GetSize())); + textureSize.x *= textureCoords.width; + textureSize.y *= textureCoords.height; + + SetPreferredSize(textureSize); + } + } + } + } +} diff --git a/src/Nazara/Widgets/ImageWidget.cpp b/src/Nazara/Widgets/ImageWidget.cpp index 4007dcd0f..ae220b370 100644 --- a/src/Nazara/Widgets/ImageWidget.cpp +++ b/src/Nazara/Widgets/ImageWidget.cpp @@ -11,7 +11,7 @@ namespace Nz { - ImageWidget::ImageWidget(BaseWidget* parent) : + ImageWidget::ImageWidget(BaseWidget* parent, std::shared_ptr material) : BaseWidget(parent) { m_sprite = std::make_shared(Widgets::Instance()->GetTransparentMaterial()); @@ -25,6 +25,8 @@ namespace Nz auto& nodeComponent = registry.emplace(m_entity); nodeComponent.SetParent(this); + + SetMaterial(std::move(material)); } void ImageWidget::Layout() diff --git a/src/Nazara/Widgets/ProgressBarWidget.cpp b/src/Nazara/Widgets/ProgressBarWidget.cpp new file mode 100644 index 000000000..a3b1945ac --- /dev/null +++ b/src/Nazara/Widgets/ProgressBarWidget.cpp @@ -0,0 +1,106 @@ +// Copyright (C) 2022 Samy Bensaid +// 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 +#include + +namespace Nz +{ + float ProgressBarWidget::s_borderScale { 16.f }; + Nz::Color ProgressBarWidget::s_borderColor { Nz::Color::Black }; + Nz::Color ProgressBarWidget::s_barBackgroundColor { Nz::Color { 225, 225, 225 } }; + Nz::Color ProgressBarWidget::s_barBackgroundCornerColor { Nz::Color { 255, 255, 255 } }; + Nz::Color ProgressBarWidget::s_barColor { Nz::Color { 0, 225, 0 } }; + Nz::Color ProgressBarWidget::s_barCornerColor { Nz::Color { 220, 255, 220 } }; + + ProgressBarWidget::ProgressBarWidget(BaseWidget* parent) : + BaseWidget(parent), + m_textColor { Nz::Color::Black }, + m_textMargin { 16.f }, + m_value { 0u } + { + m_borderSprite = Nz::Sprite::New(Nz::Material::New("Basic2D")); + m_barBackgroundSprite = Nz::Sprite::New(Nz::Material::New("Basic2D")); + m_barSprite = Nz::Sprite::New(Nz::Material::New("Basic2D")); + + m_borderSprite->SetColor(s_borderColor); + SetBarBackgroundColor(s_barBackgroundColor, s_barBackgroundCornerColor); + SetBarColor(s_barColor, s_barCornerColor); + + + m_borderEntity = CreateEntity(); + m_borderEntity->AddComponent().SetParent(this); + m_borderEntity->AddComponent().Attach(m_borderSprite); + + m_barEntity = CreateEntity(); + m_barEntity->AddComponent().SetParent(this); + GraphicsComponent& graphics = m_barEntity->AddComponent(); + + graphics.Attach(m_barBackgroundSprite, 1); + graphics.Attach(m_barSprite, 2); + + + m_textSprite = Nz::TextSprite::New(); + m_textEntity = CreateEntity(); + + m_textEntity->AddComponent().SetParent(this); + m_textEntity->AddComponent().Attach(m_textSprite); + + UpdateText(); + Layout(); + } + + + const Nz::Color& ProgressBarWidget::GetDefaultBarColor() + { + return s_barColor; + } + + const Nz::Color& ProgressBarWidget::GetDefaultBarCornerColor() + { + return s_barCornerColor; + } + + const Nz::Color& ProgressBarWidget::GetDefaultBarBackgroundColor() + { + return s_barBackgroundColor; + } + + const Nz::Color& ProgressBarWidget::GetDefaultBarBackgroundCornerColor() + { + return s_barBackgroundCornerColor; + } + + + void ProgressBarWidget::Layout() + { + Nz::Vector2f size = GetSize(); + Nz::Vector2f progressBarSize = size; + + if (IsTextEnabled()) + { + UpdateText(); + + Nz::Vector3f textSize = m_textSprite->GetBoundingVolume().obb.localBox.GetLengths(); + m_textEntity->GetComponent().SetPosition(size.x - textSize.x, size.y / 2.f - textSize.y); + + progressBarSize -= { textSize.x + m_textMargin, 0.f }; + } + + m_borderSprite->SetSize(progressBarSize); + Nz::Vector2f borderSize = GetProgressBarBorderSize(); + + m_barBackgroundSprite->SetSize(progressBarSize - (borderSize * 2.f)); + m_barSprite->SetSize((progressBarSize.x - (borderSize.x * 2.f)) / 100.f * static_cast(m_value), progressBarSize.y - (borderSize.y * 2.f)); + + m_barEntity->GetComponent().SetPosition(borderSize.x, borderSize.y); + } +} + +#endif diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/Hovered.png b/src/Nazara/Widgets/Resources/DefaultTheme/Hovered.png new file mode 100644 index 000000000..d2e2df848 Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/Hovered.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowDown.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowDown.png new file mode 100644 index 000000000..f414abe8c Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowDown.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowDownDisabled.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowDownDisabled.png new file mode 100644 index 000000000..8b8f387e1 Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowDownDisabled.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowDownHovered.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowDownHovered.png new file mode 100644 index 000000000..cbd5f54d9 Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowDownHovered.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowDownPressed.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowDownPressed.png new file mode 100644 index 000000000..a368c9ece Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowDownPressed.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowLeft.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowLeft.png new file mode 100644 index 000000000..341d1109f Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowLeft.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowLeftDisabled.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowLeftDisabled.png new file mode 100644 index 000000000..f4a8e294f Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowLeftDisabled.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowLeftHovered.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowLeftHovered.png new file mode 100644 index 000000000..8679eb68f Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowLeftHovered.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowLeftPressed.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowLeftPressed.png new file mode 100644 index 000000000..149d4d620 Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowLeftPressed.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRight.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRight.png new file mode 100644 index 000000000..b68433834 Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRight.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRightDisabled.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRightDisabled.png new file mode 100644 index 000000000..04e5c0cd4 Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRightDisabled.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRightHovered.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRightHovered.png new file mode 100644 index 000000000..db829cc1d Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRightHovered.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRightPressed.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRightPressed.png new file mode 100644 index 000000000..7f7c286f0 Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRightPressed.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUp.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUp.png new file mode 100644 index 000000000..641f747a0 Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUp.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUpDisabled.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUpDisabled.png new file mode 100644 index 000000000..cbd4183e1 Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUpDisabled.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUpHovered.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUpHovered.png new file mode 100644 index 000000000..6a321f4c9 Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUpHovered.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUpPressed.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUpPressed.png new file mode 100644 index 000000000..20fe41bd8 Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUpPressed.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarBackgroundHorizontal.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarBackgroundHorizontal.png new file mode 100644 index 000000000..66a6e5649 Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarBackgroundHorizontal.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarBackgroundVertical.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarBackgroundVertical.png new file mode 100644 index 000000000..63112abac Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarBackgroundVertical.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarCenter.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarCenter.png new file mode 100644 index 000000000..816547f8f Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarCenter.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarCenterGrabbed.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarCenterGrabbed.png new file mode 100644 index 000000000..a18825cc7 Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarCenterGrabbed.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarCenterHovered.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarCenterHovered.png new file mode 100644 index 000000000..f5dc18c03 Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarCenterHovered.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/VerticalSlider.png b/src/Nazara/Widgets/Resources/DefaultTheme/VerticalSlider.png new file mode 100644 index 000000000..3cd10431c Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/VerticalSlider.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/VerticalSliderBackground.png b/src/Nazara/Widgets/Resources/DefaultTheme/VerticalSliderBackground.png new file mode 100644 index 000000000..22ef23e4b Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/VerticalSliderBackground.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/VerticalSliderGrabbed.png b/src/Nazara/Widgets/Resources/DefaultTheme/VerticalSliderGrabbed.png new file mode 100644 index 000000000..c30ffd8ca Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/VerticalSliderGrabbed.png differ diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/VerticalSliderHovered.png b/src/Nazara/Widgets/Resources/DefaultTheme/VerticalSliderHovered.png new file mode 100644 index 000000000..0c056b639 Binary files /dev/null and b/src/Nazara/Widgets/Resources/DefaultTheme/VerticalSliderHovered.png differ diff --git a/src/Nazara/Widgets/ScrollAreaWidget.cpp b/src/Nazara/Widgets/ScrollAreaWidget.cpp new file mode 100644 index 000000000..21635efe7 --- /dev/null +++ b/src/Nazara/Widgets/ScrollAreaWidget.cpp @@ -0,0 +1,204 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// 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 + +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_content->SetParent(this); + m_content->SetPosition(Nz::Vector3f::Zero()); + + m_style = GetTheme()->CreateStyle(this); + SetRenderLayerCount(m_style->GetRenderLayerCount()); + + 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) + { + if (m_isScrollbarEnabled != enable) + { + m_isScrollbarEnabled = enable; + + bool isVisible = IsScrollbarVisible(); + m_scrollbarEntity->Enable(isVisible); + m_scrollbarBackgroundEntity->Enable(isVisible); + } + } + + 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); + } + + void ScrollAreaWidget::Layout() + { + constexpr float scrollBarBackgroundWidth = 20.f; + constexpr float scrollBarWidth = scrollBarBackgroundWidth - 2.f * scrollbarPadding; + + float areaHeight = GetHeight(); + float contentHeight = m_content->GetHeight(); + + if (contentHeight > areaHeight) + { + m_hasScrollbar = true; + + Nz::Vector2f contentSize(GetWidth() - scrollBarBackgroundWidth, contentHeight); + m_content->Resize(contentSize); + + if (m_isScrollbarEnabled) + { + m_scrollbarEntity->Enable(); + m_scrollbarBackgroundEntity->Enable(); + } + + float scrollBarHeight = std::max(std::floor(areaHeight * (areaHeight / contentHeight)), 20.f); + + 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); + } + else + { + m_hasScrollbar = false; + + m_content->Resize(GetSize()); + + m_scrollbarEntity->Disable(); + m_scrollbarBackgroundEntity->Disable(); + + ScrollToRatio(0.f); + } + + 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) + { + 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; + } + } +} + +#endif diff --git a/src/Nazara/Widgets/ScrollbarButtonWidget.cpp b/src/Nazara/Widgets/ScrollbarButtonWidget.cpp new file mode 100644 index 000000000..e3b5d095f --- /dev/null +++ b/src/Nazara/Widgets/ScrollbarButtonWidget.cpp @@ -0,0 +1,68 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Widgets module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + ScrollbarButtonWidget::ScrollbarButtonWidget(BaseWidget* parent) : + BaseWidget(parent), + m_isGrabbed(false) + { + m_style = GetTheme()->CreateStyle(this); + SetRenderLayerCount(m_style->GetRenderLayerCount()); + + Layout(); + } + + void ScrollbarButtonWidget::Layout() + { + BaseWidget::Layout(); + m_style->Layout(GetSize()); + } + + void ScrollbarButtonWidget::OnMouseButtonPress(int x, int y, Mouse::Button button) + { + if (button == Mouse::Left) + { + m_isGrabbed = true; + OnButtonGrabbed(this, x, y); + + m_style->OnGrab(); + } + } + + void ScrollbarButtonWidget::OnMouseButtonRelease(int x, int y, Mouse::Button button) + { + if (button == Mouse::Left) + { + m_isGrabbed = false; + OnButtonReleased(this); + + m_style->OnRelease(); + } + } + + void ScrollbarButtonWidget::OnMouseEnter() + { + m_style->OnHoverBegin(); + } + + void ScrollbarButtonWidget::OnMouseExit() + { + m_style->OnHoverEnd(); + } + + void ScrollbarButtonWidget::OnMouseMoved(int x, int y, int /*deltaX*/, int /*deltaY*/) + { + if (m_isGrabbed) + OnButtonMoved(this, x, y); + } + + void ScrollbarButtonWidget::OnRenderLayerUpdated(int baseRenderLayer) + { + m_style->UpdateRenderLayer(baseRenderLayer); + } +} diff --git a/src/Nazara/Widgets/ScrollbarWidget.cpp b/src/Nazara/Widgets/ScrollbarWidget.cpp new file mode 100644 index 000000000..e75786a14 --- /dev/null +++ b/src/Nazara/Widgets/ScrollbarWidget.cpp @@ -0,0 +1,151 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Widgets module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include + +namespace Nz +{ + ScrollbarWidget::ScrollbarWidget(BaseWidget* parent, ScrollbarOrientation orientation) : + BaseWidget(parent), + m_orientation(orientation), + m_isGrabbed(false), + m_maximumValue(1.f), + m_minimumValue(0.f), + m_step(0.5f), + m_value(0.f) + { + m_style = GetTheme()->CreateStyle(this); + SetRenderLayerCount(m_style->GetRenderLayerCount()); + + const WidgetTheme::Config& themeConfig = GetTheme()->GetConfig(); + + m_scrollCenterButton = Add(); + + m_scrollCenterButton->OnButtonReleased.Connect([this](const ScrollbarButtonWidget*) + { + m_style->OnButtonRelease(); + }); + + if (m_orientation == ScrollbarOrientation::Horizontal) + { + m_scrollCenterButton->OnButtonGrabbed.Connect([this](const ScrollbarButtonWidget*, int x, int /*y*/) + { + m_grabbedPosition = x; + m_grabbedValue = GetValue(); + m_style->OnButtonGrab(); + }); + + m_scrollCenterButton->OnButtonMoved.Connect([this](const ScrollbarButtonWidget*, int x, int /*y*/) + { + int deltaX = x - m_grabbedPosition; + if (deltaX == 0) + return; + + float scrollbarWidth = m_step * GetWidth(); + float remainingWidth = GetWidth() - m_scrollBackButton->GetWidth() - scrollbarWidth; + float valueRange = m_maximumValue - m_minimumValue; + + SetValue(m_grabbedValue + deltaX * valueRange / remainingWidth); + }); + + m_scrollBackButton = Add(themeConfig.scrollbarButtonLeftMaterial, themeConfig.scrollbarButtonLeftHoveredMaterial, themeConfig.scrollbarButtonLeftPressedMaterial, themeConfig.scrollbarButtonCornerSize, themeConfig.scrollbarButtonCornerTexcoords); + m_scrollNextButton = Add(themeConfig.scrollbarButtonRightMaterial, themeConfig.scrollbarButtonRightHoveredMaterial, themeConfig.scrollbarButtonRightPressedMaterial, themeConfig.scrollbarButtonCornerSize, themeConfig.scrollbarButtonCornerTexcoords); + } + else + { + m_scrollCenterButton->OnButtonGrabbed.Connect([this](const ScrollbarButtonWidget* button, int /*x*/, int y) + { + m_grabbedPosition = button->GetPosition().y + y; + m_grabbedValue = GetValue(); + m_style->OnButtonGrab(); + }); + + m_scrollCenterButton->OnButtonMoved.Connect([this](const ScrollbarButtonWidget* button, int /*x*/, int y) + { + int deltaY = m_grabbedPosition - (button->GetPosition().y + y); + if (deltaY == 0) + return; + + float scrollbarHeight = m_step * GetHeight(); + float remainingHeight = GetHeight() - m_scrollBackButton->GetHeight() - scrollbarHeight; + float valueRange = m_maximumValue - m_minimumValue; + + SetValue(m_grabbedValue + deltaY * valueRange / remainingHeight); + }); + + m_scrollBackButton = Add(themeConfig.scrollbarButtonUpMaterial, themeConfig.scrollbarButtonUpHoveredMaterial, themeConfig.scrollbarButtonUpPressedMaterial, themeConfig.scrollbarButtonCornerSize, themeConfig.scrollbarButtonCornerTexcoords); + m_scrollNextButton = Add(themeConfig.scrollbarButtonDownMaterial, themeConfig.scrollbarButtonDownHoveredMaterial, themeConfig.scrollbarButtonDownPressedMaterial, themeConfig.scrollbarButtonCornerSize, themeConfig.scrollbarButtonCornerTexcoords); + } + + m_scrollBackButton->OnButtonTrigger.Connect([this](const ImageButtonWidget*) + { + SetValue(GetValue() - 0.1f * (GetMaximumValue() - GetMinimumValue())); + }); + + m_scrollNextButton->OnButtonTrigger.Connect([this](const ImageButtonWidget*) + { + SetValue(GetValue() + 0.1f * (GetMaximumValue() - GetMinimumValue())); + }); + + Layout(); + } + + void ScrollbarWidget::Layout() + { + BaseWidget::Layout(); + + float stepPct = m_step / (m_maximumValue - m_minimumValue); + float valuePct = m_value / (m_maximumValue - m_minimumValue); + float invValuePct = 1.f - valuePct; //< Remember we're Y up + + Vector2f size = GetSize(); + if (m_orientation == ScrollbarOrientation::Horizontal) + { + m_scrollBackButton->Resize({ size.y, size.y }); + m_scrollNextButton->Resize({ size.y, size.y }); + m_scrollNextButton->SetPosition({ GetWidth() - m_scrollNextButton->GetWidth(), 0.f, 0.f }); + + float start = m_scrollBackButton->GetWidth(); + float remaining = size.x - start - m_scrollNextButton->GetWidth(); + float centerPosition = start + invValuePct * (remaining - remaining * stepPct); + + m_scrollCenterButton->Resize({ remaining * stepPct, size.y }); + m_scrollCenterButton->SetPosition(start + centerPosition, 0.f); + } + else + { + m_scrollBackButton->Resize({ size.x, size.x }); + m_scrollBackButton->SetPosition({ 0.f, GetHeight() - m_scrollBackButton->GetHeight(), 0.f }); + m_scrollNextButton->Resize({ size.x, size.x }); + + float start = m_scrollBackButton->GetHeight(); + float remaining = size.y - start - m_scrollNextButton->GetHeight(); + float centerPosition = start + invValuePct * (remaining - remaining * stepPct); + + m_scrollCenterButton->Resize({ size.x, remaining * stepPct }); + m_scrollCenterButton->SetPosition(0.f, centerPosition); + } + + m_style->Layout(size); + } + + void ScrollbarWidget::OnMouseEnter() + { + m_style->OnHoverBegin(); + } + + void ScrollbarWidget::OnMouseExit() + { + m_style->OnHoverEnd(); + } + + void ScrollbarWidget::OnRenderLayerUpdated(int baseRenderLayer) + { + m_style->UpdateRenderLayer(baseRenderLayer); + } +} diff --git a/src/Nazara/Widgets/SimpleWidgetStyles.cpp b/src/Nazara/Widgets/SimpleWidgetStyles.cpp index 1117e6d99..7aaa735aa 100644 --- a/src/Nazara/Widgets/SimpleWidgetStyles.cpp +++ b/src/Nazara/Widgets/SimpleWidgetStyles.cpp @@ -8,7 +8,10 @@ #include #include #include +#include #include +#include +#include #include #include @@ -56,26 +59,26 @@ namespace Nz void SimpleButtonWidgetStyle::OnHoverBegin() { + UpdateMaterial(true, m_isPressed); m_isHovered = true; - UpdateMaterial(m_isHovered, m_isPressed); } void SimpleButtonWidgetStyle::OnHoverEnd() { + UpdateMaterial(false, m_isPressed); m_isHovered = false; - UpdateMaterial(m_isHovered, m_isPressed); } void SimpleButtonWidgetStyle::OnPress() { + UpdateMaterial(m_isHovered, true); m_isPressed = true; - UpdateMaterial(m_isHovered, m_isPressed); } void SimpleButtonWidgetStyle::OnRelease() { + UpdateMaterial(m_isHovered, false); m_isPressed = false; - UpdateMaterial(m_isHovered, m_isPressed); } void SimpleButtonWidgetStyle::UpdateRenderLayer(int baseRenderLayer) @@ -194,6 +197,140 @@ namespace Nz } + SimpleImageButtonWidgetStyle::SimpleImageButtonWidgetStyle(ImageButtonWidget* imageButtonWidget, StyleConfig config) : + ImageButtonWidgetStyle(imageButtonWidget, 1), + m_isHovered(false), + m_isPressed(false) + { + auto& registry = GetRegistry(); + UInt32 renderMask = GetRenderMask(); + + SlicedSprite::Corner hoveredCorner; + hoveredCorner.size = Vector2f(config.hoveredCornerSize, config.hoveredCornerSize); + hoveredCorner.textureCoords = Vector2f(config.hoveredCornerTexCoords, config.hoveredCornerTexCoords); + + m_hoveredSprite = std::make_shared(config.hoveredMaterial); + m_hoveredSprite->SetCorners(hoveredCorner, hoveredCorner); + + float imageCornerSize = imageButtonWidget->GetCornerSize(); + float imageCornerTexCoords = imageButtonWidget->GetCornerTexCoords(); + + SlicedSprite::Corner corner; + corner.size = Vector2f(imageCornerSize, imageCornerSize); + corner.textureCoords = Vector2f(imageCornerTexCoords, imageCornerTexCoords); + + m_sprite = std::make_shared(imageButtonWidget->GetMaterial()); + m_sprite->SetCorners(corner, corner); + m_sprite->SetTextureCoords(imageButtonWidget->GetTextureCoords()); + + m_entity = CreateGraphicsEntity(); + + GraphicsComponent& gfxComponent = registry.get(m_entity); + gfxComponent.AttachRenderable(m_sprite, renderMask); + } + + void SimpleImageButtonWidgetStyle::Layout(const Vector2f& size) + { + m_hoveredSprite->SetSize(size); + m_sprite->SetSize(size); + } + + void SimpleImageButtonWidgetStyle::OnHoverBegin() + { + Update(true, m_isPressed); + m_isHovered = true; + } + + void SimpleImageButtonWidgetStyle::OnHoverEnd() + { + Update(false, m_isPressed); + m_isHovered = false; + } + + void SimpleImageButtonWidgetStyle::OnPress() + { + Update(m_isHovered, true); + m_isPressed = true; + } + + void SimpleImageButtonWidgetStyle::OnRelease() + { + Update(m_isHovered, false); + m_isPressed = false; + } + + void SimpleImageButtonWidgetStyle::OnUpdate() + { + ImageButtonWidget* owner = GetOwnerWidget(); + + // If a hovering material was added while we're being hovered, we need to detach the hovering sprite + if (owner->GetHoveredMaterial()) + { + GraphicsComponent& gfxComponent = GetRegistry().get(m_entity); + gfxComponent.DetachRenderable(m_hoveredSprite); + } + + m_sprite->SetTextureCoords(owner->GetTextureCoords()); + + Update(m_isHovered, m_isPressed); + } + + void SimpleImageButtonWidgetStyle::UpdateRenderLayer(int baseRenderLayer) + { + m_sprite->UpdateRenderLayer(baseRenderLayer); + m_hoveredSprite->UpdateRenderLayer(baseRenderLayer + 1); + } + + void SimpleImageButtonWidgetStyle::Update(bool hovered, bool pressed) + { + ImageButtonWidget* owner = GetOwnerWidget(); + + if (pressed) + { + if (const auto& pressedMaterial = owner->GetPressedMaterial()) + { + m_sprite->SetColor(owner->GetColor()); + m_sprite->SetMaterial(pressedMaterial); + } + else + { + m_sprite->SetColor(owner->GetColor() * Nz::Color::FromRGB8(120, 0, 0)); + m_sprite->SetMaterial(owner->GetMaterial()); + } + } + else + { + m_sprite->SetColor(owner->GetColor()); + m_sprite->SetMaterial(owner->GetMaterial()); + } + + if (hovered) + { + if (const auto& hoveredMaterial = owner->GetHoveredMaterial()) + { + if (!pressed) + m_sprite->SetMaterial(hoveredMaterial); + } + else + { + if (!pressed) + m_sprite->SetMaterial(owner->GetMaterial()); + + GraphicsComponent& gfxComponent = GetRegistry().get(m_entity); + gfxComponent.AttachRenderable(m_hoveredSprite, GetRenderMask()); + } + } + else + { + if (!pressed) + m_sprite->SetMaterial(owner->GetMaterial()); + + GraphicsComponent& gfxComponent = GetRegistry().get(m_entity); + gfxComponent.DetachRenderable(m_hoveredSprite); + } + } + + SimpleLabelWidgetStyle::SimpleLabelWidgetStyle(LabelWidget* labelWidget, std::shared_ptr material, std::shared_ptr hoveredMaterial) : LabelWidgetStyle(labelWidget, 1), m_hoveredMaterial(std::move(hoveredMaterial)), @@ -245,4 +382,123 @@ namespace Nz { m_textSprite->Update(drawer); } + + + SimpleScrollAreaWidgetStyle::SimpleScrollAreaWidgetStyle(ScrollAreaWidget* scrollAreaWidget) : + ScrollAreaWidgetStyle((BaseWidget*) scrollAreaWidget, 0) + { + } + + void SimpleScrollAreaWidgetStyle::Layout(const Vector2f& size) + { + } + + void SimpleScrollAreaWidgetStyle::UpdateRenderLayer(int baseRenderLayer) + { + } + + + SimpleScrollbarWidgetStyle::SimpleScrollbarWidgetStyle(ScrollbarWidget* scrollBarWidget, StyleConfig config) : + ScrollbarWidgetStyle(scrollBarWidget, 1), + m_config(std::move(config)) + { + auto& registry = GetRegistry(); + UInt32 renderMask = GetRenderMask(); + + m_backgroundScrollbarSprite = std::make_shared((scrollBarWidget->GetOrientation() == ScrollbarOrientation::Horizontal) ? m_config.backgroundHorizontalMaterial : m_config.backgroundVerticalMaterial); + + m_backgroundScrollbarSpriteEntity = CreateGraphicsEntity(); + registry.get(m_backgroundScrollbarSpriteEntity).AttachRenderable(m_backgroundScrollbarSprite, renderMask); + + m_scrollbarSpriteEntity = CreateGraphicsEntity(); + registry.get(m_scrollbarSpriteEntity).AttachRenderable(m_scrollbarSprite, renderMask); + } + + void SimpleScrollbarWidgetStyle::Layout(const Vector2f& size) + { + float totalSize; + if (GetOwnerWidget()->GetOrientation() == ScrollbarOrientation::Horizontal) + totalSize = size.x; + else + totalSize = size.y; + + m_backgroundScrollbarSprite->SetSize(size); + } + + void SimpleScrollbarWidgetStyle::UpdateRenderLayer(int baseRenderLayer) + { + m_backgroundScrollbarSprite->UpdateRenderLayer(baseRenderLayer); + } + + + SimpleScrollbarButtonWidgetStyle::SimpleScrollbarButtonWidgetStyle(ScrollbarButtonWidget* scrollbarButtonWidget, StyleConfig config) : + ScrollbarButtonWidgetStyle(scrollbarButtonWidget, 1), + m_hoveredMaterial(std::move(config.hoveredMaterial)), + m_material(std::move(config.material)), + m_pressedMaterial(std::move(config.grabbedMaterial)), + m_pressedHoveredMaterial(std::move(config.grabbedHoveredMaterial)), + m_isHovered(false), + m_isPressed(false) + { + assert(m_material); + + auto& registry = GetRegistry(); + UInt32 renderMask = GetRenderMask(); + + SlicedSprite::Corner corner; + corner.size.Set(config.cornerSize); + corner.textureCoords.Set(config.cornerTexCoords); + + m_sprite = std::make_shared(m_material); + m_sprite->SetCorners(corner, corner); + + m_entity = CreateGraphicsEntity(); + registry.get(m_entity).AttachRenderable(m_sprite, renderMask); + } + + void SimpleScrollbarButtonWidgetStyle::Layout(const Vector2f& size) + { + m_sprite->SetSize(size); + } + + void SimpleScrollbarButtonWidgetStyle::OnHoverBegin() + { + Update(true, m_isPressed); + m_isHovered = true; + } + + void SimpleScrollbarButtonWidgetStyle::OnHoverEnd() + { + Update(false, m_isPressed); + m_isHovered = false; + } + + void SimpleScrollbarButtonWidgetStyle::OnGrab() + { + Update(m_isHovered, true); + m_isPressed = true; + } + + void SimpleScrollbarButtonWidgetStyle::OnRelease() + { + Update(m_isHovered, false); + m_isPressed = false; + } + + void SimpleScrollbarButtonWidgetStyle::UpdateRenderLayer(int baseRenderLayer) + { + m_sprite->UpdateRenderLayer(baseRenderLayer); + } + + void SimpleScrollbarButtonWidgetStyle::Update(bool hovered, bool pressed) + { + if (pressed && hovered && m_pressedHoveredMaterial) + m_sprite->SetMaterial(m_pressedHoveredMaterial); + else if (pressed && m_pressedMaterial) + m_sprite->SetMaterial(m_pressedMaterial); + else if (hovered && m_hoveredMaterial) + m_sprite->SetMaterial(m_hoveredMaterial); + else + m_sprite->SetMaterial(m_material); + } } diff --git a/src/Nazara/Widgets/WidgetTheme.cpp b/src/Nazara/Widgets/WidgetTheme.cpp index 4e52a46aa..dd4d5f65c 100644 --- a/src/Nazara/Widgets/WidgetTheme.cpp +++ b/src/Nazara/Widgets/WidgetTheme.cpp @@ -69,6 +69,23 @@ namespace Nz } + void ImageButtonWidgetStyle::OnHoverBegin() + { + } + + void ImageButtonWidgetStyle::OnHoverEnd() + { + } + + void ImageButtonWidgetStyle::OnPress() + { + } + + void ImageButtonWidgetStyle::OnRelease() + { + } + + void LabelWidgetStyle::OnHoverBegin() { } @@ -76,4 +93,38 @@ namespace Nz void LabelWidgetStyle::OnHoverEnd() { } + + + void ScrollbarWidgetStyle::OnButtonGrab() + { + } + + void ScrollbarWidgetStyle::OnButtonRelease() + { + } + + void ScrollbarWidgetStyle::OnHoverBegin() + { + } + + void ScrollbarWidgetStyle::OnHoverEnd() + { + } + + + void ScrollbarButtonWidgetStyle::OnHoverBegin() + { + } + + void ScrollbarButtonWidgetStyle::OnHoverEnd() + { + } + + void ScrollbarButtonWidgetStyle::OnGrab() + { + } + + void ScrollbarButtonWidgetStyle::OnRelease() + { + } }