diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-11-09 18:16:59 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-11-09 18:20:02 +0100 |
| commit | 010cc2effc2fd0e1c4e52d5c914cb4d74506bc0a (patch) | |
| tree | e50060d271f076b00945e5569e7f8ffef2c28e9f /src/model/styles.rs | |
| parent | 12a59963b08b68cc39dcded4d3d3e6a6631c2732 (diff) | |
New block spacing model
Diffstat (limited to 'src/model/styles.rs')
| -rw-r--r-- | src/model/styles.rs | 86 |
1 files changed, 50 insertions, 36 deletions
diff --git a/src/model/styles.rs b/src/model/styles.rs index 62e3188f..98763c50 100644 --- a/src/model/styles.rs +++ b/src/model/styles.rs @@ -148,7 +148,7 @@ pub enum StyleEntry { /// A show rule recipe. Recipe(Recipe), /// A barrier for scoped styles. - Barrier(Barrier), + Barrier(NodeId), /// Guards against recursive show rules. Guard(RecipeId), /// Allows recursive show rules again. @@ -158,11 +158,11 @@ pub enum StyleEntry { impl StyleEntry { /// Make this style the first link of the `tail` chain. pub fn chain<'a>(&'a self, tail: &'a StyleChain) -> StyleChain<'a> { - if let StyleEntry::Barrier(barrier) = self { + if let StyleEntry::Barrier(id) = self { if !tail .entries() .filter_map(StyleEntry::property) - .any(|p| p.scoped() && barrier.is_for(p.node())) + .any(|p| p.scoped() && *id == p.node()) { return *tail; } @@ -203,7 +203,7 @@ impl Debug for StyleEntry { match self { Self::Property(property) => property.fmt(f)?, Self::Recipe(recipe) => recipe.fmt(f)?, - Self::Barrier(barrier) => barrier.fmt(f)?, + Self::Barrier(id) => write!(f, "Barrier for {id:?}")?, Self::Guard(sel) => write!(f, "Guard against {sel:?}")?, Self::Unguard(sel) => write!(f, "Unguard against {sel:?}")?, } @@ -246,6 +246,34 @@ impl<'a> StyleChain<'a> { K::get(self, self.values(key)) } + /// Whether the style chain has a matching recipe for the content. + pub fn applicable(self, content: &Content) -> bool { + let target = Target::Node(content); + + // Find out how many recipes there any and whether any of them match. + let mut n = 0; + let mut any = true; + for recipe in self.entries().filter_map(StyleEntry::recipe) { + n += 1; + any |= recipe.applicable(target); + } + + // Find an applicable recipe. + if any { + for recipe in self.entries().filter_map(StyleEntry::recipe) { + if recipe.applicable(target) { + let sel = RecipeId::Nth(n); + if !self.guarded(sel) { + return true; + } + } + n -= 1; + } + } + + false + } + /// Apply show recipes in this style chain to a target. pub fn apply( self, @@ -292,6 +320,7 @@ impl<'a> StyleChain<'a> { .to::<dyn Show>() .unwrap() .show(world, self)?; + realized = Some(content.styled_with_entry(StyleEntry::Guard(sel))); } } @@ -342,8 +371,9 @@ impl<'a> StyleChain<'a> { fn values<K: Key<'a>>(self, _: K) -> Values<'a, K> { Values { entries: self.entries(), - depth: 0, key: PhantomData, + barriers: 0, + guarded: false, } } @@ -379,8 +409,9 @@ impl PartialEq for StyleChain<'_> { /// An iterator over the values in a style chain. struct Values<'a, K> { entries: Entries<'a>, - depth: usize, key: PhantomData<K>, + barriers: usize, + guarded: bool, } impl<'a, K: Key<'a>> Iterator for Values<'a, K> { @@ -391,13 +422,22 @@ impl<'a, K: Key<'a>> Iterator for Values<'a, K> { match entry { StyleEntry::Property(property) => { if let Some(value) = property.downcast::<K>() { - if !property.scoped() || self.depth <= 1 { + if !property.scoped() + || if self.guarded { + self.barriers == 1 + } else { + self.barriers <= 1 + } + { return Some(value); } } } - StyleEntry::Barrier(barrier) => { - self.depth += barrier.is_for(K::node()) as usize; + StyleEntry::Barrier(id) => { + self.barriers += (*id == K::node()) as usize; + } + StyleEntry::Guard(RecipeId::Base(id)) => { + self.guarded |= *id == K::node(); } _ => {} } @@ -444,7 +484,7 @@ impl<'a> Iterator for Links<'a> { } /// A sequence of items with associated styles. -#[derive(Hash)] +#[derive(Clone, Hash)] pub struct StyleVec<T> { items: Vec<T>, maps: Vec<(StyleMap, usize)>, @@ -758,32 +798,6 @@ impl Debug for KeyId { } } -/// A scoped property barrier. -/// -/// Barriers interact with [scoped](super::StyleMap::scoped) styles: A scoped -/// style can still be read through a single barrier (the one of the node it -/// _should_ apply to), but a second barrier will make it invisible. -#[derive(Copy, Clone, Eq, PartialEq, Hash)] -pub struct Barrier(NodeId); - -impl Barrier { - /// Create a new barrier for the given node. - pub fn new(node: NodeId) -> Self { - Self(node) - } - - /// Whether this barrier is for the node `T`. - pub fn is_for(&self, node: NodeId) -> bool { - self.0 == node - } -} - -impl Debug for Barrier { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "Barrier for {:?}", self.0) - } -} - /// A property that is resolved with other properties from the style chain. pub trait Resolve { /// The type of the resolved output. |
