mirror of
https://github.com/storytold/figcraft.git
synced 2026-11-07 02:51:41 +00:00
fix(layout): end the fill distribution loop when no child can freeze (#1926)
Each iteration froze the children whose clamping passed a 1e-9 tolerance, but it compared the aggregate violation against the same tolerance: several clampings each under it could add up past it, so no child froze, the pending set never shrank and the loop never ended. An iteration that freezes nothing now settles the remaining children as clamped.
This commit is contained in:
1 parent
3b4de34efe
commit
9475a815da
2 files changed
+33
No files matched your search
@@ -629,14 +629,26 @@ fn distribute(items: &mut [Item], mut open: Vec<usize>, free: f64) {
|
||||
.collect();
|
||||
let violation: f64 = sized.iter().map(|(_, want, v)| v - want).sum();
|
||||
let frozen = |want: f64, v: f64| violation.abs() < 1e-9 || (violation > 0.0 && v > want + 1e-9) || (violation < 0.0 && v < want - 1e-9);
|
||||
let mut progressed = false;
|
||||
for (i, want, v) in &sized {
|
||||
if frozen(*want, *v)
|
||||
&& let Some(it) = items.get_mut(*i)
|
||||
{
|
||||
it.main = *v;
|
||||
free -= *v;
|
||||
progressed = true;
|
||||
}
|
||||
}
|
||||
if !progressed {
|
||||
// Several clampings each under the tolerance added up past it, so none froze: settle
|
||||
// them all as clamped rather than go round again with nothing changed.
|
||||
for (i, _, v) in &sized {
|
||||
if let Some(it) = items.get_mut(*i) {
|
||||
it.main = *v;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
free = free.max(0.0);
|
||||
open = sized.into_iter().filter(|(_, want, v)| !frozen(*want, *v)).map(|(i, _, _)| i).collect();
|
||||
}
|
||||
|
||||
@@ -447,3 +447,24 @@ fn grid_hostile_values() {
|
||||
assert!(x.is_finite() && y.is_finite() && w.is_finite() && h.is_finite());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fill_children_whose_tiny_clampings_add_up_past_the_tolerance_still_settle() {
|
||||
// Three fill children sharing 300 px, each with a minimum 5e-10 over its 100 px share: no
|
||||
// single clamping passes the 1e-9 tolerance, but together they do, so no child froze and the
|
||||
// distribution loop went round forever without changing anything.
|
||||
let mut d = Document::new("t");
|
||||
let p = d.first_page().unwrap();
|
||||
let f = d.create(p, NodeKind::Frame, "F", 0.0, 0.0, 300.0, 100.0).unwrap();
|
||||
d.get_mut(f).unwrap().layout = Some(AutoLayout { mode: LayoutMode::Horizontal, gap: 0.0, padding: [0.0; 4], ..Default::default() });
|
||||
let kids: Vec<NodeId> = (0..3).map(|i| d.create(f, NodeKind::Rectangle, "K", 0.0, 0.0, 10.0, 20.0 + i as f64).unwrap()).collect();
|
||||
for k in &kids {
|
||||
let n = d.get_mut(*k).unwrap();
|
||||
n.child_layout.sizing_h = Sizing::Fill;
|
||||
n.child_layout.min_w = Some(100.0 + 5e-10);
|
||||
}
|
||||
layout_frame(&mut d, f, &NoMeasure);
|
||||
for k in &kids {
|
||||
assert!((pos(&d, *k).2 - 100.0).abs() < 1e-6, "{:?}", pos(&d, *k));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user