aboutsummaryrefslogtreecommitdiff
path: root/src/ui/render
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/render')
-rw-r--r--src/ui/render/BorderRenderObject.cpp34
-rw-r--r--src/ui/render/CanvasRenderObject.cpp2
-rw-r--r--src/ui/render/FlexLayoutRenderObject.cpp23
-rw-r--r--src/ui/render/RenderObject.cpp100
-rw-r--r--src/ui/render/ScrollBar.cpp622
-rw-r--r--src/ui/render/ScrollRenderObject.cpp66
-rw-r--r--src/ui/render/TextRenderObject.cpp40
-rw-r--r--src/ui/render/WindowRenderObject.cpp40
8 files changed, 818 insertions, 109 deletions
diff --git a/src/ui/render/BorderRenderObject.cpp b/src/ui/render/BorderRenderObject.cpp
index b7e1e709..e2c40f0c 100644
--- a/src/ui/render/BorderRenderObject.cpp
+++ b/src/ui/render/BorderRenderObject.cpp
@@ -2,9 +2,11 @@
#include "../Helper.hpp"
#include "cru/common/Logger.hpp"
-#include "cru/platform/graph/Factory.hpp"
-#include "cru/platform/graph/Geometry.hpp"
-#include "cru/platform/graph/util/Painter.hpp"
+#include "cru/platform/graphics/Factory.hpp"
+#include "cru/platform/graphics/Geometry.hpp"
+#include "cru/platform/graphics/util/Painter.hpp"
+#include "cru/ui/style/ApplyBorderStyleInfo.hpp"
+#include "gsl/gsl_assert"
#include <algorithm>
@@ -16,12 +18,13 @@ BorderRenderObject::BorderRenderObject() {
BorderRenderObject::~BorderRenderObject() {}
-void BorderRenderObject::SetBorderStyle(const BorderStyle& style) {
- border_brush_ = style.border_brush;
- border_thickness_ = style.border_thickness;
- border_radius_ = style.border_radius;
- foreground_brush_ = style.foreground_brush;
- background_brush_ = style.background_brush;
+void BorderRenderObject::ApplyBorderStyle(
+ const style::ApplyBorderStyleInfo& style) {
+ if (style.border_brush) border_brush_ = *style.border_brush;
+ if (style.border_thickness) border_thickness_ = *style.border_thickness;
+ if (style.border_radius) border_radius_ = *style.border_radius;
+ if (style.foreground_brush) foreground_brush_ = *style.foreground_brush;
+ if (style.background_brush) background_brush_ = *style.background_brush;
InvalidateLayout();
}
@@ -51,7 +54,7 @@ RenderObject* BorderRenderObject::HitTest(const Point& point) {
}
}
-void BorderRenderObject::OnDrawCore(platform::graph::IPainter* painter) {
+void BorderRenderObject::OnDrawCore(platform::graphics::IPainter* painter) {
if (background_brush_ != nullptr)
painter->FillGeometry(border_inner_geometry_.get(),
background_brush_.get());
@@ -109,9 +112,10 @@ Size BorderRenderObject::OnMeasureCore(const MeasureRequirement& requirement,
if (!requirement.max.height.IsNotSpecified()) {
const auto max_height = requirement.max.height.GetLengthOrMax();
if (coerced_space_size.height > max_height) {
- log::TagWarn(log_tag,
- u"(Measure) Vertical length of padding, border and margin is "
- u"bigger than required max length.");
+ log::TagWarn(
+ log_tag,
+ u"(Measure) Vertical length of padding, border and margin is "
+ u"bigger than required max length.");
coerced_space_size.height = max_height;
}
content_requirement.max.height = max_height - coerced_space_size.height;
@@ -235,7 +239,7 @@ void BorderRenderObject::RecreateGeometry() {
r.left_bottom - Point{t.left, t.bottom},
r.right_bottom - Point{t.right, t.bottom});
- auto f = [](platform::graph::IGeometryBuilder* builder, const Rect& rect,
+ auto f = [](platform::graphics::IGeometryBuilder* builder, const Rect& rect,
const CornerRadius& corner) {
builder->BeginFigure(Point(rect.left + corner.left_top.x, rect.top));
builder->LineTo(Point(rect.GetRight() - corner.right_top.x, rect.top));
@@ -263,7 +267,7 @@ void BorderRenderObject::RecreateGeometry() {
size.width - margin.GetHorizontalTotal(),
size.height - margin.GetVerticalTotal()};
const auto graph_factory = GetGraphFactory();
- std::unique_ptr<platform::graph::IGeometryBuilder> builder{
+ std::unique_ptr<platform::graphics::IGeometryBuilder> builder{
graph_factory->CreateGeometryBuilder()};
f(builder.get(), outer_rect, outer_radius);
border_outer_geometry_ = builder->Build();
diff --git a/src/ui/render/CanvasRenderObject.cpp b/src/ui/render/CanvasRenderObject.cpp
index 967fdcec..bf1155e1 100644
--- a/src/ui/render/CanvasRenderObject.cpp
+++ b/src/ui/render/CanvasRenderObject.cpp
@@ -10,7 +10,7 @@ RenderObject* CanvasRenderObject::HitTest(const Point& point) {
return padding_rect.IsPointInside(point) ? this : nullptr;
}
-void CanvasRenderObject::OnDrawContent(platform::graph::IPainter* painter) {
+void CanvasRenderObject::OnDrawContent(platform::graphics::IPainter* painter) {
const auto rect = GetContentRect();
CanvasPaintEventArgs args{painter, rect.GetSize()};
paint_event_.Raise(args);
diff --git a/src/ui/render/FlexLayoutRenderObject.cpp b/src/ui/render/FlexLayoutRenderObject.cpp
index ade230b5..b1ef69ee 100644
--- a/src/ui/render/FlexLayoutRenderObject.cpp
+++ b/src/ui/render/FlexLayoutRenderObject.cpp
@@ -1,7 +1,7 @@
#include "cru/ui/render/FlexLayoutRenderObject.hpp"
#include "cru/common/Logger.hpp"
-#include "cru/platform/graph/util/Painter.hpp"
+#include "cru/platform/graphics/util/Painter.hpp"
#include "cru/ui/render/LayoutHelper.hpp"
#include <algorithm>
@@ -10,6 +10,10 @@
namespace cru::ui::render {
+std::u16string_view FlexLayoutRenderObject::GetName() const {
+ return u"FlexLayoutRenderObject";
+}
+
struct tag_horizontal_t {};
struct tag_vertical_t {};
@@ -64,7 +68,7 @@ template <typename TSize>
constexpr TSize CreateTSize(decltype(std::declval<TSize>().width) main,
decltype(std::declval<TSize>().height) cross,
tag_vertical_t) {
- return TSize{main, cross};
+ return TSize{cross, main};
}
enum class FlexLayoutAdjustType { None, Expand, Shrink };
@@ -387,10 +391,11 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
const auto cross_align =
GetChildLayoutDataList()[i].cross_alignment.value_or(
GetItemCrossAlign());
- child->Layout(
- Point{content_rect.top + current_main_offset,
- CalculateAnchorByAlignment(cross_align, content_rect.left,
- content_rect.width, size.width)});
+ child->Layout(Point{
+ CalculateAnchorByAlignment(cross_align, content_rect.left,
+ content_rect.width, size.width),
+ content_rect.top + current_main_offset,
+ });
current_main_offset += size.height;
}
} else {
@@ -402,9 +407,9 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
GetChildLayoutDataList()[i].cross_alignment.value_or(
GetItemCrossAlign());
child->Layout(
- Point{content_rect.GetBottom() - current_main_offset,
- CalculateAnchorByAlignment(cross_align, content_rect.left,
- content_rect.width, size.width)});
+ Point{CalculateAnchorByAlignment(cross_align, content_rect.left,
+ content_rect.width, size.width),
+ content_rect.GetBottom() - current_main_offset});
current_main_offset += size.height;
}
}
diff --git a/src/ui/render/RenderObject.cpp b/src/ui/render/RenderObject.cpp
index 30433868..7cf750cd 100644
--- a/src/ui/render/RenderObject.cpp
+++ b/src/ui/render/RenderObject.cpp
@@ -1,12 +1,21 @@
#include "cru/ui/render/RenderObject.hpp"
#include "cru/common/Logger.hpp"
-#include "cru/platform/graph/util/Painter.hpp"
-#include "cru/ui/UiHost.hpp"
+#include "cru/platform/graphics/util/Painter.hpp"
+#include "cru/ui/DebugFlags.hpp"
+#include "cru/ui/host/WindowHost.hpp"
#include <algorithm>
+#include <string>
+#include <string_view>
+#include <vector>
namespace cru::ui::render {
+void RenderObject::SetAttachedControl(controls::Control* new_control) {
+ control_ = new_control;
+ OnAttachedControlChanged(new_control);
+}
+
void RenderObject::AddChild(RenderObject* render_object, const Index position) {
Expects(child_mode_ != ChildMode::None);
Expects(!(child_mode_ == ChildMode::Single && children_.size() > 0));
@@ -20,7 +29,7 @@ void RenderObject::AddChild(RenderObject* render_object, const Index position) {
children_.insert(children_.cbegin() + position, render_object);
render_object->SetParent(this);
- render_object->SetRenderHostRecursive(GetUiHost());
+ render_object->SetWindowHostRecursive(GetWindowHost());
OnAddChild(render_object, position);
}
@@ -33,10 +42,25 @@ void RenderObject::RemoveChild(const Index position) {
const auto removed_child = *i;
children_.erase(i);
removed_child->SetParent(nullptr);
- removed_child->SetRenderHostRecursive(nullptr);
+ removed_child->SetWindowHostRecursive(nullptr);
OnRemoveChild(removed_child, position);
}
+RenderObject* RenderObject::GetFirstChild() const {
+ const auto& children = GetChildren();
+ if (children.empty()) {
+ return nullptr;
+ } else {
+ return children.front();
+ }
+}
+
+void RenderObject::TraverseDescendants(
+ const std::function<void(RenderObject*)>& action) {
+ action(this);
+ for (auto child : children_) child->TraverseDescendants(action);
+}
+
Point RenderObject::GetTotalOffset() const {
Point result{};
const RenderObject* render_object = this;
@@ -66,18 +90,34 @@ void RenderObject::Measure(const MeasureRequirement& requirement,
MeasureSize merged_preferred_size =
preferred_size.OverrideBy(preferred_size_);
+ if constexpr (cru::ui::debug_flags::layout) {
+ log::Debug(u"{} Measure begins :\nrequirement: {}\npreferred size: {}",
+ this->GetDebugPathInTree(), requirement.ToDebugString(),
+ preferred_size.ToDebugString());
+ }
+
size_ = OnMeasureCore(merged_requirement, merged_preferred_size);
+
+ if constexpr (cru::ui::debug_flags::layout) {
+ log::Debug(u"{} Measure ends :\nresult size: {}",
+ this->GetDebugPathInTree(), size_.ToDebugString());
+ }
+
Ensures(size_.width >= 0);
Ensures(size_.height >= 0);
Ensures(requirement.Satisfy(size_));
}
void RenderObject::Layout(const Point& offset) {
+ if constexpr (cru::ui::debug_flags::layout) {
+ log::Debug(u"{} Layout :\noffset: {}", this->GetDebugPathInTree(),
+ offset.ToDebugString());
+ }
offset_ = offset;
OnLayoutCore();
}
-void RenderObject::Draw(platform::graph::IPainter* painter) {
+void RenderObject::Draw(platform::graphics::IPainter* painter) {
OnDrawCore(painter);
}
@@ -112,29 +152,29 @@ void RenderObject::OnRemoveChild(RenderObject* removed_child, Index position) {
InvalidatePaint();
}
-void RenderObject::DefaultDrawChildren(platform::graph::IPainter* painter) {
+void RenderObject::DefaultDrawChildren(platform::graphics::IPainter* painter) {
for (const auto child : GetChildren()) {
auto offset = child->GetOffset();
- platform::graph::util::WithTransform(
+ platform::graphics::util::WithTransform(
painter, platform::Matrix::Translation(offset.x, offset.y),
[child](auto p) { child->Draw(p); });
}
}
-void RenderObject::DefaultDrawContent(platform::graph::IPainter* painter) {
+void RenderObject::DefaultDrawContent(platform::graphics::IPainter* painter) {
const auto content_rect = GetContentRect();
- platform::graph::util::WithTransform(
+ platform::graphics::util::WithTransform(
painter, Matrix::Translation(content_rect.left, content_rect.top),
[this](auto p) { this->OnDrawContent(p); });
}
-void RenderObject::OnDrawCore(platform::graph::IPainter* painter) {
+void RenderObject::OnDrawCore(platform::graphics::IPainter* painter) {
DefaultDrawContent(painter);
DefaultDrawChildren(painter);
}
-void RenderObject::OnDrawContent(platform::graph::IPainter* painter) {
+void RenderObject::OnDrawContent(platform::graphics::IPainter* painter) {
CRU_UNUSED(painter);
}
@@ -249,24 +289,44 @@ void RenderObject::SetParent(RenderObject* new_parent) {
}
void RenderObject::InvalidateLayout() {
- if (ui_host_ != nullptr) ui_host_->InvalidateLayout();
+ if (window_host_ != nullptr) window_host_->InvalidateLayout();
}
void RenderObject::InvalidatePaint() {
- if (ui_host_ != nullptr) ui_host_->InvalidatePaint();
+ if (window_host_ != nullptr) window_host_->InvalidatePaint();
}
-void RenderObject::NotifyAfterLayoutRecursive(RenderObject* render_object) {
- render_object->OnAfterLayout();
- for (const auto o : render_object->GetChildren()) {
- NotifyAfterLayoutRecursive(o);
+constexpr std::u16string_view kUnamedName(u"UNNAMED");
+
+std::u16string_view RenderObject::GetName() const { return kUnamedName; }
+
+std::u16string RenderObject::GetDebugPathInTree() const {
+ std::vector<std::u16string_view> chain;
+ const RenderObject* parent = this;
+ while (parent != nullptr) {
+ chain.push_back(parent->GetName());
+ parent = parent->GetParent();
}
+
+ std::u16string result(chain.back());
+ for (auto iter = chain.crbegin() + 1; iter != chain.crend(); ++iter) {
+ result += u" -> ";
+ result += *iter;
+ }
+
+ return result;
}
-void RenderObject::SetRenderHostRecursive(UiHost* host) {
- ui_host_ = host;
+void RenderObject::SetWindowHostRecursive(host::WindowHost* host) {
+ if (window_host_ != nullptr) {
+ detach_from_host_event_.Raise(nullptr);
+ }
+ window_host_ = host;
+ if (host != nullptr) {
+ attach_to_host_event_.Raise(nullptr);
+ }
for (const auto child : GetChildren()) {
- child->SetRenderHostRecursive(host);
+ child->SetWindowHostRecursive(host);
}
}
} // namespace cru::ui::render
diff --git a/src/ui/render/ScrollBar.cpp b/src/ui/render/ScrollBar.cpp
new file mode 100644
index 00000000..7f69c1e2
--- /dev/null
+++ b/src/ui/render/ScrollBar.cpp
@@ -0,0 +1,622 @@
+#include "cru/ui/render/ScrollBar.hpp"
+
+#include "../Helper.hpp"
+#include "cru/common/Base.hpp"
+#include "cru/platform/GraphBase.hpp"
+#include "cru/platform/graphics/Factory.hpp"
+#include "cru/platform/graphics/Geometry.hpp"
+#include "cru/platform/graphics/Painter.hpp"
+#include "cru/platform/graphics/util/Painter.hpp"
+#include "cru/platform/gui/Base.hpp"
+#include "cru/platform/gui/Cursor.hpp"
+#include "cru/ui/Base.hpp"
+#include "cru/ui/events/UiEvent.hpp"
+#include "cru/ui/render/ScrollRenderObject.hpp"
+#include "gsl/gsl_assert"
+
+#include <algorithm>
+#include <cassert>
+#include <chrono>
+#include <gsl/pointers>
+#include <memory>
+#include <optional>
+#include <stdexcept>
+
+namespace cru::ui::render {
+using namespace std::chrono_literals;
+constexpr float kScrollBarCollapseThumbWidth = 2;
+constexpr float kScrollBarCollapsedTriggerExpandAreaWidth = 5;
+constexpr float kScrollBarExpandWidth = 10;
+constexpr float kScrollBarArrowHeight = 3.5;
+constexpr auto kScrollBarAutoCollapseDelay = 1500ms;
+
+constexpr std::array<ScrollBarAreaKind, 5> kScrollBarAreaKindList{
+ ScrollBarAreaKind::UpArrow, ScrollBarAreaKind::DownArrow,
+ ScrollBarAreaKind::UpSlot, ScrollBarAreaKind::DownSlot,
+ ScrollBarAreaKind::Thumb};
+
+namespace {
+std::unique_ptr<platform::graphics::IGeometry> CreateScrollBarArrowGeometry() {
+ auto geometry_builder = GetGraphFactory()->CreateGeometryBuilder();
+ geometry_builder->BeginFigure({-kScrollBarArrowHeight / 2, 0});
+ geometry_builder->LineTo({kScrollBarArrowHeight / 2, kScrollBarArrowHeight});
+ geometry_builder->LineTo({kScrollBarArrowHeight / 2, -kScrollBarArrowHeight});
+ geometry_builder->CloseFigure(true);
+ return geometry_builder->Build();
+}
+} // namespace
+
+ScrollBar::ScrollBar(gsl::not_null<ScrollRenderObject*> render_object,
+ Direction direction)
+ : render_object_(render_object), direction_(direction) {
+ // TODO: Use theme resource and delete this.
+
+ auto graphics_factory = GetUiApplication()->GetInstance()->GetGraphFactory();
+
+ collapsed_thumb_brush_ =
+ graphics_factory->CreateSolidColorBrush(colors::gray.WithAlpha(128));
+ expanded_thumb_brush_ = graphics_factory->CreateSolidColorBrush(colors::gray);
+ expanded_slot_brush_ =
+ graphics_factory->CreateSolidColorBrush(colors::seashell);
+ expanded_arrow_brush_ = graphics_factory->CreateSolidColorBrush(colors::gray);
+ expanded_arrow_background_brush_ =
+ graphics_factory->CreateSolidColorBrush(colors::seashell);
+
+ arrow_geometry_ = CreateScrollBarArrowGeometry();
+}
+
+ScrollBar::~ScrollBar() { RestoreCursor(); }
+
+void ScrollBar::SetEnabled(bool value) {
+ if (value == is_enabled_) return;
+ if (!value) {
+ SetExpanded(false);
+ if (move_thumb_start_) {
+ if (const auto control = this->render_object_->GetAttachedControl()) {
+ control->ReleaseMouse();
+ }
+ move_thumb_start_ = std::nullopt;
+ }
+ }
+}
+
+void ScrollBar::SetExpanded(bool value) {
+ if (is_expanded_ == value) return;
+ is_expanded_ = value;
+ render_object_->InvalidatePaint();
+}
+
+void ScrollBar::Draw(platform::graphics::IPainter* painter) {
+ if (is_enabled_) {
+ OnDraw(painter, is_expanded_);
+ }
+}
+
+void ScrollBar::InstallHandlers(controls::Control* control) {
+ event_guard_.Clear();
+ if (control != nullptr) {
+ event_guard_ +=
+ control->MouseDownEvent()->Bubble()->PrependShortCircuitHandler(
+ [control, this](event::MouseButtonEventArgs& event) {
+ if (event.GetButton() == mouse_buttons::left && IsEnabled() &&
+ IsExpanded()) {
+ auto hit_test_result =
+ ExpandedHitTest(event.GetPoint(render_object_));
+ if (!hit_test_result) return false;
+
+ switch (*hit_test_result) {
+ case ScrollBarAreaKind::UpArrow:
+ this->scroll_attempt_event_.Raise(
+ {GetDirection(), ScrollKind::Line, -1});
+ event.SetHandled();
+ return true;
+ case ScrollBarAreaKind::DownArrow:
+ this->scroll_attempt_event_.Raise(
+ {GetDirection(), ScrollKind::Line, 1});
+ event.SetHandled();
+ return true;
+ case ScrollBarAreaKind::UpSlot:
+ this->scroll_attempt_event_.Raise(
+ {GetDirection(), ScrollKind::Page, -1});
+ event.SetHandled();
+ return true;
+ case ScrollBarAreaKind::DownSlot:
+ this->scroll_attempt_event_.Raise(
+ {GetDirection(), ScrollKind::Page, 1});
+ event.SetHandled();
+ return true;
+ case ScrollBarAreaKind::Thumb: {
+ auto thumb_rect =
+ GetExpandedAreaRect(ScrollBarAreaKind::Thumb);
+ assert(thumb_rect);
+
+ if (!control->CaptureMouse()) break;
+ move_thumb_thumb_original_rect_ = *thumb_rect;
+ move_thumb_start_ = event.GetPoint();
+ event.SetHandled();
+ return true;
+ }
+ default:
+ break;
+ }
+ }
+
+ return false;
+ });
+
+ event_guard_ +=
+ control->MouseUpEvent()->Bubble()->PrependShortCircuitHandler(
+ [control, this](event::MouseButtonEventArgs& event) {
+ if (event.GetButton() == mouse_buttons::left &&
+ move_thumb_start_) {
+ move_thumb_start_ = std::nullopt;
+
+ auto hit_test_result =
+ ExpandedHitTest(event.GetPoint(this->render_object_));
+ if (!hit_test_result) {
+ OnMouseLeave();
+ }
+
+ control->ReleaseMouse();
+ event.SetHandled();
+ return true;
+ }
+ return false;
+ });
+
+ event_guard_ +=
+ control->MouseMoveEvent()->Bubble()->PrependShortCircuitHandler(
+ [this](event::MouseEventArgs& event) {
+ if (move_thumb_start_) {
+ auto new_scroll_position = CalculateNewScrollPosition(
+ move_thumb_thumb_original_rect_,
+ event.GetPoint() - *move_thumb_start_);
+
+ this->scroll_attempt_event_.Raise({GetDirection(),
+ ScrollKind::Absolute,
+ new_scroll_position});
+ event.SetHandled();
+ return true;
+ }
+
+ if (IsEnabled()) {
+ if (IsExpanded()) {
+ auto hit_test_result =
+ ExpandedHitTest(event.GetPoint(this->render_object_));
+ if (hit_test_result) {
+ SetCursor();
+ StopAutoCollapseTimer();
+ } else {
+ OnMouseLeave();
+ }
+ } else {
+ auto trigger_expand_area =
+ GetCollapsedTriggerExpandAreaRect();
+ if (trigger_expand_area &&
+ trigger_expand_area->IsPointInside(
+ event.GetPoint(this->render_object_))) {
+ SetExpanded(true);
+ SetCursor();
+ event.SetHandled();
+ return true;
+ }
+ }
+ }
+
+ return false;
+ });
+
+ event_guard_ +=
+ control->MouseLeaveEvent()->Bubble()->PrependShortCircuitHandler(
+ [this](event::MouseEventArgs&) {
+ if (IsExpanded() && !move_thumb_start_) {
+ OnMouseLeave();
+ }
+ return false;
+ });
+ }
+}
+
+gsl::not_null<std::shared_ptr<platform::graphics::IBrush>>
+ScrollBar::GetCollapsedThumbBrush() const {
+ // TODO: Read theme resource.
+ return collapsed_thumb_brush_;
+}
+
+gsl::not_null<std::shared_ptr<platform::graphics::IBrush>>
+ScrollBar::GetExpandedThumbBrush() const {
+ // TODO: Read theme resource.
+ return expanded_thumb_brush_;
+}
+
+gsl::not_null<std::shared_ptr<platform::graphics::IBrush>>
+ScrollBar::GetExpandedSlotBrush() const {
+ // TODO: Read theme resource.
+ return expanded_slot_brush_;
+}
+
+gsl::not_null<std::shared_ptr<platform::graphics::IBrush>>
+ScrollBar::GetExpandedArrowBrush() const {
+ // TODO: Read theme resource.
+ return expanded_arrow_brush_;
+}
+
+gsl::not_null<std::shared_ptr<platform::graphics::IBrush>>
+ScrollBar::GetExpandedArrowBackgroundBrush() const {
+ // TODO: Read theme resource.
+ return expanded_arrow_background_brush_;
+}
+
+void ScrollBar::OnDraw(platform::graphics::IPainter* painter,
+ bool is_expanded) {
+ if (is_expanded) {
+ auto thumb_rect = GetExpandedAreaRect(ScrollBarAreaKind::Thumb);
+ if (thumb_rect)
+ painter->FillRectangle(*thumb_rect, GetExpandedThumbBrush().get().get());
+
+ auto slot_brush = GetExpandedSlotBrush().get().get();
+
+ auto up_slot_rect = GetExpandedAreaRect(ScrollBarAreaKind::UpSlot);
+ if (up_slot_rect) painter->FillRectangle(*up_slot_rect, slot_brush);
+
+ auto down_slot_rect = GetExpandedAreaRect(ScrollBarAreaKind::DownSlot);
+ if (down_slot_rect) painter->FillRectangle(*down_slot_rect, slot_brush);
+
+ auto up_arrow = GetExpandedAreaRect(ScrollBarAreaKind::UpArrow);
+ if (up_arrow) this->DrawUpArrow(painter, *up_arrow);
+
+ auto down_arrow = GetExpandedAreaRect(ScrollBarAreaKind::DownArrow);
+ if (down_arrow) this->DrawDownArrow(painter, *down_arrow);
+ } else {
+ auto optional_rect = GetCollapsedThumbRect();
+ if (optional_rect) {
+ painter->FillRectangle(*optional_rect,
+ GetCollapsedThumbBrush().get().get());
+ }
+ }
+}
+
+void ScrollBar::SetCursor() {
+ if (!old_cursor_) {
+ if (const auto control = render_object_->GetAttachedControl()) {
+ old_cursor_ = control->GetCursor();
+ control->SetCursor(
+ GetUiApplication()->GetCursorManager()->GetSystemCursor(
+ platform::gui::SystemCursorType::Arrow));
+ }
+ }
+}
+
+void ScrollBar::RestoreCursor() {
+ if (old_cursor_) {
+ if (const auto control = render_object_->GetAttachedControl()) {
+ control->SetCursor(*old_cursor_);
+ }
+ old_cursor_ = std::nullopt;
+ }
+}
+
+void ScrollBar::BeginAutoCollapseTimer() {
+ if (!auto_collapse_timer_canceler_ && IsExpanded()) {
+ auto_collapse_timer_canceler_ = GetUiApplication()->SetTimeout(
+ kScrollBarAutoCollapseDelay, [this] { this->SetExpanded(false); });
+ }
+}
+
+void ScrollBar::StopAutoCollapseTimer() {
+ auto_collapse_timer_canceler_.Reset();
+}
+
+void ScrollBar::OnMouseLeave() {
+ RestoreCursor();
+ BeginAutoCollapseTimer();
+}
+
+std::optional<ScrollBarAreaKind> ScrollBar::ExpandedHitTest(
+ const Point& point) {
+ for (auto kind : kScrollBarAreaKindList) {
+ auto rect = this->GetExpandedAreaRect(kind);
+ if (rect) {
+ if (rect->IsPointInside(point)) return kind;
+ }
+ }
+ return std::nullopt;
+}
+
+HorizontalScrollBar::HorizontalScrollBar(
+ gsl::not_null<ScrollRenderObject*> render_object)
+ : ScrollBar(render_object, Direction::Horizontal) {}
+
+void HorizontalScrollBar::DrawUpArrow(platform::graphics::IPainter* painter,
+ const Rect& area) {
+ painter->FillRectangle(area, GetExpandedArrowBackgroundBrush().get().get());
+
+ platform::graphics::util::WithTransform(
+ painter, Matrix::Translation(area.GetCenter()),
+ [this](platform::graphics::IPainter* painter) {
+ painter->FillGeometry(arrow_geometry_.get(),
+ GetExpandedArrowBrush().get().get());
+ });
+}
+
+void HorizontalScrollBar::DrawDownArrow(platform::graphics::IPainter* painter,
+ const Rect& area) {
+ painter->FillRectangle(area, GetExpandedArrowBackgroundBrush().get().get());
+
+ platform::graphics::util::WithTransform(
+ painter, Matrix::Rotation(180) * Matrix::Translation(area.GetCenter()),
+ [this](platform::graphics::IPainter* painter) {
+ painter->FillGeometry(arrow_geometry_.get(),
+ GetExpandedArrowBrush().get().get());
+ });
+}
+
+bool HorizontalScrollBar::IsShowBar() {
+ const auto child = render_object_->GetFirstChild();
+ if (child == nullptr) return false;
+
+ const auto view_rect = render_object_->GetViewRect();
+ const auto child_size = child->GetSize();
+
+ if (view_rect.width >= child_size.width) return false;
+
+ return true;
+}
+
+std::optional<Rect> HorizontalScrollBar::GetExpandedAreaRect(
+ ScrollBarAreaKind area_kind) {
+ auto show = IsShowBar();
+ if (!show) return std::nullopt;
+
+ const auto padding_rect = render_object_->GetPaddingRect();
+
+ const auto child = render_object_->GetFirstChild();
+
+ const auto view_rect = render_object_->GetViewRect();
+ const auto child_size = child->GetSize();
+
+ const float start_percentage = view_rect.left / child_size.width;
+ const float length_percentage = view_rect.width / child_size.width;
+ const float end_percentage = start_percentage + length_percentage;
+
+ const float top = padding_rect.GetBottom() - kScrollBarExpandWidth;
+ const float height = kScrollBarExpandWidth;
+
+ // Without arrow.
+ const float bar_area_length = padding_rect.width - 3 * kScrollBarExpandWidth;
+ const float bar_area_start = padding_rect.left + kScrollBarExpandWidth;
+
+ switch (area_kind) {
+ case ScrollBarAreaKind::UpArrow:
+ return Rect{padding_rect.left, top, kScrollBarExpandWidth, height};
+ case ScrollBarAreaKind::DownArrow:
+ return Rect{padding_rect.GetRight() - 2 * kScrollBarExpandWidth, top,
+ kScrollBarExpandWidth, height};
+ case ScrollBarAreaKind::UpSlot:
+ return Rect{bar_area_start, top, bar_area_length * start_percentage,
+ height};
+ case ScrollBarAreaKind::DownSlot:
+ return Rect{bar_area_start + bar_area_length * end_percentage, top,
+ bar_area_length * (1 - end_percentage), height};
+ case ScrollBarAreaKind::Thumb:
+ return Rect{bar_area_start + bar_area_length * start_percentage, top,
+ bar_area_length * length_percentage, height};
+ default:
+ throw std::invalid_argument("Unsupported scroll area kind.");
+ }
+}
+
+std::optional<Rect> HorizontalScrollBar::GetCollapsedTriggerExpandAreaRect() {
+ auto show = IsShowBar();
+ if (!show) return std::nullopt;
+
+ const auto padding_rect = render_object_->GetPaddingRect();
+
+ return Rect{
+ padding_rect.left,
+ padding_rect.GetBottom() - kScrollBarCollapsedTriggerExpandAreaWidth,
+ padding_rect.width, kScrollBarCollapseThumbWidth};
+}
+
+std::optional<Rect> HorizontalScrollBar::GetCollapsedThumbRect() {
+ auto show = IsShowBar();
+ if (!show) return std::nullopt;
+
+ const auto child = render_object_->GetFirstChild();
+
+ const auto view_rect = render_object_->GetViewRect();
+ const auto child_size = child->GetSize();
+
+ const float start_percentage = view_rect.left / child_size.width;
+ const float length_percentage = view_rect.width / child_size.width;
+ // const float end_percentage = start_percentage + length_percentage;
+
+ const auto padding_rect = render_object_->GetPaddingRect();
+
+ return Rect{padding_rect.left + padding_rect.width * start_percentage,
+ padding_rect.GetBottom() - kScrollBarCollapseThumbWidth,
+ padding_rect.width * length_percentage,
+ kScrollBarCollapseThumbWidth};
+}
+
+float HorizontalScrollBar::CalculateNewScrollPosition(
+ const Rect& thumb_original_rect, const Point& mouse_offset) {
+ auto new_thumb_start = thumb_original_rect.left + mouse_offset.x;
+
+ const auto padding_rect = render_object_->GetPaddingRect();
+
+ auto scroll_area_start = padding_rect.left + kScrollBarExpandWidth;
+ auto scroll_area_end = padding_rect.GetRight() - 2 * kScrollBarExpandWidth;
+
+ auto thumb_head_end = scroll_area_end - thumb_original_rect.width;
+
+ const auto child = render_object_->GetFirstChild();
+ const auto child_size = child->GetSize();
+
+ new_thumb_start =
+ std::clamp(new_thumb_start, scroll_area_start, thumb_head_end);
+
+ auto offset = (new_thumb_start - scroll_area_start) /
+ (scroll_area_end - scroll_area_start) * child_size.width;
+
+ return offset;
+}
+
+VerticalScrollBar::VerticalScrollBar(
+ gsl::not_null<ScrollRenderObject*> render_object)
+ : ScrollBar(render_object, Direction::Vertical) {}
+
+void VerticalScrollBar::DrawUpArrow(platform::graphics::IPainter* painter,
+ const Rect& area) {
+ painter->FillRectangle(area, GetExpandedArrowBackgroundBrush().get().get());
+
+ platform::graphics::util::WithTransform(
+ painter, Matrix::Rotation(90) * Matrix::Translation(area.GetCenter()),
+ [this](platform::graphics::IPainter* painter) {
+ painter->FillGeometry(arrow_geometry_.get(),
+ GetExpandedArrowBrush().get().get());
+ });
+}
+
+void VerticalScrollBar::DrawDownArrow(platform::graphics::IPainter* painter,
+ const Rect& area) {
+ painter->FillRectangle(area, GetExpandedArrowBackgroundBrush().get().get());
+
+ platform::graphics::util::WithTransform(
+ painter, Matrix::Rotation(270) * Matrix::Translation(area.GetCenter()),
+ [this](platform::graphics::IPainter* painter) {
+ painter->FillGeometry(arrow_geometry_.get(),
+ GetExpandedArrowBrush().get().get());
+ });
+}
+
+bool VerticalScrollBar::IsShowBar() {
+ const auto child = render_object_->GetFirstChild();
+ if (child == nullptr) return false;
+
+ const auto view_rect = render_object_->GetViewRect();
+ const auto child_size = child->GetSize();
+
+ if (view_rect.height >= child_size.height) return false;
+
+ return true;
+}
+
+std::optional<Rect> VerticalScrollBar::GetExpandedAreaRect(
+ ScrollBarAreaKind area_kind) {
+ auto show = IsShowBar();
+ if (!show) return std::nullopt;
+
+ const auto padding_rect = render_object_->GetPaddingRect();
+
+ const auto child = render_object_->GetFirstChild();
+
+ const auto view_rect = render_object_->GetViewRect();
+ const auto child_size = child->GetSize();
+
+ const float start_percentage = view_rect.top / child_size.height;
+ const float length_percentage = view_rect.height / child_size.height;
+ const float end_percentage = start_percentage + length_percentage;
+
+ const float left = padding_rect.GetRight() - kScrollBarExpandWidth;
+ const float width = kScrollBarExpandWidth;
+
+ // Without arrow.
+ const float bar_area_length = padding_rect.height - 3 * kScrollBarExpandWidth;
+ const float bar_area_start = padding_rect.top + kScrollBarExpandWidth;
+
+ switch (area_kind) {
+ case ScrollBarAreaKind::UpArrow:
+ return Rect{left, padding_rect.top, width, kScrollBarExpandWidth};
+ case ScrollBarAreaKind::DownArrow:
+ return Rect{left, padding_rect.GetBottom() - 2 * kScrollBarExpandWidth,
+ width, kScrollBarExpandWidth};
+ case ScrollBarAreaKind::UpSlot:
+ return Rect{left, bar_area_start, width,
+ bar_area_length * start_percentage};
+ case ScrollBarAreaKind::DownSlot:
+ return Rect{left, bar_area_start + bar_area_length * end_percentage,
+ width, bar_area_length * (1 - end_percentage)};
+ case ScrollBarAreaKind::Thumb:
+ return Rect{left, bar_area_start + bar_area_length * start_percentage,
+ width, bar_area_length * length_percentage};
+ default:
+ throw std::invalid_argument("Unsupported scroll area kind.");
+ }
+}
+
+std::optional<Rect> VerticalScrollBar::GetCollapsedTriggerExpandAreaRect() {
+ auto show = IsShowBar();
+ if (!show) return std::nullopt;
+
+ const auto padding_rect = render_object_->GetPaddingRect();
+
+ return Rect{
+ padding_rect.GetRight() - kScrollBarCollapsedTriggerExpandAreaWidth,
+ padding_rect.top, kScrollBarCollapseThumbWidth, padding_rect.height};
+}
+
+std::optional<Rect> VerticalScrollBar::GetCollapsedThumbRect() {
+ const auto child = render_object_->GetFirstChild();
+ if (child == nullptr) return std::nullopt;
+
+ const auto view_rect = render_object_->GetViewRect();
+ const auto padding_rect = render_object_->GetPaddingRect();
+ const auto child_size = child->GetSize();
+
+ if (view_rect.height >= child_size.height) return std::nullopt;
+
+ const float start_percentage = view_rect.top / child_size.height;
+ const float length_percentage = view_rect.height / child_size.height;
+ // const float end_percentage = start_percentage + length_percentage;
+
+ return Rect{padding_rect.GetRight() - kScrollBarCollapseThumbWidth,
+ padding_rect.top + padding_rect.height * start_percentage,
+ kScrollBarCollapseThumbWidth,
+ padding_rect.height * length_percentage};
+}
+
+float VerticalScrollBar::CalculateNewScrollPosition(
+ const Rect& thumb_original_rect, const Point& mouse_offset) {
+ auto new_thumb_start = thumb_original_rect.top + mouse_offset.y;
+
+ const auto padding_rect = render_object_->GetPaddingRect();
+
+ auto scroll_area_start = padding_rect.top + kScrollBarExpandWidth;
+ auto scroll_area_end = padding_rect.GetBottom() - 2 * kScrollBarExpandWidth;
+
+ auto thumb_head_end = scroll_area_end - thumb_original_rect.height;
+
+ const auto child = render_object_->GetFirstChild();
+ const auto child_size = child->GetSize();
+
+ new_thumb_start =
+ std::clamp(new_thumb_start, scroll_area_start, thumb_head_end);
+
+ auto offset = (new_thumb_start - scroll_area_start) /
+ (scroll_area_end - scroll_area_start) * child_size.width;
+
+ return offset;
+}
+
+ScrollBarDelegate::ScrollBarDelegate(
+ gsl::not_null<ScrollRenderObject*> render_object)
+ : render_object_(render_object),
+ horizontal_bar_(render_object),
+ vertical_bar_(render_object) {
+ horizontal_bar_.ScrollAttemptEvent()->AddHandler(
+ [this](auto scroll) { this->scroll_attempt_event_.Raise(scroll); });
+ vertical_bar_.ScrollAttemptEvent()->AddHandler(
+ [this](auto scroll) { this->scroll_attempt_event_.Raise(scroll); });
+}
+
+void ScrollBarDelegate::DrawScrollBar(platform::graphics::IPainter* painter) {
+ horizontal_bar_.Draw(painter);
+ vertical_bar_.Draw(painter);
+}
+
+void ScrollBarDelegate::InstallHandlers(controls::Control* control) {
+ horizontal_bar_.InstallHandlers(control);
+ vertical_bar_.InstallHandlers(control);
+}
+} // namespace cru::ui::render
diff --git a/src/ui/render/ScrollRenderObject.cpp b/src/ui/render/ScrollRenderObject.cpp
index 08ce744b..fd5143ff 100644
--- a/src/ui/render/ScrollRenderObject.cpp
+++ b/src/ui/render/ScrollRenderObject.cpp
@@ -1,11 +1,18 @@
#include "cru/ui/render/ScrollRenderObject.hpp"
-#include "cru/platform/graph/Painter.hpp"
-#include "cru/platform/graph/util/Painter.hpp"
+#include "cru/platform/graphics/Painter.hpp"
+#include "cru/platform/graphics/util/Painter.hpp"
+#include "cru/ui/Base.hpp"
+#include "cru/ui/controls/Control.hpp"
+#include "cru/ui/render/ScrollBar.hpp"
#include <algorithm>
+#include <memory>
+#include <optional>
namespace cru::ui::render {
+constexpr float kLineHeight = 16;
+
namespace {
// This method assumes margin offset is already considered.
// It promises that it won't return negetive value.
@@ -24,13 +31,46 @@ Point CoerceScroll(const Point& scroll_offset, const Size& content_size,
n = max;
};
- coerce(result.x, scroll_offset.x);
- coerce(result.y, scroll_offset.y);
+ coerce(result.x, max_scroll.x);
+ coerce(result.y, max_scroll.y);
return result;
}
} // namespace
+ScrollRenderObject::ScrollRenderObject() : RenderObject(ChildMode::Single) {
+ scroll_bar_delegate_ = std::make_unique<ScrollBarDelegate>(this);
+ scroll_bar_delegate_->ScrollAttemptEvent()->AddHandler(
+ [this](const struct Scroll& scroll) { this->Scroll(scroll); });
+}
+
+void ScrollRenderObject::Scroll(const struct Scroll& scroll) {
+ auto direction = scroll.direction;
+
+ switch (scroll.kind) {
+ case ScrollKind::Absolute:
+ SetScrollOffset(direction, scroll.value);
+ break;
+ case ScrollKind::Relative:
+ SetScrollOffset(direction,
+ GetScrollOffset(scroll.direction) + scroll.value);
+ break;
+ case ScrollKind::Page:
+ SetScrollOffset(direction, GetScrollOffset(direction) +
+ (direction == Direction::Horizontal
+ ? GetViewRect().width
+ : GetViewRect().height) *
+ scroll.value);
+ break;
+ case ScrollKind::Line:
+ SetScrollOffset(direction,
+ GetScrollOffset(direction) + kLineHeight * scroll.value);
+ break;
+ default:
+ break;
+ }
+}
+
RenderObject* ScrollRenderObject::HitTest(const Point& point) {
if (const auto child = GetSingleChild()) {
const auto offset = child->GetOffset();
@@ -42,16 +82,17 @@ RenderObject* ScrollRenderObject::HitTest(const Point& point) {
return rect.IsPointInside(point) ? this : nullptr;
} // namespace cru::ui::render
-void ScrollRenderObject::OnDrawCore(platform::graph::IPainter* painter) {
+void ScrollRenderObject::OnDrawCore(platform::graphics::IPainter* painter) {
DefaultDrawContent(painter);
if (const auto child = GetSingleChild()) {
- painter->PushLayer(this->GetPaddingRect());
+ painter->PushLayer(this->GetContentRect());
const auto offset = child->GetOffset();
- platform::graph::util::WithTransform(
+ platform::graphics::util::WithTransform(
painter, Matrix::Translation(offset.x, offset.y),
- [child](platform::graph::IPainter* p) { child->Draw(p); });
+ [child](platform::graphics::IPainter* p) { child->Draw(p); });
painter->PopLayer();
}
+ scroll_bar_delegate_->DrawScrollBar(painter);
}
Point ScrollRenderObject::GetScrollOffset() {
@@ -138,8 +179,15 @@ Size ScrollRenderObject::OnMeasureContent(const MeasureRequirement& requirement,
void ScrollRenderObject::OnLayoutContent(const Rect& content_rect) {
if (const auto child = GetSingleChild()) {
- const auto child_size = child->GetSize();
child->Layout(content_rect.GetLeftTop() - GetScrollOffset());
}
}
+
+void ScrollRenderObject::OnAttachedControlChanged(controls::Control* control) {
+ if (control) {
+ scroll_bar_delegate_->InstallHandlers(control);
+ } else {
+ scroll_bar_delegate_->UninstallHandlers();
+ }
+}
} // namespace cru::ui::render
diff --git a/src/ui/render/TextRenderObject.cpp b/src/ui/render/TextRenderObject.cpp
index cecbe1f3..06092d52 100644
--- a/src/ui/render/TextRenderObject.cpp
+++ b/src/ui/render/TextRenderObject.cpp
@@ -2,19 +2,19 @@
#include "../Helper.hpp"
#include "cru/common/Logger.hpp"
-#include "cru/platform/graph/Factory.hpp"
-#include "cru/platform/graph/TextLayout.hpp"
-#include "cru/platform/graph/util/Painter.hpp"
+#include "cru/platform/graphics/Factory.hpp"
+#include "cru/platform/graphics/TextLayout.hpp"
+#include "cru/platform/graphics/util/Painter.hpp"
#include <algorithm>
#include <limits>
namespace cru::ui::render {
TextRenderObject::TextRenderObject(
- std::shared_ptr<platform::graph::IBrush> brush,
- std::shared_ptr<platform::graph::IFont> font,
- std::shared_ptr<platform::graph::IBrush> selection_brush,
- std::shared_ptr<platform::graph::IBrush> caret_brush) {
+ std::shared_ptr<platform::graphics::IBrush> brush,
+ std::shared_ptr<platform::graphics::IFont> font,
+ std::shared_ptr<platform::graphics::IBrush> selection_brush,
+ std::shared_ptr<platform::graphics::IBrush> caret_brush) {
Expects(brush);
Expects(font);
Expects(selection_brush);
@@ -43,20 +43,22 @@ std::u16string_view TextRenderObject::GetTextView() const {
void TextRenderObject::SetText(std::u16string new_text) {
text_layout_->SetText(std::move(new_text));
+ InvalidateLayout();
}
void TextRenderObject::SetBrush(
- std::shared_ptr<platform::graph::IBrush> new_brush) {
+ std::shared_ptr<platform::graphics::IBrush> new_brush) {
Expects(new_brush);
new_brush.swap(brush_);
InvalidatePaint();
}
-std::shared_ptr<platform::graph::IFont> TextRenderObject::GetFont() const {
+std::shared_ptr<platform::graphics::IFont> TextRenderObject::GetFont() const {
return text_layout_->GetFont();
}
-void TextRenderObject::SetFont(std::shared_ptr<platform::graph::IFont> font) {
+void TextRenderObject::SetFont(
+ std::shared_ptr<platform::graphics::IFont> font) {
Expects(font);
text_layout_->SetFont(std::move(font));
}
@@ -69,7 +71,7 @@ Point TextRenderObject::TextSinglePoint(gsl::index position, bool trailing) {
return text_layout_->TextSinglePoint(position, trailing);
}
-platform::graph::TextHitTestResult TextRenderObject::TextHitTest(
+platform::graphics::TextHitTestResult TextRenderObject::TextHitTest(
const Point& point) {
return text_layout_->HitTest(point);
}
@@ -80,7 +82,7 @@ void TextRenderObject::SetSelectionRange(std::optional<TextRange> new_range) {
}
void TextRenderObject::SetSelectionBrush(
- std::shared_ptr<platform::graph::IBrush> new_brush) {
+ std::shared_ptr<platform::graphics::IBrush> new_brush) {
Expects(new_brush);
new_brush.swap(selection_brush_);
if (selection_range_ && selection_range_->count) {
@@ -105,7 +107,7 @@ void TextRenderObject::SetCaretPosition(gsl::index position) {
}
void TextRenderObject::GetCaretBrush(
- std::shared_ptr<platform::graph::IBrush> brush) {
+ std::shared_ptr<platform::graphics::IBrush> brush) {
Expects(brush);
brush.swap(caret_brush_);
if (draw_caret_) {
@@ -153,12 +155,18 @@ Rect TextRenderObject::GetCaretRect() {
return rect;
}
+void TextRenderObject::SetMeasureIncludingTrailingSpace(bool including) {
+ if (is_measure_including_trailing_space_ == including) return;
+ is_measure_including_trailing_space_ = including;
+ InvalidateLayout();
+}
+
RenderObject* TextRenderObject::HitTest(const Point& point) {
const auto padding_rect = GetPaddingRect();
return padding_rect.IsPointInside(point) ? this : nullptr;
}
-void TextRenderObject::OnDrawContent(platform::graph::IPainter* painter) {
+void TextRenderObject::OnDrawContent(platform::graphics::IPainter* painter) {
if (this->selection_range_.has_value()) {
const auto&& rects =
text_layout_->TextRangeRect(this->selection_range_.value());
@@ -184,7 +192,9 @@ Size TextRenderObject::OnMeasureContent(const MeasureRequirement& requirement,
text_layout_->SetMaxWidth(measure_width);
text_layout_->SetMaxHeight(std::numeric_limits<float>::max());
- const auto text_size = text_layout_->GetTextBounds().GetSize();
+ const auto text_size =
+ text_layout_->GetTextBounds(is_measure_including_trailing_space_)
+ .GetSize();
auto result = text_size;
if (requirement.max.width.IsSpecified() &&
diff --git a/src/ui/render/WindowRenderObject.cpp b/src/ui/render/WindowRenderObject.cpp
deleted file mode 100644
index 4adf559e..00000000
--- a/src/ui/render/WindowRenderObject.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "cru/ui/render/WindowRenderObject.hpp"
-
-#include "../Helper.hpp"
-#include "cru/platform/graph/util/Painter.hpp"
-#include "cru/ui/UiHost.hpp"
-
-namespace cru::ui::render {
-WindowRenderObject::WindowRenderObject(UiHost* host) {
- SetChildMode(ChildMode::Single);
- ui_host_ = host;
- after_layout_event_guard_.Reset(host->AfterLayoutEvent()->AddHandler(
- [this](auto) { NotifyAfterLayoutRecursive(this); }));
-}
-
-RenderObject* WindowRenderObject::HitTest(const Point& point) {
- if (const auto child = GetChild()) {
- auto offset = child->GetOffset();
- Point p{point.x - offset.x, point.y - offset.y};
- const auto result = child->HitTest(p);
- if (result != nullptr) {
- return result;
- }
- }
- return Rect{Point{}, GetSize()}.IsPointInside(point) ? this : nullptr;
-}
-
-Size WindowRenderObject::OnMeasureContent(const MeasureRequirement& requirement,
- const MeasureSize& preferred_size) {
- if (const auto child = GetChild()) {
- child->Measure(requirement, preferred_size);
- return child->GetSize();
- } else {
- return Size{};
- }
-}
-
-void WindowRenderObject::OnLayoutContent(const Rect& content_rect) {
- if (const auto child = GetChild()) child->Layout(content_rect.GetLeftTop());
-}
-} // namespace cru::ui::render