typst_library/layout/stack.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
use std::fmt::{self, Debug, Formatter};
use crate::diag::SourceResult;
use crate::engine::Engine;
use crate::foundations::{cast, elem, Content, NativeElement, Packed, Show, StyleChain};
use crate::layout::{BlockElem, Dir, Spacing};
/// Arranges content and spacing horizontally or vertically.
///
/// The stack places a list of items along an axis, with optional spacing
/// between each item.
///
/// # Example
/// ```example
/// #stack(
/// dir: ttb,
/// rect(width: 40pt),
/// rect(width: 120pt),
/// rect(width: 90pt),
/// )
/// ```
#[elem(Show)]
pub struct StackElem {
/// The direction along which the items are stacked. Possible values are:
///
/// - `{ltr}`: Left to right.
/// - `{rtl}`: Right to left.
/// - `{ttb}`: Top to bottom.
/// - `{btt}`: Bottom to top.
///
/// You can use the `start` and `end` methods to obtain the initial and
/// final points (respectively) of a direction, as `alignment`. You can also
/// use the `axis` method to determine whether a direction is
/// `{"horizontal"}` or `{"vertical"}`. The `inv` method returns a
/// direction's inverse direction.
///
/// For example, `{ttb.start()}` is `top`, `{ttb.end()}` is `bottom`,
/// `{ttb.axis()}` is `{"vertical"}` and `{ttb.inv()}` is equal to `btt`.
#[default(Dir::TTB)]
pub dir: Dir,
/// Spacing to insert between items where no explicit spacing was provided.
pub spacing: Option<Spacing>,
/// The children to stack along the axis.
#[variadic]
pub children: Vec<StackChild>,
}
impl Show for Packed<StackElem> {
fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> {
Ok(BlockElem::multi_layouter(self.clone(), engine.routines.layout_stack)
.pack()
.spanned(self.span()))
}
}
/// A child of a stack element.
#[derive(Clone, PartialEq, Hash)]
pub enum StackChild {
/// Spacing between other children.
Spacing(Spacing),
/// Arbitrary block-level content.
Block(Content),
}
impl Debug for StackChild {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::Spacing(kind) => kind.fmt(f),
Self::Block(block) => block.fmt(f),
}
}
}
cast! {
StackChild,
self => match self {
Self::Spacing(spacing) => spacing.into_value(),
Self::Block(content) => content.into_value(),
},
v: Spacing => Self::Spacing(v),
v: Content => Self::Block(v),
}