diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-05-28 00:26:24 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-05-28 00:26:24 +0200 |
| commit | 90be79dc864c776a4d6f6739af671d4ea8407549 (patch) | |
| tree | 27de49da69a388d244c3786bd326d79694cd8e83 /src | |
| parent | 1a7ce3da02a25900dcdc09c110fe00229fd193d4 (diff) | |
Page background and foreground
Diffstat (limited to 'src')
| -rw-r--r-- | src/frame.rs | 88 | ||||
| -rw-r--r-- | src/library/layout/page.rs | 35 |
2 files changed, 78 insertions, 45 deletions
diff --git a/src/frame.rs b/src/frame.rs index 2a16b6f2..1bd1f454 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -37,6 +37,34 @@ impl Frame { self.baseline.unwrap_or(self.size.y) } + /// The layer the next item will be added on. This corresponds to the number + /// of elements in the frame. + pub fn layer(&self) -> usize { + self.elements.len() + } + + /// Whether the frame has comparatively few elements. + pub fn is_light(&self) -> bool { + self.elements.len() <= 5 + } + + /// Add an element at a position in the foreground. + pub fn push(&mut self, pos: Point, element: Element) { + self.elements.push((pos, element)); + } + + /// Add a frame. + /// + /// Automatically decides whether to inline the frame or to include it as a + /// group based on the number of elements in the frame. + pub fn push_frame(&mut self, pos: Point, frame: impl FrameRepr) { + if self.elements.is_empty() || frame.as_ref().is_light() { + frame.inline(self, self.layer(), pos); + } else { + self.elements.push((pos, Element::Group(Group::new(frame.share())))); + } + } + /// Add an element at a position in the background. pub fn prepend(&mut self, pos: Point, element: Element) { self.elements.insert(0, (pos, element)); @@ -50,15 +78,14 @@ impl Frame { self.elements.splice(0 .. 0, insert); } - /// Add an element at a position in the foreground. - pub fn push(&mut self, pos: Point, element: Element) { - self.elements.push((pos, element)); - } - - /// The layer the next item will be added on. This corresponds to the number - /// of elements in the frame. - pub fn layer(&self) -> usize { - self.elements.len() + /// Add a frame at a position in the background. + pub fn prepend_frame(&mut self, pos: Point, frame: impl FrameRepr) { + if self.elements.is_empty() || frame.as_ref().is_light() { + frame.inline(self, 0, pos); + } else { + self.elements + .insert(0, (pos, Element::Group(Group::new(frame.share())))); + } } /// Insert an element at the given layer in the frame. @@ -68,18 +95,6 @@ impl Frame { self.elements.insert(layer, (pos, element)); } - /// Add a frame. - /// - /// Automatically decides whether to inline the frame or to include it as a - /// group based on the number of elements in the frame. - pub fn push_frame(&mut self, pos: Point, frame: impl FrameRepr) { - if self.elements.is_empty() || frame.as_ref().elements.len() <= 5 { - frame.inline(self, pos); - } else { - self.elements.push((pos, Element::Group(Group::new(frame.share())))); - } - } - /// Resize the frame to a new size, distributing new space according to the /// given alignments. pub fn resize(&mut self, target: Size, aligns: Spec<Align>) { @@ -153,7 +168,7 @@ pub trait FrameRepr: AsRef<Frame> { fn share(self) -> Arc<Frame>; /// Inline `self` into the sink frame. - fn inline(self, sink: &mut Frame, offset: Point); + fn inline(self, sink: &mut Frame, layer: usize, offset: Point); } impl FrameRepr for Frame { @@ -161,16 +176,18 @@ impl FrameRepr for Frame { Arc::new(self) } - fn inline(self, sink: &mut Frame, offset: Point) { + fn inline(self, sink: &mut Frame, layer: usize, offset: Point) { if offset.is_zero() { if sink.elements.is_empty() { sink.elements = self.elements; } else { - sink.elements.extend(self.elements); + sink.elements.splice(layer .. layer, self.elements); } } else { - sink.elements - .extend(self.elements.into_iter().map(|(p, e)| (p + offset, e))); + sink.elements.splice( + layer .. layer, + self.elements.into_iter().map(|(p, e)| (p + offset, e)), + ); } } } @@ -180,12 +197,15 @@ impl FrameRepr for Arc<Frame> { self } - fn inline(self, sink: &mut Frame, offset: Point) { + fn inline(self, sink: &mut Frame, layer: usize, offset: Point) { match Arc::try_unwrap(self) { - Ok(frame) => frame.inline(sink, offset), - Err(rc) => sink - .elements - .extend(rc.elements.iter().cloned().map(|(p, e)| (p + offset, e))), + Ok(frame) => frame.inline(sink, layer, offset), + Err(rc) => { + sink.elements.splice( + layer .. layer, + rc.elements.iter().cloned().map(|(p, e)| (p + offset, e)), + ); + } } } } @@ -198,10 +218,10 @@ impl FrameRepr for MaybeShared<Frame> { } } - fn inline(self, sink: &mut Frame, offset: Point) { + fn inline(self, sink: &mut Frame, layer: usize, offset: Point) { match self { - Self::Owned(owned) => owned.inline(sink, offset), - Self::Shared(shared) => shared.inline(sink, offset), + Self::Owned(owned) => owned.inline(sink, layer, offset), + Self::Shared(shared) => shared.inline(sink, layer, offset), } } } diff --git a/src/library/layout/page.rs b/src/library/layout/page.rs index 7d91aa6d..8435e510 100644 --- a/src/library/layout/page.rs +++ b/src/library/layout/page.rs @@ -34,6 +34,12 @@ impl PageNode { /// The page's footer. #[property(referenced)] pub const FOOTER: Marginal = Marginal::None; + /// Content in the page's background. + #[property(referenced)] + pub const BACKGROUND: Marginal = Marginal::None; + /// Content in the page's foreground. + #[property(referenced)] + pub const FOREGROUND: Marginal = Marginal::None; fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> { Ok(Content::Page(Self(args.expect("body")?))) @@ -95,22 +101,29 @@ impl PageNode { let header = styles.get(Self::HEADER); let footer = styles.get(Self::FOOTER); + let foreground = styles.get(Self::FOREGROUND); + let background = styles.get(Self::BACKGROUND); - // Realize header and footer. + // Realize overlays. for frame in &mut frames { let size = frame.size; - let padding = padding.resolve(styles).relative_to(size); - for (y, h, marginal) in [ - (Length::zero(), padding.top, header), - (size.y - padding.bottom, padding.bottom, footer), + let pad = padding.resolve(styles).relative_to(size); + let pw = size.x - pad.left - pad.right; + let py = size.y - pad.bottom; + for (marginal, pos, area) in [ + (header, Point::with_x(pad.left), Size::new(pw, pad.top)), + (footer, Point::new(pad.left, py), Size::new(pw, pad.bottom)), + (foreground, Point::zero(), size), + (background, Point::zero(), size), ] { if let Some(content) = marginal.resolve(ctx, page)? { - let pos = Point::new(padding.left, y); - let w = size.x - padding.left - padding.right; - let area = Size::new(w, h); - let pod = Regions::one(area, area, area.map(Length::is_finite)); + let pod = Regions::one(area, area, Spec::splat(true)); let sub = content.layout(ctx, &pod, styles)?.remove(0); - Arc::make_mut(frame).push_frame(pos, sub); + if std::ptr::eq(marginal, background) { + Arc::make_mut(frame).prepend_frame(pos, sub); + } else { + Arc::make_mut(frame).push_frame(pos, sub); + } } } @@ -140,7 +153,7 @@ impl PagebreakNode { } } -/// A header or footer definition. +/// A header, footer, foreground or background definition. #[derive(Debug, Clone, PartialEq, Hash)] pub enum Marginal { /// Nothing, |
