diff options
| author | Martin <mhaug@live.de> | 2021-06-18 13:01:55 +0200 |
|---|---|---|
| committer | Martin <mhaug@live.de> | 2021-06-18 13:01:55 +0200 |
| commit | 80a9b300d1acb8821ac0600aad3d2135ad9587bd (patch) | |
| tree | 6626ba8891fa4db4e3a1cb13f7f4b27fc05989bf /src/layout/frame.rs | |
| parent | 7db78d83bedf62adea0d715c9a2a179ce23a1a48 (diff) | |
Ref count the frames
Diffstat (limited to 'src/layout/frame.rs')
| -rw-r--r-- | src/layout/frame.rs | 80 |
1 files changed, 69 insertions, 11 deletions
diff --git a/src/layout/frame.rs b/src/layout/frame.rs index 5e5bcfe8..b6cf4645 100644 --- a/src/layout/frame.rs +++ b/src/layout/frame.rs @@ -1,3 +1,5 @@ +use std::rc::Rc; + use serde::{Deserialize, Serialize}; use super::{Constrained, Constraints}; @@ -14,37 +16,93 @@ pub struct Frame { /// The baseline of the frame measured from the top. pub baseline: Length, /// The elements composing this layout. - pub elements: Vec<(Point, Element)>, + children: Vec<(Point, Child)>, +} + +/// An iterator over all elements in a frame, alongside with their positions. +#[derive(Debug, Clone)] +pub struct ElementIter<'a> { + stack: Vec<(usize, Point, &'a Frame)>, +} + +impl<'a> Iterator for ElementIter<'a> { + type Item = (Point, &'a Element); + + /// Get the next element, if any. + fn next(&mut self) -> Option<Self::Item> { + let (cursor, offset, frame) = self.stack.last_mut()?; + match frame.children.get(*cursor) { + Some((pos, Child::Frame(f))) => { + let new_offset = *offset + *pos; + self.stack.push((0, new_offset, f.as_ref())); + self.next() + } + Some((pos, Child::Element(e))) => { + *cursor += 1; + Some((*offset + *pos, e)) + } + None => { + self.stack.pop(); + if let Some((cursor, _, _)) = self.stack.last_mut() { + *cursor += 1; + } + self.next() + } + } + } } impl Frame { /// Create a new, empty frame. pub fn new(size: Size, baseline: Length) -> Self { assert!(size.is_finite()); - Self { size, baseline, elements: vec![] } + Self { size, baseline, children: vec![] } } - /// Add an element at a position. + /// Add an element at a position in the foreground. pub fn push(&mut self, pos: Point, element: Element) { - self.elements.push((pos, element)); + self.children.push((pos, Child::Element(element))); + } + + /// Add an element at a position in the background. + pub fn prepend(&mut self, pos: Point, element: Element) { + self.children.insert(0, (pos, Child::Element(element))) + } + + /// Add a frame element. + pub fn push_frame(&mut self, pos: Point, subframe: Rc<Self>) { + self.children.push((pos, Child::Frame(subframe))) } /// Add all elements of another frame, placing them relative to the given /// position. - pub fn push_frame(&mut self, pos: Point, subframe: Self) { - if pos == Point::zero() && self.elements.is_empty() { - self.elements = subframe.elements; + pub fn merge_frame(&mut self, pos: Point, subframe: Self) { + if pos == Point::zero() && self.children.is_empty() { + self.children = subframe.children; } else { - for (subpos, element) in subframe.elements { - self.push(pos + subpos, element); + for (subpos, child) in subframe.children { + self.children.push((pos + subpos, child)); } } } /// Wraps the frame with constraints. - pub fn constrain(self, constraints: Constraints) -> Constrained<Self> { - Constrained { item: self, constraints } + pub fn constrain(self, constraints: Constraints) -> Constrained<Rc<Self>> { + Constrained { item: Rc::new(self), constraints } } + + /// Returns an iterator over all elements in the frame and its children. + pub fn elements(&self) -> ElementIter { + ElementIter { stack: vec![(0, Point::zero(), self)] } + } +} + +/// A frame can contain multiple children: elements or other frames, complete +/// with their children. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +enum Child { + Element(Element), + Frame(Rc<Frame>), } /// The building block frames are composed of. |
