aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/ui/render/BorderRenderObject.hpp7
-rw-r--r--include/cru/ui/render/MeasureRequirement.hpp24
-rw-r--r--include/cru/ui/render/RenderObject.hpp6
-rw-r--r--include/cru/ui/render/ScrollRenderObject.hpp4
-rw-r--r--src/ui/render/BorderRenderObject.cpp37
-rw-r--r--src/ui/render/FlexLayoutRenderObject.cpp2
-rw-r--r--src/ui/render/RenderObject.cpp23
-rw-r--r--src/ui/render/ScrollRenderObject.cpp59
8 files changed, 110 insertions, 52 deletions
diff --git a/include/cru/ui/render/BorderRenderObject.hpp b/include/cru/ui/render/BorderRenderObject.hpp
index 45df89f9..b1fc4ba2 100644
--- a/include/cru/ui/render/BorderRenderObject.hpp
+++ b/include/cru/ui/render/BorderRenderObject.hpp
@@ -74,11 +74,10 @@ class BorderRenderObject : public RenderObject {
void OnAfterLayout() override;
- private:
- RenderObject* GetChild() const {
- return GetChildren().empty() ? nullptr : GetChildren()[0];
- }
+ Rect GetPaddingRect() const override;
+ Rect GetContentRect() const override;
+ private:
void RecreateGeometry();
private:
diff --git a/include/cru/ui/render/MeasureRequirement.hpp b/include/cru/ui/render/MeasureRequirement.hpp
index 83de255d..661f40a9 100644
--- a/include/cru/ui/render/MeasureRequirement.hpp
+++ b/include/cru/ui/render/MeasureRequirement.hpp
@@ -6,11 +6,11 @@
namespace cru::ui::render {
class MeasureLength {
public:
- struct tag_infinate_t {};
- constexpr static tag_infinate_t tag_infinate{};
+ struct tag_not_specify_t {};
+ constexpr static tag_not_specify_t tag_not_specify{};
constexpr MeasureLength() : MeasureLength(0) {}
- constexpr MeasureLength(tag_infinate_t) : length_(-1) {}
+ constexpr MeasureLength(tag_not_specify_t) : length_(-1) {}
constexpr MeasureLength(float length) : length_(length) {
Expects(length >= 0);
}
@@ -25,11 +25,15 @@ class MeasureLength {
~MeasureLength() = default;
- constexpr static MeasureLength Infinate() {
- return MeasureLength{tag_infinate};
+ constexpr static MeasureLength NotSpecify() {
+ return MeasureLength{tag_not_specify};
}
- constexpr bool IsInfinate() const { return length_ < 0; }
+ // What not specify means depends on situation.
+ // For max size, it means no limit.
+ constexpr bool IsNotSpecify() const { return length_ < 0; }
+
+ // If not specify max value of float is returned.
constexpr float GetLength() const {
return length_ < 0 ? std::numeric_limits<float>::max() : length_;
}
@@ -60,9 +64,9 @@ struct MeasureRequirement {
: max_width(max_size.width), max_height(max_size.height) {}
constexpr bool Satisfy(const Size& size) const {
- if (!max_width.IsInfinate() && max_width.GetLength() < size.width)
+ if (!max_width.IsNotSpecify() && max_width.GetLength() < size.width)
return false;
- if (!max_height.IsInfinate() && max_height.GetLength() < size.height)
+ if (!max_height.IsNotSpecify() && max_height.GetLength() < size.height)
return false;
return true;
}
@@ -72,8 +76,8 @@ struct MeasureRequirement {
}
constexpr static MeasureRequirement Infinate() {
- return MeasureRequirement{MeasureLength::Infinate(),
- MeasureLength::Infinate()};
+ return MeasureRequirement{MeasureLength::NotSpecify(),
+ MeasureLength::NotSpecify()};
}
};
} // namespace cru::ui::render
diff --git a/include/cru/ui/render/RenderObject.hpp b/include/cru/ui/render/RenderObject.hpp
index 9de2cc27..72716d2e 100644
--- a/include/cru/ui/render/RenderObject.hpp
+++ b/include/cru/ui/render/RenderObject.hpp
@@ -84,6 +84,8 @@ class RenderObject : public Object {
void SetChildMode(ChildMode mode) { child_mode_ = mode; }
protected:
+ RenderObject* GetSingleChild() const;
+
virtual void OnParentChanged(RenderObject* old_parent,
RenderObject* new_parent);
@@ -114,8 +116,8 @@ class RenderObject : public Object {
virtual void OnAfterLayout();
static void NotifyAfterLayoutRecursive(RenderObject* render_object);
- Rect GetPaddingRect() const;
- Rect GetContentRect() const;
+ virtual Rect GetPaddingRect() const;
+ virtual Rect GetContentRect() const;
private:
void SetParent(RenderObject* new_parent);
diff --git a/include/cru/ui/render/ScrollRenderObject.hpp b/include/cru/ui/render/ScrollRenderObject.hpp
index 924b8ca6..774501a1 100644
--- a/include/cru/ui/render/ScrollRenderObject.hpp
+++ b/include/cru/ui/render/ScrollRenderObject.hpp
@@ -17,8 +17,10 @@ class ScrollRenderObject : public RenderObject {
RenderObject* HitTest(const Point& point) override;
- Point GetScrollOffset() { return scroll_offset_; }
+ // Return the coerced scroll offset.
+ Point GetScrollOffset();
void SetScrollOffset(const Point& offset);
+ Point GetRawScrollOffset() const { return scroll_offset_; }
protected:
// Logic:
diff --git a/src/ui/render/BorderRenderObject.cpp b/src/ui/render/BorderRenderObject.cpp
index fbc3c65f..ad0c6455 100644
--- a/src/ui/render/BorderRenderObject.cpp
+++ b/src/ui/render/BorderRenderObject.cpp
@@ -27,7 +27,7 @@ void BorderRenderObject::Draw(platform::graph::IPainter* painter) {
painter->FillGeometry(geometry_.get(), border_brush_.get());
}
}
- if (const auto child = GetChild()) {
+ if (const auto child = GetSingleChild()) {
auto offset = child->GetOffset();
platform::graph::util::WithTransform(
painter, platform::Matrix::Translation(offset.x, offset.y),
@@ -48,7 +48,7 @@ void BorderRenderObject::SetBorderStyle(const BorderStyle& style) {
}
RenderObject* BorderRenderObject::HitTest(const Point& point) {
- if (const auto child = GetChild()) {
+ 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);
@@ -90,7 +90,7 @@ Size BorderRenderObject::OnMeasureCore(const MeasureRequirement& requirement) {
MeasureRequirement content_requirement = requirement;
- if (!requirement.max_width.IsInfinate()) {
+ if (!requirement.max_width.IsNotSpecify()) {
const auto max_width = requirement.max_width.GetLength();
if (coerced_space_size.width > max_width) {
log::Warn(
@@ -101,7 +101,7 @@ Size BorderRenderObject::OnMeasureCore(const MeasureRequirement& requirement) {
content_requirement.max_width = max_width - coerced_space_size.width;
}
- if (!requirement.max_height.IsInfinate()) {
+ if (!requirement.max_height.IsNotSpecify()) {
const auto max_height = requirement.max_height.GetLength();
if (coerced_space_size.height > max_height) {
log::Warn(
@@ -160,7 +160,7 @@ void BorderRenderObject::OnLayoutCore(const Size& size) {
Size BorderRenderObject::OnMeasureContent(
const MeasureRequirement& requirement) {
- const auto child = GetChild();
+ const auto child = GetSingleChild();
if (child) {
child->Measure(requirement);
return child->GetMeasuredSize();
@@ -170,7 +170,7 @@ Size BorderRenderObject::OnMeasureContent(
}
void BorderRenderObject::OnLayoutContent(const Rect& content_rect) {
- const auto child = GetChild();
+ const auto child = GetSingleChild();
if (child) {
child->Layout(content_rect);
}
@@ -178,6 +178,31 @@ void BorderRenderObject::OnLayoutContent(const Rect& content_rect) {
void BorderRenderObject::OnAfterLayout() { RecreateGeometry(); }
+Rect BorderRenderObject::GetPaddingRect() const {
+ const auto size = GetSize();
+ Rect rect{Point{}, size};
+ rect = rect.Shrink(GetMargin());
+ if (is_border_enabled_) rect = rect.Shrink(border_thickness_);
+ rect.left = std::min(rect.left, size.width);
+ rect.top = std::min(rect.top, size.height);
+ rect.width = std::max(rect.width, 0.0f);
+ rect.height = std::max(rect.height, 0.0f);
+ return rect;
+}
+
+Rect BorderRenderObject::GetContentRect() const {
+ const auto size = GetSize();
+ Rect rect{Point{}, size};
+ rect = rect.Shrink(GetMargin());
+ if (is_border_enabled_) rect = rect.Shrink(border_thickness_);
+ rect = rect.Shrink(GetPadding());
+ rect.left = std::min(rect.left, size.width);
+ rect.top = std::min(rect.top, size.height);
+ rect.width = std::max(rect.width, 0.0f);
+ rect.height = std::max(rect.height, 0.0f);
+ return rect;
+}
+
void BorderRenderObject::RecreateGeometry() {
geometry_.reset();
border_outer_geometry_.reset();
diff --git a/src/ui/render/FlexLayoutRenderObject.cpp b/src/ui/render/FlexLayoutRenderObject.cpp
index 98eda066..72341a64 100644
--- a/src/ui/render/FlexLayoutRenderObject.cpp
+++ b/src/ui/render/FlexLayoutRenderObject.cpp
@@ -47,7 +47,7 @@ Size FlexLayoutRenderObject::OnMeasureContent(
const auto& children = GetChildren();
Index children_count = children.size();
- if (!main_max_length.IsInfinate()) {
+ if (!main_max_length.IsNotSpecify()) {
float remain_main_length = main_max_length.GetLength();
for (Index i = 0; i < children_count; i++) {
diff --git a/src/ui/render/RenderObject.cpp b/src/ui/render/RenderObject.cpp
index cdc3032f..abd5e1c4 100644
--- a/src/ui/render/RenderObject.cpp
+++ b/src/ui/render/RenderObject.cpp
@@ -73,6 +73,15 @@ void RenderObject::Layout(const Rect& rect) {
OnLayoutCore(rect.GetSize());
}
+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)
@@ -104,7 +113,7 @@ Size RenderObject::OnMeasureCore(const MeasureRequirement& requirement) {
MeasureRequirement content_requirement = requirement;
- if (!requirement.max_width.IsInfinate()) {
+ if (!requirement.max_width.IsNotSpecify()) {
const auto max_width = requirement.max_width.GetLength();
if (coerced_space_size.width > max_width) {
log::Warn(
@@ -115,7 +124,7 @@ Size RenderObject::OnMeasureCore(const MeasureRequirement& requirement) {
content_requirement.max_width = max_width - coerced_space_size.width;
}
- if (!requirement.max_height.IsInfinate()) {
+ if (!requirement.max_height.IsNotSpecify()) {
const auto max_height = requirement.max_height.GetLength();
if (coerced_space_size.height > max_height) {
log::Warn(
@@ -166,17 +175,23 @@ void RenderObject::OnLayoutCore(const Size& size) {
void RenderObject::OnAfterLayout() {}
Rect RenderObject::GetPaddingRect() const {
- Rect rect{Point{}, GetSize()};
+ const auto size = GetSize();
+ Rect rect{Point{}, size};
rect = rect.Shrink(GetMargin());
+ rect.left = std::min(rect.left, size.width);
+ rect.top = std::min(rect.top, size.height);
rect.width = std::max(rect.width, 0.0f);
rect.height = std::max(rect.height, 0.0f);
return rect;
}
Rect RenderObject::GetContentRect() const {
- Rect rect{Point{}, GetSize()};
+ const auto size = GetSize();
+ Rect rect{Point{}, size};
rect = rect.Shrink(GetMargin());
rect = rect.Shrink(GetPadding());
+ rect.left = std::min(rect.left, size.width);
+ rect.top = std::min(rect.top, size.height);
rect.width = std::max(rect.width, 0.0f);
rect.height = std::max(rect.height, 0.0f);
return rect;
diff --git a/src/ui/render/ScrollRenderObject.cpp b/src/ui/render/ScrollRenderObject.cpp
index f1df9d8b..98254690 100644
--- a/src/ui/render/ScrollRenderObject.cpp
+++ b/src/ui/render/ScrollRenderObject.cpp
@@ -2,6 +2,7 @@
#include "cru/platform/graph/Painter.hpp"
#include "cru/platform/graph/util/Painter.hpp"
+#include "cru/ui/render/LayoutUtility.hpp"
#include <algorithm>
@@ -9,13 +10,11 @@ namespace cru::ui::render {
namespace {
// This method assumes margin offset is already considered.
// It promises that it won't return negetive value.
-Point CalculateChildOffsetOfScroll(const Point& scroll_offset,
- const Size& content_area_size,
- const Thickness& padding,
- const Size& child_size) {
+Point CoerceScroll(const Point& scroll_offset, const Size& content_size,
+ const Size& child_size) {
Point result(scroll_offset);
- Point max_scroll(child_size - content_area_size);
+ Point max_scroll(child_size - content_size);
max_scroll.x = std::max(max_scroll.x, 0.f);
max_scroll.y = std::max(max_scroll.y, 0.f);
@@ -29,50 +28,62 @@ Point CalculateChildOffsetOfScroll(const Point& scroll_offset,
coerce(result.x, scroll_offset.x);
coerce(result.y, scroll_offset.y);
- result.x += padding.left;
- result.y += padding.top;
-
return result;
}
} // namespace
void ScrollRenderObject::Draw(platform::graph::IPainter* painter) {
- for (auto child : this->GetChildren()) {
+ if (const auto child = GetSingleChild()) {
painter->PushLayer(this->GetPaddingRect());
- const auto true_offset =
- CalculateChildOffsetOfScroll(scroll_offset_, GetContentRect().GetSize(),
- GetPadding(), child->GetSize());
+ const auto offset = child->GetOffset();
platform::graph::util::WithTransform(
- painter, Matrix::Translation(true_offset.x, true_offset.y),
+ painter, Matrix::Translation(offset.x, offset.y),
[child](platform::graph::IPainter* p) { child->Draw(p); });
painter->PopLayer();
}
}
RenderObject* ScrollRenderObject::HitTest(const Point& point) {
+ if (const auto child = GetSingleChild()) {
+ const auto offset = child->GetOffset();
+ const auto r = child->HitTest(point - offset);
+ if (r != nullptr) return r;
+ }
+
const auto rect = GetPaddingRect();
return rect.IsPointInside(point) ? this : nullptr;
+} // namespace cru::ui::render
+
+Point ScrollRenderObject::GetScrollOffset() {
+ if (const auto child = GetSingleChild())
+ return CoerceScroll(scroll_offset_, GetContentRect().GetSize(),
+ child->GetSize());
+ else
+ return scroll_offset_;
}
void ScrollRenderObject::SetScrollOffset(const Point& offset) {
scroll_offset_ = offset;
- InvalidatePaint();
+ InvalidateLayout();
}
Size ScrollRenderObject::OnMeasureContent(
const MeasureRequirement& requirement) {
- CRU_UNUSED(requirement);
- // TODO!
- // const auto& children = GetChildren();
- // if (children.empty()) return Size{};
- // const auto child = children.front();
- // child->Measure(MeasureRequirement::Infinate());
- // const auto preferred_size = child->GetMeasuredSize();
- return Size{};
+ if (const auto child = GetSingleChild()) {
+ child->Measure(MeasureRequirement::Infinate());
+ const auto preferred_size = child->GetMeasuredSize();
+ return Min(preferred_size, requirement.GetMaxSize());
+ } else {
+ return Size{};
+ }
} // namespace cru::ui::render
void ScrollRenderObject::OnLayoutContent(const Rect& content_rect) {
- CRU_UNUSED(content_rect);
- // TODO!
+ if (const auto child = GetSingleChild()) {
+ const auto child_size = child->GetMeasuredSize();
+ const auto true_scroll =
+ CoerceScroll(scroll_offset_, content_rect.GetSize(), child_size);
+ child->Layout(Rect{content_rect.GetLeftTop() - true_scroll, child_size});
+ }
}
} // namespace cru::ui::render