Added use_dpi setting to WindowDescriptor (#1131)

Added scale_factor_override
This commit is contained in:
TheRawMeatball 2020-12-28 23:26:50 +03:00 committed by GitHub
parent 4825051c6a
commit 3cb2e22e89
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 254 additions and 36 deletions

View file

@ -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"

View file

@ -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.
};
// update changed nodes
for (entity, style, calculated_size) in node_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);
} else {
flex_surface.upsert_node(entity, &style, logical_to_physical_factor);
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 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, scaling_factor);
} else {
flex_surface.upsert_node(entity, &style, scaling_factor);
}
}
}

View file

@ -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,
}

View file

@ -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 {

View file

@ -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,

View file

@ -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 =

View file

@ -38,13 +38,24 @@ 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,
))
.with_resizable(window_descriptor.resizable)
.with_decorations(window_descriptor.decorations),
_ => {
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),
};
#[allow(unused_mut)]

View 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.)));
}
}

View file

@ -8,7 +8,6 @@ fn main() {
width: 500.,
height: 300.,
vsync: true,
resizable: false,
..Default::default()
})
.add_plugins(DefaultPlugins)