aboutsummaryrefslogtreecommitdiff
path: root/include/cru/ui/render/ScrollBar.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/cru/ui/render/ScrollBar.h')
-rw-r--r--include/cru/ui/render/ScrollBar.h255
1 files changed, 255 insertions, 0 deletions
diff --git a/include/cru/ui/render/ScrollBar.h b/include/cru/ui/render/ScrollBar.h
new file mode 100644
index 00000000..84d4375b
--- /dev/null
+++ b/include/cru/ui/render/ScrollBar.h
@@ -0,0 +1,255 @@
+#pragma once
+#include "Base.h"
+#include "cru/common/Base.h"
+#include "cru/common/Event.h"
+#include "cru/platform/graphics/Base.h"
+#include "cru/platform/graphics/Brush.h"
+#include "cru/platform/graphics/Geometry.h"
+#include "cru/platform/graphics/Painter.h"
+#include "cru/platform/gui/Cursor.h"
+#include "cru/platform/gui/TimerHelper.h"
+#include "cru/platform/gui/UiApplication.h"
+#include "cru/ui/Base.h"
+#include "cru/ui/controls/Control.h"
+#include "cru/ui/helper/ClickDetector.h"
+
+#include <gsl/pointers>
+#include <memory>
+#include <optional>
+#include <unordered_map>
+
+namespace cru::ui::render {
+class ScrollRenderObject;
+
+enum class ScrollKind { Absolute, Relative, Page, Line };
+
+struct Scroll {
+ Direction direction;
+ ScrollKind kind;
+ // For absolute, the new scroll position. Otherwise, offset.
+ float value;
+};
+
+enum class ScrollBarAreaKind {
+ UpArrow, // Line up
+ DownArrow, // Line down
+ UpSlot, // Page up
+ DownSlot, // Page down
+ Thumb
+};
+
+enum class ScrollBarBrushUsageKind { Arrow, ArrowBackground, Slot, Thumb };
+enum class ScrollBarBrushStateKind { Normal, Hover, Press, Disable };
+
+String CRU_UI_API GenerateScrollBarThemeColorKey(ScrollBarBrushUsageKind usage,
+ ScrollBarBrushStateKind state);
+
+class CRU_UI_API ScrollBar : public Object {
+ public:
+ ScrollBar(gsl::not_null<ScrollRenderObject*> render_object,
+ Direction direction);
+
+ CRU_DELETE_COPY(ScrollBar)
+ CRU_DELETE_MOVE(ScrollBar)
+
+ ~ScrollBar() override;
+
+ public:
+ Direction GetDirection() const { return direction_; }
+
+ bool IsEnabled() const { return is_enabled_; }
+ void SetEnabled(bool value);
+
+ bool IsExpanded() const { return is_expanded_; }
+ void SetExpanded(bool value);
+
+ void Draw(platform::graphics::IPainter* painter);
+
+ IEvent<Scroll>* ScrollAttemptEvent() { return &scroll_attempt_event_; }
+
+ void InstallHandlers(controls::Control* control);
+ void UninstallHandlers() { InstallHandlers(nullptr); }
+
+ gsl::not_null<std::shared_ptr<platform::graphics::IBrush>>
+ GetCollapsedThumbBrush();
+ // Brush could be nullptr to use the theme brush.
+ void SetCollapsedThumbBrush(
+ std::shared_ptr<platform::graphics::IBrush> brush);
+ gsl::not_null<std::shared_ptr<platform::graphics::IBrush>> GetBrush(
+ ScrollBarBrushUsageKind usage, ScrollBarBrushStateKind state);
+ // Brush could be nullptr to use the theme brush.
+ void SetBrush(ScrollBarBrushUsageKind usage, ScrollBarBrushStateKind state,
+ std::shared_ptr<platform::graphics::IBrush> brush);
+
+ protected:
+ void OnDraw(platform::graphics::IPainter* painter, bool expand);
+
+ virtual void DrawUpArrow(
+ platform::graphics::IPainter* painter, const Rect& area,
+ gsl::not_null<platform::graphics::IBrush*> arrow_brush,
+ gsl::not_null<platform::graphics::IBrush*> background_brush) = 0;
+ virtual void DrawDownArrow(
+ platform::graphics::IPainter* painter, const Rect& area,
+ gsl::not_null<platform::graphics::IBrush*> arrow_brush,
+ gsl::not_null<platform::graphics::IBrush*> background_brush) = 0;
+
+ std::optional<ScrollBarAreaKind> ExpandedHitTest(const Point& point);
+
+ virtual bool IsShowBar() = 0;
+
+ virtual std::optional<Rect> GetExpandedAreaRect(
+ ScrollBarAreaKind area_kind) = 0;
+ virtual std::optional<Rect> GetCollapsedTriggerExpandAreaRect() = 0;
+ virtual std::optional<Rect> GetCollapsedThumbRect() = 0;
+
+ virtual float CalculateNewScrollPosition(const Rect& thumb_original_rect,
+ const Point& mouse_offset) = 0;
+
+ virtual bool CanScrollUp() = 0;
+ virtual bool CanScrollDown() = 0;
+
+ private:
+ void SetCursor();
+ void RestoreCursor();
+
+ void BeginAutoCollapseTimer();
+ void StopAutoCollapseTimer();
+
+ void OnMouseLeave();
+
+ ScrollBarBrushStateKind GetState(ScrollBarAreaKind area);
+
+ protected:
+ gsl::not_null<ScrollRenderObject*> render_object_;
+
+ std::unique_ptr<platform::graphics::IGeometry> arrow_geometry_;
+
+ private:
+ Direction direction_;
+
+ bool is_enabled_ = true;
+
+ bool is_expanded_ = false;
+
+ std::shared_ptr<platform::graphics::IBrush> collapsed_thumb_brush_;
+ std::unordered_map<
+ ScrollBarBrushUsageKind,
+ std::unordered_map<ScrollBarBrushStateKind,
+ std::shared_ptr<platform::graphics::IBrush>>>
+ brushes_;
+
+ Rect move_thumb_thumb_original_rect_;
+ std::optional<Point> move_thumb_start_;
+
+ std::optional<ScrollBarAreaKind> mouse_hover_;
+ std::optional<ScrollBarAreaKind> mouse_press_;
+
+ EventRevokerListGuard event_guard_;
+
+ Event<Scroll> scroll_attempt_event_;
+
+ bool cursor_overrided_ = false;
+
+ platform::gui::TimerAutoCanceler auto_collapse_timer_canceler_;
+};
+
+class CRU_UI_API HorizontalScrollBar : public ScrollBar {
+ public:
+ explicit HorizontalScrollBar(
+ gsl::not_null<ScrollRenderObject*> render_object);
+
+ CRU_DELETE_COPY(HorizontalScrollBar)
+ CRU_DELETE_MOVE(HorizontalScrollBar)
+
+ ~HorizontalScrollBar() override = default;
+
+ protected:
+ void DrawUpArrow(
+ platform::graphics::IPainter* painter, const Rect& area,
+ gsl::not_null<platform::graphics::IBrush*> arrow_brush,
+ gsl::not_null<platform::graphics::IBrush*> background_brush) override;
+ void DrawDownArrow(
+ platform::graphics::IPainter* painter, const Rect& area,
+ gsl::not_null<platform::graphics::IBrush*> arrow_brush,
+ gsl::not_null<platform::graphics::IBrush*> background_brush) override;
+
+ bool IsShowBar() override;
+
+ std::optional<Rect> GetExpandedAreaRect(ScrollBarAreaKind area_kind) override;
+ std::optional<Rect> GetCollapsedTriggerExpandAreaRect() override;
+ std::optional<Rect> GetCollapsedThumbRect() override;
+
+ float CalculateNewScrollPosition(const Rect& thumb_original_rect,
+ const Point& mouse_offset) override;
+
+ bool CanScrollUp() override;
+ bool CanScrollDown() override;
+};
+
+class CRU_UI_API VerticalScrollBar : public ScrollBar {
+ public:
+ explicit VerticalScrollBar(gsl::not_null<ScrollRenderObject*> render_object);
+
+ CRU_DELETE_COPY(VerticalScrollBar)
+ CRU_DELETE_MOVE(VerticalScrollBar)
+
+ ~VerticalScrollBar() override = default;
+
+ protected:
+ void DrawUpArrow(
+ platform::graphics::IPainter* painter, const Rect& area,
+ gsl::not_null<platform::graphics::IBrush*> arrow_brush,
+ gsl::not_null<platform::graphics::IBrush*> background_brush) override;
+ void DrawDownArrow(
+ platform::graphics::IPainter* painter, const Rect& area,
+ gsl::not_null<platform::graphics::IBrush*> arrow_brush,
+ gsl::not_null<platform::graphics::IBrush*> background_brush) override;
+
+ bool IsShowBar() override;
+
+ std::optional<Rect> GetExpandedAreaRect(ScrollBarAreaKind area_kind) override;
+ std::optional<Rect> GetCollapsedTriggerExpandAreaRect() override;
+ std::optional<Rect> GetCollapsedThumbRect() override;
+
+ float CalculateNewScrollPosition(const Rect& thumb_original_rect,
+ const Point& mouse_offset) override;
+
+ bool CanScrollUp() override;
+ bool CanScrollDown() override;
+};
+
+// A delegate to draw scrollbar and register related events.
+class CRU_UI_API ScrollBarDelegate : public Object {
+ public:
+ explicit ScrollBarDelegate(gsl::not_null<ScrollRenderObject*> render_object);
+
+ CRU_DELETE_COPY(ScrollBarDelegate)
+ CRU_DELETE_MOVE(ScrollBarDelegate)
+
+ ~ScrollBarDelegate() override = default;
+
+ public:
+ bool IsHorizontalBarEnabled() const { return horizontal_bar_.IsEnabled(); }
+ void SetHorizontalBarEnabled(bool value) {
+ horizontal_bar_.SetEnabled(value);
+ }
+
+ bool IsVerticalBarEnabled() const { return horizontal_bar_.IsEnabled(); }
+ void SetVerticalBarEnabled(bool value) { horizontal_bar_.SetEnabled(value); }
+
+ IEvent<Scroll>* ScrollAttemptEvent() { return &scroll_attempt_event_; }
+
+ void DrawScrollBar(platform::graphics::IPainter* painter);
+
+ void InstallHandlers(controls::Control* control);
+ void UninstallHandlers() { InstallHandlers(nullptr); }
+
+ private:
+ gsl::not_null<ScrollRenderObject*> render_object_;
+
+ HorizontalScrollBar horizontal_bar_;
+ VerticalScrollBar vertical_bar_;
+
+ Event<Scroll> scroll_attempt_event_;
+};
+} // namespace cru::ui::render