-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Add Hidden to CursorIcon and CursorSource enums #15386
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Welcome, new contributor! Please make sure you've read our contributing guide and we look forward to reviewing your pull request shortly ✨ |
100% agreed :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice! No complaints here; this is how I would have done it (including chasing errors after adding the variant).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This conflicts with the existing CursorOptions
field on Window
that sets the visibility in changed_windows
. I'm okay with considering the more ECS focused approached, but we should minimally remove visible
from CursorOptions
, as well as documenting the platform specific gotchas on the enum here, as well as explore adding a CursorGrabMode
component and I guess HitTest
too? Idk, now I'm also like that's too ECS-y lol, but minimally we need to resolve what to do with the existing window settings.
With this design it becomes harder to toggle visibility. You would have to store the previous cursor somewhere to unhide it later. But it might not matter too much. I think this option would fit better as a boolean field within the cursor component, but that unfortunately breaks change detection. Could we use the same diffing system that we use for the window settings, where we store a copy of the previous window component and that way get ergonomics of a single unified component and field level change detection? |
I kind of get the gist of it and agree with the ergonomics. Do you have a pointer of the window settings thing you're referencing? |
Look at the |
…indow::Window` component As per talks in https://discord.com/channels/691052431525675048/1287953140955746305, just going to remove visible so that we only have one API for making a cursor hidden.
1d73022
to
7cd2a57
Compare
crates/bevy_window/src/window.rs
Outdated
@@ -126,7 +126,7 @@ impl NormalizedWindowRef { | |||
)] | |||
#[reflect(Component, Default, Debug)] | |||
pub struct Window { | |||
/// The cursor options of this window. Cursor icons are set with the `Cursor` component on the | |||
/// The cursor options of this window. Cursor icons are set with the `CursorIcon` component on the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 ; I think that's important to note to ease with migration, that being said this property actually refers to bevy_render
, and it's annoying that we can't link to it through a real link :( (also, should we at all ? 🤔)
Or should CursorIcon be brought in bevy_window
?
(Those questions are probably outside this PR scope, sorry for derailing :) )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no worries! we have had a whole conversation about it inside a discord thread
tl;dr ideally this would live inside of bevy_winit
, to keep ergonomics the same since most of the use cases regarding icons right now involve Query<&Window>
and reading the cursor_options
field which is of the CursorOptions
type, which originally had CursorIcon
. Now that we have custom cursor support, this had to live inside bevy_render
because the custom cursors require access to Image
which can't be imported inside of bevy_winit
nor bevy_window
due to circular dependencies.
though I do agree that the comment should be linked properly - I tried adding the fully qualified name on another comment, but I wasn't sure about how to run the docs to check if it worked locally (i'm still a rust toolchain noob)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for the insight !
I tried adding the fully qualified name on another comment
Nice try! the CI docs step fails due to that. Check it out (and I recommend looking at the .github workflow file to see more details on what commands are run 👍
I fear it's impossible to link because bevy_window doesn't rely on bevy_render :(
well I imagine we theoretically could by adding the dependency if building docs, but I personally wouldn't approve that :/
Continued rambling about CursorIcon
I'd prefer a CursorIcon::Custom
empty enum variant, and let the other crates handle their custom thing however they want 🤔.
Or a generic Custom ? or a Box with a dyn trait something inside ?
Or straight up remove any mention to those classes and embrace this split 🤔
I wasn't sure about how to run the docs
cargo doc --open
will bring you far enough 🤞
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm certainly in favor of moving cursor related options to the cursor component, but it feels weird losing the ability that winit provides to separately toggle visibility and choose the displayed icon. I don't have super strong feelings about though, this way is ok too.
The change to automatically add the cursor component to every window is good. I should have done it that way before. Though I think observers would work better in avoiding scheduling issues.
@@ -149,6 +149,8 @@ pub struct CustomCursorCache(pub HashMap<CustomCursorCacheKey, winit::window::Cu | |||
/// A source for a cursor. Is created in `bevy_render` and consumed by the winit event loop. | |||
#[derive(Debug)] | |||
pub enum CursorSource { | |||
/// A hidden cursor, used to hide the cursor in `winit_window` | |||
Hidden, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should propagate cursor visibility to bevy_winit
. Custom cursors are required to be changed in such a convoluted way because they require access to the winit event loop. Cursor visibility can be changed directly with NonSendMut<WinitWindows>
in any system just like it was done before with cursor_options
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm starting to think what we really need to do is do something along the lines of not having a cursor from being instead Hidden
to just not having a cursor source or None
. This clearly denotes the feature set each cursor source has - the SystemCursor
is heavily part of the winit
package we use, hence the related feature set. Now that we have CursorSource::Custom
, if we think that over time it ends up having a different feature set, maybe something like if we were to support gifs as cursors, or sprite sheets as cursors with animations, there might be options relating how fast to play the gif or whether or not to loop it's animation. This way, most of the examples will look almost the same in functionality, just changing a bool
pub enum CursorSource {
None,
Custom{ custom_cursor: CustomCursor, visibility: bool },
System{ system_cursor: SystemCursor, visibility: bool },
}
Overtime, I want to probably work on moving the system related CursorOptions
found in bevy_window::Window
and moving them with the CursorIcon
.
I would ideally like to have these all live in the same crate so maybe looking at breaking the circular dependencies next is the thing to do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As to the
Cursor visibility can be changed directly with
NonSendMut<WinitWindows>
in any system just like it was done before withcursor_options
.
I don't get quite this means? Are you suggesting that if it isn't a CustomCursor
then we should just use the system winit
related API directly? I think we were initially against that because we would have two API's and it could get confusing, so I would like your take on it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I would be proposing is to just move cursor options from the window component to the cursor component and doing absolutely everything the exact same it was done before and make a new cursor component.
struct Cursor {
pub visible: bool,
... other options ...
pub icon: CursorIcon,
}
Then move everything that was done in the window update system to the cursor update system.
But I that is a different proposal than what is included in the related issue, so it might not be relevant to this PR.
I don't get quite this means? Are you suggesting that if it isn't a
CustomCursor
then we should just use the systemwinit
related API directly? I think we were initially against that because we would have two API's and it could get confusing, so I would like your take on it.
Yes. CursorSource
is an implementation detail for smuggling cursor icon bytes to the bevy_winit
crate. It would lead to less spread out code and less complexity to just set the WinitWindows
cursor visibility boolean in the bevy_render
cursor system. It doesn't create any additional APIs. Functionally your code does the same thing so consider what would be simpler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that we have CursorSource::Custom, if we think that over time it ends up having a different feature set.
CursorSource
is a direct equivalent to winit
s native cursors. Those are clearly defined and not flexible, so CursorSource
doesn't need to be flexible.
E.g. if we want to use sprite sheets as animated cursors, those would need to be converted to be winit
compatible outside of bevy_winit
anyway because in can't use assets.
@@ -29,7 +28,7 @@ impl Plugin for CursorPlugin { | |||
app.register_type::<CursorIcon>() | |||
.init_resource::<CustomCursorCache>() | |||
.add_systems(Last, update_cursors) | |||
.add_systems(Update, add_cursor_to_windows); | |||
.observe(add_cursor_to_windows); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eero-lehtinen this was quite pretty to do, I remember reading the example for this last week and now this seems so nice
examples/input/mouse_grab.rs
Outdated
@@ -19,9 +19,7 @@ fn grab_mouse( | |||
// There are cases where we can have multiple windows and cursors, | |||
// but not in this example. Keeping the naming convention since it | |||
// exists in other examples | |||
let Ok((mut window, mut cursor)) = windows_and_cursors.get_single_mut() else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it ended up fixing the non-determinism thing here so that we will always have the cursor when windows are created which is perfect
@@ -154,6 +154,8 @@ pub struct CustomCursorCache(pub HashMap<CustomCursorCacheKey, winit::window::Cu | |||
/// A source for a cursor. Is created in `bevy_render` and consumed by the winit event loop. | |||
#[derive(Debug)] | |||
pub enum CursorSource { | |||
/// A hidden cursor, used to hide the cursor in `winit_window` | |||
Hidden, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is still missing documentation about platform specific behavior.
Objective
window.cursor.visible = false
) with the new old winit cursor api (CursorIcon
implemented in Add custom cursors #14284)Hidden
enum variant forCursorIcon
and relatedCursorSource
in the consuming APISolution
I just decided to add
Hidden
variant to the enum, then decided to fix the errors one by one to find the places where the match guards weren't being exhausted properly. Once I saw that it gets consumed in theupdate_cursors
function, I decided to see how it gets used to actually change the cursor. Looking at #14284, I saw that there was an intermediaryCursorSource
enum that would get used to actually create the cursor. From what I understand, this enum was created becase we can either have system cursors that exist on our OS or a custom one that we define. My thought process then, was to propagate theHidden
value to this struct and then instead of setting the actual cursor source, figure out how to turn off the visibility. I looked at where thewindow.cursor.visibility
value that the old winit api was using and then saw that we could setwinit_window.set_cursor_visible(false)
.The only thing I'm worried about now is that I'm wondering about if there's a performance hit of doing this way. I haven't really gotten the time to look through the code properly, but previously we were not changing the visibility of this at all. Right now, I am changing the visibility whenever we are updating the cursors. I'm thinking that since this doesn't get changed too often, changing the visibility should just be minimal impact.
The only thing I wanted to do was something along the lines of
but I am quite noob at rust and couldn't figure out how to fight back at the borrow checker.
Also, if there are any docs that I should update please let me know.
Testing
trimmed.mov
Migration Guide
CursorIcon
enum, though I'm not really sure if they would ever