//! 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 { /// The list labelling style -- unordered or ordered. pub kind: L, /// The node that produces the item's body. pub child: PackedNode, } #[class] impl ListNode { /// 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 { 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 Layout for ListNode { fn layout( &self, ctx: &mut LayoutContext, regions: &Regions, styles: StyleChain, ) -> Vec>> { 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); impl ListKind for Ordered { fn label(&self) -> EcoString { format_eco!("{}.", self.0.unwrap_or(1)) } }