aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author杨宇千 <crupest@outlook.com>2019-09-16 22:11:11 +0800
committer杨宇千 <crupest@outlook.com>2019-09-16 22:11:11 +0800
commit465d89b4207cce929dc8e0b6ac93c3533ba19408 (patch)
tree157df74f42d46d9b631163c087fd126f2eed021b
parentf1da8e06253748887ae769845a6e605d56d5789b (diff)
downloadcru-465d89b4207cce929dc8e0b6ac93c3533ba19408.tar.gz
cru-465d89b4207cce929dc8e0b6ac93c3533ba19408.tar.bz2
cru-465d89b4207cce929dc8e0b6ac93c3533ba19408.zip
...
-rw-r--r--include/cru/ui/render/border_render_object.hpp59
-rw-r--r--include/cru/ui/render/render_object.hpp6
-rw-r--r--include/cru/ui/render/window_render_object.hpp4
-rw-r--r--include/cru/ui/window.hpp5
-rw-r--r--src/ui/render/window_render_object.cpp47
-rw-r--r--src/ui/window.cpp26
6 files changed, 101 insertions, 46 deletions
diff --git a/include/cru/ui/render/border_render_object.hpp b/include/cru/ui/render/border_render_object.hpp
index 22e8ab58..18809f91 100644
--- a/include/cru/ui/render/border_render_object.hpp
+++ b/include/cru/ui/render/border_render_object.hpp
@@ -32,11 +32,16 @@ struct CornerRadius {
Point right_bottom;
};
-struct BorderStyle {
- std::shared_ptr<platform::graph::Brush> brush{};
- Thickness thickness{};
- CornerRadius corner_radius{};
-};
+inline bool operator==(const CornerRadius& left, const CornerRadius& right) {
+ return left.left_top == right.left_top &&
+ left.left_bottom == right.left_bottom &&
+ left.right_top == right.right_top &&
+ left.right_bottom == right.right_bottom;
+}
+
+inline bool operator!=(const CornerRadius& left, const CornerRadius& right) {
+ return !(left == right);
+}
class BorderRenderObject : public RenderObject {
public:
@@ -50,8 +55,30 @@ class BorderRenderObject : public RenderObject {
bool IsBorderEnabled() const { return is_border_enabled_; }
void SetBorderEnabled(bool enabled) { is_border_enabled_ = enabled; }
- BorderStyle* GetBorderStyle() {
- return &border_style_;
+ std::shared_ptr<platform::graph::Brush> GetBorderBrush() {
+ return border_brush_;
+ }
+
+ void SetBorderBrush(std::shared_ptr<platform::graph::Brush> brush) {
+ if (brush == border_brush_) return;
+ border_brush_ = std::move(brush);
+ InvalidatePaint();
+ }
+
+ platform::Thickness GetBorderThickness() { return border_thickness_; }
+
+ void SetBorderThickness(const platform::Thickness thickness) {
+ if (thickness == border_thickness_) return;
+ border_thickness_ = thickness;
+ InvalidateLayout();
+ }
+
+ CornerRadius GetBorderRadius() { return border_radius_; }
+
+ void SetBorderRadius(const CornerRadius radius) {
+ if (radius == border_radius_) return;
+ border_radius_ = radius;
+ RecreateGeometry();
}
std::shared_ptr<platform::graph::Brush> GetForegroundBrush() {
@@ -59,19 +86,21 @@ class BorderRenderObject : public RenderObject {
}
void SetForegroundBrush(std::shared_ptr<platform::graph::Brush> brush) {
+ if (brush == foreground_brush_) return;
foreground_brush_ = std::move(brush);
+ InvalidatePaint();
}
std::shared_ptr<platform::graph::Brush> GetBackgroundBrush() {
- return foreground_brush_;
+ return background_brush_;
}
void SetBackgroundBrush(std::shared_ptr<platform::graph::Brush> brush) {
- foreground_brush_ = std::move(brush);
+ if (brush == background_brush_) return;
+ background_brush_ = std::move(brush);
+ InvalidatePaint();
}
- void Refresh() { RecreateGeometry(); }
-
void Draw(platform::graph::Painter* painter) override;
RenderObject* HitTest(const Point& point) override;
@@ -93,14 +122,18 @@ class BorderRenderObject : public RenderObject {
private:
bool is_border_enabled_ = false;
- BorderStyle border_style_;
+
+ std::shared_ptr<platform::graph::Brush> border_brush_;
+ platform::Thickness border_thickness_;
+ CornerRadius border_radius_;
std::shared_ptr<platform::graph::Brush> foreground_brush_;
std::shared_ptr<platform::graph::Brush> background_brush_;
// The ring. Used for painting.
std::unique_ptr<platform::graph::Geometry> geometry_;
- // Area including inner area of the border. Used for painting foreground and background.
+ // Area including inner area of the border. Used for painting foreground and
+ // background.
std::unique_ptr<platform::graph::Geometry> border_inner_geometry_;
// Area including border ring and inner area. Used for hit test.
std::unique_ptr<platform::graph::Geometry> border_outer_geometry_;
diff --git a/include/cru/ui/render/render_object.hpp b/include/cru/ui/render/render_object.hpp
index 8ea7ca79..2394bf97 100644
--- a/include/cru/ui/render/render_object.hpp
+++ b/include/cru/ui/render/render_object.hpp
@@ -2,6 +2,7 @@
#include "cru/common/base.hpp"
#include "../base.hpp"
+#include "cru/common/event.hpp"
#include <vector>
@@ -15,6 +16,9 @@ class Painter;
}
namespace cru::ui::render {
+
+struct AfterLayoutEventArgs {};
+
struct IRenderHost : Interface {
// Mark the layout as invalid, and arrange a re-layout later.
// Note this method might be called more than one times in a message cycle. So
@@ -25,6 +29,8 @@ struct IRenderHost : Interface {
// Note this method might be called more than one times in a message cycle. So
// implementation should merge multiple request into once.
virtual void InvalidatePaint() = 0;
+
+ virtual IEvent<AfterLayoutEventArgs>* AfterLayoutEvent() = 0;
};
class RenderObject : public Object {
diff --git a/include/cru/ui/render/window_render_object.hpp b/include/cru/ui/render/window_render_object.hpp
index e73a6bfe..431f7025 100644
--- a/include/cru/ui/render/window_render_object.hpp
+++ b/include/cru/ui/render/window_render_object.hpp
@@ -17,7 +17,9 @@ class WindowRenderObject : public RenderObject {
WindowRenderObject& operator=(WindowRenderObject&& other) = delete;
~WindowRenderObject() override = default;
- void MeasureAndLayout();
+ Window* GetWindow() const { return window_; }
+
+ void Relayout();
void Draw(platform::graph::Painter* painter) override;
diff --git a/include/cru/ui/window.hpp b/include/cru/ui/window.hpp
index 1325100f..f4cdefaa 100644
--- a/include/cru/ui/window.hpp
+++ b/include/cru/ui/window.hpp
@@ -53,11 +53,6 @@ class Window final : public ContentControl, public SelfResolvable<Window> {
// get more info.
Control* GetMouseHoverControl() const { return mouse_hover_control_; }
- //*************** region: layout ***************
- void Relayout();
-
- void InvalidateLayout();
-
//*************** region: focus ***************
// Request focus for specified control.
diff --git a/src/ui/render/window_render_object.cpp b/src/ui/render/window_render_object.cpp
index e61dd286..e2e96897 100644
--- a/src/ui/render/window_render_object.cpp
+++ b/src/ui/render/window_render_object.cpp
@@ -1,33 +1,64 @@
#include "cru/ui/render/window_render_object.hpp"
+#include "cru/common/logger.hpp"
#include "cru/platform/graph/util/painter_util.hpp"
#include "cru/platform/native/native_window.hpp"
+#include "cru/platform/native/ui_application.hpp"
#include "cru/ui/window.hpp"
#include <cassert>
namespace cru::ui::render {
-class WindowRenderHost : public IRenderHost {
+class WindowRenderHost : public IRenderHost,
+ public SelfResolvable<WindowRenderHost> {
public:
- WindowRenderHost(Window* window) : window_(window) {
- assert(window != nullptr);
+ WindowRenderHost(WindowRenderObject* render_object)
+ : render_object_(render_object) {
+ assert(render_object != nullptr);
}
- void InvalidateLayout() override { window_->InvalidateLayout(); }
+ void InvalidateLayout() override;
- void InvalidatePaint() override { window_->GetNativeWindow()->Repaint(); }
+ void InvalidatePaint() override {
+ render_object_->GetWindow()->GetNativeWindow()->Repaint();
+ }
+
+ IEvent<AfterLayoutEventArgs>* AfterLayoutEvent() override {
+ return &after_layout_event_;
+ }
private:
- Window* window_;
+ WindowRenderObject* render_object_;
+
+ bool need_layout_ = false;
+
+ Event<AfterLayoutEventArgs> after_layout_event_;
};
+void WindowRenderHost::InvalidateLayout() {
+ if (!need_layout_) {
+ log::Debug(L"A relayout is required.");
+ platform::native::UiApplication::GetInstance()->InvokeLater(
+ [resolver = this->CreateResolver()] {
+ if (const auto host = resolver.Resolve()) {
+ host->render_object_->Relayout();
+ host->need_layout_ = false;
+ host->after_layout_event_.Raise(AfterLayoutEventArgs{});
+ log::Debug(L"A relayout finished.");
+ host->InvalidatePaint();
+ }
+ });
+ need_layout_ = true;
+ }
+}
+
WindowRenderObject::WindowRenderObject(Window* window)
- : window_(window), render_host_(new WindowRenderHost(window)) {
+ : window_(window), render_host_(new WindowRenderHost(this)) {
SetChildMode(ChildMode::Single);
SetRenderHost(render_host_.get());
}
-void WindowRenderObject::MeasureAndLayout() {
+void WindowRenderObject::Relayout() {
const auto client_size = window_->GetNativeWindow()->GetClientSize();
Measure(client_size);
Layout(Rect{Point{}, client_size});
diff --git a/src/ui/window.cpp b/src/ui/window.cpp
index 13784718..25dffe11 100644
--- a/src/ui/window.cpp
+++ b/src/ui/window.cpp
@@ -135,21 +135,6 @@ render::RenderObject* Window::GetRenderObject() const {
return render_object_.get();
}
-void Window::Relayout() { this->render_object_->MeasureAndLayout(); }
-
-void Window::InvalidateLayout() {
- if (!need_layout_) {
- platform::native::UiApplication::GetInstance()->InvokeLater(
- [resolver = this->CreateResolver()] {
- if (const auto window = resolver.Resolve()) {
- window->Relayout();
- window->need_layout_ = false;
- }
- });
- need_layout_ = true;
- }
-}
-
bool Window::RequestFocusFor(Control* control) {
assert(control != nullptr); // The control to request focus can't be null.
// You can set it as the window.
@@ -216,7 +201,7 @@ void Window::OnNativePaint(std::nullptr_t) {
}
void Window::OnNativeResize(const Size& size) {
- render_object_->MeasureAndLayout();
+ render_object_->GetRenderHost()->InvalidateLayout();
}
void Window::OnNativeFocus(bool focus) {
@@ -241,13 +226,16 @@ void Window::OnNativeMouseMove(const Point& point) {
mouse_hover_control_ = new_mouse_hover_control;
if (mouse_captured_control_) {
- const auto n = FindLowestCommonAncestor(new_mouse_hover_control, mouse_captured_control_);
- const auto o = FindLowestCommonAncestor(old_mouse_hover_control, mouse_captured_control_);
+ const auto n = FindLowestCommonAncestor(new_mouse_hover_control,
+ mouse_captured_control_);
+ const auto o = FindLowestCommonAncestor(old_mouse_hover_control,
+ mouse_captured_control_);
bool a = IsAncestor(o, n);
if (a) {
DispatchEvent(event_names::MouseLeave, o, &Control::MouseLeaveEvent, n);
} else {
- DispatchEvent(event_names::MouseEnter, n, &Control::MouseEnterEvent, o, point);
+ DispatchEvent(event_names::MouseEnter, n, &Control::MouseEnterEvent, o,
+ point);
}
DispatchEvent(event_names::MouseMove, mouse_captured_control_,
&Control::MouseMoveEvent, nullptr, point);