summaryrefslogtreecommitdiff
path: root/src/layout/frame.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/layout/frame.rs')
-rw-r--r--src/layout/frame.rs80
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.