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 Machine, args: &mut Args) -> TypResult { 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, ctx: &mut Context, regions: &Regions, styles: StyleChain, ) -> TypResult>> { let mut frames = self.child.layout(ctx, 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)); Arc::make_mut(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 Machine, args: &mut Args) -> TypResult { 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, ctx: &mut Context, regions: &Regions, styles: StyleChain, ) -> TypResult>> { let origin = styles.get(Self::ORIGIN).unwrap_or(Align::CENTER_HORIZON); let mut frames = self.child.layout(ctx, 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)); Arc::make_mut(frame).transform(transform); } Ok(frames) } } /// Kinds of transformations. pub type TransformKind = usize; /// A rotational transformation. const ROTATE: TransformKind = 1; /// A scale transformation. const SCALE: TransformKind = 2;