aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/application.hpp2
-rw-r--r--src/math_util.hpp2
-rw-r--r--src/ui/render/render_object.cpp121
-rw-r--r--src/ui/render/render_object.hpp189
4 files changed, 312 insertions, 2 deletions
diff --git a/src/application.hpp b/src/application.hpp
index a8d59cc8..8d739938 100644
--- a/src/application.hpp
+++ b/src/application.hpp
@@ -109,7 +109,7 @@ namespace cru
std::unordered_map<std::type_index, Object*> singleton_map_;
std::list<Object*> singleton_list_; // used for reverse destroy.
#ifdef CRU_DEBUG
- std::unordered_set<std::type_index> singleton_type_set_; // used for dead recursion.
+ std::unordered_set<std::type_index> singleton_type_set_; // used for detecting dead recursion.
#endif
};
diff --git a/src/math_util.hpp b/src/math_util.hpp
index b9830d6b..8f0741b8 100644
--- a/src/math_util.hpp
+++ b/src/math_util.hpp
@@ -9,7 +9,7 @@
namespace cru
{
- template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
+ template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
float Coerce(const T n, const std::optional<T> min, const std::optional<T> max)
{
if (min.has_value() && n < min.value())
diff --git a/src/ui/render/render_object.cpp b/src/ui/render/render_object.cpp
new file mode 100644
index 00000000..d84d1d8b
--- /dev/null
+++ b/src/ui/render/render_object.cpp
@@ -0,0 +1,121 @@
+#include "render_object.hpp"
+#include <utility>
+
+namespace cru::ui::render
+{
+ void RenderObject::SetRenderHost(IRenderHost* new_render_host)
+ {
+ if (new_render_host == render_host_)
+ return;
+
+ const auto old = render_host_;
+ render_host_ = new_render_host;
+ OnRenderHostChanged(old, new_render_host);
+ }
+
+ void RenderObject::OnRenderHostChanged(IRenderHost* old_render_host, IRenderHost* new_render_host)
+ {
+
+ }
+
+ void RenderObject::InvalidateRenderHost()
+ {
+ if (render_host_ != nullptr)
+ render_host_->InvalidateRender();
+ }
+
+ SingleChildRenderObject::~SingleChildRenderObject()
+ {
+ delete child_;
+ }
+
+ void SingleChildRenderObject::SetChild(RenderObject* new_child)
+ {
+ const auto old = child_;
+ if (old)
+ old->SetRenderHost(nullptr);
+ child_ = new_child;
+ if (new_child)
+ new_child->SetRenderHost(GetRenderHost());
+ OnChildChange(old, new_child);
+ InvalidateRenderHost();
+ }
+
+ void SingleChildRenderObject::OnRenderHostChanged(IRenderHost* old_render_host, IRenderHost* new_render_host)
+ {
+ if (child_)
+ child_->SetRenderHost(new_render_host);
+ }
+
+ void SingleChildRenderObject::OnChildChange(RenderObject* old_child, RenderObject* new_object)
+ {
+
+ }
+
+ ClipRenderObject::ClipRenderObject(Microsoft::WRL::ComPtr<ID2D1Geometry> clip_geometry)
+ : clip_geometry_(std::move(clip_geometry))
+ {
+
+ }
+
+ void ClipRenderObject::SetClipGeometry(Microsoft::WRL::ComPtr<ID2D1Geometry> new_clip_geometry)
+ {
+ clip_geometry_ = std::move(new_clip_geometry);
+ InvalidateRenderHost();
+ }
+
+ void ClipRenderObject::Draw(ID2D1RenderTarget* render_target)
+ {
+ if (clip_geometry_ != nullptr)
+ render_target->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), clip_geometry_.Get()), nullptr);
+ const auto child = GetChild();
+ if (child != nullptr)
+ child->Draw(render_target);
+ if (clip_geometry_ != nullptr)
+ render_target->PopLayer();
+ }
+
+ void MatrixRenderObject::ApplyAppendMatrix(ID2D1RenderTarget* render_target, const D2D1_MATRIX_3X2_F& matrix)
+ {
+ D2D1::Matrix3x2F old_matrix;
+ render_target->GetTransform(&old_matrix);
+ render_target->SetTransform(old_matrix * matrix);
+ }
+
+ void MatrixRenderObject::ApplySetMatrix(ID2D1RenderTarget* render_target, const D2D1_MATRIX_3X2_F& matrix)
+ {
+ render_target->SetTransform(matrix);
+ }
+
+ MatrixRenderObject::MatrixRenderObject(const D2D1_MATRIX_3X2_F& matrix, MatrixApplier applier)
+ : matrix_(matrix), applier_(std::move(applier))
+ {
+
+ }
+
+ void MatrixRenderObject::SetMatrix(const D2D1_MATRIX_3X2_F& new_matrix)
+ {
+ matrix_ = new_matrix;
+ InvalidateRenderHost();
+ }
+
+ void MatrixRenderObject::SetMatrixApplier(MatrixApplier applier)
+ {
+ applier_ = std::move(applier);
+ InvalidateRenderHost();
+ }
+
+ void MatrixRenderObject::Draw(ID2D1RenderTarget* render_target)
+ {
+ D2D1_MATRIX_3X2_F old_matrix;
+ render_target->GetTransform(&old_matrix);
+ applier_(render_target, matrix_);
+ const auto child = GetChild();
+ if (child)
+ child->Draw(render_target);
+ render_target->SetTransform(&old_matrix);
+ }
+
+ const MatrixRenderObject::MatrixApplier MatrixRenderObject::append_applier(ApplyAppendMatrix);
+ const MatrixRenderObject::MatrixApplier MatrixRenderObject::set_applier(ApplySetMatrix);
+}
diff --git a/src/ui/render/render_object.hpp b/src/ui/render/render_object.hpp
new file mode 100644
index 00000000..3a8777d8
--- /dev/null
+++ b/src/ui/render/render_object.hpp
@@ -0,0 +1,189 @@
+#pragma once
+
+#include "pre.hpp"
+
+#include "system_headers.hpp"
+#include <functional>
+
+#include "base.hpp"
+#include "ui/ui_base.hpp"
+
+namespace cru::ui::render
+{
+ /* About Render Object
+ *
+ * Render object is a concrete subclass of RenderObject class.
+ * It represents a painting action on a d2d render target. By
+ * overriding "Draw" virtual method, it can customize its painting
+ * action.
+ *
+ * Render object may have implicit children to form a tree.
+ * RenderObject class doesn't provide any method to access children.
+ * Instead any concrete render object manage their own child model
+ * and interface and optionally call Draw on children so when root
+ * call Draw descendants' Draw will be called recursively.
+ *
+ * Related render objects of a control are a subtree of the whole tree.
+ * So render objects can be composed easily to form a whole control.
+ *
+ * Render object may do no actual drawing but perform particular
+ * actions on render target. Like ClipRenderObject apply a clip on
+ * render target, MatrixRenderObject apply a matrix on render
+ * target.
+ */
+
+
+
+ struct IRenderHost : Interface
+ {
+ virtual void InvalidateRender() = 0;
+ };
+
+
+ class RenderObject : public Object
+ {
+ protected:
+ RenderObject() = default;
+ public:
+ RenderObject(const RenderObject& other) = delete;
+ RenderObject(RenderObject&& other) = delete;
+ RenderObject& operator=(const RenderObject& other) = delete;
+ RenderObject& operator=(RenderObject&& other) = delete;
+ ~RenderObject() override = default;
+
+ virtual void Draw(ID2D1RenderTarget* render_target) = 0;
+
+ IRenderHost* GetRenderHost() const
+ {
+ return render_host_;
+ }
+
+ void SetRenderHost(IRenderHost* new_render_host);
+
+ protected:
+ virtual void OnRenderHostChanged(IRenderHost* old_render_host, IRenderHost* new_render_host);
+
+ void InvalidateRenderHost();
+
+ private:
+ IRenderHost* render_host_ = nullptr;
+ };
+
+
+ // It is subclass duty to call child's Draw.
+ class SingleChildRenderObject : public RenderObject
+ {
+ protected:
+ SingleChildRenderObject() = default;
+ public:
+ SingleChildRenderObject(const SingleChildRenderObject& other) = delete;
+ SingleChildRenderObject(SingleChildRenderObject&& other) = delete;
+ SingleChildRenderObject& operator=(const SingleChildRenderObject& other) = delete;
+ SingleChildRenderObject& operator=(SingleChildRenderObject&& other) = delete;
+ ~SingleChildRenderObject();
+
+ RenderObject* GetChild() const
+ {
+ return child_;
+ }
+
+ void SetChild(RenderObject* new_child);
+
+ protected:
+ void OnRenderHostChanged(IRenderHost* old_render_host, IRenderHost* new_render_host) override;
+
+ virtual void OnChildChange(RenderObject* old_child, RenderObject* new_object);
+
+ private:
+ RenderObject* child_ = nullptr;
+ };
+
+
+ class ClipRenderObject final : public SingleChildRenderObject
+ {
+ public:
+ explicit ClipRenderObject(Microsoft::WRL::ComPtr<ID2D1Geometry> clip_geometry = nullptr);
+ ClipRenderObject(const ClipRenderObject& other) = delete;
+ ClipRenderObject(ClipRenderObject&& other) = delete;
+ ClipRenderObject& operator=(const ClipRenderObject& other) = delete;
+ ClipRenderObject& operator=(ClipRenderObject&& other) = delete;
+ ~ClipRenderObject() = default;
+
+ Microsoft::WRL::ComPtr<ID2D1Geometry> GetClipGeometry() const
+ {
+ return clip_geometry_;
+ }
+ void SetClipGeometry(Microsoft::WRL::ComPtr<ID2D1Geometry> new_clip_geometry);
+
+ void Draw(ID2D1RenderTarget* render_target) override final;
+
+ private:
+ Microsoft::WRL::ComPtr<ID2D1Geometry> clip_geometry_;
+ };
+
+
+ class MatrixRenderObject: public SingleChildRenderObject
+ {
+ private:
+ static void ApplyAppendMatrix(ID2D1RenderTarget* render_target, const D2D1_MATRIX_3X2_F& matrix);
+ static void ApplySetMatrix(ID2D1RenderTarget* render_target, const D2D1_MATRIX_3X2_F& matrix);
+
+ public:
+ using MatrixApplier = std::function<void(ID2D1RenderTarget*, const D2D1_MATRIX_3X2_F&)>;
+
+ static const MatrixApplier append_applier;
+ static const MatrixApplier set_applier;
+
+ explicit MatrixRenderObject(const D2D1_MATRIX_3X2_F& matrix = D2D1::Matrix3x2F::Identity(),
+ MatrixApplier applier = append_applier);
+ MatrixRenderObject(const MatrixRenderObject& other) = delete;
+ MatrixRenderObject(MatrixRenderObject&& other) = delete;
+ MatrixRenderObject& operator=(const MatrixRenderObject& other) = delete;
+ MatrixRenderObject& operator=(MatrixRenderObject&& other) = delete;
+ ~MatrixRenderObject() = default;
+
+ D2D1_MATRIX_3X2_F GetMatrix() const
+ {
+ return matrix_;
+ }
+
+ void SetMatrix(const D2D1_MATRIX_3X2_F& new_matrix);
+
+ MatrixApplier GetMatrixApplier() const
+ {
+ return applier_;
+ }
+
+ void SetMatrixApplier(MatrixApplier applier);
+
+ void Draw(ID2D1RenderTarget* render_target) override final;
+
+ private:
+ D2D1_MATRIX_3X2_F matrix_;
+ MatrixApplier applier_;
+ };
+
+
+ class OffsetRenderObject : public MatrixRenderObject
+ {
+ public:
+ OffsetRenderObject(const float offset_x, const float offset_y) : MatrixRenderObject(D2D1::Matrix3x2F::Translation(offset_x, offset_y))
+ {
+
+ }
+ };
+
+
+ class ControlRenderObject : public RenderObject
+ {
+ public:
+ ControlRenderObject() = default;
+ ControlRenderObject(const ControlRenderObject& other) = delete;
+ ControlRenderObject(ControlRenderObject&& other) = delete;
+ ControlRenderObject& operator=(const ControlRenderObject& other) = delete;
+ ControlRenderObject& operator=(ControlRenderObject&& other) = delete;
+ ~ControlRenderObject() override = default;
+
+
+ };
+}