diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/cru/ui/Base.h | 2 | ||||
| -rw-r--r-- | include/cru/ui/controls/Button.h | 4 | ||||
| -rw-r--r-- | include/cru/ui/controls/CheckBox.h | 8 | ||||
| -rw-r--r-- | include/cru/ui/controls/Control.h | 45 | ||||
| -rw-r--r-- | include/cru/ui/controls/ControlHost.h | 191 | ||||
| -rw-r--r-- | include/cru/ui/controls/IconButton.h | 11 | ||||
| -rw-r--r-- | include/cru/ui/controls/LayoutControl.h | 67 | ||||
| -rw-r--r-- | include/cru/ui/controls/NoChildControl.h | 21 | ||||
| -rw-r--r-- | include/cru/ui/controls/SingleChildControl.h | 35 | ||||
| -rw-r--r-- | include/cru/ui/controls/TextBlock.h | 10 | ||||
| -rw-r--r-- | include/cru/ui/controls/TextBox.h | 8 | ||||
| -rw-r--r-- | include/cru/ui/controls/TreeView.h | 11 | ||||
| -rw-r--r-- | include/cru/ui/controls/Window.h | 168 | ||||
| -rw-r--r-- | include/cru/ui/events/RoutedEvent.h | 2 | ||||
| -rw-r--r-- | include/cru/ui/render/RenderObject.h | 2 |
15 files changed, 272 insertions, 313 deletions
diff --git a/include/cru/ui/Base.h b/include/cru/ui/Base.h index 9e24cfa2..06dd23c2 100644 --- a/include/cru/ui/Base.h +++ b/include/cru/ui/Base.h @@ -35,7 +35,7 @@ namespace colors = cru::platform::colors; namespace controls { class Control; -class Window; +class ControlHost; } // namespace controls //-------------------- region: basic types -------------------- diff --git a/include/cru/ui/controls/Button.h b/include/cru/ui/controls/Button.h index e8fa50f1..64b9bba0 100644 --- a/include/cru/ui/controls/Button.h +++ b/include/cru/ui/controls/Button.h @@ -16,10 +16,6 @@ class CRU_UI_API Button : public SingleChildControl<render::BorderRenderObject>, public: Button(); - Button(const Button& other) = delete; - Button(Button&& other) = delete; - Button& operator=(const Button& other) = delete; - Button& operator=(Button&& other) = delete; ~Button() override; std::string GetControlType() const final { return std::string(kControlType); } diff --git a/include/cru/ui/controls/CheckBox.h b/include/cru/ui/controls/CheckBox.h index 8a2c84a0..6f4eae2e 100644 --- a/include/cru/ui/controls/CheckBox.h +++ b/include/cru/ui/controls/CheckBox.h @@ -1,13 +1,13 @@ #pragma once #include "../helper/ClickDetector.h" #include "../render/BorderRenderObject.h" +#include "Control.h" #include "IBorderControl.h" #include "ICheckableControl.h" #include "IClickableControl.h" -#include "NoChildControl.h" namespace cru::ui::controls { -class CRU_UI_API CheckBox : public NoChildControl, +class CRU_UI_API CheckBox : public Control, public virtual IBorderControl, public virtual ICheckableControl, public virtual IClickableControl { @@ -17,7 +17,9 @@ class CRU_UI_API CheckBox : public NoChildControl, CheckBox(); ~CheckBox() override; - std::string GetControlType() const override { return std::string(kControlType); } + std::string GetControlType() const override { + return std::string(kControlType); + } render::RenderObject* GetRenderObject() const override { return container_render_object_.get(); diff --git a/include/cru/ui/controls/Control.h b/include/cru/ui/controls/Control.h index 94de4cdc..9e5e86b8 100644 --- a/include/cru/ui/controls/Control.h +++ b/include/cru/ui/controls/Control.h @@ -24,9 +24,9 @@ namespace cru::ui::controls { class CRU_UI_API Control : public Object, public DeleteLaterImpl, public SelfResolvable<Control> { - friend class RootControl; + friend class ControlHost; - CRU_DEFINE_CLASS_LOG_TAG("Control") + CRU_DEFINE_CLASS_LOG_TAG("cru::ui::controls::Control") protected: Control(); @@ -41,24 +41,33 @@ class CRU_UI_API Control : public Object, //*************** region: tree *************** public: - Window* GetWindow(); + ControlHost* GetControlHost(); - Control* GetParent() const { return parent_; } - void SetParent(Control* parent); + Control* GetParent(); bool HasAncestor(Control* control); + const std::vector<Control*>& GetChildren(); + void RemoveChild(Control* child); + void RemoveAllChild(); + void RemoveFromParent(); - virtual void ForEachChild(const std::function<void(Control*)>& predicate) = 0; - - /** - * \remarks This method should be permissive, which means if the specified - * child control is not a real child of this then nothing will be done. - */ - virtual void RemoveChild(Control* child) = 0; + template <typename F> + void TraverseDescendents(F&& f, bool include_this) { + if (include_this) { + f(this); + } - void RemoveFromParent(); + for (auto child : GetChildren()) { + child->TraverseDescendents(std::forward<F>(f), true); + } + } controls::Control* HitTest(const Point& point); + protected: + void InsertChildAt(Control* control, Index index); + void RemoveChildAt(Index index); + void AddChild(Control* control); + public: virtual render::RenderObject* GetRenderObject() const = 0; @@ -89,7 +98,7 @@ class CRU_UI_API Control : public Object, //*************** region: mouse *************** public: - bool IsMouseOver() const { return is_mouse_over_; } + bool IsMouseOver(); bool CaptureMouse(); @@ -137,12 +146,14 @@ class CRU_UI_API Control : public Object, //*************** region: tree *************** protected: - virtual void OnParentChanged(Control* old_parent, Control* new_parent) {} + virtual void OnParentChanged(Control* old_parent, Control* new_parent); + virtual void OnChildInserted(Control* control, Index index); + virtual void OnChildRemoved(Control* control, Index index); private: + ControlHost* host_ = nullptr; Control* parent_ = nullptr; - - bool is_mouse_over_ = false; + std::vector<Control*> children_; std::shared_ptr<platform::gui::ICursor> cursor_ = nullptr; diff --git a/include/cru/ui/controls/ControlHost.h b/include/cru/ui/controls/ControlHost.h new file mode 100644 index 00000000..c67e8a72 --- /dev/null +++ b/include/cru/ui/controls/ControlHost.h @@ -0,0 +1,191 @@ +#pragma once +#include "Control.h" + +#include <cru/base/Base.h> +#include <cru/base/Event.h> +#include <cru/base/Guard.h> +#include <cru/base/log/Logger.h> +#include <cru/platform/gui/UiApplication.h> +#include <cru/platform/gui/Window.h> + +namespace cru::ui::controls { +class CRU_UI_API ControlHost : public Object { + CRU_DEFINE_CLASS_LOG_TAG("cru::ui::controls::ControlHost") + friend Control; + + public: + explicit ControlHost(Control* root_control); + ~ControlHost() override; + + platform::gui::INativeWindow* GetNativeWindow(); + + void InvalidateLayout(); + void InvalidatePaint(); + + void Repaint(); + void Relayout(); + void RelayoutWithSize(const Size& available_size = Size::Infinite(), + bool set_window_size_to_fit_content = false); + + // 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); + + // 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_; } + + Control* GetFocusControl(); + void SetFocusControl(Control* control); + + Control* GetMouseCaptureControl(); + bool SetMouseCaptureControl(Control* control); + + std::shared_ptr<platform::gui::ICursor> GetOverrideCursor(); + void SetOverrideCursor(std::shared_ptr<platform::gui::ICursor> cursor); + + bool IsInEventHandling(); + + CRU_DEFINE_EVENT(AfterLayout, std::nullptr_t) + + private: + std::unique_ptr<platform::gui::INativeWindow> CreateNativeWindow(); + + void OnNativeDestroy(platform::gui::INativeWindow* window, std::nullptr_t); + void OnNativePaint(platform::gui::INativeWindow* window, std::nullptr_t); + void OnNativeResize(platform::gui::INativeWindow* window, const Size& size); + void OnNativeFocus(platform::gui::INativeWindow* window, + cru::platform::gui::FocusChangeType focus); + void OnNativeMouseEnterLeave(platform::gui::INativeWindow* window, + cru::platform::gui::MouseEnterLeaveType enter); + void OnNativeMouseMove(platform::gui::INativeWindow* window, + const Point& point); + void OnNativeMouseDown(platform::gui::INativeWindow* window, + const platform::gui::NativeMouseButtonEventArgs& args); + void OnNativeMouseUp(platform::gui::INativeWindow* window, + const platform::gui::NativeMouseButtonEventArgs& args); + void OnNativeMouseWheel(platform::gui::INativeWindow* window, + const platform::gui::NativeMouseWheelEventArgs& args); + void OnNativeKeyDown(platform::gui::INativeWindow* window, + const platform::gui::NativeKeyEventArgs& args); + void OnNativeKeyUp(platform::gui::INativeWindow* window, + const platform::gui::NativeKeyEventArgs& args); + + void DispatchFocusControlChangeEvent(Control* old_control, + Control* new_control, bool is_window); + void DispatchMouseHoverControlChangeEvent(Control* old_control, + Control* new_control, + const Point& point, bool no_leave, + bool no_enter); + + template <typename EventArgs, typename... Args> + void DispatchEvent(Control* const original_sender, + events::RoutedEvent<EventArgs>* (Control::*event_ptr)(), + Control* const last_receiver, Args&&... args) { + constexpr auto kLogTag = "cru::ui::controls::DispatchEvent"; + + event_handling_count_++; + Guard event_handling_count_guard([this] { event_handling_count_--; }); + + if (original_sender == nullptr || original_sender == last_receiver) return; + + std::string log = "Begin dispatching routed event " + + (original_sender->*event_ptr)()->GetName() + + ":\n\tTunnel:"; + + Guard logging_guard([&] { + log += "\nEnd dispatching routed event " + + (original_sender->*event_ptr)()->GetName() + "."; + CRU_LOG_TAG_DEBUG("{}", log); + }); + + std::vector<ObjectResolver<Control>> receive_list; + + auto parent = original_sender; + while (parent != last_receiver) { + receive_list.push_back(parent->CreateResolver()); + parent = parent->GetParent(); + } + + auto handled = false; + + // tunnel + for (auto i = receive_list.crbegin(); i != receive_list.crend(); ++i) { + auto control = i->Resolve(); + log += " "; + if (!control) { + log += "(deleted)"; + continue; + } + log += control->GetDebugId(); + EventArgs event_args(control, original_sender, + std::forward<Args>(args)...); + (control->*event_ptr)()->tunnel_.Raise(event_args); + if (event_args.IsHandled()) { + log += " marked as handled."; + handled = true; + break; + } + } + + // bubble + if (!handled) { + log += "\n\tBubble:"; + for (auto resolver : receive_list) { + auto control = resolver.Resolve(); + log += " "; + if (!control) { + log += "(deleted)"; + continue; + } + log += control->GetDebugId(); + EventArgs event_args(control, original_sender, + std::forward<Args>(args)...); + (control->*event_ptr)()->bubble_.Raise(event_args); + if (event_args.IsHandled()) { + log += " marked as handled."; + break; + } + } + } + + log += "\n\tDirect:"; + // direct + for (auto resolver : receive_list) { + auto control = resolver.Resolve(); + log += " "; + if (!control) { + log += "(deleted)"; + continue; + } + log += control->GetDebugId(); + EventArgs event_args(control, original_sender, + std::forward<Args>(args)...); + (control->*event_ptr)()->direct_.Raise(event_args); + } + } + + void UpdateCursor(); + void NotifyControlParentChange(Control* control, Control* old_parent, Control* new_parent); + + private: + int event_handling_count_; + + Control* root_control_; + std::unique_ptr<platform::gui::INativeWindow> native_window_; + + Control* focus_control_; + Control* mouse_hover_control_; + Control* mouse_captured_control_; + + std::shared_ptr<platform::gui::ICursor> override_cursor_; + + bool layout_prefer_to_fill_window_; + + platform::gui::TimerAutoCanceler repaint_schedule_canceler_; + platform::gui::TimerAutoCanceler relayout_schedule_canceler_; +}; +} // namespace cru::ui::controls diff --git a/include/cru/ui/controls/IconButton.h b/include/cru/ui/controls/IconButton.h index e52d2a26..0bbda327 100644 --- a/include/cru/ui/controls/IconButton.h +++ b/include/cru/ui/controls/IconButton.h @@ -1,18 +1,17 @@ #pragma once -#include <memory> -#include "NoChildControl.h" - #include "../helper/ClickDetector.h" #include "../render/BorderRenderObject.h" #include "../render/GeometryRenderObject.h" +#include "Control.h" #include "IBorderControl.h" #include "IClickableControl.h" #include "IContentBrushControl.h" -#include "cru/base/Event.h" -#include "cru/platform/graphics/Brush.h" + +#include <cru/base/Event.h> +#include <cru/platform/graphics/Brush.h> namespace cru::ui::controls { -class CRU_UI_API IconButton : public NoChildControl, +class CRU_UI_API IconButton : public Control, public virtual IClickableControl, public virtual IBorderControl, public virtual IContentBrushControl { diff --git a/include/cru/ui/controls/LayoutControl.h b/include/cru/ui/controls/LayoutControl.h index 54407a3f..fad86530 100644 --- a/include/cru/ui/controls/LayoutControl.h +++ b/include/cru/ui/controls/LayoutControl.h @@ -10,17 +10,14 @@ class LayoutControl : public Control { } public: - LayoutControl(const LayoutControl& other) = delete; - LayoutControl(LayoutControl&& other) = delete; - LayoutControl& operator=(const LayoutControl& other) = delete; - LayoutControl& operator=(LayoutControl&& other) = delete; - ~LayoutControl() override { ClearChildren(); } + using Control::AddChild; + using Control::InsertChildAt; + using Control::RemoveChildAt; - public: - const std::vector<Control*>& GetChildren() const { return children_; } Index GetChildCount() const { return children_.size(); } - Control* GetChild(Index index) const { return children_[index]; } - Index IndexOf(Control* control) const { + Control* GetChildAt(Index index) const { return children_[index]; } + + Index IndexOfChild(Control* control) const { auto it = std::find(children_.begin(), children_.end(), control); if (it == children_.end()) { return -1; @@ -28,19 +25,6 @@ class LayoutControl : public Control { return it - children_.begin(); } - void ForEachChild(const std::function<void(Control*)>& callback) override { - for (auto child : children_) { - callback(child); - } - } - - void RemoveChild(Control* child) override { - auto index = IndexOf(child); - if (index != -1) { - RemoveChildAt(index); - } - } - render::RenderObject* GetRenderObject() const override { return container_render_object_.get(); } @@ -49,36 +33,6 @@ class LayoutControl : public Control { return container_render_object_.get(); } - void AddChildAt(Control* child, Index position) { - Expects(child); - Expects(child->GetParent() == nullptr); - if (position < 0) position = 0; - if (position > children_.size()) position = children_.size(); - children_.insert(children_.begin() + position, child); - child->SetParent(this); - - assert(child->GetRenderObject()); - container_render_object_->AddChild(child->GetRenderObject(), position); - } - - void AddChild(Control* child) { AddChildAt(child, GetChildCount()); } - - void RemoveChildAt(Index position) { - if (position < 0 || position >= children_.size()) return; - auto child = children_[position]; - children_.erase(children_.begin() + position); - container_render_object_->RemoveChild(position); - child->SetParent(nullptr); - } - - void ClearChildren() { - container_render_object_->ClearChildren(); - for (auto child : children_) { - child->SetParent(nullptr); - } - children_.clear(); - } - const typename TRenderObject::ChildLayoutData& GetChildLayoutData( Index position) { return container_render_object_->GetChildLayoutDataAt(position); @@ -89,6 +43,15 @@ class LayoutControl : public Control { container_render_object_->SetChildLayoutDataAt(position, data); } + protected: + void OnChildInserted(Control* control, Index index) override { + container_render_object_->AddChild(control->GetRenderObject(), index); + } + + void OnChildRemoved([[maybe_unused]] Control* control, Index index) override { + container_render_object_->RemoveChild(index); + } + private: std::unique_ptr<TRenderObject> container_render_object_; diff --git a/include/cru/ui/controls/NoChildControl.h b/include/cru/ui/controls/NoChildControl.h deleted file mode 100644 index f22fd85e..00000000 --- a/include/cru/ui/controls/NoChildControl.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include "Control.h" - -namespace cru::ui::controls { -class CRU_UI_API NoChildControl : public Control { - protected: - NoChildControl() = default; - - public: - NoChildControl(const NoChildControl& other) = delete; - NoChildControl(NoChildControl&& other) = delete; - NoChildControl& operator=(const NoChildControl& other) = delete; - NoChildControl& operator=(NoChildControl&& other) = delete; - ~NoChildControl() override = default; - - public: - void ForEachChild(const std::function<void(Control*)>& callback) override; - - void RemoveChild(Control* child) override; -}; -} // namespace cru::ui::controls diff --git a/include/cru/ui/controls/SingleChildControl.h b/include/cru/ui/controls/SingleChildControl.h index b2e58c5f..f748a38d 100644 --- a/include/cru/ui/controls/SingleChildControl.h +++ b/include/cru/ui/controls/SingleChildControl.h @@ -10,25 +10,17 @@ class SingleChildControl : public Control { } public: - CRU_DELETE_COPY(SingleChildControl) - CRU_DELETE_MOVE(SingleChildControl) - - ~SingleChildControl() override { SetChild(nullptr); } + Control* GetChild() { + return GetChildren().empty() ? nullptr : GetChildren().front(); + } - Control* GetChild() const { return child_; } void SetChild(Control* child) { - if (child == child_) return; - - assert(child == nullptr || child->GetParent() == nullptr); - - if (child_) { - child_->SetParent(nullptr); + if (GetChild() == child) return; + if (!GetChildren().empty()) { + RemoveChildAt(0); } - - child_ = child; - if (child) { - child->SetParent(this); + InsertChildAt(child, 0); } container_render_object_->SetChild( @@ -43,20 +35,7 @@ class SingleChildControl : public Control { return container_render_object_.get(); } - void ForEachChild(const std::function<void(Control*)>& predicate) override { - if (child_) { - predicate(child_); - } - } - - void RemoveChild(Control* child) override { - if (child_ == child) { - SetChild(nullptr); - } - } - private: - Control* child_ = nullptr; std::unique_ptr<TRenderObject> container_render_object_; }; } // namespace cru::ui::controls diff --git a/include/cru/ui/controls/TextBlock.h b/include/cru/ui/controls/TextBlock.h index a3b6407f..af9865c4 100644 --- a/include/cru/ui/controls/TextBlock.h +++ b/include/cru/ui/controls/TextBlock.h @@ -1,15 +1,15 @@ #pragma once -#include "NoChildControl.h" - +#include "Control.h" #include "../render/TextRenderObject.h" #include "IContentBrushControl.h" #include "IFontControl.h" #include "TextHostControlService.h" -#include "cru/platform/graphics/Brush.h" -#include "cru/platform/graphics/Font.h" + +#include <cru/platform/graphics/Brush.h> +#include <cru/platform/graphics/Font.h> namespace cru::ui::controls { -class CRU_UI_API TextBlock : public NoChildControl, +class CRU_UI_API TextBlock : public Control, public virtual ITextHostControl, public virtual IFontControl, public virtual IContentBrushControl { diff --git a/include/cru/ui/controls/TextBox.h b/include/cru/ui/controls/TextBox.h index adb9895e..4c6ef384 100644 --- a/include/cru/ui/controls/TextBox.h +++ b/include/cru/ui/controls/TextBox.h @@ -1,18 +1,18 @@ #pragma once -#include "NoChildControl.h" - #include "../render/BorderRenderObject.h" #include "../render/TextRenderObject.h" +#include "Control.h" #include "IBorderControl.h" #include "IContentBrushControl.h" #include "IFontControl.h" #include "TextHostControlService.h" -#include "cru/platform/graphics/Brush.h" + +#include <cru/platform/graphics/Brush.h> #include <memory> namespace cru::ui::controls { -class CRU_UI_API TextBox : public NoChildControl, +class CRU_UI_API TextBox : public Control, public virtual IBorderControl, public virtual ITextHostControl, public virtual IContentBrushControl, diff --git a/include/cru/ui/controls/TreeView.h b/include/cru/ui/controls/TreeView.h index f4938259..62b1c69b 100644 --- a/include/cru/ui/controls/TreeView.h +++ b/include/cru/ui/controls/TreeView.h @@ -48,6 +48,11 @@ class CRU_UI_API TreeViewItem : public Object { }; class CRU_UI_API TreeView : public Control { + friend TreeViewItem; + + private: + using Control::AddChild; + public: constexpr static std::string_view kControlType = "TreeView"; @@ -61,11 +66,11 @@ class CRU_UI_API TreeView : public Control { } render::TreeRenderObject* GetRenderObject() { return &render_object_; } - void ForEachChild(const std::function<void(Control*)>& predicate) override; - void RemoveChild(Control* control) override; - TreeViewItem* GetRootItem() { return &root_item_; } + protected: + void OnChildRemoved(Control* control, Index index) override; + private: render::TreeRenderObject render_object_; TreeViewItem root_item_; diff --git a/include/cru/ui/controls/Window.h b/include/cru/ui/controls/Window.h index 88320219..a2ae01f9 100644 --- a/include/cru/ui/controls/Window.h +++ b/include/cru/ui/controls/Window.h @@ -19,7 +19,6 @@ class CRU_UI_API Window static constexpr std::string_view kControlType = "Window"; Window(); - ~Window() override; static Window* CreatePopup(); @@ -29,175 +28,10 @@ class CRU_UI_API Window platform::gui::INativeWindow* GetNativeWindow(); - void InvalidateLayout(); - void InvalidatePaint(); - - void Repaint(); - void Relayout(); - void RelayoutWithSize(const Size& available_size = Size::Infinite(), - bool set_window_size_to_fit_content = false); - void SetGainFocusOnCreateAndDestroyWhenLoseFocus(bool value); - // 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); - - // 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_; } - - Control* GetFocusControl(); - void SetFocusControl(Control* control); - - Control* GetMouseCaptureControl(); - bool SetMouseCaptureControl(Control* control); - - std::shared_ptr<platform::gui::ICursor> GetOverrideCursor(); - void SetOverrideCursor(std::shared_ptr<platform::gui::ICursor> cursor); - - bool IsInEventHandling(); - - CRU_DEFINE_EVENT(AfterLayout, std::nullptr_t) - - private: - std::unique_ptr<platform::gui::INativeWindow> CreateNativeWindow(); - - void OnNativeDestroy(platform::gui::INativeWindow* window, std::nullptr_t); - void OnNativePaint(platform::gui::INativeWindow* window, std::nullptr_t); - void OnNativeResize(platform::gui::INativeWindow* window, const Size& size); - void OnNativeFocus(platform::gui::INativeWindow* window, - cru::platform::gui::FocusChangeType focus); - void OnNativeMouseEnterLeave(platform::gui::INativeWindow* window, - cru::platform::gui::MouseEnterLeaveType enter); - void OnNativeMouseMove(platform::gui::INativeWindow* window, - const Point& point); - void OnNativeMouseDown(platform::gui::INativeWindow* window, - const platform::gui::NativeMouseButtonEventArgs& args); - void OnNativeMouseUp(platform::gui::INativeWindow* window, - const platform::gui::NativeMouseButtonEventArgs& args); - void OnNativeMouseWheel(platform::gui::INativeWindow* window, - const platform::gui::NativeMouseWheelEventArgs& args); - void OnNativeKeyDown(platform::gui::INativeWindow* window, - const platform::gui::NativeKeyEventArgs& args); - void OnNativeKeyUp(platform::gui::INativeWindow* window, - const platform::gui::NativeKeyEventArgs& args); - - void DispatchFocusControlChangeEvent(Control* old_control, - Control* new_control, bool is_window); - void DispatchMouseHoverControlChangeEvent(Control* old_control, - Control* new_control, - const Point& point, bool no_leave, - bool no_enter); - - template <typename EventArgs, typename... Args> - void DispatchEvent(Control* const original_sender, - events::RoutedEvent<EventArgs>* (Control::*event_ptr)(), - Control* const last_receiver, Args&&... args) { - constexpr auto kLogTag = "cru::ui::controls::DispatchEvent"; - - event_handling_count_++; - Guard event_handling_count_guard([this] { event_handling_count_--; }); - - if (original_sender == nullptr || original_sender == last_receiver) return; - - std::string log = "Begin dispatching routed event " + - (original_sender->*event_ptr)()->GetName() + - ":\n\tTunnel:"; - - Guard logging_guard([&] { - log += "\nEnd dispatching routed event " + - (original_sender->*event_ptr)()->GetName() + "."; - CRU_LOG_TAG_DEBUG("{}", log); - }); - - std::vector<ObjectResolver<Control>> receive_list; - - auto parent = original_sender; - while (parent != last_receiver) { - receive_list.push_back(parent->CreateResolver()); - parent = parent->GetParent(); - } - - auto handled = false; - - // tunnel - for (auto i = receive_list.crbegin(); i != receive_list.crend(); ++i) { - auto control = i->Resolve(); - log += " "; - if (!control) { - log += "(deleted)"; - continue; - } - log += control->GetDebugId(); - EventArgs event_args(control, original_sender, - std::forward<Args>(args)...); - (control->*event_ptr)()->tunnel_.Raise(event_args); - if (event_args.IsHandled()) { - log += " marked as handled."; - handled = true; - break; - } - } - - // bubble - if (!handled) { - log += "\n\tBubble:"; - for (auto resolver : receive_list) { - auto control = resolver.Resolve(); - log += " "; - if (!control) { - log += "(deleted)"; - continue; - } - log += control->GetDebugId(); - EventArgs event_args(control, original_sender, - std::forward<Args>(args)...); - (control->*event_ptr)()->bubble_.Raise(event_args); - if (event_args.IsHandled()) { - log += " marked as handled."; - break; - } - } - } - - log += "\n\tDirect:"; - // direct - for (auto resolver : receive_list) { - auto control = resolver.Resolve(); - log += " "; - if (!control) { - log += "(deleted)"; - continue; - } - log += control->GetDebugId(); - EventArgs event_args(control, original_sender, - std::forward<Args>(args)...); - (control->*event_ptr)()->direct_.Raise(event_args); - } - } - - void UpdateCursor(); - void NotifyControlDestroyed(Control* control); - private: - int event_handling_count_; - - std::unique_ptr<platform::gui::INativeWindow> native_window_; - - Control* focus_control_; - Control* mouse_hover_control_; - Control* mouse_captured_control_; - - std::shared_ptr<platform::gui::ICursor> override_cursor_; - - bool layout_prefer_to_fill_window_; - - platform::gui::TimerAutoCanceler repaint_schedule_canceler_; - platform::gui::TimerAutoCanceler relayout_schedule_canceler_; + std::shared_ptr<ControlHost> control_host_; Control* attached_control_; diff --git a/include/cru/ui/events/RoutedEvent.h b/include/cru/ui/events/RoutedEvent.h index 58e50d63..b14b6e42 100644 --- a/include/cru/ui/events/RoutedEvent.h +++ b/include/cru/ui/events/RoutedEvent.h @@ -8,7 +8,7 @@ namespace cru::ui::events { // EventArgs must be reference because the IsHandled property must be settable. template <typename TEventArgs> class CRU_UI_API RoutedEvent { - friend controls::Window; + friend controls::ControlHost; public: static_assert(std::is_base_of_v<UiEventArgs, TEventArgs>, diff --git a/include/cru/ui/render/RenderObject.h b/include/cru/ui/render/RenderObject.h index c299ea24..4c19ad3e 100644 --- a/include/cru/ui/render/RenderObject.h +++ b/include/cru/ui/render/RenderObject.h @@ -137,7 +137,7 @@ class CRU_UI_API RenderObject : public Object { virtual RenderObject* HitTest(const Point& point) = 0; public: - controls::Window* GetWindow(); + controls::ControlHost* GetControlHost(); void InvalidateLayout(); void InvalidatePaint(); |
