diff options
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/control.cpp | 37 | ||||
-rw-r--r-- | src/ui/controls/button.cpp | 14 | ||||
-rw-r--r-- | src/ui/window.cpp | 121 |
3 files changed, 97 insertions, 75 deletions
diff --git a/src/ui/control.cpp b/src/ui/control.cpp index 7bd33d84..50628883 100644 --- a/src/ui/control.cpp +++ b/src/ui/control.cpp @@ -1,14 +1,22 @@ #include "cru/ui/control.hpp" #include "cru/platform/native/basic_types.hpp" +#include "cru/platform/native/cursor.hpp" +#include "cru/platform/native/native_window.hpp" +#include "cru/platform/native/ui_applicaition.hpp" #include "cru/ui/base.hpp" #include "cru/ui/event/ui_event.hpp" #include "cru/ui/window.hpp" #include "routed_event_dispatch.hpp" #include <cassert> +#include <memory> namespace cru::ui { +using platform::native::Cursor; +using platform::native::SystemCursor; +using platform::native::UiApplication; + Control::Control() { MouseEnterEvent()->Direct()->AddHandler( [this](event::MouseEventArgs&) { this->is_mouse_over_ = true; }); @@ -69,18 +77,35 @@ bool Control::HasFocus() { return window->GetFocusControl() == this; } -bool Control::CaptureMouse() { - return GetWindow()->CaptureMouseFor(this); -} +bool Control::CaptureMouse() { return GetWindow()->CaptureMouseFor(this); } -bool Control::ReleaseMouse() { - return GetWindow()->CaptureMouseFor(nullptr); -} +bool Control::ReleaseMouse() { return GetWindow()->CaptureMouseFor(nullptr); } bool Control::IsMouseCaptured() { return GetWindow()->GetMouseCaptureControl() == this; } +std::shared_ptr<Cursor> Control::GetCursor() { return cursor_; } + +std::shared_ptr<Cursor> Control::GetInheritedCursor() { + Control* control = this; + while (control != nullptr) { + const auto cursor = control->GetCursor(); + if (cursor != nullptr) return cursor; + control = control->GetParent(); + } + return UiApplication::GetInstance()->GetCursorManager()->GetSystemCursor( + SystemCursor::Arrow); +} + +void Control::SetCursor(std::shared_ptr<Cursor> cursor) { + cursor_ = std::move(cursor); + const auto window = GetWindow(); + if (window != nullptr) { + window->UpdateCursor(); + } +} + void Control::OnParentChanged(Control* old_parent, Control* new_parent) {} void Control::OnAttachToWindow(Window* window) {} diff --git a/src/ui/controls/button.cpp b/src/ui/controls/button.cpp index 42a08e33..38ce75a8 100644 --- a/src/ui/controls/button.cpp +++ b/src/ui/controls/button.cpp @@ -3,12 +3,17 @@ #include "cru/platform/graph/brush.hpp" #include "cru/platform/graph/graph_factory.hpp" +#include "cru/platform/native/cursor.hpp" #include "cru/platform/native/native_window.hpp" +#include "cru/platform/native/ui_applicaition.hpp" #include "cru/ui/render/border_render_object.hpp" #include "cru/ui/ui_manager.hpp" #include "cru/ui/window.hpp" namespace cru::ui::controls { +using platform::native::SystemCursor; +using platform::native::UiApplication; + Button::Button() : click_detector_(this) { // const auto predefined_resource = // UiManager::GetInstance()->GetPredefineResources(); @@ -39,10 +44,15 @@ Button::Button() : click_detector_(this) { } else { SetState(ButtonState::Hover); } + SetCursor(UiApplication::GetInstance()->GetCursorManager()->GetSystemCursor( + SystemCursor::Hand)); }); - MouseLeaveEvent()->Direct()->AddHandler( - [this](event::MouseEventArgs& args) { SetState(ButtonState::Normal); }); + MouseLeaveEvent()->Direct()->AddHandler([this](event::MouseEventArgs& args) { + SetState(ButtonState::Normal); + SetCursor(UiApplication::GetInstance()->GetCursorManager()->GetSystemCursor( + SystemCursor::Arrow)); + }); click_detector_.ClickBeginEvent()->AddHandler([this](MouseButton button) { if (button & trigger_button_) { diff --git a/src/ui/window.cpp b/src/ui/window.cpp index 1ec34c1d..b599e479 100644 --- a/src/ui/window.cpp +++ b/src/ui/window.cpp @@ -11,6 +11,14 @@ namespace cru::ui { namespace { +bool IsAncestor(Control* control, Control* ancestor) { + while (control != nullptr) { + if (control == ancestor) return true; + control = control->GetParent(); + } + return false; +} + std::list<Control*> GetAncestorList(Control* control) { std::list<Control*> l; while (control != nullptr) { @@ -20,20 +28,7 @@ std::list<Control*> GetAncestorList(Control* control) { return l; } -constexpr int in_neither = 0; -constexpr int in_left = 1; -constexpr int in_right = 2; - -// if find_control is not nullptr, then find_result will be set as where the -// find_control is located. in_neither means mouse hover state of it is not -// changed. in_left means mouse move out it. in_right means mouse move in it. -// This is useful for mouse capture. -Control* FindLowestCommonAncestor(Control* left, Control* right, - Control* find_control, int* find_result) { - if (find_control) { - *find_result = in_neither; - } - +Control* FindLowestCommonAncestor(Control* left, Control* right) { if (left == nullptr || right == nullptr) return nullptr; auto&& left_list = GetAncestorList(left); @@ -49,45 +44,13 @@ Control* FindLowestCommonAncestor(Control* left, Control* right, while (true) { if (left_i == left_list.cend()) { - Control* result = *(--left_i); - while (right_i != right_list.cend()) { - if (*right_i == find_control) { - *find_result = in_right; - return result; - } - ++right_i; - } - return result; + return *(--left_i); } if (right_i == right_list.cend()) { - Control* result = *(--right_i); - while (left_i != left_list.cend()) { - if (*left_i == find_control) { - *find_result = in_left; - return result; - } - ++left_i; - } - return result; + return *(--right_i); } if (*left_i != *right_i) { - Control* result = *(--left_i); - ++left_i; - while (right_i != right_list.cend()) { - if (*right_i == find_control) { - *find_result = in_right; - return result; - } - ++right_i; - } - while (left_i != left_list.cend()) { - if (*left_i == find_control) { - *find_result = in_left; - return result; - } - ++left_i; - } - return result; + return *(--left_i); } ++left_i; ++right_i; @@ -185,19 +148,28 @@ bool Window::RequestFocusFor(Control* control) { Control* Window::GetFocusControl() { return focus_control_; } bool Window::CaptureMouseFor(Control* control) { + if (control == mouse_captured_control_) return true; + if (control == nullptr) { - if (mouse_captured_control_) { - mouse_captured_control_ = nullptr; - OnNativeMouseMove(GetNativeWindow()->GetMousePosition()); + const auto old_capture_control = mouse_captured_control_; + mouse_captured_control_ = + nullptr; // update this in case this is used in event handlers + if (old_capture_control != mouse_hover_control_) { + DispatchMouseHoverControlChangeEvent( + old_capture_control, mouse_hover_control_, + GetNativeWindow()->GetMousePosition(), true, false); } + UpdateCursor(); return true; } if (mouse_captured_control_) return false; + mouse_captured_control_ = control; - const auto c = - FindLowestCommonAncestor(control, mouse_hover_control_, nullptr, nullptr); - DispatchEvent(mouse_hover_control_, &Control::MouseLeaveEvent, c); + DispatchMouseHoverControlChangeEvent( + mouse_hover_control_, mouse_captured_control_, + GetNativeWindow()->GetMousePosition(), false, true); + UpdateCursor(); return true; } @@ -244,10 +216,22 @@ void Window::OnNativeMouseMove(const Point& point) { const auto old_control_mouse_hover = mouse_hover_control_; mouse_hover_control_ = new_control_mouse_hover; - DispatchMouseHoverControlChangeEvent(old_control_mouse_hover, - new_control_mouse_hover, point); + if (mouse_captured_control_) { + DispatchMouseHoverControlChangeEvent( + mouse_captured_control_, new_control_mouse_hover, point, false, true); + DispatchMouseHoverControlChangeEvent( + old_control_mouse_hover, mouse_captured_control_, point, true, false); + DispatchEvent(mouse_captured_control_, &Control::MouseMoveEvent, nullptr, + point); + UpdateCursor(); + return; + } + + DispatchMouseHoverControlChangeEvent( + old_control_mouse_hover, new_control_mouse_hover, point, false, false); DispatchEvent(new_control_mouse_hover, &Control::MouseMoveEvent, nullptr, point); + UpdateCursor(); } void Window::OnNativeMouseDown( @@ -276,24 +260,27 @@ void Window::OnNativeKeyUp(int virtual_code) { void Window::DispatchMouseHoverControlChangeEvent(Control* old_control, Control* new_control, - const Point& point) { + const Point& point, + bool no_leave, + bool no_enter) { if (new_control != old_control) // if the mouse-hover-on control changed { - int find_result; - const auto lowest_common_ancestor = FindLowestCommonAncestor( - old_control, new_control, mouse_captured_control_, &find_result); - if (old_control != nullptr && // if last mouse-hover-on control exists - (mouse_captured_control_ == nullptr || // and if mouse is not captured - find_result == in_left)) // or mouse is captured andc mouse is move - // out of capturing control + const auto lowest_common_ancestor = + FindLowestCommonAncestor(old_control, new_control); + if (!no_leave && old_control != nullptr) DispatchEvent(old_control, &Control::MouseLeaveEvent, lowest_common_ancestor); // dispatch mouse leave event. - if (new_control != nullptr && - (mouse_captured_control_ == nullptr || find_result == in_right)) { + if (!no_enter && new_control != nullptr) { DispatchEvent(new_control, &Control::MouseEnterEvent, lowest_common_ancestor, point); // dispatch mouse enter event. } } } + +void Window::UpdateCursor() { + const auto capture = GetMouseCaptureControl(); + GetNativeWindow()->SetCursor( + (capture ? capture : GetMouseHoverControl())->GetInheritedCursor()); +} } // namespace cru::ui |