From 81fd0725d020e9f302c0d40fd5a5700d3dc871aa Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 6 Dec 2018 05:44:38 +0800 Subject: Done. --- src/ui/controls/scroll_control.cpp | 65 +++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 33 deletions(-) (limited to 'src/ui/controls/scroll_control.cpp') diff --git a/src/ui/controls/scroll_control.cpp b/src/ui/controls/scroll_control.cpp index 8358abc5..ae99f414 100644 --- a/src/ui/controls/scroll_control.cpp +++ b/src/ui/controls/scroll_control.cpp @@ -3,7 +3,6 @@ #include #include "cru_debug.hpp" -#include "format.hpp" #include "ui/convert_util.hpp" #include "exception.hpp" #include "math_util.hpp" @@ -14,7 +13,7 @@ namespace cru::ui::controls { constexpr auto scroll_bar_width = 15.0f; - ScrollControl::ScrollControl(const bool container) : Control(container) + ScrollControl::ScrollControl(const bool container) { SetClipContent(true); @@ -245,38 +244,25 @@ namespace cru::ui::controls available_size_for_children.height = std::numeric_limits::max(); } - auto max_child_size = Size::Zero(); - for (auto control: GetChildren()) - { - control->Measure(available_size_for_children, AdditionalMeasureInfo{false, false}); - 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; - } + const auto child = GetChild(); - // coerce size for stretch. - for (auto control: GetChildren()) + auto size = Size::Zero(); + if (child) { - 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); + child->Measure(available_size_for_children, AdditionalMeasureInfo{false, false}); + size = child->GetDesiredSize(); } - auto result = max_child_size; + + auto result = size; if (IsHorizontalScrollEnabled()) { - SetViewWidth(max_child_size.width); + SetViewWidth(size.width); result.width = available_size.width; } if (IsVerticalScrollEnabled()) { - SetViewHeight(max_child_size.height); + SetViewHeight(size.height); result.height = available_size.height; } @@ -292,18 +278,31 @@ namespace cru::ui::controls if (IsVerticalScrollEnabled()) layout_rect.height = GetViewHeight(); - for (auto control: GetChildren()) + const auto child = GetChild(); + + if (child) { - const auto size = control->GetDesiredSize(); - // Ignore alignment, always center aligned. - auto&& calculate_anchor = [](const float anchor, const float layout_length, const float control_length, const float offset) -> float + const auto layout_params = child->GetLayoutParams(); + const auto size = child->GetDesiredSize(); + + auto&& calculate_anchor = [](const float anchor, const Alignment alignment, const float layout_length, const float control_length) -> float { - return anchor + (layout_length - control_length) / 2 - offset; + switch (alignment) + { + case Alignment::Center: + return anchor + (layout_length - control_length) / 2; + case Alignment::Start: + return anchor; + case Alignment::End: + return anchor + layout_length - control_length; + default: + UnreachableCode(); + } }; - control->Layout(Rect(Point( - calculate_anchor(rect.left, layout_rect.width, size.width, offset_x_), - calculate_anchor(rect.top, layout_rect.height, size.height, offset_y_) + child->Layout(Rect(Point( + IsHorizontalScrollEnabled() ? layout_rect.left + offset_x_ : calculate_anchor(layout_rect.left, layout_params->width.alignment, layout_rect.width, size.width), + IsVerticalScrollEnabled() ? layout_rect.top + offset_y_ : calculate_anchor(layout_rect.top, layout_params->height.alignment, layout_rect.height, size.height) ), size), additional_info); } } @@ -327,7 +326,7 @@ namespace cru::ui::controls if (update_children) { - for (auto child : GetChildren()) + if (const auto child = GetChild()) { const auto old_position = child->GetPositionRelative(); child->SetRect(Rect(Point( -- cgit v1.2.3 From 03ef76f769a55b694905898c16a176fc6bd4b0d7 Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 6 Dec 2018 21:09:12 +0800 Subject: Fix position cache bug. --- src/ui/control.cpp | 33 ++++++++++++++++++++++++++++++--- src/ui/control.hpp | 16 +++++++++++----- src/ui/controls/scroll_control.cpp | 3 ++- src/ui/window.cpp | 2 +- src/ui/window.hpp | 2 +- 5 files changed, 45 insertions(+), 11 deletions(-) (limited to 'src/ui/controls/scroll_control.cpp') diff --git a/src/ui/control.cpp b/src/ui/control.cpp index 32168891..3987e818 100644 --- a/src/ui/control.cpp +++ b/src/ui/control.cpp @@ -125,7 +125,7 @@ namespace cru::ui TraverseDescendantsInternal(this, predicate); } - Point Control::GetPositionRelative() + Point Control::GetOffset() { return rect_.GetLeftTop(); } @@ -186,6 +186,33 @@ namespace cru::ui point.y - position_cache_.lefttop_position_absolute.y); } + void Control::RefreshDescendantPositionCache() + { + auto point = Point::Zero(); + auto parent = this; + while ((parent = parent->GetParent())) + { + const auto p = parent->GetOffset(); + point.x += p.x; + point.y += p.y; + } + RefreshControlPositionCacheInternal(this, point); + } + + void Control::RefreshControlPositionCacheInternal(Control* control, const Point& parent_lefttop_absolute) + { + const auto position = control->GetOffset(); + const Point lefttop( + parent_lefttop_absolute.x + position.x, + parent_lefttop_absolute.y + position.y + ); + control->position_cache_.lefttop_position_absolute = lefttop; + for(auto c : control->GetInternalChildren()) + { + RefreshControlPositionCacheInternal(c, lefttop); + } + } + bool Control::IsPointInside(const Point & point) { const auto border_geometry = geometry_info_.border_geometry; @@ -230,7 +257,7 @@ namespace cru::ui for (auto i = children.crbegin(); i != children.crend(); ++i) { - const auto&& lefttop = (*i)->GetPositionRelative(); + const auto&& lefttop = (*i)->GetOffset(); const auto&& coerced_point = Point(point.x - lefttop.x, point.y - lefttop.y); const auto child_hit_test_result = (*i)->HitTest(coerced_point); if (child_hit_test_result != nullptr) @@ -254,7 +281,7 @@ namespace cru::ui D2D1::Matrix3x2F old_transform; device_context->GetTransform(&old_transform); - const auto position = GetPositionRelative(); + const auto position = GetOffset(); device_context->SetTransform(old_transform * D2D1::Matrix3x2F::Translation(position.x, position.y)); OnDrawDecoration(device_context); diff --git a/src/ui/control.hpp b/src/ui/control.hpp index 41d1cfe9..6abcc365 100644 --- a/src/ui/control.hpp +++ b/src/ui/control.hpp @@ -18,7 +18,6 @@ namespace cru::ui { - class Control; class Window; @@ -68,6 +67,8 @@ namespace cru::ui //*************** region: tree *************** virtual StringView GetControlType() const = 0; + virtual const std::vector& GetInternalChildren() const = 0; + Control* GetParent() const { return parent_ == nullptr ? internal_parent_ : parent_; @@ -84,9 +85,6 @@ namespace cru::ui return window_; } - - virtual const std::vector& GetInternalChildren() const = 0; - void SetParent(Control* parent); void SetInternalParent(Control* internal_parent); @@ -100,11 +98,12 @@ namespace cru::ui //*************** region: position and size *************** //Get the lefttop relative to its parent. - virtual Point GetPositionRelative(); + virtual Point GetOffset(); //Get the actual size. virtual Size GetSize(); + // If offset changes, call RefreshDescendantPositionCache. virtual void SetRect(const Rect& rect); //Get lefttop relative to ancestor. This is only valid when @@ -118,6 +117,13 @@ namespace cru::ui //Absolute point to local point. Point WindowToControl(const Point& point) const; + void RefreshDescendantPositionCache(); + + private: + static void RefreshControlPositionCacheInternal(Control* control, const Point& parent_lefttop_absolute); + + public: + // Default implement in Control is test point in border geometry's // fill and stroke with width of border. virtual bool IsPointInside(const Point& point); diff --git a/src/ui/controls/scroll_control.cpp b/src/ui/controls/scroll_control.cpp index ae99f414..622b4e4c 100644 --- a/src/ui/controls/scroll_control.cpp +++ b/src/ui/controls/scroll_control.cpp @@ -328,11 +328,12 @@ namespace cru::ui::controls { if (const auto child = GetChild()) { - const auto old_position = child->GetPositionRelative(); + const auto old_position = child->GetOffset(); child->SetRect(Rect(Point( old_position.x + old_offset_x - offset_x_, old_position.y + old_offset_y - offset_y_ ), child->GetSize())); + child->RefreshDescendantPositionCache(); } } InvalidateDraw(); diff --git a/src/ui/window.cpp b/src/ui/window.cpp index 6f1c4071..86fa4436 100644 --- a/src/ui/window.cpp +++ b/src/ui/window.cpp @@ -469,7 +469,7 @@ namespace cru::ui return PiToDip(point); } - Point Window::GetPositionRelative() + Point Window::GetOffset() { return Point(); } diff --git a/src/ui/window.hpp b/src/ui/window.hpp index e4c910e8..e96d4d92 100644 --- a/src/ui/window.hpp +++ b/src/ui/window.hpp @@ -189,7 +189,7 @@ namespace cru::ui //*************** region: position and size *************** //Always return (0, 0) for a window. - Point GetPositionRelative() override final; + Point GetOffset() override final; //Get the size of client area for a window. Size GetSize() override final; -- cgit v1.2.3