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/align.rs | |
| parent | b63c21c91d99a1554a019dc275f955d3e6a34271 (diff) | |
Reorganize library
Diffstat (limited to 'src/library/layout/align.rs')
| -rw-r--r-- | src/library/layout/align.rs | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/src/library/layout/align.rs b/src/library/layout/align.rs new file mode 100644 index 00000000..7fbe0d01 --- /dev/null +++ b/src/library/layout/align.rs @@ -0,0 +1,71 @@ +use crate::library::prelude::*; +use crate::library::text::ParNode; + +/// Align a node along the layouting axes. +#[derive(Debug, Hash)] +pub struct AlignNode { + /// How to align the node horizontally and vertically. + pub aligns: Spec<Option<Align>>, + /// The node to be aligned. + pub child: LayoutNode, +} + +#[class] +impl AlignNode { + fn construct(_: &mut Context, args: &mut Args) -> TypResult<Template> { + let aligns: Spec<_> = args.find()?.unwrap_or_default(); + let body: LayoutNode = args.expect("body")?; + Ok(Template::block(body.aligned(aligns))) + } +} + +impl Layout for AlignNode { + fn layout( + &self, + ctx: &mut Context, + regions: &Regions, + styles: StyleChain, + ) -> TypResult<Vec<Arc<Frame>>> { + // The child only needs to expand along an axis if there's no alignment. + let mut pod = regions.clone(); + pod.expand &= self.aligns.map_is_none(); + + // Align paragraphs inside the child. + let mut passed = StyleMap::new(); + if let Some(align) = self.aligns.x { + passed.set(ParNode::ALIGN, align); + } + + // Layout the child. + let mut frames = self.child.layout(ctx, &pod, passed.chain(&styles))?; + for (region, frame) in regions.iter().zip(&mut frames) { + // Align in the target size. The target size depends on whether we + // should expand. + let target = regions.expand.select(region, frame.size); + let default = Spec::new(Align::Left, Align::Top); + let aligns = self.aligns.unwrap_or(default); + Arc::make_mut(frame).resize(target, aligns); + } + + Ok(frames) + } +} + +dynamic! { + Align: "alignment", +} + +dynamic! { + Spec<Align>: "2d alignment", +} + +castable! { + Spec<Option<Align>>, + Expected: "1d or 2d alignment", + @align: Align => { + let mut aligns = Spec::default(); + aligns.set(align.axis(), Some(*align)); + aligns + }, + @aligns: Spec<Align> => aligns.map(Some), +} |
