From 20dc75e2ce6a9c38dd1888fdbf793fd8a3bc9cd3 Mon Sep 17 00:00:00 2001 From: crupest Date: Sat, 29 Sep 2018 17:35:09 +0800 Subject: Add PropertyChangedNotifyObject and BorderProperty. --- src/base.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'src/base.h') diff --git a/src/base.h b/src/base.h index 7ef78014..ce7a781d 100644 --- a/src/base.h +++ b/src/base.h @@ -20,6 +20,7 @@ #include #include #include +#include namespace cru { @@ -60,6 +61,12 @@ namespace cru return std::make_shared(std::forward(args)...); } + template + Type CreateFunctionPtr(Function&& function) + { + return std::make_shared>(std::move(function)); + } + inline ActionPtr CreateActionPtr(Action&& action) { return std::make_shared(std::move(action)); @@ -104,4 +111,26 @@ namespace cru using CancelablePtr = std::shared_ptr; MultiByteString ToUtf8String(const StringView& string); + + + class PropertyChangedNotifyObject : public Object + { + public: + PropertyChangedNotifyObject() = default; + PropertyChangedNotifyObject(const PropertyChangedNotifyObject& other) = delete; + PropertyChangedNotifyObject(PropertyChangedNotifyObject&& other) = delete; + PropertyChangedNotifyObject& operator = (const PropertyChangedNotifyObject& other) = delete; + PropertyChangedNotifyObject& operator = (PropertyChangedNotifyObject&& other) = delete; + ~PropertyChangedNotifyObject() override = default; + + void AddPropertyChangedListener(FunctionPtr listener); + + void RemovePropertyChangedListener(const FunctionPtr& listener); + + protected: + void RaisePropertyChangedEvent(String property_name); + + private: + std::list> listeners_; + }; } -- cgit v1.2.3 From 88765aab936724cb01fa2ffd86d65181182a1cd2 Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 30 Sep 2018 20:38:10 +0800 Subject: Create border delegate. --- CruUI.vcxproj | 4 +- CruUI.vcxproj.filters | 4 +- src/base.h | 4 +- src/ui/control.cpp | 14 +++--- src/ui/controls/border_control.cpp | 34 -------------- src/ui/controls/border_control.h | 61 ------------------------ src/ui/controls/border_delegate.cpp | 85 +++++++++++++++++++++++++++++++++ src/ui/controls/border_delegate.h | 91 ++++++++++++++++++++++++++++++++++++ src/ui/controls/margin_container.cpp | 85 ++++++++++++++++++++++----------- 9 files changed, 247 insertions(+), 135 deletions(-) delete mode 100644 src/ui/controls/border_control.cpp delete mode 100644 src/ui/controls/border_control.h create mode 100644 src/ui/controls/border_delegate.cpp create mode 100644 src/ui/controls/border_delegate.h (limited to 'src/base.h') diff --git a/CruUI.vcxproj b/CruUI.vcxproj index a6503833..975d74d8 100644 --- a/CruUI.vcxproj +++ b/CruUI.vcxproj @@ -122,14 +122,14 @@ - + - + diff --git a/CruUI.vcxproj.filters b/CruUI.vcxproj.filters index c72ae54c..683b3686 100644 --- a/CruUI.vcxproj.filters +++ b/CruUI.vcxproj.filters @@ -72,7 +72,7 @@ Source Files - + Source Files @@ -146,7 +146,7 @@ Header Files - + Header Files diff --git a/src/base.h b/src/base.h index ce7a781d..18bf9cc5 100644 --- a/src/base.h +++ b/src/base.h @@ -62,9 +62,9 @@ namespace cru } template - Type CreateFunctionPtr(Function&& function) + FunctionPtr CreateFunctionPtr(Function&& function) { - return std::make_shared>(std::move(function)); + return std::make_shared>(std::move(function)); } inline ActionPtr CreateActionPtr(Action&& action) diff --git a/src/ui/control.cpp b/src/ui/control.cpp index 81cfe9b1..480f7d46 100644 --- a/src/ui/control.cpp +++ b/src/ui/control.cpp @@ -257,7 +257,7 @@ namespace cru { { SetPositionRelative(rect.GetLeftTop()); SetSize(rect.GetSize()); - OnLayout(rect); + OnLayout(Rect(Point::Zero(), rect.GetSize())); } Size Control::GetDesiredSize() const @@ -617,24 +617,24 @@ namespace cru { const auto layout_params = control->GetLayoutParams(); const auto size = control->GetDesiredSize(); - auto&& calculate_anchor = [](const Alignment alignment, const float layout_length, const float control_length) -> float + auto&& calculate_anchor = [](const float anchor, const Alignment alignment, const float layout_length, const float control_length) -> float { switch (alignment) { case Alignment::Center: - return (layout_length - control_length) / 2; + return anchor + (layout_length - control_length) / 2; case Alignment::Start: - return 0; + return anchor; case Alignment::End: - return layout_length - control_length; + return anchor + layout_length - control_length; default: UnreachableCode(); } }; control->Layout(Rect(Point( - calculate_anchor(layout_params->width.alignment, rect.width, size.width), - calculate_anchor(layout_params->height.alignment, rect.height, size.height) + 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)); }); } diff --git a/src/ui/controls/border_control.cpp b/src/ui/controls/border_control.cpp deleted file mode 100644 index 9f33079c..00000000 --- a/src/ui/controls/border_control.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "border_control.h" - -namespace cru::ui::controls -{ - void BorderProperty::SetBrush(Microsoft::WRL::ComPtr brush) - { - brush_ = std::move(brush); - RaisePropertyChangedEvent(L"Brush"); - } - - void BorderProperty::SetWidth(const float width) - { - width_ = width; - RaisePropertyChangedEvent(L"Width"); - } - - void BorderProperty::SetStrokeStyle(Microsoft::WRL::ComPtr stroke_style) - { - stroke_style_ = std::move(stroke_style); - RaisePropertyChangedEvent(L"StrokeStyle"); - } - - void BorderProperty::SetRadiusX(const float radius_x) - { - radius_x_ = radius_x; - RaisePropertyChangedEvent(L"RadiusX"); - } - - void BorderProperty::SetRadiusY(const float radius_y) - { - radius_y_ = radius_y; - RaisePropertyChangedEvent(L"RadiusY"); - } -} diff --git a/src/ui/controls/border_control.h b/src/ui/controls/border_control.h deleted file mode 100644 index 582d2436..00000000 --- a/src/ui/controls/border_control.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include "ui/control.h" - -namespace cru::ui::controls -{ - class BorderProperty : public PropertyChangedNotifyObject - { - public: - BorderProperty() = default; - BorderProperty(const BorderProperty& other) = delete; - BorderProperty(BorderProperty&& other) = delete; - BorderProperty& operator=(const BorderProperty& other) = delete; - BorderProperty& operator=(BorderProperty&& other) = delete; - ~BorderProperty() override = default; - - - Microsoft::WRL::ComPtr GetBrush() const - { - return brush_; - } - - float GetWidth() const - { - return width_; - } - - Microsoft::WRL::ComPtr GetStrokeStyle() const - { - return stroke_style_; - } - - float GetRadiusX() const - { - return radius_x_; - } - - float GetRadiusY() const - { - return radius_y_; - } - - void SetBrush(Microsoft::WRL::ComPtr brush); - void SetWidth(float width); - void SetStrokeStyle(Microsoft::WRL::ComPtr stroke_style); - void SetRadiusX(float radius_x); - void SetRadiusY(float radius_y); - - private: - Microsoft::WRL::ComPtr brush_ = nullptr; - float width_ = 1.0f; - Microsoft::WRL::ComPtr stroke_style_ = nullptr; - float radius_x_ = 0.0f; - float radius_y_ = 0.0f; - }; - - class BorderControl : public Control - { - - }; -} diff --git a/src/ui/controls/border_delegate.cpp b/src/ui/controls/border_delegate.cpp new file mode 100644 index 00000000..4e841a8c --- /dev/null +++ b/src/ui/controls/border_delegate.cpp @@ -0,0 +1,85 @@ +#include "border_delegate.h" + +namespace cru::ui::controls +{ + void BorderProperty::SetBrush(Microsoft::WRL::ComPtr brush) + { + brush_ = std::move(brush); + RaisePropertyChangedEvent(brush_property_name); + } + + void BorderProperty::SetWidth(const float width) + { + width_ = width; + RaisePropertyChangedEvent(width_property_name); + } + + void BorderProperty::SetStrokeStyle(Microsoft::WRL::ComPtr stroke_style) + { + stroke_style_ = std::move(stroke_style); + RaisePropertyChangedEvent(stroke_style_property_name); + } + + void BorderProperty::SetRadiusX(const float radius_x) + { + radius_x_ = radius_x; + RaisePropertyChangedEvent(radius_x_property_name); + } + + void BorderProperty::SetRadiusY(const float radius_y) + { + radius_y_ = radius_y; + RaisePropertyChangedEvent(radius_y_property_name); + } + + BorderDelegate::BorderDelegate(Control* control) + : BorderDelegate(control, std::make_shared()) + { + + } + + BorderDelegate::BorderDelegate(Control* control, std::shared_ptr border_property)\ + : control_(control), + border_property_changed_listener_(CreateFunctionPtr([this](String property_name) + { + if (property_name == BorderProperty::width_property_name) + control_->InvalidateLayout(); + control_->Repaint(); + })) + { + border_property_ = std::move(border_property); + border_property_->AddPropertyChangedListener(border_property_changed_listener_); + } + + void BorderDelegate::SetBorderProperty(std::shared_ptr border_property) + { + border_property_->RemovePropertyChangedListener(border_property_changed_listener_); + border_property_ = std::move(border_property); + border_property_->AddPropertyChangedListener(border_property_changed_listener_); + } + + void BorderDelegate::Draw(ID2D1DeviceContext* device_context, const Size& size) const + { + device_context->DrawRoundedRectangle( + D2D1::RoundedRect(D2D1::RectF(0.0f, 0.0f, size.width, size.height), + border_property_->GetRadiusX(), + border_property_->GetRadiusY() + ), + border_property_->GetBrush().Get(), + border_property_->GetWidth(), + border_property_->GetStrokeStyle().Get() + ); + } + + Size BorderDelegate::GetBorderSize() const + { + const auto width = border_property_->GetWidth(); + return Size(width * 2, width * 2); + } + + Rect BorderDelegate::CoerceLayoutRect(const Rect& rect) const + { + const auto width = border_property_->GetWidth(); + return Rect(rect.left + width, rect.top + width, rect.width - width * 2, rect.height - width * 2); + } +} diff --git a/src/ui/controls/border_delegate.h b/src/ui/controls/border_delegate.h new file mode 100644 index 00000000..f22b303f --- /dev/null +++ b/src/ui/controls/border_delegate.h @@ -0,0 +1,91 @@ +#pragma once + +#include "ui/control.h" + +namespace cru::ui::controls +{ + class BorderProperty : public PropertyChangedNotifyObject + { + public: + constexpr static auto brush_property_name = L"Brush"; + constexpr static auto width_property_name = L"Width"; + constexpr static auto stroke_style_property_name = L"StrokeStyle"; + constexpr static auto radius_x_property_name = L"RadiusX"; + constexpr static auto radius_y_property_name = L"RadiusY"; + + BorderProperty() = default; + BorderProperty(const BorderProperty& other) = delete; + BorderProperty(BorderProperty&& other) = delete; + BorderProperty& operator=(const BorderProperty& other) = delete; + BorderProperty& operator=(BorderProperty&& other) = delete; + ~BorderProperty() override = default; + + + Microsoft::WRL::ComPtr GetBrush() const + { + return brush_; + } + + float GetWidth() const + { + return width_; + } + + Microsoft::WRL::ComPtr GetStrokeStyle() const + { + return stroke_style_; + } + + float GetRadiusX() const + { + return radius_x_; + } + + float GetRadiusY() const + { + return radius_y_; + } + + void SetBrush(Microsoft::WRL::ComPtr brush); + void SetWidth(float width); + void SetStrokeStyle(Microsoft::WRL::ComPtr stroke_style); + void SetRadiusX(float radius_x); + void SetRadiusY(float radius_y); + + private: + Microsoft::WRL::ComPtr brush_ = nullptr; + float width_ = 1.0f; + Microsoft::WRL::ComPtr stroke_style_ = nullptr; + float radius_x_ = 0.0f; + float radius_y_ = 0.0f; + }; + + class BorderDelegate : public Object + { + public: + explicit BorderDelegate(Control* control); + BorderDelegate(Control* control, std::shared_ptr border_property); + BorderDelegate(const BorderDelegate& other) = delete; + BorderDelegate(BorderDelegate&& other) = delete; + BorderDelegate& operator=(const BorderDelegate& other) = delete; + BorderDelegate& operator=(BorderDelegate&& other) = delete; + ~BorderDelegate() override = default; + + std::shared_ptr GetBorderProperty() const + { + return border_property_; + } + + void SetBorderProperty(std::shared_ptr border_property); + + void Draw(ID2D1DeviceContext* device_context, const Size& size) const; + + Size GetBorderSize() const; + Rect CoerceLayoutRect(const Rect& rect) const; + + private: + Control* control_; + std::shared_ptr border_property_; + FunctionPtr border_property_changed_listener_; + }; +} diff --git a/src/ui/controls/margin_container.cpp b/src/ui/controls/margin_container.cpp index 1f331d32..26acb172 100644 --- a/src/ui/controls/margin_container.cpp +++ b/src/ui/controls/margin_container.cpp @@ -25,39 +25,70 @@ namespace cru::ui::controls Size MarginContainer::OnMeasure(const Size& available_size) { + const auto layout_params = GetLayoutParams(); + + if (!layout_params->Validate()) + throw std::runtime_error("LayoutParams is not valid. Please check it."); + + auto&& get_available_length_for_child = [](const LayoutSideParams& layout_length, const float available_length) -> float + { + switch (layout_length.mode) + { + case MeasureMode::Exactly: + { + return std::min(layout_length.length, available_length); + } + case MeasureMode::Stretch: + case MeasureMode::Content: + { + return available_length; + } + default: + UnreachableCode(); + } + }; + + const Size size_for_children(get_available_length_for_child(layout_params->width, available_size.width), + get_available_length_for_child(layout_params->height, available_size.height)); + const auto margin_size = Size(margin_.left + margin_.right, margin_.top + margin_.bottom); - const auto coerced_available_size = AtLeast0(available_size - margin_size); - return Control::OnMeasure(coerced_available_size) + margin_size; + const auto coerced_size_for_children = AtLeast0(size_for_children - margin_size); + + auto max_child_size = Size::Zero(); + ForeachChild([coerced_size_for_children, &max_child_size](Control* control) + { + control->Measure(coerced_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; + }); + + auto&& calculate_final_length = [](const LayoutSideParams& layout_length, const float length_for_children, const float max_child_length) -> float + { + switch (layout_length.mode) + { + case MeasureMode::Exactly: + case MeasureMode::Stretch: + return length_for_children; + case MeasureMode::Content: + return max_child_length; + default: + UnreachableCode(); + } + }; + + return Size( + calculate_final_length(layout_params->width, coerced_size_for_children.width, max_child_size.width), + calculate_final_length(layout_params->height, coerced_size_for_children.height, max_child_size.height) + ); } void MarginContainer::OnLayout(const Rect& rect) { const auto anchor = Point(margin_.left, margin_.top); const auto margin_size = Size(margin_.left + margin_.right, margin_.top + margin_.bottom); - ForeachChild([anchor, margin_size, rect](Control* control) - { - const auto layout_params = control->GetLayoutParams(); - const auto size = control->GetDesiredSize(); - - auto&& calculate_anchor = [](const float anchor, const Alignment alignment, const float layout_length, const float control_length) -> float - { - 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(anchor.x, layout_params->width.alignment, rect.width - margin_size.width, size.width), - calculate_anchor(anchor.y, layout_params->height.alignment, rect.height - margin_size.height, size.height) - ), size)); - }); + Control::OnLayout(Rect(anchor, AtLeast0(rect.GetSize() - margin_size))); } } -- cgit v1.2.3