diff --git a/crates/bevy_window/src/lib.rs b/crates/bevy_window/src/lib.rs index 6e5b2abd876808..587f6cb9616167 100644 --- a/crates/bevy_window/src/lib.rs +++ b/crates/bevy_window/src/lib.rs @@ -16,7 +16,7 @@ pub mod prelude { #[doc(hidden)] pub use crate::{ CursorEntered, CursorIcon, CursorLeft, CursorMoved, FileDragAndDrop, ReceivedCharacter, - Window, WindowDescriptor, WindowMoved, Windows, + Window, WindowDescriptor, WindowMoved, WindowPosition, Windows, }; } diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index 19aa6cbbb8267b..cded21722861f4 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -216,6 +216,7 @@ pub enum WindowCommand { SetPosition { position: IVec2, }, + Center, SetResizeConstraints { resize_constraints: WindowResizeConstraints, }, @@ -370,6 +371,16 @@ impl Window { .push(WindowCommand::SetPosition { position }); } + /// Modifies the position of the window to be in the center of the current monitor + /// + /// # Platform-specific + /// - iOS: Can only be called on the main thread. + /// - Web / Android / Wayland: Unsupported. + #[inline] + pub fn center_window(&mut self) { + self.command_queue.push(WindowCommand::Center); + } + /// Modifies the minimum and maximum window bounds for resizing in logical pixels. #[inline] pub fn set_resize_constraints(&mut self, resize_constraints: WindowResizeConstraints) { @@ -624,6 +635,17 @@ impl Window { } } +/// Defines where window should be placed at creation. +#[derive(Debug, Clone)] +pub enum WindowPosition { + /// Position will be set by window manager + Default, + /// Window will be centered at primary monitor + Centered, + /// Window will be placed at + At(Vec2), +} + /// Describes the information needed for creating a window. /// /// This should be set up before adding the [`WindowPlugin`](crate::WindowPlugin). @@ -641,8 +663,8 @@ pub struct WindowDescriptor { /// 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, + /// See [`WindowPosition`] for available values. + pub position: WindowPosition, /// Sets minimum and maximum resize limits. pub resize_constraints: WindowResizeConstraints, /// Overrides the window's ratio of physical pixels to logical pixels. @@ -697,7 +719,7 @@ impl Default for WindowDescriptor { title: "app".to_string(), width: 1280., height: 720., - position: None, + position: WindowPosition::Default, resize_constraints: WindowResizeConstraints::default(), scale_factor_override: None, present_mode: PresentMode::Fifo, diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index 88e3f81126beae..04475ff58465e8 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -158,6 +158,21 @@ fn change_window( y: position[1], }); } + bevy_window::WindowCommand::Center => { + let window = winit_windows.get_window(id).unwrap(); + + // What to do if current_monitor is None? + // Abort? + // Or use primary_monitor? And then what if that also is None? + let screen_size = window.current_monitor().unwrap().size(); + + let window_size = window.outer_size(); + + window.set_outer_position(PhysicalPosition { + x: (screen_size.width - window_size.width) as f64 / 2., + y: (screen_size.height - window_size.height) as f64 / 2., + }); + } bevy_window::WindowCommand::SetResizeConstraints { resize_constraints } => { let window = winit_windows.get_window(id).unwrap(); let constraints = resize_constraints.check_constraints(); diff --git a/crates/bevy_winit/src/winit_windows.rs b/crates/bevy_winit/src/winit_windows.rs index e5565092701b79..c193463836a27f 100644 --- a/crates/bevy_winit/src/winit_windows.rs +++ b/crates/bevy_winit/src/winit_windows.rs @@ -2,7 +2,7 @@ use bevy_math::IVec2; use bevy_utils::HashMap; use bevy_window::{Window, WindowDescriptor, WindowId, WindowMode}; use raw_window_handle::HasRawWindowHandle; -use winit::dpi::LogicalSize; +use winit::dpi::{LogicalPosition, LogicalSize, PhysicalPosition}; #[derive(Debug, Default)] pub struct WinitWindows { @@ -49,30 +49,47 @@ impl WinitWindows { .. } = window_descriptor; - if let Some(position) = position { - if let Some(sf) = scale_factor_override { - winit_window_builder = winit_window_builder.with_position( - winit::dpi::LogicalPosition::new( - position[0] as f64, - position[1] as f64, - ) - .to_physical::(*sf), - ); - } else { - winit_window_builder = - winit_window_builder.with_position(winit::dpi::LogicalPosition::new( - position[0] as f64, - position[1] as f64, - )); + use bevy_window::WindowPosition::*; + match position { + Default => { /* Window manager will handle position*/ } + Centered => { + if let Some(monitor) = event_loop.primary_monitor() { + let screen_size = monitor.size(); + + let scale_factor = scale_factor_override.unwrap_or(1.0); + + // Logical to physical window size + let (width, height): (f64, f64) = LogicalSize::new(*width, *height) + .to_physical::(scale_factor) + .into(); + + let position = PhysicalPosition::new( + (screen_size.width as f64 - width) / 2., + (screen_size.height as f64 - height) / 2., + ); + + winit_window_builder = winit_window_builder.with_position(position); + } + } + At(position) => { + if let Some(sf) = scale_factor_override { + winit_window_builder = winit_window_builder.with_position( + LogicalPosition::new(position[0] as f64, position[1] as f64) + .to_physical::(*sf), + ); + } else { + winit_window_builder = winit_window_builder.with_position( + LogicalPosition::new(position[0] as f64, position[1] as f64), + ); + } } } + if let Some(sf) = scale_factor_override { - winit_window_builder.with_inner_size( - winit::dpi::LogicalSize::new(*width, *height).to_physical::(*sf), - ) - } else { winit_window_builder - .with_inner_size(winit::dpi::LogicalSize::new(*width, *height)) + .with_inner_size(LogicalSize::new(*width, *height).to_physical::(*sf)) + } else { + winit_window_builder.with_inner_size(LogicalSize::new(*width, *height)) } } .with_resizable(window_descriptor.resizable)