diff options
-rw-r--r-- | CruUI.vcxproj | 4 | ||||
-rw-r--r-- | CruUI.vcxproj.filters | 4 | ||||
-rw-r--r-- | src/base.h | 4 | ||||
-rw-r--r-- | src/ui/control.cpp | 14 | ||||
-rw-r--r-- | src/ui/controls/border_control.cpp | 34 | ||||
-rw-r--r-- | src/ui/controls/border_delegate.cpp | 85 | ||||
-rw-r--r-- | src/ui/controls/border_delegate.h (renamed from src/ui/controls/border_control.h) | 34 | ||||
-rw-r--r-- | src/ui/controls/margin_container.cpp | 85 |
8 files changed, 188 insertions, 76 deletions
diff --git a/CruUI.vcxproj b/CruUI.vcxproj index a6503833..975d74d8 100644 --- a/CruUI.vcxproj +++ b/CruUI.vcxproj @@ -122,14 +122,14 @@ <ClCompile Include="src\ui\animations\animation.cpp" /> <ClCompile Include="src\ui\control.cpp" /> <ClCompile Include="src\ui\controls\border.cpp" /> - <ClCompile Include="src\ui\controls\border_control.cpp" /> + <ClCompile Include="src\ui\controls\border_delegate.cpp" /> <ClCompile Include="src\ui\controls\button.cpp" /> <ClCompile Include="src\ui\controls\linear_layout.cpp" /> <ClCompile Include="src\ui\controls\margin_container.cpp" /> <ClCompile Include="src\ui\controls\text_block.cpp" /> <ClCompile Include="src\ui\controls\text_box.cpp" /> <ClInclude Include="src\ui\controls\border.h" /> - <ClInclude Include="src\ui\controls\border_control.h" /> + <ClInclude Include="src\ui\controls\border_delegate.h" /> <ClInclude Include="src\ui\controls\text_control.h" /> <ClCompile Include="src\ui\controls\toggle_button.cpp" /> <ClCompile Include="src\ui\events\ui_event.cpp" /> 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 @@ <ClCompile Include="src\ui\controls\border.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="src\ui\controls\border_control.cpp"> + <ClCompile Include="src\ui\controls\border_delegate.cpp"> <Filter>Source Files</Filter> </ClCompile> </ItemGroup> @@ -146,7 +146,7 @@ <ClInclude Include="src\ui\controls\border.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="src\ui\controls\border_control.h"> + <ClInclude Include="src\ui\controls\border_delegate.h"> <Filter>Header Files</Filter> </ClInclude> </ItemGroup> @@ -62,9 +62,9 @@ namespace cru } template<typename Type> - Type CreateFunctionPtr(Function<Type>&& function) + FunctionPtr<Type> CreateFunctionPtr(Function<Type>&& function) { - return std::make_shared<FunctionPtr<Type>>(std::move(function)); + return std::make_shared<Function<Type>>(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<ID2D1Brush> 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<ID2D1StrokeStyle> 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_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<ID2D1Brush> 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<ID2D1StrokeStyle> 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<BorderProperty>()) + { + + } + + BorderDelegate::BorderDelegate(Control* control, std::shared_ptr<BorderProperty> border_property)\ + : control_(control), + border_property_changed_listener_(CreateFunctionPtr<void(String)>([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<BorderProperty> 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_control.h b/src/ui/controls/border_delegate.h index 582d2436..f22b303f 100644 --- a/src/ui/controls/border_control.h +++ b/src/ui/controls/border_delegate.h @@ -7,6 +7,12 @@ 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; @@ -54,8 +60,32 @@ namespace cru::ui::controls float radius_y_ = 0.0f; }; - class BorderControl : public Control + class BorderDelegate : public Object { - + public: + explicit BorderDelegate(Control* control); + BorderDelegate(Control* control, std::shared_ptr<BorderProperty> 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<BorderProperty> GetBorderProperty() const + { + return border_property_; + } + + void SetBorderProperty(std::shared_ptr<BorderProperty> 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<BorderProperty> border_property_; + FunctionPtr<void(String)> 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))); } } |