aboutsummaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/control.cpp37
-rw-r--r--src/ui/controls/button.cpp14
-rw-r--r--src/ui/window.cpp121
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