diff options
Diffstat (limited to 'src/library/transform.rs')
| -rw-r--r-- | src/library/transform.rs | 66 |
1 files changed, 51 insertions, 15 deletions
diff --git a/src/library/transform.rs b/src/library/transform.rs index 7553bef2..8d1c6132 100644 --- a/src/library/transform.rs +++ b/src/library/transform.rs @@ -1,24 +1,54 @@ use super::prelude::*; +use crate::geom::Transform; /// `move`: Move content without affecting layout. pub fn move_(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - let offset = Spec::new(args.named("x")?, args.named("y")?); + let tx = args.named("x")?.unwrap_or_default(); + let ty = args.named("y")?.unwrap_or_default(); + let transform = Transform::translation(tx, ty); + transform_impl(args, transform) +} + +/// `scale`: Scale content without affecting layout. +pub fn scale(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { + let all = args.find(); + let sx = args.named("x")?.or(all).unwrap_or(Relative::one()); + let sy = args.named("y")?.or(all).unwrap_or(Relative::one()); + let transform = Transform::scaling(sx, sy); + transform_impl(args, transform) +} + +/// `rotate`: Rotate content without affecting layout. +pub fn rotate(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { + let angle = args.expect("angle")?; + let transform = Transform::rotation(angle); + transform_impl(args, transform) +} + +fn transform_impl(args: &mut Args, transform: Transform) -> TypResult<Value> { let body: Template = args.expect("body")?; + let origin = args + .named("origin")? + .unwrap_or(Spec::splat(None)) + .unwrap_or(Spec::new(Align::Center, Align::Horizon)); + Ok(Value::Template(Template::from_inline(move |style| { - body.pack(style).moved(offset) + body.pack(style).transformed(transform, origin) }))) } -/// A node that moves its child without affecting layout. +/// A node that transforms its child without affecting layout. #[derive(Debug, Hash)] -pub struct MoveNode { - /// The node whose contents should be moved. +pub struct TransformNode { + /// The node whose contents should be transformed. pub child: PackedNode, - /// How much to move the contents. - pub offset: Spec<Option<Linear>>, + /// Transformation to apply to the contents. + pub transform: Transform, + /// The origin of the transformation. + pub origin: Spec<Align>, } -impl Layout for MoveNode { +impl Layout for TransformNode { fn layout( &self, ctx: &mut LayoutContext, @@ -26,13 +56,19 @@ impl Layout for MoveNode { ) -> Vec<Constrained<Rc<Frame>>> { let mut frames = self.child.layout(ctx, regions); - for (Constrained { item: frame, .. }, (_, base)) in - frames.iter_mut().zip(regions.iter()) - { - Rc::make_mut(frame).translate(Point::new( - self.offset.x.map(|x| x.resolve(base.w)).unwrap_or_default(), - self.offset.y.map(|y| y.resolve(base.h)).unwrap_or_default(), - )); + for Constrained { item: frame, .. } in frames.iter_mut() { + let x = self.origin.x.resolve(frame.size.w); + let y = self.origin.y.resolve(frame.size.h); + let transform = Transform::translation(x, y) + .pre_concat(self.transform) + .pre_concat(Transform::translation(-x, -y)); + + let mut wrapper = Frame::new(frame.size, frame.baseline); + wrapper.push( + Point::zero(), + Element::Group(Group::new(std::mem::take(frame)).transform(transform)), + ); + *frame = Rc::new(wrapper); } frames |
