diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/cru/base/Event.h | 7 | ||||
| -rw-r--r-- | include/cru/ui/Base.h | 18 | ||||
| -rw-r--r-- | include/cru/ui/DeleteLater.h | 3 | ||||
| -rw-r--r-- | include/cru/ui/components/Component.h | 6 | ||||
| -rw-r--r-- | include/cru/ui/components/Menu.h | 31 | ||||
| -rw-r--r-- | include/cru/ui/components/PopupButton.h | 1 | ||||
| -rw-r--r-- | include/cru/ui/controls/Control.h | 83 | ||||
| -rw-r--r-- | include/cru/ui/controls/Popup.h | 22 | ||||
| -rw-r--r-- | include/cru/ui/controls/RootControl.h | 34 | ||||
| -rw-r--r-- | include/cru/ui/controls/TextHostControlService.h | 2 | ||||
| -rw-r--r-- | include/cru/ui/controls/Window.h | 188 | ||||
| -rw-r--r-- | include/cru/ui/events/RoutedEvent.h | 20 | ||||
| -rw-r--r-- | include/cru/ui/host/LayoutPaintCycler.h | 39 | ||||
| -rw-r--r-- | include/cru/ui/host/WindowHost.h | 172 | ||||
| -rw-r--r-- | include/cru/ui/render/RenderObject.h | 2 | ||||
| -rw-r--r-- | include/cru/ui/render/ScrollBar.h | 8 |
16 files changed, 240 insertions, 396 deletions
diff --git a/include/cru/base/Event.h b/include/cru/base/Event.h index 276c313f..c26bea83 100644 --- a/include/cru/base/Event.h +++ b/include/cru/base/Event.h @@ -128,6 +128,13 @@ class Event : public EventBase, public IEvent<TEventArgs> { EventHandlerToken current_token_ = 0; }; +#define CRU_DEFINE_EVENT(name, arg_type) \ + private: \ + ::cru::Event<arg_type> name##Event_; \ + \ + public: \ + ::cru::IEvent<arg_type>* name##Event() { return &name##Event_; } + namespace details { struct EventHandlerRevokerDestroyer { void operator()(EventHandlerRevoker* p) { diff --git a/include/cru/ui/Base.h b/include/cru/ui/Base.h index 3f270b39..9e24cfa2 100644 --- a/include/cru/ui/Base.h +++ b/include/cru/ui/Base.h @@ -35,12 +35,9 @@ namespace colors = cru::platform::colors; namespace controls { class Control; +class Window; } // namespace controls -namespace host { -class WindowHost; -} - //-------------------- region: basic types -------------------- enum class Direction { Horizontal, Vertical }; enum class Alignment { Start, End, Center, Stretch }; @@ -67,21 +64,12 @@ struct CornerRadius { return *this; } + bool operator==(const CornerRadius& other) const = default; + Point left_top; Point right_top; Point left_bottom; Point right_bottom; }; -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); -} - } // namespace cru::ui diff --git a/include/cru/ui/DeleteLater.h b/include/cru/ui/DeleteLater.h index ddbf2ce1..95301bc0 100644 --- a/include/cru/ui/DeleteLater.h +++ b/include/cru/ui/DeleteLater.h @@ -13,9 +13,6 @@ class CRU_UI_API DeleteLaterImpl { virtual ~DeleteLaterImpl(); void DeleteLater(); - protected: - virtual void OnPrepareDelete(); - private: bool delete_later_scheduled_; }; diff --git a/include/cru/ui/components/Component.h b/include/cru/ui/components/Component.h index 6d31ae79..d8966a89 100644 --- a/include/cru/ui/components/Component.h +++ b/include/cru/ui/components/Component.h @@ -10,9 +10,6 @@ namespace cru::ui::components { */ class CRU_UI_API Component : public Object, public DeleteLaterImpl { public: - Component() = default; - ~Component() = default; - virtual controls::Control* GetRootControl() = 0; bool IsDeleteByParent() const { return delete_by_parent_; } @@ -21,9 +18,6 @@ class CRU_UI_API Component : public Object, public DeleteLaterImpl { } void DeleteIfDeleteByParent(bool delete_later = true); - protected: - void OnPrepareDelete() override; - private: bool delete_by_parent_ = false; }; diff --git a/include/cru/ui/components/Menu.h b/include/cru/ui/components/Menu.h index 554a8898..92731f2e 100644 --- a/include/cru/ui/components/Menu.h +++ b/include/cru/ui/components/Menu.h @@ -1,11 +1,10 @@ #pragma once +#include "../controls/Button.h" +#include "../controls/Control.h" +#include "../controls/FlexLayout.h" +#include "../controls/TextBlock.h" +#include "../controls/Window.h" #include "Component.h" -#include "cru/base/Base.h" -#include "cru/ui/controls/Button.h" -#include "cru/ui/controls/Control.h" -#include "cru/ui/controls/FlexLayout.h" -#include "cru/ui/controls/Popup.h" -#include "cru/ui/controls/TextBlock.h" #include <functional> #include <vector> @@ -16,11 +15,6 @@ class CRU_UI_API MenuItem : public Component { MenuItem(); explicit MenuItem(std::string text); - CRU_DELETE_COPY(MenuItem) - CRU_DELETE_MOVE(MenuItem) - - ~MenuItem(); - public: controls::Control* GetRootControl() override { return &container_; } @@ -39,10 +33,6 @@ class CRU_UI_API MenuItem : public Component { class CRU_UI_API Menu : public Component { public: Menu(); - - CRU_DELETE_COPY(Menu) - CRU_DELETE_MOVE(Menu) - ~Menu(); public: @@ -58,7 +48,8 @@ class CRU_UI_API Menu : public Component { void AddTextItem(std::string text, std::function<void()> on_click) { AddTextItemAt(std::move(text), GetItemCount(), std::move(on_click)); } - void AddTextItemAt(std::string text, Index index, std::function<void()> on_click); + void AddTextItemAt(std::string text, Index index, + std::function<void()> on_click); void SetOnItemClick(std::function<void(Index)> on_item_click) { on_item_click_ = std::move(on_item_click); @@ -74,16 +65,12 @@ class CRU_UI_API Menu : public Component { class CRU_UI_API PopupMenu : public Component { public: explicit PopupMenu(controls::Control* attached_control = nullptr); - - CRU_DELETE_COPY(PopupMenu) - CRU_DELETE_MOVE(PopupMenu) - ~PopupMenu(); public: controls::Control* GetRootControl() override; - controls::Popup* GetPopup() { return &popup_; } + controls::Window* GetPopup() { return popup_; } Menu* GetMenu() { return &menu_; } // position relative to screen left top. @@ -99,7 +86,7 @@ class CRU_UI_API PopupMenu : public Component { private: controls::Control* attached_control_; - controls::Popup popup_; + controls::Window* popup_; Menu menu_; }; } // namespace cru::ui::components diff --git a/include/cru/ui/components/PopupButton.h b/include/cru/ui/components/PopupButton.h index 5fa69044..0e3d5314 100644 --- a/include/cru/ui/components/PopupButton.h +++ b/include/cru/ui/components/PopupButton.h @@ -4,7 +4,6 @@ #include "cru/ui/components/Menu.h" #include "cru/ui/controls/Button.h" #include "cru/ui/controls/IconButton.h" -#include "cru/ui/controls/Popup.h" #include "cru/ui/controls/TextBlock.h" namespace cru::ui::components { diff --git a/include/cru/ui/controls/Control.h b/include/cru/ui/controls/Control.h index 77f5f392..684bc960 100644 --- a/include/cru/ui/controls/Control.h +++ b/include/cru/ui/controls/Control.h @@ -4,6 +4,8 @@ #include "../events/UiEvents.h" #include "../render/RenderObject.h" #include "../style/StyleRuleSet.h" +#include "cru/ui/events/KeyEventArgs.h" +#include "cru/ui/events/MouseWheelEventArgs.h" #include "cru/ui/render/MeasureRequirement.h" namespace cru::ui::controls { @@ -31,9 +33,11 @@ class CRU_UI_API Control : public Object, public DeleteLaterImpl { public: virtual std::string GetControlType() const = 0; + std::string GetDebugId() const; + //*************** region: tree *************** public: - host::WindowHost* GetWindowHost() const { return window_host_; } + Window* GetWindow(); Control* GetParent() const { return parent_; } void SetParent(Control* parent); @@ -48,6 +52,8 @@ class CRU_UI_API Control : public Object, public DeleteLaterImpl { void RemoveFromParent(); + controls::Control* HitTest(const Point& point); + public: virtual render::RenderObject* GetRenderObject() const = 0; @@ -107,83 +113,30 @@ class CRU_UI_API Control : public Object, public DeleteLaterImpl { // the mouse, this event is raised as regular. But if mouse is captured by // another control, the control will not receive any mouse enter event. You // can use `IsMouseCaptured` to get more info. - events::RoutedEvent<events::MouseEventArgs>* MouseEnterEvent() { - return &mouse_enter_event_; - } + CRU_DEFINE_ROUTED_EVENT(MouseEnter, events::MouseEventArgs) + // Raised when mouse is leave the control. Even when the control itself // captures the mouse, this event is raised as regular. But if mouse is // captured by another control, the control will not receive any mouse leave // event. You can use `IsMouseCaptured` to get more info. - events::RoutedEvent<events::MouseEventArgs>* MouseLeaveEvent() { - return &mouse_leave_event_; - } - // Raised when mouse is move in the control. - events::RoutedEvent<events::MouseEventArgs>* MouseMoveEvent() { - return &mouse_move_event_; - } - // Raised when a mouse button is pressed in the control. - events::RoutedEvent<events::MouseButtonEventArgs>* MouseDownEvent() { - return &mouse_down_event_; - } - // Raised when a mouse button is released in the control. - events::RoutedEvent<events::MouseButtonEventArgs>* MouseUpEvent() { - return &mouse_up_event_; - } - events::RoutedEvent<events::MouseWheelEventArgs>* MouseWheelEvent() { - return &mouse_wheel_event_; - } - events::RoutedEvent<events::KeyEventArgs>* KeyDownEvent() { - return &key_down_event_; - } - events::RoutedEvent<events::KeyEventArgs>* KeyUpEvent() { - return &key_up_event_; - } - events::RoutedEvent<events::FocusChangeEventArgs>* GainFocusEvent() { - return &gain_focus_event_; - } - events::RoutedEvent<events::FocusChangeEventArgs>* LoseFocusEvent() { - return &lose_focus_event_; - } + CRU_DEFINE_ROUTED_EVENT(MouseLeave, events::MouseEventArgs) - private: - events::RoutedEvent<events::MouseEventArgs> mouse_enter_event_; - events::RoutedEvent<events::MouseEventArgs> mouse_leave_event_; - events::RoutedEvent<events::MouseEventArgs> mouse_move_event_; - events::RoutedEvent<events::MouseButtonEventArgs> mouse_down_event_; - events::RoutedEvent<events::MouseButtonEventArgs> mouse_up_event_; - events::RoutedEvent<events::MouseWheelEventArgs> mouse_wheel_event_; - - events::RoutedEvent<events::KeyEventArgs> key_down_event_; - events::RoutedEvent<events::KeyEventArgs> key_up_event_; - - events::RoutedEvent<events::FocusChangeEventArgs> gain_focus_event_; - events::RoutedEvent<events::FocusChangeEventArgs> lose_focus_event_; + CRU_DEFINE_ROUTED_EVENT(MouseMove, events::MouseEventArgs) + CRU_DEFINE_ROUTED_EVENT(MouseDown, events::MouseButtonEventArgs) + CRU_DEFINE_ROUTED_EVENT(MouseUp, events::MouseButtonEventArgs) + CRU_DEFINE_ROUTED_EVENT(MouseWheel, events::MouseWheelEventArgs) + CRU_DEFINE_ROUTED_EVENT(KeyDown, events::KeyEventArgs) + CRU_DEFINE_ROUTED_EVENT(KeyUp, events::KeyEventArgs) + CRU_DEFINE_ROUTED_EVENT(GainFocus, events::FocusChangeEventArgs) + CRU_DEFINE_ROUTED_EVENT(LoseFocus, events::FocusChangeEventArgs) //*************** region: tree *************** protected: virtual void OnParentChanged(Control* old_parent, Control* new_parent) {} - virtual void OnWindowHostChanged(host::WindowHost* old_host, - host::WindowHost* new_host) {} - - protected: - virtual void OnMouseHoverChange(bool newHover) { CRU_UNUSED(newHover) } - - void OnPrepareDelete() override; - - private: - void OnParentChangedCore(Control* old_parent, Control* new_parent); - void OnWindowHostChangedCore(host::WindowHost* old_host, - host::WindowHost* new_host); - private: - bool in_destruction_ = false; - Control* parent_ = nullptr; - host::WindowHost* window_host_ = nullptr; - - private: bool is_mouse_over_ = false; std::shared_ptr<platform::gui::ICursor> cursor_ = nullptr; diff --git a/include/cru/ui/controls/Popup.h b/include/cru/ui/controls/Popup.h deleted file mode 100644 index 7c57d257..00000000 --- a/include/cru/ui/controls/Popup.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include "RootControl.h" - -#include "cru/platform/gui/Base.h" - -#include <memory> - -namespace cru::ui::controls { -class CRU_UI_API Popup : public RootControl { - public: - static constexpr std::string_view kControlType = "Popup"; - - explicit Popup(Control* attached_control = nullptr); - - CRU_DELETE_COPY(Popup) - CRU_DELETE_MOVE(Popup) - - ~Popup() override; - - std::string GetControlType() const override { return std::string(kControlType); } -}; -} // namespace cru::ui::controls diff --git a/include/cru/ui/controls/RootControl.h b/include/cru/ui/controls/RootControl.h deleted file mode 100644 index e662b655..00000000 --- a/include/cru/ui/controls/RootControl.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#include "LayoutControl.h" - -#include "cru/base/Event.h" -#include "cru/platform/gui/Window.h" -#include "cru/ui/host/WindowHost.h" -#include "cru/ui/render/StackLayoutRenderObject.h" - -namespace cru::ui::controls { -class CRU_UI_API RootControl - : public LayoutControl<render::StackLayoutRenderObject> { - protected: - explicit RootControl(Control* attached_control); - - public: - CRU_DELETE_COPY(RootControl) - CRU_DELETE_MOVE(RootControl) - ~RootControl() override; - - public: - platform::gui::INativeWindow* GetNativeWindow(); - - protected: - void SetGainFocusOnCreateAndDestroyWhenLoseFocus(bool value); - - private: - std::unique_ptr<host::WindowHost> window_host_; - - Control* attached_control_; - - EventHandlerRevokerListGuard - gain_focus_on_create_and_destroy_when_lose_focus_event_guard_; -}; -} // namespace cru::ui::controls diff --git a/include/cru/ui/controls/TextHostControlService.h b/include/cru/ui/controls/TextHostControlService.h index 454be09b..40ba017a 100644 --- a/include/cru/ui/controls/TextHostControlService.h +++ b/include/cru/ui/controls/TextHostControlService.h @@ -201,6 +201,8 @@ class CRU_UI_API TextHostControlService : public Object { platform::gui::TimerAutoCanceler caret_timer_canceler_; int caret_blink_duration_ = k_default_caret_blink_duration; + platform::gui::TimerAutoCanceler scroll_to_caret_timer_canceler_; + helper::ShortcutHub shortcut_hub_; // true if left mouse is down and selecting diff --git a/include/cru/ui/controls/Window.h b/include/cru/ui/controls/Window.h index c4ba94d9..e25694ba 100644 --- a/include/cru/ui/controls/Window.h +++ b/include/cru/ui/controls/Window.h @@ -1,20 +1,188 @@ #pragma once -#include "cru/ui/controls/RootControl.h" +#include "../render/StackLayoutRenderObject.h" +#include "LayoutControl.h" -#include "cru/base/Base.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 Window final : public RootControl { +class CRU_UI_API Window + : public LayoutControl<render::StackLayoutRenderObject> { + CRU_DEFINE_CLASS_LOG_TAG("cru::ui::controls::Window") public: - static constexpr std::string_view control_type = "Window"; + static constexpr std::string_view kControlType = "Window"; - public: - explicit Window(Control* attached_control = nullptr); - CRU_DELETE_COPY(Window) - CRU_DELETE_MOVE(Window) + Window(); ~Window() override; - public: - std::string GetControlType() const final { return std::string(control_type); } + static Window* CreatePopup(); + + std::string GetControlType() const override; + + void SetAttachedControl(Control* control); + + 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(); + void UpdateCursor(); + + 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<Control*> receive_list; + + auto parent = original_sender; + while (parent != last_receiver) { + receive_list.push_back(parent); + parent = parent->GetParent(); + } + + auto handled = false; + + // tunnel + for (auto i = receive_list.crbegin(); i != receive_list.crend(); ++i) { + auto control = *i; + log += " "; + 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 control : receive_list) { + log += " "; + 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 control : receive_list) { + log += " "; + log += control->GetDebugId(); + EventArgs event_args(control, original_sender, + std::forward<Args>(args)...); + (control->*event_ptr)()->direct_.Raise(event_args); + } + } + + 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_; + + Control* attached_control_; + + EventHandlerRevokerListGuard + gain_focus_on_create_and_destroy_when_lose_focus_event_guard_; }; } // namespace cru::ui::controls diff --git a/include/cru/ui/events/RoutedEvent.h b/include/cru/ui/events/RoutedEvent.h index aa3331a6..58e50d63 100644 --- a/include/cru/ui/events/RoutedEvent.h +++ b/include/cru/ui/events/RoutedEvent.h @@ -8,6 +8,8 @@ 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; + public: static_assert(std::is_base_of_v<UiEventArgs, TEventArgs>, "TEventArgs must be subclass of UiEventArgs."); @@ -16,13 +18,29 @@ class CRU_UI_API RoutedEvent { using EventArgs = TEventArgs&; + explicit RoutedEvent(std::string name) : name_(std::move(name)) {} + + std::string GetName() const { return name_; } + IEvent<TEventArgs&>* Direct() { return &direct_; } IEvent<TEventArgs&>* Bubble() { return &bubble_; } IEvent<TEventArgs&>* Tunnel() { return &tunnel_; } private: + std::string name_; + Event<TEventArgs&> direct_; Event<TEventArgs&> bubble_; Event<TEventArgs&> tunnel_; }; -} // namespace cru::ui::event + +#define CRU_DEFINE_ROUTED_EVENT(name, arg_type) \ + private: \ + ::cru::ui::events::RoutedEvent<arg_type> name##Event_{#name}; \ + \ + public: \ + ::cru::ui::events::RoutedEvent<arg_type>* name##Event() { \ + return &name##Event_; \ + } + +} // namespace cru::ui::events diff --git a/include/cru/ui/host/LayoutPaintCycler.h b/include/cru/ui/host/LayoutPaintCycler.h deleted file mode 100644 index e4ff7aa8..00000000 --- a/include/cru/ui/host/LayoutPaintCycler.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once -#include "../Base.h" - -#include "cru/platform/gui/UiApplication.h" - -#include <chrono> - -namespace cru::ui::host { -class CRU_UI_API LayoutPaintCycler { - public: - explicit LayoutPaintCycler(WindowHost* host); - - CRU_DELETE_COPY(LayoutPaintCycler) - CRU_DELETE_MOVE(LayoutPaintCycler) - - ~LayoutPaintCycler(); - - public: - void InvalidateLayout(); - void InvalidatePaint(); - - bool IsLayoutDirty() { return layout_dirty_; } - - private: - void OnCycle(); - - private: - WindowHost* host_; - - platform::gui::TimerAutoCanceler timer_canceler_; - - bool layout_dirty_ = true; - bool paint_dirty_ = true; - - std::chrono::steady_clock::time_point last_cycle_time_; - std::chrono::steady_clock::duration cycle_threshold_ = - std::chrono::milliseconds(1000) / 144; -}; -} // namespace cru::ui::host diff --git a/include/cru/ui/host/WindowHost.h b/include/cru/ui/host/WindowHost.h deleted file mode 100644 index 13b06b07..00000000 --- a/include/cru/ui/host/WindowHost.h +++ /dev/null @@ -1,172 +0,0 @@ -#pragma once -#include "../Base.h" - -#include "../render/RenderObject.h" -#include "cru/base/Event.h" -#include "cru/platform/gui/Cursor.h" -#include "cru/platform/gui/UiApplication.h" -#include "cru/platform/gui/Window.h" - -#include <functional> -#include <memory> - -namespace cru::ui::host { -class LayoutPaintCycler; - -struct AfterLayoutEventArgs {}; - -// The bridge between control tree and native window. -class CRU_UI_API WindowHost : public Object { - friend controls::Control; - CRU_DEFINE_CLASS_LOG_TAG("WindowHost") - - private: - static int event_handling_depth_; - - public: - static bool IsInEventHandling() { return event_handling_depth_ > 0; } - static void EnterEventHandling(); - static void LeaveEventHandling(); - - public: - explicit WindowHost(controls::Control* root_control); - ~WindowHost() override; - - public: - platform::gui::INativeWindow* GetNativeWindow() { - return native_window_.get(); - } - - // 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(); - void RelayoutWithSize(const Size& available_size = Size::Infinite(), - bool set_window_size_to_fit_content = false); - - void Repaint(); - - // Is layout is invalid, wait for relayout and then run the action. Otherwist - // run it right now. - void RunAfterLayoutStable(std::function<void()> action); - - // 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. - controls::Control* GetMouseHoverControl() const { - return mouse_hover_control_; - } - - //*************** region: focus *************** - - controls::Control* GetFocusControl(); - - void SetFocusControl(controls::Control* control); - - //*************** 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(controls::Control* control); - - // Return null if not captured. - controls::Control* GetMouseCaptureControl(); - - controls::Control* HitTest(const Point& point); - - void UpdateCursor(); - - IEvent<platform::gui::INativeWindow*>* NativeWindowChangeEvent() { - return &native_window_change_event_; - } - - std::shared_ptr<platform::gui::ICursor> GetOverrideCursor(); - void SetOverrideCursor(std::shared_ptr<platform::gui::ICursor> cursor); - - private: - std::unique_ptr<platform::gui::INativeWindow> CreateNativeWindow(); - - //*************** region: native messages *************** - 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); - - //*************** region: event dispatcher helper *************** - - void DispatchMouseHoverControlChangeEvent(controls::Control* old_control, - controls::Control* new_control, - const Point& point, bool no_leave, - bool no_enter); - - void OnControlDetach(controls::Control* control); - - private: - controls::Control* root_control_ = nullptr; - render::RenderObject* root_render_object_ = nullptr; - - std::unique_ptr<platform::gui::INativeWindow> native_window_; - - std::unique_ptr<LayoutPaintCycler> layout_paint_cycler_; - - Event<AfterLayoutEventArgs> after_layout_event_; - std::vector<std::function<void()> > after_layout_stable_action_; - - std::vector<EventHandlerRevokerGuard> event_revoker_guards_; - - controls::Control* mouse_hover_control_ = nullptr; - - controls::Control* focus_control_; - - controls::Control* mouse_captured_control_ = nullptr; - - bool layout_prefer_to_fill_window_ = false; - - Event<platform::gui::INativeWindow*> native_window_change_event_; - - std::shared_ptr<platform::gui::ICursor> override_cursor_; -}; -} // namespace cru::ui::host diff --git a/include/cru/ui/render/RenderObject.h b/include/cru/ui/render/RenderObject.h index 34761b51..c299ea24 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: - host::WindowHost* GetWindowHost(); + controls::Window* GetWindow(); void InvalidateLayout(); void InvalidatePaint(); diff --git a/include/cru/ui/render/ScrollBar.h b/include/cru/ui/render/ScrollBar.h index 13c7d8b0..2325acd1 100644 --- a/include/cru/ui/render/ScrollBar.h +++ b/include/cru/ui/render/ScrollBar.h @@ -5,11 +5,9 @@ #include "cru/platform/graphics/Brush.h" #include "cru/platform/graphics/Geometry.h" #include "cru/platform/graphics/Painter.h" -#include "cru/platform/gui/Cursor.h" #include "cru/platform/gui/UiApplication.h" #include "cru/ui/Base.h" #include "cru/ui/controls/Control.h" -#include "cru/ui/helper/ClickDetector.h" #include <memory> #include <optional> @@ -38,8 +36,8 @@ enum class ScrollBarAreaKind { enum class ScrollBarBrushUsageKind { Arrow, ArrowBackground, Slot, Thumb }; enum class ScrollBarBrushStateKind { Normal, Hover, Press, Disable }; -std::string CRU_UI_API GenerateScrollBarThemeColorKey(ScrollBarBrushUsageKind usage, - ScrollBarBrushStateKind state); +std::string CRU_UI_API GenerateScrollBarThemeColorKey( + ScrollBarBrushUsageKind usage, ScrollBarBrushStateKind state); class CRU_UI_API ScrollBar : public Object { public: @@ -139,7 +137,7 @@ class CRU_UI_API ScrollBar : public Object { Event<Scroll> scroll_attempt_event_; - bool cursor_overrided_ = false; + bool cursor_overridden_ = false; platform::gui::TimerAutoCanceler auto_collapse_timer_canceler_; }; |
