Skip to content

Commit 51650f1

Browse files
run stretch's layout on physical coordinates to fix pixel alignment (#1061)
run stretch's layout on physical coordinates to fix pixel alignment of the results
1 parent 2e24231 commit 51650f1

File tree

2 files changed

+88
-70
lines changed

2 files changed

+88
-70
lines changed

crates/bevy_ui/src/flex/convert.rs

+53-52
Original file line numberDiff line numberDiff line change
@@ -3,71 +3,72 @@ use crate::{
33
JustifyContent, PositionType, Style, Val,
44
};
55
use bevy_math::{Rect, Size};
6-
use bevy_reflect::Reflect;
76

8-
fn from_rect<T, U: Reflect>(rect: Rect<U>) -> stretch::geometry::Rect<T>
9-
where
10-
T: From<U>,
11-
{
7+
pub fn from_rect(
8+
scale_factor: f64,
9+
rect: Rect<Val>,
10+
) -> stretch::geometry::Rect<stretch::style::Dimension> {
1211
stretch::geometry::Rect {
13-
start: rect.left.into(),
14-
end: rect.right.into(),
12+
start: from_val(scale_factor, rect.left),
13+
end: from_val(scale_factor, rect.right),
1514
// NOTE: top and bottom are intentionally flipped. stretch has a flipped y-axis
16-
top: rect.bottom.into(),
17-
bottom: rect.top.into(),
15+
top: from_val(scale_factor, rect.bottom),
16+
bottom: from_val(scale_factor, rect.top),
1817
}
1918
}
2019

21-
fn from_size<T, U>(size: Size<U>) -> stretch::geometry::Size<T>
22-
where
23-
U: Reflect,
24-
T: From<U>,
25-
{
20+
pub fn from_f32_size(scale_factor: f64, size: Size<f32>) -> stretch::geometry::Size<f32> {
2621
stretch::geometry::Size {
27-
width: size.width.into(),
28-
height: size.height.into(),
22+
width: (scale_factor * size.width as f64) as f32,
23+
height: (scale_factor * size.height as f64) as f32,
2924
}
3025
}
3126

32-
impl From<&Style> for stretch::style::Style {
33-
fn from(value: &Style) -> Self {
34-
Self {
35-
overflow: stretch::style::Overflow::Visible,
36-
display: value.display.into(),
37-
position_type: value.position_type.into(),
38-
direction: value.direction.into(),
39-
flex_direction: value.flex_direction.into(),
40-
flex_wrap: value.flex_wrap.into(),
41-
align_items: value.align_items.into(),
42-
align_self: value.align_self.into(),
43-
align_content: value.align_content.into(),
44-
justify_content: value.justify_content.into(),
45-
position: from_rect(value.position),
46-
margin: from_rect(value.margin),
47-
padding: from_rect(value.padding),
48-
border: from_rect(value.border),
49-
flex_grow: value.flex_grow,
50-
flex_shrink: value.flex_shrink,
51-
flex_basis: value.flex_basis.into(),
52-
size: from_size(value.size),
53-
min_size: from_size(value.min_size),
54-
max_size: from_size(value.max_size),
55-
aspect_ratio: match value.aspect_ratio {
56-
Some(value) => stretch::number::Number::Defined(value),
57-
None => stretch::number::Number::Undefined,
58-
},
59-
}
27+
pub fn from_val_size(
28+
scale_factor: f64,
29+
size: Size<Val>,
30+
) -> stretch::geometry::Size<stretch::style::Dimension> {
31+
stretch::geometry::Size {
32+
width: from_val(scale_factor, size.width),
33+
height: from_val(scale_factor, size.height),
6034
}
6135
}
6236

63-
impl From<Val> for stretch::style::Dimension {
64-
fn from(val: Val) -> Self {
65-
match val {
66-
Val::Auto => stretch::style::Dimension::Auto,
67-
Val::Percent(value) => stretch::style::Dimension::Percent(value / 100.0),
68-
Val::Px(value) => stretch::style::Dimension::Points(value),
69-
Val::Undefined => stretch::style::Dimension::Undefined,
70-
}
37+
pub fn from_style(scale_factor: f64, value: &Style) -> stretch::style::Style {
38+
stretch::style::Style {
39+
overflow: stretch::style::Overflow::Visible,
40+
display: value.display.into(),
41+
position_type: value.position_type.into(),
42+
direction: value.direction.into(),
43+
flex_direction: value.flex_direction.into(),
44+
flex_wrap: value.flex_wrap.into(),
45+
align_items: value.align_items.into(),
46+
align_self: value.align_self.into(),
47+
align_content: value.align_content.into(),
48+
justify_content: value.justify_content.into(),
49+
position: from_rect(scale_factor, value.position),
50+
margin: from_rect(scale_factor, value.margin),
51+
padding: from_rect(scale_factor, value.padding),
52+
border: from_rect(scale_factor, value.border),
53+
flex_grow: value.flex_grow,
54+
flex_shrink: value.flex_shrink,
55+
flex_basis: from_val(scale_factor, value.flex_basis),
56+
size: from_val_size(scale_factor, value.size),
57+
min_size: from_val_size(scale_factor, value.min_size),
58+
max_size: from_val_size(scale_factor, value.max_size),
59+
aspect_ratio: match value.aspect_ratio {
60+
Some(value) => stretch::number::Number::Defined(value),
61+
None => stretch::number::Number::Undefined,
62+
},
63+
}
64+
}
65+
66+
pub fn from_val(scale_factor: f64, val: Val) -> stretch::style::Dimension {
67+
match val {
68+
Val::Auto => stretch::style::Dimension::Auto,
69+
Val::Percent(value) => stretch::style::Dimension::Percent(value / 100.0),
70+
Val::Px(value) => stretch::style::Dimension::Points((scale_factor * value as f64) as f32),
71+
Val::Undefined => stretch::style::Dimension::Undefined,
7172
}
7273
}
7374

crates/bevy_ui/src/flex/mod.rs

+35-18
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ impl Default for FlexSurface {
3535
}
3636

3737
impl FlexSurface {
38-
pub fn upsert_node(&mut self, entity: Entity, style: &Style) {
38+
pub fn upsert_node(&mut self, entity: Entity, style: &Style, scale_factor: f64) {
3939
let mut added = false;
4040
let stretch = &mut self.stretch;
41-
let stretch_style = style.into();
41+
let stretch_style = convert::from_style(scale_factor, style);
4242
let stretch_node = self.entity_to_stretch.entry(entity).or_insert_with(|| {
4343
added = true;
4444
stretch.new_node(stretch_style, Vec::new()).unwrap()
@@ -51,14 +51,17 @@ impl FlexSurface {
5151
}
5252
}
5353

54-
pub fn upsert_leaf(&mut self, entity: Entity, style: &Style, calculated_size: CalculatedSize) {
54+
pub fn upsert_leaf(
55+
&mut self,
56+
entity: Entity,
57+
style: &Style,
58+
calculated_size: CalculatedSize,
59+
scale_factor: f64,
60+
) {
5561
let stretch = &mut self.stretch;
56-
let stretch_style = style.into();
62+
let stretch_style = convert::from_style(scale_factor, style);
5763
let measure = Box::new(move |constraints: stretch::geometry::Size<Number>| {
58-
let mut size = stretch::geometry::Size {
59-
width: calculated_size.size.width,
60-
height: calculated_size.size.height,
61-
};
64+
let mut size = convert::from_f32_size(scale_factor, calculated_size.size);
6265
match (constraints.width, constraints.height) {
6366
(Number::Undefined, Number::Undefined) => {}
6467
(Number::Defined(width), Number::Undefined) => {
@@ -116,8 +119,8 @@ impl FlexSurface {
116119
*node,
117120
stretch::style::Style {
118121
size: stretch::geometry::Size {
119-
width: stretch::style::Dimension::Points(window.width()),
120-
height: stretch::style::Dimension::Points(window.height()),
122+
width: stretch::style::Dimension::Points(window.physical_width() as f32),
123+
height: stretch::style::Dimension::Points(window.physical_height() as f32),
121124
},
122125
..Default::default()
123126
},
@@ -174,18 +177,25 @@ pub fn flex_node_system(
174177
flex_surface.update_window(window);
175178
}
176179

180+
// assume one window for time being...
181+
let logical_to_physical_factor = if let Some(primary_window) = windows.get_primary() {
182+
primary_window.scale_factor()
183+
} else {
184+
1.
185+
};
186+
177187
// update changed nodes
178188
for (entity, style, calculated_size) in node_query.iter() {
179189
// TODO: remove node from old hierarchy if its root has changed
180190
if let Some(calculated_size) = calculated_size {
181-
flex_surface.upsert_leaf(entity, &style, *calculated_size);
191+
flex_surface.upsert_leaf(entity, &style, *calculated_size, logical_to_physical_factor);
182192
} else {
183-
flex_surface.upsert_node(entity, &style);
193+
flex_surface.upsert_node(entity, &style, logical_to_physical_factor);
184194
}
185195
}
186196

187197
for (entity, style, calculated_size) in changed_size_query.iter() {
188-
flex_surface.upsert_leaf(entity, &style, *calculated_size);
198+
flex_surface.upsert_leaf(entity, &style, *calculated_size, logical_to_physical_factor);
189199
}
190200

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

216+
let physical_to_logical_factor = 1. / logical_to_physical_factor;
217+
218+
let to_logical = |v| (physical_to_logical_factor * v as f64) as f32;
219+
206220
for (entity, mut node, mut transform, parent) in node_transform_query.iter_mut() {
207221
let layout = flex_surface.get_layout(entity).unwrap();
208-
node.size = Vec2::new(layout.size.width, layout.size.height);
222+
node.size = Vec2::new(
223+
to_logical(layout.size.width),
224+
to_logical(layout.size.height),
225+
);
209226
let position = &mut transform.translation;
210-
position.x = layout.location.x + layout.size.width / 2.0;
211-
position.y = layout.location.y + layout.size.height / 2.0;
227+
position.x = to_logical(layout.location.x + layout.size.width / 2.0);
228+
position.y = to_logical(layout.location.y + layout.size.height / 2.0);
212229
if let Some(parent) = parent {
213230
if let Ok(parent_layout) = flex_surface.get_layout(parent.0) {
214-
position.x -= parent_layout.size.width / 2.0;
215-
position.y -= parent_layout.size.height / 2.0;
231+
position.x -= to_logical(parent_layout.size.width / 2.0);
232+
position.y -= to_logical(parent_layout.size.height / 2.0);
216233
}
217234
}
218235
}

0 commit comments

Comments
 (0)