aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/ui/controls/container.hpp31
-rw-r--r--include/cru/ui/render/border_render_object.hpp55
-rw-r--r--src/ui/CMakeLists.txt2
-rw-r--r--src/ui/controls/button.cpp15
-rw-r--r--src/ui/controls/container.cpp13
-rw-r--r--src/ui/controls/flex_layout.cpp4
-rw-r--r--src/ui/render/border_render_object.cpp61
7 files changed, 122 insertions, 59 deletions
diff --git a/include/cru/ui/controls/container.hpp b/include/cru/ui/controls/container.hpp
new file mode 100644
index 00000000..3c877067
--- /dev/null
+++ b/include/cru/ui/controls/container.hpp
@@ -0,0 +1,31 @@
+#pragma once
+#include "../content_control.hpp"
+
+namespace cru::ui::render {
+class BorderRenderObject;
+}
+
+namespace cru::ui::controls {
+class Container : public ContentControl {
+ static constexpr auto control_type = L"Container";
+
+ protected:
+ Container();
+
+ public:
+ CRU_DELETE_COPY(Container)
+ CRU_DELETE_MOVE(Container)
+
+ ~Container() override;
+
+ public:
+ std::wstring_view GetControlType() const override final {
+ return control_type;
+ }
+
+ render::RenderObject* GetRenderObject() const override;
+
+ private:
+ std::unique_ptr<render::BorderRenderObject> render_object_;
+};
+} // namespace cru::ui::controls
diff --git a/include/cru/ui/render/border_render_object.hpp b/include/cru/ui/render/border_render_object.hpp
index 69372eb8..5c147df5 100644
--- a/include/cru/ui/render/border_render_object.hpp
+++ b/include/cru/ui/render/border_render_object.hpp
@@ -33,48 +33,41 @@ struct CornerRadius {
};
struct BorderStyle {
- std::shared_ptr<platform::graph::Brush> brush;
- Thickness thickness;
- CornerRadius corner_radius;
+ std::shared_ptr<platform::graph::Brush> brush{};
+ Thickness thickness{};
+ CornerRadius corner_radius{};
};
class BorderRenderObject : public RenderObject {
public:
- explicit BorderRenderObject(std::shared_ptr<platform::graph::Brush> brush);
+ BorderRenderObject();
BorderRenderObject(const BorderRenderObject& other) = delete;
BorderRenderObject(BorderRenderObject&& other) = delete;
BorderRenderObject& operator=(const BorderRenderObject& other) = delete;
BorderRenderObject& operator=(BorderRenderObject&& other) = delete;
- ~BorderRenderObject() override = default;
+ ~BorderRenderObject() override;
- bool IsEnabled() const { return is_enabled_; }
- void SetEnabled(bool enabled) { is_enabled_ = enabled; }
+ bool IsBorderEnabled() const { return is_border_enabled_; }
+ void SetBorderEnabled(bool enabled) { is_border_enabled_ = enabled; }
- std::shared_ptr<platform::graph::Brush> GetBrush() const {
- return style_.brush;
- }
- void SetBrush(std::shared_ptr<platform::graph::Brush> new_brush) {
- style_.brush = std::move(new_brush);
+ BorderStyle* GetBorderStyle() {
+ return &border_style_;
}
- Thickness GetBorderWidth() const { return style_.thickness; }
- // Remember to call Refresh after set shape properties.
- void SetBorderWidth(const Thickness& thickness) {
- style_.thickness = thickness;
+ std::shared_ptr<platform::graph::Brush> GetForegroundBrush() {
+ return foreground_brush_;
}
- CornerRadius GetCornerRadius() const { return style_.corner_radius; }
- // Remember to call Refresh after set shape properties.
- void SetCornerRadius(const CornerRadius& new_corner_radius) {
- style_.corner_radius = new_corner_radius;
+ void SetForegroundBrush(std::shared_ptr<platform::graph::Brush> brush) {
+ foreground_brush_ = std::move(brush);
}
- BorderStyle GetStyle() const {
- return style_;
+ std::shared_ptr<platform::graph::Brush> GetBackgroundBrush() {
+ return foreground_brush_;
}
- // Remember to call Refresh after set shape properties.
- void SetStyle(BorderStyle newStyle) {
- style_ = std::move(newStyle);
+
+ void SetBackgroundBrush(std::shared_ptr<platform::graph::Brush> brush) {
+ foreground_brush_ = std::move(brush);
}
void Refresh() { RecreateGeometry(); }
@@ -101,13 +94,17 @@ class BorderRenderObject : public RenderObject {
void RecreateGeometry();
private:
- bool is_enabled_ = false;
+ bool is_border_enabled_ = false;
+ BorderStyle border_style_;
- BorderStyle style_;
+ std::shared_ptr<platform::graph::Brush> foreground_brush_;
+ std::shared_ptr<platform::graph::Brush> background_brush_;
// The ring. Used for painting.
- std::shared_ptr<platform::graph::Geometry> geometry_ = nullptr;
+ std::unique_ptr<platform::graph::Geometry> geometry_;
+ // Area including inner area of the border. Used for painting foreground and background.
+ std::unique_ptr<platform::graph::Geometry> border_inner_geometry_;
// Area including border ring and inner area. Used for hit test.
- std::shared_ptr<platform::graph::Geometry> border_outer_geometry_ = nullptr;
+ std::unique_ptr<platform::graph::Geometry> border_outer_geometry_;
};
} // namespace cru::ui::render
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index ac69c644..18d1ca16 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -11,6 +11,7 @@ add_library(cru_ui STATIC
ui_manager.cpp
window.cpp
controls/button.cpp
+ controls/container.cpp
controls/flex_layout.cpp
controls/text_block.cpp
render/border_render_object.cpp
@@ -29,6 +30,7 @@ target_sources(cru_ui PUBLIC
${CRU_UI_INCLUDE_DIR}/ui_manager.hpp
${CRU_UI_INCLUDE_DIR}/window.hpp
${CRU_UI_INCLUDE_DIR}/controls/button.hpp
+ ${CRU_UI_INCLUDE_DIR}/controls/container.hpp
${CRU_UI_INCLUDE_DIR}/controls/flex_layout.hpp
${CRU_UI_INCLUDE_DIR}/controls/text_block.hpp
${CRU_UI_INCLUDE_DIR}/event/ui_event.hpp
diff --git a/src/ui/controls/button.cpp b/src/ui/controls/button.cpp
index 5e32e064..1a1f4286 100644
--- a/src/ui/controls/button.cpp
+++ b/src/ui/controls/button.cpp
@@ -37,11 +37,10 @@ Button::Button() : click_detector_(this) {
border_style_.press_cancel.corner_radius =
render::CornerRadius{Point{10, 5}};
- render_object_.reset(
- new render::BorderRenderObject(border_style_.normal.brush));
+ render_object_.reset(new render::BorderRenderObject);
render_object_->SetAttachedControl(this);
- render_object_->SetEnabled(true);
- render_object_->SetStyle(border_style_.normal);
+ render_object_->SetBorderEnabled(true);
+ (*render_object_->GetBorderStyle()) = border_style_.normal;
MouseEnterEvent()->Direct()->AddHandler([this](event::MouseEventArgs& args) {
if (click_detector_.GetPressingButton() & trigger_button_) {
@@ -85,19 +84,19 @@ void Button::OnChildChanged(Control* old_child, Control* new_child) {
void Button::OnStateChange(ButtonState oldState, ButtonState newState) {
switch (newState) {
case ButtonState::Normal:
- render_object_->SetStyle(border_style_.normal);
+ (*render_object_->GetBorderStyle()) = border_style_.normal;
SetCursor(GetSystemCursor(SystemCursor::Arrow));
break;
case ButtonState::Hover:
- render_object_->SetStyle(border_style_.hover);
+ (*render_object_->GetBorderStyle()) = border_style_.hover;
SetCursor(GetSystemCursor(SystemCursor::Hand));
break;
case ButtonState::Press:
- render_object_->SetStyle(border_style_.press);
+ (*render_object_->GetBorderStyle()) = border_style_.press;
SetCursor(GetSystemCursor(SystemCursor::Hand));
break;
case ButtonState::PressCancel:
- render_object_->SetStyle(border_style_.press_cancel);
+ (*render_object_->GetBorderStyle()) = border_style_.press_cancel;
SetCursor(GetSystemCursor(SystemCursor::Arrow));
break;
}
diff --git a/src/ui/controls/container.cpp b/src/ui/controls/container.cpp
new file mode 100644
index 00000000..7ebee4b4
--- /dev/null
+++ b/src/ui/controls/container.cpp
@@ -0,0 +1,13 @@
+#include "cru/ui/controls/container.hpp"
+
+#include "cru/platform/graph/graph_factory.hpp"
+#include "cru/ui/render/border_render_object.hpp"
+
+namespace cru::ui::controls {
+Container::Container() {
+ render_object_.reset(new render::BorderRenderObject);
+ render_object_->SetBorderEnabled(false);
+}
+
+Container::~Container() {}
+} // namespace cru::ui::controls
diff --git a/src/ui/controls/flex_layout.cpp b/src/ui/controls/flex_layout.cpp
index bb8e3c14..a8200a12 100644
--- a/src/ui/controls/flex_layout.cpp
+++ b/src/ui/controls/flex_layout.cpp
@@ -22,7 +22,7 @@ FlexChildLayoutData FlexLayout::GetChildLayoutData(Control* control) {
if (find_result == render_objects.cend()) {
throw std::logic_error("Control is not a child of FlexLayout.");
}
- int position = find_result - render_objects.cbegin();
+ int position = static_cast<int>(find_result - render_objects.cbegin());
return *(render_object_->GetChildLayoutData(position));
}
@@ -35,7 +35,7 @@ void FlexLayout::SetChildLayoutData(Control* control,
if (find_result == render_objects.cend()) {
throw std::logic_error("Control is not a child of FlexLayout.");
}
- int position = find_result - render_objects.cbegin();
+ int position = static_cast<int>(find_result - render_objects.cbegin());
const auto d = render_object_->GetChildLayoutData(position);
*d = data;
if (const auto window = GetWindow()) window->InvalidateLayout();
diff --git a/src/ui/render/border_render_object.cpp b/src/ui/render/border_render_object.cpp
index 20bc2a50..68e74740 100644
--- a/src/ui/render/border_render_object.cpp
+++ b/src/ui/render/border_render_object.cpp
@@ -9,21 +9,30 @@
#include <cassert>
namespace cru::ui::render {
-BorderRenderObject::BorderRenderObject(
- std::shared_ptr<platform::graph::Brush> brush) {
- assert(brush);
- this->style_.brush = std::move(brush);
- RecreateGeometry();
-}
+BorderRenderObject::BorderRenderObject() { RecreateGeometry(); }
+
+BorderRenderObject::~BorderRenderObject() {}
void BorderRenderObject::Draw(platform::graph::Painter* painter) {
- painter->FillGeometry(geometry_.get(), style_.brush.get());
+ if (background_brush_ != nullptr)
+ painter->FillGeometry(border_inner_geometry_.get(),
+ background_brush_.get());
+ if (is_border_enabled_) {
+ if (border_style_.brush == nullptr) {
+ log::Warn(L"Border is enabled but brush is null");
+ } else {
+ painter->FillGeometry(geometry_.get(), border_style_.brush.get());
+ }
+ }
if (const auto child = GetChild()) {
auto offset = child->GetOffset();
platform::graph::util::WithTransform(
painter, platform::Matrix::Translation(offset.x, offset.y),
[child](auto p) { child->Draw(p); });
}
+ if (foreground_brush_ != nullptr)
+ painter->FillGeometry(border_inner_geometry_.get(),
+ foreground_brush_.get());
}
RenderObject* BorderRenderObject::HitTest(const Point& point) {
@@ -36,7 +45,7 @@ RenderObject* BorderRenderObject::HitTest(const Point& point) {
}
}
- if (is_enabled_) {
+ if (is_border_enabled_) {
const auto contains =
border_outer_geometry_->FillContains(Point{point.x, point.y});
return contains ? this : nullptr;
@@ -68,9 +77,11 @@ void BorderRenderObject::OnMeasureCore(const Size& available_size) {
margin.GetHorizontalTotal() + padding.GetHorizontalTotal(),
margin.GetVerticalTotal() + padding.GetVerticalTotal()};
- if (is_enabled_) {
- margin_border_padding_size.width += style_.thickness.GetHorizontalTotal();
- margin_border_padding_size.height += style_.thickness.GetVerticalTotal();
+ if (is_border_enabled_) {
+ margin_border_padding_size.width +=
+ border_style_.thickness.GetHorizontalTotal();
+ margin_border_padding_size.height +=
+ border_style_.thickness.GetVerticalTotal();
}
auto coerced_margin_border_padding_size = margin_border_padding_size;
@@ -103,9 +114,11 @@ void BorderRenderObject::OnLayoutCore(const Rect& rect) {
margin.GetHorizontalTotal() + padding.GetHorizontalTotal(),
margin.GetVerticalTotal() + padding.GetVerticalTotal()};
- if (is_enabled_) {
- margin_border_padding_size.width += style_.thickness.GetHorizontalTotal();
- margin_border_padding_size.height += style_.thickness.GetVerticalTotal();
+ if (is_border_enabled_) {
+ margin_border_padding_size.width +=
+ border_style_.thickness.GetHorizontalTotal();
+ margin_border_padding_size.height +=
+ border_style_.thickness.GetVerticalTotal();
}
const auto content_available_size =
@@ -126,8 +139,10 @@ void BorderRenderObject::OnLayoutCore(const Rect& rect) {
}
OnLayoutContent(Rect{
- margin.left + (is_enabled_ ? style_.thickness.left : 0) + padding.left,
- margin.top + (is_enabled_ ? style_.thickness.top : 0) + padding.top,
+ margin.left + (is_border_enabled_ ? border_style_.thickness.left : 0) +
+ padding.left,
+ margin.top + (is_border_enabled_ ? border_style_.thickness.top : 0) +
+ padding.top,
coerced_content_available_size.width,
coerced_content_available_size.height});
}
@@ -183,14 +198,20 @@ void BorderRenderObject::RecreateGeometry() {
const auto graph_factory = platform::graph::GraphFactory::GetInstance();
std::unique_ptr<platform::graph::GeometryBuilder> builder{
graph_factory->CreateGeometryBuilder()};
- f(builder.get(), outer_rect, style_.corner_radius);
+ f(builder.get(), outer_rect, border_style_.corner_radius);
border_outer_geometry_.reset(builder->Build());
builder.reset();
- const Rect inner_rect = outer_rect.Shrink(style_.thickness);
+ const Rect inner_rect = outer_rect.Shrink(border_style_.thickness);
+
+ builder.reset(graph_factory->CreateGeometryBuilder());
+ f(builder.get(), inner_rect, border_style_.corner_radius);
+ border_inner_geometry_.reset(builder->Build());
+ builder.reset();
+
builder.reset(graph_factory->CreateGeometryBuilder());
- f(builder.get(), outer_rect, style_.corner_radius);
- f(builder.get(), inner_rect, style_.corner_radius);
+ f(builder.get(), outer_rect, border_style_.corner_radius);
+ f(builder.get(), inner_rect, border_style_.corner_radius);
geometry_.reset(builder->Build());
builder.reset();
}