typst/src/library/list.rs

92 lines
2.6 KiB
Rust

//! Unordered (bulleted) and ordered (numbered) lists.
use super::prelude::*;
use super::{GridNode, TextNode, TrackSizing};
/// An unordered or ordered list.
#[derive(Debug, Hash)]
pub struct ListNode<L: ListKind> {
/// The list labelling style -- unordered or ordered.
pub kind: L,
/// The node that produces the item's body.
pub child: PackedNode,
}
#[class]
impl<L: ListKind> ListNode<L> {
/// The indentation of each item's label.
pub const LABEL_INDENT: Linear = Relative::new(0.0).into();
/// The space between the label and the body of each item.
pub const BODY_INDENT: Linear = Relative::new(0.5).into();
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
Ok(args
.all()
.map(|child: PackedNode| Node::block(Self { kind: L::default(), child }))
.sum())
}
fn set(args: &mut Args, styles: &mut StyleMap) -> TypResult<()> {
styles.set_opt(Self::LABEL_INDENT, args.named("label-indent")?);
styles.set_opt(Self::BODY_INDENT, args.named("body-indent")?);
Ok(())
}
}
impl<L: ListKind> Layout for ListNode<L> {
fn layout(
&self,
ctx: &mut LayoutContext,
regions: &Regions,
styles: StyleChain,
) -> Vec<Constrained<Arc<Frame>>> {
let em = styles.get(TextNode::SIZE).abs;
let label_indent = styles.get(Self::LABEL_INDENT).resolve(em);
let body_indent = styles.get(Self::BODY_INDENT).resolve(em);
let grid = GridNode {
tracks: Spec::with_x(vec![
TrackSizing::Linear(label_indent.into()),
TrackSizing::Auto,
TrackSizing::Linear(body_indent.into()),
TrackSizing::Auto,
]),
gutter: Spec::default(),
children: vec![
PackedNode::default(),
Node::Text(self.kind.label()).into_block(),
PackedNode::default(),
self.child.clone(),
],
};
grid.layout(ctx, regions, styles)
}
}
/// How to label a list.
pub trait ListKind: Debug + Default + Hash + Sync + Send + 'static {
/// Return the item's label.
fn label(&self) -> EcoString;
}
/// Unordered list labelling style.
#[derive(Debug, Default, Hash)]
pub struct Unordered;
impl ListKind for Unordered {
fn label(&self) -> EcoString {
'•'.into()
}
}
/// Ordered list labelling style.
#[derive(Debug, Default, Hash)]
pub struct Ordered(pub Option<usize>);
impl ListKind for Ordered {
fn label(&self) -> EcoString {
format_eco!("{}.", self.0.unwrap_or(1))
}
}