summaryrefslogtreecommitdiff
path: root/src/library/layout
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-11-01 16:56:35 +0100
committerLaurenz <laurmaedje@gmail.com>2022-11-02 09:18:33 +0100
commit37ac5d966ebaf97ac79c507028cd5b742b510b89 (patch)
tree249d43ff0f8d880cb5d00c236993f8ff0c1f10d8 /src/library/layout
parentf547c97072881069417acd3b79b08fb7ecf40ba2 (diff)
More dynamic content representation
Diffstat (limited to 'src/library/layout')
-rw-r--r--src/library/layout/align.rs26
-rw-r--r--src/library/layout/columns.rs24
-rw-r--r--src/library/layout/container.rs78
-rw-r--r--src/library/layout/flow.rs15
-rw-r--r--src/library/layout/grid.rs28
-rw-r--r--src/library/layout/pad.rs14
-rw-r--r--src/library/layout/page.rs17
-rw-r--r--src/library/layout/place.rs16
-rw-r--r--src/library/layout/spacing.rs17
-rw-r--r--src/library/layout/stack.rs26
-rw-r--r--src/library/layout/transform.rs30
11 files changed, 207 insertions, 84 deletions
diff --git a/src/library/layout/align.rs b/src/library/layout/align.rs
index 95f5c01f..f49763b5 100644
--- a/src/library/layout/align.rs
+++ b/src/library/layout/align.rs
@@ -7,21 +7,25 @@ pub struct AlignNode {
/// How to align the node horizontally and vertically.
pub aligns: Axes<Option<RawAlign>>,
/// The node to be aligned.
- pub child: LayoutNode,
+ pub child: Content,
}
-#[node]
+#[node(Layout)]
impl AlignNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
let aligns: Axes<Option<RawAlign>> = args.find()?.unwrap_or_default();
let body: Content = args.expect("body")?;
- Ok(match (body, aligns) {
- (Content::Block(node), _) => Content::Block(node.aligned(aligns)),
- (other, Axes { x: Some(x), y: None }) => {
- other.styled(ParNode::ALIGN, HorizontalAlign(x))
+
+ if let Axes { x: Some(x), y: None } = aligns {
+ if body
+ .to::<dyn Layout>()
+ .map_or(true, |node| node.level() == Level::Inline)
+ {
+ return Ok(body.styled(ParNode::ALIGN, HorizontalAlign(x)));
}
- (other, _) => Content::Block(other.pack().aligned(aligns)),
- })
+ }
+
+ Ok(body.aligned(aligns))
}
}
@@ -43,7 +47,7 @@ impl Layout for AlignNode {
}
// Layout the child.
- let mut frames = self.child.layout(world, &pod, passed.chain(&styles))?;
+ let mut frames = self.child.layout_block(world, &pod, passed.chain(&styles))?;
for (region, frame) in regions.iter().zip(&mut frames) {
// Align in the target size. The target size depends on whether we
// should expand.
@@ -58,4 +62,8 @@ impl Layout for AlignNode {
Ok(frames)
}
+
+ fn level(&self) -> Level {
+ Level::Block
+ }
}
diff --git a/src/library/layout/columns.rs b/src/library/layout/columns.rs
index 3ba3598c..79d98e11 100644
--- a/src/library/layout/columns.rs
+++ b/src/library/layout/columns.rs
@@ -8,20 +8,21 @@ pub struct ColumnsNode {
pub columns: NonZeroUsize,
/// The child to be layouted into the columns. Most likely, this should be a
/// flow or stack node.
- pub child: LayoutNode,
+ pub child: Content,
}
-#[node]
+#[node(Layout)]
impl ColumnsNode {
/// The size of the gutter space between each column.
#[property(resolve)]
pub const GUTTER: Rel<Length> = Ratio::new(0.04).into();
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
- Ok(Content::block(Self {
+ Ok(Self {
columns: args.expect("column count")?,
child: args.expect("body")?,
- }))
+ }
+ .pack())
}
}
@@ -35,7 +36,7 @@ impl Layout for ColumnsNode {
// Separating the infinite space into infinite columns does not make
// much sense.
if !regions.first.x.is_finite() {
- return self.child.layout(world, regions, styles);
+ return self.child.layout_block(world, regions, styles);
}
// Determine the width of the gutter and each column.
@@ -57,7 +58,7 @@ impl Layout for ColumnsNode {
};
// Layout the children.
- let mut frames = self.child.layout(world, &pod, styles)?.into_iter();
+ let mut frames = self.child.layout_block(world, &pod, styles)?.into_iter();
let mut finished = vec![];
let dir = styles.get(TextNode::DIR);
@@ -99,15 +100,22 @@ impl Layout for ColumnsNode {
Ok(finished)
}
+
+ fn level(&self) -> Level {
+ Level::Block
+ }
}
/// A column break.
-pub struct ColbreakNode;
+#[derive(Debug, Clone, Hash)]
+pub struct ColbreakNode {
+ pub weak: bool,
+}
#[node]
impl ColbreakNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
let weak = args.named("weak")?.unwrap_or(false);
- Ok(Content::Colbreak { weak })
+ Ok(Self { weak }.pack())
}
}
diff --git a/src/library/layout/container.rs b/src/library/layout/container.rs
index 9b1f8f56..60f9139b 100644
--- a/src/library/layout/container.rs
+++ b/src/library/layout/container.rs
@@ -1,24 +1,88 @@
use crate::library::prelude::*;
/// An inline-level container that sizes content and places it into a paragraph.
-pub struct BoxNode;
+#[derive(Debug, Clone, Hash)]
+pub struct BoxNode {
+ /// How to size the node horizontally and vertically.
+ pub sizing: Axes<Option<Rel<Length>>>,
+ /// The node to be sized.
+ pub child: Content,
+}
-#[node]
+#[node(Layout)]
impl BoxNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
let width = args.named("width")?;
let height = args.named("height")?;
- let body: LayoutNode = args.eat()?.unwrap_or_default();
- Ok(Content::inline(body.sized(Axes::new(width, height))))
+ let body = args.eat::<Content>()?.unwrap_or_default();
+ Ok(body.boxed(Axes::new(width, height)))
+ }
+}
+
+impl Layout for BoxNode {
+ fn layout(
+ &self,
+ world: Tracked<dyn World>,
+ regions: &Regions,
+ styles: StyleChain,
+ ) -> SourceResult<Vec<Frame>> {
+ // 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
+ .resolve(styles)
+ .zip(regions.base)
+ .map(|(s, b)| s.map(|v| v.relative_to(b)))
+ .unwrap_or(regions.first);
+
+ // Select the appropriate base and expansion for the child depending
+ // on whether it is automatically or relatively sized.
+ let is_auto = self.sizing.as_ref().map(Option::is_none);
+ let base = is_auto.select(regions.base, size);
+ let expand = regions.expand | !is_auto;
+
+ Regions::one(size, base, expand)
+ };
+
+ // Layout the child.
+ let mut frames = self.child.layout_inline(world, &pod, styles)?;
+
+ // Ensure frame size matches regions size if expansion is on.
+ let frame = &mut frames[0];
+ let target = regions.expand.select(regions.first, frame.size());
+ frame.resize(target, Align::LEFT_TOP);
+
+ Ok(frames)
+ }
+
+ fn level(&self) -> Level {
+ Level::Inline
}
}
/// A block-level container that places content into a separate flow.
-pub struct BlockNode;
+#[derive(Debug, Clone, Hash)]
+pub struct BlockNode(pub Content);
-#[node]
+#[node(Layout)]
impl BlockNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
- Ok(Content::Block(args.eat()?.unwrap_or_default()))
+ Ok(Self(args.eat()?.unwrap_or_default()).pack())
+ }
+}
+
+impl Layout for BlockNode {
+ fn layout(
+ &self,
+ world: Tracked<dyn World>,
+ regions: &Regions,
+ styles: StyleChain,
+ ) -> SourceResult<Vec<Frame>> {
+ self.0.layout_block(world, regions, styles)
+ }
+
+ fn level(&self) -> Level {
+ Level::Block
}
}
diff --git a/src/library/layout/flow.rs b/src/library/layout/flow.rs
index 1f0a2b4a..01ee9dc9 100644
--- a/src/library/layout/flow.rs
+++ b/src/library/layout/flow.rs
@@ -17,11 +17,14 @@ pub enum FlowChild {
/// Vertical spacing between other children.
Spacing(Spacing),
/// An arbitrary block-level node.
- Node(LayoutNode),
+ Node(Content),
/// A column / region break.
Colbreak,
}
+#[node(Layout)]
+impl FlowNode {}
+
impl Layout for FlowNode {
fn layout(
&self,
@@ -48,6 +51,10 @@ impl Layout for FlowNode {
Ok(layouter.finish())
}
+
+ fn level(&self) -> Level {
+ Level::Block
+ }
}
impl Debug for FlowNode {
@@ -150,7 +157,7 @@ impl FlowLayouter {
pub fn layout_node(
&mut self,
world: Tracked<dyn World>,
- node: &LayoutNode,
+ node: &Content,
styles: StyleChain,
) -> SourceResult<()> {
// Don't even try layouting into a full region.
@@ -162,7 +169,7 @@ impl FlowLayouter {
// aligned later.
if let Some(placed) = node.downcast::<PlaceNode>() {
if placed.out_of_flow() {
- let frame = node.layout(world, &self.regions, styles)?.remove(0);
+ let frame = node.layout_block(world, &self.regions, styles)?.remove(0);
self.items.push(FlowItem::Placed(frame));
return Ok(());
}
@@ -180,7 +187,7 @@ impl FlowLayouter {
.unwrap_or(Align::Top),
);
- let frames = node.layout(world, &self.regions, styles)?;
+ let frames = node.layout_block(world, &self.regions, styles)?;
let len = frames.len();
for (i, mut frame) in frames.into_iter().enumerate() {
// Set the generic block role.
diff --git a/src/library/layout/grid.rs b/src/library/layout/grid.rs
index a1098c6d..7e5cbbd5 100644
--- a/src/library/layout/grid.rs
+++ b/src/library/layout/grid.rs
@@ -8,10 +8,10 @@ pub struct GridNode {
/// Defines sizing of gutter rows and columns between content.
pub gutter: Axes<Vec<TrackSizing>>,
/// The nodes to be arranged in a grid.
- pub cells: Vec<LayoutNode>,
+ pub cells: Vec<Content>,
}
-#[node]
+#[node(Layout)]
impl GridNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
let columns = args.named("columns")?.unwrap_or_default();
@@ -19,14 +19,15 @@ impl GridNode {
let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default();
let column_gutter = args.named("column-gutter")?;
let row_gutter = args.named("row-gutter")?;
- Ok(Content::block(Self {
+ Ok(Self {
tracks: Axes::new(columns, rows),
gutter: Axes::new(
column_gutter.unwrap_or_else(|| base_gutter.clone()),
row_gutter.unwrap_or(base_gutter),
),
cells: args.all()?,
- }))
+ }
+ .pack())
}
}
@@ -50,6 +51,10 @@ impl Layout for GridNode {
// Measure the columns and layout the grid row-by-row.
layouter.layout()
}
+
+ fn level(&self) -> Level {
+ Level::Block
+ }
}
/// Defines how to size a grid cell along an axis.
@@ -95,7 +100,7 @@ pub struct GridLayouter<'a> {
/// The core context.
world: Tracked<'a, dyn World>,
/// The grid cells.
- cells: &'a [LayoutNode],
+ cells: &'a [Content],
/// The column tracks including gutter tracks.
cols: Vec<TrackSizing>,
/// The row tracks including gutter tracks.
@@ -136,7 +141,7 @@ impl<'a> GridLayouter<'a> {
world: Tracked<'a, dyn World>,
tracks: Axes<&[TrackSizing]>,
gutter: Axes<&[TrackSizing]>,
- cells: &'a [LayoutNode],
+ cells: &'a [Content],
regions: &Regions,
styles: StyleChain<'a>,
) -> Self {
@@ -301,7 +306,8 @@ impl<'a> GridLayouter<'a> {
v.resolve(self.styles).relative_to(self.regions.base.y);
}
- let frame = node.layout(self.world, &pod, self.styles)?.remove(0);
+ let frame =
+ node.layout_block(self.world, &pod, self.styles)?.remove(0);
resolved.set_max(frame.width());
}
}
@@ -371,7 +377,7 @@ impl<'a> GridLayouter<'a> {
}
let mut sizes = node
- .layout(self.world, &pod, self.styles)?
+ .layout_block(self.world, &pod, self.styles)?
.into_iter()
.map(|frame| frame.height());
@@ -460,7 +466,7 @@ impl<'a> GridLayouter<'a> {
.select(self.regions.base, size);
let pod = Regions::one(size, base, Axes::splat(true));
- let frame = node.layout(self.world, &pod, self.styles)?.remove(0);
+ let frame = node.layout_block(self.world, &pod, self.styles)?.remove(0);
match frame.role() {
Some(Role::ListLabel | Role::ListItemBody) => {
output.apply_role(Role::ListItem)
@@ -508,7 +514,7 @@ impl<'a> GridLayouter<'a> {
}
// Push the layouted frames into the individual output frames.
- let frames = node.layout(self.world, &pod, self.styles)?;
+ let frames = node.layout_block(self.world, &pod, self.styles)?;
for (output, frame) in outputs.iter_mut().zip(frames) {
match frame.role() {
Some(Role::ListLabel | Role::ListItemBody) => {
@@ -576,7 +582,7 @@ impl<'a> GridLayouter<'a> {
///
/// Returns `None` if it's a gutter cell.
#[track_caller]
- fn cell(&self, x: usize, y: usize) -> Option<&'a LayoutNode> {
+ fn cell(&self, x: usize, y: usize) -> Option<&'a Content> {
assert!(x < self.cols.len());
assert!(y < self.rows.len());
diff --git a/src/library/layout/pad.rs b/src/library/layout/pad.rs
index b0238d40..effdd5f8 100644
--- a/src/library/layout/pad.rs
+++ b/src/library/layout/pad.rs
@@ -6,10 +6,10 @@ pub struct PadNode {
/// The amount of padding.
pub padding: Sides<Rel<Length>>,
/// The child node whose sides to pad.
- pub child: LayoutNode,
+ pub child: Content,
}
-#[node]
+#[node(Layout)]
impl PadNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
let all = args.named("rest")?.or(args.find()?);
@@ -19,9 +19,9 @@ impl PadNode {
let top = args.named("top")?.or(y).or(all).unwrap_or_default();
let right = args.named("right")?.or(x).or(all).unwrap_or_default();
let bottom = args.named("bottom")?.or(y).or(all).unwrap_or_default();
- let body: LayoutNode = args.expect("body")?;
+ let body = args.expect::<Content>("body")?;
let padding = Sides::new(left, top, right, bottom);
- Ok(Content::block(body.padded(padding)))
+ Ok(body.padded(padding))
}
}
@@ -35,7 +35,7 @@ impl Layout for PadNode {
// Layout child into padded regions.
let padding = self.padding.resolve(styles);
let pod = regions.map(|size| shrink(size, padding));
- let mut frames = self.child.layout(world, &pod, styles)?;
+ let mut frames = self.child.layout_block(world, &pod, styles)?;
for frame in &mut frames {
// Apply the padding inversely such that the grown size padded
@@ -51,6 +51,10 @@ impl Layout for PadNode {
Ok(frames)
}
+
+ fn level(&self) -> Level {
+ Level::Block
+ }
}
/// Shrink a size by padding relative to the size itself.
diff --git a/src/library/layout/page.rs b/src/library/layout/page.rs
index 2e5cf2f9..f5821ae6 100644
--- a/src/library/layout/page.rs
+++ b/src/library/layout/page.rs
@@ -5,7 +5,7 @@ use crate::library::prelude::*;
/// Layouts its child onto one or multiple pages.
#[derive(PartialEq, Clone, Hash)]
-pub struct PageNode(pub LayoutNode);
+pub struct PageNode(pub Content);
#[node]
impl PageNode {
@@ -41,7 +41,7 @@ impl PageNode {
pub const FOREGROUND: Marginal = Marginal::None;
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
- Ok(Content::Page(Self(args.expect("body")?)))
+ Ok(Self(args.expect("body")?).pack())
}
fn set(...) {
@@ -96,7 +96,7 @@ impl PageNode {
// Layout the child.
let regions = Regions::repeat(size, size, size.map(Abs::is_finite));
- let mut frames = child.layout(world, &regions, styles)?;
+ let mut frames = child.layout_block(world, &regions, styles)?;
let header = styles.get(Self::HEADER);
let footer = styles.get(Self::FOOTER);
@@ -127,7 +127,7 @@ impl PageNode {
] {
if let Some(content) = marginal.resolve(world, page)? {
let pod = Regions::one(area, area, Axes::splat(true));
- let mut sub = content.layout(world, &pod, styles)?.remove(0);
+ let mut sub = content.layout_block(world, &pod, styles)?.remove(0);
sub.apply_role(role);
if role == Role::Background {
@@ -154,13 +154,16 @@ impl Debug for PageNode {
}
/// A page break.
-pub struct PagebreakNode;
+#[derive(Debug, Copy, Clone, Hash)]
+pub struct PagebreakNode {
+ pub weak: bool,
+}
#[node]
impl PagebreakNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
let weak = args.named("weak")?.unwrap_or(false);
- Ok(Content::Pagebreak { weak })
+ Ok(Self { weak }.pack())
}
}
@@ -201,7 +204,7 @@ impl Cast<Spanned<Value>> for Marginal {
fn cast(value: Spanned<Value>) -> StrResult<Self> {
match value.v {
Value::None => Ok(Self::None),
- Value::Str(v) => Ok(Self::Content(Content::Text(v.into()))),
+ Value::Str(v) => Ok(Self::Content(TextNode(v.into()).pack())),
Value::Content(v) => Ok(Self::Content(v)),
Value::Func(v) => Ok(Self::Func(v, value.span)),
v => Err(format!(
diff --git a/src/library/layout/place.rs b/src/library/layout/place.rs
index 8b68c087..42ab0fba 100644
--- a/src/library/layout/place.rs
+++ b/src/library/layout/place.rs
@@ -3,18 +3,16 @@ use crate::library::prelude::*;
/// Place a node at an absolute position.
#[derive(Debug, Hash)]
-pub struct PlaceNode(pub LayoutNode);
+pub struct PlaceNode(pub Content);
-#[node]
+#[node(Layout)]
impl PlaceNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
let aligns = args.find()?.unwrap_or(Axes::with_x(Some(RawAlign::Start)));
let dx = args.named("dx")?.unwrap_or_default();
let dy = args.named("dy")?.unwrap_or_default();
- let body: LayoutNode = args.expect("body")?;
- Ok(Content::block(Self(
- body.moved(Axes::new(dx, dy)).aligned(aligns),
- )))
+ let body = args.expect::<Content>("body")?;
+ Ok(Self(body.moved(Axes::new(dx, dy)).aligned(aligns)).pack())
}
}
@@ -35,7 +33,7 @@ impl Layout for PlaceNode {
Regions::one(regions.base, regions.base, expand)
};
- let mut frames = self.0.layout(world, &pod, styles)?;
+ let mut frames = self.0.layout_block(world, &pod, styles)?;
// If expansion is off, zero all sizes so that we don't take up any
// space in our parent. Otherwise, respect the expand settings.
@@ -44,6 +42,10 @@ impl Layout for PlaceNode {
Ok(frames)
}
+
+ fn level(&self) -> Level {
+ Level::Block
+ }
}
impl PlaceNode {
diff --git a/src/library/layout/spacing.rs b/src/library/layout/spacing.rs
index 28e52d73..6df5cde5 100644
--- a/src/library/layout/spacing.rs
+++ b/src/library/layout/spacing.rs
@@ -4,26 +4,35 @@ use crate::library::prelude::*;
use crate::library::text::ParNode;
/// Horizontal spacing.
-pub struct HNode;
+#[derive(Debug, Clone, Hash)]
+pub struct HNode {
+ pub amount: Spacing,
+ pub weak: bool,
+}
#[node]
impl HNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
let amount = args.expect("spacing")?;
let weak = args.named("weak")?.unwrap_or(false);
- Ok(Content::Horizontal { amount, weak })
+ Ok(Self { amount, weak }.pack())
}
}
/// Vertical spacing.
-pub struct VNode;
+#[derive(Debug, Clone, Hash)]
+pub struct VNode {
+ pub amount: Spacing,
+ pub weak: bool,
+ pub generated: bool,
+}
#[node]
impl VNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
let amount = args.expect("spacing")?;
let weak = args.named("weak")?.unwrap_or(false);
- Ok(Content::Vertical { amount, weak, generated: false })
+ Ok(Self { amount, weak, generated: false }.pack())
}
}
diff --git a/src/library/layout/stack.rs b/src/library/layout/stack.rs
index b9663dd6..9ea7965d 100644
--- a/src/library/layout/stack.rs
+++ b/src/library/layout/stack.rs
@@ -1,6 +1,7 @@
use super::{AlignNode, Spacing};
use crate::library::prelude::*;
use crate::library::text::ParNode;
+use crate::model::StyledNode;
/// Arrange nodes and spacing along an axis.
#[derive(Debug, Hash)]
@@ -13,14 +14,15 @@ pub struct StackNode {
pub children: Vec<StackChild>,
}
-#[node]
+#[node(Layout)]
impl StackNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
- Ok(Content::block(Self {
+ Ok(Self {
dir: args.named("dir")?.unwrap_or(Dir::TTB),
spacing: args.named("spacing")?,
children: args.all()?,
- }))
+ }
+ .pack())
}
}
@@ -55,6 +57,10 @@ impl Layout for StackNode {
Ok(layouter.finish())
}
+
+ fn level(&self) -> Level {
+ Level::Block
+ }
}
/// A child of a stack node.
@@ -63,7 +69,7 @@ pub enum StackChild {
/// Spacing between other nodes.
Spacing(Spacing),
/// An arbitrary node.
- Node(LayoutNode),
+ Node(Content),
}
impl Debug for StackChild {
@@ -82,7 +88,7 @@ castable! {
Value::Ratio(v) => Self::Spacing(Spacing::Relative(v.into())),
Value::Relative(v) => Self::Spacing(Spacing::Relative(v)),
Value::Fraction(v) => Self::Spacing(Spacing::Fractional(v)),
- Value::Content(v) => Self::Node(v.pack()),
+ Value::Content(v) => Self::Node(v),
}
/// Performs stack layout.
@@ -169,7 +175,7 @@ impl<'a> StackLayouter<'a> {
pub fn layout_node(
&mut self,
world: Tracked<dyn World>,
- node: &LayoutNode,
+ node: &Content,
styles: StyleChain,
) -> SourceResult<()> {
if self.regions.is_full() {
@@ -183,17 +189,17 @@ impl<'a> StackLayouter<'a> {
.and_then(|node| node.aligns.get(self.axis))
.map(|align| align.resolve(styles))
.unwrap_or_else(|| {
- if let Some(Content::Styled(styled)) = node.downcast::<Content>() {
- let map = &styled.1;
+ if let Some(styled) = node.downcast::<StyledNode>() {
+ let map = &styled.map;
if map.contains(ParNode::ALIGN) {
- return StyleChain::with_root(&styled.1).get(ParNode::ALIGN);
+ return StyleChain::with_root(map).get(ParNode::ALIGN);
}
}
self.dir.start().into()
});
- let frames = node.layout(world, &self.regions, styles)?;
+ let frames = node.layout_block(world, &self.regions, styles)?;
let len = frames.len();
for (i, mut frame) in frames.into_iter().enumerate() {
// Set the generic block role.
diff --git a/src/library/layout/transform.rs b/src/library/layout/transform.rs
index ff42744a..061efa6b 100644
--- a/src/library/layout/transform.rs
+++ b/src/library/layout/transform.rs
@@ -7,18 +7,19 @@ pub struct MoveNode {
/// The offset by which to move the node.
pub delta: Axes<Rel<Length>>,
/// The node whose contents should be moved.
- pub child: LayoutNode,
+ pub child: Content,
}
-#[node]
+#[node(Layout)]
impl MoveNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
let dx = args.named("dx")?.unwrap_or_default();
let dy = args.named("dy")?.unwrap_or_default();
- Ok(Content::inline(Self {
+ Ok(Self {
delta: Axes::new(dx, dy),
child: args.expect("body")?,
- }))
+ }
+ .pack())
}
}
@@ -29,7 +30,7 @@ impl Layout for MoveNode {
regions: &Regions,
styles: StyleChain,
) -> SourceResult<Vec<Frame>> {
- let mut frames = self.child.layout(world, regions, styles)?;
+ let mut frames = self.child.layout_inline(world, regions, styles)?;
let delta = self.delta.resolve(styles);
for frame in &mut frames {
@@ -39,6 +40,10 @@ impl Layout for MoveNode {
Ok(frames)
}
+
+ fn level(&self) -> Level {
+ Level::Inline
+ }
}
/// Transform a node without affecting layout.
@@ -47,7 +52,7 @@ pub struct TransformNode<const T: TransformKind> {
/// Transformation to apply to the contents.
pub transform: Transform,
/// The node whose contents should be transformed.
- pub child: LayoutNode,
+ pub child: Content,
}
/// Rotate a node without affecting layout.
@@ -56,7 +61,7 @@ pub type RotateNode = TransformNode<ROTATE>;
/// Scale a node without affecting layout.
pub type ScaleNode = TransformNode<SCALE>;
-#[node]
+#[node(Layout)]
impl<const T: TransformKind> TransformNode<T> {
/// The origin of the transformation.
#[property(resolve)]
@@ -76,10 +81,7 @@ impl<const T: TransformKind> TransformNode<T> {
}
};
- Ok(Content::inline(Self {
- transform,
- child: args.expect("body")?,
- }))
+ Ok(Self { transform, child: args.expect("body")? }.pack())
}
}
@@ -91,7 +93,7 @@ impl<const T: TransformKind> Layout for TransformNode<T> {
styles: StyleChain,
) -> SourceResult<Vec<Frame>> {
let origin = styles.get(Self::ORIGIN).unwrap_or(Align::CENTER_HORIZON);
- let mut frames = self.child.layout(world, regions, styles)?;
+ let mut frames = self.child.layout_inline(world, regions, styles)?;
for frame in &mut frames {
let Axes { x, y } = origin.zip(frame.size()).map(|(o, s)| o.position(s));
@@ -104,6 +106,10 @@ impl<const T: TransformKind> Layout for TransformNode<T> {
Ok(frames)
}
+
+ fn level(&self) -> Level {
+ Level::Inline
+ }
}
/// Kinds of transformations.