From c0e972b91a7bf8d22cd24a38fc92a9c6214c8a0c Mon Sep 17 00:00:00 2001 From: Laurenz Date: Tue, 18 Oct 2022 00:02:38 +0200 Subject: Reduce dependencies from compiler on library --- src/library/layout/mod.rs | 2 + src/library/layout/page.rs | 2 +- src/library/layout/transform.rs | 118 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 src/library/layout/transform.rs (limited to 'src/library/layout') diff --git a/src/library/layout/mod.rs b/src/library/layout/mod.rs index 588b15aa..02276f22 100644 --- a/src/library/layout/mod.rs +++ b/src/library/layout/mod.rs @@ -10,6 +10,7 @@ mod page; mod place; mod spacing; mod stack; +mod transform; pub use align::*; pub use columns::*; @@ -21,3 +22,4 @@ pub use page::*; pub use place::*; pub use spacing::*; pub use stack::*; +pub use transform::*; diff --git a/src/library/layout/page.rs b/src/library/layout/page.rs index 9cbbcca5..7d13163d 100644 --- a/src/library/layout/page.rs +++ b/src/library/layout/page.rs @@ -188,7 +188,7 @@ impl Marginal { Self::Content(content) => Some(content.clone()), Self::Func(func, span) => { let args = Args::new(*span, [Value::Int(page as i64)]); - Some(func.call_detached(world, args)?.display()) + Some(func.call_detached(world, args)?.display(world)) } }) } diff --git a/src/library/layout/transform.rs b/src/library/layout/transform.rs new file mode 100644 index 00000000..b110f343 --- /dev/null +++ b/src/library/layout/transform.rs @@ -0,0 +1,118 @@ +use crate::geom::Transform; +use crate::library::prelude::*; + +/// Move a node without affecting layout. +#[derive(Debug, Hash)] +pub struct MoveNode { + /// The offset by which to move the node. + pub delta: Spec>, + /// The node whose contents should be moved. + pub child: LayoutNode, +} + +#[node] +impl MoveNode { + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult { + let dx = args.named("dx")?.unwrap_or_default(); + let dy = args.named("dy")?.unwrap_or_default(); + Ok(Content::inline(Self { + delta: Spec::new(dx, dy), + child: args.expect("body")?, + })) + } +} + +impl Layout for MoveNode { + fn layout( + &self, + world: Tracked, + regions: &Regions, + styles: StyleChain, + ) -> SourceResult> { + let mut frames = self.child.layout(world, regions, styles)?; + + let delta = self.delta.resolve(styles); + for frame in &mut frames { + let delta = delta.zip(frame.size()).map(|(d, s)| d.relative_to(s)); + frame.translate(delta.to_point()); + } + + Ok(frames) + } +} + +/// Transform a node without affecting layout. +#[derive(Debug, Hash)] +pub struct TransformNode { + /// Transformation to apply to the contents. + pub transform: Transform, + /// The node whose contents should be transformed. + pub child: LayoutNode, +} + +/// Rotate a node without affecting layout. +pub type RotateNode = TransformNode; + +/// Scale a node without affecting layout. +pub type ScaleNode = TransformNode; + +#[node] +impl TransformNode { + /// The origin of the transformation. + #[property(resolve)] + pub const ORIGIN: Spec> = Spec::default(); + + fn construct(_: &mut Vm, args: &mut Args) -> SourceResult { + let transform = match T { + ROTATE => { + let angle = args.named_or_find("angle")?.unwrap_or_default(); + Transform::rotate(angle) + } + SCALE | _ => { + let all = args.find()?; + let sx = args.named("x")?.or(all).unwrap_or(Ratio::one()); + let sy = args.named("y")?.or(all).unwrap_or(Ratio::one()); + Transform::scale(sx, sy) + } + }; + + Ok(Content::inline(Self { + transform, + child: args.expect("body")?, + })) + } +} + +impl Layout for TransformNode { + fn layout( + &self, + world: Tracked, + regions: &Regions, + styles: StyleChain, + ) -> SourceResult> { + let origin = styles.get(Self::ORIGIN).unwrap_or(Align::CENTER_HORIZON); + let mut frames = self.child.layout(world, regions, styles)?; + + for frame in &mut frames { + let Spec { x, y } = origin.zip(frame.size()).map(|(o, s)| o.position(s)); + let transform = Transform::translate(x, y) + .pre_concat(self.transform) + .pre_concat(Transform::translate(-x, -y)); + + frame.transform(transform); + } + + Ok(frames) + } +} + +/// Kinds of transformations. +/// +/// The move transformation is handled separately. +pub type TransformKind = usize; + +/// A rotational transformation. +const ROTATE: TransformKind = 1; + +/// A scale transformation. +const SCALE: TransformKind = 2; -- cgit v1.2.3