diff options
author | crupest <crupest@outlook.com> | 2018-11-24 22:39:50 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2018-11-24 22:39:50 +0800 |
commit | abc776a9ea02a564dfe44141e51e4cbc87a7a3a1 (patch) | |
tree | 67c11e09856799b8fa40a3f2e124a37e7538115f /src | |
parent | d4658bfd97e1770e7ab4de356b3fd8c0d1999493 (diff) | |
download | cru-abc776a9ea02a564dfe44141e51e4cbc87a7a3a1.tar.gz cru-abc776a9ea02a564dfe44141e51e4cbc87a7a3a1.tar.bz2 cru-abc776a9ea02a564dfe44141e51e4cbc87a7a3a1.zip |
Develop layout for ScrollView
Diffstat (limited to 'src')
-rw-r--r-- | src/ui/control.cpp | 2 | ||||
-rw-r--r-- | src/ui/control.hpp | 5 | ||||
-rw-r--r-- | src/ui/controls/scroll_control.cpp | 146 | ||||
-rw-r--r-- | src/ui/controls/scroll_control.hpp | 85 |
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; + }; +} |