summaryrefslogtreecommitdiff
path: root/src/layout
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-01-17 16:01:01 +0100
committerLaurenz <laurmaedje@gmail.com>2022-01-17 16:01:01 +0100
commit0c5243fa802d8133d75c0823c3efa6f14794ba60 (patch)
treee8554c25aa9d5c3ec33c9b4d6de56f1c97d30eff /src/layout
parent4abdafcd158ab15d9d2ae18553067578ae559d33 (diff)
Basic tables
Diffstat (limited to 'src/layout')
-rw-r--r--src/layout/mod.rs120
1 files changed, 117 insertions, 3 deletions
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index cb6f1348..d563dafb 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -17,10 +17,10 @@ use std::rc::Rc;
use crate::eval::{StyleChain, Styled};
use crate::font::FontStore;
-use crate::frame::Frame;
-use crate::geom::{Align, Linear, Point, Sides, Size, Spec};
+use crate::frame::{Element, Frame, Geometry, Shape, Stroke};
+use crate::geom::{Align, Linear, Paint, Point, Sides, Size, Spec};
use crate::image::ImageStore;
-use crate::library::{AlignNode, Move, PadNode, PageNode, SizedNode, TransformNode};
+use crate::library::{AlignNode, Move, PadNode, PageNode, TransformNode};
use crate::Context;
/// The root layout node, a document consisting of top-level page runs.
@@ -153,6 +153,16 @@ impl PackedNode {
}
}
+ /// Fill the frames resulting from a node.
+ pub fn filled(self, fill: Paint) -> Self {
+ FillNode { fill, child: self }.pack()
+ }
+
+ /// Stroke the frames resulting from a node.
+ pub fn stroked(self, stroke: Stroke) -> Self {
+ StrokeNode { stroke, child: self }.pack()
+ }
+
/// Set alignments for this node.
pub fn aligned(self, aligns: Spec<Option<Align>>) -> Self {
if aligns.any(Option::is_some) {
@@ -294,3 +304,107 @@ where
state.finish()
}
}
+
+/// A node that sizes its child.
+#[derive(Debug, Hash)]
+pub struct SizedNode {
+ /// How to size the node horizontally and vertically.
+ pub sizing: Spec<Option<Linear>>,
+ /// The node to be sized.
+ pub child: PackedNode,
+}
+
+impl Layout for SizedNode {
+ fn layout(
+ &self,
+ ctx: &mut LayoutContext,
+ regions: &Regions,
+ styles: StyleChain,
+ ) -> Vec<Constrained<Rc<Frame>>> {
+ let is_auto = self.sizing.map_is_none();
+ let is_rel = self.sizing.map(|s| s.map_or(false, Linear::is_relative));
+
+ // The "pod" is the region into which the child will be layouted.
+ let pod = {
+ // Resolve the sizing to a concrete size.
+ let size = self
+ .sizing
+ .zip(regions.base)
+ .map(|(s, b)| s.map(|v| v.resolve(b)))
+ .unwrap_or(regions.current);
+
+ // Select the appropriate base and expansion for the child depending
+ // on whether it is automatically or linearly sized.
+ let base = is_auto.select(regions.base, size);
+ let expand = regions.expand | !is_auto;
+
+ Regions::one(size, base, expand)
+ };
+
+ let mut frames = self.child.layout(ctx, &pod, styles);
+ let Constrained { item: frame, cts } = &mut frames[0];
+
+ // Ensure frame size matches regions size if expansion is on.
+ let target = regions.expand.select(regions.current, frame.size);
+ Rc::make_mut(frame).resize(target, Align::LEFT_TOP);
+
+ // Set base & exact constraints if the child is automatically sized
+ // since we don't know what the child might have done. Also set base if
+ // our sizing is relative.
+ *cts = Constraints::new(regions.expand);
+ cts.exact = regions.current.filter(regions.expand | is_auto);
+ cts.base = regions.base.filter(is_rel | is_auto);
+
+ frames
+ }
+}
+
+/// Fill the frames resulting from a node.
+#[derive(Debug, Hash)]
+pub struct FillNode {
+ /// How to fill the frames resulting from the `child`.
+ pub fill: Paint,
+ /// The node to fill.
+ pub child: PackedNode,
+}
+
+impl Layout for FillNode {
+ fn layout(
+ &self,
+ ctx: &mut LayoutContext,
+ regions: &Regions,
+ styles: StyleChain,
+ ) -> Vec<Constrained<Rc<Frame>>> {
+ let mut frames = self.child.layout(ctx, regions, styles);
+ for Constrained { item: frame, .. } in &mut frames {
+ let shape = Shape::filled(Geometry::Rect(frame.size), self.fill);
+ Rc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape));
+ }
+ frames
+ }
+}
+
+/// Stroke the frames resulting from a node.
+#[derive(Debug, Hash)]
+pub struct StrokeNode {
+ /// How to stroke the frames resulting from the `child`.
+ pub stroke: Stroke,
+ /// The node to stroke.
+ pub child: PackedNode,
+}
+
+impl Layout for StrokeNode {
+ fn layout(
+ &self,
+ ctx: &mut LayoutContext,
+ regions: &Regions,
+ styles: StyleChain,
+ ) -> Vec<Constrained<Rc<Frame>>> {
+ let mut frames = self.child.layout(ctx, regions, styles);
+ for Constrained { item: frame, .. } in &mut frames {
+ let shape = Shape::stroked(Geometry::Rect(frame.size), self.stroke);
+ Rc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape));
+ }
+ frames
+ }
+}