From 6ce70ed4b08c7db20b6b384be26c7fc4e11c98de Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 28 Oct 2020 20:51:55 +0800 Subject: ... --- include/cru/ui/Base.hpp | 2 +- include/cru/ui/Control.hpp | 12 +- include/cru/ui/UiHost.hpp | 185 --------------------------- include/cru/ui/Window.hpp | 6 +- include/cru/ui/WindowHost.hpp | 185 +++++++++++++++++++++++++++ include/cru/ui/render/RenderObject.hpp | 6 +- include/cru/ui/render/WindowRenderObject.hpp | 2 +- 7 files changed, 199 insertions(+), 199 deletions(-) delete mode 100644 include/cru/ui/UiHost.hpp create mode 100644 include/cru/ui/WindowHost.hpp (limited to 'include') diff --git a/include/cru/ui/Base.hpp b/include/cru/ui/Base.hpp index 6be359ab..dd93f187 100644 --- a/include/cru/ui/Base.hpp +++ b/include/cru/ui/Base.hpp @@ -29,7 +29,7 @@ namespace colors = cru::platform::colors; class Window; class Control; class ClickDetector; -class UiHost; +class WindowHost; namespace render { class RenderObject; diff --git a/include/cru/ui/Control.hpp b/include/cru/ui/Control.hpp index bd86bc2f..692dcc9b 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 UiHost; + friend WindowHost; protected: Control(); @@ -27,7 +27,7 @@ class Control : public Object { //*************** region: tree *************** public: // Get the ui host if attached, otherwise, return nullptr. - UiHost* GetUiHost() const { return ui_host_; } + WindowHost* GetWindowHost() const { return ui_host_; } Control* GetParent() const { return parent_; } @@ -37,7 +37,7 @@ class Control : public Object { void TraverseDescendants(const std::function& predicate); void _SetParent(Control* parent); - void _SetDescendantUiHost(UiHost* host); + void _SetDescendantWindowHost(WindowHost* host); private: static void _TraverseDescendants( @@ -135,13 +135,13 @@ class Control : public Object { //*************** region: tree *************** protected: virtual void OnParentChanged(Control* old_parent, Control* new_parent); - virtual void OnAttachToHost(UiHost* host); - virtual void OnDetachFromHost(UiHost* host); + virtual void OnAttachToHost(WindowHost* host); + virtual void OnDetachFromHost(WindowHost* host); virtual void OnMouseHoverChange(bool newHover) { CRU_UNUSED(newHover) } private: - UiHost* ui_host_ = nullptr; + WindowHost* ui_host_ = nullptr; Control* parent_ = nullptr; private: diff --git a/include/cru/ui/UiHost.hpp b/include/cru/ui/UiHost.hpp deleted file mode 100644 index 2437b967..00000000 --- a/include/cru/ui/UiHost.hpp +++ /dev/null @@ -1,185 +0,0 @@ -#pragma once -#include -#include "Base.hpp" - -#include "cru/common/Event.hpp" -#include "cru/common/SelfResolvable.hpp" -#include "render/Base.hpp" - -namespace cru::ui { -struct AfterLayoutEventArgs {}; - -// The host of all controls and render objects. -// -// 3 situations on destroy: -// 1. Native window destroyed, IsRetainAfterDestroy: false: -// OnNativeDestroy(set native_window_destroyed_ to true, call ~Window due to -// deleting_ is false and IsRetainAfterDestroy is false) -> ~Window -> -// ~UiHost(not destroy native window repeatedly due to native_window_destroyed_ -// is true) -// 2. Native window destroyed, IsRetainAfterDestroy: true: -// OnNativeDestroy(set native_window_destroyed_ to true, not call ~Window -// because deleting_ is false and IsRetainAfterDestroy is true) -// then, ~Window -> ~UiHost(not destroy native window repeatedly due to -// native_window_destroyed_ is true) -// 3. Native window not destroyed, ~Window is called: -// ~Window -> ~UiHost(set deleting_ to true, destroy native window -// due to native_window_destroyed is false) -> OnNativeDestroy(not call ~Window -// due to deleting_ is true and IsRetainAfterDestroy is whatever) -// In conclusion: -// 1. Set native_window_destroyed_ to true at the beginning of OnNativeDestroy. -// 2. Set deleting_ to true at the beginning of ~UiHost. -// 3. Destroy native window when native_window_destroy_ is false in ~Window. -// 4. Delete Window when deleting_ is false and IsRetainAfterDestroy is false in -// OnNativeDestroy. -class UiHost : public Object, public SelfResolvable { - CRU_DEFINE_CLASS_LOG_TAG(u"cru::ui::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* AfterLayoutEvent() { - return &after_layout_event_; - } - - // If true, preferred size of root render object is set to window size when - // measure. Default is true. - bool IsLayoutPreferToFillWindow() const; - void SetLayoutPreferToFillWindow(bool value); - - 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(); - - std::shared_ptr - GetNativeWindowResolver() { - return native_window_resolver_; - } - - bool IsRetainAfterDestroy() { return retain_after_destroy_; } - - void SetRetainAfterDestroy(bool destroy) { retain_after_destroy_ = destroy; } - - // Is layout is invalid, wait for relayout and then run the action. Otherwist - // run it right now. - void RunAfterLayoutStable(std::function action); - - 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 after_layout_event_; - std::vector > after_layout_stable_action_; - - std::shared_ptr - native_window_resolver_; - - // See remarks of UiHost. - bool retain_after_destroy_ = false; - // See remarks of UiHost. - bool deleting_ = false; - - // We need this because calling Resolve on resolver in handler of destroy - // event is bad and will always get the dying window. But we need to label the - // window as destroyed so the destructor will not destroy native window - // repeatedly. See remarks of UiHost. - bool native_window_destroyed_ = false; - - std::vector event_revoker_guards_; - - Window* window_control_; - std::unique_ptr root_render_object_; - - Control* mouse_hover_control_; - - Control* focus_control_; // "focus_control_" can't be nullptr - - Control* mouse_captured_control_; - - bool layout_prefer_to_fill_window_ = true; -}; -} // namespace cru::ui diff --git a/include/cru/ui/Window.hpp b/include/cru/ui/Window.hpp index 450ea97b..5ea24855 100644 --- a/include/cru/ui/Window.hpp +++ b/include/cru/ui/Window.hpp @@ -3,7 +3,7 @@ namespace cru::ui { class Window final : public ContentControl { - friend UiHost; + friend WindowHost; public: static constexpr std::u16string_view control_type = u"Window"; @@ -32,9 +32,9 @@ class Window final : public ContentControl { void OnChildChanged(Control* old_child, Control* new_child) override; private: - std::unique_ptr managed_ui_host_; + std::unique_ptr managed_ui_host_; - // UiHost is responsible to take care of lifetime of this. + // WindowHost is responsible to take care of lifetime of this. render::WindowRenderObject* render_object_; }; } // namespace cru::ui diff --git a/include/cru/ui/WindowHost.hpp b/include/cru/ui/WindowHost.hpp new file mode 100644 index 00000000..64116590 --- /dev/null +++ b/include/cru/ui/WindowHost.hpp @@ -0,0 +1,185 @@ +#pragma once +#include +#include "Base.hpp" + +#include "cru/common/Event.hpp" +#include "cru/common/SelfResolvable.hpp" +#include "render/Base.hpp" + +namespace cru::ui { +struct AfterLayoutEventArgs {}; + +// The host of all controls and render objects. +// +// 3 situations on destroy: +// 1. Native window destroyed, IsRetainAfterDestroy: false: +// OnNativeDestroy(set native_window_destroyed_ to true, call ~Window due to +// deleting_ is false and IsRetainAfterDestroy is false) -> ~Window -> +// ~WindowHost(not destroy native window repeatedly due to native_window_destroyed_ +// is true) +// 2. Native window destroyed, IsRetainAfterDestroy: true: +// OnNativeDestroy(set native_window_destroyed_ to true, not call ~Window +// because deleting_ is false and IsRetainAfterDestroy is true) +// then, ~Window -> ~WindowHost(not destroy native window repeatedly due to +// native_window_destroyed_ is true) +// 3. Native window not destroyed, ~Window is called: +// ~Window -> ~WindowHost(set deleting_ to true, destroy native window +// due to native_window_destroyed is false) -> OnNativeDestroy(not call ~Window +// due to deleting_ is true and IsRetainAfterDestroy is whatever) +// In conclusion: +// 1. Set native_window_destroyed_ to true at the beginning of OnNativeDestroy. +// 2. Set deleting_ to true at the beginning of ~WindowHost. +// 3. Destroy native window when native_window_destroy_ is false in ~Window. +// 4. Delete Window when deleting_ is false and IsRetainAfterDestroy is false in +// OnNativeDestroy. +class WindowHost : public Object, public SelfResolvable { + CRU_DEFINE_CLASS_LOG_TAG(u"cru::ui::WindowHost") + + public: + // This will create root window render object and attach it to window. + // It will also create and manage a native window. + WindowHost(Window* window); + + CRU_DELETE_COPY(WindowHost) + CRU_DELETE_MOVE(WindowHost) + + ~WindowHost() 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* AfterLayoutEvent() { + return &after_layout_event_; + } + + // If true, preferred size of root render object is set to window size when + // measure. Default is true. + bool IsLayoutPreferToFillWindow() const; + void SetLayoutPreferToFillWindow(bool value); + + 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(); + + std::shared_ptr + GetNativeWindowResolver() { + return native_window_resolver_; + } + + bool IsRetainAfterDestroy() { return retain_after_destroy_; } + + void SetRetainAfterDestroy(bool destroy) { retain_after_destroy_ = destroy; } + + // Is layout is invalid, wait for relayout and then run the action. Otherwist + // run it right now. + void RunAfterLayoutStable(std::function action); + + 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 after_layout_event_; + std::vector > after_layout_stable_action_; + + std::shared_ptr + native_window_resolver_; + + // See remarks of WindowHost. + bool retain_after_destroy_ = false; + // See remarks of WindowHost. + bool deleting_ = false; + + // We need this because calling Resolve on resolver in handler of destroy + // event is bad and will always get the dying window. But we need to label the + // window as destroyed so the destructor will not destroy native window + // repeatedly. See remarks of WindowHost. + bool native_window_destroyed_ = false; + + std::vector event_revoker_guards_; + + Window* window_control_; + std::unique_ptr root_render_object_; + + Control* mouse_hover_control_; + + Control* focus_control_; // "focus_control_" can't be nullptr + + Control* mouse_captured_control_; + + bool layout_prefer_to_fill_window_ = true; +}; +} // namespace cru::ui diff --git a/include/cru/ui/render/RenderObject.hpp b/include/cru/ui/render/RenderObject.hpp index 57251e3a..f052221e 100644 --- a/include/cru/ui/render/RenderObject.hpp +++ b/include/cru/ui/render/RenderObject.hpp @@ -64,7 +64,7 @@ class RenderObject : public Object { Control* GetAttachedControl() const { return control_; } void SetAttachedControl(Control* new_control) { control_ = new_control; } - UiHost* GetUiHost() const { return ui_host_; } + WindowHost* GetWindowHost() const { return ui_host_; } RenderObject* GetParent() const { return parent_; } @@ -198,11 +198,11 @@ class RenderObject : public Object { private: void SetParent(RenderObject* new_parent); - void SetRenderHostRecursive(UiHost* host); + void SetRenderHostRecursive(WindowHost* host); private: Control* control_ = nullptr; - UiHost* ui_host_ = nullptr; + WindowHost* ui_host_ = nullptr; RenderObject* parent_ = nullptr; std::vector children_{}; diff --git a/include/cru/ui/render/WindowRenderObject.hpp b/include/cru/ui/render/WindowRenderObject.hpp index d2ca5526..23fd8748 100644 --- a/include/cru/ui/render/WindowRenderObject.hpp +++ b/include/cru/ui/render/WindowRenderObject.hpp @@ -6,7 +6,7 @@ namespace cru::ui::render { class WindowRenderObject : public RenderObject { public: - WindowRenderObject(UiHost* host); + WindowRenderObject(WindowHost* host); WindowRenderObject(const WindowRenderObject& other) = delete; WindowRenderObject(WindowRenderObject&& other) = delete; WindowRenderObject& operator=(const WindowRenderObject& other) = delete; -- cgit v1.2.3