diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-04-30 14:12:28 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-04-30 14:12:28 +0200 |
| commit | f9e115daf54c29358f890b137f50a33a781af680 (patch) | |
| tree | 496de52246629ea8039db6beea94eb779ed2851d /src/model/collapse.rs | |
| parent | f7c67cde72e6a67f45180856b332bae9863243bd (diff) | |
New block spacing model
Diffstat (limited to 'src/model/collapse.rs')
| -rw-r--r-- | src/model/collapse.rs | 110 |
1 files changed, 91 insertions, 19 deletions
diff --git a/src/model/collapse.rs b/src/model/collapse.rs index 17933fe8..258f577e 100644 --- a/src/model/collapse.rs +++ b/src/model/collapse.rs @@ -35,26 +35,37 @@ impl<'a, T> CollapsingBuilder<'a, T> { } /// Can only exist when there is at least one supportive item to its left - /// and to its right, with no destructive items or weak items in between to - /// its left and no destructive items in between to its right. There may be + /// and to its right, with no destructive items in between. There may be /// ignorant items in between in both directions. - pub fn weak(&mut self, item: T, strength: u8, styles: StyleChain<'a>) { - if self.last != Last::Destructive { - if self.last == Last::Weak { - if let Some(i) = self - .staged - .iter() - .position(|(.., prev)| prev.map_or(false, |p| p < strength)) - { - self.staged.remove(i); - } else { - return; - } - } + /// + /// Between weak items, there may be at least one per layer and among the + /// candidates the strongest one (smallest `weakness`) wins. When tied, + /// the one that compares larger through `PartialOrd` wins. + pub fn weak(&mut self, item: T, styles: StyleChain<'a>, weakness: u8) + where + T: PartialOrd, + { + if self.last == Last::Destructive { + return; + } - self.staged.push((item, styles, Some(strength))); - self.last = Last::Weak; + if self.last == Last::Weak { + if let Some(i) = + self.staged.iter().position(|(prev_item, _, prev_weakness)| { + prev_weakness.map_or(false, |prev_weakness| { + weakness < prev_weakness + || (weakness == prev_weakness && item > *prev_item) + }) + }) + { + self.staged.remove(i); + } else { + return; + } } + + self.staged.push((item, styles, Some(weakness))); + self.last = Last::Weak; } /// Forces nearby weak items to collapse. @@ -90,8 +101,8 @@ impl<'a, T> CollapsingBuilder<'a, T> { /// Push the staged items, filtering out weak items if `supportive` is /// false. fn flush(&mut self, supportive: bool) { - for (item, styles, strength) in self.staged.drain(..) { - if supportive || strength.is_none() { + for (item, styles, meta) in self.staged.drain(..) { + if supportive || meta.is_none() { self.builder.push(item, styles); } } @@ -103,3 +114,64 @@ impl<'a, T> Default for CollapsingBuilder<'a, T> { Self::new() } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::library::layout::FlowChild; + use crate::library::prelude::*; + + #[track_caller] + fn test<T>(builder: CollapsingBuilder<T>, expected: &[T]) + where + T: Debug + PartialEq, + { + let result = builder.finish().0; + let items: Vec<_> = result.items().collect(); + let expected: Vec<_> = expected.iter().collect(); + assert_eq!(items, expected); + } + + fn node() -> FlowChild { + FlowChild::Node(Content::Text("Hi".into()).pack()) + } + + fn abs(pt: f64) -> FlowChild { + FlowChild::Spacing(Length::pt(pt).into()) + } + + #[test] + fn test_collapsing_weak() { + let mut builder = CollapsingBuilder::new(); + let styles = StyleChain::default(); + builder.weak(FlowChild::Colbreak, styles, 0); + builder.supportive(node(), styles); + builder.weak(abs(10.0), styles, 0); + builder.ignorant(FlowChild::Colbreak, styles); + builder.weak(abs(20.0), styles, 0); + builder.supportive(node(), styles); + builder.weak(abs(10.0), styles, 0); + builder.weak(abs(20.0), styles, 1); + builder.supportive(node(), styles); + test(builder, &[ + node(), + FlowChild::Colbreak, + abs(20.0), + node(), + abs(10.0), + node(), + ]); + } + + #[test] + fn test_collapsing_destructive() { + let mut builder = CollapsingBuilder::new(); + let styles = StyleChain::default(); + builder.supportive(node(), styles); + builder.weak(abs(10.0), styles, 0); + builder.destructive(FlowChild::Colbreak, styles); + builder.weak(abs(20.0), styles, 0); + builder.supportive(node(), styles); + test(builder, &[node(), FlowChild::Colbreak, node()]); + } +} |
