diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-01-07 21:24:36 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-01-08 00:20:48 +0100 |
| commit | e74ae6ce70d4c6ca006613eadf07f920951789e3 (patch) | |
| tree | 0b9b2ddabf79dad8d55631780ee5d70afe7362d7 /src/library/transform.rs | |
| parent | 0b624390906e911bde325b487b2710b67c8205c8 (diff) | |
Make all nodes into classes
Diffstat (limited to 'src/library/transform.rs')
| -rw-r--r-- | src/library/transform.rs | 122 |
1 files changed, 81 insertions, 41 deletions
diff --git a/src/library/transform.rs b/src/library/transform.rs index 7392b89f..aceb4197 100644 --- a/src/library/transform.rs +++ b/src/library/transform.rs @@ -3,64 +3,49 @@ use super::prelude::*; use crate::geom::Transform; -/// `move`: Move content without affecting layout. -pub fn move_(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - 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.named("angle")?.or_else(|| args.find()).unwrap_or_default(); - let transform = Transform::rotation(angle); - transform_impl(args, transform) -} - -fn transform_impl(args: &mut Args, transform: Transform) -> TypResult<Value> { - let body: PackedNode = args.expect("body")?; - let origin = args - .named("origin")? - .unwrap_or(Spec::splat(None)) - .unwrap_or(Align::CENTER_HORIZON); - - Ok(Value::inline(body.transformed(transform, origin))) -} - /// A node that transforms its child without affecting layout. #[derive(Debug, Hash)] -pub struct TransformNode { +pub struct TransformNode<T: TransformKind> { /// Transformation to apply to the contents. - pub transform: Transform, - /// The origin of the transformation. - pub origin: Spec<Align>, + pub kind: T, /// The node whose contents should be transformed. pub child: PackedNode, } -impl Layout for TransformNode { +#[class] +impl<T: TransformKind> TransformNode<T> { + /// The origin of the transformation. + pub const ORIGIN: Spec<Option<Align>> = Spec::default(); + + fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> { + Ok(Node::inline(Self { + kind: T::construct(args)?, + child: args.expect("body")?, + })) + } + + fn set(args: &mut Args, styles: &mut StyleMap) -> TypResult<()> { + styles.set_opt(Self::ORIGIN, args.named("origin")?); + Ok(()) + } +} + +impl<T: TransformKind> Layout for TransformNode<T> { fn layout( &self, ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, ) -> Vec<Constrained<Rc<Frame>>> { + let origin = styles.get(Self::ORIGIN).unwrap_or(Align::CENTER_HORIZON); + let matrix = self.kind.matrix(); + let mut frames = self.child.layout(ctx, regions, styles); for Constrained { item: frame, .. } in &mut frames { - let Spec { x, y } = self.origin.zip(frame.size).map(|(o, s)| o.resolve(s)); + let Spec { x, y } = origin.zip(frame.size).map(|(o, s)| o.resolve(s)); let transform = Transform::translation(x, y) - .pre_concat(self.transform) + .pre_concat(matrix) .pre_concat(Transform::translation(-x, -y)); Rc::make_mut(frame).transform(transform); @@ -69,3 +54,58 @@ impl Layout for TransformNode { frames } } + +/// Kinds of transformations. +pub trait TransformKind: Debug + Hash + Sized + 'static { + fn construct(args: &mut Args) -> TypResult<Self>; + fn matrix(&self) -> Transform; +} + +/// A translation on the X and Y axes. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct Move(pub Length, pub Length); + +impl TransformKind for Move { + fn construct(args: &mut Args) -> TypResult<Self> { + let tx = args.named("x")?.unwrap_or_default(); + let ty = args.named("y")?.unwrap_or_default(); + Ok(Self(tx, ty)) + } + + fn matrix(&self) -> Transform { + Transform::translation(self.0, self.1) + } +} + +/// A rotational transformation. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct Rotate(pub Angle); + +impl TransformKind for Rotate { + fn construct(args: &mut Args) -> TypResult<Self> { + Ok(Self( + args.named("angle")?.or_else(|| args.find()).unwrap_or_default(), + )) + } + + fn matrix(&self) -> Transform { + Transform::rotation(self.0) + } +} + +/// A scale transformation. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct Scale(pub Relative, pub Relative); + +impl TransformKind for Scale { + fn construct(args: &mut Args) -> TypResult<Self> { + 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()); + Ok(Self(sx, sy)) + } + + fn matrix(&self) -> Transform { + Transform::scale(self.0, self.1) + } +} |
