From a1427976b5529377289f0ebf4f9ccb9fd0710e0a Mon Sep 17 00:00:00 2001 From: TehPers Date: Fri, 9 Dec 2022 01:20:44 +0000 Subject: [PATCH] Derive `Reflect` + `FromReflect` for window event types (#6235) # Objective The window event types currently don't support reflection. This PR adds support to them (as requested [here](https://github.com/bevyengine/bevy/issues/6223#issuecomment-1273852329)). ## Solution Implement `Reflect` + `FromReflect` for window event types. Relevant traits are also being reflected with `#[reflect(...)]` attributes. Additionally, this PR derives `Reflect` + `FromReflect` for `WindowDescriptor` and the types it depends on so that `CreateWindow` events can be fully manipulated through reflection. Finally, this PR adds `FromReflect` for `PathBuf` as a value type, which is needed for `FileDragAndDrop`. This adds the "glam" feature to the `bevy_reflect` dependency for package `bevy_window`. Since `bevy_window` transitively depends on `glam` already, all this brings in are the reflection `impl`s. ## Open questions Should `app.register_type::();` be moved to `CorePlugin`? I added it to `WindowPlugin` because that's where it's used and `CorePlugin` doesn't seem to register all the missing std types, but it would also make sense in `CorePlugin` I believe since it's a commonly used type. --- ## Changelog Added: - Implemented `Reflect` + `FromReflect` for window events and related types. These types are automatically registered when adding the `WindowPlugin`. --- crates/bevy_window/Cargo.toml | 4 +- crates/bevy_window/src/event.rs | 143 ++++++++++++++++++++++++------- crates/bevy_window/src/lib.rs | 30 +++++++ crates/bevy_window/src/window.rs | 87 ++++++++++++++----- 4 files changed, 213 insertions(+), 51 deletions(-) diff --git a/crates/bevy_window/Cargo.toml b/crates/bevy_window/Cargo.toml index 5686739692608..4b4add266b715 100644 --- a/crates/bevy_window/Cargo.toml +++ b/crates/bevy_window/Cargo.toml @@ -17,7 +17,9 @@ serialize = ["serde"] bevy_app = { path = "../bevy_app", version = "0.9.0" } bevy_ecs = { path = "../bevy_ecs", version = "0.9.0" } bevy_math = { path = "../bevy_math", version = "0.9.0" } -bevy_reflect = { path = "../bevy_reflect", version = "0.9.0" } +bevy_reflect = { path = "../bevy_reflect", version = "0.9.0", features = [ + "glam", +] } bevy_utils = { path = "../bevy_utils", version = "0.9.0" } # Used for close_on_esc bevy_input = { path = "../bevy_input", version = "0.9.0" } diff --git a/crates/bevy_window/src/event.rs b/crates/bevy_window/src/event.rs index 5f97b1ac410ce..6c8b0e10ba8f5 100644 --- a/crates/bevy_window/src/event.rs +++ b/crates/bevy_window/src/event.rs @@ -2,10 +2,19 @@ use std::path::PathBuf; use super::{WindowDescriptor, WindowId}; use bevy_math::{IVec2, Vec2}; +use bevy_reflect::{FromReflect, Reflect}; + +#[cfg(feature = "serialize")] +use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; /// A window event that is sent whenever a window's logical size has changed. -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub struct WindowResized { pub id: WindowId, /// The new logical width of the window. @@ -15,8 +24,13 @@ pub struct WindowResized { } /// An event that indicates that a new window should be created. -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub struct CreateWindow { pub id: WindowId, pub descriptor: WindowDescriptor, @@ -24,16 +38,26 @@ pub struct CreateWindow { /// An event that indicates the window should redraw, even if its control flow is set to `Wait` and /// there have been no window events. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub struct RequestRedraw; /// An event that is sent whenever a new window is created. /// /// To create a new window, send a [`CreateWindow`] event - this /// event will be sent in the handler for that event. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub struct WindowCreated { pub id: WindowId, } @@ -49,8 +73,13 @@ pub struct WindowCreated { /// [`WindowPlugin`]: crate::WindowPlugin /// [`Window`]: crate::Window /// [closing]: crate::Window::close -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub struct WindowCloseRequested { pub id: WindowId, } @@ -59,11 +88,17 @@ pub struct WindowCloseRequested { /// handler for [`Window::close`]. /// /// [`Window::close`]: crate::Window::close -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub struct WindowClosed { pub id: WindowId, } + /// An event reporting that the mouse cursor has moved on a window. /// /// The event is sent only if the cursor is over one of the application's windows. @@ -73,8 +108,13 @@ pub struct WindowClosed { /// /// [`WindowEvent::CursorMoved`]: https://docs.rs/winit/latest/winit/event/enum.WindowEvent.html#variant.CursorMoved /// [`MouseMotion`]: bevy_input::mouse::MouseMotion -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub struct CursorMoved { /// The identifier of the window the cursor has moved on. pub id: WindowId, @@ -82,53 +122,91 @@ pub struct CursorMoved { /// The position of the cursor, in window coordinates. pub position: Vec2, } + /// An event that is sent whenever the user's cursor enters a window. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub struct CursorEntered { pub id: WindowId, } + /// An event that is sent whenever the user's cursor leaves a window. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub struct CursorLeft { pub id: WindowId, } /// An event that is sent whenever a window receives a character from the OS or underlying system. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub struct ReceivedCharacter { pub id: WindowId, pub char: char, } /// An event that indicates a window has received or lost focus. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub struct WindowFocused { pub id: WindowId, pub focused: bool, } /// An event that indicates a window's scale factor has changed. -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub struct WindowScaleFactorChanged { pub id: WindowId, pub scale_factor: f64, } + /// An event that indicates a window's OS-reported scale factor has changed. -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub struct WindowBackendScaleFactorChanged { pub id: WindowId, pub scale_factor: f64, } /// Events related to files being dragged and dropped on a window. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub enum FileDragAndDrop { DroppedFile { id: WindowId, path_buf: PathBuf }, @@ -138,8 +216,13 @@ pub enum FileDragAndDrop { } /// An event that is sent when a window is repositioned in physical pixels. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub struct WindowMoved { pub id: WindowId, pub position: IVec2, diff --git a/crates/bevy_window/src/lib.rs b/crates/bevy_window/src/lib.rs index 6bfd8532d2c1b..1632c06042d66 100644 --- a/crates/bevy_window/src/lib.rs +++ b/crates/bevy_window/src/lib.rs @@ -24,6 +24,7 @@ pub mod prelude { use bevy_app::prelude::*; use bevy_ecs::schedule::{IntoSystemDescriptor, SystemLabel}; +use std::path::PathBuf; impl Default for WindowPlugin { fn default() -> Self { @@ -97,6 +98,35 @@ impl Plugin for WindowPlugin { if self.close_when_requested { app.add_system(close_when_requested); } + + // Register event types + app.register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::(); + + // Register window descriptor and related types + app.register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::(); + + // Register `PathBuf` as it's used by `FileDragAndDrop` + app.register_type::(); } } diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index 3a84983f11f69..17b54b508a59c 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -1,11 +1,18 @@ use bevy_math::{DVec2, IVec2, UVec2, Vec2}; -use bevy_reflect::{FromReflect, Reflect}; +use bevy_reflect::{std_traits::ReflectDefault, FromReflect, Reflect}; use bevy_utils::{tracing::warn, Uuid}; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Reflect, FromReflect)] -#[reflect_value(PartialEq, Hash)] +#[cfg(feature = "serialize")] +use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; + /// A unique ID for a [`Window`]. -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Reflect, FromReflect)] +#[reflect_value(Debug, PartialEq, Hash, Default)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect_value(Serialize, Deserialize) +)] pub struct WindowId(Uuid); /// Presentation mode for a window. @@ -24,8 +31,13 @@ pub struct WindowId(Uuid); /// The presentation mode may be declared in the [`WindowDescriptor`](WindowDescriptor) using [`WindowDescriptor::present_mode`](WindowDescriptor::present_mode) /// or updated on a [`Window`](Window) using [`set_present_mode`](Window::set_present_mode). #[repr(C)] -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Reflect, FromReflect)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] +#[reflect(Debug, PartialEq, Hash)] #[doc(alias = "vsync")] pub enum PresentMode { /// Chooses FifoRelaxed -> Fifo based on availability. @@ -58,8 +70,13 @@ pub enum PresentMode { /// Specifies how the alpha channel of the textures should be handled during compositing. #[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, FromReflect)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] +#[reflect(Debug, PartialEq, Hash)] pub enum CompositeAlphaMode { /// Chooses either `Opaque` or `Inherit` automatically,depending on the /// `alpha_mode` that the current surface can support. @@ -125,8 +142,13 @@ impl Default for WindowId { /// Please note that if the window is resizable, then when the window is /// maximized it may have a size outside of these limits. The functionality /// required to disable maximizing is not yet exposed by winit. -#[derive(Debug, Clone, Copy, PartialEq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Reflect, FromReflect)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] +#[reflect(Debug, PartialEq, Default)] pub struct WindowResizeConstraints { pub min_width: f32, pub min_height: f32, @@ -385,8 +407,13 @@ pub enum WindowCommand { /// Defines if and how the cursor is grabbed. /// /// Use this enum with [`Window::set_cursor_grab_mode`] to grab the cursor. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Reflect, FromReflect)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] +#[reflect(Debug, PartialEq)] pub enum CursorGrabMode { /// The cursor can freely leave the window. None, @@ -397,8 +424,13 @@ pub enum CursorGrabMode { } /// Defines the way a window is displayed. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Reflect, FromReflect)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] +#[reflect(Debug, PartialEq)] pub enum WindowMode { /// Creates a window that uses the given size. Windowed, @@ -898,8 +930,13 @@ impl Window { } /// Defines where window should be placed at on creation. -#[derive(Debug, Clone, Copy, PartialEq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Reflect, FromReflect)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] +#[reflect(Debug, PartialEq)] pub enum WindowPosition { /// The position will be set by the window manager. Automatic, @@ -916,8 +953,13 @@ pub enum WindowPosition { } /// Defines which monitor to use. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Reflect, FromReflect)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] +#[reflect(Debug, PartialEq)] pub enum MonitorSelection { /// Uses current monitor of the window. /// @@ -937,8 +979,13 @@ pub enum MonitorSelection { /// See [`examples/window/window_settings.rs`] for usage. /// /// [`examples/window/window_settings.rs`]: https://github.com/bevyengine/bevy/blob/latest/examples/window/window_settings.rs -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] +#[reflect(Debug, PartialEq, Default)] pub struct WindowDescriptor { /// The requested logical width of the window's client area. ///