Make alignment a widget property
This commit is contained in:
1 parent
8220a78d4a
commit
d3b0ebf90c
21 files changed
+823
-300
No files matched your search
+113
-15
@@ -13,7 +13,7 @@ use std::collections::HashMap;
|
||||
|
||||
use iris::harness::Harness;
|
||||
use iris::prelude::*;
|
||||
use iris::random::{Edits, Lens, Rng, SpanEdit, Tree, grow};
|
||||
use iris::random::{Aligns, Edits, Lens, Rng, SpanEdit, Tree, grow};
|
||||
|
||||
/// How deep the generator branches. The generator widens two to four ways per
|
||||
/// level, so depth is exponential in width and a deep narrow tree is not
|
||||
@@ -179,12 +179,28 @@ fn describe(id: WidgetId, h: &Harness) -> String {
|
||||
Some(len) => format!("{len}"),
|
||||
None => "-".into(),
|
||||
};
|
||||
// A size rule is a property of whatever carries it, so it prints with
|
||||
// that widget rather than as one of its own.
|
||||
match (rules.x, rules.y) {
|
||||
(SizeRule::Free, SizeRule::Free) => describe_widget(id, h),
|
||||
(x, y) => format!("{}[x:{},y:{}]", describe_widget(id, h), rule(x), rule(y)),
|
||||
let align = h.rsc.widgets().alignment(id);
|
||||
let side = |a: AxisAlign| {
|
||||
if a == AxisAlign::NEG {
|
||||
"neg".into()
|
||||
} else if a == AxisAlign::CENTER {
|
||||
"mid".into()
|
||||
} else if a == AxisAlign::POS {
|
||||
"pos".into()
|
||||
} else {
|
||||
format!("{:.2}", a.rel())
|
||||
}
|
||||
};
|
||||
// A rule and an alignment are properties of whatever carries them, so
|
||||
// they print with that widget rather than as widgets of their own.
|
||||
let mut out = describe_widget(id, h);
|
||||
if (rules.x, rules.y) != (SizeRule::Free, SizeRule::Free) {
|
||||
out += &format!("[x:{},y:{}]", rule(rules.x), rule(rules.y));
|
||||
}
|
||||
if align != RegionAlign::default() {
|
||||
out += &format!("@{},{}", side(align.x), side(align.y));
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn describe_widget(id: WidgetId, h: &Harness) -> String {
|
||||
@@ -210,15 +226,6 @@ fn describe_widget(id: WidgetId, h: &Harness) -> String {
|
||||
p.left, p.right, p.top, p.bottom
|
||||
);
|
||||
}
|
||||
if let Some(w) = any.downcast_ref::<Aligned>() {
|
||||
let a = |v: Option<AxisAlign>| match v {
|
||||
None => "-",
|
||||
Some(AxisAlign::Neg) => "neg",
|
||||
Some(AxisAlign::Center) => "mid",
|
||||
Some(AxisAlign::Pos) => "pos",
|
||||
};
|
||||
return format!("Aligned{{x:{},y:{}}}", a(w.align.x), a(w.align.y));
|
||||
}
|
||||
if let Some(w) = any.downcast_ref::<Stack>() {
|
||||
return format!("Stack{{n:{}}}", w.children.len());
|
||||
}
|
||||
@@ -290,6 +297,87 @@ fn changed_size(seed: u64) {
|
||||
assert_same(seed, "a size change", (&warm, &grown), (&cold, &same));
|
||||
}
|
||||
|
||||
/// Moves one widget to a different corner of the box it is given.
|
||||
fn realign_one(h: &mut Harness, tree: &Tree, idx: usize, rng: &mut Rng) -> Aligns {
|
||||
let mut side = || match rng.below(4) {
|
||||
0 => None,
|
||||
1 => Some(AxisAlign::NEG),
|
||||
2 => Some(AxisAlign::CENTER),
|
||||
_ => Some(AxisAlign::POS),
|
||||
};
|
||||
let aligns = [side(), side()];
|
||||
for (axis, align) in [Axis::X, Axis::Y].into_iter().zip(aligns) {
|
||||
h.rsc
|
||||
.widgets_mut()
|
||||
.set_alignment(tree.aligned[idx], axis, align.unwrap_or_default());
|
||||
}
|
||||
aligns
|
||||
}
|
||||
|
||||
fn changed_alignment(seed: u64) {
|
||||
let mut warm = Harness::new((900, 1200));
|
||||
let grown = plant(&mut warm, seed, &Edits::default());
|
||||
if grown.aligned.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut rng = Rng::new(seed ^ 0xa11);
|
||||
let aligns = (0..grown.aligned.len())
|
||||
.step_by(3)
|
||||
.map(|idx| (idx, realign_one(&mut warm, &grown, idx, &mut rng)))
|
||||
.collect();
|
||||
warm.frame();
|
||||
|
||||
let mut cold = Harness::new((900, 1200));
|
||||
let same = plant(
|
||||
&mut cold,
|
||||
seed,
|
||||
&Edits {
|
||||
aligns,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
assert_same(seed, "an alignment change", (&warm, &grown), (&cold, &same));
|
||||
}
|
||||
|
||||
/// Giving a widget a movable region of its own, or taking it away, is a
|
||||
/// structural change: every primitive under it changes which chain resolves
|
||||
/// it. A cold tree built that way is what says the rebuild was complete.
|
||||
fn changed_region_node(seed: u64) {
|
||||
let mut warm = Harness::new((900, 1200));
|
||||
let grown = plant(&mut warm, seed, &Edits::default());
|
||||
if grown.nodes.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let nodes: HashMap<usize, bool> = (0..grown.nodes.len())
|
||||
.step_by(2)
|
||||
.map(|idx| {
|
||||
let id = grown.nodes[idx];
|
||||
let was = warm.rsc.widgets().is_region_node(id);
|
||||
warm.rsc.widgets_mut().set_region_node(id, !was);
|
||||
(idx, !was)
|
||||
})
|
||||
.collect();
|
||||
warm.frame();
|
||||
|
||||
let mut cold = Harness::new((900, 1200));
|
||||
let same = plant(
|
||||
&mut cold,
|
||||
seed,
|
||||
&Edits {
|
||||
nodes,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
assert_same(
|
||||
seed,
|
||||
"a region-node change",
|
||||
(&warm, &grown),
|
||||
(&cold, &same),
|
||||
);
|
||||
}
|
||||
|
||||
fn reshuffled(seed: u64, shuffle: Shuffle) {
|
||||
let mut warm = Harness::new((900, 1200));
|
||||
let mut grown = plant(&mut warm, seed, &Edits::default());
|
||||
@@ -411,6 +499,16 @@ fn a_changed_size_lands_where_growing_it_that_way_would() {
|
||||
SEEDS.into_iter().for_each(changed_size);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_changed_alignment_lands_where_growing_it_that_way_would() {
|
||||
SEEDS.into_iter().for_each(changed_alignment);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_toggled_region_node_lands_where_growing_it_that_way_would() {
|
||||
SEEDS.into_iter().for_each(changed_region_node);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_size_changing_at_once_lands_where_growing_it_that_way_would() {
|
||||
SEEDS.into_iter().for_each(changed_every_size);
|
||||
|
||||
Reference in new issue
Block a user