diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml index 85b502544ec4..ced04bb17745 100644 --- a/doc/classes/Window.xml +++ b/doc/classes/Window.xml @@ -371,6 +371,12 @@ Causes the window to grab focus, allowing it to receive user input. + + + + Moves the window to the current mouse position. + + diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 76a7e3e3a55a..9aa7082c807f 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1854,8 +1854,8 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_ return nullptr; } - Control *drag_preview = _gui_get_drag_preview(); - if (!drag_preview || (c != drag_preview && !drag_preview->is_ancestor_of(c))) { + Window *drag_preview = _gui_get_drag_preview(); + if (!drag_preview || !drag_preview->is_ancestor_of(c)) { return c; } @@ -2029,7 +2029,7 @@ void Viewport::_gui_input_event(Ref p_event) { gui.dragging = true; break; } else { - Control *drag_preview = _gui_get_drag_preview(); + Window *drag_preview = _gui_get_drag_preview(); if (drag_preview) { ERR_PRINT("Don't set a drag preview and return null data. Preview was deleted and drag request ignored."); memdelete(drag_preview); @@ -2150,10 +2150,9 @@ void Viewport::_gui_input_event(Ref p_event) { if (gui.dragging) { // Handle drag & drop. This happens in the viewport where dragging started. - Control *drag_preview = _gui_get_drag_preview(); + Window *drag_preview = _gui_get_drag_preview(); if (drag_preview) { - Vector2 pos = drag_preview->get_canvas_transform().affine_inverse().xform(mpos); - drag_preview->set_position(pos); + drag_preview->move_to_mouse(); } gui.drag_mouse_over = section_root->gui.target_control; @@ -2390,7 +2389,7 @@ void Viewport::gui_perform_drop_at(const Point2 &p_pos, Control *p_control) { gui.drag_successful = false; } - Control *drag_preview = _gui_get_drag_preview(); + Window *drag_preview = _gui_get_drag_preview(); if (drag_preview) { memdelete(drag_preview); gui.drag_preview_id = ObjectID(); @@ -2460,23 +2459,34 @@ void Viewport::_gui_set_drag_preview(Control *p_base, Control *p_control) { ERR_FAIL_COND(p_control->is_inside_tree()); ERR_FAIL_COND(p_control->get_parent() != nullptr); - Control *drag_preview = _gui_get_drag_preview(); + Window *drag_preview = _gui_get_drag_preview(); if (drag_preview) { memdelete(drag_preview); } + + Window *window = memnew(Window); + + window->wrap_controls = true; + window->set_flag(Window::FLAG_BORDERLESS, true); + window->set_flag(Window::FLAG_ALWAYS_ON_TOP, true); + window->set_flag(Window::FLAG_MOUSE_PASSTHROUGH, true); + window->set_flag(Window::FLAG_NO_FOCUS, true); + window->set_flag(Window::FLAG_TRANSPARENT, true); + window->set_size(Size2i(0, 0)); + p_base->get_root_parent_control()->add_child(window); + p_control->set_as_top_level(true); - p_control->set_position(gui.last_mouse_pos); - p_base->get_root_parent_control()->add_child(p_control); // Add as child of viewport. p_control->move_to_front(); - - gui.drag_preview_id = p_control->get_instance_id(); + window->add_child(p_control); + window->visible = true; + gui.drag_preview_id = window->get_instance_id(); } -Control *Viewport::_gui_get_drag_preview() { +Window *Viewport::_gui_get_drag_preview() { if (gui.drag_preview_id.is_null()) { return nullptr; } else { - Control *drag_preview = ObjectDB::get_instance(gui.drag_preview_id); + Window *drag_preview = ObjectDB::get_instance(gui.drag_preview_id); if (!drag_preview) { ERR_PRINT("Don't free the control set as drag preview."); gui.drag_preview_id = ObjectID(); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 0ed3864b08ed..7a0d49fbe331 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -455,7 +455,7 @@ class Viewport : public Node { void _gui_force_drag_cancel(); void _gui_force_drag(Control *p_base, const Variant &p_data, Control *p_control); void _gui_set_drag_preview(Control *p_base, Control *p_control); - Control *_gui_get_drag_preview(); + Window *_gui_get_drag_preview(); void _gui_remove_focus_for_window(Node *p_window); void _gui_unfocus_control(Control *p_control); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 5d1694973cf7..7f2ac5e3609a 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -380,6 +380,20 @@ Point2i Window::get_position() const { return position; } +void Window::move_to_mouse() { + ERR_MAIN_THREAD_GUARD; + ERR_FAIL_COND(!is_inside_tree()); + + Point2i mouse_pos; + if (is_embedded() && !force_native) { + mouse_pos = get_embedder()->get_mouse_position(); + set_position(mouse_pos + Point2i(10, 10)); + } else { + mouse_pos = DisplayServer::get_singleton()->mouse_get_position(); + set_position(mouse_pos + Point2i(10, 10)); + } +} + void Window::move_to_center() { ERR_MAIN_THREAD_GUARD; ERR_FAIL_COND(!is_inside_tree()); @@ -3153,6 +3167,7 @@ void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("set_position", "position"), &Window::set_position); ClassDB::bind_method(D_METHOD("get_position"), &Window::get_position); ClassDB::bind_method(D_METHOD("move_to_center"), &Window::move_to_center); + ClassDB::bind_method(D_METHOD("move_to_mouse"), &Window::move_to_mouse); ClassDB::bind_method(D_METHOD("set_size", "size"), &Window::set_size); ClassDB::bind_method(D_METHOD("get_size"), &Window::get_size); diff --git a/scene/main/window.h b/scene/main/window.h index 64d99a4ff821..d414be7cb982 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -312,6 +312,7 @@ class Window : public Viewport { void set_position(const Point2i &p_position); Point2i get_position() const; void move_to_center(); + void move_to_mouse(); void set_size(const Size2i &p_size); Size2i get_size() const; diff --git a/tests/scene/test_text_edit.h b/tests/scene/test_text_edit.h index d40bdbbf4aa1..4a70a604212c 100644 --- a/tests/scene/test_text_edit.h +++ b/tests/scene/test_text_edit.h @@ -2402,7 +2402,8 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { CHECK(text_edit->get_caret_column() == 4); CHECK(text_edit->get_selection_origin_line() == 0); CHECK(text_edit->get_selection_origin_column() == 0); - SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 11).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE); + // Increased offset to ensure drag preview window moves before dropping, otherwise drop data would be consumed by drag preview window + SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 11).get_center() + Point2i(20, 20), MouseButtonMask::LEFT, Key::NONE); SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(text_edit->get_rect_at_line_column(1, 11).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE); CHECK_FALSE(text_edit->get_viewport()->gui_is_dragging()); CHECK(text_edit->get_text() == " test\ndrop here 'drag'");