Răsfoiți Sursa

Merge pull request #66625 from Sauermann/fix-move-child-update

Create a virtual mouse move event after moving child nodes in tree
Yuri Sizov 2 ani în urmă
părinte
comite
6dd5ccdedd

+ 6 - 0
doc/classes/Viewport.xml

@@ -212,6 +212,12 @@
 				Sets the number of subdivisions to use in the specified quadrant. A higher number of subdivisions allows you to have more shadows in the scene at once, but reduces the quality of the shadows. A good practice is to have quadrants with a varying number of subdivisions and to have as few subdivisions as possible.
 			</description>
 		</method>
+		<method name="update_mouse_cursor_state">
+			<return type="void" />
+			<description>
+				Force instantly updating the display based on the current mouse cursor position. This includes updating the mouse cursor shape and sending necessary [signal Control.mouse_entered], [signal CollisionObject2D.mouse_entered], [signal CollisionObject3D.mouse_entered] and [signal Window.mouse_entered] signals and their respective [code]mouse_exited[/code] counterparts.
+			</description>
+		</method>
 		<method name="warp_mouse">
 			<return type="void" />
 			<param index="0" name="position" type="Vector2" />

+ 2 - 1
scene/gui/control.cpp

@@ -2400,7 +2400,8 @@ void Control::set_default_cursor_shape(CursorShape p_shape) {
 		return;
 	}
 
-	get_viewport()->get_base_window()->update_mouse_cursor_shape();
+	// Display the new cursor shape instantly.
+	get_viewport()->update_mouse_cursor_state();
 }
 
 Control::CursorShape Control::get_default_cursor_shape() const {

+ 8 - 0
scene/main/node.cpp

@@ -216,6 +216,14 @@ void Node::_notification(int p_notification) {
 				memdelete(child);
 			}
 		} break;
+
+		case NOTIFICATION_CHILD_ORDER_CHANGED: {
+			// The order, in which canvas items are drawn gets rearranged.
+			// This makes it necessary to update mouse cursor and send according mouse_enter/mouse_exit signals for Control nodes.
+			if (get_viewport()) {
+				get_viewport()->update_mouse_cursor_state();
+			}
+		} break;
 	}
 }
 

+ 2 - 1
scene/main/scene_tree.cpp

@@ -1395,7 +1395,8 @@ void SceneTree::_change_scene(Node *p_to) {
 	if (p_to) {
 		current_scene = p_to;
 		root->add_child(p_to);
-		root->update_mouse_cursor_shape();
+		// Update display for cursor instantly.
+		root->update_mouse_cursor_state();
 	}
 }
 

+ 11 - 1
scene/main/viewport.cpp

@@ -2299,7 +2299,8 @@ void Viewport::_perform_drop(Control *p_control, Point2 p_pos) {
 	gui.dragging = false;
 	gui.drag_mouse_over = nullptr;
 	_propagate_viewport_notification(this, NOTIFICATION_DRAG_END);
-	get_base_window()->update_mouse_cursor_shape();
+	// Display the new cursor shape instantly.
+	update_mouse_cursor_state();
 }
 
 void Viewport::_gui_cleanup_internal_state(Ref<InputEvent> p_event) {
@@ -3541,6 +3542,14 @@ Transform2D Viewport::get_screen_transform_internal(bool p_absolute_position) co
 	return get_final_transform();
 }
 
+void Viewport::update_mouse_cursor_state() {
+	// Updates need to happen in Window, because SubViewportContainers might be hidden behind other Controls.
+	Window *base_window = get_base_window();
+	if (base_window) {
+		base_window->update_mouse_cursor_state();
+	}
+}
+
 void Viewport::set_canvas_cull_mask(uint32_t p_canvas_cull_mask) {
 	ERR_MAIN_THREAD_GUARD;
 	canvas_cull_mask = p_canvas_cull_mask;
@@ -4143,6 +4152,7 @@ void Viewport::_bind_methods() {
 
 	ClassDB::bind_method(D_METHOD("get_mouse_position"), &Viewport::get_mouse_position);
 	ClassDB::bind_method(D_METHOD("warp_mouse", "position"), &Viewport::warp_mouse);
+	ClassDB::bind_method(D_METHOD("update_mouse_cursor_state"), &Viewport::update_mouse_cursor_state);
 
 	ClassDB::bind_method(D_METHOD("gui_get_drag_data"), &Viewport::gui_get_drag_data);
 	ClassDB::bind_method(D_METHOD("gui_is_dragging"), &Viewport::gui_is_dragging);

+ 1 - 0
scene/main/viewport.h

@@ -582,6 +582,7 @@ public:
 
 	Vector2 get_mouse_position() const;
 	void warp_mouse(const Vector2 &p_position);
+	virtual void update_mouse_cursor_state();
 
 	void set_physics_object_picking(bool p_enable);
 	bool get_physics_object_picking();

+ 6 - 3
scene/main/window.cpp

@@ -719,10 +719,13 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) {
 	}
 }
 
-void Window::update_mouse_cursor_shape() {
+void Window::update_mouse_cursor_state() {
 	ERR_MAIN_THREAD_GUARD;
-	// The default shape is set in Viewport::_gui_input_event. To instantly
-	// see the shape in the viewport we need to trigger a mouse motion event.
+	// Update states based on mouse cursor position.
+	// This includes updated mouse_enter or mouse_exit signals or the current mouse cursor shape.
+	// These details are set in Viewport::_gui_input_event. To instantly
+	// see the changes in the viewport, we need to trigger a mouse motion event.
+	// This function should be called whenever scene tree changes affect the mouse cursor.
 	Ref<InputEventMouseMotion> mm;
 	Vector2 pos = get_mouse_position();
 	Transform2D xform = get_global_canvas_transform().affine_inverse();

+ 1 - 1
scene/main/window.h

@@ -261,7 +261,7 @@ public:
 	void set_visible(bool p_visible);
 	bool is_visible() const;
 
-	void update_mouse_cursor_shape();
+	void update_mouse_cursor_state() override;
 
 	void show();
 	void hide();