aboutsummaryrefslogtreecommitdiff
path: root/include/cru/ui/render/layout_render_object.hpp
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-03-01 22:08:15 +0800
committercrupest <crupest@outlook.com>2020-03-01 22:08:15 +0800
commit6e0e0e18cbeff6487160c84d71997575f6cccebd (patch)
tree9b4c552234dfc4f9b5129dd96b25dba3518e4581 /include/cru/ui/render/layout_render_object.hpp
parent8fc4e33b97372d93b1bcc4b598e5c8e2f15652d8 (diff)
downloadcru-6e0e0e18cbeff6487160c84d71997575f6cccebd.tar.gz
cru-6e0e0e18cbeff6487160c84d71997575f6cccebd.tar.bz2
cru-6e0e0e18cbeff6487160c84d71997575f6cccebd.zip
Add stack layout.
Diffstat (limited to 'include/cru/ui/render/layout_render_object.hpp')
-rw-r--r--include/cru/ui/render/layout_render_object.hpp91
1 files changed, 91 insertions, 0 deletions
diff --git a/include/cru/ui/render/layout_render_object.hpp b/include/cru/ui/render/layout_render_object.hpp
new file mode 100644
index 00000000..db6daba9
--- /dev/null
+++ b/include/cru/ui/render/layout_render_object.hpp
@@ -0,0 +1,91 @@
+#pragma once
+#include "render_object.hpp"
+
+#include "cru/platform/graph/util/painter.hpp"
+
+#include <cassert>
+#include <functional>
+
+namespace cru::ui::render {
+template <typename TChildLayoutData>
+class LayoutRenderObject : public RenderObject {
+ public:
+ using ChildLayoutData = TChildLayoutData;
+
+ protected:
+ LayoutRenderObject() : RenderObject(ChildMode::Multiple) {}
+
+ public:
+ CRU_DELETE_COPY(LayoutRenderObject)
+ CRU_DELETE_MOVE(LayoutRenderObject)
+
+ ~LayoutRenderObject() override = default;
+
+ ChildLayoutData* GetChildLayoutData(int position) {
+ assert(position >= 0 &&
+ position < static_cast<int>(child_layout_data_.size()));
+ return &child_layout_data_[position];
+ }
+
+ void Draw(platform::graph::IPainter* painter) override;
+
+ RenderObject* HitTest(const Point& point) override;
+
+ protected:
+ void OnAddChild(RenderObject* new_child, int position) override;
+ void OnRemoveChild(RenderObject* removed_child, int position) override;
+
+ private:
+ std::vector<ChildLayoutData> child_layout_data_{};
+};
+
+template <typename TChildLayoutData>
+void LayoutRenderObject<TChildLayoutData>::Draw(
+ platform::graph::IPainter* painter) {
+ for (const auto child : GetChildren()) {
+ auto offset = child->GetOffset();
+ platform::graph::util::WithTransform(
+ painter, platform::Matrix::Translation(offset.x, offset.y),
+ [child](auto p) { child->Draw(p); });
+ }
+}
+
+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,
+ int position) {
+ CRU_UNUSED(new_child)
+
+ child_layout_data_.emplace(child_layout_data_.cbegin() + position);
+}
+
+template <typename TChildLayoutData>
+void LayoutRenderObject<TChildLayoutData>::OnRemoveChild(
+ RenderObject* removed_child, int position) {
+ CRU_UNUSED(removed_child)
+
+ child_layout_data_.erase(child_layout_data_.cbegin() + position);
+}
+} // namespace cru::ui::render