mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Add option to center a window (#4999)
# Objective - Fixes #4993 ## Solution - ~~Add `centered` property to `WindowDescriptor`~~ - Add `WindowPosition` enum - `WindowDescriptor.position` is now `WindowPosition` instead of `Option<Vec2>` - Add `center_window` function to `Window` ## Migration Guide - If using `WindowDescriptor`, replace `position: None` with `position: WindowPosition::Default` and `position: Some(vec2)` with `WindowPosition::At(vec2)`. I'm not sure if this is the best approach, so feel free to give any feedback. Also I'm not sure how `Option`s should be handled in `bevy_winit/src/lib.rs:161`. Also, on window creation we can't (or at least I couldn't) get `outer_size`, so this doesn't include decorations in calculations.
This commit is contained in:
parent
c0f807ce38
commit
49da4e741d
4 changed files with 122 additions and 29 deletions
|
@ -16,8 +16,8 @@ pub use windows::*;
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
CursorEntered, CursorIcon, CursorLeft, CursorMoved, FileDragAndDrop, ReceivedCharacter,
|
CursorEntered, CursorIcon, CursorLeft, CursorMoved, FileDragAndDrop, MonitorSelection,
|
||||||
Window, WindowDescriptor, WindowMoved, Windows,
|
ReceivedCharacter, Window, WindowDescriptor, WindowMoved, WindowPosition, Windows,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -259,6 +259,8 @@ pub enum WindowCommand {
|
||||||
SetPosition {
|
SetPosition {
|
||||||
position: IVec2,
|
position: IVec2,
|
||||||
},
|
},
|
||||||
|
/// Modifies the position of the window to be in the center of the current monitor
|
||||||
|
Center(MonitorSelection),
|
||||||
/// Set the window's [`WindowResizeConstraints`]
|
/// Set the window's [`WindowResizeConstraints`]
|
||||||
SetResizeConstraints {
|
SetResizeConstraints {
|
||||||
resize_constraints: WindowResizeConstraints,
|
resize_constraints: WindowResizeConstraints,
|
||||||
|
@ -416,6 +418,17 @@ impl Window {
|
||||||
.push(WindowCommand::SetPosition { position });
|
.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, monitor_selection: MonitorSelection) {
|
||||||
|
self.command_queue
|
||||||
|
.push(WindowCommand::Center(monitor_selection));
|
||||||
|
}
|
||||||
|
|
||||||
/// Modifies the minimum and maximum window bounds for resizing in logical pixels.
|
/// Modifies the minimum and maximum window bounds for resizing in logical pixels.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_resize_constraints(&mut self, resize_constraints: WindowResizeConstraints) {
|
pub fn set_resize_constraints(&mut self, resize_constraints: WindowResizeConstraints) {
|
||||||
|
@ -714,6 +727,32 @@ impl Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines where window should be placed at on creation.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum WindowPosition {
|
||||||
|
/// Position will be set by the window manager
|
||||||
|
Automatic,
|
||||||
|
/// Window will be centered on the selected monitor
|
||||||
|
///
|
||||||
|
/// Note that this does not account for window decorations.
|
||||||
|
Centered(MonitorSelection),
|
||||||
|
/// The window's top-left corner will be placed at the specified position (in pixels)
|
||||||
|
///
|
||||||
|
/// (0,0) represents top-left corner of screen space.
|
||||||
|
At(Vec2),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Defines which monitor to use.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum MonitorSelection {
|
||||||
|
/// Uses current monitor of the window.
|
||||||
|
Current,
|
||||||
|
/// Uses primary monitor of the system.
|
||||||
|
Primary,
|
||||||
|
/// Uses monitor with the specified index.
|
||||||
|
Number(usize),
|
||||||
|
}
|
||||||
|
|
||||||
/// Describes the information needed for creating a window.
|
/// Describes the information needed for creating a window.
|
||||||
///
|
///
|
||||||
/// This should be set up before adding the [`WindowPlugin`](crate::WindowPlugin).
|
/// This should be set up before adding the [`WindowPlugin`](crate::WindowPlugin).
|
||||||
|
@ -732,10 +771,8 @@ pub struct WindowDescriptor {
|
||||||
///
|
///
|
||||||
/// May vary from the physical height due to different pixel density on different monitors.
|
/// May vary from the physical height due to different pixel density on different monitors.
|
||||||
pub height: f32,
|
pub height: f32,
|
||||||
/// The position on the screen that the window will be centered at.
|
/// The position on the screen that the window will be placed at.
|
||||||
///
|
pub position: WindowPosition,
|
||||||
/// If set to `None`, some platform-specific position will be chosen.
|
|
||||||
pub position: Option<Vec2>,
|
|
||||||
/// Sets minimum and maximum resize limits.
|
/// Sets minimum and maximum resize limits.
|
||||||
pub resize_constraints: WindowResizeConstraints,
|
pub resize_constraints: WindowResizeConstraints,
|
||||||
/// Overrides the window's ratio of physical pixels to logical pixels.
|
/// Overrides the window's ratio of physical pixels to logical pixels.
|
||||||
|
@ -799,7 +836,7 @@ impl Default for WindowDescriptor {
|
||||||
title: "app".to_string(),
|
title: "app".to_string(),
|
||||||
width: 1280.,
|
width: 1280.,
|
||||||
height: 720.,
|
height: 720.,
|
||||||
position: None,
|
position: WindowPosition::Automatic,
|
||||||
resize_constraints: WindowResizeConstraints::default(),
|
resize_constraints: WindowResizeConstraints::default(),
|
||||||
scale_factor_override: None,
|
scale_factor_override: None,
|
||||||
present_mode: PresentMode::Fifo,
|
present_mode: PresentMode::Fifo,
|
||||||
|
|
|
@ -162,6 +162,31 @@ fn change_window(
|
||||||
y: position[1],
|
y: position[1],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
bevy_window::WindowCommand::Center(monitor_selection) => {
|
||||||
|
let window = winit_windows.get_window(id).unwrap();
|
||||||
|
|
||||||
|
use bevy_window::MonitorSelection::*;
|
||||||
|
let maybe_monitor = match monitor_selection {
|
||||||
|
Current => window.current_monitor(),
|
||||||
|
Primary => window.primary_monitor(),
|
||||||
|
Number(n) => window.available_monitors().nth(n),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(monitor) = maybe_monitor {
|
||||||
|
let screen_size = monitor.size();
|
||||||
|
|
||||||
|
let window_size = window.outer_size();
|
||||||
|
|
||||||
|
window.set_outer_position(PhysicalPosition {
|
||||||
|
x: screen_size.width.saturating_sub(window_size.width) as f64 / 2.
|
||||||
|
+ monitor.position().x as f64,
|
||||||
|
y: screen_size.height.saturating_sub(window_size.height) as f64 / 2.
|
||||||
|
+ monitor.position().y as f64,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
warn!("Couldn't get monitor selected with: {monitor_selection:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
bevy_window::WindowCommand::SetResizeConstraints { resize_constraints } => {
|
bevy_window::WindowCommand::SetResizeConstraints { resize_constraints } => {
|
||||||
let window = winit_windows.get_window(id).unwrap();
|
let window = winit_windows.get_window(id).unwrap();
|
||||||
let constraints = resize_constraints.check_constraints();
|
let constraints = resize_constraints.check_constraints();
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use bevy_math::IVec2;
|
use bevy_math::IVec2;
|
||||||
use bevy_utils::HashMap;
|
use bevy_utils::{tracing::warn, HashMap};
|
||||||
use bevy_window::{Window, WindowDescriptor, WindowId, WindowMode};
|
use bevy_window::{Window, WindowDescriptor, WindowId, WindowMode};
|
||||||
use raw_window_handle::HasRawWindowHandle;
|
use raw_window_handle::HasRawWindowHandle;
|
||||||
use winit::dpi::LogicalSize;
|
use winit::dpi::{LogicalPosition, LogicalSize, PhysicalPosition};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct WinitWindows {
|
pub struct WinitWindows {
|
||||||
|
@ -49,30 +49,61 @@ impl WinitWindows {
|
||||||
..
|
..
|
||||||
} = window_descriptor;
|
} = window_descriptor;
|
||||||
|
|
||||||
if let Some(position) = position {
|
use bevy_window::WindowPosition::*;
|
||||||
|
match position {
|
||||||
|
Automatic => { /* Window manager will handle position */ }
|
||||||
|
Centered(monitor_selection) => {
|
||||||
|
use bevy_window::MonitorSelection::*;
|
||||||
|
let maybe_monitor = match monitor_selection {
|
||||||
|
Current => {
|
||||||
|
warn!("Can't select current monitor on window creation!");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Primary => event_loop.primary_monitor(),
|
||||||
|
Number(n) => event_loop.available_monitors().nth(*n),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(monitor) = maybe_monitor {
|
||||||
|
let screen_size = monitor.size();
|
||||||
|
|
||||||
|
let scale_factor = scale_factor_override.unwrap_or(1.0);
|
||||||
|
|
||||||
|
// Logical to physical window size
|
||||||
|
let (width, height): (u32, u32) = LogicalSize::new(*width, *height)
|
||||||
|
.to_physical::<u32>(scale_factor)
|
||||||
|
.into();
|
||||||
|
|
||||||
|
let position = PhysicalPosition {
|
||||||
|
x: screen_size.width.saturating_sub(width) as f64 / 2.
|
||||||
|
+ monitor.position().x as f64,
|
||||||
|
y: screen_size.height.saturating_sub(height) as f64 / 2.
|
||||||
|
+ monitor.position().y as f64,
|
||||||
|
};
|
||||||
|
|
||||||
|
winit_window_builder = winit_window_builder.with_position(position);
|
||||||
|
} else {
|
||||||
|
warn!("Couldn't get monitor selected with: {monitor_selection:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
At(position) => {
|
||||||
if let Some(sf) = scale_factor_override {
|
if let Some(sf) = scale_factor_override {
|
||||||
winit_window_builder = winit_window_builder.with_position(
|
winit_window_builder = winit_window_builder.with_position(
|
||||||
winit::dpi::LogicalPosition::new(
|
LogicalPosition::new(position[0] as f64, position[1] as f64)
|
||||||
position[0] as f64,
|
|
||||||
position[1] as f64,
|
|
||||||
)
|
|
||||||
.to_physical::<f64>(*sf),
|
.to_physical::<f64>(*sf),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
winit_window_builder =
|
winit_window_builder = winit_window_builder.with_position(
|
||||||
winit_window_builder.with_position(winit::dpi::LogicalPosition::new(
|
LogicalPosition::new(position[0] as f64, position[1] as f64),
|
||||||
position[0] as f64,
|
);
|
||||||
position[1] as f64,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(sf) = scale_factor_override {
|
if let Some(sf) = scale_factor_override {
|
||||||
winit_window_builder.with_inner_size(
|
|
||||||
winit::dpi::LogicalSize::new(*width, *height).to_physical::<f64>(*sf),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
winit_window_builder
|
winit_window_builder
|
||||||
.with_inner_size(winit::dpi::LogicalSize::new(*width, *height))
|
.with_inner_size(LogicalSize::new(*width, *height).to_physical::<f64>(*sf))
|
||||||
|
} else {
|
||||||
|
winit_window_builder.with_inner_size(LogicalSize::new(*width, *height))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.with_resizable(window_descriptor.resizable)
|
.with_resizable(window_descriptor.resizable)
|
||||||
|
|
Loading…
Reference in a new issue