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

Val viewport unit variants #8137

Merged
merged 6 commits into from
Mar 21, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
158 changes: 79 additions & 79 deletions crates/bevy_ui/src/flex/convert.rs
Original file line number Diff line number Diff line change
@@ -1,99 +1,77 @@
use taffy::style::LengthPercentageAuto;
use bevy_math::Vec2;

use crate::{
AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, JustifyContent,
PositionType, Size, Style, UiRect, Val,
};

impl Val {
fn scaled(self, scale_factor: f64) -> Self {
fn scaled(self, scale_factor: f64, physical_size: Vec2) -> Self {
match self {
Val::Auto => Val::Auto,
Val::Percent(value) => Val::Percent(value),
Val::Px(value) => Val::Px((scale_factor * value as f64) as f32),
Val::VMin(value) => Val::Px(physical_size.x.min(physical_size.y) * value / 100.),
ickshonpe marked this conversation as resolved.
Show resolved Hide resolved
Val::VMax(value) => Val::Px(physical_size.x.max(physical_size.y) * value / 100.),
ickshonpe marked this conversation as resolved.
Show resolved Hide resolved
Val::Vw(value) => Val::Px(physical_size.x * value / 100.),
Val::Vh(value) => Val::Px(physical_size.y * value / 100.),
}
}

fn to_inset(self) -> LengthPercentageAuto {
match self {
Val::Auto => taffy::style::LengthPercentageAuto::Auto,
Val::Percent(value) => taffy::style::LengthPercentageAuto::Percent(value / 100.0),
Val::Px(value) => taffy::style::LengthPercentageAuto::Points(value),
}
}
}

impl UiRect {
fn scaled(self, scale_factor: f64) -> Self {
Self {
left: self.left.scaled(scale_factor),
right: self.right.scaled(scale_factor),
top: self.top.scaled(scale_factor),
bottom: self.bottom.scaled(scale_factor),
}
}
}

impl Size {
fn scaled(self, scale_factor: f64) -> Self {
Self {
width: self.width.scaled(scale_factor),
height: self.height.scaled(scale_factor),
}
}
}

impl<T: From<Val>> From<UiRect> for taffy::prelude::Rect<T> {
fn from(value: UiRect) -> Self {
Self {
left: value.left.into(),
right: value.right.into(),
top: value.top.into(),
bottom: value.bottom.into(),
}
}
}

impl<T: From<Val>> From<Size> for taffy::prelude::Size<T> {
fn from(value: Size) -> Self {
Self {
width: value.width.into(),
height: value.height.into(),
}
}
}

impl From<Val> for taffy::style::Dimension {
fn from(value: Val) -> Self {
match value {
fn into_dimension(self, scale_factor: f64, physical_size: Vec2) -> taffy::style::Dimension {
match self.scaled(scale_factor, physical_size) {
Val::Auto => taffy::style::Dimension::Auto,
Val::Percent(value) => taffy::style::Dimension::Percent(value / 100.0),
Val::Px(value) => taffy::style::Dimension::Points(value),
_ => unreachable!(),
ickshonpe marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

impl From<Val> for taffy::style::LengthPercentage {
fn from(value: Val) -> Self {
match value {
fn into_length_percentage(
self,
scale_factor: f64,
physical_size: Vec2,
) -> taffy::style::LengthPercentage {
match self.scaled(scale_factor, physical_size) {
Val::Auto => taffy::style::LengthPercentage::Points(0.0),
Val::Percent(value) => taffy::style::LengthPercentage::Percent(value / 100.0),
Val::Px(value) => taffy::style::LengthPercentage::Points(value),
_ => unreachable!(),
}
}
}

impl From<Val> for taffy::style::LengthPercentageAuto {
fn from(value: Val) -> Self {
match value {
fn into_length_percentage_auto(
self,
scale_factor: f64,
physical_size: Vec2,
) -> taffy::style::LengthPercentageAuto {
match self.scaled(scale_factor, physical_size) {
Val::Auto => taffy::style::LengthPercentageAuto::Auto,
Val::Percent(value) => taffy::style::LengthPercentageAuto::Percent(value / 100.0),
Val::Px(value) => taffy::style::LengthPercentageAuto::Points(value),
_ => unreachable!(),
}
}
}

impl UiRect {
fn map_to_taffy_rect<T>(self, map_fn: impl Fn(Val) -> T) -> taffy::geometry::Rect<T> {
taffy::geometry::Rect {
left: map_fn(self.left),
right: map_fn(self.right),
top: map_fn(self.top),
bottom: map_fn(self.bottom),
}
}
}

impl Size {
fn map_to_taffy_size<T>(self, map_fn: impl Fn(Val) -> T) -> taffy::geometry::Size<T> {
taffy::geometry::Size {
width: map_fn(self.width),
height: map_fn(self.height),
}
}
}

pub fn from_style(scale_factor: f64, style: &Style) -> taffy::style::Style {
pub fn from_style(scale_factor: f64, physical_size: Vec2, style: &Style) -> taffy::style::Style {
taffy::style::Style {
display: style.display.into(),
position: style.position_type.into(),
Expand All @@ -104,22 +82,44 @@ pub fn from_style(scale_factor: f64, style: &Style) -> taffy::style::Style {
align_content: Some(style.align_content.into()),
justify_content: Some(style.justify_content.into()),
inset: taffy::prelude::Rect {
left: style.left.scaled(scale_factor).to_inset(),
right: style.right.scaled(scale_factor).to_inset(),
top: style.top.scaled(scale_factor).to_inset(),
bottom: style.bottom.scaled(scale_factor).to_inset(),
left: style
.left
.into_length_percentage_auto(scale_factor, physical_size),
right: style
.right
.into_length_percentage_auto(scale_factor, physical_size),
top: style
.top
.into_length_percentage_auto(scale_factor, physical_size),
bottom: style
.bottom
.into_length_percentage_auto(scale_factor, physical_size),
},
margin: style.margin.scaled(scale_factor).into(),
padding: style.padding.scaled(scale_factor).into(),
border: style.border.scaled(scale_factor).into(),
margin: style
.margin
.map_to_taffy_rect(|m| m.into_length_percentage_auto(scale_factor, physical_size)),
padding: style
.padding
.map_to_taffy_rect(|m| m.into_length_percentage(scale_factor, physical_size)),
border: style
.border
.map_to_taffy_rect(|m| m.into_length_percentage(scale_factor, physical_size)),
flex_grow: style.flex_grow,
flex_shrink: style.flex_shrink,
flex_basis: style.flex_basis.scaled(scale_factor).into(),
size: style.size.scaled(scale_factor).into(),
min_size: style.min_size.scaled(scale_factor).into(),
max_size: style.max_size.scaled(scale_factor).into(),
flex_basis: style.flex_basis.into_dimension(scale_factor, physical_size),
size: style
.size
.map_to_taffy_size(|s| s.into_dimension(scale_factor, physical_size)),
min_size: style
.min_size
.map_to_taffy_size(|s| s.into_dimension(scale_factor, physical_size)),
max_size: style
.max_size
.map_to_taffy_size(|s| s.into_dimension(scale_factor, physical_size)),
aspect_ratio: style.aspect_ratio,
gap: style.gap.scaled(scale_factor).into(),
gap: style
.gap
.map_to_taffy_size(|s| s.into_length_percentage(scale_factor, physical_size)),
justify_self: None,
}
}
Expand Down Expand Up @@ -283,7 +283,7 @@ mod tests {
height: Val::Percent(0.),
},
};
let taffy_style = from_style(1.0, &bevy_style);
let taffy_style = from_style(1.0, Vec2::new(800., 600.), &bevy_style);
assert_eq!(taffy_style.display, taffy::style::Display::Flex);
assert_eq!(taffy_style.position, taffy::style::Position::Absolute);
assert!(matches!(
Expand Down
58 changes: 46 additions & 12 deletions crates/bevy_ui/src/flex/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,28 @@ impl Default for FlexSurface {
}

impl FlexSurface {
pub fn upsert_node(&mut self, entity: Entity, style: &Style, scale_factor: f64) {
pub fn upsert_node(
&mut self,
entity: Entity,
style: &Style,
scale_factor: f64,
physical_size: Vec2,
) {
let mut added = false;
let taffy = &mut self.taffy;
let taffy_node = self.entity_to_taffy.entry(entity).or_insert_with(|| {
added = true;
taffy
.new_leaf(convert::from_style(scale_factor, style))
.new_leaf(convert::from_style(scale_factor, physical_size, style))
.unwrap()
});

if !added {
self.taffy
.set_style(*taffy_node, convert::from_style(scale_factor, style))
.set_style(
*taffy_node,
convert::from_style(scale_factor, physical_size, style),
)
.unwrap();
}
}
Expand All @@ -82,9 +91,10 @@ impl FlexSurface {
style: &Style,
calculated_size: CalculatedSize,
scale_factor: f64,
physical_size: Vec2,
) {
let taffy = &mut self.taffy;
let taffy_style = convert::from_style(scale_factor, style);
let taffy_style = convert::from_style(scale_factor, physical_size, style);
let measure = taffy::node::MeasureFunc::Boxed(Box::new(
move |constraints: Size<Option<f32>>, _available: Size<AvailableSpace>| {
let mut size = Size {
Expand Down Expand Up @@ -229,6 +239,7 @@ pub fn flex_node_system(
windows: Query<(Entity, &Window)>,
ui_scale: Res<UiScale>,
mut scale_factor_events: EventReader<WindowScaleFactorChanged>,
mut resize_events: EventReader<bevy_window::WindowResized>,
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>)>,
Expand All @@ -244,13 +255,24 @@ pub fn flex_node_system(
) {
// assume one window for time being...
// TODO: Support window-independent scaling: https://github.com/bevyengine/bevy/issues/5621
let (primary_window_entity, logical_to_physical_factor) =
let (primary_window_entity, logical_to_physical_factor, physical_size) =
ickshonpe marked this conversation as resolved.
Show resolved Hide resolved
if let Ok((entity, primary_window)) = primary_window.get_single() {
(entity, primary_window.resolution.scale_factor())
(
entity,
primary_window.resolution.scale_factor(),
Vec2::new(
primary_window.resolution.physical_width() as f32,
primary_window.resolution.physical_height() as f32,
),
)
} else {
return;
};

let resized = resize_events
.iter()
.any(|resized_window| resized_window.window == primary_window_entity);

// update window root nodes
for (entity, window) in windows.iter() {
flex_surface.update_window(entity, &window.resolution);
Expand All @@ -261,28 +283,40 @@ pub fn flex_node_system(
fn update_changed<F: ReadOnlyWorldQuery>(
flex_surface: &mut FlexSurface,
scaling_factor: f64,
physical_size: Vec2,
query: Query<(Entity, &Style, Option<&CalculatedSize>), F>,
) {
// update changed nodes
for (entity, style, calculated_size) in &query {
// 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);
flex_surface.upsert_leaf(
entity,
style,
*calculated_size,
scaling_factor,
physical_size,
);
} else {
flex_surface.upsert_node(entity, style, scaling_factor);
flex_surface.upsert_node(entity, style, scaling_factor, physical_size);
}
}
}

if !scale_factor_events.is_empty() || ui_scale.is_changed() {
if !scale_factor_events.is_empty() || ui_scale.is_changed() || resized {
scale_factor_events.clear();
update_changed(&mut flex_surface, scale_factor, full_node_query);
update_changed(
&mut flex_surface,
scale_factor,
physical_size,
full_node_query,
);
} else {
update_changed(&mut flex_surface, scale_factor, node_query);
update_changed(&mut flex_surface, scale_factor, physical_size, node_query);
}

for (entity, style, calculated_size) in &changed_size_query {
flex_surface.upsert_leaf(entity, style, *calculated_size, scale_factor);
flex_surface.upsert_leaf(entity, style, *calculated_size, scale_factor, physical_size);
}

// clean up removed nodes
Expand Down
Loading