godot: Control node "Pass" mousefilter is not passing input
Godot version
3.4.1 rc1
System information
Win64 Nvidea 765M
Issue description
Control node “Pass” mouse filter behaves like “Stop”.
The white Control has mouse_enter
, mouse_exit
and input_event
signals connected. When the mouse hovers over it, it should turn green:
extends ColorRect
func _on_Control_mouse_entered():
color = Color.green
func _on_Control_mouse_exited():
color = Color.white
func _on_Control_gui_input(event):
print(event)
However if there is a Control node above with a “Pass” mouse filter, it will stop the input, instead of passing it through.
Possibly related: https://github.com/godotengine/godot/issues/55430 https://github.com/godotengine/godot/issues/54529
Steps to reproduce
- Add a Control Node and connect input mouse input signals such as mouse_enter, mouse_exit, input_event to a script.
- In the script print something or change color when event occurs.
- Add another Control node, overlapping the first and set it’s mouse filter to “Pass”
- Observe the top Control consuming the input and not passing it on despite being set to “Pass”.
Minimal reproduction project
About this issue
- Original URL
- State: open
- Created 3 years ago
- Reactions: 3
- Comments: 20 (11 by maintainers)
Why would this be expected?
The purpose of the “Pass” mouse filter compared to “Stop” is to handle the input and pass it on. That’s it’s only purpose.
Why would it be expected behaviour to have “Pass” behave like “Stop” in any circumstance? That would not make any sense whatsoever. We already have “Stop” for the stop behaviour!
I’m trying to help out another user on Reddit having the same issue as me in the previous menu example. Here I break it down to it’s essence:
A VboxContainer node with two Button nodes as children. When the mouse cursor exits the VboxContainer rect, the Vbox and it’s children should be hidden. Of course the Button
mouse_filter
default “stop”, stops the mouse event from propagating to the Vbox, so the mouse_exited signal fires. As a result the Vbox is hidden as soon as the user “touches” one of the Buttons.On first glance the solution seems obvious and simple: just set both Button
mouse_filters
to “pass”, right?Well this does not work at all, has the exact same effect as “stop”.
Other configurations I tried which also don’t work:
main2 This is how I previously thought I fixed it:
main3 Here the first button is totally ignored; as soon as the user touches the second button, again, the mouse_exit signal is fired:
main4 This just breaks everything, top Button hover is triggered when just entering parent control node rect. All Nodes here have mouse filter set to pass:
Minimal Project containing these variations:
Godot 3.X: mouse_filter_pass_issue_vbox_and_buttons.zip
Godot 4.0 Alpha11: mouse_filer_pass_issue.zip
I have also spend a few hours today testing any other configuration I could think of. Countless variations, any other property which could only remotely have an influence I tested and run individually. To no avail.
This is especially infuriating to me as I have already solved this, or at least I thought. But whatever I try I can’t replicate that solution anymore.
I can only repeat: mouse filter “pass” feels absolutely broken to me. This is not some obscure usecase either. I think this desperately needs a propper fix.
Control nodes mouse filtering continuously costs me days if not weeks of productive work time. I’ve been working around this as much as I can, but I still get stuck for days at a time. I’m pretty sure I’ve already lost hair and a few years of life-expectancy over this.
“Pass” seems completely broken to me. It does nothing I would expect of it.
For example right now I’m stuck again because it passes mouse_enter and mouse_exit signals on controls that are touching (aka when you typically would not want it to pass) …
https://user-images.githubusercontent.com/47016402/159120229-e1434b43-7d0f-4e41-8a5b-e6265f921680.mp4
Scene Tree:
Code:
Minimal Project: control_pass_mousefilter_issue.zip
… while it does NOT pass Input events when you really, really do need it to pass, like here:
Detailed issue description: Reddit post. Minimal Project: sliding_menu_issue.zip
This is so incredibly frustrating. I’ve lost so much time over this.
The behavior is expected, the problem is that the naming of the mouse filter modes suck and the documentation should be better on what is the premise of how it works. We were debating changing the names for the filters and adding a new skip one that is more akin to what users expect in this situation.
There’s a proposal https://github.com/godotengine/godot-proposals/issues/788
So I encountered a very similar issue and found this bug report. I have a little info I learned about what’s going on that I thought I’d share.
In the first reproduction project, the issue is that you have overlapping siblings. In my experience Control nodes don’t behave nicely when you do that. In this case, the pass filter can only pass the input to an immediate parent control node, so it fails to pass it along to the sibling node that is underneath it. I’ve also learned the pass filter breaks if there is an intermediate non-control parent. So Control->Node->Control will interrupt the pass filter as well. Has to be a stack of control nodes all the way down.
The second reproduction project actually seems like a different issue entirely. It looks like mouse_exited signal is always emitted if the top-most gui changes. Filter settings do not impact this. However the pass filter does influence what receives mouse_entered signals. So evidently if your buttons are set to pass filter, the vbox will receive mouse_exited followed immediately by mouse_entered. So you can workaround your issue by showing the vbox again on it’s own mouse_enter signal (weird, but it works)
As promised, here is a proposal that should shed more detail. https://github.com/godotengine/godot-proposals/issues/3613
Kooha-2023-10-01-01-57-50.webm
The Mouse > Filter setting on my Button is set to pass. However, it acts the same as if it as set to stop. I thought I’d add a gif to the issue to at least add some extra context.
This is for the mouse entered and exited signals.
@IceReaper This is more of a “How do I do X in Godot question” than a bug-report, which would be better suited for other Godot User-support community channels. That being said, try ContainerDnD.zip
Joining in. Having a similar problem on a software with a near deadline 😦
Layout is simple:
I want to capture MouseDown on B, and set a parent container property (a line2d instance). Then while holding the button, moving the mouse should trigger a mouse move events up to the container. Which should keep drawing a line from original mouse down elements center towards the cursor position. When i get a mouseup, i remove the line. If the mouseup occurs on C, i want to call a function, so i know the user wants to connect B with C. Sadly, even when setting B and C to pass, the GuiInput signal is only received by the node which received the mouse down. Meaning B receives MouseDown, all MouseMove signals, even the ones out of its bounds, and at the end the final MouseUp.
To my understanding, thats actualy what setting the filter to PASS should allow to do properly: Ignore -> no event stop -> always consume pass -> trigger but bubble up (more precise ensure the parent also gets the event, its not the same bubbled up)
When creating my minimal project, I noticed something I overlooked before: The mouse_filter for simple “Control” nodes is set to “stop” by default! 🤨 Since “pass” was the default for all my Containers and TextureRects, it hadn’t occurred to me that it could be “stop” for Control nodes. Is there any good reason for this? Otherwise, I’d suggest to change that. (Once I changed the Control node filter to “pass”, everything worked as expected)