mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 12:43:34 +00:00
Add docs and common helper functions to Windows
(#4107)
# Objective - Improve documentation. - Provide helper functions for common uses of `Windows` relating to getting the primary `Window`. - Reduce repeated `Window` code. # Solution - Adds infallible `primary()` and `primary_mut()` functions with standard error text. This replaces the commonly used `get_primary().unwrap()` seen throughout bevy which has inconsistent or nonexistent error messages. - Adds `scale_factor(WindowId)` to replace repeated code blocks throughout. # Considerations - The added functions can panic if the primary window does not exist. - It is very uncommon for the primary window to not exist, as seen by the regular use of `get_primary().unwrap()`. Most users will have a single window and will need to reference the primary window in their code multiple times. - The panic provides a consistent error message to make this class of error easy to spot from the panic text. - This follows the established standard of short names for infallible-but-unlikely-to-panic functions in bevy. - Removes line noise for common usage of `Windows`.
This commit is contained in:
parent
e36c9b6cf0
commit
b3aff9a7b1
12 changed files with 55 additions and 39 deletions
|
@ -9,7 +9,7 @@ use bevy_math::{Size, Vec3};
|
||||||
use bevy_render::{texture::Image, view::Visibility, RenderWorld};
|
use bevy_render::{texture::Image, view::Visibility, RenderWorld};
|
||||||
use bevy_sprite::{ExtractedSprite, ExtractedSprites, TextureAtlas};
|
use bevy_sprite::{ExtractedSprite, ExtractedSprites, TextureAtlas};
|
||||||
use bevy_transform::prelude::{GlobalTransform, Transform};
|
use bevy_transform::prelude::{GlobalTransform, Transform};
|
||||||
use bevy_window::Windows;
|
use bevy_window::{WindowId, Windows};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
DefaultTextPipeline, Font, FontAtlasSet, HorizontalAlign, Text, Text2dSize, TextError,
|
DefaultTextPipeline, Font, FontAtlasSet, HorizontalAlign, Text, Text2dSize, TextError,
|
||||||
|
@ -50,11 +50,7 @@ pub fn extract_text2d_sprite(
|
||||||
) {
|
) {
|
||||||
let mut extracted_sprites = render_world.resource_mut::<ExtractedSprites>();
|
let mut extracted_sprites = render_world.resource_mut::<ExtractedSprites>();
|
||||||
|
|
||||||
let scale_factor = if let Some(window) = windows.get_primary() {
|
let scale_factor = windows.scale_factor(WindowId::primary()) as f32;
|
||||||
window.scale_factor() as f32
|
|
||||||
} else {
|
|
||||||
1.
|
|
||||||
};
|
|
||||||
|
|
||||||
for (entity, visibility, text, transform, calculated_size) in text2d_query.iter() {
|
for (entity, visibility, text, transform, calculated_size) in text2d_query.iter() {
|
||||||
if !visibility.is_visible {
|
if !visibility.is_visible {
|
||||||
|
@ -139,11 +135,7 @@ pub fn text2d_system(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let scale_factor = if let Some(window) = windows.get_primary() {
|
let scale_factor = windows.scale_factor(WindowId::primary());
|
||||||
window.scale_factor()
|
|
||||||
} else {
|
|
||||||
1.
|
|
||||||
};
|
|
||||||
|
|
||||||
// Computes all text in the local queue
|
// Computes all text in the local queue
|
||||||
let mut new_queue = Vec::new();
|
let mut new_queue = Vec::new();
|
||||||
|
|
|
@ -218,11 +218,7 @@ pub fn flex_node_system(
|
||||||
}
|
}
|
||||||
|
|
||||||
// assume one window for time being...
|
// assume one window for time being...
|
||||||
let logical_to_physical_factor = if let Some(primary_window) = windows.get_primary() {
|
let logical_to_physical_factor = windows.scale_factor(WindowId::primary());
|
||||||
primary_window.scale_factor()
|
|
||||||
} else {
|
|
||||||
1.
|
|
||||||
};
|
|
||||||
|
|
||||||
if scale_factor_events.iter().next_back().is_some() {
|
if scale_factor_events.iter().next_back().is_some() {
|
||||||
update_changed(
|
update_changed(
|
||||||
|
|
|
@ -30,7 +30,7 @@ use bevy_sprite::{Rect, SpriteAssetEvents, TextureAtlas};
|
||||||
use bevy_text::{DefaultTextPipeline, Text};
|
use bevy_text::{DefaultTextPipeline, Text};
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::components::GlobalTransform;
|
||||||
use bevy_utils::HashMap;
|
use bevy_utils::HashMap;
|
||||||
use bevy_window::Windows;
|
use bevy_window::{WindowId, Windows};
|
||||||
|
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
|
||||||
|
@ -186,11 +186,7 @@ pub fn extract_text_uinodes(
|
||||||
) {
|
) {
|
||||||
let mut extracted_uinodes = render_world.resource_mut::<ExtractedUiNodes>();
|
let mut extracted_uinodes = render_world.resource_mut::<ExtractedUiNodes>();
|
||||||
|
|
||||||
let scale_factor = if let Some(window) = windows.get_primary() {
|
let scale_factor = windows.scale_factor(WindowId::primary()) as f32;
|
||||||
window.scale_factor() as f32
|
|
||||||
} else {
|
|
||||||
1.
|
|
||||||
};
|
|
||||||
|
|
||||||
for (entity, uinode, transform, text, visibility, clip) in uinode_query.iter() {
|
for (entity, uinode, transform, text, visibility, clip) in uinode_query.iter() {
|
||||||
if !visibility.is_visible {
|
if !visibility.is_visible {
|
||||||
|
|
|
@ -10,7 +10,7 @@ use bevy_math::Size;
|
||||||
use bevy_render::texture::Image;
|
use bevy_render::texture::Image;
|
||||||
use bevy_sprite::TextureAtlas;
|
use bevy_sprite::TextureAtlas;
|
||||||
use bevy_text::{DefaultTextPipeline, Font, FontAtlasSet, Text, TextError};
|
use bevy_text::{DefaultTextPipeline, Font, FontAtlasSet, Text, TextError};
|
||||||
use bevy_window::Windows;
|
use bevy_window::{WindowId, Windows};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct QueuedText {
|
pub struct QueuedText {
|
||||||
|
@ -52,11 +52,7 @@ pub fn text_system(
|
||||||
QueryState<(&Text, &Style, &mut CalculatedSize)>,
|
QueryState<(&Text, &Style, &mut CalculatedSize)>,
|
||||||
)>,
|
)>,
|
||||||
) {
|
) {
|
||||||
let scale_factor = if let Some(window) = windows.get_primary() {
|
let scale_factor = windows.scale_factor(WindowId::primary());
|
||||||
window.scale_factor()
|
|
||||||
} else {
|
|
||||||
1.
|
|
||||||
};
|
|
||||||
|
|
||||||
let inv_scale_factor = 1. / scale_factor;
|
let inv_scale_factor = 1. / scale_factor;
|
||||||
|
|
||||||
|
|
|
@ -1,36 +1,72 @@
|
||||||
use super::{Window, WindowId};
|
use super::{Window, WindowId};
|
||||||
use bevy_utils::HashMap;
|
use bevy_utils::HashMap;
|
||||||
|
|
||||||
|
/// A collection of [`Window`]s with unique [`WindowId`]s.
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Windows {
|
pub struct Windows {
|
||||||
windows: HashMap<WindowId, Window>,
|
windows: HashMap<WindowId, Window>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Windows {
|
impl Windows {
|
||||||
|
/// Add the provided [`Window`] to the [`Windows`] resource.
|
||||||
pub fn add(&mut self, window: Window) {
|
pub fn add(&mut self, window: Window) {
|
||||||
self.windows.insert(window.id(), window);
|
self.windows.insert(window.id(), window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a reference to the [`Window`] of `id`
|
||||||
pub fn get(&self, id: WindowId) -> Option<&Window> {
|
pub fn get(&self, id: WindowId) -> Option<&Window> {
|
||||||
self.windows.get(&id)
|
self.windows.get(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a mutable reference to the provided [`WindowId`].
|
||||||
pub fn get_mut(&mut self, id: WindowId) -> Option<&mut Window> {
|
pub fn get_mut(&mut self, id: WindowId) -> Option<&mut Window> {
|
||||||
self.windows.get_mut(&id)
|
self.windows.get_mut(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a reference to the primary [`Window`].
|
||||||
pub fn get_primary(&self) -> Option<&Window> {
|
pub fn get_primary(&self) -> Option<&Window> {
|
||||||
self.get(WindowId::primary())
|
self.get(WindowId::primary())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a reference to the primary [`Window`].
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the primary window does not exist in [`Windows`]
|
||||||
|
pub fn primary(&self) -> &Window {
|
||||||
|
self.get_primary().expect("Primary window does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a mutable reference to the primary [`Window`].
|
||||||
pub fn get_primary_mut(&mut self) -> Option<&mut Window> {
|
pub fn get_primary_mut(&mut self) -> Option<&mut Window> {
|
||||||
self.get_mut(WindowId::primary())
|
self.get_mut(WindowId::primary())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a mutable reference to the primary [`Window`].
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// 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")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the scale factor for the [`Window`] of `id`, or `1.0` if the window does not exist.
|
||||||
|
pub fn scale_factor(&self, id: WindowId) -> f64 {
|
||||||
|
if let Some(window) = self.get(id) {
|
||||||
|
window.scale_factor()
|
||||||
|
} else {
|
||||||
|
1.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An iterator over all registered [`Window`]s
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &Window> {
|
pub fn iter(&self) -> impl Iterator<Item = &Window> {
|
||||||
self.windows.values()
|
self.windows.values()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A mutable iterator over all registered [`Window`]s
|
||||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Window> {
|
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Window> {
|
||||||
self.windows.values_mut()
|
self.windows.values_mut()
|
||||||
}
|
}
|
||||||
|
|
|
@ -412,7 +412,7 @@ pub fn winit_runner_with(mut app: App) {
|
||||||
// On a mobile window, the start is from the top while on PC/Linux/OSX from
|
// On a mobile window, the start is from the top while on PC/Linux/OSX from
|
||||||
// bottom
|
// bottom
|
||||||
if cfg!(target_os = "android") || cfg!(target_os = "ios") {
|
if cfg!(target_os = "android") || cfg!(target_os = "ios") {
|
||||||
let window_height = windows.get_primary().unwrap().height();
|
let window_height = windows.primary().height();
|
||||||
location.y = window_height - location.y;
|
location.y = window_height - location.y;
|
||||||
}
|
}
|
||||||
touch_input_events.send(converters::convert_touch_input(touch, location));
|
touch_input_events.send(converters::convert_touch_input(touch, location));
|
||||||
|
|
|
@ -245,7 +245,7 @@ fn collision_system(
|
||||||
) {
|
) {
|
||||||
let mut rnd = rand::thread_rng();
|
let mut rnd = rand::thread_rng();
|
||||||
|
|
||||||
let window = windows.get_primary().unwrap();
|
let window = windows.primary();
|
||||||
|
|
||||||
let ceiling = window.height() / 2.;
|
let ceiling = window.height() / 2.;
|
||||||
let ground = -(window.height() / 2.);
|
let ground = -(window.height() / 2.);
|
||||||
|
|
|
@ -41,7 +41,7 @@ fn bounce_system(
|
||||||
windows: Res<Windows>,
|
windows: Res<Windows>,
|
||||||
mut sprites: Query<(&Transform, &mut Velocity)>,
|
mut sprites: Query<(&Transform, &mut Velocity)>,
|
||||||
) {
|
) {
|
||||||
let window = windows.get_primary().expect("No primary window.");
|
let window = windows.primary();
|
||||||
let width = window.width();
|
let width = window.width();
|
||||||
let height = window.height();
|
let height = window.height();
|
||||||
let left = width / -2.0;
|
let left = width / -2.0;
|
||||||
|
|
|
@ -28,7 +28,7 @@ fn touch_camera(
|
||||||
*last_position = None;
|
*last_position = None;
|
||||||
}
|
}
|
||||||
if let Some(last_position) = *last_position {
|
if let Some(last_position) = *last_position {
|
||||||
let window = windows.get_primary().unwrap();
|
let window = windows.primary();
|
||||||
let mut transform = camera.single_mut();
|
let mut transform = camera.single_mut();
|
||||||
*transform = Transform::from_xyz(
|
*transform = Transform::from_xyz(
|
||||||
transform.translation.x
|
transform.translation.x
|
||||||
|
|
|
@ -189,7 +189,7 @@ fn spawn_birds(
|
||||||
spawn_count: usize,
|
spawn_count: usize,
|
||||||
texture: Handle<Image>,
|
texture: Handle<Image>,
|
||||||
) {
|
) {
|
||||||
let window = windows.get_primary().unwrap();
|
let window = windows.primary();
|
||||||
let bird_x = (window.width() as f32 / -2.) + HALF_BIRD_SIZE;
|
let bird_x = (window.width() as f32 / -2.) + HALF_BIRD_SIZE;
|
||||||
let bird_y = (window.height() as f32 / 2.) - HALF_BIRD_SIZE;
|
let bird_y = (window.height() as f32 / 2.) - HALF_BIRD_SIZE;
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
|
@ -230,7 +230,7 @@ fn movement_system(time: Res<Time>, mut bird_query: Query<(&mut Bird, &mut Trans
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collision_system(windows: Res<Windows>, mut bird_query: Query<(&mut Bird, &Transform)>) {
|
fn collision_system(windows: Res<Windows>, mut bird_query: Query<(&mut Bird, &Transform)>) {
|
||||||
let window = windows.get_primary().unwrap();
|
let window = windows.primary();
|
||||||
let half_width = window.width() as f32 * 0.5;
|
let half_width = window.width() as f32 * 0.5;
|
||||||
let half_height = window.height() as f32 * 0.5;
|
let half_height = window.height() as f32 * 0.5;
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
|
|
||||||
/// This system toggles scale factor overrides when enter is pressed
|
/// This system toggles scale factor overrides when enter is pressed
|
||||||
fn toggle_override(input: Res<Input<KeyCode>>, mut windows: ResMut<Windows>) {
|
fn toggle_override(input: Res<Input<KeyCode>>, mut windows: ResMut<Windows>) {
|
||||||
let window = windows.get_primary_mut().unwrap();
|
let window = windows.primary_mut();
|
||||||
if input.just_pressed(KeyCode::Return) {
|
if input.just_pressed(KeyCode::Return) {
|
||||||
window.set_scale_factor_override(window.scale_factor_override().xor(Some(1.)));
|
window.set_scale_factor_override(window.scale_factor_override().xor(Some(1.)));
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ fn toggle_override(input: Res<Input<KeyCode>>, mut windows: ResMut<Windows>) {
|
||||||
|
|
||||||
/// This system changes the scale factor override when up or down is pressed
|
/// This system changes the scale factor override when up or down is pressed
|
||||||
fn change_scale_factor(input: Res<Input<KeyCode>>, mut windows: ResMut<Windows>) {
|
fn change_scale_factor(input: Res<Input<KeyCode>>, mut windows: ResMut<Windows>) {
|
||||||
let window = windows.get_primary_mut().unwrap();
|
let window = windows.primary_mut();
|
||||||
if input.just_pressed(KeyCode::Up) {
|
if input.just_pressed(KeyCode::Up) {
|
||||||
window.set_scale_factor_override(window.scale_factor_override().map(|n| n + 1.));
|
window.set_scale_factor_override(window.scale_factor_override().map(|n| n + 1.));
|
||||||
} else if input.just_pressed(KeyCode::Down) {
|
} else if input.just_pressed(KeyCode::Down) {
|
||||||
|
|
|
@ -19,7 +19,7 @@ fn main() {
|
||||||
|
|
||||||
/// This system will then change the title during execution
|
/// This system will then change the title during execution
|
||||||
fn change_title(time: Res<Time>, mut windows: ResMut<Windows>) {
|
fn change_title(time: Res<Time>, mut windows: ResMut<Windows>) {
|
||||||
let window = windows.get_primary_mut().unwrap();
|
let window = windows.primary_mut();
|
||||||
window.set_title(format!(
|
window.set_title(format!(
|
||||||
"Seconds since startup: {}",
|
"Seconds since startup: {}",
|
||||||
time.seconds_since_startup().round()
|
time.seconds_since_startup().round()
|
||||||
|
@ -28,7 +28,7 @@ fn change_title(time: Res<Time>, mut windows: ResMut<Windows>) {
|
||||||
|
|
||||||
/// This system toggles the cursor's visibility when the space bar is pressed
|
/// This system toggles the cursor's visibility when the space bar is pressed
|
||||||
fn toggle_cursor(input: Res<Input<KeyCode>>, mut windows: ResMut<Windows>) {
|
fn toggle_cursor(input: Res<Input<KeyCode>>, mut windows: ResMut<Windows>) {
|
||||||
let window = windows.get_primary_mut().unwrap();
|
let window = windows.primary_mut();
|
||||||
if input.just_pressed(KeyCode::Space) {
|
if input.just_pressed(KeyCode::Space) {
|
||||||
window.set_cursor_lock_mode(!window.cursor_locked());
|
window.set_cursor_lock_mode(!window.cursor_locked());
|
||||||
window.set_cursor_visibility(!window.cursor_visible());
|
window.set_cursor_visibility(!window.cursor_visible());
|
||||||
|
@ -48,7 +48,7 @@ fn cycle_cursor_icon(
|
||||||
CursorIcon::Text,
|
CursorIcon::Text,
|
||||||
CursorIcon::Copy,
|
CursorIcon::Copy,
|
||||||
];
|
];
|
||||||
let window = windows.get_primary_mut().unwrap();
|
let window = windows.primary_mut();
|
||||||
if input.just_pressed(MouseButton::Left) {
|
if input.just_pressed(MouseButton::Left) {
|
||||||
*index = (*index + 1) % ICONS.len();
|
*index = (*index + 1) % ICONS.len();
|
||||||
window.set_cursor_icon(ICONS[*index]);
|
window.set_cursor_icon(ICONS[*index]);
|
||||||
|
|
Loading…
Reference in a new issue