summaryrefslogtreecommitdiff
path: root/src/library/transform.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-01-07 21:24:36 +0100
committerLaurenz <laurmaedje@gmail.com>2022-01-08 00:20:48 +0100
commite74ae6ce70d4c6ca006613eadf07f920951789e3 (patch)
tree0b9b2ddabf79dad8d55631780ee5d70afe7362d7 /src/library/transform.rs
parent0b624390906e911bde325b487b2710b67c8205c8 (diff)
Make all nodes into classes
Diffstat (limited to 'src/library/transform.rs')
-rw-r--r--src/library/transform.rs122
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)
+ }
+}