diff options
Diffstat (limited to 'include/cru/ui/render/ScrollRenderObject.h')
-rw-r--r-- | include/cru/ui/render/ScrollRenderObject.h | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/include/cru/ui/render/ScrollRenderObject.h b/include/cru/ui/render/ScrollRenderObject.h new file mode 100644 index 00000000..bb282953 --- /dev/null +++ b/include/cru/ui/render/ScrollRenderObject.h @@ -0,0 +1,98 @@ +#pragma once +#include "RenderObject.h" + +#include "cru/common/Event.h" +#include "cru/platform/graphics/util/Painter.h" +#include "cru/ui/Base.h" +#include "cru/ui/render/ScrollBar.h" + +#include <memory> +#include <optional> + +namespace cru::ui::render { +// Measure logic: +// Measure child with unspecified min and max size. +// If parent's preferred size is specified, then it is used as measure result. +// Or child's size is coerced into requirement and then used as result. +// If no child, then use the preferred size if set or min size if set or 0. +// Layout logic: +// If child is smaller than content area, layout at lefttop. +// Or layout by scroll state. +class CRU_UI_API ScrollRenderObject : public RenderObject { + public: + ScrollRenderObject(); + + CRU_DELETE_COPY(ScrollRenderObject) + CRU_DELETE_MOVE(ScrollRenderObject) + + ~ScrollRenderObject() override = default; + + RenderObject* HitTest(const Point& point) override; + + // Return the coerced scroll offset. + Point GetScrollOffset(); + float GetScrollOffset(Direction direction) { + return direction == Direction::Horizontal ? GetScrollOffset().x + : GetScrollOffset().y; + } + void SetScrollOffset(const Point& offset); + void SetScrollOffset(std::optional<float> x, std::optional<float> y); + void SetScrollOffset(Direction direction, std::optional<float> value) { + if (direction == Direction::Horizontal) { + SetScrollOffset(value, std::nullopt); + } else { + SetScrollOffset(std::nullopt, value); + } + } + + void ApplyScroll(const Scroll& scroll); + + Point GetRawScrollOffset() const { return scroll_offset_; } + + // Return the viewable area rect. + // Lefttop is scroll offset. Size is content size. + // If size exceeds view area, left and top is more important when calculate + // new scroll offset. + Rect GetViewRect() { + return Rect{GetScrollOffset(), GetContentRect().GetSize()}; + } + + // Rect lefttop relative to content rect. + // Param margin is just for convenience and it will just add to the rect. + void ScrollToContain(const Rect& rect, const Thickness& margin = Thickness{}); + + std::u16string_view GetName() const override { return u"ScrollRenderObject"; } + + bool IsMouseWheelScrollEnabled() const { return is_mouse_wheel_enabled_; } + void SetMouseWheelScrollEnabled(bool enable); + + bool HorizontalCanScrollUp(); + bool HorizontalCanScrollDown(); + bool VerticalCanScrollUp(); + bool VerticalCanScrollDown(); + + protected: + void OnDrawCore(platform::graphics::IPainter* painter) override; + + // Logic: + // If available size is bigger than child's preferred size, then child's + // preferred size is taken. + // If not, all available size is taken while forming a scroll area. + Size OnMeasureContent(const MeasureRequirement& requirement, + const MeasureSize& preferred_size) override; + void OnLayoutContent(const Rect& content_rect) override; + + void OnAttachedControlChanged(controls::Control* control) override; + + void InstallMouseWheelHandler(controls::Control* control); + + private: + Point scroll_offset_; + + std::unique_ptr<ScrollBarDelegate> scroll_bar_delegate_; + + bool is_mouse_wheel_enabled_ = true; + + EventRevokerListGuard guard_; +}; +} // namespace cru::ui::render |