summaryrefslogtreecommitdiff
path: root/src/library/transform.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/library/transform.rs')
-rw-r--r--src/library/transform.rs66
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