#pragma once #include "Base.hpp" #include "cru/common/Event.hpp" #include "render/Base.hpp" #include "UiEvent.hpp" #include namespace cru::ui { class Control : public Object { friend UiHost; protected: Control(); public: Control(const Control& other) = delete; Control(Control&& other) = delete; Control& operator=(const Control& other) = delete; Control& operator=(Control&& other) = delete; ~Control() override = default; public: virtual std::string_view GetControlType() const = 0; //*************** region: tree *************** public: // Get the ui host if attached, otherwise, return nullptr. UiHost* GetUiHost() const { return ui_host_; } Control* GetParent() const { return parent_; } virtual const std::vector& GetChildren() const = 0; // Traverse the tree rooted the control including itself. void TraverseDescendants(const std::function& predicate); void _SetParent(Control* parent); void _SetDescendantUiHost(UiHost* host); private: static void _TraverseDescendants( Control* control, const std::function& predicate); public: virtual render::RenderObject* GetRenderObject() const = 0; //*************** region: focus *************** public: bool RequestFocus(); bool HasFocus(); //*************** region: mouse *************** public: bool IsMouseOver() const { return is_mouse_over_; } bool CaptureMouse(); bool ReleaseMouse(); bool IsMouseCaptured(); //*************** region: cursor *************** // Cursor is inherited from parent recursively if not set. public: // null for not set std::shared_ptr GetCursor(); // will not return nullptr std::shared_ptr GetInheritedCursor(); // null to unset void SetCursor(std::shared_ptr cursor); //*************** region: events *************** public: // Raised when mouse enter 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 enter event. You // can use `IsMouseCaptured` to get more info. event::RoutedEvent* MouseEnterEvent() { return &mouse_enter_event_; } // 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. event::RoutedEvent* MouseLeaveEvent() { return &mouse_leave_event_; } // Raised when mouse is move in the control. event::RoutedEvent* MouseMoveEvent() { return &mouse_move_event_; } // Raised when a mouse button is pressed in the control. event::RoutedEvent* MouseDownEvent() { return &mouse_down_event_; } // Raised when a mouse button is released in the control. event::RoutedEvent* MouseUpEvent() { return &mouse_up_event_; } event::RoutedEvent* MouseWheelEvent() { return &mouse_wheel_event_; } event::RoutedEvent* KeyDownEvent() { return &key_down_event_; } event::RoutedEvent* KeyUpEvent() { return &key_up_event_; } event::RoutedEvent* GainFocusEvent() { return &gain_focus_event_; } event::RoutedEvent* LoseFocusEvent() { return &lose_focus_event_; } private: event::RoutedEvent mouse_enter_event_; event::RoutedEvent mouse_leave_event_; event::RoutedEvent mouse_move_event_; event::RoutedEvent mouse_down_event_; event::RoutedEvent mouse_up_event_; event::RoutedEvent mouse_wheel_event_; event::RoutedEvent key_down_event_; event::RoutedEvent key_up_event_; event::RoutedEvent gain_focus_event_; event::RoutedEvent lose_focus_event_; //*************** region: tree *************** protected: virtual void OnParentChanged(Control* old_parent, Control* new_parent); virtual void OnAttachToHost(UiHost* host); virtual void OnDetachFromHost(UiHost* host); virtual void OnMouseHoverChange(bool newHover) { CRU_UNUSED(newHover) } private: UiHost* ui_host_ = nullptr; Control* parent_ = nullptr; private: bool is_mouse_over_ = false; std::shared_ptr cursor_ = nullptr; }; } // namespace cru::ui