From f397143e308aacc8334b009cccbb6c08df0add1b Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Fri, 7 Aug 2026 17:15:40 +0800 Subject: [PATCH] feat(ui): add ScrollView widget and dynamic layout on resize Introduces a ScrollView widget with mouse wheel support and viewport clipping. Credits and screenshot screens now use it and recompute layout on window resize. Offset storage switched from ivec2 to vec2 with new accessors. --- include/Cubed/ui/credits_ui.hpp | 2 + include/Cubed/ui/scroll_view.hpp | 35 ++++++++++ include/Cubed/ui/widget.hpp | 6 +- src/CMakeLists.txt | 1 + src/ui/credits_ui.cpp | 59 +++++++++++----- src/ui/screenshot_ui.cpp | 42 +++++++----- src/ui/scroll_view.cpp | 112 +++++++++++++++++++++++++++++++ src/ui/widget.cpp | 8 ++- 8 files changed, 230 insertions(+), 35 deletions(-) create mode 100644 include/Cubed/ui/scroll_view.hpp create mode 100644 src/ui/scroll_view.cpp diff --git a/include/Cubed/ui/credits_ui.hpp b/include/Cubed/ui/credits_ui.hpp index ed9b7dc..9872c94 100644 --- a/include/Cubed/ui/credits_ui.hpp +++ b/include/Cubed/ui/credits_ui.hpp @@ -9,9 +9,11 @@ class CreditsUI : public UIManager { public: CreditsUI(CreditsScene& m_scene); void init() override; + void update_layout(int width, int height); private: bool handle_key_event(const KeyEvent& e) override; + bool handle_window_resize_event(const WindowResizeEvent& e) override; CreditsScene& m_scene; }; } // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/ui/scroll_view.hpp b/include/Cubed/ui/scroll_view.hpp new file mode 100644 index 0000000..7d99b83 --- /dev/null +++ b/include/Cubed/ui/scroll_view.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include "Cubed/ui/widget.hpp" +namespace Cubed { +class ColumnLayout; +class ScrollView : public Widget { +public: + ScrollView(const ScrollView&) = delete; + ScrollView(ScrollView&&) = delete; + ScrollView& operator=(const ScrollView&) = delete; + ScrollView& operator=(ScrollView&&) = delete; + + ScrollView(Widget* parent); + ~ScrollView(); + + void render(Renderer& renderer) override; + + float width() const override; + // visable height, you need notice offset + float height() const override; + + ScrollView& set_child(std::unique_ptr children); + + bool handle_mouse_wheel_event(const MouseWheelEvent& e) override; + bool handle_mouse_move_event(const MouseMoveEvent& e) override; + Widget& set_fill_parent(bool fill) override; + Widget& set_fill_width(bool fill) override; + Widget& set_fill_height(bool fill) override; + +private: + ColumnLayout* m_child = nullptr; + bool m_hovered = false; + float m_scroll_speed = 50.0f; +}; +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/ui/widget.hpp b/include/Cubed/ui/widget.hpp index 9b7928b..49f67b5 100644 --- a/include/Cubed/ui/widget.hpp +++ b/include/Cubed/ui/widget.hpp @@ -32,7 +32,9 @@ public: virtual void update(float dt); virtual void render(Renderer& renderer); virtual Widget& set_anchor(Anchor anchor); - virtual Widget& set_offset(glm::ivec2 offset); + virtual Widget& set_offset(glm::vec2 offset); + virtual Widget& add_offset(glm::vec2 offset); + virtual glm::vec2 get_offset() const; static void set_window_size(int width, int height); virtual Widget& set_visible(bool visible); // Returns the final display size @@ -78,7 +80,7 @@ protected: bool m_fill_width = false; bool m_show_border = false; int m_border_size = 5; - glm::ivec2 m_offset{0, 0}; + glm::vec2 m_offset{0, 0}; std::vector>& children(); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5ef935c..b1fdc73 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -108,4 +108,5 @@ target_sources(${PROJECT_NAME} gameplay/block_manager.cpp ui/screenshot_ui.cpp scene/screenshot_scene.cpp + ui/scroll_view.cpp ) \ No newline at end of file diff --git a/src/ui/credits_ui.cpp b/src/ui/credits_ui.cpp index 003c8cc..d2bdfb8 100644 --- a/src/ui/credits_ui.cpp +++ b/src/ui/credits_ui.cpp @@ -8,12 +8,19 @@ #include "Cubed/ui/column_layout.hpp" #include "Cubed/ui/image.hpp" #include "Cubed/ui/rect.hpp" +#include "Cubed/ui/scroll_view.hpp" +#include namespace Cubed { CreditsUI::CreditsUI(CreditsScene& scene) : m_scene(scene) {} void CreditsUI::init() { + auto& renderer = m_scene.scene_manager().app().renderer(); + update_layout(renderer.window_width(), renderer.window_height()); +} +void CreditsUI::update_layout(int, int height) { + m_root_widget.reset(); auto image = std::make_unique(nullptr); image ->set_image("texture/ui/background.png", @@ -23,25 +30,38 @@ void CreditsUI::init() { auto& rect = image->add_child(); rect.set_color(Color::BLACK).set_alpha(0.7f).set_fill_parent(true); + auto& title = rect.add_child