diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-02-28 15:50:48 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-02-28 23:54:34 +0100 |
| commit | 3ca5b238238e1128aa7bbfbd5db9e632045d8600 (patch) | |
| tree | 2471f4b340a15695b7f4d518c0b39fabaea676c4 /src/library/layout/transform.rs | |
| parent | b63c21c91d99a1554a019dc275f955d3e6a34271 (diff) | |
Reorganize library
Diffstat (limited to 'src/library/layout/transform.rs')
| -rw-r--r-- | src/library/layout/transform.rs | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/src/library/layout/transform.rs b/src/library/layout/transform.rs new file mode 100644 index 00000000..fafb37a4 --- /dev/null +++ b/src/library/layout/transform.rs @@ -0,0 +1,86 @@ +use crate::geom::Transform; +use crate::library::prelude::*; + +/// Transform a node without affecting layout. +#[derive(Debug, Hash)] +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, +} + +/// Transform a node by translating it without affecting layout. +pub type MoveNode = TransformNode<MOVE>; + +/// Transform a node by rotating it without affecting layout. +pub type RotateNode = TransformNode<ROTATE>; + +/// Transform a node by scaling it without affecting layout. +pub type ScaleNode = TransformNode<SCALE>; + +#[class] +impl<const T: TransformKind> TransformNode<T> { + /// The origin of the transformation. + pub const ORIGIN: Spec<Option<Align>> = Spec::default(); + + fn construct(_: &mut Context, args: &mut Args) -> TypResult<Template> { + let transform = match T { + MOVE => { + let tx = args.named("x")?.unwrap_or_default(); + let ty = args.named("y")?.unwrap_or_default(); + Transform::translation(tx, ty) + } + ROTATE => { + let angle = args.named_or_find("angle")?.unwrap_or_default(); + Transform::rotation(angle) + } + SCALE | _ => { + 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()); + Transform::scale(sx, sy) + } + }; + + Ok(Template::inline(Self { + transform, + child: args.expect("body")?, + })) + } +} + +impl<const T: TransformKind> Layout for TransformNode<T> { + fn layout( + &self, + ctx: &mut Context, + regions: &Regions, + styles: StyleChain, + ) -> TypResult<Vec<Arc<Frame>>> { + 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.resolve(s)); + let transform = Transform::translation(x, y) + .pre_concat(self.transform) + .pre_concat(Transform::translation(-x, -y)); + + Arc::make_mut(frame).transform(transform); + } + + Ok(frames) + } +} + +/// Kinds of transformations. +pub type TransformKind = usize; + +/// A translation on the X and Y axes. +const MOVE: TransformKind = 0; + +/// A rotational transformation. +const ROTATE: TransformKind = 1; + +/// A scale transformation. +const SCALE: TransformKind = 2; |
