Refactor mouse_entered and mouse_exited notifications

The previous implementation for signals mouse_entered and mouse_exited
had shortcomings that relate to focused windows and pressed mouse buttons.
For example a Control can be hovered by mouse, even if it is occluded by
an embedded window.

This patch changes the behavior, so that Control and Viewport send
their mouse-enter/exit-notifications based solely on mouse position,
visible area, and input restrictions and not on which window has
focus or which mouse buttons are pressed. This implicitly also
changes when the mouse_entered and mouse_exited signals are sent.

This functionality can not be implemented as a part of
Viewport::_gui_input_event, because of its interplay with Windows and
because Viewport::_gui_input_event is based on input and not on
visibility.
This commit is contained in:
Markus Sauermann
2023-01-06 21:48:20 +01:00
parent da81ca62a5
commit 1c3c17c608
8 changed files with 213 additions and 56 deletions

View File

@@ -1094,15 +1094,15 @@
</signal>
<signal name="mouse_entered">
<description>
Emitted when the mouse enters the control's [code]Rect[/code] area, provided its [member mouse_filter] lets the event reach it.
[b]Note:[/b] [signal mouse_entered] will not be emitted if the mouse enters a child [Control] node before entering the parent's [code]Rect[/code] area, at least until the mouse is moved to reach the parent's [code]Rect[/code] area.
Emitted when the mouse cursor enters the control's visible area, that is not occluded behind other Controls or Windows, provided its [member mouse_filter] lets the event reach it and regardless if it's currently focused or not.
[b]Note:[/b] [member CanvasItem.z_index] doesn't affect, which Control receives the signal.
</description>
</signal>
<signal name="mouse_exited">
<description>
Emitted when the mouse leaves the control's [code]Rect[/code] area, provided its [member mouse_filter] lets the event reach it.
[b]Note:[/b] [signal mouse_exited] will be emitted if the mouse enters a child [Control] node, even if the mouse cursor is still inside the parent's [code]Rect[/code] area.
If you want to check whether the mouse truly left the area, ignoring any top nodes, you can use code like this:
Emitted when the mouse cursor leaves the control's visible area, that is not occluded behind other Controls or Windows, provided its [member mouse_filter] lets the event reach it and regardless if it's currently focused or not.
[b]Note:[/b] [member CanvasItem.z_index] doesn't affect, which Control receives the signal.
[b]Note:[/b] If you want to check whether the mouse truly left the area, ignoring any top nodes, you can use code like this:
[codeblock]
func _on_mouse_exited():
if not Rect2(Vector2(), size).has_point(get_local_mouse_position()):
@@ -1140,10 +1140,12 @@
Sent when the node changes size. Use [member size] to get the new size.
</constant>
<constant name="NOTIFICATION_MOUSE_ENTER" value="41">
Sent when the mouse pointer enters the node.
Sent when the mouse cursor enters the control's visible area, that is not occluded behind other Controls or Windows, provided its [member mouse_filter] lets the event reach it and regardless if it's currently focused or not.
[b]Note:[/b] [member CanvasItem.z_index] doesn't affect, which Control receives the notification.
</constant>
<constant name="NOTIFICATION_MOUSE_EXIT" value="42">
Sent when the mouse pointer exits the node.
Sent when the mouse cursor leaves the control's visible area, that is not occluded behind other Controls or Windows, provided its [member mouse_filter] lets the event reach it and regardless if it's currently focused or not.
[b]Note:[/b] [member CanvasItem.z_index] doesn't affect, which Control receives the notification.
</constant>
<constant name="NOTIFICATION_FOCUS_ENTER" value="43">
Sent when the node grabs focus.