From 05c78da22ae5bab7d0434db99b6e27c9d481dbc0 Mon Sep 17 00:00:00 2001 From: SirLynix Date: Sat, 16 Jul 2022 14:11:03 +0200 Subject: [PATCH] WIP --- examples/WidgetDemo/main.cpp | 13 +- include/Nazara/Widgets/BoxLayout.hpp | 41 +++ include/Nazara/Widgets/BoxLayout.inl | 13 + include/Nazara/Widgets/DefaultWidgetTheme.hpp | 14 +- include/Nazara/Widgets/Enums.hpp | 6 + include/Nazara/Widgets/ImageButtonWidget.hpp | 76 +++++ include/Nazara/Widgets/ImageButtonWidget.inl | 101 +++++++ include/Nazara/Widgets/ImageWidget.hpp | 3 +- include/Nazara/Widgets/ImageWidget.inl | 26 +- include/Nazara/Widgets/ProgressBarWidget.hpp | 101 +++++++ include/Nazara/Widgets/ProgressBarWidget.inl | 155 ++++++++++ include/Nazara/Widgets/ScrollAreaWidget.hpp | 66 +++++ include/Nazara/Widgets/ScrollAreaWidget.inl | 43 +++ .../Nazara/Widgets/ScrollbarButtonWidget.hpp | 54 ++++ .../Nazara/Widgets/ScrollbarButtonWidget.inl | 12 + include/Nazara/Widgets/ScrollbarWidget.hpp | 60 ++++ include/Nazara/Widgets/ScrollbarWidget.inl | 44 +++ include/Nazara/Widgets/SimpleWidgetStyles.hpp | 142 ++++++++++ include/Nazara/Widgets/WidgetTheme.hpp | 116 +++++++- include/Nazara/Widgets/WidgetTheme.inl | 13 + src/Nazara/Widgets/BaseWidget.cpp | 10 +- src/Nazara/Widgets/BoxLayout.cpp | 142 ++++++++++ src/Nazara/Widgets/ButtonWidget.cpp | 10 +- src/Nazara/Widgets/DefaultWidgetTheme.cpp | 147 +++++++++- src/Nazara/Widgets/ImageButtonWidget.cpp | 91 ++++++ src/Nazara/Widgets/ImageWidget.cpp | 4 +- src/Nazara/Widgets/ProgressBarWidget.cpp | 106 +++++++ .../Resources/DefaultTheme/Hovered.png | Bin 0 -> 1112 bytes .../DefaultTheme/ScrollbarArrowDown.png | Bin 0 -> 1508 bytes .../ScrollbarArrowDownDisabled.png | Bin 0 -> 1376 bytes .../ScrollbarArrowDownHovered.png | Bin 0 -> 1956 bytes .../ScrollbarArrowDownPressed.png | Bin 0 -> 1154 bytes .../DefaultTheme/ScrollbarArrowLeft.png | Bin 0 -> 1420 bytes .../ScrollbarArrowLeftDisabled.png | Bin 0 -> 1296 bytes .../ScrollbarArrowLeftHovered.png | Bin 0 -> 1850 bytes .../ScrollbarArrowLeftPressed.png | Bin 0 -> 1173 bytes .../DefaultTheme/ScrollbarArrowRight.png | Bin 0 -> 1368 bytes .../ScrollbarArrowRightDisabled.png | Bin 0 -> 1228 bytes .../ScrollbarArrowRightHovered.png | Bin 0 -> 1810 bytes .../ScrollbarArrowRightPressed.png | Bin 0 -> 1126 bytes .../DefaultTheme/ScrollbarArrowUp.png | Bin 0 -> 1309 bytes .../DefaultTheme/ScrollbarArrowUpDisabled.png | Bin 0 -> 1246 bytes .../DefaultTheme/ScrollbarArrowUpHovered.png | Bin 0 -> 1867 bytes .../DefaultTheme/ScrollbarArrowUpPressed.png | Bin 0 -> 1271 bytes .../ScrollbarBackgroundHorizontal.png | Bin 0 -> 250 bytes .../ScrollbarBackgroundVertical.png | Bin 0 -> 230 bytes .../DefaultTheme/ScrollbarCenter.png | Bin 0 -> 721 bytes .../DefaultTheme/ScrollbarCenterGrabbed.png | Bin 0 -> 552 bytes .../DefaultTheme/ScrollbarCenterHovered.png | Bin 0 -> 900 bytes .../Resources/DefaultTheme/VerticalSlider.png | Bin 0 -> 1404 bytes .../DefaultTheme/VerticalSliderBackground.png | Bin 0 -> 566 bytes .../DefaultTheme/VerticalSliderGrabbed.png | Bin 0 -> 1149 bytes .../DefaultTheme/VerticalSliderHovered.png | Bin 0 -> 1998 bytes src/Nazara/Widgets/ScrollAreaWidget.cpp | 204 ++++++++++++++ src/Nazara/Widgets/ScrollbarButtonWidget.cpp | 68 +++++ src/Nazara/Widgets/ScrollbarWidget.cpp | 151 ++++++++++ src/Nazara/Widgets/SimpleWidgetStyles.cpp | 264 +++++++++++++++++- src/Nazara/Widgets/WidgetTheme.cpp | 51 ++++ 58 files changed, 2306 insertions(+), 41 deletions(-) create mode 100644 include/Nazara/Widgets/BoxLayout.hpp create mode 100644 include/Nazara/Widgets/BoxLayout.inl create mode 100644 include/Nazara/Widgets/ImageButtonWidget.hpp create mode 100644 include/Nazara/Widgets/ImageButtonWidget.inl create mode 100644 include/Nazara/Widgets/ProgressBarWidget.hpp create mode 100644 include/Nazara/Widgets/ProgressBarWidget.inl create mode 100644 include/Nazara/Widgets/ScrollAreaWidget.hpp create mode 100644 include/Nazara/Widgets/ScrollAreaWidget.inl create mode 100644 include/Nazara/Widgets/ScrollbarButtonWidget.hpp create mode 100644 include/Nazara/Widgets/ScrollbarButtonWidget.inl create mode 100644 include/Nazara/Widgets/ScrollbarWidget.hpp create mode 100644 include/Nazara/Widgets/ScrollbarWidget.inl create mode 100644 src/Nazara/Widgets/BoxLayout.cpp create mode 100644 src/Nazara/Widgets/ImageButtonWidget.cpp create mode 100644 src/Nazara/Widgets/ProgressBarWidget.cpp create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/Hovered.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowDown.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowDownDisabled.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowDownHovered.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowDownPressed.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowLeft.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowLeftDisabled.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowLeftHovered.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowLeftPressed.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRight.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRightDisabled.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRightHovered.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRightPressed.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUp.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUpDisabled.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUpHovered.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUpPressed.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarBackgroundHorizontal.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarBackgroundVertical.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarCenter.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarCenterGrabbed.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarCenterHovered.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/VerticalSlider.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/VerticalSliderBackground.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/VerticalSliderGrabbed.png create mode 100644 src/Nazara/Widgets/Resources/DefaultTheme/VerticalSliderHovered.png create mode 100644 src/Nazara/Widgets/ScrollAreaWidget.cpp create mode 100644 src/Nazara/Widgets/ScrollbarButtonWidget.cpp create mode 100644 src/Nazara/Widgets/ScrollbarWidget.cpp 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 0000000000000000000000000000000000000000..d2e2df848d1c262415a4a20ec86c4fcb03ec2cac GIT binary patch literal 1112 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP-i-b6n`lgx+1)z{@W=KSdbAE1aYF-JD%fR4Vl$uzQ znxasiS(2gP?&%wlqL<3fz`(r6)5S5Q;?~>SXY*uS1=v5-hx(rHN#854#&%nUPkvH! z(~+s+9x4;!nSY*|Ip@SoZO%Q+LPFE`c&JSBP_*#Qd8}fc{k|$~*Y2)nPOl9+3U2#e zkBL_PTYoveUGvcXtb*^i&U(~^H?C%RvLuB;se^|*T+K~o*)5~X?}eT|e|hh4_4@t= z=7;L{7e{w&KVe~UdfCpMw;Z1d2{K%2J>}-FZ!= zU21H8zPi5tKcmE-g16COH5-IZeN2nlU%&OHRQ{2RYvjG&?+F%b+n{qts6%Sy(`o6h z(`8?Me3gIn;nU_vKYqi=Ht+A2 zPoW|cS?_%L$Lw_U*NgVt$CKCP9ygxF-?#IfJKye{mbWslfBhun_Pu7`%ynAy-&d{K zLFT0;yVf0MP7jjaa8^OYZ}UryFMhukepz%{QjWppNYyRw?7EUkvsWjE7)Y*cK2yCh zV{Unus{Zr2p;6n;ZL$=c!q~OwL+e@=vAA!41jMu_xEp>`=z8Ay_RqBK9qxDk?^4#3 zZtUqeP;pwDQKf-p0)vnPlLrH*0$Cg#a|TJq=elb7&Kbd~%@b!fG77V9;#->$^K1Xp z^S?Vb`7O%g+uGCHvG+*UH1pQ-x|h>i%I7`1BVxy`%_cBA>w2Vw-=@s^W3ghDmD3%2 zCZ^e(R;%25Yoa{Uiy58Y_WpQSywbey&gVGgvzN{_xk=eQIQeShmD%$iO*ru__33Hv zi3jFaep|{^+`dP1QHxH>u`}MEpPv8WbL{EESBqc0oVqxt$ad4$gdd)_;^S;i?T`2! z-_p6t+&u??q0ZAE~PSeZ1#hjplOs?RWATUYxyl zGaQr(q7|ZZp3L=}JA3uq)Z#EM9y0+kwu1>vSgr?#mp*Bq_b4Dy&*}e+ceXpeX5DF( ztuIJ_?xu3r^oALar67;X#Eg%8?8d3a96Yju-(2;#o&V4J&C#^Ta&6}}PzLvO^>bP0 Hl+XkKIx_Fa literal 0 HcmV?d00001 diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowDown.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowDown.png new file mode 100644 index 0000000000000000000000000000000000000000..f414abe8ce15ee79865d9cc18553b0f235c5d176 GIT binary patch literal 1508 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 literal 0 HcmV?d00001 diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowLeftPressed.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowLeftPressed.png new file mode 100644 index 0000000000000000000000000000000000000000..149d4d6206f75673b218c84bc9c2d4669cd15e0c GIT binary patch literal 1173 zcmV;G1Zw+WFU8GbZ8()Nlj2>E@cM*00a3+L_t(|+U1+EYTPg! z#y`ul?7M^HLLh+*NpXfiNZ_DwQ*KEh1WcwrK$fgsGH2)mWNDYIeTNddXAE@c6QtbG zM>s;cJ9Rl3S(bcP8cT{TF!tGT&fibp|1aq*1u&N@0G9yX1K0t;(2{Zm;28jK$yO*| zS|pqU;DI9kqe^5r9OCfs5WQXxVHkoCQn=1JH}1u;>%uul5CjN<0E58**VotiH7eP@ zAU;h~oS&bg*XtpQB2Y>}2mv7kK@gO_Ko+Yzb_s)X4nhd__V$pbY2lgx@JX%plamu9 zNrE_z5k(QAC;}k_VHj!w=#G7Yu(7d$-QC^NGtfotzmsczG#a7X?V{7^AdX|iaSTc+ zD5bfTf*`0AvR!5N=X2|?udgFX5_CG9+yQb3$in4+wyGO!7D5OZW7_AH0qlqm$H&KDjDazh z*F0k^x4#O&_o7SMItS!EynerrD2j5+3*kb%9RF_xz%n;d`2%ANVHko^n(qZgUF4(W1FqW}(IbkVWe{JxwbG097&mmSX?E0W{I-D*;&Mf>r@Ab$A*d0={JXEX$B( znSBSCfY=tVJGKtMwRjs4h)+$O4ag^@kRhP!@#9@=Q+T&c&85V zL40Kns1t%O;+?btK8d#uz&G($0r)818USC#8;8Sf5nnkRZcC{>1gdJ;#o)(D4)7U* zwGi+XLhVV=cL)Ul;;m5CY>=iwC^IcX(L2MRR5Gr4f`vk!X0Cg&?i@}i&g0=SovIAC~0#`SLx?MrlBeOd+bnytVe zEanT3$75`5Z58Y;R$ItnQUzg|Yizm7^o;8F69B)(hsVdqJP)Whs5h#8203?_u9>da zvB`O?YVigI@B@n#BTr9H7>~!;-`_VjhoNk^D`~>&ydy)4TnSA-rknh2${OeRZfv@=&FOoImdK5%|V=< zos|Gw0r)E4l%^?eZffbRf)0T=-2qXi|@ nocjsj^8&;SKzFf)O$6{4V*=?`u#OEi00000NkvXXu0mjfX|?_^ literal 0 HcmV?d00001 diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRight.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRight.png new file mode 100644 index 0000000000000000000000000000000000000000..b68433834ddd49ca78f29380069a91f327f28e28 GIT binary patch literal 1368 zcmV-e1*iInP)FNLg03B&m zSad^gZEa<4bN~PV002XBWnpw>WFU8GbZ8()Nlj2>E@cM*00g{AL_t(|+T~l#O6*7! z{*n%YAcD{!%%+)Vm`8BqLkM$su4b0Hokx(FC+MA<>!vqu-0AXy(CSj7!nkNfkN_W=PEL6M6qa`h0ek~60x-1wNPUua1K{`1On`2G zQ}6-Zd3}9F5Cl%Nsg$zr>utU+%Mwbds_Ff*EUTuJ!qd|e#^W)D!y!&iPWY|=_`d!V z06gjg9v>eO1Oa-zo>Kzqwso@+K!GczP!z??@$2hr?CtI0^74{D!WRI;83HDg36xUk z^?LAqzjYN*@N}Q|z6MT7DT<;ZLrRJL{e7;65Wuf*2+)7%`+nmj*a+aDO$3-sfGa>s zSrL)vId*q@9(j*vqNw9wbtVm zMFG$A8Xpff`u#q(wzjA#{PsrU9IU>WI+mZ&=Jh7uo=2Dl z&WYd-b9;N6UiwS0Xm6Qr+_X8=9p@dT{T5XPJ*R!b=H@27Y$f1-`kseyO@wLTKy}Z1 zo;Tyev;ugX6EyW;Z4zPfTl5XF5CL^+aJ876FMXyuGq9bPQqCOn@xc}0SX8c+(`)z}FFngCz-(X~?qG}ZI-qQg!Q&@}i(zh?Q% zD*Hvv!CzL{FRBQCnQeaF=+G$vu6w?Y1m^^FLH4$2&|g;YoP<_Ppv|7AgC4ry`Gm;N z9R1A$-#7s#piRr(R8++iBTf}S0lVyZK0>s`0>MX?yas3^gG#@VK#1SGE4cvE_dqG7 z(FB4Y1>ZIaruRH8ljU{8{L4`Af5Ep2oYnx|ROz?DTT>of+&hw2X88i<@PUxfDi(493x2* z#Bq!$ijbx$(lo{D>gtR|2lH${3`0CWKRX9rcT5APDxh|sWmyG&I-MelA|y$IBuQ|0 zcSry7-&zHX$74J^JUH)pUiZt_6u4frx7P~LvY$?;Ra;+Q$Kl~2z16qC_L@68JHyS* zO(&e4srcDc4zE?99bg>CRZG(p=jZ4A79*nx93LO!;^Lw+;3)|vA}9fRevno{nx@FI z3{e#E`9dLp;hXsaM@L6EJw0tTy0e*psZg4B91ViBFX;FCxVpMBO`H1*VDknK4h}FH zjXDwAQ-FH*8U;>|(NMT33T$j_U~O#;VHlbwP6EI`_&#wG_~cV(KNA7Q$WFU8GbZ8()Nlj2>E@cM*00b~eL_t(|+T~kKPTVjQ z{$fHAqd{Wb4YOjwwpR!%)EgkR7bsVlvS!y_pd10Q%>_mXB*X%V#fS}o1wlgmDH$i} zrbZ9P_5_&NZm?u&#*<|HeeZjIw(}fBQB%+qXk|e=sG{V{0nf%xvQ4}GL zZ6QF9RK$`#;BrPl~U@#b9Wn~4|*VowF+r#DMrA)$M9LKv%{_~ENfNQUR9N`UH5xY6j)wf#^&ZGR##VLu7B1PAV?_75{xkfLEuyc)6`(9 zGEo~F8@Ri>qe>V=QS?o#b(5uLRhw8=2ad{KMIfyL$NKuZeCby<%|fP*yr)vICV;AT zol2f#`#UEMS-QICHm8+Q1wt(1ibaXR^S7cbrsV6w7F9kWmY>mv9juim{Npe@V4X0pV(3cl$(4Ayna zPjd&>b=iBR09)WqGeKtrxU{_U#gHrTO)}3|*L~ip3-};=c@gCOhDaN+-`N_ONs{39_SU-WRfNzs zRZ=%SCL{bm&vRs1_FNYi7jblSL~lC`b$&G-kCCRS7e24b3D!+{#b750pssLnaUtKf zuXKUa(^Di#;uO426}o$96c8i`zvrAI%QE@o*m)esyS4KI$H&JQkH_A`cv<>7BIFsL zP(i=n$JN!93?5LO8ap^Rz{$ypm%yjB(M-@@uZLc*hcrzw8jVzs|1FNtex$R*6#SOc q9U({M9Kd%9-r9bEW6;Lq^M3)3dB@i&9a@qA0000WFU8GbZ8()Nlj2>E@cM*00wqRL_t(|+U=XmZX?GP zhQBHnNs+QfzDzU|PbL~<;ml$H8}KT-z(5vR1PJm1d4l*E<^i(v6Bx(?7;uaLj*%>4 z?J|LpF`$9%u}DuWDbiTfjcoR%>SWREW~;l!XdttjQqn-9yZS=*|DV53-Of>faDBHP z@Cf)2c)#ocl@g$UhPo!W1w?^Jj80NA9_ERN2~fb2hE)wM1^SAM!UCay2Y41Dz@>NJ z1Kv#v1^}&KRdM_G4-jz^W>nQSd$Fe^|BfICkyw^>hnM^=&4Lkh^caN%+YjyC3&q5XEYUNq7XjZ_=8e702NTub5SSe)DJCXs*m%1tLWo zX743?zAOUbV&KlX*z!??70YQjWIs5dH~bfWKmI5GIQg7|cVK<(KK(yz!huVa@GwKb z)Ezd^w583m>R=kCS^_d)v!IIv2%;z8Cr4)-P8?n7@QPmLhh~i*HE;2{S>uz#4ZeA> z&Fx>@WA~3=!wDeV1Ac4r^-C#@0-SX?97?HLNk~N@#XV7|LZOugfmWl57KKvqllG5k zt+cR_<)i4Y*mpwMFyMs{0>ZCmR&r}C*4mii?|DytJHIFQ&U>$*1d%gFQc9t<#%M!} zCb!IMyxFdf~xbc2>^ za@+iX2kkfbV!Va?)ItY1Re-#1F8YyWe>`t8W?j!4L`2Y97gV8@rlXd)(^%tA`$|!4P0Bb zSdlK-zVWmpblwlv+#@dYJ6Td@RfFt(g~DKH>gI%w>3fe(fZjX$D2A_W_GQLUt5csSl`& zgwhruC7~uCP=^xoRFX-{i^#tg0;-aIfe03$8LYa_pE;MB6;QS1 zFS@j@ueI!R6E9mS!=Uf^dn}Cm^2;cV!f*?HxVaPD@IMv?7 z`0B+75D^X!4+(;xR^a*P%IbX-MFc^B=Xs3BV@BSH;dsbFIAG8@p(zG0npOjI5%Bx_ z`wWM}+QFBF#pdgO5CjB4z-TnW^E`&5A&285_Bi06b<9fG;W%<}QWX-IBH**-Ua!Ys zFsK~(tZNDItO~OA-uHbx&*OA>%HimUonViCcbAjah?Or_<7BEB==MwnJbwI`ot>S^ zEuWA3%^$PClP&S~N!=ffN1TjL+41-Js`ZTR?sK|siQWfK;!Lvm)khful7PZkPM>ak zN^h&T5Y8?i{9INYoO4)b38Rp4=yMXB@^AZ`t@bugZ)`Ja`P|%SWfP|WJ~Ww0Gf)tT z<)gp+iT;zVxd%&M6nvJ1G9pqZ=px4W9Lp)+HIDdpd7s@I1H87+oiAUe|L4s(eQuga znIugKIN?U~CI0r=276C;(XN8LL74$w(n6}wGo<7r#c@Q+;u)Xgr4h&75ySSFu3h5h zMw|Y}PvZQ+X|U+SX)7QKLSgUtIsNb%++ExhT2(m7kf1=6(6UWdf-WzA71#NrK{QF6 zOu@g$B!#w^I=gh0^M@z0d4bf~|0hrLKb}7SAIC7}l$@Gj0ssI207*qoM6N<$f-fy# AVgLXD literal 0 HcmV?d00001 diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRightPressed.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowRightPressed.png new file mode 100644 index 0000000000000000000000000000000000000000..7f7c286f0ac633e0d6f98d4eb79f62b77b8285b0 GIT binary patch literal 1126 zcmV-s1eyDZP)WFU8GbZ8()Nlj2>E@cM*00YWNL_t(|+T~lzN+UrO zJyq3th!Sv-O%{>?!4DX4=?{eY2750vKM;_BKcF*T;KGdy7m7b21V#5wR)b)0<053V zZp~(@sZ^>vK1fw1T~Ks)rQ7av?zy)f)@1+`mbVN5^Z{G|IL^CCm8AX#uv=yVbp2_9 zPt1#Mw~OcJXAlvT^5+?hF)+ra&N=53ZHzH+&a-nNM0RbqkH=#?Jw2h{@8jy~%6{GV z|HmHyz|0tMczB4>XoS&d1S0ZAfC6;|T(e zj*d{RRzXA!qu!t5{oG z!^_KyR|UM~H(M>bO@juI0Vg655u}tz(-gzu&{RSj!0rSA`j0TiP^;Cjva$jxrI#4s zI?rn>y4Il0Dy0MwAx%^4@9&$Bew!db`@LpT2!TqaGWU2;q<}n9ii%di>+36s2%K{e z5!&rGwzs!USNJ;R0=D0C&LM;dGKzUGaM$-sDZv=ajJUJ2V-nCx-rG$rLJ>lMh#-Uj zV=N;ENd`g(nR9k~OcMK5{5)a)f{wc7F$FsqkvjW?E( z028>DzdfSN)PW^0_9)Ws(GrxPnDYf&0ZEw@;EDm>T%gnGpwsCDCnHDCc(AR z96ShyRDx^eDM&96LJ83*z&8oA7F2`I21CV!sHVfANr+-SAZTEWW!gGV5~2)(A=d_? zB%sL3Me6wM?2wlMeAF=@B>3P2ga#k&g2=qUM-v2nf}i#OOkPIW2O}Uh@Lmas1$>Z^ zV2qacMnKHqgLZ>4fcHXx3#f1Kc{4$83NQhOvV7inASs*VOT8Wt?R0pa)^^oW5b%~g z$E9!q+xqtAZ~hrZ7fJehf6#C^e19(x%UHb%W(N2OAU*6KwgJ`;SBBoIR2_V(6Jo9QQcQg1XGsMqV! z`S&b0u;s4_0Dyyo1N)H+XAEdIn`kr|(FVCZ66{UUS^-3ay}dmr-Hk?JM?-zSK3@}su$SW+Cr<<^3wHvG$qgVoNm+K`|$99>+5Trot?Q7CjsCW sj9lVUr_Pp%0B7>_vhNljU`G1;M1& literal 0 HcmV?d00001 diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUp.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUp.png new file mode 100644 index 0000000000000000000000000000000000000000..641f747a00808f7495c9d8cffa35c22a3faa2503 GIT binary patch literal 1309 zcmV+&1>*XNP){010qNS#tmY3ljhU3ljkVnw%H_000McNliru;{+KN5)AEpo?`$203B&m zSad^gZEa<4bN~PV002XBWnpw>WFU8GbZ8()Nlj2>E@cM*00ep*osLOR+lD9IPtg^G$#akrw|rGa9%K$M6tKnDnk0*SQ*iUdJ| zB1kxXY;hUucrtz_wkMDyS$@Qi`TypeGvo0Dh_@{O{{XlH@D3mt!{zQn!xnPb*2jgx zCtL2afcWtVh0DtiD%g<3|1J}0wOZKQ+r#?$I_Bo)U>HWK3uQS+SP%r6_JbgZZ2P_s z0PuZ3{7oExetyQ))fM*l_i=W1rh4q30REr=wgCJ^&uBKAI6gkc%F0UQ!Eps0g?QC7 zk^oTAVokS$Ai(YIEw;C}aeaL)KdKGjZ&BJi0Kd>$KRG#pVHgp*qk@n{xT^M(0LT!; zzUO)9_xsq{*^#~BKLEcPa_u*pO`M;f4~S0!QN)5E2%iz>`YHhOF(DQJJkJY{d7c-p z1%!6HEqg-S_-H166Gv`tZm_z#I^bHWLKN|WwAxRKds($z_geo!8-voeuzmKJ*CA3;C8VcVzfNx@NcXxLn zjDPum)14acQttnJ_n4Cl8^9;iX zJyD2vT^GyC%k*@M)4hd-1*LG67mTv@^BhNZKT`;dv&rucg>t~S1CU>nQ*%I;*VR#3qtQU4(I_1N z-A~K`RmMLRUIqkJCrIRj+CxAkc$5(022NCokm(?Pln~-VIIbhdbP+!+gt$RfIS16{ z0eOU#l^AR52NV%h zL42JMm@eY$g1~eVUk3!HoA|0BFdfBL38BO9x!IcziQ1F1|U8#h}l-Uz$p4LhvyaVI1V`HT6#ed z2t1GYx3@Q#raAD1^-F}n%gYN))6_oxRkKHj2Jra!2;cVy#?*C&AkPRb4B+A60li)? z^9{9W-xzziR literal 0 HcmV?d00001 diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUpDisabled.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUpDisabled.png new file mode 100644 index 0000000000000000000000000000000000000000..cbd4183e1987c17913c10cbed1af63d1816208a7 GIT binary patch literal 1246 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 FV1k}iaJ&Ej literal 0 HcmV?d00001 diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUpPressed.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarArrowUpPressed.png new file mode 100644 index 0000000000000000000000000000000000000000..20fe41bd86e946def3e31abc4a7db7378350ea17 GIT binary patch literal 1271 zcmVWFU8GbZ8()Nlj2>E@cM*00dh}L_t(|+U;AhPV6`o zJ+U1phCo4uo`f`y25CApVmc)HX^{2zyB~B*!Eb5 zh;IV~Zf@Unz@7pA50jDUbc&Oc6L8LvWf=$|@H`J$mgUE!XdwU_xHHFyR!}X7l1!?0_Fhz){i(oKE}nx1vuy6oP#k2N@-yr8%P)U zD&VTEf0}JIHX$T$>x8KB(lmvX5>iUMzP{q-<^~TB59aW{1Ng4~!6Sf??)B5tQwSjt zhG9;EB0wL|1h0F$415`IQw{oly>EV}OiGC~P4V{jh9pT4$1!eiZ%sA)0PvN)dw-;R zelnS0cXt;%J39!&FekwzAj>i*&@$P(zH^bF1J~O&HLB^DBuT!-ag58$OFTb6>q-~_ zn0xPO;y1PT>go!6dwYnY2vHP42w_!#{zvP0x~>wcrihI!UBM5?g?gv4DAP92sl+q6YYEw-q)r?u^=jS>BUl;(cdQlYRa#vng zEUL)c2k=S_%3+jJaLz#p!Duwn593VlDX@&O9K4dfnR+(e`)QiyZQu8E$L;U$7mh6u zKq)PNrj&ljvwiTs8AGI$xf+5XC?4aQH+rh+6KJzWP>%IHFL$t00cOdmpQJBy-$sTi z;cdq1rk*|wu<7 z_!U4+lHh#s(nTd$24t~VV6j+qO2SfUa8)v@z}wnwkWgCzU3$LGz9vX0edN}b{Fepa zl@clop>={^2MMI?+WA-Fz^dT8CZW;G;ikZMNkU_3uxapJkx+U+poyTk3iu|^(RvVE zHmz;S`AZ2{cI8Li!lnrl>YTrhdRbH8yO8TD=Xa4os(?4K{%4bo*ud(`-G)xW2LiSU zeCroOy;Z>060i+cdOyGx13ne-Nx+s9FodNtD-kgCc)+R-&{vCY9RX@(WuL)U{dXq; zzVAZ_u`z1~t6sb+`(4>@tORh*ad2?pe5T$v)9V|xirh&6=Nv~zNAP`rP;*_qMIxni z6F@1&csxcJhK)ZWYibJAo#(du8tOeFCjn{XE z)7O>#F)OF2n8oqg`AdL8vY8S|xv6<2KrRD=b5UwyNotBhd1gt5g1e`0K#E=} zJ5ap9)5S5Q;?~bP0l+XkKGp08V literal 0 HcmV?d00001 diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarBackgroundVertical.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarBackgroundVertical.png new file mode 100644 index 0000000000000000000000000000000000000000..63112abac1af7463e69858525a4d3047dafb9725 GIT binary patch literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1SD0tpLGH$&H|6fVg?3oVGw3ym^DWND9B#o z>Fdh=n3YphOipy#t4N@bY-UJAiF1B#Zfaf$kjuc}T$GwvlA5AWo>`Ki;O^-gkfN8$ z4it~^ba4#HxcBzFAuodh55vKx&R^nzfu)U1H#ih`#@Fu(4Be=2{J8XP?G9r*ey~Zz b5)bOQXQi^v*HixL1JdH@>gTe~DWM4fHo7t5 literal 0 HcmV?d00001 diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarCenter.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarCenter.png new file mode 100644 index 0000000000000000000000000000000000000000..816547f8f333193a371a31cf8b89e2efb878c75e GIT binary patch literal 721 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#F)OF2kzmO|u{@xVY-UJAiF1B#Zfaf$kjuc}T$GwvlA5AWo>`Ki;O^-gkfN8$ z&cMLr?&;zfQgQ3;?X%}TI*71;sJGv+NswDxx>88|q1xT1?hTtoq;ob*h{#mQ4e8=q zYJ9moG;{T@E6E?fJ)R@0T3A}J&nb25iL)PIxl93RQdPTbrka{vWU29hJ2cRmhJLOkyWeI zn1680`FuzrV^-VOD&ELxik_F=GcYK$Gzc(ln)AN(kO5D|tZzPdKJO`EaCO+A!@VrC zZIZat67~=Kk4T)BJ@mAwG57YuC${IApZ~FS*kZrvv(u%oI<1c_3S`u$?6ChOztthe zJ4NpSJ7p~k>>rT5uB|xVjZ&|G1z-9yyH(IcCy6YLoBWfAQvf^_Hl$>5o=MC2WjHu#gdZmgj%H zbj$5rjjm6>D;sa-v>i+c*byBUd;Q|el1cu(y~mTk{Qi6B-goJ?#=Py)aY~Nu%U>4m bxbl(zl)7A5bbZBSP+IeJ^>bP0l+XkKvKKJ{ literal 0 HcmV?d00001 diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarCenterGrabbed.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarCenterGrabbed.png new file mode 100644 index 0000000000000000000000000000000000000000..a18825cc752d2e4d4ddc5c2733e9f3ea35c774d3 GIT binary patch literal 552 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#F)ODShlSvrcS=AZ+02lL66gHf+|;}hAeVu`xhOTUBsE2$JhLQ2!QIn0AVn{g zoq>UIo~MgrNX4zUw;k6t83?dFsK2EoD!8cg*w&9MRjkwRop7GL!$47St#+r9LihFx z-THC|C!_e~%-xcV4-6kJHTY;+$?&8a?hq)Vaa!p6 zZ`*xy&Df4V7JU76mp${8pc9*TPCpguKdwCM!PaXx-hbCPUG#&);<ykt??ajomt?ZklnFucnpauuw3y>|-xq!JI(6Zae>c*ft&cln@5m(3z`&xw zz{ugiKmxNNfH7&VlHps0-Bzo1zx(_B>h(K!_x;}-9+Ca`Vv*b_p^0iY7W#c(KXK;w zyW6fQc}`jo{KxjkI=_m`(_gs;9*B}YYAG-EJM3D<~^JLV99mi=kpR@PChZ^D<}#*UHx3v IIVCg!0H$)^ZU6uP literal 0 HcmV?d00001 diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarCenterHovered.png b/src/Nazara/Widgets/Resources/DefaultTheme/ScrollbarCenterHovered.png new file mode 100644 index 0000000000000000000000000000000000000000..f5dc18c0359024d2761639114dc3570c0959266b GIT binary patch literal 900 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#F)OF2k`Ki;O^-gkfN8$ z&cML*%hSa%q~g}w+h_fR14Rye{J+zfhv`~|Dr3y)re6LB=jN_|s{O-Zl7Pvi7fvm$ z8y0QMTDWAYqt)9pdygNzaO(I6!Cf1S?@TtyytU=!&$Bz9`%SK933yl7vN)a1pvZpH zHZHEyr%!V%kVtTQ;K?xYiRnU7Z63?BtJiqusx_j1MyRuw3t;M~JG+PY55 zFE6~Cr>wNxb=?cr#t+Zf7NtanS+zWVoczebZhFndYjXF#aj)IFSbz2xk4Y^mp8sOM z8uwc>^GrXoM0rW3*Q{mJS4D&tK4$9i%5*wx*}iq#hwX7&S+t6GFJEQxoGaeG{Nfij zhKWUL^}(rp_ph%CJ+Q-j(-(%vW>2&JKK;xfcYwKqf&T%cO#}M}VmJLO zERKnx9Ucz_cSJLPsj_`!q34?1y=cV-t~0TWyYA}E^;>Q-_wSP@EiYfbEIxUEC)2IB zX1#8Ur$ooB4U?X$yypsc9`l79vzzzs>AjV!uc+|Y8z+C3qr=0_q|nyEE@Z>z-G`4I z@4a;Y#g=c;Iy!m}3M`LI-QB>ks&BGmzyIv{KX?3EXk@&!`Zw=9yV>av*ro?r8Jn;+ z>!jwsW^RwK6N(BhxE*jU;LW|!c^ebI9c=9XXKBXNY8y7bB1eQLZ zyx7Uk>bF6|i!XH%+Gg%+X5}|a3ZzeX!eO*Y;M2pGtIqptKltLrdgt*E?oLLpLy}Tq Qi$U4L)78&qol`;+0E$7AdjJ3c literal 0 HcmV?d00001 diff --git a/src/Nazara/Widgets/Resources/DefaultTheme/VerticalSlider.png b/src/Nazara/Widgets/Resources/DefaultTheme/VerticalSlider.png new file mode 100644 index 0000000000000000000000000000000000000000..3cd10431c5378fcb12729a2388d397901fee6ec9 GIT binary patch literal 1404 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 literal 0 HcmV?d00001 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() + { + } }