use crate::diag::SourceResult;
use crate::engine::Engine;
use crate::foundations::{
elem, Content, NativeElement, Packed, Resolve, Show, StyleChain,
};
use crate::introspection::Locator;
use crate::layout::{
layout_fragment, Abs, BlockElem, Fragment, Frame, Length, Point, Regions, Rel, Sides,
Size,
};
#[elem(title = "Padding", Show)]
pub struct PadElem {
#[parse(
let all = args.named("rest")?.or(args.find()?);
let x = args.named("x")?.or(all);
let y = args.named("y")?.or(all);
args.named("left")?.or(x)
)]
pub left: Rel<Length>,
#[parse(args.named("top")?.or(y))]
pub top: Rel<Length>,
#[parse(args.named("right")?.or(x))]
pub right: Rel<Length>,
#[parse(args.named("bottom")?.or(y))]
pub bottom: Rel<Length>,
#[external]
pub x: Rel<Length>,
#[external]
pub y: Rel<Length>,
#[external]
pub rest: Rel<Length>,
#[required]
pub body: Content,
}
impl Show for Packed<PadElem> {
fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> {
Ok(BlockElem::multi_layouter(self.clone(), layout_pad)
.pack()
.spanned(self.span()))
}
}
#[typst_macros::time(span = elem.span())]
fn layout_pad(
elem: &Packed<PadElem>,
engine: &mut Engine,
locator: Locator,
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
let padding = Sides::new(
elem.left(styles).resolve(styles),
elem.top(styles).resolve(styles),
elem.right(styles).resolve(styles),
elem.bottom(styles).resolve(styles),
);
let mut backlog = vec![];
let pod = regions.map(&mut backlog, |size| shrink(size, &padding));
let mut fragment = layout_fragment(engine, &elem.body, locator, styles, pod)?;
for frame in &mut fragment {
grow(frame, &padding);
}
Ok(fragment)
}
pub(crate) fn shrink(size: Size, inset: &Sides<Rel<Abs>>) -> Size {
size - inset.sum_by_axis().relative_to(size)
}
pub(crate) fn shrink_multiple(
size: &mut Size,
full: &mut Abs,
backlog: &mut [Abs],
last: &mut Option<Abs>,
inset: &Sides<Rel<Abs>>,
) {
let summed = inset.sum_by_axis();
*size -= summed.relative_to(*size);
*full -= summed.y.relative_to(*full);
for item in backlog {
*item -= summed.y.relative_to(*item);
}
*last = last.map(|v| v - summed.y.relative_to(v));
}
pub(crate) fn grow(frame: &mut Frame, inset: &Sides<Rel<Abs>>) {
let padded = frame
.size()
.zip_map(inset.sum_by_axis(), |s, p| (s + p.abs) / (1.0 - p.rel.get()));
let inset = inset.relative_to(padded);
let offset = Point::new(inset.left, inset.top);
frame.set_size(padded);
frame.translate(offset);
}