aboutsummaryrefslogtreecommitdiff
path: root/include/cru/ui
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-04-11 00:01:51 +0800
committercrupest <crupest@outlook.com>2020-04-11 00:01:51 +0800
commit23ef59b6aa14874e3b68c8716c137eb65583cd63 (patch)
tree3f15dbfe3115b03a19a49abb7fcbc27d9c440769 /include/cru/ui
parent41e17e281ba31e9eff612017f5a2dafd847278b0 (diff)
downloadcru-23ef59b6aa14874e3b68c8716c137eb65583cd63.tar.gz
cru-23ef59b6aa14874e3b68c8716c137eb65583cd63.tar.bz2
cru-23ef59b6aa14874e3b68c8716c137eb65583cd63.zip
...
Diffstat (limited to 'include/cru/ui')
-rw-r--r--include/cru/ui/base.hpp1
-rw-r--r--include/cru/ui/control.hpp16
-rw-r--r--include/cru/ui/render/render_object.hpp35
-rw-r--r--include/cru/ui/render/window_render_object.hpp10
-rw-r--r--include/cru/ui/ui_host.hpp127
-rw-r--r--include/cru/ui/window.hpp98
6 files changed, 151 insertions, 136 deletions
diff --git a/include/cru/ui/base.hpp b/include/cru/ui/base.hpp
index fbb87c8c..a1335f90 100644
--- a/include/cru/ui/base.hpp
+++ b/include/cru/ui/base.hpp
@@ -183,6 +183,7 @@ using cru::platform::colors::yellowgreen;
class Window;
class Control;
class ClickDetector;
+class UiHost;
//-------------------- region: basic types --------------------
namespace internal {
diff --git a/include/cru/ui/control.hpp b/include/cru/ui/control.hpp
index f0475dea..30dc589a 100644
--- a/include/cru/ui/control.hpp
+++ b/include/cru/ui/control.hpp
@@ -9,7 +9,7 @@
namespace cru::ui {
class Control : public Object {
- friend class Window;
+ friend UiHost;
protected:
Control();
@@ -26,8 +26,8 @@ class Control : public Object {
//*************** region: tree ***************
public:
- // Get the window if attached, otherwise, return nullptr.
- Window* GetWindow() const { return window_; }
+ // Get the ui host if attached, otherwise, return nullptr.
+ UiHost* GetUiHost() const { return ui_host_; }
Control* GetParent() const { return parent_; }
@@ -37,7 +37,7 @@ class Control : public Object {
void TraverseDescendants(const std::function<void(Control*)>& predicate);
void _SetParent(Control* parent);
- void _SetDescendantWindow(Window* window);
+ void _SetDescendantUiHost(UiHost* host);
private:
static void _TraverseDescendants(
@@ -111,7 +111,6 @@ class Control : public Object {
event::RoutedEvent<event::KeyEventArgs>* KeyUpEvent() {
return &key_up_event_;
}
- event::RoutedEvent<event::CharEventArgs>* CharEvent() { return &char_event_; }
event::RoutedEvent<event::FocusChangeEventArgs>* GainFocusEvent() {
return &gain_focus_event_;
}
@@ -129,7 +128,6 @@ class Control : public Object {
event::RoutedEvent<event::KeyEventArgs> key_down_event_;
event::RoutedEvent<event::KeyEventArgs> key_up_event_;
- event::RoutedEvent<event::CharEventArgs> char_event_;
event::RoutedEvent<event::FocusChangeEventArgs> gain_focus_event_;
event::RoutedEvent<event::FocusChangeEventArgs> lose_focus_event_;
@@ -137,13 +135,13 @@ class Control : public Object {
//*************** region: tree ***************
protected:
virtual void OnParentChanged(Control* old_parent, Control* new_parent);
- virtual void OnAttachToWindow(Window* window);
- virtual void OnDetachToWindow(Window* window);
+ virtual void OnAttachToHost(UiHost* host);
+ virtual void OnDetachFromHost(UiHost* host);
virtual void OnMouseHoverChange(bool newHover) { CRU_UNUSED(newHover) }
private:
- Window* window_ = nullptr;
+ UiHost* ui_host_ = nullptr;
Control* parent_ = nullptr;
private:
diff --git a/include/cru/ui/render/render_object.hpp b/include/cru/ui/render/render_object.hpp
index 33ef3d1a..6a8db52f 100644
--- a/include/cru/ui/render/render_object.hpp
+++ b/include/cru/ui/render/render_object.hpp
@@ -4,27 +4,12 @@
#include "cru/common/event.hpp"
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
- // implementation should merge multiple request into once.
- virtual void InvalidateLayout() = 0;
-
- // Mark the paint as invalid, and arrange a re-paint later.
- // 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;
-};
-
// Render object will not destroy its children when destroyed. Control must
// manage lifecycle of its render objects. Since control will destroy its
// children when destroyed, render objects will be destroyed along with it.
class RenderObject : public Object {
+ friend WindowRenderObject;
+
protected:
enum class ChildMode {
None,
@@ -47,8 +32,7 @@ class RenderObject : public Object {
Control* GetAttachedControl() const { return control_; }
void SetAttachedControl(Control* new_control) { control_ = new_control; }
- IRenderHost* GetRenderHost() const { return render_host_; }
- void SetRenderHost(IRenderHost* render_host) { render_host_ = render_host; }
+ UiHost* GetUiHost() const { return ui_host_; }
RenderObject* GetParent() const { return parent_; }
@@ -83,13 +67,8 @@ class RenderObject : public Object {
virtual RenderObject* HitTest(const Point& point) = 0;
public:
- void InvalidateLayout() const {
- if (render_host_ != nullptr) render_host_->InvalidateLayout();
- }
-
- void InvalidatePaint() const {
- if (render_host_ != nullptr) render_host_->InvalidatePaint();
- }
+ void InvalidateLayout();
+ void InvalidatePaint();
protected:
void SetChildMode(ChildMode mode) { child_mode_ = mode; }
@@ -117,11 +96,11 @@ class RenderObject : public Object {
private:
void SetParent(RenderObject* new_parent);
- void SetRenderHostRecursive(IRenderHost* host);
+ void SetRenderHostRecursive(UiHost* host);
private:
Control* control_ = nullptr;
- IRenderHost* render_host_ = nullptr;
+ UiHost* ui_host_ = nullptr;
RenderObject* parent_ = nullptr;
std::vector<RenderObject*> children_{};
diff --git a/include/cru/ui/render/window_render_object.hpp b/include/cru/ui/render/window_render_object.hpp
index 2f7f1e84..76b17b82 100644
--- a/include/cru/ui/render/window_render_object.hpp
+++ b/include/cru/ui/render/window_render_object.hpp
@@ -4,17 +4,13 @@
namespace cru::ui::render {
class WindowRenderObject : public RenderObject {
public:
- WindowRenderObject(Window* window);
+ WindowRenderObject(UiHost* host);
WindowRenderObject(const WindowRenderObject& other) = delete;
WindowRenderObject(WindowRenderObject&& other) = delete;
WindowRenderObject& operator=(const WindowRenderObject& other) = delete;
WindowRenderObject& operator=(WindowRenderObject&& other) = delete;
~WindowRenderObject() override = default;
- Window* GetWindow() const { return window_; }
-
- void Relayout();
-
void Draw(platform::graph::IPainter* painter) override;
RenderObject* HitTest(const Point& point) override;
@@ -29,10 +25,6 @@ class WindowRenderObject : public RenderObject {
}
private:
- Window* window_;
-
EventRevokerGuard after_layout_event_guard_;
-
- std::unique_ptr<IRenderHost> render_host_;
};
} // namespace cru::ui::render
diff --git a/include/cru/ui/ui_host.hpp b/include/cru/ui/ui_host.hpp
new file mode 100644
index 00000000..96026675
--- /dev/null
+++ b/include/cru/ui/ui_host.hpp
@@ -0,0 +1,127 @@
+#pragma once
+#include "base.hpp"
+
+#include "cru/common/event.hpp"
+#include "cru/common/self_resolvable.hpp"
+#include "render/base.hpp"
+
+namespace cru::ui {
+struct AfterLayoutEventArgs {};
+
+class UiHost : public Object, public SelfResolvable<UiHost> {
+ public:
+ // This will create root window render object and attach it to window.
+ // It will also create and manage a native window.
+ UiHost(Window* window);
+
+ CRU_DELETE_COPY(UiHost)
+ CRU_DELETE_MOVE(UiHost)
+
+ ~UiHost() override;
+
+ public:
+ // Mark the layout as invalid, and arrange a re-layout later.
+ // This method could be called more than one times in a message cycle. But
+ // layout only takes place once.
+ void InvalidateLayout();
+
+ // Mark the paint as invalid, and arrange a re-paint later.
+ // This method could be called more than one times in a message cycle. But
+ // paint only takes place once.
+ void InvalidatePaint();
+
+ IEvent<AfterLayoutEventArgs>* AfterLayoutEvent() {
+ return &after_layout_event_;
+ }
+
+ void Relayout();
+
+ // Get current control that mouse hovers on. This ignores the mouse-capture
+ // control. Even when mouse is captured by another control, this function
+ // return the control under cursor. You can use `GetMouseCaptureControl` to
+ // get more info.
+ Control* GetMouseHoverControl() const { return mouse_hover_control_; }
+
+ //*************** region: focus ***************
+
+ // Request focus for specified control.
+ bool RequestFocusFor(Control* control);
+
+ // Get the control that has focus.
+ Control* GetFocusControl();
+
+ //*************** region: focus ***************
+
+ // Pass nullptr to release capture. If mouse is already capture by a control,
+ // this capture will fail and return false. If control is identical to the
+ // capturing control, capture is not changed and this function will return
+ // true.
+ //
+ // When capturing control changes,
+ // appropriate event will be sent. If mouse is not on the capturing control
+ // and capture is released, mouse enter event will be sent to the mouse-hover
+ // control. If mouse is not on the capturing control and capture is set, mouse
+ // leave event will be sent to the mouse-hover control.
+ bool CaptureMouseFor(Control* control);
+
+ // Return null if not captured.
+ Control* GetMouseCaptureControl();
+
+ Control* HitTest(const Point& point);
+
+ void UpdateCursor();
+
+ private:
+ //*************** region: native messages ***************
+ void OnNativeDestroy(platform::native::INativeWindow* window, std::nullptr_t);
+ void OnNativePaint(platform::native::INativeWindow* window, std::nullptr_t);
+ void OnNativeResize(platform::native::INativeWindow* window,
+ const Size& size);
+
+ void OnNativeFocus(platform::native::INativeWindow* window,
+ cru::platform::native::FocusChangeType focus);
+
+ void OnNativeMouseEnterLeave(
+ platform::native::INativeWindow* window,
+ cru::platform::native::MouseEnterLeaveType enter);
+ void OnNativeMouseMove(platform::native::INativeWindow* window,
+ const Point& point);
+ void OnNativeMouseDown(
+ platform::native::INativeWindow* window,
+ const platform::native::NativeMouseButtonEventArgs& args);
+ void OnNativeMouseUp(
+ platform::native::INativeWindow* window,
+ const platform::native::NativeMouseButtonEventArgs& args);
+
+ void OnNativeKeyDown(platform::native::INativeWindow* window,
+ const platform::native::NativeKeyEventArgs& args);
+ void OnNativeKeyUp(platform::native::INativeWindow* window,
+ const platform::native::NativeKeyEventArgs& args);
+
+ //*************** region: event dispatcher helper ***************
+
+ void DispatchMouseHoverControlChangeEvent(Control* old_control,
+ Control* new_control,
+ const Point& point, bool no_leave,
+ bool no_enter);
+
+ private:
+ bool need_layout_ = false;
+
+ Event<AfterLayoutEventArgs> after_layout_event_;
+
+ std::shared_ptr<platform::native::INativeWindowResolver>
+ native_window_resolver_;
+
+ std::vector<EventRevokerGuard> event_revoker_guards_;
+
+ Window* window_control_;
+ std::unique_ptr<render::WindowRenderObject> root_render_object_;
+
+ Control* mouse_hover_control_;
+
+ Control* focus_control_; // "focus_control_" can't be nullptr
+
+ Control* mouse_captured_control_;
+};
+} // namespace cru::ui
diff --git a/include/cru/ui/window.hpp b/include/cru/ui/window.hpp
index 86112189..f15e605b 100644
--- a/include/cru/ui/window.hpp
+++ b/include/cru/ui/window.hpp
@@ -1,13 +1,9 @@
#pragma once
#include "content_control.hpp"
-#include "cru/common/self_resolvable.hpp"
-
namespace cru::ui {
-// TODO: Make Window able to be invalid and handle operations in invalidity
-// situation.
-class Window final : public ContentControl, public SelfResolvable<Window> {
- friend class Control;
+class Window final : public ContentControl {
+ friend UiHost;
public:
static constexpr std::string_view control_type = "Window";
@@ -32,96 +28,18 @@ class Window final : public ContentControl, public SelfResolvable<Window> {
render::RenderObject* GetRenderObject() const override;
- platform::native::INativeWindow* ResolveNativeWindow();
-
- // Get current control that mouse hovers on. This ignores the mouse-capture
- // control. Even when mouse is captured by another control, this function
- // return the control under cursor. You can use `GetMouseCaptureControl` to
- // get more info.
- Control* GetMouseHoverControl() const { return mouse_hover_control_; }
-
- //*************** region: focus ***************
-
- // Request focus for specified control.
- bool RequestFocusFor(Control* control);
-
- // Get the control that has focus.
- Control* GetFocusControl();
-
- //*************** region: focus ***************
-
- // Pass nullptr to release capture. If mouse is already capture by a control,
- // this capture will fail and return false. If control is identical to the
- // capturing control, capture is not changed and this function will return
- // true.
- //
- // When capturing control changes,
- // appropriate event will be sent. If mouse is not on the capturing control
- // and capture is released, mouse enter event will be sent to the mouse-hover
- // control. If mouse is not on the capturing control and capture is set, mouse
- // leave event will be sent to the mouse-hover control.
- bool CaptureMouseFor(Control* control);
-
- // Return null if not captured.
- Control* GetMouseCaptureControl();
+ bool IsRetainAfterDestroy() { return retain_after_destroy_; }
+ void SetRetainAfterDestroy(bool destroy) { retain_after_destroy_ = destroy; }
protected:
void OnChildChanged(Control* old_child, Control* new_child) override;
private:
- Control* HitTest(const Point& point);
-
- //*************** region: native messages ***************
-
- void OnNativeDestroy(platform::native::INativeWindow* window, std::nullptr_t);
- void OnNativePaint(platform::native::INativeWindow* window, std::nullptr_t);
- void OnNativeResize(platform::native::INativeWindow* window,
- const Size& size);
-
- void OnNativeFocus(platform::native::INativeWindow* window,
- cru::platform::native::FocusChangeType focus);
-
- void OnNativeMouseEnterLeave(
- platform::native::INativeWindow* window,
- cru::platform::native::MouseEnterLeaveType enter);
- void OnNativeMouseMove(platform::native::INativeWindow* window,
- const Point& point);
- void OnNativeMouseDown(
- platform::native::INativeWindow* window,
- const platform::native::NativeMouseButtonEventArgs& args);
- void OnNativeMouseUp(
- platform::native::INativeWindow* window,
- const platform::native::NativeMouseButtonEventArgs& args);
-
- void OnNativeKeyDown(platform::native::INativeWindow* window,
- const platform::native::NativeKeyEventArgs& args);
- void OnNativeKeyUp(platform::native::INativeWindow* window,
- const platform::native::NativeKeyEventArgs& args);
- void OnNativeChar(platform::native::INativeWindow* window, std::string c);
-
- //*************** region: event dispatcher helper ***************
-
- void DispatchMouseHoverControlChangeEvent(Control* old_control,
- Control* new_control,
- const Point& point, bool no_leave,
- bool no_enter);
-
- void UpdateCursor();
-
- private:
- std::shared_ptr<platform::native::INativeWindowResolver>
- native_window_resolver_;
-
- std::vector<EventRevokerGuard> event_revoker_guards_;
-
- std::unique_ptr<render::WindowRenderObject> render_object_;
-
- Control* mouse_hover_control_;
-
- Control* focus_control_; // "focus_control_" can't be nullptr
+ std::unique_ptr<UiHost> managed_ui_host_;
- Control* mouse_captured_control_;
+ // UiHost is responsible to take care of lifetime of this.
+ render::WindowRenderObject* render_object_;
- bool need_layout_ = false;
+ bool retain_after_destroy_ = false;
};
} // namespace cru::ui