From 3ec1e536bd0ced5abcf82e84d1eee42960912b37 Mon Sep 17 00:00:00 2001 From: crupest Date: Sat, 8 Dec 2018 22:51:48 +0800 Subject: Add single render objects. --- src/application.hpp | 2 +- src/math_util.hpp | 2 +- src/ui/render/render_object.cpp | 121 +++++++++++++++++++++++++ src/ui/render/render_object.hpp | 189 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 312 insertions(+), 2 deletions(-) create mode 100644 src/ui/render/render_object.cpp create mode 100644 src/ui/render/render_object.hpp (limited to 'src') 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 singleton_map_; std::list singleton_list_; // used for reverse destroy. #ifdef CRU_DEBUG - std::unordered_set singleton_type_set_; // used for dead recursion. + std::unordered_set 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 >> + template >> float Coerce(const T n, const std::optional min, const std::optional 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 + +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 clip_geometry) + : clip_geometry_(std::move(clip_geometry)) + { + + } + + void ClipRenderObject::SetClipGeometry(Microsoft::WRL::ComPtr 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 + +#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 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 GetClipGeometry() const + { + return clip_geometry_; + } + void SetClipGeometry(Microsoft::WRL::ComPtr new_clip_geometry); + + void Draw(ID2D1RenderTarget* render_target) override final; + + private: + Microsoft::WRL::ComPtr 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; + + 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; + + + }; +} -- cgit v1.2.3