diff options
author | crupest <crupest@outlook.com> | 2018-12-05 16:37:58 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2018-12-05 16:37:58 +0800 |
commit | 8898aee6c70bde922ee5de2a6213a44798525a16 (patch) | |
tree | 90b6fc6eb526e2421458f942f390906d6a48a628 /src | |
parent | 01b0378ed32eb2011863393892717483004cc375 (diff) | |
download | cru-8898aee6c70bde922ee5de2a6213a44798525a16.tar.gz cru-8898aee6c70bde922ee5de2a6213a44798525a16.tar.bz2 cru-8898aee6c70bde922ee5de2a6213a44798525a16.zip |
...
Diffstat (limited to 'src')
-rw-r--r-- | src/ui/control.cpp | 95 | ||||
-rw-r--r-- | src/ui/control.hpp | 45 | ||||
-rw-r--r-- | src/ui/controls/linear_layout.cpp | 6 | ||||
-rw-r--r-- | src/ui/controls/linear_layout.hpp | 2 | ||||
-rw-r--r-- | src/ui/controls/scroll_control.cpp | 10 | ||||
-rw-r--r-- | src/ui/controls/scroll_control.hpp | 4 | ||||
-rw-r--r-- | src/ui/controls/text_control.cpp | 15 | ||||
-rw-r--r-- | src/ui/controls/text_control.hpp | 2 | ||||
-rw-r--r-- | src/ui/events/ui_event.hpp | 59 | ||||
-rw-r--r-- | src/ui/layout_base.cpp | 78 | ||||
-rw-r--r-- | src/ui/layout_base.hpp | 43 | ||||
-rw-r--r-- | src/ui/window.cpp | 11 | ||||
-rw-r--r-- | src/ui/window.hpp | 7 |
13 files changed, 75 insertions, 302 deletions
diff --git a/src/ui/control.cpp b/src/ui/control.cpp index 91301e0b..8c9578df 100644 --- a/src/ui/control.cpp +++ b/src/ui/control.cpp @@ -180,27 +180,25 @@ namespace cru::ui Point Control::GetPositionRelative() { - return position_; + return rect_.GetLeftTop(); } - void Control::SetPositionRelative(const Point & position) + Size Control::GetSize() { - if (position != position_) - { - if (old_position_ == position) // if cache has been refreshed and no pending notify - old_position_ = position_; - position_ = position; - LayoutManager::GetInstance()->InvalidateControlPositionCache(this); - if (auto window = GetWindow()) - { - window->InvalidateDraw(); - } - } + return rect_.GetSize(); } - Size Control::GetSize() + void Control::SetRect(const Rect& rect) { - return size_; + const auto old_rect = rect_; + rect_ = rect; + + RegenerateGeometryInfo(); + + OnRectChange(old_rect, rect); + + if (auto window = GetWindow()) + window->InvalidateDraw(); } namespace @@ -224,24 +222,6 @@ namespace cru::ui #endif } - void Control::SetSize(const Size & size) - { - const auto old_size = size_; - size_ = size; - events::SizeChangedEventArgs args(this, this, old_size, size); - size_changed_event.Raise(args); - - RegenerateGeometryInfo(); - -#ifdef CRU_DEBUG_LAYOUT - margin_geometry_ = CalculateSquareRingGeometry(GetRect(RectRange::Margin), GetRect(RectRange::FullBorder)); - padding_geometry_ = CalculateSquareRingGeometry(GetRect(RectRange::Padding), GetRect(RectRange::Content)); -#endif - - if (auto window = GetWindow()) - window->InvalidateDraw(); - } - Point Control::GetPositionAbsolute() const { return position_cache_.lefttop_position_absolute; @@ -382,13 +362,16 @@ namespace cru::ui SetDesiredSize(OnMeasureCore(available_size, additional_info)); } - - void Control::Layout(const Rect& rect) + void Control::Layout(const Rect& rect, const AdditionalLayoutInfo& additional_info) { - SetPositionRelative(rect.GetLeftTop()); - SetSize(rect.GetSize()); - AfterLayoutSelf(); - OnLayoutCore(Rect(Point::Zero(), rect.GetSize())); + auto my_additional_info = additional_info; + my_additional_info.total_offset.x += rect.left; + my_additional_info.total_offset.y += rect.top; + position_cache_.lefttop_position_absolute.x = my_additional_info.total_offset.x; + position_cache_.lefttop_position_absolute.y = my_additional_info.total_offset.y; + + SetRect(rect); + OnLayoutCore(Rect(Point::Zero(), rect.GetSize()), my_additional_info); } Size Control::GetDesiredSize() const @@ -571,6 +554,11 @@ namespace cru::ui }); } + void Control::OnRectChange(const Rect& old_rect, const Rect& new_rect) + { + + } + void Control::RegenerateGeometryInfo() { if (IsBordered()) @@ -630,6 +618,12 @@ namespace cru::ui ); geometry_info_.content_geometry = std::move(geometry2); } + + //TODO: generate debug geometry +#ifdef CRU_DEBUG_LAYOUT + margin_geometry_ = CalculateSquareRingGeometry(GetRect(RectRange::Margin), GetRect(RectRange::FullBorder)); + padding_geometry_ = CalculateSquareRingGeometry(GetRect(RectRange::Padding), GetRect(RectRange::Content)); +#endif } void Control::OnMouseClickBegin(MouseButton button) @@ -717,7 +711,7 @@ namespace cru::ui return final_size; } - void Control::OnLayoutCore(const Rect& rect) + void Control::OnLayoutCore(const Rect& rect, const AdditionalLayoutInfo& additional_info) { const auto layout_params = GetLayoutParams(); @@ -739,7 +733,7 @@ namespace cru::ui if (content_rect.height < 0.0) throw std::runtime_error(Format("Height to layout must sufficient. But in {}, height for content is {}.", ToUtf8String(GetControlType()), content_rect.height)); - OnLayoutContent(content_rect); + OnLayoutContent(content_rect, additional_info); } Size Control::OnMeasureContent(const Size& available_size, const AdditionalMeasureInfo& additional_info) @@ -770,7 +764,7 @@ namespace cru::ui return max_child_size; } - void Control::OnLayoutContent(const Rect& rect) + void Control::OnLayoutContent(const Rect& rect, const AdditionalLayoutInfo& additional_info) { for (auto control: GetChildren()) { @@ -795,22 +789,7 @@ namespace cru::ui control->Layout(Rect(Point( calculate_anchor(rect.left, layout_params->width.alignment, rect.width, size.width), calculate_anchor(rect.top, layout_params->height.alignment, rect.height, size.height) - ), size)); - } - } - - void Control::AfterLayoutSelf() - { - - } - - void Control::CheckAndNotifyPositionChanged() - { - if (this->old_position_ != this->position_) - { - events::PositionChangedEventArgs args(this, this, this->old_position_, this->position_); - position_changed_event.Raise(args); - this->old_position_ = this->position_; + ), size), additional_info); } } diff --git a/src/ui/control.hpp b/src/ui/control.hpp index b2dad9fd..8dd1898d 100644 --- a/src/ui/control.hpp +++ b/src/ui/control.hpp @@ -28,19 +28,22 @@ namespace cru::ui bool vertical_stretchable = true; }; + struct AdditionalLayoutInfo + { + Point total_offset = Point::Zero(); + }; //the position cache struct ControlPositionCache { //The lefttop relative to the ancestor. - Point lefttop_position_absolute; + Point lefttop_position_absolute = Point::Zero(); }; class Control : public Object { friend class Window; - friend class LayoutManager; protected: struct GeometryInfo @@ -110,21 +113,14 @@ namespace cru::ui void TraverseDescendants(const std::function<void(Control*)>& predicate); //*************** region: position and size *************** - // Position and size part must be isolated from layout part. - // All the operations in this part must be done independently. - // And layout part must use api of this part. //Get the lefttop relative to its parent. virtual Point GetPositionRelative(); - //Set the lefttop relative to its parent. - virtual void SetPositionRelative(const Point& position); - //Get the actual size. virtual Size GetSize(); - //Set the actual size directly without re-layout. - virtual void SetSize(const Size& size); + virtual void SetRect(const Rect& rect); //Get lefttop relative to ancestor. This is only valid when //attached to window. Notice that the value is cached. @@ -203,7 +199,7 @@ namespace cru::ui void Measure(const Size& available_size, const AdditionalMeasureInfo& additional_info); - void Layout(const Rect& rect); + void Layout(const Rect& rect, const AdditionalLayoutInfo& additional_info); Size GetDesiredSize() const; @@ -281,8 +277,6 @@ namespace cru::ui Event<events::DrawEventArgs> draw_background_event; Event<events::DrawEventArgs> draw_foreground_event; - Event<events::PositionChangedEventArgs> position_changed_event; - Event<events::SizeChangedEventArgs> size_changed_event; //*************** region: tree event *************** protected: @@ -305,6 +299,8 @@ namespace cru::ui //*************** region: position and size event *************** protected: + virtual void OnRectChange(const Rect& old_rect, const Rect& new_rect); + void RegenerateGeometryInfo(); const GeometryInfo& GetGeometryInfo() const @@ -322,22 +318,14 @@ namespace cru::ui //*************** region: layout *************** private: Size OnMeasureCore(const Size& available_size, const AdditionalMeasureInfo& additional_info); - void OnLayoutCore(const Rect& rect); + void OnLayoutCore(const Rect& rect, const AdditionalLayoutInfo& additional_info); protected: virtual Size OnMeasureContent(const Size& available_size, const AdditionalMeasureInfo& additional_info); - virtual void OnLayoutContent(const Rect& rect); + virtual void OnLayoutContent(const Rect& rect, const AdditionalLayoutInfo& additional_info); - // Called by Layout after set position and size. - virtual void AfterLayoutSelf(); private: - // Only for layout manager to use. - // Check if the old position is updated to current position. - // If not, then a notify of position change and update will - // be done. - void CheckAndNotifyPositionChanged(); - void ThrowIfNotContainer() const { if (!is_container_) @@ -352,15 +340,8 @@ namespace cru::ui Control * parent_ = nullptr; std::vector<Control*> children_{}; - // When position is changed and notification hasn't been - // sent, it will be the old position. When position is changed - // more than once, it will be the oldest position since last - // notification. If notification has been sent, it will be updated - // to position_. - Point old_position_ = Point::Zero(); - Point position_ = Point::Zero(); - Size size_ = Size::Zero(); - + Rect rect_{}; + ControlPositionCache position_cache_{}; std::unordered_map<MouseButton, bool> is_mouse_click_valid_map_ diff --git a/src/ui/controls/linear_layout.cpp b/src/ui/controls/linear_layout.cpp index 8f2e7e80..2b8f3e43 100644 --- a/src/ui/controls/linear_layout.cpp +++ b/src/ui/controls/linear_layout.cpp @@ -107,7 +107,7 @@ namespace cru::ui::controls return actual_size_for_children; } - void LinearLayout::OnLayoutContent(const Rect& rect) + void LinearLayout::OnLayoutContent(const Rect& rect, const AdditionalLayoutInfo& additional_info) { float current_main_side_anchor = 0; for(auto control: GetChildren()) @@ -138,12 +138,12 @@ namespace cru::ui::controls if (orientation_ == Orientation::Horizontal) { - control->Layout(calculate_rect(current_main_side_anchor, calculate_secondary_side_anchor(rect.height, size.height))); + control->Layout(calculate_rect(current_main_side_anchor, calculate_secondary_side_anchor(rect.height, size.height)), additional_info); current_main_side_anchor += size.width; } else { - control->Layout(calculate_rect(calculate_secondary_side_anchor(rect.width, size.width), current_main_side_anchor)); + control->Layout(calculate_rect(calculate_secondary_side_anchor(rect.width, size.width), current_main_side_anchor), additional_info); current_main_side_anchor += size.height; } } diff --git a/src/ui/controls/linear_layout.hpp b/src/ui/controls/linear_layout.hpp index 9606b8a6..96becc6f 100644 --- a/src/ui/controls/linear_layout.hpp +++ b/src/ui/controls/linear_layout.hpp @@ -42,7 +42,7 @@ namespace cru::ui::controls protected: Size OnMeasureContent(const Size& available_size, const AdditionalMeasureInfo& additional_info) override; - void OnLayoutContent(const Rect& rect) override; + void OnLayoutContent(const Rect& rect, const AdditionalLayoutInfo& additional_info) override; private: Orientation orientation_; diff --git a/src/ui/controls/scroll_control.cpp b/src/ui/controls/scroll_control.cpp index db8ac438..8358abc5 100644 --- a/src/ui/controls/scroll_control.cpp +++ b/src/ui/controls/scroll_control.cpp @@ -283,7 +283,7 @@ namespace cru::ui::controls return result; } - void ScrollControl::OnLayoutContent(const Rect& rect) + void ScrollControl::OnLayoutContent(const Rect& rect, const AdditionalLayoutInfo& additional_info) { auto layout_rect = rect; @@ -304,11 +304,11 @@ namespace cru::ui::controls 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_) - ), size)); + ), size), additional_info); } } - void ScrollControl::AfterLayoutSelf() + void ScrollControl::OnRectChange(const Rect& old_rect, const Rect& new_rect) { UpdateScrollBarBorderInfo(); CoerceAndSetOffsets(offset_x_, offset_y_, false); @@ -330,10 +330,10 @@ namespace cru::ui::controls for (auto child : GetChildren()) { const auto old_position = child->GetPositionRelative(); - child->SetPositionRelative(Point( + child->SetRect(Rect(Point( old_position.x + old_offset_x - offset_x_, old_position.y + old_offset_y - offset_y_ - )); + ), child->GetSize())); } } InvalidateDraw(); diff --git a/src/ui/controls/scroll_control.hpp b/src/ui/controls/scroll_control.hpp index d70a7b35..db29b141 100644 --- a/src/ui/controls/scroll_control.hpp +++ b/src/ui/controls/scroll_control.hpp @@ -118,9 +118,9 @@ namespace cru::ui::controls void SetViewHeight(float length); Size OnMeasureContent(const Size& available_size, const AdditionalMeasureInfo& additional_info) override final; - void OnLayoutContent(const Rect& rect) override final; + void OnLayoutContent(const Rect& rect, const AdditionalLayoutInfo& additional_info) override final; - void AfterLayoutSelf() override; + void OnRectChange(const Rect& old_rect, const Rect& new_rect) override; private: void CoerceAndSetOffsets(float offset_x, float offset_y, bool update_children = true); diff --git a/src/ui/controls/text_control.cpp b/src/ui/controls/text_control.cpp index 9a799916..6412eec9 100644 --- a/src/ui/controls/text_control.cpp +++ b/src/ui/controls/text_control.cpp @@ -56,14 +56,6 @@ namespace cru::ui::controls SetClipContent(true); - size_changed_event.AddHandler([this](events::SizeChangedEventArgs& args) - { - const auto content = GetRect(RectRange::Content); - ThrowIfFailed(text_layout_->SetMaxWidth(content.width)); - ThrowIfFailed(text_layout_->SetMaxHeight(content.height)); - InvalidateDraw(); - }); - draw_content_event.AddHandler([this](events::DrawEventArgs& args) { const auto device_context = args.GetDeviceContext(); @@ -196,6 +188,13 @@ namespace cru::ui::controls } + void TextControl::OnRectChange(const Rect& old_rect, const Rect& new_rect) + { + const auto content = GetRect(RectRange::Content); + ThrowIfFailed(text_layout_->SetMaxWidth(content.width)); + ThrowIfFailed(text_layout_->SetMaxHeight(content.height)); + } + void TextControl::OnTextChangedCore(const String& old_text, const String& new_text) { RecreateTextLayout(); diff --git a/src/ui/controls/text_control.hpp b/src/ui/controls/text_control.hpp index fddd8ec7..9b83f4bb 100644 --- a/src/ui/controls/text_control.hpp +++ b/src/ui/controls/text_control.hpp @@ -66,6 +66,8 @@ namespace cru::ui::controls virtual void RequestChangeCaretPosition(unsigned position); + void OnRectChange(const Rect& old_rect, const Rect& new_rect) override; + private: void OnTextChangedCore(const String& old_text, const String& new_text); diff --git a/src/ui/events/ui_event.hpp b/src/ui/events/ui_event.hpp index 8380827a..e0040942 100644 --- a/src/ui/events/ui_event.hpp +++ b/src/ui/events/ui_event.hpp @@ -166,65 +166,6 @@ namespace cru::ui::events }; - class PositionChangedEventArgs : public UiEventArgs - { - public: - PositionChangedEventArgs(Object* sender, Object* original_sender, const Point& old_position, const Point& new_position) - : UiEventArgs(sender, original_sender), old_position_(old_position), new_position_(new_position) - { - - } - PositionChangedEventArgs(const PositionChangedEventArgs& other) = default; - PositionChangedEventArgs(PositionChangedEventArgs&& other) = default; - PositionChangedEventArgs& operator=(const PositionChangedEventArgs& other) = default; - PositionChangedEventArgs& operator=(PositionChangedEventArgs&& other) = default; - ~PositionChangedEventArgs() override = default; - - Point GetOldPosition() const - { - return old_position_; - } - - Point GetNewPosition() const - { - return new_position_; - } - - private: - Point old_position_; - Point new_position_; - }; - - - class SizeChangedEventArgs : public UiEventArgs - { - public: - SizeChangedEventArgs(Object* sender, Object* original_sender, const Size& old_size, const Size& new_size) - : UiEventArgs(sender, original_sender), old_size_(old_size), new_size_(new_size) - { - - } - SizeChangedEventArgs(const SizeChangedEventArgs& other) = default; - SizeChangedEventArgs(SizeChangedEventArgs&& other) = default; - SizeChangedEventArgs& operator=(const SizeChangedEventArgs& other) = default; - SizeChangedEventArgs& operator=(SizeChangedEventArgs&& other) = default; - ~SizeChangedEventArgs() override = default; - - Size GetOldSize() const - { - return old_size_; - } - - Size GetNewSize() const - { - return new_size_; - } - - private: - Size old_size_; - Size new_size_; - }; - class FocusChangeEventArgs : public UiEventArgs { public: diff --git a/src/ui/layout_base.cpp b/src/ui/layout_base.cpp index 40bb71b3..5898a623 100644 --- a/src/ui/layout_base.cpp +++ b/src/ui/layout_base.cpp @@ -1,84 +1,6 @@ #include "layout_base.hpp" -#include "application.hpp" -#include "control.hpp" -#include "window.hpp" - namespace cru::ui { - LayoutManager* LayoutManager::GetInstance() - { - return Application::GetInstance()->ResolveSingleton<LayoutManager>([](auto) - { - return new LayoutManager{}; - }); - } - - void LayoutManager::InvalidateControlPositionCache(Control * control) - { - if (cache_invalid_controls_.count(control) == 1) - return; - - // find descendant then erase it; find ancestor then just return. - auto i = cache_invalid_controls_.cbegin(); - while (i != cache_invalid_controls_.cend()) - { - auto current_i = i++; - const auto result = IsAncestorOrDescendant(*current_i, control); - if (result == control) - cache_invalid_controls_.erase(current_i); - else if (result != nullptr) - return; // find a ancestor of "control", just return - } - - cache_invalid_controls_.insert(control); - - if (cache_invalid_controls_.size() == 1) // when insert just now and not repeat to "InvokeLater". - { - InvokeLater([this] { - for (const auto i : cache_invalid_controls_) - RefreshControlPositionCache(i); - for (const auto i : cache_invalid_controls_) // traverse all descendants of position-invalid controls and notify position change event - i->TraverseDescendants([](Control* control) - { - control->CheckAndNotifyPositionChanged(); - }); - cache_invalid_controls_.clear(); // after update and notify, clear the set. - - }); - } - } - - void LayoutManager::RefreshInvalidControlPositionCache() - { - for (const auto i : cache_invalid_controls_) - RefreshControlPositionCache(i); - cache_invalid_controls_.clear(); - } - - void LayoutManager::RefreshControlPositionCache(Control * control) - { - auto point = Point::Zero(); - auto parent = control; - while ((parent = parent->GetParent())) { - const auto p = parent->GetPositionRelative(); - point.x += p.x; - point.y += p.y; - } - RefreshControlPositionCacheInternal(control, point); - } - void LayoutManager::RefreshControlPositionCacheInternal(Control * control, const Point & parent_lefttop_absolute) - { - const auto position = control->GetPositionRelative(); - 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->GetChildren()) - { - RefreshControlPositionCacheInternal(c, lefttop); - } - } } diff --git a/src/ui/layout_base.hpp b/src/ui/layout_base.hpp index 2ae21837..527d9f98 100644 --- a/src/ui/layout_base.hpp +++ b/src/ui/layout_base.hpp @@ -3,16 +3,10 @@ // ReSharper disable once CppUnusedIncludeDirective #include "pre.hpp" -#include <unordered_set> - -#include "base.hpp" #include "ui_base.hpp" namespace cru::ui { - class Control; - class Window; - enum class Alignment { Center, @@ -105,41 +99,4 @@ namespace cru::ui Thickness padding; Thickness margin; }; - - - class LayoutManager : public Object - { - public: - static LayoutManager* GetInstance(); - private: - LayoutManager() = default; - public: - LayoutManager(const LayoutManager& other) = delete; - LayoutManager(LayoutManager&& other) = delete; - LayoutManager& operator=(const LayoutManager& other) = delete; - LayoutManager& operator=(LayoutManager&& other) = delete; - ~LayoutManager() override = default; - - - //*************** region: position cache *************** - - //Mark position cache of the control and its descendants invalid, - //(which is saved as an auto-managed list internal) - //and send a message to refresh them. - void InvalidateControlPositionCache(Control* control); - - //Refresh position cache of the control and its descendants whose cache - //has been marked as invalid. - void RefreshInvalidControlPositionCache(); - - //Refresh position cache of the control and its descendants immediately. - static void RefreshControlPositionCache(Control* control); - - private: - static void RefreshControlPositionCacheInternal(Control* control, const Point& parent_lefttop_absolute); - - private: - std::unordered_set<Control*> cache_invalid_controls_; - std::unordered_set<Window*> layout_invalid_windows_; - }; } diff --git a/src/ui/window.cpp b/src/ui/window.cpp index b4569366..dfc6db43 100644 --- a/src/ui/window.cpp +++ b/src/ui/window.cpp @@ -464,17 +464,12 @@ namespace cru::ui return Point(); } - void Window::SetPositionRelative(const Point & position) - { - - } - Size Window::GetSize() { return GetClientSize(); } - void Window::SetSize(const Size & size) + void Window::SetRect(const Rect& size) { } @@ -500,7 +495,7 @@ namespace cru::ui void Window::Relayout() { Measure(GetSize(), AdditionalMeasureInfo{}); - OnLayoutCore(Rect(Point::Zero(), GetSize())); + OnLayoutCore(Rect(Point::Zero(), GetSize()), AdditionalLayoutInfo{}); is_layout_invalid_ = false; } @@ -508,7 +503,7 @@ namespace cru::ui { Measure(max_size, AdditionalMeasureInfo{}); SetClientSize(GetDesiredSize()); - OnLayoutCore(Rect(Point::Zero(), GetSize())); + OnLayoutCore(Rect(Point::Zero(), GetSize()), AdditionalLayoutInfo{}); is_layout_invalid_ = false; } diff --git a/src/ui/window.hpp b/src/ui/window.hpp index 7287c7e5..26d3fe40 100644 --- a/src/ui/window.hpp +++ b/src/ui/window.hpp @@ -190,14 +190,11 @@ namespace cru::ui //Always return (0, 0) for a window. Point GetPositionRelative() override final; - //This method has no effect for a window. - void SetPositionRelative(const Point& position) override final; - //Get the size of client area for a window. Size GetSize() override final; //This method has no effect for a window. Use SetClientSize instead. - void SetSize(const Size& size) override final; + void SetRect(const Rect& size) override final; //Override. If point is in client area, it is in window. bool IsPointInside(const Point& point) override final; @@ -282,7 +279,7 @@ namespace cru::ui //*************** region: event dispatcher helper *************** void DispatchMouseHoverControlChangeEvent(Control* old_control, Control * new_control, const Point& point); - + private: bool delete_this_on_destroy_ = true; |