diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-10-31 15:52:16 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-10-31 15:52:35 +0100 |
| commit | 5b344b663a3d224134923eea0d67ebf44c069b07 (patch) | |
| tree | 34a5fb464a38b9d4cb11294379b3ddf351dfce21 /src/library/layout.rs | |
| parent | feff013abb17f31bc5305fe77fe67cf615c19ff2 (diff) | |
Reorganize modules
Instead of separating functionality into layout and library, everything lives in the library now. This way, related things live side by side and there are no duplicate file names in the two directories.
Diffstat (limited to 'src/library/layout.rs')
| -rw-r--r-- | src/library/layout.rs | 332 |
1 files changed, 0 insertions, 332 deletions
diff --git a/src/library/layout.rs b/src/library/layout.rs deleted file mode 100644 index e5650664..00000000 --- a/src/library/layout.rs +++ /dev/null @@ -1,332 +0,0 @@ -use super::*; -use crate::layout::{ - GridNode, PadNode, ShapeKind, ShapeNode, StackChild, StackNode, TrackSizing, -}; -use crate::style::{Paper, PaperClass}; - -/// `page`: Configure pages. -pub fn page(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - let paper = match args.named::<Spanned<Str>>("paper")?.or_else(|| args.find()) { - Some(name) => match Paper::from_name(&name.v) { - None => bail!(name.span, "invalid paper name"), - paper => paper, - }, - None => None, - }; - - let width = args.named("width")?; - let height = args.named("height")?; - let margins = args.named("margins")?; - let left = args.named("left")?; - let top = args.named("top")?; - let right = args.named("right")?; - let bottom = args.named("bottom")?; - let flip = args.named("flip")?; - - ctx.template.modify(move |style| { - let page = style.page_mut(); - - if let Some(paper) = paper { - page.class = paper.class(); - page.size = paper.size(); - } - - if let Some(width) = width { - page.class = PaperClass::Custom; - page.size.w = width; - } - - if let Some(height) = height { - page.class = PaperClass::Custom; - page.size.h = height; - } - - if let Some(margins) = margins { - page.margins = Sides::splat(Some(margins)); - } - - if let Some(left) = left { - page.margins.left = Some(left); - } - - if let Some(top) = top { - page.margins.top = Some(top); - } - - if let Some(right) = right { - page.margins.right = Some(right); - } - - if let Some(bottom) = bottom { - page.margins.bottom = Some(bottom); - } - - if flip.unwrap_or(false) { - std::mem::swap(&mut page.size.w, &mut page.size.h); - } - }); - - ctx.template.pagebreak(false); - - Ok(Value::None) -} - -/// `pagebreak`: Start a new page. -pub fn pagebreak(_: &mut EvalContext, _: &mut Args) -> TypResult<Value> { - let mut template = Template::new(); - template.pagebreak(true); - Ok(Value::Template(template)) -} - -/// `align`: Configure the alignment along the layouting axes. -pub fn align(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - let first = args.find::<Align>(); - let second = args.find::<Align>(); - let body = args.find::<Template>(); - - let mut horizontal = args.named("horizontal")?; - let mut vertical = args.named("vertical")?; - - for value in first.into_iter().chain(second) { - match value.axis() { - Some(SpecAxis::Horizontal) | None if horizontal.is_none() => { - horizontal = Some(value); - } - Some(SpecAxis::Vertical) | None if vertical.is_none() => { - vertical = Some(value); - } - _ => {} - } - } - - let realign = |template: &mut Template| { - template.modify(move |style| { - if let Some(horizontal) = horizontal { - style.aligns.inline = horizontal; - } - - if let Some(vertical) = vertical { - style.aligns.block = vertical; - } - }); - - if vertical.is_some() { - template.parbreak(); - } - }; - - Ok(if let Some(body) = body { - let mut template = Template::new(); - template.save(); - realign(&mut template); - template += body; - template.restore(); - Value::Template(template) - } else { - realign(&mut ctx.template); - Value::None - }) -} - -/// `h`: Horizontal spacing. -pub fn h(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - let mut template = Template::new(); - template.spacing(GenAxis::Inline, args.expect("spacing")?); - Ok(Value::Template(template)) -} - -/// `v`: Vertical spacing. -pub fn v(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - let mut template = Template::new(); - template.spacing(GenAxis::Block, args.expect("spacing")?); - Ok(Value::Template(template)) -} - -/// `box`: Place content in a rectangular box. -pub fn box_(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - let width = args.named("width")?; - let height = args.named("height")?; - let fill = args.named("fill")?; - let body: Template = args.find().unwrap_or_default(); - Ok(Value::Template(Template::from_inline(move |style| { - ShapeNode { - shape: ShapeKind::Rect, - width, - height, - fill: fill.map(Paint::Color), - child: Some(body.to_stack(style).pack()), - } - }))) -} - -/// `block`: Place content in a block. -pub fn block(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - let body: Template = args.expect("body")?; - Ok(Value::Template(Template::from_block(move |style| { - body.to_stack(style) - }))) -} - -/// `pad`: Pad content at the sides. -pub fn pad(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - let all = args.find(); - let left = args.named("left")?; - let top = args.named("top")?; - let right = args.named("right")?; - let bottom = args.named("bottom")?; - let body: Template = args.expect("body")?; - - let padding = Sides::new( - left.or(all).unwrap_or_default(), - top.or(all).unwrap_or_default(), - right.or(all).unwrap_or_default(), - bottom.or(all).unwrap_or_default(), - ); - - Ok(Value::Template(Template::from_block(move |style| { - PadNode { - padding, - child: body.to_stack(&style).pack(), - } - }))) -} - -/// `move`: Move content without affecting layout. -pub fn move_(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - #[derive(Debug, Hash)] - struct MoveNode { - offset: Spec<Option<Linear>>, - child: ShapeNode, - } - - impl InlineLevel for MoveNode { - fn layout(&self, ctx: &mut LayoutContext, space: Length, base: Size) -> Frame { - let offset = 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(), - ); - - let mut frame = self.child.layout(ctx, space, base); - for (point, _) in &mut frame.children { - *point += offset; - } - - frame - } - } - - let x = args.named("x")?; - let y = args.named("y")?; - let body: Template = args.expect("body")?; - - Ok(Value::Template(Template::from_inline(move |style| { - MoveNode { - offset: Spec::new(x, y), - child: ShapeNode { - shape: ShapeKind::Rect, - width: None, - height: None, - fill: None, - child: Some(body.to_stack(style).pack()), - }, - } - }))) -} - -/// `stack`: Stack children along an axis. -pub fn stack(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - enum Child { - Spacing(Spacing), - Any(Template), - } - - castable! { - Child: "linear, fractional or template", - Value::Length(v) => Self::Spacing(Spacing::Linear(v.into())), - Value::Relative(v) => Self::Spacing(Spacing::Linear(v.into())), - Value::Linear(v) => Self::Spacing(Spacing::Linear(v)), - Value::Fractional(v) => Self::Spacing(Spacing::Fractional(v)), - Value::Template(v) => Self::Any(v), - } - - let dir = args.named("dir")?.unwrap_or(Dir::TTB); - let spacing = args.named("spacing")?; - let list: Vec<Child> = args.all().collect(); - - Ok(Value::Template(Template::from_block(move |style| { - let mut children = vec![]; - let mut delayed = None; - - // Build the list of stack children. - for child in &list { - match child { - Child::Spacing(v) => { - children.push(StackChild::Spacing(*v)); - delayed = None; - } - Child::Any(template) => { - if let Some(v) = delayed { - children.push(StackChild::Spacing(v)); - } - - let node = template.to_stack(style).pack(); - children.push(StackChild::Node(node, style.aligns.block)); - delayed = spacing; - } - } - } - - StackNode { dir, children } - }))) -} - -/// `grid`: Arrange children into a grid. -pub fn grid(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - castable! { - Vec<TrackSizing>: "integer or (auto, linear, fractional, or array thereof)", - Value::Auto => vec![TrackSizing::Auto], - Value::Length(v) => vec![TrackSizing::Linear(v.into())], - Value::Relative(v) => vec![TrackSizing::Linear(v.into())], - Value::Linear(v) => vec![TrackSizing::Linear(v)], - Value::Fractional(v) => vec![TrackSizing::Fractional(v)], - Value::Int(count) => vec![TrackSizing::Auto; count.max(0) as usize], - Value::Array(values) => values - .into_iter() - .filter_map(|v| v.cast().ok()) - .collect(), - } - - castable! { - TrackSizing: "auto, linear, or fractional", - Value::Auto => Self::Auto, - Value::Length(v) => Self::Linear(v.into()), - Value::Relative(v) => Self::Linear(v.into()), - Value::Linear(v) => Self::Linear(v), - Value::Fractional(v) => Self::Fractional(v), - } - - let columns = args.named("columns")?.unwrap_or_default(); - let rows = args.named("rows")?.unwrap_or_default(); - let tracks = Spec::new(columns, rows); - - let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default(); - let column_gutter = args.named("column-gutter")?; - let row_gutter = args.named("row-gutter")?; - let gutter = Spec::new( - column_gutter.unwrap_or_else(|| base_gutter.clone()), - row_gutter.unwrap_or(base_gutter), - ); - - let children: Vec<Template> = args.all().collect(); - - Ok(Value::Template(Template::from_block(move |style| { - GridNode { - tracks: tracks.clone(), - gutter: gutter.clone(), - children: children - .iter() - .map(|child| child.to_stack(&style).pack()) - .collect(), - } - }))) -} |
