Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - Add option to center a window #4999

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/bevy_window/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ pub use windows::*;
pub mod prelude {
#[doc(hidden)]
pub use crate::{
CursorEntered, CursorIcon, CursorLeft, CursorMoved, FileDragAndDrop, ReceivedCharacter,
Window, WindowDescriptor, WindowMoved, Windows,
CursorEntered, CursorIcon, CursorLeft, CursorMoved, FileDragAndDrop, MonitorSelection,
ReceivedCharacter, Window, WindowDescriptor, WindowMoved, WindowPosition, Windows,
};
}

Expand Down
47 changes: 42 additions & 5 deletions crates/bevy_window/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,8 @@ pub enum WindowCommand {
SetPosition {
position: IVec2,
},
/// Modifies the position of the window to be in the center of the current monitor
Center(MonitorSelection),
/// Set the window's [`WindowResizeConstraints`]
SetResizeConstraints {
resize_constraints: WindowResizeConstraints,
Expand Down Expand Up @@ -416,6 +418,17 @@ 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, monitor_selection: MonitorSelection) {
self.command_queue
.push(WindowCommand::Center(monitor_selection));
}

/// Modifies the minimum and maximum window bounds for resizing in logical pixels.
#[inline]
pub fn set_resize_constraints(&mut self, resize_constraints: WindowResizeConstraints) {
Expand Down Expand Up @@ -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),
LoipesMas marked this conversation as resolved.
Show resolved Hide resolved
}

/// 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.
///
/// This should be set up before adding the [`WindowPlugin`](crate::WindowPlugin).
Expand All @@ -732,10 +771,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<Vec2>,
/// The position on the screen that the window will be placed at.
pub position: WindowPosition,
/// Sets minimum and maximum resize limits.
pub resize_constraints: WindowResizeConstraints,
/// Overrides the window's ratio of physical pixels to logical pixels.
Expand Down Expand Up @@ -799,7 +836,7 @@ impl Default for WindowDescriptor {
title: "app".to_string(),
width: 1280.,
height: 720.,
position: None,
position: WindowPosition::Automatic,
resize_constraints: WindowResizeConstraints::default(),
scale_factor_override: None,
present_mode: PresentMode::Fifo,
Expand Down
25 changes: 25 additions & 0 deletions crates/bevy_winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,31 @@ fn change_window(
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 } => {
let window = winit_windows.get_window(id).unwrap();
let constraints = resize_constraints.check_constraints();
Expand Down
75 changes: 53 additions & 22 deletions crates/bevy_winit/src/winit_windows.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use bevy_math::IVec2;
use bevy_utils::HashMap;
use bevy_utils::{tracing::warn, 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 {
Expand Down Expand Up @@ -49,30 +49,61 @@ 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::<f64>(*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 {
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 {
winit_window_builder = winit_window_builder.with_position(
LogicalPosition::new(position[0] as f64, position[1] as f64)
.to_physical::<f64>(*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::<f64>(*sf),
)
} else {
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)
Expand Down