mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 04:33:37 +00:00
Added use_dpi setting to WindowDescriptor (#1131)
Added scale_factor_override
This commit is contained in:
parent
4825051c6a
commit
3cb2e22e89
9 changed files with 254 additions and 36 deletions
|
@ -346,6 +346,10 @@ path = "examples/window/clear_color.rs"
|
|||
name = "multiple_windows"
|
||||
path = "examples/window/multiple_windows.rs"
|
||||
|
||||
[[example]]
|
||||
name = "scale_factor_override"
|
||||
path = "examples/window/scale_factor_override.rs"
|
||||
|
||||
[[example]]
|
||||
name = "window_settings"
|
||||
path = "examples/window/window_settings.rs"
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
mod convert;
|
||||
|
||||
use crate::{Node, Style};
|
||||
use bevy_ecs::{Changed, Entity, Query, Res, ResMut, With, Without};
|
||||
use bevy_app::{EventReader, Events};
|
||||
use bevy_ecs::{Changed, Entity, Local, Query, QueryFilter, Res, ResMut, With, Without};
|
||||
use bevy_math::Vec2;
|
||||
use bevy_text::CalculatedSize;
|
||||
use bevy_transform::prelude::{Children, Parent, Transform};
|
||||
use bevy_utils::HashMap;
|
||||
use bevy_window::{Window, WindowId, Windows};
|
||||
use bevy_window::{Window, WindowId, WindowScaleFactorChanged, Windows};
|
||||
use std::fmt;
|
||||
use stretch::{number::Number, Stretch};
|
||||
|
||||
|
@ -161,11 +162,15 @@ impl FlexSurface {
|
|||
unsafe impl Send for FlexSurface {}
|
||||
unsafe impl Sync for FlexSurface {}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn flex_node_system(
|
||||
windows: Res<Windows>,
|
||||
mut scale_factor_reader: Local<EventReader<WindowScaleFactorChanged>>,
|
||||
scale_factor_events: Res<Events<WindowScaleFactorChanged>>,
|
||||
mut flex_surface: ResMut<FlexSurface>,
|
||||
root_node_query: Query<Entity, (With<Node>, Without<Parent>)>,
|
||||
node_query: Query<(Entity, &Style, Option<&CalculatedSize>), (With<Node>, Changed<Style>)>,
|
||||
full_node_query: Query<(Entity, &Style, Option<&CalculatedSize>), With<Node>>,
|
||||
changed_size_query: Query<
|
||||
(Entity, &Style, &CalculatedSize),
|
||||
(With<Node>, Changed<CalculatedSize>),
|
||||
|
@ -185,13 +190,31 @@ pub fn flex_node_system(
|
|||
1.
|
||||
};
|
||||
|
||||
if scale_factor_reader.latest(&scale_factor_events).is_some() {
|
||||
update_changed(
|
||||
&mut *flex_surface,
|
||||
logical_to_physical_factor,
|
||||
full_node_query,
|
||||
);
|
||||
} else {
|
||||
update_changed(&mut *flex_surface, logical_to_physical_factor, node_query);
|
||||
}
|
||||
|
||||
fn update_changed<F>(
|
||||
flex_surface: &mut FlexSurface,
|
||||
scaling_factor: f64,
|
||||
query: Query<(Entity, &Style, Option<&CalculatedSize>), F>,
|
||||
) where
|
||||
F: QueryFilter,
|
||||
{
|
||||
// update changed nodes
|
||||
for (entity, style, calculated_size) in node_query.iter() {
|
||||
for (entity, style, calculated_size) in query.iter() {
|
||||
// TODO: remove node from old hierarchy if its root has changed
|
||||
if let Some(calculated_size) = calculated_size {
|
||||
flex_surface.upsert_leaf(entity, &style, *calculated_size, logical_to_physical_factor);
|
||||
flex_surface.upsert_leaf(entity, &style, *calculated_size, scaling_factor);
|
||||
} else {
|
||||
flex_surface.upsert_node(entity, &style, logical_to_physical_factor);
|
||||
flex_surface.upsert_node(entity, &style, scaling_factor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -64,3 +64,16 @@ pub struct WindowFocused {
|
|||
pub id: WindowId,
|
||||
pub focused: bool,
|
||||
}
|
||||
|
||||
/// An event that indicates a window's scale factor has changed.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WindowScaleFactorChanged {
|
||||
pub id: WindowId,
|
||||
pub scale_factor: f64,
|
||||
}
|
||||
/// An event that indicates a window's OS-reported scale factor has changed.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WindowBackendScaleFactorChanged {
|
||||
pub id: WindowId,
|
||||
pub scale_factor: f64,
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@ impl Plugin for WindowPlugin {
|
|||
.add_event::<CursorLeft>()
|
||||
.add_event::<ReceivedCharacter>()
|
||||
.add_event::<WindowFocused>()
|
||||
.add_event::<WindowScaleFactorChanged>()
|
||||
.add_event::<WindowBackendScaleFactorChanged>()
|
||||
.init_resource::<Windows>();
|
||||
|
||||
if self.add_primary_window {
|
||||
|
|
|
@ -54,7 +54,8 @@ pub struct Window {
|
|||
requested_height: f32,
|
||||
physical_width: u32,
|
||||
physical_height: u32,
|
||||
scale_factor: f64,
|
||||
scale_factor_override: Option<f64>,
|
||||
backend_scale_factor: f64,
|
||||
title: String,
|
||||
vsync: bool,
|
||||
resizable: bool,
|
||||
|
@ -77,8 +78,12 @@ pub enum WindowCommand {
|
|||
SetTitle {
|
||||
title: String,
|
||||
},
|
||||
SetScaleFactor {
|
||||
scale_factor: f64,
|
||||
},
|
||||
SetResolution {
|
||||
resolution: (f32, f32),
|
||||
logical_resolution: (f32, f32),
|
||||
scale_factor: f64,
|
||||
},
|
||||
SetVsync {
|
||||
vsync: bool,
|
||||
|
@ -129,7 +134,8 @@ impl Window {
|
|||
requested_height: window_descriptor.height,
|
||||
physical_width,
|
||||
physical_height,
|
||||
scale_factor,
|
||||
scale_factor_override: window_descriptor.scale_factor_override,
|
||||
backend_scale_factor: scale_factor,
|
||||
title: window_descriptor.title.clone(),
|
||||
vsync: window_descriptor.vsync,
|
||||
resizable: window_descriptor.resizable,
|
||||
|
@ -152,13 +158,13 @@ impl Window {
|
|||
/// The current logical width of the window's client area.
|
||||
#[inline]
|
||||
pub fn width(&self) -> f32 {
|
||||
(self.physical_width as f64 / self.scale_factor) as f32
|
||||
(self.physical_width as f64 / self.scale_factor()) as f32
|
||||
}
|
||||
|
||||
/// The current logical height of the window's client area.
|
||||
#[inline]
|
||||
pub fn height(&self) -> f32 {
|
||||
(self.physical_height as f64 / self.scale_factor) as f32
|
||||
(self.physical_height as f64 / self.scale_factor()) as f32
|
||||
}
|
||||
|
||||
/// The requested window client area width in logical pixels from window
|
||||
|
@ -201,18 +207,40 @@ impl Window {
|
|||
|
||||
/// Request the OS to resize the window such the the client area matches the
|
||||
/// specified width and height.
|
||||
#[allow(clippy::float_cmp)]
|
||||
pub fn set_resolution(&mut self, width: f32, height: f32) {
|
||||
if self.requested_width == width && self.requested_height == height {
|
||||
return;
|
||||
}
|
||||
self.requested_width = width;
|
||||
self.requested_height = height;
|
||||
self.command_queue.push(WindowCommand::SetResolution {
|
||||
resolution: (self.requested_width, self.requested_height),
|
||||
logical_resolution: (self.requested_width, self.requested_height),
|
||||
scale_factor: self.scale_factor(),
|
||||
});
|
||||
}
|
||||
|
||||
/// Override the os-reported scaling factor
|
||||
#[allow(clippy::float_cmp)]
|
||||
pub fn set_scale_factor_override(&mut self, scale_factor: Option<f64>) {
|
||||
if self.scale_factor_override == scale_factor {
|
||||
return;
|
||||
}
|
||||
|
||||
self.scale_factor_override = scale_factor;
|
||||
self.command_queue.push(WindowCommand::SetScaleFactor {
|
||||
scale_factor: self.scale_factor(),
|
||||
});
|
||||
self.command_queue.push(WindowCommand::SetResolution {
|
||||
logical_resolution: (self.requested_width, self.requested_height),
|
||||
scale_factor: self.scale_factor(),
|
||||
});
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[inline]
|
||||
pub fn update_scale_factor_from_backend(&mut self, scale_factor: f64) {
|
||||
self.scale_factor = scale_factor;
|
||||
self.backend_scale_factor = scale_factor;
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
|
@ -225,9 +253,21 @@ impl Window {
|
|||
/// The ratio of physical pixels to logical pixels
|
||||
///
|
||||
/// `physical_pixels = logical_pixels * scale_factor`
|
||||
#[inline]
|
||||
pub fn scale_factor(&self) -> f64 {
|
||||
self.scale_factor
|
||||
self.scale_factor_override
|
||||
.unwrap_or(self.backend_scale_factor)
|
||||
}
|
||||
|
||||
/// The window scale factor as reported by the window backend.
|
||||
/// This value is unaffected by scale_factor_override.
|
||||
#[inline]
|
||||
pub fn backend_scale_factor(&self) -> f64 {
|
||||
self.backend_scale_factor
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn scale_factor_override(&self) -> Option<f64> {
|
||||
self.scale_factor_override
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -335,6 +375,7 @@ impl Window {
|
|||
pub struct WindowDescriptor {
|
||||
pub width: f32,
|
||||
pub height: f32,
|
||||
pub scale_factor_override: Option<f64>,
|
||||
pub title: String,
|
||||
pub vsync: bool,
|
||||
pub resizable: bool,
|
||||
|
@ -352,6 +393,7 @@ impl Default for WindowDescriptor {
|
|||
title: "bevy".to_string(),
|
||||
width: 1280.,
|
||||
height: 720.,
|
||||
scale_factor_override: None,
|
||||
vsync: true,
|
||||
resizable: true,
|
||||
decorations: true,
|
||||
|
|
|
@ -14,8 +14,9 @@ use bevy_ecs::{IntoSystem, Resources, World};
|
|||
use bevy_math::Vec2;
|
||||
use bevy_utils::tracing::{error, trace, warn};
|
||||
use bevy_window::{
|
||||
CreateWindow, CursorEntered, CursorLeft, CursorMoved, ReceivedCharacter, WindowCloseRequested,
|
||||
WindowCreated, WindowFocused, WindowResized, Windows,
|
||||
CreateWindow, CursorEntered, CursorLeft, CursorMoved, ReceivedCharacter,
|
||||
WindowBackendScaleFactorChanged, WindowCloseRequested, WindowCreated, WindowFocused,
|
||||
WindowResized, WindowScaleFactorChanged, Windows,
|
||||
};
|
||||
use winit::{
|
||||
event::{self, DeviceEvent, Event, WindowEvent},
|
||||
|
@ -76,14 +77,21 @@ fn change_window(_: &mut World, resources: &mut Resources) {
|
|||
let window = winit_windows.get_window(id).unwrap();
|
||||
window.set_title(&title);
|
||||
}
|
||||
bevy_window::WindowCommand::SetScaleFactor { scale_factor } => {
|
||||
let mut window_dpi_changed_events = resources
|
||||
.get_mut::<Events<WindowScaleFactorChanged>>()
|
||||
.unwrap();
|
||||
window_dpi_changed_events.send(WindowScaleFactorChanged { id, scale_factor });
|
||||
}
|
||||
bevy_window::WindowCommand::SetResolution {
|
||||
resolution: (logical_width, logical_height),
|
||||
logical_resolution: (width, height),
|
||||
scale_factor,
|
||||
} => {
|
||||
let window = winit_windows.get_window(id).unwrap();
|
||||
window.set_inner_size(winit::dpi::LogicalSize::new(
|
||||
logical_width,
|
||||
logical_height,
|
||||
));
|
||||
window.set_inner_size(
|
||||
winit::dpi::LogicalSize::new(width, height)
|
||||
.to_physical::<f64>(scale_factor),
|
||||
);
|
||||
}
|
||||
bevy_window::WindowCommand::SetVsync { .. } => (),
|
||||
bevy_window::WindowCommand::SetResizable { resizable } => {
|
||||
|
@ -342,13 +350,44 @@ pub fn winit_runner_with(mut app: App, mut event_loop: EventLoop<()>) {
|
|||
scale_factor,
|
||||
new_inner_size,
|
||||
} => {
|
||||
let mut backend_scale_factor_change_events = app
|
||||
.resources
|
||||
.get_mut::<Events<WindowBackendScaleFactorChanged>>()
|
||||
.unwrap();
|
||||
backend_scale_factor_change_events.send(WindowBackendScaleFactorChanged {
|
||||
id: window_id,
|
||||
scale_factor,
|
||||
});
|
||||
#[allow(clippy::float_cmp)]
|
||||
if window.scale_factor() != scale_factor {
|
||||
let mut scale_factor_change_events = app
|
||||
.resources
|
||||
.get_mut::<Events<WindowScaleFactorChanged>>()
|
||||
.unwrap();
|
||||
|
||||
scale_factor_change_events.send(WindowScaleFactorChanged {
|
||||
id: window_id,
|
||||
scale_factor,
|
||||
});
|
||||
}
|
||||
|
||||
window.update_scale_factor_from_backend(scale_factor);
|
||||
|
||||
if window.physical_width() != new_inner_size.width
|
||||
|| window.physical_height() != new_inner_size.height
|
||||
{
|
||||
let mut resize_events =
|
||||
app.resources.get_mut::<Events<WindowResized>>().unwrap();
|
||||
resize_events.send(WindowResized {
|
||||
id: window_id,
|
||||
width: window.width(),
|
||||
height: window.height(),
|
||||
});
|
||||
}
|
||||
window.update_actual_size_from_backend(
|
||||
new_inner_size.width,
|
||||
new_inner_size.height,
|
||||
);
|
||||
window.update_scale_factor_from_backend(scale_factor);
|
||||
// should we send a resize event to indicate the change in
|
||||
// logical size?
|
||||
}
|
||||
WindowEvent::Focused(focused) => {
|
||||
let mut focused_events =
|
||||
|
|
|
@ -38,11 +38,22 @@ impl WinitWindows {
|
|||
false => get_best_videomode(&event_loop.primary_monitor().unwrap()),
|
||||
}),
|
||||
)),
|
||||
_ => winit_window_builder
|
||||
.with_inner_size(winit::dpi::LogicalSize::new(
|
||||
window_descriptor.width,
|
||||
window_descriptor.height,
|
||||
))
|
||||
_ => {
|
||||
let WindowDescriptor {
|
||||
width,
|
||||
height,
|
||||
scale_factor_override,
|
||||
..
|
||||
} = window_descriptor;
|
||||
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_resizable(window_descriptor.resizable)
|
||||
.with_decorations(window_descriptor.decorations),
|
||||
};
|
||||
|
|
85
examples/window/scale_factor_override.rs
Normal file
85
examples/window/scale_factor_override.rs
Normal file
|
@ -0,0 +1,85 @@
|
|||
use bevy::prelude::*;
|
||||
|
||||
/// This example illustrates how to customize the default window settings
|
||||
fn main() {
|
||||
App::build()
|
||||
.add_resource(WindowDescriptor {
|
||||
width: 500.,
|
||||
height: 300.,
|
||||
..Default::default()
|
||||
})
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_startup_system(setup.system())
|
||||
.add_system(toggle_override.system())
|
||||
.add_system(change_scale_factor.system())
|
||||
.run();
|
||||
}
|
||||
|
||||
fn setup(
|
||||
commands: &mut Commands,
|
||||
asset_server: Res<AssetServer>,
|
||||
mut materials: ResMut<Assets<ColorMaterial>>,
|
||||
) {
|
||||
commands
|
||||
// ui camera
|
||||
.spawn(CameraUiBundle::default())
|
||||
// root node
|
||||
.spawn(NodeBundle {
|
||||
style: Style {
|
||||
size: Size::new(Val::Percent(100.0), Val::Percent(100.0)),
|
||||
justify_content: JustifyContent::SpaceBetween,
|
||||
..Default::default()
|
||||
},
|
||||
material: materials.add(Color::NONE.into()),
|
||||
..Default::default()
|
||||
})
|
||||
.with_children(|parent| {
|
||||
parent
|
||||
// left vertical fill (border)
|
||||
.spawn(NodeBundle {
|
||||
style: Style {
|
||||
size: Size::new(Val::Px(200.0), Val::Percent(100.0)),
|
||||
border: Rect::all(Val::Px(2.0)),
|
||||
..Default::default()
|
||||
},
|
||||
material: materials.add(Color::rgb(0.65, 0.65, 0.65).into()),
|
||||
..Default::default()
|
||||
})
|
||||
.with_children(|parent| {
|
||||
parent.spawn(TextBundle {
|
||||
style: Style {
|
||||
align_self: AlignSelf::FlexEnd,
|
||||
..Default::default()
|
||||
},
|
||||
text: Text {
|
||||
value: "Example text".to_string(),
|
||||
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
|
||||
style: TextStyle {
|
||||
font_size: 30.0,
|
||||
color: Color::WHITE,
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// This system toggles scale factor overrides when enter is pressed
|
||||
fn toggle_override(input: Res<Input<KeyCode>>, mut windows: ResMut<Windows>) {
|
||||
let window = windows.get_primary_mut().unwrap();
|
||||
if input.just_pressed(KeyCode::Return) {
|
||||
window.set_scale_factor_override(window.scale_factor_override().xor(Some(1.)));
|
||||
}
|
||||
}
|
||||
|
||||
/// 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>) {
|
||||
let window = windows.get_primary_mut().unwrap();
|
||||
if input.just_pressed(KeyCode::Up) {
|
||||
window.set_scale_factor_override(window.scale_factor_override().map(|n| n + 1.));
|
||||
} else if input.just_pressed(KeyCode::Down) {
|
||||
window.set_scale_factor_override(window.scale_factor_override().map(|n| (n - 1.).max(1.)));
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@ fn main() {
|
|||
width: 500.,
|
||||
height: 300.,
|
||||
vsync: true,
|
||||
resizable: false,
|
||||
..Default::default()
|
||||
})
|
||||
.add_plugins(DefaultPlugins)
|
||||
|
|
Loading…
Reference in a new issue