summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorMarkus Sauermann <6299227+Sauermann@users.noreply.github.com>2023-01-20 00:21:11 +0100
committerMarkus Sauermann <6299227+Sauermann@users.noreply.github.com>2024-09-15 01:06:02 +0200
commit60aaa017ff3dc026d89cc8a0eb7817f2b7eac727 (patch)
tree2c595af228282e28e5c0c64be0c951486c7236ba /tests
parent6681f2563b99e14929a8acb27f4908fece398ef1 (diff)
downloadredot-engine-60aaa017ff3dc026d89cc8a0eb7817f2b7eac727.tar.gz
Enable Drag and Drop for SubViewports and Windows
Make Drag and Drop an application-wide operation. This allows do drop on Controls in other Viewports/Windows. In order to achieve this, `Viewport::_update_mouse_over` is adjusted to remember the Control, that the mouse is over (possibly within nested viewports). This Control is used as a basis for the Drop-operation, which replaces the previous algorithm, which was only aware of the topmost Viewport. Also now all nodes in the SceneTree are notified about the Drag and Drop operation, with the exception of SubViewports that are not children of SubViewportContainers.
Diffstat (limited to 'tests')
-rw-r--r--tests/scene/test_viewport.h144
1 files changed, 131 insertions, 13 deletions
diff --git a/tests/scene/test_viewport.h b/tests/scene/test_viewport.h
index 1341cc0332..9d02c41719 100644
--- a/tests/scene/test_viewport.h
+++ b/tests/scene/test_viewport.h
@@ -119,8 +119,23 @@ public:
class DragTarget : public NotificationControlViewport {
GDCLASS(DragTarget, NotificationControlViewport);
+protected:
+ void _notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_DRAG_BEGIN: {
+ during_drag = true;
+ } break;
+
+ case NOTIFICATION_DRAG_END: {
+ during_drag = false;
+ } break;
+ }
+ }
+
public:
Variant drag_data;
+ bool valid_drop = false;
+ bool during_drag = false;
virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const override {
StringName string_data = p_data;
// Verify drag data is compatible.
@@ -136,6 +151,7 @@ public:
virtual void drop_data(const Point2 &p_point, const Variant &p_data) override {
drag_data = p_data;
+ valid_drop = true;
}
};
@@ -1107,12 +1123,10 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
SUBCASE("[Viewport][GuiInputEvent] Drag and Drop") {
// FIXME: Drag-Preview will likely change. Tests for this part would have to be rewritten anyway.
// See https://github.com/godotengine/godot/pull/67531#issuecomment-1385353430 for details.
- // FIXME: Testing Drag and Drop with non-embedded windows would require DisplayServerMock additions
- // FIXME: Drag and Drop currently doesn't work with embedded Windows and SubViewports - not testing.
- // See https://github.com/godotengine/godot/issues/28522 for example.
+ // Note: Testing Drag and Drop with non-embedded windows would require DisplayServerMock additions.
int min_grab_movement = 11;
- SUBCASE("[Viewport][GuiInputEvent] Drag from one Control to another in the same viewport.") {
- SUBCASE("[Viewport][GuiInputEvent] Perform successful Drag and Drop on a different Control.") {
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Drag from one Control to another in the same viewport.") {
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Perform successful Drag and Drop on a different Control.") {
SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(root->gui_is_dragging());
@@ -1131,7 +1145,7 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
CHECK((StringName)node_d->drag_data == SNAME("Drag Data"));
}
- SUBCASE("[Viewport][GuiInputEvent] Perform unsuccessful drop on Control.") {
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Perform unsuccessful drop on Control.") {
SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(root->gui_is_dragging());
@@ -1157,7 +1171,7 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
CHECK_FALSE(root->gui_is_drag_successful());
}
- SUBCASE("[Viewport][GuiInputEvent] Perform unsuccessful drop on No-Control.") {
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Perform unsuccessful drop on No-Control.") {
SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(root->gui_is_dragging());
@@ -1171,7 +1185,7 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
// Move away from Controls.
SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::LEFT, Key::NONE);
- CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_ARROW); // This could also be CURSOR_FORBIDDEN.
+ CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_ARROW);
CHECK(root->gui_is_dragging());
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_background, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
@@ -1179,7 +1193,7 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
CHECK_FALSE(root->gui_is_drag_successful());
}
- SUBCASE("[Viewport][GuiInputEvent] Perform unsuccessful drop outside of window.") {
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Perform unsuccessful drop outside of window.") {
SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(root->gui_is_dragging());
@@ -1192,7 +1206,6 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
// Move outside of window.
SEND_GUI_MOUSE_MOTION_EVENT(on_outside, MouseButtonMask::LEFT, Key::NONE);
- CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_ARROW);
CHECK(root->gui_is_dragging());
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_outside, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
@@ -1200,7 +1213,7 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
CHECK_FALSE(root->gui_is_drag_successful());
}
- SUBCASE("[Viewport][GuiInputEvent] Drag and Drop doesn't work with other Mouse Buttons than LMB.") {
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Drag and Drop doesn't work with other Mouse Buttons than LMB.") {
SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::MIDDLE, MouseButtonMask::MIDDLE, Key::NONE);
CHECK_FALSE(root->gui_is_dragging());
@@ -1209,7 +1222,7 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_a, MouseButton::MIDDLE, MouseButtonMask::NONE, Key::NONE);
}
- SUBCASE("[Viewport][GuiInputEvent] Drag and Drop parent propagation.") {
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Drag and Drop parent propagation.") {
Node2D *node_aa = memnew(Node2D);
Control *node_aaa = memnew(Control);
Node2D *node_dd = memnew(Node2D);
@@ -1318,7 +1331,7 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
memdelete(node_aa);
}
- SUBCASE("[Viewport][GuiInputEvent] Force Drag and Drop.") {
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Force Drag and Drop.") {
SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
CHECK_FALSE(root->gui_is_dragging());
node_a->force_drag(SNAME("Drag Data"), nullptr);
@@ -1339,6 +1352,111 @@ TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_d, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
}
}
+
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Drag to a different Viewport.") {
+ SubViewportContainer *svc = memnew(SubViewportContainer);
+ svc->set_size(Size2(100, 100));
+ svc->set_position(Point2(200, 50));
+ root->add_child(svc);
+
+ SubViewport *sv = memnew(SubViewport);
+ sv->set_embedding_subwindows(true);
+ sv->set_size(Size2i(100, 100));
+ svc->add_child(sv);
+
+ DragStart *sv_a = memnew(DragStart);
+ sv_a->set_position(Point2(10, 10));
+ sv_a->set_size(Size2(10, 10));
+ sv->add_child(sv_a);
+ Point2i on_sva = Point2i(215, 65);
+
+ DragTarget *sv_b = memnew(DragTarget);
+ sv_b->set_position(Point2(30, 30));
+ sv_b->set_size(Size2(20, 20));
+ sv->add_child(sv_b);
+ Point2i on_svb = Point2i(235, 85);
+
+ Window *ew = memnew(Window);
+ ew->set_position(Point2(50, 200));
+ ew->set_size(Size2(100, 100));
+ root->add_child(ew);
+
+ DragStart *ew_a = memnew(DragStart);
+ ew_a->set_position(Point2(10, 10));
+ ew_a->set_size(Size2(10, 10));
+ ew->add_child(ew_a);
+ Point2i on_ewa = Point2i(65, 215);
+
+ DragTarget *ew_b = memnew(DragTarget);
+ ew_b->set_position(Point2(30, 30));
+ ew_b->set_size(Size2(20, 20));
+ ew->add_child(ew_b);
+ Point2i on_ewb = Point2i(85, 235);
+
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Drag to SubViewport") {
+ sv_b->valid_drop = false;
+ SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_MOTION_EVENT(on_a + Point2i(min_grab_movement, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(root->gui_is_dragging());
+ CHECK(sv_b->during_drag);
+ SEND_GUI_MOUSE_MOTION_EVENT(on_svb, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_CAN_DROP);
+
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_svb, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ CHECK(sv_b->valid_drop);
+ CHECK(!sv_b->during_drag);
+ }
+
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Drag from SubViewport") {
+ node_d->valid_drop = false;
+ SEND_GUI_MOUSE_BUTTON_EVENT(on_sva, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_MOTION_EVENT(on_sva + Point2i(min_grab_movement, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(sv->gui_is_dragging());
+ CHECK(node_d->during_drag);
+ SEND_GUI_MOUSE_MOTION_EVENT(on_d, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_CAN_DROP);
+
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_d, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ CHECK(node_d->valid_drop);
+ CHECK(!node_d->during_drag);
+ }
+
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Drag to embedded Window") {
+ ew_b->valid_drop = false;
+ SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_MOTION_EVENT(on_a + Point2i(min_grab_movement, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(root->gui_is_dragging());
+ CHECK(ew_b->during_drag);
+ SEND_GUI_MOUSE_MOTION_EVENT(on_ewb, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_CAN_DROP);
+
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_ewb, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ CHECK(ew_b->valid_drop);
+ CHECK(!ew_b->during_drag);
+ }
+
+ SUBCASE("[Viewport][GuiInputEvent][DnD] Drag from embedded Window") {
+ node_d->valid_drop = false;
+ SEND_GUI_MOUSE_BUTTON_EVENT(on_ewa, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_MOTION_EVENT(on_ewa + Point2i(min_grab_movement, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(ew->gui_is_dragging());
+ CHECK(node_d->during_drag);
+ SEND_GUI_MOUSE_MOTION_EVENT(on_d, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_CAN_DROP);
+
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_d, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ CHECK(node_d->valid_drop);
+ CHECK(!node_d->during_drag);
+ }
+
+ memdelete(ew_a);
+ memdelete(ew_b);
+ memdelete(ew);
+ memdelete(sv_a);
+ memdelete(sv_b);
+ memdelete(sv);
+ memdelete(svc);
+ }
}
memdelete(node_j);