aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2018-11-24 22:39:50 +0800
committercrupest <crupest@outlook.com>2018-11-24 22:39:50 +0800
commitabc776a9ea02a564dfe44141e51e4cbc87a7a3a1 (patch)
tree67c11e09856799b8fa40a3f2e124a37e7538115f /src
parentd4658bfd97e1770e7ab4de356b3fd8c0d1999493 (diff)
downloadcru-abc776a9ea02a564dfe44141e51e4cbc87a7a3a1.tar.gz
cru-abc776a9ea02a564dfe44141e51e4cbc87a7a3a1.tar.bz2
cru-abc776a9ea02a564dfe44141e51e4cbc87a7a3a1.zip
Develop layout for ScrollView
Diffstat (limited to 'src')
-rw-r--r--src/ui/control.cpp2
-rw-r--r--src/ui/control.hpp5
-rw-r--r--src/ui/controls/scroll_control.cpp146
-rw-r--r--src/ui/controls/scroll_control.hpp85
4 files changed, 235 insertions, 3 deletions
diff --git a/src/ui/control.cpp b/src/ui/control.cpp
index 91b5aea3..22b7164f 100644
--- a/src/ui/control.cpp
+++ b/src/ui/control.cpp
@@ -877,7 +877,7 @@ namespace cru::ui
auto parent = GetParent();
while (parent != nullptr)
{
- auto lp = parent->GetLayoutParams();
+ const auto lp = parent->GetLayoutParams();
if (!stretch_width_determined)
{
diff --git a/src/ui/control.hpp b/src/ui/control.hpp
index 6de7f450..44c98728 100644
--- a/src/ui/control.hpp
+++ b/src/ui/control.hpp
@@ -122,7 +122,7 @@ namespace cru::ui
virtual bool IsPointInside(const Point& point);
// Get the top control among all descendants (including self) in local coordinate.
- Control* HitTest(const Point& point);
+ virtual Control* HitTest(const Point& point);
//*************** region: graphic ***************
@@ -406,7 +406,8 @@ namespace cru::ui
bool clip_to_padding_ = false;
Microsoft::WRL::ComPtr<ID2D1Geometry> border_geometry_ = nullptr;
- Microsoft::WRL::ComPtr<ID2D1Geometry> in_border_geometry_ = nullptr; //used for foreground and background brush.
+ // used for foreground and background brush and clip.
+ Microsoft::WRL::ComPtr<ID2D1Geometry> in_border_geometry_ = nullptr;
Microsoft::WRL::ComPtr<ID2D1Brush> foreground_brush_ = nullptr;
Microsoft::WRL::ComPtr<ID2D1Brush> background_brush_ = nullptr;
diff --git a/src/ui/controls/scroll_control.cpp b/src/ui/controls/scroll_control.cpp
new file mode 100644
index 00000000..00969ab7
--- /dev/null
+++ b/src/ui/controls/scroll_control.cpp
@@ -0,0 +1,146 @@
+#include "scroll_control.hpp"
+
+#include <limits>
+
+#include "cru_debug.hpp"
+#include "format.hpp"
+
+namespace cru::ui::controls
+{
+ ScrollControl::ScrollControl(const bool container) : Control(container)
+ {
+ SetClipToPadding(true);
+ }
+
+ ScrollControl::~ScrollControl()
+ {
+
+ }
+
+ void ScrollControl::SetHorizontalScrollEnabled(const bool enable)
+ {
+ horizontal_scroll_enabled_ = enable;
+ InvalidateLayout();
+ InvalidateDraw();
+ }
+
+ void ScrollControl::SetVerticalScrollEnabled(const bool enable)
+ {
+ vertical_scroll_enabled_ = enable;
+ InvalidateLayout();
+ InvalidateDraw();
+ }
+
+ Control* ScrollControl::HitTest(const Point& point)
+ {
+
+ }
+
+ void ScrollControl::SetViewWidth(const float length)
+ {
+ view_width_ = length;
+ }
+
+ void ScrollControl::SetViewHeight(const float length)
+ {
+ view_height_ = length;
+ }
+
+ Size ScrollControl::OnMeasureContent(const Size& available_size)
+ {
+ const auto layout_params = GetLayoutParams();
+
+ auto available_size_for_children = available_size;
+ if (IsHorizontalScrollEnabled())
+ {
+ if (layout_params->width.mode == MeasureMode::Content)
+ debug::DebugMessage(L"ScrollView: Width measure mode is Content and horizontal scroll is enabled. So Stretch is used instead.");
+
+ for (auto child : GetChildren())
+ {
+ const auto child_layout_params = child->GetLayoutParams();
+ if (child_layout_params->width.mode == MeasureMode::Stretch)
+ throw std::runtime_error(Format("ScrollView: Horizontal scroll is enabled but a child {} 's width measure mode is Stretch which may cause infinite length.", ToUtf8String(child->GetControlType())));
+ }
+
+ available_size_for_children.width = std::numeric_limits<float>::max();
+ }
+
+ if (IsVerticalScrollEnabled())
+ {
+ if (layout_params->height.mode == MeasureMode::Content)
+ debug::DebugMessage(L"ScrollView: Height measure mode is Content and vertical scroll is enabled. So Stretch is used instead.");
+
+ for (auto child : GetChildren())
+ {
+ const auto child_layout_params = child->GetLayoutParams();
+ if (child_layout_params->height.mode == MeasureMode::Stretch)
+ throw std::runtime_error(Format("ScrollView: Vertical scroll is enabled but a child {} 's height measure mode is Stretch which may cause infinite length.", ToUtf8String(child->GetControlType())));
+ }
+
+ available_size_for_children.height = std::numeric_limits<float>::max();
+ }
+
+ auto max_child_size = Size::Zero();
+ for (auto control: GetChildren())
+ {
+ control->Measure(available_size_for_children);
+ const auto&& size = control->GetDesiredSize();
+ if (max_child_size.width < size.width)
+ max_child_size.width = size.width;
+ if (max_child_size.height < size.height)
+ max_child_size.height = size.height;
+ }
+
+ // coerce size fro stretch.
+ for (auto control: GetChildren())
+ {
+ auto size = control->GetDesiredSize();
+ const auto child_layout_params = control->GetLayoutParams();
+ if (child_layout_params->width.mode == MeasureMode::Stretch)
+ size.width = max_child_size.width;
+ if (child_layout_params->height.mode == MeasureMode::Stretch)
+ size.height = max_child_size.height;
+ control->SetDesiredSize(size);
+ }
+
+ auto result = max_child_size;
+ if (IsHorizontalScrollEnabled())
+ {
+ SetViewWidth(max_child_size.width);
+ result.width = available_size.width;
+ }
+ if (IsVerticalScrollEnabled())
+ {
+ SetViewHeight(max_child_size.height);
+ result.height = available_size.height;
+ }
+
+ return result;
+ }
+
+ void ScrollControl::OnLayoutContent(const Rect& rect)
+ {
+ auto layout_rect = rect;
+
+ if (IsHorizontalScrollEnabled())
+ layout_rect.width = GetViewWidth();
+ if (IsVerticalScrollEnabled())
+ layout_rect.height = GetViewHeight();
+
+ for (auto control: GetChildren())
+ {
+ const auto size = control->GetDesiredSize();
+ // Ignore alignment, always center aligned.
+ auto&& calculate_anchor = [](const float anchor, const float layout_length, const float control_length) -> float
+ {
+ return anchor + (layout_length - control_length) / 2;
+ };
+
+ control->Layout(Rect(Point(
+ calculate_anchor(rect.left, layout_rect.width, size.width),
+ calculate_anchor(rect.top, layout_rect.height, size.height)
+ ), size));
+ }
+ }
+}
diff --git a/src/ui/controls/scroll_control.hpp b/src/ui/controls/scroll_control.hpp
new file mode 100644
index 00000000..c39b18f4
--- /dev/null
+++ b/src/ui/controls/scroll_control.hpp
@@ -0,0 +1,85 @@
+#pragma once
+
+#include "ui/control.hpp"
+
+namespace cru::ui::controls
+{
+ // Done: OnMeasureContent
+ // Done: OnLayoutContent
+ // TODO: HitTest
+ // TODO: Draw
+ // TODO: ScrollBar
+ // TODO: MouseEvent
+ class ScrollControl : public Control
+ {
+ public:
+ enum class ScrollBarVisibility
+ {
+ None,
+ Auto,
+ Always
+ };
+
+ protected:
+ explicit ScrollControl(bool container);
+ public:
+ ScrollControl(const ScrollControl& other) = delete;
+ ScrollControl(ScrollControl&& other) = delete;
+ ScrollControl& operator=(const ScrollControl& other) = delete;
+ ScrollControl& operator=(ScrollControl&& other) = delete;
+ ~ScrollControl() override;
+
+
+ bool IsHorizontalScrollEnabled() const
+ {
+ return horizontal_scroll_enabled_;
+ }
+
+ void SetHorizontalScrollEnabled(bool enable);
+
+ bool IsVerticalScrollEnabled() const
+ {
+ return vertical_scroll_enabled_;
+ }
+
+ void SetVerticalScrollEnabled(bool enable);
+
+
+ ScrollBarVisibility GetHorizontalScrollBarVisibility() const;
+ void SetHorizontalScrollBarVisibility(ScrollBarVisibility visibility);
+ ScrollBarVisibility GetVerticalScrollBarVisibility() const;
+ void SetVerticalScrollBarVisibility(ScrollBarVisibility visibility);
+
+ Control* HitTest(const Point& point) override final;
+
+ protected:
+ float GetViewWidth() const
+ {
+ return view_width_;
+ }
+
+ float GetViewHeight() const
+ {
+ return view_height_;
+ }
+
+ void SetViewWidth(float length);
+ void SetViewHeight(float length);
+
+ Size OnMeasureContent(const Size& available_size) override final;
+ void OnLayoutContent(const Rect& rect) override final;
+
+ private:
+ bool horizontal_scroll_enabled_ = true;
+ bool vertical_scroll_enabled_ = true;
+
+ ScrollBarVisibility horizontal_scroll_bar_visibility_ = ScrollBarVisibility::Auto;
+ ScrollBarVisibility vertical_scroll_bar_visibility_ = ScrollBarVisibility::Auto;
+
+ float offset_x_ = 0.0f;
+ float offset_y_ = 0.0f;
+
+ float view_width_ = 0.0f;
+ float view_height_ = 0.0f;
+ };
+}