aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CruUI.vcxproj4
-rw-r--r--CruUI.vcxproj.filters4
-rw-r--r--src/base.h4
-rw-r--r--src/ui/control.cpp14
-rw-r--r--src/ui/controls/border_control.cpp34
-rw-r--r--src/ui/controls/border_delegate.cpp85
-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.cpp85
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>
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<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)));
}
}