diff options
-rw-r--r-- | include/cru/ui/controls/container.hpp | 31 | ||||
-rw-r--r-- | include/cru/ui/render/border_render_object.hpp | 55 | ||||
-rw-r--r-- | src/ui/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/ui/controls/button.cpp | 15 | ||||
-rw-r--r-- | src/ui/controls/container.cpp | 13 | ||||
-rw-r--r-- | src/ui/controls/flex_layout.cpp | 4 | ||||
-rw-r--r-- | src/ui/render/border_render_object.cpp | 61 |
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(); } |