diff --git a/crates/bevy_window/src/cursor.rs b/crates/bevy_window/src/cursor.rs index 8fa0edfae1548..c3926d1b04726 100644 --- a/crates/bevy_window/src/cursor.rs +++ b/crates/bevy_window/src/cursor.rs @@ -1,39 +1,81 @@ -/// The icon to display for a window's cursor +/// The icon to display for a window's cursor. +/// +/// Examples of all of these cursors can be found [here](https://www.w3schools.com/cssref/playit.asp?filename=playcss_cursor). +/// This `enum` is simply a copy of a similar `enum` found in [`winit`](https://docs.rs/winit/latest/winit/window/enum.CursorIcon.html). +/// `winit`, in turn, mostly copied cursor types avilable in the browser. #[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] pub enum CursorIcon { + /// The platform-dependent default cursor. Default, + /// A simple crosshair. Crosshair, + /// A hand (often used to indicate links in web browsers). Hand, + /// An arrow. This is the default cursor on most systems. Arrow, + /// Indicates something is to be moved. Move, + /// Indicates text that may be selected or edited. Text, + /// Program busy indicator. Wait, + /// Help indicator (often rendered as a "?") Help, + /// Progress indicator. Shows that processing is being done. + /// + /// But in contrast with "Wait" the user may still interact with the program. + /// Often rendered as a spinning beach ball, or an arrow with a watch or hourglass. Progress, + /// Cursor showing that something cannot be done. NotAllowed, + /// Indicates that a context menu is available. ContextMenu, + /// Indicates that a cell (or set of cells) may be selected. Cell, + /// Indicates vertical text that may be selected or edited. VerticalText, + /// Indicates that an alias of something is to be created. Alias, + /// Indicates something is to be copied. Copy, + /// Indicates that the dragged item cannot be dropped here. NoDrop, + /// Indicates that something can be grabbed. Grab, + /// Indicates that something is grabbed. Grabbing, + /// Indicates that the user can scroll by dragging the mouse. AllScroll, + /// Indicates that the user can zoom in. ZoomIn, + /// Indicates that the user can zoom out. ZoomOut, + /// Indicates that an edge of a box is to be moved right (east). EResize, + /// Indicates that an edge of a box is to be moved up (north). NResize, + /// Indicates that an edge of a box is to be moved up and right (north/east). NeResize, + /// indicates that an edge of a box is to be moved up and left (north/west). NwResize, + /// Indicates that an edge of a box is to be moved down (south). SResize, + /// The cursor indicates that an edge of a box is to be moved down and right (south/east). SeResize, + /// The cursor indicates that an edge of a box is to be moved down and left (south/west). SwResize, + /// Indicates that an edge of a box is to be moved left (west). WResize, + /// Indicates a bidirectional resize cursor. EwResize, + /// Indicates a bidirectional resize cursor. NsResize, + /// Indicates a bidirectional resize cursor. NeswResize, + /// Indicates a bidirectional resize cursor. NwseResize, + /// Indicates that a column can be resized horizontally. ColResize, + /// Indicates that the row can be resized vertically. RowResize, } diff --git a/crates/bevy_window/src/event.rs b/crates/bevy_window/src/event.rs index 8452c482035ca..c57222973b84a 100644 --- a/crates/bevy_window/src/event.rs +++ b/crates/bevy_window/src/event.rs @@ -3,13 +3,13 @@ use std::path::PathBuf; use super::{WindowDescriptor, WindowId}; use bevy_math::{IVec2, Vec2}; -/// A window event that is sent whenever a windows logical size has changed +/// A window event that is sent whenever a window's logical size has changed. #[derive(Debug, Clone)] pub struct WindowResized { pub id: WindowId, - /// The new logical width of the window + /// The new logical width of the window. pub width: f32, - /// The new logical height of the window + /// The new logical height of the window. pub height: f32, } @@ -58,18 +58,18 @@ pub struct WindowCloseRequested { pub struct WindowClosed { pub id: WindowId, } - +/// An event that is sent whenenver the user's cursor moves. #[derive(Debug, Clone)] pub struct CursorMoved { pub id: WindowId, pub position: Vec2, } - +/// An event that is sent whenever the user's cursor enters a window. #[derive(Debug, Clone)] pub struct CursorEntered { pub id: WindowId, } - +/// An event that is sent whenever the user's cursor leaves a window. #[derive(Debug, Clone)] pub struct CursorLeft { pub id: WindowId, diff --git a/crates/bevy_window/src/lib.rs b/crates/bevy_window/src/lib.rs index 6e5b2abd87680..ca57cde6fac6b 100644 --- a/crates/bevy_window/src/lib.rs +++ b/crates/bevy_window/src/lib.rs @@ -1,3 +1,4 @@ +#[warn(missing_docs)] mod cursor; mod event; mod raw_window_handle; @@ -23,6 +24,7 @@ pub mod prelude { use bevy_app::prelude::*; use bevy_ecs::{event::Events, schedule::SystemLabel}; +/// A [`Plugin`] that defines an interface for windowing support in Bevy. pub struct WindowPlugin { /// Whether to create a window when added. /// @@ -30,6 +32,7 @@ pub struct WindowPlugin { /// due to [`exit_on_all_closed`]. pub add_primary_window: bool, /// Whether to exit the app when there are no open windows. + /// /// If disabling this, ensure that you send the [`bevy_app::AppExit`] /// event when the app should exit. If this does not occur, you will /// create 'headless' processes (processes without windows), which may @@ -38,7 +41,7 @@ pub struct WindowPlugin { /// If true, this plugin will add [`exit_on_all_closed`] to [`CoreStage::Update`]. pub exit_on_all_closed: bool, /// Whether to close windows when they are requested to be closed (i.e. - /// when the close button is pressed) + /// when the close button is pressed). /// /// If true, this plugin will add [`close_when_requested`] to [`CoreStage::Update`]. /// If this system (or a replacement) is not running, the close button will have no effect. diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index 19aa6cbbb8267..6557d414c590d 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -3,6 +3,7 @@ use bevy_utils::{tracing::warn, Uuid}; use raw_window_handle::RawWindowHandle; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +/// A unique ID for a [`Window`]. pub struct WindowId(Uuid); /// Presentation mode for a window. @@ -39,14 +40,15 @@ pub enum PresentMode { } impl WindowId { + /// Creates a new [`WindowId`]. pub fn new() -> Self { WindowId(Uuid::new_v4()) } - + /// The [`WindowId`] for the primary window. pub fn primary() -> Self { WindowId(Uuid::from_u128(0)) } - + /// Get whether or not this [`WindowId`] is for the primary window. pub fn is_primary(&self) -> bool { *self == WindowId::primary() } @@ -70,6 +72,7 @@ impl Default for WindowId { } /// The size limits on a window. +/// /// These values are measured in logical pixels, so the user's /// scale factor does affect the size limits on the window. /// Please note that if the window is resizable, then when the window is @@ -130,6 +133,8 @@ impl WindowResizeConstraints { /// An operating system window that can present content and receive user input. /// +/// To create a window, use a [`EventWriter`](`crate::CreateWindow`). +/// /// ## Window Sizes /// /// There are three sizes associated with a window. The physical size which is @@ -143,6 +148,25 @@ impl WindowResizeConstraints { /// requested size due to operating system limits on the window size, or the /// quantization of the logical size when converting the physical size to the /// logical size through the scaling factor. +/// +/// ## Accessing a `Window` from a system +/// +/// To access a `Window` from a system, use [`bevy_ecs::change_detection::ResMut`]`<`[`crate::Windows`]`>`. +/// +/// ### Example +/// ```no_run +/// # use bevy_app::App; +/// # use bevy_window::Windows; +/// # use bevy_ecs::change_detection::ResMut; +/// # fn main(){ +/// # App::new().add_system(access_window_system).run(); +/// # } +/// fn access_window_system(mut windows: ResMut){ +/// for mut window in windows.iter_mut(){ +/// window.set_title(String::from("Yay, I'm a window!")); +/// } +/// } +/// ``` #[derive(Debug)] pub struct Window { id: WindowId, @@ -169,74 +193,96 @@ pub struct Window { fit_canvas_to_parent: bool, command_queue: Vec, } - +/// A command to be sent to a window. +/// +/// Bevy apps don't interact with this `enum` directly. Instead, they should use the methods on [`Window`]. +/// This `enum` is meant for authors of windowing plugins. See the documentation on [`crate::WindowPlugin`] for more information. #[derive(Debug)] pub enum WindowCommand { + /// Set the window's [`WindowMode`]. SetWindowMode { mode: WindowMode, resolution: (u32, u32), }, + /// Set the window's title. SetTitle { title: String, }, + /// Set the window's scale factor. SetScaleFactor { scale_factor: f64, }, + /// Set the window's resolution. SetResolution { logical_resolution: (f32, f32), scale_factor: f64, }, + /// Set the window's [`PresentMode`]. SetPresentMode { present_mode: PresentMode, }, + /// Set whether or not the window is resizable. SetResizable { resizable: bool, }, + /// Set whether or not the window has decorations. + /// + /// Examples of decorations include the close, full screen, and minimize buttons SetDecorations { decorations: bool, }, + /// Set whether or not the cursor's postition is locked. SetCursorLockMode { locked: bool, }, + /// Set the cursor's [`CursorIcon`]. SetCursorIcon { icon: CursorIcon, }, + /// Set whether or not the cursor is visible. SetCursorVisibility { visible: bool, }, + /// Set the cursor's position. SetCursorPosition { position: Vec2, }, + /// Set whether or not the window is maxizimed. SetMaximized { maximized: bool, }, + /// Set whether or not the window is minimized. SetMinimized { minimized: bool, }, + /// Set the window's position on the screen. SetPosition { position: IVec2, }, + /// Set the window's [`WindowResizeConstraints`] SetResizeConstraints { resize_constraints: WindowResizeConstraints, }, Close, } -/// Defines the way a window is displayed +/// Defines the way a window is displayed. #[derive(Debug, Clone, Copy, PartialEq)] pub enum WindowMode { - /// Creates a window that uses the given size + /// Creates a window that uses the given size. Windowed, - /// Creates a borderless window that uses the full size of the screen + /// Creates a borderless window that uses the full size of the screen. BorderlessFullscreen, - /// Creates a fullscreen window that will render at desktop resolution. The app will use the closest supported size - /// from the given size and scale it to fit the screen. + /// Creates a fullscreen window that will render at desktop resolution. + /// + /// The app will use the closest supported size from the given size and scale it to fit the screen. SizedFullscreen, - /// Creates a fullscreen window that uses the maximum supported size + /// Creates a fullscreen window that uses the maximum supported size. Fullscreen, } impl Window { + /// Creates a new [`Window`]. pub fn new( id: WindowId, window_descriptor: &WindowDescriptor, @@ -272,7 +318,7 @@ impl Window { command_queue: Vec::new(), } } - + /// Get the window's [`WindowId`]. #[inline] pub fn id(&self) -> WindowId { self.id @@ -333,7 +379,7 @@ impl Window { pub fn position(&self) -> Option { self.position } - + /// Set whether or not the window is maximized. #[inline] pub fn set_maximized(&mut self, maximized: bool) { self.command_queue @@ -393,7 +439,7 @@ impl Window { }); } - /// Override the os-reported scaling factor + /// Override the os-reported scaling factor. #[allow(clippy::float_cmp)] pub fn set_scale_factor_override(&mut self, scale_factor: Option) { if self.scale_factor_override == scale_factor { @@ -438,22 +484,25 @@ impl Window { } /// The window scale factor as reported by the window backend. + /// /// This value is unaffected by [`scale_factor_override`](Window::scale_factor_override). #[inline] pub fn backend_scale_factor(&self) -> f64 { self.backend_scale_factor } - + /// The scale factor set with [`set_scale_factor_override`](Window::set_scale_factor_override). + /// + /// This value may be different from the scale factor reported by the window backend. #[inline] pub fn scale_factor_override(&self) -> Option { self.scale_factor_override } - + /// Get the window's title. #[inline] pub fn title(&self) -> &str { &self.title } - + /// Set the window's title. pub fn set_title(&mut self, title: String) { self.title = title.to_string(); self.command_queue.push(WindowCommand::SetTitle { title }); @@ -461,68 +510,106 @@ impl Window { #[inline] #[doc(alias = "vsync")] + /// Get the window's [`PresentMode`]. pub fn present_mode(&self) -> PresentMode { self.present_mode } #[inline] #[doc(alias = "set_vsync")] + /// Set the window's [`PresentMode`]. pub fn set_present_mode(&mut self, present_mode: PresentMode) { self.present_mode = present_mode; self.command_queue .push(WindowCommand::SetPresentMode { present_mode }); } - + /// Get whether or not the window is resizable. #[inline] pub fn resizable(&self) -> bool { self.resizable } - + /// Set whether or not the window is resizable. pub fn set_resizable(&mut self, resizable: bool) { self.resizable = resizable; self.command_queue .push(WindowCommand::SetResizable { resizable }); } - + /// Get whether or not decorations are enabled. + /// + /// (Decorations are the minimize, maximize, and close buttons on desktop apps) + /// + /// ## Platform-specific + /// + /// **`iOS`**, **`Android`**, and the **`Web`** do not have decorations. #[inline] pub fn decorations(&self) -> bool { self.decorations } - + /// Set whether or not decorations are enabled. + /// + /// (Decorations are the minimize, maximize, and close buttons on desktop apps) + /// + /// ## Platform-specific + /// + /// **`iOS`**, **`Android`**, and the **`Web`** do not have decorations. pub fn set_decorations(&mut self, decorations: bool) { self.decorations = decorations; self.command_queue .push(WindowCommand::SetDecorations { decorations }); } - + /// Get whether or not the cursor is locked. + /// + /// ## Platform-specific + /// + /// - **`macOS`** doesn't support cursor lock, but most windowing plugins can emulate it. See [issue #4875](https://github.com/bevyengine/bevy/issues/4875#issuecomment-1153977546) for more information. + /// - **`iOS/Android`** don't have cursors. #[inline] pub fn cursor_locked(&self) -> bool { self.cursor_locked } - + /// Set whether or not the cursor is locked. + /// + /// This doesn't hide the cursor. For that, use [`set_cursor_visibility`](Window::set_cursor_visibility) + /// + /// ## Platform-specific + /// + /// - **`macOS`** doesn't support cursor lock, but most windowing plugins can emulate it. See [issue #4875](https://github.com/bevyengine/bevy/issues/4875#issuecomment-1153977546) for more information. + /// - **`iOS/Android`** don't have cursors. pub fn set_cursor_lock_mode(&mut self, lock_mode: bool) { self.cursor_locked = lock_mode; self.command_queue .push(WindowCommand::SetCursorLockMode { locked: lock_mode }); } - + /// Get whether or not the cursor is visible. + /// + /// ## Platform-specific + /// + /// - **`Windows`**, **`X11`**, and **`Wayland`**: The cursor is hidden only when inside the window. To stop the cursor from leaving the window, use [`set_cursor_lock_mode`](Window::set_cursor_lock_mode). + /// - **`macOS`**: The cursor is hidden only when the window is focused. + /// - **`iOS`** and **`Android`** do not have cursors #[inline] pub fn cursor_visible(&self) -> bool { self.cursor_visible } - + /// Set whether or not the cursor is visible. + /// + /// ## Platform-specific + /// + /// - **`Windows`**, **`X11`**, and **`Wayland`**: The cursor is hidden only when inside the window. To stop the cursor from leaving the window, use [`set_cursor_lock_mode`](Window::set_cursor_lock_mode). + /// - **`macOS`**: The cursor is hidden only when the window is focused. + /// - **`iOS`** and **`Android`** do not have cursors pub fn set_cursor_visibility(&mut self, visibile_mode: bool) { self.cursor_visible = visibile_mode; self.command_queue.push(WindowCommand::SetCursorVisibility { visible: visibile_mode, }); } - + /// Get the current [`CursorIcon`] #[inline] pub fn cursor_icon(&self) -> CursorIcon { self.cursor_icon } - + /// Set the [`CursorIcon`] pub fn set_cursor_icon(&mut self, icon: CursorIcon) { self.command_queue .push(WindowCommand::SetCursorIcon { icon }); @@ -541,7 +628,7 @@ impl Window { self.physical_cursor_position .map(|p| (p / self.scale_factor()).as_vec2()) } - + /// Set the cursor's position pub fn set_cursor_position(&mut self, position: Vec2) { self.command_queue .push(WindowCommand::SetCursorPosition { position }); @@ -558,12 +645,12 @@ impl Window { pub fn update_cursor_physical_position_from_backend(&mut self, cursor_position: Option) { self.physical_cursor_position = cursor_position; } - + /// Get the window's [`WindowMode`] #[inline] pub fn mode(&self) -> WindowMode { self.mode } - + /// Set the window's [`WindowMode`] pub fn set_mode(&mut self, mode: WindowMode) { self.mode = mode; self.command_queue.push(WindowCommand::SetWindowMode { @@ -571,8 +658,8 @@ impl Window { resolution: (self.physical_width, self.physical_height), }); } - - /// Close the operating system window corresponding to this [`Window`]. + /// Close the operating system window corresponding to this [`Window`]. + /// /// This will also lead to this [`Window`] being removed from the /// [`Windows`] resource. /// @@ -586,22 +673,25 @@ impl Window { pub fn close(&mut self) { self.command_queue.push(WindowCommand::Close); } - #[inline] pub fn drain_commands(&mut self) -> impl Iterator + '_ { self.command_queue.drain(..) } - + /// Get whether or not the window has focus. + /// + /// A window loses focus when the user switches to another window, and regains focus when the user uses the window again #[inline] pub fn is_focused(&self) -> bool { self.focused } - + /// Get the [`RawWindowHandleWrapper`] corresponding to this window pub fn raw_window_handle(&self) -> RawWindowHandleWrapper { self.raw_window_handle.clone() } - /// The "html canvas" element selector. If set, this selector will be used to find a matching html canvas element, + /// The "html canvas" element selector. + /// + /// If set, this selector will be used to find a matching html canvas element, /// rather than creating a new one. /// Uses the [CSS selector format](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector). /// @@ -635,27 +725,36 @@ impl Window { #[derive(Debug, Clone)] pub struct WindowDescriptor { /// The requested logical width of the window's client area. + /// /// May vary from the physical width due to different pixel density on different monitors. pub width: f32, /// The requested logical height of the window's client area. + /// /// May vary from the physical height due to different pixel density on different monitors. pub height: f32, /// The position on the screen that the window will be centered at. + /// /// If set to `None`, some platform-specific position will be chosen. pub position: Option, /// Sets minimum and maximum resize limits. pub resize_constraints: WindowResizeConstraints, /// Overrides the window's ratio of physical pixels to logical pixels. + /// /// If there are some scaling problems on X11 try to set this option to `Some(1.0)`. pub scale_factor_override: Option, /// Sets the title that displays on the window top bar, on the system task bar and other OS specific places. + /// /// ## Platform-specific /// - Web: Unsupported. pub title: String, /// Controls when a frame is presented to the screen. #[doc(alias = "vsync")] + /// The window's [`PresentMode`]. + /// + /// Used to select whether or not VSync is used pub present_mode: PresentMode, /// Sets whether the window is resizable. + /// /// ## Platform-specific /// - iOS / Android / Web: Unsupported. pub resizable: bool, @@ -668,6 +767,7 @@ pub struct WindowDescriptor { /// Sets the [`WindowMode`](crate::WindowMode). pub mode: WindowMode, /// Sets whether the background of the window should be transparent. + /// /// ## Platform-specific /// - iOS / Android / Web: Unsupported. /// - macOS X: Not working as expected. @@ -675,7 +775,9 @@ pub struct WindowDescriptor { /// macOS X transparent works with winit out of the box, so this issue might be related to: /// Windows 11 is related to pub transparent: bool, - /// The "html canvas" element selector. If set, this selector will be used to find a matching html canvas element, + /// The "html canvas" element selector. + /// + /// If set, this selector will be used to find a matching html canvas element, /// rather than creating a new one. /// Uses the [CSS selector format](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector). /// diff --git a/crates/bevy_window/src/windows.rs b/crates/bevy_window/src/windows.rs index df20688018133..608009b7b2c52 100644 --- a/crates/bevy_window/src/windows.rs +++ b/crates/bevy_window/src/windows.rs @@ -13,7 +13,7 @@ impl Windows { self.windows.insert(window.id(), window); } - /// Get a reference to the [`Window`] of `id` + /// Get a reference to the [`Window`] of `id`. pub fn get(&self, id: WindowId) -> Option<&Window> { self.windows.get(&id) } @@ -32,7 +32,7 @@ impl Windows { /// /// # Panics /// - /// Panics if the primary window does not exist in [`Windows`] + /// Panics if the primary window does not exist in [`Windows`]. pub fn primary(&self) -> &Window { self.get_primary().expect("Primary window does not exist") } @@ -46,7 +46,7 @@ impl Windows { /// /// # Panics /// - /// Panics if the primary window does not exist in [`Windows`] + /// Panics if the primary window does not exist in [`Windows`]. pub fn primary_mut(&mut self) -> &mut Window { self.get_primary_mut() .expect("Primary window does not exist") @@ -61,12 +61,12 @@ impl Windows { } } - /// An iterator over all registered [`Window`]s + /// An iterator over all registered [`Window`]s. pub fn iter(&self) -> impl Iterator { self.windows.values() } - /// A mutable iterator over all registered [`Window`]s + /// A mutable iterator over all registered [`Window`]s. pub fn iter_mut(&mut self) -> impl Iterator { self.windows.values_mut() }