aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/ui/controls/TreeView.h40
-rw-r--r--include/cru/ui/render/BorderRenderObject.h24
-rw-r--r--include/cru/ui/render/CanvasRenderObject.h6
-rw-r--r--include/cru/ui/render/FlexLayoutRenderObject.h7
-rw-r--r--include/cru/ui/render/LayoutRenderObject.h95
-rw-r--r--include/cru/ui/render/RenderObject.h128
-rw-r--r--include/cru/ui/render/ScrollRenderObject.h14
-rw-r--r--include/cru/ui/render/StackLayoutRenderObject.h4
-rw-r--r--include/cru/ui/render/TextRenderObject.h8
-rw-r--r--include/cru/ui/render/TreeRenderObject.h13
-rw-r--r--src/ui/CMakeLists.txt1
-rw-r--r--src/ui/controls/TreeView.cpp0
-rw-r--r--src/ui/host/WindowHost.cpp7
-rw-r--r--src/ui/render/BorderRenderObject.cpp52
-rw-r--r--src/ui/render/CanvasRenderObject.cpp4
-rw-r--r--src/ui/render/FlexLayoutRenderObject.cpp61
-rw-r--r--src/ui/render/RenderObject.cpp206
-rw-r--r--src/ui/render/ScrollBar.cpp16
-rw-r--r--src/ui/render/ScrollRenderObject.cpp60
-rw-r--r--src/ui/render/StackLayoutRenderObject.cpp16
-rw-r--r--src/ui/render/TextRenderObject.cpp13
-rw-r--r--src/ui/render/TreeRenderObject.cpp12
22 files changed, 331 insertions, 456 deletions
diff --git a/include/cru/ui/controls/TreeView.h b/include/cru/ui/controls/TreeView.h
new file mode 100644
index 00000000..2e782ee0
--- /dev/null
+++ b/include/cru/ui/controls/TreeView.h
@@ -0,0 +1,40 @@
+#pragma once
+#include "Control.h"
+
+namespace cru::ui::controls {
+class TreeView;
+
+class CRU_UI_API TreeViewItem : public Object {
+ friend TreeView;
+
+ private:
+ TreeViewItem(TreeView* tree_view, TreeViewItem* parent);
+
+ public:
+ CRU_DELETE_COPY(TreeViewItem)
+ CRU_DELETE_MOVE(TreeViewItem)
+
+ ~TreeViewItem() override;
+
+ TreeView* GetTreeView() { return tree_view_; }
+ TreeViewItem* GetParent() { return parent_; }
+
+ const std::vector<TreeViewItem*>& GetChildren() const { return children_; }
+ Index GetChildCount() const { return children_.size(); }
+ TreeViewItem* GetChildAt(Index index) {
+ Expects(index >= 0 && index < children_.size());
+ return children_[index];
+ }
+
+ TreeViewItem* AddItem(Index position);
+ void RemoveItem(Index position);
+
+ private:
+ TreeView* tree_view_;
+ TreeViewItem* parent_;
+ std::vector<TreeViewItem*> children_;
+
+ Control* control_;
+};
+
+} // namespace cru::ui::controls
diff --git a/include/cru/ui/render/BorderRenderObject.h b/include/cru/ui/render/BorderRenderObject.h
index d75a979f..1720d680 100644
--- a/include/cru/ui/render/BorderRenderObject.h
+++ b/include/cru/ui/render/BorderRenderObject.h
@@ -1,9 +1,7 @@
#pragma once
-#include <string_view>
-#include "../style/ApplyBorderStyleInfo.h"
#include "RenderObject.h"
-#include "cru/platform/GraphicsBase.h"
-#include "cru/ui/Base.h"
+
+#include "../style/ApplyBorderStyleInfo.h"
namespace cru::ui::render {
class CRU_UI_API BorderRenderObject : public RenderObject {
@@ -11,12 +9,13 @@ class CRU_UI_API BorderRenderObject : public RenderObject {
public:
BorderRenderObject();
- BorderRenderObject(const BorderRenderObject& other) = delete;
- BorderRenderObject(BorderRenderObject&& other) = delete;
- BorderRenderObject& operator=(const BorderRenderObject& other) = delete;
- BorderRenderObject& operator=(BorderRenderObject&& other) = delete;
+ CRU_DELETE_COPY(BorderRenderObject)
+ CRU_DELETE_MOVE(BorderRenderObject)
~BorderRenderObject() override;
+ RenderObject* GetChild() const { return child_; }
+ void SetChild(RenderObject* new_child);
+
bool IsBorderEnabled() const { return is_border_enabled_; }
void SetBorderEnabled(bool enabled) { is_border_enabled_ = enabled; }
@@ -69,26 +68,27 @@ class CRU_UI_API BorderRenderObject : public RenderObject {
void ApplyBorderStyle(const style::ApplyBorderStyleInfo& style);
RenderObject* HitTest(const Point& point) override;
+ void Draw(platform::graphics::IPainter* painter) override;
Thickness GetOuterSpaceThickness() const override;
Rect GetPaddingRect() const override;
Rect GetContentRect() const override;
- std::u16string_view GetName() const override { return u"BorderRenderObject"; }
+ String GetName() const override { return u"BorderRenderObject"; }
protected:
- void OnDrawCore(platform::graphics::IPainter* painter) override;
-
Size OnMeasureContent(const MeasureRequirement& requirement,
const MeasureSize& preferred_size) override;
void OnLayoutContent(const Rect& content_rect) override;
- void OnAfterLayout() override;
+ void OnResize(const Size& new_size) override;
private:
void RecreateGeometry();
private:
+ RenderObject* child_ = nullptr;
+
bool is_border_enabled_ = false;
std::shared_ptr<platform::graphics::IBrush> border_brush_;
diff --git a/include/cru/ui/render/CanvasRenderObject.h b/include/cru/ui/render/CanvasRenderObject.h
index ca55ebc6..8343a5f5 100644
--- a/include/cru/ui/render/CanvasRenderObject.h
+++ b/include/cru/ui/render/CanvasRenderObject.h
@@ -1,6 +1,8 @@
#pragma once
#include "RenderObject.h"
+#include "cru/common/Event.h"
+
namespace cru::ui::render {
// Layout logic:
// If no preferred size is set. Then (100, 100) is used and then coerced to
@@ -21,9 +23,9 @@ class CRU_UI_API CanvasRenderObject : public RenderObject {
IEvent<CanvasPaintEventArgs>* PaintEvent() { return &paint_event_; }
- protected:
- void OnDrawContent(platform::graphics::IPainter* painter) override;
+ void Draw(platform::graphics::IPainter* painter) override;
+ protected:
Size OnMeasureContent(const MeasureRequirement& requirement,
const MeasureSize& preferred_size) override;
void OnLayoutContent(const Rect& content_rect) override;
diff --git a/include/cru/ui/render/FlexLayoutRenderObject.h b/include/cru/ui/render/FlexLayoutRenderObject.h
index 3a8348f6..164bae39 100644
--- a/include/cru/ui/render/FlexLayoutRenderObject.h
+++ b/include/cru/ui/render/FlexLayoutRenderObject.h
@@ -1,8 +1,6 @@
#pragma once
#include "LayoutRenderObject.h"
-#include <string_view>
-
namespace cru::ui::render {
// Measure Logic (v0.1):
// Cross axis measure logic is the same as stack layout.
@@ -75,7 +73,8 @@ namespace cru::ui::render {
// (if specified), then coerce the length to the min value but not report error
// and just fill the rest space with blank.
//
-class CRU_UI_API FlexLayoutRenderObject : public LayoutRenderObject<FlexChildLayoutData> {
+class CRU_UI_API FlexLayoutRenderObject
+ : public LayoutRenderObject<FlexChildLayoutData> {
CRU_DEFINE_CLASS_LOG_TAG(u"cru::ui::render::FlexLayoutRenderObject")
public:
@@ -87,7 +86,7 @@ class CRU_UI_API FlexLayoutRenderObject : public LayoutRenderObject<FlexChildLay
FlexLayoutRenderObject& operator=(FlexLayoutRenderObject&& other) = delete;
~FlexLayoutRenderObject() override = default;
- std::u16string_view GetName() const override;
+ String GetName() const override;
FlexDirection GetFlexDirection() const { return direction_; }
void SetFlexDirection(FlexDirection direction) {
diff --git a/include/cru/ui/render/LayoutRenderObject.h b/include/cru/ui/render/LayoutRenderObject.h
index 42a3aa55..05da1bb8 100644
--- a/include/cru/ui/render/LayoutRenderObject.h
+++ b/include/cru/ui/render/LayoutRenderObject.h
@@ -9,8 +9,14 @@ class CRU_UI_API LayoutRenderObject : public RenderObject {
public:
using ChildLayoutData = TChildLayoutData;
+ private:
+ struct ChildData {
+ RenderObject* child;
+ ChildLayoutData layout_data;
+ };
+
protected:
- LayoutRenderObject() : RenderObject(ChildMode::Multiple) {}
+ LayoutRenderObject() = default;
public:
CRU_DELETE_COPY(LayoutRenderObject)
@@ -18,69 +24,50 @@ class CRU_UI_API LayoutRenderObject : public RenderObject {
~LayoutRenderObject() override = default;
- const std::vector<ChildLayoutData>& GetChildLayoutDataList() const {
- return this->child_layout_data_;
+ Index GetChildCount() const { return static_cast<Index>(children_.size()); }
+ RenderObject* GetChildAt(Index position) {
+ Expects(position > 0 && position < GetChildCount());
+ return children_[position].render_object;
+ }
+ void AddChild(RenderObject* render_object, Index position) {
+ if (position < 0) position = 0;
+ if (position > GetChildCount()) position = GetChildCount();
+ children_.insert(children_.begin() + position,
+ ChildData{render_object, ChildLayoutData()});
+ render_object->SetParent(this);
+ }
+
+ void RemoveChild(Index position) {
+ Expects(position > 0 && position < GetChildCount());
+ children_[position].render_object->SetParent(nullptr);
+ children_.erase(children_.begin() + position);
}
void SetChildLayoutData(Index position, ChildLayoutData data) {
- Expects(position >= 0 &&
- position < static_cast<Index>(this->child_layout_data_.size()));
- this->child_layout_data_[position] = std::move(data);
- this->InvalidateLayout();
+ Expects(position >= 0 && position < GetChildCount());
+ children_[position].layout_data = std::move(data);
+ InvalidateLayout();
}
const ChildLayoutData& GetChildLayoutData(Index position) const {
- Expects(position >= 0 &&
- position < static_cast<Index>(this->child_layout_data_.size()));
- return this->child_layout_data_[position];
+ Expects(position >= 0 && position < GetChildCount());
+ return children_[position].layout_data;
}
- RenderObject* HitTest(const Point& point) override;
+ RenderObject* HitTest(const Point& point) override {
+ const auto child_count = GetChildCount();
+ for (auto i = child_count - 1; i >= 0; --i) {
+ const auto child = GetChildAt(i);
+ const auto result = child->HitTest(point - child->GetOffset());
+ if (result != nullptr) {
+ return result;
+ }
+ }
- protected:
- void OnAddChild(RenderObject* new_child, Index position) override;
- void OnRemoveChild(RenderObject* removed_child, Index position) override;
+ return GetPaddingRect().IsPointInside(point) ? this : nullptr;
+ }
private:
- std::vector<ChildLayoutData> child_layout_data_{};
+ std::vector<ChildData> children_;
};
-
-template <typename TChildLayoutData>
-RenderObject* LayoutRenderObject<TChildLayoutData>::HitTest(
- const Point& point) {
- const auto& children = GetChildren();
- for (auto i = children.crbegin(); i != children.crend(); ++i) {
- auto offset = (*i)->GetOffset();
- Point p{point.x - offset.x, point.y - offset.y};
- const auto result = (*i)->HitTest(p);
- if (result != nullptr) {
- return result;
- }
- }
-
- const auto margin = GetMargin();
- const auto size = GetSize();
- return Rect{margin.left, margin.top,
- std::max(size.width - margin.GetHorizontalTotal(), 0.0f),
- std::max(size.height - margin.GetVerticalTotal(), 0.0f)}
- .IsPointInside(point)
- ? this
- : nullptr;
-} // namespace cru::ui::render
-
-template <typename TChildLayoutData>
-void LayoutRenderObject<TChildLayoutData>::OnAddChild(RenderObject* new_child,
- const Index position) {
- CRU_UNUSED(new_child)
-
- child_layout_data_.emplace(child_layout_data_.cbegin() + position);
-}
-
-template <typename TChildLayoutData>
-void LayoutRenderObject<TChildLayoutData>::OnRemoveChild(
- RenderObject* removed_child, const Index position) {
- CRU_UNUSED(removed_child)
-
- child_layout_data_.erase(child_layout_data_.cbegin() + position);
-}
} // namespace cru::ui::render
diff --git a/include/cru/ui/render/RenderObject.h b/include/cru/ui/render/RenderObject.h
index a4ac0f4b..67ef6162 100644
--- a/include/cru/ui/render/RenderObject.h
+++ b/include/cru/ui/render/RenderObject.h
@@ -3,13 +3,9 @@
#include "MeasureRequirement.h"
#include "cru/common/Base.h"
-#include "cru/common/Event.h"
+#include "cru/common/String.h"
#include "cru/ui/Base.h"
-#include <cstddef>
-#include <string>
-#include <string_view>
-
namespace cru::ui::render {
// Render object will not destroy its children when destroyed. Control must
// manage lifecycle of its render objects. Since control will destroy its
@@ -40,80 +36,46 @@ namespace cru::ui::render {
// Size OnMeasureContent(const MeasureRequirement& requirement) override;
// void OnLayoutContent(const Rect& content_rect) override;
class CRU_UI_API RenderObject : public Object {
- friend host::WindowHost;
-
CRU_DEFINE_CLASS_LOG_TAG(u"cru::ui::render::RenderObject")
protected:
- enum class ChildMode {
- None,
- Single,
- Multiple,
- };
-
RenderObject() = default;
- RenderObject(ChildMode child_mode) : RenderObject() {
- SetChildMode(child_mode);
- }
public:
- RenderObject(const RenderObject& other) = delete;
- RenderObject(RenderObject&& other) = delete;
- RenderObject& operator=(const RenderObject& other) = delete;
- RenderObject& operator=(RenderObject&& other) = delete;
+ CRU_DELETE_COPY(RenderObject)
+ CRU_DELETE_MOVE(RenderObject)
~RenderObject() override = default;
controls::Control* GetAttachedControl() const { return control_; }
void SetAttachedControl(controls::Control* new_control);
- host::WindowHost* GetWindowHost() const { return window_host_; }
-
RenderObject* GetParent() const { return parent_; }
-
- const std::vector<RenderObject*>& GetChildren() const { return children_; }
- Index GetChildCount() const { return static_cast<Index>(children_.size()); }
- void AddChild(RenderObject* render_object, Index position);
- void RemoveChild(Index position);
-
- RenderObject* GetFirstChild() const;
- void TraverseDescendants(const std::function<void(RenderObject*)>& action);
+ void SetParent(RenderObject* new_parent) { parent_ = new_parent; }
// Offset from parent's lefttop to lefttop of this render object. Margin is
// accounted for.
Point GetOffset() const { return offset_; }
Size GetSize() const { return size_; }
+
Point GetTotalOffset() const;
Point FromRootToContent(const Point& point) const;
+ Size GetDesiredSize() const { return desired_size_; }
+
Thickness GetMargin() const { return margin_; }
- void SetMargin(const Thickness& margin) {
- margin_ = margin;
- InvalidateLayout();
- }
+ void SetMargin(const Thickness& margin);
Thickness GetPadding() const { return padding_; }
- void SetPadding(const Thickness& padding) {
- padding_ = padding;
- InvalidateLayout();
- }
+ void SetPadding(const Thickness& padding);
MeasureSize GetPreferredSize() const { return preferred_size_; }
- void SetPreferredSize(const MeasureSize& preferred_size) {
- preferred_size_ = preferred_size;
- InvalidateLayout();
- }
+ void SetPreferredSize(const MeasureSize& preferred_size);
MeasureSize GetMinSize() const { return custom_measure_requirement_.min; }
- void SetMinSize(const MeasureSize& min_size) {
- custom_measure_requirement_.min = min_size;
- InvalidateLayout();
- }
+ void SetMinSize(const MeasureSize& min_size);
MeasureSize GetMaxSize() const { return custom_measure_requirement_.max; }
- void SetMaxSize(const MeasureSize& max_size) {
- custom_measure_requirement_.max = max_size;
- InvalidateLayout();
- }
+ void SetMaxSize(const MeasureSize& max_size);
MeasureRequirement GetCustomMeasureRequirement() const {
return custom_measure_requirement_;
@@ -135,56 +97,22 @@ class CRU_UI_API RenderObject : public Object {
virtual Rect GetPaddingRect() const;
virtual Rect GetContentRect() const;
- void Draw(platform::graphics::IPainter* painter);
+ virtual void Draw(platform::graphics::IPainter* painter) = 0;
// Param point must be relative the lefttop of render object including margin.
// Add offset before pass point to children.
virtual RenderObject* HitTest(const Point& point) = 0;
- IEvent<host::WindowHost*>* AttachToHostEvent() {
- return &attach_to_host_event_;
- }
- IEvent<std::nullptr_t>* DetachFromHostEvent() {
- return &detach_from_host_event_;
- }
-
public:
+ host::WindowHost* GetWindowHost();
void InvalidateLayout();
void InvalidatePaint();
public:
- virtual std::u16string_view GetName() const;
- std::u16string GetDebugPathInTree() const;
-
- protected:
- void SetChildMode(ChildMode mode) { child_mode_ = mode; }
+ virtual String GetName() const;
+ String GetDebugPathInTree() const;
protected:
- RenderObject* GetSingleChild() const;
-
- virtual void OnParentChanged(RenderObject* old_parent,
- RenderObject* new_parent);
-
- // default is to invalidate both layout and paint
- virtual void OnAddChild(RenderObject* new_child, Index position);
- // default is to invalidate both layout and paint
- virtual void OnRemoveChild(RenderObject* removed_child, Index position);
-
- /**
- * \brief Draw all children with offset.
- */
- void DefaultDrawChildren(platform::graphics::IPainter* painter);
-
- /**
- * \brief Call OnDrawContent with translation of content rect lefttop.
- */
- void DefaultDrawContent(platform::graphics::IPainter* painter);
-
- // Call DefaultDrawContent. Then call DefaultDrawChildren.
- virtual void OnDrawCore(platform::graphics::IPainter* painter);
-
- virtual void OnDrawContent(platform::graphics::IPainter* painter);
-
// Size measure including margin and padding. Please reduce margin and padding
// or other custom things and pass the result content measure requirement and
// preferred size to OnMeasureContent. Return value must not be negative and
@@ -209,36 +137,24 @@ class CRU_UI_API RenderObject : public Object {
// Lefttop of content_rect should be added when calculated children's offset.
virtual void OnLayoutContent(const Rect& content_rect) = 0;
- virtual void OnAttachedControlChanged(controls::Control* control) {
- CRU_UNUSED(control)
- }
-
- virtual void OnAfterLayout();
-
- private:
- void SetParent(RenderObject* new_parent);
-
- void SetWindowHostRecursive(host::WindowHost* host);
+ virtual void OnAttachedControlChanged(controls::Control* old_control,
+ controls::Control* new_control) {}
+ virtual void OnResize(const Size& new_size) {}
private:
controls::Control* control_ = nullptr;
- host::WindowHost* window_host_ = nullptr;
RenderObject* parent_ = nullptr;
- std::vector<RenderObject*> children_{};
-
- ChildMode child_mode_ = ChildMode::None;
Point offset_{};
Size size_{};
- MeasureSize preferred_size_;
- MeasureRequirement custom_measure_requirement_;
+ Size desired_size_{};
Thickness margin_{};
Thickness padding_{};
- Event<host::WindowHost*> attach_to_host_event_;
- Event<std::nullptr_t> detach_from_host_event_;
+ MeasureSize preferred_size_{};
+ MeasureRequirement custom_measure_requirement_{};
};
} // namespace cru::ui::render
diff --git a/include/cru/ui/render/ScrollRenderObject.h b/include/cru/ui/render/ScrollRenderObject.h
index bb282953..0890ec21 100644
--- a/include/cru/ui/render/ScrollRenderObject.h
+++ b/include/cru/ui/render/ScrollRenderObject.h
@@ -27,6 +27,9 @@ class CRU_UI_API ScrollRenderObject : public RenderObject {
~ScrollRenderObject() override = default;
+ RenderObject* GetChild() const { return child_; }
+ void SetChild(RenderObject* new_child);
+
RenderObject* HitTest(const Point& point) override;
// Return the coerced scroll offset.
@@ -61,7 +64,7 @@ class CRU_UI_API ScrollRenderObject : public RenderObject {
// Param margin is just for convenience and it will just add to the rect.
void ScrollToContain(const Rect& rect, const Thickness& margin = Thickness{});
- std::u16string_view GetName() const override { return u"ScrollRenderObject"; }
+ String GetName() const override { return u"ScrollRenderObject"; }
bool IsMouseWheelScrollEnabled() const { return is_mouse_wheel_enabled_; }
void SetMouseWheelScrollEnabled(bool enable);
@@ -71,9 +74,9 @@ class CRU_UI_API ScrollRenderObject : public RenderObject {
bool VerticalCanScrollUp();
bool VerticalCanScrollDown();
- protected:
- void OnDrawCore(platform::graphics::IPainter* painter) override;
+ void Draw(platform::graphics::IPainter* painter) override;
+ protected:
// Logic:
// If available size is bigger than child's preferred size, then child's
// preferred size is taken.
@@ -82,11 +85,14 @@ class CRU_UI_API ScrollRenderObject : public RenderObject {
const MeasureSize& preferred_size) override;
void OnLayoutContent(const Rect& content_rect) override;
- void OnAttachedControlChanged(controls::Control* control) override;
+ void OnAttachedControlChanged(controls::Control* old_control,
+ controls::Control* new_control) override;
void InstallMouseWheelHandler(controls::Control* control);
private:
+ RenderObject* child_;
+
Point scroll_offset_;
std::unique_ptr<ScrollBarDelegate> scroll_bar_delegate_;
diff --git a/include/cru/ui/render/StackLayoutRenderObject.h b/include/cru/ui/render/StackLayoutRenderObject.h
index e141d16e..68b5b30c 100644
--- a/include/cru/ui/render/StackLayoutRenderObject.h
+++ b/include/cru/ui/render/StackLayoutRenderObject.h
@@ -32,9 +32,7 @@ class CRU_UI_API StackLayoutRenderObject
CRU_DELETE_MOVE(StackLayoutRenderObject)
~StackLayoutRenderObject() = default;
- std::u16string_view GetName() const override {
- return u"StackLayoutRenderObject";
- }
+ String GetName() const override { return u"StackLayoutRenderObject"; }
Alignment GetDefaultHorizontalAlignment() const {
return default_vertical_alignment_;
diff --git a/include/cru/ui/render/TextRenderObject.h b/include/cru/ui/render/TextRenderObject.h
index 3b5f581a..f3a7332f 100644
--- a/include/cru/ui/render/TextRenderObject.h
+++ b/include/cru/ui/render/TextRenderObject.h
@@ -91,17 +91,17 @@ class CRU_UI_API TextRenderObject : public RenderObject {
RenderObject* HitTest(const Point& point) override;
- std::u16string_view GetName() const override { return u"TextRenderObject"; }
+ String GetName() const override { return u"TextRenderObject"; }
- protected:
- void OnDrawContent(platform::graphics::IPainter* painter) override;
+ void Draw(platform::graphics::IPainter* painter) override;
+ protected:
// See remarks of this class.
Size OnMeasureContent(const MeasureRequirement& requirement,
const MeasureSize& preferred_size) override;
void OnLayoutContent(const Rect& content_rect) override;
- void OnAfterLayout() override;
+ void OnResize(const Size& size) override;
private:
std::shared_ptr<platform::graphics::IBrush> brush_;
diff --git a/include/cru/ui/render/TreeRenderObject.h b/include/cru/ui/render/TreeRenderObject.h
index 77ec0cff..4a176926 100644
--- a/include/cru/ui/render/TreeRenderObject.h
+++ b/include/cru/ui/render/TreeRenderObject.h
@@ -26,7 +26,7 @@ class CRU_UI_API TreeRenderObjectItem : public Object {
Index GetChildCount() const { return children_.size(); }
- TreeRenderObjectItem* GetChild(Index index) {
+ TreeRenderObjectItem* GetChildAt(Index index) {
Expects(index >= 0 && index < children_.size());
return children_[index];
}
@@ -34,6 +34,9 @@ class CRU_UI_API TreeRenderObjectItem : public Object {
TreeRenderObjectItem* AddItem(Index position);
void RemoveItem(Index position);
+ void* GetUserData() const { return user_data_; }
+ void SetUserData(void* user_data) { user_data_ = user_data; }
+
private:
TreeRenderObject* tree_render_object_;
@@ -41,6 +44,8 @@ class CRU_UI_API TreeRenderObjectItem : public Object {
std::vector<TreeRenderObjectItem*> children_;
RenderObject* render_object_;
+
+ void* user_data_;
};
class CRU_UI_API TreeRenderObject : public RenderObject {
@@ -52,7 +57,7 @@ class CRU_UI_API TreeRenderObject : public RenderObject {
CRU_DELETE_MOVE(TreeRenderObject)
~TreeRenderObject() override;
- std::u16string_view GetName() const override { return u"TreeRenderObject"; }
+ String GetName() const override { return u"TreeRenderObject"; }
TreeRenderObjectItem* GetRootItem() { return root_item_; }
@@ -61,9 +66,9 @@ class CRU_UI_API TreeRenderObject : public RenderObject {
RenderObject* HitTest(const Point& point) override;
- protected:
- void OnDrawCore(platform::graphics::IPainter* painter) override;
+ void Draw(platform::graphics::IPainter* painter) override;
+ protected:
Size OnMeasureContent(const MeasureRequirement& requirement,
const MeasureSize& preferred_size) override;
void OnLayoutContent(const Rect& content_rect) override;
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index fd15e433..d358940f 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -17,6 +17,7 @@ add_library(cru_ui SHARED
controls/TextBlock.cpp
controls/TextBox.cpp
controls/TextHostControlService.cpp
+ controls/TreeView.cpp
controls/Window.cpp
events/MouseEventArgs.cpp
helper/ClickDetector.cpp
diff --git a/src/ui/controls/TreeView.cpp b/src/ui/controls/TreeView.cpp
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/ui/controls/TreeView.cpp
diff --git a/src/ui/host/WindowHost.cpp b/src/ui/host/WindowHost.cpp
index 4373afe9..9773c117 100644
--- a/src/ui/host/WindowHost.cpp
+++ b/src/ui/host/WindowHost.cpp
@@ -111,7 +111,6 @@ WindowHost::WindowHost(controls::Control* root_control)
});
root_render_object_ = root_control->GetRenderObject();
- root_render_object_->SetWindowHostRecursive(this);
this->layout_paint_cycler_ = std::make_unique<LayoutPaintCycler>(this);
@@ -187,16 +186,12 @@ void WindowHost::RelayoutWithSize(const Size& available_size,
render::MeasureSize::NotSpecified());
if (set_window_size_to_fit_content) {
- native_window_->SetClientSize(root_render_object_->GetSize());
+ native_window_->SetClientSize(root_render_object_->GetDesiredSize());
}
root_render_object_->Layout(Point{});
for (auto& action : after_layout_stable_action_) action();
after_layout_event_.Raise(AfterLayoutEventArgs{});
- root_render_object_->TraverseDescendants(
- [](render::RenderObject* render_object) {
- render_object->OnAfterLayout();
- });
after_layout_stable_action_.clear();
if constexpr (debug_flags::layout)
log::TagDebug(log_tag, u"A relayout is finished.");
diff --git a/src/ui/render/BorderRenderObject.cpp b/src/ui/render/BorderRenderObject.cpp
index 61af27bc..5916c7aa 100644
--- a/src/ui/render/BorderRenderObject.cpp
+++ b/src/ui/render/BorderRenderObject.cpp
@@ -12,13 +12,18 @@
#include <algorithm>
namespace cru::ui::render {
-BorderRenderObject::BorderRenderObject() {
- SetChildMode(ChildMode::Single);
- RecreateGeometry();
-}
+BorderRenderObject::BorderRenderObject() { RecreateGeometry(); }
BorderRenderObject::~BorderRenderObject() {}
+void BorderRenderObject::SetChild(RenderObject* new_child) {
+ if (child_ == new_child) return;
+ if (child_ != nullptr) child_->SetParent(nullptr);
+ child_ = new_child;
+ if (child_ != nullptr) child_->SetParent(this);
+ InvalidateLayout();
+}
+
void BorderRenderObject::ApplyBorderStyle(
const style::ApplyBorderStyleInfo& style) {
if (style.border_brush) border_brush_ = *style.border_brush;
@@ -30,10 +35,8 @@ void BorderRenderObject::ApplyBorderStyle(
}
RenderObject* BorderRenderObject::HitTest(const Point& point) {
- if (const auto child = GetSingleChild()) {
- auto offset = child->GetOffset();
- Point p{point.x - offset.x, point.y - offset.y};
- const auto result = child->HitTest(p);
+ if (child_) {
+ const auto result = child_->HitTest(point - child_->GetOffset());
if (result != nullptr) {
return result;
}
@@ -45,7 +48,7 @@ RenderObject* BorderRenderObject::HitTest(const Point& point) {
return contains ? this : nullptr;
} else {
const auto margin = GetMargin();
- const auto size = GetSize();
+ const auto size = GetDesiredSize();
return Rect{margin.left, margin.top,
std::max(size.width - margin.GetHorizontalTotal(), 0.0f),
std::max(size.height - margin.GetVerticalTotal(), 0.0f)}
@@ -55,7 +58,7 @@ RenderObject* BorderRenderObject::HitTest(const Point& point) {
}
}
-void BorderRenderObject::OnDrawCore(platform::graphics::IPainter* painter) {
+void BorderRenderObject::Draw(platform::graphics::IPainter* painter) {
if constexpr (debug_flags::draw) {
log::TagDebug(
log_tag, u"BorderRenderObject draw, background: {}, foreground: {}.",
@@ -77,34 +80,35 @@ void BorderRenderObject::OnDrawCore(platform::graphics::IPainter* painter) {
}
}
- DefaultDrawContent(painter);
+ if (child_) {
+ painter->PushState();
+ painter->ConcatTransform(Matrix::Translation(child_->GetOffset()));
+ child_->Draw(painter);
+ painter->PopState();
+ }
if (foreground_brush_ != nullptr)
painter->FillGeometry(border_inner_geometry_.get(),
foreground_brush_.get());
-
- DefaultDrawChildren(painter);
}
Size BorderRenderObject::OnMeasureContent(const MeasureRequirement& requirement,
const MeasureSize& preferred_size) {
- const auto child = GetSingleChild();
- if (child) {
- child->Measure(requirement, preferred_size);
- return child->GetSize();
+ if (child_) {
+ child_->Measure(requirement, preferred_size);
+ return child_->GetDesiredSize();
} else {
return Size{};
}
}
void BorderRenderObject::OnLayoutContent(const Rect& content_rect) {
- const auto child = GetSingleChild();
- if (child) {
- child->Layout(content_rect.GetLeftTop());
+ if (child_) {
+ child_->Layout(content_rect.GetLeftTop());
}
}
-void BorderRenderObject::OnAfterLayout() { RecreateGeometry(); }
+void BorderRenderObject::OnResize(const Size& new_size) { RecreateGeometry(); }
Thickness BorderRenderObject::GetOuterSpaceThickness() const {
return is_border_enabled_
@@ -113,7 +117,7 @@ Thickness BorderRenderObject::GetOuterSpaceThickness() const {
}
Rect BorderRenderObject::GetPaddingRect() const {
- const auto size = GetSize();
+ const auto size = GetDesiredSize();
Rect rect{Point{}, size};
rect = rect.Shrink(GetMargin());
if (is_border_enabled_) rect = rect.Shrink(border_thickness_);
@@ -125,7 +129,7 @@ Rect BorderRenderObject::GetPaddingRect() const {
}
Rect BorderRenderObject::GetContentRect() const {
- const auto size = GetSize();
+ const auto size = GetDesiredSize();
Rect rect{Point{}, size};
rect = rect.Shrink(GetMargin());
if (is_border_enabled_) rect = rect.Shrink(border_thickness_);
@@ -180,7 +184,7 @@ void BorderRenderObject::RecreateGeometry() {
builder->CloseFigure(true);
};
- const auto size = GetSize();
+ const auto size = GetDesiredSize();
const auto margin = GetMargin();
const Rect outer_rect{margin.left, margin.top,
size.width - margin.GetHorizontalTotal(),
diff --git a/src/ui/render/CanvasRenderObject.cpp b/src/ui/render/CanvasRenderObject.cpp
index 985a2dae..e818333c 100644
--- a/src/ui/render/CanvasRenderObject.cpp
+++ b/src/ui/render/CanvasRenderObject.cpp
@@ -1,7 +1,7 @@
#include "cru/ui/render/CanvasRenderObject.h"
namespace cru::ui::render {
-CanvasRenderObject::CanvasRenderObject() : RenderObject(ChildMode::None) {}
+CanvasRenderObject::CanvasRenderObject() : RenderObject() {}
CanvasRenderObject::~CanvasRenderObject() = default;
@@ -10,7 +10,7 @@ RenderObject* CanvasRenderObject::HitTest(const Point& point) {
return padding_rect.IsPointInside(point) ? this : nullptr;
}
-void CanvasRenderObject::OnDrawContent(platform::graphics::IPainter* painter) {
+void CanvasRenderObject::Draw(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 e4d16169..261a0f43 100644
--- a/src/ui/render/FlexLayoutRenderObject.cpp
+++ b/src/ui/render/FlexLayoutRenderObject.cpp
@@ -11,8 +11,7 @@
#include <type_traits>
namespace cru::ui::render {
-
-std::u16string_view FlexLayoutRenderObject::GetName() const {
+String FlexLayoutRenderObject::GetName() const {
return u"FlexLayoutRenderObject";
}
@@ -121,7 +120,7 @@ Size FlexLayoutMeasureContentImpl(
float total_length = 0.f;
for (auto child : children) {
- total_length += GetMain(child->GetSize(), direction_tag);
+ total_length += GetMain(child->GetDesiredSize(), direction_tag);
}
// step 2.
@@ -190,7 +189,7 @@ Size FlexLayoutMeasureContentImpl(
const float shrink_length = layout_data[i].shrink_factor /
total_shrink_factor * total_shrink_length;
float new_measure_length =
- GetMain(child->GetSize(), direction_tag) - shrink_length;
+ GetMain(child->GetDesiredSize(), direction_tag) - shrink_length;
MeasureLength child_min_main_length =
GetMain(child->GetMinSize(), direction_tag);
@@ -210,7 +209,7 @@ Size FlexLayoutMeasureContentImpl(
MeasureLength::NotSpecified(),
direction_tag));
- const Size new_size = child->GetSize();
+ const Size new_size = child->GetDesiredSize();
const float new_main_length = GetMain(new_size, direction_tag);
if (new_main_length > new_measure_length) {
to_remove.push_back(i);
@@ -219,7 +218,7 @@ Size FlexLayoutMeasureContentImpl(
total_length = 0.f;
for (auto child : children) {
- total_length += GetMain(child->GetSize(), direction_tag);
+ total_length += GetMain(child->GetDesiredSize(), direction_tag);
}
if (total_length <= target_length) break;
@@ -250,7 +249,7 @@ Size FlexLayoutMeasureContentImpl(
const float expand_length = layout_data[i].expand_factor /
total_expand_factor * total_expand_length;
float new_measure_length =
- GetMain(child->GetSize(), direction_tag) + expand_length;
+ GetMain(child->GetDesiredSize(), direction_tag) + expand_length;
MeasureLength child_max_main_length =
GetMain(child->GetMaxSize(), direction_tag);
@@ -271,7 +270,7 @@ Size FlexLayoutMeasureContentImpl(
MeasureLength::NotSpecified(),
direction_tag));
- const Size new_size = child->GetSize();
+ const Size new_size = child->GetDesiredSize();
const float new_main_length = GetMain(new_size, direction_tag);
if (new_main_length < new_measure_length) {
to_remove.push_back(i);
@@ -280,7 +279,7 @@ Size FlexLayoutMeasureContentImpl(
total_length = 0.f;
for (auto child : children) {
- total_length += GetMain(child->GetSize(), direction_tag);
+ total_length += GetMain(child->GetDesiredSize(), direction_tag);
}
if (total_length >= target_length) break;
@@ -292,7 +291,7 @@ Size FlexLayoutMeasureContentImpl(
float child_max_cross_length = 0.f;
for (auto child : children) {
- const float cross_length = GetCross(child->GetSize(), direction_tag);
+ const float cross_length = GetCross(child->GetDesiredSize(), direction_tag);
if (cross_length > child_max_cross_length) {
child_max_cross_length = cross_length;
}
@@ -319,7 +318,7 @@ Size FlexLayoutMeasureContentImpl(
auto child = children[i];
if (child_layout_data.cross_alignment.value_or(item_cross_align) ==
Alignment::Stretch) {
- auto size = child->GetSize();
+ auto size = child->GetDesiredSize();
GetCross(size, direction_tag) = child_max_cross_length;
child->Measure({size, size}, MeasureSize::NotSpecified());
}
@@ -333,29 +332,40 @@ Size FlexLayoutRenderObject::OnMeasureContent(
const MeasureRequirement& requirement, const MeasureSize& preferred_size) {
const bool horizontal = (direction_ == FlexDirection::Horizontal ||
direction_ == FlexDirection::HorizontalReverse);
+ std::vector<RenderObject*> children;
+ std::vector<FlexChildLayoutData> layout_data_list;
+ for (int i = 0; i < GetChildCount(); i++) {
+ children.push_back(GetChildAt(i));
+ layout_data_list.push_back(GetChildLayoutData(i));
+ }
+
if (horizontal) {
return FlexLayoutMeasureContentImpl<tag_horizontal_t>(
- requirement, preferred_size, GetChildren(), GetChildLayoutDataList(),
+ requirement, preferred_size, children, layout_data_list,
item_cross_align_, log_tag);
} else {
return FlexLayoutMeasureContentImpl<tag_vertical_t>(
- requirement, preferred_size, GetChildren(), GetChildLayoutDataList(),
+ requirement, preferred_size, children, layout_data_list,
item_cross_align_, log_tag);
}
}
void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
- const auto& children = GetChildren();
- const Index child_count = children.size();
+ const auto child_count = GetChildCount();
+ std::vector<RenderObject*> children;
+ std::vector<FlexChildLayoutData> layout_data_list;
+ for (int i = 0; i < child_count; i++) {
+ children.push_back(GetChildAt(i));
+ layout_data_list.push_back(GetChildLayoutData(i));
+ }
if (direction_ == FlexDirection::Horizontal) {
float current_main_offset = 0;
for (Index i = 0; i < child_count; i++) {
const auto child = children[i];
- const auto size = child->GetSize();
+ const auto size = child->GetDesiredSize();
const auto cross_align =
- GetChildLayoutDataList()[i].cross_alignment.value_or(
- GetItemCrossAlign());
+ layout_data_list[i].cross_alignment.value_or(GetItemCrossAlign());
child->Layout(
Point{content_rect.left + current_main_offset,
CalculateAnchorByAlignment(cross_align, content_rect.top,
@@ -367,10 +377,9 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
float current_main_offset = 0;
for (Index i = 0; i < child_count; i++) {
const auto child = children[i];
- const auto size = child->GetSize();
+ const auto size = child->GetDesiredSize();
const auto cross_align =
- GetChildLayoutDataList()[i].cross_alignment.value_or(
- GetItemCrossAlign());
+ layout_data_list[i].cross_alignment.value_or(GetItemCrossAlign());
child->Layout(
Point{content_rect.GetRight() - current_main_offset,
CalculateAnchorByAlignment(cross_align, content_rect.top,
@@ -381,10 +390,9 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
float current_main_offset = 0;
for (Index i = 0; i < child_count; i++) {
const auto child = children[i];
- const auto size = child->GetSize();
+ const auto size = child->GetDesiredSize();
const auto cross_align =
- GetChildLayoutDataList()[i].cross_alignment.value_or(
- GetItemCrossAlign());
+ layout_data_list[i].cross_alignment.value_or(GetItemCrossAlign());
child->Layout(Point{
CalculateAnchorByAlignment(cross_align, content_rect.left,
content_rect.width, size.width),
@@ -396,10 +404,9 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
float current_main_offset = 0;
for (Index i = 0; i < child_count; i++) {
const auto child = children[i];
- const auto size = child->GetSize();
+ const auto size = child->GetDesiredSize();
const auto cross_align =
- GetChildLayoutDataList()[i].cross_alignment.value_or(
- GetItemCrossAlign());
+ layout_data_list[i].cross_alignment.value_or(GetItemCrossAlign());
child->Layout(
Point{CalculateAnchorByAlignment(cross_align, content_rect.left,
content_rect.width, size.width),
diff --git a/src/ui/render/RenderObject.cpp b/src/ui/render/RenderObject.cpp
index 00488425..67bbae12 100644
--- a/src/ui/render/RenderObject.cpp
+++ b/src/ui/render/RenderObject.cpp
@@ -1,66 +1,15 @@
#include "cru/ui/render/RenderObject.h"
#include "cru/common/Logger.h"
-#include "cru/platform/GraphicsBase.h"
-#include "cru/platform/graphics/util/Painter.h"
-#include "cru/ui/Base.h"
#include "cru/ui/DebugFlags.h"
+#include "cru/ui/controls/Control.h"
#include "cru/ui/host/WindowHost.h"
-#include <algorithm>
-#include <string>
-#include <string_view>
-#include <vector>
-
namespace cru::ui::render {
void RenderObject::SetAttachedControl(controls::Control* new_control) {
+ auto old_control = 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));
-
- Expects(render_object->GetParent() ==
- nullptr); // Render object already has a parent.
- Expects(position >= 0); // Position index is less than 0.
- Expects(
- position <=
- static_cast<Index>(children_.size())); // Position index is out of bound.
-
- children_.insert(children_.cbegin() + position, render_object);
- render_object->SetParent(this);
- render_object->SetWindowHostRecursive(GetWindowHost());
- OnAddChild(render_object, position);
-}
-
-void RenderObject::RemoveChild(const Index position) {
- Expects(position >= 0); // Position index is less than 0.
- Expects(position < static_cast<Index>(
- children_.size())); // Position index is out of bound.
-
- const auto i = children_.cbegin() + position;
- const auto removed_child = *i;
- children_.erase(i);
- removed_child->SetParent(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);
+ OnAttachedControlChanged(old_control, new_control);
}
Point RenderObject::GetTotalOffset() const {
@@ -84,6 +33,31 @@ Point RenderObject::FromRootToContent(const Point& point) const {
point.y - (offset.y + rect.top)};
}
+void RenderObject::SetMargin(const Thickness& margin) {
+ margin_ = margin;
+ InvalidateLayout();
+}
+
+void RenderObject::SetPadding(const Thickness& padding) {
+ padding_ = padding;
+ InvalidateLayout();
+}
+
+void RenderObject::SetPreferredSize(const MeasureSize& preferred_size) {
+ preferred_size_ = preferred_size;
+ InvalidateLayout();
+}
+
+void RenderObject::SetMinSize(const MeasureSize& min_size) {
+ custom_measure_requirement_.min = min_size;
+ InvalidateLayout();
+}
+
+void RenderObject::SetMaxSize(const MeasureSize& max_size) {
+ custom_measure_requirement_.max = max_size;
+ InvalidateLayout();
+}
+
void RenderObject::Measure(const MeasureRequirement& requirement,
const MeasureSize& preferred_size) {
MeasureRequirement merged_requirement =
@@ -98,23 +72,27 @@ void RenderObject::Measure(const MeasureRequirement& requirement,
preferred_size.ToDebugString());
}
- size_ = OnMeasureCore(merged_requirement, merged_preferred_size);
+ desired_size_ = OnMeasureCore(merged_requirement, merged_preferred_size);
if constexpr (cru::ui::debug_flags::layout) {
log::Debug(u"{} Measure ends :\nresult size: {}",
- this->GetDebugPathInTree(), size_);
+ this->GetDebugPathInTree(), desired_size_);
}
- Ensures(size_.width >= 0);
- Ensures(size_.height >= 0);
+ Ensures(desired_size_.width >= 0);
+ Ensures(desired_size_.height >= 0);
}
void RenderObject::Layout(const Point& offset) {
if constexpr (cru::ui::debug_flags::layout) {
log::Debug(u"{} Layout :\noffset: {} size: {}", this->GetDebugPathInTree(),
- offset, GetSize());
+ offset, desired_size_);
}
offset_ = offset;
+ size_ = desired_size_;
+
+ OnResize(size_);
+
OnLayoutCore();
}
@@ -122,67 +100,6 @@ Thickness RenderObject::GetOuterSpaceThickness() const {
return margin_ + padding_;
}
-void RenderObject::Draw(platform::graphics::IPainter* painter) {
- OnDrawCore(painter);
-}
-
-RenderObject* RenderObject::GetSingleChild() const {
- Expects(child_mode_ == ChildMode::Single);
- const auto& children = GetChildren();
- if (children.empty())
- return nullptr;
- else
- return children.front();
-}
-
-void RenderObject::OnParentChanged(RenderObject* old_parent,
- RenderObject* new_parent) {
- CRU_UNUSED(old_parent)
- CRU_UNUSED(new_parent)
-}
-
-void RenderObject::OnAddChild(RenderObject* new_child, Index position) {
- CRU_UNUSED(new_child)
- CRU_UNUSED(position)
-
- InvalidateLayout();
- InvalidatePaint();
-}
-
-void RenderObject::OnRemoveChild(RenderObject* removed_child, Index position) {
- CRU_UNUSED(removed_child)
- CRU_UNUSED(position)
-
- InvalidateLayout();
- InvalidatePaint();
-}
-
-void RenderObject::DefaultDrawChildren(platform::graphics::IPainter* painter) {
- for (const auto child : GetChildren()) {
- auto offset = child->GetOffset();
- platform::graphics::util::WithTransform(
- painter, platform::Matrix::Translation(offset.x, offset.y),
- [child](auto p) { child->Draw(p); });
- }
-}
-
-void RenderObject::DefaultDrawContent(platform::graphics::IPainter* painter) {
- const auto content_rect = GetContentRect();
-
- platform::graphics::util::WithTransform(
- painter, Matrix::Translation(content_rect.left, content_rect.top),
- [this](auto p) { this->OnDrawContent(p); });
-}
-
-void RenderObject::OnDrawCore(platform::graphics::IPainter* painter) {
- DefaultDrawContent(painter);
- DefaultDrawChildren(painter);
-}
-
-void RenderObject::OnDrawContent(platform::graphics::IPainter* painter) {
- CRU_UNUSED(painter);
-}
-
Size RenderObject::OnMeasureCore(const MeasureRequirement& requirement,
const MeasureSize& preferred_size) {
const Thickness outer_space = GetOuterSpaceThickness();
@@ -204,7 +121,7 @@ Size RenderObject::OnMeasureCore(const MeasureRequirement& requirement,
}
void RenderObject::OnLayoutCore() {
- Size total_size = GetSize();
+ Size total_size = GetDesiredSize();
const Thickness outer_space = GetOuterSpaceThickness();
const Size space_size{outer_space.GetHorizontalTotal(),
outer_space.GetVerticalTotal()};
@@ -231,10 +148,8 @@ void RenderObject::OnLayoutCore() {
OnLayoutContent(content_rect);
}
-void RenderObject::OnAfterLayout() {}
-
Rect RenderObject::GetPaddingRect() const {
- const auto size = GetSize();
+ const auto size = GetDesiredSize();
Rect rect{Point{}, size};
rect = rect.Shrink(GetMargin());
rect.left = std::min(rect.left, size.width);
@@ -245,7 +160,7 @@ Rect RenderObject::GetPaddingRect() const {
}
Rect RenderObject::GetContentRect() const {
- const auto size = GetSize();
+ const auto size = GetDesiredSize();
Rect rect{Point{}, size};
rect = rect.Shrink(GetMargin());
rect = rect.Shrink(GetPadding());
@@ -256,33 +171,37 @@ Rect RenderObject::GetContentRect() const {
return rect;
}
-void RenderObject::SetParent(RenderObject* new_parent) {
- const auto old_parent = parent_;
- parent_ = new_parent;
- OnParentChanged(old_parent, new_parent);
+host::WindowHost* RenderObject::GetWindowHost() {
+ if (control_) {
+ return control_->GetWindowHost();
+ }
+ return nullptr;
}
void RenderObject::InvalidateLayout() {
- if (window_host_ != nullptr) window_host_->InvalidateLayout();
+ if (auto window_host = GetWindowHost()) {
+ window_host->InvalidateLayout();
+ }
}
void RenderObject::InvalidatePaint() {
- if (window_host_ != nullptr) window_host_->InvalidatePaint();
+ if (auto window_host = GetWindowHost()) {
+ window_host->InvalidatePaint();
+ }
}
-constexpr std::u16string_view kUnamedName(u"UNNAMED");
-
-std::u16string_view RenderObject::GetName() const { return kUnamedName; }
+String kUnamedName(u"UNNAMED");
+String RenderObject::GetName() const { return kUnamedName; }
-std::u16string RenderObject::GetDebugPathInTree() const {
- std::vector<std::u16string_view> chain;
+String RenderObject::GetDebugPathInTree() const {
+ std::vector<String> chain;
const RenderObject* parent = this;
while (parent != nullptr) {
chain.push_back(parent->GetName());
parent = parent->GetParent();
}
- std::u16string result(chain.back());
+ String result(chain.back());
for (auto iter = chain.crbegin() + 1; iter != chain.crend(); ++iter) {
result += u" -> ";
result += *iter;
@@ -290,17 +209,4 @@ std::u16string RenderObject::GetDebugPathInTree() const {
return result;
}
-
-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->SetWindowHostRecursive(host);
- }
-}
} // namespace cru::ui::render
diff --git a/src/ui/render/ScrollBar.cpp b/src/ui/render/ScrollBar.cpp
index e3cc006b..e6389e16 100644
--- a/src/ui/render/ScrollBar.cpp
+++ b/src/ui/render/ScrollBar.cpp
@@ -452,7 +452,7 @@ bool HorizontalScrollBar::IsShowBar() {
if (child == nullptr) return false;
const auto view_rect = render_object_->GetViewRect();
- const auto child_size = child->GetSize();
+ const auto child_size = child->GetDesiredSize();
if (view_rect.width >= child_size.width) return false;
@@ -469,7 +469,7 @@ std::optional<Rect> HorizontalScrollBar::GetExpandedAreaRect(
const auto child = render_object_->GetFirstChild();
const auto view_rect = render_object_->GetViewRect();
- const auto child_size = child->GetSize();
+ const auto child_size = child->GetDesiredSize();
const float start_percentage = view_rect.left / child_size.width;
const float length_percentage = view_rect.width / child_size.width;
@@ -521,7 +521,7 @@ std::optional<Rect> HorizontalScrollBar::GetCollapsedThumbRect() {
const auto child = render_object_->GetFirstChild();
const auto view_rect = render_object_->GetViewRect();
- const auto child_size = child->GetSize();
+ const auto child_size = child->GetDesiredSize();
const float start_percentage = view_rect.left / child_size.width;
const float length_percentage = view_rect.width / child_size.width;
@@ -547,7 +547,7 @@ float HorizontalScrollBar::CalculateNewScrollPosition(
auto thumb_head_end = scroll_area_end - thumb_original_rect.width;
const auto child = render_object_->GetFirstChild();
- const auto child_size = child->GetSize();
+ const auto child_size = child->GetDesiredSize();
new_thumb_start =
std::clamp(new_thumb_start, scroll_area_start, thumb_head_end);
@@ -601,7 +601,7 @@ bool VerticalScrollBar::IsShowBar() {
if (child == nullptr) return false;
const auto view_rect = render_object_->GetViewRect();
- const auto child_size = child->GetSize();
+ const auto child_size = child->GetDesiredSize();
if (view_rect.height >= child_size.height) return false;
@@ -618,7 +618,7 @@ std::optional<Rect> VerticalScrollBar::GetExpandedAreaRect(
const auto child = render_object_->GetFirstChild();
const auto view_rect = render_object_->GetViewRect();
- const auto child_size = child->GetSize();
+ const auto child_size = child->GetDesiredSize();
const float start_percentage = view_rect.top / child_size.height;
const float length_percentage = view_rect.height / child_size.height;
@@ -668,7 +668,7 @@ std::optional<Rect> VerticalScrollBar::GetCollapsedThumbRect() {
const auto view_rect = render_object_->GetViewRect();
const auto padding_rect = render_object_->GetPaddingRect();
- const auto child_size = child->GetSize();
+ const auto child_size = child->GetDesiredSize();
if (view_rect.height >= child_size.height) return std::nullopt;
@@ -694,7 +694,7 @@ float VerticalScrollBar::CalculateNewScrollPosition(
auto thumb_head_end = scroll_area_end - thumb_original_rect.height;
const auto child = render_object_->GetFirstChild();
- const auto child_size = child->GetSize();
+ const auto child_size = child->GetDesiredSize();
new_thumb_start =
std::clamp(new_thumb_start, scroll_area_start, thumb_head_end);
diff --git a/src/ui/render/ScrollRenderObject.cpp b/src/ui/render/ScrollRenderObject.cpp
index 2400cc11..e2710de4 100644
--- a/src/ui/render/ScrollRenderObject.cpp
+++ b/src/ui/render/ScrollRenderObject.cpp
@@ -38,12 +38,19 @@ Point CoerceScroll(const Point& scroll_offset, const Size& content_size,
}
} // namespace
-ScrollRenderObject::ScrollRenderObject() : RenderObject(ChildMode::Single) {
+ScrollRenderObject::ScrollRenderObject() : RenderObject() {
scroll_bar_delegate_ = std::make_unique<ScrollBarDelegate>(this);
scroll_bar_delegate_->ScrollAttemptEvent()->AddHandler(
[this](const struct Scroll& scroll) { this->ApplyScroll(scroll); });
}
+void ScrollRenderObject::SetChild(RenderObject* new_child) {
+ if (child_ == new_child) return;
+ if (child_) child_->SetParent(nullptr);
+ child_ = new_child;
+ if (child_) child_->SetParent(this);
+}
+
void ScrollRenderObject::ApplyScroll(const struct Scroll& scroll) {
auto direction = scroll.direction;
@@ -72,9 +79,9 @@ void ScrollRenderObject::ApplyScroll(const struct Scroll& scroll) {
}
RenderObject* ScrollRenderObject::HitTest(const Point& point) {
- if (const auto child = GetSingleChild()) {
- const auto offset = child->GetOffset();
- const auto r = child->HitTest(point - offset);
+ if (child_) {
+ const auto offset = child_->GetOffset();
+ const auto r = child_->HitTest(point - offset);
if (r != nullptr) return r;
}
@@ -82,23 +89,23 @@ RenderObject* ScrollRenderObject::HitTest(const Point& point) {
return rect.IsPointInside(point) ? this : nullptr;
} // namespace cru::ui::render
-void ScrollRenderObject::OnDrawCore(platform::graphics::IPainter* painter) {
- DefaultDrawContent(painter);
- if (const auto child = GetSingleChild()) {
+void ScrollRenderObject::Draw(platform::graphics::IPainter* painter) {
+ if (child_) {
painter->PushLayer(this->GetContentRect());
- const auto offset = child->GetOffset();
- platform::graphics::util::WithTransform(
- painter, Matrix::Translation(offset.x, offset.y),
- [child](platform::graphics::IPainter* p) { child->Draw(p); });
+ const auto offset = child_->GetOffset();
+ painter->PushState();
+ painter->ConcatTransform(Matrix::Translation(offset));
+ child_->Draw(painter);
+ painter->PopState();
painter->PopLayer();
}
scroll_bar_delegate_->DrawScrollBar(painter);
}
Point ScrollRenderObject::GetScrollOffset() {
- if (const auto child = GetSingleChild())
+ if (child_)
return CoerceScroll(scroll_offset_, GetContentRect().GetSize(),
- child->GetSize());
+ child_->GetDesiredSize());
else
return scroll_offset_;
}
@@ -164,12 +171,12 @@ void ScrollRenderObject::SetMouseWheelScrollEnabled(bool enable) {
Size ScrollRenderObject::OnMeasureContent(const MeasureRequirement& requirement,
const MeasureSize& preferred_size) {
- if (const auto child = GetSingleChild()) {
- child->Measure(MeasureRequirement{MeasureSize::NotSpecified(),
- MeasureSize::NotSpecified()},
- MeasureSize::NotSpecified());
+ if (child_) {
+ child_->Measure(MeasureRequirement{MeasureSize::NotSpecified(),
+ MeasureSize::NotSpecified()},
+ MeasureSize::NotSpecified());
- Size result = requirement.Coerce(child->GetSize());
+ Size result = requirement.Coerce(child_->GetDesiredSize());
if (preferred_size.width.IsSpecified()) {
result.width = preferred_size.width.GetLengthOrUndefined();
}
@@ -189,16 +196,17 @@ Size ScrollRenderObject::OnMeasureContent(const MeasureRequirement& requirement,
} // namespace cru::ui::render
void ScrollRenderObject::OnLayoutContent(const Rect& content_rect) {
- if (const auto child = GetSingleChild()) {
- child->Layout(content_rect.GetLeftTop() - GetScrollOffset());
+ if (child_) {
+ child_->Layout(content_rect.GetLeftTop() - GetScrollOffset());
}
}
-void ScrollRenderObject::OnAttachedControlChanged(controls::Control* control) {
- if (control) {
- scroll_bar_delegate_->InstallHandlers(control);
+void ScrollRenderObject::OnAttachedControlChanged(
+ controls::Control* old_control, controls::Control* new_control) {
+ if (new_control) {
+ scroll_bar_delegate_->InstallHandlers(new_control);
if (is_mouse_wheel_enabled_) {
- InstallMouseWheelHandler(control);
+ InstallMouseWheelHandler(new_control);
}
} else {
InstallMouseWheelHandler(nullptr);
@@ -248,7 +256,7 @@ bool ScrollRenderObject::HorizontalCanScrollUp() {
bool ScrollRenderObject::HorizontalCanScrollDown() {
return GetScrollOffset().x <
- GetFirstChild()->GetSize().width - GetViewRect().width;
+ child_->GetDesiredSize().width - GetViewRect().width;
}
bool ScrollRenderObject::VerticalCanScrollUp() {
@@ -257,6 +265,6 @@ bool ScrollRenderObject::VerticalCanScrollUp() {
bool ScrollRenderObject::VerticalCanScrollDown() {
return GetScrollOffset().y <
- GetFirstChild()->GetSize().height - GetViewRect().height;
+ child_->GetDesiredSize().height - GetViewRect().height;
}
} // namespace cru::ui::render
diff --git a/src/ui/render/StackLayoutRenderObject.cpp b/src/ui/render/StackLayoutRenderObject.cpp
index ea65fe02..6c79716f 100644
--- a/src/ui/render/StackLayoutRenderObject.cpp
+++ b/src/ui/render/StackLayoutRenderObject.cpp
@@ -21,11 +21,12 @@ void StackLayoutRenderObject::SetDefaultVertialAlignment(Alignment alignment) {
Size StackLayoutRenderObject::OnMeasureContent(
const MeasureRequirement& requirement, const MeasureSize& preferred_size) {
Size child_max_size;
- for (const auto child : GetChildren()) {
+ for (int i = 0; i < GetChildCount(); i++) {
+ auto child = GetChildAt(i);
child->Measure(
MeasureRequirement(requirement.max, MeasureSize::NotSpecified()),
MeasureSize::NotSpecified());
- const auto size = child->GetSize();
+ const auto size = child->GetDesiredSize();
child_max_size.width = std::max(child_max_size.width, size.width);
child_max_size.height = std::max(child_max_size.height, size.height);
}
@@ -33,7 +34,7 @@ Size StackLayoutRenderObject::OnMeasureContent(
child_max_size = Max(preferred_size.GetSizeOr0(), child_max_size);
child_max_size = Max(requirement.min.GetSizeOr0(), child_max_size);
- for (Index i = 0; i < GetChildren().size(); ++i) {
+ for (Index i = 0; i < GetChildCount(); ++i) {
auto child_layout_data = GetChildLayoutData(i);
auto horizontal_stretch =
child_layout_data.horizontal.value_or(default_horizontal_alignment_) ==
@@ -42,8 +43,8 @@ Size StackLayoutRenderObject::OnMeasureContent(
child_layout_data.vertical.value_or(default_vertical_alignment_) ==
Alignment::Stretch;
if (horizontal_stretch || vertical_stretch) {
- auto child = GetChildren()[i];
- auto child_size = child->GetSize();
+ auto child = GetChildAt(i);
+ auto child_size = child->GetDesiredSize();
MeasureRequirement child_requirement(child_size, child_size);
if (horizontal_stretch) {
child_requirement.min.width = child_requirement.max.width =
@@ -63,12 +64,11 @@ Size StackLayoutRenderObject::OnMeasureContent(
void StackLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
const auto count = GetChildCount();
- const auto& children = GetChildren();
for (int i = 0; i < count; i++) {
- const auto child = children[i];
+ const auto child = GetChildAt(i);
const auto& layout_data = GetChildLayoutData(i);
- const auto& size = child->GetSize();
+ const auto& size = child->GetDesiredSize();
child->Layout(Point{
CalculateAnchorByAlignment(
layout_data.horizontal.value_or(default_horizontal_alignment_),
diff --git a/src/ui/render/TextRenderObject.cpp b/src/ui/render/TextRenderObject.cpp
index 675bac3c..ec5ce662 100644
--- a/src/ui/render/TextRenderObject.cpp
+++ b/src/ui/render/TextRenderObject.cpp
@@ -21,8 +21,6 @@ TextRenderObject::TextRenderObject(
Expects(selection_brush);
Expects(caret_brush);
- SetChildMode(ChildMode::None);
-
brush.swap(brush_);
font.swap(font_);
selection_brush.swap(selection_brush_);
@@ -176,16 +174,19 @@ RenderObject* TextRenderObject::HitTest(const Point& point) {
return padding_rect.IsPointInside(point) ? this : nullptr;
}
-void TextRenderObject::OnDrawContent(platform::graphics::IPainter* painter) {
+void TextRenderObject::Draw(platform::graphics::IPainter* painter) {
if constexpr (debug_flags::draw) {
log::TagDebug(log_tag,
u"Begin to paint, total_offset: {}, size: {}, text_layout: "
u"{}, brush: {}.",
- this->GetTotalOffset(), this->GetSize(),
+ this->GetTotalOffset(), this->GetDesiredSize(),
this->text_layout_->GetDebugString(),
this->brush_->GetDebugString());
}
+ painter->PushState();
+ painter->ConcatTransform(Matrix::Translation(GetOffset()));
+
if (this->selection_range_.has_value()) {
const auto&& rects =
text_layout_->TextRangeRect(this->selection_range_.value());
@@ -198,6 +199,8 @@ void TextRenderObject::OnDrawContent(platform::graphics::IPainter* painter) {
if (this->draw_caret_ && this->caret_width_ != 0.0f) {
painter->FillRectangle(GetCaretRectInContent(), this->caret_brush_.get());
}
+
+ painter->PopState();
}
Size TextRenderObject::OnMeasureContent(const MeasureRequirement& requirement,
@@ -229,6 +232,4 @@ Size TextRenderObject::OnMeasureContent(const MeasureRequirement& requirement,
void TextRenderObject::OnLayoutContent(const Rect& content_rect) {
CRU_UNUSED(content_rect)
}
-
-void TextRenderObject::OnAfterLayout() {}
} // namespace cru::ui::render
diff --git a/src/ui/render/TreeRenderObject.cpp b/src/ui/render/TreeRenderObject.cpp
index bea5b9de..9bf74535 100644
--- a/src/ui/render/TreeRenderObject.cpp
+++ b/src/ui/render/TreeRenderObject.cpp
@@ -34,7 +34,6 @@ void TreeRenderObjectItem::RemoveItem(Index position) {
}
TreeRenderObject::TreeRenderObject() {
- SetChildMode(ChildMode::None);
root_item_ = new TreeRenderObjectItem(this, nullptr);
}
@@ -81,7 +80,7 @@ void TreeRenderObjectItemDraw(TreeRenderObjectItem* item,
}
}
-void TreeRenderObject::OnDrawCore(platform::graphics::IPainter* painter) {
+void TreeRenderObject::Draw(platform::graphics::IPainter* painter) {
TreeRenderObjectItemDraw(root_item_, painter);
}
@@ -95,7 +94,7 @@ static Size MeasureTreeRenderObjectItem(MeasureSize max_size,
MeasureSize::NotSpecified());
}
- Size item_size = render_object ? render_object->GetSize() : Size{};
+ Size item_size = render_object ? render_object->GetDesiredSize() : Size{};
if (max_size.width.IsSpecified()) {
max_size.width = max_size.width.GetLengthOrUndefined() - tab_width;
@@ -133,7 +132,7 @@ static void LayoutTreeRenderObjectItem(Rect rect, TreeRenderObjectItem* item,
float item_height = 0.f;
if (render_object) {
render_object->Layout(rect.GetLeftTop());
- item_height = render_object->GetSize().height;
+ item_height = render_object->GetDesiredSize().height;
}
rect.left += tab_width;
@@ -144,8 +143,9 @@ static void LayoutTreeRenderObjectItem(Rect rect, TreeRenderObjectItem* item,
for (auto child : item->GetChildren()) {
LayoutTreeRenderObjectItem(rect, child, tab_width);
auto child_render_object = child->GetRenderObject();
- auto child_height =
- child_render_object ? child_render_object->GetSize().height : 0.f;
+ auto child_height = child_render_object
+ ? child_render_object->GetDesiredSize().height
+ : 0.f;
rect.top += child_height;
rect.height -= child_height;
}