godotengine / godotengine/godot-docs
Specify that holding Mouse Button down on a Control will prevent `mouse_exited` on itself and `mouse_entered` on others until release.
- Dominant language
- reStructuredText
- Stars
- 5.7k
- Forks
- 3.8k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 25
Description
Godot Engine v3.2.3.stable.official
Current Documentation:
--------
> mouse_entered ( )
>
> Emitted when the mouse enters the control's Rect area, provided its mouse_filter lets the event reach it.
API -> class Control -> Signals -> mouse_entered
> mouse_exited ( )
>
> Emitted when the mouse leaves the control's Rect area, provided its mouse_filter lets the event reach it.
API -> class Control -> Signals -> mouse_entered
Both found at :
https://docs.godotengine.org/en/stable/classes/class_control.html#signals
Issue Summary:
----------
It is not documented and not intuitive that the Control class's `mouse_entered` signal will not fire if mouse button is clicked over another Control, then (without releasing the mouse button) the mouse is moved within the bounds of the Control node which has the `mouse_entered` signal connected.
This happens because the `mouse_exited` signal is not triggered for the first Control (even if the mouse is outside the Control) until the mouse is released.
This blocking happens any time the first Control is clicked and it has a `mouse_filter` of "Stop" or "Pass", regardless of whether the first Control has signals or a script with `_gui_input(event)`.
All other controls will have `mouse_entered` and `mouse_exited` and mouse motion detected in `_gui_input(event)` blocked until the mouse is released, even if the mouse is within their Rect area.
Detailed Example for `mouse_entered` and `mouse_exited` signals:
----------
**Scene Tree Setup:**
- No overlapping node placement (also referred to as non-obstructed).
- All Mouse Filters set to `Pass`.
- Have at least two Control nodes which connect the `mouse_entered` signal to print to console.
- (Optionally also connect `mouse_exited` to print to console.)
**Expected Behavior, based on the Docs:**
When no mouse button is held, Control derived nodes which connect their `mouse_entered` signal work as expected, any time the mouse initially enters the bounds of their Rect area.
Clicking on a blank area of the screen, holding the mouse button down, then hovering over Controls will trigger each `mouse_entered` as expected. As does clicking and holding on a Sprite, then moving the mouse over the Control before releasing the mouse button.
**Unexpected Behavior, based on the Docs:**
The following happens with Left Mouse Button, Right Mouse Button, or Middle Mouse Button.
A Control derived node will not fire `mouse_entered` if
1. The Control node with `mouse_entered` is not obstructed
and has `mouse_filter` set to "Pass" (or "Stop").
2. The mouse is clicked on another Control,
3. the mouse button is held down,
4. then the mouse is moved within the bounds
of the node connected to `mouse_entered`.
Upon releasing the mouse, the `mouse_entered` signal immediately fires.
If the first Control has `mouse_exited` it will also emit at this point.
**Demonstration:**
Two Label nodes with `mouse_filter` set to "Pass".
Each has `mouse_entered` connected to itself, and prints to output.
For simplicity, `mouse_exited` is not connected in this demo.

_(Note:
The yellow circle represents when the mouse is held down.
It is not part of Godot -- it's an overlay feature of ScreenToGif.)_
**Suggestion:**
I'm assuming this is expected (and at times desired) behavior.
But this behavior seems to be undocumented & contradicts the documentation
for the `mouse_entered` signal:
> "Emitted when the mouse enters the control's Rect area"
Similarly, `mouse_exited` does not always emit
> "when the mouse leaves the control's Rect area".
I'd like to propose just a few details be added here to reflect this case.
Identical Behavior using `_gui_input(event)` instead of (or in addition to) signals
-------
This behavior (of clicking on one control, then all `mouse_entered` signals on all other control nodes being blocked until the mouse button is released) happens identically if some (or all) of the signals are replaced with `_gui_input(event)` functions waiting for InputEventMouseMotion over the control node.
The outcome is identical to the demo above.
```
func _gui_input(event):
if event is InputEventMouseMotion:
print("Hovered over control #2")
```
This behavior using `_gui_input(event)` is unexpected
given this currently listed information :
https://docs.godotengine.org/en/stable/classes/class_control.html#class-control-method-gui-input
API -> class Control -> Methods -> void _gui_input ( InputEvent event ) virtual
> func _gui_input(event):
> if event is InputEventMouseButton:
> if event.button_index == BUTTON_LEFT and event.pressed:
> print("I've been clicked D:")
>
> The event won't trigger if:
>
>* clicking outside the control (see has_point);
>
>* control has mouse_filter set to MOUSE_FILTER_IGNORE;
>
>* control is obstructed by another Control on top of it, which doesn't have mouse_filter set to MOUSE_FILTER_IGNORE;
>
>* control's parent has mouse_filter set to MOUSE_FILTER_STOP or has accepted the event;
>
>* it happens outside parent's rectangle and the parent has either rect_clip_content or _clips_input enabled.
The Control which is clicked does not need to have a `_gui_input(event)` in order for it to block the `InputEventMouseMotion` in another Control node's `_gui_input(event)`.
**Regarding "clicking outside the control":**
If anything other than a Control is clicked and held, a node listening for mouse motion in `_gui_input(event)` will fire, even when the click originated outside its Rect area. So the current description for `_gui_input(event)` is partially describing `InputEventMouseButton`'s bounds within `_gui_input()` (which is very useful), but not the specific bounds of when `_gui_input(event)` itself is triggered (or blocked by other gui elements).
**Suggestion:**
I'd like to propose adding a little detail here to clarify that when holding the mouse button down on one Control, other Controls with `_gui_input(event)` functions will be blocked. (I haven't read the code for this, so I'm unsure if it's more complicated or nuanced than this, but even a little more information will save users from discovering this rule through trial and error alone).
---------
This took a while to figure out all the different bounds and interactions of this behavior, so I hope this is useful.
I absolutely love these docs,
(+) I appreciate everyone who puts effort into Godot.
Thanks for your time.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.