diff options
Diffstat (limited to 'include/cru')
-rw-r--r-- | include/cru/ui/base.hpp | 1 | ||||
-rw-r--r-- | include/cru/ui/control.hpp | 16 | ||||
-rw-r--r-- | include/cru/ui/render/render_object.hpp | 35 | ||||
-rw-r--r-- | include/cru/ui/render/window_render_object.hpp | 10 | ||||
-rw-r--r-- | include/cru/ui/ui_host.hpp | 127 | ||||
-rw-r--r-- | include/cru/ui/window.hpp | 98 |
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 |