# Objective Fix https://github.com/bevyengine/bevy/issues/4530 - Make it easier to open/close/modify windows by setting them up as `Entity`s with a `Window` component. - Make multiple windows very simple to set up. (just add a `Window` component to an entity and it should open) ## Solution - Move all properties of window descriptor to ~components~ a component. - Replace `WindowId` with `Entity`. - ~Use change detection for components to update backend rather than events/commands. (The `CursorMoved`/`WindowResized`/... events are kept for user convenience.~ Check each field individually to see what we need to update, events are still kept for user convenience. --- ## Changelog - `WindowDescriptor` renamed to `Window`. - Width/height consolidated into a `WindowResolution` component. - Requesting maximization/minimization is done on the [`Window::state`] field. - `WindowId` is now `Entity`. ## Migration Guide - Replace `WindowDescriptor` with `Window`. - Change `width` and `height` fields in a `WindowResolution`, either by doing ```rust WindowResolution::new(width, height) // Explicitly // or using From<_> for tuples for convenience (1920., 1080.).into() ``` - Replace any `WindowCommand` code to just modify the `Window`'s fields directly and creating/closing windows is now by spawning/despawning an entity with a `Window` component like so: ```rust let window = commands.spawn(Window { ... }).id(); // open window commands.entity(window).despawn(); // close window ``` ## Unresolved - ~How do we tell when a window is minimized by a user?~ ~Currently using the `Resize(0, 0)` as an indicator of minimization.~ No longer attempting to tell given how finnicky this was across platforms, now the user can only request that a window be maximized/minimized. ## Future work - Move `exit_on_close` functionality out from windowing and into app(?) - https://github.com/bevyengine/bevy/issues/5621 - https://github.com/bevyengine/bevy/issues/7099 - https://github.com/bevyengine/bevy/issues/7098 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
247 lines
7.7 KiB
Rust
247 lines
7.7 KiB
Rust
use std::path::PathBuf;
|
|
|
|
use bevy_ecs::entity::Entity;
|
|
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, Reflect, FromReflect)]
|
|
#[reflect(Debug, PartialEq)]
|
|
#[cfg_attr(
|
|
feature = "serialize",
|
|
derive(serde::Serialize, serde::Deserialize),
|
|
reflect(Serialize, Deserialize)
|
|
)]
|
|
pub struct WindowResized {
|
|
/// Window that has changed.
|
|
pub window: Entity,
|
|
/// The new logical width of the window.
|
|
pub width: f32,
|
|
/// The new logical height of the window.
|
|
pub height: f32,
|
|
}
|
|
|
|
// TODO: This would redraw all windows ? If yes, update docs to reflect this
|
|
/// 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, 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, spawn an entity with a [`crate::Window`] on it.
|
|
#[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 {
|
|
/// Window that has been created.
|
|
pub window: Entity,
|
|
}
|
|
|
|
/// An event that is sent whenever the operating systems requests that a window
|
|
/// be closed. This will be sent when the close button of the window is pressed.
|
|
///
|
|
/// If the default [`WindowPlugin`] is used, these events are handled
|
|
/// by closing the corresponding [`Window`].
|
|
/// To disable this behaviour, set `close_when_requested` on the [`WindowPlugin`]
|
|
/// to `false`.
|
|
///
|
|
/// [`WindowPlugin`]: crate::WindowPlugin
|
|
/// [`Window`]: crate::Window
|
|
#[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 {
|
|
/// Window to close.
|
|
pub window: Entity,
|
|
}
|
|
|
|
/// An event that is sent whenever a window is closed. This will be sent when
|
|
/// the window entity loses its `Window` component or is despawned.
|
|
#[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 {
|
|
/// Window that has been closed.
|
|
///
|
|
/// Note that this entity probably no longer exists
|
|
/// by the time this event is received.
|
|
pub window: Entity,
|
|
}
|
|
/// An event reporting that the mouse cursor has moved inside a window.
|
|
///
|
|
/// The event is sent only if the cursor is over one of the application's windows.
|
|
/// It is the translated version of [`WindowEvent::CursorMoved`] from the `winit` crate.
|
|
///
|
|
/// Not to be confused with the [`MouseMotion`] event from `bevy_input`.
|
|
///
|
|
/// [`WindowEvent::CursorMoved`]: https://docs.rs/winit/latest/winit/event/enum.WindowEvent.html#variant.CursorMoved
|
|
/// [`MouseMotion`]: bevy_input::mouse::MouseMotion
|
|
#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)]
|
|
#[reflect(Debug, PartialEq)]
|
|
#[cfg_attr(
|
|
feature = "serialize",
|
|
derive(serde::Serialize, serde::Deserialize),
|
|
reflect(Serialize, Deserialize)
|
|
)]
|
|
pub struct CursorMoved {
|
|
/// Window that the cursor moved inside.
|
|
pub window: Entity,
|
|
/// The cursor position in logical pixels.
|
|
pub position: Vec2,
|
|
}
|
|
|
|
/// An event that is sent whenever the user's cursor enters a window.
|
|
#[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 {
|
|
/// Window that the cursor entered.
|
|
pub window: Entity,
|
|
}
|
|
|
|
/// An event that is sent whenever the user's cursor leaves a window.
|
|
#[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 {
|
|
/// Window that the cursor left.
|
|
pub window: Entity,
|
|
}
|
|
|
|
/// An event that is sent whenever a window receives a character from the OS or underlying system.
|
|
#[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 {
|
|
/// Window that received the character.
|
|
pub window: Entity,
|
|
/// Received character.
|
|
pub char: char,
|
|
}
|
|
|
|
/// An event that indicates a window has received or lost focus.
|
|
#[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 {
|
|
/// Window that changed focus.
|
|
pub window: Entity,
|
|
/// Whether it was focused (true) or lost focused (false).
|
|
pub focused: bool,
|
|
}
|
|
|
|
/// An event that indicates a window's scale factor has changed.
|
|
#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)]
|
|
#[reflect(Debug, PartialEq)]
|
|
#[cfg_attr(
|
|
feature = "serialize",
|
|
derive(serde::Serialize, serde::Deserialize),
|
|
reflect(Serialize, Deserialize)
|
|
)]
|
|
pub struct WindowScaleFactorChanged {
|
|
/// Window that had it's scale factor changed.
|
|
pub window: Entity,
|
|
/// The new scale factor.
|
|
pub scale_factor: f64,
|
|
}
|
|
|
|
/// An event that indicates a window's OS-reported scale factor has changed.
|
|
#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)]
|
|
#[reflect(Debug, PartialEq)]
|
|
#[cfg_attr(
|
|
feature = "serialize",
|
|
derive(serde::Serialize, serde::Deserialize),
|
|
reflect(Serialize, Deserialize)
|
|
)]
|
|
pub struct WindowBackendScaleFactorChanged {
|
|
/// Window that had it's scale factor changed by the backend.
|
|
pub window: Entity,
|
|
/// The new scale factor.
|
|
pub scale_factor: f64,
|
|
}
|
|
|
|
/// Events related to files being dragged and dropped on a window.
|
|
#[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 {
|
|
/// File is being dropped into a window.
|
|
DroppedFile {
|
|
/// Window the file was dropped into.
|
|
window: Entity,
|
|
/// Path to the file that was dropped in.
|
|
path_buf: PathBuf,
|
|
},
|
|
|
|
/// File is currently being hovered over a window.
|
|
HoveredFile {
|
|
/// Window a file is possibly going to be dropped into.
|
|
window: Entity,
|
|
/// Path to the file that might be dropped in.
|
|
path_buf: PathBuf,
|
|
},
|
|
|
|
/// File hovering was cancelled.
|
|
HoveredFileCancelled {
|
|
/// Window that had a cancelled file drop.
|
|
window: Entity,
|
|
},
|
|
}
|
|
|
|
/// An event that is sent when a window is repositioned in physical pixels.
|
|
#[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 {
|
|
/// Window that moved.
|
|
pub entity: Entity,
|
|
/// Where the window moved to in physical pixels.
|
|
pub position: IVec2,
|
|
}
|