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
+68
-16
@@ -11,6 +11,10 @@ use std::collections::HashMap;
|
||||
/// The declared lengths of one widget carrying a size rule, by axis.
|
||||
pub type Lens = [Option<Len>; 2];
|
||||
|
||||
/// Where one widget carrying an alignment sits, by axis. `None` uses the
|
||||
/// centered default.
|
||||
pub type Aligns = [Option<AxisAlign>; 2];
|
||||
|
||||
/// What a test changes between two trees grown from the same seed, so the
|
||||
/// warm one can be mutated and the cold one grown that way to begin with.
|
||||
#[derive(Default)]
|
||||
@@ -19,6 +23,12 @@ pub struct Edits {
|
||||
pub sizes: HashMap<usize, Lens>,
|
||||
/// Which children a span has, by the order the spans were made.
|
||||
pub spans: HashMap<usize, SpanEdit>,
|
||||
/// Alignments, by the order they were put on.
|
||||
pub aligns: HashMap<usize, Aligns>,
|
||||
/// Which widgets own a movable region, by the order they were offered
|
||||
/// one. Region nodes change what a move writes and how deep a primitive's
|
||||
/// chain is, so a tree that never grows one leaves both untested.
|
||||
pub nodes: HashMap<usize, bool>,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
@@ -76,6 +86,8 @@ const WORDS: &str = "Wrapping shapes one source into as many lines as the box \
|
||||
pub struct Tree {
|
||||
pub ids: Vec<WidgetId>,
|
||||
pub sized: Vec<WidgetId>,
|
||||
pub aligned: Vec<WidgetId>,
|
||||
pub nodes: Vec<WidgetId>,
|
||||
pub spans: Vec<Spanned>,
|
||||
pub scrolls: Vec<WeakWidget<Scroll>>,
|
||||
/// Children a `SpanEdit` took out, held so that dropping the last share
|
||||
@@ -180,26 +192,32 @@ impl<Rsc: UiRsc + 'static> Grow<'_, Rsc> {
|
||||
fn align(&mut self) -> Align {
|
||||
let mut axis = || match self.rng.below(4) {
|
||||
0 => None,
|
||||
1 => Some(AxisAlign::Neg),
|
||||
2 => Some(AxisAlign::Center),
|
||||
_ => Some(AxisAlign::Pos),
|
||||
1 => Some(AxisAlign::NEG),
|
||||
2 => Some(AxisAlign::CENTER),
|
||||
_ => Some(AxisAlign::POS),
|
||||
};
|
||||
let (mut x, y) = (axis(), axis());
|
||||
// Aligning on neither axis is just another transparent wrapper and
|
||||
// would leave this branch unexercised.
|
||||
// Aligning on neither axis leaves the branch unexercised.
|
||||
if x.is_none() && y.is_none() {
|
||||
x = Some(AxisAlign::Center);
|
||||
x = Some(AxisAlign::CENTER);
|
||||
}
|
||||
Align { x, y }
|
||||
}
|
||||
|
||||
/// A declared size over half the tree, kept where a test can change it.
|
||||
fn sized(&mut self, inner: StrongWidget) -> StrongWidget {
|
||||
if !self.rng.chance() {
|
||||
// A rule is a property now, so a node already carrying one would take
|
||||
// a second entry in `sized` -- and two edits naming one widget settle
|
||||
// in the order they are applied, which is grow order cold and edit
|
||||
// order warm. One entry per widget instead. Both draws are taken
|
||||
// whatever is decided, and the decision is grow order alone, so the
|
||||
// two trees consume the same random stream.
|
||||
let take = self.rng.chance();
|
||||
let lens = [self.len(), self.len()];
|
||||
if !take || self.tree.sized.contains(&inner.id()) {
|
||||
return inner;
|
||||
}
|
||||
let idx = self.tree.sized.len();
|
||||
let lens = [self.len(), self.len()];
|
||||
let lens = self.edits.sizes.get(&idx).copied().unwrap_or(lens);
|
||||
let id = inner.id();
|
||||
self.rsc
|
||||
@@ -210,6 +228,41 @@ impl<Rsc: UiRsc + 'static> Grow<'_, Rsc> {
|
||||
inner
|
||||
}
|
||||
|
||||
/// An alignment over some of the tree, kept where a test can change it.
|
||||
/// One entry per widget for the reason `sized` gives.
|
||||
fn aligned(&mut self, inner: StrongWidget) -> StrongWidget {
|
||||
let align = self.align();
|
||||
let align = [align.x, align.y];
|
||||
if self.tree.aligned.contains(&inner.id()) {
|
||||
return inner;
|
||||
}
|
||||
let idx = self.tree.aligned.len();
|
||||
let align = self.edits.aligns.get(&idx).copied().unwrap_or(align);
|
||||
let id = inner.id();
|
||||
let widgets = &mut self.rsc.ui_mut().widgets;
|
||||
for (axis, align) in [Axis::X, Axis::Y].into_iter().zip(align) {
|
||||
widgets.set_alignment(id, axis, align.unwrap_or_default());
|
||||
}
|
||||
self.tree.aligned.push(id);
|
||||
inner
|
||||
}
|
||||
|
||||
/// A movable region of its own over some of the tree. What it changes is
|
||||
/// how a move is written and how long a primitive's chain is, neither of
|
||||
/// which any other branch here varies.
|
||||
fn noded(&mut self, inner: StrongWidget) -> StrongWidget {
|
||||
let take = self.rng.below(4) == 0;
|
||||
if self.tree.nodes.contains(&inner.id()) {
|
||||
return inner;
|
||||
}
|
||||
let idx = self.tree.nodes.len();
|
||||
let take = self.edits.nodes.get(&idx).copied().unwrap_or(take);
|
||||
let id = inner.id();
|
||||
self.rsc.ui_mut().widgets.set_region_node(id, take);
|
||||
self.tree.nodes.push(id);
|
||||
inner
|
||||
}
|
||||
|
||||
fn node(&mut self, depth: usize) -> StrongWidget {
|
||||
if depth == 0 {
|
||||
return self.leaf();
|
||||
@@ -220,6 +273,7 @@ impl<Rsc: UiRsc + 'static> Grow<'_, Rsc> {
|
||||
// else here does, and gives its child a box longer than its own.
|
||||
let inner = self.node(depth - 1);
|
||||
let inner = self.sized(inner);
|
||||
let inner = self.noded(inner);
|
||||
let axis = if self.rng.chance() { Axis::X } else { Axis::Y };
|
||||
let id = Scroll::new(inner, axis).add(self.rsc);
|
||||
self.tree.scrolls.push(id);
|
||||
@@ -246,17 +300,13 @@ impl<Rsc: UiRsc + 'static> Grow<'_, Rsc> {
|
||||
if positioned == 1 {
|
||||
let inner = self.node(depth - 1);
|
||||
let inner = self.sized(inner);
|
||||
let id = Aligned {
|
||||
inner,
|
||||
align: self.align(),
|
||||
}
|
||||
.add_strong(self.rsc);
|
||||
self.tree.ids.push(id.id());
|
||||
return id;
|
||||
let inner = self.noded(inner);
|
||||
return self.aligned(inner);
|
||||
}
|
||||
if self.rng.below(4) == 0 {
|
||||
let inner = self.node(depth - 1);
|
||||
let inner = self.sized(inner);
|
||||
let inner = self.noded(inner);
|
||||
// Each side its own, since a padding that is the same all round
|
||||
// hides anything that treats one edge differently from another.
|
||||
let mut side = || self.rng.below(24) as f32;
|
||||
@@ -274,7 +324,9 @@ impl<Rsc: UiRsc + 'static> Grow<'_, Rsc> {
|
||||
let mut children = Vec::with_capacity(grown);
|
||||
for _ in 0..grown {
|
||||
let child = self.node(depth - 1);
|
||||
children.push(self.sized(child));
|
||||
let child = self.sized(child);
|
||||
let child = self.noded(child);
|
||||
children.push(child);
|
||||
}
|
||||
if self.rng.chance() {
|
||||
let id = Stack {
|
||||
|
||||
Reference in new issue
Block a user