aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2019-03-23 21:49:42 +0800
committercrupest <crupest@outlook.com>2019-03-23 21:49:42 +0800
commit2ecfdaa20d8436948e4a73da73d6a11b78e88371 (patch)
treed1ebabb929e58882d2d98b5f2e0a546aea3f80e4 /src
parent3ee6e0bc3675689c5f24d36bbecb7ca1bc93d433 (diff)
downloadcru-2ecfdaa20d8436948e4a73da73d6a11b78e88371.tar.gz
cru-2ecfdaa20d8436948e4a73da73d6a11b78e88371.tar.bz2
cru-2ecfdaa20d8436948e4a73da73d6a11b78e88371.zip
...
Diffstat (limited to 'src')
-rw-r--r--src/ui/render/border_render_object.cpp120
-rw-r--r--src/ui/render/border_render_object.hpp34
2 files changed, 134 insertions, 20 deletions
diff --git a/src/ui/render/border_render_object.cpp b/src/ui/render/border_render_object.cpp
index c98d6c29..033f59d8 100644
--- a/src/ui/render/border_render_object.cpp
+++ b/src/ui/render/border_render_object.cpp
@@ -1,11 +1,113 @@
#include "border_render_object.hpp"
+#include <algorithm>
+
#include "cru_debug.hpp"
+#include "exception.hpp"
+#include "graph/graph.hpp"
namespace cru::ui::render {
BorderRenderObject::BorderRenderObject(Microsoft::WRL::ComPtr<ID2D1Brush> brush)
: border_brush_(std::move(brush)) {}
+void BorderRenderObject::RecreateGeometry() {
+ const auto d2d_factory = graph::GraphManager::GetInstance()->GetD2D1Factory();
+
+ Microsoft::WRL::ComPtr<ID2D1PathGeometry> geometry;
+ ThrowIfFailed(d2d_factory->CreatePathGeometry(&geometry));
+
+ Microsoft::WRL::ComPtr<ID2D1PathGeometry> border_outer_geometry;
+ ThrowIfFailed(d2d_factory->CreatePathGeometry(&border_outer_geometry));
+
+ ID2D1GeometrySink* sink;
+ auto f = [sink](const Rect& rect, const CornerRadius& corner) {
+ sink->BeginFigure(D2D1::Point2F(rect.left + corner.left_top.x, rect.top),
+ D2D1_FIGURE_BEGIN_FILLED);
+ sink->AddLine(
+ D2D1::Point2F(rect.GetRight() - corner.right_top.x, rect.top));
+ sink->AddQuadraticBezier(D2D1::QuadraticBezierSegment(
+ D2D1::Point2F(rect.GetRight(), rect.top),
+ D2D1::Point2F(rect.GetRight(), rect.top + corner.right_top.y)));
+ sink->AddLine(D2D1::Point2F(rect.GetRight(),
+ rect.GetBottom() - corner.right_bottom.y));
+ sink->AddQuadraticBezier(D2D1::QuadraticBezierSegment(
+ D2D1::Point2F(rect.GetRight(), rect.GetBottom()),
+ D2D1::Point2F(rect.GetRight() - corner.right_bottom.x,
+ rect.GetBottom())));
+ sink->AddLine(
+ D2D1::Point2F(rect.left + corner.left_bottom.x, rect.GetBottom()));
+ sink->AddQuadraticBezier(D2D1::QuadraticBezierSegment(
+ D2D1::Point2F(rect.left, rect.GetBottom()),
+ D2D1::Point2F(rect.left, rect.GetBottom() - corner.left_bottom.y)));
+ sink->AddLine(D2D1::Point2F(rect.left, rect.top + corner.left_top.y));
+ sink->AddQuadraticBezier(D2D1::QuadraticBezierSegment(
+ D2D1::Point2F(rect.left, rect.top),
+ D2D1::Point2F(rect.left + corner.left_top.x, rect.top)));
+ sink->EndFigure(D2D1_FIGURE_END_CLOSED);
+ };
+
+ const auto size = GetSize();
+ const auto margin = GetMargin();
+ const Rect outer_rect{margin.left, margin.top, size.width - margin.right,
+ size.height - size.height};
+ ThrowIfFailed(border_outer_geometry->Open(&sink));
+ f(outer_rect, corner_radius_);
+ ThrowIfFailed(sink->Close());
+ sink->Release();
+
+ const Rect inner_rect = outer_rect.Shrink(border_thickness_);
+ ThrowIfFailed(geometry->Open(&sink));
+ f(outer_rect, corner_radius_);
+ f(inner_rect, corner_radius_);
+ ThrowIfFailed(sink->Close());
+ sink->Release();
+
+ geometry_ = std::move(geometry);
+ border_outer_geometry_ = std::move(border_outer_geometry);
+}
+
+void BorderRenderObject::Draw(ID2D1RenderTarget* render_target) {
+ render_target->FillGeometry(geometry_.Get(), border_brush_.Get());
+ if (const auto child = GetChild()) {
+ auto offset = child->GetOffset();
+ graph::WithTransform(render_target,
+ D2D1::Matrix3x2F::Translation(offset.x, offset.y),
+ [child](auto rt) { child->Draw(rt); });
+ }
+}
+
+RenderObject* BorderRenderObject::HitTest(const Point& point) {
+ if (const auto child = GetChild()) {
+ auto offset = child->GetOffset();
+ Point p{point.x - offset.x, point.y - offset.y};
+ const auto result = child->HitTest(point);
+ if (result != nullptr) {
+ return result;
+ }
+ }
+
+ if (is_enabled_) {
+ BOOL contains;
+ ThrowIfFailed(border_outer_geometry_->FillContainsPoint(
+ D2D1::Point2F(point.x, point.y), D2D1::Matrix3x2F::Identity(),
+ &contains));
+ return contains != 0 ? this : nullptr;
+ } else {
+ 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;
+ }
+}
+
+void BorderRenderObject::OnAddChild(RenderObject* new_child, int position) {
+ assert(GetChildren().size() == 1);
+}
+
void BorderRenderObject::OnMeasureCore(const Size& available_size) {
const auto margin = GetMargin();
const auto padding = GetPadding();
@@ -14,8 +116,8 @@ void BorderRenderObject::OnMeasureCore(const Size& available_size) {
margin.GetVerticalTotal() + padding.GetVerticalTotal()};
if (is_enabled_) {
- margin_border_padding_size.width += border_width_.GetHorizontalTotal();
- margin_border_padding_size.height += border_width_.GetVerticalTotal();
+ margin_border_padding_size.width += border_thickness_.GetHorizontalTotal();
+ margin_border_padding_size.height += border_thickness_.GetVerticalTotal();
}
auto coerced_margin_border_padding_size = margin_border_padding_size;
@@ -49,8 +151,8 @@ void BorderRenderObject::OnLayoutCore(const Rect& rect) {
margin.GetVerticalTotal() + padding.GetVerticalTotal()};
if (is_enabled_) {
- margin_border_padding_size.width += border_width_.GetHorizontalTotal();
- margin_border_padding_size.height += border_width_.GetVerticalTotal();
+ margin_border_padding_size.width += border_thickness_.GetHorizontalTotal();
+ margin_border_padding_size.height += border_thickness_.GetVerticalTotal();
}
const auto content_available_size =
@@ -70,11 +172,11 @@ void BorderRenderObject::OnLayoutCore(const Rect& rect) {
coerced_content_available_size.height = 0;
}
- OnLayoutContent(
- Rect{margin.left + (is_enabled_ ? border_width_.left : 0) + padding.left,
- margin.top + (is_enabled_ ? border_width_.top : 0) + padding.top,
- coerced_content_available_size.width,
- coerced_content_available_size.height});
+ OnLayoutContent(Rect{
+ margin.left + (is_enabled_ ? border_thickness_.left : 0) + padding.left,
+ margin.top + (is_enabled_ ? border_thickness_.top : 0) + padding.top,
+ coerced_content_available_size.width,
+ coerced_content_available_size.height});
}
Size BorderRenderObject::OnMeasureContent(const Size& available_size) {
diff --git a/src/ui/render/border_render_object.hpp b/src/ui/render/border_render_object.hpp
index d7a595af..d6effc21 100644
--- a/src/ui/render/border_render_object.hpp
+++ b/src/ui/render/border_render_object.hpp
@@ -9,14 +9,23 @@
struct ID2D1Brush;
struct ID2D1Geometry;
+namespace cru::ui::render {
struct CornerRadius {
- float left_top;
- float right_top;
- float left_bottom;
- float right_bottom;
+ constexpr CornerRadius()
+ : left_top(), right_top(), left_bottom(), right_bottom() {}
+ constexpr CornerRadius(Point left_top, Point right_top, Point left_bottom,
+ Point right_bottom)
+ : left_top(left_top),
+ right_top(right_top),
+ left_bottom(left_bottom),
+ right_bottom(right_bottom) {}
+
+ Point left_top;
+ Point right_top;
+ Point left_bottom;
+ Point right_bottom;
};
-namespace cru::ui::render {
class BorderRenderObject : public RenderObject {
public:
explicit BorderRenderObject(Microsoft::WRL::ComPtr<ID2D1Brush> brush);
@@ -34,8 +43,8 @@ class BorderRenderObject : public RenderObject {
border_brush_ = std::move(new_brush);
}
- Thickness GetBorderWidth() const { return border_width_; }
- void SetBorderWidth(const Thickness& thickness) { border_width_ = thickness; }
+ Thickness GetBorderWidth() const { return border_thickness_; }
+ void SetBorderWidth(const Thickness& thickness) { border_thickness_ = thickness; }
CornerRadius GetCornerRadius() const { return corner_radius_; }
void SetCornerRadius(const CornerRadius& new_corner_radius) {
@@ -49,6 +58,8 @@ class BorderRenderObject : public RenderObject {
RenderObject* HitTest(const Point& point) override; // TODO
protected:
+ void OnAddChild(RenderObject* new_child, int position) override;
+
void OnMeasureCore(const Size& available_size) override;
void OnLayoutCore(const Rect& rect) override;
Size OnMeasureContent(const Size& available_size) override;
@@ -60,12 +71,13 @@ class BorderRenderObject : public RenderObject {
}
private:
- bool is_enabled_;
+ bool is_enabled_ = false;
Microsoft::WRL::ComPtr<ID2D1Brush> border_brush_;
- Thickness border_width_;
- CornerRadius corner_radius_;
+ Thickness border_thickness_ = Thickness::Zero();
+ CornerRadius corner_radius_{};
- Microsoft::WRL::ComPtr<ID2D1Geometry> geometry_;
+ Microsoft::WRL::ComPtr<ID2D1Geometry> geometry_{nullptr};
+ Microsoft::WRL::ComPtr<ID2D1Geometry> border_outer_geometry_{nullptr};
};
} // namespace cru::ui::render