Skip to content
Merged
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
105 changes: 53 additions & 52 deletions crates/bevy_ui/src/flex/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,71 +3,72 @@ use crate::{
JustifyContent, PositionType, Style, Val,
};
use bevy_math::{Rect, Size};
use bevy_reflect::Reflect;

fn from_rect<T, U: Reflect>(rect: Rect<U>) -> stretch::geometry::Rect<T>
where
T: From<U>,
{
pub fn from_rect(
scale_factor: f64,
rect: Rect<Val>,
) -> stretch::geometry::Rect<stretch::style::Dimension> {
stretch::geometry::Rect {
start: rect.left.into(),
end: rect.right.into(),
start: from_val(scale_factor, rect.left),
end: from_val(scale_factor, rect.right),
// NOTE: top and bottom are intentionally flipped. stretch has a flipped y-axis
top: rect.bottom.into(),
bottom: rect.top.into(),
top: from_val(scale_factor, rect.bottom),
bottom: from_val(scale_factor, rect.top),
}
}

fn from_size<T, U>(size: Size<U>) -> stretch::geometry::Size<T>
where
U: Reflect,
T: From<U>,
{
pub fn from_f32_size(scale_factor: f64, size: Size<f32>) -> stretch::geometry::Size<f32> {
stretch::geometry::Size {
width: size.width.into(),
height: size.height.into(),
width: (scale_factor * size.width as f64) as f32,
height: (scale_factor * size.height as f64) as f32,
}
}

impl From<&Style> for stretch::style::Style {
fn from(value: &Style) -> Self {
Self {
overflow: stretch::style::Overflow::Visible,
display: value.display.into(),
position_type: value.position_type.into(),
direction: value.direction.into(),
flex_direction: value.flex_direction.into(),
flex_wrap: value.flex_wrap.into(),
align_items: value.align_items.into(),
align_self: value.align_self.into(),
align_content: value.align_content.into(),
justify_content: value.justify_content.into(),
position: from_rect(value.position),
margin: from_rect(value.margin),
padding: from_rect(value.padding),
border: from_rect(value.border),
flex_grow: value.flex_grow,
flex_shrink: value.flex_shrink,
flex_basis: value.flex_basis.into(),
size: from_size(value.size),
min_size: from_size(value.min_size),
max_size: from_size(value.max_size),
aspect_ratio: match value.aspect_ratio {
Some(value) => stretch::number::Number::Defined(value),
None => stretch::number::Number::Undefined,
},
}
pub fn from_val_size(
scale_factor: f64,
size: Size<Val>,
) -> stretch::geometry::Size<stretch::style::Dimension> {
stretch::geometry::Size {
width: from_val(scale_factor, size.width),
height: from_val(scale_factor, size.height),
}
}

impl From<Val> for stretch::style::Dimension {
fn from(val: Val) -> Self {
match val {
Val::Auto => stretch::style::Dimension::Auto,
Val::Percent(value) => stretch::style::Dimension::Percent(value / 100.0),
Val::Px(value) => stretch::style::Dimension::Points(value),
Val::Undefined => stretch::style::Dimension::Undefined,
}
pub fn from_style(scale_factor: f64, value: &Style) -> stretch::style::Style {
stretch::style::Style {
overflow: stretch::style::Overflow::Visible,
display: value.display.into(),
position_type: value.position_type.into(),
direction: value.direction.into(),
flex_direction: value.flex_direction.into(),
flex_wrap: value.flex_wrap.into(),
align_items: value.align_items.into(),
align_self: value.align_self.into(),
align_content: value.align_content.into(),
justify_content: value.justify_content.into(),
position: from_rect(scale_factor, value.position),
margin: from_rect(scale_factor, value.margin),
padding: from_rect(scale_factor, value.padding),
border: from_rect(scale_factor, value.border),
flex_grow: value.flex_grow,
flex_shrink: value.flex_shrink,
flex_basis: from_val(scale_factor, value.flex_basis),
size: from_val_size(scale_factor, value.size),
min_size: from_val_size(scale_factor, value.min_size),
max_size: from_val_size(scale_factor, value.max_size),
aspect_ratio: match value.aspect_ratio {
Some(value) => stretch::number::Number::Defined(value),
None => stretch::number::Number::Undefined,
},
}
}

pub fn from_val(scale_factor: f64, val: Val) -> stretch::style::Dimension {
match val {
Val::Auto => stretch::style::Dimension::Auto,
Val::Percent(value) => stretch::style::Dimension::Percent(value / 100.0),
Val::Px(value) => stretch::style::Dimension::Points((scale_factor * value as f64) as f32),
Val::Undefined => stretch::style::Dimension::Undefined,
}
}

Expand Down
53 changes: 35 additions & 18 deletions crates/bevy_ui/src/flex/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ impl Default for FlexSurface {
}

impl FlexSurface {
pub fn upsert_node(&mut self, entity: Entity, style: &Style) {
pub fn upsert_node(&mut self, entity: Entity, style: &Style, scale_factor: f64) {
let mut added = false;
let stretch = &mut self.stretch;
let stretch_style = style.into();
let stretch_style = convert::from_style(scale_factor, style);
let stretch_node = self.entity_to_stretch.entry(entity).or_insert_with(|| {
added = true;
stretch.new_node(stretch_style, Vec::new()).unwrap()
Expand All @@ -51,14 +51,17 @@ impl FlexSurface {
}
}

pub fn upsert_leaf(&mut self, entity: Entity, style: &Style, calculated_size: CalculatedSize) {
pub fn upsert_leaf(
&mut self,
entity: Entity,
style: &Style,
calculated_size: CalculatedSize,
scale_factor: f64,
) {
let stretch = &mut self.stretch;
let stretch_style = style.into();
let stretch_style = convert::from_style(scale_factor, style);
let measure = Box::new(move |constraints: stretch::geometry::Size<Number>| {
let mut size = stretch::geometry::Size {
width: calculated_size.size.width,
height: calculated_size.size.height,
};
let mut size = convert::from_f32_size(scale_factor, calculated_size.size);
match (constraints.width, constraints.height) {
(Number::Undefined, Number::Undefined) => {}
(Number::Defined(width), Number::Undefined) => {
Expand Down Expand Up @@ -116,8 +119,8 @@ impl FlexSurface {
*node,
stretch::style::Style {
size: stretch::geometry::Size {
width: stretch::style::Dimension::Points(window.width()),
height: stretch::style::Dimension::Points(window.height()),
width: stretch::style::Dimension::Points(window.physical_width() as f32),
height: stretch::style::Dimension::Points(window.physical_height() as f32),
},
..Default::default()
},
Expand Down Expand Up @@ -174,18 +177,25 @@ pub fn flex_node_system(
flex_surface.update_window(window);
}

// assume one window for time being...
let logical_to_physical_factor = if let Some(primary_window) = windows.get_primary() {
primary_window.scale_factor()
} else {
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);
flex_surface.upsert_leaf(entity, &style, *calculated_size, logical_to_physical_factor);
} else {
flex_surface.upsert_node(entity, &style);
flex_surface.upsert_node(entity, &style, logical_to_physical_factor);
}
}

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

// TODO: handle removed nodes
Expand All @@ -203,16 +213,23 @@ pub fn flex_node_system(
// compute layouts
flex_surface.compute_window_layouts();

let physical_to_logical_factor = 1. / logical_to_physical_factor;

let to_logical = |v| (physical_to_logical_factor * v as f64) as f32;

for (entity, mut node, mut transform, parent) in node_transform_query.iter_mut() {
let layout = flex_surface.get_layout(entity).unwrap();
node.size = Vec2::new(layout.size.width, layout.size.height);
node.size = Vec2::new(
to_logical(layout.size.width),
to_logical(layout.size.height),
);
let position = &mut transform.translation;
position.x = layout.location.x + layout.size.width / 2.0;
position.y = layout.location.y + layout.size.height / 2.0;
position.x = to_logical(layout.location.x + layout.size.width / 2.0);
position.y = to_logical(layout.location.y + layout.size.height / 2.0);
if let Some(parent) = parent {
if let Ok(parent_layout) = flex_surface.get_layout(parent.0) {
position.x -= parent_layout.size.width / 2.0;
position.y -= parent_layout.size.height / 2.0;
position.x -= to_logical(parent_layout.size.width / 2.0);
position.y -= to_logical(parent_layout.size.height / 2.0);
}
}
}
Expand Down