Fixed _input
being falsely detected when a Godot GUI element is on top of the other element.
#9
Conversation
I'm a bit concerned about this, because I've been relying on this exact behavior for some features. For instance, having a fullscreen Control showing a There should be a way to let godot know you want a click to "fall through" when the mouse is hovering empty space. That would be the ideal way to handle this, but I'm not sure godot's event system supports this. Is there a way to ensure the mouse event propagates to other nodes? From the egui side, I think there are ways to detect when the pointer is hovering some GUI element (e.g. using the ui rect for the last frame). That being said, I admit the current state of input support is no better than this. If we can't find a solution that allows both workflows, we could at least make this a configurable setting, so that you could choose between _input or _gui_input modes. But I'd rather have something that works well all the time, of course! |
I see. I can see where that is a concern. From testing, this appears to use the Godot input event propagation. Generally speaking, this is all controlled based on which node has focus and what the focus mode and mouse filtering settings are. In the example above, the puffin profiler gui will be stop all input events as long as Godot's mouse filter setting for the node is set to either "MOUSE_FILTER_STOP" where it will consume all mouse events or "MOUSE_FILTER_PASS" where it will only consume it if it is actually handled. Regarding keyboard input, keyboard input also requires that the In this way, the real workflow breakage is mainly returning to using the Godot editor's settings in order to manage this. I think this is appropriate for most users. One thing I did just realize is that I need to do another quick push to make the defaults for the example and the stylist to use click as the "focus_mode" |
The problem is a bit more subtle than that. To my understanding, there's no way the user can do the right thing, even when in control of the whole scene tree. Let me ellaborate: In Godot, mouse filter can either be set as ignore, pass or stop. The difference between pass and stop is whether mouse events "bubble up" to their parents. Godot roughly proceeds as follows: 1- Select the bottommost Control node that's in front of the screen where mouse input occurs, let's call it At no point, event propagation considers siblings on the scene tree, it only travels up. This becomes an issue with GodotEgui's workflow: What people are usually doing is having one fullscreen Control node to draw the whole UI. Egui has its own notion of panels, buttons and windows, but to Godot, the whole egui rect is like a huge button covering the whole screen. So, if at any point, the GodotEgui node takes a To illustrate my point, here's a very simple Godot project setup with three nodes, a I'm not sure how can we go about solving this in a way that's completely transparent to the user, honestly 🤔 Something that would almost work is setting Otherwise, we need to consider this a tradeoff. You can either use _input, and always get mouse input but manage overlapping yourself in code, or use |
Based on our conversation in discord, there's still a lot more that probably needs to be done, so I'm downgrading this PR to a work in progress. I'll work on making the following changes
|
I've done the initial refactor. The next step is to add this to the documentation to help ensure that users understand that they are responsible for passing the input events to |
I've fixed up the remaining stuff. @setzer22 Let me know what you think when you get a chance :) |
One thing I'm not completely satisfied with is how at the moment, for generic use-cases, you have to always implement #[export]
pub fn _gui_input(&mut self, owner: TRef<Control>, event: Ref<InputEvent>) {
let gui = unsafe { self.gui.as_ref().expect("GUI initialized").assume_safe() };
gui.map_mut(|gui, instance| {
gui.handle_godot_input(instance, event, true);
if gui.mouse_was_captured(instance) {
owner.accept_event();
}
})
.expect("map_mut should succeed");
} For every class, which strikes me a kind of boiler-platey. Maybe this could use some kind of macro to automatically implement a generic solution? It seems like a lot of work to add a proc macro though 🤣 I wonder if a fairly generic normal macro would be helpful. Something like 🤔 Maybe this sort of thing should be added in a separate PR to avoid adding too much complexity right now. |
Sorry about the delay! The changes look good to me overall 🙂 There's just one thing I feel remains to be discussed: It's not ideal forcing users to have a wrapping Control to every GodotEgui node that forwards input events, and indeed it looks a bit boilerplate-y. However I don't think a macro would be very useful in abstracting this implementation detail away: The main drawback I see is that a GodotEgui node is not useful on its own anymore. Now it needs a parent node that forwards its events. Creating this parent node is where the boilerplate lies in, but this can't be done with a Rust macro alone, you still need a way to create the node in Godot's scene tree. How adding a way to opt into the old behavior. Let me ellaborate: We add a new parameter
The default would still be I believe this would be a good way to get rid of the boilerplate in some cases. It would also make the migration process way simpler for those of us who have a substantial amount of code using the old style and no incentive to change (I can't use I'm not sure how many people are using this library right now, but I believe it's unfair to ask our users for this kind of refactor for a minor version bump: People that are happy with the current state of things should be able to just "toggle a flag" to restore the old behavior. Anyway, I don't think any of this is a blocker for merging the PR, which looks good already! But for an official 0.2.0, I would like to see a solution that requires a lower migration effort for existing projects. |
…godot input callbacks. Instead `GodotEgui` requires the parent node to pass the relevant `InputEvent` received from any of Godot's callbacks into `handle_godot_input` with a flag for whether it is gui input as only gui handles mouse positions differently. This also includes a fix to allow for free rotation of the egui nodes via the the parent's rotation.
Added example code that should have been in the previous commit. Fixed clippy lints. Ran rust fmt to ensure the formatting was correct.
@setzer22 This now has the flag, if you have any other changes you'd like, let me know. |
Thanks! I'll try upgrading my project to the latest release ASAP to confirm this is working (I'm waiting on godot-rust/gdnative#791 to be merged for that) I think this should be good for a merge. If there's any other changes we can always open another PR :) |
@setzer22 Sounds great! I'll go ahead and merge this, with the new toggle there's technically no breaking changes (you just need to set the one flag and then you should be good to go). Feel free to ping me on the discord if you have any other changes you'd like me to look into. |
This PR closes #7
A note about the changes. As you noted in #7 the correct place to put the input is
_gui_input
as that respects the input propagation and resolves the issue when multiple elements are overlapping with one another.The one use-case this may break is anyone that expects two overlapping EGUI controls to both accept input will end up with broken behaviors between these UIs. This may break some expectations.
In addition, it appears that
_gui_input()
doesn't require matching the mouse position offset from the screen, it seems to get the correct coordinates, so I removed that code. (it still needs to be mapped toegui::Vec2
though.Please let me know if you have any questions.